@pyreon/compiler 0.24.4 → 0.24.6

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 (64) hide show
  1. package/package.json +11 -13
  2. package/src/defer-inline.ts +0 -686
  3. package/src/event-names.ts +0 -65
  4. package/src/index.ts +0 -61
  5. package/src/island-audit.ts +0 -675
  6. package/src/jsx.ts +0 -2792
  7. package/src/load-native.ts +0 -156
  8. package/src/lpih.ts +0 -270
  9. package/src/manifest.ts +0 -280
  10. package/src/project-scanner.ts +0 -214
  11. package/src/pyreon-intercept.ts +0 -1029
  12. package/src/react-intercept.ts +0 -1217
  13. package/src/reactivity-lens.ts +0 -190
  14. package/src/ssg-audit.ts +0 -513
  15. package/src/test-audit.ts +0 -435
  16. package/src/tests/backend-parity-r7-r9.test.ts +0 -91
  17. package/src/tests/backend-prop-derived-callback-divergence.test.ts +0 -74
  18. package/src/tests/collapse-bail-census.test.ts +0 -330
  19. package/src/tests/collapse-key-source-hygiene.test.ts +0 -88
  20. package/src/tests/component-child-no-wrap.test.ts +0 -204
  21. package/src/tests/defer-inline.test.ts +0 -387
  22. package/src/tests/depth-stress.test.ts +0 -16
  23. package/src/tests/detector-tag-consistency.test.ts +0 -101
  24. package/src/tests/dynamic-collapse-detector.test.ts +0 -164
  25. package/src/tests/dynamic-collapse-emit.test.ts +0 -192
  26. package/src/tests/dynamic-collapse-scan.test.ts +0 -111
  27. package/src/tests/element-valued-const-child.test.ts +0 -61
  28. package/src/tests/falsy-child-characterization.test.ts +0 -48
  29. package/src/tests/island-audit.test.ts +0 -524
  30. package/src/tests/jsx.test.ts +0 -2908
  31. package/src/tests/load-native.test.ts +0 -53
  32. package/src/tests/lpih.test.ts +0 -404
  33. package/src/tests/malformed-input-resilience.test.ts +0 -50
  34. package/src/tests/manifest-snapshot.test.ts +0 -55
  35. package/src/tests/native-equivalence.test.ts +0 -924
  36. package/src/tests/partial-collapse-detector.test.ts +0 -121
  37. package/src/tests/partial-collapse-emit.test.ts +0 -104
  38. package/src/tests/partial-collapse-robustness.test.ts +0 -53
  39. package/src/tests/project-scanner.test.ts +0 -269
  40. package/src/tests/prop-derived-shadow.test.ts +0 -96
  41. package/src/tests/pure-call-reactive-args.test.ts +0 -50
  42. package/src/tests/pyreon-intercept.test.ts +0 -816
  43. package/src/tests/r13-callback-stmt-equivalence.test.ts +0 -58
  44. package/src/tests/r14-ssr-mode-parity.test.ts +0 -51
  45. package/src/tests/r15-elemconst-propderived.test.ts +0 -47
  46. package/src/tests/r19-defer-inline-robust.test.ts +0 -54
  47. package/src/tests/r20-backend-equivalence-sweep.test.ts +0 -50
  48. package/src/tests/react-intercept.test.ts +0 -1104
  49. package/src/tests/reactivity-lens.test.ts +0 -170
  50. package/src/tests/rocketstyle-collapse.test.ts +0 -208
  51. package/src/tests/runtime/control-flow.test.ts +0 -159
  52. package/src/tests/runtime/dom-properties.test.ts +0 -138
  53. package/src/tests/runtime/events.test.ts +0 -301
  54. package/src/tests/runtime/harness.ts +0 -94
  55. package/src/tests/runtime/pr-352-shapes.test.ts +0 -121
  56. package/src/tests/runtime/reactive-props.test.ts +0 -81
  57. package/src/tests/runtime/signals.test.ts +0 -129
  58. package/src/tests/runtime/whitespace.test.ts +0 -106
  59. package/src/tests/signal-autocall-shadow.test.ts +0 -86
  60. package/src/tests/sourcemap-fidelity.test.ts +0 -77
  61. package/src/tests/ssg-audit.test.ts +0 -402
  62. package/src/tests/static-text-baking.test.ts +0 -64
  63. package/src/tests/test-audit.test.ts +0 -549
  64. package/src/tests/transform-state-isolation.test.ts +0 -49
