spec-controller 0.1.0-alpha.9 → 0.1.1

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.
Files changed (130) hide show
  1. package/README.md +18 -11
  2. package/dist/cli-allocate/cli.d.ts +2 -0
  3. package/dist/cli-allocate/cli.d.ts.map +1 -0
  4. package/dist/cli-allocate/cli.js +61 -0
  5. package/dist/cli-allocate/cli.js.map +1 -0
  6. package/dist/cli-allocate/readHistory.d.ts +14 -0
  7. package/dist/cli-allocate/readHistory.d.ts.map +1 -0
  8. package/dist/cli-allocate/readHistory.js +109 -0
  9. package/dist/cli-allocate/readHistory.js.map +1 -0
  10. package/dist/cli-allocate/readParts.d.ts +2 -0
  11. package/dist/cli-allocate/readParts.d.ts.map +1 -0
  12. package/dist/cli-allocate/readParts.js +23 -0
  13. package/dist/cli-allocate/readParts.js.map +1 -0
  14. package/dist/cli-allocate/readTree.d.ts +5 -0
  15. package/dist/cli-allocate/readTree.d.ts.map +1 -0
  16. package/dist/cli-allocate/readTree.js +74 -0
  17. package/dist/cli-allocate/readTree.js.map +1 -0
  18. package/dist/cli-allocate/refStore.d.ts +2 -0
  19. package/dist/cli-allocate/refStore.d.ts.map +1 -0
  20. package/dist/cli-allocate/refStore.js +35 -0
  21. package/dist/cli-allocate/refStore.js.map +1 -0
  22. package/dist/cli-allocate/request.d.ts +9 -0
  23. package/dist/cli-allocate/request.d.ts.map +1 -0
  24. package/dist/cli-allocate/request.js +23 -0
  25. package/dist/cli-allocate/request.js.map +1 -0
  26. package/dist/cli-allocate/stderr.d.ts +7 -0
  27. package/dist/cli-allocate/stderr.d.ts.map +1 -0
  28. package/dist/cli-allocate/stderr.js +32 -0
  29. package/dist/cli-allocate/stderr.js.map +1 -0
  30. package/dist/cli-allocate/unreadable.d.ts +13 -0
  31. package/dist/cli-allocate/unreadable.d.ts.map +1 -0
  32. package/dist/cli-allocate/unreadable.js +37 -0
  33. package/dist/cli-allocate/unreadable.js.map +1 -0
  34. package/dist/cli-args.d.ts +15 -70
  35. package/dist/cli-args.d.ts.map +1 -1
  36. package/dist/cli-args.js +167 -85
  37. package/dist/cli-args.js.map +1 -1
  38. package/dist/cli-balance/cli.d.ts +1 -82
  39. package/dist/cli-balance/cli.d.ts.map +1 -1
  40. package/dist/cli-balance/cli.js +86 -397
  41. package/dist/cli-balance/cli.js.map +1 -1
  42. package/dist/cli-balance/emit/format.d.ts +18 -39
  43. package/dist/cli-balance/emit/format.d.ts.map +1 -1
  44. package/dist/cli-balance/emit/format.js +32 -63
  45. package/dist/cli-balance/emit/format.js.map +1 -1
  46. package/dist/cli-balance/emit/writer.d.ts +2 -34
  47. package/dist/cli-balance/emit/writer.d.ts.map +1 -1
  48. package/dist/cli-balance/emit/writer.js +62 -37
  49. package/dist/cli-balance/emit/writer.js.map +1 -1
  50. package/dist/cli-balance/exitStatus.d.ts +2 -0
  51. package/dist/cli-balance/exitStatus.d.ts.map +1 -0
  52. package/dist/cli-balance/exitStatus.js +5 -0
  53. package/dist/cli-balance/exitStatus.js.map +1 -0
  54. package/dist/cli-balance/inputsRead.d.ts +11 -0
  55. package/dist/cli-balance/inputsRead.d.ts.map +1 -0
  56. package/dist/cli-balance/inputsRead.js +51 -0
  57. package/dist/cli-balance/inputsRead.js.map +1 -0
  58. package/dist/cli-balance/reRender.d.ts +8 -0
  59. package/dist/cli-balance/reRender.d.ts.map +1 -0
  60. package/dist/cli-balance/reRender.js +21 -0
  61. package/dist/cli-balance/reRender.js.map +1 -0
  62. package/dist/cli-balance/unreadableInputs.d.ts +15 -0
  63. package/dist/cli-balance/unreadableInputs.d.ts.map +1 -0
  64. package/dist/cli-balance/unreadableInputs.js +100 -0
  65. package/dist/cli-balance/unreadableInputs.js.map +1 -0
  66. package/dist/cli-registry.d.ts +16 -71
  67. package/dist/cli-registry.d.ts.map +1 -1
  68. package/dist/cli-registry.js +71 -136
  69. package/dist/cli-registry.js.map +1 -1
  70. package/dist/cli.d.ts +0 -21
  71. package/dist/cli.d.ts.map +1 -1
  72. package/dist/cli.js +1 -85
  73. package/dist/cli.js.map +1 -1
  74. package/dist/deferralTags.d.ts +0 -14
  75. package/dist/deferralTags.d.ts.map +1 -1
  76. package/dist/deferralTags.js +0 -14
  77. package/dist/deferralTags.js.map +1 -1
  78. package/dist/host.d.ts +10 -41
  79. package/dist/host.d.ts.map +1 -1
  80. package/dist/host.js +99 -50
  81. package/dist/host.js.map +1 -1
  82. package/dist/ingest/ciSourcePaths.d.ts +0 -39
  83. package/dist/ingest/ciSourcePaths.d.ts.map +1 -1
  84. package/dist/ingest/ciSourcePaths.js +1 -39
  85. package/dist/ingest/ciSourcePaths.js.map +1 -1
  86. package/dist/ingest/gherkinValidation.d.ts +0 -80
  87. package/dist/ingest/gherkinValidation.d.ts.map +1 -1
  88. package/dist/ingest/gherkinValidation.js +3 -82
  89. package/dist/ingest/gherkinValidation.js.map +1 -1
  90. package/dist/ingest/ingestQualityChecks.d.ts +8 -93
  91. package/dist/ingest/ingestQualityChecks.d.ts.map +1 -1
  92. package/dist/ingest/ingestQualityChecks.js +61 -224
  93. package/dist/ingest/ingestQualityChecks.js.map +1 -1
  94. package/dist/ingest/ingestScenarios.d.ts +5 -45
  95. package/dist/ingest/ingestScenarios.d.ts.map +1 -1
  96. package/dist/ingest/ingestScenarios.js +50 -118
  97. package/dist/ingest/ingestScenarios.js.map +1 -1
  98. package/dist/ingest/inputShapes.d.ts +16 -0
  99. package/dist/ingest/inputShapes.d.ts.map +1 -0
  100. package/dist/ingest/inputShapes.js +114 -0
  101. package/dist/ingest/inputShapes.js.map +1 -0
  102. package/dist/main.d.ts +2 -0
  103. package/dist/main.d.ts.map +1 -0
  104. package/dist/main.js +93 -0
  105. package/dist/main.js.map +1 -0
  106. package/dist/messages.d.ts +223 -0
  107. package/dist/messages.d.ts.map +1 -0
  108. package/dist/messages.js +319 -0
  109. package/dist/messages.js.map +1 -0
  110. package/dist/outputLocation.d.ts +23 -0
  111. package/dist/outputLocation.d.ts.map +1 -0
  112. package/dist/outputLocation.js +139 -0
  113. package/dist/outputLocation.js.map +1 -0
  114. package/dist/run-management/keptRun.d.ts +8 -109
  115. package/dist/run-management/keptRun.d.ts.map +1 -1
  116. package/dist/run-management/keptRun.js +49 -89
  117. package/dist/run-management/keptRun.js.map +1 -1
  118. package/dist/run-management/resolveRunInputs.d.ts +0 -67
  119. package/dist/run-management/resolveRunInputs.d.ts.map +1 -1
  120. package/dist/run-management/resolveRunInputs.js +13 -117
  121. package/dist/run-management/resolveRunInputs.js.map +1 -1
  122. package/dist/storedRun.d.ts +6 -0
  123. package/dist/storedRun.d.ts.map +1 -0
  124. package/dist/storedRun.js +27 -0
  125. package/dist/storedRun.js.map +1 -0
  126. package/package.json +2 -2
  127. package/dist/corpus/cli.d.ts +0 -34
  128. package/dist/corpus/cli.d.ts.map +0 -1
  129. package/dist/corpus/cli.js +0 -125
  130. package/dist/corpus/cli.js.map +0 -1
