@barefootjs/jsx 0.32.0 → 0.33.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/adapters/dangerous-inner-html.d.ts.map +1 -1
- package/dist/adapters/parsed-expr-emitter.d.ts +22 -0
- package/dist/adapters/parsed-expr-emitter.d.ts.map +1 -1
- package/dist/expression-parser.d.ts +29 -6
- package/dist/expression-parser.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +129 -40
- package/dist/query-href-lowering.d.ts.map +1 -1
- package/dist/ssr-seed-plan.d.ts.map +1 -1
- package/dist/static-literal.d.ts.map +1 -1
- package/dist/to-locale-date-lowering.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/expression-parser.test.ts +43 -6
- package/src/__tests__/serialize-parsed-expr.test.ts +17 -3
- package/src/__tests__/ssr-defaults.test.ts +41 -0
- package/src/__tests__/ssr-seed-plan.test.ts +12 -2
- package/src/adapters/dangerous-inner-html.ts +1 -0
- package/src/adapters/parsed-expr-emitter.ts +49 -3
- package/src/expression-parser.ts +200 -89
- package/src/index.ts +2 -2
- package/src/jsx-to-ir.ts +4 -1
- package/src/query-href-lowering.ts +4 -0
- package/src/rich-type-refusal.ts +1 -1
- package/src/ssr-defaults.ts +51 -2
- package/src/ssr-seed-plan.ts +20 -3
- package/src/static-literal.ts +15 -1
- package/src/to-locale-date-lowering.ts +4 -0
package/src/ssr-seed-plan.ts
CHANGED
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
extractArrowBodyExpression,
|
|
37
37
|
freeIdentifiers,
|
|
38
38
|
inlineBinding,
|
|
39
|
-
|
|
39
|
+
isSupportedValue,
|
|
40
40
|
parseExpression,
|
|
41
41
|
type ParsedExpr,
|
|
42
42
|
} from './expression-parser.ts'
|
|
@@ -81,6 +81,11 @@ export interface SsrSeedPlan {
|
|
|
81
81
|
* opaque). The scope check runs over the parsed SOURCE tree, so a shadowed
|
|
82
82
|
* name (`items.filter((p) => p.ok) && p`, where the trailing `p` is a
|
|
83
83
|
* different, unbound reference from the callback's own param) is rejected.
|
|
84
|
+
*
|
|
85
|
+
* Uses `isSupportedValue`, not `isSupported`: a signal/memo initializer is an
|
|
86
|
+
* ASSIGNMENT, never a render, so it's checked at VALUE position — this is
|
|
87
|
+
* what admits e.g. `createSignal([{ a: 'p' }].map(t => t.a).join(','))`
|
|
88
|
+
* (an object-literal array-method receiver) as `derived` instead of opaque.
|
|
84
89
|
*/
|
|
85
90
|
function classify(
|
|
86
91
|
name: string,
|
|
@@ -89,7 +94,7 @@ function classify(
|
|
|
89
94
|
parsed: ParsedExpr,
|
|
90
95
|
available: ReadonlySet<string>,
|
|
91
96
|
): SsrSeedStep {
|
|
92
|
-
if (!
|
|
97
|
+
if (!isSupportedValue(parsed).supported) return { kind: 'opaque', name, origin }
|
|
93
98
|
const frees = freeIdentifiers(parsed)
|
|
94
99
|
if (frees === null) return { kind: 'opaque', name, origin }
|
|
95
100
|
for (const free of frees) {
|
|
@@ -198,7 +203,19 @@ export function computeSsrSeedPlan(metadata: IRMetadata): SsrSeedPlan {
|
|
|
198
203
|
signal.getter,
|
|
199
204
|
'signal',
|
|
200
205
|
expr,
|
|
201
|
-
|
|
206
|
+
// Prefer the analyzer's already-parenthesised parse (`analyzer.ts`'s
|
|
207
|
+
// `parseExpression(\`(${signal.initialValue})\`)`, Roadmap A) over
|
|
208
|
+
// re-parsing the bare `expr` string here — re-parsing WITHOUT the
|
|
209
|
+
// wrap misreads a bare object-literal initializer
|
|
210
|
+
// (`createSignal({ ...base, done: true })`) as a block statement
|
|
211
|
+
// (`parseExpression`'s documented block-vs-expression-statement
|
|
212
|
+
// rule), silently opaquing an otherwise-derivable signal (#2696
|
|
213
|
+
// Step 2 follow-up: this only became observable once `object-
|
|
214
|
+
// literal` could classify `derived` at all). Falling back to a
|
|
215
|
+
// parenthesised re-parse (not the bare string) keeps a signal
|
|
216
|
+
// whose shape the analyzer's pass left unparsed (`signal.parsed`
|
|
217
|
+
// undefined) equally safe.
|
|
218
|
+
resolveThroughLocalConsts(signal.parsed ?? parseExpression(`(${expr})`), localConsts),
|
|
202
219
|
available,
|
|
203
220
|
),
|
|
204
221
|
)
|
package/src/static-literal.ts
CHANGED
|
@@ -60,9 +60,23 @@ export function evaluateStaticLiteral(
|
|
|
60
60
|
// Shorthand (`{ a }`) and explicit (`{ a: value }`) properties both
|
|
61
61
|
// carry their resolved tree in `value` (shorthand's is an
|
|
62
62
|
// `identifier`) — recursing here handles both uniformly: a shorthand
|
|
63
|
-
// property only resolves when `bindings` supplies it.
|
|
63
|
+
// property only resolves when `bindings` supplies it. A spread
|
|
64
|
+
// (`{ ...base, a: 1 }`, #2696 Step 2) resolves its source and merges
|
|
65
|
+
// in source order — the same shallow-merge, later-wins, null/undefined-
|
|
66
|
+
// is-a-no-op semantics as the runtime evaluator (`toEvalNode`'s
|
|
67
|
+
// `object-literal` case) and JS itself; a spread source that resolves
|
|
68
|
+
// to anything other than a plain object/null/undefined isn't
|
|
69
|
+
// statically mergeable here, so the whole literal declines.
|
|
64
70
|
const out: Record<string, unknown> = {}
|
|
65
71
|
for (const prop of expr.properties) {
|
|
72
|
+
if (prop.kind === 'spread') {
|
|
73
|
+
const resolved = evaluateStaticLiteral(prop.expr, bindings)
|
|
74
|
+
if (!resolved) return null
|
|
75
|
+
if (resolved.value === null || resolved.value === undefined) continue
|
|
76
|
+
if (typeof resolved.value !== 'object' || Array.isArray(resolved.value)) return null
|
|
77
|
+
Object.assign(out, resolved.value)
|
|
78
|
+
continue
|
|
79
|
+
}
|
|
66
80
|
const resolved = evaluateStaticLiteral(prop.value, bindings)
|
|
67
81
|
if (!resolved) return null
|
|
68
82
|
out[prop.key] = resolved.value
|
|
@@ -504,6 +504,10 @@ export function matchToLocaleDateStringCall(
|
|
|
504
504
|
let tz: string | null = null
|
|
505
505
|
const probeOptions: Record<string, string> = {}
|
|
506
506
|
for (const prop of options.properties) {
|
|
507
|
+
// A spread (`{ ...opts, timeZone: 'UTC' }`, #2696 Step 2) isn't a
|
|
508
|
+
// literal-keyed entry this probe can read without evaluating the spread
|
|
509
|
+
// source — decline rather than silently skipping its keys.
|
|
510
|
+
if (prop.kind === 'spread') return null
|
|
507
511
|
if (prop.value.kind !== 'literal' || prop.value.literalType !== 'string') return null
|
|
508
512
|
const value = String(prop.value.value)
|
|
509
513
|
if (prop.key === 'timeZone') {
|