@barefootjs/jsx 0.34.0 → 0.35.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 (101) hide show
  1. package/dist/analyzer.d.ts.map +1 -1
  2. package/dist/index.d.ts +2 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +344 -215
  5. package/dist/ir-to-client-js/collect-elements.d.ts.map +1 -1
  6. package/dist/ir-to-client-js/control-flow/plan/build-branch-loop.d.ts.map +1 -1
  7. package/dist/ir-to-client-js/control-flow/plan/build-component-loop.d.ts.map +1 -1
  8. package/dist/ir-to-client-js/control-flow/plan/build-composite-loop.d.ts.map +1 -1
  9. package/dist/ir-to-client-js/control-flow/plan/build-lazy-row.d.ts +11 -0
  10. package/dist/ir-to-client-js/control-flow/plan/build-lazy-row.d.ts.map +1 -1
  11. package/dist/ir-to-client-js/control-flow/plan/build-loop.d.ts.map +1 -1
  12. package/dist/ir-to-client-js/control-flow/plan/build-plain-row.d.ts +52 -0
  13. package/dist/ir-to-client-js/control-flow/plan/build-plain-row.d.ts.map +1 -0
  14. package/dist/ir-to-client-js/control-flow/plan/build-reactive-effects.d.ts +2 -0
  15. package/dist/ir-to-client-js/control-flow/plan/build-reactive-effects.d.ts.map +1 -1
  16. package/dist/ir-to-client-js/control-flow/plan/lazy-conditional.d.ts +6 -7
  17. package/dist/ir-to-client-js/control-flow/plan/lazy-conditional.d.ts.map +1 -1
  18. package/dist/ir-to-client-js/control-flow/plan/lazy-preamble.d.ts +5 -7
  19. package/dist/ir-to-client-js/control-flow/plan/lazy-preamble.d.ts.map +1 -1
  20. package/dist/ir-to-client-js/control-flow/plan/lazy-row-eligibility.d.ts.map +1 -1
  21. package/dist/ir-to-client-js/control-flow/plan/loop.d.ts +10 -6
  22. package/dist/ir-to-client-js/control-flow/plan/loop.d.ts.map +1 -1
  23. package/dist/ir-to-client-js/control-flow/shared.d.ts +11 -9
  24. package/dist/ir-to-client-js/control-flow/shared.d.ts.map +1 -1
  25. package/dist/ir-to-client-js/control-flow/stringify/composite-loop.d.ts.map +1 -1
  26. package/dist/ir-to-client-js/control-flow/stringify/lazy-row.d.ts.map +1 -1
  27. package/dist/ir-to-client-js/csr-substitute.d.ts +16 -0
  28. package/dist/ir-to-client-js/csr-substitute.d.ts.map +1 -1
  29. package/dist/ir-to-client-js/emit-reactive.d.ts.map +1 -1
  30. package/dist/ir-to-client-js/emit-registration.d.ts.map +1 -1
  31. package/dist/ir-to-client-js/html-template.d.ts +2 -2
  32. package/dist/ir-to-client-js/html-template.d.ts.map +1 -1
  33. package/dist/ir-to-client-js/imports.d.ts +2 -2
  34. package/dist/ir-to-client-js/imports.d.ts.map +1 -1
  35. package/dist/ir-to-client-js/index.d.ts.map +1 -1
  36. package/dist/ir-to-client-js/markup-slots.d.ts +21 -0
  37. package/dist/ir-to-client-js/markup-slots.d.ts.map +1 -0
  38. package/dist/ir-to-client-js/safe-html.d.ts +158 -0
  39. package/dist/ir-to-client-js/safe-html.d.ts.map +1 -0
  40. package/dist/ir-to-client-js/utils.d.ts +34 -1
  41. package/dist/ir-to-client-js/utils.d.ts.map +1 -1
  42. package/dist/jsx-to-ir.d.ts.map +1 -1
  43. package/dist/prop-rewrite.d.ts +8 -3
  44. package/dist/prop-rewrite.d.ts.map +1 -1
  45. package/dist/props-binding.d.ts +22 -1
  46. package/dist/props-binding.d.ts.map +1 -1
  47. package/dist/ssr-defaults.d.ts.map +1 -1
  48. package/dist/types.d.ts +5 -10
  49. package/dist/types.d.ts.map +1 -1
  50. package/package.json +2 -2
  51. package/src/__tests__/__snapshots__/doc-examples.test.ts.snap +10 -12
  52. package/src/__tests__/build-plain-row-consolidation.test.ts +120 -0
  53. package/src/__tests__/client-template-escape-soundness.test.ts +538 -0
  54. package/src/__tests__/csr-template-loop-shadowing.test.ts +4 -2
  55. package/src/__tests__/flatmap-segments.test.ts +1 -1
  56. package/src/__tests__/lazy-conditional.test.ts +52 -12
  57. package/src/__tests__/lazy-preamble.test.ts +11 -11
  58. package/src/__tests__/lazy-row-eligibility.test.ts +8 -3
  59. package/src/__tests__/loop-child-reactive-attr-const-shadow.test.ts +25 -3
  60. package/src/__tests__/loop-item-conditional-codegen.test.ts +4 -2
  61. package/src/__tests__/map-arbitrary-body.test.ts +1 -1
  62. package/src/__tests__/nested-loop-index-param.test.ts +14 -3
  63. package/src/__tests__/nested-loop-reactive-attrs.test.ts +4 -2
  64. package/src/__tests__/reactive-attrs-in-map.test.ts +13 -10
  65. package/src/__tests__/rewrite-destructured-props.test.ts +37 -0
  66. package/src/__tests__/safe-html-splice-door.test.ts +61 -0
  67. package/src/__tests__/ssr-defaults.test.ts +59 -0
  68. package/src/analyzer.ts +4 -0
  69. package/src/index.ts +8 -2
  70. package/src/ir-to-client-js/collect-elements.ts +18 -2
  71. package/src/ir-to-client-js/control-flow/plan/build-branch-loop.ts +20 -28
  72. package/src/ir-to-client-js/control-flow/plan/build-component-loop.ts +9 -7
  73. package/src/ir-to-client-js/control-flow/plan/build-composite-loop.ts +10 -6
  74. package/src/ir-to-client-js/control-flow/plan/build-inner-loop.ts +8 -8
  75. package/src/ir-to-client-js/control-flow/plan/build-lazy-row.ts +18 -2
  76. package/src/ir-to-client-js/control-flow/plan/build-loop-child-arm.ts +3 -3
  77. package/src/ir-to-client-js/control-flow/plan/build-loop.ts +35 -35
  78. package/src/ir-to-client-js/control-flow/plan/build-plain-row.ts +110 -0
  79. package/src/ir-to-client-js/control-flow/plan/build-reactive-effects.ts +5 -2
  80. package/src/ir-to-client-js/control-flow/plan/lazy-conditional.ts +11 -10
  81. package/src/ir-to-client-js/control-flow/plan/lazy-preamble.ts +11 -13
  82. package/src/ir-to-client-js/control-flow/plan/lazy-row-eligibility.ts +13 -3
  83. package/src/ir-to-client-js/control-flow/plan/loop.ts +10 -6
  84. package/src/ir-to-client-js/control-flow/shared.ts +40 -17
  85. package/src/ir-to-client-js/control-flow/stringify/composite-loop.ts +2 -1
  86. package/src/ir-to-client-js/control-flow/stringify/lazy-row.ts +10 -0
  87. package/src/ir-to-client-js/csr-substitute.ts +29 -0
  88. package/src/ir-to-client-js/emit-reactive.ts +4 -1
  89. package/src/ir-to-client-js/emit-registration.ts +2 -4
  90. package/src/ir-to-client-js/html-template.ts +58 -244
  91. package/src/ir-to-client-js/imports.ts +3 -0
  92. package/src/ir-to-client-js/index.ts +4 -4
  93. package/src/ir-to-client-js/markup-slots.ts +25 -0
  94. package/src/ir-to-client-js/safe-html.ts +243 -0
  95. package/src/ir-to-client-js/utils.ts +58 -10
  96. package/src/jsx-to-ir.ts +115 -20
  97. package/src/prop-rewrite.ts +8 -4
  98. package/src/props-binding.ts +37 -1
  99. package/src/ssr-defaults.ts +45 -0
  100. package/src/types.ts +5 -10
  101. package/src/__tests__/text-slot-escaping.test.ts +0 -65
