@barefootjs/mojolicious 0.35.2 → 0.35.3

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.
@@ -977,7 +977,7 @@ function generateDerivedMemoSeed(ctx, ir) {
977
977
  }
978
978
 
979
979
  // src/adapter/props/prop-classes.ts
980
- import { collectLoopBoundNames } from "@barefootjs/jsx";
980
+ import { collectLoopBoundNames, resolveBodyDestructuredPropAliases } from "@barefootjs/jsx";
981
981
 
982
982
  // src/adapter/value/parsed-literal.ts
983
983
  function isStringTypeInfo(type) {
@@ -1015,6 +1015,10 @@ function collectStringValueNames(ir) {
1015
1015
  if (isStringTypeInfo(p.type))
1016
1016
  names.add(p.name);
1017
1017
  }
1018
+ for (const [local, callerKey] of resolveBodyDestructuredPropAliases(ir.metadata.localConstants ?? [], ir.metadata.propsObjectName)) {
1019
+ if (names.has(callerKey))
1020
+ names.add(local);
1021
+ }
1018
1022
  for (const c of ir.metadata.localConstants) {
1019
1023
  if (isStringTypeInfo(c.type ?? undefined) || isBareStringLiteral(c.value))
1020
1024
  names.add(c.name);
@@ -59,6 +59,22 @@ export declare function collectNullableOptionalProps(ir: ComponentIR): Set<strin
59
59
  * elsewhere in the component) but safe: the suppressed case just falls
60
60
  * back to today's numeric `+` — the same, already-accepted residual as an
61
61
  * unresolvable operand — never silently-wrong output.
62
+ *
63
+ * A bare-props-form component's BODY-destructured, RENAMED prop
64
+ * (`const { fallbackLabel: skipLabel } = props`, the #2788 alias family)
65
+ * has no `propsParams` entry of its own — `propsParams` only carries the
66
+ * TYPE-level, caller-facing names, and the local alias never appears
67
+ * there. Without the alias resolved here too, a string-typed prop
68
+ * referenced only under its local rename inside a filter predicate
69
+ * (`t => t.label !== skipLabel`) is invisible to this witness, so its
70
+ * equality lowers to numeric `!=` instead of `ne` — every row is
71
+ * dropped, since `'Alpha' != 'Alpha'` and `'Beta' != 'Alpha'` both
72
+ * numify to `0 != 0` (#2883). `resolveBodyDestructuredPropAliases`
73
+ * already recognizes this exact destructuring shape (built for #2788's
74
+ * top-level splice path); reusing it here keeps this one witness the
75
+ * single source of truth `MojoFilterEmitter`/`MojoTopLevelEmitter` both
76
+ * read via `_isStringValueName`, rather than growing a second, adapter-
77
+ * emitter-local alias lookup.
62
78
  */
63
79
  export declare function collectStringValueNames(ir: ComponentIR): Set<string>;
64
80
  //# sourceMappingURL=prop-classes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"prop-classes.d.ts","sourceRoot":"","sources":["../../../src/adapter/props/prop-classes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAyB,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAGzE;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,CAMrE;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,CAMrE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,4BAA4B,CAAC,EAAE,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,CAWzE;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,CAepE"}
1
+ {"version":3,"file":"prop-classes.d.ts","sourceRoot":"","sources":["../../../src/adapter/props/prop-classes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAA6D,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAG7G;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,CAMrE;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,CAMrE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,4BAA4B,CAAC,EAAE,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,CAWzE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,CAqBpE"}
package/dist/index.js CHANGED
@@ -977,7 +977,7 @@ function generateDerivedMemoSeed(ctx, ir) {
977
977
  }
978
978
 
979
979
  // src/adapter/props/prop-classes.ts
980
- import { collectLoopBoundNames } from "@barefootjs/jsx";
980
+ import { collectLoopBoundNames, resolveBodyDestructuredPropAliases } from "@barefootjs/jsx";
981
981
 
982
982
  // src/adapter/value/parsed-literal.ts
983
983
  function isStringTypeInfo(type) {
@@ -1015,6 +1015,10 @@ function collectStringValueNames(ir) {
1015
1015
  if (isStringTypeInfo(p.type))
1016
1016
  names.add(p.name);
1017
1017
  }
1018
+ for (const [local, callerKey] of resolveBodyDestructuredPropAliases(ir.metadata.localConstants ?? [], ir.metadata.propsObjectName)) {
1019
+ if (names.has(callerKey))
1020
+ names.add(local);
1021
+ }
1018
1022
  for (const c of ir.metadata.localConstants) {
1019
1023
  if (isStringTypeInfo(c.type ?? undefined) || isBareStringLiteral(c.value))
1020
1024
  names.add(c.name);
@@ -1922,9 +1926,7 @@ var conformancePins = {
1922
1926
  "namespace-import-primitive": [{ code: "BF013", severity: "error" }]
1923
1927
  };
1924
1928
  // src/render-divergences.ts
1925
- var renderDivergences = {
1926
- "filter-predicate-renamed-prop": "https://github.com/piconic-ai/barefootjs/issues/2883"
1927
- };
1929
+ var renderDivergences = {};
1928
1930
  export {
1929
1931
  renderDivergences,
1930
1932
  mojoAdapter,
@@ -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;AAQxD,eAAO,MAAM,iBAAiB,EAAE,iBAW/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;AAQxD,eAAO,MAAM,iBAAiB,EAAE,iBAAsB,CAAA"}
package/dist/vite.js CHANGED
@@ -2175,6 +2175,20 @@ function propsDestructureBinding(p) {
2175
2175
  const binding = callerKey === localName ? localName : `${isIdentifierName(callerKey) ? callerKey : JSON.stringify(callerKey)}: ${localName}`;
2176
2176
  return p.defaultValue ? `${binding} = ${p.defaultValue}` : binding;
2177
2177
  }
2178
+ function resolveBodyDestructuredPropAliases(localConstants, propsObjectName) {
2179
+ const aliases = new Map;
2180
+ if (propsObjectName === null)
2181
+ return aliases;
2182
+ for (const c of localConstants) {
2183
+ if (c.isModule)
2184
+ continue;
2185
+ const m = c.parsed;
2186
+ if (m?.kind === "member" && !m.computed && m.object.kind === "identifier" && m.object.name === propsObjectName) {
2187
+ aliases.set(c.name, m.property);
2188
+ }
2189
+ }
2190
+ return aliases;
2191
+ }
2178
2192
  var EMPTY_SET = new Set;
2179
2193
 
2180
2194
  // ../jsx/src/ir-to-client-js/csr-substitute.ts
@@ -3421,8 +3435,11 @@ function matchSearchParamsMethodCall(callee, args, localNames) {
3421
3435
  // ../jsx/src/ir-to-client-js/prune-unused-prop-extractions.ts
3422
3436
  import ts19 from "typescript";
3423
3437
 
3424
- // ../jsx/src/ir-to-client-js/control-flow/plan/lazy-preamble.ts
3438
+ // ../jsx/src/ir-to-client-js/emit-reactive.ts
3425
3439
  import ts20 from "typescript";
3440
+
3441
+ // ../jsx/src/ir-to-client-js/control-flow/plan/lazy-preamble.ts
3442
+ import ts21 from "typescript";
3426
3443
  var NO_PREAMBLE = {
3427
3444
  lazySafe: true,
3428
3445
  facts: { declaredNames: new Set, freeNames: new Set }
@@ -3471,9 +3488,6 @@ var INERT_BINDING_GLOBALS = new Set([
3471
3488
  "decodeURI"
3472
3489
  ]);
3473
3490
 
3474
- // ../jsx/src/ir-to-client-js/emit-reactive.ts
3475
- import ts21 from "typescript";
3476
-
3477
3491
  // ../jsx/src/ir-to-client-js/control-flow/stringify/event-delegation.ts
3478
3492
  var NON_BUBBLING_EVENTS = new Set([
3479
3493
  "blur",
@@ -6250,6 +6264,10 @@ function collectStringValueNames(ir) {
6250
6264
  if (isStringTypeInfo(p.type))
6251
6265
  names.add(p.name);
6252
6266
  }
6267
+ for (const [local, callerKey] of resolveBodyDestructuredPropAliases(ir.metadata.localConstants ?? [], ir.metadata.propsObjectName)) {
6268
+ if (names.has(callerKey))
6269
+ names.add(local);
6270
+ }
6253
6271
  for (const c of ir.metadata.localConstants) {
6254
6272
  if (isStringTypeInfo(c.type ?? undefined) || isBareStringLiteral(c.value))
6255
6273
  names.add(c.name);
@@ -1,5 +1,5 @@
1
1
  package BarefootJS::Backend::Mojo;
2
- our $VERSION = "0.35.1";
2
+ our $VERSION = "0.35.2";
3
3
  use Mojo::Base -base, -signatures;
4
4
 
5
5
  use Mojo::ByteStream qw(b);
@@ -1,5 +1,5 @@
1
1
  package Mojolicious::Plugin::BarefootJS::DevReload;
2
- our $VERSION = "0.35.1";
2
+ our $VERSION = "0.35.2";
3
3
  use Mojo::Base 'Mojolicious::Plugin', -signatures;
4
4
 
5
5
  =head1 NAME
@@ -1,5 +1,5 @@
1
1
  package Mojolicious::Plugin::BarefootJS;
2
- our $VERSION = "0.35.1";
2
+ our $VERSION = "0.35.2";
3
3
  use Mojo::Base 'Mojolicious::Plugin', -signatures;
4
4
 
5
5
  use Mojo::File qw(path);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/mojolicious",
3
- "version": "0.35.2",
3
+ "version": "0.35.3",
4
4
  "description": "Mojolicious EP template adapter for BarefootJS - generates .html.ep files from IR",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -52,7 +52,7 @@
52
52
  "directory": "packages/adapter-mojolicious"
53
53
  },
54
54
  "dependencies": {
55
- "@barefootjs/shared": "0.35.2"
55
+ "@barefootjs/shared": "0.35.3"
56
56
  },
57
57
  "peerDependencies": {
58
58
  "@barefootjs/jsx": ">=0.2.0",
@@ -70,9 +70,9 @@
70
70
  },
71
71
  "devDependencies": {
72
72
  "@barefootjs/adapter-tests": "0.1.0",
73
- "@barefootjs/jsx": "0.35.2",
74
- "@barefootjs/vite": "0.35.2",
75
- "@barefootjs/client": "0.35.2",
73
+ "@barefootjs/jsx": "0.35.3",
74
+ "@barefootjs/vite": "0.35.3",
75
+ "@barefootjs/client": "0.35.3",
76
76
  "vite": "^6.0.0"
77
77
  }
78
78
  }
@@ -733,6 +733,40 @@ export function L() {
733
733
  expect(result.template).not.toContain('$sel eq $t->{n}')
734
734
  })
735
735
 
736
+ test('compares a filter predicate against a renamed body-destructured prop with Perl `ne`, not numeric `!=` (#2883)', () => {
737
+ // `MojoFilterEmitter.identifier()` correctly resolves `skipLabel` to
738
+ // `$skipLabel` (Mojo seeds/derives that stash key for the #2788 alias
739
+ // family, same as the top-level splice path) — the actual bug was
740
+ // `collectStringValueNames`'s witness for `eq`/`ne` vs `==`/`!=` not
741
+ // knowing about body-destructured RENAMED props, so this comparison
742
+ // fell through to numeric `!=`. `'Alpha' != 'Alpha'` and
743
+ // `'Beta' != 'Alpha'` both numify to `0 != 0` — every row was
744
+ // filtered out regardless of the real string value.
745
+ const result = compileAndGenerate(`
746
+ "use client"
747
+ import { createSignal } from "@barefootjs/client"
748
+
749
+ type Todo = { id: number; label: string }
750
+
751
+ export function FilterPredicateRenamedProp(props: { fallbackLabel: string }) {
752
+ const { fallbackLabel: skipLabel } = props
753
+ const [todos] = createSignal<Todo[]>([
754
+ { id: 1, label: 'Alpha' },
755
+ { id: 2, label: 'Beta' },
756
+ ])
757
+ return (
758
+ <ul>
759
+ {todos().filter(t => t.label !== skipLabel).map(t => (
760
+ <li key={t.id}>{t.label}</li>
761
+ ))}
762
+ </ul>
763
+ )
764
+ }
765
+ `)
766
+ expect(result.template).toContain('$t->{label} ne $skipLabel')
767
+ expect(result.template).not.toContain('$t->{label} != $skipLabel')
768
+ })
769
+
736
770
  test('generates script registration for client components', () => {
737
771
  const result = compileAndGenerate(`
738
772
  "use client"
@@ -7,7 +7,7 @@
7
7
  * adapter's `props/prop-types.ts`. No adapter instance state.
8
8
  */
9
9
 
10
- import { collectLoopBoundNames, type ComponentIR } from '@barefootjs/jsx'
10
+ import { collectLoopBoundNames, resolveBodyDestructuredPropAliases, type ComponentIR } from '@barefootjs/jsx'
11
11
  import { isStringTypeInfo, isBareStringLiteral } from '../value/parsed-literal.ts'
12
12
 
13
13
  /**
@@ -88,6 +88,22 @@ export function collectNullableOptionalProps(ir: ComponentIR): Set<string> {
88
88
  * elsewhere in the component) but safe: the suppressed case just falls
89
89
  * back to today's numeric `+` — the same, already-accepted residual as an
90
90
  * unresolvable operand — never silently-wrong output.
91
+ *
92
+ * A bare-props-form component's BODY-destructured, RENAMED prop
93
+ * (`const { fallbackLabel: skipLabel } = props`, the #2788 alias family)
94
+ * has no `propsParams` entry of its own — `propsParams` only carries the
95
+ * TYPE-level, caller-facing names, and the local alias never appears
96
+ * there. Without the alias resolved here too, a string-typed prop
97
+ * referenced only under its local rename inside a filter predicate
98
+ * (`t => t.label !== skipLabel`) is invisible to this witness, so its
99
+ * equality lowers to numeric `!=` instead of `ne` — every row is
100
+ * dropped, since `'Alpha' != 'Alpha'` and `'Beta' != 'Alpha'` both
101
+ * numify to `0 != 0` (#2883). `resolveBodyDestructuredPropAliases`
102
+ * already recognizes this exact destructuring shape (built for #2788's
103
+ * top-level splice path); reusing it here keeps this one witness the
104
+ * single source of truth `MojoFilterEmitter`/`MojoTopLevelEmitter` both
105
+ * read via `_isStringValueName`, rather than growing a second, adapter-
106
+ * emitter-local alias lookup.
91
107
  */
92
108
  export function collectStringValueNames(ir: ComponentIR): Set<string> {
93
109
  const names = new Set<string>()
@@ -99,6 +115,12 @@ export function collectStringValueNames(ir: ComponentIR): Set<string> {
99
115
  for (const p of ir.metadata.propsParams) {
100
116
  if (isStringTypeInfo(p.type)) names.add(p.name)
101
117
  }
118
+ for (const [local, callerKey] of resolveBodyDestructuredPropAliases(
119
+ ir.metadata.localConstants ?? [],
120
+ ir.metadata.propsObjectName,
121
+ )) {
122
+ if (names.has(callerKey)) names.add(local)
123
+ }
102
124
  for (const c of ir.metadata.localConstants) {
103
125
  if (isStringTypeInfo(c.type ?? undefined) || isBareStringLiteral(c.value)) names.add(c.name)
104
126
  }
@@ -15,15 +15,4 @@ import type { RenderDivergences } from '@barefootjs/jsx'
15
15
  // at value position and the runtime evaluator's `object-literal` case
16
16
  // now merges it, so the seed classifies `derived` and SSRs identically
17
17
  // to Hono.
18
- export const renderDivergences: RenderDivergences = {
19
- // #2883: `MojoFilterEmitter.identifier()` (expr/emitters.ts) resolves a
20
- // `.filter()` predicate identifier against only the loop param and
21
- // `localVarMap` — a bare-props-form renamed prop destructure (`const {
22
- // fallbackLabel: skipLabel } = props`, the #2788 alias family) falls
23
- // through to a bare `$skipLabel`, a Perl variable never declared in the
24
- // generated `.html.ep`. Every row is filtered out (the fixture's
25
- // reference expects only the non-matching row to survive). Unrelated to
26
- // #2857's Go Template adapter fix that this fixture was added for — this
27
- // fixture is a shared cross-adapter conformance fixture, not Go-specific.
28
- 'filter-predicate-renamed-prop': 'https://github.com/piconic-ai/barefootjs/issues/2883',
29
- }
18
+ export const renderDivergences: RenderDivergences = {}