package/dist/cli.js CHANGED
@@ -1,88 +1,4 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * The `spec-controller` binary — the top-level command host + dispatcher.
4
- *
5
- * Usage:
6
- * spec-controller [--store <root>] [--run-id <id>] <command> [command-args]
7
- *
8
- * Commands: `balance` — the deterministic reconciliation of scenarios against
9
- * observed evidence, standalone on the public core + app layer (no engine); `tags` — the
10
- * @SCN scheme policing itself over the same corpus, which is a fault about the corpus rather
11
- * than a verdict about its evidence, and so has its own status ladder rather than a fifth
12
- * meaning on balance's. The `analyse` / `migrate` capabilities are a separate, closed offering
13
- * built on the same core.
14
- *
15
- * Storage is a CROSS-CUTTING host modifier, not a command. A leading `--store <root>`
16
- * turns any command into a STORED run: the host wraps the command via the kept-run
17
- * scaffold — a named `<root>/<target>/<run-id>/` directory, the command's outputs routed
18
- * in, and a `run.yaml` manifest — and hands the command its own clean args, unchanged. So
19
- * `balance` stays emit-only (its default, no-store output is byte-identical); the store
20
- * opinion lives at the host, injected via `--store` (required — there is no default, a
21
- * default would write inside the repo). `--run-id` defaults to a timestamp.
22
- */
23
- import { dirname } from "node:path";
24
- import { runBalance } from "./cli-balance/cli.js";
25
- import { runTags } from "./corpus/cli.js";
26
- import { resolveSourceSha, resolveToolIdentity } from "./run-management/resolveRunInputs.js";
27
- import { executeKeptRun, resolveRunId, } from "./run-management/keptRun.js";
28
- import { parseHostInvocation, wrapCommandArgv, peekFlag } from "./host.js";
29
- import { cliRegistry, renderTopLevelHelp } from "./cli-registry.js";
30
- /** Dispatch a command to its handler with the given (clean or store-wrapped) argv. */
31
- function runCommand(command, argv) {
32
- switch (command) {
33
- case "balance":
34
- runBalance(argv);
35
- return;
36
- case "tags":
37
- runTags(argv);
38
- return;
39
- default:
40
- process.stderr.write(`spec-controller: unknown command "${command}".\n\n${renderTopLevelHelp(cliRegistry)}\n`);
41
- process.exit(1);
42
- }
43
- }
44
- function main(hostArgv) {
45
- const inv = parseHostInvocation(hostArgv);
46
- const command = inv.command;
47
- if (command === undefined || command === "help" || command === "--help" || command === "-h") {
48
- process.stdout.write(renderTopLevelHelp(cliRegistry) + "\n");
49
- return;
50
- }
51
- // No store directive → dispatch the command directly; its output is unchanged.
52
- if (inv.store === undefined) {
53
- runCommand(command, inv.commandArgs);
54
- return;
55
- }
56
- // Store directive → wrap the command via keptRun. The scaffold makes the run dir, hands
57
- // the injected route the two store-dir `--format` specs, and stamps run.yaml. The route
58
- // dispatches the command with its own clean args PLUS those specs, so the command's own
59
- // writer produces the stored artefacts (byte-identical to a bare `--format` run). The
60
- // host peeks the conventional provenance flags off the command args to name the dir +
61
- // stamp the manifest, without consuming them (the command still sees them).
62
- const runId = resolveRunId({ runId: inv.runId, now: new Date() });
63
- const target = peekFlag(inv.commandArgs, "target") ?? "unknown-target";
64
- const features = peekFlag(inv.commandArgs, "features");
65
- const sourceSha = resolveSourceSha({
66
- sourceSha: peekFlag(inv.commandArgs, "source-sha"),
67
- targetDir: features !== undefined ? dirname(features) : undefined,
68
- }) ?? "unknown";
69
- const spec = { storeRoot: inv.store, target, runId };
70
- // `mode` is the command's run kind; only `balance` ships today (analyse/migrate are the
71
- // private engine's, added when it lands).
72
- // The TOOL's own identity (3F-1916) — which spec-controller produced this run, read
73
- // from the tool's OWN dir (never cwd, which is the target). "unknown" for a null SHA,
74
- // matching sourceSha's own fallback so run.yaml is internally consistent.
75
- const toolIdentity = resolveToolIdentity();
76
- const meta = {
77
- sourceSha,
78
- toolSha: toolIdentity.toolSha ?? "unknown",
79
- toolVersion: toolIdentity.toolVersion,
80
- mode: "balance",
81
- date: new Date().toISOString(),
82
- };
83
- const plan = executeKeptRun(spec, meta, (formatSpecs) => runCommand(command, wrapCommandArgv(inv.commandArgs, [...formatSpecs])));
84
- // The command's stdout was routed into the run dir, so tell the operator where it landed.
85
- process.stdout.write(plan.runDir + "\n");
86
- }
2
+ import { main } from "./main.js";
87
3
  main(process.argv.slice(2));
