@barefootjs/jsx 0.28.1 → 0.30.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/adapters/child-scope.d.ts +17 -0
  2. package/dist/adapters/child-scope.d.ts.map +1 -0
  3. package/dist/adapters/loop-bound-names.d.ts.map +1 -1
  4. package/dist/analyzer-context.d.ts.map +1 -1
  5. package/dist/analyzer.d.ts.map +1 -1
  6. package/dist/index.d.ts +1 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +890 -357
  9. package/dist/ir-to-client-js/collect-elements.d.ts +5 -25
  10. package/dist/ir-to-client-js/collect-elements.d.ts.map +1 -1
  11. package/dist/ir-to-client-js/control-flow/plan/build-lazy-row.d.ts +66 -2
  12. package/dist/ir-to-client-js/control-flow/plan/build-lazy-row.d.ts.map +1 -1
  13. package/dist/ir-to-client-js/control-flow/plan/build-reactive-effects.d.ts.map +1 -1
  14. package/dist/ir-to-client-js/control-flow/plan/lazy-conditional.d.ts +92 -0
  15. package/dist/ir-to-client-js/control-flow/plan/lazy-conditional.d.ts.map +1 -0
  16. package/dist/ir-to-client-js/control-flow/plan/lazy-preamble.d.ts +134 -0
  17. package/dist/ir-to-client-js/control-flow/plan/lazy-preamble.d.ts.map +1 -0
  18. package/dist/ir-to-client-js/control-flow/plan/lazy-row-eligibility.d.ts +46 -11
  19. package/dist/ir-to-client-js/control-flow/plan/lazy-row-eligibility.d.ts.map +1 -1
  20. package/dist/ir-to-client-js/control-flow/plan/reactive-effects.d.ts +7 -0
  21. package/dist/ir-to-client-js/control-flow/plan/reactive-effects.d.ts.map +1 -1
  22. package/dist/ir-to-client-js/control-flow/stringify/composite-loop.d.ts.map +1 -1
  23. package/dist/ir-to-client-js/control-flow/stringify/lazy-row.d.ts.map +1 -1
  24. package/dist/ir-to-client-js/control-flow/stringify/template-parse.d.ts +14 -0
  25. package/dist/ir-to-client-js/control-flow/stringify/template-parse.d.ts.map +1 -1
  26. package/dist/ir-to-client-js/csr-substitute.d.ts.map +1 -1
  27. package/dist/ir-to-client-js/html-template.d.ts +2 -3
  28. package/dist/ir-to-client-js/html-template.d.ts.map +1 -1
  29. package/dist/ir-to-client-js/imports.d.ts +2 -2
  30. package/dist/ir-to-client-js/imports.d.ts.map +1 -1
  31. package/dist/ir-to-client-js/plan/declaration-emit.d.ts +6 -0
  32. package/dist/ir-to-client-js/plan/declaration-emit.d.ts.map +1 -1
  33. package/dist/ir-to-client-js/reactivity.d.ts +1 -10
  34. package/dist/ir-to-client-js/reactivity.d.ts.map +1 -1
  35. package/dist/ir-to-client-js/types.d.ts +12 -0
  36. package/dist/ir-to-client-js/types.d.ts.map +1 -1
  37. package/dist/jsx-to-ir.d.ts.map +1 -1
  38. package/dist/rich-type-evidence.d.ts.map +1 -1
  39. package/dist/ssr-defaults.d.ts.map +1 -1
  40. package/dist/to-locale-date-lowering.d.ts.map +1 -1
  41. package/dist/types.d.ts +78 -0
  42. package/dist/types.d.ts.map +1 -1
  43. package/dist/value-references.d.ts +17 -4
  44. package/dist/value-references.d.ts.map +1 -1
  45. package/package.json +2 -2
  46. package/src/__tests__/__snapshots__/doc-examples.test.ts.snap +6 -24
  47. package/src/__tests__/branch-loop-plain.test.ts +28 -45
  48. package/src/__tests__/csr-substitution-safety-divergence.test.ts +9 -3
  49. package/src/__tests__/csr-template-scope-soundness.test.ts +96 -0
  50. package/src/__tests__/early-return-branch-switch.test.ts +96 -0
  51. package/src/__tests__/form-control-value-ssr.test.ts +102 -0
  52. package/src/__tests__/ir-to-client-js/imports.test.ts +18 -0
  53. package/src/__tests__/lazy-conditional.test.ts +190 -0
  54. package/src/__tests__/lazy-preamble.test.ts +297 -0
  55. package/src/__tests__/lazy-row-eligibility.test.ts +97 -28
  56. package/src/__tests__/loop-item-root-scope.test.ts +213 -0
  57. package/src/__tests__/loop-row-creation-paths.test.ts +169 -0
  58. package/src/__tests__/map-multi-return-body.test.ts +30 -3
  59. package/src/__tests__/nested-loop-conditional.test.ts +27 -6
  60. package/src/__tests__/preamble-attr-reactivity.test.ts +217 -0
  61. package/src/__tests__/preamble-declarations.test.ts +207 -0
  62. package/src/__tests__/ssr-defaults.test.ts +44 -0
  63. package/src/__tests__/value-references.test.ts +88 -0
  64. package/src/adapters/child-scope.ts +22 -0
  65. package/src/adapters/loop-bound-names.ts +6 -0
  66. package/src/analyzer-context.ts +43 -0
  67. package/src/analyzer.ts +33 -3
  68. package/src/index.ts +1 -0
  69. package/src/ir-to-client-js/collect-elements.ts +51 -10
  70. package/src/ir-to-client-js/control-flow/plan/build-branch-loop.ts +1 -1
  71. package/src/ir-to-client-js/control-flow/plan/build-composite-loop.ts +2 -2
  72. package/src/ir-to-client-js/control-flow/plan/build-event-delegation.ts +3 -3
  73. package/src/ir-to-client-js/control-flow/plan/build-inner-loop.ts +2 -2
  74. package/src/ir-to-client-js/control-flow/plan/build-lazy-row.ts +147 -5
  75. package/src/ir-to-client-js/control-flow/plan/build-loop.ts +2 -2
  76. package/src/ir-to-client-js/control-flow/plan/build-reactive-effects.ts +1 -0
  77. package/src/ir-to-client-js/control-flow/plan/lazy-conditional.ts +151 -0
  78. package/src/ir-to-client-js/control-flow/plan/lazy-preamble.ts +287 -0
  79. package/src/ir-to-client-js/control-flow/plan/lazy-row-eligibility.ts +85 -22
  80. package/src/ir-to-client-js/control-flow/plan/reactive-effects.ts +7 -0
  81. package/src/ir-to-client-js/control-flow/stringify/composite-loop.ts +4 -0
  82. package/src/ir-to-client-js/control-flow/stringify/lazy-row.ts +133 -35
  83. package/src/ir-to-client-js/control-flow/stringify/reactive-effects.ts +24 -4
  84. package/src/ir-to-client-js/control-flow/stringify/template-parse.ts +23 -4
  85. package/src/ir-to-client-js/csr-substitute.ts +6 -1
  86. package/src/ir-to-client-js/emit-registration.ts +1 -1
  87. package/src/ir-to-client-js/html-template.ts +51 -40
  88. package/src/ir-to-client-js/imports.ts +5 -0
  89. package/src/ir-to-client-js/index.ts +1 -1
  90. package/src/ir-to-client-js/plan/build-declaration-emit.ts +2 -0
  91. package/src/ir-to-client-js/plan/build-static-array-child-init.ts +1 -1
  92. package/src/ir-to-client-js/plan/declaration-emit.ts +6 -0
  93. package/src/ir-to-client-js/reactivity.ts +25 -0
  94. package/src/ir-to-client-js/stringify/declaration-emit.ts +9 -4
  95. package/src/ir-to-client-js/types.ts +12 -0
  96. package/src/jsx-to-ir.ts +400 -24
  97. package/src/rich-type-evidence.ts +6 -7
  98. package/src/ssr-defaults.ts +7 -2
  99. package/src/to-locale-date-lowering.ts +8 -2
  100. package/src/types.ts +80 -0
  101. package/src/value-references.ts +26 -4
