@lynxwall/cucumber-tsflow 7.5.0 → 7.6.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/README.md +21 -5
- package/bin/cucumber-tsflow +3 -3
- package/bin/cucumber-tsflow.js +0 -0
- package/lib/api/convert-configuration.d.ts +1 -1
- package/lib/api/convert-configuration.js +62 -19
- package/lib/api/convert-configuration.js.map +1 -1
- package/lib/api/load-configuration.js +223 -101
- package/lib/api/load-configuration.js.map +1 -1
- package/lib/api/load-support.d.ts +14 -0
- package/lib/api/load-support.js +112 -0
- package/lib/api/load-support.js.map +1 -1
- package/lib/cli/index.js +61 -13
- package/lib/cli/index.js.map +1 -1
- package/lib/cli/run.js +29 -15
- package/lib/cli/run.js.map +1 -1
- package/lib/transpilers/esm/esbuild-transpiler-cjs.js +118 -15
- package/lib/transpilers/esm/esbuild-transpiler.mjs +27 -6
- package/lib/transpilers/esm/esbuild.mjs +70 -26
- package/lib/transpilers/esm/esnode-loader.mjs +7 -0
- package/lib/transpilers/esm/esvue-loader.mjs +7 -0
- package/lib/transpilers/esm/loader-utils.mjs +283 -157
- package/lib/transpilers/esm/tsnode-loader.mjs +84 -38
- package/lib/transpilers/esm/tsnode-service.mjs +50 -6
- package/lib/transpilers/esm/vue-jsdom-setup.mjs +36 -7
- package/lib/transpilers/esm/vue-loader.mjs +48 -62
- package/lib/transpilers/esm/vue-sfc-compiler.mjs +17 -207
- package/lib/transpilers/esvue.js +6 -9
- package/lib/transpilers/esvue.js.map +1 -1
- package/lib/transpilers/tsvue-exp.js +6 -9
- package/lib/transpilers/tsvue-exp.js.map +1 -1
- package/lib/transpilers/tsvue.js +5 -8
- package/lib/transpilers/tsvue.js.map +1 -1
- package/lib/transpilers/vue-sfc-compiler.d.ts +23 -0
- package/lib/transpilers/vue-sfc-compiler.js +242 -0
- package/lib/transpilers/vue-sfc-compiler.js.map +1 -0
- package/lib/tsconfig.node.tsbuildinfo +1 -1
- package/lib/utils/tsflow-logger.d.ts +29 -0
- package/lib/utils/tsflow-logger.js +79 -0
- package/lib/utils/tsflow-logger.js.map +1 -0
- package/lib/utils/tsflow-logger.mjs +78 -0
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/lib/version.js.map +1 -1
- package/package.json +4 -5
- package/lib/support_code_library_builder/index.d.ts +0 -80
- package/lib/support_code_library_builder/index.js +0 -337
- package/lib/support_code_library_builder/index.js.map +0 -1
- package/lib/transpilers/esm/esmbuild-transpiler.d.ts +0 -4
- package/lib/transpilers/esm/esmbuild-transpiler.js +0 -19
- package/lib/transpilers/esm/esmbuild-transpiler.js.map +0 -1
- package/lib/transpilers/esm/esmbuild.d.ts +0 -12
- package/lib/transpilers/esm/esmbuild.js +0 -72
- package/lib/transpilers/esm/esmbuild.js.map +0 -1
- package/lib/transpilers/esm/esmnode.d.ts +0 -1
- package/lib/transpilers/esm/esmnode.js +0 -8
- package/lib/transpilers/esm/esmnode.js.map +0 -1
- package/lib/transpilers/esm/esmvue.d.ts +0 -1
- package/lib/transpilers/esm/esmvue.js +0 -29
- package/lib/transpilers/esm/esmvue.js.map +0 -1
- package/lib/transpilers/esm/tsnode-esm.d.ts +0 -1
- package/lib/transpilers/esm/tsnode-esm.js +0 -25
- package/lib/transpilers/esm/tsnode-esm.js.map +0 -1
- package/lib/transpilers/esm/tsnode-exp-esm.d.ts +0 -1
- package/lib/transpilers/esm/tsnode-exp-esm.js +0 -19
- package/lib/transpilers/esm/tsnode-exp-esm.js.map +0 -1
- package/lib/transpilers/esm/tsvue-esm.d.ts +0 -1
- package/lib/transpilers/esm/tsvue-esm.js +0 -40
- package/lib/transpilers/esm/tsvue-esm.js.map +0 -1
- package/lib/transpilers/esm/tsvue-exp-esm.d.ts +0 -1
- package/lib/transpilers/esm/tsvue-exp-esm.js +0 -40
- package/lib/transpilers/esm/tsvue-exp-esm.js.map +0 -1
- package/lib/transpilers/vue-sfc/compiler.d.ts +0 -7
- package/lib/transpilers/vue-sfc/compiler.js +0 -22
- package/lib/transpilers/vue-sfc/compiler.js.map +0 -1
- package/lib/transpilers/vue-sfc/index.d.ts +0 -23
- package/lib/transpilers/vue-sfc/index.js +0 -46
- package/lib/transpilers/vue-sfc/index.js.map +0 -1
- package/lib/transpilers/vue-sfc/main.d.ts +0 -8
- package/lib/transpilers/vue-sfc/main.js +0 -258
- package/lib/transpilers/vue-sfc/main.js.map +0 -1
- package/lib/transpilers/vue-sfc/script.d.ts +0 -5
- package/lib/transpilers/vue-sfc/script.js +0 -41
- package/lib/transpilers/vue-sfc/script.js.map +0 -1
- package/lib/transpilers/vue-sfc/template.d.ts +0 -8
- package/lib/transpilers/vue-sfc/template.js +0 -101
- package/lib/transpilers/vue-sfc/template.js.map +0 -1
- package/lib/transpilers/vue-sfc/types.d.ts +0 -55
- package/lib/transpilers/vue-sfc/types.js +0 -3
- package/lib/transpilers/vue-sfc/types.js.map +0 -1
- package/lib/transpilers/vue-sfc/utils/descriptorCache.d.ts +0 -13
- package/lib/transpilers/vue-sfc/utils/descriptorCache.js +0 -68
- package/lib/transpilers/vue-sfc/utils/descriptorCache.js.map +0 -1
- package/lib/transpilers/vue-sfc/utils/error.d.ts +0 -3
- package/lib/transpilers/vue-sfc/utils/error.js +0 -23
- package/lib/transpilers/vue-sfc/utils/error.js.map +0 -1
- package/lib/transpilers/vue-sfc/utils/query.d.ts +0 -13
- package/lib/transpilers/vue-sfc/utils/query.js +0 -36
- package/lib/transpilers/vue-sfc/utils/query.js.map +0 -1
|
@@ -3,9 +3,13 @@ import { createRequire } from 'node:module';
|
|
|
3
3
|
import { resolveSpecifier } from './loader-utils.mjs';
|
|
4
4
|
import { loadConfig } from 'tsconfig-paths';
|
|
5
5
|
import path from 'path';
|
|
6
|
+
import { createLogger } from '../../utils/tsflow-logger.mjs';
|
|
6
7
|
|
|
8
|
+
const logger = createLogger('tsnode-loader');
|
|
7
9
|
const require = createRequire(import.meta.url);
|
|
8
10
|
|
|
11
|
+
logger.checkpoint('Initializing tsnode-loader');
|
|
12
|
+
|
|
9
13
|
// Load tsconfig to get paths
|
|
10
14
|
const configLoaderResult = loadConfig(process.cwd());
|
|
11
15
|
let paths = {};
|
|
@@ -14,31 +18,54 @@ let baseUrl = './';
|
|
|
14
18
|
if (configLoaderResult.resultType === 'success') {
|
|
15
19
|
paths = configLoaderResult.paths || {};
|
|
16
20
|
baseUrl = configLoaderResult.baseUrl || './';
|
|
21
|
+
logger.checkpoint('tsconfig loaded', {
|
|
22
|
+
baseUrl,
|
|
23
|
+
pathCount: Object.keys(paths).length,
|
|
24
|
+
cwd: process.cwd()
|
|
25
|
+
});
|
|
26
|
+
} else {
|
|
27
|
+
logger.warn('tsconfig load failed', {
|
|
28
|
+
resultType: configLoaderResult.resultType,
|
|
29
|
+
cwd: process.cwd()
|
|
30
|
+
});
|
|
17
31
|
}
|
|
18
32
|
|
|
19
33
|
// Create ts-node service with our configuration
|
|
34
|
+
logger.checkpoint('Loading ts-node-maintained');
|
|
20
35
|
const tsNode = require('ts-node-maintained');
|
|
21
36
|
|
|
37
|
+
const experimentalDecorators = process.env.CUCUMBER_EXPERIMENTAL_DECORATORS === 'true';
|
|
38
|
+
|
|
39
|
+
logger.checkpoint('Creating ts-node service', {
|
|
40
|
+
experimentalDecorators,
|
|
41
|
+
baseUrl,
|
|
42
|
+
pathCount: Object.keys(paths).length
|
|
43
|
+
});
|
|
44
|
+
|
|
22
45
|
const service = tsNode.create({
|
|
23
46
|
esm: true,
|
|
24
47
|
experimentalSpecifierResolution: 'node',
|
|
25
48
|
files: true,
|
|
26
49
|
transpileOnly: true,
|
|
27
50
|
compilerOptions: {
|
|
28
|
-
experimentalDecorators
|
|
51
|
+
experimentalDecorators,
|
|
29
52
|
module: 'ESNext',
|
|
30
53
|
target: 'ES2022',
|
|
31
|
-
// Add path mapping to ts-node's compiler options
|
|
32
54
|
baseUrl: baseUrl,
|
|
33
55
|
paths: paths
|
|
34
56
|
}
|
|
35
57
|
});
|
|
36
58
|
|
|
59
|
+
logger.checkpoint('ts-node service created');
|
|
60
|
+
|
|
37
61
|
// Create ESM hooks from the service
|
|
38
62
|
const esmHooks = tsNode.createEsmHooks(service);
|
|
63
|
+
logger.checkpoint('ESM hooks created');
|
|
39
64
|
|
|
40
65
|
export async function resolve(specifier, context, nextResolve) {
|
|
41
|
-
|
|
66
|
+
logger.checkpoint('resolve', { specifier, parentURL: context.parentURL });
|
|
67
|
+
|
|
68
|
+
// Try common resolution logic
|
|
42
69
|
const resolved = await resolveSpecifier(specifier, context, {
|
|
43
70
|
checkExtensions: true,
|
|
44
71
|
handleTsFiles: true,
|
|
@@ -47,59 +74,78 @@ export async function resolve(specifier, context, nextResolve) {
|
|
|
47
74
|
});
|
|
48
75
|
|
|
49
76
|
if (resolved) {
|
|
77
|
+
logger.checkpoint('resolve success', { specifier, url: resolved.url });
|
|
50
78
|
return resolved;
|
|
51
79
|
}
|
|
52
80
|
|
|
53
81
|
// Fall back to ts-node's resolver
|
|
82
|
+
logger.checkpoint('resolve delegating to ts-node', { specifier });
|
|
54
83
|
return esmHooks.resolve(specifier, context, nextResolve);
|
|
55
84
|
}
|
|
56
85
|
|
|
57
86
|
export const load = async (url, context, nextLoad) => {
|
|
87
|
+
logger.checkpoint('load', { url });
|
|
88
|
+
|
|
58
89
|
// Only intercept TypeScript files for path rewriting
|
|
59
90
|
if (url.endsWith('.ts') || url.endsWith('.tsx')) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
let code = result.source.toString();
|
|
66
|
-
let modified = false;
|
|
67
|
-
|
|
68
|
-
for (const [pattern, replacements] of Object.entries(configLoaderResult.paths)) {
|
|
69
|
-
// Convert TS path pattern to regex: @fixtures/* -> @fixtures/
|
|
70
|
-
const searchPattern = pattern.replace('/*', '/');
|
|
71
|
-
const searchRegex = new RegExp(`(from\\s+['"])${searchPattern}([^'"]+)(['"])`, 'g');
|
|
72
|
-
|
|
73
|
-
if (searchRegex.test(code)) {
|
|
74
|
-
// Get the replacement path (use first one if multiple)
|
|
75
|
-
const replacementPath = replacements[0].replace('/*', '');
|
|
76
|
-
|
|
77
|
-
code = code.replace(searchRegex, (match, prefix, importPath, suffix) => {
|
|
78
|
-
// Create the full path
|
|
79
|
-
const fullPath = path.join(configLoaderResult.absoluteBaseUrl, replacementPath, importPath);
|
|
80
|
-
// Convert to file:// URL for ESM
|
|
81
|
-
const fileUrl = pathToFileURL(fullPath).href;
|
|
82
|
-
return `${prefix}${fileUrl}${suffix}`;
|
|
83
|
-
});
|
|
91
|
+
logger.checkpoint('load handling TypeScript', { url });
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
// First, let ts-node load the file
|
|
95
|
+
const result = await esmHooks.load(url, context, nextLoad);
|
|
84
96
|
|
|
85
|
-
|
|
97
|
+
// If we have path mappings, check if we need to rewrite the source
|
|
98
|
+
if (configLoaderResult.resultType === 'success' && configLoaderResult.paths) {
|
|
99
|
+
let code = result.source.toString();
|
|
100
|
+
let modified = false;
|
|
101
|
+
let replacementCount = 0;
|
|
102
|
+
|
|
103
|
+
for (const [pattern, replacements] of Object.entries(configLoaderResult.paths)) {
|
|
104
|
+
const searchPattern = pattern.replace('/*', '/');
|
|
105
|
+
const searchRegex = new RegExp(`(from\\s+['"])${searchPattern}([^'"]+)(['"])`, 'g');
|
|
106
|
+
|
|
107
|
+
if (searchRegex.test(code)) {
|
|
108
|
+
const replacementPath = replacements[0].replace('/*', '');
|
|
109
|
+
|
|
110
|
+
code = code.replace(searchRegex, (match, prefix, importPath, suffix) => {
|
|
111
|
+
const fullPath = path.join(configLoaderResult.absoluteBaseUrl, replacementPath, importPath);
|
|
112
|
+
const fileUrl = pathToFileURL(fullPath).href;
|
|
113
|
+
|
|
114
|
+
replacementCount++;
|
|
115
|
+
logger.checkpoint('Path rewritten', {
|
|
116
|
+
from: `${searchPattern}${importPath}`,
|
|
117
|
+
to: fileUrl
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
return `${prefix}${fileUrl}${suffix}`;
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
modified = true;
|
|
124
|
+
}
|
|
86
125
|
}
|
|
87
|
-
}
|
|
88
126
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
127
|
+
if (modified) {
|
|
128
|
+
logger.checkpoint('load complete with path rewrites', {
|
|
129
|
+
url,
|
|
130
|
+
replacementCount
|
|
131
|
+
});
|
|
132
|
+
return {
|
|
133
|
+
...result,
|
|
134
|
+
source: code
|
|
135
|
+
};
|
|
136
|
+
}
|
|
95
137
|
}
|
|
96
|
-
}
|
|
97
138
|
|
|
98
|
-
|
|
99
|
-
|
|
139
|
+
logger.checkpoint('load complete', { url });
|
|
140
|
+
return result;
|
|
141
|
+
} catch (error) {
|
|
142
|
+
logger.error('load failed', error, { url });
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
100
145
|
}
|
|
101
146
|
|
|
102
147
|
// For non-TypeScript files, let ts-node handle it
|
|
148
|
+
logger.checkpoint('load delegating to ts-node', { url });
|
|
103
149
|
return esmHooks.load(url, context, nextLoad);
|
|
104
150
|
};
|
|
105
151
|
|
|
@@ -1,40 +1,84 @@
|
|
|
1
1
|
import { createRequire } from 'module';
|
|
2
|
+
import { createLogger } from '../../utils/tsflow-logger.mjs';
|
|
3
|
+
|
|
4
|
+
const logger = createLogger('tsnode-service');
|
|
5
|
+
|
|
6
|
+
logger.checkpoint('Loading ts-node-maintained');
|
|
2
7
|
|
|
3
8
|
const require = createRequire(import.meta.url);
|
|
4
|
-
|
|
9
|
+
|
|
10
|
+
let tsNode;
|
|
11
|
+
try {
|
|
12
|
+
tsNode = require('ts-node-maintained');
|
|
13
|
+
logger.checkpoint('ts-node-maintained loaded successfully');
|
|
14
|
+
} catch (error) {
|
|
15
|
+
logger.error('Failed to load ts-node-maintained', error);
|
|
16
|
+
throw new Error(`Failed to load ts-node-maintained: ${error.message}`, { cause: error });
|
|
17
|
+
}
|
|
5
18
|
|
|
6
19
|
// Cache for different ts-node configurations
|
|
7
20
|
const serviceCache = new Map();
|
|
8
21
|
|
|
9
22
|
export function createTsNodeService(options = {}) {
|
|
23
|
+
logger.checkpoint('createTsNodeService called', { options });
|
|
24
|
+
|
|
10
25
|
const cacheKey = JSON.stringify(options);
|
|
11
26
|
|
|
12
27
|
if (serviceCache.has(cacheKey)) {
|
|
28
|
+
logger.checkpoint('Returning cached ts-node service', { cacheKey });
|
|
13
29
|
return serviceCache.get(cacheKey);
|
|
14
30
|
}
|
|
15
31
|
|
|
16
32
|
// Ensure ts-node respects tsconfig.json files
|
|
17
33
|
process.env.TS_NODE_FILES = process.env.TS_NODE_FILES || 'true';
|
|
18
34
|
|
|
35
|
+
const experimentalDecorators = process.env.CUCUMBER_EXPERIMENTAL_DECORATORS === 'true';
|
|
36
|
+
|
|
19
37
|
const defaultOptions = {
|
|
20
38
|
esm: true,
|
|
21
39
|
experimentalSpecifierResolution: 'node',
|
|
22
40
|
files: true,
|
|
23
41
|
transpileOnly: true,
|
|
24
42
|
compilerOptions: {
|
|
25
|
-
experimentalDecorators
|
|
43
|
+
experimentalDecorators,
|
|
26
44
|
module: 'ESNext',
|
|
27
45
|
target: 'ES2022'
|
|
28
46
|
}
|
|
29
47
|
};
|
|
30
48
|
|
|
31
|
-
const
|
|
32
|
-
|
|
49
|
+
const mergedOptions = { ...defaultOptions, ...options };
|
|
50
|
+
logger.checkpoint('Creating ts-node service', {
|
|
51
|
+
experimentalDecorators,
|
|
52
|
+
transpiler: mergedOptions.transpiler,
|
|
53
|
+
esm: mergedOptions.esm
|
|
54
|
+
});
|
|
33
55
|
|
|
56
|
+
let service;
|
|
57
|
+
try {
|
|
58
|
+
service = tsNode.create(mergedOptions);
|
|
59
|
+
logger.checkpoint('ts-node service created successfully');
|
|
60
|
+
} catch (error) {
|
|
61
|
+
logger.error('Failed to create ts-node service', error, { options: mergedOptions });
|
|
62
|
+
throw new Error(`Failed to create ts-node service: ${error.message}`, { cause: error });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
serviceCache.set(cacheKey, service);
|
|
34
66
|
return service;
|
|
35
67
|
}
|
|
36
68
|
|
|
37
69
|
export function createEsmHooks(transpiler) {
|
|
38
|
-
|
|
39
|
-
|
|
70
|
+
logger.checkpoint('createEsmHooks called', { transpiler });
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const service = createTsNodeService({ transpiler });
|
|
74
|
+
logger.checkpoint('Creating ESM hooks from service');
|
|
75
|
+
|
|
76
|
+
const hooks = tsNode.createEsmHooks(service);
|
|
77
|
+
logger.checkpoint('ESM hooks created successfully');
|
|
78
|
+
|
|
79
|
+
return hooks;
|
|
80
|
+
} catch (error) {
|
|
81
|
+
logger.error('Failed to create ESM hooks', error, { transpiler });
|
|
82
|
+
throw new Error(`Failed to create ESM hooks: ${error.message}`, { cause: error });
|
|
83
|
+
}
|
|
40
84
|
}
|
|
@@ -2,18 +2,47 @@
|
|
|
2
2
|
/* eslint-disable no-undef */
|
|
3
3
|
|
|
4
4
|
import { createRequire } from 'module';
|
|
5
|
+
import { createLogger } from '../../utils/tsflow-logger.mjs';
|
|
6
|
+
|
|
7
|
+
const logger = createLogger('jsdom-setup');
|
|
8
|
+
|
|
9
|
+
logger.checkpoint('Initializing JSDOM environment');
|
|
10
|
+
|
|
5
11
|
const require = createRequire(import.meta.url);
|
|
6
12
|
|
|
7
|
-
|
|
13
|
+
try {
|
|
14
|
+
logger.checkpoint('Loading jsdom-global');
|
|
15
|
+
require('jsdom-global')();
|
|
16
|
+
logger.checkpoint('jsdom-global loaded and executed');
|
|
17
|
+
} catch (error) {
|
|
18
|
+
logger.error('Failed to initialize jsdom-global', error);
|
|
19
|
+
throw new Error(`Failed to initialize JSDOM: ${error.message}`, { cause: error });
|
|
20
|
+
}
|
|
8
21
|
|
|
9
22
|
// After jsdom-global, window and document should be global
|
|
10
|
-
// Add Vue-specific constructors to global scope
|
|
11
23
|
if (typeof window !== 'undefined') {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
24
|
+
logger.checkpoint('Window is available, setting up Vue-specific globals');
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
globalThis.SVGElement = window.SVGElement;
|
|
28
|
+
globalThis.Element = window.Element;
|
|
29
|
+
globalThis.HTMLElement = window.HTMLElement;
|
|
30
|
+
globalThis.HTMLDivElement = window.HTMLDivElement;
|
|
31
|
+
|
|
32
|
+
logger.checkpoint('Vue-specific globals set', {
|
|
33
|
+
hasSVGElement: !!globalThis.SVGElement,
|
|
34
|
+
hasElement: !!globalThis.Element,
|
|
35
|
+
hasHTMLElement: !!globalThis.HTMLElement,
|
|
36
|
+
hasHTMLDivElement: !!globalThis.HTMLDivElement
|
|
37
|
+
});
|
|
38
|
+
} catch (error) {
|
|
39
|
+
logger.error('Failed to set Vue-specific globals', error);
|
|
40
|
+
throw new Error(`Failed to set Vue globals: ${error.message}`, { cause: error });
|
|
41
|
+
}
|
|
42
|
+
} else {
|
|
43
|
+
logger.warn('Window is not available after jsdom-global initialization');
|
|
17
44
|
}
|
|
18
45
|
|
|
46
|
+
logger.checkpoint('JSDOM environment setup complete');
|
|
47
|
+
|
|
19
48
|
export {}; // Make it a module
|
|
@@ -1,110 +1,96 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ESM loader for Vue Single File Components (.vue files)
|
|
3
|
-
*
|
|
4
|
-
* This loader enables importing and testing Vue SFC components in Node.js ESM environments.
|
|
5
|
-
* It provides feature parity with the CJS vue-loader but uses Node.js ESM loader hooks.
|
|
6
|
-
*
|
|
7
|
-
* Key features:
|
|
8
|
-
* - Compiles Vue SFC components (template, script, and optionally styles)
|
|
9
|
-
* - Handles TypeScript in Vue components via ts-node delegation
|
|
10
|
-
* - Supports extensionless imports (e.g., import Component from './Component')
|
|
11
|
-
* - Handles asset imports (images, fonts, etc.)
|
|
12
|
-
* - Integrates with tsconfig path mappings
|
|
13
|
-
* - Optional style processing controlled by global.enableVueStyle
|
|
14
|
-
*
|
|
15
|
-
* Differences from CJS version:
|
|
16
|
-
* - Uses ESM loader hooks (resolve/load) instead of require.extensions
|
|
17
|
-
* - Delegates TypeScript handling to ts-node/esm instead of inline transpilation
|
|
18
|
-
* - Sets TS_NODE_FILES=true to ensure ts-node respects tsconfig.json includes
|
|
19
|
-
* (needed for type definition files like Vue shims)
|
|
20
|
-
*
|
|
21
|
-
* Usage:
|
|
22
|
-
* 1. Or configure in cucumber.json:
|
|
23
|
-
* {
|
|
24
|
-
* "default": {
|
|
25
|
-
* "transpiler": ["tsvueesm"]
|
|
26
|
-
* }
|
|
27
|
-
* }
|
|
28
|
-
*
|
|
29
|
-
* 2. Register this loader when running tests:
|
|
30
|
-
* node --loader=@lynxwall/cucumber-tsflow/lib/transpilers/esm/vue-loader.mjs
|
|
31
|
-
*
|
|
32
|
-
* 3. To enable style processing:
|
|
33
|
-
* - Set global.enableVueStyle = true in your test setup
|
|
34
|
-
* - Or set environment variable: CUCUMBER_ENABLE_VUE_STYLE=true
|
|
35
|
-
*
|
|
36
|
-
* Note: Style preprocessing (SCSS, Less, etc.) requires the corresponding
|
|
37
|
-
* preprocessor packages to be installed. Missing preprocessors will be skipped
|
|
38
|
-
* with a warning rather than failing the compilation.
|
|
3
|
+
* [... keep existing docblock ...]
|
|
39
4
|
*/
|
|
40
5
|
import { resolveSpecifier, loadVue, handleCommonFileTypes } from './loader-utils.mjs';
|
|
6
|
+
import { createLogger } from '../../utils/tsflow-logger.mjs';
|
|
7
|
+
|
|
8
|
+
const logger = createLogger('vue-loader');
|
|
41
9
|
|
|
42
10
|
// Cache for the TypeScript loader
|
|
43
11
|
let tsLoader;
|
|
44
12
|
|
|
45
13
|
async function getTsLoader() {
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
14
|
+
if (tsLoader) {
|
|
15
|
+
logger.checkpoint('getTsLoader (cached)');
|
|
16
|
+
return tsLoader;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
logger.checkpoint('getTsLoader initializing');
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
// Ensure ts-node respects tsconfig.json files
|
|
23
|
+
process.env.TS_NODE_FILES = process.env.TS_NODE_FILES || 'true';
|
|
24
|
+
|
|
25
|
+
logger.checkpoint('Importing ts-node-maintained/esm');
|
|
26
|
+
const tsNodeEsm = await import('ts-node-maintained/esm');
|
|
27
|
+
tsLoader = tsNodeEsm;
|
|
28
|
+
|
|
29
|
+
logger.checkpoint('ts-node ESM loader cached');
|
|
30
|
+
return tsLoader;
|
|
31
|
+
} catch (error) {
|
|
32
|
+
logger.error('Failed to load ts-node ESM loader', error);
|
|
33
|
+
throw new Error(`Failed to load ts-node ESM loader: ${error.message}`, { cause: error });
|
|
62
34
|
}
|
|
63
|
-
return tsLoader;
|
|
64
35
|
}
|
|
65
36
|
|
|
66
37
|
export async function load(url, context, nextLoad) {
|
|
38
|
+
logger.checkpoint('load', { url });
|
|
39
|
+
|
|
67
40
|
// Check common file types first
|
|
68
41
|
const commonResult = await handleCommonFileTypes(url, context, nextLoad);
|
|
69
|
-
if (commonResult)
|
|
42
|
+
if (commonResult) {
|
|
43
|
+
logger.checkpoint('load handled as common file type', { url });
|
|
44
|
+
return commonResult;
|
|
45
|
+
}
|
|
70
46
|
|
|
71
47
|
// Only process .vue files directly
|
|
72
48
|
if (url.endsWith('.vue')) {
|
|
49
|
+
logger.checkpoint('load handling Vue file', { url });
|
|
73
50
|
try {
|
|
74
|
-
|
|
51
|
+
const result = await loadVue(url, context, nextLoad);
|
|
52
|
+
logger.checkpoint('Vue file loaded successfully', { url });
|
|
53
|
+
return result;
|
|
75
54
|
} catch (error) {
|
|
76
|
-
|
|
77
|
-
throw new Error(`Failed to compile Vue SFC ${url}: ${error.message}
|
|
55
|
+
logger.error('Failed to compile Vue SFC', error, { url });
|
|
56
|
+
throw new Error(`Failed to compile Vue SFC ${url}: ${error.message}`, { cause: error });
|
|
78
57
|
}
|
|
79
58
|
}
|
|
80
59
|
|
|
81
60
|
// For TypeScript files, delegate to ts-node
|
|
82
61
|
if (url.endsWith('.ts') || url.endsWith('.tsx')) {
|
|
62
|
+
logger.checkpoint('load delegating to ts-node', { url });
|
|
83
63
|
try {
|
|
84
64
|
const tsNode = await getTsLoader();
|
|
85
|
-
|
|
65
|
+
const result = await tsNode.load(url, context, nextLoad);
|
|
66
|
+
logger.checkpoint('ts-node load success', { url });
|
|
67
|
+
return result;
|
|
86
68
|
} catch (error) {
|
|
87
|
-
|
|
88
|
-
throw error;
|
|
69
|
+
logger.error('ts-node failed', error, { url });
|
|
70
|
+
throw new Error(`ts-node failed for ${url}: ${error.message}`, { cause: error });
|
|
89
71
|
}
|
|
90
72
|
}
|
|
91
73
|
|
|
92
74
|
// For everything else, use the default loader
|
|
93
|
-
|
|
75
|
+
logger.checkpoint('load delegating to nextLoad', { url });
|
|
94
76
|
return nextLoad(url, context);
|
|
95
77
|
}
|
|
96
78
|
|
|
97
79
|
export async function resolve(specifier, context, nextResolve) {
|
|
80
|
+
logger.checkpoint('resolve', { specifier, parentURL: context.parentURL });
|
|
81
|
+
|
|
98
82
|
// Try common resolution logic
|
|
99
83
|
const resolved = await resolveSpecifier(specifier, context, {
|
|
100
84
|
checkExtensions: true,
|
|
101
|
-
handleTsFiles: false,
|
|
85
|
+
handleTsFiles: false,
|
|
102
86
|
nextResolve
|
|
103
87
|
});
|
|
104
88
|
|
|
105
89
|
if (resolved) {
|
|
90
|
+
logger.checkpoint('resolve success', { specifier, url: resolved.url });
|
|
106
91
|
return resolved;
|
|
107
92
|
}
|
|
108
93
|
|
|
94
|
+
logger.checkpoint('resolve delegating to nextResolve', { specifier });
|
|
109
95
|
return nextResolve(specifier, context);
|
|
110
96
|
}
|