88
4
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC"}
@@ -1,16 +1,2 @@
1
- /**
2
- * The single-sourced STARTER set of recognised community deferral tags — bare names
3
- * (the `@` is tag-line syntax). A scenario whose tag block carries one of these DEFERS
4
- * every obligation it raises to a Pending Item (scenario-scope). These are the
5
- * established Cucumber deferral conventions.
6
- *
7
- * This is **product policy, not a core-domain invariant** — an evolvable list of tag
8
- * strings, so it lives in the application layer, NOT on the v1 core barrel.
9
- * The core `parseScenarios` recognises only the deferral set it is
10
- * handed (its default is `[]`, a policy-free pure core); the app is the single source
11
- * of the starter policy and always passes the resolved set (starter ∪ configured) into
12
- * the parser at the ingest edge. Both `resolveDeferralTags` (the `@SCN-PND-021` config
13
- * union) and `renderCommandHelp`'s `--help` listing source this constant.
14
- */
15
1
  export declare const DEFAULT_DEFERRAL_TAGS: readonly string[];
16
2
  //# sourceMappingURL=deferralTags.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"deferralTags.d.ts","sourceRoot":"","sources":["../src/deferralTags.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAMlD,CAAC"}
1
+ {"version":3,"file":"deferralTags.d.ts","sourceRoot":"","sources":["../src/deferralTags.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAMlD,CAAC"}
@@ -1,17 +1,3 @@
1
- /**
2
- * The single-sourced STARTER set of recognised community deferral tags — bare names
3
- * (the `@` is tag-line syntax). A scenario whose tag block carries one of these DEFERS
4
- * every obligation it raises to a Pending Item (scenario-scope). These are the
5
- * established Cucumber deferral conventions.
6
- *
7
- * This is **product policy, not a core-domain invariant** — an evolvable list of tag
8
- * strings, so it lives in the application layer, NOT on the v1 core barrel.
9
- * The core `parseScenarios` recognises only the deferral set it is
10
- * handed (its default is `[]`, a policy-free pure core); the app is the single source
11
- * of the starter policy and always passes the resolved set (starter ∪ configured) into
12
- * the parser at the ingest edge. Both `resolveDeferralTags` (the `@SCN-PND-021` config
13
- * union) and `renderCommandHelp`'s `--help` listing source this constant.
14
- */
15
1
  export const DEFAULT_DEFERRAL_TAGS = [
16
2
  "wip",
17
3
  "ignore",
@@ -1 +1 @@
1
- {"version":3,"file":"deferralTags.js","sourceRoot":"","sources":["../src/deferralTags.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAsB;IACtD,KAAK;IACL,QAAQ;IACR,MAAM;IACN,MAAM;IACN,SAAS;CACV,CAAC"}
1
+ {"version":3,"file":"deferralTags.js","sourceRoot":"","sources":["../src/deferralTags.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,qBAAqB,GAAsB;IACtD,KAAK;IACL,QAAQ;IACR,MAAM;IACN,MAAM;IACN,SAAS;CACV,CAAC"}
package/dist/host.d.ts CHANGED
@@ -1,50 +1,19 @@
1
- /**
2
- * The host-invocation parse — the pure half of the `spec-controller` command host.
3
- *
4
- * The shipped binary is `spec-controller [--store <root>] [--run-id <id>] <command>
5
- * [command-args]`. `--store` / `--run-id` are CROSS-CUTTING host options recognised
6
- * ONLY in leading position, before the command: storage applies across balance /
7
- * analyse / migrate, so it belongs at the host (wrapping any command via the kept-run
8
- * scaffold), not as a peer command and never as a flag inside `balance`. This module
9
- * holds the pure rules the impure dispatcher (`cli.ts`) drives — parsing the leading
10
- * options, building the wrapped command argv, and peeking the conventional provenance
11
- * flags — so the whole host contract is `@unit`-testable with no IO.
12
- *
13
- * @SCN-RMG-004 — features/run-management.feature.
14
- */
15
- /** A parsed host invocation: leading global options, then the command and its clean args. */
1
+ import { type CommandSpec, type FlagSpec } from "./cli-registry.js";
16
2
  export interface HostInvocation {
17
- /** The injected store root from a leading `--store <root>`, or undefined (no store). */
18
3
  store?: string;
19
- /** The mnemonic from a leading `--run-id <id>`, or undefined (→ the timestamp default). */
20
4
  runId?: string;
21
- /** The command token (e.g. "balance"), or undefined when none was given. */
22
5
  command?: string;
23
- /** The command's own args — everything after the command token, verbatim. */
24
6
  commandArgs: string[];
7
+ refusal?: string;
25
8
  }
26
- /**
27
- * Parse the host argv into its leading global options (`--store`, `--run-id`) and the
28
- * command + its clean args. Global options are recognised ONLY before the command: the
29
- * first token that is not a consumed global option (or its value) is the command, and
30
- * everything after it is the command's own args, verbatim. So `--store /s balance
31
- * --features f` yields the store + `balance` + `[--features, f]`, while `balance --store
32
- * /s` leaves `--store` in the command's args (a `--store` AFTER the command is the
33
- * command's own arg, never a host store directive) — the "global before command" contract.
34
- */
35
- export declare function parseHostInvocation(argv: readonly string[]): HostInvocation;
36
- /**
37
- * Build the wrapped command argv: the command's clean args followed by a repeated
38
- * `--format <spec>` per store-dir output spec. Pure — the impure runner hands the result
39
- * straight to the command, so the command's OWN writer produces the stored artefacts
40
- * (byte-identical to a bare `--format` run; no writer duplication).
41
- */
9
+ export declare function parseHostInvocation(argv: readonly string[], globalFlags?: readonly FlagSpec[], commands?: readonly string[]): HostInvocation;
42
10
  export declare function wrapCommandArgv(commandArgs: readonly string[], formatSpecs: readonly string[]): string[];
43
- /**
44
- * Read a `--<name> <value>` flag's value from an arg list WITHOUT consuming it — the host
45
- * peeks the conventional cross-cutting provenance flags (`--target`, `--features`,
46
- * `--source-sha`) to name the run dir + stamp run.yaml, while the command still receives
47
- * them in its own args. Returns undefined when the flag is absent or has no value.
48
- */
49
11
  export declare function peekFlag(argv: readonly string[], name: string): string | undefined;
12
+ export interface UnknownCommandAnswer {
13
+ exitCode: number;
14
+ stderr: string;
15
+ }
16
+ export declare function answerUnknownCommand(command: string, help: string): UnknownCommandAnswer;
17
+ export declare function modifiersNotTakenRefusal(inv: HostInvocation, commands?: readonly CommandSpec[]): string | undefined;
18
+ export declare function formatFilePaths(argv: readonly string[]): string[];
50
19
  //# sourceMappingURL=host.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,6FAA6F;AAC7F,MAAM,WAAW,cAAc;IAC7B,wFAAwF;IACxF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2FAA2F;IAC3F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,cAAc,CAmB3E;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,EAAE,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAExG;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CASlF"}
1
+ {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAUA,OAAO,EAAe,KAAK,WAAW,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAGjF,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,WAAW,GAAE,SAAS,QAAQ,EAAuB,EACrD,QAAQ,GAAE,SAAS,MAAM,EAAwD,GAChF,cAAc,CAIhB;AA+FD,wBAAgB,eAAe,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,EAAE,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAExG;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CASlF;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,oBAAoB,CAKxF;AAED,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,cAAc,EACnB,QAAQ,GAAE,SAAS,WAAW,EAAyB,GACtD,MAAM,GAAG,SAAS,CASpB;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CASjE"}
package/dist/host.js CHANGED
@@ -1,61 +1,82 @@
1
- /**
2
- * The host-invocation parse — the pure half of the `spec-controller` command host.
3
- *
4
- * The shipped binary is `spec-controller [--store <root>] [--run-id <id>] <command>
5
- * [command-args]`. `--store` / `--run-id` are CROSS-CUTTING host options recognised
6
- * ONLY in leading position, before the command: storage applies across balance /
7
- * analyse / migrate, so it belongs at the host (wrapping any command via the kept-run
8
- * scaffold), not as a peer command and never as a flag inside `balance`. This module
9
- * holds the pure rules the impure dispatcher (`cli.ts`) drives — parsing the leading
10
- * options, building the wrapped command argv, and peeking the conventional provenance
11
- * flags — so the whole host contract is `@unit`-testable with no IO.
12
- *
13
- * @SCN-RMG-004 — features/run-management.feature.
14
- */
15
- /**
16
- * Parse the host argv into its leading global options (`--store`, `--run-id`) and the
17
- * command + its clean args. Global options are recognised ONLY before the command: the
18
- * first token that is not a consumed global option (or its value) is the command, and
19
- * everything after it is the command's own args, verbatim. So `--store /s balance
20
- * --features f` yields the store + `balance` + `[--features, f]`, while `balance --store
21
- * /s` leaves `--store` in the command's args (a `--store` AFTER the command is the
22
- * command's own arg, never a host store directive) — the "global before command" contract.
23
- */
24
- export function parseHostInvocation(argv) {
25
- let store;
26
- let runId;
1
+ import { asksForHelp, equalsFormRefusal, givenTwiceRefusal, givenValue, isEqualsForm, missingValueRefusal, valueFlagsOf, } from "./cli-args.js";
2
+ import { cliRegistry } from "./cli-registry.js";
3
+ import { APP_MESSAGES, AppMessage } from "./messages.js";
4
+ export function parseHostInvocation(argv, globalFlags = cliRegistry.global, commands = cliRegistry.commands.map((command) => command.name)) {
5
+ const read = readHostTokens(argv, globalFlags, commands);
6
+ const help = argv.slice(0, hostTokenCount(argv, read)).find((token) => TOP_LEVEL_HELP.has(token));
7
+ return help === undefined ? read : { command: help, commandArgs: [] };
8
+ }
9
+ function hostTokenCount(argv, read) {
10
+ if (read.refusal !== undefined || read.command === undefined)
11
+ return argv.length;
12
+ return argv.length - read.commandArgs.length - 1;
13
+ }
14
+ function readHostTokens(argv, globalFlags, commands) {
15
+ const modifiers = valueFlagsOf(globalFlags);
16
+ const values = new Map();
27
17
  let i = 0;
28
18
  for (; i < argv.length; i++) {
29
- const token = argv[i];
30
- if (token === "--store" && i + 1 < argv.length) {
31
- store = argv[i + 1];
32
- i++;
33
- continue;
19
+ const token = argv[i] ?? "";
20
+ const modifier = modifiers.get(token);
21
+ if (modifier === undefined) {
22
+ const refusal = leadingFlagRefusal(token, modifiers, globalFlags);
23
+ if (refusal !== undefined)
24
+ return { commandArgs: [], refusal };
25
+ break;
34
26
  }
35
- if (token === "--run-id" && i + 1 < argv.length) {
36
- runId = argv[i + 1];
37
- i++;
38
- continue;
39
- }
40
- break; // first non-global-option token is the command
27
+ const read = readModifier(token, modifier, argv.slice(i + 1, i + 3), { values, commands });
28
+ if ("refusal" in read)
29
+ return { commandArgs: [], refusal: read.refusal };
30
+ values.set(modifier.name, read.value);
31
+ i++;
41
32
  }
42
- return { store, runId, command: argv[i], commandArgs: argv.slice(i + 1) };
33
+ if (i === argv.length && values.size > 0)
34
+ return { commandArgs: [], refusal: noCommandRefusal([...values.keys()]) };
35
+ return {
36
+ store: values.get("--store"),
37
+ runId: values.get("--run-id"),
38
+ command: argv[i],
39
+ commandArgs: argv.slice(i + 1),
40
+ };
41
+ }
42
+ function readModifier(token, modifier, [next, after], read) {
43
+ if (read.values.has(modifier.name))
44
+ return { refusal: givenTwiceRefusal(token, "spec-controller") };
45
+ const value = givenValue(next);
46
+ if (value === undefined)
47
+ return { refusal: missingValueRefusal(token, modifier, "spec-controller") };
48
+ if (read.commands.includes(value) && (after === undefined || after.startsWith("-"))) {
49
+ return { refusal: commandAsValueRefusal(token, modifier, value) };
50
+ }
51
+ return { value };
52
+ }
53
+ function noCommandRefusal(given) {
54
+ return (`${APP_MESSAGES[AppMessage.NoCommandAfterModifiers](given.join(", "))}\n` +
55
+ APP_MESSAGES[AppMessage.SeeCommandsAndModifiers]());
56
+ }
57
+ function commandAsValueRefusal(token, modifier, command) {
58
+ return (`${APP_MESSAGES[AppMessage.ModifierTookCommand](token, command)}\n` +
59
+ `${APP_MESSAGES[AppMessage.GiveModifierItsOwnValue](token, modifier.arg, command)} ` +
60
+ APP_MESSAGES[AppMessage.SeeCommandsAndModifiers]());
61
+ }
62
+ function leadingFlagRefusal(token, modifiers, globalFlags) {
63
+ if (isEqualsForm(token))
64
+ return equalsFormRefusal(token, modifiers, "spec-controller");
65
+ if (isFlagOutOfPlace(token))
66
+ return flagBeforeCommandRefusal(token, globalFlags);
67
+ return undefined;
68
+ }
69
+ const TOP_LEVEL_HELP = new Set(["--help", "-h"]);
70
+ function isFlagOutOfPlace(token) {
71
+ return token.length > 1 && token.startsWith("-") && !TOP_LEVEL_HELP.has(token);
72
+ }
73
+ function flagBeforeCommandRefusal(flag, globalFlags) {
74
+ const modifiers = globalFlags.map((modifier) => modifier.name).join(", ");
75
+ return `${APP_MESSAGES[AppMessage.FlagBeforeCommand](flag, modifiers)}\n${APP_MESSAGES[AppMessage.SeeCommandsAndModifiers]()}`;
43
76
  }
44
- /**
45
- * Build the wrapped command argv: the command's clean args followed by a repeated
46
- * `--format <spec>` per store-dir output spec. Pure — the impure runner hands the result
47
- * straight to the command, so the command's OWN writer produces the stored artefacts
48
- * (byte-identical to a bare `--format` run; no writer duplication).
49
- */
50
77
  export function wrapCommandArgv(commandArgs, formatSpecs) {
51
78
  return [...commandArgs, ...formatSpecs.flatMap((spec) => ["--format", spec])];
52
79
  }
53
- /**
54
- * Read a `--<name> <value>` flag's value from an arg list WITHOUT consuming it — the host
55
- * peeks the conventional cross-cutting provenance flags (`--target`, `--features`,
56
- * `--source-sha`) to name the run dir + stamp run.yaml, while the command still receives
57
- * them in its own args. Returns undefined when the flag is absent or has no value.
58
- */
59
80
  export function peekFlag(argv, name) {
60
81
  const flag = `--${name}`;
61
82
  for (let i = 0; i < argv.length; i++) {
@@ -66,4 +87,32 @@ export function peekFlag(argv, name) {
66
87
  }
67
88
  return undefined;
68
89
  }
90
+ export function answerUnknownCommand(command, help) {
91
+ return {
92
+ exitCode: 2,
93
+ stderr: `spec-controller: ${APP_MESSAGES[AppMessage.UnknownCommand](command)}\n\n${help}\n`,
94
+ };
95
+ }
96
+ export function modifiersNotTakenRefusal(inv, commands = cliRegistry.commands) {
97
+ const entry = commands.find((command) => command.name === inv.command);
98
+ if (entry?.acceptsHostModifiers !== false || asksForHelp(inv.commandArgs))
99
+ return undefined;
100
+ const given = [inv.store === undefined ? [] : ["--store"], inv.runId === undefined ? [] : ["--run-id"]].flat();
101
+ if (given.length === 0)
102
+ return undefined;
103
+ return (`${APP_MESSAGES[AppMessage.HostUsageError](APP_MESSAGES[AppMessage.ModifiersNotTaken](entry.name, given.join(", ")))}\n` +
104
+ APP_MESSAGES[AppMessage.RunWithoutModifiers](entry.name));
105
+ }
106
+ export function formatFilePaths(argv) {
107
+ const paths = [];
108
+ argv.forEach((token, index) => {
109
+ const value = argv[index + 1];
110
+ if (token !== "--format" || value === undefined)
111
+ return;
112
+ const colon = value.indexOf(":");
113
+ if (colon !== -1)
114
+ paths.push(value.slice(colon + 1));
115
+ });
116
+ return paths;
117
+ }
69
118
  //# sourceMappingURL=host.js.map
package/dist/host.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"host.js","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAcH;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAuB;IACzD,IAAI,KAAyB,CAAC;IAC9B,IAAI,KAAyB,CAAC;IAC9B,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YAC/C,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACpB,CAAC,EAAE,CAAC;YACJ,SAAS;QACX,CAAC;QACD,IAAI,KAAK,KAAK,UAAU,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YAChD,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACpB,CAAC,EAAE,CAAC;YACJ,SAAS;QACX,CAAC;QACD,MAAM,CAAC,+CAA+C;IACxD,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;AAC5E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,WAA8B,EAAE,WAA8B;IAC5F,OAAO,CAAC,GAAG,WAAW,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;AAChF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAuB,EAAE,IAAY;IAC5D,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;IACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACrB,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1B,OAAO,KAAK,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;QAC5E,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
1
+ {"version":3,"file":"host.js","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"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"}
@@ -1,46 +1,7 @@
1
- /**
2
- * Resolve a CI input to the workflow files it names (@SCN-USG-006, 3F-2497).
3
- *
4
- * A target's pipeline is routinely split across files — a nightly sweep, a security
5
- * scan — and reading one of them scores the rest against the target twice over: a
6
- * NAMED check enforced elsewhere is called a watermelon it is not, an UNNAMED one
7
- * never reaches the books at all (3F-2238).
8
- *
9
- * THIS IS THE ONLY PLACE THAT KNOWS A CI INPUT CAN BE A DIRECTORY. The core takes
10
- * anonymous source strings so a second ecosystem can supply its own; teaching it to
11
- * walk a folder would import a filesystem and one provider's layout into a pure
12
- * parser and close that seam for good. So the walk lives here, at the edge that
13
- * already resolved `.github/workflows/ci.yml`, and the edge knows exactly as much
14
- * about GitHub after this slice as it did before.
15
- *
16
- * Pure, with the filesystem injected — the resolution rules are the part worth
17
- * asserting directly, and a fixture tree can only show one of them going wrong at a
18
- * time.
19
- */
20
- /** The filesystem reads the resolution needs, injected so the rules stay pure. */
21
1
  export interface CiPathReader {
22
2
  exists(path: string): boolean;
23
3
  isDirectory(path: string): boolean;
24
4
  readDir(path: string): string[];
25
5
  }
26
- /** The real filesystem, for the CLI edge. */
27
- export declare const NODE_CI_PATH_READER: CiPathReader;
28
- /**
29
- * The workflow files a CI input names: every workflow in a directory, or the single
30
- * file itself.
31
- *
32
- * Sorted, so two runs over one tree cannot differ and a diff of two reports never
33
- * turns on `readdir` ordering.
34
- *
35
- * A FILE RESOLVES TO ITSELF ALONE. Sweeping its parent directory would silently widen
36
- * a caller's deliberate scope, which is the promise @SCN-USG-008 pins at the report level.
37
- *
38
- * An absent path resolves to nothing — no sources, no commands, every static check
39
- * read as unenforced. That over-reports gaps and hides none, the same fail-safe
40
- * direction `ciRunCommands` takes on a document it cannot parse. The HARD error for a
41
- * path the caller SUPPLIED and that does not exist is @SCN-CLI-002's, raised upstream;
42
- * reaching here with nothing means the DEFAULT found no workflows, which is a fact
43
- * about the target rather than a mistake by its author.
44
- */
45
6
  export declare function ciSourcePathsOf(ciPath: string, reader?: CiPathReader): string[];
46
7
  //# sourceMappingURL=ciSourcePaths.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ciSourcePaths.d.ts","sourceRoot":"","sources":["../../src/ingest/ciSourcePaths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,kFAAkF;AAClF,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9B,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACnC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACjC;AAED,6CAA6C;AAC7C,eAAO,MAAM,mBAAmB,EAAE,YAIjC,CAAC;AAKF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,YAAkC,GACzC,MAAM,EAAE,CAQV"}
1
+ {"version":3,"file":"ciSourcePaths.d.ts","sourceRoot":"","sources":["../../src/ingest/ciSourcePaths.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9B,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACnC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACjC;AAUD,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,YAAkC,GACzC,MAAM,EAAE,CAQV"}
@@ -1,49 +1,11 @@
1
- /**
2
- * Resolve a CI input to the workflow files it names (@SCN-USG-006, 3F-2497).
3
- *
4
- * A target's pipeline is routinely split across files — a nightly sweep, a security
5
- * scan — and reading one of them scores the rest against the target twice over: a
6
- * NAMED check enforced elsewhere is called a watermelon it is not, an UNNAMED one
7
- * never reaches the books at all (3F-2238).
8
- *
9
- * THIS IS THE ONLY PLACE THAT KNOWS A CI INPUT CAN BE A DIRECTORY. The core takes
10
- * anonymous source strings so a second ecosystem can supply its own; teaching it to
11
- * walk a folder would import a filesystem and one provider's layout into a pure
12
- * parser and close that seam for good. So the walk lives here, at the edge that
13
- * already resolved `.github/workflows/ci.yml`, and the edge knows exactly as much
14
- * about GitHub after this slice as it did before.
15
- *
16
- * Pure, with the filesystem injected — the resolution rules are the part worth
17
- * asserting directly, and a fixture tree can only show one of them going wrong at a
18
- * time.
19
- */
20
1
  import { existsSync, readdirSync, statSync } from "node:fs";
21
2
  import { join } from "node:path";
22
- /** The real filesystem, for the CLI edge. */
23
- export const NODE_CI_PATH_READER = {
3
+ const NODE_CI_PATH_READER = {
24
4
  exists: existsSync,
25
5
  isDirectory: (path) => statSync(path).isDirectory(),
26
6
  readDir: readdirSync,
27
7
  };
28
- /** Both YAML spellings: a target picks one, and the tool does not get to mind which. */
29
8
  const WORKFLOW_EXTENSIONS = [".yml", ".yaml"];
30
- /**
31
- * The workflow files a CI input names: every workflow in a directory, or the single
32
- * file itself.
33
- *
34
- * Sorted, so two runs over one tree cannot differ and a diff of two reports never
35
- * turns on `readdir` ordering.
36
- *
37
- * A FILE RESOLVES TO ITSELF ALONE. Sweeping its parent directory would silently widen
38
- * a caller's deliberate scope, which is the promise @SCN-USG-008 pins at the report level.
39
- *
40
- * An absent path resolves to nothing — no sources, no commands, every static check
41
- * read as unenforced. That over-reports gaps and hides none, the same fail-safe
42
- * direction `ciRunCommands` takes on a document it cannot parse. The HARD error for a
43
- * path the caller SUPPLIED and that does not exist is @SCN-CLI-002's, raised upstream;
44
- * reaching here with nothing means the DEFAULT found no workflows, which is a fact
45
- * about the target rather than a mistake by its author.
46
- */
47
9
  export function ciSourcePathsOf(ciPath, reader = NODE_CI_PATH_READER) {
48
10
  if (!reader.exists(ciPath))
49
11
  return [];
@@ -1 +1 @@
1
- {"version":3,"file":"ciSourcePaths.js","sourceRoot":"","sources":["../../src/ingest/ciSourcePaths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AASjC,6CAA6C;AAC7C,MAAM,CAAC,MAAM,mBAAmB,GAAiB;IAC/C,MAAM,EAAE,UAAU;IAClB,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE;IACnD,OAAO,EAAE,WAAW;CACrB,CAAC;AAEF,wFAAwF;AACxF,MAAM,mBAAmB,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE9C;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAc,EACd,SAAuB,mBAAmB;IAE1C,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAC;IACtC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC;QAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACjD,OAAO,MAAM;SACV,OAAO,CAAC,MAAM,CAAC;SACf,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;SACvE,IAAI,EAAE;SACN,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;AACvC,CAAC"}
1
+ {"version":3,"file":"ciSourcePaths.js","sourceRoot":"","sources":["../../src/ingest/ciSourcePaths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAQjC,MAAM,mBAAmB,GAAiB;IACxC,MAAM,EAAE,UAAU;IAClB,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE;IACnD,OAAO,EAAE,WAAW;CACrB,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE9C,MAAM,UAAU,eAAe,CAC7B,MAAc,EACd,SAAuB,mBAAmB;IAE1C,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAC;IACtC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC;QAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACjD,OAAO,MAAM;SACV,OAAO,CAAC,MAAM,CAAC;SACf,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;SACvE,IAAI,EAAE;SACN,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;AACvC,CAAC"}
@@ -1,93 +1,13 @@
1
- /**
2
- * The Gherkin VALIDATOR — the feature corpus's integrity checkpoint (@SCN-CLI-016, 3F-1767).
3
- *
4
- * WHY THIS EXISTS. The feature corpus is the ledger's DEBIT side, and it was read by a
5
- * hand-rolled TAG-LINE SCAN (`parseScenarios`) that never looked for a `Scenario:` header at
6
- * all: a scenario EXISTED purely because an `@SCN-FFF-NNN` tag line did. So a
7
- * malformed tag line simply STOPPED BEING A TAG LINE, and its scenario ceased to exist —
8
- * silently. One stray character, in a file cucumber itself rejects, deleted a failing row and
9
- * turned an out-of-balance run (exit 1) into a clean BALANCED (exit 0). A dropped scenario
10
- * cannot even reconcile `missing`, because it was never raised to be missing: the run reads
11
- * CLEANER THAN REALITY. That is the false-green this tool exists to prevent, aimed at itself.
12
- *
13
- * THE FIX (this slice). VALIDATE every feature file with the REAL Gherkin parser — the same one
14
- * cucumber uses. A file the parser rejects is an input the tool CANNOT READ, and the CLI refuses
15
- * it: exit 2, halting before reconciling (@SCN-CLI-014/015's Rule — "an input the tool cannot read
16
- * is a usage error, never a verdict" — extended from the OBSERVATION side to the OBLIGATION side).
17
- *
18
- * VALIDATION IS HALF THE STORY. This decides whether a feature file can be READ at all; the corpus
19
- * is then EXTRACTED from the same real AST by `parseScenarios` (@SCN-LDG-020, 3F-1775), so the
20
- * scenarios spec-controller reconciles carry exactly the tags cucumber gives them — Feature/Rule
21
- * tag inheritance included. One reading of the file, not two.
22
- *
23
- * PURE: `string → parse errors`. No fs, no process — the file READ lives beside it at the ingest
24
- * edge, as it does for every other input.
25
- *
26
- * WHY IT LIVES IN THE APP, NOT CORE. Core's barrel is the v1 contract surface downstream consumers
27
- * build on. Since 3F-3449 nothing reds when a symbol is added there — the guard that reconciled it
28
- * both directions is gone — so keeping it narrow is a discipline rather than a gate. This validator
29
- * is an INGEST concern (it decides whether an input can be read at all), not part of the
30
- * reconciliation contract, so it belongs with the other readers at the app edge and the v1 surface
31
- * stays untouched.
32
- */
33
- /** A Gherkin parse failure: the file could not be read as Gherkin at all. */
34
1
  export interface GherkinParseError {
35
- /** The offending file, as supplied (the operator's locator — what to go and fix). */
36
2
  file: string;
37
- /** The parser's own message, verbatim — WHAT broke, in the parser's words. */
38
3
  message: string;
39
4
  }
40
- /**
41
- * Validate one `.feature` source with the real Gherkin parser. Returns the parse errors it
42
- * reports — empty when the file is well-formed Gherkin.
43
- *
44
- * The parser is authoritative BY CONSTRUCTION: it is cucumber's own. A file it rejects is one
45
- * cucumber would refuse to RUN, so a scenario corpus built from it would be a FICTION — which is
46
- * precisely how a corrupt spec used to read balanced.
47
- *
48
- * A parse failure is reported, never thrown: the CLI edge routes it to stderr + exit 2 (the
49
- * shared typed-error surface), so it can never reach Node's default exit 1 and masquerade as an
50
- * out-of-balance verdict (@SCN-CLI-014's collision, on the obligation side).
51
- *
52
- * @SCN-CLI-016 (3F-1773).
53
- */
54
5
  export declare function parseErrorsIn(file: string, source: string): GherkinParseError[];
55
- /**
56
- * The corpus-level REFUSAL (@SCN-GPG-001, 3F-2817). A parse failure is reported per file by
57
- * `parseErrorsIn` above; this is how a reader of the WHOLE corpus says no.
58
- *
59
- * WHY IT CARRIES EVERY FILE. The balance CLI already names every unparseable file it found
60
- * (@SCN-CLI-016), and a refusal raised at the first bad one would silently narrow that message —
61
- * a behaviour change dressed as an implementation detail. So the discovery collects the corpus
62
- * and refuses ONCE, carrying the lot in discovery order.
63
- *
64
- * The rendered message is the parser's words, per file, verbatim: a reader must be told WHAT
65
- * broke by the parser rather than by our paraphrase of it.
66
- */
67
6
  export declare class UnreadableFeatureCorpusError extends Error {
68
7
  readonly errors: readonly GherkinParseError[];
69
8
  constructor(errors: readonly GherkinParseError[]);
70
9
  }
71
- /**
72
- * The corpus-level ABSENCE refusal (@SCN-CLI-017, 3F-3345) — sibling to the parse refusal above,
73
- * and deliberately the same shape: the reader refuses ONCE, and each command decides what the
74
- * refusal means for it.
75
- *
76
- * WHY A TYPED ERROR RATHER THAN AN EMPTY CORPUS. The obvious fix is for `discoverFeatures` to hand
77
- * back `[]` when the directory is not there. Measured, that would ship a NEW false green in a
78
- * second command: `spec-controller tags` reaches the same reader through `readCorpusInputs`, whose
79
- * GENERIC catch is the only thing turning an absent corpus — and, since `tags` carries no
80
- * `checkInputsExist`, a supplied-but-absent `--features` too — into `The corpus could not be
81
- * read: …` at exit 2. Tolerance at the reader turns both into `tags: OK …` at exit 0, inside the
82
- * slice whose whole purpose is killing a vacuous certification. Typed, both survive untouched:
83
- * this IS an `Error`, so it still lands in that generic catch.
84
- *
85
- * IT CARRIES THE DIRECTORY because the report is owed the name of what it examined — "I found no
86
- * record" and "I found no regression" must never wear one word (3F-2947), and a consumer told
87
- * their corpus is empty deserves to know which directory was read to reach that.
88
- */
89
10
  export declare class MissingFeatureCorpusError extends Error {
90
- /** The directory that is not there — as resolved, so a reader can print the path examined. */
91
11
  readonly directory: string;
92
12
  constructor(directory: string);
93
13
  }
@@ -1 +1 @@
1
- {"version":3,"file":"gherkinValidation.d.ts","sourceRoot":"","sources":["../../src/ingest/gherkinValidation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAKH,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB;IAChC,qFAAqF;IACrF,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAa/E;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,4BAA6B,SAAQ,KAAK;IACrD,QAAQ,CAAC,MAAM,EAAE,SAAS,iBAAiB,EAAE,CAAC;gBAElC,MAAM,EAAE,SAAS,iBAAiB,EAAE;CAUjD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,8FAA8F;IAC9F,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,SAAS,EAAE,MAAM;CAK9B"}
1
+ {"version":3,"file":"gherkinValidation.d.ts","sourceRoot":"","sources":["../../src/ingest/gherkinValidation.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAU/E;AAED,qBAAa,4BAA6B,SAAQ,KAAK;IACrD,QAAQ,CAAC,MAAM,EAAE,SAAS,iBAAiB,EAAE,CAAC;gBAElC,MAAM,EAAE,SAAS,iBAAiB,EAAE;CAUjD;AAED,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,SAAS,EAAE,MAAM;CAK9B"}