@opensip-cli/lang-typescript 0.1.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.
Files changed (60) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +8 -0
  3. package/README.md +31 -0
  4. package/dist/__tests__/adapter.test.d.ts +2 -0
  5. package/dist/__tests__/adapter.test.d.ts.map +1 -0
  6. package/dist/__tests__/adapter.test.js +56 -0
  7. package/dist/__tests__/adapter.test.js.map +1 -0
  8. package/dist/__tests__/ast-utilities.test.d.ts +2 -0
  9. package/dist/__tests__/ast-utilities.test.d.ts.map +1 -0
  10. package/dist/__tests__/ast-utilities.test.js +442 -0
  11. package/dist/__tests__/ast-utilities.test.js.map +1 -0
  12. package/dist/__tests__/filter.test.d.ts +2 -0
  13. package/dist/__tests__/filter.test.d.ts.map +1 -0
  14. package/dist/__tests__/filter.test.js +183 -0
  15. package/dist/__tests__/filter.test.js.map +1 -0
  16. package/dist/__tests__/query.test.d.ts +2 -0
  17. package/dist/__tests__/query.test.d.ts.map +1 -0
  18. package/dist/__tests__/query.test.js +76 -0
  19. package/dist/__tests__/query.test.js.map +1 -0
  20. package/dist/__tests__/workspace-units.test.d.ts +2 -0
  21. package/dist/__tests__/workspace-units.test.d.ts.map +1 -0
  22. package/dist/__tests__/workspace-units.test.js +94 -0
  23. package/dist/__tests__/workspace-units.test.js.map +1 -0
  24. package/dist/adapter.d.ts +6 -0
  25. package/dist/adapter.d.ts.map +1 -0
  26. package/dist/adapter.js +17 -0
  27. package/dist/adapter.js.map +1 -0
  28. package/dist/ast-utilities.d.ts +76 -0
  29. package/dist/ast-utilities.d.ts.map +1 -0
  30. package/dist/ast-utilities.js +212 -0
  31. package/dist/ast-utilities.js.map +1 -0
  32. package/dist/filter.d.ts +39 -0
  33. package/dist/filter.d.ts.map +1 -0
  34. package/dist/filter.js +263 -0
  35. package/dist/filter.js.map +1 -0
  36. package/dist/function-scope.d.ts +70 -0
  37. package/dist/function-scope.d.ts.map +1 -0
  38. package/dist/function-scope.js +142 -0
  39. package/dist/function-scope.js.map +1 -0
  40. package/dist/index.d.ts +13 -0
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/index.js +24 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/parse.d.ts +10 -0
  45. package/dist/parse.d.ts.map +1 -0
  46. package/dist/parse.js +19 -0
  47. package/dist/parse.js.map +1 -0
  48. package/dist/query.d.ts +4 -0
  49. package/dist/query.d.ts.map +1 -0
  50. package/dist/query.js +74 -0
  51. package/dist/query.js.map +1 -0
  52. package/dist/strip.d.ts +25 -0
  53. package/dist/strip.d.ts.map +1 -0
  54. package/dist/strip.js +30 -0
  55. package/dist/strip.js.map +1 -0
  56. package/dist/workspace-units.d.ts +19 -0
  57. package/dist/workspace-units.d.ts.map +1 -0
  58. package/dist/workspace-units.js +78 -0
  59. package/dist/workspace-units.js.map +1 -0
  60. package/package.json +50 -0