package/src/types.ts CHANGED
@@ -60,6 +60,13 @@ export interface TypeInfo {
60
60
  // For primitives
61
61
  primitive?: 'string' | 'number' | 'boolean' | 'null' | 'undefined'
62
62
 
63
+ /** Set when the type is a LITERAL of its primitive family (`'a'`, `42`,
64
+ * `true`) — the literal's source value. `typeNodeToTypeInfo` lowers a
65
+ * literal type to `kind: 'primitive'` + this field, so family-only
66
+ * consumers need no special case and value consumers never re-parse
67
+ * `raw`. */
68
+ literalValue?: string
69
+
63
70
  // For objects/interfaces
64
71
  properties?: PropertyInfo[]
65
72
 
@@ -854,6 +861,28 @@ export interface MapCallbackPreamble {
854
861
  ssrText: TsxSourceText
855
862
  /** const/let/function names the preamble declares (D5 key-derivability guard). */
856
863
  declaredNames: string[]
864
+ /**
865
+ * The whole preamble as backend-neutral value declarations — set only when
866
+ * EVERY statement is one (#2447). This is the DSL SSR carrier: a template
867
+ * language cannot execute `segments` (that is JS text, for the client bundle
868
+ * and for JS-runtime SSR), but it CAN declare a per-row local, and each
869
+ * declaration's initializer is a {@link ParsedExpr} every adapter already
870
+ * knows how to emit in its own syntax — the same door `arrayParsed` /
871
+ * `filterPredicate.predicate` / `sortComparator` go through.
872
+ *
873
+ * All-or-nothing on purpose. A preamble is a statement SEQUENCE with
874
+ * order-dependent scope; lowering the declarable prefix and dropping the rest
875
+ * would leave later statements' effects missing with no diagnostic — the
876
+ * silent divergence #2447 was. So one non-declaration statement (an
877
+ * assignment, a loop, a call for side effects) or one initializer the
878
+ * expression subset cannot model leaves this `undefined`, and the Phase-1
879
+ * DSL gate refuses the whole loop with `/* @client *\/` guidance.
880
+ *
881
+ * Declarations appear in source order and may read earlier ones; adapters
882
+ * emit them in order, so an earlier local is in scope for a later
883
+ * initializer, exactly as in the source.
884
+ */
885
+ declarations?: PreambleValueDeclaration[]
857
886
  /**
858
887
  * The subset of {@link declaredNames} that accumulate JSX leaves — the
859
888
  * `push`/`unshift` targets of a `jsx` segment and the declaration targets of
@@ -864,6 +893,25 @@ export interface MapCallbackPreamble {
864
893
  builderNames: string[]
865
894
  }
866
895
 
896
+ /**
897
+ * One `const`/`let` value declaration from a `.map()` callback preamble, in
898
+ * backend-neutral form (#2447 — see {@link MapCallbackPreamble.declarations}).
899
+ * `name` is always a simple identifier: a destructuring binding declares
900
+ * several names from one initializer, which no adapter has a single per-row
901
+ * local form for, so that shape refuses instead of being carried here.
902
+ */
903
+ export interface PreambleValueDeclaration {
904
+ /** Declared local name (simple identifier binding). */
905
+ name: string
906
+ /** Initializer, structured for per-adapter emission. */
907
+ valueParsed: ParsedExpr
908
+ /**
909
+ * Initializer source text, for a diagnostic that needs to quote it. Never an
910
+ * emission input — emission goes through `valueParsed`.
911
+ */
912
+ raw: string
913
+ }
914
+
867
915
  /**
868
916
  * One loop-body expression child classified as a preamble-patched region
869
917
  * (#2389 — see `IRLoop.preambleRegions`). `expr` is the raw (unwrapped)
@@ -1002,6 +1050,20 @@ export interface IRComponent {
1002
1050
  * Omitted (undefined) for ordinary components to keep IR diffs minimal.
1003
1051
  */
1004
1052
  dynamicTag?: boolean
1053
+ /**
1054
+ * True when this component is a DIRECT member of an `IRLoop.children`
1055
+ * array (the loop's row-root component, e.g. `{rows().map(r => <Row/>)}`).
1056
+ * Such a component owns its own per-row identity and gets a freshly
1057
+ * randomized `bf-s` — it does NOT derive its scope id from the parent
1058
+ * scope + mount slot the way an ordinarily-slotted child does.
1059
+ *
1060
+ * A component nested *below* the row root (e.g. `<li><Badge/></li>` where
1061
+ * `<li>` is the loop row root) is NOT marked — it derives its scope id
1062
+ * from parent scope + slot like any other slotted child. See
1063
+ * `derivesScopeFromSlot` in `./adapters/child-scope.ts`, which is the one
1064
+ * predicate every backend must consult instead of re-deriving this fact.
1065
+ */
1066
+ loopItemRoot?: boolean
1005
1067
  loc: SourceLocation
1006
1068
  }
1007
1069
 
@@ -1399,6 +1461,15 @@ export interface SignalInfo {
1399
1461
  * AST-level pre-rewrite).
1400
1462
  */
1401
1463
  templateInitialValue?: string
1464
+ /**
1465
+ * True for the getter-elided declaration form `const [, setX] =
1466
+ * createSignal(...)`. `getter` then holds a synthesized internal name
1467
+ * (`__bfGet_<setter>`) that no expression ever references — it exists so
1468
+ * getter-keyed consumers (substitution env, SSR seeding) stay total.
1469
+ * Emit reproduces the source's `[, setter]` hole instead of introducing
1470
+ * the synthesized name into output.
1471
+ */
1472
+ getterElided?: boolean
1402
1473
  type: TypeInfo
1403
1474
  loc: SourceLocation
1404
1475
  /**
@@ -1458,6 +1529,15 @@ export interface SignalInfo {
1458
1529
  export interface MemoInfo {
1459
1530
  name: string
1460
1531
  computation: string
1532
+ /**
1533
+ * `computation` with bare destructured-prop refs rewritten to `_p.X` —
1534
+ * the memo twin of `SignalInfo.templateInitialValue` (#2265). Consumed by
1535
+ * `buildSignalMemoEnv` when the memo body is inlined into the module-scope
1536
+ * CSR `template:` arrow, which is not a closure over init's destructured
1537
+ * extractions (#2468). Only set for destructured-arg components that
1538
+ * actually reference a prop.
1539
+ */
1540
+ templateComputation?: string
1461
1541
  /** Computation with TypeScript type annotations preserved, for .tsx output */
1462
1542
  typedComputation?: string
1463
1543
  /**
@@ -26,13 +26,26 @@ import ts from 'typescript'
26
26
  * A ShorthandPropertyAssignment (`{ Theme }`) intentionally counts as a
27
27
  * reference — it reads the binding, it doesn't just spell its name.
28
28
  *
29
+ * CONTRACT: this classifies identifier positions in **JavaScript** source.
30
+ * Both current callers parse with `ts.ScriptKind.JS` —
31
+ * `collectValueReferencedNames` below, and `detectStrippedReferences` in
32
+ * `packages/cli/src/lib/resolve-imports.ts`, which parses the assembled
33
+ * bundle. TypeScript-only positions are deliberately NOT handled: an
34
+ * identifier in a type position (`const x: Foo = …`, a
35
+ * `TypeReferenceNode`) is still reported as a value reference, and so are
36
+ * `interface` / `type` / `enum` declaration names. Do not point this at
37
+ * TypeScript source — it would over-report there.
38
+ *
29
39
  * Caveat: this is a syntactic test, not a scope analysis. If a local
30
40
  * function parameter happens to share a name with an imported binding,
31
41
  * references inside that function's body will count as references to
32
- * the import (false positive). Acceptable: over-counting a reference
33
- * just means we keep an import we didn't strictly need, which is a
34
- * strict improvement over the alternative failure direction (dropping a
35
- * needed import and producing a `ReferenceError`).
42
+ * the import (false positive). For the import-emission caller
43
+ * (`makeValueUsageTest` in `ir-to-client-js/imports.ts`), over-counting is
44
+ * the safe direction an extra import whose binding exists is harmless.
45
+ * It is NOT safe for the BF053 caller (`detectStrippedReferences`): there,
46
+ * an over-reported reference to a stripped binding is a false build
47
+ * error on legal code. That asymmetry is why every exclusion branch below
48
+ * matters — each one is a case that would otherwise misfire BF053.
36
49
  */
37
50
  export function isValueReferenceIdentifier(id: ts.Identifier): boolean {
38
51
  const parent = id.parent
@@ -47,6 +60,15 @@ export function isValueReferenceIdentifier(id: ts.Identifier): boolean {
47
60
  ) {
48
61
  return false
49
62
  }
63
+ // Class field name (`class C { helper = 1 }`, including `static helper
64
+ // = 1`): the name is a member key, not a read. The `parent.name === id`
65
+ // guard is what preserves the computed case — in `class C { [helper] =
66
+ // 1 }` the name is a ComputedPropertyName, not `id` itself, so `helper`
67
+ // (inside the brackets) still falls through and counts as a reference.
68
+ if (ts.isPropertyDeclaration(parent) && parent.name === id) return false
69
+ // `new.target` / `import.meta`: `target`/`meta` sits in keyword
70
+ // position, not a binding.
71
+ if (ts.isMetaProperty(parent) && parent.name === id) return false
50
72
  if (ts.isVariableDeclaration(parent) && parent.name === id) return false
51
73
  if (ts.isFunctionDeclaration(parent) && parent.name === id) return false
52
74
  if (ts.isFunctionExpression(parent) && parent.name === id) return false