@step-forge/step-forge 0.0.20 → 0.0.22
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/README.md +2 -0
- package/RUNTIME.md +242 -0
- package/dist/{analyzer-DJyJbU_V.js → analyzer-byS8yRrY.js} +202 -34
- package/dist/analyzer-byS8yRrY.js.map +1 -0
- package/dist/analyzer-cli.js +1 -1
- package/dist/analyzer.d.ts +2 -0
- package/dist/analyzer.js +1 -2
- package/dist/cli.cjs +525 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +526 -0
- package/dist/cli.js.map +1 -0
- package/dist/{hooks-Dar49TtT.d.ts → config-C7PCYgYy.d.cts} +65 -16
- package/dist/{hooks-Dar49TtT.d.cts → config-C7PCYgYy.d.ts} +65 -16
- package/dist/engine-DPVLEHBi.js +163 -0
- package/dist/engine-DPVLEHBi.js.map +1 -0
- package/dist/engine-vqA-eL_T.cjs +186 -0
- package/dist/engine-vqA-eL_T.cjs.map +1 -0
- package/dist/gherkinParser-BT40q_i3.cjs +338 -0
- package/dist/gherkinParser-BT40q_i3.cjs.map +1 -0
- package/dist/gherkinParser-NcttZgN4.js +259 -0
- package/dist/gherkinParser-NcttZgN4.js.map +1 -0
- package/dist/hooks-BDCMKeNq.js +71 -0
- package/dist/{hooks-CywugMQQ.js.map → hooks-BDCMKeNq.js.map} +1 -1
- package/dist/{hooks-CGYzwDOv.cjs → hooks-Be0cjULN.cjs} +20 -31
- package/dist/{hooks-CGYzwDOv.cjs.map → hooks-Be0cjULN.cjs.map} +1 -1
- package/dist/runtime.cjs +7 -162
- package/dist/runtime.d.cts +44 -8
- package/dist/runtime.d.ts +44 -8
- package/dist/runtime.js +3 -159
- package/dist/step-forge.cjs +73 -216
- package/dist/step-forge.cjs.map +1 -1
- package/dist/step-forge.d.cts +19 -10
- package/dist/step-forge.d.ts +19 -10
- package/dist/step-forge.js +67 -185
- package/dist/step-forge.js.map +1 -1
- package/package.json +12 -18
- package/dist/analyzer-DJyJbU_V.js.map +0 -1
- package/dist/gherkinParser-Dp2d7JNr.js +0 -116
- package/dist/gherkinParser-Dp2d7JNr.js.map +0 -1
- package/dist/hooks-CywugMQQ.js +0 -82
- package/dist/runtime.cjs.map +0 -1
- package/dist/runtime.js.map +0 -1
- package/dist/vitest.d.ts +0 -74
- package/dist/vitest.js +0 -136
- package/dist/vitest.js.map +0 -1
package/dist/step-forge.cjs
CHANGED
|
@@ -1,39 +1,10 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var __defProp = Object.defineProperty;
|
|
5
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
-
var __copyProps = (to, from, except, desc) => {
|
|
10
|
-
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
-
key = keys[i];
|
|
12
|
-
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
13
|
-
get: ((k) => from[k]).bind(null, key),
|
|
14
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
20
|
-
value: mod,
|
|
21
|
-
enumerable: true
|
|
22
|
-
}) : target, mod));
|
|
23
|
-
//#endregion
|
|
24
|
-
const require_hooks = require("./hooks-CGYzwDOv.cjs");
|
|
2
|
+
const require_gherkinParser = require("./gherkinParser-BT40q_i3.cjs");
|
|
3
|
+
const require_hooks = require("./hooks-Be0cjULN.cjs");
|
|
25
4
|
let lodash = require("lodash");
|
|
26
|
-
lodash = __toESM(lodash, 1);
|
|
27
|
-
let node_fs_promises = require("node:fs/promises");
|
|
28
|
-
let node_path = require("node:path");
|
|
29
|
-
node_path = __toESM(node_path, 1);
|
|
5
|
+
lodash = require_gherkinParser.__toESM(lodash, 1);
|
|
30
6
|
let typescript = require("typescript");
|
|
31
|
-
typescript = __toESM(typescript, 1);
|
|
32
|
-
let node_fs = require("node:fs");
|
|
33
|
-
node_fs = __toESM(node_fs, 1);
|
|
34
|
-
let _cucumber_gherkin = require("@cucumber/gherkin");
|
|
35
|
-
let _cucumber_messages = require("@cucumber/messages");
|
|
36
|
-
_cucumber_messages = __toESM(_cucumber_messages, 1);
|
|
7
|
+
typescript = require_gherkinParser.__toESM(typescript, 1);
|
|
37
8
|
//#region src/builderTypeUtils.ts
|
|
38
9
|
const isString = (statement) => typeof statement === "string";
|
|
39
10
|
//#endregion
|
|
@@ -146,11 +117,13 @@ const addStep = (statement, stepType, dependencies = {
|
|
|
146
117
|
});
|
|
147
118
|
world[stepType].merge({ ...result });
|
|
148
119
|
};
|
|
120
|
+
const source = require_gherkinParser.captureDefinitionSite();
|
|
149
121
|
require_hooks.globalRegistry.add({
|
|
150
122
|
stepType,
|
|
151
123
|
expression,
|
|
152
124
|
parsers,
|
|
153
|
-
execute
|
|
125
|
+
execute,
|
|
126
|
+
source
|
|
154
127
|
});
|
|
155
128
|
return {
|
|
156
129
|
statement,
|
|
@@ -224,42 +197,6 @@ const thenStatement = () => (statement) => {
|
|
|
224
197
|
};
|
|
225
198
|
const thenBuilder = () => ({ statement: thenStatement() });
|
|
226
199
|
//#endregion
|
|
227
|
-
//#region src/world.ts
|
|
228
|
-
function mergeCustomizer(objValue, srcValue) {
|
|
229
|
-
if (lodash.default.isArray(objValue)) return objValue.concat(srcValue);
|
|
230
|
-
else if (objValue && !lodash.default.isPlainObject(objValue) && objValue !== srcValue) throw new Error(`Merge would have destroyed previous value ${objValue} with ${srcValue}`);
|
|
231
|
-
return objValue;
|
|
232
|
-
}
|
|
233
|
-
var BasicWorld = class {
|
|
234
|
-
givenState = {};
|
|
235
|
-
whenState = {};
|
|
236
|
-
thenState = {};
|
|
237
|
-
get given() {
|
|
238
|
-
return {
|
|
239
|
-
...this.givenState,
|
|
240
|
-
merge: (newState) => {
|
|
241
|
-
this.givenState = lodash.default.merge({ ...this.givenState }, newState, mergeCustomizer);
|
|
242
|
-
}
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
get when() {
|
|
246
|
-
return {
|
|
247
|
-
...this.whenState,
|
|
248
|
-
merge: (newState) => {
|
|
249
|
-
this.whenState = lodash.default.merge({ ...this.whenState }, newState, mergeCustomizer);
|
|
250
|
-
}
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
get then() {
|
|
254
|
-
return {
|
|
255
|
-
...this.thenState,
|
|
256
|
-
merge: (newState) => {
|
|
257
|
-
this.thenState = lodash.default.merge({ ...this.thenState }, newState, mergeCustomizer);
|
|
258
|
-
}
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
};
|
|
262
|
-
//#endregion
|
|
263
200
|
//#region src/analyzer/stepExtractor.ts
|
|
264
201
|
const BUILDER_NAMES = {
|
|
265
202
|
givenBuilder: "given",
|
|
@@ -267,6 +204,21 @@ const BUILDER_NAMES = {
|
|
|
267
204
|
thenBuilder: "then"
|
|
268
205
|
};
|
|
269
206
|
function extractStepDefinitions(filePaths, tsConfigPath) {
|
|
207
|
+
const fast = extractWithSources(filePaths.map(parseSourceFile).filter((s) => s !== null), null);
|
|
208
|
+
if (!fast.needsChecker) return fast.results;
|
|
209
|
+
const program = typescript.default.createProgram(filePaths, resolveCompilerOptions(tsConfigPath));
|
|
210
|
+
const checker = program.getTypeChecker();
|
|
211
|
+
return extractWithSources(filePaths.map((fp) => program.getSourceFile(fp)).filter((s) => s !== void 0), checker).results;
|
|
212
|
+
}
|
|
213
|
+
/** Parse a single file into an AST with no type resolution. */
|
|
214
|
+
function parseSourceFile(filePath) {
|
|
215
|
+
const text = typescript.default.sys.readFile(filePath);
|
|
216
|
+
if (text === void 0) return null;
|
|
217
|
+
const scriptKind = filePath.endsWith(".tsx") ? typescript.default.ScriptKind.TSX : typescript.default.ScriptKind.TS;
|
|
218
|
+
return typescript.default.createSourceFile(filePath, text, typescript.default.ScriptTarget.ESNext, true, scriptKind);
|
|
219
|
+
}
|
|
220
|
+
/** Resolve compiler options from tsconfig (fallback to sane defaults). */
|
|
221
|
+
function resolveCompilerOptions(tsConfigPath) {
|
|
270
222
|
const configPath = tsConfigPath ?? typescript.default.findConfigFile(process.cwd(), typescript.default.sys.fileExists);
|
|
271
223
|
let compilerOptions = {
|
|
272
224
|
target: typescript.default.ScriptTarget.ESNext,
|
|
@@ -280,22 +232,25 @@ function extractStepDefinitions(filePaths, tsConfigPath) {
|
|
|
280
232
|
if (!configFile.error) compilerOptions = typescript.default.parseJsonConfigFileContent(configFile.config, typescript.default.sys, configPath.replace(/[/\\][^/\\]+$/, "")).options;
|
|
281
233
|
}
|
|
282
234
|
compilerOptions.noEmit = true;
|
|
283
|
-
|
|
284
|
-
|
|
235
|
+
return compilerOptions;
|
|
236
|
+
}
|
|
237
|
+
function extractWithSources(sources, checker) {
|
|
238
|
+
const ctx = {
|
|
239
|
+
checker,
|
|
240
|
+
needsChecker: false
|
|
241
|
+
};
|
|
285
242
|
const results = [];
|
|
286
|
-
for (const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
}
|
|
292
|
-
return results;
|
|
243
|
+
for (const sourceFile of sources) results.push(...extractFromSourceFile(sourceFile, ctx));
|
|
244
|
+
return {
|
|
245
|
+
results,
|
|
246
|
+
needsChecker: ctx.needsChecker
|
|
247
|
+
};
|
|
293
248
|
}
|
|
294
|
-
function extractFromSourceFile(sourceFile,
|
|
249
|
+
function extractFromSourceFile(sourceFile, ctx) {
|
|
295
250
|
const results = [];
|
|
296
251
|
function visit(node) {
|
|
297
252
|
if (typescript.default.isCallExpression(node) && typescript.default.isPropertyAccessExpression(node.expression) && node.expression.name.text === "step") {
|
|
298
|
-
const meta = extractFromRegisterCall(node, sourceFile,
|
|
253
|
+
const meta = extractFromRegisterCall(node, sourceFile, ctx);
|
|
299
254
|
if (meta) results.push(meta);
|
|
300
255
|
}
|
|
301
256
|
typescript.default.forEachChild(node, visit);
|
|
@@ -303,7 +258,7 @@ function extractFromSourceFile(sourceFile, checker) {
|
|
|
303
258
|
visit(sourceFile);
|
|
304
259
|
return results;
|
|
305
260
|
}
|
|
306
|
-
function extractFromRegisterCall(registerCall, sourceFile,
|
|
261
|
+
function extractFromRegisterCall(registerCall, sourceFile, ctx) {
|
|
307
262
|
const chain = collectCallChain(registerCall);
|
|
308
263
|
let stepType = null;
|
|
309
264
|
let expression = null;
|
|
@@ -318,7 +273,7 @@ function extractFromRegisterCall(registerCall, sourceFile, checker) {
|
|
|
318
273
|
if (!name) continue;
|
|
319
274
|
if (name === "register") continue;
|
|
320
275
|
if (name === "step") {
|
|
321
|
-
produces = extractProducedKeys(link,
|
|
276
|
+
produces = extractProducedKeys(link, ctx);
|
|
322
277
|
continue;
|
|
323
278
|
}
|
|
324
279
|
if (name === "dependencies") {
|
|
@@ -335,7 +290,7 @@ function extractFromRegisterCall(registerCall, sourceFile, checker) {
|
|
|
335
290
|
}
|
|
336
291
|
}
|
|
337
292
|
if (!stepType || !expression) {
|
|
338
|
-
const reExport = resolveReExportedCall(chain,
|
|
293
|
+
const reExport = resolveReExportedCall(chain, ctx);
|
|
339
294
|
if (reExport) {
|
|
340
295
|
if (!stepType) stepType = reExport.stepType;
|
|
341
296
|
if (!expression) expression = reExport.expression;
|
|
@@ -422,33 +377,37 @@ function extractDependencies(depsCall) {
|
|
|
422
377
|
}
|
|
423
378
|
return deps;
|
|
424
379
|
}
|
|
425
|
-
function extractProducedKeys(stepCall,
|
|
380
|
+
function extractProducedKeys(stepCall, ctx) {
|
|
426
381
|
const callback = stepCall.arguments[0];
|
|
427
382
|
if (!callback) return [];
|
|
428
|
-
if (typescript.default.isArrowFunction(callback) || typescript.default.isFunctionExpression(callback)) return extractProducedKeysFromCallback(callback,
|
|
383
|
+
if (typescript.default.isArrowFunction(callback) || typescript.default.isFunctionExpression(callback)) return extractProducedKeysFromCallback(callback, ctx);
|
|
429
384
|
return [];
|
|
430
385
|
}
|
|
431
|
-
function extractProducedKeysFromCallback(callback,
|
|
386
|
+
function extractProducedKeysFromCallback(callback, ctx) {
|
|
432
387
|
const body = callback.body;
|
|
433
|
-
if (!typescript.default.isBlock(body)) return extractKeysFromExpression(body,
|
|
388
|
+
if (!typescript.default.isBlock(body)) return extractKeysFromExpression(body, ctx);
|
|
434
389
|
const keys = /* @__PURE__ */ new Set();
|
|
435
390
|
function visitReturn(node) {
|
|
436
|
-
if (typescript.default.isReturnStatement(node) && node.expression) for (const key of extractKeysFromExpression(node.expression,
|
|
391
|
+
if (typescript.default.isReturnStatement(node) && node.expression) for (const key of extractKeysFromExpression(node.expression, ctx)) keys.add(key);
|
|
437
392
|
typescript.default.forEachChild(node, visitReturn);
|
|
438
393
|
}
|
|
439
394
|
visitReturn(body);
|
|
440
395
|
return [...keys];
|
|
441
396
|
}
|
|
442
|
-
function extractKeysFromExpression(expr,
|
|
397
|
+
function extractKeysFromExpression(expr, ctx) {
|
|
443
398
|
while (typescript.default.isParenthesizedExpression(expr)) expr = expr.expression;
|
|
444
399
|
if (typescript.default.isObjectLiteralExpression(expr)) return expr.properties.filter((p) => typescript.default.isPropertyAssignment(p) || typescript.default.isShorthandPropertyAssignment(p)).map((p) => p.name.getText()).filter(Boolean);
|
|
400
|
+
if (!ctx.checker) {
|
|
401
|
+
ctx.needsChecker = true;
|
|
402
|
+
return [];
|
|
403
|
+
}
|
|
445
404
|
try {
|
|
446
|
-
return checker.getTypeAtLocation(expr).getProperties().map((p) => p.name).filter((n) => n !== "merge");
|
|
405
|
+
return ctx.checker.getTypeAtLocation(expr).getProperties().map((p) => p.name).filter((n) => n !== "merge");
|
|
447
406
|
} catch {
|
|
448
407
|
return [];
|
|
449
408
|
}
|
|
450
409
|
}
|
|
451
|
-
function resolveReExportedCall(chain,
|
|
410
|
+
function resolveReExportedCall(chain, ctx) {
|
|
452
411
|
const lastCall = chain[chain.length - 1];
|
|
453
412
|
if (!lastCall) return null;
|
|
454
413
|
const expr = lastCall.expression;
|
|
@@ -456,7 +415,11 @@ function resolveReExportedCall(chain, checker) {
|
|
|
456
415
|
if (typescript.default.isIdentifier(expr)) identifier = expr;
|
|
457
416
|
else if (typescript.default.isPropertyAccessExpression(expr) && typescript.default.isIdentifier(expr.expression)) identifier = expr.expression;
|
|
458
417
|
if (!identifier) return null;
|
|
459
|
-
|
|
418
|
+
if (!ctx.checker) {
|
|
419
|
+
ctx.needsChecker = true;
|
|
420
|
+
return null;
|
|
421
|
+
}
|
|
422
|
+
const symbol = ctx.checker.getSymbolAtLocation(identifier);
|
|
460
423
|
if (!symbol) return null;
|
|
461
424
|
const decl = symbol.valueDeclaration;
|
|
462
425
|
if (!decl || !typescript.default.isVariableDeclaration(decl) || !decl.initializer) return null;
|
|
@@ -477,116 +440,6 @@ function resolveReExportedCall(chain, checker) {
|
|
|
477
440
|
return null;
|
|
478
441
|
}
|
|
479
442
|
//#endregion
|
|
480
|
-
//#region src/analyzer/gherkinParser.ts
|
|
481
|
-
function parseFeatureFiles(filePaths) {
|
|
482
|
-
const scenarios = [];
|
|
483
|
-
for (const filePath of filePaths) {
|
|
484
|
-
const parsed = parseFeatureContent(node_fs.readFileSync(filePath, "utf-8"), filePath);
|
|
485
|
-
scenarios.push(...parsed);
|
|
486
|
-
}
|
|
487
|
-
return scenarios;
|
|
488
|
-
}
|
|
489
|
-
function parseFeatureContent(content, filePath) {
|
|
490
|
-
const feature = new _cucumber_gherkin.Parser(new _cucumber_gherkin.AstBuilder(_cucumber_messages.IdGenerator.uuid()), new _cucumber_gherkin.GherkinClassicTokenMatcher()).parse(content).feature;
|
|
491
|
-
if (!feature) return [];
|
|
492
|
-
const featureBackground = [];
|
|
493
|
-
const scenarios = [];
|
|
494
|
-
const featureTags = tagNames(feature.tags);
|
|
495
|
-
for (const child of feature.children) {
|
|
496
|
-
if (child.background) featureBackground.push(...child.background.steps);
|
|
497
|
-
if (child.scenario) scenarios.push(...expandScenario(child.scenario, featureBackground, filePath, featureTags));
|
|
498
|
-
if (child.rule) {
|
|
499
|
-
const ruleBackground = [...featureBackground];
|
|
500
|
-
const ruleTags = [...featureTags, ...tagNames(child.rule.tags)];
|
|
501
|
-
for (const ruleChild of child.rule.children) {
|
|
502
|
-
if (ruleChild.background) ruleBackground.push(...ruleChild.background.steps);
|
|
503
|
-
if (ruleChild.scenario) scenarios.push(...expandScenario(ruleChild.scenario, ruleBackground, filePath, ruleTags));
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
return scenarios;
|
|
508
|
-
}
|
|
509
|
-
/** Extract tag names (each keeping its leading `@`), deduped in order. */
|
|
510
|
-
function tagNames(tags) {
|
|
511
|
-
return [...new Set((tags ?? []).map((t) => t.name))];
|
|
512
|
-
}
|
|
513
|
-
function expandScenario(scenario, backgroundSteps, filePath, inheritedTags) {
|
|
514
|
-
const scenarioTags = [...inheritedTags, ...tagNames(scenario.tags)];
|
|
515
|
-
if (!(scenario.examples.length > 0 && scenario.examples.some((e) => e.tableBody.length > 0))) {
|
|
516
|
-
const bgParsed = convertSteps(backgroundSteps);
|
|
517
|
-
const scenarioParsed = convertSteps(scenario.steps);
|
|
518
|
-
const allSteps = resolveEffectiveKeywords([...bgParsed, ...scenarioParsed]);
|
|
519
|
-
return [{
|
|
520
|
-
name: scenario.name,
|
|
521
|
-
file: filePath,
|
|
522
|
-
steps: allSteps,
|
|
523
|
-
tags: scenarioTags
|
|
524
|
-
}];
|
|
525
|
-
}
|
|
526
|
-
const results = [];
|
|
527
|
-
for (const example of scenario.examples) {
|
|
528
|
-
if (!example.tableHeader || example.tableBody.length === 0) continue;
|
|
529
|
-
const headers = example.tableHeader.cells.map((c) => c.value);
|
|
530
|
-
const exampleTags = [...scenarioTags, ...tagNames(example.tags)];
|
|
531
|
-
for (const row of example.tableBody) {
|
|
532
|
-
const values = row.cells.map((c) => c.value);
|
|
533
|
-
const substitution = {};
|
|
534
|
-
headers.forEach((h, i) => {
|
|
535
|
-
substitution[h] = values[i];
|
|
536
|
-
});
|
|
537
|
-
const bgParsed = convertSteps(backgroundSteps);
|
|
538
|
-
const scenarioSteps = convertSteps(scenario.steps).map((step) => ({
|
|
539
|
-
...step,
|
|
540
|
-
text: substituteExampleValues(step.text, substitution)
|
|
541
|
-
}));
|
|
542
|
-
const allSteps = resolveEffectiveKeywords([...bgParsed, ...scenarioSteps]);
|
|
543
|
-
results.push({
|
|
544
|
-
name: headers.map((h, i) => `${h}=${values[i]}`).join(", "),
|
|
545
|
-
file: filePath,
|
|
546
|
-
steps: allSteps,
|
|
547
|
-
tags: exampleTags,
|
|
548
|
-
outline: { name: scenario.name }
|
|
549
|
-
});
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
return results;
|
|
553
|
-
}
|
|
554
|
-
function convertSteps(steps) {
|
|
555
|
-
return steps.map((step) => ({
|
|
556
|
-
keyword: normalizeKeyword(step.keyword),
|
|
557
|
-
text: step.text,
|
|
558
|
-
line: step.location.line,
|
|
559
|
-
column: (step.location.column ?? 1) + step.keyword.length
|
|
560
|
-
}));
|
|
561
|
-
}
|
|
562
|
-
function normalizeKeyword(keyword) {
|
|
563
|
-
const trimmed = keyword.trim();
|
|
564
|
-
if (trimmed === "Given") return "Given";
|
|
565
|
-
if (trimmed === "When") return "When";
|
|
566
|
-
if (trimmed === "Then") return "Then";
|
|
567
|
-
if (trimmed === "And") return "And";
|
|
568
|
-
if (trimmed === "But") return "But";
|
|
569
|
-
return "Given";
|
|
570
|
-
}
|
|
571
|
-
function resolveEffectiveKeywords(steps) {
|
|
572
|
-
let lastEffective = "Given";
|
|
573
|
-
return steps.map((step) => {
|
|
574
|
-
let effectiveKeyword;
|
|
575
|
-
if (step.keyword === "And" || step.keyword === "But") effectiveKeyword = lastEffective;
|
|
576
|
-
else effectiveKeyword = step.keyword;
|
|
577
|
-
lastEffective = effectiveKeyword;
|
|
578
|
-
return {
|
|
579
|
-
...step,
|
|
580
|
-
effectiveKeyword
|
|
581
|
-
};
|
|
582
|
-
});
|
|
583
|
-
}
|
|
584
|
-
function substituteExampleValues(text, substitution) {
|
|
585
|
-
let result = text;
|
|
586
|
-
for (const [key, value] of Object.entries(substitution)) result = result.replace(new RegExp(`<${key}>`, "g"), value);
|
|
587
|
-
return result;
|
|
588
|
-
}
|
|
589
|
-
//#endregion
|
|
590
443
|
//#region src/analyzer/stepMatcher.ts
|
|
591
444
|
function compileDefinitions(definitions) {
|
|
592
445
|
const compiled = [];
|
|
@@ -721,12 +574,12 @@ function runRules(rules, scenario, matchedSteps) {
|
|
|
721
574
|
//#region src/analyzer/index.ts
|
|
722
575
|
async function analyze(config, options) {
|
|
723
576
|
const rules = options?.rules ?? defaultRules;
|
|
724
|
-
const stepFilePaths = await
|
|
725
|
-
const featureFilePaths = await
|
|
577
|
+
const stepFilePaths = await require_gherkinParser.globFiles(config.stepFiles);
|
|
578
|
+
const featureFilePaths = await require_gherkinParser.globFiles(config.featureFiles);
|
|
726
579
|
if (stepFilePaths.length === 0) return [];
|
|
727
580
|
if (featureFilePaths.length === 0) return [];
|
|
728
581
|
const stepDefinitions = extractStepDefinitions(stepFilePaths, config.tsConfigPath);
|
|
729
|
-
const scenarios = parseFeatureFiles(featureFilePaths);
|
|
582
|
+
const scenarios = require_gherkinParser.parseFeatureFiles(featureFilePaths);
|
|
730
583
|
const diagnostics = [];
|
|
731
584
|
for (const scenario of scenarios) {
|
|
732
585
|
const scenarioDiags = runRules(rules, scenario, matchScenarioSteps(scenario, stepDefinitions));
|
|
@@ -734,11 +587,6 @@ async function analyze(config, options) {
|
|
|
734
587
|
}
|
|
735
588
|
return diagnostics;
|
|
736
589
|
}
|
|
737
|
-
async function resolveGlobs(patterns) {
|
|
738
|
-
const files = [];
|
|
739
|
-
for (const pattern of patterns) for await (const file of (0, node_fs_promises.glob)(pattern)) files.push(node_path.resolve(file));
|
|
740
|
-
return [...new Set(files)];
|
|
741
|
-
}
|
|
742
590
|
//#endregion
|
|
743
591
|
//#region src/init.ts
|
|
744
592
|
const createBuilders = () => {
|
|
@@ -791,7 +639,12 @@ function afterFeature(fn) {
|
|
|
791
639
|
fn
|
|
792
640
|
});
|
|
793
641
|
}
|
|
794
|
-
/**
|
|
642
|
+
/**
|
|
643
|
+
* Run once before the entire run, ahead of any scenario (and before
|
|
644
|
+
* concurrency starts). Multiple `beforeAll` hooks run **in parallel** with no
|
|
645
|
+
* ordering between them — if a step of setup must precede another, sequence both
|
|
646
|
+
* inside a single hook.
|
|
647
|
+
*/
|
|
795
648
|
function beforeAll(fn) {
|
|
796
649
|
require_hooks.globalHookRegistry.add({
|
|
797
650
|
scope: "global",
|
|
@@ -799,7 +652,11 @@ function beforeAll(fn) {
|
|
|
799
652
|
fn
|
|
800
653
|
});
|
|
801
654
|
}
|
|
802
|
-
/**
|
|
655
|
+
/**
|
|
656
|
+
* Run once after the entire run, once every scenario is done. Multiple
|
|
657
|
+
* `afterAll` hooks run **in parallel** with no ordering between them — sequence
|
|
658
|
+
* dependent teardown inside a single hook.
|
|
659
|
+
*/
|
|
803
660
|
function afterAll(fn) {
|
|
804
661
|
require_hooks.globalHookRegistry.add({
|
|
805
662
|
scope: "global",
|
|
@@ -812,14 +669,14 @@ function afterAll(fn) {
|
|
|
812
669
|
const analyzer = {
|
|
813
670
|
analyze,
|
|
814
671
|
extractStepDefinitions,
|
|
815
|
-
parseFeatureFiles,
|
|
816
|
-
parseFeatureContent,
|
|
672
|
+
parseFeatureFiles: require_gherkinParser.parseFeatureFiles,
|
|
673
|
+
parseFeatureContent: require_gherkinParser.parseFeatureContent,
|
|
817
674
|
matchScenarioSteps,
|
|
818
675
|
findMatchingDefinitions,
|
|
819
676
|
defaultRules
|
|
820
677
|
};
|
|
821
678
|
//#endregion
|
|
822
|
-
exports.BasicWorld = BasicWorld;
|
|
679
|
+
exports.BasicWorld = require_gherkinParser.BasicWorld;
|
|
823
680
|
exports.afterAll = afterAll;
|
|
824
681
|
exports.afterFeature = afterFeature;
|
|
825
682
|
exports.afterScenario = afterScenario;
|