@barefootjs/mojolicious 0.17.0 → 0.17.1
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/expr/array-method.d.ts +10 -0
- package/dist/adapter/expr/array-method.d.ts.map +1 -1
- package/dist/adapter/expr/emitters.d.ts +2 -1
- package/dist/adapter/expr/emitters.d.ts.map +1 -1
- package/dist/adapter/index.js +44 -55
- package/dist/adapter/lib/ir-scope.d.ts +0 -7
- package/dist/adapter/lib/ir-scope.d.ts.map +1 -1
- package/dist/adapter/memo/seed.d.ts +10 -19
- package/dist/adapter/memo/seed.d.ts.map +1 -1
- package/dist/adapter/mojo-adapter.d.ts.map +1 -1
- package/dist/build.js +44 -55
- package/dist/index.js +44 -55
- package/lib/BarefootJS/Backend/Mojo.pm +1 -1
- package/lib/Mojolicious/Plugin/BarefootJS/DevReload.pm +1 -1
- package/lib/Mojolicious/Plugin/BarefootJS.pm +1 -1
- package/package.json +3 -3
- package/src/__tests__/mojo-adapter.test.ts +165 -12
- package/src/adapter/expr/array-method.ts +21 -0
- package/src/adapter/expr/emitters.ts +36 -4
- package/src/adapter/lib/ir-scope.ts +0 -13
- package/src/adapter/memo/seed.ts +20 -73
- package/src/adapter/mojo-adapter.ts +25 -9
package/src/adapter/memo/seed.ts
CHANGED
|
@@ -13,13 +13,10 @@ import {
|
|
|
13
13
|
type ComponentIR,
|
|
14
14
|
type ContextConsumer,
|
|
15
15
|
collectContextConsumers,
|
|
16
|
-
|
|
17
|
-
isSupported,
|
|
18
|
-
parseExpression,
|
|
16
|
+
computeSsrSeedPlan,
|
|
19
17
|
} from '@barefootjs/jsx'
|
|
20
18
|
|
|
21
19
|
import type { MojoMemoContext } from '../emit-context.ts'
|
|
22
|
-
import { referencedVarsAreAvailable } from '../lib/ir-scope.ts'
|
|
23
20
|
|
|
24
21
|
/** Perl literal for a context-consumer's `createContext` default. */
|
|
25
22
|
export function contextDefaultPerl(c: ContextConsumer): string {
|
|
@@ -49,78 +46,28 @@ export function generateContextConsumerSeed(ir: ComponentIR): string {
|
|
|
49
46
|
}
|
|
50
47
|
|
|
51
48
|
/**
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
49
|
+
* Emit `% my $<name> = <perl>;` seed lines for every `derived` step of the
|
|
50
|
+
* backend-neutral SSR seed plan — the scope/availability/ordering analysis
|
|
51
|
+
* lives in `computeSsrSeedPlan` (packages/jsx/src/ssr-seed-plan.ts); this
|
|
52
|
+
* only lowers each step's expression to Perl and applies the two
|
|
53
|
+
* backend-specific emit guards: skip an empty lowering, and skip a lowering
|
|
54
|
+
* that references no `$var` at all (a constant init/body — e.g. a `derived`
|
|
55
|
+
* step with empty `frees` — keeps the existing static ssr-defaults seed
|
|
56
|
+
* instead). `env-reader` and `opaque` steps emit nothing (the runtime
|
|
57
|
+
* supplies the reader, or the adapter's ssr-defaults path already covers it).
|
|
58
|
+
* (#1297, #2075)
|
|
61
59
|
*/
|
|
62
60
|
export function generateDerivedMemoSeed(ctx: MojoMemoContext, ir: ComponentIR): string {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
// later one can reference an earlier one.
|
|
68
|
-
const available = new Set<string>(ir.metadata.propsParams.map(p => p.name))
|
|
61
|
+
// Package G attached this to metadata at compile time; the `??` fallback
|
|
62
|
+
// only covers hand-built metadata in older tests that predate the attached
|
|
63
|
+
// plan — same shared function, so there's no divergence from the compiler.
|
|
64
|
+
const plan = ir.metadata.ssrSeedPlan ?? computeSsrSeedPlan(ir.metadata)
|
|
69
65
|
const lines: string[] = []
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
// the passed prop — but ONLY when the init lowers cleanly AND references an
|
|
76
|
-
// in-scope var (i.e. it's genuinely derived). Object/array/constant inits
|
|
77
|
-
// (`createSignal({…})`, `createSignal([…])`, `createSignal('b')`) keep the
|
|
78
|
-
// existing ssr-defaults seeding, so the spread / loop fixtures are
|
|
79
|
-
// untouched.
|
|
80
|
-
for (const signal of signals) {
|
|
81
|
-
const perl = tryLowerToPerl(ctx, signal.initialValue, available)
|
|
82
|
-
if (perl !== null) lines.push(`% my $${signal.getter} = ${perl};`)
|
|
83
|
-
available.add(signal.getter)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
for (const memo of memos) {
|
|
87
|
-
// Seed every memo whose body lowers cleanly — not just the ones whose
|
|
88
|
-
// static SSR default is null. A statically-foldable prop-derived memo
|
|
89
|
-
// (`createMemo(() => props.disabled ?? false)` → default `false`)
|
|
90
|
-
// still depends on the per-call prop: the static stash seed bakes in
|
|
91
|
-
// the absent-prop fold, so a caller passing `disabled => 1` would
|
|
92
|
-
// render the default branch (#1897, select's disabled item). The
|
|
93
|
-
// in-template recomputation reads the prop lexical the stash already
|
|
94
|
-
// seeded, so it's correct per call; block-bodied arrows /
|
|
95
|
-
// out-of-scope references fall back to the static ssr-defaults seed.
|
|
96
|
-
const body = extractArrowBodyExpression(memo.computation)
|
|
97
|
-
if (body !== null) {
|
|
98
|
-
const perl = tryLowerToPerl(ctx, body, available)
|
|
99
|
-
if (perl !== null) lines.push(`% my $${memo.name} = ${perl};`)
|
|
100
|
-
}
|
|
101
|
-
available.add(memo.name)
|
|
66
|
+
for (const step of plan.steps) {
|
|
67
|
+
if (step.kind !== 'derived') continue
|
|
68
|
+
const perl = ctx.convertExpressionToPerl(step.expr, step.parsed)
|
|
69
|
+
if (perl === '' || !/\$[A-Za-z_]\w*/.test(perl)) continue
|
|
70
|
+
lines.push(`% my $${step.name} = ${perl};`)
|
|
102
71
|
}
|
|
103
72
|
return lines.length > 0 ? lines.join('\n') + '\n' : ''
|
|
104
73
|
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Lower a signal init / memo body to Perl for an in-template SSR seed, or
|
|
108
|
-
* `null` when it shouldn't be seeded this way. Returns null — without
|
|
109
|
-
* recording a BF101 — when the expression isn't a supported shape
|
|
110
|
-
* (`isSupported` pre-check, so object/array literals don't fail the build),
|
|
111
|
-
* when the lowering references no in-scope var (a constant — keep the
|
|
112
|
-
* existing ssr-defaults seeding), or when it references an out-of-scope
|
|
113
|
-
* binding. (#1297)
|
|
114
|
-
*/
|
|
115
|
-
export function tryLowerToPerl(
|
|
116
|
-
ctx: MojoMemoContext,
|
|
117
|
-
expr: string,
|
|
118
|
-
available: ReadonlySet<string>,
|
|
119
|
-
): string | null {
|
|
120
|
-
const trimmed = expr.trim()
|
|
121
|
-
if (!trimmed) return null
|
|
122
|
-
if (!isSupported(parseExpression(trimmed)).supported) return null
|
|
123
|
-
const perl = ctx.convertExpressionToPerl(trimmed)
|
|
124
|
-
if (perl === '' || !/\$[A-Za-z_]\w*/.test(perl)) return null
|
|
125
|
-
return referencedVarsAreAvailable(perl, available) ? perl : null
|
|
126
|
-
}
|
|
@@ -695,8 +695,15 @@ export class MojoAdapter extends BaseAdapter implements IRNodeEmitter<MojoRender
|
|
|
695
695
|
// ===========================================================================
|
|
696
696
|
|
|
697
697
|
renderLoop(loop: IRLoop): string {
|
|
698
|
-
//
|
|
699
|
-
|
|
698
|
+
// clientOnly loops must not render items at SSR time, but must still emit
|
|
699
|
+
// the `loop:`/`/loop:` boundary marker pair (Hono and Go parity) so the
|
|
700
|
+
// client runtime's mapArray() can locate the insertion anchor when
|
|
701
|
+
// hydrating the array. Without the markers, mapArray() resolves
|
|
702
|
+
// anchor = null and appends after sibling markers (#872). The marker id
|
|
703
|
+
// disambiguates sibling `.map()` calls under the same parent (#1087).
|
|
704
|
+
if (loop.clientOnly) {
|
|
705
|
+
return `<%== bf->comment("loop:${loop.markerId}") %><%== bf->comment("/loop:${loop.markerId}") %>`
|
|
706
|
+
}
|
|
700
707
|
|
|
701
708
|
// An array/object-destructure loop param (`([emoji, users]) => ...`
|
|
702
709
|
// or `({ name, age }) => ...`) lowers to invalid Perl — the adapter
|
|
@@ -1389,13 +1396,22 @@ export class MojoAdapter extends BaseAdapter implements IRNodeEmitter<MojoRender
|
|
|
1389
1396
|
// now lowering `.length` on a higher-order object to
|
|
1390
1397
|
// `scalar(@{...})`, the canonical
|
|
1391
1398
|
// `x.tags.filter(t => t.active).length > 0` shape lowers
|
|
1392
|
-
// cleanly
|
|
1393
|
-
//
|
|
1394
|
-
//
|
|
1395
|
-
//
|
|
1396
|
-
//
|
|
1397
|
-
// canonical case
|
|
1398
|
-
|
|
1399
|
+
// cleanly, and nested `filter` / `every` / `some` lower to real
|
|
1400
|
+
// inline `grep` forms. The shapes the emitter can only DEGRADE
|
|
1401
|
+
// (nested `find*`, sort / reduce / flatMap inside a predicate)
|
|
1402
|
+
// surface BF101 through the hook below instead of silently
|
|
1403
|
+
// rewriting the predicate (#2038). Wholesale refusal would block
|
|
1404
|
+
// the canonical case #1443 exists to enable, so the gate lives at
|
|
1405
|
+
// the exact degrade points inside `MojoFilterEmitter.callbackMethod`.
|
|
1406
|
+
return emitParsedExpr(
|
|
1407
|
+
expr,
|
|
1408
|
+
new MojoFilterEmitter(
|
|
1409
|
+
param,
|
|
1410
|
+
localVarMap,
|
|
1411
|
+
n => this._isStringValueName(n),
|
|
1412
|
+
(message, reason) => this._recordExprBF101(message, reason),
|
|
1413
|
+
),
|
|
1414
|
+
)
|
|
1399
1415
|
}
|
|
1400
1416
|
|
|
1401
1417
|
// ===========================================================================
|