@autometa/jest-transformer 0.1.111 → 1.0.0-rc.3
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 +73 -2
- package/dist/index.cjs +445 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +31 -14
- package/dist/index.js +429 -55
- package/dist/index.js.map +1 -1
- package/package.json +32 -25
- package/.eslintignore +0 -3
- package/.eslintrc.cjs +0 -4
- package/.turbo/turbo-lint$colon$fix.log +0 -4
- package/.turbo/turbo-prettify.log +0 -0
- package/.turbo/turbo-test.log +0 -13
- package/CHANGELOG.md +0 -730
- package/LICENSE +0 -21
- package/dist/esm/index.js +0 -26
- package/dist/esm/index.js.map +0 -1
- package/dist/index.d.mts +0 -16
- package/tsup.config.ts +0 -14
package/dist/index.js
CHANGED
|
@@ -1,62 +1,436 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
1
|
+
import { dirname, isAbsolute, resolve, extname, relative } from 'path';
|
|
2
|
+
import { existsSync } from 'fs';
|
|
3
|
+
import jiti from 'jiti';
|
|
29
4
|
|
|
30
5
|
// src/index.ts
|
|
31
|
-
var
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
6
|
+
var STEP_FALLBACK_GLOB = "**/*.{ts,tsx,js,jsx,mjs,cjs,mts,cts}";
|
|
7
|
+
var cachedConfig;
|
|
8
|
+
var cachedProjectRoot;
|
|
9
|
+
function process(sourceText, sourcePath, options) {
|
|
10
|
+
const projectRoot = options.config.rootDir;
|
|
11
|
+
if (!cachedConfig || cachedProjectRoot !== projectRoot) {
|
|
12
|
+
const configPath2 = options.transformerConfig?.configPath;
|
|
13
|
+
cachedConfig = loadAutometaConfig(projectRoot, configPath2);
|
|
14
|
+
cachedProjectRoot = projectRoot;
|
|
15
|
+
}
|
|
16
|
+
const autometaConfig = cachedConfig.config;
|
|
17
|
+
const configPath = cachedConfig.path;
|
|
18
|
+
const resolved = autometaConfig.resolve();
|
|
19
|
+
const stepRoots = resolved.config.roots.steps;
|
|
20
|
+
const configDir = configPath ? dirname(configPath) : projectRoot;
|
|
21
|
+
const stepGlobs = buildStepGlobs(stepRoots, {
|
|
22
|
+
configDir,
|
|
23
|
+
projectRoot
|
|
24
|
+
});
|
|
25
|
+
if (stepGlobs.length === 0) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
"Autometa config did not resolve any step files within the current project root."
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
const eventRequires = generateEventRequires(resolved.config.events, configDir);
|
|
31
|
+
const stepRequires = generateStepRequires(stepRoots, configDir);
|
|
32
|
+
const runtimeConfig = JSON.stringify(resolved.config);
|
|
33
|
+
const gherkinContent = JSON.stringify(sourceText);
|
|
34
|
+
const code = `
|
|
35
|
+
const { describe, beforeAll, afterAll, beforeEach, afterEach, it, expect } = require('@jest/globals');
|
|
36
|
+
const { execute } = require('@autometa/jest-executor');
|
|
37
|
+
const { coordinateRunnerFeature, CucumberRunner } = require('@autometa/runner');
|
|
38
|
+
const { parseGherkin } = require('@autometa/gherkin');
|
|
39
|
+
|
|
40
|
+
${eventRequires}
|
|
41
|
+
${stepRequires}
|
|
42
|
+
|
|
43
|
+
function collectCandidateModules(imported) {
|
|
44
|
+
if (!imported || typeof imported !== 'object') {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const modules = new Set();
|
|
49
|
+
modules.add(imported);
|
|
50
|
+
|
|
51
|
+
const exportedModules = imported.modules;
|
|
52
|
+
if (Array.isArray(exportedModules)) {
|
|
53
|
+
for (const entry of exportedModules) {
|
|
54
|
+
if (entry && typeof entry === 'object') {
|
|
55
|
+
modules.add(entry);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const defaultExport = imported.default;
|
|
61
|
+
if (Array.isArray(defaultExport)) {
|
|
62
|
+
for (const entry of defaultExport) {
|
|
63
|
+
if (entry && typeof entry === 'object') {
|
|
64
|
+
modules.add(entry);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
} else if (defaultExport && typeof defaultExport === 'object') {
|
|
68
|
+
modules.add(defaultExport);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return Array.from(modules);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function isStepsEnvironment(candidate) {
|
|
75
|
+
return Boolean(
|
|
76
|
+
candidate &&
|
|
77
|
+
typeof candidate === 'object' &&
|
|
78
|
+
typeof candidate.coordinateFeature === 'function' &&
|
|
79
|
+
typeof candidate.getPlan === 'function' &&
|
|
80
|
+
typeof candidate.Given === 'function' &&
|
|
81
|
+
typeof candidate.When === 'function' &&
|
|
82
|
+
typeof candidate.Then === 'function'
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function extractStepsEnvironment(candidate) {
|
|
87
|
+
if (!candidate || typeof candidate !== 'object') {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (isStepsEnvironment(candidate)) {
|
|
92
|
+
return candidate;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const stepsEnv = candidate.stepsEnvironment;
|
|
96
|
+
if (isStepsEnvironment(stepsEnv)) {
|
|
97
|
+
return stepsEnv;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const defaultExport = candidate.default;
|
|
101
|
+
if (isStepsEnvironment(defaultExport)) {
|
|
102
|
+
return defaultExport;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function resolveStepsEnvironment(modules) {
|
|
109
|
+
for (const moduleExports of modules) {
|
|
110
|
+
for (const candidate of collectCandidateModules(moduleExports)) {
|
|
111
|
+
const environment = extractStepsEnvironment(candidate);
|
|
112
|
+
if (environment) {
|
|
113
|
+
return environment;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function isScenario(element) {
|
|
121
|
+
return Boolean(
|
|
122
|
+
element &&
|
|
123
|
+
typeof element === 'object' &&
|
|
124
|
+
'steps' in element &&
|
|
125
|
+
!('exampleGroups' in element) &&
|
|
126
|
+
!('elements' in element)
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function isScenarioOutline(element) {
|
|
131
|
+
return Boolean(
|
|
132
|
+
element &&
|
|
133
|
+
typeof element === 'object' &&
|
|
134
|
+
'steps' in element &&
|
|
135
|
+
'exampleGroups' in element
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function isRule(element) {
|
|
140
|
+
return Boolean(
|
|
141
|
+
element &&
|
|
142
|
+
typeof element === 'object' &&
|
|
143
|
+
'elements' in element &&
|
|
144
|
+
Array.isArray(element.elements)
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function createFeatureScopePlan(feature, basePlan) {
|
|
149
|
+
const allSteps = Array.from(basePlan.stepsById.values());
|
|
150
|
+
const featureChildren = [];
|
|
151
|
+
const scopesById = new Map(basePlan.scopesById);
|
|
152
|
+
|
|
153
|
+
for (const element of feature.elements ?? []) {
|
|
154
|
+
if (isScenario(element) || isScenarioOutline(element)) {
|
|
155
|
+
const scenarioScope = {
|
|
156
|
+
id: element.id ?? element.name,
|
|
157
|
+
kind: isScenarioOutline(element) ? 'scenarioOutline' : 'scenario',
|
|
158
|
+
name: element.name,
|
|
159
|
+
mode: 'default',
|
|
160
|
+
tags: element.tags ?? [],
|
|
161
|
+
steps: allSteps,
|
|
162
|
+
hooks: [],
|
|
163
|
+
children: [],
|
|
164
|
+
pending: false,
|
|
165
|
+
};
|
|
166
|
+
featureChildren.push(scenarioScope);
|
|
167
|
+
scopesById.set(scenarioScope.id, scenarioScope);
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (isRule(element)) {
|
|
172
|
+
const ruleChildren = [];
|
|
173
|
+
for (const ruleElement of element.elements ?? []) {
|
|
174
|
+
if (isScenario(ruleElement) || isScenarioOutline(ruleElement)) {
|
|
175
|
+
const scenarioScope = {
|
|
176
|
+
id: ruleElement.id ?? ruleElement.name,
|
|
177
|
+
kind: isScenarioOutline(ruleElement) ? 'scenarioOutline' : 'scenario',
|
|
178
|
+
name: ruleElement.name,
|
|
179
|
+
mode: 'default',
|
|
180
|
+
tags: ruleElement.tags ?? [],
|
|
181
|
+
steps: allSteps,
|
|
182
|
+
hooks: [],
|
|
183
|
+
children: [],
|
|
184
|
+
pending: false,
|
|
185
|
+
};
|
|
186
|
+
ruleChildren.push(scenarioScope);
|
|
187
|
+
scopesById.set(scenarioScope.id, scenarioScope);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const ruleScope = {
|
|
192
|
+
id: element.id ?? element.name,
|
|
193
|
+
kind: 'rule',
|
|
194
|
+
name: element.name,
|
|
195
|
+
mode: 'default',
|
|
196
|
+
tags: element.tags ?? [],
|
|
197
|
+
steps: allSteps,
|
|
198
|
+
hooks: [],
|
|
199
|
+
children: ruleChildren,
|
|
200
|
+
pending: false,
|
|
201
|
+
};
|
|
202
|
+
featureChildren.push(ruleScope);
|
|
203
|
+
scopesById.set(ruleScope.id, ruleScope);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const featureScope = {
|
|
208
|
+
id: feature.uri ?? feature.name,
|
|
209
|
+
kind: 'feature',
|
|
210
|
+
name: feature.name,
|
|
211
|
+
mode: 'default',
|
|
212
|
+
tags: feature.tags ?? [],
|
|
213
|
+
steps: allSteps,
|
|
214
|
+
hooks: [],
|
|
215
|
+
children: featureChildren,
|
|
216
|
+
pending: false,
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const existingRoot = basePlan.root;
|
|
220
|
+
const updatedRoot = {
|
|
221
|
+
...existingRoot,
|
|
222
|
+
children: [...existingRoot.children, featureScope],
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
scopesById.set(featureScope.id, featureScope);
|
|
226
|
+
scopesById.set(updatedRoot.id, updatedRoot);
|
|
227
|
+
|
|
228
|
+
const scopePlan = {
|
|
229
|
+
root: updatedRoot,
|
|
230
|
+
stepsById: basePlan.stepsById,
|
|
231
|
+
hooksById: basePlan.hooksById,
|
|
232
|
+
scopesById,
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
if (basePlan.worldFactory) {
|
|
236
|
+
scopePlan.worldFactory = basePlan.worldFactory;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (basePlan.parameterRegistry) {
|
|
240
|
+
scopePlan.parameterRegistry = basePlan.parameterRegistry;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return scopePlan;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const gherkin = ${gherkinContent};
|
|
247
|
+
const feature = parseGherkin(gherkin);
|
|
248
|
+
const steps = resolveStepsEnvironment(stepModules);
|
|
249
|
+
|
|
250
|
+
if (!steps) {
|
|
251
|
+
throw new Error('Autometa could not find an exported steps environment for the configured step roots. Export your runner environment as "stepsEnvironment" or default.');
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
CucumberRunner.setSteps(steps);
|
|
255
|
+
|
|
256
|
+
describe(feature.name, () => {
|
|
257
|
+
const basePlan = steps.getPlan();
|
|
258
|
+
const scopedPlan = createFeatureScopePlan(feature, basePlan);
|
|
259
|
+
const { plan, adapter } = coordinateRunnerFeature({
|
|
260
|
+
feature,
|
|
261
|
+
environment: steps,
|
|
262
|
+
config: ${runtimeConfig},
|
|
263
|
+
plan: scopedPlan
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
execute({ plan, adapter, config: ${runtimeConfig} });
|
|
36
267
|
});
|
|
37
|
-
module.exports = __toCommonJS(src_exports);
|
|
38
|
-
var import_crypto = __toESM(require("crypto"));
|
|
39
|
-
var import_core = require("@babel/core");
|
|
40
|
-
var canInstrument;
|
|
41
|
-
var getCacheKey = (fileData, filename, _configString, instrument) => import_crypto.default.createHash("md5").update("\0", "utf8").update(fileData).update("\0", "utf8").update(filename).update("\0", "utf8").update("\0", "utf8").update("\0", "utf8").update(instrument ? "instrument" : "").digest("hex");
|
|
42
|
-
var src_default = {
|
|
43
|
-
getCacheKey,
|
|
44
|
-
process: (_src, filePath, jestConfig) => {
|
|
45
|
-
const windowsFix = filePath.replace(/\\/g, "/");
|
|
46
|
-
const testFile = `
|
|
47
|
-
const { Feature } = require('@autometa/runner');
|
|
48
|
-
Feature('${windowsFix}')
|
|
49
268
|
`;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return
|
|
269
|
+
return { code };
|
|
270
|
+
}
|
|
271
|
+
function generateStepRequires(stepRoots, configDir, _projectRoot) {
|
|
272
|
+
if (!stepRoots || stepRoots.length === 0) {
|
|
273
|
+
return "const stepModules = [];";
|
|
274
|
+
}
|
|
275
|
+
const requires = [];
|
|
276
|
+
let moduleIndex = 0;
|
|
277
|
+
for (const root of stepRoots) {
|
|
278
|
+
const normalizedRoot = root.trim();
|
|
279
|
+
if (!normalizedRoot) {
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
const absolutePath = isAbsolute(normalizedRoot) ? normalizedRoot : resolve(configDir, normalizedRoot);
|
|
283
|
+
if (existsSync(absolutePath)) {
|
|
284
|
+
const normalizedAbsolutePath = normalizeSlashes(absolutePath);
|
|
285
|
+
requires.push(`const stepModule${moduleIndex} = require('${normalizedAbsolutePath}');`);
|
|
286
|
+
moduleIndex++;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
if (requires.length === 0) {
|
|
290
|
+
return "const stepModules = [];";
|
|
55
291
|
}
|
|
292
|
+
const moduleList = Array.from({ length: moduleIndex }, (_, i) => `stepModule${i}`).join(", ");
|
|
293
|
+
return `${requires.join("\n")}
|
|
294
|
+
const stepModules = [${moduleList}];`;
|
|
295
|
+
}
|
|
296
|
+
function generateEventRequires(eventModules, configDir) {
|
|
297
|
+
if (!eventModules || eventModules.length === 0) {
|
|
298
|
+
return "";
|
|
299
|
+
}
|
|
300
|
+
const requires = [];
|
|
301
|
+
for (const entry of eventModules) {
|
|
302
|
+
const normalized = entry.trim();
|
|
303
|
+
if (!normalized) {
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
const absolutePath = isAbsolute(normalized) ? normalized : resolve(configDir, normalized);
|
|
307
|
+
if (!existsSync(absolutePath)) {
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
const normalizedAbsolutePath = normalizeSlashes(absolutePath);
|
|
311
|
+
requires.push(`require('${normalizedAbsolutePath}');`);
|
|
312
|
+
}
|
|
313
|
+
return requires.length > 0 ? requires.join("\n") : "";
|
|
314
|
+
}
|
|
315
|
+
function buildStepGlobs(entries, options) {
|
|
316
|
+
if (!entries || entries.length === 0) {
|
|
317
|
+
return [];
|
|
318
|
+
}
|
|
319
|
+
const patterns = /* @__PURE__ */ new Set();
|
|
320
|
+
for (const entry of entries) {
|
|
321
|
+
const normalized = entry.trim();
|
|
322
|
+
if (!normalized) {
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
for (const candidate of toPatterns(normalized, STEP_FALLBACK_GLOB)) {
|
|
326
|
+
const absolute = isAbsolute(candidate) ? normalizeSlashes(candidate) : normalizeSlashes(resolve(options.configDir, candidate));
|
|
327
|
+
const rootRelative = toRootRelativeGlob(absolute, options.projectRoot);
|
|
328
|
+
patterns.add(rootRelative);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return Array.from(patterns);
|
|
332
|
+
}
|
|
333
|
+
function toPatterns(entry, fallbackGlob) {
|
|
334
|
+
if (hasGlobMagic(entry) || hasFileExtension(entry)) {
|
|
335
|
+
return [entry];
|
|
336
|
+
}
|
|
337
|
+
return [appendGlob(entry, fallbackGlob)];
|
|
338
|
+
}
|
|
339
|
+
function hasGlobMagic(input) {
|
|
340
|
+
return /[*?{}()[\]!,@+]/u.test(input);
|
|
341
|
+
}
|
|
342
|
+
function hasFileExtension(input) {
|
|
343
|
+
const normalized = normalizeSlashes(input);
|
|
344
|
+
const trimmed = normalized === "/" ? normalized : normalized.replace(/\/+$/u, "");
|
|
345
|
+
if (!trimmed || trimmed === "." || trimmed === "..") {
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
return Boolean(extname(trimmed));
|
|
349
|
+
}
|
|
350
|
+
function appendGlob(entry, glob) {
|
|
351
|
+
const normalized = normalizeSlashes(entry);
|
|
352
|
+
const trimmed = normalized === "/" ? normalized : normalized.replace(/\/+$/u, "");
|
|
353
|
+
if (!trimmed || trimmed === ".") {
|
|
354
|
+
return glob;
|
|
355
|
+
}
|
|
356
|
+
if (trimmed === "/") {
|
|
357
|
+
return `/${glob}`;
|
|
358
|
+
}
|
|
359
|
+
return `${trimmed}/${glob}`;
|
|
360
|
+
}
|
|
361
|
+
function toRootRelativeGlob(pattern, rootDir) {
|
|
362
|
+
const normalizedRoot = normalizeSlashes(rootDir);
|
|
363
|
+
const normalizedPattern = normalizeSlashes(pattern);
|
|
364
|
+
let relativePattern = normalizeSlashes(relative(normalizedRoot, normalizedPattern));
|
|
365
|
+
if (!relativePattern || relativePattern === ".") {
|
|
366
|
+
relativePattern = "";
|
|
367
|
+
}
|
|
368
|
+
if (!relativePattern || relativePattern.startsWith("..")) {
|
|
369
|
+
return ensureGlobPrefix(normalizedPattern);
|
|
370
|
+
}
|
|
371
|
+
return ensureGlobPrefix(relativePattern);
|
|
372
|
+
}
|
|
373
|
+
function ensureGlobPrefix(pattern) {
|
|
374
|
+
if (/^[A-Za-z]:\//u.test(pattern)) {
|
|
375
|
+
return pattern;
|
|
376
|
+
}
|
|
377
|
+
if (pattern.startsWith("/")) {
|
|
378
|
+
return pattern;
|
|
379
|
+
}
|
|
380
|
+
return `/${pattern.replace(/^\/+/, "")}`;
|
|
381
|
+
}
|
|
382
|
+
function normalizeSlashes(pathname) {
|
|
383
|
+
return pathname.replace(/\\/gu, "/");
|
|
384
|
+
}
|
|
385
|
+
function loadAutometaConfig(root, explicitPath) {
|
|
386
|
+
const _jiti = jiti(root, { interopDefault: true });
|
|
387
|
+
if (explicitPath) {
|
|
388
|
+
const absolutePath = isAbsolute(explicitPath) ? explicitPath : resolve(root, explicitPath);
|
|
389
|
+
if (!existsSync(absolutePath)) {
|
|
390
|
+
throw new Error(`Autometa config not found at ${absolutePath}`);
|
|
391
|
+
}
|
|
392
|
+
const mod = _jiti(absolutePath);
|
|
393
|
+
const config = mod.default || mod;
|
|
394
|
+
if (!isConfig(config)) {
|
|
395
|
+
throw new Error(`Config at ${absolutePath} does not export a valid Config instance.`);
|
|
396
|
+
}
|
|
397
|
+
return { config, path: absolutePath };
|
|
398
|
+
}
|
|
399
|
+
const candidates = [
|
|
400
|
+
"autometa.config.ts",
|
|
401
|
+
"autometa.config.js",
|
|
402
|
+
"autometa.config.mts",
|
|
403
|
+
"autometa.config.mjs",
|
|
404
|
+
"autometa.config.cts",
|
|
405
|
+
"autometa.config.cjs"
|
|
406
|
+
];
|
|
407
|
+
for (const candidate of candidates) {
|
|
408
|
+
const path = resolve(root, candidate);
|
|
409
|
+
if (!existsSync(path)) {
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
412
|
+
try {
|
|
413
|
+
const mod = _jiti(path);
|
|
414
|
+
const config = mod.default || mod;
|
|
415
|
+
if (isConfig(config)) {
|
|
416
|
+
return { config, path };
|
|
417
|
+
} else {
|
|
418
|
+
console.warn(`Found config at ${path} but it does not export a Config instance.`);
|
|
419
|
+
}
|
|
420
|
+
} catch (error) {
|
|
421
|
+
console.error(`Error loading config at ${path}:`, error);
|
|
422
|
+
throw error;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
throw new Error("Could not find autometa.config.{ts,js,mjs,cjs} in " + root);
|
|
426
|
+
}
|
|
427
|
+
function isConfig(config) {
|
|
428
|
+
return typeof config === "object" && config !== null && "resolve" in config && typeof config.resolve === "function" && "current" in config && typeof config.current === "function";
|
|
429
|
+
}
|
|
430
|
+
var src_default = {
|
|
431
|
+
process
|
|
56
432
|
};
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
getCacheKey
|
|
61
|
-
});
|
|
433
|
+
|
|
434
|
+
export { src_default as default, process };
|
|
435
|
+
//# sourceMappingURL=out.js.map
|
|
62
436
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import crypto from \"crypto\";\n\nimport { transform } from \"@babel/core\";\nimport type { Config } from \"@jest/types\";\n// import jestPreset from \"babel-preset-jest\";\n\nexport let canInstrument: false;\nexport const getCacheKey = (\n fileData: crypto.BinaryLike,\n filename: crypto.BinaryLike,\n _configString: crypto.BinaryLike,\n instrument: { instrument?: crypto.BinaryLike }\n) =>\n crypto\n .createHash(\"md5\")\n .update(\"\\0\", \"utf8\")\n .update(fileData)\n .update(\"\\0\", \"utf8\")\n .update(filename)\n .update(\"\\0\", \"utf8\")\n .update(\"\\0\", \"utf8\")\n .update(\"\\0\", \"utf8\")\n .update(instrument ? \"instrument\" : \"\")\n .digest(\"hex\");\n\nexport default {\n getCacheKey,\n process: (\n _src: string,\n filePath: string,\n jestConfig: Config.ProjectConfig\n ) => {\n const windowsFix = filePath.replace(/\\\\/g, \"/\");\n const testFile = `\nconst { Feature } = require('@autometa/runner'); \nFeature('${windowsFix}')\n`;\n\n const featureFile = transform(testFile, {\n filename: windowsFix,\n root: jestConfig.cwd,\n });\n\n return featureFile;\n },\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAmB;AAEnB,kBAA0B;AAInB,IAAI;AACJ,IAAM,cAAc,CACzB,UACA,UACA,eACA,eAEA,cAAAA,QACG,WAAW,KAAK,EAChB,OAAO,MAAM,MAAM,EACnB,OAAO,QAAQ,EACf,OAAO,MAAM,MAAM,EACnB,OAAO,QAAQ,EACf,OAAO,MAAM,MAAM,EACnB,OAAO,MAAM,MAAM,EACnB,OAAO,MAAM,MAAM,EACnB,OAAO,aAAa,eAAe,EAAE,EACrC,OAAO,KAAK;AAEjB,IAAO,cAAQ;AAAA,EACb;AAAA,EACA,SAAS,CACP,MACA,UACA,eACG;AACH,UAAM,aAAa,SAAS,QAAQ,OAAO,GAAG;AAC9C,UAAM,WAAW;AAAA;AAAA,WAEV,UAAU;AAAA;AAGjB,UAAM,kBAAc,uBAAU,UAAU;AAAA,MACtC,UAAU;AAAA,MACV,MAAM,WAAW;AAAA,IACnB,CAAC;AAED,WAAO;AAAA,EACT;AACF;","names":["crypto"]}
|
|
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/package.json
CHANGED
|
@@ -1,49 +1,56 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autometa/jest-transformer",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "",
|
|
5
|
-
"type": "
|
|
6
|
-
"main": "dist/index.
|
|
7
|
-
"module": "dist/
|
|
3
|
+
"version": "1.0.0-rc.3",
|
|
4
|
+
"description": "Jest transformer for Autometa - transforms .feature files into test suites",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"module": "dist/index.js",
|
|
8
8
|
"types": "dist/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
9
12
|
"exports": {
|
|
10
|
-
"import": "./dist/
|
|
11
|
-
"require": "./dist/index.
|
|
12
|
-
"default": "./dist/
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"require": "./dist/index.cjs",
|
|
15
|
+
"default": "./dist/index.js",
|
|
13
16
|
"types": "./dist/index.d.ts"
|
|
14
17
|
},
|
|
15
18
|
"license": "MIT",
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"jiti": "^1.21.0",
|
|
21
|
+
"@autometa/config": "1.0.0-rc.1"
|
|
22
|
+
},
|
|
16
23
|
"devDependencies": {
|
|
17
24
|
"@types/node": "^18.11.18",
|
|
18
|
-
"@types/uuid": "^9.0.5",
|
|
19
|
-
"@typescript-eslint/eslint-plugin": "^5.54.1",
|
|
20
|
-
"@typescript-eslint/parser": "^5.54.1",
|
|
21
|
-
"@vitest/coverage-istanbul": "^1.4.0",
|
|
22
|
-
"@vitest/coverage-v8": "^1.4.0",
|
|
23
25
|
"eslint": "^8.37.0",
|
|
24
|
-
"eslint-config-prettier": "^8.3.0",
|
|
25
|
-
"istanbul": "^0.4.5",
|
|
26
26
|
"rimraf": "^4.1.2",
|
|
27
27
|
"tsup": "^7.2.0",
|
|
28
28
|
"typescript": "^4.9.5",
|
|
29
29
|
"vitest": "1.4.0",
|
|
30
30
|
"tsconfig": "0.7.0",
|
|
31
|
+
"tsup-config": "0.1.0",
|
|
31
32
|
"eslint-config-custom": "0.6.0"
|
|
32
33
|
},
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"@
|
|
36
|
-
"@
|
|
37
|
-
"
|
|
38
|
-
"@autometa/runner": "^0.6.4"
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"jest": ">=29.0.0",
|
|
36
|
+
"@autometa/gherkin": "1.0.0-rc.1",
|
|
37
|
+
"@autometa/jest-executor": "1.0.0-rc.3",
|
|
38
|
+
"@autometa/runner": "1.0.0-rc.1"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
|
+
"type-check": "tsc --noEmit",
|
|
42
|
+
"type-check:watch": "tsc --noEmit --watch",
|
|
43
|
+
"build": "tsup && pnpm run build:types",
|
|
44
|
+
"build:types": "rimraf tsconfig.types.tsbuildinfo && tsc --build tsconfig.types.json",
|
|
45
|
+
"build:watch": "tsup --watch",
|
|
46
|
+
"dev": "tsup --watch",
|
|
41
47
|
"test": "vitest run --passWithNoTests",
|
|
42
|
-
"
|
|
48
|
+
"test:watch": "vitest --passWithNoTests",
|
|
49
|
+
"test:ui": "vitest --ui --passWithNoTests",
|
|
50
|
+
"coverage": "vitest run --coverage --passWithNoTests",
|
|
43
51
|
"lint": "eslint . --max-warnings 0",
|
|
44
52
|
"lint:fix": "eslint . --fix",
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"build:watch": "tsup --watch"
|
|
53
|
+
"prettify": "prettier --config .prettierrc 'src/**/*.ts' --write",
|
|
54
|
+
"clean": "rimraf dist"
|
|
48
55
|
}
|
|
49
56
|
}
|
package/.eslintignore
DELETED
package/.eslintrc.cjs
DELETED
|
File without changes
|
package/.turbo/turbo-test.log
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
> @autometa/jest-transformer@0.1.106 test /Users/ben.aherne/Documents/GitHub/autometa/packages/jest-transformer
|
|
3
|
-
> vitest run --passWithNoTests
|
|
4
|
-
|
|
5
|
-
[33mThe CJS build of Vite's Node API is deprecated. See https://vitejs.dev/guide/troubleshooting.html#vite-cjs-node-api-deprecated for more details.[39m
|
|
6
|
-
|
|
7
|
-
RUN v1.4.0 /Users/ben.aherne/Documents/GitHub/autometa/packages/jest-transformer
|
|
8
|
-
|
|
9
|
-
include: **/*.{test,spec}.?(c|m)[jt]s?(x)
|
|
10
|
-
No test files found, exiting with code 0
|
|
11
|
-
|
|
12
|
-
exclude: **/node_modules/**, **/dist/**, **/cypress/**, **/.{idea,git,cache,output,temp}/**, **/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build,eslint,prettier}.config.*
|
|
13
|
-
watch exclude: **/node_modules/**, **/dist/**
|