taist 0.1.11 → 0.1.12
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/transform.js +56 -4
- package/package.json +1 -1
package/lib/transform.js
CHANGED
|
@@ -30,7 +30,7 @@ export function hasExports(code) {
|
|
|
30
30
|
/**
|
|
31
31
|
* Find all exports in the source code
|
|
32
32
|
* @param {string} source - Source code
|
|
33
|
-
* @returns {Array<{name: string, type: 'function'|'const'|'class', declaration: string|null}>}
|
|
33
|
+
* @returns {Array<{name: string, type: 'function'|'const'|'class'|'object', declaration: string|null}>}
|
|
34
34
|
*/
|
|
35
35
|
export function findExports(source) {
|
|
36
36
|
const exports = [];
|
|
@@ -49,6 +49,16 @@ export function findExports(source) {
|
|
|
49
49
|
exports.push({ name: match[1], type: "const", declaration: "inline" });
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
// Match: export const name = { - object literal exports
|
|
53
|
+
// Negative lookahead to avoid matching functions/arrows already caught above
|
|
54
|
+
const objectExportRegex = /export\s+const\s+(\w+)\s*=\s*\{/g;
|
|
55
|
+
while ((match = objectExportRegex.exec(source)) !== null) {
|
|
56
|
+
const name = match[1];
|
|
57
|
+
// Skip if already found as a function/const export
|
|
58
|
+
if (exports.some(e => e.name === name)) continue;
|
|
59
|
+
exports.push({ name, type: "object", declaration: "inline" });
|
|
60
|
+
}
|
|
61
|
+
|
|
52
62
|
// Match: export class ClassName
|
|
53
63
|
const classExportRegex = /export\s+class\s+(\w+)/g;
|
|
54
64
|
while ((match = classExportRegex.exec(source)) !== null) {
|
|
@@ -66,13 +76,14 @@ export function findExports(source) {
|
|
|
66
76
|
const isFunction = new RegExp(`function\\s+${name}\\s*\\(`).test(source) ||
|
|
67
77
|
new RegExp(`(const|let|var)\\s+${name}\\s*=\\s*(async\\s*)?\\(`).test(source) ||
|
|
68
78
|
new RegExp(`(const|let|var)\\s+${name}\\s*=\\s*(async\\s+)?function`).test(source);
|
|
79
|
+
const isObject = new RegExp(`(const|let|var)\\s+${name}\\s*=\\s*\\{`).test(source);
|
|
69
80
|
|
|
70
81
|
// Skip if already found as inline export
|
|
71
82
|
if (exports.some(e => e.name === name)) continue;
|
|
72
83
|
|
|
73
84
|
exports.push({
|
|
74
85
|
name,
|
|
75
|
-
type: isClass ? "class" : isFunction ? "function" : "unknown",
|
|
86
|
+
type: isClass ? "class" : isFunction ? "function" : isObject ? "object" : "unknown",
|
|
76
87
|
declaration: "named"
|
|
77
88
|
});
|
|
78
89
|
}
|
|
@@ -205,6 +216,19 @@ const __taist_instrumentClass = (cls, name) => {
|
|
|
205
216
|
}
|
|
206
217
|
return cls;
|
|
207
218
|
};
|
|
219
|
+
const __taist_instrumentObject = (obj, name, visited = new WeakSet()) => {
|
|
220
|
+
if (!obj || typeof obj !== 'object' || visited.has(obj)) return obj;
|
|
221
|
+
visited.add(obj);
|
|
222
|
+
for (const key of Object.keys(obj)) {
|
|
223
|
+
const value = obj[key];
|
|
224
|
+
if (typeof value === 'function') {
|
|
225
|
+
obj[key] = __taist_wrap(value, name + '.' + key);
|
|
226
|
+
} else if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
227
|
+
__taist_instrumentObject(value, name + '.' + key, visited);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return obj;
|
|
231
|
+
};
|
|
208
232
|
const __taist_module = "${moduleName}";
|
|
209
233
|
// --- END TAIST ---
|
|
210
234
|
|
|
@@ -227,6 +251,20 @@ const __taist_instrumentClass = (cls, name) => {
|
|
|
227
251
|
__taist.instrument(cls, name);
|
|
228
252
|
return cls;
|
|
229
253
|
};
|
|
254
|
+
const __taist_instrumentObject = (obj, name, visited = new WeakSet()) => {
|
|
255
|
+
if (!__taist?.options?.enabled) return obj;
|
|
256
|
+
if (!obj || typeof obj !== 'object' || visited.has(obj)) return obj;
|
|
257
|
+
visited.add(obj);
|
|
258
|
+
for (const key of Object.keys(obj)) {
|
|
259
|
+
const value = obj[key];
|
|
260
|
+
if (typeof value === 'function') {
|
|
261
|
+
obj[key] = __taist_wrap(value, name + '.' + key);
|
|
262
|
+
} else if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
263
|
+
__taist_instrumentObject(value, name + '.' + key, visited);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return obj;
|
|
267
|
+
};
|
|
230
268
|
const __taist_module = "${moduleName}";
|
|
231
269
|
// --- END TAIST ---
|
|
232
270
|
|
|
@@ -246,9 +284,10 @@ const __taist_module = "${moduleName}";
|
|
|
246
284
|
|
|
247
285
|
let transformed = shebang + injection + sourceWithoutShebang;
|
|
248
286
|
|
|
249
|
-
// Separate
|
|
287
|
+
// Separate exports by type - each needs different handling
|
|
250
288
|
const classExports = exports.filter(e => e.type === "class");
|
|
251
|
-
const
|
|
289
|
+
const objectExports = exports.filter(e => e.type === "object");
|
|
290
|
+
const functionExports = exports.filter(e => e.type !== "class" && e.type !== "object");
|
|
252
291
|
|
|
253
292
|
// For CLASSES: Keep original export, instrument in-place (preserves hoisting)
|
|
254
293
|
// This avoids TDZ issues with circular dependencies
|
|
@@ -355,6 +394,15 @@ const __taist_module = "${moduleName}";
|
|
|
355
394
|
})
|
|
356
395
|
.join("\n");
|
|
357
396
|
|
|
397
|
+
// Add in-place instrumentation for OBJECT LITERALS (wraps nested methods)
|
|
398
|
+
// __taist_instrumentObject recursively wraps function properties
|
|
399
|
+
const objectInstrumentations = objectExports
|
|
400
|
+
.map((exp) => {
|
|
401
|
+
const nameExpr = `(__taist_module === "${exp.name}" ? "${exp.name}" : __taist_module + ".${exp.name}")`;
|
|
402
|
+
return `__taist_instrumentObject(${exp.name}, ${nameExpr});`;
|
|
403
|
+
})
|
|
404
|
+
.join("\n");
|
|
405
|
+
|
|
358
406
|
transformed += `\n\n// --- TAIST INSTRUMENTATION ---\n`;
|
|
359
407
|
|
|
360
408
|
if (functionReexports) {
|
|
@@ -365,6 +413,10 @@ const __taist_module = "${moduleName}";
|
|
|
365
413
|
transformed += `// In-place class instrumentation (preserves hoisting)\n${classInstrumentations}\n`;
|
|
366
414
|
}
|
|
367
415
|
|
|
416
|
+
if (objectInstrumentations) {
|
|
417
|
+
transformed += `// In-place object literal instrumentation (wraps nested methods)\n${objectInstrumentations}\n`;
|
|
418
|
+
}
|
|
419
|
+
|
|
368
420
|
// Add default exports at the end (after the wrapped versions are defined)
|
|
369
421
|
for (const name of defaultExports) {
|
|
370
422
|
transformed += `export default ${name};\n`;
|