@autometa/executor 1.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,2409 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var path = require('path');
6
+ var url = require('url');
7
+ var cucumberExpressions = require('@cucumber/cucumber-expressions');
8
+ var events = require('@autometa/events');
9
+ var errors = require('@autometa/errors');
10
+ var gherkin = require('@autometa/gherkin');
11
+ var TagExpressions = require('@cucumber/tag-expressions');
12
+ var async_hooks = require('async_hooks');
13
+
14
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
15
+
16
+ function _interopNamespace(e) {
17
+ if (e && e.__esModule) return e;
18
+ var n = Object.create(null);
19
+ if (e) {
20
+ Object.keys(e).forEach(function (k) {
21
+ if (k !== 'default') {
22
+ var d = Object.getOwnPropertyDescriptor(e, k);
23
+ Object.defineProperty(n, k, d.get ? d : {
24
+ enumerable: true,
25
+ get: function () { return e[k]; }
26
+ });
27
+ }
28
+ });
29
+ }
30
+ n.default = e;
31
+ return Object.freeze(n);
32
+ }
33
+
34
+ var path__default = /*#__PURE__*/_interopDefault(path);
35
+ var TagExpressions__namespace = /*#__PURE__*/_interopNamespace(TagExpressions);
36
+
37
+ // src/timeouts.ts
38
+ var UNIT_TO_MILLISECONDS = {
39
+ ms: 1,
40
+ s: 1e3,
41
+ m: 6e4,
42
+ h: 36e5
43
+ };
44
+ var normalizeSpec = (spec) => {
45
+ if (spec === void 0 || spec === null) {
46
+ return void 0;
47
+ }
48
+ if (typeof spec === "number") {
49
+ return spec <= 0 ? void 0 : spec;
50
+ }
51
+ if (Array.isArray(spec)) {
52
+ const [value2, unit2] = spec;
53
+ if (typeof value2 !== "number" || value2 <= 0) {
54
+ return void 0;
55
+ }
56
+ const multiplier2 = UNIT_TO_MILLISECONDS[unit2] ?? 1;
57
+ return value2 * multiplier2;
58
+ }
59
+ if (typeof spec !== "object") {
60
+ return void 0;
61
+ }
62
+ const value = "duration" in spec ? spec.duration : spec.value;
63
+ if (typeof value !== "number" || value <= 0) {
64
+ return void 0;
65
+ }
66
+ const unit = "duration" in spec ? spec.unit : spec.unit;
67
+ if (!unit) {
68
+ return value;
69
+ }
70
+ const multiplier = UNIT_TO_MILLISECONDS[unit] ?? 1;
71
+ return value * multiplier;
72
+ };
73
+ var resolveTimeout = (explicit, config, explicitSource = "scenario") => {
74
+ const explicitMs = normalizeSpec(explicit);
75
+ if (explicitMs !== void 0) {
76
+ return { milliseconds: explicitMs, source: explicitSource };
77
+ }
78
+ const configMs = normalizeSpec(config.test?.timeout);
79
+ if (configMs !== void 0) {
80
+ return { milliseconds: configMs, source: "config" };
81
+ }
82
+ return { milliseconds: void 0, source: "default" };
83
+ };
84
+ var chooseTimeout = (primary, secondary, config) => {
85
+ const secondaryResolution = resolveTimeout(secondary, config, "hook");
86
+ if (secondaryResolution.milliseconds !== void 0) {
87
+ return secondaryResolution;
88
+ }
89
+ return resolveTimeout(primary, config, "scenario");
90
+ };
91
+
92
+ // src/hooks.ts
93
+ var EMPTY_COLLECTION = {
94
+ beforeFeature: [],
95
+ afterFeature: [],
96
+ beforeRule: [],
97
+ afterRule: [],
98
+ beforeScenario: [],
99
+ afterScenario: [],
100
+ beforeScenarioOutline: [],
101
+ afterScenarioOutline: [],
102
+ beforeStep: [],
103
+ afterStep: []
104
+ };
105
+ function collectScenarioHooks(adapter, execution) {
106
+ const scopes = buildScopeChain(adapter, execution);
107
+ if (scopes.length === 0) {
108
+ return EMPTY_COLLECTION;
109
+ }
110
+ const buckets = {
111
+ beforeFeature: [],
112
+ afterFeature: [],
113
+ beforeRule: [],
114
+ afterRule: [],
115
+ beforeScenario: [],
116
+ afterScenario: [],
117
+ beforeScenarioOutline: [],
118
+ afterScenarioOutline: [],
119
+ beforeStep: [],
120
+ afterStep: []
121
+ };
122
+ for (const scope of scopes) {
123
+ for (const hook of scope.hooks) {
124
+ addHookToBuckets(buckets, hook, scope);
125
+ }
126
+ }
127
+ return buckets;
128
+ }
129
+ function buildScopeChain(adapter, execution) {
130
+ const chain = [adapter.plan.root];
131
+ chain.push(...execution.ancestors);
132
+ chain.push(execution.scope);
133
+ return chain;
134
+ }
135
+ function addHookToBuckets(buckets, hook, scope) {
136
+ const entry = { hook, scope };
137
+ switch (hook.type) {
138
+ case "beforeFeature":
139
+ buckets.beforeFeature.push(entry);
140
+ break;
141
+ case "afterFeature":
142
+ buckets.afterFeature.push(entry);
143
+ break;
144
+ case "beforeRule":
145
+ buckets.beforeRule.push(entry);
146
+ break;
147
+ case "afterRule":
148
+ buckets.afterRule.push(entry);
149
+ break;
150
+ case "beforeScenario":
151
+ buckets.beforeScenario.push(entry);
152
+ break;
153
+ case "afterScenario":
154
+ buckets.afterScenario.push(entry);
155
+ break;
156
+ case "beforeScenarioOutline":
157
+ buckets.beforeScenarioOutline.push(entry);
158
+ break;
159
+ case "afterScenarioOutline":
160
+ buckets.afterScenarioOutline.push(entry);
161
+ break;
162
+ case "beforeStep":
163
+ buckets.beforeStep.push(entry);
164
+ break;
165
+ case "afterStep":
166
+ buckets.afterStep.push(entry);
167
+ break;
168
+ }
169
+ }
170
+ var DATA_TABLE_SYMBOL = Symbol.for(
171
+ "autometa:runner:step:data-table"
172
+ );
173
+ var DOCSTRING_SYMBOL = Symbol.for(
174
+ "autometa:runner:step:docstring"
175
+ );
176
+ var DOCSTRING_MEDIA_TYPE_SYMBOL = Symbol.for(
177
+ "autometa:runner:step:docstring:media-type"
178
+ );
179
+ var STEP_RUNTIME_SYMBOL = Symbol.for(
180
+ "autometa:runner:step:runtime"
181
+ );
182
+ var STEP_METADATA_SYMBOL = Symbol.for(
183
+ "autometa:runner:step:metadata"
184
+ );
185
+ var DEFAULT_CONFIG = { ...gherkin.DEFAULT_COERCE_BY_SHAPE };
186
+ var activeConfig = { ...DEFAULT_CONFIG };
187
+ var DEFAULT_DOCSTRING_CONFIG = { transformers: {} };
188
+ var activeDocstringConfig = { ...DEFAULT_DOCSTRING_CONFIG };
189
+ function isObjectLike(value) {
190
+ return typeof value === "object" && value !== null;
191
+ }
192
+ function cloneTable(source) {
193
+ return source.map((row) => [...row]);
194
+ }
195
+ function withCarrier(world) {
196
+ if (!isObjectLike(world)) {
197
+ return void 0;
198
+ }
199
+ return world;
200
+ }
201
+ function configureStepTables(config) {
202
+ if (config.coercePrimitives) {
203
+ activeConfig = {
204
+ ...activeConfig,
205
+ ...config.coercePrimitives
206
+ };
207
+ }
208
+ }
209
+ function resetStepTableConfig() {
210
+ activeConfig = { ...DEFAULT_CONFIG };
211
+ }
212
+ function setStepTable(world, table) {
213
+ const carrier = withCarrier(world);
214
+ if (!carrier) {
215
+ return;
216
+ }
217
+ if (!table) {
218
+ Reflect.deleteProperty(carrier, DATA_TABLE_SYMBOL);
219
+ return;
220
+ }
221
+ const cloned = cloneTable(table);
222
+ if (Object.prototype.hasOwnProperty.call(carrier, DATA_TABLE_SYMBOL)) {
223
+ carrier[DATA_TABLE_SYMBOL] = cloned;
224
+ } else {
225
+ Object.defineProperty(carrier, DATA_TABLE_SYMBOL, {
226
+ value: cloned,
227
+ writable: true,
228
+ configurable: true,
229
+ enumerable: false
230
+ });
231
+ }
232
+ }
233
+ function clearStepTable(world) {
234
+ const carrier = withCarrier(world);
235
+ if (!carrier) {
236
+ return;
237
+ }
238
+ Reflect.deleteProperty(carrier, DATA_TABLE_SYMBOL);
239
+ }
240
+ function setStepDocstring(world, docstring) {
241
+ const carrier = withCarrier(world);
242
+ if (!carrier) {
243
+ return;
244
+ }
245
+ if (docstring === void 0) {
246
+ Reflect.deleteProperty(carrier, DOCSTRING_SYMBOL);
247
+ Reflect.deleteProperty(carrier, DOCSTRING_MEDIA_TYPE_SYMBOL);
248
+ return;
249
+ }
250
+ if (Object.prototype.hasOwnProperty.call(carrier, DOCSTRING_SYMBOL)) {
251
+ carrier[DOCSTRING_SYMBOL] = docstring;
252
+ } else {
253
+ Object.defineProperty(carrier, DOCSTRING_SYMBOL, {
254
+ value: docstring,
255
+ writable: true,
256
+ configurable: true,
257
+ enumerable: false
258
+ });
259
+ }
260
+ Reflect.deleteProperty(carrier, DOCSTRING_MEDIA_TYPE_SYMBOL);
261
+ }
262
+ function setStepDocstringInfo(world, docstring) {
263
+ if (docstring === void 0) {
264
+ setStepDocstring(world, void 0);
265
+ return;
266
+ }
267
+ setStepDocstring(world, docstring.content);
268
+ const carrier = withCarrier(world);
269
+ if (!carrier) {
270
+ return;
271
+ }
272
+ const mediaType = docstring.mediaType;
273
+ if (mediaType === void 0) {
274
+ Reflect.deleteProperty(carrier, DOCSTRING_MEDIA_TYPE_SYMBOL);
275
+ return;
276
+ }
277
+ if (Object.prototype.hasOwnProperty.call(carrier, DOCSTRING_MEDIA_TYPE_SYMBOL)) {
278
+ carrier[DOCSTRING_MEDIA_TYPE_SYMBOL] = mediaType;
279
+ } else {
280
+ Object.defineProperty(carrier, DOCSTRING_MEDIA_TYPE_SYMBOL, {
281
+ value: mediaType,
282
+ writable: true,
283
+ configurable: true,
284
+ enumerable: false
285
+ });
286
+ }
287
+ }
288
+ function clearStepDocstring(world) {
289
+ const carrier = withCarrier(world);
290
+ if (!carrier) {
291
+ return;
292
+ }
293
+ Reflect.deleteProperty(carrier, DOCSTRING_SYMBOL);
294
+ Reflect.deleteProperty(carrier, DOCSTRING_MEDIA_TYPE_SYMBOL);
295
+ }
296
+ function setStepMetadata(world, metadata) {
297
+ const carrier = withCarrier(world);
298
+ if (!carrier) {
299
+ return;
300
+ }
301
+ if (!metadata) {
302
+ Reflect.deleteProperty(carrier, STEP_METADATA_SYMBOL);
303
+ return;
304
+ }
305
+ if (Object.prototype.hasOwnProperty.call(carrier, STEP_METADATA_SYMBOL)) {
306
+ carrier[STEP_METADATA_SYMBOL] = metadata;
307
+ } else {
308
+ Object.defineProperty(carrier, STEP_METADATA_SYMBOL, {
309
+ value: metadata,
310
+ writable: true,
311
+ configurable: true,
312
+ enumerable: false
313
+ });
314
+ }
315
+ }
316
+ function clearStepMetadata(world) {
317
+ const carrier = withCarrier(world);
318
+ if (!carrier) {
319
+ return;
320
+ }
321
+ Reflect.deleteProperty(carrier, STEP_METADATA_SYMBOL);
322
+ }
323
+ function getStepMetadata(world) {
324
+ const carrier = withCarrier(world);
325
+ return carrier?.[STEP_METADATA_SYMBOL];
326
+ }
327
+ function getDocstring(world) {
328
+ const carrier = withCarrier(world);
329
+ return carrier?.[DOCSTRING_SYMBOL];
330
+ }
331
+ function getDocstringMediaType(world) {
332
+ const carrier = withCarrier(world);
333
+ return carrier?.[DOCSTRING_MEDIA_TYPE_SYMBOL];
334
+ }
335
+ function getDocstringInfo(world) {
336
+ const content = getDocstring(world);
337
+ if (content === void 0) {
338
+ return void 0;
339
+ }
340
+ const mediaType = getDocstringMediaType(world);
341
+ if (mediaType === void 0) {
342
+ return { content };
343
+ }
344
+ return { content, mediaType };
345
+ }
346
+ function getRawTable(world) {
347
+ const carrier = withCarrier(world);
348
+ return carrier?.[DATA_TABLE_SYMBOL];
349
+ }
350
+ function getStepRuntimeFromWorld(world) {
351
+ const carrier = withCarrier(world);
352
+ return carrier?.[STEP_RUNTIME_SYMBOL];
353
+ }
354
+ function resolveCoerceOverride(shape, coerceOverride) {
355
+ if (typeof coerceOverride === "boolean") {
356
+ return coerceOverride;
357
+ }
358
+ return activeConfig[shape];
359
+ }
360
+ function getTable(world, shape, options) {
361
+ const table = getRawTable(world);
362
+ if (!table) {
363
+ return void 0;
364
+ }
365
+ const coerce = resolveCoerceOverride(shape, options?.coerce);
366
+ switch (shape) {
367
+ case "headerless":
368
+ return gherkin.createTable(table, "headerless", {
369
+ ...options,
370
+ coerce
371
+ });
372
+ case "horizontal":
373
+ return gherkin.createTable(table, "horizontal", {
374
+ ...options,
375
+ coerce
376
+ });
377
+ case "vertical":
378
+ return gherkin.createTable(table, "vertical", {
379
+ ...options,
380
+ coerce
381
+ });
382
+ case "matrix":
383
+ return gherkin.createTable(table, "matrix", {
384
+ ...options,
385
+ coerce
386
+ });
387
+ default:
388
+ return void 0;
389
+ }
390
+ }
391
+ function consumeTable(world, shape, options) {
392
+ let instance;
393
+ switch (shape) {
394
+ case "headerless":
395
+ instance = getTable(world, "headerless", options);
396
+ break;
397
+ case "horizontal":
398
+ instance = getTable(world, "horizontal", options);
399
+ break;
400
+ case "vertical":
401
+ instance = getTable(world, "vertical", options);
402
+ break;
403
+ case "matrix":
404
+ instance = getTable(world, "matrix", options);
405
+ break;
406
+ default:
407
+ instance = void 0;
408
+ }
409
+ clearStepTable(world);
410
+ return instance;
411
+ }
412
+ function consumeDocstring(world) {
413
+ const value = getDocstring(world);
414
+ clearStepDocstring(world);
415
+ return value;
416
+ }
417
+ function normalizeDocstringMediaType(mediaType) {
418
+ if (!mediaType) {
419
+ return void 0;
420
+ }
421
+ const normalized = mediaType.trim();
422
+ if (!normalized) {
423
+ return void 0;
424
+ }
425
+ const [primary] = normalized.split(";", 1);
426
+ return primary?.trim().toLowerCase() || void 0;
427
+ }
428
+ function resolveDocstringTransformer(transformers, mediaType) {
429
+ const normalized = normalizeDocstringMediaType(mediaType);
430
+ if (!normalized) {
431
+ return void 0;
432
+ }
433
+ if (transformers[normalized]) {
434
+ return transformers[normalized];
435
+ }
436
+ const slashIndex = normalized.indexOf("/");
437
+ if (slashIndex !== -1) {
438
+ const subtype = normalized.slice(slashIndex + 1);
439
+ if (transformers[subtype]) {
440
+ return transformers[subtype];
441
+ }
442
+ const plusIndex = subtype.lastIndexOf("+");
443
+ if (plusIndex !== -1) {
444
+ const suffix = subtype.slice(plusIndex + 1);
445
+ if (transformers[`+${suffix}`]) {
446
+ return transformers[`+${suffix}`];
447
+ }
448
+ if (transformers[suffix]) {
449
+ return transformers[suffix];
450
+ }
451
+ }
452
+ }
453
+ return void 0;
454
+ }
455
+ function configureStepDocstrings(config) {
456
+ if (config.transformers) {
457
+ activeDocstringConfig = {
458
+ ...activeDocstringConfig,
459
+ transformers: {
460
+ ...activeDocstringConfig.transformers,
461
+ ...config.transformers
462
+ }
463
+ };
464
+ }
465
+ }
466
+ function resetStepDocstringConfig() {
467
+ activeDocstringConfig = { ...DEFAULT_DOCSTRING_CONFIG };
468
+ }
469
+ function bindGetTable(world) {
470
+ function getTable2(shape, options) {
471
+ switch (shape) {
472
+ case "headerless":
473
+ return getTableForShape(world, "headerless", options);
474
+ case "horizontal":
475
+ return getTableForShape(world, "horizontal", options);
476
+ case "vertical":
477
+ return getTableForShape(world, "vertical", options);
478
+ case "matrix":
479
+ return getTableForShape(world, "matrix", options);
480
+ default:
481
+ return void 0;
482
+ }
483
+ }
484
+ return getTable2;
485
+ }
486
+ function getTableForShape(world, shape, options) {
487
+ switch (shape) {
488
+ case "headerless":
489
+ return getTable(world, "headerless", options);
490
+ case "horizontal":
491
+ return getTable(world, "horizontal", options);
492
+ case "vertical":
493
+ return getTable(world, "vertical", options);
494
+ case "matrix":
495
+ return getTable(world, "matrix", options);
496
+ default:
497
+ return void 0;
498
+ }
499
+ }
500
+ function bindConsumeTable(world) {
501
+ function consume(shape, options) {
502
+ switch (shape) {
503
+ case "headerless":
504
+ return consumeTable(world, "headerless", options);
505
+ case "horizontal":
506
+ return consumeTable(world, "horizontal", options);
507
+ case "vertical":
508
+ return consumeTable(world, "vertical", options);
509
+ case "matrix":
510
+ return consumeTable(world, "matrix", options);
511
+ default:
512
+ return void 0;
513
+ }
514
+ }
515
+ return consume;
516
+ }
517
+ function bindRequireTable(world) {
518
+ function require2(shape, options) {
519
+ switch (shape) {
520
+ case "headerless": {
521
+ const table = consumeTable(
522
+ world,
523
+ "headerless",
524
+ options
525
+ );
526
+ if (!table) {
527
+ throw new RangeError("No headerless data table is attached to the current step.");
528
+ }
529
+ return table;
530
+ }
531
+ case "horizontal": {
532
+ const table = consumeTable(
533
+ world,
534
+ "horizontal",
535
+ options
536
+ );
537
+ if (!table) {
538
+ throw new RangeError("No horizontal data table is attached to the current step.");
539
+ }
540
+ return table;
541
+ }
542
+ case "vertical": {
543
+ const table = consumeTable(
544
+ world,
545
+ "vertical",
546
+ options
547
+ );
548
+ if (!table) {
549
+ throw new RangeError("No vertical data table is attached to the current step.");
550
+ }
551
+ return table;
552
+ }
553
+ case "matrix": {
554
+ const table = consumeTable(
555
+ world,
556
+ "matrix",
557
+ options
558
+ );
559
+ if (!table) {
560
+ throw new RangeError("No matrix data table is attached to the current step.");
561
+ }
562
+ return table;
563
+ }
564
+ default:
565
+ throw new RangeError(`Unsupported table shape: ${String(shape)}`);
566
+ }
567
+ }
568
+ return require2;
569
+ }
570
+ function cacheRuntime(world, runtime) {
571
+ const carrier = withCarrier(world);
572
+ if (!carrier) {
573
+ return;
574
+ }
575
+ if (!Object.prototype.hasOwnProperty.call(carrier, STEP_RUNTIME_SYMBOL)) {
576
+ Object.defineProperty(carrier, STEP_RUNTIME_SYMBOL, {
577
+ value: runtime,
578
+ writable: true,
579
+ configurable: true,
580
+ enumerable: false
581
+ });
582
+ } else {
583
+ carrier[STEP_RUNTIME_SYMBOL] = runtime;
584
+ }
585
+ if (!Object.prototype.hasOwnProperty.call(carrier, "runtime")) {
586
+ Object.defineProperty(carrier, "runtime", {
587
+ get() {
588
+ return carrier[STEP_RUNTIME_SYMBOL];
589
+ },
590
+ enumerable: false,
591
+ configurable: true
592
+ });
593
+ }
594
+ }
595
+ function createStepRuntime(world) {
596
+ const existing = getStepRuntimeFromWorld(world);
597
+ if (existing) {
598
+ return existing;
599
+ }
600
+ const getDocstringTransformed = (options) => {
601
+ const info = getDocstringInfo(world);
602
+ if (!info) {
603
+ return void 0;
604
+ }
605
+ const transformer = resolveDocstringTransformer(
606
+ activeDocstringConfig.transformers,
607
+ info.mediaType
608
+ );
609
+ if (!transformer) {
610
+ if (options?.fallback === "throw") {
611
+ const type = normalizeDocstringMediaType(info.mediaType) ?? "<unknown>";
612
+ throw new RangeError(
613
+ `No docstring transformer is configured for media type '${type}'.`
614
+ );
615
+ }
616
+ return info.content;
617
+ }
618
+ return transformer(
619
+ info.content,
620
+ info.mediaType === void 0 ? {} : { mediaType: info.mediaType }
621
+ );
622
+ };
623
+ const runtime = {
624
+ get hasTable() {
625
+ return getRawTable(world) !== void 0;
626
+ },
627
+ get hasDocstring() {
628
+ return getDocstring(world) !== void 0;
629
+ },
630
+ get currentStep() {
631
+ return getStepMetadata(world);
632
+ },
633
+ getTable: bindGetTable(world),
634
+ consumeTable: bindConsumeTable(world),
635
+ getRawTable() {
636
+ return getRawTable(world);
637
+ },
638
+ getDocstring() {
639
+ return getDocstring(world);
640
+ },
641
+ getDocstringMediaType() {
642
+ return getDocstringMediaType(world);
643
+ },
644
+ getDocstringInfo() {
645
+ return getDocstringInfo(world);
646
+ },
647
+ consumeDocstring() {
648
+ return consumeDocstring(world);
649
+ },
650
+ getDocstringTransformed,
651
+ consumeDocstringTransformed(options) {
652
+ const result = getDocstringTransformed(options);
653
+ clearStepDocstring(world);
654
+ return result;
655
+ },
656
+ getStepMetadata() {
657
+ return getStepMetadata(world);
658
+ },
659
+ requireTable: bindRequireTable(world)
660
+ };
661
+ cacheRuntime(world, runtime);
662
+ return runtime;
663
+ }
664
+
665
+ // src/pending.ts
666
+ var PENDING_SCENARIO_SYMBOL = Symbol("autometa:scenario:pending");
667
+ var _a;
668
+ var ScenarioPendingError = class extends Error {
669
+ constructor(reason) {
670
+ super(reason ? `Scenario pending: ${reason}` : "Scenario pending");
671
+ this[_a] = true;
672
+ this.name = "ScenarioPendingError";
673
+ if (reason !== void 0 && reason !== null) {
674
+ const trimmed = String(reason).trim();
675
+ if (trimmed.length > 0) {
676
+ this.reason = trimmed;
677
+ }
678
+ }
679
+ }
680
+ };
681
+ _a = PENDING_SCENARIO_SYMBOL;
682
+ function isScenarioPendingError(error) {
683
+ return typeof error === "object" && error !== null && error[PENDING_SCENARIO_SYMBOL] === true;
684
+ }
685
+ function createPendingError(reason) {
686
+ return new ScenarioPendingError(reason);
687
+ }
688
+ function Pending(reason) {
689
+ return function pendingStepHandler(world, ..._args) {
690
+ throw createPendingError(reason);
691
+ };
692
+ }
693
+ var ToDo = Pending;
694
+ function markScenarioPending(reason) {
695
+ throw createPendingError(reason);
696
+ }
697
+ function createFeatureRef(feature) {
698
+ return {
699
+ id: feature.id,
700
+ name: feature.name,
701
+ location: feature.location ?? { line: 1, column: 1 },
702
+ tags: feature.tags,
703
+ comments: feature.comments?.map((comment) => comment.text)
704
+ };
705
+ }
706
+ function createRuleRef(rule) {
707
+ return {
708
+ id: rule.id,
709
+ name: rule.name,
710
+ location: rule.location ?? { line: 1, column: 1 },
711
+ tags: rule.tags
712
+ };
713
+ }
714
+ function requirePickle(feature, scenarioId) {
715
+ const pickle = gherkin.generatePickleById(feature, scenarioId);
716
+ if (!pickle) {
717
+ throw new Error(
718
+ `Unable to generate pickle for scenario "${scenarioId}". Ensure the feature contains compiled scenarios and stable ids.`
719
+ );
720
+ }
721
+ return pickle;
722
+ }
723
+ function findPickleStep(pickle, stepId) {
724
+ return pickle.steps.find((step) => step.id === stepId || step.astNodeIds?.includes(stepId));
725
+ }
726
+
727
+ // src/scenario-runner.ts
728
+ var matcherCache = /* @__PURE__ */ new WeakMap();
729
+ async function runScenarioExecution(execution, context) {
730
+ execution.reset();
731
+ const eventEmitter = context.events ? events.getEventEmitter() : void 0;
732
+ const pickle = context.events?.pickle;
733
+ const { world, beforeStepHooks, afterStepHooks, invokeHooks } = context;
734
+ const parameterRegistry = resolveParameterRegistry(context.parameterRegistry);
735
+ const stepSummaries = [];
736
+ try {
737
+ const { steps, gherkinSteps } = execution;
738
+ for (let index = 0; index < steps.length; index++) {
739
+ const step = steps[index];
740
+ if (!step) {
741
+ continue;
742
+ }
743
+ const gherkinStep = gherkinSteps[index];
744
+ const metadata = buildStepMetadata(execution, index);
745
+ const stepDetails = {
746
+ index,
747
+ definition: step,
748
+ ...gherkinStep ? { gherkin: gherkinStep } : {}
749
+ };
750
+ const beforeOptions = {
751
+ direction: "asc",
752
+ step: stepDetails
753
+ };
754
+ await invokeHooks(beforeStepHooks, beforeOptions);
755
+ const pickleStep = pickle && gherkinStep?.id ? findPickleStep(pickle, gherkinStep.id) : void 0;
756
+ if (eventEmitter && pickle && pickleStep) {
757
+ await eventEmitter.stepStarted({
758
+ feature: pickle.feature,
759
+ scenario: pickle.scenario,
760
+ step: pickleStep,
761
+ pickle,
762
+ ...pickle.rule ? { rule: pickle.rule } : {},
763
+ metadata: { index }
764
+ });
765
+ }
766
+ setStepMetadata(world, metadata);
767
+ setStepTable(world, gherkinStep?.dataTable);
768
+ if (!gherkinStep?.docString) {
769
+ setStepDocstringInfo(world, void 0);
770
+ } else if (gherkinStep.docString.mediaType === void 0) {
771
+ setStepDocstringInfo(world, { content: gherkinStep.docString.content });
772
+ } else {
773
+ setStepDocstringInfo(world, {
774
+ content: gherkinStep.docString.content,
775
+ mediaType: gherkinStep.docString.mediaType
776
+ });
777
+ }
778
+ let status = "passed";
779
+ try {
780
+ const args = resolveStepArguments(
781
+ step,
782
+ gherkinStep,
783
+ parameterRegistry,
784
+ world
785
+ );
786
+ await step.handler(world, ...args);
787
+ stepSummaries.push(createStepSummary(metadata, gherkinStep, "passed"));
788
+ } catch (error) {
789
+ if (isScenarioPendingError(error)) {
790
+ status = "skipped";
791
+ throw error;
792
+ }
793
+ status = "failed";
794
+ if (eventEmitter && pickle && pickleStep) {
795
+ await eventEmitter.errorRaised({
796
+ error,
797
+ phase: "step",
798
+ feature: pickle.feature,
799
+ scenario: pickle.scenario,
800
+ ...pickle.rule ? { rule: pickle.rule } : {},
801
+ pickle,
802
+ metadata: { index, stepId: pickleStep.id }
803
+ });
804
+ }
805
+ stepSummaries.push(createStepSummary(metadata, gherkinStep, "failed"));
806
+ for (let remaining = index + 1; remaining < gherkinSteps.length; remaining++) {
807
+ const remainingMetadata = buildStepMetadata(execution, remaining);
808
+ const remainingStep = gherkinSteps[remaining];
809
+ stepSummaries.push(
810
+ createStepSummary(remainingMetadata, remainingStep, "skipped")
811
+ );
812
+ }
813
+ throw enrichStepError(error, metadata, stepSummaries);
814
+ } finally {
815
+ const afterStepDetails = {
816
+ ...stepDetails,
817
+ status
818
+ };
819
+ const afterOptions = {
820
+ direction: "desc",
821
+ step: afterStepDetails
822
+ };
823
+ await invokeHooks(afterStepHooks, afterOptions);
824
+ if (eventEmitter && pickle && pickleStep) {
825
+ await eventEmitter.stepCompleted({
826
+ feature: pickle.feature,
827
+ scenario: pickle.scenario,
828
+ step: pickleStep,
829
+ pickle,
830
+ ...pickle.rule ? { rule: pickle.rule } : {},
831
+ metadata: { index, status }
832
+ });
833
+ }
834
+ clearStepTable(world);
835
+ clearStepDocstring(world);
836
+ clearStepMetadata(world);
837
+ }
838
+ }
839
+ execution.markPassed();
840
+ } catch (error) {
841
+ if (isScenarioPendingError(error)) {
842
+ execution.markPending(error.reason);
843
+ return;
844
+ }
845
+ execution.markFailed(error);
846
+ throw error;
847
+ }
848
+ }
849
+ function resolveStepArguments(definition, gherkinStep, registry, world) {
850
+ if (!gherkinStep) {
851
+ return [];
852
+ }
853
+ const matcher = getStepArgumentMatcher(definition, registry);
854
+ return matcher(gherkinStep.text, world);
855
+ }
856
+ function getStepArgumentMatcher(definition, registry) {
857
+ const cached = matcherCache.get(definition);
858
+ if (cached) {
859
+ return cached;
860
+ }
861
+ const matcher = createStepArgumentMatcher(
862
+ definition.expression,
863
+ registry
864
+ );
865
+ matcherCache.set(
866
+ definition,
867
+ matcher
868
+ );
869
+ return matcher;
870
+ }
871
+ function createStepArgumentMatcher(expression, registry) {
872
+ if (expression instanceof RegExp) {
873
+ const evaluator2 = new cucumberExpressions.RegularExpression(expression, registry);
874
+ return (text, world) => collectArguments(evaluator2.match(text), world, text, expression);
875
+ }
876
+ const evaluator = new cucumberExpressions.CucumberExpression(expression, registry);
877
+ return (text, world) => collectArguments(evaluator.match(text), world, text, expression);
878
+ }
879
+ function collectArguments(match, world, text, expression) {
880
+ if (!match) {
881
+ throw new Error(
882
+ `Step '${text}' did not match expression ${String(expression)}`
883
+ );
884
+ }
885
+ return match.map((argument) => argument.getValue(world));
886
+ }
887
+ function resolveParameterRegistry(source) {
888
+ if (isParameterTypeRegistry(source)) {
889
+ return source;
890
+ }
891
+ const carrier = source;
892
+ const registry = carrier?.registry;
893
+ if (isParameterTypeRegistry(registry)) {
894
+ return registry;
895
+ }
896
+ return new cucumberExpressions.ParameterTypeRegistry();
897
+ }
898
+ function isParameterTypeRegistry(value) {
899
+ if (!value || typeof value !== "object") {
900
+ return false;
901
+ }
902
+ if (value instanceof cucumberExpressions.ParameterTypeRegistry) {
903
+ return true;
904
+ }
905
+ const registry = value;
906
+ return typeof registry.lookupByTypeName === "function" && typeof registry.defineParameterType === "function" && typeof registry.lookupByRegexp === "function";
907
+ }
908
+ function buildStepMetadata(execution, index) {
909
+ const stepDefinition = execution.steps[index];
910
+ const gherkinStep = execution.gherkinSteps[index];
911
+ const featureNode = execution.feature;
912
+ const feature = featureNode.feature;
913
+ const featureSource = combineSourceRef(
914
+ featureNode.scope.source,
915
+ feature.uri,
916
+ feature.location
917
+ );
918
+ const featureMeta = {
919
+ name: featureNode.name,
920
+ keyword: featureNode.keyword,
921
+ uri: feature.uri,
922
+ ...featureSource ? { source: featureSource } : {}
923
+ };
924
+ const scenarioSource = combineSourceRef(
925
+ execution.scope.source,
926
+ feature.uri,
927
+ extractScenarioLocation(execution)
928
+ );
929
+ const scenarioMeta = {
930
+ name: execution.name,
931
+ keyword: execution.keyword,
932
+ ...scenarioSource ? { source: scenarioSource } : {}
933
+ };
934
+ const outlineMeta = execution.outline ? (() => {
935
+ const outlineSource = combineSourceRef(
936
+ execution.outline?.scope.source,
937
+ feature.uri,
938
+ execution.outline.outline.location
939
+ );
940
+ return {
941
+ name: execution.outline.name,
942
+ keyword: execution.outline.keyword,
943
+ ...outlineSource ? { source: outlineSource } : {}
944
+ };
945
+ })() : void 0;
946
+ const exampleMeta = isScenarioOutlineExample(execution) ? (() => {
947
+ const group = execution.exampleGroup;
948
+ const exampleSource = combineSourceRef(
949
+ void 0,
950
+ feature.uri,
951
+ group.location
952
+ );
953
+ return {
954
+ name: group.name,
955
+ index: execution.exampleIndex,
956
+ values: buildExampleValues(group, execution.exampleIndex),
957
+ ...exampleSource ? { source: exampleSource } : {}
958
+ };
959
+ })() : void 0;
960
+ const stepMeta = gherkinStep ? (() => {
961
+ const stepSource = combineSourceRef(
962
+ void 0,
963
+ feature.uri,
964
+ gherkinStep.location
965
+ );
966
+ return {
967
+ keyword: gherkinStep.keyword,
968
+ text: gherkinStep.text,
969
+ ...stepSource ? { source: stepSource } : {}
970
+ };
971
+ })() : void 0;
972
+ const definitionMeta = stepDefinition ? (() => {
973
+ const definitionSource = normalizeDefinitionSource(stepDefinition.source);
974
+ return {
975
+ keyword: stepDefinition.keyword,
976
+ expression: stepDefinition.expression,
977
+ ...definitionSource ? { source: definitionSource } : {}
978
+ };
979
+ })() : void 0;
980
+ const metadata = {
981
+ ...featureMeta ? { feature: featureMeta } : {},
982
+ ...scenarioMeta ? { scenario: scenarioMeta } : {},
983
+ ...outlineMeta ? { outline: outlineMeta } : {},
984
+ ...exampleMeta ? { example: exampleMeta } : {},
985
+ ...stepMeta ? { step: stepMeta } : {},
986
+ ...definitionMeta ? { definition: definitionMeta } : {}
987
+ };
988
+ return hasMetadata(metadata) ? metadata : void 0;
989
+ }
990
+ function combineSourceRef(source, uri, location) {
991
+ const file = source?.file ?? uri;
992
+ const line = source?.line ?? location?.line;
993
+ const column = source?.column ?? location?.column;
994
+ if (file === void 0 && line === void 0 && column === void 0) {
995
+ return void 0;
996
+ }
997
+ return {
998
+ ...file !== void 0 ? { file } : {},
999
+ ...line !== void 0 ? { line } : {},
1000
+ ...column !== void 0 ? { column } : {}
1001
+ };
1002
+ }
1003
+ function normalizeDefinitionSource(source) {
1004
+ if (!source) {
1005
+ return void 0;
1006
+ }
1007
+ return {
1008
+ ...source.file !== void 0 ? { file: source.file } : {},
1009
+ ...source.line !== void 0 ? { line: source.line } : {},
1010
+ ...source.column !== void 0 ? { column: source.column } : {}
1011
+ };
1012
+ }
1013
+ function extractScenarioLocation(execution) {
1014
+ if (execution.type === "example") {
1015
+ return execution.outline?.outline.location;
1016
+ }
1017
+ const scenario = execution.gherkin;
1018
+ return scenario.location;
1019
+ }
1020
+ function isScenarioOutlineExample(execution) {
1021
+ return execution.type === "example";
1022
+ }
1023
+ function buildExampleValues(group, index) {
1024
+ const values = {};
1025
+ const headers = group.tableHeader;
1026
+ const row = group.tableBody[index] ?? [];
1027
+ for (let i = 0; i < headers.length; i++) {
1028
+ const header = headers[i];
1029
+ if (header === void 0 || header.length === 0) {
1030
+ continue;
1031
+ }
1032
+ values[header] = row[i] ?? "";
1033
+ }
1034
+ return Object.freeze(values);
1035
+ }
1036
+ function hasMetadata(metadata) {
1037
+ return Boolean(
1038
+ metadata.feature || metadata.scenario || metadata.outline || metadata.example || metadata.step || metadata.definition
1039
+ );
1040
+ }
1041
+ function enrichStepError(error, metadata, steps) {
1042
+ const base = error instanceof Error ? error : new Error(String(error));
1043
+ if (errors.isGherkinStepError(base)) {
1044
+ return base;
1045
+ }
1046
+ const wrapped = new errors.GherkinStepError(base.message, {
1047
+ cause: base,
1048
+ context: buildGherkinErrorContext(metadata, base, steps) ?? {}
1049
+ });
1050
+ if (base.stack) {
1051
+ Object.defineProperty(wrapped, "stack", {
1052
+ configurable: true,
1053
+ enumerable: false,
1054
+ writable: true,
1055
+ value: base.stack
1056
+ });
1057
+ }
1058
+ return wrapped;
1059
+ }
1060
+ function buildGherkinErrorContext(metadata, error, steps) {
1061
+ if (!metadata) {
1062
+ return void 0;
1063
+ }
1064
+ const gherkinLocation = toSourceLocation(metadata.step?.source);
1065
+ const definitionLocation = toSourceLocation(metadata.definition?.source);
1066
+ const errorLocation = extractErrorLocation(error);
1067
+ const pathSegments = buildGherkinPath(metadata);
1068
+ const gherkinSegment = gherkinLocation ? {
1069
+ location: gherkinLocation,
1070
+ ...metadata.feature?.name !== void 0 ? { featureName: metadata.feature.name } : {},
1071
+ ...metadata.step?.keyword !== void 0 ? { stepKeyword: metadata.step.keyword } : {},
1072
+ ...metadata.step?.text !== void 0 ? { stepText: metadata.step.text } : {}
1073
+ } : void 0;
1074
+ const expression = metadata.definition?.expression;
1075
+ const functionName = typeof expression === "string" ? expression : expression !== void 0 ? String(expression) : void 0;
1076
+ const codeLocation = errorLocation ?? definitionLocation;
1077
+ const codeSegment = codeLocation ? {
1078
+ location: codeLocation,
1079
+ ...functionName !== void 0 ? { functionName } : {}
1080
+ } : void 0;
1081
+ const hasSteps = Boolean(steps && steps.length > 0);
1082
+ if (!gherkinSegment && !codeSegment && !pathSegments && !hasSteps) {
1083
+ return void 0;
1084
+ }
1085
+ return {
1086
+ ...gherkinSegment ? { gherkin: gherkinSegment } : {},
1087
+ ...codeSegment ? { code: codeSegment } : {},
1088
+ ...pathSegments ? { path: pathSegments } : {},
1089
+ ...hasSteps && steps ? { steps } : {}
1090
+ };
1091
+ }
1092
+ function createStepSummary(metadata, gherkinStep, status) {
1093
+ const keyword = metadata?.step?.keyword ?? gherkinStep?.keyword;
1094
+ const text = metadata?.step?.text ?? gherkinStep?.text;
1095
+ const location = metadata?.step?.source ? toSourceLocation(metadata.step.source) : void 0;
1096
+ return {
1097
+ status,
1098
+ ...keyword !== void 0 ? { keyword } : {},
1099
+ ...text !== void 0 ? { text } : {},
1100
+ ...location ? { location } : {}
1101
+ };
1102
+ }
1103
+ function buildGherkinPath(metadata) {
1104
+ if (!metadata) {
1105
+ return void 0;
1106
+ }
1107
+ const segments = [];
1108
+ const featureLocation = toSourceLocation(metadata.feature?.source);
1109
+ if (featureLocation) {
1110
+ segments.push({
1111
+ role: "feature",
1112
+ location: featureLocation,
1113
+ ...metadata.feature?.keyword !== void 0 ? { keyword: metadata.feature.keyword } : {},
1114
+ ...metadata.feature?.name !== void 0 ? { name: metadata.feature.name } : {}
1115
+ });
1116
+ }
1117
+ const outlineLocation = toSourceLocation(metadata.outline?.source);
1118
+ if (outlineLocation) {
1119
+ segments.push({
1120
+ role: "outline",
1121
+ location: outlineLocation,
1122
+ ...metadata.outline?.keyword !== void 0 ? { keyword: metadata.outline.keyword } : {},
1123
+ ...metadata.outline?.name !== void 0 ? { name: metadata.outline.name } : {}
1124
+ });
1125
+ }
1126
+ const scenarioLocation = toSourceLocation(metadata.scenario?.source);
1127
+ if (scenarioLocation) {
1128
+ segments.push({
1129
+ role: "scenario",
1130
+ location: scenarioLocation,
1131
+ ...metadata.scenario?.keyword !== void 0 ? { keyword: metadata.scenario.keyword } : {},
1132
+ ...metadata.scenario?.name !== void 0 ? { name: metadata.scenario.name } : {}
1133
+ });
1134
+ }
1135
+ const exampleLocation = toSourceLocation(metadata.example?.source);
1136
+ if (exampleLocation) {
1137
+ segments.push({
1138
+ role: "example",
1139
+ keyword: "Example",
1140
+ location: exampleLocation,
1141
+ ...metadata.example?.name !== void 0 ? { name: metadata.example.name } : {},
1142
+ ...metadata.example?.index !== void 0 ? { index: metadata.example.index } : {}
1143
+ });
1144
+ }
1145
+ const stepLocation = toSourceLocation(metadata.step?.source);
1146
+ if (stepLocation) {
1147
+ segments.push({
1148
+ role: "step",
1149
+ location: stepLocation,
1150
+ ...metadata.step?.keyword !== void 0 ? { keyword: metadata.step.keyword } : {},
1151
+ ...metadata.step?.text !== void 0 ? { text: metadata.step.text } : {}
1152
+ });
1153
+ }
1154
+ return segments.length ? segments : void 0;
1155
+ }
1156
+ var STACK_FRAME_IGNORE_PATTERNS = [
1157
+ /^node:/,
1158
+ /node:internal\//,
1159
+ /internal\/(?:modules|process)/,
1160
+ /node_modules\/@autometa\//,
1161
+ /packages\/(?:runner|executor|errors|cli|assertions)\//,
1162
+ /\/\.autometa-cli\/cache\//,
1163
+ /\/\.autometa\/cache\//,
1164
+ /\/node_modules\/\.cache\/autometa\//
1165
+ ];
1166
+ function extractErrorLocation(error) {
1167
+ if (!error?.stack) {
1168
+ return void 0;
1169
+ }
1170
+ const lines = error.stack.split("\n").slice(1);
1171
+ for (const raw of lines) {
1172
+ const trimmed = raw.trim();
1173
+ if (!trimmed.startsWith("at ")) {
1174
+ continue;
1175
+ }
1176
+ const parsed = parseStackFrame(trimmed);
1177
+ if (!parsed) {
1178
+ continue;
1179
+ }
1180
+ if (isFrameworkStackFile(parsed.file)) {
1181
+ continue;
1182
+ }
1183
+ const filePath = normalizeFilePath(parsed.file);
1184
+ return {
1185
+ filePath,
1186
+ start: {
1187
+ line: parsed.line,
1188
+ column: parsed.column
1189
+ }
1190
+ };
1191
+ }
1192
+ return void 0;
1193
+ }
1194
+ function parseStackFrame(line) {
1195
+ const match = line.match(/at (?:.+?\()?((?:[a-zA-Z]:)?[^():]+):(\d+):(\d+)\)?$/);
1196
+ if (!match) {
1197
+ return void 0;
1198
+ }
1199
+ const [, file = "", lineText = "", columnText = ""] = match;
1200
+ if (!file || !lineText) {
1201
+ return void 0;
1202
+ }
1203
+ const lineNumber = Number.parseInt(lineText, 10);
1204
+ if (Number.isNaN(lineNumber)) {
1205
+ return void 0;
1206
+ }
1207
+ const columnNumber = Number.parseInt(columnText, 10);
1208
+ return {
1209
+ file,
1210
+ line: lineNumber,
1211
+ column: Number.isNaN(columnNumber) ? 1 : columnNumber
1212
+ };
1213
+ }
1214
+ function isFrameworkStackFile(file) {
1215
+ const normalized = file.replace(/\\/g, "/");
1216
+ return STACK_FRAME_IGNORE_PATTERNS.some((pattern) => pattern.test(normalized));
1217
+ }
1218
+ function toSourceLocation(source) {
1219
+ if (!source?.file) {
1220
+ return void 0;
1221
+ }
1222
+ const filePath = normalizeFilePath(source.file);
1223
+ const line = source.line ?? 1;
1224
+ const column = source.column ?? 1;
1225
+ return {
1226
+ filePath,
1227
+ start: {
1228
+ line,
1229
+ column
1230
+ }
1231
+ };
1232
+ }
1233
+ function normalizeFilePath(file) {
1234
+ if (file.startsWith("file://")) {
1235
+ try {
1236
+ return url.fileURLToPath(file);
1237
+ } catch {
1238
+ return file;
1239
+ }
1240
+ }
1241
+ return path__default.default.isAbsolute(file) ? file : path__default.default.resolve(file);
1242
+ }
1243
+ var ALWAYS_TRUE = {
1244
+ evaluate: () => true
1245
+ };
1246
+ var resolveParser = () => {
1247
+ const namespace = TagExpressions__namespace;
1248
+ if (typeof namespace.parse === "function") {
1249
+ return namespace.parse;
1250
+ }
1251
+ if (typeof namespace.default === "function") {
1252
+ return namespace.default;
1253
+ }
1254
+ throw new Error("Unable to resolve @cucumber/tag-expressions parser export");
1255
+ };
1256
+ var parseExpression = resolveParser();
1257
+ var createTagFilter = (expression) => {
1258
+ if (!expression || expression.trim().length === 0) {
1259
+ return ALWAYS_TRUE;
1260
+ }
1261
+ const parsed = parseExpression(expression);
1262
+ return {
1263
+ evaluate(tags) {
1264
+ return parsed.evaluate(tags.map((tag) => tag.trim()));
1265
+ }
1266
+ };
1267
+ };
1268
+
1269
+ // src/modes.ts
1270
+ var MODE_TAG_ALIASES = {
1271
+ concurrent: "concurrent",
1272
+ sequential: "sequential",
1273
+ failing: "failing",
1274
+ fails: "failing"
1275
+ };
1276
+ function normalizeTagValue(tag) {
1277
+ return tag.replace(/^@/, "").trim().toLowerCase();
1278
+ }
1279
+ function wrapFailingTest(test) {
1280
+ const failing = (title, handler, timeout) => {
1281
+ const wrapped = async () => {
1282
+ let threw = false;
1283
+ try {
1284
+ await handler();
1285
+ } catch (_error) {
1286
+ threw = true;
1287
+ return;
1288
+ }
1289
+ if (!threw) {
1290
+ throw new Error("Expected scenario to fail, but it passed");
1291
+ }
1292
+ };
1293
+ test(title, wrapped, timeout);
1294
+ };
1295
+ failing.skip = test.skip;
1296
+ failing.only = test.only;
1297
+ if (typeof test.concurrent === "function") {
1298
+ failing.concurrent = test.concurrent;
1299
+ }
1300
+ failing.failing = failing;
1301
+ failing.fails = failing;
1302
+ return failing;
1303
+ }
1304
+ function selectFailingTest(test) {
1305
+ if (typeof test.failing === "function") {
1306
+ return test.failing;
1307
+ }
1308
+ if (typeof test.fails === "function") {
1309
+ return test.fails;
1310
+ }
1311
+ return wrapFailingTest(test);
1312
+ }
1313
+ var selectSuiteByMode = (suite, mode) => {
1314
+ switch (mode) {
1315
+ case "skip":
1316
+ return suite.skip;
1317
+ case "only":
1318
+ return suite.only;
1319
+ case "concurrent":
1320
+ return typeof suite.concurrent === "function" ? suite.concurrent : suite;
1321
+ case "sequential":
1322
+ return typeof suite.sequential === "function" ? suite.sequential : suite;
1323
+ default:
1324
+ return suite;
1325
+ }
1326
+ };
1327
+ var selectTestByMode = (test, mode) => {
1328
+ switch (mode) {
1329
+ case "skip":
1330
+ return test.skip;
1331
+ case "only":
1332
+ return test.only;
1333
+ case "concurrent":
1334
+ return typeof test.concurrent === "function" ? test.concurrent : test;
1335
+ case "sequential":
1336
+ return typeof test.sequential === "function" ? test.sequential : test;
1337
+ case "failing":
1338
+ return selectFailingTest(test);
1339
+ default:
1340
+ return test;
1341
+ }
1342
+ };
1343
+ var resolveModeFromTags = (currentMode, tags) => {
1344
+ if (currentMode !== "default") {
1345
+ return currentMode;
1346
+ }
1347
+ if (!tags || tags.length === 0) {
1348
+ return currentMode;
1349
+ }
1350
+ for (const tag of tags) {
1351
+ const normalized = normalizeTagValue(tag);
1352
+ const derived = MODE_TAG_ALIASES[normalized];
1353
+ if (derived) {
1354
+ return derived;
1355
+ }
1356
+ }
1357
+ return currentMode;
1358
+ };
1359
+ var WORLD_CONTEXT_KEY = "__AUTOMETA_EXECUTOR_WORLD_CONTEXT__";
1360
+ var globalTarget = globalThis;
1361
+ var getOrCreateWorldContext = () => {
1362
+ const existing = globalTarget[WORLD_CONTEXT_KEY];
1363
+ if (existing) {
1364
+ return existing;
1365
+ }
1366
+ const created = new async_hooks.AsyncLocalStorage();
1367
+ globalTarget[WORLD_CONTEXT_KEY] = created;
1368
+ return created;
1369
+ };
1370
+ var WorldContext = getOrCreateWorldContext();
1371
+ function getWorld() {
1372
+ const store = WorldContext.getStore();
1373
+ if (store === void 0) {
1374
+ throw new Error(
1375
+ "World context is not available. Are you running inside a scenario?"
1376
+ );
1377
+ }
1378
+ return store;
1379
+ }
1380
+ function tryGetWorld() {
1381
+ return WorldContext.getStore();
1382
+ }
1383
+
1384
+ // src/scope-lifecycle.ts
1385
+ var PERSISTENT_SCOPE_KINDS = /* @__PURE__ */ new Set([
1386
+ "feature",
1387
+ "rule",
1388
+ "scenarioOutline"
1389
+ ]);
1390
+ var BEFORE_HOOK_TYPES = {
1391
+ root: void 0,
1392
+ feature: "beforeFeature",
1393
+ rule: "beforeRule",
1394
+ scenario: "beforeScenario",
1395
+ scenarioOutline: "beforeScenarioOutline"
1396
+ };
1397
+ var AFTER_HOOK_TYPES = {
1398
+ root: void 0,
1399
+ feature: "afterFeature",
1400
+ rule: "afterRule",
1401
+ scenario: "afterScenario",
1402
+ scenarioOutline: "afterScenarioOutline"
1403
+ };
1404
+ function formatSourceRef(source) {
1405
+ if (!source?.file) {
1406
+ return void 0;
1407
+ }
1408
+ const line = source.line ? `:${source.line}` : "";
1409
+ const column = source.column ? `:${source.column}` : "";
1410
+ return `${source.file}${line}${column}`;
1411
+ }
1412
+ function isRecord(value) {
1413
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1414
+ }
1415
+ var ScopeLifecycle = class {
1416
+ constructor(adapter, options = {}) {
1417
+ this.adapter = adapter;
1418
+ this.states = /* @__PURE__ */ new Map();
1419
+ this.depthMap = /* @__PURE__ */ new Map();
1420
+ this.root = adapter.plan.root;
1421
+ this.buildDepthMap(this.root, 0);
1422
+ if (options.hookLogger) {
1423
+ this.hookLogger = options.hookLogger;
1424
+ }
1425
+ this.featureLanguage = options.featureLanguage;
1426
+ this.scopeKeywords = options.scopeKeywords ?? /* @__PURE__ */ new Map();
1427
+ }
1428
+ configurePersistentScope(scope, runtime) {
1429
+ if (!this.isPersistentScope(scope)) {
1430
+ return;
1431
+ }
1432
+ if (!this.shouldMaterializePersistentScope(scope)) {
1433
+ return;
1434
+ }
1435
+ runtime.beforeAll(async () => {
1436
+ await this.ensureState(scope);
1437
+ });
1438
+ runtime.afterAll(async () => {
1439
+ await this.teardownState(scope);
1440
+ });
1441
+ }
1442
+ collectScenarioHooks(execution) {
1443
+ return collectScenarioHooks(this.adapter, execution);
1444
+ }
1445
+ async runScenario(execution, hooks, runner, options = {}) {
1446
+ const parentWorld = await this.resolveParentWorldForScenario(execution);
1447
+ const world = await this.adapter.createWorld(execution.scope, parentWorld);
1448
+ const disposeWorld = createWorldDisposer(world);
1449
+ const invokeHooks = this.createHookInvoker(execution, world, options.events);
1450
+ const scenarioContext = {
1451
+ world,
1452
+ parameterRegistry: this.adapter.getParameterRegistry(),
1453
+ beforeStepHooks: hooks.beforeStep,
1454
+ afterStepHooks: hooks.afterStep,
1455
+ ...options.events ? { events: options.events } : {},
1456
+ invokeHooks
1457
+ };
1458
+ const errors = [];
1459
+ try {
1460
+ await WorldContext.run(world, async () => {
1461
+ await this.invokeHooks(hooks.beforeScenario, {
1462
+ world,
1463
+ scope: execution.scope,
1464
+ scenario: execution,
1465
+ ...options.events ? { events: options.events } : {},
1466
+ direction: "asc"
1467
+ });
1468
+ await runner(world, scenarioContext);
1469
+ });
1470
+ } catch (error) {
1471
+ errors.push(error);
1472
+ } finally {
1473
+ try {
1474
+ await this.invokeHooks(hooks.afterScenario, {
1475
+ world,
1476
+ scope: execution.scope,
1477
+ scenario: execution,
1478
+ ...options.events ? { events: options.events } : {},
1479
+ direction: "desc",
1480
+ metadata: { result: execution.result }
1481
+ });
1482
+ } catch (error) {
1483
+ errors.push(error);
1484
+ }
1485
+ try {
1486
+ await disposeWorld();
1487
+ } catch (error) {
1488
+ errors.push(error);
1489
+ }
1490
+ }
1491
+ if (errors.length === 1) {
1492
+ throw toError(errors[0], "Scenario execution failed");
1493
+ }
1494
+ if (errors.length > 1) {
1495
+ throw combineErrors(errors, "Multiple errors occurred during scenario execution");
1496
+ }
1497
+ }
1498
+ async ensureState(scope) {
1499
+ let state = this.states.get(scope.id);
1500
+ if (state) {
1501
+ if (!state.beforeExecuted) {
1502
+ await this.runScopeHooks(scope, "before", state.world);
1503
+ state.beforeExecuted = true;
1504
+ }
1505
+ return state;
1506
+ }
1507
+ await this.ensureAncestorStates(scope);
1508
+ const parentWorld = await this.resolveParentWorld(scope);
1509
+ const world = await this.adapter.createWorld(scope, parentWorld);
1510
+ const dispose = createWorldDisposer(world);
1511
+ state = {
1512
+ scope,
1513
+ world,
1514
+ dispose,
1515
+ beforeExecuted: false,
1516
+ afterExecuted: false
1517
+ };
1518
+ this.states.set(scope.id, state);
1519
+ await this.runScopeHooks(scope, "before", world);
1520
+ state.beforeExecuted = true;
1521
+ return state;
1522
+ }
1523
+ async teardownState(scope) {
1524
+ const state = this.states.get(scope.id);
1525
+ if (!state) {
1526
+ return;
1527
+ }
1528
+ if (!state.afterExecuted) {
1529
+ await this.runScopeHooks(scope, "after", state.world);
1530
+ state.afterExecuted = true;
1531
+ }
1532
+ await state.dispose();
1533
+ this.states.delete(scope.id);
1534
+ }
1535
+ async ensureAncestorStates(scope) {
1536
+ const parent = this.getParentScope(scope);
1537
+ if (!parent) {
1538
+ return;
1539
+ }
1540
+ if (!this.isPersistentScope(parent)) {
1541
+ return;
1542
+ }
1543
+ if (!this.shouldMaterializePersistentScope(parent)) {
1544
+ return;
1545
+ }
1546
+ await this.ensureState(parent);
1547
+ }
1548
+ async resolveParentWorld(scope) {
1549
+ const parent = this.getParentScope(scope);
1550
+ if (!parent || !this.isPersistentScope(parent)) {
1551
+ return void 0;
1552
+ }
1553
+ if (!this.shouldMaterializePersistentScope(parent)) {
1554
+ return void 0;
1555
+ }
1556
+ const parentState = this.states.get(parent.id) ?? await this.ensureState(parent);
1557
+ return parentState.world;
1558
+ }
1559
+ async resolveParentWorldForScenario(execution) {
1560
+ const scope = execution.scope;
1561
+ const ownState = this.states.get(scope.id);
1562
+ if (ownState) {
1563
+ return ownState.world;
1564
+ }
1565
+ const ancestors = this.adapter.getAncestors(scope.id);
1566
+ for (let index = ancestors.length - 1; index >= 0; index -= 1) {
1567
+ const candidate = ancestors[index];
1568
+ if (!candidate || !this.isPersistentScope(candidate)) {
1569
+ continue;
1570
+ }
1571
+ if (!this.shouldMaterializePersistentScope(candidate)) {
1572
+ continue;
1573
+ }
1574
+ const state = this.states.get(candidate.id) ?? await this.ensureState(candidate);
1575
+ if (state) {
1576
+ return state.world;
1577
+ }
1578
+ }
1579
+ return void 0;
1580
+ }
1581
+ getParentScope(scope) {
1582
+ const ancestors = this.adapter.getAncestors(scope.id);
1583
+ if (ancestors.length === 0) {
1584
+ return void 0;
1585
+ }
1586
+ return ancestors[ancestors.length - 1];
1587
+ }
1588
+ isPersistentScope(scope) {
1589
+ return PERSISTENT_SCOPE_KINDS.has(scope.kind);
1590
+ }
1591
+ shouldMaterializePersistentScope(scope) {
1592
+ const beforeType = BEFORE_HOOK_TYPES[scope.kind];
1593
+ const afterType = AFTER_HOOK_TYPES[scope.kind];
1594
+ if (beforeType) {
1595
+ const hooks = this.collectHooksForScope(scope, beforeType);
1596
+ if (hooks.length > 0) {
1597
+ return true;
1598
+ }
1599
+ }
1600
+ if (afterType) {
1601
+ const hooks = this.collectHooksForScope(scope, afterType);
1602
+ if (hooks.length > 0) {
1603
+ return true;
1604
+ }
1605
+ }
1606
+ return false;
1607
+ }
1608
+ async runScopeHooks(scope, phase, world) {
1609
+ const hookType = phase === "before" ? BEFORE_HOOK_TYPES[scope.kind] : AFTER_HOOK_TYPES[scope.kind];
1610
+ if (!hookType) {
1611
+ return;
1612
+ }
1613
+ const hooks = this.collectHooksForScope(scope, hookType);
1614
+ if (!hooks.length) {
1615
+ return;
1616
+ }
1617
+ await this.invokeHooks(hooks, {
1618
+ world,
1619
+ scope,
1620
+ direction: phase === "before" ? "asc" : "desc"
1621
+ });
1622
+ }
1623
+ createHookInvoker(execution, world, events) {
1624
+ return async (hooks, options) => {
1625
+ const params = {
1626
+ world,
1627
+ scope: execution.scope,
1628
+ scenario: execution,
1629
+ ...events ? { events } : {},
1630
+ ...options.direction ? { direction: options.direction } : {},
1631
+ ...options.step ? { step: options.step } : {},
1632
+ ...options.metadata ? { metadata: options.metadata } : {}
1633
+ };
1634
+ await this.invokeHooks(hooks, params);
1635
+ };
1636
+ }
1637
+ async invokeHooks(hooks, params) {
1638
+ if (hooks.length === 0) {
1639
+ return;
1640
+ }
1641
+ const sorted = this.sortHooks(hooks, params.direction ?? "asc");
1642
+ const eventEmitter = events.getEventEmitter();
1643
+ const pickle = params.events?.pickle;
1644
+ for (const entry of sorted) {
1645
+ const source = formatSourceRef(entry.hook.source ?? entry.scope.source);
1646
+ const hookMetadata = isRecord(entry.hook.options.data) ? entry.hook.options.data : void 0;
1647
+ const pickleStep = pickle && params.step?.gherkin?.id ? findPickleStep(pickle, params.step.gherkin.id) : void 0;
1648
+ const hookDescriptor = {
1649
+ kind: entry.hook.type,
1650
+ ...entry.hook.description ? { name: entry.hook.description } : {},
1651
+ ...source ? { source } : {},
1652
+ ...pickle ? { feature: pickle.feature } : {},
1653
+ ...pickle?.rule ? { rule: pickle.rule } : {},
1654
+ ...pickle ? { scenario: pickle.scenario } : {},
1655
+ ...pickleStep ? { step: pickleStep } : {},
1656
+ ...pickle ? { pickle } : {},
1657
+ ...hookMetadata ? { metadata: hookMetadata } : {}
1658
+ };
1659
+ await eventEmitter.hookStarted({
1660
+ hook: hookDescriptor,
1661
+ metadata: { hookId: entry.hook.id }
1662
+ });
1663
+ const metadata = this.buildHookMetadata(entry, params);
1664
+ const log = this.createContextLogger(entry, params);
1665
+ const context = {
1666
+ world: params.world,
1667
+ scope: entry.scope,
1668
+ ...metadata ? { metadata } : {},
1669
+ ...log ? { log } : {}
1670
+ };
1671
+ try {
1672
+ await entry.hook.handler(context);
1673
+ } catch (error) {
1674
+ await eventEmitter.errorRaised({
1675
+ error,
1676
+ phase: "hook",
1677
+ ...pickle ? { feature: pickle.feature } : {},
1678
+ ...pickle?.rule ? { rule: pickle.rule } : {},
1679
+ ...pickle ? { scenario: pickle.scenario } : {},
1680
+ ...pickle ? { pickle } : {},
1681
+ metadata: { hook: hookDescriptor, hookId: entry.hook.id }
1682
+ });
1683
+ throw error;
1684
+ } finally {
1685
+ await eventEmitter.hookCompleted({
1686
+ hook: hookDescriptor,
1687
+ metadata: { hookId: entry.hook.id }
1688
+ });
1689
+ }
1690
+ }
1691
+ }
1692
+ buildHookMetadata(entry, params) {
1693
+ const metadata = {};
1694
+ if (params.metadata) {
1695
+ Object.assign(metadata, params.metadata);
1696
+ }
1697
+ if (entry.hook.options.data !== void 0) {
1698
+ metadata.hook = entry.hook.options.data;
1699
+ }
1700
+ metadata.targetScope = {
1701
+ id: params.scope.id,
1702
+ kind: params.scope.kind,
1703
+ name: params.scope.name
1704
+ };
1705
+ if (params.scenario) {
1706
+ metadata.scenario = {
1707
+ id: params.scenario.id,
1708
+ name: params.scenario.name,
1709
+ type: params.scenario.type,
1710
+ tags: params.scenario.tags,
1711
+ qualifiedName: params.scenario.qualifiedName
1712
+ };
1713
+ }
1714
+ if (params.step) {
1715
+ const { step } = params;
1716
+ metadata.step = {
1717
+ index: step.index,
1718
+ status: step.status,
1719
+ keyword: step.gherkin?.keyword ?? step.definition?.keyword,
1720
+ text: step.gherkin?.text
1721
+ };
1722
+ }
1723
+ return Object.keys(metadata).length > 0 ? metadata : void 0;
1724
+ }
1725
+ collectHooksForScope(scope, type) {
1726
+ const chain = this.buildChain(scope);
1727
+ const collected = [];
1728
+ for (const candidate of chain) {
1729
+ for (const hook of candidate.hooks) {
1730
+ if (hook.type === type) {
1731
+ collected.push({ hook, scope: candidate });
1732
+ }
1733
+ }
1734
+ }
1735
+ return collected;
1736
+ }
1737
+ buildChain(scope) {
1738
+ const ancestors = this.adapter.getAncestors(scope.id);
1739
+ return [this.root, ...ancestors, scope];
1740
+ }
1741
+ createContextLogger(entry, params) {
1742
+ if (!this.hookLogger) {
1743
+ return void 0;
1744
+ }
1745
+ const emit = this.hookLogger;
1746
+ return (rawMessage) => {
1747
+ if (rawMessage === void 0 || rawMessage === null) {
1748
+ return;
1749
+ }
1750
+ const message = String(rawMessage);
1751
+ if (message.length === 0) {
1752
+ return;
1753
+ }
1754
+ try {
1755
+ emit(this.buildHookLogEvent(entry, params, message));
1756
+ } catch (error) {
1757
+ if (typeof console !== "undefined" && typeof console.error === "function") {
1758
+ console.error(error);
1759
+ }
1760
+ }
1761
+ };
1762
+ }
1763
+ buildHookLogEvent(entry, params, message) {
1764
+ const ancestors = this.adapter.getAncestors(params.scope.id);
1765
+ const path2 = ancestors.map((node) => this.toPathSegment(node));
1766
+ const targetSegment = this.toPathSegment(params.scope);
1767
+ path2.push(targetSegment);
1768
+ const direction = params.direction ?? "asc";
1769
+ const phase = direction === "desc" ? "after" : "before";
1770
+ const scenarioIndex = this.findScenarioSegmentIndex(path2);
1771
+ const scenarioDetails = this.buildScenarioDetails(path2, scenarioIndex, params);
1772
+ const language = this.resolveLanguage(params, scenarioDetails);
1773
+ const targetKeyword = this.scopeKeywords.get(params.scope.id);
1774
+ if (params.step) {
1775
+ path2.push(this.toStepSegment(params.scope, params.step));
1776
+ }
1777
+ return {
1778
+ message,
1779
+ hookId: entry.hook.id,
1780
+ hookType: entry.hook.type,
1781
+ ...entry.hook.description ? { hookDescription: entry.hook.description } : {},
1782
+ phase,
1783
+ path: path2,
1784
+ ...scenarioDetails ? { scenario: scenarioDetails } : {},
1785
+ ...params.step ? { step: this.toStepDetails(params.step) } : {},
1786
+ ...targetKeyword ? { targetKeyword } : {},
1787
+ ...language ? { language } : {}
1788
+ };
1789
+ }
1790
+ toPathSegment(scope) {
1791
+ const keyword = this.scopeKeywords.get(scope.id);
1792
+ return {
1793
+ id: scope.id,
1794
+ kind: scope.kind,
1795
+ name: scope.name,
1796
+ ...keyword ? { keyword } : {}
1797
+ };
1798
+ }
1799
+ toStepSegment(scope, step) {
1800
+ const keyword = step.gherkin?.keyword ?? step.definition?.keyword;
1801
+ return {
1802
+ id: `${scope.id}:step:${step.index}`,
1803
+ kind: "step",
1804
+ name: this.describeStep(step),
1805
+ ...keyword ? { keyword: keyword.trim() } : {}
1806
+ };
1807
+ }
1808
+ toStepDetails(step) {
1809
+ return {
1810
+ index: step.index,
1811
+ ...step.gherkin?.keyword ? { keyword: step.gherkin.keyword } : {},
1812
+ ...step.gherkin?.text ? { text: step.gherkin.text } : {},
1813
+ ...step.status ? { status: step.status } : {}
1814
+ };
1815
+ }
1816
+ describeStep(step) {
1817
+ const keyword = step.gherkin?.keyword ?? step.definition?.keyword;
1818
+ const text = step.gherkin?.text ?? this.describeStepExpression(step.definition);
1819
+ if (keyword) {
1820
+ const trimmedKeyword = keyword.trim();
1821
+ if (text && text.length > 0) {
1822
+ const needsSpace = text.startsWith(" ");
1823
+ return `${trimmedKeyword}${needsSpace ? "" : " "}${text}`;
1824
+ }
1825
+ return trimmedKeyword;
1826
+ }
1827
+ if (text && text.length > 0) {
1828
+ return text;
1829
+ }
1830
+ return `Step #${step.index + 1}`;
1831
+ }
1832
+ describeStepExpression(definition) {
1833
+ if (!definition) {
1834
+ return void 0;
1835
+ }
1836
+ const expression = definition.expression;
1837
+ if (typeof expression === "string") {
1838
+ return expression;
1839
+ }
1840
+ return expression.toString();
1841
+ }
1842
+ findScenarioSegmentIndex(path2) {
1843
+ for (let index = path2.length - 1; index >= 0; index -= 1) {
1844
+ const segment = path2[index];
1845
+ if (!segment) {
1846
+ continue;
1847
+ }
1848
+ if (segment.kind === "scenario") {
1849
+ return index;
1850
+ }
1851
+ if (segment.kind === "scenarioOutline") {
1852
+ return index;
1853
+ }
1854
+ }
1855
+ return -1;
1856
+ }
1857
+ buildScenarioDetails(path2, scenarioIndex, params) {
1858
+ if (scenarioIndex < 0) {
1859
+ return void 0;
1860
+ }
1861
+ const scenarioSegment = path2[scenarioIndex];
1862
+ if (!scenarioSegment) {
1863
+ return void 0;
1864
+ }
1865
+ const segments = path2.slice(0, scenarioIndex + 1).map((segment) => segment.name);
1866
+ const fullName = segments.join(" \u203A ");
1867
+ const scenario = params.scenario;
1868
+ const keyword = scenario?.keyword ?? scenarioSegment.keyword;
1869
+ const language = scenario?.feature.feature.language ?? this.featureLanguage;
1870
+ if (scenario) {
1871
+ return {
1872
+ id: scenario.id,
1873
+ name: scenario.name,
1874
+ fullName,
1875
+ ...keyword ? { keyword } : {},
1876
+ ...language ? { language } : {}
1877
+ };
1878
+ }
1879
+ return {
1880
+ id: scenarioSegment.id,
1881
+ name: scenarioSegment.name,
1882
+ fullName,
1883
+ ...keyword ? { keyword } : {},
1884
+ ...language ? { language } : {}
1885
+ };
1886
+ }
1887
+ resolveLanguage(params, scenarioDetails) {
1888
+ if (params.scenario) {
1889
+ const scenarioLanguage = params.scenario.feature.feature.language;
1890
+ if (scenarioLanguage) {
1891
+ return scenarioLanguage;
1892
+ }
1893
+ }
1894
+ if (scenarioDetails?.language) {
1895
+ return scenarioDetails.language;
1896
+ }
1897
+ return this.featureLanguage;
1898
+ }
1899
+ sortHooks(hooks, direction) {
1900
+ return hooks.slice().sort((a, b) => this.compareHooks(a, b, direction));
1901
+ }
1902
+ compareHooks(a, b, direction) {
1903
+ const orderA = a.hook.options.order ?? 5;
1904
+ const orderB = b.hook.options.order ?? 5;
1905
+ if (orderA !== orderB) {
1906
+ return direction === "asc" ? orderA - orderB : orderB - orderA;
1907
+ }
1908
+ const depthA = this.depthMap.get(a.scope.id) ?? 0;
1909
+ const depthB = this.depthMap.get(b.scope.id) ?? 0;
1910
+ if (depthA !== depthB) {
1911
+ return direction === "asc" ? depthB - depthA : depthA - depthB;
1912
+ }
1913
+ return a.hook.id.localeCompare(b.hook.id);
1914
+ }
1915
+ buildDepthMap(node, depth) {
1916
+ this.depthMap.set(node.id, depth);
1917
+ for (const child of node.children) {
1918
+ this.buildDepthMap(child, depth + 1);
1919
+ }
1920
+ }
1921
+ };
1922
+ function normalizeError(value, fallbackMessage) {
1923
+ if (value instanceof Error) {
1924
+ return value;
1925
+ }
1926
+ const error = new Error(fallbackMessage);
1927
+ Object.defineProperty(error, "cause", {
1928
+ configurable: true,
1929
+ enumerable: false,
1930
+ writable: true,
1931
+ value
1932
+ });
1933
+ return error;
1934
+ }
1935
+ function toError(value, fallbackMessage) {
1936
+ return normalizeError(value, fallbackMessage);
1937
+ }
1938
+ function combineErrors(values, message) {
1939
+ const normalized = values.map(
1940
+ (value, index) => normalizeError(value, `${message} (${index + 1})`)
1941
+ );
1942
+ const aggregate = new Error(message);
1943
+ Object.defineProperty(aggregate, "cause", {
1944
+ configurable: true,
1945
+ enumerable: false,
1946
+ writable: true,
1947
+ value: normalized
1948
+ });
1949
+ return aggregate;
1950
+ }
1951
+ function createWorldDisposer(world) {
1952
+ const disposers = [];
1953
+ if (world && typeof world === "object") {
1954
+ const record = world;
1955
+ const app = record.app;
1956
+ if (isDisposable(app)) {
1957
+ disposers.push(async () => {
1958
+ await app.dispose();
1959
+ });
1960
+ }
1961
+ const container = record.di ?? record.container;
1962
+ if (isDisposable(container)) {
1963
+ disposers.push(async () => {
1964
+ await container.dispose();
1965
+ });
1966
+ }
1967
+ }
1968
+ return async () => {
1969
+ if (disposers.length === 0) {
1970
+ return;
1971
+ }
1972
+ const errors = [];
1973
+ for (const dispose of disposers) {
1974
+ try {
1975
+ await dispose();
1976
+ } catch (error) {
1977
+ errors.push(error);
1978
+ }
1979
+ }
1980
+ if (errors.length === 1) {
1981
+ throw toError(errors[0], "World disposal failed");
1982
+ }
1983
+ if (errors.length > 1) {
1984
+ throw combineErrors(errors, "Multiple errors occurred while disposing world resources");
1985
+ }
1986
+ };
1987
+ }
1988
+ function isDisposable(value) {
1989
+ if (!value || typeof value !== "object") {
1990
+ return false;
1991
+ }
1992
+ const candidate = value;
1993
+ const dispose = candidate.dispose;
1994
+ return typeof dispose === "function";
1995
+ }
1996
+
1997
+ // src/execute-plan.ts
1998
+ function runSuiteWithMetadata(suite, metadata, title, handler, timeout) {
1999
+ const target = suite;
2000
+ if (typeof target.__withMetadata === "function") {
2001
+ target.__withMetadata(metadata, () => {
2002
+ suite(title, handler, timeout);
2003
+ });
2004
+ return;
2005
+ }
2006
+ suite(title, handler, timeout);
2007
+ }
2008
+ function isScenarioOutlineExample2(execution) {
2009
+ return execution.type === "example";
2010
+ }
2011
+ function shouldDisplayExamplesGroup(group, totalGroups) {
2012
+ if (totalGroups > 1) {
2013
+ return true;
2014
+ }
2015
+ const name = group.name?.trim();
2016
+ return Boolean(name && name.length > 0);
2017
+ }
2018
+ function formatExamplesGroupTitle(group, index) {
2019
+ const trimmed = group.name?.trim();
2020
+ if (trimmed && trimmed.length > 0) {
2021
+ return trimmed;
2022
+ }
2023
+ return `Table #${index + 1}`;
2024
+ }
2025
+ function registerFeaturePlan(options) {
2026
+ const { plan, runtime, adapter, config, hookLogger } = options;
2027
+ const feature = plan.feature;
2028
+ const tagFilter = createTagFilter(config.test?.tagFilter);
2029
+ const scopeKeywords = collectScopeKeywords(feature);
2030
+ const eventEmitter = events.getEventEmitter();
2031
+ const featureRef = createFeatureRef(feature.feature);
2032
+ const lifecycle = new ScopeLifecycle(adapter, {
2033
+ ...hookLogger ? { hookLogger } : {},
2034
+ featureLanguage: feature.feature.language,
2035
+ scopeKeywords
2036
+ });
2037
+ const featureTags = [
2038
+ ...feature.feature.tags ?? [],
2039
+ ...feature.scope.tags ?? []
2040
+ ];
2041
+ const featureMode = resolveModeFromTags(feature.scope.mode, featureTags);
2042
+ const featureTimeout = resolveTimeout(feature.scope.timeout, config);
2043
+ const featureSuite = selectSuiteByMode(runtime.suite, featureMode);
2044
+ runSuiteWithMetadata(
2045
+ featureSuite,
2046
+ { kind: "feature", keyword: feature.keyword },
2047
+ feature.name,
2048
+ () => {
2049
+ runtime.beforeAll(async () => {
2050
+ await eventEmitter.featureStarted({ feature: featureRef });
2051
+ });
2052
+ runtime.afterAll(async () => {
2053
+ await eventEmitter.featureCompleted({ feature: featureRef });
2054
+ });
2055
+ lifecycle.configurePersistentScope(feature.scope, runtime);
2056
+ registerScenarios(feature.scenarios, runtime, config, tagFilter, lifecycle, feature.feature);
2057
+ registerScenarioOutlines(feature.scenarioOutlines, runtime, config, tagFilter, lifecycle, feature.feature, featureRef);
2058
+ registerRules(feature.rules, runtime, config, tagFilter, lifecycle, feature.feature, featureRef);
2059
+ },
2060
+ featureTimeout.milliseconds
2061
+ );
2062
+ }
2063
+ function collectScopeKeywords(feature) {
2064
+ const entries = [];
2065
+ entries.push([feature.scope.id, feature.keyword]);
2066
+ for (const scenario of feature.scenarios) {
2067
+ entries.push([scenario.scope.id, scenario.keyword]);
2068
+ }
2069
+ for (const outline of feature.scenarioOutlines) {
2070
+ entries.push([outline.scope.id, outline.keyword]);
2071
+ for (const example of outline.examples) {
2072
+ entries.push([example.scope.id, example.keyword]);
2073
+ }
2074
+ }
2075
+ for (const rule of feature.rules) {
2076
+ entries.push([rule.scope.id, rule.keyword]);
2077
+ for (const scenario of rule.scenarios) {
2078
+ entries.push([scenario.scope.id, scenario.keyword]);
2079
+ }
2080
+ for (const outline of rule.scenarioOutlines) {
2081
+ entries.push([outline.scope.id, outline.keyword]);
2082
+ for (const example of outline.examples) {
2083
+ entries.push([example.scope.id, example.keyword]);
2084
+ }
2085
+ }
2086
+ }
2087
+ return new Map(entries);
2088
+ }
2089
+ function registerRules(rules, runtime, config, tagFilter, lifecycle, feature, featureRef) {
2090
+ const eventEmitter = events.getEventEmitter();
2091
+ for (const rule of rules) {
2092
+ const ruleRef = createRuleRef(rule.rule);
2093
+ const ruleTags = [
2094
+ ...rule.rule.tags ?? [],
2095
+ ...rule.scope.tags ?? []
2096
+ ];
2097
+ const ruleMode = resolveModeFromTags(rule.scope.mode, ruleTags);
2098
+ const suite = selectSuiteByMode(runtime.suite, ruleMode);
2099
+ const timeout = resolveTimeout(rule.scope.timeout, config);
2100
+ runSuiteWithMetadata(
2101
+ suite,
2102
+ { kind: "rule", keyword: rule.keyword },
2103
+ rule.name,
2104
+ () => {
2105
+ runtime.beforeAll(async () => {
2106
+ await eventEmitter.ruleStarted({ feature: featureRef, rule: ruleRef });
2107
+ });
2108
+ runtime.afterAll(async () => {
2109
+ await eventEmitter.ruleCompleted({ feature: featureRef, rule: ruleRef });
2110
+ });
2111
+ lifecycle.configurePersistentScope(rule.scope, runtime);
2112
+ registerScenarios(rule.scenarios, runtime, config, tagFilter, lifecycle, feature);
2113
+ registerScenarioOutlines(rule.scenarioOutlines, runtime, config, tagFilter, lifecycle, feature, featureRef);
2114
+ },
2115
+ timeout.milliseconds
2116
+ );
2117
+ }
2118
+ }
2119
+ function registerScenarioOutlines(outlines, runtime, config, tagFilter, lifecycle, feature, featureRef) {
2120
+ const eventEmitter = events.getEventEmitter();
2121
+ for (const outline of outlines) {
2122
+ const outlineMode = resolveModeFromTags(outline.mode, outline.tags);
2123
+ const suite = selectSuiteByMode(runtime.suite, outlineMode);
2124
+ const timeout = resolveTimeout(outline.timeout, config);
2125
+ runSuiteWithMetadata(
2126
+ suite,
2127
+ { kind: "scenarioOutline", keyword: outline.keyword },
2128
+ outline.name,
2129
+ () => {
2130
+ const firstRule = outline.examples[0]?.rule?.rule;
2131
+ runtime.beforeAll(async () => {
2132
+ await eventEmitter.scenarioOutlineStarted({
2133
+ feature: featureRef,
2134
+ scenarioOutline: outline.outline,
2135
+ ...firstRule ? { rule: createRuleRef(firstRule) } : {}
2136
+ });
2137
+ });
2138
+ runtime.afterAll(async () => {
2139
+ await eventEmitter.scenarioOutlineCompleted({
2140
+ feature: featureRef,
2141
+ scenarioOutline: outline.outline,
2142
+ ...firstRule ? { rule: createRuleRef(firstRule) } : {}
2143
+ });
2144
+ });
2145
+ lifecycle.configurePersistentScope(outline.scope, runtime);
2146
+ registerScenarioExecutions(outline.examples, runtime, config, tagFilter, lifecycle, feature);
2147
+ },
2148
+ timeout.milliseconds
2149
+ );
2150
+ }
2151
+ }
2152
+ function registerScenarios(scenarios, runtime, config, tagFilter, lifecycle, feature) {
2153
+ registerScenarioExecutions(scenarios, runtime, config, tagFilter, lifecycle, feature);
2154
+ }
2155
+ function registerScenarioExecutions(executions, runtime, config, tagFilter, lifecycle, feature) {
2156
+ const standaloneExecutions = [];
2157
+ const outlineExamples = /* @__PURE__ */ new Map();
2158
+ for (const execution of executions) {
2159
+ if (isScenarioOutlineExample2(execution)) {
2160
+ const outlineId = execution.outline.scope.id;
2161
+ let collection = outlineExamples.get(outlineId);
2162
+ if (!collection) {
2163
+ collection = {
2164
+ outline: execution.outline,
2165
+ order: [],
2166
+ groups: /* @__PURE__ */ new Map()
2167
+ };
2168
+ outlineExamples.set(outlineId, collection);
2169
+ }
2170
+ const groupId = execution.exampleGroup.id;
2171
+ let groupInfo = collection.groups.get(groupId);
2172
+ if (!groupInfo) {
2173
+ groupInfo = {
2174
+ group: execution.exampleGroup,
2175
+ examples: []
2176
+ };
2177
+ collection.groups.set(groupId, groupInfo);
2178
+ collection.order.push(groupId);
2179
+ }
2180
+ groupInfo.examples.push(execution);
2181
+ continue;
2182
+ }
2183
+ standaloneExecutions.push(execution);
2184
+ }
2185
+ for (const execution of standaloneExecutions) {
2186
+ scheduleScenario(execution, runtime, config, tagFilter, lifecycle, feature);
2187
+ }
2188
+ for (const collection of outlineExamples.values()) {
2189
+ const orderedGroups = collection.order.map((id) => collection.groups.get(id)).filter((info) => Boolean(info));
2190
+ if (orderedGroups.length === 0) {
2191
+ continue;
2192
+ }
2193
+ if (orderedGroups.length === 1) {
2194
+ const [singleGroup] = orderedGroups;
2195
+ if (singleGroup && !shouldDisplayExamplesGroup(singleGroup.group, orderedGroups.length)) {
2196
+ for (const example of singleGroup.examples) {
2197
+ scheduleScenario(example, runtime, config, tagFilter, lifecycle, feature);
2198
+ }
2199
+ continue;
2200
+ }
2201
+ }
2202
+ orderedGroups.forEach((info, index) => {
2203
+ const title = formatExamplesGroupTitle(info.group, index);
2204
+ const keyword = (info.group.keyword ?? "Examples").trim() || "Examples";
2205
+ runSuiteWithMetadata(
2206
+ runtime.suite,
2207
+ { kind: "examples", keyword },
2208
+ title,
2209
+ () => {
2210
+ for (const example of info.examples) {
2211
+ scheduleScenario(example, runtime, config, tagFilter, lifecycle, feature);
2212
+ }
2213
+ }
2214
+ );
2215
+ });
2216
+ }
2217
+ }
2218
+ function scheduleScenario(execution, runtime, config, tagFilter, lifecycle, feature) {
2219
+ const title = buildScenarioTitle(execution);
2220
+ const eventEmitter = events.getEventEmitter();
2221
+ if (!tagFilter.evaluate(execution.tags)) {
2222
+ runtime.test.skip(title, () => void 0);
2223
+ return;
2224
+ }
2225
+ if (execution.pending) {
2226
+ execution.markPending(execution.pendingReason);
2227
+ registerPendingScenarioTest(execution, runtime, title);
2228
+ return;
2229
+ }
2230
+ const effectiveMode = resolveModeFromTags(execution.mode, execution.tags);
2231
+ const testFn = selectTestByMode(runtime.test, effectiveMode);
2232
+ const scenarioTimeout = resolveTimeout(execution.timeout, config);
2233
+ testFn(title, async () => {
2234
+ const hooks = lifecycle.collectScenarioHooks(execution);
2235
+ const pickle = requirePickle(feature, execution.gherkin.id);
2236
+ const scenarioScope = pickle.scenario;
2237
+ const isExample = isScenarioOutlineExample2(execution);
2238
+ if (isExample) {
2239
+ await eventEmitter.exampleStarted({
2240
+ feature: pickle.feature,
2241
+ scenarioOutline: execution.outline.outline,
2242
+ example: execution.exampleGroup,
2243
+ pickle,
2244
+ ...pickle.rule ? { rule: pickle.rule } : {}
2245
+ });
2246
+ }
2247
+ await eventEmitter.scenarioStarted({
2248
+ feature: pickle.feature,
2249
+ scenario: scenarioScope,
2250
+ pickle,
2251
+ ...pickle.rule ? { rule: pickle.rule } : {}
2252
+ });
2253
+ let status;
2254
+ try {
2255
+ await lifecycle.runScenario(
2256
+ execution,
2257
+ hooks,
2258
+ async (_world, context) => {
2259
+ await runScenarioExecution(execution, context);
2260
+ },
2261
+ { events: { pickle } }
2262
+ );
2263
+ status = execution.result.status === "passed" ? events.TestStatus.PASSED : execution.result.status === "failed" ? events.TestStatus.FAILED : execution.result.status === "skipped" ? events.TestStatus.SKIPPED : execution.result.status === "pending" ? events.TestStatus.SKIPPED : void 0;
2264
+ } catch (error) {
2265
+ status = events.TestStatus.FAILED;
2266
+ if (!errors.isGherkinStepError(error)) {
2267
+ await eventEmitter.errorRaised({
2268
+ error,
2269
+ phase: "scenario",
2270
+ feature: pickle.feature,
2271
+ scenario: pickle.scenario,
2272
+ ...pickle.rule ? { rule: pickle.rule } : {},
2273
+ pickle
2274
+ });
2275
+ }
2276
+ throw error;
2277
+ } finally {
2278
+ if (status) {
2279
+ await eventEmitter.statusChanged({
2280
+ status,
2281
+ feature: pickle.feature,
2282
+ scenario: pickle.scenario,
2283
+ ...pickle.rule ? { rule: pickle.rule } : {},
2284
+ pickle,
2285
+ metadata: { result: execution.result }
2286
+ });
2287
+ }
2288
+ await eventEmitter.scenarioCompleted({
2289
+ feature: pickle.feature,
2290
+ scenario: scenarioScope,
2291
+ pickle,
2292
+ ...pickle.rule ? { rule: pickle.rule } : {},
2293
+ metadata: { result: execution.result }
2294
+ });
2295
+ if (isExample) {
2296
+ await eventEmitter.exampleCompleted({
2297
+ feature: pickle.feature,
2298
+ scenarioOutline: execution.outline.outline,
2299
+ example: execution.exampleGroup,
2300
+ pickle,
2301
+ ...pickle.rule ? { rule: pickle.rule } : {},
2302
+ metadata: { result: execution.result }
2303
+ });
2304
+ }
2305
+ }
2306
+ }, scenarioTimeout.milliseconds);
2307
+ }
2308
+ function registerPendingScenarioTest(execution, runtime, title) {
2309
+ const reason = execution.pendingReason;
2310
+ const { test } = runtime;
2311
+ if (typeof test.todo === "function") {
2312
+ test.todo(title, reason);
2313
+ return;
2314
+ }
2315
+ if (typeof test.pending === "function") {
2316
+ test.pending(title, reason);
2317
+ return;
2318
+ }
2319
+ if (typeof test.skip === "function") {
2320
+ test.skip(title, () => void 0);
2321
+ return;
2322
+ }
2323
+ test(title, () => void 0);
2324
+ }
2325
+ function buildScenarioTitle(execution) {
2326
+ if (!isScenarioOutlineExample2(execution)) {
2327
+ return execution.name;
2328
+ }
2329
+ const descriptor = formatExampleDescriptor(execution);
2330
+ if (!descriptor) {
2331
+ return `${execution.name} [Example ${execution.exampleIndex + 1}]`;
2332
+ }
2333
+ return `${execution.name} [${descriptor}]`;
2334
+ }
2335
+ function formatExampleDescriptor(example) {
2336
+ const segments = [];
2337
+ segments.push(`Example ${example.exampleIndex + 1}`);
2338
+ const groupName = example.exampleGroup.name?.trim();
2339
+ if (groupName) {
2340
+ segments.push(groupName);
2341
+ }
2342
+ const valueSummary = formatExampleValues(example.exampleGroup, example.exampleIndex);
2343
+ if (valueSummary) {
2344
+ segments.push(valueSummary);
2345
+ }
2346
+ return segments.length > 0 ? segments.join(" \xB7 ") : void 0;
2347
+ }
2348
+ function formatExampleValues(group, index) {
2349
+ const headers = group.tableHeader ?? [];
2350
+ const rows = group.tableBody ?? [];
2351
+ const row = rows[index];
2352
+ if (!row || headers.length === 0) {
2353
+ return void 0;
2354
+ }
2355
+ const pairs = [];
2356
+ headers.forEach((header, headerIndex) => {
2357
+ const key = header?.trim();
2358
+ if (!key) {
2359
+ return;
2360
+ }
2361
+ const value = row[headerIndex] ?? "";
2362
+ pairs.push(`${key}=${String(value).trim()}`);
2363
+ });
2364
+ return pairs.length > 0 ? pairs.join(", ") : void 0;
2365
+ }
2366
+
2367
+ // src/index.ts
2368
+ var src_default = {};
2369
+
2370
+ exports.Pending = Pending;
2371
+ exports.ScenarioPendingError = ScenarioPendingError;
2372
+ exports.ScopeLifecycle = ScopeLifecycle;
2373
+ exports.ToDo = ToDo;
2374
+ exports.chooseTimeout = chooseTimeout;
2375
+ exports.clearStepDocstring = clearStepDocstring;
2376
+ exports.clearStepMetadata = clearStepMetadata;
2377
+ exports.clearStepTable = clearStepTable;
2378
+ exports.collectScenarioHooks = collectScenarioHooks;
2379
+ exports.configureStepDocstrings = configureStepDocstrings;
2380
+ exports.configureStepTables = configureStepTables;
2381
+ exports.consumeDocstring = consumeDocstring;
2382
+ exports.consumeTable = consumeTable;
2383
+ exports.createStepRuntime = createStepRuntime;
2384
+ exports.createTagFilter = createTagFilter;
2385
+ exports.default = src_default;
2386
+ exports.getDocstring = getDocstring;
2387
+ exports.getDocstringInfo = getDocstringInfo;
2388
+ exports.getDocstringMediaType = getDocstringMediaType;
2389
+ exports.getRawTable = getRawTable;
2390
+ exports.getStepMetadata = getStepMetadata;
2391
+ exports.getTable = getTable;
2392
+ exports.getWorld = getWorld;
2393
+ exports.isScenarioPendingError = isScenarioPendingError;
2394
+ exports.markScenarioPending = markScenarioPending;
2395
+ exports.registerFeaturePlan = registerFeaturePlan;
2396
+ exports.resetStepDocstringConfig = resetStepDocstringConfig;
2397
+ exports.resetStepTableConfig = resetStepTableConfig;
2398
+ exports.resolveModeFromTags = resolveModeFromTags;
2399
+ exports.resolveTimeout = resolveTimeout;
2400
+ exports.runScenarioExecution = runScenarioExecution;
2401
+ exports.selectSuiteByMode = selectSuiteByMode;
2402
+ exports.selectTestByMode = selectTestByMode;
2403
+ exports.setStepDocstring = setStepDocstring;
2404
+ exports.setStepDocstringInfo = setStepDocstringInfo;
2405
+ exports.setStepMetadata = setStepMetadata;
2406
+ exports.setStepTable = setStepTable;
2407
+ exports.tryGetWorld = tryGetWorld;
2408
+ //# sourceMappingURL=out.js.map
2409
+ //# sourceMappingURL=index.cjs.map