trickle-observe 0.2.25 → 0.2.26
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/dist/observe-register.js +84 -7
- package/package.json +1 -1
- package/src/observe-register.ts +84 -7
package/dist/observe-register.js
CHANGED
|
@@ -166,11 +166,11 @@ function findClosingBrace(source, openBrace) {
|
|
|
166
166
|
* Handles: const x = ...; let x = ...; var x = ...;
|
|
167
167
|
* Skips: destructuring, for-loop vars, require() calls, imports.
|
|
168
168
|
*/
|
|
169
|
-
function findVarDeclarations(source) {
|
|
169
|
+
function findVarDeclarations(source, lineOffset = 0) {
|
|
170
170
|
const varInsertions = [];
|
|
171
|
-
// Match: const/let/var <identifier> = <something>
|
|
172
|
-
//
|
|
173
|
-
const varRegex = /^([ \t]*)(const|let|var)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)
|
|
171
|
+
// Match: const/let/var <identifier>[: TypeAnnotation] = <something>
|
|
172
|
+
// Handles both JS (no annotation) and TS (with annotation like `: string` or `: MyType`)
|
|
173
|
+
const varRegex = /^([ \t]*)(?:export\s+)?(const|let|var)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)(?:\s*:[^=]+?)?\s*=[^=]/gm;
|
|
174
174
|
let vmatch;
|
|
175
175
|
while ((vmatch = varRegex.exec(source)) !== null) {
|
|
176
176
|
const varName = vmatch[3];
|
|
@@ -186,11 +186,13 @@ function findVarDeclarations(source) {
|
|
|
186
186
|
if (/^\s*require\s*\(/.test(restOfLine))
|
|
187
187
|
continue;
|
|
188
188
|
// Calculate line number (count newlines before this position)
|
|
189
|
+
// Subtract lineOffset to map compiled line numbers back to original source lines
|
|
189
190
|
let lineNo = 1;
|
|
190
191
|
for (let i = 0; i < vmatch.index; i++) {
|
|
191
192
|
if (source[i] === '\n')
|
|
192
193
|
lineNo++;
|
|
193
194
|
}
|
|
195
|
+
lineNo = Math.max(1, lineNo - lineOffset);
|
|
194
196
|
// Find the end of this statement — look for the semicolon at depth 0
|
|
195
197
|
// or the end of the line for semicolon-free code
|
|
196
198
|
const startPos = vmatch.index + vmatch[0].length - 1; // position of the '='
|
|
@@ -257,7 +259,7 @@ function findVarDeclarations(source) {
|
|
|
257
259
|
/**
|
|
258
260
|
* Find destructured variable declarations: const { a, b } = ... and const [a, b] = ...
|
|
259
261
|
*/
|
|
260
|
-
function findDestructuredDeclarations(source) {
|
|
262
|
+
function findDestructuredDeclarations(source, lineOffset = 0) {
|
|
261
263
|
const results = [];
|
|
262
264
|
const destructRegex = /^[ \t]*(?:export\s+)?(?:const|let|var)\s+(\{[^}]*\}|\[[^\]]*\])\s*(?::\s*[^=]+?)?\s*=[^=]/gm;
|
|
263
265
|
let match;
|
|
@@ -274,6 +276,7 @@ function findDestructuredDeclarations(source) {
|
|
|
274
276
|
if (source[i] === '\n')
|
|
275
277
|
lineNo++;
|
|
276
278
|
}
|
|
279
|
+
lineNo = Math.max(1, lineNo - lineOffset);
|
|
277
280
|
const startPos = match.index + match[0].length - 1;
|
|
278
281
|
let pos = startPos;
|
|
279
282
|
let depth = 0;
|
|
@@ -417,8 +420,82 @@ function transformCjsSource(source, filename, moduleName, env) {
|
|
|
417
420
|
}
|
|
418
421
|
// Also find variable declarations for tracing
|
|
419
422
|
const varTraceEnabled = process.env.TRICKLE_TRACE_VARS !== '0';
|
|
420
|
-
|
|
421
|
-
|
|
423
|
+
// For TypeScript files (compiled by ts-node/tsc), type declarations (interfaces, type aliases)
|
|
424
|
+
// are stripped from the compiled JS, shifting line numbers. The only accurate way to get correct
|
|
425
|
+
// line numbers is to read the original .ts source file and parse it directly.
|
|
426
|
+
// For plain JS files, we parse the source directly.
|
|
427
|
+
let varInsertions = [];
|
|
428
|
+
let destructInsertions = [];
|
|
429
|
+
if (varTraceEnabled) {
|
|
430
|
+
const isTsFile = /\.[mc]?tsx?$/.test(filename);
|
|
431
|
+
if (isTsFile) {
|
|
432
|
+
try {
|
|
433
|
+
// Read original TypeScript source to get correct line numbers
|
|
434
|
+
const fs = require('fs');
|
|
435
|
+
const originalSource = fs.readFileSync(filename, 'utf8');
|
|
436
|
+
const tsVarInsertions = findVarDeclarations(originalSource);
|
|
437
|
+
const tsDestructInsertions = findDestructuredDeclarations(originalSource);
|
|
438
|
+
// Map TypeScript variable names → correct line numbers (by occurrence order)
|
|
439
|
+
// Use a counter map to handle duplicate variable names in different scopes
|
|
440
|
+
const tsLineByVarAndOccurrence = new Map();
|
|
441
|
+
for (const { varName, lineNo } of tsVarInsertions) {
|
|
442
|
+
if (!tsLineByVarAndOccurrence.has(varName))
|
|
443
|
+
tsLineByVarAndOccurrence.set(varName, []);
|
|
444
|
+
tsLineByVarAndOccurrence.get(varName).push(lineNo);
|
|
445
|
+
}
|
|
446
|
+
// Find positions in compiled JS (for inserting trace calls),
|
|
447
|
+
// but use line numbers from original TypeScript source
|
|
448
|
+
const compiledInsertions = findVarDeclarations(source);
|
|
449
|
+
const varOccurrenceCounter = new Map();
|
|
450
|
+
for (const ins of compiledInsertions) {
|
|
451
|
+
const occCount = (varOccurrenceCounter.get(ins.varName) || 0);
|
|
452
|
+
varOccurrenceCounter.set(ins.varName, occCount + 1);
|
|
453
|
+
const tsLines = tsLineByVarAndOccurrence.get(ins.varName);
|
|
454
|
+
const correctLineNo = tsLines ? (tsLines[occCount] ?? tsLines[tsLines.length - 1]) : undefined;
|
|
455
|
+
varInsertions.push({ ...ins, lineNo: correctLineNo ?? ins.lineNo });
|
|
456
|
+
}
|
|
457
|
+
const compiledDestructInsertions = findDestructuredDeclarations(source);
|
|
458
|
+
destructInsertions = compiledDestructInsertions; // Keep compiled line numbers as fallback
|
|
459
|
+
// Try to fix destructured line numbers too
|
|
460
|
+
const tsDestructByKey = new Map();
|
|
461
|
+
for (const { varNames, lineNo } of tsDestructInsertions) {
|
|
462
|
+
const key = varNames.join(',');
|
|
463
|
+
if (!tsDestructByKey.has(key))
|
|
464
|
+
tsDestructByKey.set(key, []);
|
|
465
|
+
tsDestructByKey.get(key).push(lineNo);
|
|
466
|
+
}
|
|
467
|
+
const destructOccCounter = new Map();
|
|
468
|
+
destructInsertions = compiledDestructInsertions.map(ins => {
|
|
469
|
+
const key = ins.varNames.join(',');
|
|
470
|
+
const occ = destructOccCounter.get(key) || 0;
|
|
471
|
+
destructOccCounter.set(key, occ + 1);
|
|
472
|
+
const tsLines = tsDestructByKey.get(key);
|
|
473
|
+
const correctLineNo = tsLines ? (tsLines[occ] ?? tsLines[tsLines.length - 1]) : undefined;
|
|
474
|
+
return { ...ins, lineNo: correctLineNo ?? ins.lineNo };
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
catch {
|
|
478
|
+
// Fallback: use compiled line numbers with prologue offset
|
|
479
|
+
let lineOffset = 0;
|
|
480
|
+
const lines = source.split('\n');
|
|
481
|
+
for (const line of lines) {
|
|
482
|
+
const trimmed = line.trim();
|
|
483
|
+
if (trimmed === '"use strict";' || trimmed === "'use strict';" || trimmed === '') {
|
|
484
|
+
lineOffset++;
|
|
485
|
+
}
|
|
486
|
+
else {
|
|
487
|
+
break;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
varInsertions = findVarDeclarations(source, lineOffset);
|
|
491
|
+
destructInsertions = findDestructuredDeclarations(source, lineOffset);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
varInsertions = findVarDeclarations(source);
|
|
496
|
+
destructInsertions = findDestructuredDeclarations(source);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
422
499
|
if (insertions.length === 0 && varInsertions.length === 0 && destructInsertions.length === 0)
|
|
423
500
|
return source;
|
|
424
501
|
// Resolve the path to the wrap helper (compiled JS)
|
package/package.json
CHANGED
package/src/observe-register.ts
CHANGED
|
@@ -153,12 +153,12 @@ function findClosingBrace(source: string, openBrace: number): number {
|
|
|
153
153
|
* Handles: const x = ...; let x = ...; var x = ...;
|
|
154
154
|
* Skips: destructuring, for-loop vars, require() calls, imports.
|
|
155
155
|
*/
|
|
156
|
-
function findVarDeclarations(source: string): Array<{ lineEnd: number; varName: string; lineNo: number }> {
|
|
156
|
+
function findVarDeclarations(source: string, lineOffset: number = 0): Array<{ lineEnd: number; varName: string; lineNo: number }> {
|
|
157
157
|
const varInsertions: Array<{ lineEnd: number; varName: string; lineNo: number }> = [];
|
|
158
158
|
|
|
159
|
-
// Match: const/let/var <identifier> = <something>
|
|
160
|
-
//
|
|
161
|
-
const varRegex = /^([ \t]*)(const|let|var)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)
|
|
159
|
+
// Match: const/let/var <identifier>[: TypeAnnotation] = <something>
|
|
160
|
+
// Handles both JS (no annotation) and TS (with annotation like `: string` or `: MyType`)
|
|
161
|
+
const varRegex = /^([ \t]*)(?:export\s+)?(const|let|var)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)(?:\s*:[^=]+?)?\s*=[^=]/gm;
|
|
162
162
|
let vmatch;
|
|
163
163
|
|
|
164
164
|
while ((vmatch = varRegex.exec(source)) !== null) {
|
|
@@ -174,10 +174,12 @@ function findVarDeclarations(source: string): Array<{ lineEnd: number; varName:
|
|
|
174
174
|
if (/^\s*require\s*\(/.test(restOfLine)) continue;
|
|
175
175
|
|
|
176
176
|
// Calculate line number (count newlines before this position)
|
|
177
|
+
// Subtract lineOffset to map compiled line numbers back to original source lines
|
|
177
178
|
let lineNo = 1;
|
|
178
179
|
for (let i = 0; i < vmatch.index; i++) {
|
|
179
180
|
if (source[i] === '\n') lineNo++;
|
|
180
181
|
}
|
|
182
|
+
lineNo = Math.max(1, lineNo - lineOffset);
|
|
181
183
|
|
|
182
184
|
// Find the end of this statement — look for the semicolon at depth 0
|
|
183
185
|
// or the end of the line for semicolon-free code
|
|
@@ -237,7 +239,7 @@ function findVarDeclarations(source: string): Array<{ lineEnd: number; varName:
|
|
|
237
239
|
/**
|
|
238
240
|
* Find destructured variable declarations: const { a, b } = ... and const [a, b] = ...
|
|
239
241
|
*/
|
|
240
|
-
function findDestructuredDeclarations(source: string): Array<{ lineEnd: number; varNames: string[]; lineNo: number }> {
|
|
242
|
+
function findDestructuredDeclarations(source: string, lineOffset: number = 0): Array<{ lineEnd: number; varNames: string[]; lineNo: number }> {
|
|
241
243
|
const results: Array<{ lineEnd: number; varNames: string[]; lineNo: number }> = [];
|
|
242
244
|
|
|
243
245
|
const destructRegex = /^[ \t]*(?:export\s+)?(?:const|let|var)\s+(\{[^}]*\}|\[[^\]]*\])\s*(?::\s*[^=]+?)?\s*=[^=]/gm;
|
|
@@ -255,6 +257,7 @@ function findDestructuredDeclarations(source: string): Array<{ lineEnd: number;
|
|
|
255
257
|
for (let i = 0; i < match.index; i++) {
|
|
256
258
|
if (source[i] === '\n') lineNo++;
|
|
257
259
|
}
|
|
260
|
+
lineNo = Math.max(1, lineNo - lineOffset);
|
|
258
261
|
|
|
259
262
|
const startPos = match.index + match[0].length - 1;
|
|
260
263
|
let pos = startPos;
|
|
@@ -388,8 +391,82 @@ function transformCjsSource(source: string, filename: string, moduleName: string
|
|
|
388
391
|
|
|
389
392
|
// Also find variable declarations for tracing
|
|
390
393
|
const varTraceEnabled = process.env.TRICKLE_TRACE_VARS !== '0';
|
|
391
|
-
|
|
392
|
-
|
|
394
|
+
|
|
395
|
+
// For TypeScript files (compiled by ts-node/tsc), type declarations (interfaces, type aliases)
|
|
396
|
+
// are stripped from the compiled JS, shifting line numbers. The only accurate way to get correct
|
|
397
|
+
// line numbers is to read the original .ts source file and parse it directly.
|
|
398
|
+
// For plain JS files, we parse the source directly.
|
|
399
|
+
let varInsertions: Array<{ lineEnd: number; varName: string; lineNo: number }> = [];
|
|
400
|
+
let destructInsertions: Array<{ lineEnd: number; varNames: string[]; lineNo: number }> = [];
|
|
401
|
+
|
|
402
|
+
if (varTraceEnabled) {
|
|
403
|
+
const isTsFile = /\.[mc]?tsx?$/.test(filename);
|
|
404
|
+
if (isTsFile) {
|
|
405
|
+
try {
|
|
406
|
+
// Read original TypeScript source to get correct line numbers
|
|
407
|
+
const fs = require('fs');
|
|
408
|
+
const originalSource: string = fs.readFileSync(filename, 'utf8');
|
|
409
|
+
const tsVarInsertions = findVarDeclarations(originalSource);
|
|
410
|
+
const tsDestructInsertions = findDestructuredDeclarations(originalSource);
|
|
411
|
+
|
|
412
|
+
// Map TypeScript variable names → correct line numbers (by occurrence order)
|
|
413
|
+
// Use a counter map to handle duplicate variable names in different scopes
|
|
414
|
+
const tsLineByVarAndOccurrence = new Map<string, number[]>();
|
|
415
|
+
for (const { varName, lineNo } of tsVarInsertions) {
|
|
416
|
+
if (!tsLineByVarAndOccurrence.has(varName)) tsLineByVarAndOccurrence.set(varName, []);
|
|
417
|
+
tsLineByVarAndOccurrence.get(varName)!.push(lineNo);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Find positions in compiled JS (for inserting trace calls),
|
|
421
|
+
// but use line numbers from original TypeScript source
|
|
422
|
+
const compiledInsertions = findVarDeclarations(source);
|
|
423
|
+
const varOccurrenceCounter = new Map<string, number>();
|
|
424
|
+
for (const ins of compiledInsertions) {
|
|
425
|
+
const occCount = (varOccurrenceCounter.get(ins.varName) || 0);
|
|
426
|
+
varOccurrenceCounter.set(ins.varName, occCount + 1);
|
|
427
|
+
const tsLines = tsLineByVarAndOccurrence.get(ins.varName);
|
|
428
|
+
const correctLineNo = tsLines ? (tsLines[occCount] ?? tsLines[tsLines.length - 1]) : undefined;
|
|
429
|
+
varInsertions.push({ ...ins, lineNo: correctLineNo ?? ins.lineNo });
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const compiledDestructInsertions = findDestructuredDeclarations(source);
|
|
433
|
+
destructInsertions = compiledDestructInsertions; // Keep compiled line numbers as fallback
|
|
434
|
+
// Try to fix destructured line numbers too
|
|
435
|
+
const tsDestructByKey = new Map<string, number[]>();
|
|
436
|
+
for (const { varNames, lineNo } of tsDestructInsertions) {
|
|
437
|
+
const key = varNames.join(',');
|
|
438
|
+
if (!tsDestructByKey.has(key)) tsDestructByKey.set(key, []);
|
|
439
|
+
tsDestructByKey.get(key)!.push(lineNo);
|
|
440
|
+
}
|
|
441
|
+
const destructOccCounter = new Map<string, number>();
|
|
442
|
+
destructInsertions = compiledDestructInsertions.map(ins => {
|
|
443
|
+
const key = ins.varNames.join(',');
|
|
444
|
+
const occ = destructOccCounter.get(key) || 0;
|
|
445
|
+
destructOccCounter.set(key, occ + 1);
|
|
446
|
+
const tsLines = tsDestructByKey.get(key);
|
|
447
|
+
const correctLineNo = tsLines ? (tsLines[occ] ?? tsLines[tsLines.length - 1]) : undefined;
|
|
448
|
+
return { ...ins, lineNo: correctLineNo ?? ins.lineNo };
|
|
449
|
+
});
|
|
450
|
+
} catch {
|
|
451
|
+
// Fallback: use compiled line numbers with prologue offset
|
|
452
|
+
let lineOffset = 0;
|
|
453
|
+
const lines = source.split('\n');
|
|
454
|
+
for (const line of lines) {
|
|
455
|
+
const trimmed = line.trim();
|
|
456
|
+
if (trimmed === '"use strict";' || trimmed === "'use strict';" || trimmed === '') {
|
|
457
|
+
lineOffset++;
|
|
458
|
+
} else {
|
|
459
|
+
break;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
varInsertions = findVarDeclarations(source, lineOffset);
|
|
463
|
+
destructInsertions = findDestructuredDeclarations(source, lineOffset);
|
|
464
|
+
}
|
|
465
|
+
} else {
|
|
466
|
+
varInsertions = findVarDeclarations(source);
|
|
467
|
+
destructInsertions = findDestructuredDeclarations(source);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
393
470
|
|
|
394
471
|
if (insertions.length === 0 && varInsertions.length === 0 && destructInsertions.length === 0) return source;
|
|
395
472
|
|