@lynxwall/cucumber-tsflow 7.7.1 → 7.7.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/lib/api/loader-worker.d.ts +2 -0
- package/lib/api/loader-worker.js +182 -12
- package/lib/api/loader-worker.js.map +1 -1
- package/lib/api/parallel-loader.js +18 -1
- package/lib/api/parallel-loader.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/lib/version.js.map +1 -1
- package/package.json +1 -1
package/lib/api/loader-worker.js
CHANGED
|
@@ -11,9 +11,165 @@
|
|
|
11
11
|
* Cucumber step/hook registration — only BindingRegistry population occurs.
|
|
12
12
|
*/
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
// Shim
|
|
14
|
+
// Shim browser globals for libraries that expect a browser environment in worker threads.
|
|
15
|
+
// Workers are a constrained Node.js environment — many libraries probe for browser APIs
|
|
16
|
+
// during module evaluation. These stubs prevent "Cannot read properties of undefined" errors.
|
|
17
|
+
// Aligned with the globals expected by @uis/testing-bdd (uis-jest setup).
|
|
15
18
|
if (typeof globalThis.window === 'undefined') {
|
|
16
|
-
|
|
19
|
+
const noop = () => { };
|
|
20
|
+
const noopObj = new Proxy({}, { get: () => noop });
|
|
21
|
+
// Helper: safely set a global property (some like `navigator` are getter-only in modern Node)
|
|
22
|
+
const safeDefine = (target, key, value) => {
|
|
23
|
+
try {
|
|
24
|
+
Object.defineProperty(target, key, { value, writable: true, configurable: true });
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// Property may be non-configurable — ignore and move on
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
// Minimal location stub — covers window.location.href / .origin / .protocol etc.
|
|
31
|
+
const locationStub = {
|
|
32
|
+
href: '',
|
|
33
|
+
origin: '',
|
|
34
|
+
protocol: 'file:',
|
|
35
|
+
host: '',
|
|
36
|
+
hostname: '',
|
|
37
|
+
port: '',
|
|
38
|
+
pathname: '',
|
|
39
|
+
search: '',
|
|
40
|
+
hash: '',
|
|
41
|
+
assign: noop,
|
|
42
|
+
replace: noop,
|
|
43
|
+
reload: noop,
|
|
44
|
+
toString: () => ''
|
|
45
|
+
};
|
|
46
|
+
// Minimal document stub — covers document.createElement, querySelector, etc.
|
|
47
|
+
const documentStub = {
|
|
48
|
+
createElement: () => noopObj,
|
|
49
|
+
createElementNS: () => noopObj,
|
|
50
|
+
createTextNode: () => noopObj,
|
|
51
|
+
createDocumentFragment: () => noopObj,
|
|
52
|
+
createComment: () => noopObj,
|
|
53
|
+
getElementById: () => null,
|
|
54
|
+
getElementsByClassName: () => [],
|
|
55
|
+
getElementsByTagName: () => [],
|
|
56
|
+
querySelector: () => null,
|
|
57
|
+
querySelectorAll: () => [],
|
|
58
|
+
head: noopObj,
|
|
59
|
+
body: noopObj,
|
|
60
|
+
documentElement: noopObj,
|
|
61
|
+
addEventListener: noop,
|
|
62
|
+
removeEventListener: noop,
|
|
63
|
+
dispatchEvent: noop,
|
|
64
|
+
cookie: ''
|
|
65
|
+
};
|
|
66
|
+
// Minimal navigator stub
|
|
67
|
+
const navigatorStub = {
|
|
68
|
+
userAgent: 'node',
|
|
69
|
+
platform: process.platform,
|
|
70
|
+
language: 'en',
|
|
71
|
+
languages: ['en']
|
|
72
|
+
};
|
|
73
|
+
// Fake localStorage — matches @uis/testing-bdd FakeLocalStorage
|
|
74
|
+
const localStorageStub = {
|
|
75
|
+
store: {},
|
|
76
|
+
clear() {
|
|
77
|
+
this.store = {};
|
|
78
|
+
},
|
|
79
|
+
getItem(key) {
|
|
80
|
+
return this.store[key] ?? null;
|
|
81
|
+
},
|
|
82
|
+
setItem(key, value) {
|
|
83
|
+
this.store[key] = value;
|
|
84
|
+
},
|
|
85
|
+
removeItem(key) {
|
|
86
|
+
delete this.store[key];
|
|
87
|
+
},
|
|
88
|
+
get length() {
|
|
89
|
+
return Object.keys(this.store).length;
|
|
90
|
+
},
|
|
91
|
+
key() {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
// matchMedia stub — matches @uis/testing-bdd mock
|
|
96
|
+
const matchMediaStub = (query) => ({
|
|
97
|
+
matches: false,
|
|
98
|
+
media: query,
|
|
99
|
+
onchange: null,
|
|
100
|
+
addListener: noop,
|
|
101
|
+
removeListener: noop,
|
|
102
|
+
addEventListener: noop,
|
|
103
|
+
removeEventListener: noop,
|
|
104
|
+
dispatchEvent: noop
|
|
105
|
+
});
|
|
106
|
+
// Minimal Element prototype for scrollIntoView etc.
|
|
107
|
+
class HTMLElementStub {
|
|
108
|
+
scrollIntoView = noop;
|
|
109
|
+
getBoundingClientRect = () => ({
|
|
110
|
+
top: 0,
|
|
111
|
+
left: 0,
|
|
112
|
+
bottom: 0,
|
|
113
|
+
right: 0,
|
|
114
|
+
width: 0,
|
|
115
|
+
height: 0,
|
|
116
|
+
x: 0,
|
|
117
|
+
y: 0
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
class ElementStub extends HTMLElementStub {
|
|
121
|
+
}
|
|
122
|
+
// Minimal XMLSerializer stub
|
|
123
|
+
class XMLSerializerStub {
|
|
124
|
+
serializeToString() {
|
|
125
|
+
return '';
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// Build the window shim
|
|
129
|
+
const windowShim = {};
|
|
130
|
+
for (const key of Object.getOwnPropertyNames(globalThis)) {
|
|
131
|
+
try {
|
|
132
|
+
windowShim[key] = globalThis[key];
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// skip non-readable properties
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
windowShim.location = locationStub;
|
|
139
|
+
windowShim.document = documentStub;
|
|
140
|
+
windowShim.navigator = navigatorStub;
|
|
141
|
+
windowShim.localStorage = localStorageStub;
|
|
142
|
+
windowShim.self = windowShim;
|
|
143
|
+
windowShim.top = windowShim;
|
|
144
|
+
windowShim.parent = windowShim;
|
|
145
|
+
windowShim.addEventListener = noop;
|
|
146
|
+
windowShim.removeEventListener = noop;
|
|
147
|
+
windowShim.dispatchEvent = noop;
|
|
148
|
+
windowShim.requestAnimationFrame = noop;
|
|
149
|
+
windowShim.cancelAnimationFrame = noop;
|
|
150
|
+
windowShim.getComputedStyle = () => noopObj;
|
|
151
|
+
windowShim.matchMedia = matchMediaStub;
|
|
152
|
+
windowShim.open = noop;
|
|
153
|
+
windowShim.close = noop;
|
|
154
|
+
windowShim.focus = noop;
|
|
155
|
+
windowShim.blur = noop;
|
|
156
|
+
windowShim.scroll = noop;
|
|
157
|
+
windowShim.scrollTo = noop;
|
|
158
|
+
windowShim.scrollBy = noop;
|
|
159
|
+
windowShim.CustomEvent = class CustomEvent extends Event {
|
|
160
|
+
};
|
|
161
|
+
windowShim.HTMLElement = HTMLElementStub;
|
|
162
|
+
windowShim.Element = ElementStub;
|
|
163
|
+
windowShim.XMLSerializer = XMLSerializerStub;
|
|
164
|
+
// Set globals on globalThis
|
|
165
|
+
safeDefine(globalThis, 'window', windowShim);
|
|
166
|
+
safeDefine(globalThis, 'document', documentStub);
|
|
167
|
+
safeDefine(globalThis, 'navigator', navigatorStub);
|
|
168
|
+
safeDefine(globalThis, 'location', locationStub);
|
|
169
|
+
safeDefine(globalThis, 'localStorage', localStorageStub);
|
|
170
|
+
safeDefine(globalThis, 'self', windowShim);
|
|
171
|
+
safeDefine(globalThis, 'matchMedia', matchMediaStub);
|
|
172
|
+
safeDefine(globalThis, 'XMLSerializer', XMLSerializerStub);
|
|
17
173
|
}
|
|
18
174
|
const node_worker_threads_1 = require("node:worker_threads");
|
|
19
175
|
const node_module_1 = require("node:module");
|
|
@@ -25,25 +181,36 @@ async function processMessage(message) {
|
|
|
25
181
|
if (message.type !== 'LOAD') {
|
|
26
182
|
return;
|
|
27
183
|
}
|
|
184
|
+
const fileErrors = [];
|
|
28
185
|
try {
|
|
29
186
|
// Set the experimental decorators flag before loading support code
|
|
30
187
|
global.experimentalDecorators = message.experimentalDecorators;
|
|
31
188
|
process.env.CUCUMBER_EXPERIMENTAL_DECORATORS = String(message.experimentalDecorators);
|
|
32
|
-
// Load require modules (transpiler setup)
|
|
189
|
+
// Load require modules (transpiler setup) — these are critical, fail fast
|
|
33
190
|
for (const modulePath of message.requireModules) {
|
|
34
191
|
require(modulePath);
|
|
35
192
|
}
|
|
36
|
-
//
|
|
37
|
-
for (const filePath of message.requirePaths) {
|
|
38
|
-
require(filePath);
|
|
39
|
-
}
|
|
40
|
-
// Register ESM loaders
|
|
193
|
+
// Register ESM loaders — also critical for import phase
|
|
41
194
|
for (const specifier of message.loaders) {
|
|
42
195
|
(0, node_module_1.register)(specifier, (0, node_url_1.pathToFileURL)('./'));
|
|
43
196
|
}
|
|
44
|
-
// Load support files via
|
|
197
|
+
// Load support files via require (CJS) — per-file isolation
|
|
198
|
+
for (const filePath of message.requirePaths) {
|
|
199
|
+
try {
|
|
200
|
+
require(filePath);
|
|
201
|
+
}
|
|
202
|
+
catch (err) {
|
|
203
|
+
fileErrors.push(`CJS ${filePath}: ${err.message || String(err)}`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// Load support files via import (ESM) — per-file isolation
|
|
45
207
|
for (const filePath of message.importPaths) {
|
|
46
|
-
|
|
208
|
+
try {
|
|
209
|
+
await import((0, node_url_1.pathToFileURL)(filePath).toString());
|
|
210
|
+
}
|
|
211
|
+
catch (err) {
|
|
212
|
+
fileErrors.push(`ESM ${filePath}: ${err.message || String(err)}`);
|
|
213
|
+
}
|
|
47
214
|
}
|
|
48
215
|
// Extract descriptors from the binding registry
|
|
49
216
|
const { BindingRegistry } = require('../bindings/binding-registry');
|
|
@@ -53,14 +220,17 @@ async function processMessage(message) {
|
|
|
53
220
|
const response = {
|
|
54
221
|
type: 'LOADED',
|
|
55
222
|
descriptors,
|
|
56
|
-
loadedFiles
|
|
223
|
+
loadedFiles,
|
|
224
|
+
fileErrors: fileErrors.length > 0 ? fileErrors : undefined
|
|
57
225
|
};
|
|
58
226
|
node_worker_threads_1.parentPort.postMessage(response);
|
|
59
227
|
}
|
|
60
228
|
catch (err) {
|
|
229
|
+
// Critical failure (transpiler setup / loader registration / registry extraction)
|
|
61
230
|
const response = {
|
|
62
231
|
type: 'ERROR',
|
|
63
|
-
error: err.message || String(err)
|
|
232
|
+
error: err.message || String(err),
|
|
233
|
+
fileErrors: fileErrors.length > 0 ? fileErrors : undefined
|
|
64
234
|
};
|
|
65
235
|
node_worker_threads_1.parentPort.postMessage(response);
|
|
66
236
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader-worker.js","sourceRoot":"","sources":["../../src/api/loader-worker.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;AAEH,kFAAkF;AAClF,IAAI,OAAO,UAAU,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;IAC7C,UAAsC,CAAC,MAAM,GAAG,UAAU,CAAC;AAC7D,CAAC;AAED,6DAA6D;AAC7D,6CAAuC;AACvC,uCAAyC;AACzC,oCAAkC;AAElC,gFAAgF;AAC/E,MAAc,CAAC,eAAe,GAAG,IAAI,CAAC;AA4BvC,KAAK,UAAU,cAAc,CAAC,OAA4B;IACzD,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC7B,OAAO;IACR,CAAC;IAED,IAAI,CAAC;QACJ,mEAAmE;QACnE,MAAM,CAAC,sBAAsB,GAAG,OAAO,CAAC,sBAAsB,CAAC;QAC/D,OAAO,CAAC,GAAG,CAAC,gCAAgC,GAAG,MAAM,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC;QAEtF,0CAA0C;QAC1C,KAAK,MAAM,UAAU,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;YACjD,OAAO,CAAC,UAAU,CAAC,CAAC;QACrB,CAAC;QAED,uCAAuC;QACvC,KAAK,MAAM,QAAQ,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;YAC7C,OAAO,CAAC,QAAQ,CAAC,CAAC;QACnB,CAAC;QAED,uBAAuB;QACvB,KAAK,MAAM,SAAS,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACzC,IAAA,sBAAQ,EAAC,SAAS,EAAE,IAAA,wBAAa,EAAC,IAAI,CAAC,CAAC,CAAC;QAC1C,CAAC;QAED,sCAAsC;QACtC,KAAK,MAAM,QAAQ,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YAC5C,MAAM,MAAM,CAAC,IAAA,wBAAa,EAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;QAClD,CAAC;QAED,gDAAgD;QAChD,MAAM,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,8BAA8B,CAAC,CAAC;QACpE,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC;QAC1C,MAAM,WAAW,GAAG,QAAQ,CAAC,aAAa,EAAE,CAAC;QAC7C,MAAM,WAAW,GAAa,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,wBAAwB,EAAE,CAAC,CAAC;QAE9E,MAAM,QAAQ,GAAyB;YACtC,IAAI,EAAE,QAAQ;YACd,WAAW;YACX,WAAW;SACX,CAAC;QACF,gCAAW,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IACnC,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QACnB,MAAM,QAAQ,GAAyB;YACtC,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,GAAG,CAAC,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC;SACjC,CAAC;QACF,gCAAW,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IACnC,CAAC;AACF,CAAC;AAED,uEAAuE;AACvE,IAAI,gCAAU,IAAI,gCAAU,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC9C,cAAc,CAAC,gCAAiC,CAAC,CAAC;AACnD,CAAC;AAED,4CAA4C;AAC5C,gCAAU,EAAE,EAAE,CAAC,SAAS,EAAE,CAAC,GAAwB,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC","sourcesContent":["/**\r\n * loader-worker.ts\r\n *\r\n * Runs inside a worker_threads Worker. Receives support-code file paths and\r\n * transpiler configuration, loads the files (warming the transpiler cache),\r\n * extracts serializable binding descriptors from the BindingRegistry, and\r\n * posts them back to the main thread.\r\n *\r\n * The __LOADER_WORKER global flag causes the binding decorator to skip\r\n * Cucumber step/hook registration — only BindingRegistry population occurs.\r\n */\r\n\r\n// Shim 'window' for libraries that expect a browser environment in worker threads\r\nif (typeof globalThis.window === 'undefined') {\r\n\t(globalThis as Record<string, unknown>).window = globalThis;\r\n}\r\n\r\nimport { parentPort, workerData } from 'node:worker_threads';\r\nimport { register } from 'node:module';\r\nimport { pathToFileURL } from 'node:url';\r\nimport 'polyfill-symbol-metadata';\r\n\r\n// Signal that we're in a loader-worker context so decorators skip Cucumber APIs\r\n(global as any).__LOADER_WORKER = true;\r\n\r\n/** Message types sent from main thread to worker */\r\nexport interface LoaderWorkerRequest {\r\n\ttype: 'LOAD';\r\n\t/** Absolute paths to load via require() */\r\n\trequirePaths: string[];\r\n\t/** Absolute paths to load via import() */\r\n\timportPaths: string[];\r\n\t/** Modules to require before support code (transpiler setup etc.) */\r\n\trequireModules: string[];\r\n\t/** ESM loaders to register before importing */\r\n\tloaders: string[];\r\n\t/** Whether to use experimental decorators */\r\n\texperimentalDecorators: boolean;\r\n}\r\n\r\n/** Message types sent from worker back to main thread */\r\nexport interface LoaderWorkerResponse {\r\n\ttype: 'LOADED' | 'ERROR';\r\n\t/** Serializable binding descriptors extracted from the registry */\r\n\tdescriptors?: import('../bindings/step-binding').SerializableBindingDescriptor[];\r\n\t/** Source files that were successfully loaded */\r\n\tloadedFiles?: string[];\r\n\t/** Error message if something went wrong */\r\n\terror?: string;\r\n}\r\n\r\nasync function processMessage(message: LoaderWorkerRequest): Promise<void> {\r\n\tif (message.type !== 'LOAD') {\r\n\t\treturn;\r\n\t}\r\n\r\n\ttry {\r\n\t\t// Set the experimental decorators flag before loading support code\r\n\t\tglobal.experimentalDecorators = message.experimentalDecorators;\r\n\t\tprocess.env.CUCUMBER_EXPERIMENTAL_DECORATORS = String(message.experimentalDecorators);\r\n\r\n\t\t// Load require modules (transpiler setup)\r\n\t\tfor (const modulePath of message.requireModules) {\r\n\t\t\trequire(modulePath);\r\n\t\t}\r\n\r\n\t\t// Load support files via require (CJS)\r\n\t\tfor (const filePath of message.requirePaths) {\r\n\t\t\trequire(filePath);\r\n\t\t}\r\n\r\n\t\t// Register ESM loaders\r\n\t\tfor (const specifier of message.loaders) {\r\n\t\t\tregister(specifier, pathToFileURL('./'));\r\n\t\t}\r\n\r\n\t\t// Load support files via import (ESM)\r\n\t\tfor (const filePath of message.importPaths) {\r\n\t\t\tawait import(pathToFileURL(filePath).toString());\r\n\t\t}\r\n\r\n\t\t// Extract descriptors from the binding registry\r\n\t\tconst { BindingRegistry } = require('../bindings/binding-registry');\r\n\t\tconst registry = BindingRegistry.instance;\r\n\t\tconst descriptors = registry.toDescriptors();\r\n\t\tconst loadedFiles: string[] = Array.from(registry.getDescriptorSourceFiles());\r\n\r\n\t\tconst response: LoaderWorkerResponse = {\r\n\t\t\ttype: 'LOADED',\r\n\t\t\tdescriptors,\r\n\t\t\tloadedFiles\r\n\t\t};\r\n\t\tparentPort!.postMessage(response);\r\n\t} catch (err: any) {\r\n\t\tconst response: LoaderWorkerResponse = {\r\n\t\t\ttype: 'ERROR',\r\n\t\t\terror: err.message || String(err)\r\n\t\t};\r\n\t\tparentPort!.postMessage(response);\r\n\t}\r\n}\r\n\r\n// Handle initial workerData (if files are passed at construction time)\r\nif (workerData && workerData.type === 'LOAD') {\r\n\tprocessMessage(workerData as LoaderWorkerRequest);\r\n}\r\n\r\n// Handle messages posted after construction\r\nparentPort?.on('message', (msg: LoaderWorkerRequest) => processMessage(msg));\r\n"]}
|
|
1
|
+
{"version":3,"file":"loader-worker.js","sourceRoot":"","sources":["../../src/api/loader-worker.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * loader-worker.ts\r\n *\r\n * Runs inside a worker_threads Worker. Receives support-code file paths and\r\n * transpiler configuration, loads the files (warming the transpiler cache),\r\n * extracts serializable binding descriptors from the BindingRegistry, and\r\n * posts them back to the main thread.\r\n *\r\n * The __LOADER_WORKER global flag causes the binding decorator to skip\r\n * Cucumber step/hook registration — only BindingRegistry population occurs.\r\n */\r\n\r\n// Shim browser globals for libraries that expect a browser environment in worker threads.\r\n// Workers are a constrained Node.js environment — many libraries probe for browser APIs\r\n// during module evaluation. These stubs prevent \"Cannot read properties of undefined\" errors.\r\n// Aligned with the globals expected by @uis/testing-bdd (uis-jest setup).\r\nif (typeof globalThis.window === 'undefined') {\r\n\tconst noop = (): void => {};\r\n\tconst noopObj = new Proxy({}, { get: () => noop });\r\n\r\n\t// Helper: safely set a global property (some like `navigator` are getter-only in modern Node)\r\n\tconst safeDefine = (target: object, key: string, value: unknown): void => {\r\n\t\ttry {\r\n\t\t\tObject.defineProperty(target, key, { value, writable: true, configurable: true });\r\n\t\t} catch {\r\n\t\t\t// Property may be non-configurable — ignore and move on\r\n\t\t}\r\n\t};\r\n\r\n\t// Minimal location stub — covers window.location.href / .origin / .protocol etc.\r\n\tconst locationStub = {\r\n\t\thref: '',\r\n\t\torigin: '',\r\n\t\tprotocol: 'file:',\r\n\t\thost: '',\r\n\t\thostname: '',\r\n\t\tport: '',\r\n\t\tpathname: '',\r\n\t\tsearch: '',\r\n\t\thash: '',\r\n\t\tassign: noop,\r\n\t\treplace: noop,\r\n\t\treload: noop,\r\n\t\ttoString: () => ''\r\n\t};\r\n\r\n\t// Minimal document stub — covers document.createElement, querySelector, etc.\r\n\tconst documentStub = {\r\n\t\tcreateElement: (): unknown => noopObj,\r\n\t\tcreateElementNS: (): unknown => noopObj,\r\n\t\tcreateTextNode: (): unknown => noopObj,\r\n\t\tcreateDocumentFragment: (): unknown => noopObj,\r\n\t\tcreateComment: (): unknown => noopObj,\r\n\t\tgetElementById: (): null => null,\r\n\t\tgetElementsByClassName: (): unknown[] => [],\r\n\t\tgetElementsByTagName: (): unknown[] => [],\r\n\t\tquerySelector: (): null => null,\r\n\t\tquerySelectorAll: (): unknown[] => [],\r\n\t\thead: noopObj,\r\n\t\tbody: noopObj,\r\n\t\tdocumentElement: noopObj,\r\n\t\taddEventListener: noop,\r\n\t\tremoveEventListener: noop,\r\n\t\tdispatchEvent: noop,\r\n\t\tcookie: ''\r\n\t};\r\n\r\n\t// Minimal navigator stub\r\n\tconst navigatorStub = {\r\n\t\tuserAgent: 'node',\r\n\t\tplatform: process.platform,\r\n\t\tlanguage: 'en',\r\n\t\tlanguages: ['en']\r\n\t};\r\n\r\n\t// Fake localStorage — matches @uis/testing-bdd FakeLocalStorage\r\n\tconst localStorageStub = {\r\n\t\tstore: {} as Record<string, string>,\r\n\t\tclear(): void {\r\n\t\t\tthis.store = {};\r\n\t\t},\r\n\t\tgetItem(key: string): string | null {\r\n\t\t\treturn this.store[key] ?? null;\r\n\t\t},\r\n\t\tsetItem(key: string, value: string): void {\r\n\t\t\tthis.store[key] = value;\r\n\t\t},\r\n\t\tremoveItem(key: string): void {\r\n\t\t\tdelete this.store[key];\r\n\t\t},\r\n\t\tget length(): number {\r\n\t\t\treturn Object.keys(this.store).length;\r\n\t\t},\r\n\t\tkey(): null {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t};\r\n\r\n\t// matchMedia stub — matches @uis/testing-bdd mock\r\n\tconst matchMediaStub = (query: string): Record<string, unknown> => ({\r\n\t\tmatches: false,\r\n\t\tmedia: query,\r\n\t\tonchange: null,\r\n\t\taddListener: noop,\r\n\t\tremoveListener: noop,\r\n\t\taddEventListener: noop,\r\n\t\tremoveEventListener: noop,\r\n\t\tdispatchEvent: noop\r\n\t});\r\n\r\n\t// Minimal Element prototype for scrollIntoView etc.\r\n\tclass HTMLElementStub {\r\n\t\tscrollIntoView = noop;\r\n\t\tgetBoundingClientRect = (): Record<string, number> => ({\r\n\t\t\ttop: 0,\r\n\t\t\tleft: 0,\r\n\t\t\tbottom: 0,\r\n\t\t\tright: 0,\r\n\t\t\twidth: 0,\r\n\t\t\theight: 0,\r\n\t\t\tx: 0,\r\n\t\t\ty: 0\r\n\t\t});\r\n\t}\r\n\tclass ElementStub extends HTMLElementStub {}\r\n\r\n\t// Minimal XMLSerializer stub\r\n\tclass XMLSerializerStub {\r\n\t\tserializeToString(): string {\r\n\t\t\treturn '';\r\n\t\t}\r\n\t}\r\n\r\n\t// Build the window shim\r\n\tconst windowShim: Record<string, unknown> = {};\r\n\tfor (const key of Object.getOwnPropertyNames(globalThis)) {\r\n\t\ttry {\r\n\t\t\t(windowShim as Record<string, unknown>)[key] = (globalThis as Record<string, unknown>)[key];\r\n\t\t} catch {\r\n\t\t\t// skip non-readable properties\r\n\t\t}\r\n\t}\r\n\r\n\twindowShim.location = locationStub;\r\n\twindowShim.document = documentStub;\r\n\twindowShim.navigator = navigatorStub;\r\n\twindowShim.localStorage = localStorageStub;\r\n\twindowShim.self = windowShim;\r\n\twindowShim.top = windowShim;\r\n\twindowShim.parent = windowShim;\r\n\twindowShim.addEventListener = noop;\r\n\twindowShim.removeEventListener = noop;\r\n\twindowShim.dispatchEvent = noop;\r\n\twindowShim.requestAnimationFrame = noop;\r\n\twindowShim.cancelAnimationFrame = noop;\r\n\twindowShim.getComputedStyle = () => noopObj;\r\n\twindowShim.matchMedia = matchMediaStub;\r\n\twindowShim.open = noop;\r\n\twindowShim.close = noop;\r\n\twindowShim.focus = noop;\r\n\twindowShim.blur = noop;\r\n\twindowShim.scroll = noop;\r\n\twindowShim.scrollTo = noop;\r\n\twindowShim.scrollBy = noop;\r\n\twindowShim.CustomEvent = class CustomEvent extends Event {};\r\n\twindowShim.HTMLElement = HTMLElementStub;\r\n\twindowShim.Element = ElementStub;\r\n\twindowShim.XMLSerializer = XMLSerializerStub;\r\n\r\n\t// Set globals on globalThis\r\n\tsafeDefine(globalThis, 'window', windowShim);\r\n\tsafeDefine(globalThis, 'document', documentStub);\r\n\tsafeDefine(globalThis, 'navigator', navigatorStub);\r\n\tsafeDefine(globalThis, 'location', locationStub);\r\n\tsafeDefine(globalThis, 'localStorage', localStorageStub);\r\n\tsafeDefine(globalThis, 'self', windowShim);\r\n\tsafeDefine(globalThis, 'matchMedia', matchMediaStub);\r\n\tsafeDefine(globalThis, 'XMLSerializer', XMLSerializerStub);\r\n}\r\n\r\nimport { parentPort, workerData } from 'node:worker_threads';\r\nimport { register } from 'node:module';\r\nimport { pathToFileURL } from 'node:url';\r\nimport 'polyfill-symbol-metadata';\r\n\r\n// Signal that we're in a loader-worker context so decorators skip Cucumber APIs\r\n(global as any).__LOADER_WORKER = true;\r\n\r\n/** Message types sent from main thread to worker */\r\nexport interface LoaderWorkerRequest {\r\n\ttype: 'LOAD';\r\n\t/** Absolute paths to load via require() */\r\n\trequirePaths: string[];\r\n\t/** Absolute paths to load via import() */\r\n\timportPaths: string[];\r\n\t/** Modules to require before support code (transpiler setup etc.) */\r\n\trequireModules: string[];\r\n\t/** ESM loaders to register before importing */\r\n\tloaders: string[];\r\n\t/** Whether to use experimental decorators */\r\n\texperimentalDecorators: boolean;\r\n}\r\n\r\n/** Message types sent from worker back to main thread */\r\nexport interface LoaderWorkerResponse {\r\n\ttype: 'LOADED' | 'ERROR';\r\n\t/** Serializable binding descriptors extracted from the registry */\r\n\tdescriptors?: import('../bindings/step-binding').SerializableBindingDescriptor[];\r\n\t/** Source files that were successfully loaded */\r\n\tloadedFiles?: string[];\r\n\t/** Error message if something went wrong */\r\n\terror?: string;\r\n\t/** Per-file errors that were caught but did not kill the worker */\r\n\tfileErrors?: string[];\r\n}\r\n\r\nasync function processMessage(message: LoaderWorkerRequest): Promise<void> {\r\n\tif (message.type !== 'LOAD') {\r\n\t\treturn;\r\n\t}\r\n\r\n\tconst fileErrors: string[] = [];\r\n\r\n\ttry {\r\n\t\t// Set the experimental decorators flag before loading support code\r\n\t\tglobal.experimentalDecorators = message.experimentalDecorators;\r\n\t\tprocess.env.CUCUMBER_EXPERIMENTAL_DECORATORS = String(message.experimentalDecorators);\r\n\r\n\t\t// Load require modules (transpiler setup) — these are critical, fail fast\r\n\t\tfor (const modulePath of message.requireModules) {\r\n\t\t\trequire(modulePath);\r\n\t\t}\r\n\r\n\t\t// Register ESM loaders — also critical for import phase\r\n\t\tfor (const specifier of message.loaders) {\r\n\t\t\tregister(specifier, pathToFileURL('./'));\r\n\t\t}\r\n\r\n\t\t// Load support files via require (CJS) — per-file isolation\r\n\t\tfor (const filePath of message.requirePaths) {\r\n\t\t\ttry {\r\n\t\t\t\trequire(filePath);\r\n\t\t\t} catch (err: any) {\r\n\t\t\t\tfileErrors.push(`CJS ${filePath}: ${err.message || String(err)}`);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Load support files via import (ESM) — per-file isolation\r\n\t\tfor (const filePath of message.importPaths) {\r\n\t\t\ttry {\r\n\t\t\t\tawait import(pathToFileURL(filePath).toString());\r\n\t\t\t} catch (err: any) {\r\n\t\t\t\tfileErrors.push(`ESM ${filePath}: ${err.message || String(err)}`);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Extract descriptors from the binding registry\r\n\t\tconst { BindingRegistry } = require('../bindings/binding-registry');\r\n\t\tconst registry = BindingRegistry.instance;\r\n\t\tconst descriptors = registry.toDescriptors();\r\n\t\tconst loadedFiles: string[] = Array.from(registry.getDescriptorSourceFiles());\r\n\r\n\t\tconst response: LoaderWorkerResponse = {\r\n\t\t\ttype: 'LOADED',\r\n\t\t\tdescriptors,\r\n\t\t\tloadedFiles,\r\n\t\t\tfileErrors: fileErrors.length > 0 ? fileErrors : undefined\r\n\t\t};\r\n\t\tparentPort!.postMessage(response);\r\n\t} catch (err: any) {\r\n\t\t// Critical failure (transpiler setup / loader registration / registry extraction)\r\n\t\tconst response: LoaderWorkerResponse = {\r\n\t\t\ttype: 'ERROR',\r\n\t\t\terror: err.message || String(err),\r\n\t\t\tfileErrors: fileErrors.length > 0 ? fileErrors : undefined\r\n\t\t};\r\n\t\tparentPort!.postMessage(response);\r\n\t}\r\n}\r\n\r\n// Handle initial workerData (if files are passed at construction time)\r\nif (workerData && workerData.type === 'LOAD') {\r\n\tprocessMessage(workerData as LoaderWorkerRequest);\r\n}\r\n\r\n// Handle messages posted after construction\r\nparentPort?.on('message', (msg: LoaderWorkerRequest) => processMessage(msg));\r\n"]}
|
|
@@ -64,6 +64,7 @@ async function parallelPreload(options) {
|
|
|
64
64
|
const allDescriptors = [];
|
|
65
65
|
const allFiles = new Set();
|
|
66
66
|
let errors = 0;
|
|
67
|
+
let fileWarnings = 0;
|
|
67
68
|
for (const result of results) {
|
|
68
69
|
if (result.status === 'fulfilled') {
|
|
69
70
|
const response = result.value;
|
|
@@ -74,10 +75,22 @@ async function parallelPreload(options) {
|
|
|
74
75
|
if (response.loadedFiles) {
|
|
75
76
|
response.loadedFiles.forEach(f => allFiles.add(f));
|
|
76
77
|
}
|
|
78
|
+
// Per-file errors are non-fatal — the file just didn't contribute to the cache
|
|
79
|
+
if (response.fileErrors && response.fileErrors.length > 0) {
|
|
80
|
+
fileWarnings += response.fileErrors.length;
|
|
81
|
+
for (const fe of response.fileErrors) {
|
|
82
|
+
logger.checkpoint('File skipped during preload', { detail: fe });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
77
85
|
}
|
|
78
86
|
else {
|
|
79
87
|
errors++;
|
|
80
88
|
logger.error('Worker reported error', new Error(response.error || 'Unknown worker error'));
|
|
89
|
+
if (response.fileErrors) {
|
|
90
|
+
for (const fe of response.fileErrors) {
|
|
91
|
+
logger.checkpoint('File skipped during preload', { detail: fe });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
81
94
|
}
|
|
82
95
|
}
|
|
83
96
|
else {
|
|
@@ -90,11 +103,15 @@ async function parallelPreload(options) {
|
|
|
90
103
|
durationMs,
|
|
91
104
|
descriptorCount: allDescriptors.length,
|
|
92
105
|
fileCount: allFiles.size,
|
|
93
|
-
errors
|
|
106
|
+
errors,
|
|
107
|
+
fileWarnings
|
|
94
108
|
});
|
|
95
109
|
if (errors > 0) {
|
|
96
110
|
logger.checkpoint('Some workers failed — main thread will do full load as fallback');
|
|
97
111
|
}
|
|
112
|
+
if (fileWarnings > 0) {
|
|
113
|
+
logger.checkpoint(`${fileWarnings} file(s) skipped during preload — these will be loaded by the main thread`);
|
|
114
|
+
}
|
|
98
115
|
return {
|
|
99
116
|
descriptors: allDescriptors,
|
|
100
117
|
loadedFiles: Array.from(allFiles),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parallel-loader.js","sourceRoot":"","sources":["../../src/api/parallel-loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * parallel-loader.ts\r\n *\r\n * Orchestrates parallel pre-warming of transpiler caches using worker_threads.\r\n * Each worker loads a subset of support-code files, warming the transpiler's\r\n * on-disk cache. After all workers finish, the main thread performs the\r\n * authoritative load (which hits warm caches and runs much faster).\r\n *\r\n * The descriptors returned by workers are used for validation — the main\r\n * thread's BindingRegistry is the canonical source of truth.\r\n */\r\nimport { Worker } from 'node:worker_threads';\r\nimport { availableParallelism } from 'node:os';\r\nimport path from 'node:path';\r\nimport type { LoaderWorkerRequest, LoaderWorkerResponse } from './loader-worker';\r\nimport type { SerializableBindingDescriptor } from '../bindings/step-binding';\r\nimport { createLogger } from '../utils/tsflow-logger';\r\n\r\nconst logger = createLogger('parallel-loader');\r\n\r\nexport interface ParallelLoadOptions {\r\n\t/** Absolute require-paths for CJS support files */\r\n\trequirePaths: string[];\r\n\t/** Absolute import-paths for ESM support files */\r\n\timportPaths: string[];\r\n\t/** Modules to require before support code (transpiler hooks) */\r\n\trequireModules: string[];\r\n\t/** ESM loaders to register */\r\n\tloaders: string[];\r\n\t/** Whether experimental decorators are enabled */\r\n\texperimentalDecorators: boolean;\r\n\t/** Number of threads (true = auto, number = explicit) */\r\n\tthreadCount: boolean | number;\r\n}\r\n\r\nexport interface ParallelLoadResult {\r\n\t/** All descriptors collected across workers (for validation) */\r\n\tdescriptors: SerializableBindingDescriptor[];\r\n\t/** Unique source files loaded across all workers */\r\n\tloadedFiles: string[];\r\n\t/** Time spent in parallel phase (ms) */\r\n\tdurationMs: number;\r\n}\r\n\r\n/**\r\n * Pre-warm transpiler caches by loading support files in parallel worker threads.\r\n *\r\n * Each worker receives a subset of files, loads them (which triggers transpilation),\r\n * and returns serializable binding descriptors. The transpiler cache on disk is now\r\n * warm for the main thread's subsequent load.\r\n */\r\nexport async function parallelPreload(options: ParallelLoadOptions): Promise<ParallelLoadResult> {\r\n\tconst start = performance.now();\r\n\r\n\tconst threads = resolveThreadCount(options.threadCount);\r\n\tlogger.checkpoint('Starting parallel preload', {\r\n\t\tthreads,\r\n\t\trequirePaths: options.requirePaths.length,\r\n\t\timportPaths: options.importPaths.length\r\n\t});\r\n\r\n\t// Split files across workers — round-robin distribution\r\n\tconst requireChunks = chunkRoundRobin(options.requirePaths, threads);\r\n\tconst importChunks = chunkRoundRobin(options.importPaths, threads);\r\n\r\n\t// Resolve the worker script path (compiled JS in lib/)\r\n\tconst workerScript = resolveWorkerScript();\r\n\tlogger.checkpoint('Worker script resolved', { workerScript });\r\n\r\n\t// Launch workers\r\n\tconst workerPromises: Promise<LoaderWorkerResponse>[] = [];\r\n\r\n\tfor (let i = 0; i < threads; i++) {\r\n\t\t// Only launch a worker if it has files to process\r\n\t\tif (requireChunks[i].length === 0 && importChunks[i].length === 0) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tconst request: LoaderWorkerRequest = {\r\n\t\t\ttype: 'LOAD',\r\n\t\t\trequirePaths: requireChunks[i],\r\n\t\t\timportPaths: importChunks[i],\r\n\t\t\trequireModules: options.requireModules,\r\n\t\t\tloaders: options.loaders,\r\n\t\t\texperimentalDecorators: options.experimentalDecorators\r\n\t\t};\r\n\r\n\t\tworkerPromises.push(runWorker(workerScript, request, i));\r\n\t}\r\n\r\n\t// Await all workers\r\n\tconst results = await Promise.allSettled(workerPromises);\r\n\r\n\t// Collect results\r\n\tconst allDescriptors: SerializableBindingDescriptor[] = [];\r\n\tconst allFiles = new Set<string>();\r\n\tlet errors = 0;\r\n\r\n\tfor (const result of results) {\r\n\t\tif (result.status === 'fulfilled') {\r\n\t\t\tconst response = result.value;\r\n\t\t\tif (response.type === 'LOADED') {\r\n\t\t\t\tif (response.descriptors) {\r\n\t\t\t\t\tallDescriptors.push(...response.descriptors);\r\n\t\t\t\t}\r\n\t\t\t\tif (response.loadedFiles) {\r\n\t\t\t\t\tresponse.loadedFiles.forEach(f => allFiles.add(f));\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\terrors++;\r\n\t\t\t\tlogger.error('Worker reported error', new Error(response.error || 'Unknown worker error'));\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\terrors++;\r\n\t\t\tlogger.error('Worker promise rejected', result.reason);\r\n\t\t}\r\n\t}\r\n\r\n\tconst durationMs = Math.round(performance.now() - start);\r\n\tlogger.checkpoint('Parallel preload completed', {\r\n\t\tdurationMs,\r\n\t\tdescriptorCount: allDescriptors.length,\r\n\t\tfileCount: allFiles.size,\r\n\t\terrors\r\n\t});\r\n\r\n\tif (errors > 0) {\r\n\t\tlogger.checkpoint('Some workers failed — main thread will do full load as fallback');\r\n\t}\r\n\r\n\treturn {\r\n\t\tdescriptors: allDescriptors,\r\n\t\tloadedFiles: Array.from(allFiles),\r\n\t\tdurationMs\r\n\t};\r\n}\r\n\r\n/**\r\n * Run a single loader-worker and return its response.\r\n */\r\nfunction runWorker(workerScript: string, request: LoaderWorkerRequest, index: number): Promise<LoaderWorkerResponse> {\r\n\treturn new Promise((resolve, reject) => {\r\n\t\tconst worker = new Worker(workerScript, {\r\n\t\t\tworkerData: request\r\n\t\t});\r\n\r\n\t\tlet settled = false;\r\n\r\n\t\tworker.on('message', (msg: LoaderWorkerResponse) => {\r\n\t\t\tif (!settled) {\r\n\t\t\t\tsettled = true;\r\n\t\t\t\tlogger.checkpoint(`Worker ${index} completed`, { type: msg.type });\r\n\t\t\t\tworker.terminate();\r\n\t\t\t\tresolve(msg);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tworker.on('error', err => {\r\n\t\t\tif (!settled) {\r\n\t\t\t\tsettled = true;\r\n\t\t\t\tlogger.error(`Worker ${index} error`, err);\r\n\t\t\t\treject(err);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tworker.on('exit', code => {\r\n\t\t\tif (!settled) {\r\n\t\t\t\tsettled = true;\r\n\t\t\t\tif (code !== 0) {\r\n\t\t\t\t\treject(new Error(`Worker ${index} exited with code ${code}`));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\t});\r\n}\r\n\r\n/**\r\n * Resolve the number of threads to use.\r\n * - true: use availableParallelism() capped at 4\r\n * - number: use that exact count (min 1)\r\n */\r\nfunction resolveThreadCount(threadCount: boolean | number): number {\r\n\tif (typeof threadCount === 'number') {\r\n\t\treturn Math.max(1, threadCount);\r\n\t}\r\n\t// Auto-detect: use available parallelism, capped at a reasonable default\r\n\treturn Math.min(availableParallelism(), 4);\r\n}\r\n\r\n/**\r\n * Distribute items round-robin across N buckets.\r\n */\r\nfunction chunkRoundRobin<T>(items: T[], buckets: number): T[][] {\r\n\tconst chunks: T[][] = Array.from({ length: buckets }, (): T[] => []);\r\n\tfor (let i = 0; i < items.length; i++) {\r\n\t\tchunks[i % buckets].push(items[i]);\r\n\t}\r\n\treturn chunks;\r\n}\r\n\r\n/**\r\n * Resolve the path to the compiled loader-worker script.\r\n * In development (src), this file is adjacent; in production (lib/), it's compiled.\r\n */\r\nfunction resolveWorkerScript(): string {\r\n\t// Try the compiled lib path first, falling back to __dirname\r\n\tconst libPath = path.resolve(__dirname, 'loader-worker.js');\r\n\treturn libPath;\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"parallel-loader.js","sourceRoot":"","sources":["../../src/api/parallel-loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * parallel-loader.ts\r\n *\r\n * Orchestrates parallel pre-warming of transpiler caches using worker_threads.\r\n * Each worker loads a subset of support-code files, warming the transpiler's\r\n * on-disk cache. After all workers finish, the main thread performs the\r\n * authoritative load (which hits warm caches and runs much faster).\r\n *\r\n * The descriptors returned by workers are used for validation — the main\r\n * thread's BindingRegistry is the canonical source of truth.\r\n */\r\nimport { Worker } from 'node:worker_threads';\r\nimport { availableParallelism } from 'node:os';\r\nimport path from 'node:path';\r\nimport type { LoaderWorkerRequest, LoaderWorkerResponse } from './loader-worker';\r\nimport type { SerializableBindingDescriptor } from '../bindings/step-binding';\r\nimport { createLogger } from '../utils/tsflow-logger';\r\n\r\nconst logger = createLogger('parallel-loader');\r\n\r\nexport interface ParallelLoadOptions {\r\n\t/** Absolute require-paths for CJS support files */\r\n\trequirePaths: string[];\r\n\t/** Absolute import-paths for ESM support files */\r\n\timportPaths: string[];\r\n\t/** Modules to require before support code (transpiler hooks) */\r\n\trequireModules: string[];\r\n\t/** ESM loaders to register */\r\n\tloaders: string[];\r\n\t/** Whether experimental decorators are enabled */\r\n\texperimentalDecorators: boolean;\r\n\t/** Number of threads (true = auto, number = explicit) */\r\n\tthreadCount: boolean | number;\r\n}\r\n\r\nexport interface ParallelLoadResult {\r\n\t/** All descriptors collected across workers (for validation) */\r\n\tdescriptors: SerializableBindingDescriptor[];\r\n\t/** Unique source files loaded across all workers */\r\n\tloadedFiles: string[];\r\n\t/** Time spent in parallel phase (ms) */\r\n\tdurationMs: number;\r\n}\r\n\r\n/**\r\n * Pre-warm transpiler caches by loading support files in parallel worker threads.\r\n *\r\n * Each worker receives a subset of files, loads them (which triggers transpilation),\r\n * and returns serializable binding descriptors. The transpiler cache on disk is now\r\n * warm for the main thread's subsequent load.\r\n */\r\nexport async function parallelPreload(options: ParallelLoadOptions): Promise<ParallelLoadResult> {\r\n\tconst start = performance.now();\r\n\r\n\tconst threads = resolveThreadCount(options.threadCount);\r\n\tlogger.checkpoint('Starting parallel preload', {\r\n\t\tthreads,\r\n\t\trequirePaths: options.requirePaths.length,\r\n\t\timportPaths: options.importPaths.length\r\n\t});\r\n\r\n\t// Split files across workers — round-robin distribution\r\n\tconst requireChunks = chunkRoundRobin(options.requirePaths, threads);\r\n\tconst importChunks = chunkRoundRobin(options.importPaths, threads);\r\n\r\n\t// Resolve the worker script path (compiled JS in lib/)\r\n\tconst workerScript = resolveWorkerScript();\r\n\tlogger.checkpoint('Worker script resolved', { workerScript });\r\n\r\n\t// Launch workers\r\n\tconst workerPromises: Promise<LoaderWorkerResponse>[] = [];\r\n\r\n\tfor (let i = 0; i < threads; i++) {\r\n\t\t// Only launch a worker if it has files to process\r\n\t\tif (requireChunks[i].length === 0 && importChunks[i].length === 0) {\r\n\t\t\tcontinue;\r\n\t\t}\r\n\r\n\t\tconst request: LoaderWorkerRequest = {\r\n\t\t\ttype: 'LOAD',\r\n\t\t\trequirePaths: requireChunks[i],\r\n\t\t\timportPaths: importChunks[i],\r\n\t\t\trequireModules: options.requireModules,\r\n\t\t\tloaders: options.loaders,\r\n\t\t\texperimentalDecorators: options.experimentalDecorators\r\n\t\t};\r\n\r\n\t\tworkerPromises.push(runWorker(workerScript, request, i));\r\n\t}\r\n\r\n\t// Await all workers\r\n\tconst results = await Promise.allSettled(workerPromises);\r\n\r\n\t// Collect results\r\n\tconst allDescriptors: SerializableBindingDescriptor[] = [];\r\n\tconst allFiles = new Set<string>();\r\n\tlet errors = 0;\r\n\tlet fileWarnings = 0;\r\n\r\n\tfor (const result of results) {\r\n\t\tif (result.status === 'fulfilled') {\r\n\t\t\tconst response = result.value;\r\n\t\t\tif (response.type === 'LOADED') {\r\n\t\t\t\tif (response.descriptors) {\r\n\t\t\t\t\tallDescriptors.push(...response.descriptors);\r\n\t\t\t\t}\r\n\t\t\t\tif (response.loadedFiles) {\r\n\t\t\t\t\tresponse.loadedFiles.forEach(f => allFiles.add(f));\r\n\t\t\t\t}\r\n\t\t\t\t// Per-file errors are non-fatal — the file just didn't contribute to the cache\r\n\t\t\t\tif (response.fileErrors && response.fileErrors.length > 0) {\r\n\t\t\t\t\tfileWarnings += response.fileErrors.length;\r\n\t\t\t\t\tfor (const fe of response.fileErrors) {\r\n\t\t\t\t\t\tlogger.checkpoint('File skipped during preload', { detail: fe });\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\terrors++;\r\n\t\t\t\tlogger.error('Worker reported error', new Error(response.error || 'Unknown worker error'));\r\n\t\t\t\tif (response.fileErrors) {\r\n\t\t\t\t\tfor (const fe of response.fileErrors) {\r\n\t\t\t\t\t\tlogger.checkpoint('File skipped during preload', { detail: fe });\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\terrors++;\r\n\t\t\tlogger.error('Worker promise rejected', result.reason);\r\n\t\t}\r\n\t}\r\n\r\n\tconst durationMs = Math.round(performance.now() - start);\r\n\tlogger.checkpoint('Parallel preload completed', {\r\n\t\tdurationMs,\r\n\t\tdescriptorCount: allDescriptors.length,\r\n\t\tfileCount: allFiles.size,\r\n\t\terrors,\r\n\t\tfileWarnings\r\n\t});\r\n\r\n\tif (errors > 0) {\r\n\t\tlogger.checkpoint('Some workers failed — main thread will do full load as fallback');\r\n\t}\r\n\tif (fileWarnings > 0) {\r\n\t\tlogger.checkpoint(`${fileWarnings} file(s) skipped during preload — these will be loaded by the main thread`);\r\n\t}\r\n\r\n\treturn {\r\n\t\tdescriptors: allDescriptors,\r\n\t\tloadedFiles: Array.from(allFiles),\r\n\t\tdurationMs\r\n\t};\r\n}\r\n\r\n/**\r\n * Run a single loader-worker and return its response.\r\n */\r\nfunction runWorker(workerScript: string, request: LoaderWorkerRequest, index: number): Promise<LoaderWorkerResponse> {\r\n\treturn new Promise((resolve, reject) => {\r\n\t\tconst worker = new Worker(workerScript, {\r\n\t\t\tworkerData: request\r\n\t\t});\r\n\r\n\t\tlet settled = false;\r\n\r\n\t\tworker.on('message', (msg: LoaderWorkerResponse) => {\r\n\t\t\tif (!settled) {\r\n\t\t\t\tsettled = true;\r\n\t\t\t\tlogger.checkpoint(`Worker ${index} completed`, { type: msg.type });\r\n\t\t\t\tworker.terminate();\r\n\t\t\t\tresolve(msg);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tworker.on('error', err => {\r\n\t\t\tif (!settled) {\r\n\t\t\t\tsettled = true;\r\n\t\t\t\tlogger.error(`Worker ${index} error`, err);\r\n\t\t\t\treject(err);\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tworker.on('exit', code => {\r\n\t\t\tif (!settled) {\r\n\t\t\t\tsettled = true;\r\n\t\t\t\tif (code !== 0) {\r\n\t\t\t\t\treject(new Error(`Worker ${index} exited with code ${code}`));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\t});\r\n}\r\n\r\n/**\r\n * Resolve the number of threads to use.\r\n * - true: use availableParallelism() capped at 4\r\n * - number: use that exact count (min 1)\r\n */\r\nfunction resolveThreadCount(threadCount: boolean | number): number {\r\n\tif (typeof threadCount === 'number') {\r\n\t\treturn Math.max(1, threadCount);\r\n\t}\r\n\t// Auto-detect: use available parallelism, capped at a reasonable default\r\n\treturn Math.min(availableParallelism(), 4);\r\n}\r\n\r\n/**\r\n * Distribute items round-robin across N buckets.\r\n */\r\nfunction chunkRoundRobin<T>(items: T[], buckets: number): T[][] {\r\n\tconst chunks: T[][] = Array.from({ length: buckets }, (): T[] => []);\r\n\tfor (let i = 0; i < items.length; i++) {\r\n\t\tchunks[i % buckets].push(items[i]);\r\n\t}\r\n\treturn chunks;\r\n}\r\n\r\n/**\r\n * Resolve the path to the compiled loader-worker script.\r\n * In development (src), this file is adjacent; in production (lib/), it's compiled.\r\n */\r\nfunction resolveWorkerScript(): string {\r\n\t// Try the compiled lib path first, falling back to __dirname\r\n\tconst libPath = path.resolve(__dirname, 'loader-worker.js');\r\n\treturn libPath;\r\n}\r\n"]}
|
package/lib/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "7.7.
|
|
1
|
+
export declare const version = "7.7.2";
|
package/lib/version.js
CHANGED
package/lib/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":";;;AAAA,2BAA2B;AACd,QAAA,OAAO,GAAG,OAAO,CAAA","sourcesContent":["// Generated by genversion.\nexport const version = '7.7.
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":";;;AAAA,2BAA2B;AACd,QAAA,OAAO,GAAG,OAAO,CAAA","sourcesContent":["// Generated by genversion.\nexport const version = '7.7.2'\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lynxwall/cucumber-tsflow",
|
|
3
3
|
"description": "Provides 'specflow' like bindings for CucumberJS 12.7.0 in TypeScript 5.9+.",
|
|
4
|
-
"version": "7.7.
|
|
4
|
+
"version": "7.7.2",
|
|
5
5
|
"author": "Lonnie Wall <lynxdev@lynxwall.com>",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"keywords": [
|