Загрузка данных


#!/usr/bin/env bash
set -euo pipefail

usage() {
  local script_name
  script_name=$(basename "$0")
  printf 'Usage: ./%s OPENAPI_SPEC.json\n\n' "$script_name" >&2
  cat >&2 <<'USAGE'
Print a focused OpenAPI JSON extract to stdout:
- paths whose path key starts with /rest/api/workflow/v2/
- only top-level schema objects referenced from those paths, following internal
  $ref links transitively through the spec

Example:
USAGE
  echo "  ./${script_name} tt-api-schema.json > workflow-v2.extract.json" >&2
}

if [[ $# -ne 1 ]]; then
  usage
  exit 2
fi

spec_file=$1
prefix="/rest/api/workflow/v2/"

if ! command -v jq >/dev/null 2>&1; then
  echo "error: jq is required" >&2
  exit 127
fi

if [[ ! -f "$spec_file" ]]; then
  echo "error: input file not found: $spec_file" >&2
  exit 1
fi

jq --arg prefix "$prefix" '
def pointer_segments:
  sub("^#/"; "")
  | split("/")
  | map(gsub("~1"; "/") | gsub("~0"; "~"));

def internal_refs:
  [.. | objects | .["$ref"]? | strings | select(startswith("#/"))] | unique;

def deref($doc; $ref):
  if ($ref | startswith("#/")) then
    try ($doc | getpath($ref | pointer_segments)) catch empty
  else
    empty
  end;

def ref_closure($doc; $start):
  {seen: [], pending: ($start | unique)}
  | until((.pending | length) == 0;
      .pending as $todo
      | .seen = ((.seen + $todo) | unique)
      | ([ $todo[] as $ref | deref($doc; $ref) | internal_refs[] ] | unique) as $next
      | .pending = ($next - .seen)
    )
  | .seen;

def component_schema_name:
  select(startswith("#/components/schemas/"))
  | pointer_segments as $p
  | $p[2];

def definition_name:
  select(startswith("#/definitions/"))
  | pointer_segments as $p
  | $p[1];

. as $spec
| (($spec.paths // {}) | with_entries(select(.key | startswith($prefix)))) as $paths
| (ref_closure($spec; ($paths | internal_refs))) as $refs
| ([$refs[] | component_schema_name] | unique) as $component_schema_names
| ([$refs[] | definition_name] | unique) as $definition_names
| (($spec.components.schemas // {})
    | with_entries(select(.key as $name | ($component_schema_names | index($name)) != null))
  ) as $filtered_component_schemas
| (($spec.definitions // {})
    | with_entries(select(.key as $name | ($definition_names | index($name)) != null))
  ) as $filtered_definitions
| {
    openapi: $spec.openapi,
    swagger: $spec.swagger,
    info: $spec.info,
    paths: $paths,
    components: (
      if ($filtered_component_schemas | length) > 0 then
        {schemas: $filtered_component_schemas}
      else
        null
      end
    ),
    definitions: (
      if ($filtered_definitions | length) > 0 then
        $filtered_definitions
      else
        null
      end
    ),
    "x-filter": {
      path_prefix: $prefix,
      path_count: ($paths | length),
      component_schema_count: ($filtered_component_schemas | length),
      definition_count: ($filtered_definitions | length)
    }
  }
| with_entries(select(.key == "paths" or .key == "x-filter" or .value != null))
' "$spec_file"