@kraken-e2e/gherkin 0.1.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.
@@ -0,0 +1,114 @@
1
+ import { CucumberExpression, ParameterType, } from '@cucumber/cucumber-expressions';
2
+ import { KrakenError } from '@kraken-e2e/contracts';
3
+ import { createParameterTypeRegistry } from './parameter-types.js';
4
+ /** Ordered parameter names in an expression source ('{actor} sees {string}'). */
5
+ function parameterNames(source) {
6
+ return [...source.matchAll(/\{(\w+)\}/g)].map((match) => match[1] ?? '');
7
+ }
8
+ /** Survives duplicate copies of this package in one process (jiti + node_modules). */
9
+ export const STEP_REGISTRY_BRAND = Symbol.for('kraken.stepRegistry/v1');
10
+ export function isStepRegistry(value) {
11
+ return (typeof value === 'object' &&
12
+ value !== null &&
13
+ value[STEP_REGISTRY_BRAND] === true);
14
+ }
15
+ export class StepRegistry {
16
+ [STEP_REGISTRY_BRAND] = true;
17
+ #definitions = [];
18
+ #parameterTypes;
19
+ constructor() {
20
+ this.#parameterTypes = createParameterTypeRegistry();
21
+ }
22
+ define(expressionSource, options, handler, kind = 'step') {
23
+ const names = parameterNames(expressionSource);
24
+ const actorParameterIndex = names.indexOf('actor');
25
+ if (actorParameterIndex === -1) {
26
+ throw new KrakenError('KRK-STEP-UNKNOWN-ACTOR', `Step "${expressionSource}" has no {actor} parameter. Every Kraken step is addressed ` +
27
+ 'to exactly one actor (ADR-0004 D1).', { fix: "Start the expression with '{actor} …'." });
28
+ }
29
+ const expression = new CucumberExpression(expressionSource, this.#parameterTypes);
30
+ this.#definitions.push({
31
+ expressionSource,
32
+ expression,
33
+ options,
34
+ kind,
35
+ handler,
36
+ actorParameterIndex,
37
+ });
38
+ }
39
+ defineParameterType(options) {
40
+ this.#parameterTypes.defineParameterType(new ParameterType(options.name, options.regexp, null, options.transformer ?? ((value) => value), false, false));
41
+ }
42
+ get definitions() {
43
+ return this.#definitions;
44
+ }
45
+ /**
46
+ * Matches a pickle step's text. Zero matches → undefined (the compiler turns
47
+ * it into a STEP_UNMATCHED diagnostic); more than one → STEP_AMBIGUOUS error.
48
+ */
49
+ match(text) {
50
+ const matches = [];
51
+ for (const definition of this.#definitions) {
52
+ const matched = definition.expression.match(text);
53
+ if (!matched)
54
+ continue;
55
+ const values = matched.map((argument) => argument.getValue(null));
56
+ const actorName = String(values[definition.actorParameterIndex]);
57
+ const args = values.filter((_, index) => index !== definition.actorParameterIndex);
58
+ matches.push({ definition, actorName, args });
59
+ }
60
+ if (matches.length === 0)
61
+ return undefined;
62
+ if (matches.length > 1) {
63
+ throw new KrakenError('KRK-STEP-AMBIGUOUS', `Step "${text}" matches ${matches.length} definitions: ` +
64
+ matches.map((match) => `"${match.definition.expressionSource}"`).join(', '), { fix: 'Make the step expressions mutually exclusive.' });
65
+ }
66
+ return matches[0];
67
+ }
68
+ }
69
+ /**
70
+ * The step-authoring API (ADR-0004 D1). Instance-based — no import-order
71
+ * magic; destructure so call sites are bare identifiers, which is exactly what
72
+ * the Cucumber VS Code extension's tree-sitter queries recognize (appendix B):
73
+ *
74
+ * export const { Given, When, Then } = createStepRegistry();
75
+ */
76
+ export function createStepRegistry() {
77
+ const registry = new StepRegistry();
78
+ registerBuiltInSteps(registry);
79
+ const makeKeyword = () => (expression, optionsOrHandler, maybeHandler) => {
80
+ const options = typeof optionsOrHandler === 'function' ? {} : optionsOrHandler;
81
+ const handler = typeof optionsOrHandler === 'function' ? optionsOrHandler : maybeHandler;
82
+ if (!handler) {
83
+ throw new KrakenError('KRK-STEP-UNMATCHED', `Step "${expression}" has no handler.`);
84
+ }
85
+ registry.define(expression, options, handler, options.detached ? 'detach' : 'step');
86
+ };
87
+ return {
88
+ Given: makeKeyword(),
89
+ When: makeKeyword(),
90
+ Then: makeKeyword(),
91
+ defineParameterType: (options) => registry.defineParameterType(options),
92
+ registry,
93
+ };
94
+ }
95
+ /**
96
+ * Built-in choreography vocabulary (ADR-0004 D4) — deliberately minimal:
97
+ * signal waiting (v2 continuity) and background-task joining. App-domain
98
+ * steps belong to the USER's project, never here.
99
+ */
100
+ export function registerBuiltInSteps(registry) {
101
+ registry.define('{actor} waits for the signal {string} within {duration}', {}, async (ctx, ...args) => {
102
+ const [name, timeoutMs] = args;
103
+ await ctx.actor.signals.waitFor(name, { timeoutMs });
104
+ }, 'wait-signal');
105
+ registry.define('{actor} waits for the signal {string} from {actor} within {duration}', {}, async (ctx, ...args) => {
106
+ const [name, from, timeoutMs] = args;
107
+ await ctx.actor.signals.waitFor(name, { timeoutMs, from });
108
+ }, 'wait-signal');
109
+ registry.define("{actor}'s background task {string} completes within {duration}", {}, async () => {
110
+ // The scheduler performs the join (compiler emits a 'join' node);
111
+ // this handler never runs.
112
+ }, 'join');
113
+ }
114
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@kraken-e2e/gherkin",
3
+ "version": "0.1.0",
4
+ "description": "BDD front-end: .feature parsing (official Gherkin stack), typed step registry, scenario compiler, built-in choreography steps",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/index.d.ts",
9
+ "default": "./dist/index.js"
10
+ },
11
+ "./package.json": "./package.json"
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "LICENSE"
16
+ ],
17
+ "sideEffects": false,
18
+ "engines": {
19
+ "node": ">=22.13.0"
20
+ },
21
+ "dependencies": {
22
+ "@cucumber/cucumber-expressions": "^20.0.0",
23
+ "@cucumber/gherkin": "^41.0.0",
24
+ "@cucumber/messages": "^33.0.4",
25
+ "@cucumber/tag-expressions": "^10.0.0",
26
+ "@kraken-e2e/contracts": "0.1.0",
27
+ "@kraken-e2e/core": "0.1.0"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "^22.15.0",
31
+ "typescript": "~6.0.3",
32
+ "vitest": "^4.1.9"
33
+ },
34
+ "license": "GPL-3.0-only",
35
+ "scripts": {
36
+ "build": "tsc -p tsconfig.build.json",
37
+ "typecheck": "tsc --noEmit",
38
+ "test": "vitest run"
39
+ }
40
+ }