@solidjs/babel-plugin 2.0.0-rc.6 → 2.0.0-rc.8
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +34 -0
- package/README.md +14 -0
- package/index.js +134 -449
- package/package.json +2 -3
package/.turbo/turbo-build.log
CHANGED
|
@@ -7,4 +7,4 @@ src/shared/transform.ts -> src/ssr/element.ts -> src/shared/transform.ts
|
|
|
7
7
|
src/shared/transform.ts -> src/universal/element.ts -> src/shared/transform.ts
|
|
8
8
|
src/shared/transform.ts -> src/shared/component.ts -> src/shared/transform.ts
|
|
9
9
|
src/shared/transform.ts -> src/shared/fragment.ts -> src/shared/transform.ts
|
|
10
|
-
[32mcreated [1mindex.js[22m in [
|
|
10
|
+
[32mcreated [1mindex.js[22m in [1m2.7s[22m[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# @solidjs/babel-plugin
|
|
2
2
|
|
|
3
|
+
## 2.0.0-rc.8
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 01ac18c: Compiler `componentNames` option: component owner labels that survive minification. With the flag on, DOM output carries the tag as written in source as a third `createComponent` argument — `<Home />` compiles to `createComponent(Home, props, "Home")`, `<Ui.Button />` to `"Ui.Button"`, `<this.Row />` to `"this.Row"` — and the dev and observe runtimes label the component's owner with it (`<Home>` in diagnostic `ownerPath`s, attribution chains, and the devtools `_component.name`), falling back to `Comp.name` as before. Until now an observe-tier production bundle reported hot scopes and holds under whatever the minifier left of the function name (`<Xt> › <Kn>`), and a `lazy()` or HMR wrapper hid the tag name even in dev. Off by default and byte-identical output when off; SSR (which inlines the call) and universal output never emit it; the production `createComponent` ignores the argument. Both compilers implement it in parity (shared fixtures, cross-mode ratchet). `@solidjs/vite-plugin` enables it for the dev and `observe` postures.
|
|
8
|
+
- 7d985b6: Fix SSR XSS: strings yielded by flow-control memos rendered unescaped
|
|
9
|
+
|
|
10
|
+
`<Show when={s}>{s}</Show>`, `<For>{v => v}</For>`, `<Dynamic component={() => s} />`,
|
|
11
|
+
`<Switch>/<Match>`, boundary fallbacks and any component that returns a string through a
|
|
12
|
+
memo rendered that string raw on the server. The server flow controls return memos for
|
|
13
|
+
hydration-id alignment; `escape()` passed functions through by identity, and the resolver
|
|
14
|
+
appended whatever they later produced without escaping.
|
|
15
|
+
|
|
16
|
+
One rule now: `escape(x)` at a hole covers everything reachable from `x` — strings, array
|
|
17
|
+
items, and what a function yields when the resolver calls it (a deferred-escape wrapper).
|
|
18
|
+
Finished `{ t }` nodes pass through. `Loading` escapes its content the way it already
|
|
19
|
+
escaped its fallback. The compilers stop wrapping fragment / mixed component children in
|
|
20
|
+
`_$escape` (they are values; escaping them too double-escaped through
|
|
21
|
+
`<Comp>{props.children}</Comp>`), and a single-expression fragment at a hole keeps the
|
|
22
|
+
hole's wrap. Live-hole tags ride the wrapper and `$slot` survives the array copy, so
|
|
23
|
+
frames behave as before.
|
|
24
|
+
|
|
25
|
+
- ab4c40c: Object-valued `style` / `class` bindings are read in the TRACKED half of their effect. `style()` and `className()` enumerate their object in the effect's untracked commit phase, so a proxy value — a store sub-object (`style={state.style}`, `class={row.classes}`), merged props, anything arriving through a spread — was identity-reactive only: in-place key mutations never re-applied, and every leaf read tripped `STRICT_READ_UNTRACKED` in dev. Both compilers now wrap the compute value of a non-inline `style={expr}` / `class={expr}` in a new compiler primitive, `readShallow()`, and `spread()` applies it to those two keys as it copies. `readShallow` is an identity passthrough for strings, plain objects and proxy-free arrays (a fresh literal is already the compute's own — the common case pays a `typeof`); a proxy is copied with one `ownKeys` trap (its own trap keeps the key set tracked) plus one tracked read per key; arrays are re-mapped only when an element is a proxy. Inline literals are untouched — they already compile per property. Provably-string expressions (string/template literals, concatenation) and literal objects/arrays skip the wrap at compile time. New Tier-1 bench `style-class-object`: plain-object rows at parity; store-backed rows go from identity-only (and, in dev, ~97 ms per 500 elements of diagnostics) to per-key reactive at ~3.5 ms. Octane svg-dashboard (prod build, store-backed style/attrs through spread): mount at parity, style_spread_pulse −6%, select_toggle −7%.
|
|
26
|
+
|
|
27
|
+
`spread()` shares the same enumeration: its compute half copied the source with `for…in` + `hasOwn`, which on a proxy source (`merge()`/`omit()`, `{...props}` in a component, store records — nearly every spread) is an `ownKeys` trap plus two `getOwnPropertyDescriptor` traps per key, each allocating a descriptor and a getter closure. It now takes the key set from one `Reflect.ownKeys` trap (the trap keeps the key set tracked) and reads each string key once; plain sources use `Object.keys`, the exact own-enumerable set the old loop yielded. New Tier-1 bench `spread-enumerate` (500 elements, 8 keys): `merge(static, reactive)` 376 → 537 ops/s (+43%), store record 253 → 415 ops/s (+64%), plain object at parity.
|
|
28
|
+
|
|
29
|
+
## 2.0.0-rc.7
|
|
30
|
+
|
|
31
|
+
### Patch Changes
|
|
32
|
+
|
|
33
|
+
- ead7b1a: Keep hydration IDs aligned when an intrinsic element has a ref and one reactive spread.
|
|
34
|
+
- b3586e8: Validate document-shell templates in the document context (#3259). The `validate` pass round-trips templates through a body-context fragment parse, which strips `<html>`/`<head>`/`<body>` wrappers no matter how well-formed the markup — so once #3099 made validate failures compile errors, a root component owning the document shell failed to compile in plain client mode, and merely importing it (the jsdom component-test configuration) was fatal. Shell-rooted templates now parse as a document and the shell element is compared back — the analogue of the synthetic `<table>` wrap for table partials, in both the Babel plugin and the native compiler. Genuine restructuring (an implied `<head>`, flow content in `<head>`, a `<p>` split in `<body>`) still errors. Since `<template>` parsing flattens shells, actually client-creating one now throws a descriptive dev-mode error from `template()` pointing at `hydrate()` — the failure moved from every import to the one broken act.
|
|
35
|
+
- d601119: Remove the experimental patch channel and patch-mode list driver (always opt-in, never default). Graph-native regions own value delivery and the unified-For design owns list structure, so the channel's parallel delivery machinery is retired: `patch.ts`/`patch-driver.ts` deleted, the compiler-contract exports (`registerPatch`/`registerRowOps`/`registerSlotPatch`/`patchableRaw`, `patchDriver`/`rowProof`/`driveList`) removed, the `patchDriver` compiler option dropped from both compilers, the insert `$ll` seam stripped, and the write-side channel struct dieted to the single written-keys bound (`t.wk`) the core fold/notify paths actually use. Store-family app bundles reclaim up to ~900 B brotli; every measured tier shrinks.
|
|
36
|
+
|
|
3
37
|
## 2.0.0-rc.6
|
|
4
38
|
|
|
5
39
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -120,6 +120,20 @@ Source syntax frontend. `"auto"` routes `.tsrx` files through the TSRX frontend
|
|
|
120
120
|
|
|
121
121
|
Emit hydratable markers.
|
|
122
122
|
|
|
123
|
+
### dev
|
|
124
|
+
|
|
125
|
+
- Type: `boolean`
|
|
126
|
+
- Default: `false`
|
|
127
|
+
|
|
128
|
+
Development output. With `hydratable`, emits the hydration walk validation helpers.
|
|
129
|
+
|
|
130
|
+
### componentNames
|
|
131
|
+
|
|
132
|
+
- Type: `boolean`
|
|
133
|
+
- Default: `false`
|
|
134
|
+
|
|
135
|
+
DOM output only. Emit the tag as written in source as a third `createComponent` argument — `<Home />` compiles to `createComponent(Home, props, "Home")`, `<Ui.Button />` to `"Ui.Button"` — so the dev and observe runtimes label each component's owner (`<Home>` in diagnostic `ownerPath`s and attribution chains) even after a minifier renames the function or a `lazy()`/HMR wrapper hides it. The production runtime ignores the argument; SSR and universal output are unaffected. `@solidjs/vite-plugin` turns this on for its dev and `observe` postures.
|
|
136
|
+
|
|
123
137
|
### delegateEvents
|
|
124
138
|
|
|
125
139
|
- Type: `boolean`
|
package/index.js
CHANGED
|
@@ -2821,170 +2821,6 @@ attributes,
|
|
|
2821
2821
|
|
|
2822
2822
|
}
|
|
2823
2823
|
|
|
2824
|
-
/**
|
|
2825
|
-
* Patch-mode eligibility + emission (DESIGN-PATCH-CHANNEL.md, PR-C).
|
|
2826
|
-
*
|
|
2827
|
-
* A template scope qualifies for patch mode when EVERY dynamic binding's
|
|
2828
|
-
* value is a pure expression over member reads of ONE stable subject
|
|
2829
|
-
* identifier (Tier 1: bare member chains; Tier 2: ternary/binary/logical/
|
|
2830
|
-
* template-literal/unary compositions of Tier-1 reads and literals).
|
|
2831
|
-
* Anything else — calls, assignments, functions, foreign identifiers —
|
|
2832
|
-
* disqualifies the SCOPE (per-binding islands remain future work; v1 is
|
|
2833
|
-
* all-or-nothing per template scope, matching the fixture shape).
|
|
2834
|
-
*
|
|
2835
|
-
* Emission (dual driver, shared body):
|
|
2836
|
-
*
|
|
2837
|
-
* _$patchDriver(subject, (_n$, _p$, _f$) => {
|
|
2838
|
-
* let _v$;
|
|
2839
|
-
* if (_f$ || (_v$ = <expr(_n$)>) !== <expr(_p$)>) <setAttr(..., _v$)>;
|
|
2840
|
-
* ...
|
|
2841
|
-
* });
|
|
2842
|
-
*
|
|
2843
|
-
* The runtime driver registers on the store's patch channel when the
|
|
2844
|
-
* subject is a patchable record, else falls back to a tracked force-mode
|
|
2845
|
-
* effect running the same body (reads through the subject track; force
|
|
2846
|
-
* short-circuits every compare, so `prev` is never dereferenced there).
|
|
2847
|
-
* Semantics are therefore IDENTICAL either way; patch mode only changes
|
|
2848
|
-
* who dispatches.
|
|
2849
|
-
*/
|
|
2850
|
-
|
|
2851
|
-
// Node types allowed inside an eligible binding expression (Tier 1+2).
|
|
2852
|
-
function isEligibleExpr(node, subject) {
|
|
2853
|
-
switch (node.type) {
|
|
2854
|
-
case "Identifier":
|
|
2855
|
-
return node.name === subject || node.name === "undefined";
|
|
2856
|
-
case "MemberExpression":{
|
|
2857
|
-
const m = node;
|
|
2858
|
-
if (m.computed) {
|
|
2859
|
-
if (!t__namespace.isStringLiteral(m.property) && !t__namespace.isNumericLiteral(m.property)) return false;
|
|
2860
|
-
} else if (!t__namespace.isIdentifier(m.property)) {
|
|
2861
|
-
return false;
|
|
2862
|
-
}
|
|
2863
|
-
return isEligibleExpr(m.object, subject);
|
|
2864
|
-
}
|
|
2865
|
-
case "StringLiteral":
|
|
2866
|
-
case "NumericLiteral":
|
|
2867
|
-
case "BooleanLiteral":
|
|
2868
|
-
case "NullLiteral":
|
|
2869
|
-
case "BigIntLiteral":
|
|
2870
|
-
return true;
|
|
2871
|
-
case "ConditionalExpression":{
|
|
2872
|
-
const c = node;
|
|
2873
|
-
return (
|
|
2874
|
-
isEligibleExpr(c.test, subject) &&
|
|
2875
|
-
isEligibleExpr(c.consequent, subject) &&
|
|
2876
|
-
isEligibleExpr(c.alternate, subject));
|
|
2877
|
-
|
|
2878
|
-
}
|
|
2879
|
-
case "BinaryExpression":{
|
|
2880
|
-
const b = node;
|
|
2881
|
-
if (b.operator === "in" || b.operator === "instanceof") return false;
|
|
2882
|
-
return isEligibleExpr(b.left, subject) && isEligibleExpr(b.right, subject);
|
|
2883
|
-
}
|
|
2884
|
-
case "LogicalExpression":{
|
|
2885
|
-
const l = node;
|
|
2886
|
-
return isEligibleExpr(l.left, subject) && isEligibleExpr(l.right, subject);
|
|
2887
|
-
}
|
|
2888
|
-
case "UnaryExpression":{
|
|
2889
|
-
const u = node;
|
|
2890
|
-
if (u.operator === "delete" || u.operator === "throw") return false;
|
|
2891
|
-
return isEligibleExpr(u.argument, subject);
|
|
2892
|
-
}
|
|
2893
|
-
case "TemplateLiteral":
|
|
2894
|
-
return node.expressions.every((e) =>
|
|
2895
|
-
t__namespace.isExpression(e) ? isEligibleExpr(e, subject) : false
|
|
2896
|
-
);
|
|
2897
|
-
case "ParenthesizedExpression":
|
|
2898
|
-
return isEligibleExpr(node.expression, subject);
|
|
2899
|
-
default:
|
|
2900
|
-
return false;
|
|
2901
|
-
}
|
|
2902
|
-
}
|
|
2903
|
-
|
|
2904
|
-
/** Find the single subject: the root identifier of the FIRST member chain
|
|
2905
|
-
* encountered. Every other read must root at the same name. */
|
|
2906
|
-
function findSubject(node) {
|
|
2907
|
-
switch (node.type) {
|
|
2908
|
-
case "MemberExpression":
|
|
2909
|
-
return findSubject(node.object);
|
|
2910
|
-
case "Identifier":
|
|
2911
|
-
return node.name === "undefined" ? null : node.name;
|
|
2912
|
-
case "ConditionalExpression":
|
|
2913
|
-
return (
|
|
2914
|
-
findSubject(node.test) ??
|
|
2915
|
-
findSubject(node.consequent) ??
|
|
2916
|
-
findSubject(node.alternate));
|
|
2917
|
-
|
|
2918
|
-
case "BinaryExpression":
|
|
2919
|
-
case "LogicalExpression":
|
|
2920
|
-
return (
|
|
2921
|
-
findSubject(node.left) ?? findSubject(node.right));
|
|
2922
|
-
|
|
2923
|
-
case "UnaryExpression":
|
|
2924
|
-
return findSubject(node.argument);
|
|
2925
|
-
case "TemplateLiteral":{
|
|
2926
|
-
for (const e of node.expressions) {
|
|
2927
|
-
const s = findSubject(e);
|
|
2928
|
-
if (s) return s;
|
|
2929
|
-
}
|
|
2930
|
-
return null;
|
|
2931
|
-
}
|
|
2932
|
-
case "ParenthesizedExpression":
|
|
2933
|
-
return findSubject(node.expression);
|
|
2934
|
-
default:
|
|
2935
|
-
return null;
|
|
2936
|
-
}
|
|
2937
|
-
}
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
/** Analyze a template scope's dynamic binding values. Returns the subject
|
|
2944
|
-
* when EVERY value is an eligible pure expression over it, else null. */
|
|
2945
|
-
function analyzePatchEligibility(values) {
|
|
2946
|
-
if (values.length === 0) return null;
|
|
2947
|
-
let subject = null;
|
|
2948
|
-
for (const v of values) {
|
|
2949
|
-
const s = findSubject(v);
|
|
2950
|
-
if (s === null) return null; // static-only binding: no dispatch source
|
|
2951
|
-
if (subject === null) subject = s;else
|
|
2952
|
-
if (subject !== s) return null; // multi-subject: Q3 territory, bail in v1
|
|
2953
|
-
}
|
|
2954
|
-
if (subject === null) return null;
|
|
2955
|
-
for (const v of values) {
|
|
2956
|
-
if (!isEligibleExpr(v, subject)) return null;
|
|
2957
|
-
}
|
|
2958
|
-
return { subject };
|
|
2959
|
-
}
|
|
2960
|
-
|
|
2961
|
-
/** Clone `expr` substituting the subject identifier with `replacement`.
|
|
2962
|
-
* Safe because eligibility rejected functions/shadowing constructs. */
|
|
2963
|
-
function substituteSubject(
|
|
2964
|
-
expr,
|
|
2965
|
-
subject,
|
|
2966
|
-
replacement)
|
|
2967
|
-
{
|
|
2968
|
-
const clone = t__namespace.cloneNode(expr, true);
|
|
2969
|
-
const rewrite = (node) => {
|
|
2970
|
-
if (t__namespace.isIdentifier(node) && node.name === subject) return t__namespace.cloneNode(replacement);
|
|
2971
|
-
for (const key of Object.keys(node)) {
|
|
2972
|
-
const value = node[key];
|
|
2973
|
-
if (Array.isArray(value)) {
|
|
2974
|
-
for (let i = 0; i < value.length; i++) {
|
|
2975
|
-
if (value[i] && typeof value[i].type === "string") value[i] = rewrite(value[i]);
|
|
2976
|
-
}
|
|
2977
|
-
} else if (value && typeof value.type === "string") {
|
|
2978
|
-
// Never rewrite non-computed member PROPERTY positions.
|
|
2979
|
-
if (t__namespace.isMemberExpression(node) && key === "property" && !node.computed) continue;
|
|
2980
|
-
node[key] = rewrite(value);
|
|
2981
|
-
}
|
|
2982
|
-
}
|
|
2983
|
-
return node;
|
|
2984
|
-
};
|
|
2985
|
-
return rewrite(clone);
|
|
2986
|
-
}
|
|
2987
|
-
|
|
2988
2824
|
function createTemplate$2(
|
|
2989
2825
|
path,
|
|
2990
2826
|
result,
|
|
@@ -2998,16 +2834,9 @@ wrap)
|
|
|
2998
2834
|
!(result.exprs.length || result.dynamics.length || result.postExprs?.length) &&
|
|
2999
2835
|
decl.declarations.length === 1)
|
|
3000
2836
|
{
|
|
3001
|
-
// Static single-root template: a candidate row function returning it is
|
|
3002
|
-
// trivially pure (no reactive work at all).
|
|
3003
|
-
if (config.patchDriver) recordPureRow(path, result, null);
|
|
3004
2837
|
return decl.declarations[0].init;
|
|
3005
2838
|
} else {
|
|
3006
|
-
const
|
|
3007
|
-
const dynamicsStmt = patched ? patched.stmt : wrapDynamics$1(path, result.dynamics);
|
|
3008
|
-
if (config.patchDriver && (result.dynamics.length === 0 || patched)) {
|
|
3009
|
-
recordPureRow(path, result, patched ? patched.subject : null);
|
|
3010
|
-
}
|
|
2839
|
+
const dynamicsStmt = wrapDynamics$1(path, result.dynamics);
|
|
3011
2840
|
const stmts = [
|
|
3012
2841
|
decl,
|
|
3013
2842
|
...result.exprs,
|
|
@@ -3123,177 +2952,30 @@ function registerTemplate(path, results) {
|
|
|
3123
2952
|
results.decl = t__namespace.variableDeclaration("var", results.declarations);
|
|
3124
2953
|
}
|
|
3125
2954
|
|
|
3126
|
-
/**
|
|
3127
|
-
*
|
|
3128
|
-
*
|
|
3129
|
-
*
|
|
3130
|
-
*
|
|
3131
|
-
*
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
* it (checked before the flat-statement emission inserts our own);
|
|
3135
|
-
* - the template has a single root element (`result.id` — fragments never
|
|
3136
|
-
* reach here) and emitted NO reactive or owned work: dynamics either
|
|
3137
|
-
* absent or all landed in ONE patchDriver body, and `result.exprs` holds
|
|
3138
|
-
* only inert DOM wiring (member-target assignments like `_el$.$$click =
|
|
3139
|
-
* fn` / `_el$.style.cssText = v`, and `_el$.addEventListener(...)`) —
|
|
3140
|
-
* any `insert`/`createComponent`/`memo`/`use`/ref/spread emission is a
|
|
3141
|
-
* call or conditional shape and fails the walk (default-deny);
|
|
3142
|
-
* - the patch subject IS the row parameter. A pure template patching an
|
|
3143
|
-
* OUTER subject would register once per created row on a long-lived
|
|
3144
|
-
* record with no per-row disposal — the foreign-subject leak the runtime
|
|
3145
|
-
* probe never caught.
|
|
3146
|
-
*
|
|
3147
|
-
* Handler/attribute VALUE expressions may be arbitrary user code: stamped
|
|
3148
|
-
* rows are only ever built for real mounts (never speculatively), so their
|
|
3149
|
-
* evaluation timing is identical to the classic path. Event handlers are
|
|
3150
|
-
* not reactive bindings — values evaluate exactly once at build — so the
|
|
3151
|
-
* only ownership divergence is a factory creating owned work in value
|
|
3152
|
-
* position (`onClick={makeHandler(row)}` calling onCleanup), which is not
|
|
3153
|
-
* a supported pattern (owned work belongs in effects/refs; ruled
|
|
3154
|
-
* non-responsibility). Denying evaluation-position calls would cost
|
|
3155
|
-
* legitimate currying to guard it; instead the runtime dev-asserts that a
|
|
3156
|
-
* stamped row's build attaches nothing to the list owner.
|
|
3157
|
-
*
|
|
3158
|
-
* Qualifying functions are recorded and wrapped with `rowProof` at program
|
|
3159
|
-
* exit (postprocess) — the stamp travels with the function object, so
|
|
3160
|
-
* extracted row functions prove at their DEFINITION site and work across
|
|
3161
|
-
* modules, which the runtime probe could never see.
|
|
3162
|
-
*/
|
|
3163
|
-
function recordPureRow(path, result, subject) {
|
|
3164
|
-
const parent = path.parentPath;
|
|
3165
|
-
if (!parent) return;
|
|
3166
|
-
let fn;
|
|
2955
|
+
/** A non-inline object-valued `style` / `class` binding is read in the TRACKED
|
|
2956
|
+
* half of its effect through `readShallow()`: `style()`/`className()` enumerate
|
|
2957
|
+
* their object in the untracked commit phase, so a proxy value (a store
|
|
2958
|
+
* sub-object, merged props) would be identity-reactive only. Skipped when the
|
|
2959
|
+
* expression is provably a string or a fresh literal (`readShallow` would pass
|
|
2960
|
+
* those through anyway; the call is what's saved). */
|
|
2961
|
+
function wrapReadShallow(path, key, value) {
|
|
2962
|
+
if (key !== "class" && key !== "style") return value;
|
|
3167
2963
|
if (
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
t__namespace.
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
parent.parentPath.node.body.length === 1 &&
|
|
3178
|
-
parent.parentPath.parentPath && (
|
|
3179
|
-
t__namespace.isArrowFunctionExpression(parent.parentPath.parentPath.node) ||
|
|
3180
|
-
t__namespace.isFunctionExpression(parent.parentPath.parentPath.node)) &&
|
|
3181
|
-
parent.parentPath.parentPath.node.body === parent.parentPath.node)
|
|
3182
|
-
{
|
|
3183
|
-
fn = parent.parentPath.parentPath.node;
|
|
3184
|
-
}
|
|
3185
|
-
if (!fn || fn.async || fn.generator) return;
|
|
3186
|
-
if (fn.params.length !== 1 || !t__namespace.isIdentifier(fn.params[0])) return;
|
|
3187
|
-
const param = fn.params[0].name;
|
|
3188
|
-
if (subject !== null && subject !== param) return;
|
|
3189
|
-
|
|
3190
|
-
const isLocalMemberTarget = (n) => {
|
|
3191
|
-
if (!t__namespace.isMemberExpression(n) || n.computed) return false;
|
|
3192
|
-
let obj = n.object;
|
|
3193
|
-
while (t__namespace.isMemberExpression(obj) && !obj.computed) obj = obj.object;
|
|
3194
|
-
return t__namespace.isIdentifier(obj);
|
|
3195
|
-
};
|
|
3196
|
-
for (const stmt of result.exprs) {
|
|
3197
|
-
if (!t__namespace.isExpressionStatement(stmt)) return;
|
|
3198
|
-
const e = stmt.expression;
|
|
3199
|
-
if (t__namespace.isAssignmentExpression(e) && e.operator === "=" && isLocalMemberTarget(e.left)) continue;
|
|
3200
|
-
if (
|
|
3201
|
-
t__namespace.isCallExpression(e) &&
|
|
3202
|
-
t__namespace.isMemberExpression(e.callee) &&
|
|
3203
|
-
!e.callee.computed &&
|
|
3204
|
-
t__namespace.isIdentifier(e.callee.property) &&
|
|
3205
|
-
e.callee.property.name === "addEventListener")
|
|
3206
|
-
|
|
3207
|
-
continue;
|
|
3208
|
-
return;
|
|
3209
|
-
}
|
|
3210
|
-
if (result.postExprs?.length) {
|
|
3211
|
-
const data = path.scope.getProgramParent().data;
|
|
3212
|
-
const moduleName = getRendererConfig(path, "dom").moduleName;
|
|
3213
|
-
const rheUid = data.imports?.get(`${moduleName}:runHydrationEvents`);
|
|
3214
|
-
for (const stmt of result.postExprs) {
|
|
3215
|
-
if (
|
|
3216
|
-
!t__namespace.isExpressionStatement(stmt) ||
|
|
3217
|
-
!t__namespace.isCallExpression(stmt.expression) ||
|
|
3218
|
-
!t__namespace.isIdentifier(stmt.expression.callee) ||
|
|
3219
|
-
!rheUid ||
|
|
3220
|
-
stmt.expression.callee.name !== rheUid.name)
|
|
3221
|
-
|
|
3222
|
-
return;
|
|
3223
|
-
}
|
|
3224
|
-
}
|
|
3225
|
-
|
|
3226
|
-
const data = path.scope.getProgramParent().data;
|
|
3227
|
-
(data.pureRows || (data.pureRows = new Set())).add(fn);
|
|
3228
|
-
}
|
|
2964
|
+
t__namespace.isStringLiteral(value) ||
|
|
2965
|
+
t__namespace.isTemplateLiteral(value) ||
|
|
2966
|
+
t__namespace.isBinaryExpression(value) ||
|
|
2967
|
+
t__namespace.isObjectExpression(value) ||
|
|
2968
|
+
// a class array of literals cannot hold a proxy either
|
|
2969
|
+
t__namespace.isArrayExpression(value) &&
|
|
2970
|
+
value.elements.every(
|
|
2971
|
+
(e) => t__namespace.isStringLiteral(e) || t__namespace.isTemplateLiteral(e) || t__namespace.isObjectExpression(e)
|
|
2972
|
+
))
|
|
3229
2973
|
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
* The subject rides along for row-proof analysis (recordPureRow). */
|
|
3236
|
-
function wrapPatchMode(
|
|
3237
|
-
path,
|
|
3238
|
-
dynamics)
|
|
3239
|
-
{
|
|
3240
|
-
const config = getConfig(path);
|
|
3241
|
-
if (dynamics.length === 0) return;
|
|
3242
|
-
const eligibility = analyzePatchEligibility(dynamics.map((d) => d.value));
|
|
3243
|
-
if (!eligibility) return;
|
|
3244
|
-
const subject = eligibility.subject;
|
|
3245
|
-
// The subject must be a stable local binding (not reassigned): row params
|
|
3246
|
-
// and const destructures qualify; anything else falls back to effects.
|
|
3247
|
-
const binding = path.scope.getBinding(subject);
|
|
3248
|
-
if (!binding || !binding.constant) return;
|
|
3249
|
-
// Fixed `$`-suffixed locals, matching wrapDynamics' `_v$`/`_p$` convention
|
|
3250
|
-
// (and byte-parity with the Oxc compiler's emission): substitution only
|
|
3251
|
-
// rewrites subject references, so nothing else in an eligible expression
|
|
3252
|
-
// can collide with these.
|
|
3253
|
-
const nId = t__namespace.identifier("_n$");
|
|
3254
|
-
const pId = t__namespace.identifier("_p$");
|
|
3255
|
-
const fId = t__namespace.identifier("_f$");
|
|
3256
|
-
const stmts = [];
|
|
3257
|
-
let vIndex = 0;
|
|
3258
|
-
for (const d of dynamics) {
|
|
3259
|
-
let value = d.value;
|
|
3260
|
-
if (d.classProperty && !t__namespace.isBooleanLiteral(value) && !t__namespace.isUnaryExpression(value)) {
|
|
3261
|
-
value = t__namespace.unaryExpression("!", t__namespace.unaryExpression("!", value));
|
|
3262
|
-
}
|
|
3263
|
-
const vId = t__namespace.identifier(++vIndex === 1 ? "_v$" : `_v$${vIndex}`);
|
|
3264
|
-
stmts.push(
|
|
3265
|
-
t__namespace.variableDeclaration("const", [
|
|
3266
|
-
t__namespace.variableDeclarator(vId, substituteSubject(value, subject, nId))]
|
|
3267
|
-
)
|
|
3268
|
-
);
|
|
3269
|
-
stmts.push(
|
|
3270
|
-
t__namespace.ifStatement(
|
|
3271
|
-
t__namespace.logicalExpression(
|
|
3272
|
-
"||",
|
|
3273
|
-
t__namespace.cloneNode(fId),
|
|
3274
|
-
t__namespace.binaryExpression("!==", t__namespace.cloneNode(vId), substituteSubject(value, subject, pId))
|
|
3275
|
-
),
|
|
3276
|
-
t__namespace.expressionStatement(
|
|
3277
|
-
setAttr$2(path, d.elem, d.key, t__namespace.cloneNode(vId), {
|
|
3278
|
-
tagName: d.tagName,
|
|
3279
|
-
dynamic: true,
|
|
3280
|
-
styleProperty: d.styleProperty,
|
|
3281
|
-
classProperty: d.classProperty
|
|
3282
|
-
})
|
|
3283
|
-
)
|
|
3284
|
-
)
|
|
3285
|
-
);
|
|
3286
|
-
}
|
|
3287
|
-
const driverId = registerImportMethod(path, config.patchDriver, undefined);
|
|
3288
|
-
return {
|
|
3289
|
-
stmt: t__namespace.expressionStatement(
|
|
3290
|
-
t__namespace.callExpression(driverId, [
|
|
3291
|
-
t__namespace.identifier(subject),
|
|
3292
|
-
t__namespace.arrowFunctionExpression([nId, pId, fId], t__namespace.blockStatement(stmts))]
|
|
3293
|
-
)
|
|
3294
|
-
),
|
|
3295
|
-
subject
|
|
3296
|
-
};
|
|
2974
|
+
return value;
|
|
2975
|
+
return t__namespace.callExpression(
|
|
2976
|
+
registerImportMethod(path, "readShallow", getRendererConfig(path, "dom").moduleName),
|
|
2977
|
+
[value]
|
|
2978
|
+
);
|
|
3297
2979
|
}
|
|
3298
2980
|
|
|
3299
2981
|
function wrapDynamics$1(path, dynamics) {
|
|
@@ -3319,7 +3001,7 @@ function wrapDynamics$1(path, dynamics) {
|
|
|
3319
3001
|
const newValue = t__namespace.identifier("_v$");
|
|
3320
3002
|
return t__namespace.expressionStatement(
|
|
3321
3003
|
t__namespace.callExpression(effectWrapperId, [
|
|
3322
|
-
wrapForEffect(dynamics[0].value),
|
|
3004
|
+
wrapForEffect(wrapReadShallow(path, dynamics[0].key, dynamics[0].value)),
|
|
3323
3005
|
t__namespace.arrowFunctionExpression(
|
|
3324
3006
|
prevValue ? [newValue, prevValue] : [newValue],
|
|
3325
3007
|
t__namespace.blockStatement([
|
|
@@ -3354,7 +3036,7 @@ function wrapDynamics$1(path, dynamics) {
|
|
|
3354
3036
|
}
|
|
3355
3037
|
|
|
3356
3038
|
properties.push(propIdent);
|
|
3357
|
-
values.push(t__namespace.objectProperty(propIdent, value));
|
|
3039
|
+
values.push(t__namespace.objectProperty(propIdent, wrapReadShallow(path, key, value)));
|
|
3358
3040
|
|
|
3359
3041
|
if (key === "class" || key === "style" || isStatefulDOMProperty(tagName, key)) {
|
|
3360
3042
|
statements.push(
|
|
@@ -3809,9 +3491,8 @@ escapeLiterals)
|
|
|
3809
3491
|
expression.wontEscape = true;
|
|
3810
3492
|
return expression;
|
|
3811
3493
|
} else if (t.isJSXFragment(expression) && fragmentWillSelfEscape(expression)) {
|
|
3812
|
-
// The fragment will later be transformed into
|
|
3813
|
-
// `escape` helper passes through unchanged
|
|
3814
|
-
// accessor function or an `_$ssr(...)` SSRNode object (see
|
|
3494
|
+
// The fragment will later be transformed into an `_$ssr(...)` SSRNode
|
|
3495
|
+
// object the `escape` helper passes through unchanged (see
|
|
3815
3496
|
// `fragmentWillSelfEscape`). Wrapping it in another `_$escape(...)`
|
|
3816
3497
|
// here would be a guaranteed no-op, so leave the fragment in place
|
|
3817
3498
|
// and let the later traversal emit the inner form directly.
|
|
@@ -3839,23 +3520,16 @@ function escapeTemplateQuasis(expression, attr) {
|
|
|
3839
3520
|
// Predicts whether a JSXFragment AST will compile to a single runtime
|
|
3840
3521
|
// value for which the outer `_$escape(...)` wrap is a no-op. Must stay
|
|
3841
3522
|
// conservative: any shape this returns `true` for must, when later
|
|
3842
|
-
// transformed, produce
|
|
3843
|
-
//
|
|
3523
|
+
// transformed, produce an escape-immune runtime value. When in doubt,
|
|
3524
|
+
// return false so the outer `_$escape` wrap is kept.
|
|
3525
|
+
//
|
|
3526
|
+
// The one recognized shape is `<><native /></>` — a single native
|
|
3527
|
+
// (non-component) JSXElement, whose `createTemplate` output is
|
|
3528
|
+
// `_$ssr(_tmpl$N, …)`: an SSRNode object `escape` passes through.
|
|
3844
3529
|
//
|
|
3845
|
-
//
|
|
3846
|
-
//
|
|
3847
|
-
//
|
|
3848
|
-
// `isDynamic({ checkMember: true })` (member access, call, tagged
|
|
3849
|
-
// template, optional variants, `in` checks). `createTemplate`
|
|
3850
|
-
// emits `_$memo(() => _$escape(expr))`; the memo returns a
|
|
3851
|
-
// function accessor at runtime and `escape(fn)` is a pass-through.
|
|
3852
|
-
// Nested-dynamic shapes (conditional/logical carrying dynamic
|
|
3853
|
-
// sub-expressions) are excluded — confirming them needs the full
|
|
3854
|
-
// `isDynamic` traversal and a missed optimization costs only one
|
|
3855
|
-
// runtime no-op call.
|
|
3856
|
-
// B. `<><native /></>` — a single native (non-component) JSXElement.
|
|
3857
|
-
// `createTemplate` emits `_$ssr(_tmpl$N, …)`, which returns an
|
|
3858
|
-
// SSRNode object; `escape(object)` is a pass-through.
|
|
3530
|
+
// A single expression child (`<>{x()}</>`) is NOT immune: it compiles to a
|
|
3531
|
+
// memo the runtime's `escape` defers into (a function's yield is content
|
|
3532
|
+
// like any other), so the hole must keep its wrap.
|
|
3859
3533
|
function fragmentWillSelfEscape(fragment) {
|
|
3860
3534
|
let only = null;
|
|
3861
3535
|
for (const c of fragment.children) {
|
|
@@ -3865,25 +3539,10 @@ function fragmentWillSelfEscape(fragment) {
|
|
|
3865
3539
|
}
|
|
3866
3540
|
if (t__namespace.isJSXExpressionContainer(c) && t__namespace.isJSXEmptyExpression(c.expression))
|
|
3867
3541
|
continue;
|
|
3868
|
-
if (only !== null) return false;
|
|
3869
|
-
|
|
3870
|
-
return false;
|
|
3871
|
-
}
|
|
3872
|
-
if (!only) return false;
|
|
3873
|
-
if (t__namespace.isJSXExpressionContainer(only)) {
|
|
3874
|
-
const expr = only.expression;
|
|
3875
|
-
if (t__namespace.isJSXEmptyExpression(expr)) return false;
|
|
3876
|
-
return (
|
|
3877
|
-
t.isCallExpression(expr) ||
|
|
3878
|
-
t.isOptionalCallExpression(expr) ||
|
|
3879
|
-
t.isTaggedTemplateExpression(expr) ||
|
|
3880
|
-
t.isMemberExpression(expr) ||
|
|
3881
|
-
t.isOptionalMemberExpression(expr) ||
|
|
3882
|
-
t__namespace.isBinaryExpression(expr) && expr.operator === "in");
|
|
3883
|
-
|
|
3542
|
+
if (only !== null || !t__namespace.isJSXElement(c)) return false;
|
|
3543
|
+
only = c;
|
|
3884
3544
|
}
|
|
3885
|
-
|
|
3886
|
-
return false;
|
|
3545
|
+
return only !== null && !isComponent(getTagName(only));
|
|
3887
3546
|
}
|
|
3888
3547
|
|
|
3889
3548
|
function normalizeAttributes(path) {
|
|
@@ -4382,9 +4041,15 @@ path,
|
|
|
4382
4041
|
return memo;
|
|
4383
4042
|
}, []);
|
|
4384
4043
|
|
|
4044
|
+
// The DOM transform handles `ref` outside its spread prop sources.
|
|
4045
|
+
const propAttributes = attributes.filter((attribute) => {
|
|
4046
|
+
const node = attribute.node;
|
|
4047
|
+
return !(t.isJSXAttribute(node) && t.isJSXIdentifier(node.name) && node.name.name === "ref");
|
|
4048
|
+
});
|
|
4049
|
+
|
|
4385
4050
|
let props;
|
|
4386
|
-
if (
|
|
4387
|
-
props = [
|
|
4051
|
+
if (propAttributes.length === 1 && t.isJSXSpreadAttribute(propAttributes[0].node)) {
|
|
4052
|
+
props = [propAttributes[0].node.argument];
|
|
4388
4053
|
} else {
|
|
4389
4054
|
props = [];
|
|
4390
4055
|
let runningObject = [],
|
|
@@ -4477,31 +4142,6 @@ path,
|
|
|
4477
4142
|
return { exprs, template: "", declarations: [], dynamics: [], spreadElement: true };
|
|
4478
4143
|
}
|
|
4479
4144
|
|
|
4480
|
-
// Wrap the *inner* value of a fragment-child accessor with `_$escape` so that
|
|
4481
|
-
// hostile string values returned from reactive accessors cannot be
|
|
4482
|
-
// concatenated raw into the SSR output. Element-child expressions already get
|
|
4483
|
-
// this treatment via `escapeExpression` in `ssr/element.js`; fragment
|
|
4484
|
-
// children reach SSR via a different code path and would otherwise skip the
|
|
4485
|
-
// escape step.
|
|
4486
|
-
//
|
|
4487
|
-
// `expr` is the first entry of `result.exprs` produced by `transformNode`
|
|
4488
|
-
// for a `JSXExpressionContainer`. It is either:
|
|
4489
|
-
// - an arrow function `() => X` (default case)
|
|
4490
|
-
// - a bare callee (`fnRef`, emitted when the expression is `fnRef()` with
|
|
4491
|
-
// no args — see the JSXExpressionContainer branch in shared/transform.js)
|
|
4492
|
-
// - the result of `transformCondition(..., inline=true)`, which also
|
|
4493
|
-
// returns an arrow function
|
|
4494
|
-
// For arrows with an expression body we rewrite in place; for anything else
|
|
4495
|
-
// we conservatively wrap in a new arrow that calls and escapes.
|
|
4496
|
-
function wrapFragmentChildWithEscape(path, expr) {
|
|
4497
|
-
const escape = registerImportMethod(path, "escape", undefined);
|
|
4498
|
-
if (t__namespace.isArrowFunctionExpression(expr) && !t__namespace.isBlockStatement(expr.body)) {
|
|
4499
|
-
expr.body = t__namespace.callExpression(escape, [expr.body]);
|
|
4500
|
-
return expr;
|
|
4501
|
-
}
|
|
4502
|
-
return t__namespace.arrowFunctionExpression([], t__namespace.callExpression(escape, [t__namespace.callExpression(expr, [])]));
|
|
4503
|
-
}
|
|
4504
|
-
|
|
4505
4145
|
function createTemplate$1(
|
|
4506
4146
|
path,
|
|
4507
4147
|
result,
|
|
@@ -4509,19 +4149,16 @@ wrap)
|
|
|
4509
4149
|
{
|
|
4510
4150
|
if (!result.template) {
|
|
4511
4151
|
// `wrap` is true for fragment children and for mixed component children.
|
|
4512
|
-
//
|
|
4513
|
-
//
|
|
4514
|
-
//
|
|
4152
|
+
// Both are VALUES — they flow to whatever hole eventually inserts them,
|
|
4153
|
+
// and that hole's `_$escape` covers everything reachable from the value:
|
|
4154
|
+
// strings, array items, and what a function (this memo) yields when the
|
|
4155
|
+
// resolver calls it. Escaping here as well double-escapes through
|
|
4156
|
+
// `<Comp>{props.children}</Comp>`. The memo exists for hydration-id
|
|
4157
|
+
// alignment with the client, not for escaping.
|
|
4515
4158
|
if (wrap && result.dynamic && getConfig(path).memoWrapper) {
|
|
4516
|
-
// wontEscape is set on JSXElement children whose compiled form is
|
|
4517
|
-
// already a safe SSR node (e.g. `_$ssr(...)` call). Wrapping those in
|
|
4518
|
-
// escape would be a no-op at runtime but obscures intent — skip it.
|
|
4519
|
-
const inner = result.wontEscape ?
|
|
4520
|
-
result.exprs[0] :
|
|
4521
|
-
wrapFragmentChildWithEscape(path, result.exprs[0]);
|
|
4522
4159
|
return t__namespace.callExpression(
|
|
4523
4160
|
registerImportMethod(path, getConfig(path).memoWrapper, undefined),
|
|
4524
|
-
[
|
|
4161
|
+
[result.exprs[0]]
|
|
4525
4162
|
);
|
|
4526
4163
|
}
|
|
4527
4164
|
return result.exprs[0];
|
|
@@ -5278,11 +4915,24 @@ node)
|
|
|
5278
4915
|
return t__namespace.stringLiteral(`${node.namespace.name}:${node.name.name}`);
|
|
5279
4916
|
}
|
|
5280
4917
|
|
|
4918
|
+
/**
|
|
4919
|
+
* The tag as written in source (`Home`, `Ui.Button`, `this.Row`) — the label
|
|
4920
|
+
* `componentNames` emits. Read before `convertComponentIdentifier` since that
|
|
4921
|
+
* retypes the JSX identifier nodes in place.
|
|
4922
|
+
*/
|
|
4923
|
+
function jsxTagName(node) {
|
|
4924
|
+
if (t__namespace.isJSXIdentifier(node)) return thisTagIdentifiers.has(node) ? "this" : node.name;
|
|
4925
|
+
if (t__namespace.isJSXMemberExpression(node))
|
|
4926
|
+
return `${jsxTagName(node.object)}.${jsxTagName(node.property)}`;
|
|
4927
|
+
return `${node.namespace.name}:${node.name.name}`;
|
|
4928
|
+
}
|
|
4929
|
+
|
|
5281
4930
|
function transformComponent(
|
|
5282
4931
|
path)
|
|
5283
4932
|
{
|
|
5284
4933
|
let exprs = [],
|
|
5285
4934
|
config = getConfig(path),
|
|
4935
|
+
tagName = jsxTagName(path.node.openingElement.name),
|
|
5286
4936
|
tagId = convertComponentIdentifier(path.node.openingElement.name),
|
|
5287
4937
|
props = [],
|
|
5288
4938
|
runningObject = [],
|
|
@@ -5551,13 +5201,20 @@ path)
|
|
|
5551
5201
|
props = [t__namespace.callExpression(registerImportMethod(path, "mergeProps"), props)];
|
|
5552
5202
|
}
|
|
5553
5203
|
const componentArgs = [tagId, props[0]];
|
|
5204
|
+
// `componentNames` carries the source tag name into the call so the
|
|
5205
|
+
// dev/observe runtimes can label the owner after minification renames the
|
|
5206
|
+
// function. DOM output only: SSR inlines the call below and the universal
|
|
5207
|
+
// renderer's `createComponent` is user code with a two-argument contract.
|
|
5208
|
+
if (config.componentNames && config.generate === "dom") {
|
|
5209
|
+
componentArgs.push(t__namespace.stringLiteral(tagName));
|
|
5210
|
+
}
|
|
5554
5211
|
// SSR's `createComponent` is literally `Comp(props || {})`. Since the
|
|
5555
5212
|
// compiler always emits a real `props[0]` object expression above (see the
|
|
5556
5213
|
// `props.push(t.objectExpression(runningObject))` line), the `|| {}` fallback
|
|
5557
5214
|
// never fires in compiled output. Inline to a direct `Comp(props)` call to
|
|
5558
5215
|
// drop one function-call frame per component invocation. (DOM/dev modes
|
|
5559
5216
|
// keep the wrapper since it does real work — `untrack`, dev metadata.)
|
|
5560
|
-
if (
|
|
5217
|
+
if (config.generate === "ssr") {
|
|
5561
5218
|
exprs.push(t__namespace.callExpression(tagId, [props[0]]));
|
|
5562
5219
|
} else {
|
|
5563
5220
|
exprs.push(t__namespace.callExpression(registerImportMethod(path, "createComponent"), componentArgs));
|
|
@@ -5749,6 +5406,13 @@ function getTargetFunctionParent(path, parent) {
|
|
|
5749
5406
|
return current;
|
|
5750
5407
|
}
|
|
5751
5408
|
|
|
5409
|
+
/**
|
|
5410
|
+
* JSX tag identifiers `transformThis` rewrote from `this` to the `_self$`
|
|
5411
|
+
* capture, so `componentNames` can label `<this.Row />` by its source text
|
|
5412
|
+
* rather than the generated uid.
|
|
5413
|
+
*/
|
|
5414
|
+
const thisTagIdentifiers = new WeakSet();
|
|
5415
|
+
|
|
5752
5416
|
function transformThis(path) {
|
|
5753
5417
|
const parent = path.scope.getFunctionParent();
|
|
5754
5418
|
let thisId, inserted;
|
|
@@ -5769,7 +5433,9 @@ function transformThis(path) {
|
|
|
5769
5433
|
const current = getTargetFunctionParent(path, parent);
|
|
5770
5434
|
if (current === parent) {
|
|
5771
5435
|
thisId || (thisId = path.scope.generateUidIdentifier("self$"));
|
|
5772
|
-
|
|
5436
|
+
const selfTag = t__namespace.jsxIdentifier(thisId.name);
|
|
5437
|
+
thisTagIdentifiers.add(selfTag);
|
|
5438
|
+
source.replaceWith(selfTag);
|
|
5773
5439
|
|
|
5774
5440
|
if (path.node.closingElement) {
|
|
5775
5441
|
path.node.closingElement.name = path.node.openingElement.name;
|
|
@@ -14283,6 +13949,29 @@ function serialize(node, options) {
|
|
|
14283
13949
|
}
|
|
14284
13950
|
return serializeChildNodes(node, opts);
|
|
14285
13951
|
}
|
|
13952
|
+
/**
|
|
13953
|
+
* Serializes an AST element node to an HTML string, including the element node.
|
|
13954
|
+
*
|
|
13955
|
+
* @example
|
|
13956
|
+
*
|
|
13957
|
+
* ```js
|
|
13958
|
+
* const parse5 = require('parse5');
|
|
13959
|
+
*
|
|
13960
|
+
* const document = parse5.parseFragment('<div>Hello, <b>world</b>!</div>');
|
|
13961
|
+
*
|
|
13962
|
+
* // Serializes the <div> element.
|
|
13963
|
+
* const str = parse5.serializeOuter(document.childNodes[0]);
|
|
13964
|
+
*
|
|
13965
|
+
* console.log(str); //> '<div>Hello, <b>world</b>!</div>'
|
|
13966
|
+
* ```
|
|
13967
|
+
*
|
|
13968
|
+
* @param node Node to serialize.
|
|
13969
|
+
* @param options Serialization options.
|
|
13970
|
+
*/
|
|
13971
|
+
function serializeOuter(node, options) {
|
|
13972
|
+
const opts = { ...defaultOpts, ...options };
|
|
13973
|
+
return serializeNode(node, opts);
|
|
13974
|
+
}
|
|
14286
13975
|
function serializeChildNodes(parentNode, options) {
|
|
14287
13976
|
let html = '';
|
|
14288
13977
|
// Get container of the child nodes
|
|
@@ -14416,6 +14105,29 @@ function innerHTML(htmlFragment) {
|
|
|
14416
14105
|
return serialize(parsedFragment);
|
|
14417
14106
|
}
|
|
14418
14107
|
|
|
14108
|
+
/**
|
|
14109
|
+
* A document shell (`<html>`/`<head>`/`<body>` root) can never round-trip a
|
|
14110
|
+
* body-context fragment parse — the parser strips those wrappers no matter
|
|
14111
|
+
* how well-formed the markup is — so it is parsed as a DOCUMENT instead and
|
|
14112
|
+
* the shell element serialized back out (#3259). The same "used in the right
|
|
14113
|
+
* place" assumption the synthetic `<table>` makes for table partials: a
|
|
14114
|
+
* shell template is hydrated against a real document, not client-created.
|
|
14115
|
+
* Restructuring inside the shell still mismatches — an implied `<head>`,
|
|
14116
|
+
* flow content hoisted out of `<head>`, a `<p>` split in `<body>` — so the
|
|
14117
|
+
* #3099 guarantee holds for markup a browser would actually rebuild.
|
|
14118
|
+
*/
|
|
14119
|
+
function documentShell(html, tag) {
|
|
14120
|
+
const document = parse(html);
|
|
14121
|
+
const htmlElement = document.childNodes.find(
|
|
14122
|
+
(node) => node.tagName === "html"
|
|
14123
|
+
);
|
|
14124
|
+
const shell =
|
|
14125
|
+
tag === "html" ?
|
|
14126
|
+
htmlElement :
|
|
14127
|
+
htmlElement.childNodes.find((node) => node.tagName === tag);
|
|
14128
|
+
return serializeOuter(shell);
|
|
14129
|
+
}
|
|
14130
|
+
|
|
14419
14131
|
/**
|
|
14420
14132
|
* Returns an object with information when the markup is invalid
|
|
14421
14133
|
*
|
|
@@ -14486,7 +14198,8 @@ function isInvalidMarkup(html) {
|
|
|
14486
14198
|
}
|
|
14487
14199
|
|
|
14488
14200
|
/** Parse HTML. `browser` is a string with the supposed resulting html of a real `innerHTML` call */
|
|
14489
|
-
const
|
|
14201
|
+
const shell = /^<(html|head|body)>/.exec(html);
|
|
14202
|
+
const browser = shell ? documentShell(html, shell[1]) : innerHTML(html);
|
|
14490
14203
|
|
|
14491
14204
|
if (html.toLowerCase() !== browser.toLowerCase()) {
|
|
14492
14205
|
return {
|
|
@@ -14547,31 +14260,6 @@ var postprocess = (path, state) => {
|
|
|
14547
14260
|
domTemplates.length > 0 && appendTemplates$1(path, domTemplates);
|
|
14548
14261
|
ssrTemplates.length > 0 && appendTemplates(path, ssrTemplates);
|
|
14549
14262
|
}
|
|
14550
|
-
|
|
14551
|
-
// Compile-time row proofs (DESIGN-PATCH-CHANNEL §3c): wrap each function
|
|
14552
|
-
// recorded by recordPureRow with the runtime's `rowProof` marker so the
|
|
14553
|
-
// patch-mode list driver can engage on proven-pure rows — admission is
|
|
14554
|
-
// decided here, statically; there is no runtime purity probe. The stamp
|
|
14555
|
-
// travels with the function object, so extracted row functions qualify at
|
|
14556
|
-
// their definition site.
|
|
14557
|
-
if (data.pureRows?.size) {
|
|
14558
|
-
const rowProofId = registerImportMethod(
|
|
14559
|
-
path,
|
|
14560
|
-
"rowProof",
|
|
14561
|
-
getRendererConfig(path, "dom").moduleName
|
|
14562
|
-
);
|
|
14563
|
-
const pureRows = data.pureRows;
|
|
14564
|
-
path.traverse({
|
|
14565
|
-
"ArrowFunctionExpression|FunctionExpression"(fnPath) {
|
|
14566
|
-
if (!pureRows.has(fnPath.node)) return;
|
|
14567
|
-
pureRows.delete(fnPath.node);
|
|
14568
|
-
fnPath.replaceWith(
|
|
14569
|
-
t__namespace.callExpression(t__namespace.cloneNode(rowProofId), [fnPath.node])
|
|
14570
|
-
);
|
|
14571
|
-
fnPath.skip();
|
|
14572
|
-
}
|
|
14573
|
-
});
|
|
14574
|
-
}
|
|
14575
14263
|
};
|
|
14576
14264
|
|
|
14577
14265
|
const config = {
|
|
@@ -14580,6 +14268,7 @@ const config = {
|
|
|
14580
14268
|
generate: "dom",
|
|
14581
14269
|
hydratable: false,
|
|
14582
14270
|
dev: false,
|
|
14271
|
+
componentNames: false,
|
|
14583
14272
|
delegateEvents: true,
|
|
14584
14273
|
delegatedEvents: [],
|
|
14585
14274
|
builtIns: [
|
|
@@ -14603,7 +14292,6 @@ const config = {
|
|
|
14603
14292
|
contextToCustomElements: true,
|
|
14604
14293
|
staticMarker: "@static",
|
|
14605
14294
|
effectWrapper: "effect",
|
|
14606
|
-
patchDriver: false,
|
|
14607
14295
|
memoWrapper: "memo",
|
|
14608
14296
|
validate: true,
|
|
14609
14297
|
inlineStyles: true,
|
|
@@ -14619,9 +14307,6 @@ var preprocess = (path, state) => {
|
|
|
14619
14307
|
delete file.ast.tsrxStyle;
|
|
14620
14308
|
}
|
|
14621
14309
|
const merged = file.metadata.config = Object.assign({}, config, state.opts);
|
|
14622
|
-
// Boolean opt-in parity with the native loader: `patchDriver: true` means
|
|
14623
|
-
// the default import name (downstream code uses the value AS the name).
|
|
14624
|
-
if (merged.patchDriver === true) merged.patchDriver = "patchDriver";
|
|
14625
14310
|
const lib = merged.requireImportSource;
|
|
14626
14311
|
if (lib) {
|
|
14627
14312
|
const comments = file.ast.comments ?? [];
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solidjs/babel-plugin",
|
|
3
3
|
"description": "Babel compiler plugin for Solid templates",
|
|
4
|
-
"version": "2.0.0-rc.
|
|
4
|
+
"version": "2.0.0-rc.8",
|
|
5
5
|
"author": "Ryan Carniato",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -24,8 +24,7 @@
|
|
|
24
24
|
"@babel/plugin-syntax-jsx": "^7.18.6",
|
|
25
25
|
"@babel/types": "^7.20.7",
|
|
26
26
|
"html-entities": "2.3.3",
|
|
27
|
-
"parse5": "^7.1.2"
|
|
28
|
-
"validate-html-nesting": "^1.2.1"
|
|
27
|
+
"parse5": "^7.1.2"
|
|
29
28
|
},
|
|
30
29
|
"peerDependencies": {
|
|
31
30
|
"@babel/core": "^7.20.12",
|