@barefootjs/erb 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/index.js CHANGED
@@ -189273,7 +189273,11 @@ var conformancePins = {
189273
189273
  "rich-prop-client-read": [{ code: "BF049", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2648" }]
189274
189274
  };
189275
189275
  // src/render-divergences.ts
189276
- var renderDivergences = {};
189276
+ var renderDivergences = {
189277
+ "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 `nil`; 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)",
189278
+ "todo-app-ssr": "same root cause as `todo-app` (https://github.com/piconic-ai/barefootjs/issues/2696), but this fixture's todo-list loop carries no `/* @client */` marker — the compiled ERB loop iterates the nil-seeded `todos` directly and raises `NoMethodError: undefined method 'length' for nil` instead of rendering",
189279
+ "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)"
189280
+ };
189277
189281
  export {
189278
189282
  renderDivergences,
189279
189283
  erbAdapter,
@@ -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;AAExD,eAAO,MAAM,iBAAiB,EAAE,iBAC/B,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;AAExD,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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/erb",
3
- "version": "0.31.9",
3
+ "version": "0.32.0",
4
4
  "description": "ERB (Embedded Ruby) adapter for BarefootJS — compiles IR to .erb templates and ships the Ruby rendering backend; runs under any Rack app (Sinatra, Rails)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -54,7 +54,7 @@
54
54
  "directory": "packages/adapter-erb"
55
55
  },
56
56
  "dependencies": {
57
- "@barefootjs/shared": "0.31.9"
57
+ "@barefootjs/shared": "0.32.0"
58
58
  },
59
59
  "peerDependencies": {
60
60
  "@barefootjs/jsx": ">=0.2.0",
@@ -71,9 +71,9 @@
71
71
  },
72
72
  "devDependencies": {
73
73
  "@barefootjs/adapter-tests": "0.1.0",
74
- "@barefootjs/jsx": "0.31.9",
75
- "@barefootjs/vite": "0.31.9",
76
- "@barefootjs/client": "0.31.9",
74
+ "@barefootjs/jsx": "0.32.0",
75
+ "@barefootjs/vite": "0.32.0",
76
+ "@barefootjs/client": "0.32.0",
77
77
  "typescript": "^5.0.0",
78
78
  "vite": "^6.0.0"
79
79
  }
@@ -10,4 +10,10 @@
10
10
  import type { RenderDivergences } from '@barefootjs/jsx'
11
11
 
12
12
  export const renderDivergences: RenderDivergences = {
13
+ 'todo-app':
14
+ '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 `nil`; 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)',
15
+ 'todo-app-ssr':
16
+ 'same root cause as `todo-app` (https://github.com/piconic-ai/barefootjs/issues/2696), but this fixture\'s todo-list loop carries no `/* @client */` marker — the compiled ERB loop iterates the nil-seeded `todos` directly and raises `NoMethodError: undefined method \'length\' for nil` instead of rendering',
17
+ 'callback-param-shadows-prop':
18
+ "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
19
  }
@@ -36,7 +36,7 @@
36
36
  * regression test.
37
37
  */
38
38
 
39
- import { compileJSX, extractSsrDefaults, deriveStashFromDefaults, importsSearchParams, evaluateSignalInit } from '@barefootjs/jsx'
39
+ import { compileJSX, extractSsrDefaults, deriveStashFromDefaults, importsSearchParams } from '@barefootjs/jsx'
40
40
  import type { ComponentIR, SsrDefault } from '@barefootjs/jsx'
41
41
  import { mkdir, rm } from 'node:fs/promises'
42
42
  import { resolve } from 'node:path'
@@ -600,21 +600,22 @@ function buildRubyProps(
600
600
  }
601
601
  }
602
602
 
603
- // Signal values evaluated from props (after user props).
603
+ // No initializer re-evaluation against raw props production's
604
+ // before_render seeds only from `deriveStashFromDefaults` (#2696).
604
605
  for (const signal of ir.metadata.signals) {
605
606
  // Env signals (#2057 / #1922) are bound below via `search_params('')`,
606
607
  // not from a static initial value.
607
608
  if (signal.envReader) continue
608
- const value = evaluateSignalInit(signal.initialValue.trim(), props)
609
- if (value !== null) {
610
- obj[signal.getter] = value
609
+ if (Object.prototype.hasOwnProperty.call(derivedProps, signal.getter)) {
610
+ obj[signal.getter] = derivedProps[signal.getter]
611
611
  }
612
612
  }
613
613
 
614
- // Memo values seeded from the statically-evaluated ssrDefaults, same
615
- // as the production plugin's before_render hook.
614
+ // No `?? 0` for entries the manifest lacks — production seeds nothing there (#2696).
616
615
  for (const memo of ir.metadata.memos) {
617
- obj[memo.name] = rootSsrDefaults[memo.name]?.value ?? 0
616
+ if (Object.prototype.hasOwnProperty.call(derivedProps, memo.name)) {
617
+ obj[memo.name] = derivedProps[memo.name]
618
+ }
618
619
  }
619
620
 
620
621
  const needsSearchParams = importsSearchParams(ir.metadata)