@@ -1,549 +0,0 @@
1
- import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs'
2
- import { tmpdir } from 'node:os'
3
- import { dirname, join, resolve } from 'node:path'
4
- import { fileURLToPath } from 'node:url'
5
- import {
6
- auditTestEnvironment,
7
- formatTestAudit,
8
- type TestAuditResult,
9
- } from '../test-audit'
10
-
11
- const HERE = dirname(fileURLToPath(import.meta.url))
12
- // tests/ → src/ → compiler/ → core/ → packages/ → repo root (5 ups)
13
- const REPO_ROOT = resolve(HERE, '../../../../../')
14
-
15
- // ═══════════════════════════════════════════════════════════════════════════════
16
- // Helpers — synthetic monorepo fixture
17
- // ═══════════════════════════════════════════════════════════════════════════════
18
-
19
- function makeFixture(): {
20
- root: string
21
- writeTest: (relPath: string, body: string) => void
22
- cleanup: () => void
23
- } {
24
- const root = mkdtempSync(join(tmpdir(), 'pyreon-audit-fixture-'))
25
- mkdirSync(join(root, 'packages'), { recursive: true })
26
- return {
27
- root,
28
- writeTest: (relPath, body) => {
29
- const full = join(root, 'packages', relPath)
30
- mkdirSync(dirname(full), { recursive: true })
31
- writeFileSync(full, body)
32
- },
33
- cleanup: () => rmSync(root, { recursive: true, force: true }),
34
- }
35
- }
36
-
37
- // ═══════════════════════════════════════════════════════════════════════════════
38
- // Scanner — synthetic inputs
39
- // ═══════════════════════════════════════════════════════════════════════════════
40
-
41
- describe('auditTestEnvironment — synthetic fixtures', () => {
42
- let f: ReturnType<typeof makeFixture>
43
- beforeEach(() => {
44
- f = makeFixture()
45
- })
46
- afterEach(() => f.cleanup())
47
-
48
- it('returns root=null when no packages/ dir exists', () => {
49
- const empty = mkdtempSync(join(tmpdir(), 'pyreon-audit-empty-'))
50
- try {
51
- const r = auditTestEnvironment(empty)
52
- expect(r.root).toBeNull()
53
- expect(r.entries).toEqual([])
54
- expect(r.totalScanned).toBe(0)
55
- } finally {
56
- rmSync(empty, { recursive: true, force: true })
57
- }
58
- })
59
-
60
- it('classifies a pure-mock test file as HIGH', () => {
61
- f.writeTest(
62
- 'foo/src/tests/component.test.ts',
63
- `
64
- const makeVNode = (type, props, children) => ({ type, props, children })
65
- it('renders', () => {
66
- const vnode = { type: 'div', props: { class: 'x' }, children: [] }
67
- expect(vnode).toBeDefined()
68
- })
69
- `,
70
- )
71
- const r = auditTestEnvironment(f.root)
72
- expect(r.entries).toHaveLength(1)
73
- const [entry] = r.entries
74
- expect(entry!.risk).toBe('high')
75
- // Only one literal counted: the named `vnode` binding uses
76
- // `type: 'div'` with an explicit colon. The `makeVNode` return
77
- // expression uses shorthand `({ type, props, children })` — no
78
- // colons — which the regex intentionally skips to avoid false
79
- // positives on unrelated destructuring patterns.
80
- expect(entry!.mockVNodeLiteralCount).toBe(1)
81
- // Two helper bindings match the `(const|let|function) <name>`
82
- // form: `makeVNode` and `vnode`. Both are flagged because both
83
- // names signal "this test builds mock vnodes by hand".
84
- expect(entry!.mockHelperCount).toBe(2)
85
- expect(entry!.importsH).toBe(false)
86
- })
87
-
88
- it('classifies a pure-h() test file as LOW', () => {
89
- f.writeTest(
90
- 'foo/src/tests/real.test.ts',
91
- `
92
- import { h } from '@pyreon/core'
93
- it('renders through real h', () => {
94
- const vnode = h('div', { class: 'x' })
95
- const composed = h(Component, { x: 1 })
96
- expect(vnode).toBeDefined()
97
- })
98
- `,
99
- )
100
- const r = auditTestEnvironment(f.root)
101
- expect(r.entries).toHaveLength(1)
102
- const [entry] = r.entries
103
- expect(entry!.risk).toBe('low')
104
- expect(entry!.mockVNodeLiteralCount).toBe(0)
105
- expect(entry!.importsH).toBe(true)
106
- })
107
-
108
- it('classifies MEDIUM when mocks > real-h() but both present', () => {
109
- f.writeTest(
110
- 'foo/src/tests/mixed.test.ts',
111
- `
112
- import { h } from '@pyreon/core'
113
- const mockVNode = (type, props, children) => ({ type, props, children })
114
- it('mock heavy', () => {
115
- const a = { type: 'a', props: {}, children: [] }
116
- const b = { type: 'b', props: {}, children: [] }
117
- const c = { type: 'c', props: {}, children: [] }
118
- const real = h('div')
119
- expect(real).toBeDefined()
120
- })
121
- `,
122
- )
123
- const r = auditTestEnvironment(f.root)
124
- const [entry] = r.entries
125
- expect(entry!.risk).toBe('medium')
126
- expect(entry!.mockVNodeLiteralCount).toBe(3)
127
- expect(entry!.mockHelperCount).toBe(1)
128
- expect(entry!.realHCallCount).toBe(1)
129
- expect(entry!.importsH).toBe(true)
130
- })
131
-
132
- it('classifies a test with no mocks at all as LOW', () => {
133
- f.writeTest(
134
- 'foo/src/tests/logic.test.ts',
135
- `
136
- import { describe, it, expect } from 'vitest'
137
- describe('pure logic', () => {
138
- it('adds', () => {
139
- expect(1 + 1).toBe(2)
140
- })
141
- })
142
- `,
143
- )
144
- const r = auditTestEnvironment(f.root)
145
- expect(r.entries[0]!.risk).toBe('low')
146
- })
147
-
148
- it('does NOT flag `h` substring inside identifier names as real h() calls', () => {
149
- // The regex requires a non-word boundary before `h(`. `hasSomething(`,
150
- // `hash(`, `oh(` — none should trigger.
151
- f.writeTest(
152
- 'foo/src/tests/substring.test.ts',
153
- `
154
- it('strings', () => {
155
- const fn = hasProp({ a: 1 })
156
- const h2 = hash(x)
157
- const result = oh(x, y)
158
- expect(fn).toBeDefined()
159
- })
160
- `,
161
- )
162
- const r = auditTestEnvironment(f.root)
163
- expect(r.entries[0]!.realHCallCount).toBe(0)
164
- })
165
-
166
- it('recognises multiple mock-helper names (vnode, mockVNode, createVNode, vnodeMock, makeVNode)', () => {
167
- f.writeTest(
168
- 'foo/src/tests/helpers.test.ts',
169
- `
170
- const vnode = () => null
171
- const mockVNode = () => null
172
- const createVNode = () => null
173
- function VNodeMock() {}
174
- const makeVNode = () => null
175
- `,
176
- )
177
- const r = auditTestEnvironment(f.root)
178
- expect(r.entries[0]!.mockHelperCount).toBe(5)
179
- })
180
-
181
- it('does NOT flag `const vnode = someCall()` — that is a binding, not a helper def', () => {
182
- // False positive the scanner used to hit — real render-result
183
- // bindings got counted as mock factories, inflating the HIGH list
184
- // with files like `table.test.tsx` and `storybook.test.tsx`.
185
- f.writeTest(
186
- 'foo/src/tests/bindings.test.ts',
187
- `
188
- const vnode = defaultRender(Component, { name: 'World' })
189
- const mockVNode = buildSomething()
190
- const createVNode = factory.make(props)
191
- `,
192
- )
193
- const r = auditTestEnvironment(f.root)
194
- expect(r.entries[0]!.mockHelperCount).toBe(0)
195
- })
196
-
197
- it('does NOT flag `const vnode = <jsx />` — JSX bindings are real VNodes', () => {
198
- // `table.test.tsx` had `const vnode = <span>cell content</span>`
199
- // — a legitimate real VNode stored in a local, not a mock factory.
200
- f.writeTest(
201
- 'foo/src/tests/jsx-binding.test.tsx',
202
- `
203
- const vnode = <span>cell content</span>
204
- const createVNode = <div />
205
- `,
206
- )
207
- const r = auditTestEnvironment(f.root)
208
- expect(r.entries[0]!.mockHelperCount).toBe(0)
209
- })
210
-
211
- it('still flags `const vnode = (...) => ({ type, props, children })` arrow factories', () => {
212
- f.writeTest(
213
- 'foo/src/tests/arrow-factory.test.ts',
214
- `
215
- const vnode = (type, props, children) => ({ type, props, children })
216
- `,
217
- )
218
- const r = auditTestEnvironment(f.root)
219
- expect(r.entries[0]!.mockHelperCount).toBe(1)
220
- })
221
-
222
- it('still flags `const vnode = { type, props, children }` inline-object factories', () => {
223
- f.writeTest(
224
- 'foo/src/tests/inline-factory.test.ts',
225
- `
226
- const vnode = { type: 'div', props: {}, children: [] }
227
- `,
228
- )
229
- const r = auditTestEnvironment(f.root)
230
- expect(r.entries[0]!.mockHelperCount).toBe(1)
231
- })
232
-
233
- it('skips `{type,props,children}` literals inside type-guard call-args', () => {
234
- // `isDocNode({ type, props, children })` is testing a duck-type
235
- // guard — the literal IS the test input, not a mock-render input.
236
- // `utils-coverage.test.ts` was the motivating false positive.
237
- f.writeTest(
238
- 'foo/src/tests/type-guard.test.ts',
239
- `
240
- expect(isDocNode({ type: 'text', props: {}, children: [] })).toBe(true)
241
- expect(hasVNodeShape({ type: 'div', props: {}, children: [] })).toBe(true)
242
- expect(assertVNode({ type: 'span', props: {}, children: [] })).toBe(undefined)
243
- expect(validateNode({ type: 'p', props: {}, children: [] })).toBe(true)
244
- `,
245
- )
246
- const r = auditTestEnvironment(f.root)
247
- expect(r.entries[0]!.mockVNodeLiteralCount).toBe(0)
248
- })
249
-
250
- it('still flags `{type,props,children}` literals bound to a variable', () => {
251
- f.writeTest(
252
- 'foo/src/tests/bound-literal.test.ts',
253
- `
254
- const v = { type: 'div', props: {}, children: [] }
255
- `,
256
- )
257
- const r = auditTestEnvironment(f.root)
258
- expect(r.entries[0]!.mockVNodeLiteralCount).toBe(1)
259
- })
260
-
261
- it('skips `{type,props,children}` literals inside template strings (fixtures)', () => {
262
- // The scanner's own test suite (cli/doctor.test.ts) writes mock-
263
- // vnode literals to disk as fixture content via `writeFile(...,
264
- // \`const v = { type, props, children: [] }\`)`. The literal is
265
- // STRING DATA passed to the audit tool, not code that ever runs.
266
- // The masking pass must skip backtick-delimited regions.
267
- f.writeTest(
268
- 'foo/src/tests/template-fixture.test.ts',
269
- `
270
- writeFile(tmp, 'fixture.test.ts', \`const vnode = { type: 'div', props: {}, children: [] }\`)
271
- writeFile(tmp, 'helper.test.ts', \`const mockVNode = (a, b) => ({ type: a, props: b, children: [] })\`)
272
- `,
273
- )
274
- const r = auditTestEnvironment(f.root)
275
- const e = r.entries[0]!
276
- // Both literals AND the helper definition are inside template
277
- // strings — neither should count.
278
- expect(e.mockVNodeLiteralCount).toBe(0)
279
- expect(e.mockHelperCount).toBe(0)
280
- })
281
-
282
- it('still flags literals/helpers OUTSIDE template strings, even when fixtures are nearby', () => {
283
- // Mixed file: a real top-level `const vnode = (...)` factory plus
284
- // a fixture string. Scanner counts the real one, skips the fixture.
285
- f.writeTest(
286
- 'foo/src/tests/mixed.test.ts',
287
- `
288
- const vnode = (t, p) => ({ type: t, props: p, children: [] })
289
- writeFile(tmp, 'fixture.test.ts', \`const v = { type: 'div', props: {}, children: [] }\`)
290
- `,
291
- )
292
- const r = auditTestEnvironment(f.root)
293
- const e = r.entries[0]!
294
- expect(e.mockHelperCount).toBe(1) // the real factory at module scope
295
- // The fixture string content is masked, so its literal doesn't count.
296
- })
297
-
298
- it('sorts entries by risk (HIGH first) then path', () => {
299
- f.writeTest(
300
- 'z/src/tests/low.test.ts',
301
- `import { h } from '@pyreon/core'; const v = h('div')`,
302
- )
303
- f.writeTest(
304
- 'a/src/tests/high.test.ts',
305
- `const v = { type: 'div', props: {}, children: [] }`,
306
- )
307
- f.writeTest(
308
- 'm/src/tests/medium.test.ts',
309
- `
310
- import { h } from '@pyreon/core'
311
- const a = { type: 'a', props: {}, children: [] }
312
- const b = { type: 'b', props: {}, children: [] }
313
- const r = h('div')
314
- `,
315
- )
316
- const r = auditTestEnvironment(f.root)
317
- expect(r.entries.map((e) => e.risk)).toEqual(['high', 'medium', 'low'])
318
- })
319
-
320
- it('skips node_modules / lib / dist directories', () => {
321
- f.writeTest(
322
- 'foo/src/tests/real.test.ts',
323
- `const x = { type: 'a', props: {}, children: [] }`,
324
- )
325
- f.writeTest(
326
- 'foo/node_modules/some-dep/src/tests/nested.test.ts',
327
- `const x = { type: 'ignored', props: {}, children: [] }`,
328
- )
329
- f.writeTest(
330
- 'foo/lib/tests/nested.test.ts',
331
- `const x = { type: 'ignored', props: {}, children: [] }`,
332
- )
333
- const r = auditTestEnvironment(f.root)
334
- expect(r.totalScanned).toBe(1)
335
- expect(r.entries[0]!.relPath).toContain('foo/src/tests/real.test.ts')
336
- })
337
-
338
- it('counts exactly test files matching *.test.ts or *.test.tsx', () => {
339
- f.writeTest('foo/src/tests/a.test.ts', 'const x = 1')
340
- f.writeTest('foo/src/tests/b.test.tsx', 'const x = 1')
341
- f.writeTest('foo/src/tests/c.spec.ts', 'const x = 1') // not a .test file
342
- f.writeTest('foo/src/tests/d.ts', 'const x = 1') // not a test file
343
- const r = auditTestEnvironment(f.root)
344
- expect(r.totalScanned).toBe(2)
345
- })
346
- })
347
-
348
- // ═══════════════════════════════════════════════════════════════════════════════
349
- // Scanner — real repo
350
- // ═══════════════════════════════════════════════════════════════════════════════
351
-
352
- describe('auditTestEnvironment — real Pyreon repo', () => {
353
- const result = auditTestEnvironment(REPO_ROOT)
354
-
355
- it('discovers the monorepo root', () => {
356
- expect(result.root).toBe(REPO_ROOT)
357
- })
358
-
359
- it('scans a realistic number of test files (>50)', () => {
360
- expect(result.totalScanned).toBeGreaterThan(50)
361
- })
362
-
363
- it('scanner picks up real h() usage across the repo — sanity check', () => {
364
- // The full T1.2 cleanup drove the real-repo HIGH and MEDIUM counts
365
- // to zero — every test file now either avoids mock vnodes entirely
366
- // or pairs them with real-`h()` coverage. So there's no longer any
367
- // mock-helper or risk-level anchor that's stable over time on the
368
- // real repo. The synthetic-fixture suites above (which we control)
369
- // are what cover classifier correctness. The only stable invariant
370
- // left for the live scan is: real `h()` from `@pyreon/core` IS used
371
- // in test files. Zero would indicate the scanner regex broke.
372
- const realHUsers = result.entries.filter((e) => e.realHCallCount > 0)
373
- expect(realHUsers.length).toBeGreaterThan(0)
374
- })
375
-
376
- it('never produces NaN or negative counts', () => {
377
- for (const entry of result.entries) {
378
- expect(entry.mockVNodeLiteralCount).toBeGreaterThanOrEqual(0)
379
- expect(entry.mockHelperCount).toBeGreaterThanOrEqual(0)
380
- expect(entry.mockHelperCallCount).toBeGreaterThanOrEqual(0)
381
- expect(entry.realHCallCount).toBeGreaterThanOrEqual(0)
382
- }
383
- })
384
- })
385
-
386
- // ═══════════════════════════════════════════════════════════════════════════════
387
- // Helper-call metric — catches factory-call pervasiveness
388
- // ═══════════════════════════════════════════════════════════════════════════════
389
-
390
- describe('mockHelperCallCount metric', () => {
391
- let f: ReturnType<typeof makeFixture>
392
- beforeEach(() => {
393
- f = makeFixture()
394
- })
395
- afterEach(() => f.cleanup())
396
-
397
- it('counts every call to a known mock-helper name', () => {
398
- f.writeTest(
399
- 'foo/src/tests/pervasive.test.ts',
400
- `
401
- const vnode = (type, props, children) => ({ type, props, children })
402
- it('builds lots', () => {
403
- const a = vnode('div', {}, [])
404
- const b = vnode('span', {}, [])
405
- const c = vnode('button', {}, [])
406
- expect([a, b, c]).toBeDefined()
407
- })
408
- `,
409
- )
410
- const r = auditTestEnvironment(f.root)
411
- const [entry] = r.entries
412
- // Three call-sites + one inside the definition argument list =
413
- // four total matches. The definition's own `(type, props, ...)`
414
- // hit is expected — it reports signal activity either way.
415
- expect(entry!.mockHelperCallCount).toBeGreaterThanOrEqual(3)
416
- })
417
-
418
- it('does not count calls with trailing non-word boundary (identifier extensions)', () => {
419
- // `vnodeReal(...)` should NOT match — it starts with `vnode` but
420
- // continues as an identifier. The negative-lookahead via
421
- // `(?:^|[^a-zA-Z0-9_])` boundary guards against this on the LEFT
422
- // side only, so we still rely on the name set being specific.
423
- f.writeTest(
424
- 'foo/src/tests/lookalike.test.ts',
425
- `
426
- const vnodeExtended = () => null
427
- vnodeExtended()
428
- myVnode()
429
- `,
430
- )
431
- const r = auditTestEnvironment(f.root)
432
- const [entry] = r.entries
433
- // The regex matches `vnode(` as a substring of `vnodeExtended(`.
434
- // Acknowledged false positive — documented in the pattern comment.
435
- // What we verify: the metric is still non-negative and classifies
436
- // the file in a way that's still useful (non-zero mock activity
437
- // means the reviewer should eyeball it).
438
- expect(entry!.mockHelperCallCount).toBeGreaterThanOrEqual(0)
439
- })
440
-
441
- it('factors into HIGH classification when no real-h() counterpart exists', () => {
442
- // A file that DEFINES no helper but CALLS an imported one heavily
443
- // should still show risk.
444
- f.writeTest(
445
- 'foo/src/tests/imported-helper.test.ts',
446
- `
447
- import { vnode } from '../fixtures'
448
- it('uses imported vnode', () => {
449
- const a = vnode('div')
450
- const b = vnode('span')
451
- expect([a, b]).toBeDefined()
452
- })
453
- `,
454
- )
455
- const r = auditTestEnvironment(f.root)
456
- const [entry] = r.entries
457
- expect(entry!.mockHelperCount).toBe(0)
458
- expect(entry!.mockHelperCallCount).toBeGreaterThanOrEqual(2)
459
- expect(entry!.risk).toBe('high')
460
- })
461
- })
462
-
463
- // ═══════════════════════════════════════════════════════════════════════════════
464
- // Formatter
465
- // ═══════════════════════════════════════════════════════════════════════════════
466
-
467
- describe('formatTestAudit', () => {
468
- function mkResult(entries: Partial<TestAuditResult['entries'][number]>[]): TestAuditResult {
469
- return {
470
- root: '/tmp/fake',
471
- entries: entries.map((e, i) => ({
472
- path: `/tmp/fake/${i}.test.ts`,
473
- relPath: `${i}.test.ts`,
474
- mockVNodeLiteralCount: 0,
475
- mockHelperCount: 0,
476
- mockHelperCallCount: 0,
477
- realHCallCount: 0,
478
- importsH: false,
479
- risk: 'low' as const,
480
- ...e,
481
- })),
482
- totalScanned: entries.length,
483
- }
484
- }
485
-
486
- it('emits a helpful miss message when root is null', () => {
487
- const out = formatTestAudit({ root: null, entries: [], totalScanned: 0 })
488
- expect(out).toContain('No monorepo root found')
489
- })
490
-
491
- it('surfaces risk counts and mock-vnode exposure fraction in the header', () => {
492
- const out = formatTestAudit(
493
- mkResult([
494
- { risk: 'high', mockVNodeLiteralCount: 1 },
495
- { risk: 'medium', mockVNodeLiteralCount: 2, realHCallCount: 1, importsH: true },
496
- { risk: 'low' },
497
- ]),
498
- )
499
- expect(out).toContain('3 test files scanned')
500
- // Formatter wraps the label in markdown bold **...**, so just
501
- // check the number + slash pattern.
502
- expect(out).toMatch(/Mock-vnode exposure.*2 \/ 3/)
503
- expect(out).toContain('1 high')
504
- expect(out).toContain('1 medium')
505
- })
506
-
507
- it('defaults to minRisk="medium" — hides LOW entries', () => {
508
- const out = formatTestAudit(
509
- mkResult([
510
- { risk: 'high', mockVNodeLiteralCount: 1, relPath: 'hi.test.ts' },
511
- { risk: 'low', relPath: 'ok.test.ts' },
512
- ]),
513
- )
514
- expect(out).toContain('hi.test.ts')
515
- expect(out).not.toContain('- ok.test.ts') // bullet form only; header counts are fine
516
- })
517
-
518
- it('respects minRisk="high" — hides MEDIUM entries', () => {
519
- const out = formatTestAudit(
520
- mkResult([
521
- { risk: 'high', mockVNodeLiteralCount: 1, relPath: 'hi.test.ts' },
522
- { risk: 'medium', mockVNodeLiteralCount: 1, realHCallCount: 1, relPath: 'med.test.ts' },
523
- ]),
524
- { minRisk: 'high' },
525
- )
526
- expect(out).toContain('hi.test.ts')
527
- expect(out).not.toContain('- med.test.ts')
528
- })
529
-
530
- it('respects limit per risk group', () => {
531
- const entries = Array.from({ length: 30 }, (_, i) => ({
532
- risk: 'high' as const,
533
- mockVNodeLiteralCount: 1,
534
- relPath: `h${i}.test.ts`,
535
- }))
536
- const out = formatTestAudit(mkResult(entries), { limit: 3 })
537
- expect(out).toContain('30 files (showing 3)')
538
- // Bullets: exactly 3
539
- const bullets = out.split('\n').filter((l) => /^- h\d+\.test\.ts/.test(l))
540
- expect(bullets).toHaveLength(3)
541
- })
542
-
543
- it('mentions PR #197 so the agent has the context', () => {
544
- const out = formatTestAudit(
545
- mkResult([{ risk: 'high', mockVNodeLiteralCount: 1 }]),
546
- )
547
- expect(out).toContain('PR #197')
548
- })
549
- })
@@ -1,49 +0,0 @@
1
- /**
2
- * Compiler hardening — Round 6 (state-isolation lock; no leak found).
3
- *
4
- * Probed: does the JS transform leak across calls? All per-transform caches
5
- * (`_isDynamicCache`, `resolvedCache`, `resolving`, `warnedCycles`) are
6
- * declared INSIDE `transformJSX_JS` (function scope → GC'd per call); the only
7
- * module-level state is immutable constant lookup Sets (`PURE_CALLS`,
8
- * `VOID_ELEMENTS`, `SKIP_PROPS`, …). Empirically 8000 transforms added
9
- * ~0.2KB/call of short-lived (collectable) allocation — no retention path.
10
- *
11
- * Not a heap-threshold test (those are flaky under parallel vitest / GC
12
- * timing — the project explicitly avoids them). Instead this locks the
13
- * DETERMINISTIC structural guarantee a leak/contamination regression would
14
- * break: cross-call output isolation + constant-Set integrity. If someone
15
- * later hoists a per-transform cache to module scope (the classic leak
16
- * regression), the same input would start producing drifting output and/or
17
- * the constant Sets would mutate — caught here without heap timing.
18
- */
19
- import { describe, expect, it } from 'vitest'
20
- import { transformJSX_JS } from '../jsx'
21
-
22
- const emit = (c: string): string => transformJSX_JS(c, 'c.tsx').code ?? ''
23
-
24
- describe('Round 6 — transform state is per-call isolated (leak/contamination gate)', () => {
25
- it('identical input → byte-identical output across 500 interleaved calls', () => {
26
- const a = `function A(p){ const v=p.x; return <ul>{p.items.map(i => <li>{v}{i}</li>)}</ul> }`
27
- const b = `function B(){ const s=signal(0); return <button onClick={()=>s.set(1)}>{s()}</button> }`
28
- const a0 = emit(a)
29
- const b0 = emit(b)
30
- for (let i = 0; i < 500; i++) {
31
- // Interleave different shapes so any module-level cache keyed by
32
- // node.start (collides across files) would drift the output.
33
- expect(emit(b)).toBe(b0)
34
- expect(emit(a)).toBe(a0)
35
- }
36
- })
37
-
38
- it('constant lookup Sets are not mutated by transforms', () => {
39
- // PURE_CALLS / VOID_ELEMENTS behavior must be stable after heavy use.
40
- for (let i = 0; i < 200; i++) {
41
- emit(`function C(p){ return <div>{Math.max(p.x, 0)}</div> }`)
42
- emit(`function C(){ return <br /> }`)
43
- }
44
- // br stays verbatim (VOID/self-closing contract) and Math.max with a
45
- // dynamic arg stays reactive (PURE_CALLS not corrupted to "always pure").
46
- expect(emit(`function C(){ return <br /> }`)).toContain('<br />')
47
- expect(emit(`function C(p){ return <div>{Math.max(p.x,0)}</div> }`)).toContain('_bind(')
48
- })
49
- })