@autometa/jest-transformer 0.1.110 → 1.0.0-rc.2

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 CHANGED
@@ -1,3 +1,74 @@
1
- # Introduction
1
+ # @autometa/jest-transformer
2
2
 
3
- There's nothing here yet
3
+ Jest transformer for Autometa - transforms `.feature` files into Jest test suites.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @autometa/jest-transformer @autometa/jest-executor @autometa/runner @autometa/gherkin
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ Configure Jest to use the transformer for `.feature` files:
14
+
15
+ ```javascript
16
+ // jest.config.js
17
+ module.exports = {
18
+ transform: {
19
+ "^.+\\.feature$": "@autometa/jest-transformer"
20
+ },
21
+ testMatch: ["**/*.feature"],
22
+ // Required for TypeScript step definitions
23
+ moduleFileExtensions: ["ts", "tsx", "js", "jsx", "feature"]
24
+ };
25
+ ```
26
+
27
+ ## Configuration
28
+
29
+ The transformer reads from `autometa.config.ts` (or `.js`, `.mjs`, etc.) in your project root.
30
+
31
+ ```typescript
32
+ // autometa.config.ts
33
+ import { defineConfig } from "@autometa/config";
34
+
35
+ export default defineConfig({
36
+ roots: {
37
+ features: ["./features"],
38
+ steps: ["./src/step-definitions.ts"]
39
+ }
40
+ });
41
+ ```
42
+
43
+ ### Transformer Options
44
+
45
+ You can pass options to the transformer:
46
+
47
+ ```javascript
48
+ // jest.config.js
49
+ module.exports = {
50
+ transform: {
51
+ "^.+\\.feature$": [
52
+ "@autometa/jest-transformer",
53
+ {
54
+ configPath: "./custom-autometa.config.ts"
55
+ }
56
+ ]
57
+ }
58
+ };
59
+ ```
60
+
61
+ ## How It Works
62
+
63
+ The transformer:
64
+
65
+ 1. Reads your `autometa.config.ts` to locate step definition files
66
+ 2. Parses the Gherkin feature file
67
+ 3. Generates Jest test code that:
68
+ - Imports your step definitions
69
+ - Creates `describe` blocks for features
70
+ - Uses `@autometa/jest-executor` to run scenarios
71
+
72
+ ## License
73
+
74
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,445 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var path = require('path');
6
+ var fs = require('fs');
7
+ var jiti = require('jiti');
8
+
9
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
+
11
+ var jiti__default = /*#__PURE__*/_interopDefault(jiti);
12
+
13
+ // src/index.ts
14
+ var STEP_FALLBACK_GLOB = "**/*.{ts,tsx,js,jsx,mjs,cjs,mts,cts}";
15
+ var cachedConfig;
16
+ var cachedProjectRoot;
17
+ function process(sourceText, sourcePath, options) {
18
+ const projectRoot = options.config.rootDir;
19
+ if (!cachedConfig || cachedProjectRoot !== projectRoot) {
20
+ const configPath2 = options.transformerConfig?.configPath;
21
+ cachedConfig = loadAutometaConfig(projectRoot, configPath2);
22
+ cachedProjectRoot = projectRoot;
23
+ }
24
+ const autometaConfig = cachedConfig.config;
25
+ const configPath = cachedConfig.path;
26
+ const resolved = autometaConfig.resolve();
27
+ const stepRoots = resolved.config.roots.steps;
28
+ const configDir = configPath ? path.dirname(configPath) : projectRoot;
29
+ const stepGlobs = buildStepGlobs(stepRoots, {
30
+ configDir,
31
+ projectRoot
32
+ });
33
+ if (stepGlobs.length === 0) {
34
+ throw new Error(
35
+ "Autometa config did not resolve any step files within the current project root."
36
+ );
37
+ }
38
+ const eventRequires = generateEventRequires(resolved.config.events, configDir);
39
+ const stepRequires = generateStepRequires(stepRoots, configDir);
40
+ const runtimeConfig = JSON.stringify(resolved.config);
41
+ const gherkinContent = JSON.stringify(sourceText);
42
+ const code = `
43
+ const { describe, beforeAll, afterAll, beforeEach, afterEach, it, expect } = require('@jest/globals');
44
+ const { execute } = require('@autometa/jest-executor');
45
+ const { coordinateRunnerFeature, CucumberRunner } = require('@autometa/runner');
46
+ const { parseGherkin } = require('@autometa/gherkin');
47
+
48
+ ${eventRequires}
49
+ ${stepRequires}
50
+
51
+ function collectCandidateModules(imported) {
52
+ if (!imported || typeof imported !== 'object') {
53
+ return [];
54
+ }
55
+
56
+ const modules = new Set();
57
+ modules.add(imported);
58
+
59
+ const exportedModules = imported.modules;
60
+ if (Array.isArray(exportedModules)) {
61
+ for (const entry of exportedModules) {
62
+ if (entry && typeof entry === 'object') {
63
+ modules.add(entry);
64
+ }
65
+ }
66
+ }
67
+
68
+ const defaultExport = imported.default;
69
+ if (Array.isArray(defaultExport)) {
70
+ for (const entry of defaultExport) {
71
+ if (entry && typeof entry === 'object') {
72
+ modules.add(entry);
73
+ }
74
+ }
75
+ } else if (defaultExport && typeof defaultExport === 'object') {
76
+ modules.add(defaultExport);
77
+ }
78
+
79
+ return Array.from(modules);
80
+ }
81
+
82
+ function isStepsEnvironment(candidate) {
83
+ return Boolean(
84
+ candidate &&
85
+ typeof candidate === 'object' &&
86
+ typeof candidate.coordinateFeature === 'function' &&
87
+ typeof candidate.getPlan === 'function' &&
88
+ typeof candidate.Given === 'function' &&
89
+ typeof candidate.When === 'function' &&
90
+ typeof candidate.Then === 'function'
91
+ );
92
+ }
93
+
94
+ function extractStepsEnvironment(candidate) {
95
+ if (!candidate || typeof candidate !== 'object') {
96
+ return undefined;
97
+ }
98
+
99
+ if (isStepsEnvironment(candidate)) {
100
+ return candidate;
101
+ }
102
+
103
+ const stepsEnv = candidate.stepsEnvironment;
104
+ if (isStepsEnvironment(stepsEnv)) {
105
+ return stepsEnv;
106
+ }
107
+
108
+ const defaultExport = candidate.default;
109
+ if (isStepsEnvironment(defaultExport)) {
110
+ return defaultExport;
111
+ }
112
+
113
+ return undefined;
114
+ }
115
+
116
+ function resolveStepsEnvironment(modules) {
117
+ for (const moduleExports of modules) {
118
+ for (const candidate of collectCandidateModules(moduleExports)) {
119
+ const environment = extractStepsEnvironment(candidate);
120
+ if (environment) {
121
+ return environment;
122
+ }
123
+ }
124
+ }
125
+ return undefined;
126
+ }
127
+
128
+ function isScenario(element) {
129
+ return Boolean(
130
+ element &&
131
+ typeof element === 'object' &&
132
+ 'steps' in element &&
133
+ !('exampleGroups' in element) &&
134
+ !('elements' in element)
135
+ );
136
+ }
137
+
138
+ function isScenarioOutline(element) {
139
+ return Boolean(
140
+ element &&
141
+ typeof element === 'object' &&
142
+ 'steps' in element &&
143
+ 'exampleGroups' in element
144
+ );
145
+ }
146
+
147
+ function isRule(element) {
148
+ return Boolean(
149
+ element &&
150
+ typeof element === 'object' &&
151
+ 'elements' in element &&
152
+ Array.isArray(element.elements)
153
+ );
154
+ }
155
+
156
+ function createFeatureScopePlan(feature, basePlan) {
157
+ const allSteps = Array.from(basePlan.stepsById.values());
158
+ const featureChildren = [];
159
+ const scopesById = new Map(basePlan.scopesById);
160
+
161
+ for (const element of feature.elements ?? []) {
162
+ if (isScenario(element) || isScenarioOutline(element)) {
163
+ const scenarioScope = {
164
+ id: element.id ?? element.name,
165
+ kind: isScenarioOutline(element) ? 'scenarioOutline' : 'scenario',
166
+ name: element.name,
167
+ mode: 'default',
168
+ tags: element.tags ?? [],
169
+ steps: allSteps,
170
+ hooks: [],
171
+ children: [],
172
+ pending: false,
173
+ };
174
+ featureChildren.push(scenarioScope);
175
+ scopesById.set(scenarioScope.id, scenarioScope);
176
+ continue;
177
+ }
178
+
179
+ if (isRule(element)) {
180
+ const ruleChildren = [];
181
+ for (const ruleElement of element.elements ?? []) {
182
+ if (isScenario(ruleElement) || isScenarioOutline(ruleElement)) {
183
+ const scenarioScope = {
184
+ id: ruleElement.id ?? ruleElement.name,
185
+ kind: isScenarioOutline(ruleElement) ? 'scenarioOutline' : 'scenario',
186
+ name: ruleElement.name,
187
+ mode: 'default',
188
+ tags: ruleElement.tags ?? [],
189
+ steps: allSteps,
190
+ hooks: [],
191
+ children: [],
192
+ pending: false,
193
+ };
194
+ ruleChildren.push(scenarioScope);
195
+ scopesById.set(scenarioScope.id, scenarioScope);
196
+ }
197
+ }
198
+
199
+ const ruleScope = {
200
+ id: element.id ?? element.name,
201
+ kind: 'rule',
202
+ name: element.name,
203
+ mode: 'default',
204
+ tags: element.tags ?? [],
205
+ steps: allSteps,
206
+ hooks: [],
207
+ children: ruleChildren,
208
+ pending: false,
209
+ };
210
+ featureChildren.push(ruleScope);
211
+ scopesById.set(ruleScope.id, ruleScope);
212
+ }
213
+ }
214
+
215
+ const featureScope = {
216
+ id: feature.uri ?? feature.name,
217
+ kind: 'feature',
218
+ name: feature.name,
219
+ mode: 'default',
220
+ tags: feature.tags ?? [],
221
+ steps: allSteps,
222
+ hooks: [],
223
+ children: featureChildren,
224
+ pending: false,
225
+ };
226
+
227
+ const existingRoot = basePlan.root;
228
+ const updatedRoot = {
229
+ ...existingRoot,
230
+ children: [...existingRoot.children, featureScope],
231
+ };
232
+
233
+ scopesById.set(featureScope.id, featureScope);
234
+ scopesById.set(updatedRoot.id, updatedRoot);
235
+
236
+ const scopePlan = {
237
+ root: updatedRoot,
238
+ stepsById: basePlan.stepsById,
239
+ hooksById: basePlan.hooksById,
240
+ scopesById,
241
+ };
242
+
243
+ if (basePlan.worldFactory) {
244
+ scopePlan.worldFactory = basePlan.worldFactory;
245
+ }
246
+
247
+ if (basePlan.parameterRegistry) {
248
+ scopePlan.parameterRegistry = basePlan.parameterRegistry;
249
+ }
250
+
251
+ return scopePlan;
252
+ }
253
+
254
+ const gherkin = ${gherkinContent};
255
+ const feature = parseGherkin(gherkin);
256
+ const steps = resolveStepsEnvironment(stepModules);
257
+
258
+ if (!steps) {
259
+ throw new Error('Autometa could not find an exported steps environment for the configured step roots. Export your runner environment as "stepsEnvironment" or default.');
260
+ }
261
+
262
+ CucumberRunner.setSteps(steps);
263
+
264
+ describe(feature.name, () => {
265
+ const basePlan = steps.getPlan();
266
+ const scopedPlan = createFeatureScopePlan(feature, basePlan);
267
+ const { plan, adapter } = coordinateRunnerFeature({
268
+ feature,
269
+ environment: steps,
270
+ config: ${runtimeConfig},
271
+ plan: scopedPlan
272
+ });
273
+
274
+ execute({ plan, adapter, config: ${runtimeConfig} });
275
+ });
276
+ `;
277
+ return { code };
278
+ }
279
+ function generateStepRequires(stepRoots, configDir, _projectRoot) {
280
+ if (!stepRoots || stepRoots.length === 0) {
281
+ return "const stepModules = [];";
282
+ }
283
+ const requires = [];
284
+ let moduleIndex = 0;
285
+ for (const root of stepRoots) {
286
+ const normalizedRoot = root.trim();
287
+ if (!normalizedRoot) {
288
+ continue;
289
+ }
290
+ const absolutePath = path.isAbsolute(normalizedRoot) ? normalizedRoot : path.resolve(configDir, normalizedRoot);
291
+ if (fs.existsSync(absolutePath)) {
292
+ const normalizedAbsolutePath = normalizeSlashes(absolutePath);
293
+ requires.push(`const stepModule${moduleIndex} = require('${normalizedAbsolutePath}');`);
294
+ moduleIndex++;
295
+ }
296
+ }
297
+ if (requires.length === 0) {
298
+ return "const stepModules = [];";
299
+ }
300
+ const moduleList = Array.from({ length: moduleIndex }, (_, i) => `stepModule${i}`).join(", ");
301
+ return `${requires.join("\n")}
302
+ const stepModules = [${moduleList}];`;
303
+ }
304
+ function generateEventRequires(eventModules, configDir) {
305
+ if (!eventModules || eventModules.length === 0) {
306
+ return "";
307
+ }
308
+ const requires = [];
309
+ for (const entry of eventModules) {
310
+ const normalized = entry.trim();
311
+ if (!normalized) {
312
+ continue;
313
+ }
314
+ const absolutePath = path.isAbsolute(normalized) ? normalized : path.resolve(configDir, normalized);
315
+ if (!fs.existsSync(absolutePath)) {
316
+ continue;
317
+ }
318
+ const normalizedAbsolutePath = normalizeSlashes(absolutePath);
319
+ requires.push(`require('${normalizedAbsolutePath}');`);
320
+ }
321
+ return requires.length > 0 ? requires.join("\n") : "";
322
+ }
323
+ function buildStepGlobs(entries, options) {
324
+ if (!entries || entries.length === 0) {
325
+ return [];
326
+ }
327
+ const patterns = /* @__PURE__ */ new Set();
328
+ for (const entry of entries) {
329
+ const normalized = entry.trim();
330
+ if (!normalized) {
331
+ continue;
332
+ }
333
+ for (const candidate of toPatterns(normalized, STEP_FALLBACK_GLOB)) {
334
+ const absolute = path.isAbsolute(candidate) ? normalizeSlashes(candidate) : normalizeSlashes(path.resolve(options.configDir, candidate));
335
+ const rootRelative = toRootRelativeGlob(absolute, options.projectRoot);
336
+ patterns.add(rootRelative);
337
+ }
338
+ }
339
+ return Array.from(patterns);
340
+ }
341
+ function toPatterns(entry, fallbackGlob) {
342
+ if (hasGlobMagic(entry) || hasFileExtension(entry)) {
343
+ return [entry];
344
+ }
345
+ return [appendGlob(entry, fallbackGlob)];
346
+ }
347
+ function hasGlobMagic(input) {
348
+ return /[*?{}()[\]!,@+]/u.test(input);
349
+ }
350
+ function hasFileExtension(input) {
351
+ const normalized = normalizeSlashes(input);
352
+ const trimmed = normalized === "/" ? normalized : normalized.replace(/\/+$/u, "");
353
+ if (!trimmed || trimmed === "." || trimmed === "..") {
354
+ return false;
355
+ }
356
+ return Boolean(path.extname(trimmed));
357
+ }
358
+ function appendGlob(entry, glob) {
359
+ const normalized = normalizeSlashes(entry);
360
+ const trimmed = normalized === "/" ? normalized : normalized.replace(/\/+$/u, "");
361
+ if (!trimmed || trimmed === ".") {
362
+ return glob;
363
+ }
364
+ if (trimmed === "/") {
365
+ return `/${glob}`;
366
+ }
367
+ return `${trimmed}/${glob}`;
368
+ }
369
+ function toRootRelativeGlob(pattern, rootDir) {
370
+ const normalizedRoot = normalizeSlashes(rootDir);
371
+ const normalizedPattern = normalizeSlashes(pattern);
372
+ let relativePattern = normalizeSlashes(path.relative(normalizedRoot, normalizedPattern));
373
+ if (!relativePattern || relativePattern === ".") {
374
+ relativePattern = "";
375
+ }
376
+ if (!relativePattern || relativePattern.startsWith("..")) {
377
+ return ensureGlobPrefix(normalizedPattern);
378
+ }
379
+ return ensureGlobPrefix(relativePattern);
380
+ }
381
+ function ensureGlobPrefix(pattern) {
382
+ if (/^[A-Za-z]:\//u.test(pattern)) {
383
+ return pattern;
384
+ }
385
+ if (pattern.startsWith("/")) {
386
+ return pattern;
387
+ }
388
+ return `/${pattern.replace(/^\/+/, "")}`;
389
+ }
390
+ function normalizeSlashes(pathname) {
391
+ return pathname.replace(/\\/gu, "/");
392
+ }
393
+ function loadAutometaConfig(root, explicitPath) {
394
+ const _jiti = jiti__default.default(root, { interopDefault: true });
395
+ if (explicitPath) {
396
+ const absolutePath = path.isAbsolute(explicitPath) ? explicitPath : path.resolve(root, explicitPath);
397
+ if (!fs.existsSync(absolutePath)) {
398
+ throw new Error(`Autometa config not found at ${absolutePath}`);
399
+ }
400
+ const mod = _jiti(absolutePath);
401
+ const config = mod.default || mod;
402
+ if (!isConfig(config)) {
403
+ throw new Error(`Config at ${absolutePath} does not export a valid Config instance.`);
404
+ }
405
+ return { config, path: absolutePath };
406
+ }
407
+ const candidates = [
408
+ "autometa.config.ts",
409
+ "autometa.config.js",
410
+ "autometa.config.mts",
411
+ "autometa.config.mjs",
412
+ "autometa.config.cts",
413
+ "autometa.config.cjs"
414
+ ];
415
+ for (const candidate of candidates) {
416
+ const path$1 = path.resolve(root, candidate);
417
+ if (!fs.existsSync(path$1)) {
418
+ continue;
419
+ }
420
+ try {
421
+ const mod = _jiti(path$1);
422
+ const config = mod.default || mod;
423
+ if (isConfig(config)) {
424
+ return { config, path: path$1 };
425
+ } else {
426
+ console.warn(`Found config at ${path$1} but it does not export a Config instance.`);
427
+ }
428
+ } catch (error) {
429
+ console.error(`Error loading config at ${path$1}:`, error);
430
+ throw error;
431
+ }
432
+ }
433
+ throw new Error("Could not find autometa.config.{ts,js,mjs,cjs} in " + root);
434
+ }
435
+ function isConfig(config) {
436
+ return typeof config === "object" && config !== null && "resolve" in config && typeof config.resolve === "function" && "current" in config && typeof config.current === "function";
437
+ }
438
+ var src_default = {
439
+ process
440
+ };
441
+
442
+ exports.default = src_default;
443
+ exports.process = process;
444
+ //# sourceMappingURL=out.js.map
445
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":["configPath"],"mappings":"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","sourcesContent":["import { resolve, isAbsolute, relative, dirname, extname } from \"path\";\nimport { existsSync } from \"fs\";\nimport type { Config } from \"@autometa/config\";\nimport jiti from \"jiti\";\n\nconst STEP_FALLBACK_GLOB = \"**/*.{ts,tsx,js,jsx,mjs,cjs,mts,cts}\";\n\n/**\n * Jest transformer options that can be passed via jest.config.js\n */\nexport interface JestTransformerOptions {\n /**\n * Path to the autometa config file. If not provided, will search for\n * autometa.config.{ts,js,mts,mjs,cts,cjs} in the project root.\n */\n readonly configPath?: string;\n}\n\ninterface TransformOptions {\n readonly config: {\n readonly rootDir: string;\n };\n readonly transformerConfig?: JestTransformerOptions;\n}\n\ninterface TransformResult {\n readonly code: string;\n readonly map?: unknown;\n}\n\ninterface StepGlobOptions {\n readonly configDir: string;\n readonly projectRoot: string;\n}\n\nlet cachedConfig: { config: Config; path: string } | undefined;\nlet cachedProjectRoot: string | undefined;\n\n/**\n * Jest transformer for .feature files.\n * Converts Gherkin feature files into Jest test suites.\n */\nexport function process(\n sourceText: string,\n sourcePath: string,\n options: TransformOptions\n): TransformResult {\n const projectRoot = options.config.rootDir;\n\n // Load config if not cached or project root changed\n if (!cachedConfig || cachedProjectRoot !== projectRoot) {\n const configPath = options.transformerConfig?.configPath;\n cachedConfig = loadAutometaConfig(projectRoot, configPath);\n cachedProjectRoot = projectRoot;\n }\n\n const autometaConfig = cachedConfig.config;\n const configPath = cachedConfig.path;\n\n const resolved = autometaConfig.resolve();\n const stepRoots = resolved.config.roots.steps;\n const configDir = configPath ? dirname(configPath) : projectRoot;\n \n const stepGlobs = buildStepGlobs(stepRoots, {\n configDir,\n projectRoot,\n });\n\n if (stepGlobs.length === 0) {\n throw new Error(\n \"Autometa config did not resolve any step files within the current project root.\"\n );\n }\n\n // For Jest, we need to use require.context or manual requires\n // Since Jest doesn't have import.meta.glob, we generate explicit requires\n const eventRequires = generateEventRequires(resolved.config.events, configDir);\n const stepRequires = generateStepRequires(stepRoots, configDir, projectRoot);\n const runtimeConfig = JSON.stringify(resolved.config);\n const gherkinContent = JSON.stringify(sourceText);\n\n const code = `\nconst { describe, beforeAll, afterAll, beforeEach, afterEach, it, expect } = require('@jest/globals');\nconst { execute } = require('@autometa/jest-executor');\nconst { coordinateRunnerFeature, CucumberRunner } = require('@autometa/runner');\nconst { parseGherkin } = require('@autometa/gherkin');\n\n${eventRequires}\n${stepRequires}\n\nfunction collectCandidateModules(imported) {\n if (!imported || typeof imported !== 'object') {\n return [];\n }\n\n const modules = new Set();\n modules.add(imported);\n\n const exportedModules = imported.modules;\n if (Array.isArray(exportedModules)) {\n for (const entry of exportedModules) {\n if (entry && typeof entry === 'object') {\n modules.add(entry);\n }\n }\n }\n\n const defaultExport = imported.default;\n if (Array.isArray(defaultExport)) {\n for (const entry of defaultExport) {\n if (entry && typeof entry === 'object') {\n modules.add(entry);\n }\n }\n } else if (defaultExport && typeof defaultExport === 'object') {\n modules.add(defaultExport);\n }\n\n return Array.from(modules);\n}\n\nfunction isStepsEnvironment(candidate) {\n return Boolean(\n candidate &&\n typeof candidate === 'object' &&\n typeof candidate.coordinateFeature === 'function' &&\n typeof candidate.getPlan === 'function' &&\n typeof candidate.Given === 'function' &&\n typeof candidate.When === 'function' &&\n typeof candidate.Then === 'function'\n );\n}\n\nfunction extractStepsEnvironment(candidate) {\n if (!candidate || typeof candidate !== 'object') {\n return undefined;\n }\n\n if (isStepsEnvironment(candidate)) {\n return candidate;\n }\n\n const stepsEnv = candidate.stepsEnvironment;\n if (isStepsEnvironment(stepsEnv)) {\n return stepsEnv;\n }\n\n const defaultExport = candidate.default;\n if (isStepsEnvironment(defaultExport)) {\n return defaultExport;\n }\n\n return undefined;\n}\n\nfunction resolveStepsEnvironment(modules) {\n for (const moduleExports of modules) {\n for (const candidate of collectCandidateModules(moduleExports)) {\n const environment = extractStepsEnvironment(candidate);\n if (environment) {\n return environment;\n }\n }\n }\n return undefined;\n}\n\nfunction isScenario(element) {\n return Boolean(\n element &&\n typeof element === 'object' &&\n 'steps' in element &&\n !('exampleGroups' in element) &&\n !('elements' in element)\n );\n}\n\nfunction isScenarioOutline(element) {\n return Boolean(\n element &&\n typeof element === 'object' &&\n 'steps' in element &&\n 'exampleGroups' in element\n );\n}\n\nfunction isRule(element) {\n return Boolean(\n element &&\n typeof element === 'object' &&\n 'elements' in element &&\n Array.isArray(element.elements)\n );\n}\n\nfunction createFeatureScopePlan(feature, basePlan) {\n const allSteps = Array.from(basePlan.stepsById.values());\n const featureChildren = [];\n const scopesById = new Map(basePlan.scopesById);\n\n for (const element of feature.elements ?? []) {\n if (isScenario(element) || isScenarioOutline(element)) {\n const scenarioScope = {\n id: element.id ?? element.name,\n kind: isScenarioOutline(element) ? 'scenarioOutline' : 'scenario',\n name: element.name,\n mode: 'default',\n tags: element.tags ?? [],\n steps: allSteps,\n hooks: [],\n children: [],\n pending: false,\n };\n featureChildren.push(scenarioScope);\n scopesById.set(scenarioScope.id, scenarioScope);\n continue;\n }\n\n if (isRule(element)) {\n const ruleChildren = [];\n for (const ruleElement of element.elements ?? []) {\n if (isScenario(ruleElement) || isScenarioOutline(ruleElement)) {\n const scenarioScope = {\n id: ruleElement.id ?? ruleElement.name,\n kind: isScenarioOutline(ruleElement) ? 'scenarioOutline' : 'scenario',\n name: ruleElement.name,\n mode: 'default',\n tags: ruleElement.tags ?? [],\n steps: allSteps,\n hooks: [],\n children: [],\n pending: false,\n };\n ruleChildren.push(scenarioScope);\n scopesById.set(scenarioScope.id, scenarioScope);\n }\n }\n\n const ruleScope = {\n id: element.id ?? element.name,\n kind: 'rule',\n name: element.name,\n mode: 'default',\n tags: element.tags ?? [],\n steps: allSteps,\n hooks: [],\n children: ruleChildren,\n pending: false,\n };\n featureChildren.push(ruleScope);\n scopesById.set(ruleScope.id, ruleScope);\n }\n }\n\n const featureScope = {\n id: feature.uri ?? feature.name,\n kind: 'feature',\n name: feature.name,\n mode: 'default',\n tags: feature.tags ?? [],\n steps: allSteps,\n hooks: [],\n children: featureChildren,\n pending: false,\n };\n\n const existingRoot = basePlan.root;\n const updatedRoot = {\n ...existingRoot,\n children: [...existingRoot.children, featureScope],\n };\n\n scopesById.set(featureScope.id, featureScope);\n scopesById.set(updatedRoot.id, updatedRoot);\n\n const scopePlan = {\n root: updatedRoot,\n stepsById: basePlan.stepsById,\n hooksById: basePlan.hooksById,\n scopesById,\n };\n\n if (basePlan.worldFactory) {\n scopePlan.worldFactory = basePlan.worldFactory;\n }\n\n if (basePlan.parameterRegistry) {\n scopePlan.parameterRegistry = basePlan.parameterRegistry;\n }\n\n return scopePlan;\n}\n\nconst gherkin = ${gherkinContent};\nconst feature = parseGherkin(gherkin);\nconst steps = resolveStepsEnvironment(stepModules);\n\nif (!steps) {\n throw new Error('Autometa could not find an exported steps environment for the configured step roots. Export your runner environment as \"stepsEnvironment\" or default.');\n}\n\nCucumberRunner.setSteps(steps);\n\ndescribe(feature.name, () => {\n const basePlan = steps.getPlan();\n const scopedPlan = createFeatureScopePlan(feature, basePlan);\n const { plan, adapter } = coordinateRunnerFeature({\n feature,\n environment: steps,\n config: ${runtimeConfig},\n plan: scopedPlan\n });\n\n execute({ plan, adapter, config: ${runtimeConfig} });\n});\n`;\n\n return { code };\n}\n\n/**\n * Generate require statements for step definition files.\n * Since Jest doesn't have import.meta.glob, we need to explicitly require files.\n * Uses absolute paths to ensure require works from any feature file location.\n */\nfunction generateStepRequires(\n stepRoots: readonly string[] | undefined,\n configDir: string,\n _projectRoot: string\n): string {\n if (!stepRoots || stepRoots.length === 0) {\n return \"const stepModules = [];\";\n }\n\n const requires: string[] = [];\n let moduleIndex = 0;\n\n for (const root of stepRoots) {\n const normalizedRoot = root.trim();\n if (!normalizedRoot) {\n continue;\n }\n\n // Resolve the step root path to absolute\n const absolutePath = isAbsolute(normalizedRoot)\n ? normalizedRoot\n : resolve(configDir, normalizedRoot);\n\n // Check if it's a file or directory\n if (existsSync(absolutePath)) {\n // Use absolute path to ensure require works from any feature file location\n const normalizedAbsolutePath = normalizeSlashes(absolutePath);\n requires.push(`const stepModule${moduleIndex} = require('${normalizedAbsolutePath}');`);\n moduleIndex++;\n }\n }\n\n if (requires.length === 0) {\n return \"const stepModules = [];\";\n }\n\n const moduleList = Array.from({ length: moduleIndex }, (_, i) => `stepModule${i}`).join(\", \");\n return `${requires.join(\"\\n\")}\\nconst stepModules = [${moduleList}];`;\n}\n\n/**\n * Generate require statements for event listener modules.\n * These modules are imported for side effects (e.g. registering listeners).\n */\nfunction generateEventRequires(\n eventModules: readonly string[] | undefined,\n configDir: string\n): string {\n if (!eventModules || eventModules.length === 0) {\n return \"\";\n }\n\n const requires: string[] = [];\n\n for (const entry of eventModules) {\n const normalized = entry.trim();\n if (!normalized) {\n continue;\n }\n\n const absolutePath = isAbsolute(normalized)\n ? normalized\n : resolve(configDir, normalized);\n\n if (!existsSync(absolutePath)) {\n continue;\n }\n\n const normalizedAbsolutePath = normalizeSlashes(absolutePath);\n requires.push(`require('${normalizedAbsolutePath}');`);\n }\n\n return requires.length > 0 ? requires.join(\"\\n\") : \"\";\n}\n\nfunction buildStepGlobs(\n entries: readonly string[] | undefined,\n options: StepGlobOptions\n): string[] {\n if (!entries || entries.length === 0) {\n return [];\n }\n\n const patterns = new Set<string>();\n for (const entry of entries) {\n const normalized = entry.trim();\n if (!normalized) {\n continue;\n }\n\n for (const candidate of toPatterns(normalized, STEP_FALLBACK_GLOB)) {\n const absolute = isAbsolute(candidate)\n ? normalizeSlashes(candidate)\n : normalizeSlashes(resolve(options.configDir, candidate));\n const rootRelative = toRootRelativeGlob(absolute, options.projectRoot);\n patterns.add(rootRelative);\n }\n }\n\n return Array.from(patterns);\n}\n\nfunction toPatterns(entry: string, fallbackGlob: string): string[] {\n if (hasGlobMagic(entry) || hasFileExtension(entry)) {\n return [entry];\n }\n return [appendGlob(entry, fallbackGlob)];\n}\n\nfunction hasGlobMagic(input: string): boolean {\n return /[*?{}()[\\]!,@+]/u.test(input);\n}\n\nfunction hasFileExtension(input: string): boolean {\n const normalized = normalizeSlashes(input);\n const trimmed = normalized === \"/\" ? normalized : normalized.replace(/\\/+$/u, \"\");\n if (!trimmed || trimmed === \".\" || trimmed === \"..\") {\n return false;\n }\n return Boolean(extname(trimmed));\n}\n\nfunction appendGlob(entry: string, glob: string): string {\n const normalized = normalizeSlashes(entry);\n const trimmed = normalized === \"/\" ? normalized : normalized.replace(/\\/+$/u, \"\");\n if (!trimmed || trimmed === \".\") {\n return glob;\n }\n if (trimmed === \"/\") {\n return `/${glob}`;\n }\n return `${trimmed}/${glob}`;\n}\n\nfunction toRootRelativeGlob(pattern: string, rootDir: string): string {\n const normalizedRoot = normalizeSlashes(rootDir);\n const normalizedPattern = normalizeSlashes(pattern);\n let relativePattern = normalizeSlashes(relative(normalizedRoot, normalizedPattern));\n\n if (!relativePattern || relativePattern === \".\") {\n relativePattern = \"\";\n }\n\n if (!relativePattern || relativePattern.startsWith(\"..\")) {\n return ensureGlobPrefix(normalizedPattern);\n }\n\n return ensureGlobPrefix(relativePattern);\n}\n\nfunction ensureGlobPrefix(pattern: string): string {\n if (/^[A-Za-z]:\\//u.test(pattern)) {\n return pattern;\n }\n if (pattern.startsWith(\"/\")) {\n return pattern;\n }\n return `/${pattern.replace(/^\\/+/, \"\")}`;\n}\n\nfunction normalizeSlashes(pathname: string): string {\n return pathname.replace(/\\\\/gu, \"/\");\n}\n\nfunction loadAutometaConfig(\n root: string,\n explicitPath?: string\n): { config: Config; path: string } {\n const _jiti = jiti(root, { interopDefault: true });\n\n if (explicitPath) {\n const absolutePath = isAbsolute(explicitPath)\n ? explicitPath\n : resolve(root, explicitPath);\n\n if (!existsSync(absolutePath)) {\n throw new Error(`Autometa config not found at ${absolutePath}`);\n }\n\n const mod = _jiti(absolutePath);\n const config = mod.default || mod;\n\n if (!isConfig(config)) {\n throw new Error(`Config at ${absolutePath} does not export a valid Config instance.`);\n }\n\n return { config, path: absolutePath };\n }\n\n const candidates = [\n \"autometa.config.ts\",\n \"autometa.config.js\",\n \"autometa.config.mts\",\n \"autometa.config.mjs\",\n \"autometa.config.cts\",\n \"autometa.config.cjs\",\n ];\n\n for (const candidate of candidates) {\n const path = resolve(root, candidate);\n if (!existsSync(path)) {\n continue;\n }\n\n try {\n const mod = _jiti(path);\n const config = mod.default || mod;\n\n if (isConfig(config)) {\n return { config, path };\n } else {\n console.warn(`Found config at ${path} but it does not export a Config instance.`);\n }\n } catch (error: unknown) {\n console.error(`Error loading config at ${path}:`, error);\n throw error;\n }\n }\n\n throw new Error(\"Could not find autometa.config.{ts,js,mjs,cjs} in \" + root);\n}\n\nfunction isConfig(config: unknown): config is Config {\n return (\n typeof config === \"object\" &&\n config !== null &&\n \"resolve\" in config &&\n typeof (config as Config).resolve === \"function\" &&\n \"current\" in config &&\n typeof (config as Config).current === \"function\"\n );\n}\n\n/**\n * Default export for Jest transformer compatibility.\n * Jest expects the transformer to have a `process` method.\n */\nexport default {\n process,\n};\n"]}
package/dist/index.d.ts CHANGED
@@ -1,16 +1,33 @@
1
- import * as _babel_core from '@babel/core';
2
- import crypto from 'crypto';
3
- import { Config } from '@jest/types';
4
-
5
- declare let canInstrument: false;
6
- declare const getCacheKey: (fileData: crypto.BinaryLike, filename: crypto.BinaryLike, _configString: crypto.BinaryLike, instrument: {
7
- instrument?: crypto.BinaryLike | undefined;
8
- }) => string;
1
+ /**
2
+ * Jest transformer options that can be passed via jest.config.js
3
+ */
4
+ export interface JestTransformerOptions {
5
+ /**
6
+ * Path to the autometa config file. If not provided, will search for
7
+ * autometa.config.{ts,js,mts,mjs,cts,cjs} in the project root.
8
+ */
9
+ readonly configPath?: string;
10
+ }
11
+ interface TransformOptions {
12
+ readonly config: {
13
+ readonly rootDir: string;
14
+ };
15
+ readonly transformerConfig?: JestTransformerOptions;
16
+ }
17
+ interface TransformResult {
18
+ readonly code: string;
19
+ readonly map?: unknown;
20
+ }
21
+ /**
22
+ * Jest transformer for .feature files.
23
+ * Converts Gherkin feature files into Jest test suites.
24
+ */
25
+ export declare function process(sourceText: string, sourcePath: string, options: TransformOptions): TransformResult;
26
+ /**
27
+ * Default export for Jest transformer compatibility.
28
+ * Jest expects the transformer to have a `process` method.
29
+ */
9
30
  declare const _default: {
10
- getCacheKey: (fileData: crypto.BinaryLike, filename: crypto.BinaryLike, _configString: crypto.BinaryLike, instrument: {
11
- instrument?: crypto.BinaryLike | undefined;
12
- }) => string;
13
- process: (_src: string, filePath: string, jestConfig: Config.ProjectConfig) => _babel_core.BabelFileResult | null;
31
+ process: typeof process;
14
32
  };
15
-
16
- export { canInstrument, _default as default, getCacheKey };
33
+ export default _default;