@barefootjs/xslate 0.31.9 → 0.32.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.
- package/dist/adapter/index.js +5 -1
- package/dist/adapter/memo/seed.d.ts +13 -7
- package/dist/adapter/memo/seed.d.ts.map +1 -1
- package/dist/index.js +10 -2
- package/dist/render-divergences.d.ts.map +1 -1
- package/dist/vite.js +40 -3
- package/lib/BarefootJS/Backend/Xslate.pm +1 -1
- package/package.json +5 -5
- package/src/__tests__/xslate-adapter.test.ts +7 -4
- package/src/adapter/memo/seed.ts +28 -8
- package/src/render-divergences.ts +13 -0
- package/src/test-render.ts +9 -10
package/dist/adapter/index.js
CHANGED
|
@@ -188198,8 +188198,12 @@ function generateDerivedMemoSeed(ctx, ir) {
|
|
|
188198
188198
|
const kolon = ctx.convertExpressionToKolon(step.expr, step.parsed);
|
|
188199
188199
|
if (kolon === "" || !/\$[A-Za-z_]\w*/.test(kolon))
|
|
188200
188200
|
continue;
|
|
188201
|
-
if (new RegExp(`\\$${step.name}\\b`).test(kolon))
|
|
188201
|
+
if (new RegExp(`\\$${step.name}\\b`).test(kolon)) {
|
|
188202
|
+
const tmp = `__bf_seed_${step.name}`;
|
|
188203
|
+
lines.push(`: my $${tmp} = ${kolon};`);
|
|
188204
|
+
lines.push(`: my $${step.name} = $${tmp};`);
|
|
188202
188205
|
continue;
|
|
188206
|
+
}
|
|
188203
188207
|
lines.push(`: my $${step.name} = ${kolon};`);
|
|
188204
188208
|
}
|
|
188205
188209
|
return lines.length > 0 ? lines.join(`
|
|
@@ -26,13 +26,19 @@ export declare function generateContextConsumerSeed(ir: ComponentIR): string;
|
|
|
26
26
|
* backend-specific emit guards: skip an empty lowering, skip a lowering that
|
|
27
27
|
* references no `$var` at all (a constant init/body — e.g. a `derived` step
|
|
28
28
|
* with empty `frees` — keeps the existing static ssr-defaults seed instead),
|
|
29
|
-
* and
|
|
30
|
-
* `: my $x = … $x …` would read the just-declared
|
|
31
|
-
* than the render var — the plan rules out
|
|
32
|
-
* lowered canonical name could still collide,
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
29
|
+
* and capture-before-shadow a self-referencing lowering (Kolon's `my`
|
|
30
|
+
* shadows the RHS, so `: my $x = … $x …` would read the just-declared
|
|
31
|
+
* undefined lexical rather than the render var — the plan rules out
|
|
32
|
+
* SOURCE-level self-refs, but a lowered canonical name could still collide,
|
|
33
|
+
* e.g. `createMemo(() => props.size ?? 'icon')` lowers `props.size` straight
|
|
34
|
+
* to the stash var `$size`, colliding with the memo's own name). The
|
|
35
|
+
* self-referencing case still emits the SAME verbatim Kolon — nothing about
|
|
36
|
+
* `kolon` changes — just as the RHS of a throwaway `__bf_seed_*` local
|
|
37
|
+
* declared BEFORE `$<name>` is shadowed, so `$<name>` inside `kolon` still
|
|
38
|
+
* resolves to the stash var, not the fresh lexical; a second statement then
|
|
39
|
+
* binds the real name off the already-evaluated capture. `env-reader` and
|
|
40
|
+
* `opaque` steps emit nothing (the runtime supplies the reader, or the
|
|
41
|
+
* adapter's ssr-defaults path already covers it). (#1297, #2075, #2679)
|
|
36
42
|
*/
|
|
37
43
|
export declare function generateDerivedMemoSeed(ctx: XslateMemoContext, ir: ComponentIR): string;
|
|
38
44
|
//# sourceMappingURL=seed.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../../../src/adapter/memo/seed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,eAAe,EAGrB,MAAM,iBAAiB,CAAA;AAExB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAE3D,sEAAsE;AACtE,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,eAAe,GAAG,MAAM,CAM9D;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,EAAE,EAAE,WAAW,GAAG,MAAM,CAWnE;AAED
|
|
1
|
+
{"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../../../src/adapter/memo/seed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,eAAe,EAGrB,MAAM,iBAAiB,CAAA;AAExB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAE3D,sEAAsE;AACtE,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,eAAe,GAAG,MAAM,CAM9D;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,EAAE,EAAE,WAAW,GAAG,MAAM,CAWnE;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,iBAAiB,EAAE,EAAE,EAAE,WAAW,GAAG,MAAM,CA4BvF"}
|
package/dist/index.js
CHANGED
|
@@ -188198,8 +188198,12 @@ function generateDerivedMemoSeed(ctx, ir) {
|
|
|
188198
188198
|
const kolon = ctx.convertExpressionToKolon(step.expr, step.parsed);
|
|
188199
188199
|
if (kolon === "" || !/\$[A-Za-z_]\w*/.test(kolon))
|
|
188200
188200
|
continue;
|
|
188201
|
-
if (new RegExp(`\\$${step.name}\\b`).test(kolon))
|
|
188201
|
+
if (new RegExp(`\\$${step.name}\\b`).test(kolon)) {
|
|
188202
|
+
const tmp = `__bf_seed_${step.name}`;
|
|
188203
|
+
lines.push(`: my $${tmp} = ${kolon};`);
|
|
188204
|
+
lines.push(`: my $${step.name} = $${tmp};`);
|
|
188202
188205
|
continue;
|
|
188206
|
+
}
|
|
188203
188207
|
lines.push(`: my $${step.name} = ${kolon};`);
|
|
188204
188208
|
}
|
|
188205
188209
|
return lines.length > 0 ? lines.join(`
|
|
@@ -189187,7 +189191,11 @@ var conformancePins = {
|
|
|
189187
189191
|
"rich-prop-client-read": [{ code: "BF049", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2648" }]
|
|
189188
189192
|
};
|
|
189189
189193
|
// src/render-divergences.ts
|
|
189190
|
-
var renderDivergences = {
|
|
189194
|
+
var renderDivergences = {
|
|
189195
|
+
"todo-app": "the `todos` signal seeds from `(props.initialTodos ?? []).map(t => ({ ...t, editing: false }))` — a different-prop-derived `.map()` chain `extractSsrDefaults` cannot statically resolve, and `computeSsrSeedPlan` classifies it opaque (no in-template recompute), so it seeds `undef`; the non-`/* @client */`-marked `{todos().length > 0 && ...}` toggle-all block SSRs as if there are zero todos regardless of `initialTodos` (https://github.com/piconic-ai/barefootjs/issues/2696)",
|
|
189196
|
+
"todo-app-ssr": "same root cause as `todo-app` (https://github.com/piconic-ai/barefootjs/issues/2696); this fixture's todo-list loop carries no `/* @client */` marker, but Kolon's `for` iterates an undef list as empty rather than raising, so it SSRs an empty `<ul class=\"todo-list\">` with the toggle-all controls also absent, regardless of `initialTodos`",
|
|
189197
|
+
"callback-param-shadows-prop": "the `first` signal seeds from `[{ a: 'p' }].map((title) => title.a).join(',')` — a constant expression `extractSsrDefaults` still cannot statically resolve (`.map()` is unsupported for any receiver) and, unlike the sibling `joined` memo's structurally similar chain, gets no in-template recompute (`computeSsrSeedPlan` classifies it opaque too); `<span>{first()}</span>` SSRs empty instead of `p` (https://github.com/piconic-ai/barefootjs/issues/2696)"
|
|
189198
|
+
};
|
|
189191
189199
|
export {
|
|
189192
189200
|
xslateAdapter,
|
|
189193
189201
|
renderDivergences,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AASxD,eAAO,MAAM,iBAAiB,EAAE,iBAO/B,CAAA"}
|
package/dist/vite.js
CHANGED
|
@@ -3916,6 +3916,38 @@ function classify(name, origin, expr, parsed, available) {
|
|
|
3916
3916
|
}
|
|
3917
3917
|
return { kind: "derived", name, origin, expr, parsed, frees: [...frees] };
|
|
3918
3918
|
}
|
|
3919
|
+
function localConstExprsByName(metadata) {
|
|
3920
|
+
const out = new Map;
|
|
3921
|
+
for (const c of metadata.localConstants ?? []) {
|
|
3922
|
+
if (c.isModule || c.declarationKind !== "const" || c.value === undefined)
|
|
3923
|
+
continue;
|
|
3924
|
+
out.set(c.name, c.parsed ?? parseExpression(c.value.trim()));
|
|
3925
|
+
}
|
|
3926
|
+
return out;
|
|
3927
|
+
}
|
|
3928
|
+
function resolveThroughLocalConsts(parsed, localConsts) {
|
|
3929
|
+
let current = parsed;
|
|
3930
|
+
const maxIter = localConsts.size + 1;
|
|
3931
|
+
for (let i = 0;i < maxIter; i++) {
|
|
3932
|
+
const frees = freeIdentifiers(current);
|
|
3933
|
+
if (frees === null)
|
|
3934
|
+
break;
|
|
3935
|
+
let changed = false;
|
|
3936
|
+
for (const name of frees) {
|
|
3937
|
+
const value = localConsts.get(name);
|
|
3938
|
+
if (!value)
|
|
3939
|
+
continue;
|
|
3940
|
+
const inlined = inlineBinding(current, name, value);
|
|
3941
|
+
if (inlined === null)
|
|
3942
|
+
continue;
|
|
3943
|
+
current = inlined;
|
|
3944
|
+
changed = true;
|
|
3945
|
+
}
|
|
3946
|
+
if (!changed)
|
|
3947
|
+
break;
|
|
3948
|
+
}
|
|
3949
|
+
return current;
|
|
3950
|
+
}
|
|
3919
3951
|
function computeSsrSeedPlan(metadata) {
|
|
3920
3952
|
const baseScope = metadata.propsParams.map((p) => p.name);
|
|
3921
3953
|
if (metadata.propsObjectName)
|
|
@@ -3924,6 +3956,7 @@ function computeSsrSeedPlan(metadata) {
|
|
|
3924
3956
|
baseScope.push(name);
|
|
3925
3957
|
}
|
|
3926
3958
|
const available = new Set(baseScope);
|
|
3959
|
+
const localConsts = localConstExprsByName(metadata);
|
|
3927
3960
|
const steps = [];
|
|
3928
3961
|
for (const signal of metadata.signals) {
|
|
3929
3962
|
if (signal.envReader) {
|
|
@@ -3935,13 +3968,13 @@ function computeSsrSeedPlan(metadata) {
|
|
|
3935
3968
|
}
|
|
3936
3969
|
}
|
|
3937
3970
|
const expr = signal.initialValue.trim();
|
|
3938
|
-
steps.push(expr === "" ? { kind: "opaque", name: signal.getter, origin: "signal" } : classify(signal.getter, "signal", expr, parseExpression(expr), available));
|
|
3971
|
+
steps.push(expr === "" ? { kind: "opaque", name: signal.getter, origin: "signal" } : classify(signal.getter, "signal", expr, resolveThroughLocalConsts(parseExpression(expr), localConsts), available));
|
|
3939
3972
|
available.add(signal.getter);
|
|
3940
3973
|
}
|
|
3941
3974
|
for (const memo of metadata.memos) {
|
|
3942
3975
|
const body = extractArrowBodyExpression(memo.computation);
|
|
3943
3976
|
const expr = body?.trim() ?? "";
|
|
3944
|
-
steps.push(expr === "" ? { kind: "opaque", name: memo.name, origin: "memo" } : classify(memo.name, "memo", expr, memo.parsed ?? parseExpression(expr), available));
|
|
3977
|
+
steps.push(expr === "" ? { kind: "opaque", name: memo.name, origin: "memo" } : classify(memo.name, "memo", expr, resolveThroughLocalConsts(memo.parsed ?? parseExpression(expr), localConsts), available));
|
|
3945
3978
|
available.add(memo.name);
|
|
3946
3979
|
}
|
|
3947
3980
|
return { baseScope, steps };
|
|
@@ -6004,8 +6037,12 @@ function generateDerivedMemoSeed(ctx, ir) {
|
|
|
6004
6037
|
const kolon = ctx.convertExpressionToKolon(step.expr, step.parsed);
|
|
6005
6038
|
if (kolon === "" || !/\$[A-Za-z_]\w*/.test(kolon))
|
|
6006
6039
|
continue;
|
|
6007
|
-
if (new RegExp(`\\$${step.name}\\b`).test(kolon))
|
|
6040
|
+
if (new RegExp(`\\$${step.name}\\b`).test(kolon)) {
|
|
6041
|
+
const tmp = `__bf_seed_${step.name}`;
|
|
6042
|
+
lines.push(`: my $${tmp} = ${kolon};`);
|
|
6043
|
+
lines.push(`: my $${step.name} = $${tmp};`);
|
|
6008
6044
|
continue;
|
|
6045
|
+
}
|
|
6009
6046
|
lines.push(`: my $${step.name} = ${kolon};`);
|
|
6010
6047
|
}
|
|
6011
6048
|
return lines.length > 0 ? lines.join(`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/xslate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.0",
|
|
4
4
|
"description": "Text::Xslate (Kolon) adapter for BarefootJS — compiles IR to .tx templates and ships the Xslate rendering backend; runs under any PSGI/Plack app",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"directory": "packages/adapter-xslate"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@barefootjs/shared": "0.
|
|
58
|
+
"@barefootjs/shared": "0.32.0"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
61
|
"@barefootjs/jsx": ">=0.2.0",
|
|
@@ -72,9 +72,9 @@
|
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
74
|
"@barefootjs/adapter-tests": "0.1.0",
|
|
75
|
-
"@barefootjs/jsx": "0.
|
|
76
|
-
"@barefootjs/vite": "0.
|
|
77
|
-
"@barefootjs/client": "0.
|
|
75
|
+
"@barefootjs/jsx": "0.32.0",
|
|
76
|
+
"@barefootjs/vite": "0.32.0",
|
|
77
|
+
"@barefootjs/client": "0.32.0",
|
|
78
78
|
"typescript": "^5.0.0",
|
|
79
79
|
"vite": "^6.0.0"
|
|
80
80
|
}
|
|
@@ -199,9 +199,11 @@ export function Item(props: { defaultOn?: boolean }) {
|
|
|
199
199
|
expect(template).toContain(': my $on = ($defaultOn // 0);')
|
|
200
200
|
})
|
|
201
201
|
|
|
202
|
-
// Kolon can't `: my $x = … $x
|
|
203
|
-
//
|
|
204
|
-
|
|
202
|
+
// Kolon can't `: my $x = … $x …` directly (the declaration shadows the
|
|
203
|
+
// RHS's own reference), so a same-name signal captures the lowered
|
|
204
|
+
// expression into a throwaway `__bf_seed_<name>` local BEFORE `$x` is
|
|
205
|
+
// declared, then binds `$x` off that capture (#2679).
|
|
206
|
+
test('in-template-seeds a same-name signal via capture-before-shadow', () => {
|
|
205
207
|
const { template } = compileAndGenerate(`
|
|
206
208
|
'use client'
|
|
207
209
|
import { createSignal } from '@barefootjs/client'
|
|
@@ -210,7 +212,8 @@ export function C(props: { x?: number }) {
|
|
|
210
212
|
return <span>{x()}</span>
|
|
211
213
|
}
|
|
212
214
|
`)
|
|
213
|
-
expect(template).
|
|
215
|
+
expect(template).toContain(': my $__bf_seed_x = ($x // 7);')
|
|
216
|
+
expect(template).toContain(': my $x = $__bf_seed_x;')
|
|
214
217
|
})
|
|
215
218
|
|
|
216
219
|
test('emits data_key_attr on the component root', () => {
|
package/src/adapter/memo/seed.ts
CHANGED
|
@@ -53,13 +53,19 @@ export function generateContextConsumerSeed(ir: ComponentIR): string {
|
|
|
53
53
|
* backend-specific emit guards: skip an empty lowering, skip a lowering that
|
|
54
54
|
* references no `$var` at all (a constant init/body — e.g. a `derived` step
|
|
55
55
|
* with empty `frees` — keeps the existing static ssr-defaults seed instead),
|
|
56
|
-
* and
|
|
57
|
-
* `: my $x = … $x …` would read the just-declared
|
|
58
|
-
* than the render var — the plan rules out
|
|
59
|
-
* lowered canonical name could still collide,
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
56
|
+
* and capture-before-shadow a self-referencing lowering (Kolon's `my`
|
|
57
|
+
* shadows the RHS, so `: my $x = … $x …` would read the just-declared
|
|
58
|
+
* undefined lexical rather than the render var — the plan rules out
|
|
59
|
+
* SOURCE-level self-refs, but a lowered canonical name could still collide,
|
|
60
|
+
* e.g. `createMemo(() => props.size ?? 'icon')` lowers `props.size` straight
|
|
61
|
+
* to the stash var `$size`, colliding with the memo's own name). The
|
|
62
|
+
* self-referencing case still emits the SAME verbatim Kolon — nothing about
|
|
63
|
+
* `kolon` changes — just as the RHS of a throwaway `__bf_seed_*` local
|
|
64
|
+
* declared BEFORE `$<name>` is shadowed, so `$<name>` inside `kolon` still
|
|
65
|
+
* resolves to the stash var, not the fresh lexical; a second statement then
|
|
66
|
+
* binds the real name off the already-evaluated capture. `env-reader` and
|
|
67
|
+
* `opaque` steps emit nothing (the runtime supplies the reader, or the
|
|
68
|
+
* adapter's ssr-defaults path already covers it). (#1297, #2075, #2679)
|
|
63
69
|
*/
|
|
64
70
|
export function generateDerivedMemoSeed(ctx: XslateMemoContext, ir: ComponentIR): string {
|
|
65
71
|
// Package G attached this to metadata at compile time; the `??` fallback
|
|
@@ -71,7 +77,21 @@ export function generateDerivedMemoSeed(ctx: XslateMemoContext, ir: ComponentIR)
|
|
|
71
77
|
if (step.kind !== 'derived') continue
|
|
72
78
|
const kolon = ctx.convertExpressionToKolon(step.expr, step.parsed)
|
|
73
79
|
if (kolon === '' || !/\$[A-Za-z_]\w*/.test(kolon)) continue
|
|
74
|
-
if (new RegExp(`\\$${step.name}\\b`).test(kolon))
|
|
80
|
+
if (new RegExp(`\\$${step.name}\\b`).test(kolon)) {
|
|
81
|
+
// Self-referencing lowering (#2679): capture the RHS into a
|
|
82
|
+
// throwaway local BEFORE `$<name>` is declared — `$<name>` inside
|
|
83
|
+
// `kolon` still reads the stash var at this point, nothing is
|
|
84
|
+
// shadowed yet — then bind the real name off the capture. The
|
|
85
|
+
// `__bf_seed_` prefix follows the adapter's established internal-
|
|
86
|
+
// temporary convention (`__bf_item` / `__bf_pair` in the loop
|
|
87
|
+
// lowering); suffixing with `step.name` keeps two derived steps in
|
|
88
|
+
// the same template from colliding, since `step.name` is itself
|
|
89
|
+
// unique per plan (each step declares a distinct local).
|
|
90
|
+
const tmp = `__bf_seed_${step.name}`
|
|
91
|
+
lines.push(`: my $${tmp} = ${kolon};`)
|
|
92
|
+
lines.push(`: my $${step.name} = $${tmp};`)
|
|
93
|
+
continue
|
|
94
|
+
}
|
|
75
95
|
lines.push(`: my $${step.name} = ${kolon};`)
|
|
76
96
|
}
|
|
77
97
|
return lines.length > 0 ? lines.join('\n') + '\n' : ''
|
|
@@ -9,5 +9,18 @@
|
|
|
9
9
|
|
|
10
10
|
import type { RenderDivergences } from '@barefootjs/jsx'
|
|
11
11
|
|
|
12
|
+
// #2679 graduated (capture-before-shadow in `generateDerivedMemoSeed`,
|
|
13
|
+
// packages/adapter-xslate/src/adapter/memo/seed.ts): a self-referencing
|
|
14
|
+
// derived signal/memo now seeds a throwaway `__bf_seed_<name>` local from
|
|
15
|
+
// the RAW-stash-var Kolon lowering BEFORE `$<name>` is declared, then binds
|
|
16
|
+
// the real name off that capture — the same in-template recompute the other
|
|
17
|
+
// six template-stash backends already had. Keep the file even when the set
|
|
18
|
+
// is empty — the next divergence lands here, not in a re-created file.
|
|
12
19
|
export const renderDivergences: RenderDivergences = {
|
|
20
|
+
'todo-app':
|
|
21
|
+
'the `todos` signal seeds from `(props.initialTodos ?? []).map(t => ({ ...t, editing: false }))` — a different-prop-derived `.map()` chain `extractSsrDefaults` cannot statically resolve, and `computeSsrSeedPlan` classifies it opaque (no in-template recompute), so it seeds `undef`; the non-`/* @client */`-marked `{todos().length > 0 && ...}` toggle-all block SSRs as if there are zero todos regardless of `initialTodos` (https://github.com/piconic-ai/barefootjs/issues/2696)',
|
|
22
|
+
'todo-app-ssr':
|
|
23
|
+
"same root cause as `todo-app` (https://github.com/piconic-ai/barefootjs/issues/2696); this fixture's todo-list loop carries no `/* @client */` marker, but Kolon's `for` iterates an undef list as empty rather than raising, so it SSRs an empty `<ul class=\"todo-list\">` with the toggle-all controls also absent, regardless of `initialTodos`",
|
|
24
|
+
'callback-param-shadows-prop':
|
|
25
|
+
"the `first` signal seeds from `[{ a: 'p' }].map((title) => title.a).join(',')` — a constant expression `extractSsrDefaults` still cannot statically resolve (`.map()` is unsupported for any receiver) and, unlike the sibling `joined` memo's structurally similar chain, gets no in-template recompute (`computeSsrSeedPlan` classifies it opaque too); `<span>{first()}</span>` SSRs empty instead of `p` (https://github.com/piconic-ai/barefootjs/issues/2696)",
|
|
13
26
|
}
|
package/src/test-render.ts
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* than the Mojo harness's literal `test_<sN>`.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { compileJSX, extractSsrDefaults, deriveStashFromDefaults, importsSearchParams
|
|
20
|
+
import { compileJSX, extractSsrDefaults, deriveStashFromDefaults, importsSearchParams } from '@barefootjs/jsx'
|
|
21
21
|
import type { ComponentIR, SsrDefault } from '@barefootjs/jsx'
|
|
22
22
|
import { mkdir, rm } from 'node:fs/promises'
|
|
23
23
|
import { resolve } from 'node:path'
|
|
@@ -563,23 +563,22 @@ function buildPerlProps(
|
|
|
563
563
|
}
|
|
564
564
|
}
|
|
565
565
|
|
|
566
|
-
//
|
|
566
|
+
// No initializer re-evaluation against raw props — production's
|
|
567
|
+
// before_render seeds only from `deriveStashFromDefaults` (#2696).
|
|
567
568
|
for (const signal of ir.metadata.signals) {
|
|
568
569
|
// Env signals (#2057) are bound below via `search_params('')`, not from a
|
|
569
570
|
// static initial value.
|
|
570
571
|
if (signal.envReader) continue
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
entries.push(`${signal.getter} => ${toPerlLiteral(value)}`)
|
|
572
|
+
if (Object.prototype.hasOwnProperty.call(derivedProps, signal.getter)) {
|
|
573
|
+
entries.push(`${signal.getter} => ${toPerlLiteral(derivedProps[signal.getter])}`)
|
|
574
574
|
}
|
|
575
575
|
}
|
|
576
576
|
|
|
577
|
-
//
|
|
578
|
-
// as the production plugin's before_render hook.
|
|
577
|
+
// No `?? 0` for entries the manifest lacks — production seeds nothing there (#2696).
|
|
579
578
|
for (const memo of ir.metadata.memos) {
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
579
|
+
if (Object.prototype.hasOwnProperty.call(derivedProps, memo.name)) {
|
|
580
|
+
entries.push(`${memo.name} => ${toPerlLiteral(derivedProps[memo.name])}`)
|
|
581
|
+
}
|
|
583
582
|
}
|
|
584
583
|
|
|
585
584
|
// (#1922) Request-scoped `searchParams()`: bind `$searchParams` to an
|