package/src/types.ts CHANGED
@@ -404,18 +404,13 @@ export interface IRText {
404
404
  export interface IRExpression {
405
405
  type: 'expression'
406
406
  expr: string
407
- /** Pre-transformed expr with destructured prop refs rewritten to _p.xxx (for client JS templates). */
408
- templateExpr?: string
409
407
  /**
410
- * Marks a VALUE moved into element content by a lowering (today only
411
- * `lowerFormControlValueSsr`'s `<textarea>`, #2765) — client builders
412
- * must escape it, unlike the normal pre-rendered-HTML `${...}` case.
413
- *
414
- * Not read via `templateExpr` instead: that field also rebinds to
415
- * `_p.xxx`, which drops a destructured prop's `?? {}` default when the
416
- * builder's output lives in init scope (`client-js-generation.test.ts`).
408
+ * Pre-transformed expr with destructured prop refs rewritten to _p.xxx
409
+ * (for client JS templates). Carries ONLY that rewrite never an
410
+ * escaping wrapper: client-side escaping is decided at the splice
411
+ * (`ir-to-client-js/safe-html.ts`), not baked into IR text (#2795).
417
412
  */
418
- escapeInClientTemplate?: boolean
413
+ templateExpr?: string
419
414
  /**
420
415
  * Structured parse of `expr` (`parseExpression(expr.trim())`), attached once
421
416
  * during IR construction so SSR adapters emit from the tree instead of each
@@ -1,65 +0,0 @@
1
- /**
2
- * Text-slot HTML-escaping emit shape (#1694 + follow-up, #2651).
3
- *
4
- * Pins which interpolations the client template wraps in an escape call:
5
- * - a plain, non-conditional dynamic text slot (`{stringValue}`) IS
6
- * escaped — it becomes the slot's text content under `innerHTML`. Since
7
- * #2651 this goes through `escapeTextOrMarkup`, not bare `escapeText`:
8
- * the slot is claim-plan `kind: 'markup'` (the value may be a live
9
- * `Node`, or a `bfMarkup()`-branded JSX-element-prop value), and
10
- * `escapeTextOrMarkup` is a strict superset of `escapeText` for every
11
- * non-branded value — this pin's actual escaping behaviour for a plain
12
- * string is unchanged, only the call name changed to match the
13
- * REACTIVE side's existing `escapeTextOrNode` classification;
14
- * - a branch-slot expression (Child-position value inside a conditional
15
- * `template()` arrow) is routed through `__bfSlot` and must NOT be
16
- * wrapped in either escape call. `__bfSlot` returns raw
17
- * `<!--bf-slot:N-->` markers for live nodes; escaping the whole call
18
- * corrupts them and drops slotted content (the regression that broke
19
- * `e2e-site-ui`). `__bfSlot` escapes its own plain-string path
20
- * internally instead.
21
- */
22
-
23
- import { describe, test, expect } from 'bun:test'
24
- import { compileJSX } from '../compiler'
25
- import { TestAdapter } from '../adapters/test-adapter'
26
-
27
- const adapter = new TestAdapter()
28
-
29
- function getClientJs(source: string, filename: string): string {
30
- const result = compileJSX(source, filename, { adapter })
31
- expect(result.errors.filter(e => e.severity === 'error')).toHaveLength(0)
32
- const clientJs = result.files.find(f => f.type === 'clientJs')
33
- expect(clientJs).toBeDefined()
34
- return clientJs!.content
35
- }
36
-
37
- describe('text-slot escaping', () => {
38
- test('a plain text slot is wrapped in escapeTextOrMarkup (#2651)', () => {
39
- const clientJs = getClientJs(
40
- `'use client'
41
- export function Label({ text }: { text: string }) {
42
- return <span>{text}</span>
43
- }`,
44
- 'Label.tsx',
45
- )
46
- expect(clientJs).toMatch(/<!--bf:\w+-->\$\{escapeTextOrMarkup\(_p\.text\)\}<!--\/-->/)
47
- })
48
-
49
- test('a branch-slot expression is NOT wrapped in escapeTextOrMarkup or escapeText', () => {
50
- const clientJs = getClientJs(
51
- `'use client'
52
- import { createSignal } from '@barefootjs/client'
53
- export function Branch({ show }: { show: boolean }) {
54
- const [t] = createSignal('hi')
55
- return <div>{show ? <span>{t()}</span> : null}</div>
56
- }`,
57
- 'Branch.tsx',
58
- )
59
- // The branch value goes through __bfSlot (raw markers preserved)…
60
- expect(clientJs).toMatch(/\$\{__bfSlot\(/)
61
- // …and must never be double-wrapped by either text-escape call.
62
- expect(clientJs).not.toMatch(/escapeTextOrMarkup\(\s*__bfSlot/)
63
- expect(clientJs).not.toMatch(/escapeText\(\s*__bfSlot/)
64
- })
65
- })