@kirrosh/zond 0.26.0 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +59 -0
- package/README.md +22 -21
- package/bin/zond.mjs +23 -0
- package/package.json +13 -16
- package/scripts/npm/postinstall.mjs +76 -0
- package/src/CLAUDE.md +0 -112
- package/src/bun-types.d.ts +0 -5
- package/src/cli/argv.ts +0 -122
- package/src/cli/commands/add-api.ts +0 -146
- package/src/cli/commands/api/annotate/idempotency.ts +0 -59
- package/src/cli/commands/api/annotate/index.ts +0 -880
- package/src/cli/commands/api/annotate/lifecycle.ts +0 -74
- package/src/cli/commands/api/annotate/overlay.ts +0 -206
- package/src/cli/commands/api/annotate/pagination.ts +0 -64
- package/src/cli/commands/api/annotate/prompts.ts +0 -220
- package/src/cli/commands/api/annotate/readback.ts +0 -58
- package/src/cli/commands/api/annotate/resources.ts +0 -91
- package/src/cli/commands/api/annotate/seed-bodies.ts +0 -61
- package/src/cli/commands/audit.ts +0 -786
- package/src/cli/commands/catalog.ts +0 -97
- package/src/cli/commands/check.ts +0 -361
- package/src/cli/commands/checks.ts +0 -1072
- package/src/cli/commands/ci-init.ts +0 -223
- package/src/cli/commands/clean.ts +0 -212
- package/src/cli/commands/cleanup.ts +0 -236
- package/src/cli/commands/completions.ts +0 -192
- package/src/cli/commands/coverage.ts +0 -872
- package/src/cli/commands/db.ts +0 -611
- package/src/cli/commands/describe.ts +0 -120
- package/src/cli/commands/discover.ts +0 -1356
- package/src/cli/commands/doctor.ts +0 -661
- package/src/cli/commands/fixtures.ts +0 -402
- package/src/cli/commands/generate.ts +0 -577
- package/src/cli/commands/init/agents-md.ts +0 -61
- package/src/cli/commands/init/bootstrap.ts +0 -111
- package/src/cli/commands/init/index.ts +0 -244
- package/src/cli/commands/init/skills.ts +0 -141
- package/src/cli/commands/init/templates/agents.md +0 -86
- package/src/cli/commands/init/templates/markdown.d.ts +0 -4
- package/src/cli/commands/init/templates/skills/warm-up-target.md +0 -122
- package/src/cli/commands/init/templates/skills/zond-checks.md +0 -621
- package/src/cli/commands/init/templates/skills/zond-seed.md +0 -114
- package/src/cli/commands/init/templates/skills/zond-triage.md +0 -272
- package/src/cli/commands/init/templates/skills/zond.md +0 -861
- package/src/cli/commands/init/templates/zond-config.yml +0 -14
- package/src/cli/commands/prepare-fixtures.ts +0 -97
- package/src/cli/commands/probe/_seed-bodies.ts +0 -52
- package/src/cli/commands/probe/mass-assignment.ts +0 -594
- package/src/cli/commands/probe/security.ts +0 -537
- package/src/cli/commands/probe/static.ts +0 -255
- package/src/cli/commands/probe/webhooks.ts +0 -163
- package/src/cli/commands/probe.ts +0 -535
- package/src/cli/commands/reference.ts +0 -87
- package/src/cli/commands/refresh-api.ts +0 -227
- package/src/cli/commands/remove-api.ts +0 -150
- package/src/cli/commands/report-bundle.ts +0 -310
- package/src/cli/commands/report.ts +0 -241
- package/src/cli/commands/request.ts +0 -548
- package/src/cli/commands/run.ts +0 -1142
- package/src/cli/commands/schema-from-runs.ts +0 -128
- package/src/cli/commands/secrets.ts +0 -133
- package/src/cli/commands/session.ts +0 -244
- package/src/cli/commands/use.ts +0 -74
- package/src/cli/index.ts +0 -55
- package/src/cli/json-envelope.ts +0 -108
- package/src/cli/json-schemas.ts +0 -314
- package/src/cli/output.ts +0 -40
- package/src/cli/program.ts +0 -219
- package/src/cli/resolve.ts +0 -105
- package/src/cli/runtime.ts +0 -7
- package/src/cli/safe-live.ts +0 -24
- package/src/cli/status-filter.ts +0 -114
- package/src/cli/util/api-context.ts +0 -85
- package/src/cli/version.ts +0 -8
- package/src/core/audit/persist.ts +0 -183
- package/src/core/checks/budget.ts +0 -59
- package/src/core/checks/checks/_crud-helpers.ts +0 -133
- package/src/core/checks/checks/_negative_mutator.ts +0 -133
- package/src/core/checks/checks/_readback-helpers.ts +0 -133
- package/src/core/checks/checks/content_type_conformance.ts +0 -39
- package/src/core/checks/checks/cross_call_references.ts +0 -147
- package/src/core/checks/checks/cursor_boundary_fuzzing.ts +0 -219
- package/src/core/checks/checks/ensure_resource_availability.ts +0 -62
- package/src/core/checks/checks/idempotency_replay.ts +0 -242
- package/src/core/checks/checks/ignored_auth.ts +0 -254
- package/src/core/checks/checks/index.ts +0 -68
- package/src/core/checks/checks/lifecycle_transitions.ts +0 -416
- package/src/core/checks/checks/missing_required_header.ts +0 -40
- package/src/core/checks/checks/negative_data_rejection.ts +0 -148
- package/src/core/checks/checks/not_a_server_error.ts +0 -35
- package/src/core/checks/checks/open_cors_on_sensitive.ts +0 -160
- package/src/core/checks/checks/pagination_invariants.ts +0 -419
- package/src/core/checks/checks/positive_data_acceptance.ts +0 -33
- package/src/core/checks/checks/rate_limit_headers_absent.ts +0 -77
- package/src/core/checks/checks/response_headers_conformance.ts +0 -74
- package/src/core/checks/checks/response_schema_conformance.ts +0 -30
- package/src/core/checks/checks/status_code_conformance.ts +0 -132
- package/src/core/checks/checks/unsupported_method.ts +0 -63
- package/src/core/checks/checks/use_after_free.ts +0 -78
- package/src/core/checks/index.ts +0 -30
- package/src/core/checks/mode.ts +0 -82
- package/src/core/checks/recommended-action.ts +0 -68
- package/src/core/checks/registry.ts +0 -78
- package/src/core/checks/runner.ts +0 -1461
- package/src/core/checks/sarif.ts +0 -230
- package/src/core/checks/spec-findings.ts +0 -308
- package/src/core/checks/stateful.ts +0 -121
- package/src/core/checks/types.ts +0 -305
- package/src/core/checks/zond-extensions.ts +0 -73
- package/src/core/classifier/recommended-action.ts +0 -251
- package/src/core/context/current.ts +0 -51
- package/src/core/context/session.ts +0 -78
- package/src/core/coverage/loader.ts +0 -216
- package/src/core/coverage/reasons.ts +0 -300
- package/src/core/diagnostics/db-analysis.ts +0 -666
- package/src/core/diagnostics/failure-class.ts +0 -140
- package/src/core/diagnostics/failure-hints.ts +0 -112
- package/src/core/diagnostics/spec-pointer.ts +0 -99
- package/src/core/diagnostics/suggested-fixes.ts +0 -155
- package/src/core/exporter/case-study/index.ts +0 -270
- package/src/core/exporter/curl.ts +0 -40
- package/src/core/exporter/exporter.ts +0 -48
- package/src/core/exporter/html-report/escape.ts +0 -24
- package/src/core/exporter/html-report/index.ts +0 -479
- package/src/core/exporter/html-report/script.ts +0 -100
- package/src/core/exporter/html-report/styles.ts +0 -408
- package/src/core/generator/catalog-builder.ts +0 -179
- package/src/core/generator/chunker.ts +0 -78
- package/src/core/generator/coverage-phase.ts +0 -0
- package/src/core/generator/coverage-scanner.ts +0 -87
- package/src/core/generator/data-factory.ts +0 -759
- package/src/core/generator/describe.ts +0 -302
- package/src/core/generator/endpoint-warnings.ts +0 -52
- package/src/core/generator/fixtures-builder.ts +0 -332
- package/src/core/generator/index.ts +0 -14
- package/src/core/generator/openapi-reader.ts +0 -297
- package/src/core/generator/path-param-disambig.ts +0 -140
- package/src/core/generator/resources-builder.ts +0 -898
- package/src/core/generator/schema-utils.ts +0 -112
- package/src/core/generator/serializer.ts +0 -343
- package/src/core/generator/suite-generator.ts +0 -1301
- package/src/core/generator/types.ts +0 -63
- package/src/core/identity/identity-file.ts +0 -0
- package/src/core/lint/affects.ts +0 -28
- package/src/core/lint/config.ts +0 -96
- package/src/core/lint/format.ts +0 -42
- package/src/core/lint/index.ts +0 -94
- package/src/core/lint/reporter.ts +0 -128
- package/src/core/lint/rules/consistency.ts +0 -158
- package/src/core/lint/rules/heuristics.ts +0 -97
- package/src/core/lint/rules/strictness.ts +0 -109
- package/src/core/lint/types.ts +0 -96
- package/src/core/lint/walker.ts +0 -248
- package/src/core/meta/meta-store.ts +0 -11
- package/src/core/output/README.md +0 -73
- package/src/core/output/index.ts +0 -13
- package/src/core/output/run.ts +0 -91
- package/src/core/output/types.ts +0 -122
- package/src/core/parser/dynamic-values.ts +0 -160
- package/src/core/parser/env-interpolation.ts +0 -104
- package/src/core/parser/filter.ts +0 -97
- package/src/core/parser/schema.ts +0 -359
- package/src/core/parser/types.ts +0 -117
- package/src/core/parser/variables.ts +0 -0
- package/src/core/parser/yaml-parser.ts +0 -181
- package/src/core/probe/bootstrap.ts +0 -34
- package/src/core/probe/dry-run-envelope.ts +0 -61
- package/src/core/probe/mass-assignment/classify.ts +0 -175
- package/src/core/probe/mass-assignment/cleanup.ts +0 -52
- package/src/core/probe/mass-assignment/digest.ts +0 -114
- package/src/core/probe/mass-assignment/orchestrator.ts +0 -459
- package/src/core/probe/mass-assignment/regression.ts +0 -141
- package/src/core/probe/mass-assignment/suspects.ts +0 -92
- package/src/core/probe/mass-assignment/types.ts +0 -135
- package/src/core/probe/mass-assignment-probe-class.ts +0 -198
- package/src/core/probe/mass-assignment-probe.ts +0 -27
- package/src/core/probe/mass-assignment-template.ts +0 -240
- package/src/core/probe/method-probe.ts +0 -164
- package/src/core/probe/method-shared.ts +0 -69
- package/src/core/probe/negative-probe.ts +0 -691
- package/src/core/probe/orphan-tracker.ts +0 -188
- package/src/core/probe/path-discovery.ts +0 -439
- package/src/core/probe/probe-harness.ts +0 -119
- package/src/core/probe/registry.ts +0 -89
- package/src/core/probe/runner.ts +0 -136
- package/src/core/probe/security/baseline.ts +0 -174
- package/src/core/probe/security/classify.ts +0 -341
- package/src/core/probe/security/cleanup.ts +0 -125
- package/src/core/probe/security/detectors.ts +0 -71
- package/src/core/probe/security/digest.ts +0 -104
- package/src/core/probe/security/orchestrator.ts +0 -398
- package/src/core/probe/security/regression.ts +0 -103
- package/src/core/probe/security/types.ts +0 -151
- package/src/core/probe/security-probe-class.ts +0 -207
- package/src/core/probe/security-probe.ts +0 -32
- package/src/core/probe/shared.ts +0 -531
- package/src/core/probe/static-probe-class.ts +0 -125
- package/src/core/probe/types.ts +0 -165
- package/src/core/probe/verdict-aggregator.ts +0 -33
- package/src/core/probe/webhooks-probe.ts +0 -282
- package/src/core/reporter/console.ts +0 -240
- package/src/core/reporter/index.ts +0 -22
- package/src/core/reporter/json.ts +0 -22
- package/src/core/reporter/junit.ts +0 -93
- package/src/core/reporter/ndjson.ts +0 -37
- package/src/core/reporter/types.ts +0 -15
- package/src/core/runner/assertions.ts +0 -383
- package/src/core/runner/async-pool.ts +0 -108
- package/src/core/runner/auth-path.ts +0 -8
- package/src/core/runner/ci-context.ts +0 -72
- package/src/core/runner/executor.ts +0 -652
- package/src/core/runner/expr-eval.ts +0 -41
- package/src/core/runner/form-encode.ts +0 -41
- package/src/core/runner/http-client.ts +0 -224
- package/src/core/runner/learn-drift.ts +0 -293
- package/src/core/runner/preflight-vars.ts +0 -153
- package/src/core/runner/progress-tracker.ts +0 -73
- package/src/core/runner/rate-limiter.ts +0 -185
- package/src/core/runner/run-kind.ts +0 -45
- package/src/core/runner/schema-validator.ts +0 -308
- package/src/core/runner/send-request.ts +0 -232
- package/src/core/runner/transforms.ts +0 -65
- package/src/core/runner/types.ts +0 -94
- package/src/core/secrets/registry.ts +0 -164
- package/src/core/secrets/secrets-file.ts +0 -115
- package/src/core/selectors/operation-filter.ts +0 -144
- package/src/core/setup-api.ts +0 -590
- package/src/core/severity/category.ts +0 -94
- package/src/core/severity/index.ts +0 -58
- package/src/core/spec/infer-schema.ts +0 -102
- package/src/core/spec/layers.ts +0 -154
- package/src/core/spec/merge-specs.ts +0 -156
- package/src/core/spec/schema-from-runs.ts +0 -117
- package/src/core/spec/schema-overlay.ts +0 -130
- package/src/core/util/ajv.ts +0 -13
- package/src/core/util/format-eta.ts +0 -21
- package/src/core/util/headers.ts +0 -9
- package/src/core/util/url.ts +0 -24
- package/src/core/utils.ts +0 -13
- package/src/core/workspace/config.ts +0 -129
- package/src/core/workspace/fixture-gap-report.ts +0 -84
- package/src/core/workspace/fixture-gaps.ts +0 -71
- package/src/core/workspace/manifest.ts +0 -283
- package/src/core/workspace/output-rotation.ts +0 -62
- package/src/core/workspace/root.ts +0 -96
- package/src/core/workspace/triage-path.ts +0 -87
- package/src/db/lint-runs.ts +0 -47
- package/src/db/migrate.ts +0 -128
- package/src/db/migrations/0001_run_kind.sql +0 -25
- package/src/db/migrations/0002_run_kind_request.sql +0 -59
- package/src/db/migrations/sql.d.ts +0 -4
- package/src/db/queries/collections.ts +0 -133
- package/src/db/queries/coverage.ts +0 -9
- package/src/db/queries/dashboard.ts +0 -59
- package/src/db/queries/results.ts +0 -216
- package/src/db/queries/runs.ts +0 -289
- package/src/db/queries/sessions.ts +0 -42
- package/src/db/queries/settings.ts +0 -28
- package/src/db/queries/types.ts +0 -172
- package/src/db/queries.ts +0 -75
- package/src/db/schema.ts +0 -298
package/src/core/output/run.ts
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ARV-116 (m-19): runner that turns an `OutputSpec` + CLI flags into
|
|
3
|
-
* a `ResolvedOutput`, then renders and writes the payload.
|
|
4
|
-
*
|
|
5
|
-
* Resolution order:
|
|
6
|
-
* 1. `--json` and `--report` are mutually exclusive — error.
|
|
7
|
-
* 2. If `--report` is set, look it up in `aliases` first, then in
|
|
8
|
-
* `formats`. Unknown → error (consistent with ARV-97; never
|
|
9
|
-
* silently swallow a typo).
|
|
10
|
-
* 3. If `--json` is set, pick the first envelope-wrapping format
|
|
11
|
-
* from the spec. Specs without one fall back to the
|
|
12
|
-
* `defaultFormat` (acceptable for commands like `run` whose
|
|
13
|
-
* `--json` is special-cased — see ARV-117).
|
|
14
|
-
* 4. Otherwise use `defaultFormat`.
|
|
15
|
-
* 5. Channel: `--output` forces file. Without it, take the format's
|
|
16
|
-
* `defaultChannel`. File channel without an explicit `--output`
|
|
17
|
-
* uses `defaultFilename` (relative paths resolved against cwd).
|
|
18
|
-
*/
|
|
19
|
-
import { resolve as resolvePath } from "path";
|
|
20
|
-
import {
|
|
21
|
-
OutputSpecError,
|
|
22
|
-
type OutputOptions,
|
|
23
|
-
type OutputSpec,
|
|
24
|
-
type ResolvedOutput,
|
|
25
|
-
} from "./types.ts";
|
|
26
|
-
|
|
27
|
-
export function resolveOutput<P>(
|
|
28
|
-
spec: OutputSpec<P>,
|
|
29
|
-
opts: OutputOptions,
|
|
30
|
-
): ResolvedOutput {
|
|
31
|
-
if (opts.json && typeof opts.report === "string" && opts.report.length > 0) {
|
|
32
|
-
throw new OutputSpecError(
|
|
33
|
-
"--json and --report are mutually exclusive — pick one output channel",
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Step 1: resolve the format.
|
|
38
|
-
let format: string;
|
|
39
|
-
if (typeof opts.report === "string" && opts.report.length > 0) {
|
|
40
|
-
const alias = spec.aliases?.[opts.report];
|
|
41
|
-
format = alias ?? opts.report;
|
|
42
|
-
} else if (opts.json) {
|
|
43
|
-
format = pickEnvelopeFormat(spec) ?? spec.defaultFormat;
|
|
44
|
-
} else {
|
|
45
|
-
format = spec.defaultFormat;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const policy = spec.formats[format];
|
|
49
|
-
if (!policy) {
|
|
50
|
-
const known = Object.keys(spec.formats).sort().join(", ");
|
|
51
|
-
throw new OutputSpecError(
|
|
52
|
-
`Unknown --report format: "${format}". Available for ${spec.command}: ${known}`,
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Step 2: resolve channel + path.
|
|
57
|
-
const explicitOutput = typeof opts.output === "string" && opts.output.length > 0
|
|
58
|
-
? opts.output
|
|
59
|
-
: undefined;
|
|
60
|
-
let channel: "stdout" | "file";
|
|
61
|
-
let path: string | undefined;
|
|
62
|
-
if (explicitOutput) {
|
|
63
|
-
channel = "file";
|
|
64
|
-
path = resolvePath(explicitOutput);
|
|
65
|
-
} else if (policy.defaultChannel === "file") {
|
|
66
|
-
channel = "file";
|
|
67
|
-
path = policy.defaultFilename ? resolvePath(policy.defaultFilename) : undefined;
|
|
68
|
-
if (!path) {
|
|
69
|
-
throw new OutputSpecError(
|
|
70
|
-
`Format "${format}" defaults to file but has no defaultFilename and --output was not set`,
|
|
71
|
-
);
|
|
72
|
-
}
|
|
73
|
-
} else {
|
|
74
|
-
channel = "stdout";
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return {
|
|
78
|
-
format,
|
|
79
|
-
channel,
|
|
80
|
-
path,
|
|
81
|
-
envelopeWrap: policy.envelopeWrap === true,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function pickEnvelopeFormat<P>(spec: OutputSpec<P>): string | undefined {
|
|
86
|
-
for (const [name, policy] of Object.entries(spec.formats)) {
|
|
87
|
-
if (policy.envelopeWrap) return name;
|
|
88
|
-
}
|
|
89
|
-
return undefined;
|
|
90
|
-
}
|
|
91
|
-
|
package/src/core/output/types.ts
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ARV-116 (m-19): typed declaration of every `--report` / `--output` /
|
|
3
|
-
* `--json` combination a command supports.
|
|
4
|
-
*
|
|
5
|
-
* Background. Lesson §E of strategy/lessons.md collects seven separate
|
|
6
|
-
* bug reports about output-flag plumbing:
|
|
7
|
-
* - ARV-97 — `--report ndjson --output <path>` silently dropped events;
|
|
8
|
-
* - ARV-50 — probe `--dry-run` JSON shape diverged from `--report json`;
|
|
9
|
-
* - ARV-82 — `db runs --json` envelope `data` field shape disagreed
|
|
10
|
-
* with sibling commands;
|
|
11
|
-
* - …and four more along the same lines.
|
|
12
|
-
*
|
|
13
|
-
* Root cause: each command has its own ad-hoc flag parser. Some treat
|
|
14
|
-
* "ndjson" as an alias for `--ndjson`, some don't. Some honour
|
|
15
|
-
* `--output` for SARIF only, some for every format. Some wrap in a JSON
|
|
16
|
-
* envelope, some emit a raw stream. There is no single place to read
|
|
17
|
-
* "what does `command X` produce when I pass `--report Y --output Z`".
|
|
18
|
-
*
|
|
19
|
-
* This module gives that single place. A command declares an
|
|
20
|
-
* `OutputSpec<Payload>` once — listing the formats it supports, each
|
|
21
|
-
* format's default channel (stdout vs file), each format's default
|
|
22
|
-
* filename, and whether the format wraps in the standard `--json`
|
|
23
|
-
* envelope. A runner helper (`runCommandWithOutput`) consumes the spec
|
|
24
|
-
* plus the CLI flags and resolves them to a single `ResolvedOutput`
|
|
25
|
-
* decision, with consistent mutual-exclusion enforcement.
|
|
26
|
-
*
|
|
27
|
-
* The spec is the source-of-truth for ARV-120's build-time check:
|
|
28
|
-
* every `--json` command must declare an `OutputSpec` with an
|
|
29
|
-
* `envelopeWrap: true` entry, so the published schema and the runtime
|
|
30
|
-
* output cannot drift.
|
|
31
|
-
*
|
|
32
|
-
* This task only ships the infrastructure. Per-command migration
|
|
33
|
-
* (`run`, `checks`, `probe*`) lands in ARV-117/118/119.
|
|
34
|
-
*/
|
|
35
|
-
|
|
36
|
-
/** Where a rendered payload lands. */
|
|
37
|
-
export type OutputChannel = "stdout" | "file";
|
|
38
|
-
|
|
39
|
-
/** A format name — `sarif` / `ndjson` / `json` / `junit` etc. The set is
|
|
40
|
-
* open: each command declares its own. */
|
|
41
|
-
export type OutputFormat = string;
|
|
42
|
-
|
|
43
|
-
/** Per-format policy: where the format writes by default, what filename
|
|
44
|
-
* to use when it writes to a file, and whether the payload is wrapped
|
|
45
|
-
* in the standard `{ ok, command, data, ... }` envelope. */
|
|
46
|
-
export interface FormatPolicy {
|
|
47
|
-
/** Default destination when neither `--output` nor channel-overriding
|
|
48
|
-
* flags are present. SARIF defaults to file (`zond-checks.sarif`);
|
|
49
|
-
* NDJSON defaults to stdout (one event per line for piping); JSON
|
|
50
|
-
* envelopes default to stdout. */
|
|
51
|
-
defaultChannel: OutputChannel;
|
|
52
|
-
/** Default filename when `defaultChannel === "file"`. Relative paths
|
|
53
|
-
* are resolved against cwd by the runner. Ignored when
|
|
54
|
-
* `defaultChannel === "stdout"` — the user has to opt in to a file
|
|
55
|
-
* via `--output`. */
|
|
56
|
-
defaultFilename?: string;
|
|
57
|
-
/** True for formats that should be wrapped in the shared envelope
|
|
58
|
-
* (`jsonOk` / `jsonError` from `cli/json-envelope.ts`). Streaming
|
|
59
|
-
* formats (NDJSON) and bespoke serialisations (SARIF, JUnit) are
|
|
60
|
-
* not envelope-wrapped — they have their own contracts. */
|
|
61
|
-
envelopeWrap?: boolean;
|
|
62
|
-
/** ARV-120: for `envelopeWrap` formats — basename of the JSON schema
|
|
63
|
-
* under `docs/json-schema/` that describes the envelope's `data`
|
|
64
|
-
* field. The build-time coverage test asserts the file exists, so
|
|
65
|
-
* a renamed/deleted schema fails CI together with the spec. */
|
|
66
|
-
envelopeSchemaFile?: string;
|
|
67
|
-
/** Optional human description, surfaced by `--help` generators and
|
|
68
|
-
* the README table. */
|
|
69
|
-
description?: string;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export interface OutputSpec<Payload = unknown> {
|
|
73
|
-
/** Command name — propagated into the JSON envelope's `command` field
|
|
74
|
-
* and used by error messages. */
|
|
75
|
-
command: string;
|
|
76
|
-
/** Supported formats keyed by name. Unknown formats fall through to
|
|
77
|
-
* an error (no silent acceptance, see ARV-97). */
|
|
78
|
-
formats: Record<OutputFormat, FormatPolicy>;
|
|
79
|
-
/** Default format when neither `--report` nor `--json` is set. */
|
|
80
|
-
defaultFormat: OutputFormat;
|
|
81
|
-
/** Optional alias map: `{ ndjson: 'ndjson' }` lets `--report ndjson`
|
|
82
|
-
* fold into the `--ndjson` flag (ARV-63 alias, retained because
|
|
83
|
-
* skill prompts ship it). Keys are flag values seen on the CLI;
|
|
84
|
-
* values are the resolved format name. */
|
|
85
|
-
aliases?: Record<string, OutputFormat>;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/** Decision the runner makes after applying the spec to CLI flags. */
|
|
89
|
-
export interface ResolvedOutput {
|
|
90
|
-
/** Resolved format name (always one of `spec.formats`). */
|
|
91
|
-
format: OutputFormat;
|
|
92
|
-
/** Resolved destination. */
|
|
93
|
-
channel: OutputChannel;
|
|
94
|
-
/** Filesystem path when `channel === "file"`. Absolute path expected
|
|
95
|
-
* by callers — the runner resolves it against cwd. */
|
|
96
|
-
path?: string;
|
|
97
|
-
/** Whether the runner should wrap the payload in the standard
|
|
98
|
-
* envelope before writing. Mirrors `FormatPolicy.envelopeWrap`. */
|
|
99
|
-
envelopeWrap: boolean;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/** Inputs the runner reads from the CLI layer. Names mirror commander
|
|
103
|
-
* options so a command can pass `cmd.opts<OutputOptions>()` directly. */
|
|
104
|
-
export interface OutputOptions {
|
|
105
|
-
/** `--report <format>`. */
|
|
106
|
-
report?: string;
|
|
107
|
-
/** `--output <path>`. */
|
|
108
|
-
output?: string;
|
|
109
|
-
/** `--json`. */
|
|
110
|
-
json?: boolean;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/** Thrown by `resolveOutput` when the user-supplied flags violate the
|
|
114
|
-
* spec's policy (unknown format, mutually exclusive flags, …). The
|
|
115
|
-
* CLI layer catches this and emits the standard `jsonError` or
|
|
116
|
-
* human `printError`. */
|
|
117
|
-
export class OutputSpecError extends Error {
|
|
118
|
-
constructor(message: string) {
|
|
119
|
-
super(message);
|
|
120
|
-
this.name = "OutputSpecError";
|
|
121
|
-
}
|
|
122
|
-
}
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `#(funcName)` / `#(funcName(args))` dynamic-value substitution for
|
|
3
|
-
* loaded YAML values (ARV-190, m-21).
|
|
4
|
-
*
|
|
5
|
-
* Lets a workspace avoid stale hardcoded data — UUIDs that get reused
|
|
6
|
-
* by the API and pin existing rows, dates that expire days after
|
|
7
|
-
* checkout, idempotency keys that race against past runs. Functions
|
|
8
|
-
* are evaluated at LOAD time (per-run, not per-request), so a single
|
|
9
|
-
* `#(uuid)` reference resolves to the same value across every step
|
|
10
|
-
* inside one run — the idempotency-replay scenarios only work if the
|
|
11
|
-
* key stays stable for the run's lifetime.
|
|
12
|
-
*
|
|
13
|
-
* Supported functions:
|
|
14
|
-
* #(uuid) — fresh UUID v4 (stable within one run via cache)
|
|
15
|
-
* #(uuidStable(seed)) — deterministic UUID derived from seed (sha-256 → v4 shape)
|
|
16
|
-
* #(today) — YYYY-MM-DD now (UTC)
|
|
17
|
-
* #(todayPlus(N)) — today + N days (N may be negative)
|
|
18
|
-
* #(now) — ISO 8601 timestamp
|
|
19
|
-
* #(unix) — seconds since epoch
|
|
20
|
-
* #(alphanumeric(N)) — N random a-z0-9 chars
|
|
21
|
-
* #(env:VAR) — process.env.VAR (alias for ${VAR})
|
|
22
|
-
*
|
|
23
|
-
* Resolution order: env-interpolation (${VAR}) runs first because its
|
|
24
|
-
* default-value syntax can produce strings the dynamic resolver should
|
|
25
|
-
* see literally. Dynamic values run BEFORE @secret/@identity reference
|
|
26
|
-
* resolution so the function tokens never leak into a secret-typed
|
|
27
|
-
* value (and so secret-stored values that happen to look like `#(...)`
|
|
28
|
-
* stay opaque). Strings that have no `#(` substring short-circuit.
|
|
29
|
-
*
|
|
30
|
-
* Nested forms: a single value may carry multiple references mixed
|
|
31
|
-
* with literal text — `"req-#(uuid)-#(today)"` yields `req-<uuid>-2026-05-16`.
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
import { createHash } from "node:crypto";
|
|
35
|
-
|
|
36
|
-
export interface DynamicValueContext {
|
|
37
|
-
/** Per-run cache keyed by raw expression (`#(uuid)`, `#(today)`). */
|
|
38
|
-
cache: Map<string, string>;
|
|
39
|
-
/** Source of env vars; defaults to process.env. Override in tests. */
|
|
40
|
-
env?: Record<string, string | undefined>;
|
|
41
|
-
/** File path the value came from — surfaced in error messages. */
|
|
42
|
-
filePath?: string;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/** Build a fresh cache for one resolution pass. Exported so the caller
|
|
46
|
-
* can share a cache across multiple `resolveDynamicValuesDeep` calls
|
|
47
|
-
* that belong to the same run (e.g. workspace + per-API env files). */
|
|
48
|
-
export function newDynamicCache(): Map<string, string> {
|
|
49
|
-
return new Map();
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Captures `#(funcName)` or `#(funcName(args))`. `args` may contain any
|
|
53
|
-
// chars except an unescaped closing paren — keep it simple, the funcs we
|
|
54
|
-
// support take string or integer args without nested parens.
|
|
55
|
-
const FUNC_RE = /#\(([A-Za-z_][A-Za-z0-9_]*)(?::([^)]*))?(?:\(([^)]*)\))?\)/g;
|
|
56
|
-
|
|
57
|
-
export function resolveDynamicValues(
|
|
58
|
-
text: string,
|
|
59
|
-
ctx: DynamicValueContext,
|
|
60
|
-
): string {
|
|
61
|
-
if (typeof text !== "string" || text.indexOf("#(") === -1) return text;
|
|
62
|
-
return text.replace(FUNC_RE, (full, name: string, colonArg: string | undefined, parenArg: string | undefined) => {
|
|
63
|
-
const cached = ctx.cache.get(full);
|
|
64
|
-
if (cached !== undefined) return cached;
|
|
65
|
-
const value = evaluate(name, colonArg ?? parenArg, full, ctx);
|
|
66
|
-
ctx.cache.set(full, value);
|
|
67
|
-
return value;
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function resolveDynamicValuesDeep(
|
|
72
|
-
obj: Record<string, unknown>,
|
|
73
|
-
ctx: DynamicValueContext,
|
|
74
|
-
): Record<string, string> {
|
|
75
|
-
const out: Record<string, string> = {};
|
|
76
|
-
for (const [k, v] of Object.entries(obj)) {
|
|
77
|
-
if (typeof v === "string") {
|
|
78
|
-
out[k] = resolveDynamicValues(v, ctx);
|
|
79
|
-
} else {
|
|
80
|
-
out[k] = String(v);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return out;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function evaluate(
|
|
87
|
-
name: string,
|
|
88
|
-
arg: string | undefined,
|
|
89
|
-
fullExpr: string,
|
|
90
|
-
ctx: DynamicValueContext,
|
|
91
|
-
): string {
|
|
92
|
-
switch (name) {
|
|
93
|
-
case "uuid":
|
|
94
|
-
return crypto.randomUUID();
|
|
95
|
-
case "uuidStable": {
|
|
96
|
-
if (!arg) throw makeError(`#(uuidStable(seed)) requires a seed argument`, fullExpr, ctx);
|
|
97
|
-
return seedToUuid(arg);
|
|
98
|
-
}
|
|
99
|
-
case "today":
|
|
100
|
-
return new Date().toISOString().slice(0, 10);
|
|
101
|
-
case "todayPlus": {
|
|
102
|
-
if (!arg) throw makeError(`#(todayPlus(N)) requires an integer N`, fullExpr, ctx);
|
|
103
|
-
const n = Number.parseInt(arg, 10);
|
|
104
|
-
if (!Number.isFinite(n)) throw makeError(`#(todayPlus(${arg})) — N must be an integer`, fullExpr, ctx);
|
|
105
|
-
const d = new Date();
|
|
106
|
-
d.setUTCDate(d.getUTCDate() + n);
|
|
107
|
-
return d.toISOString().slice(0, 10);
|
|
108
|
-
}
|
|
109
|
-
case "now":
|
|
110
|
-
return new Date().toISOString();
|
|
111
|
-
case "unix":
|
|
112
|
-
return String(Math.floor(Date.now() / 1000));
|
|
113
|
-
case "alphanumeric": {
|
|
114
|
-
const n = arg ? Number.parseInt(arg, 10) : 8;
|
|
115
|
-
if (!Number.isFinite(n) || n <= 0 || n > 1024) {
|
|
116
|
-
throw makeError(`#(alphanumeric(${arg ?? ""})) — length must be 1..1024`, fullExpr, ctx);
|
|
117
|
-
}
|
|
118
|
-
return randomAlphanumeric(n);
|
|
119
|
-
}
|
|
120
|
-
case "env": {
|
|
121
|
-
if (!arg) throw makeError(`#(env:VAR) requires a variable name`, fullExpr, ctx);
|
|
122
|
-
const env = ctx.env ?? (process.env as Record<string, string | undefined>);
|
|
123
|
-
const v = env[arg];
|
|
124
|
-
if (v === undefined || v === "") {
|
|
125
|
-
throw makeError(`#(env:${arg}) is not set — define it in your shell or CI secret`, fullExpr, ctx);
|
|
126
|
-
}
|
|
127
|
-
return v;
|
|
128
|
-
}
|
|
129
|
-
default:
|
|
130
|
-
throw makeError(`unknown dynamic function "${name}" in ${fullExpr} — supported: uuid, uuidStable, today, todayPlus, now, unix, alphanumeric, env`, fullExpr, ctx);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function seedToUuid(seed: string): string {
|
|
135
|
-
// SHA-256 the seed, take first 16 bytes, format as UUID v4 shape so
|
|
136
|
-
// any consumer-side `format: uuid` validator accepts it. Variant +
|
|
137
|
-
// version bits are forced to match v4 — the value is still
|
|
138
|
-
// deterministic because the source bytes are stable per seed.
|
|
139
|
-
const hash = createHash("sha256").update(seed).digest();
|
|
140
|
-
const bytes = Buffer.from(hash.subarray(0, 16));
|
|
141
|
-
bytes[6] = (bytes[6]! & 0x0f) | 0x40; // version 4
|
|
142
|
-
bytes[8] = (bytes[8]! & 0x3f) | 0x80; // RFC 4122 variant
|
|
143
|
-
const hex = bytes.toString("hex");
|
|
144
|
-
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const ALPHANUM = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
148
|
-
|
|
149
|
-
function randomAlphanumeric(n: number): string {
|
|
150
|
-
let out = "";
|
|
151
|
-
for (let i = 0; i < n; i++) {
|
|
152
|
-
out += ALPHANUM[Math.floor(Math.random() * ALPHANUM.length)];
|
|
153
|
-
}
|
|
154
|
-
return out;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
function makeError(msg: string, expr: string, ctx: DynamicValueContext): Error {
|
|
158
|
-
const where = ctx.filePath ? ` (referenced from ${ctx.filePath})` : "";
|
|
159
|
-
return new Error(`Dynamic value ${expr}: ${msg}${where}`);
|
|
160
|
-
}
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `${VAR}` / `${VAR:-default}` substitution for `.env.yaml` (TASK-169, m-10).
|
|
3
|
-
*
|
|
4
|
-
* Lets a workspace commit `.env.yaml` without bare secrets:
|
|
5
|
-
*
|
|
6
|
-
* auth_token: "${MYAPI_AUTH_TOKEN}"
|
|
7
|
-
* base_url: "${MYAPI_BASE_URL:-https://api.example.com}"
|
|
8
|
-
*
|
|
9
|
-
* Rules:
|
|
10
|
-
* - `${VAR}` → process.env.VAR (throws if missing).
|
|
11
|
-
* - `${VAR:-default}` → process.env.VAR ?? default. The default may
|
|
12
|
-
* contain `:` (everything after `:-` up to the closing `}` is the
|
|
13
|
-
* default).
|
|
14
|
-
* - `\${LITERAL}` → literal `${LITERAL}` (the backslash is
|
|
15
|
-
* stripped). Matches the `dotenv-expand` / docker-compose convention.
|
|
16
|
-
* - One level of resolution only — values pulled from env are NOT
|
|
17
|
-
* re-scanned for further `${...}` (cycle-risk).
|
|
18
|
-
* - Variable names matching /TOKEN|SECRET|PASSWORD|KEY|DSN/i are NOT
|
|
19
|
-
* auto-registered with the redaction registry. Auto-registration is
|
|
20
|
-
* opt-in via `@secret:` (TASK-170). We do print a one-line warning
|
|
21
|
-
* suggesting the user mark them as a secret, but only the first time.
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
const ENV_REF_RE = /(\\?)\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\}/g;
|
|
25
|
-
const SUSPICIOUS_NAME_RE = /TOKEN|SECRET|PASSWORD|API_KEY|^KEY$|_KEY$|DSN/i;
|
|
26
|
-
|
|
27
|
-
export interface EnvInterpolationContext {
|
|
28
|
-
/** Absolute path of the file we're resolving — used for error messages. */
|
|
29
|
-
filePath: string;
|
|
30
|
-
/** YAML key whose value contains the reference — used for error messages. */
|
|
31
|
-
key: string;
|
|
32
|
-
/** Source of variables; defaults to `process.env`. Override in tests. */
|
|
33
|
-
env?: Record<string, string | undefined>;
|
|
34
|
-
/** Sink for human-facing warnings. Default: stderr write. */
|
|
35
|
-
warn?: (msg: string) => void;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/** Module-level set of variable names we've already warned about, so the
|
|
39
|
-
* same `${MYAPI_AUTH_TOKEN}` reference doesn't yell once per env file. */
|
|
40
|
-
const warned = new Set<string>();
|
|
41
|
-
|
|
42
|
-
export function _resetEnvInterpolationWarnings(): void {
|
|
43
|
-
warned.clear();
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Substitute every `${VAR}` / `${VAR:-default}` in `text`. Returns the
|
|
48
|
-
* fully-resolved string. Throws `Error` when an unresolved reference has
|
|
49
|
-
* no default.
|
|
50
|
-
*/
|
|
51
|
-
export function interpolateEnvRefs(text: string, ctx: EnvInterpolationContext): string {
|
|
52
|
-
if (typeof text !== "string" || text.length === 0) return text;
|
|
53
|
-
if (text.indexOf("${") === -1 && text.indexOf("\\$") === -1) return text;
|
|
54
|
-
const env = ctx.env ?? (process.env as Record<string, string | undefined>);
|
|
55
|
-
const warn = ctx.warn ?? ((m: string) => process.stderr.write(m + "\n"));
|
|
56
|
-
|
|
57
|
-
return text.replace(ENV_REF_RE, (full, escape: string, name: string, def: string | undefined) => {
|
|
58
|
-
if (escape === "\\") {
|
|
59
|
-
// Escaped reference → strip the backslash, keep the literal.
|
|
60
|
-
return full.slice(1);
|
|
61
|
-
}
|
|
62
|
-
const value = env[name];
|
|
63
|
-
if (value === undefined || value === "") {
|
|
64
|
-
if (def !== undefined) {
|
|
65
|
-
return def;
|
|
66
|
-
}
|
|
67
|
-
throw new Error(
|
|
68
|
-
`Environment variable \${${name}} is not set (referenced from "${ctx.filePath}", key "${ctx.key}"). ` +
|
|
69
|
-
`Provide it via your shell, CI secret, or use the \${${name}:-<default>} form to give it a fallback.`,
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
if (SUSPICIOUS_NAME_RE.test(name) && !warned.has(name)) {
|
|
73
|
-
warned.add(name);
|
|
74
|
-
warn(
|
|
75
|
-
`[zond] ${ctx.filePath}: variable \${${name}} looks like a secret. ` +
|
|
76
|
-
`Consider mapping it through @secret:${ctx.key} (TASK-170) so it is redacted in artifacts.`,
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
return value;
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Apply interpolation to every string value in a flat env object. Other
|
|
85
|
-
* value types (numbers, booleans, nulls coming back from YAML) are
|
|
86
|
-
* stringified untouched, matching the existing loader behaviour.
|
|
87
|
-
*/
|
|
88
|
-
export function interpolateEnvObject(
|
|
89
|
-
obj: Record<string, unknown>,
|
|
90
|
-
filePath: string,
|
|
91
|
-
env?: Record<string, string | undefined>,
|
|
92
|
-
): Record<string, string> {
|
|
93
|
-
const out: Record<string, string> = {};
|
|
94
|
-
for (const [k, v] of Object.entries(obj)) {
|
|
95
|
-
if (typeof v === "string") {
|
|
96
|
-
out[k] = interpolateEnvRefs(v, { filePath, key: k, env });
|
|
97
|
-
} else {
|
|
98
|
-
out[k] = String(v);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
return out;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const SUSPICIOUS_ENV_NAME_RE = SUSPICIOUS_NAME_RE;
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import type { TestSuite } from "./types.ts";
|
|
2
|
-
import { compileOperationFilter } from "../selectors/operation-filter.ts";
|
|
3
|
-
import type { EndpointInfo } from "../generator/types.ts";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Filter suites by tags (OR logic, case-insensitive).
|
|
7
|
-
* Suites without tags are excluded when filtering is active.
|
|
8
|
-
*/
|
|
9
|
-
export function filterSuitesByTags(suites: TestSuite[], tags: string[]): TestSuite[] {
|
|
10
|
-
if (tags.length === 0) return suites;
|
|
11
|
-
const normalizedTags = tags.map(t => t.toLowerCase());
|
|
12
|
-
return suites.filter(suite => {
|
|
13
|
-
if (!suite.tags || suite.tags.length === 0) return false;
|
|
14
|
-
return suite.tags.some(t => normalizedTags.includes(t.toLowerCase()));
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Exclude suites whose tags intersect with the exclusion set (OR logic, case-insensitive).
|
|
20
|
-
* Suites without tags are kept.
|
|
21
|
-
*/
|
|
22
|
-
export function excludeSuitesByTags(suites: TestSuite[], excludeTags: string[]): TestSuite[] {
|
|
23
|
-
if (excludeTags.length === 0) return suites;
|
|
24
|
-
const normalizedTags = excludeTags.map(t => t.toLowerCase());
|
|
25
|
-
return suites.filter(suite => {
|
|
26
|
-
if (!suite.tags || suite.tags.length === 0) return true;
|
|
27
|
-
return !suite.tags.some(t => normalizedTags.includes(t.toLowerCase()));
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Filter test steps within suites by HTTP method (case-insensitive).
|
|
33
|
-
* Suites with no remaining tests are removed.
|
|
34
|
-
*/
|
|
35
|
-
export function filterSuitesByMethod(suites: TestSuite[], method: string): TestSuite[] {
|
|
36
|
-
const upperMethod = method.toUpperCase();
|
|
37
|
-
const filtered = suites.map(suite => ({
|
|
38
|
-
...suite,
|
|
39
|
-
tests: suite.tests.filter(t => (t.method ?? "GET").toUpperCase() === upperMethod),
|
|
40
|
-
}));
|
|
41
|
-
return filtered.filter(s => s.tests.length > 0);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export interface SuiteFilterResult {
|
|
45
|
-
suites: TestSuite[];
|
|
46
|
-
errors: string[];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* ARV-25: parity with `zond generate`/`zond checks run` — apply the unified
|
|
51
|
-
* `--include`/`--exclude` selector grammar (path/method/tag/operation-id)
|
|
52
|
-
* to a list of test suites. Step-level selectors (path, method, operation-id)
|
|
53
|
-
* filter steps within a suite; suite-level selectors (tag) borrow each
|
|
54
|
-
* step's parent suite tags. A suite drops out once it has no steps left.
|
|
55
|
-
*
|
|
56
|
-
* Reuses `compileOperationFilter` so semantics match generate/checks 1:1
|
|
57
|
-
* (multiple --include combine with OR; --exclude evaluated after includes).
|
|
58
|
-
*
|
|
59
|
-
* `operation-id` matches against `step.source?.endpoint` ("METHOD /path"),
|
|
60
|
-
* which is what the generator records; tests authored manually without
|
|
61
|
-
* `source.endpoint` simply never match operation-id selectors.
|
|
62
|
-
*/
|
|
63
|
-
export function filterSuitesByOperationFilter(
|
|
64
|
-
suites: TestSuite[],
|
|
65
|
-
includes: string[],
|
|
66
|
-
excludes: string[],
|
|
67
|
-
): SuiteFilterResult {
|
|
68
|
-
if (includes.length === 0 && excludes.length === 0) {
|
|
69
|
-
return { suites, errors: [] };
|
|
70
|
-
}
|
|
71
|
-
const compiled = compileOperationFilter({ includes, excludes });
|
|
72
|
-
if (compiled.errors.length > 0) {
|
|
73
|
-
return { suites: [], errors: compiled.errors };
|
|
74
|
-
}
|
|
75
|
-
const filtered = suites.map(suite => ({
|
|
76
|
-
...suite,
|
|
77
|
-
tests: suite.tests.filter(step => compiled.filter(stepToEndpoint(suite, step))),
|
|
78
|
-
}));
|
|
79
|
-
return { suites: filtered.filter(s => s.tests.length > 0), errors: [] };
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function stepToEndpoint(suite: TestSuite, step: TestSuite["tests"][number]): EndpointInfo {
|
|
83
|
-
const sourceEndpoint = typeof step.source?.endpoint === "string" ? step.source.endpoint : undefined;
|
|
84
|
-
return {
|
|
85
|
-
path: step.path,
|
|
86
|
-
method: step.method,
|
|
87
|
-
operationId: sourceEndpoint,
|
|
88
|
-
summary: undefined,
|
|
89
|
-
tags: suite.tags ?? [],
|
|
90
|
-
parameters: [],
|
|
91
|
-
requestBodySchema: undefined,
|
|
92
|
-
requestBodyContentType: undefined,
|
|
93
|
-
responseContentTypes: [],
|
|
94
|
-
responses: [],
|
|
95
|
-
security: [],
|
|
96
|
-
};
|
|
97
|
-
}
|