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.
Files changed (2) hide show
  1. package/lib/transform.js +56 -4
  2. 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 classes from functions - classes need different handling to preserve hoisting
287
+ // Separate exports by type - each needs different handling
250
288
  const classExports = exports.filter(e => e.type === "class");
251
- const functionExports = exports.filter(e => e.type !== "class");
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`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taist",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "Token-Optimized Testing Framework for AI-Assisted Development",
5
5
  "main": "index.js",
6
6
  "type": "module",