Загрузка данных
#!/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 compact OpenAPI path catalog to stdout:
- paths whose path key starts with /rest/api/workflow/v2/
- paths whose path key contains suit
- paths whose subtree mentions suit, for example in description, summary,
operation id, parameters, request bodies, responses, or refs
- short path/method descriptions, operation ids, tags, and internal ref names
- minimum object catalog for referenced objects, with lightweight fields such
as section, name, type, format, title, description, required/property names,
enum values, and nested refs
It intentionally does not include full parameters, response bodies, return-code
payloads, or full schema/component bodies.
Example:
USAGE
echo " ./${script_name} tt-api-schema.json > workflow-v2-suit.path-catalog.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 compact_text($n):
if . == null then
null
else
tostring
| gsub("[[:space:]]+"; " ")
| if length > $n then .[0:$n] + "..." else . end
end;
def mentions_suit:
any(.. | strings; test("suit"; "i"));
def selected_path($prefix):
(.key | startswith($prefix) or test("suit"; "i"))
or (.value | mentions_suit);
def deref($doc; $ref):
if ($ref | startswith("#/")) then
try ($doc | getpath($ref | pointer_segments)) catch null
else
null
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) | select(. != null) | internal_refs[] ] | unique) as $next
| .pending = ($next - .seen)
)
| .seen;
def ref_meta:
pointer_segments as $p
| {
ref: .,
section: (if $p[0] == "components" then $p[1] else $p[0] end),
name: $p[-1]
};
def object_summary($doc; $ref):
(deref($doc; $ref)) as $obj
| if $obj == null then
empty
else
($ref | ref_meta)
+ {
type: $obj.type,
format: $obj.format,
title: $obj.title,
description: ($obj.description | compact_text(360)),
required: $obj.required,
enum: (
if (($obj.enum // null) | type) == "array" then
($obj.enum | .[0:30])
else
null
end
),
property_count: (
(($obj.properties // {}) | length) as $n
| if $n > 0 then $n else null end
),
property_names: (
(($obj.properties // {}) | keys | sort) as $names
| if ($names | length) > 0 then $names[0:60] else null end
),
nested_refs: ([$obj | internal_refs[]] | unique)
}
| with_entries(select(.value != null and .value != [] and .value != {}))
end;
def http_methods:
["get", "put", "post", "delete", "patch", "options", "head", "trace"];
def operation_entries:
to_entries | map(select(.key as $method | http_methods | index($method)));
def compact_operation($entry):
{
method: $entry.key,
operationId: $entry.value.operationId,
summary: ($entry.value.summary | compact_text(240)),
description: ($entry.value.description | compact_text(520)),
tags: $entry.value.tags,
refs: ($entry.value | internal_refs)
}
| with_entries(select(.value != null and .value != []));
. as $spec
| (($spec.paths // {}) | with_entries(select(selected_path($prefix)))) as $selected_paths
| ($selected_paths
| to_entries
| map(
{
path: .key,
summary: (.value.summary | compact_text(240)),
description: (.value.description | compact_text(520)),
refs: (.value | internal_refs),
operations: (.value | operation_entries | map(compact_operation(.)))
}
| with_entries(select(.value != null and .value != []))
)
) as $path_catalog
| (ref_closure($spec; ($selected_paths | internal_refs))) as $refs
| ([$refs[] as $ref | object_summary($spec; $ref)] | sort_by(.section, .name, .ref)) as $objects
| {
openapi: $spec.openapi,
swagger: $spec.swagger,
info: $spec.info,
paths: $path_catalog,
objects: $objects,
"x-filter": {
purpose: "workflow-v2 and suit-related path catalog for choosing a later focused full extract",
path_prefix: $prefix,
extra_path_match: "path key contains suit, or path subtree mentions suit",
path_count: ($path_catalog | length),
operation_count: ([$path_catalog[].operations[]?] | length),
object_count: ($objects | length),
note: "No full parameters, responses, request bodies, or full schema/component bodies are included. Objects contain minimum metadata only. Use this catalog to choose exact paths/objects for a later full extract."
}
}
| with_entries(select(.key == "paths" or .key == "objects" or .key == "x-filter" or .value != null))
' "$spec_file"