@@ -0,0 +1,442 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { countUnescapedBackticks, findBinaryExpressions, findCallExpressions, findTemplateLiterals, getColumn, getIdentifierName, getLineNumber, getPropertyChain, getSharedSourceFile, isInComment, isInStringLiteral, isLiteral, isPropertyAccess, ts, walkNodes, } from '../ast-utilities.js';
3
+ import { findEnclosingFunction, findEnclosingFunctionBody, findEnclosingScope, getEnclosingFunctionName, isAsync, isInAsyncContext, isInsideConditionalBlock, } from '../function-scope.js';
4
+ import { parseSource } from '../parse.js';
5
+ const parse = (content) => parseSource(content, 'x.ts');
6
+ describe('parseSource', () => {
7
+ it('parses valid TypeScript', () => {
8
+ expect(parse('const x = 1;')).not.toBeNull();
9
+ });
10
+ it('returns null on parse failure', () => {
11
+ // Note: TS parser is permissive — try with a sentinel call that throws.
12
+ // Most invalid syntax still produces a tree; instead exercise the catch
13
+ // path by passing a non-string.
14
+ // Cast to any to bypass the type guard for this test.
15
+ const result = parseSource(undefined, 'x.ts');
16
+ expect(result).toBeNull();
17
+ });
18
+ });
19
+ describe('getSharedSourceFile', () => {
20
+ it('returns a parsed source file', () => {
21
+ expect(getSharedSourceFile('shared.ts', 'export const x = 1;')).not.toBeNull();
22
+ });
23
+ });
24
+ describe('walkNodes', () => {
25
+ it('visits every descendant node', () => {
26
+ const sf = parse('const x = 1; const y = 2;');
27
+ if (!sf)
28
+ throw new Error('parse failed');
29
+ let count = 0;
30
+ walkNodes(sf, () => count++);
31
+ expect(count).toBeGreaterThan(2);
32
+ });
33
+ });
34
+ describe('getIdentifierName / getPropertyChain', () => {
35
+ it('returns the leaf identifier from an Identifier', () => {
36
+ const sf = parse('foo;');
37
+ if (!sf)
38
+ throw new Error('parse failed');
39
+ let leaf = '';
40
+ walkNodes(sf, (n) => {
41
+ if (ts.isIdentifier(n) && leaf === '')
42
+ leaf = getIdentifierName(n);
43
+ });
44
+ expect(leaf).toBe('foo');
45
+ });
46
+ it('returns the property name from a PropertyAccessExpression', () => {
47
+ const sf = parse('a.b.c;');
48
+ if (!sf)
49
+ throw new Error('parse failed');
50
+ let result = '';
51
+ walkNodes(sf, (n) => {
52
+ if (ts.isPropertyAccessExpression(n) && result === '')
53
+ result = getPropertyChain(n);
54
+ });
55
+ expect(result).toBe('a.b.c');
56
+ });
57
+ it('returns empty string for non-identifier non-property nodes', () => {
58
+ const sf = parse('1 + 2;');
59
+ if (!sf)
60
+ throw new Error('parse failed');
61
+ let found = '';
62
+ walkNodes(sf, (n) => {
63
+ if (ts.isBinaryExpression(n))
64
+ found = getIdentifierName(n);
65
+ });
66
+ expect(found).toBe('');
67
+ });
68
+ it('getPropertyChain returns empty for non-identifier non-property', () => {
69
+ const sf = parse('1 + 2;');
70
+ if (!sf)
71
+ throw new Error('parse failed');
72
+ let found = '';
73
+ walkNodes(sf, (n) => {
74
+ if (ts.isBinaryExpression(n) && found === '')
75
+ found = getPropertyChain(n);
76
+ });
77
+ expect(found).toBe('');
78
+ });
79
+ });
80
+ describe('getLineNumber / getColumn', () => {
81
+ it('returns 1-based line and 0-based column', () => {
82
+ const sf = parse('\n\nconst x = 1;');
83
+ if (!sf)
84
+ throw new Error('parse failed');
85
+ let line = 0;
86
+ let col = 0;
87
+ walkNodes(sf, (n) => {
88
+ if (ts.isVariableDeclaration(n)) {
89
+ line = getLineNumber(n, sf);
90
+ col = getColumn(n, sf);
91
+ }
92
+ });
93
+ expect(line).toBe(3);
94
+ expect(col).toBe(6); // "const " (6 chars)
95
+ });
96
+ });
97
+ describe('isPropertyAccess', () => {
98
+ it('matches when the property name is the right one', () => {
99
+ const sf = parse('foo.bar();');
100
+ if (!sf)
101
+ throw new Error('parse failed');
102
+ let matched = false;
103
+ walkNodes(sf, (n) => {
104
+ if (ts.isPropertyAccessExpression(n) && isPropertyAccess(n, 'bar'))
105
+ matched = true;
106
+ });
107
+ expect(matched).toBe(true);
108
+ });
109
+ it('does not match when the property name differs', () => {
110
+ const sf = parse('foo.bar();');
111
+ if (!sf)
112
+ throw new Error('parse failed');
113
+ let matched = false;
114
+ walkNodes(sf, (n) => {
115
+ if (ts.isPropertyAccessExpression(n) && isPropertyAccess(n, 'baz'))
116
+ matched = true;
117
+ });
118
+ expect(matched).toBe(false);
119
+ });
120
+ });
121
+ describe('isLiteral', () => {
122
+ it.each([
123
+ ['"hi"', true],
124
+ ['42', true],
125
+ ['true', true],
126
+ ['false', true],
127
+ ['null', true],
128
+ ['undefined', true],
129
+ ['x', false],
130
+ ])('isLiteral(%s) === %s', (src, expected) => {
131
+ const sf = parse(`(${src});`);
132
+ if (!sf)
133
+ throw new Error('parse failed');
134
+ let result = null;
135
+ walkNodes(sf, (n) => {
136
+ if (ts.isParenthesizedExpression(n) && result === null)
137
+ result = isLiteral(n.expression);
138
+ });
139
+ expect(result).toBe(expected);
140
+ });
141
+ });
142
+ describe('isInStringLiteral', () => {
143
+ it('returns true for nodes inside a string template', () => {
144
+ const sf = parse('const x = `${foo}`;');
145
+ if (!sf)
146
+ throw new Error('parse failed');
147
+ let found = false;
148
+ walkNodes(sf, (n) => {
149
+ if (ts.isIdentifier(n) && n.text === 'foo' && isInStringLiteral(n))
150
+ found = true;
151
+ });
152
+ expect(found).toBe(true);
153
+ });
154
+ it('returns false for nodes outside string literals', () => {
155
+ const sf = parse('const x = 1; const y = x;');
156
+ if (!sf)
157
+ throw new Error('parse failed');
158
+ let foundOutside = false;
159
+ walkNodes(sf, (n) => {
160
+ if (ts.isIdentifier(n) && n.text === 'y' && !isInStringLiteral(n))
161
+ foundOutside = true;
162
+ });
163
+ expect(foundOutside).toBe(true);
164
+ });
165
+ });
166
+ describe('findCallExpressions', () => {
167
+ it('finds matching call sites by object + method name', () => {
168
+ const sf = parse('console.log(1); foo(); console.log(2);');
169
+ if (!sf)
170
+ throw new Error('parse failed');
171
+ const calls = findCallExpressions(sf, 'console', 'log');
172
+ expect(calls.length).toBe(2);
173
+ });
174
+ it('matches when objectName is a suffix of the property chain', () => {
175
+ const sf = parse('a.b.console.log(1);');
176
+ if (!sf)
177
+ throw new Error('parse failed');
178
+ const calls = findCallExpressions(sf, 'console', 'log');
179
+ expect(calls.length).toBe(1);
180
+ });
181
+ it('returns empty when no matches', () => {
182
+ const sf = parse('foo();');
183
+ if (!sf)
184
+ throw new Error('parse failed');
185
+ expect(findCallExpressions(sf, 'console', 'log')).toEqual([]);
186
+ });
187
+ });
188
+ describe('findBinaryExpressions', () => {
189
+ it('finds binary expressions of the given operator kind', () => {
190
+ const sf = parse('a + b; c - d; a + e;');
191
+ if (!sf)
192
+ throw new Error('parse failed');
193
+ expect(findBinaryExpressions(sf, ts.SyntaxKind.PlusToken).length).toBe(2);
194
+ });
195
+ });
196
+ describe('findTemplateLiterals', () => {
197
+ it('finds template expressions with interpolations', () => {
198
+ const sf = parse('const x = `${a}${b}`;');
199
+ if (!sf)
200
+ throw new Error('parse failed');
201
+ expect(findTemplateLiterals(sf).length).toBe(1);
202
+ });
203
+ it('skips no-substitution templates', () => {
204
+ const sf = parse('const x = `static`;');
205
+ if (!sf)
206
+ throw new Error('parse failed');
207
+ expect(findTemplateLiterals(sf)).toEqual([]);
208
+ });
209
+ });
210
+ describe('isInComment', () => {
211
+ it('returns false for a position outside a comment', () => {
212
+ const src = 'const x = 1;\nconst y = 2;';
213
+ const sf = parse(src);
214
+ if (!sf)
215
+ throw new Error('parse failed');
216
+ const xIdx = src.indexOf('const x');
217
+ expect(isInComment(xIdx, sf)).toBe(false);
218
+ });
219
+ it('returns true for a position inside a leading block comment', () => {
220
+ const src = '/* block\n comment\n*/\nconst x = 1;';
221
+ const sf = parse(src);
222
+ if (!sf)
223
+ throw new Error('parse failed');
224
+ const insideIdx = src.indexOf('block');
225
+ expect(isInComment(insideIdx, sf)).toBe(true);
226
+ });
227
+ });
228
+ describe('countUnescapedBackticks', () => {
229
+ it('counts unescaped backticks', () => {
230
+ expect(countUnescapedBackticks('a `b` c')).toBe(2);
231
+ });
232
+ it('does not count escaped backticks', () => {
233
+ expect(countUnescapedBackticks('a \\` b')).toBe(0);
234
+ });
235
+ it('returns 0 when there are none', () => {
236
+ expect(countUnescapedBackticks('plain text')).toBe(0);
237
+ });
238
+ });
239
+ // =============================================================================
240
+ // FUNCTION-SCOPE HELPERS (Phase D2)
241
+ // =============================================================================
242
+ /** Helper: find first descendant matching a predicate. */
243
+ function find(root, pred) {
244
+ let found = null;
245
+ walkNodes(root, (n) => {
246
+ if (!found && pred(n))
247
+ found = n;
248
+ });
249
+ return found;
250
+ }
251
+ describe('findEnclosingFunction', () => {
252
+ it('returns the nearest function declaration', () => {
253
+ const sf = parse('function outer() { function inner() { const x = 1; } }');
254
+ if (!sf)
255
+ throw new Error('parse failed');
256
+ const decl = find(sf, (n) => ts.isVariableDeclaration(n) && n.name.getText(sf) === 'x');
257
+ if (!decl)
258
+ throw new Error('decl not found');
259
+ const fn = findEnclosingFunction(decl);
260
+ expect(fn && ts.isFunctionDeclaration(fn) && fn.name?.text).toBe('inner');
261
+ });
262
+ it('returns null at module scope', () => {
263
+ const sf = parse('const x = 1;');
264
+ if (!sf)
265
+ throw new Error('parse failed');
266
+ const decl = find(sf, ts.isVariableDeclaration);
267
+ if (!decl)
268
+ throw new Error('decl not found');
269
+ expect(findEnclosingFunction(decl)).toBeNull();
270
+ });
271
+ it('returns the nearest method declaration', () => {
272
+ const sf = parse('class C { m() { const y = 2; } }');
273
+ if (!sf)
274
+ throw new Error('parse failed');
275
+ const decl = find(sf, (n) => ts.isVariableDeclaration(n) && n.name.getText(sf) === 'y');
276
+ if (!decl)
277
+ throw new Error('decl not found');
278
+ const fn = findEnclosingFunction(decl);
279
+ expect(fn && ts.isMethodDeclaration(fn)).toBe(true);
280
+ });
281
+ });
282
+ describe('findEnclosingFunctionBody', () => {
283
+ it('returns a Block when the function has a body block', () => {
284
+ const sf = parse('function f() { const x = 1; }');
285
+ if (!sf)
286
+ throw new Error('parse failed');
287
+ const decl = find(sf, ts.isVariableDeclaration);
288
+ if (!decl)
289
+ throw new Error('decl not found');
290
+ const body = findEnclosingFunctionBody(decl);
291
+ expect(body && ts.isBlock(body)).toBe(true);
292
+ });
293
+ it('returns null for arrow function with expression body', () => {
294
+ const sf = parse('const f = () => 1 + 1;');
295
+ if (!sf)
296
+ throw new Error('parse failed');
297
+ const arrow = find(sf, ts.isArrowFunction);
298
+ if (!arrow || !ts.isArrowFunction(arrow))
299
+ throw new Error('arrow not found');
300
+ // The expression body itself is the BinaryExpression `1 + 1`
301
+ const body = findEnclosingFunctionBody(arrow.body);
302
+ expect(body).toBeNull();
303
+ });
304
+ });
305
+ describe('getEnclosingFunctionName', () => {
306
+ it('returns the method name', () => {
307
+ const sf = parse('class C { foo() { const x = 1; } }');
308
+ if (!sf)
309
+ throw new Error('parse failed');
310
+ const decl = find(sf, ts.isVariableDeclaration);
311
+ if (!decl)
312
+ throw new Error('decl not found');
313
+ expect(getEnclosingFunctionName(decl, sf)).toBe('foo');
314
+ });
315
+ it('returns the function declaration name', () => {
316
+ const sf = parse('function bar() { const x = 1; }');
317
+ if (!sf)
318
+ throw new Error('parse failed');
319
+ const decl = find(sf, ts.isVariableDeclaration);
320
+ if (!decl)
321
+ throw new Error('decl not found');
322
+ expect(getEnclosingFunctionName(decl, sf)).toBe('bar');
323
+ });
324
+ it('returns null when there is no named ancestor', () => {
325
+ const sf = parse('const x = 1;');
326
+ if (!sf)
327
+ throw new Error('parse failed');
328
+ const decl = find(sf, ts.isVariableDeclaration);
329
+ if (!decl)
330
+ throw new Error('decl not found');
331
+ expect(getEnclosingFunctionName(decl, sf)).toBeNull();
332
+ });
333
+ });
334
+ describe('findEnclosingScope', () => {
335
+ it('returns the SourceFile at module scope', () => {
336
+ const sf = parse('const x = 1;');
337
+ if (!sf)
338
+ throw new Error('parse failed');
339
+ const decl = find(sf, ts.isVariableDeclaration);
340
+ if (!decl)
341
+ throw new Error('decl not found');
342
+ expect(findEnclosingScope(decl)).toBe(sf);
343
+ });
344
+ it('returns the nearest function-like ancestor', () => {
345
+ const sf = parse('function f() { const x = 1; }');
346
+ if (!sf)
347
+ throw new Error('parse failed');
348
+ const decl = find(sf, ts.isVariableDeclaration);
349
+ if (!decl)
350
+ throw new Error('decl not found');
351
+ const scope = findEnclosingScope(decl);
352
+ expect(ts.isFunctionDeclaration(scope)).toBe(true);
353
+ });
354
+ });
355
+ describe('isAsync', () => {
356
+ it('returns true for async function', () => {
357
+ const sf = parse('async function f() {}');
358
+ if (!sf)
359
+ throw new Error('parse failed');
360
+ const fn = find(sf, ts.isFunctionDeclaration);
361
+ if (!fn)
362
+ throw new Error('fn not found');
363
+ expect(isAsync(fn)).toBe(true);
364
+ });
365
+ it('returns false for sync function', () => {
366
+ const sf = parse('function g() {}');
367
+ if (!sf)
368
+ throw new Error('parse failed');
369
+ const fn = find(sf, ts.isFunctionDeclaration);
370
+ if (!fn)
371
+ throw new Error('fn not found');
372
+ expect(isAsync(fn)).toBe(false);
373
+ });
374
+ });
375
+ describe('isInAsyncContext', () => {
376
+ it('returns true inside an async function', () => {
377
+ const sf = parse('async function f() { foo(); }');
378
+ if (!sf)
379
+ throw new Error('parse failed');
380
+ const call = find(sf, ts.isCallExpression);
381
+ if (!call)
382
+ throw new Error('call not found');
383
+ expect(isInAsyncContext(call)).toBe(true);
384
+ });
385
+ it('returns false inside a sync function', () => {
386
+ const sf = parse('function f() { foo(); }');
387
+ if (!sf)
388
+ throw new Error('parse failed');
389
+ const call = find(sf, ts.isCallExpression);
390
+ if (!call)
391
+ throw new Error('call not found');
392
+ expect(isInAsyncContext(call)).toBe(false);
393
+ });
394
+ it('returns false at module scope', () => {
395
+ const sf = parse('foo();');
396
+ if (!sf)
397
+ throw new Error('parse failed');
398
+ const call = find(sf, ts.isCallExpression);
399
+ if (!call)
400
+ throw new Error('call not found');
401
+ expect(isInAsyncContext(call)).toBe(false);
402
+ });
403
+ });
404
+ describe('isInsideConditionalBlock', () => {
405
+ it('returns true inside an if statement', () => {
406
+ const sf = parse('function f() { if (x) { return 1; } }');
407
+ if (!sf)
408
+ throw new Error('parse failed');
409
+ const ret = find(sf, ts.isReturnStatement);
410
+ if (!ret)
411
+ throw new Error('return not found');
412
+ expect(isInsideConditionalBlock(ret)).toBe(true);
413
+ });
414
+ it('returns true inside a switch case', () => {
415
+ const sf = parse('function f() { switch (x) { case 1: return 2; } }');
416
+ if (!sf)
417
+ throw new Error('parse failed');
418
+ const ret = find(sf, ts.isReturnStatement);
419
+ if (!ret)
420
+ throw new Error('return not found');
421
+ expect(isInsideConditionalBlock(ret)).toBe(true);
422
+ });
423
+ it('returns false at the top of a function body', () => {
424
+ const sf = parse('function f() { return 1; }');
425
+ if (!sf)
426
+ throw new Error('parse failed');
427
+ const ret = find(sf, ts.isReturnStatement);
428
+ if (!ret)
429
+ throw new Error('return not found');
430
+ expect(isInsideConditionalBlock(ret)).toBe(false);
431
+ });
432
+ it('does not cross function boundaries', () => {
433
+ const sf = parse('if (x) { function inner() { return 1; } }');
434
+ if (!sf)
435
+ throw new Error('parse failed');
436
+ const ret = find(sf, ts.isReturnStatement);
437
+ if (!ret)
438
+ throw new Error('return not found');
439
+ expect(isInsideConditionalBlock(ret)).toBe(false);
440
+ });
441
+ });
442
+ //# sourceMappingURL=ast-utilities.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast-utilities.test.js","sourceRoot":"","sources":["../../src/__tests__/ast-utilities.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=filter.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/filter.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,183 @@
1
+ import { RunScope, runWithScopeSync } from '@opensip-cli/core';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { filterContent } from '../filter.js';
4
+ describe('filterContent', () => {
5
+ describe('string and comment masking', () => {
6
+ it('replaces string-literal content with spaces but preserves length', () => {
7
+ const src = `const x = 'hello'`;
8
+ const { code } = filterContent(src);
9
+ expect(code.length).toBe(src.length);
10
+ expect(code).toBe(`const x = ' '`);
11
+ });
12
+ it('preserves comment content verbatim (comments tracked, not masked)', () => {
13
+ const src = `const x = 1 // loadConfig() mentioned here\nconst y = 2`;
14
+ const { code } = filterContent(src);
15
+ // Line comments are left intact — directives live in comments
16
+ expect(code).toContain('loadConfig() mentioned here');
17
+ });
18
+ });
19
+ describe('template literals', () => {
20
+ it('masks simple template body text', () => {
21
+ const src = `const x = \`hello world\``;
22
+ const { code } = filterContent(src);
23
+ expect(code).toBe(`const x = \` \``);
24
+ });
25
+ it('masks template-head and template-tail text, preserves expressions', () => {
26
+ const src = `const x = \`pre \${value} post\``;
27
+ const { code } = filterContent(src);
28
+ // Expression `value` is code — preserved. Text around `${ ... }` is masked.
29
+ expect(code).toContain('value');
30
+ expect(code).not.toContain('pre ');
31
+ expect(code).not.toContain(' post');
32
+ });
33
+ // Regression: nested templates inside `${...}` expressions used to desync the
34
+ // scanner state (a plain `inTemplate` boolean flipped off by the inner
35
+ // TemplateTail left the outer's CloseBrace unrescanned, which caused every
36
+ // token after the inner template to be misinterpreted as part of a string).
37
+ // The symptom was that real code — `loadConfig(process.cwd())`, type
38
+ // annotations, anything — below the nested template got wiped to whitespace
39
+ // silently, producing false negatives in every `contentFilter: 'strip-strings'`
40
+ // check that scanned the affected file. Fix replaced the boolean with a
41
+ // depth counter; this test keeps it fixed.
42
+ it('handles nested templates inside ${} expressions — code below is preserved', () => {
43
+ const src = [
44
+ 'const lines = items.map(f => `- ${sanitize(f)}`).join("\\n")',
45
+ 'const after = loadConfig(process.cwd())',
46
+ 'export function helper(cfg: ReturnType<typeof loadConfig>): string { return "" }',
47
+ ].join('\n');
48
+ const { code } = filterContent(src);
49
+ // The nested template's inner text `- ` should be masked, but sanitize(f),
50
+ // the .map/.join chain, and everything below must survive intact.
51
+ expect(code).toContain('sanitize(f)');
52
+ expect(code).toContain('loadConfig(process.cwd())');
53
+ expect(code).toContain('ReturnType<typeof loadConfig>');
54
+ });
55
+ it('handles doubly-nested templates', () => {
56
+ const src = [
57
+ 'const s = `a ${`b ${c}`} d`',
58
+ 'const survives = loadConfig(process.cwd())',
59
+ ].join('\n');
60
+ const { code } = filterContent(src);
61
+ expect(code).toContain('survives');
62
+ expect(code).toContain('loadConfig(process.cwd())');
63
+ // The identifier `c` inside the innermost expression is code and must survive
64
+ expect(code).toContain('${c}');
65
+ });
66
+ });
67
+ describe('codeNoComments — strings AND comments masked', () => {
68
+ it('masks line comments while preserving line/column offsets', () => {
69
+ const src = `const x = 1 // calls getDatabase() somewhere\nconst y = 2`;
70
+ const { code, codeNoComments } = filterContent(src);
71
+ // `code` (strings-only) leaves the line comment intact
72
+ expect(code).toContain('getDatabase()');
73
+ // `codeNoComments` masks the comment text but keeps length
74
+ expect(codeNoComments.length).toBe(src.length);
75
+ expect(codeNoComments).not.toContain('getDatabase');
76
+ // Code BEFORE the comment survives
77
+ expect(codeNoComments).toContain('const x = 1');
78
+ // Newlines are preserved so line numbers stay accurate
79
+ expect(codeNoComments.split('\n')).toHaveLength(2);
80
+ expect(codeNoComments.split('\n')[1]).toBe('const y = 2');
81
+ });
82
+ it('masks block / JSDoc comments across multiple lines', () => {
83
+ const src = [
84
+ '/**',
85
+ ' * Replace getDatabase() with the constructor StoreDeps.',
86
+ ' * The check guards against process-wide tenant accessors.',
87
+ ' */',
88
+ 'export class TicketStore {}',
89
+ ].join('\n');
90
+ const { codeNoComments } = filterContent(src);
91
+ expect(codeNoComments).not.toContain('getDatabase');
92
+ expect(codeNoComments).not.toContain('StoreDeps');
93
+ expect(codeNoComments).not.toContain('process-wide');
94
+ // Code AFTER the JSDoc survives
95
+ expect(codeNoComments).toContain('export class TicketStore');
96
+ // Line count preserved
97
+ expect(codeNoComments.split('\n')).toHaveLength(5);
98
+ });
99
+ it('masks both strings and comments in the same content', () => {
100
+ const src = `const url = 'https://api.example.com' // call openai.messages.create() here`;
101
+ const { codeNoComments } = filterContent(src);
102
+ expect(codeNoComments).not.toContain('https');
103
+ expect(codeNoComments).not.toContain('messages.create');
104
+ expect(codeNoComments).toContain('const url = ');
105
+ });
106
+ it('does not strip comments when only `code` is requested', () => {
107
+ // Regression guard: codeNoComments is a sibling field, not a replacement.
108
+ // `code` must continue to leave comments intact (some checks scan
109
+ // comments for `@deprecated` / `@fitness-ignore` directives).
110
+ const src = `const x = 1 // @deprecated — use Y instead`;
111
+ const { code, codeNoComments } = filterContent(src);
112
+ expect(code).toContain('@deprecated');
113
+ expect(codeNoComments).not.toContain('@deprecated');
114
+ });
115
+ });
116
+ describe('isInString / isInComment range queries', () => {
117
+ it('isInString reports true for positions inside a string literal', () => {
118
+ const src = `const x = 'hello'`;
119
+ const { isInString } = filterContent(src);
120
+ expect(isInString(1, 12)).toBe(true);
121
+ });
122
+ it('isInString reports false for positions outside any string', () => {
123
+ const src = `const x = 'hello'`;
124
+ const { isInString } = filterContent(src);
125
+ expect(isInString(1, 0)).toBe(false);
126
+ });
127
+ it('isInString returns false for an out-of-range line', () => {
128
+ const src = `const x = 'a'`;
129
+ const { isInString } = filterContent(src);
130
+ expect(isInString(99, 0)).toBe(false);
131
+ });
132
+ it('isInString returns false when there are no strings', () => {
133
+ const { isInString } = filterContent('const x = 1');
134
+ expect(isInString(1, 5)).toBe(false);
135
+ });
136
+ it('isInComment reports true for positions inside a line comment', () => {
137
+ const src = `const x = 1 // hello`;
138
+ const { isInComment } = filterContent(src);
139
+ expect(isInComment(1, 15)).toBe(true);
140
+ });
141
+ it('isInComment reports false outside any comment', () => {
142
+ const src = `const x = 1 // hello`;
143
+ const { isInComment } = filterContent(src);
144
+ expect(isInComment(1, 2)).toBe(false);
145
+ });
146
+ });
147
+ describe('cache behavior — scope-bound (Phase 6 Task 6.4)', () => {
148
+ it('returns the same FilteredContent instance for repeated calls with identical content inside a scope', () => {
149
+ const scope = new RunScope();
150
+ runWithScopeSync(scope, () => {
151
+ const src = `const x = 'cached'`;
152
+ const first = filterContent(src);
153
+ const second = filterContent(src);
154
+ expect(second).toBe(first);
155
+ });
156
+ });
157
+ it('a fresh scope re-parses (cache is per-scope)', () => {
158
+ const src = `const x = 'cleared'`;
159
+ const first = runWithScopeSync(new RunScope(), () => filterContent(src));
160
+ const second = runWithScopeSync(new RunScope(), () => filterContent(src));
161
+ // Two different scopes have independent caches; the FilteredContent
162
+ // values are distinct identities though structurally equivalent.
163
+ expect(second).not.toBe(first);
164
+ });
165
+ it('outside a scope, filterContent bypasses the cache (each call re-parses)', () => {
166
+ const src = `const x = 'no-scope'`;
167
+ const first = filterContent(src);
168
+ const second = filterContent(src);
169
+ // No scope -> no shared cache -> each call returns a fresh instance.
170
+ expect(second).not.toBe(first);
171
+ });
172
+ });
173
+ describe('template middle (multi-substitution)', () => {
174
+ it('masks text between substitutions in a multi-${ } template', () => {
175
+ const src = 'const x = `pre ${a} mid ${b} post`';
176
+ const { code } = filterContent(src);
177
+ expect(code).not.toContain(' mid ');
178
+ expect(code).toContain('${a}');
179
+ expect(code).toContain('${b}');
180
+ });
181
+ });
182
+ });
183
+ //# sourceMappingURL=filter.test.js.map