@step-forge/step-forge 0.0.19 → 0.0.21

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 (40) hide show
  1. package/README.md +5 -2
  2. package/RUNTIME.md +212 -0
  3. package/dist/{analyzer-QH03uejK.js → analyzer-DYfdoSIS.js} +55 -16
  4. package/dist/analyzer-DYfdoSIS.js.map +1 -0
  5. package/dist/analyzer-cli.js +1 -1
  6. package/dist/analyzer-cli.js.map +1 -1
  7. package/dist/analyzer.d.ts +14 -0
  8. package/dist/analyzer.js +1 -1
  9. package/dist/cli.cjs +470 -0
  10. package/dist/cli.cjs.map +1 -0
  11. package/dist/cli.d.cts +1 -0
  12. package/dist/cli.d.ts +1 -0
  13. package/dist/cli.js +471 -0
  14. package/dist/cli.js.map +1 -0
  15. package/dist/engine-DPRxs6eC.js +181 -0
  16. package/dist/engine-DPRxs6eC.js.map +1 -0
  17. package/dist/engine-DWAIlwWp.cjs +204 -0
  18. package/dist/engine-DWAIlwWp.cjs.map +1 -0
  19. package/dist/gherkinParser-CHpkEwii.cjs +243 -0
  20. package/dist/gherkinParser-CHpkEwii.cjs.map +1 -0
  21. package/dist/gherkinParser-CKARHgt4.js +188 -0
  22. package/dist/gherkinParser-CKARHgt4.js.map +1 -0
  23. package/dist/hooks-CGYzwDOv.cjs +117 -0
  24. package/dist/hooks-CGYzwDOv.cjs.map +1 -0
  25. package/dist/hooks-CywugMQQ.js +82 -0
  26. package/dist/hooks-CywugMQQ.js.map +1 -0
  27. package/dist/hooks-Dar49TtT.d.cts +189 -0
  28. package/dist/hooks-Dar49TtT.d.ts +189 -0
  29. package/dist/runtime.cjs +13 -0
  30. package/dist/runtime.d.cts +142 -0
  31. package/dist/runtime.d.ts +142 -0
  32. package/dist/runtime.js +3 -0
  33. package/dist/step-forge.cjs +185 -306
  34. package/dist/step-forge.cjs.map +1 -1
  35. package/dist/step-forge.d.cts +193 -733
  36. package/dist/step-forge.d.ts +193 -733
  37. package/dist/step-forge.js +174 -276
  38. package/dist/step-forge.js.map +1 -1
  39. package/package.json +20 -9
  40. package/dist/analyzer-QH03uejK.js.map +0 -1
