@barefootjs/jsx 0.33.2 → 0.33.4
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/analyzer.d.ts +17 -0
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/compiler.d.ts +21 -5
- package/dist/compiler.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +804 -445
- package/dist/ir-to-client-js/build-references.d.ts.map +1 -1
- package/dist/ir-to-client-js/collect-elements.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/plan/build-component-loop.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/plan/loop.d.ts +2 -4
- package/dist/ir-to-client-js/control-flow/plan/loop.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/stringify/component-loop.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow/stringify/loop-child-arm.d.ts.map +1 -1
- package/dist/ir-to-client-js/control-flow.d.ts.map +1 -1
- package/dist/ir-to-client-js/html-template.d.ts.map +1 -1
- package/dist/ir-to-client-js/imports.d.ts +60 -2
- package/dist/ir-to-client-js/imports.d.ts.map +1 -1
- package/dist/ir-to-client-js/prop-handling.d.ts +4 -7
- package/dist/ir-to-client-js/prop-handling.d.ts.map +1 -1
- package/dist/ir-to-client-js/utils.d.ts +26 -2
- package/dist/ir-to-client-js/utils.d.ts.map +1 -1
- package/dist/jsx-to-ir.d.ts.map +1 -1
- package/dist/props-binding.d.ts +35 -0
- package/dist/props-binding.d.ts.map +1 -1
- package/dist/types.d.ts +63 -13
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/__snapshots__/doc-examples.test.ts.snap +145 -97
- package/src/__tests__/child-component-ref-not-mirrored.test.ts +90 -0
- package/src/__tests__/fragment-body-loop-key.test.ts +95 -0
- package/src/__tests__/ir-to-client-js/imports.test.ts +107 -0
- package/src/__tests__/ir-to-client-js/merge-compiled-client-js-imports.test.ts +138 -0
- package/src/__tests__/issue-2754-rest-spread-needs-slot.test.ts +85 -0
- package/src/__tests__/issue-2756-loop-row-honors-client-only.test.ts +173 -0
- package/src/__tests__/merge-template-imports.test.ts +41 -1
- package/src/__tests__/multi-component-shared-default-import.test.ts +55 -0
- package/src/__tests__/multi-root-loop-body.test.ts +7 -3
- package/src/__tests__/preamble-declarations.test.ts +42 -0
- package/src/__tests__/root-key-relay.test.ts +170 -0
- package/src/__tests__/signal-getter-not-called.test.ts +149 -0
- package/src/__tests__/state-only-file-default-import.test.ts +47 -0
- package/src/analyzer.ts +36 -0
- package/src/compiler.ts +94 -104
- package/src/index.ts +1 -1
- package/src/ir-to-client-js/build-references.ts +7 -0
- package/src/ir-to-client-js/collect-elements.ts +27 -5
- package/src/ir-to-client-js/control-flow/plan/build-component-loop.ts +19 -1
- package/src/ir-to-client-js/control-flow/plan/loop.ts +2 -4
- package/src/ir-to-client-js/control-flow/stringify/component-loop.ts +7 -0
- package/src/ir-to-client-js/control-flow/stringify/inner-loop.ts +6 -2
- package/src/ir-to-client-js/control-flow/stringify/loop-child-arm.ts +5 -2
- package/src/ir-to-client-js/control-flow.ts +12 -0
- package/src/ir-to-client-js/html-template.ts +174 -23
- package/src/ir-to-client-js/imports.ts +178 -5
- package/src/ir-to-client-js/index.ts +5 -0
- package/src/ir-to-client-js/prop-handling.ts +6 -17
- package/src/ir-to-client-js/utils.ts +30 -2
- package/src/jsx-to-ir.ts +592 -58
- package/src/props-binding.ts +51 -0
- package/src/types.ts +60 -13
package/src/props-binding.ts
CHANGED
|
@@ -68,3 +68,54 @@ export function buildPropAliasMap(params: readonly ParamInfo[]): Map<string, str
|
|
|
68
68
|
}
|
|
69
69
|
return map
|
|
70
70
|
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The two component bindings that forward the caller's leftover props:
|
|
74
|
+
* the destructured `...rest` binding and a whole undestructured `(props)`
|
|
75
|
+
* parameter. Both phases carry these names — the analyzer context in
|
|
76
|
+
* Phase 1, the client-JS context in Phase 2 — so the resolver below takes
|
|
77
|
+
* them as data rather than binding to either context type.
|
|
78
|
+
*/
|
|
79
|
+
export interface RestSpreadBindings {
|
|
80
|
+
restPropsName: string | null
|
|
81
|
+
propsObjectName: string | null
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Which of `bindings` the name `name` ultimately reaches, walking through
|
|
86
|
+
* any bare `const x__alias = <name>` hop recorded in `constantValues`
|
|
87
|
+
* (name → initializer text). `'rest'` for the destructured rest binding,
|
|
88
|
+
* `'props'` for the whole props object, `null` for anything else.
|
|
89
|
+
*
|
|
90
|
+
* The single definition of "this `{...spread}` forwards the caller's
|
|
91
|
+
* leftover props", shared by the two phases that must agree on it: Phase 1
|
|
92
|
+
* decides whether the host element gets a slot id (#2754 — without one the
|
|
93
|
+
* spread has no client-side patch point at all, so a pure CSR mount drops
|
|
94
|
+
* every caller-supplied attribute), and Phase 2 decides whether to route
|
|
95
|
+
* the spread to `applyRestAttrs` and filter it out of the template's
|
|
96
|
+
* `spreadAttrs({...})` merge. Two copies of the rule would let an element
|
|
97
|
+
* qualify for one and not the other, which is exactly the silent-drop
|
|
98
|
+
* shape #2754 reports.
|
|
99
|
+
*
|
|
100
|
+
* Walks hop by hop (not a precomputed set) so a multi-hop alias
|
|
101
|
+
* (`const p2 = props; const p3 = p2`) resolves through every link;
|
|
102
|
+
* `visited` guards a constant cycle (`const a = b; const b = a`). A
|
|
103
|
+
* constant whose value isn't a bare identifier on the chain (a real
|
|
104
|
+
* computed object) stops the walk, so a genuinely different spread
|
|
105
|
+
* expression is never mistaken for the rest object.
|
|
106
|
+
*/
|
|
107
|
+
export function resolveRestSpreadOriginCore(
|
|
108
|
+
bindings: RestSpreadBindings,
|
|
109
|
+
constantValues: ReadonlyMap<string, string | undefined>,
|
|
110
|
+
name: string,
|
|
111
|
+
): 'rest' | 'props' | null {
|
|
112
|
+
const visited = new Set<string>()
|
|
113
|
+
let current: string | undefined = name.trim()
|
|
114
|
+
while (current !== undefined && !visited.has(current)) {
|
|
115
|
+
if (bindings.restPropsName && current === bindings.restPropsName) return 'rest'
|
|
116
|
+
if (bindings.propsObjectName && current === bindings.propsObjectName) return 'props'
|
|
117
|
+
visited.add(current)
|
|
118
|
+
current = constantValues.get(current)?.trim()
|
|
119
|
+
}
|
|
120
|
+
return null
|
|
121
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -348,19 +348,43 @@ export interface IRElement {
|
|
|
348
348
|
slotId: string | null
|
|
349
349
|
needsScope: boolean
|
|
350
350
|
/**
|
|
351
|
-
*
|
|
352
|
-
*
|
|
353
|
-
*
|
|
354
|
-
*
|
|
355
|
-
*
|
|
356
|
-
*
|
|
357
|
-
*
|
|
358
|
-
*
|
|
359
|
-
*
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
|
|
363
|
-
|
|
351
|
+
* The row-key attribute this element carries, resolved ONCE here instead
|
|
352
|
+
* of independently by 16 emit sites (#2753 root-cause: the client
|
|
353
|
+
* runtime's `mapArray` stamping an index key onto unkeyed rows SSR never
|
|
354
|
+
* emits, and disagreeing with SSR's depth-suffixed name on nested rows —
|
|
355
|
+
* see that issue for the two measured shapes). Replaces the `carriesDataKey`
|
|
356
|
+
* boolean (#2732/#2744): a boolean was a degenerate encoding of the same
|
|
357
|
+
* decision — "does this element get a key attribute, and what is it
|
|
358
|
+
* called" — that still left the VALUE and the depth-derived NAME to be
|
|
359
|
+
* re-derived by every adapter (a mutable stack in Hono, a
|
|
360
|
+
* `currentLoopKeyDepth` field in every DSL adapter) and by the client
|
|
361
|
+
* runtime. Absent means "this element carries no key attribute" — the
|
|
362
|
+
* correct, final answer for an unkeyed loop's row, not a hint adapters
|
|
363
|
+
* still have to gate further.
|
|
364
|
+
*
|
|
365
|
+
* Two disjoint sources, both resolved at IR-build time
|
|
366
|
+
* (`resolveKeyAttrs`/loop construction in `jsx-to-ir.ts`):
|
|
367
|
+
*
|
|
368
|
+
* - `value` present: this element is DIRECTLY a `.map()` row root
|
|
369
|
+
* compiled inline in this same component (`IRLoop.key`/`.depth`
|
|
370
|
+
* already resolved the expression and nesting depth) — adapters lower
|
|
371
|
+
* `value` exactly like any other attribute-value expression.
|
|
372
|
+
* - `value` absent: this element is one of the component's own possible
|
|
373
|
+
* render roots (a plain element/if-statement-branch root, or — when
|
|
374
|
+
* `needsScope` is false because hydration markers moved to a wrapping
|
|
375
|
+
* `<!--bf-scope:...-->` comment (#2732) — the first eligible element
|
|
376
|
+
* of a `needsScopeComment` fragment root) that RELAYS a key an
|
|
377
|
+
* external caller supplies at runtime, when THIS component is itself
|
|
378
|
+
* invoked as a caller's keyed loop row (the `data-key` prop / Rust
|
|
379
|
+
* `bf.data_key` field, or client `createComponent`'s `key` argument).
|
|
380
|
+
* There is no local expression to lower here, only a name.
|
|
381
|
+
*
|
|
382
|
+
* "First element, not first node" (for the fragment-root shape) mirrors
|
|
383
|
+
* the CSR runtime's own resolution of the identical ambiguity
|
|
384
|
+
* (`component.ts`'s `roots.find(isElement)`, #2735) rather than inventing
|
|
385
|
+
* a second answer.
|
|
386
|
+
*/
|
|
387
|
+
keyAttr?: { name: string; value?: string }
|
|
364
388
|
/**
|
|
365
389
|
* Page-lifecycle boundary id for an element lowered from `<Region>`
|
|
366
390
|
* (spec/router.md). Set only on region host elements; adapters emit it as
|
|
@@ -382,6 +406,16 @@ export interface IRExpression {
|
|
|
382
406
|
expr: string
|
|
383
407
|
/** Pre-transformed expr with destructured prop refs rewritten to _p.xxx (for client JS templates). */
|
|
384
408
|
templateExpr?: string
|
|
409
|
+
/**
|
|
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`).
|
|
417
|
+
*/
|
|
418
|
+
escapeInClientTemplate?: boolean
|
|
385
419
|
/**
|
|
386
420
|
* Structured parse of `expr` (`parseExpression(expr.trim())`), attached once
|
|
387
421
|
* during IR construction so SSR adapters emit from the tree instead of each
|
|
@@ -902,6 +936,19 @@ export interface MapCallbackPreamble {
|
|
|
902
936
|
* expression subset cannot model leaves this `undefined`, and the Phase-1
|
|
903
937
|
* DSL gate refuses the whole loop with `/* @client *\/` guidance.
|
|
904
938
|
*
|
|
939
|
+
* ONE exception (#2797): a declaration whose initializer is a function
|
|
940
|
+
* literal is ELIDED (contributes no entry here) rather than refusing the
|
|
941
|
+
* preamble, when EVERY read of that name outside its own binding sits
|
|
942
|
+
* inside an event-handler `JsxAttribute` (`/^on[A-Z]/`) value position —
|
|
943
|
+
* see `neutralPreambleDeclarations`'s `everyReadIsEventHandlerPropValue`
|
|
944
|
+
* check. Every DSL adapter's own SSR component-prop builder already skips
|
|
945
|
+
* an event-handler prop outright, so a name read only that way never needs
|
|
946
|
+
* an SSR representation; the client-JS preamble (`segments`) still carries
|
|
947
|
+
* the real closure. This can leave `declarations` a legally EMPTY array
|
|
948
|
+
* (all-declared names elided) rather than `undefined` — the Phase-1 gate
|
|
949
|
+
* checks falsiness, and `[]` is truthy, so an empty array reads as "fully
|
|
950
|
+
* declared, nothing to emit," not a refusal.
|
|
951
|
+
*
|
|
905
952
|
* Declarations appear in source order and may read earlier ones; adapters
|
|
906
953
|
* emit them in order, so an earlier local is in scope for a later
|
|
907
954
|
* initializer, exactly as in the source.
|