@@ -0,0 +1,189 @@
1
+ //#region src/parsers.d.ts
2
+ /**
3
+ * A Parser is a typed cucumber-expression *parameter type*: it declares how a
4
+ * value is recognised in a Gherkin step (`regexp`) and how the matched text is
5
+ * turned into a TypeScript value (`parse`). The step expression uses `{name}`
6
+ * as the placeholder.
7
+ *
8
+ * The engine folds each parser straight into the cucumber-expression matcher —
9
+ * `parse` is the parameter type's transform, so coercion happens exactly once,
10
+ * during matching (no second pass). This is also what lets a parser introduce a
11
+ * brand-new placeholder like `{color}`: it is registered as a real parameter
12
+ * type, so text that doesn't match `regexp` simply doesn't match the step.
13
+ *
14
+ * The four built-ins below reuse cucumber-expressions' own built-in parameter
15
+ * types (`{int}`, `{float}`, `{string}`) — those names are already registered,
16
+ * so the library performs the match + coercion and each parser's `regexp`/
17
+ * `parse` serve to document intent and to drive TypeScript inference of the
18
+ * variable type. `booleanParser` has no built-in equivalent, so it is a genuine
19
+ * custom parameter type whose `parse` runs at match time.
20
+ */
21
+ type Parser<T> = {
22
+ /** Parameter-type name; the step expression uses `{name}` as the placeholder. */name: string; /** How cucumber-expressions recognises the value in the step text. */
23
+ regexp: RegExp | RegExp[]; /** Transform the matched text into the typed value. */
24
+ parse: (value: string) => T;
25
+ };
26
+ /** Matches a quoted string (`{string}`) and strips the surrounding quotes. */
27
+ declare const stringParser: Parser<string>;
28
+ /** Matches an unquoted integer (`{int}`). */
29
+ declare const intParser: Parser<number>;
30
+ /** Matches an unquoted floating point number (`{float}`). */
31
+ declare const numberParser: Parser<number>;
32
+ /**
33
+ * Matches an unquoted `true`/`false` word (`{boolean}`) and parses it to a
34
+ * boolean. Unlike the others this is a genuine custom parameter type — cucumber
35
+ * has no built-in `boolean` — so its `regexp`/`parse` are what the matcher uses.
36
+ */
37
+ declare const booleanParser: Parser<boolean>;
38
+ //#endregion
39
+ //#region src/world.d.ts
40
+ type WorldState<State> = { readonly [K in keyof State]?: State[K] };
41
+ type MergeableWorldState<T> = WorldState<T> & {
42
+ merge: (newState: Partial<T>) => void;
43
+ };
44
+ type MergeableWorld<Given, When, Then> = {
45
+ given: MergeableWorldState<Given>;
46
+ when: MergeableWorldState<When>;
47
+ then: MergeableWorldState<Then>;
48
+ };
49
+ declare class BasicWorld<Given, When, Then> {
50
+ private givenState;
51
+ private whenState;
52
+ private thenState;
53
+ get given(): MergeableWorldState<Given>;
54
+ get when(): MergeableWorldState<When>;
55
+ get then(): MergeableWorldState<Then>;
56
+ }
57
+ //#endregion
58
+ //#region src/analyzer/types.d.ts
59
+ interface StepDefinitionMeta {
60
+ stepType: "given" | "when" | "then";
61
+ expression: string;
62
+ dependencies: {
63
+ given: Record<string, "required" | "optional">;
64
+ when: Record<string, "required" | "optional">;
65
+ then: Record<string, "required" | "optional">;
66
+ };
67
+ produces: string[];
68
+ sourceFile: string;
69
+ line: number;
70
+ }
71
+ interface ParsedScenario {
72
+ name: string;
73
+ file: string;
74
+ steps: ParsedStep[];
75
+ /**
76
+ * Gherkin tags in effect for this scenario, each including the leading `@`
77
+ * (feature + scenario tags, plus the Examples-block tags for outline rows).
78
+ * The Vitest plugin maps `@skip`/`@only` onto `test.skip`/`test.only`.
79
+ */
80
+ tags: string[];
81
+ /**
82
+ * Present only for rows expanded from a `Scenario Outline`. Carries the base
83
+ * outline name so the plugin can group its rows under one `describe`, with
84
+ * each row a separate `test` labelled by its example values.
85
+ */
86
+ outline?: {
87
+ name: string;
88
+ };
89
+ }
90
+ interface ParsedStep {
91
+ keyword: "Given" | "When" | "Then" | "And" | "But";
92
+ effectiveKeyword: "Given" | "When" | "Then";
93
+ text: string;
94
+ line: number;
95
+ column: number;
96
+ }
97
+ interface MatchedStep extends ParsedStep {
98
+ definitions: StepDefinitionMeta[];
99
+ }
100
+ interface Diagnostic {
101
+ file: string;
102
+ range: {
103
+ startLine: number;
104
+ startColumn: number;
105
+ endLine: number;
106
+ endColumn: number;
107
+ };
108
+ severity: "error" | "warning" | "info";
109
+ message: string;
110
+ rule: string;
111
+ source: "step-forge";
112
+ }
113
+ interface AnalysisRule {
114
+ name: string;
115
+ check(scenario: ParsedScenario, matchedSteps: MatchedStep[]): Diagnostic[];
116
+ }
117
+ interface AnalyzerConfig {
118
+ stepFiles: string[];
119
+ featureFiles: string[];
120
+ tsConfigPath?: string;
121
+ }
122
+ //#endregion
123
+ //#region src/runtime/hooks.d.ts
124
+ /**
125
+ * Hooks are side-effect callbacks that run around scenarios, feature files, or
126
+ * the whole run. Unlike steps they never seed state: state is owned end to end
127
+ * by the typed dependency graph (given/when/then), and hooks exist for setup and
128
+ * teardown (opening a DB, starting a server, resetting mocks). A scenario hook
129
+ * may *read* the world, but its return value is ignored.
130
+ */
131
+ type HookScope = "scenario" | "feature" | "global";
132
+ type HookTiming = "before" | "after";
133
+ /** Lightweight scenario identity handed to per-scenario hooks. */
134
+ interface ScenarioInfo {
135
+ name: string;
136
+ file: string;
137
+ }
138
+ /** A per-scenario hook: gets the scenario's world (read-only in spirit). */
139
+ type ScenarioHookFn = (context: {
140
+ world: MergeableWorld<any, any, any>;
141
+ scenario: ScenarioInfo;
142
+ }) => void | Promise<void>;
143
+ /** A per-feature-file or global hook: no world exists at these boundaries. */
144
+ type PlainHookFn = () => void | Promise<void>;
145
+ interface RegisteredHook {
146
+ scope: HookScope;
147
+ timing: HookTiming;
148
+ fn: ScenarioHookFn | PlainHookFn;
149
+ }
150
+ /**
151
+ * Collection of registered hooks. Like {@link StepRegistry}, a plain instance
152
+ * (not a hidden global) so tests can isolate; `globalHookRegistry` is the
153
+ * default sink the public `beforeScenario`/`afterAll`/etc helpers write to.
154
+ */
155
+ declare class HookRegistry {
156
+ private hooks;
157
+ add(hook: RegisteredHook): void;
158
+ /**
159
+ * Hooks for a scope+timing. `before` hooks run in registration order;
160
+ * `after` hooks run in reverse (LIFO), so teardown unwinds setup.
161
+ */
162
+ for(scope: HookScope, timing: HookTiming): RegisteredHook[];
163
+ clear(): void;
164
+ }
165
+ declare const globalHookRegistry: HookRegistry;
166
+ /**
167
+ * Run every registered feature/global hook of a scope+timing in order. Used by
168
+ * the generated test modules (feature hooks). Throws if a hook throws, so the
169
+ * runner reports it against the enclosing boundary.
170
+ */
171
+ declare function runHooks(scope: "feature" | "global", timing: HookTiming, registry?: HookRegistry): Promise<void>;
172
+ /**
173
+ * Run global before-hooks once per worker, ahead of that worker's first
174
+ * scenario, and schedule global after-hooks for worker exit. Idempotent: every
175
+ * feature module calls this in a `beforeAll`, but only the first call in a given
176
+ * worker does anything.
177
+ *
178
+ * Semantics & caveats (the once-per-worker model):
179
+ * - Runs in the *same* realm as steps, so global setup may touch in-process
180
+ * state that steps later read.
181
+ * - "Once per worker", not strictly once per run — with multiple workers it runs
182
+ * in each. Size global setup to be worker-safe (e.g. a server per worker).
183
+ * - Teardown is best-effort: after-hooks start on the worker's `beforeExit` and
184
+ * are not awaited by the runner, so keep them fast/synchronous.
185
+ */
186
+ declare function ensureGlobalHooks(registry?: HookRegistry): Promise<void>;
187
+ //#endregion
188
+ export { numberParser as C, intParser as S, StepDefinitionMeta as _, RegisteredHook as a, Parser as b, ensureGlobalHooks as c, AnalysisRule as d, AnalyzerConfig as f, ParsedStep as g, ParsedScenario as h, PlainHookFn as i, globalHookRegistry as l, MatchedStep as m, HookScope as n, ScenarioHookFn as o, Diagnostic as p, HookTiming as r, ScenarioInfo as s, HookRegistry as t, runHooks as u, BasicWorld as v, stringParser as w, booleanParser as x, MergeableWorld as y };
189
+ //# sourceMappingURL=hooks-Dar49TtT.d.cts.map
@@ -0,0 +1,189 @@
1
+ //#region src/parsers.d.ts
2
+ /**
3
+ * A Parser is a typed cucumber-expression *parameter type*: it declares how a
4
+ * value is recognised in a Gherkin step (`regexp`) and how the matched text is
5
+ * turned into a TypeScript value (`parse`). The step expression uses `{name}`
6
+ * as the placeholder.
7
+ *
8
+ * The engine folds each parser straight into the cucumber-expression matcher —
9
+ * `parse` is the parameter type's transform, so coercion happens exactly once,
10
+ * during matching (no second pass). This is also what lets a parser introduce a
11
+ * brand-new placeholder like `{color}`: it is registered as a real parameter
12
+ * type, so text that doesn't match `regexp` simply doesn't match the step.
13
+ *
14
+ * The four built-ins below reuse cucumber-expressions' own built-in parameter
15
+ * types (`{int}`, `{float}`, `{string}`) — those names are already registered,
16
+ * so the library performs the match + coercion and each parser's `regexp`/
17
+ * `parse` serve to document intent and to drive TypeScript inference of the
18
+ * variable type. `booleanParser` has no built-in equivalent, so it is a genuine
19
+ * custom parameter type whose `parse` runs at match time.
20
+ */
21
+ type Parser<T> = {
22
+ /** Parameter-type name; the step expression uses `{name}` as the placeholder. */name: string; /** How cucumber-expressions recognises the value in the step text. */
23
+ regexp: RegExp | RegExp[]; /** Transform the matched text into the typed value. */
24
+ parse: (value: string) => T;
25
+ };
26
+ /** Matches a quoted string (`{string}`) and strips the surrounding quotes. */
27
+ declare const stringParser: Parser<string>;
28
+ /** Matches an unquoted integer (`{int}`). */
29
+ declare const intParser: Parser<number>;
30
+ /** Matches an unquoted floating point number (`{float}`). */
31
+ declare const numberParser: Parser<number>;
32
+ /**
33
+ * Matches an unquoted `true`/`false` word (`{boolean}`) and parses it to a
34
+ * boolean. Unlike the others this is a genuine custom parameter type — cucumber
35
+ * has no built-in `boolean` — so its `regexp`/`parse` are what the matcher uses.
36
+ */
37
+ declare const booleanParser: Parser<boolean>;
38
+ //#endregion
39
+ //#region src/world.d.ts
40
+ type WorldState<State> = { readonly [K in keyof State]?: State[K] };
41
+ type MergeableWorldState<T> = WorldState<T> & {
42
+ merge: (newState: Partial<T>) => void;
43
+ };
44
+ type MergeableWorld<Given, When, Then> = {
45
+ given: MergeableWorldState<Given>;
46
+ when: MergeableWorldState<When>;
47
+ then: MergeableWorldState<Then>;
48
+ };
49
+ declare class BasicWorld<Given, When, Then> {
50
+ private givenState;
51
+ private whenState;
52
+ private thenState;
53
+ get given(): MergeableWorldState<Given>;
54
+ get when(): MergeableWorldState<When>;
55
+ get then(): MergeableWorldState<Then>;
56
+ }
57
+ //#endregion
58
+ //#region src/analyzer/types.d.ts
59
+ interface StepDefinitionMeta {
60
+ stepType: "given" | "when" | "then";
61
+ expression: string;
62
+ dependencies: {
63
+ given: Record<string, "required" | "optional">;
64
+ when: Record<string, "required" | "optional">;
65
+ then: Record<string, "required" | "optional">;
66
+ };
67
+ produces: string[];
68
+ sourceFile: string;
69
+ line: number;
70
+ }
71
+ interface ParsedScenario {
72
+ name: string;
73
+ file: string;
74
+ steps: ParsedStep[];
75
+ /**
76
+ * Gherkin tags in effect for this scenario, each including the leading `@`
77
+ * (feature + scenario tags, plus the Examples-block tags for outline rows).
78
+ * The Vitest plugin maps `@skip`/`@only` onto `test.skip`/`test.only`.
79
+ */
80
+ tags: string[];
81
+ /**
82
+ * Present only for rows expanded from a `Scenario Outline`. Carries the base
83
+ * outline name so the plugin can group its rows under one `describe`, with
84
+ * each row a separate `test` labelled by its example values.
85
+ */
86
+ outline?: {
87
+ name: string;
88
+ };
89
+ }
90
+ interface ParsedStep {
91
+ keyword: "Given" | "When" | "Then" | "And" | "But";
92
+ effectiveKeyword: "Given" | "When" | "Then";
93
+ text: string;
94
+ line: number;
95
+ column: number;
96
+ }
97
+ interface MatchedStep extends ParsedStep {
98
+ definitions: StepDefinitionMeta[];
99
+ }
100
+ interface Diagnostic {
101
+ file: string;
102
+ range: {
103
+ startLine: number;
104
+ startColumn: number;
105
+ endLine: number;
106
+ endColumn: number;
107
+ };
108
+ severity: "error" | "warning" | "info";
109
+ message: string;
110
+ rule: string;
111
+ source: "step-forge";
112
+ }
113
+ interface AnalysisRule {
114
+ name: string;
115
+ check(scenario: ParsedScenario, matchedSteps: MatchedStep[]): Diagnostic[];
116
+ }
117
+ interface AnalyzerConfig {
118
+ stepFiles: string[];
119
+ featureFiles: string[];
120
+ tsConfigPath?: string;
121
+ }
122
+ //#endregion
123
+ //#region src/runtime/hooks.d.ts
124
+ /**
125
+ * Hooks are side-effect callbacks that run around scenarios, feature files, or
126
+ * the whole run. Unlike steps they never seed state: state is owned end to end
127
+ * by the typed dependency graph (given/when/then), and hooks exist for setup and
128
+ * teardown (opening a DB, starting a server, resetting mocks). A scenario hook
129
+ * may *read* the world, but its return value is ignored.
130
+ */
131
+ type HookScope = "scenario" | "feature" | "global";
132
+ type HookTiming = "before" | "after";
133
+ /** Lightweight scenario identity handed to per-scenario hooks. */
134
+ interface ScenarioInfo {
135
+ name: string;
136
+ file: string;
137
+ }
138
+ /** A per-scenario hook: gets the scenario's world (read-only in spirit). */
139
+ type ScenarioHookFn = (context: {
140
+ world: MergeableWorld<any, any, any>;
141
+ scenario: ScenarioInfo;
142
+ }) => void | Promise<void>;
143
+ /** A per-feature-file or global hook: no world exists at these boundaries. */
144
+ type PlainHookFn = () => void | Promise<void>;
145
+ interface RegisteredHook {
146
+ scope: HookScope;
147
+ timing: HookTiming;
148
+ fn: ScenarioHookFn | PlainHookFn;
149
+ }
150
+ /**
151
+ * Collection of registered hooks. Like {@link StepRegistry}, a plain instance
152
+ * (not a hidden global) so tests can isolate; `globalHookRegistry` is the
153
+ * default sink the public `beforeScenario`/`afterAll`/etc helpers write to.
154
+ */
155
+ declare class HookRegistry {
156
+ private hooks;
157
+ add(hook: RegisteredHook): void;
158
+ /**
159
+ * Hooks for a scope+timing. `before` hooks run in registration order;
160
+ * `after` hooks run in reverse (LIFO), so teardown unwinds setup.
161
+ */
162
+ for(scope: HookScope, timing: HookTiming): RegisteredHook[];
163
+ clear(): void;
164
+ }
165
+ declare const globalHookRegistry: HookRegistry;
166
+ /**
167
+ * Run every registered feature/global hook of a scope+timing in order. Used by
168
+ * the generated test modules (feature hooks). Throws if a hook throws, so the
169
+ * runner reports it against the enclosing boundary.
170
+ */
171
+ declare function runHooks(scope: "feature" | "global", timing: HookTiming, registry?: HookRegistry): Promise<void>;
172
+ /**
173
+ * Run global before-hooks once per worker, ahead of that worker's first
174
+ * scenario, and schedule global after-hooks for worker exit. Idempotent: every
175
+ * feature module calls this in a `beforeAll`, but only the first call in a given
176
+ * worker does anything.
177
+ *
178
+ * Semantics & caveats (the once-per-worker model):
179
+ * - Runs in the *same* realm as steps, so global setup may touch in-process
180
+ * state that steps later read.
181
+ * - "Once per worker", not strictly once per run — with multiple workers it runs
182
+ * in each. Size global setup to be worker-safe (e.g. a server per worker).
183
+ * - Teardown is best-effort: after-hooks start on the worker's `beforeExit` and
184
+ * are not awaited by the runner, so keep them fast/synchronous.
185
+ */
186
+ declare function ensureGlobalHooks(registry?: HookRegistry): Promise<void>;
187
+ //#endregion
188
+ export { numberParser as C, intParser as S, StepDefinitionMeta as _, RegisteredHook as a, Parser as b, ensureGlobalHooks as c, AnalysisRule as d, AnalyzerConfig as f, ParsedStep as g, ParsedScenario as h, PlainHookFn as i, globalHookRegistry as l, MatchedStep as m, HookScope as n, ScenarioHookFn as o, Diagnostic as p, HookTiming as r, ScenarioInfo as s, HookRegistry as t, runHooks as u, BasicWorld as v, stringParser as w, booleanParser as x, MergeableWorld as y };
189
+ //# sourceMappingURL=hooks-Dar49TtT.d.ts.map
@@ -0,0 +1,13 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_hooks = require("./hooks-CGYzwDOv.cjs");
3
+ const require_engine = require("./engine-DWAIlwWp.cjs");
4
+ exports.AmbiguousStepError = require_engine.AmbiguousStepError;
5
+ exports.HookRegistry = require_hooks.HookRegistry;
6
+ exports.StepRegistry = require_hooks.StepRegistry;
7
+ exports.UndefinedStepError = require_engine.UndefinedStepError;
8
+ exports.compileRegistry = require_engine.compileRegistry;
9
+ exports.ensureGlobalHooks = require_hooks.ensureGlobalHooks;
10
+ exports.globalHookRegistry = require_hooks.globalHookRegistry;
11
+ exports.globalRegistry = require_hooks.globalRegistry;
12
+ exports.runHooks = require_hooks.runHooks;
13
+ exports.runScenario = require_engine.runScenario;
@@ -0,0 +1,142 @@
1
+ import { a as RegisteredHook, b as Parser, c as ensureGlobalHooks, g as ParsedStep, h as ParsedScenario, i as PlainHookFn, l as globalHookRegistry, n as HookScope, o as ScenarioHookFn, r as HookTiming, s as ScenarioInfo, t as HookRegistry, u as runHooks, y as MergeableWorld } from "./hooks-Dar49TtT.cjs";
2
+ import { CucumberExpression } from "@cucumber/cucumber-expressions";
3
+
4
+ //#region src/runtime/registry.d.ts
5
+ type StepType = "given" | "when" | "then";
6
+ /**
7
+ * A step definition as it exists at *runtime*, independent of any test runner.
8
+ *
9
+ * `execute` is the fully-wired step body: given a world and the raw values
10
+ * captured from a Gherkin step, it applies parsers, validates + narrows
11
+ * dependencies, runs the user's step function, and merges the result back into
12
+ * the world. The engine never needs to know how any of that works — it just
13
+ * matches text to a step and calls `execute`.
14
+ */
15
+ interface RegisteredStep {
16
+ stepType: StepType;
17
+ /** The Cucumber-expression source, e.g. `a user named {string}`. */
18
+ expression: string;
19
+ /** Parsers, one per captured variable, applied after expression capture. */
20
+ parsers: Parser<any>[];
21
+ execute: (world: MergeableWorld<any, any, any>, capturedArgs: unknown[]) => Promise<void>;
22
+ /** Where the step was defined, for ambiguous-match diagnostics. */
23
+ source?: string;
24
+ }
25
+ /**
26
+ * A collection of registered steps. Deliberately a plain instance (not a hidden
27
+ * module global) so tests and the Vitest plugin can create isolated registries.
28
+ * `globalRegistry` is the default sink that `.step()` writes to.
29
+ */
30
+ declare class StepRegistry {
31
+ private steps;
32
+ add(step: RegisteredStep): void;
33
+ all(): readonly RegisteredStep[];
34
+ clear(): void;
35
+ }
36
+ declare const globalRegistry: StepRegistry;
37
+ //#endregion
38
+ //#region src/runtime/engine.d.ts
39
+ /** A registered step paired with its compiled Cucumber expression. */
40
+ interface CompiledStep {
41
+ step: RegisteredStep;
42
+ expression: CucumberExpression;
43
+ }
44
+ declare class UndefinedStepError extends Error {
45
+ readonly step: ParsedStep;
46
+ constructor(step: ParsedStep);
47
+ }
48
+ declare class AmbiguousStepError extends Error {
49
+ readonly step: ParsedStep;
50
+ readonly matches: RegisteredStep[];
51
+ constructor(step: ParsedStep, matches: RegisteredStep[]);
52
+ }
53
+ /**
54
+ * Compile a registry's steps into matchable Cucumber expressions **once** per
55
+ * run. The result is reused for every scenario — compilation is pure and depends
56
+ * only on the registry, so recompiling per scenario (as an earlier version did)
57
+ * was wasted work proportional to scenarios × steps.
58
+ */
59
+ declare function compileRegistry(registry: StepRegistry): CompiledStep[];
60
+ interface StepResult {
61
+ step: ParsedStep;
62
+ status: "passed" | "failed" | "skipped";
63
+ error?: Error;
64
+ durationMs?: number;
65
+ }
66
+ interface ScenarioResult {
67
+ scenario: ParsedScenario;
68
+ status: "passed" | "failed";
69
+ steps: StepResult[];
70
+ /**
71
+ * The scenario's first error, if it failed. Usually the same object as the
72
+ * failing step's `error` (with a synthetic `.feature` stack frame attached),
73
+ * but for a hook failure there's no step to point at, so this is the only
74
+ * place it surfaces. Reporters read this; the runner never throws it.
75
+ */
76
+ error?: Error;
77
+ /** Wall-clock duration of the whole scenario, in milliseconds. */
78
+ durationMs?: number;
79
+ }
80
+ /**
81
+ * Run one scenario against a pre-compiled step table. A fresh world is created
82
+ * per scenario (state never leaks between scenarios). On the first failing step
83
+ * the remaining steps are marked skipped, matching Cucumber's execution
84
+ * semantics.
85
+ *
86
+ * Never throws for step or hook failures: it always resolves to a
87
+ * `ScenarioResult` carrying the per-step breakdown and (on failure) the first
88
+ * `error` with a synthetic `.feature` stack frame attached. Callers decide what
89
+ * to do with a failure — the CLI runner reports it, a test-runner adapter can
90
+ * re-throw `result.error`. It still rejects for truly exceptional conditions
91
+ * (e.g. a bug in the engine itself), never for a normal test failure.
92
+ *
93
+ * Pass the compiled table from {@link compileRegistry} once and reuse it across
94
+ * every scenario in the run.
95
+ */
96
+ declare function runScenario(scenario: ParsedScenario, compiled: CompiledStep[], makeWorld: () => MergeableWorld<any, any, any>, hooks?: HookRegistry): Promise<ScenarioResult>;
97
+ //#endregion
98
+ //#region src/runtime/config.d.ts
99
+ /**
100
+ * User-facing runner configuration. The same shape is accepted from a
101
+ * `step-forge.config.ts` file (default export) and from CLI flags, with flags
102
+ * taking precedence. Everything is optional; {@link resolveConfig} fills in
103
+ * defaults.
104
+ */
105
+ interface RunnerOptions {
106
+ /** Feature-file glob(s), relative to `cwd`. Defaults to every `.feature` file. */
107
+ features?: string | string[];
108
+ /** Step-module glob(s), relative to `cwd`. Defaults to every `.steps.ts` file. */
109
+ steps?: string | string[];
110
+ /**
111
+ * Module that default-exports a world factory `() => world`, relative to
112
+ * `cwd`. When omitted each scenario gets a fresh `BasicWorld`.
113
+ */
114
+ world?: string;
115
+ /**
116
+ * Max scenarios in flight at once. Defaults to `1` (serial), matching
117
+ * Cucumber's default execution model — scenarios often share module-level
118
+ * state via hooks, which only holds under serial execution. Raise it to opt
119
+ * into parallelism for isolated, I/O-bound suites.
120
+ */
121
+ concurrency?: number;
122
+ /** Reporter name. Default `pretty`. */
123
+ reporter?: "pretty" | "progress";
124
+ /** Only run scenarios whose name matches this (string → substring/regex). */
125
+ name?: string;
126
+ /** Cucumber tag expression, e.g. `@smoke and not @wip`. */
127
+ tags?: string;
128
+ }
129
+ /** Fully-resolved config: no optionals, globs kept as arrays, paths absolute. */
130
+ interface ResolvedConfig {
131
+ cwd: string;
132
+ features: string[];
133
+ steps: string[];
134
+ world?: string;
135
+ concurrency: number;
136
+ reporter: "pretty" | "progress";
137
+ name?: string;
138
+ tags?: string;
139
+ }
140
+ //#endregion
141
+ export { AmbiguousStepError, type CompiledStep, HookRegistry, type HookScope, type HookTiming, type PlainHookFn, type RegisteredHook, type RegisteredStep, type ResolvedConfig, type RunnerOptions, type ScenarioHookFn, type ScenarioInfo, type ScenarioResult, StepRegistry, type StepResult, type StepType, UndefinedStepError, compileRegistry, ensureGlobalHooks, globalHookRegistry, globalRegistry, runHooks, runScenario };
142
+ //# sourceMappingURL=runtime.d.cts.map
@@ -0,0 +1,142 @@
1
+ import { a as RegisteredHook, b as Parser, c as ensureGlobalHooks, g as ParsedStep, h as ParsedScenario, i as PlainHookFn, l as globalHookRegistry, n as HookScope, o as ScenarioHookFn, r as HookTiming, s as ScenarioInfo, t as HookRegistry, u as runHooks, y as MergeableWorld } from "./hooks-Dar49TtT.js";
2
+ import { CucumberExpression } from "@cucumber/cucumber-expressions";
3
+
4
+ //#region src/runtime/registry.d.ts
5
+ type StepType = "given" | "when" | "then";
6
+ /**
7
+ * A step definition as it exists at *runtime*, independent of any test runner.
8
+ *
9
+ * `execute` is the fully-wired step body: given a world and the raw values
10
+ * captured from a Gherkin step, it applies parsers, validates + narrows
11
+ * dependencies, runs the user's step function, and merges the result back into
12
+ * the world. The engine never needs to know how any of that works — it just
13
+ * matches text to a step and calls `execute`.
14
+ */
15
+ interface RegisteredStep {
16
+ stepType: StepType;
17
+ /** The Cucumber-expression source, e.g. `a user named {string}`. */
18
+ expression: string;
19
+ /** Parsers, one per captured variable, applied after expression capture. */
20
+ parsers: Parser<any>[];
21
+ execute: (world: MergeableWorld<any, any, any>, capturedArgs: unknown[]) => Promise<void>;
22
+ /** Where the step was defined, for ambiguous-match diagnostics. */
23
+ source?: string;
24
+ }
25
+ /**
26
+ * A collection of registered steps. Deliberately a plain instance (not a hidden
27
+ * module global) so tests and the Vitest plugin can create isolated registries.
28
+ * `globalRegistry` is the default sink that `.step()` writes to.
29
+ */
30
+ declare class StepRegistry {
31
+ private steps;
32
+ add(step: RegisteredStep): void;
33
+ all(): readonly RegisteredStep[];
34
+ clear(): void;
35
+ }
36
+ declare const globalRegistry: StepRegistry;
37
+ //#endregion
38
+ //#region src/runtime/engine.d.ts
39
+ /** A registered step paired with its compiled Cucumber expression. */
40
+ interface CompiledStep {
41
+ step: RegisteredStep;
42
+ expression: CucumberExpression;
43
+ }
44
+ declare class UndefinedStepError extends Error {
45
+ readonly step: ParsedStep;
46
+ constructor(step: ParsedStep);
47
+ }
48
+ declare class AmbiguousStepError extends Error {
49
+ readonly step: ParsedStep;
50
+ readonly matches: RegisteredStep[];
51
+ constructor(step: ParsedStep, matches: RegisteredStep[]);
52
+ }
53
+ /**
54
+ * Compile a registry's steps into matchable Cucumber expressions **once** per
55
+ * run. The result is reused for every scenario — compilation is pure and depends
56
+ * only on the registry, so recompiling per scenario (as an earlier version did)
57
+ * was wasted work proportional to scenarios × steps.
58
+ */
59
+ declare function compileRegistry(registry: StepRegistry): CompiledStep[];
60
+ interface StepResult {
61
+ step: ParsedStep;
62
+ status: "passed" | "failed" | "skipped";
63
+ error?: Error;
64
+ durationMs?: number;
65
+ }
66
+ interface ScenarioResult {
67
+ scenario: ParsedScenario;
68
+ status: "passed" | "failed";
69
+ steps: StepResult[];
70
+ /**
71
+ * The scenario's first error, if it failed. Usually the same object as the
72
+ * failing step's `error` (with a synthetic `.feature` stack frame attached),
73
+ * but for a hook failure there's no step to point at, so this is the only
74
+ * place it surfaces. Reporters read this; the runner never throws it.
75
+ */
76
+ error?: Error;
77
+ /** Wall-clock duration of the whole scenario, in milliseconds. */
78
+ durationMs?: number;
79
+ }
80
+ /**
81
+ * Run one scenario against a pre-compiled step table. A fresh world is created
82
+ * per scenario (state never leaks between scenarios). On the first failing step
83
+ * the remaining steps are marked skipped, matching Cucumber's execution
84
+ * semantics.
85
+ *
86
+ * Never throws for step or hook failures: it always resolves to a
87
+ * `ScenarioResult` carrying the per-step breakdown and (on failure) the first
88
+ * `error` with a synthetic `.feature` stack frame attached. Callers decide what
89
+ * to do with a failure — the CLI runner reports it, a test-runner adapter can
90
+ * re-throw `result.error`. It still rejects for truly exceptional conditions
91
+ * (e.g. a bug in the engine itself), never for a normal test failure.
92
+ *
93
+ * Pass the compiled table from {@link compileRegistry} once and reuse it across
94
+ * every scenario in the run.
95
+ */
96
+ declare function runScenario(scenario: ParsedScenario, compiled: CompiledStep[], makeWorld: () => MergeableWorld<any, any, any>, hooks?: HookRegistry): Promise<ScenarioResult>;
97
+ //#endregion
98
+ //#region src/runtime/config.d.ts
99
+ /**
100
+ * User-facing runner configuration. The same shape is accepted from a
101
+ * `step-forge.config.ts` file (default export) and from CLI flags, with flags
102
+ * taking precedence. Everything is optional; {@link resolveConfig} fills in
103
+ * defaults.
104
+ */
105
+ interface RunnerOptions {
106
+ /** Feature-file glob(s), relative to `cwd`. Defaults to every `.feature` file. */
107
+ features?: string | string[];
108
+ /** Step-module glob(s), relative to `cwd`. Defaults to every `.steps.ts` file. */
109
+ steps?: string | string[];
110
+ /**
111
+ * Module that default-exports a world factory `() => world`, relative to
112
+ * `cwd`. When omitted each scenario gets a fresh `BasicWorld`.
113
+ */
114
+ world?: string;
115
+ /**
116
+ * Max scenarios in flight at once. Defaults to `1` (serial), matching
117
+ * Cucumber's default execution model — scenarios often share module-level
118
+ * state via hooks, which only holds under serial execution. Raise it to opt
119
+ * into parallelism for isolated, I/O-bound suites.
120
+ */
121
+ concurrency?: number;
122
+ /** Reporter name. Default `pretty`. */
123
+ reporter?: "pretty" | "progress";
124
+ /** Only run scenarios whose name matches this (string → substring/regex). */
125
+ name?: string;
126
+ /** Cucumber tag expression, e.g. `@smoke and not @wip`. */
127
+ tags?: string;
128
+ }
129
+ /** Fully-resolved config: no optionals, globs kept as arrays, paths absolute. */
130
+ interface ResolvedConfig {
131
+ cwd: string;
132
+ features: string[];
133
+ steps: string[];
134
+ world?: string;
135
+ concurrency: number;
136
+ reporter: "pretty" | "progress";
137
+ name?: string;
138
+ tags?: string;
139
+ }
140
+ //#endregion
141
+ export { AmbiguousStepError, type CompiledStep, HookRegistry, type HookScope, type HookTiming, type PlainHookFn, type RegisteredHook, type RegisteredStep, type ResolvedConfig, type RunnerOptions, type ScenarioHookFn, type ScenarioInfo, type ScenarioResult, StepRegistry, type StepResult, type StepType, UndefinedStepError, compileRegistry, ensureGlobalHooks, globalHookRegistry, globalRegistry, runHooks, runScenario };
142
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1,3 @@
1
+ import { a as StepRegistry, i as runHooks, n as ensureGlobalHooks, o as globalRegistry, r as globalHookRegistry, t as HookRegistry } from "./hooks-CywugMQQ.js";
2
+ import { i as runScenario, n as UndefinedStepError, r as compileRegistry, t as AmbiguousStepError } from "./engine-DPRxs6eC.js";
3
+ export { AmbiguousStepError, HookRegistry, StepRegistry, UndefinedStepError, compileRegistry, ensureGlobalHooks, globalHookRegistry, globalRegistry, runHooks, runScenario };