@solidjs/babel-plugin 2.0.0-rc.4 → 2.0.0-rc.6
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 +33 -0
- package/README.md +38 -7
- package/index.js +3534 -25
- package/package.json +10 -3
package/index.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
var SyntaxJSX = require('@babel/plugin-syntax-jsx');
|
|
4
4
|
var t$2 = require('@babel/types');
|
|
5
|
-
var helperModuleImports = require('@babel/helper-module-imports');
|
|
6
5
|
var htmlEntities = require('html-entities');
|
|
6
|
+
var helperModuleImports = require('@babel/helper-module-imports');
|
|
7
7
|
|
|
8
8
|
function _interopNamespaceDefault(e) {
|
|
9
9
|
var n = Object.create(null);
|
|
@@ -1520,7 +1520,11 @@ value,
|
|
|
1520
1520
|
const isLocked = isLockedDOMProperty(tagName, name);
|
|
1521
1521
|
|
|
1522
1522
|
if (isChildProp || namespace === "prop" || isLocked) {
|
|
1523
|
-
|
|
1523
|
+
// Locked/stateful DOM properties (value/checked/...) must go through the
|
|
1524
|
+
// runtime in hydratable builds so the hydration claim pass can adopt
|
|
1525
|
+
// pre-hydration user state instead of overwriting it (#3182). setProperty
|
|
1526
|
+
// carries the select-microtask and input/textarea nullish special cases.
|
|
1527
|
+
if (config.hydratable && (isLocked || namespace !== "prop")) {
|
|
1524
1528
|
return t$1.callExpression(registerImportMethod(path, "setProperty"), [
|
|
1525
1529
|
elem,
|
|
1526
1530
|
t$1.stringLiteral(name),
|
|
@@ -2330,7 +2334,10 @@ results)
|
|
|
2330
2334
|
}
|
|
2331
2335
|
|
|
2332
2336
|
// properties
|
|
2333
|
-
if (
|
|
2337
|
+
if (
|
|
2338
|
+
staticValue && (
|
|
2339
|
+
ChildProperties.has(key) || tagName === "select" && key === "value"))
|
|
2340
|
+
{
|
|
2334
2341
|
results.exprs.push(
|
|
2335
2342
|
t$1.expressionStatement(
|
|
2336
2343
|
setAttr$2(attribute, elem, key, staticValue, { tagName })
|
|
@@ -2725,7 +2732,6 @@ attributes,
|
|
|
2725
2732
|
const filteredAttributes = [];
|
|
2726
2733
|
const spreadArgs = [];
|
|
2727
2734
|
let runningObject = [];
|
|
2728
|
-
let dynamicSpread = false;
|
|
2729
2735
|
attributes.forEach((attribute) => {
|
|
2730
2736
|
const node = attribute.node;
|
|
2731
2737
|
const key =
|
|
@@ -2744,10 +2750,9 @@ attributes,
|
|
|
2744
2750
|
runningObject = [];
|
|
2745
2751
|
}
|
|
2746
2752
|
|
|
2747
|
-
const s =
|
|
2748
|
-
isDynamic(attribute.get("argument"), {
|
|
2753
|
+
const s = isDynamic(attribute.get("argument"), {
|
|
2749
2754
|
checkMember: true
|
|
2750
|
-
})
|
|
2755
|
+
}) ?
|
|
2751
2756
|
inlineCallExpression(node.argument) :
|
|
2752
2757
|
node.argument;
|
|
2753
2758
|
|
|
@@ -2796,8 +2801,12 @@ attributes,
|
|
|
2796
2801
|
spreadArgs.push(t$1.objectExpression(runningObject));
|
|
2797
2802
|
}
|
|
2798
2803
|
|
|
2804
|
+
// A lone spread — reactive included — passes straight through: spread()
|
|
2805
|
+
// resolves a function source inside its own tracking scopes, and merging
|
|
2806
|
+
// one source would mint a memo that consumes a hydration id the SSR fast
|
|
2807
|
+
// path never allocates (#3105).
|
|
2799
2808
|
const props =
|
|
2800
|
-
spreadArgs.length === 1
|
|
2809
|
+
spreadArgs.length === 1 ?
|
|
2801
2810
|
spreadArgs[0] :
|
|
2802
2811
|
t$1.callExpression(registerImportMethod(path, "mergeProps"), spreadArgs);
|
|
2803
2812
|
|
|
@@ -3091,7 +3100,11 @@ function registerTemplate(path, results) {
|
|
|
3091
3100
|
templateWithClosingTags: results.templateWithClosingTags,
|
|
3092
3101
|
isImportNode: results.isImportNode,
|
|
3093
3102
|
isWrapped: results.isWrapped,
|
|
3094
|
-
renderer: "dom"
|
|
3103
|
+
renderer: "dom",
|
|
3104
|
+
// templates dedupe on markup, so the FIRST site carries the blame
|
|
3105
|
+
// for a validate failure (#3099) — good enough: every site with
|
|
3106
|
+
// this markup has the same problem
|
|
3107
|
+
path
|
|
3095
3108
|
});
|
|
3096
3109
|
}
|
|
3097
3110
|
}
|
|
@@ -4841,7 +4854,15 @@ results)
|
|
|
4841
4854
|
t__namespace.jsxExpressionContainer(value || t__namespace.booleanLiteral(true));
|
|
4842
4855
|
}
|
|
4843
4856
|
} else {
|
|
4844
|
-
addStaticAttr(
|
|
4857
|
+
addStaticAttr(
|
|
4858
|
+
attribute,
|
|
4859
|
+
results,
|
|
4860
|
+
initProps,
|
|
4861
|
+
elem,
|
|
4862
|
+
key,
|
|
4863
|
+
decodedAttrValue(value),
|
|
4864
|
+
hasSpread
|
|
4865
|
+
);
|
|
4845
4866
|
}
|
|
4846
4867
|
});
|
|
4847
4868
|
if (spreadExpr) results.exprs.push(spreadExpr);
|
|
@@ -4851,6 +4872,18 @@ results)
|
|
|
4851
4872
|
return initProps;
|
|
4852
4873
|
}
|
|
4853
4874
|
|
|
4875
|
+
// A JSX string attribute prints its `extra.raw` — the source text, entities
|
|
4876
|
+
// included — so `normal="Search…"` reached the host's setProp as the
|
|
4877
|
+
// six raw characters (#3127, same class as text children). The parser
|
|
4878
|
+
// already decoded the entities into `.value` (that decoded form is what the
|
|
4879
|
+
// DOM generator's template parser produces and what component props receive);
|
|
4880
|
+
// rebuild the literal so the host gets the decoded string. Only for the
|
|
4881
|
+
// attribute's own StringLiteral: an expression container's string is a JS
|
|
4882
|
+
// string, where `…` is six literal characters by JS semantics.
|
|
4883
|
+
function decodedAttrValue(value) {
|
|
4884
|
+
return t__namespace.isStringLiteral(value) ? t__namespace.stringLiteral(value.value) : value;
|
|
4885
|
+
}
|
|
4886
|
+
|
|
4854
4887
|
function addStaticAttr(
|
|
4855
4888
|
path,
|
|
4856
4889
|
results,
|
|
@@ -4893,8 +4926,11 @@ value,
|
|
|
4893
4926
|
function transformChildren(path, results) {
|
|
4894
4927
|
const filteredChildren = filterChildren(path.get("children")),
|
|
4895
4928
|
multi = checkLength(filteredChildren),
|
|
4896
|
-
childNodes = filteredChildren
|
|
4897
|
-
|
|
4929
|
+
childNodes = filteredChildren
|
|
4930
|
+
// `universal: true`: this text feeds the host's createTextNode, so the
|
|
4931
|
+
// shared text branch must not HTML-escape it and must decode entities
|
|
4932
|
+
// (#3127) — element-scoped because dynamic mode mixes renderers.
|
|
4933
|
+
.map((path) => transformNode(path, { universal: true })).
|
|
4898
4934
|
reduce((memo, child) => {
|
|
4899
4935
|
if (!child) return memo;
|
|
4900
4936
|
const i = memo.length;
|
|
@@ -5061,7 +5097,7 @@ attributes,
|
|
|
5061
5097
|
t__namespace.stringLiteral(key),
|
|
5062
5098
|
isContainer ?
|
|
5063
5099
|
node.value.expression :
|
|
5064
|
-
node.value || t__namespace.booleanLiteral(true)
|
|
5100
|
+
decodedAttrValue(node.value) || t__namespace.booleanLiteral(true)
|
|
5065
5101
|
)
|
|
5066
5102
|
);
|
|
5067
5103
|
}
|
|
@@ -5795,11 +5831,23 @@ info = {})
|
|
|
5795
5831
|
t__namespace.isJSXText(node) ||
|
|
5796
5832
|
(staticValue = getStaticExpression(path)) !== false)
|
|
5797
5833
|
{
|
|
5834
|
+
// Universal text is text (#3127): the DOM and SSR generators splice this
|
|
5835
|
+
// string into an HTML template that a parser later unescapes, so static
|
|
5836
|
+
// values are escaped and JSXText keeps its source entities. Universal
|
|
5837
|
+
// text goes straight to the host's `createTextNode` with no parser
|
|
5838
|
+
// downstream — what is written here is what renders — so static values
|
|
5839
|
+
// pass through unescaped and JSX entities decode, exactly as text
|
|
5840
|
+
// reaching a component child already did (component.ts, fragment.ts).
|
|
5841
|
+
// `info.universal` marks children of a universal-rendered element, which
|
|
5842
|
+
// in `generate: "dynamic"` is a per-element fact, not a config-wide one.
|
|
5843
|
+
const universal = info.universal || config.generate === "universal";
|
|
5798
5844
|
const text =
|
|
5799
5845
|
staticValue !== undefined ?
|
|
5800
|
-
info.doNotEscape ?
|
|
5846
|
+
info.doNotEscape || universal ?
|
|
5801
5847
|
String(staticValue) :
|
|
5802
5848
|
escapeHTML(String(staticValue)) :
|
|
5849
|
+
universal ?
|
|
5850
|
+
htmlEntities.decode(trimWhitespace(node.extra?.raw ?? "")) :
|
|
5803
5851
|
trimWhitespace(node.extra?.raw ?? "");
|
|
5804
5852
|
if (!text.length) return null;
|
|
5805
5853
|
const results = {
|
|
@@ -14474,13 +14522,22 @@ var postprocess = (path, state) => {
|
|
|
14474
14522
|
if (typeof html === "string") {
|
|
14475
14523
|
const result = isInvalidMarkup(html);
|
|
14476
14524
|
if (result) {
|
|
14525
|
+
// A compile ERROR, not a warning (#3099): once the validator has
|
|
14526
|
+
// fired, the emitted template is guaranteed not to match its own
|
|
14527
|
+
// positional walk — the browser rebuilds the DOM, and the walk
|
|
14528
|
+
// binds against nodes that moved (crash or silent wrong-node
|
|
14529
|
+
// bindings; under SSR the restructuring desyncs hydration too).
|
|
14530
|
+
// Warn-and-emit put this diagnostic in server stdout while the
|
|
14531
|
+
// browser failed with an unrelated-looking runtime crash. The
|
|
14532
|
+
// error throws from the template's registration site, so
|
|
14533
|
+
// bundlers surface it at the right file and line. `validate:
|
|
14534
|
+
// false` remains the opt-out.
|
|
14477
14535
|
const message =
|
|
14478
|
-
"
|
|
14479
|
-
|
|
14480
|
-
|
|
14481
|
-
|
|
14482
|
-
|
|
14483
|
-
// throw path.buildCodeFrameError();
|
|
14536
|
+
"The HTML provided is malformed and will yield unexpected output when evaluated by a browser.\n" +
|
|
14537
|
+
`User HTML:\n ${result.html}\n` +
|
|
14538
|
+
`Browser HTML:\n ${result.browser}\n` +
|
|
14539
|
+
`Original HTML:\n ${html}`;
|
|
14540
|
+
throw (template.path ?? path).buildCodeFrameError(message);
|
|
14484
14541
|
}
|
|
14485
14542
|
}
|
|
14486
14543
|
}
|
|
@@ -14519,6 +14576,7 @@ var postprocess = (path, state) => {
|
|
|
14519
14576
|
|
|
14520
14577
|
const config = {
|
|
14521
14578
|
moduleName: "@solidjs/web",
|
|
14579
|
+
syntax: "auto",
|
|
14522
14580
|
generate: "dom",
|
|
14523
14581
|
hydratable: false,
|
|
14524
14582
|
dev: false,
|
|
@@ -14554,6 +14612,12 @@ const config = {
|
|
|
14554
14612
|
|
|
14555
14613
|
var preprocess = (path, state) => {
|
|
14556
14614
|
const file = path.hub.file;
|
|
14615
|
+
const parsedMetadata = file.ast.tsrxStyle;
|
|
14616
|
+
if (parsedMetadata) {
|
|
14617
|
+
file.metadata.css = parsedMetadata.css;
|
|
14618
|
+
file.metadata.cssHash = parsedMetadata.cssHash;
|
|
14619
|
+
delete file.ast.tsrxStyle;
|
|
14620
|
+
}
|
|
14557
14621
|
const merged = file.metadata.config = Object.assign({}, config, state.opts);
|
|
14558
14622
|
// Boolean opt-in parity with the native loader: `patchDriver: true` means
|
|
14559
14623
|
// the default import name (downstream code uses the value AS the name).
|
|
@@ -14577,14 +14641,3459 @@ var preprocess = (path, state) => {
|
|
|
14577
14641
|
}
|
|
14578
14642
|
};
|
|
14579
14643
|
|
|
14580
|
-
|
|
14644
|
+
/**
|
|
14645
|
+
* TSRX → Solid JSX desugaring.
|
|
14646
|
+
*
|
|
14647
|
+
* Walks the ESTree AST produced by `@tsrx/core` (before Solid's local
|
|
14648
|
+
* lazy-destructuring transform runs) and lowers every TSRX construct to Solid 2.0 builtIn
|
|
14649
|
+
* component JSX, in place. The result is a plain ESTree TSX program that
|
|
14650
|
+
* `estree-to-babel` converts for the existing JSX pipeline. BuiltIns are
|
|
14651
|
+
* referenced as bare identifiers (`Show`, `For`, …) so the plugin's normal
|
|
14652
|
+
* `builtIns` auto-import machinery resolves them against `moduleName`.
|
|
14653
|
+
*
|
|
14654
|
+
* Lowering contract (mirrored byte-for-byte by the Oxc frontend):
|
|
14655
|
+
* - `@{ body; render }` — expression position: `render` alone when there is no
|
|
14656
|
+
* setup, otherwise `(() => { body; return render; })()`; function-body
|
|
14657
|
+
* position: inline statements ending in `return render`.
|
|
14658
|
+
* - `@if` — `Show` for a single branch, `Switch`/`Match` for chains; `@else`
|
|
14659
|
+
* becomes `fallback`.
|
|
14660
|
+
* - `@for (const x of expr; index i; key k)` — `For`; `key` present emits
|
|
14661
|
+
* `keyed={(x) => k}`, while an index without a key emits `keyed={false}`;
|
|
14662
|
+
* `@empty` becomes `fallback`. RC `For` hands the callback an item accessor
|
|
14663
|
+
* in custom-key and non-keyed modes. The index is an accessor only with a
|
|
14664
|
+
* custom key.
|
|
14665
|
+
* - `@switch` — `Switch` with one `Match when={disc === test}` per `@case`;
|
|
14666
|
+
* `@default` becomes `fallback`.
|
|
14667
|
+
* - `@try/@pending/@catch (e, reset)` — `<Errored fallback={(e, reset) =>
|
|
14668
|
+
* …}><Loading fallback={pending}>{content}</Loading></Errored>`; RC
|
|
14669
|
+
* `Errored` passes an `ErrorAccessor`, so reads of `e` rewrite to calls.
|
|
14670
|
+
* - `<{expr}>` — `<Dynamic component={expr} …>` (deliberate adaptation from
|
|
14671
|
+
* `@tsrx/solid`'s hoisted `dynamic()` factory; semantically equivalent).
|
|
14672
|
+
*
|
|
14673
|
+
* Scoped `<style>` elements are handled and stripped by the preceding style
|
|
14674
|
+
* pass, so they must never reach this transform.
|
|
14675
|
+
*/
|
|
14676
|
+
|
|
14581
14677
|
|
|
14582
14678
|
|
|
14583
14679
|
|
|
14584
|
-
|
|
14585
|
-
|
|
14586
|
-
|
|
14587
|
-
|
|
14680
|
+
|
|
14681
|
+
|
|
14682
|
+
|
|
14683
|
+
|
|
14684
|
+
|
|
14685
|
+
|
|
14686
|
+
|
|
14687
|
+
/** Keys that are never traversed: locations, tooling metadata, and TSRX
|
|
14688
|
+
* keyword-span pointers that carry no semantics of their own. */
|
|
14689
|
+
const SKIP_KEYS$2 = new Set([
|
|
14690
|
+
"type",
|
|
14691
|
+
"loc",
|
|
14692
|
+
"start",
|
|
14693
|
+
"end",
|
|
14694
|
+
"range",
|
|
14695
|
+
"metadata",
|
|
14696
|
+
"leadingComments",
|
|
14697
|
+
"trailingComments",
|
|
14698
|
+
"innerComments",
|
|
14699
|
+
"alternateKeyword",
|
|
14700
|
+
"emptyKeyword"]
|
|
14701
|
+
);
|
|
14702
|
+
|
|
14703
|
+
const RENDER_ENTRY_TYPES = new Set([
|
|
14704
|
+
"JSXElement",
|
|
14705
|
+
"JSXFragment",
|
|
14706
|
+
"JSXText",
|
|
14707
|
+
"JSXCodeBlock",
|
|
14708
|
+
"JSXIfExpression",
|
|
14709
|
+
"JSXForExpression",
|
|
14710
|
+
"JSXSwitchExpression",
|
|
14711
|
+
"JSXTryExpression",
|
|
14712
|
+
"JSXStyleElement"]
|
|
14713
|
+
);
|
|
14714
|
+
|
|
14715
|
+
const VALID_JSX_CHILD_TYPES = new Set([
|
|
14716
|
+
"JSXElement",
|
|
14717
|
+
"JSXFragment",
|
|
14718
|
+
"JSXText",
|
|
14719
|
+
"JSXExpressionContainer",
|
|
14720
|
+
"JSXSpreadChild"]
|
|
14721
|
+
);
|
|
14722
|
+
|
|
14723
|
+
const FUNCTION_TYPES$1 = new Set([
|
|
14724
|
+
"FunctionDeclaration",
|
|
14725
|
+
"FunctionExpression",
|
|
14726
|
+
"ArrowFunctionExpression"]
|
|
14727
|
+
);
|
|
14728
|
+
|
|
14729
|
+
function isNode$3(value) {
|
|
14730
|
+
return (
|
|
14731
|
+
typeof value === "object" &&
|
|
14732
|
+
value !== null &&
|
|
14733
|
+
typeof value.type === "string");
|
|
14734
|
+
|
|
14735
|
+
}
|
|
14736
|
+
|
|
14737
|
+
function fail$2(message, node) {
|
|
14738
|
+
const start = node?.loc?.start;
|
|
14739
|
+
throw new SyntaxError(start ? `${message} (${start.line}:${start.column})` : message);
|
|
14740
|
+
}
|
|
14741
|
+
|
|
14742
|
+
// ---------------------------------------------------------------------------
|
|
14743
|
+
// ESTree builders (converted to Babel shapes later by estree-to-babel)
|
|
14744
|
+
// ---------------------------------------------------------------------------
|
|
14745
|
+
|
|
14746
|
+
function withLoc$2(node, src) {
|
|
14747
|
+
if (src) {
|
|
14748
|
+
if (src.start !== undefined) node.start = src.start;
|
|
14749
|
+
if (src.end !== undefined) node.end = src.end;
|
|
14750
|
+
if (src.loc !== undefined) node.loc = src.loc;
|
|
14751
|
+
}
|
|
14752
|
+
return node;
|
|
14753
|
+
}
|
|
14754
|
+
|
|
14755
|
+
function ident$1(name, src) {
|
|
14756
|
+
return withLoc$2({ type: "Identifier", name }, src);
|
|
14757
|
+
}
|
|
14758
|
+
|
|
14759
|
+
function jsxIdent(name, src) {
|
|
14760
|
+
return withLoc$2({ type: "JSXIdentifier", name }, src);
|
|
14761
|
+
}
|
|
14762
|
+
|
|
14763
|
+
function jsxContainer(expression, src) {
|
|
14764
|
+
return withLoc$2({ type: "JSXExpressionContainer", expression }, src ?? expression);
|
|
14765
|
+
}
|
|
14766
|
+
|
|
14767
|
+
function jsxAttr(name, expression, src) {
|
|
14768
|
+
return withLoc$2(
|
|
14769
|
+
{
|
|
14770
|
+
type: "JSXAttribute",
|
|
14771
|
+
name: jsxIdent(name, src),
|
|
14772
|
+
value: jsxContainer(expression, src ?? expression)
|
|
14773
|
+
},
|
|
14774
|
+
src ?? expression
|
|
14775
|
+
);
|
|
14776
|
+
}
|
|
14777
|
+
|
|
14778
|
+
function jsxElement(name, attributes, children, src) {
|
|
14779
|
+
const selfClosing = children.length === 0;
|
|
14780
|
+
return withLoc$2(
|
|
14781
|
+
{
|
|
14782
|
+
type: "JSXElement",
|
|
14783
|
+
openingElement: withLoc$2(
|
|
14784
|
+
{ type: "JSXOpeningElement", name: jsxIdent(name, src), attributes, selfClosing },
|
|
14785
|
+
src
|
|
14786
|
+
),
|
|
14787
|
+
closingElement: selfClosing ?
|
|
14788
|
+
null :
|
|
14789
|
+
withLoc$2({ type: "JSXClosingElement", name: jsxIdent(name, src) }, src),
|
|
14790
|
+
children
|
|
14791
|
+
},
|
|
14792
|
+
src
|
|
14793
|
+
);
|
|
14794
|
+
}
|
|
14795
|
+
|
|
14796
|
+
function jsxFragment(children, src) {
|
|
14797
|
+
return withLoc$2(
|
|
14798
|
+
{
|
|
14799
|
+
type: "JSXFragment",
|
|
14800
|
+
openingFragment: withLoc$2({ type: "JSXOpeningFragment" }, src),
|
|
14801
|
+
closingFragment: withLoc$2({ type: "JSXClosingFragment" }, src),
|
|
14802
|
+
children
|
|
14803
|
+
},
|
|
14804
|
+
src
|
|
14805
|
+
);
|
|
14806
|
+
}
|
|
14807
|
+
|
|
14808
|
+
function arrow(params, body, src) {
|
|
14809
|
+
return withLoc$2(
|
|
14810
|
+
{
|
|
14811
|
+
type: "ArrowFunctionExpression",
|
|
14812
|
+
id: null,
|
|
14813
|
+
params,
|
|
14814
|
+
body,
|
|
14815
|
+
expression: body.type !== "BlockStatement",
|
|
14816
|
+
async: false,
|
|
14817
|
+
generator: false
|
|
14818
|
+
},
|
|
14819
|
+
src
|
|
14820
|
+
);
|
|
14821
|
+
}
|
|
14822
|
+
|
|
14823
|
+
function blockStatement(body, src) {
|
|
14824
|
+
return withLoc$2({ type: "BlockStatement", body }, src);
|
|
14825
|
+
}
|
|
14826
|
+
|
|
14827
|
+
function returnStatement(argument, src) {
|
|
14828
|
+
return withLoc$2({ type: "ReturnStatement", argument }, src);
|
|
14829
|
+
}
|
|
14830
|
+
|
|
14831
|
+
function iife(statements, src) {
|
|
14832
|
+
return withLoc$2(
|
|
14833
|
+
{
|
|
14834
|
+
type: "CallExpression",
|
|
14835
|
+
callee: arrow([], blockStatement(statements, src), src),
|
|
14836
|
+
arguments: [],
|
|
14837
|
+
optional: false
|
|
14838
|
+
},
|
|
14839
|
+
src
|
|
14840
|
+
);
|
|
14841
|
+
}
|
|
14842
|
+
|
|
14843
|
+
function callOn(callee, src) {
|
|
14844
|
+
return withLoc$2({ type: "CallExpression", callee, arguments: [], optional: false }, src);
|
|
14845
|
+
}
|
|
14846
|
+
|
|
14847
|
+
function strictEquals(left, right, src) {
|
|
14848
|
+
return withLoc$2({ type: "BinaryExpression", operator: "===", left, right }, src);
|
|
14849
|
+
}
|
|
14850
|
+
|
|
14851
|
+
function stringLiteral(value, src) {
|
|
14852
|
+
return withLoc$2({ type: "Literal", value, raw: JSON.stringify(value) }, src);
|
|
14853
|
+
}
|
|
14854
|
+
|
|
14855
|
+
function cloneNode$1(value) {
|
|
14856
|
+
if (Array.isArray(value)) return value.map(cloneNode$1);
|
|
14857
|
+
if (typeof value === "object" && value !== null) {
|
|
14858
|
+
const out = {};
|
|
14859
|
+
for (const key of Object.keys(value)) {
|
|
14860
|
+
out[key] = cloneNode$1(value[key]);
|
|
14861
|
+
}
|
|
14862
|
+
return out;
|
|
14863
|
+
}
|
|
14864
|
+
return value;
|
|
14865
|
+
}
|
|
14866
|
+
|
|
14867
|
+
function accessorLazyPattern(pattern) {
|
|
14868
|
+
const clone = cloneNode$1(pattern);
|
|
14869
|
+
clone.lazy = true;
|
|
14870
|
+
const metadata = clone.metadata ??= {};
|
|
14871
|
+
delete metadata.lazy_id;
|
|
14872
|
+
metadata.lazy_source_accessor = true;
|
|
14873
|
+
return clone;
|
|
14874
|
+
}
|
|
14875
|
+
|
|
14876
|
+
function eagerPattern(pattern) {
|
|
14877
|
+
const clone = cloneNode$1(pattern);
|
|
14878
|
+
clearLazy(clone);
|
|
14879
|
+
return clone;
|
|
14880
|
+
|
|
14881
|
+
function clearLazy(node) {
|
|
14882
|
+
if (node.type === "ObjectPattern" || node.type === "ArrayPattern") node.lazy = false;
|
|
14883
|
+
for (const key of Object.keys(node)) {
|
|
14884
|
+
if (SKIP_KEYS$2.has(key)) continue;
|
|
14885
|
+
const value = node[key];
|
|
14886
|
+
if (Array.isArray(value)) {
|
|
14887
|
+
for (const item of value) if (isNode$3(item)) clearLazy(item);
|
|
14888
|
+
} else if (isNode$3(value)) {
|
|
14889
|
+
clearLazy(value);
|
|
14890
|
+
}
|
|
14891
|
+
}
|
|
14892
|
+
}
|
|
14893
|
+
}
|
|
14894
|
+
|
|
14895
|
+
// ---------------------------------------------------------------------------
|
|
14896
|
+
// Main walk
|
|
14897
|
+
// ---------------------------------------------------------------------------
|
|
14898
|
+
|
|
14899
|
+
function desugarProgram(program) {
|
|
14900
|
+
genericVisit(program);
|
|
14901
|
+
return program;
|
|
14902
|
+
}
|
|
14903
|
+
|
|
14904
|
+
/** Desugars `node`, returning its replacement for expression-shaped slots. */
|
|
14905
|
+
function transform$1(node) {
|
|
14906
|
+
switch (node.type) {
|
|
14907
|
+
case "JSXCodeBlock":
|
|
14908
|
+
return codeBlockToExpression(node);
|
|
14909
|
+
case "JSXIfExpression":
|
|
14910
|
+
return ifToJsx(node);
|
|
14911
|
+
case "JSXForExpression":
|
|
14912
|
+
return forToJsx(node);
|
|
14913
|
+
case "JSXSwitchExpression":
|
|
14914
|
+
return switchToJsx(node);
|
|
14915
|
+
case "JSXTryExpression":
|
|
14916
|
+
return tryToJsx(node);
|
|
14917
|
+
case "JSXStyleElement":
|
|
14918
|
+
return fail$2("A TSRX <style> element survived the scoped style pass", node);
|
|
14919
|
+
case "JSXElement":
|
|
14920
|
+
return desugarElement(node);
|
|
14921
|
+
case "JSXFragment":
|
|
14922
|
+
node.children && (node.children = desugarChildren(node.children));
|
|
14923
|
+
return node;
|
|
14924
|
+
default:
|
|
14925
|
+
if (FUNCTION_TYPES$1.has(node.type) && isNode$3(node.body) && node.body.type === "JSXCodeBlock") {
|
|
14926
|
+
const body = node.body;
|
|
14927
|
+
genericVisit(node, "body");
|
|
14928
|
+
node.body = codeBlockToFunctionBody(body);
|
|
14929
|
+
if (node.type === "ArrowFunctionExpression") node.expression = false;
|
|
14930
|
+
return node;
|
|
14931
|
+
}
|
|
14932
|
+
genericVisit(node);
|
|
14933
|
+
return node;
|
|
14934
|
+
}
|
|
14935
|
+
}
|
|
14936
|
+
|
|
14937
|
+
function genericVisit(node, skipKey) {
|
|
14938
|
+
for (const key of Object.keys(node)) {
|
|
14939
|
+
if (SKIP_KEYS$2.has(key) || key === skipKey) continue;
|
|
14940
|
+
const value = node[key];
|
|
14941
|
+
if (Array.isArray(value)) {
|
|
14942
|
+
for (let i = 0; i < value.length; i++) {
|
|
14943
|
+
if (isNode$3(value[i])) value[i] = transform$1(value[i]);
|
|
14944
|
+
}
|
|
14945
|
+
} else if (isNode$3(value)) {
|
|
14946
|
+
node[key] = transform$1(value);
|
|
14947
|
+
}
|
|
14948
|
+
}
|
|
14949
|
+
}
|
|
14950
|
+
|
|
14951
|
+
// ---------------------------------------------------------------------------
|
|
14952
|
+
// Elements and children
|
|
14953
|
+
// ---------------------------------------------------------------------------
|
|
14954
|
+
|
|
14955
|
+
function desugarElement(el) {
|
|
14956
|
+
const opening = el.openingElement;
|
|
14957
|
+
const isDynamic = !!opening.isDynamic;
|
|
14958
|
+
genericVisit(opening);
|
|
14959
|
+
const children = desugarChildren(el.children ?? []);
|
|
14960
|
+
if (isDynamic) {
|
|
14961
|
+
const nameContainer = opening.name;
|
|
14962
|
+
const componentExpr = nameContainer.expression;
|
|
14963
|
+
const attributes = [
|
|
14964
|
+
jsxAttr("component", componentExpr, nameContainer),
|
|
14965
|
+
...(opening.attributes ?? [])];
|
|
14966
|
+
|
|
14967
|
+
return jsxElement("Dynamic", attributes, children, el);
|
|
14968
|
+
}
|
|
14969
|
+
el.children = children;
|
|
14970
|
+
return el;
|
|
14971
|
+
}
|
|
14972
|
+
|
|
14973
|
+
function desugarChildren(children) {
|
|
14974
|
+
return children.map((child) => {
|
|
14975
|
+
const result = transform$1(child);
|
|
14976
|
+
if (!VALID_JSX_CHILD_TYPES.has(result.type)) return jsxContainer(result, child);
|
|
14977
|
+
return result;
|
|
14978
|
+
});
|
|
14979
|
+
}
|
|
14980
|
+
|
|
14981
|
+
/** Embed an expression as a JSX child: JSX stays structural, everything else
|
|
14982
|
+
* goes through an expression container. */
|
|
14983
|
+
function asChild(expression) {
|
|
14984
|
+
if (expression.type === "JSXElement" || expression.type === "JSXFragment") return expression;
|
|
14985
|
+
return jsxContainer(expression);
|
|
14986
|
+
}
|
|
14987
|
+
|
|
14988
|
+
// ---------------------------------------------------------------------------
|
|
14989
|
+
// Template blocks (implicit statement containers)
|
|
14990
|
+
// ---------------------------------------------------------------------------
|
|
14991
|
+
|
|
14992
|
+
|
|
14993
|
+
|
|
14994
|
+
|
|
14995
|
+
|
|
14996
|
+
|
|
14997
|
+
const LOOP_TYPES = new Set([
|
|
14998
|
+
"ForStatement",
|
|
14999
|
+
"ForInStatement",
|
|
15000
|
+
"ForOfStatement",
|
|
15001
|
+
"WhileStatement",
|
|
15002
|
+
"DoWhileStatement"]
|
|
15003
|
+
);
|
|
15004
|
+
|
|
15005
|
+
/** TSRX constructs are validation boundaries: their blocks are checked when
|
|
15006
|
+
* they desugar, with their own construct label. `@{}` containers become
|
|
15007
|
+
* function bodies (IIFEs) where escaping statements are legal again. */
|
|
15008
|
+
const ESCAPE_BOUNDARY_TYPES = new Set([
|
|
15009
|
+
"JSXCodeBlock",
|
|
15010
|
+
"JSXIfExpression",
|
|
15011
|
+
"JSXForExpression",
|
|
15012
|
+
"JSXSwitchExpression",
|
|
15013
|
+
"JSXTryExpression"]
|
|
15014
|
+
);
|
|
15015
|
+
|
|
15016
|
+
function escapeMessage(kind, construct) {
|
|
15017
|
+
// Match the ecosystem (@tsrx/solid) diagnostics verbatim for @if and @for.
|
|
15018
|
+
if (construct === "@if" || construct === "@else") {
|
|
15019
|
+
if (kind === "return")
|
|
15020
|
+
return "Return statements are not allowed inside TSRX template @if blocks. Move the return before the template output or render conditionally instead.";
|
|
15021
|
+
if (kind === "break")
|
|
15022
|
+
return "Break statements are not allowed inside TSRX template @if blocks.";
|
|
15023
|
+
return "Continue statements are not allowed inside TSRX template @if blocks. Filter before rendering or use conditional output instead.";
|
|
15024
|
+
}
|
|
15025
|
+
if (construct === "@for" || construct === "@empty") {
|
|
15026
|
+
if (kind === "return")
|
|
15027
|
+
return "Return statements are not allowed inside TSRX template for...of loops. Filter the iterable before rendering or use an @empty fallback for empty lists.";
|
|
15028
|
+
if (kind === "break")
|
|
15029
|
+
return "Break statements are not allowed inside TSRX template for...of loops.";
|
|
15030
|
+
return "Continue statements are not allowed inside TSRX template for...of loops. Filter the iterable before rendering.";
|
|
15031
|
+
}
|
|
15032
|
+
const noun = kind === "return" ? "Return" : kind === "break" ? "Break" : "Continue";
|
|
15033
|
+
return `${noun} statements are not allowed inside TSRX template ${construct} blocks.`;
|
|
15034
|
+
}
|
|
15035
|
+
|
|
15036
|
+
/** Reject return/break/continue that would escape a template control-flow
|
|
15037
|
+
* block. Nested functions, loops, switches, and labels open their own escape
|
|
15038
|
+
* targets; nested TSRX constructs validate themselves. */
|
|
15039
|
+
function validateNoControlFlowEscape(entries, construct) {
|
|
15040
|
+
for (const entry of entries) check(entry, 0, 0, new Set());
|
|
15041
|
+
|
|
15042
|
+
function check(node, loops, breakables, labels) {
|
|
15043
|
+
if (FUNCTION_TYPES$1.has(node.type) || ESCAPE_BOUNDARY_TYPES.has(node.type)) return;
|
|
15044
|
+
switch (node.type) {
|
|
15045
|
+
case "ReturnStatement":
|
|
15046
|
+
fail$2(escapeMessage("return", construct), node);
|
|
15047
|
+
break;
|
|
15048
|
+
case "BreakStatement":{
|
|
15049
|
+
const label = isNode$3(node.label) ? node.label.name : null;
|
|
15050
|
+
if (label ? !labels.has(label) : breakables === 0) {
|
|
15051
|
+
fail$2(escapeMessage("break", construct), node);
|
|
15052
|
+
}
|
|
15053
|
+
return;
|
|
15054
|
+
}
|
|
15055
|
+
case "ContinueStatement":{
|
|
15056
|
+
const label = isNode$3(node.label) ? node.label.name : null;
|
|
15057
|
+
if (label ? !labels.has(label) : loops === 0) {
|
|
15058
|
+
fail$2(escapeMessage("continue", construct), node);
|
|
15059
|
+
}
|
|
15060
|
+
return;
|
|
15061
|
+
}
|
|
15062
|
+
case "SwitchStatement":{
|
|
15063
|
+
if (isNode$3(node.discriminant)) check(node.discriminant, loops, breakables, labels);
|
|
15064
|
+
for (const switchCase of node.cases) {
|
|
15065
|
+
check(switchCase, loops, breakables + 1, labels);
|
|
15066
|
+
}
|
|
15067
|
+
return;
|
|
15068
|
+
}
|
|
15069
|
+
case "LabeledStatement":{
|
|
15070
|
+
const withLabel = new Set(labels);
|
|
15071
|
+
withLabel.add(node.label.name);
|
|
15072
|
+
check(node.body, loops, breakables, withLabel);
|
|
15073
|
+
return;
|
|
15074
|
+
}
|
|
15075
|
+
}
|
|
15076
|
+
const nextLoops = LOOP_TYPES.has(node.type) ? loops + 1 : loops;
|
|
15077
|
+
const nextBreakables = LOOP_TYPES.has(node.type) ? breakables + 1 : breakables;
|
|
15078
|
+
for (const key of Object.keys(node)) {
|
|
15079
|
+
if (SKIP_KEYS$2.has(key)) continue;
|
|
15080
|
+
const value = node[key];
|
|
15081
|
+
if (Array.isArray(value)) {
|
|
15082
|
+
for (const item of value) if (isNode$3(item)) check(item, nextLoops, nextBreakables, labels);
|
|
15083
|
+
} else if (isNode$3(value)) {
|
|
15084
|
+
check(value, nextLoops, nextBreakables, labels);
|
|
15085
|
+
}
|
|
15086
|
+
}
|
|
15087
|
+
}
|
|
15088
|
+
}
|
|
15089
|
+
|
|
15090
|
+
function toBlockBody(node) {
|
|
15091
|
+
return node.type === "BlockStatement" ? node.body : [node];
|
|
15092
|
+
}
|
|
15093
|
+
|
|
15094
|
+
/** Split a template block into leading setup statements and trailing render
|
|
15095
|
+
* output nodes. Setup is desugared here; renders are desugared by callers
|
|
15096
|
+
* (their lowering depends on the position they land in). When `construct` is
|
|
15097
|
+
* given, escaping control flow (return/break/continue) is rejected first. */
|
|
15098
|
+
function blockToParts(entries, construct) {
|
|
15099
|
+
if (construct) validateNoControlFlowEscape(entries, construct);
|
|
15100
|
+
const setup = [];
|
|
15101
|
+
const renders = [];
|
|
15102
|
+
for (const entry of entries) {
|
|
15103
|
+
if (RENDER_ENTRY_TYPES.has(entry.type)) {
|
|
15104
|
+
if (entry.type === "JSXText" && /^\s*$/.test(String(entry.value))) continue;
|
|
15105
|
+
renders.push(entry);
|
|
15106
|
+
} else {
|
|
15107
|
+
if (renders.length > 0) {
|
|
15108
|
+
fail$2("Statements may not follow the rendered output inside a TSRX template block", entry);
|
|
15109
|
+
}
|
|
15110
|
+
setup.push(transform$1(entry));
|
|
15111
|
+
}
|
|
15112
|
+
}
|
|
15113
|
+
return { setup, renders };
|
|
15114
|
+
}
|
|
15115
|
+
|
|
15116
|
+
function renderNodeToExpression(node) {
|
|
15117
|
+
const result = transform$1(node);
|
|
15118
|
+
if (result.type === "JSXText") return stringLiteral(String(result.value), result);
|
|
15119
|
+
return result;
|
|
15120
|
+
}
|
|
15121
|
+
|
|
15122
|
+
/** Combine desugared render nodes into one expression (fragment for
|
|
15123
|
+
* siblings). Returns null when the block rendered nothing. */
|
|
15124
|
+
function rendersToExpression(renders, src) {
|
|
15125
|
+
if (renders.length === 0) return null;
|
|
15126
|
+
if (renders.length === 1) return renderNodeToExpression(renders[0]);
|
|
15127
|
+
return jsxFragment(
|
|
15128
|
+
renders.map((render) => {
|
|
15129
|
+
const result = transform$1(render);
|
|
15130
|
+
if (!VALID_JSX_CHILD_TYPES.has(result.type)) return jsxContainer(result, render);
|
|
15131
|
+
return result;
|
|
15132
|
+
}),
|
|
15133
|
+
src
|
|
15134
|
+
);
|
|
15135
|
+
}
|
|
15136
|
+
|
|
15137
|
+
/** Lower a whole template block to a single expression. Returns null only for
|
|
15138
|
+
* a fully empty block; a block with setup but no render is an error. */
|
|
15139
|
+
function blockToExpression(blockNode, context) {
|
|
15140
|
+
const parts = blockToParts(toBlockBody(blockNode), context);
|
|
15141
|
+
const renderExpr = rendersToExpression(parts.renders, blockNode);
|
|
15142
|
+
if (parts.setup.length === 0) return renderExpr;
|
|
15143
|
+
if (!renderExpr) {
|
|
15144
|
+
fail$2(`A TSRX ${context} block with setup statements must end with rendered output`, blockNode);
|
|
15145
|
+
}
|
|
15146
|
+
return iife([...parts.setup, returnStatement(renderExpr, blockNode)], blockNode);
|
|
15147
|
+
}
|
|
15148
|
+
|
|
15149
|
+
// ---------------------------------------------------------------------------
|
|
15150
|
+
// @{} statement containers
|
|
15151
|
+
// ---------------------------------------------------------------------------
|
|
15152
|
+
|
|
15153
|
+
function codeBlockToExpression(cb) {
|
|
15154
|
+
const setup = cb.body.map(transform$1);
|
|
15155
|
+
if (!isNode$3(cb.render)) {
|
|
15156
|
+
fail$2("A TSRX statement container is missing its rendered output node", cb);
|
|
15157
|
+
}
|
|
15158
|
+
const renderExpr = renderNodeToExpression(cb.render);
|
|
15159
|
+
if (setup.length === 0) return renderExpr;
|
|
15160
|
+
return iife([...setup, returnStatement(renderExpr, cb)], cb);
|
|
15161
|
+
}
|
|
15162
|
+
|
|
15163
|
+
function codeBlockToFunctionBody(cb) {
|
|
15164
|
+
const setup = cb.body.map(transform$1);
|
|
15165
|
+
if (!isNode$3(cb.render)) {
|
|
15166
|
+
fail$2("A TSRX statement container is missing its rendered output node", cb);
|
|
15167
|
+
}
|
|
15168
|
+
const renderExpr = renderNodeToExpression(cb.render);
|
|
15169
|
+
return blockStatement([...setup, returnStatement(renderExpr, cb)], cb);
|
|
15170
|
+
}
|
|
15171
|
+
|
|
15172
|
+
// ---------------------------------------------------------------------------
|
|
15173
|
+
// @if — Show / Switch+Match
|
|
15174
|
+
// ---------------------------------------------------------------------------
|
|
15175
|
+
|
|
15176
|
+
function ifToJsx(node) {
|
|
15177
|
+
const branches = [];
|
|
15178
|
+
let current = node;
|
|
15179
|
+
let elseBlock = null;
|
|
15180
|
+
for (;;) {
|
|
15181
|
+
branches.push({
|
|
15182
|
+
test: transform$1(current.test),
|
|
15183
|
+
block: current.consequent,
|
|
15184
|
+
src: current
|
|
15185
|
+
});
|
|
15186
|
+
const alternate = current.alternate;
|
|
15187
|
+
if (alternate && (alternate.type === "IfStatement" || alternate.type === "JSXIfExpression")) {
|
|
15188
|
+
current = alternate;
|
|
15189
|
+
} else {
|
|
15190
|
+
elseBlock = alternate;
|
|
15191
|
+
break;
|
|
15192
|
+
}
|
|
15193
|
+
}
|
|
15194
|
+
|
|
15195
|
+
const elseExpr = elseBlock ? blockToExpression(elseBlock, "@else") : null;
|
|
15196
|
+
|
|
15197
|
+
if (branches.length === 1) {
|
|
15198
|
+
const branch = branches[0];
|
|
15199
|
+
const branchExpr = blockToExpression(branch.block, "@if");
|
|
15200
|
+
const attributes = [jsxAttr("when", branch.test, branch.src)];
|
|
15201
|
+
if (elseExpr) attributes.push(jsxAttr("fallback", elseExpr, elseBlock));
|
|
15202
|
+
return jsxElement("Show", attributes, branchExpr ? [asChild(branchExpr)] : [], node);
|
|
15203
|
+
}
|
|
15204
|
+
|
|
15205
|
+
const matches = branches.map((branch) => {
|
|
15206
|
+
const branchExpr = blockToExpression(branch.block, "@if");
|
|
15207
|
+
return jsxElement(
|
|
15208
|
+
"Match",
|
|
15209
|
+
[jsxAttr("when", branch.test, branch.src)],
|
|
15210
|
+
branchExpr ? [asChild(branchExpr)] : [],
|
|
15211
|
+
branch.src
|
|
15212
|
+
);
|
|
15213
|
+
});
|
|
15214
|
+
const attributes = elseExpr ? [jsxAttr("fallback", elseExpr, elseBlock)] : [];
|
|
15215
|
+
return jsxElement("Switch", attributes, matches, node);
|
|
15216
|
+
}
|
|
15217
|
+
|
|
15218
|
+
// ---------------------------------------------------------------------------
|
|
15219
|
+
// @for — For
|
|
15220
|
+
// ---------------------------------------------------------------------------
|
|
15221
|
+
|
|
15222
|
+
function forToJsx(node) {
|
|
15223
|
+
if (node.statementType !== "ForOfStatement") {
|
|
15224
|
+
fail$2(
|
|
15225
|
+
"@for must iterate with for...of; for...in and classic for loops are not TSRX template constructs",
|
|
15226
|
+
node
|
|
15227
|
+
);
|
|
15228
|
+
}
|
|
15229
|
+
if (node.await) {
|
|
15230
|
+
fail$2("`for await` is not supported inside Solid TSRX templates", node);
|
|
15231
|
+
}
|
|
15232
|
+
|
|
15233
|
+
const left = node.left;
|
|
15234
|
+
const pattern =
|
|
15235
|
+
left.type === "VariableDeclaration" ? left.declarations[0].id : left;
|
|
15236
|
+
const each = transform$1(node.right);
|
|
15237
|
+
const index = isNode$3(node.index) ? node.index : null;
|
|
15238
|
+
const key = isNode$3(node.key) ? node.key : null;
|
|
15239
|
+
const usesIndexOnlyMode = index !== null && key === null;
|
|
15240
|
+
const itemIsAccessor = key !== null || usesIndexOnlyMode;
|
|
15241
|
+
|
|
15242
|
+
const parts = blockToParts(toBlockBody(node.body), "@for");
|
|
15243
|
+
const renderExpr = rendersToExpression(parts.renders, node.body);
|
|
15244
|
+
if (!renderExpr) fail$2("A TSRX @for body must end with rendered output", node);
|
|
15245
|
+
|
|
15246
|
+
const callbackBody =
|
|
15247
|
+
parts.setup.length > 0 ?
|
|
15248
|
+
blockStatement(
|
|
15249
|
+
[...parts.setup, returnStatement(renderExpr, node.body)],
|
|
15250
|
+
node.body
|
|
15251
|
+
) :
|
|
15252
|
+
renderExpr;
|
|
15253
|
+
|
|
15254
|
+
// RC `For` callback shape:
|
|
15255
|
+
// - default keyed mode: raw item, accessor index (there is no TSRX index)
|
|
15256
|
+
// - keyed={false}: accessor item, raw index
|
|
15257
|
+
// - custom key: accessor item, accessor index
|
|
15258
|
+
if (itemIsAccessor && pattern.type === "Identifier")
|
|
15259
|
+
rewriteReadsToCalls(callbackBody, pattern.name);
|
|
15260
|
+
if (key && index) rewriteReadsToCalls(callbackBody, index.name);
|
|
15261
|
+
|
|
15262
|
+
const callbackPattern =
|
|
15263
|
+
itemIsAccessor && pattern.type !== "Identifier" ? accessorLazyPattern(pattern) : pattern;
|
|
15264
|
+
const params = [callbackPattern];
|
|
15265
|
+
if (index) params.push(index);
|
|
15266
|
+
|
|
15267
|
+
const attributes = [jsxAttr("each", each, node.right)];
|
|
15268
|
+
if (key) {
|
|
15269
|
+
attributes.push(jsxAttr("keyed", arrow([eagerPattern(pattern)], transform$1(key), key), key));
|
|
15270
|
+
} else if (usesIndexOnlyMode) {
|
|
15271
|
+
attributes.push(
|
|
15272
|
+
jsxAttr("keyed", withLoc$2({ type: "Literal", value: false, raw: "false" }, index), index)
|
|
15273
|
+
);
|
|
15274
|
+
}
|
|
15275
|
+
if (isNode$3(node.empty)) {
|
|
15276
|
+
const emptyExpr = blockToExpression(node.empty, "@empty");
|
|
15277
|
+
if (emptyExpr) attributes.push(jsxAttr("fallback", emptyExpr, node.empty));
|
|
15278
|
+
}
|
|
15279
|
+
|
|
15280
|
+
return jsxElement(
|
|
15281
|
+
"For",
|
|
15282
|
+
attributes,
|
|
15283
|
+
[jsxContainer(arrow(params, callbackBody, node), node)],
|
|
15284
|
+
node
|
|
15285
|
+
);
|
|
15286
|
+
}
|
|
15287
|
+
|
|
15288
|
+
// ---------------------------------------------------------------------------
|
|
15289
|
+
// @switch — Switch / Match
|
|
15290
|
+
// ---------------------------------------------------------------------------
|
|
15291
|
+
|
|
15292
|
+
function switchToJsx(node) {
|
|
15293
|
+
const discriminant = transform$1(node.discriminant);
|
|
15294
|
+
const matches = [];
|
|
15295
|
+
let fallbackExpr = null;
|
|
15296
|
+
let fallbackSrc = null;
|
|
15297
|
+
|
|
15298
|
+
for (const switchCase of node.cases) {
|
|
15299
|
+
const consequent = switchCase.consequent;
|
|
15300
|
+
const entries =
|
|
15301
|
+
consequent.length === 1 && consequent[0].type === "BlockStatement" ?
|
|
15302
|
+
consequent[0].body :
|
|
15303
|
+
consequent;
|
|
15304
|
+
const parts = blockToParts(entries, switchCase.test == null ? "@default" : "@case");
|
|
15305
|
+
const renderExpr = rendersToExpression(parts.renders, switchCase);
|
|
15306
|
+
const caseExpr =
|
|
15307
|
+
parts.setup.length > 0 ?
|
|
15308
|
+
renderExpr ?
|
|
15309
|
+
iife([...parts.setup, returnStatement(renderExpr, switchCase)], switchCase) :
|
|
15310
|
+
fail$2(
|
|
15311
|
+
"A TSRX @case block with setup statements must end with rendered output",
|
|
15312
|
+
switchCase
|
|
15313
|
+
) :
|
|
15314
|
+
renderExpr;
|
|
15315
|
+
|
|
15316
|
+
if (switchCase.test == null) {
|
|
15317
|
+
fallbackExpr = caseExpr;
|
|
15318
|
+
fallbackSrc = switchCase;
|
|
15319
|
+
} else {
|
|
15320
|
+
const when = strictEquals(
|
|
15321
|
+
cloneNode$1(discriminant),
|
|
15322
|
+
transform$1(switchCase.test),
|
|
15323
|
+
switchCase
|
|
15324
|
+
);
|
|
15325
|
+
matches.push(
|
|
15326
|
+
jsxElement(
|
|
15327
|
+
"Match",
|
|
15328
|
+
[jsxAttr("when", when, switchCase)],
|
|
15329
|
+
caseExpr ? [asChild(caseExpr)] : [],
|
|
15330
|
+
switchCase
|
|
15331
|
+
)
|
|
15332
|
+
);
|
|
15333
|
+
}
|
|
15334
|
+
}
|
|
15335
|
+
|
|
15336
|
+
const attributes = fallbackExpr ? [jsxAttr("fallback", fallbackExpr, fallbackSrc)] : [];
|
|
15337
|
+
return jsxElement("Switch", attributes, matches, node);
|
|
15338
|
+
}
|
|
15339
|
+
|
|
15340
|
+
// ---------------------------------------------------------------------------
|
|
15341
|
+
// @try / @pending / @catch — Errored / Loading
|
|
15342
|
+
// ---------------------------------------------------------------------------
|
|
15343
|
+
|
|
15344
|
+
function tryToJsx(node) {
|
|
15345
|
+
if (isNode$3(node.finalizer)) {
|
|
15346
|
+
fail$2("@finally is not part of the TSRX template grammar", node.finalizer);
|
|
15347
|
+
}
|
|
15348
|
+
|
|
15349
|
+
const contentExpr = blockToExpression(node.block, "@try");
|
|
15350
|
+
if (!contentExpr) fail$2("A TSRX @try block must end with rendered output", node);
|
|
15351
|
+
|
|
15352
|
+
let result = contentExpr;
|
|
15353
|
+
|
|
15354
|
+
if (isNode$3(node.pending)) {
|
|
15355
|
+
const pendingExpr = blockToExpression(node.pending, "@pending");
|
|
15356
|
+
const attributes = pendingExpr ? [jsxAttr("fallback", pendingExpr, node.pending)] : [];
|
|
15357
|
+
result = jsxElement("Loading", attributes, [asChild(result)], node);
|
|
15358
|
+
}
|
|
15359
|
+
|
|
15360
|
+
if (isNode$3(node.handler)) {
|
|
15361
|
+
const handler = node.handler;
|
|
15362
|
+
const param = isNode$3(handler.param) ? handler.param : null;
|
|
15363
|
+
if (
|
|
15364
|
+
param &&
|
|
15365
|
+
param.type !== "Identifier" &&
|
|
15366
|
+
param.type !== "ObjectPattern" &&
|
|
15367
|
+
param.type !== "ArrayPattern")
|
|
15368
|
+
{
|
|
15369
|
+
fail$2(
|
|
15370
|
+
"The @catch error binding must be an identifier, object pattern, or array pattern",
|
|
15371
|
+
param
|
|
15372
|
+
);
|
|
15373
|
+
}
|
|
15374
|
+
const resetParam = isNode$3(handler.resetParam) ? handler.resetParam : null;
|
|
15375
|
+
const errorName = param ? param.name : "_e";
|
|
15376
|
+
|
|
15377
|
+
const handlerExpr = blockToExpression(handler.body, "@catch");
|
|
15378
|
+
if (!handlerExpr) fail$2("A TSRX @catch block must end with rendered output", handler);
|
|
15379
|
+
// RC `Errored` passes an `ErrorAccessor`: reads of the binding become calls.
|
|
15380
|
+
if (param) rewriteReadsToCalls(handlerExpr, errorName);
|
|
15381
|
+
|
|
15382
|
+
const params = [
|
|
15383
|
+
param && param.type !== "Identifier" ? accessorLazyPattern(param) : ident$1(errorName, param)];
|
|
15384
|
+
|
|
15385
|
+
if (resetParam)
|
|
15386
|
+
params.push(ident$1(resetParam.name, resetParam));
|
|
15387
|
+
|
|
15388
|
+
result = jsxElement(
|
|
15389
|
+
"Errored",
|
|
15390
|
+
[jsxAttr("fallback", arrow(params, handlerExpr, handler), handler)],
|
|
15391
|
+
[asChild(result)],
|
|
15392
|
+
node
|
|
15393
|
+
);
|
|
15394
|
+
}
|
|
15395
|
+
|
|
15396
|
+
return result;
|
|
15397
|
+
}
|
|
15398
|
+
|
|
15399
|
+
// ---------------------------------------------------------------------------
|
|
15400
|
+
// Lazy-engine adaptation: intrinsic element names
|
|
15401
|
+
// ---------------------------------------------------------------------------
|
|
15402
|
+
|
|
15403
|
+
/**
|
|
15404
|
+
* Older lazy-transform paths rewrote *any* JSX name matching a lazy binding —
|
|
15405
|
+
* including lowercase intrinsic tags (`<address>` with a lazy `address` in
|
|
15406
|
+
* scope became `<__lazy0.address>`), which hijacked the element into a
|
|
15407
|
+
* component. Per JSX semantics a single lowercase identifier tag is always
|
|
15408
|
+
* intrinsic, so such rewrites are unambiguously wrong. Keep this repair for
|
|
15409
|
+
* compatibility with trees produced by those paths; the local engine does not
|
|
15410
|
+
* produce the invalid rewrite.
|
|
15411
|
+
*/
|
|
15412
|
+
function restoreIntrinsicJsxNames(root) {
|
|
15413
|
+
visit(root);
|
|
15414
|
+
|
|
15415
|
+
function restore(owner) {
|
|
15416
|
+
const name = owner.name;
|
|
15417
|
+
if (!name || name.type !== "JSXMemberExpression") return;
|
|
15418
|
+
const object = name.object;
|
|
15419
|
+
const property = name.property;
|
|
15420
|
+
if (
|
|
15421
|
+
object.type === "JSXIdentifier" &&
|
|
15422
|
+
/^__lazy\d+$/.test(object.name) &&
|
|
15423
|
+
property.type === "JSXIdentifier" &&
|
|
15424
|
+
/^[a-z]/.test(property.name))
|
|
15425
|
+
{
|
|
15426
|
+
owner.name = jsxIdent(property.name, name);
|
|
15427
|
+
}
|
|
15428
|
+
}
|
|
15429
|
+
|
|
15430
|
+
function visit(node) {
|
|
15431
|
+
if (node.type === "JSXOpeningElement" || node.type === "JSXClosingElement") restore(node);
|
|
15432
|
+
for (const key of Object.keys(node)) {
|
|
15433
|
+
if (SKIP_KEYS$2.has(key)) continue;
|
|
15434
|
+
const value = node[key];
|
|
15435
|
+
if (Array.isArray(value)) {
|
|
15436
|
+
for (const item of value) if (isNode$3(item)) visit(item);
|
|
15437
|
+
} else if (isNode$3(value)) {
|
|
15438
|
+
visit(value);
|
|
15439
|
+
}
|
|
15440
|
+
}
|
|
15441
|
+
}
|
|
15442
|
+
}
|
|
15443
|
+
|
|
15444
|
+
// ---------------------------------------------------------------------------
|
|
15445
|
+
// Scope-aware read → call rewriting (accessor adaptations)
|
|
15446
|
+
// ---------------------------------------------------------------------------
|
|
15447
|
+
|
|
15448
|
+
/** Keys whose contents are TS type positions — never value references. */
|
|
15449
|
+
const TYPE_KEYS$1 = new Set([
|
|
15450
|
+
"typeAnnotation",
|
|
15451
|
+
"typeParameters",
|
|
15452
|
+
"typeArguments",
|
|
15453
|
+
"superTypeArguments",
|
|
15454
|
+
"returnType"]
|
|
15455
|
+
);
|
|
15456
|
+
|
|
15457
|
+
function patternNames$1(pattern, into) {
|
|
15458
|
+
switch (pattern.type) {
|
|
15459
|
+
case "Identifier":
|
|
15460
|
+
into.add(pattern.name);
|
|
15461
|
+
break;
|
|
15462
|
+
case "ObjectPattern":
|
|
15463
|
+
for (const prop of pattern.properties) {
|
|
15464
|
+
if (prop.type === "RestElement") patternNames$1(prop.argument, into);else
|
|
15465
|
+
patternNames$1(prop.value, into);
|
|
15466
|
+
}
|
|
15467
|
+
break;
|
|
15468
|
+
case "ArrayPattern":
|
|
15469
|
+
for (const el of pattern.elements) {
|
|
15470
|
+
if (el) patternNames$1(el, into);
|
|
15471
|
+
}
|
|
15472
|
+
break;
|
|
15473
|
+
case "AssignmentPattern":
|
|
15474
|
+
patternNames$1(pattern.left, into);
|
|
15475
|
+
break;
|
|
15476
|
+
case "RestElement":
|
|
15477
|
+
patternNames$1(pattern.argument, into);
|
|
15478
|
+
break;
|
|
15479
|
+
}
|
|
15480
|
+
}
|
|
15481
|
+
|
|
15482
|
+
function statementsShadow(statements, name) {
|
|
15483
|
+
const names = new Set();
|
|
15484
|
+
for (const stmt of statements) {
|
|
15485
|
+
if (stmt.type === "VariableDeclaration") {
|
|
15486
|
+
for (const decl of stmt.declarations) patternNames$1(decl.id, names);
|
|
15487
|
+
} else if (
|
|
15488
|
+
(stmt.type === "FunctionDeclaration" || stmt.type === "ClassDeclaration") &&
|
|
15489
|
+
isNode$3(stmt.id))
|
|
15490
|
+
{
|
|
15491
|
+
names.add(stmt.id.name);
|
|
15492
|
+
}
|
|
15493
|
+
}
|
|
15494
|
+
return names.has(name);
|
|
15495
|
+
}
|
|
15496
|
+
|
|
15497
|
+
/**
|
|
15498
|
+
* Rewrite value reads of `name` within `root` (a plain, already-desugared
|
|
15499
|
+
* subtree) to zero-argument calls, respecting shadowing by function params,
|
|
15500
|
+
* block declarations, and catch clauses. Write targets are left untouched.
|
|
15501
|
+
*/
|
|
15502
|
+
function rewriteReadsToCalls(root, name) {
|
|
15503
|
+
visit(root);
|
|
15504
|
+
|
|
15505
|
+
function shouldReplace(value) {
|
|
15506
|
+
return isNode$3(value) && value.type === "Identifier" && value.name === name;
|
|
15507
|
+
}
|
|
15508
|
+
|
|
15509
|
+
function replaceIn(container, key) {
|
|
15510
|
+
const value = container[key];
|
|
15511
|
+
container[key] = callOn(value, value);
|
|
15512
|
+
}
|
|
15513
|
+
|
|
15514
|
+
function visit(node) {
|
|
15515
|
+
if (FUNCTION_TYPES$1.has(node.type)) {
|
|
15516
|
+
const bound = new Set();
|
|
15517
|
+
for (const param of node.params) patternNames$1(param, bound);
|
|
15518
|
+
if (bound.has(name)) return;
|
|
15519
|
+
if (isNode$3(node.body)) visit(node.body);
|
|
15520
|
+
return;
|
|
15521
|
+
}
|
|
15522
|
+
if (node.type === "BlockStatement" || node.type === "Program") {
|
|
15523
|
+
if (statementsShadow(node.body, name)) return;
|
|
15524
|
+
}
|
|
15525
|
+
if (node.type === "CatchClause") {
|
|
15526
|
+
const bound = new Set();
|
|
15527
|
+
if (isNode$3(node.param)) patternNames$1(node.param, bound);
|
|
15528
|
+
if (bound.has(name)) return;
|
|
15529
|
+
}
|
|
15530
|
+
if (node.type === "MetaProperty") return;
|
|
15531
|
+
|
|
15532
|
+
for (const key of Object.keys(node)) {
|
|
15533
|
+
if (SKIP_KEYS$2.has(key) || TYPE_KEYS$1.has(key)) continue;
|
|
15534
|
+
// Labels, binding sites, and non-computed accesses are not value reads.
|
|
15535
|
+
if (key === "property" && node.type === "MemberExpression" && !node.computed) continue;
|
|
15536
|
+
if (key === "property" && node.type === "JSXMemberExpression") continue;
|
|
15537
|
+
if (key === "name" && (node.type === "JSXAttribute" || node.type === "JSXNamespacedName"))
|
|
15538
|
+
continue;
|
|
15539
|
+
if (key === "key" && node.type === "Property" && !node.computed) continue;
|
|
15540
|
+
if (key === "id" && (node.type === "VariableDeclarator" || FUNCTION_TYPES$1.has(node.type)))
|
|
15541
|
+
continue;
|
|
15542
|
+
if (key === "label") continue;
|
|
15543
|
+
if (key === "left" && node.type === "AssignmentExpression") {
|
|
15544
|
+
// Writes to the accessor binding are invalid anyway; skip identifier
|
|
15545
|
+
// targets but still walk member-expression targets.
|
|
15546
|
+
if (shouldReplace(node.left)) continue;
|
|
15547
|
+
}
|
|
15548
|
+
if (key === "argument" && node.type === "UpdateExpression" && shouldReplace(node.argument))
|
|
15549
|
+
continue;
|
|
15550
|
+
if (
|
|
15551
|
+
(key === "imported" || key === "local" || key === "exported") &&
|
|
15552
|
+
/Specifier$/.test(node.type))
|
|
15553
|
+
|
|
15554
|
+
continue;
|
|
15555
|
+
|
|
15556
|
+
const value = node[key];
|
|
15557
|
+
if (Array.isArray(value)) {
|
|
15558
|
+
for (let i = 0; i < value.length; i++) {
|
|
15559
|
+
const item = value[i];
|
|
15560
|
+
if (shouldReplace(item)) replaceIn(value, i);else
|
|
15561
|
+
if (isNode$3(item)) visit(item);
|
|
15562
|
+
}
|
|
15563
|
+
} else if (shouldReplace(value)) {
|
|
15564
|
+
// Object-pattern shorthand shares the key/value node: split them.
|
|
15565
|
+
if (node.type === "Property" && node.shorthand && key === "value") {
|
|
15566
|
+
node.shorthand = false;
|
|
15567
|
+
node.key = ident$1(name, value);
|
|
15568
|
+
}
|
|
15569
|
+
replaceIn(node, key);
|
|
15570
|
+
} else if (isNode$3(value)) {
|
|
15571
|
+
visit(value);
|
|
15572
|
+
}
|
|
15573
|
+
}
|
|
15574
|
+
}
|
|
15575
|
+
}
|
|
15576
|
+
|
|
15577
|
+
/**
|
|
15578
|
+
* ESTree (acorn / typescript-eslint shaped, as produced by `@tsrx/core`) to
|
|
15579
|
+
* Babel AST conversion.
|
|
15580
|
+
*
|
|
15581
|
+
* Purely mechanical: no TSRX node may reach this pass (the desugarer lowers
|
|
15582
|
+
* them all first), and unknown shapes fail closed rather than producing a
|
|
15583
|
+
* silently wrong tree. Location info (`start`/`end`/`loc`) is preserved for
|
|
15584
|
+
* sourcemaps. Comments are not attached in v1 (documented limitation).
|
|
15585
|
+
*/
|
|
15586
|
+
|
|
15587
|
+
|
|
15588
|
+
|
|
15589
|
+
|
|
15590
|
+
/** ESTree/TSRX bookkeeping keys with no Babel equivalent. */
|
|
15591
|
+
const STRIP_KEYS = new Set([
|
|
15592
|
+
"type",
|
|
15593
|
+
"start",
|
|
15594
|
+
"end",
|
|
15595
|
+
"loc",
|
|
15596
|
+
"range",
|
|
15597
|
+
"metadata",
|
|
15598
|
+
"leadingComments",
|
|
15599
|
+
"trailingComments",
|
|
15600
|
+
"innerComments",
|
|
15601
|
+
"alternateKeyword",
|
|
15602
|
+
"emptyKeyword",
|
|
15603
|
+
"isDynamic",
|
|
15604
|
+
"statementType",
|
|
15605
|
+
"resetParam",
|
|
15606
|
+
"lazy",
|
|
15607
|
+
"directive"]
|
|
15608
|
+
);
|
|
15609
|
+
|
|
15610
|
+
function isNode$2(value) {
|
|
15611
|
+
return (
|
|
15612
|
+
typeof value === "object" &&
|
|
15613
|
+
value !== null &&
|
|
15614
|
+
typeof value.type === "string");
|
|
15615
|
+
|
|
15616
|
+
}
|
|
15617
|
+
|
|
15618
|
+
function fail$1(message, node) {
|
|
15619
|
+
const start = node.loc?.start;
|
|
15620
|
+
throw new SyntaxError(start ? `${message} (${start.line}:${start.column})` : message);
|
|
15621
|
+
}
|
|
15622
|
+
|
|
15623
|
+
function copyLoc(from, to) {
|
|
15624
|
+
if (from.start !== undefined) to.start = from.start;
|
|
15625
|
+
if (from.end !== undefined) to.end = from.end;
|
|
15626
|
+
if (from.loc !== undefined) to.loc = from.loc;
|
|
15627
|
+
}
|
|
15628
|
+
|
|
15629
|
+
function convertValue(value) {
|
|
15630
|
+
if (Array.isArray(value)) return value.map(convertValue);
|
|
15631
|
+
if (isNode$2(value)) return convertNode(value);
|
|
15632
|
+
return value;
|
|
15633
|
+
}
|
|
15634
|
+
|
|
15635
|
+
/** Shallow-map every kept key, renaming typescript-eslint's `typeArguments`
|
|
15636
|
+
* to Babel 7's `typeParameters` along the way. */
|
|
15637
|
+
function convertGeneric(node, overrideType) {
|
|
15638
|
+
const out = { type: overrideType ?? node.type };
|
|
15639
|
+
copyLoc(node, out);
|
|
15640
|
+
for (const key of Object.keys(node)) {
|
|
15641
|
+
if (STRIP_KEYS.has(key)) continue;
|
|
15642
|
+
const outKey =
|
|
15643
|
+
key === "typeArguments" && node.typeParameters === undefined ? "typeParameters" : key;
|
|
15644
|
+
out[outKey] = convertValue(node[key]);
|
|
15645
|
+
}
|
|
15646
|
+
return out;
|
|
15647
|
+
}
|
|
15648
|
+
|
|
15649
|
+
function convertLiteral(node) {
|
|
15650
|
+
const out = {};
|
|
15651
|
+
copyLoc(node, out);
|
|
15652
|
+
const regex = node.regex;
|
|
15653
|
+
if (regex) {
|
|
15654
|
+
out.type = "RegExpLiteral";
|
|
15655
|
+
out.pattern = regex.pattern;
|
|
15656
|
+
out.flags = regex.flags;
|
|
15657
|
+
return out;
|
|
15658
|
+
}
|
|
15659
|
+
if (node.bigint !== undefined && node.bigint !== null) {
|
|
15660
|
+
out.type = "BigIntLiteral";
|
|
15661
|
+
out.value = node.bigint;
|
|
15662
|
+
return out;
|
|
15663
|
+
}
|
|
15664
|
+
const value = node.value;
|
|
15665
|
+
if (value === null) {
|
|
15666
|
+
out.type = "NullLiteral";
|
|
15667
|
+
return out;
|
|
15668
|
+
}
|
|
15669
|
+
switch (typeof value) {
|
|
15670
|
+
case "string":
|
|
15671
|
+
out.type = "StringLiteral";
|
|
15672
|
+
break;
|
|
15673
|
+
case "number":
|
|
15674
|
+
out.type = "NumericLiteral";
|
|
15675
|
+
break;
|
|
15676
|
+
case "boolean":
|
|
15677
|
+
out.type = "BooleanLiteral";
|
|
15678
|
+
break;
|
|
15679
|
+
default:
|
|
15680
|
+
return fail$1(`Unsupported literal value type: ${typeof value}`, node);
|
|
15681
|
+
}
|
|
15682
|
+
out.value = value;
|
|
15683
|
+
if (typeof node.raw === "string") out.extra = { raw: node.raw, rawValue: value };
|
|
15684
|
+
return out;
|
|
15685
|
+
}
|
|
15686
|
+
|
|
15687
|
+
function extractDirectives(body) {
|
|
15688
|
+
const directives = [];
|
|
15689
|
+
let i = 0;
|
|
15690
|
+
while (i < body.length) {
|
|
15691
|
+
const stmt = body[i];
|
|
15692
|
+
if (stmt.type !== "ExpressionStatement" || typeof stmt.directive !== "string") break;
|
|
15693
|
+
const expr = stmt.expression;
|
|
15694
|
+
const literal = {
|
|
15695
|
+
type: "DirectiveLiteral",
|
|
15696
|
+
value: expr.value
|
|
15697
|
+
};
|
|
15698
|
+
copyLoc(expr, literal);
|
|
15699
|
+
if (typeof expr.raw === "string") literal.extra = { raw: expr.raw, rawValue: expr.value };
|
|
15700
|
+
const directive = { type: "Directive", value: literal };
|
|
15701
|
+
copyLoc(stmt, directive);
|
|
15702
|
+
directives.push(directive);
|
|
15703
|
+
i++;
|
|
15704
|
+
}
|
|
15705
|
+
return { directives, rest: body.slice(i) };
|
|
15706
|
+
}
|
|
15707
|
+
|
|
15708
|
+
function convertFunctionParts(fn, out) {
|
|
15709
|
+
out.params = convertValue(fn.params);
|
|
15710
|
+
out.body = convertValue(fn.body);
|
|
15711
|
+
out.generator = !!fn.generator;
|
|
15712
|
+
out.async = !!fn.async;
|
|
15713
|
+
if (fn.returnType !== undefined) out.returnType = convertValue(fn.returnType);
|
|
15714
|
+
if (fn.typeParameters !== undefined) out.typeParameters = convertValue(fn.typeParameters);
|
|
15715
|
+
}
|
|
15716
|
+
|
|
15717
|
+
/** Convert an optional chain, dropping the ESTree `ChainExpression` wrapper
|
|
15718
|
+
* and switching member/call links to Babel's `Optional*` node types. */
|
|
15719
|
+
function convertChainLink(node) {
|
|
15720
|
+
switch (node.type) {
|
|
15721
|
+
case "MemberExpression":{
|
|
15722
|
+
const out = {
|
|
15723
|
+
type: "OptionalMemberExpression",
|
|
15724
|
+
object: convertChainLink(node.object),
|
|
15725
|
+
property: convertValue(node.property),
|
|
15726
|
+
computed: !!node.computed,
|
|
15727
|
+
optional: !!node.optional
|
|
15728
|
+
};
|
|
15729
|
+
copyLoc(node, out);
|
|
15730
|
+
return out;
|
|
15731
|
+
}
|
|
15732
|
+
case "CallExpression":{
|
|
15733
|
+
const out = {
|
|
15734
|
+
type: "OptionalCallExpression",
|
|
15735
|
+
callee: convertChainLink(node.callee),
|
|
15736
|
+
arguments: convertValue(node.arguments),
|
|
15737
|
+
optional: !!node.optional
|
|
15738
|
+
};
|
|
15739
|
+
copyLoc(node, out);
|
|
15740
|
+
if (node.typeParameters !== undefined || node.typeArguments !== undefined) {
|
|
15741
|
+
out.typeParameters = convertValue(node.typeParameters ?? node.typeArguments);
|
|
15742
|
+
}
|
|
15743
|
+
return out;
|
|
15744
|
+
}
|
|
15745
|
+
case "TSNonNullExpression":{
|
|
15746
|
+
const out = {
|
|
15747
|
+
type: "TSNonNullExpression",
|
|
15748
|
+
expression: convertChainLink(node.expression)
|
|
15749
|
+
};
|
|
15750
|
+
copyLoc(node, out);
|
|
15751
|
+
return out;
|
|
15752
|
+
}
|
|
15753
|
+
default:
|
|
15754
|
+
return convertNode(node);
|
|
15755
|
+
}
|
|
15756
|
+
}
|
|
15757
|
+
|
|
15758
|
+
function convertNode(node) {
|
|
15759
|
+
switch (node.type) {
|
|
15760
|
+
case "Program":{
|
|
15761
|
+
const { directives, rest } = extractDirectives(node.body);
|
|
15762
|
+
const out = {
|
|
15763
|
+
type: "Program",
|
|
15764
|
+
sourceType: node.sourceType ?? "module",
|
|
15765
|
+
interpreter: null,
|
|
15766
|
+
body: rest.map(convertNode),
|
|
15767
|
+
directives
|
|
15768
|
+
};
|
|
15769
|
+
copyLoc(node, out);
|
|
15770
|
+
return out;
|
|
15771
|
+
}
|
|
15772
|
+
|
|
15773
|
+
case "BlockStatement":{
|
|
15774
|
+
const { directives, rest } = extractDirectives(node.body);
|
|
15775
|
+
const out = {
|
|
15776
|
+
type: "BlockStatement",
|
|
15777
|
+
body: rest.map(convertNode),
|
|
15778
|
+
directives
|
|
15779
|
+
};
|
|
15780
|
+
copyLoc(node, out);
|
|
15781
|
+
return out;
|
|
15782
|
+
}
|
|
15783
|
+
|
|
15784
|
+
case "Literal":
|
|
15785
|
+
return convertLiteral(node);
|
|
15786
|
+
|
|
15787
|
+
case "Property":{
|
|
15788
|
+
const kind = node.kind;
|
|
15789
|
+
if (kind === "get" || kind === "set" || node.method) {
|
|
15790
|
+
const fn = node.value;
|
|
15791
|
+
const out = {
|
|
15792
|
+
type: "ObjectMethod",
|
|
15793
|
+
kind: node.method ? "method" : kind,
|
|
15794
|
+
key: convertValue(node.key),
|
|
15795
|
+
computed: !!node.computed
|
|
15796
|
+
};
|
|
15797
|
+
copyLoc(node, out);
|
|
15798
|
+
convertFunctionParts(fn, out);
|
|
15799
|
+
return out;
|
|
15800
|
+
}
|
|
15801
|
+
const out = {
|
|
15802
|
+
type: "ObjectProperty",
|
|
15803
|
+
key: convertValue(node.key),
|
|
15804
|
+
value: convertValue(node.value),
|
|
15805
|
+
computed: !!node.computed,
|
|
15806
|
+
shorthand: !!node.shorthand
|
|
15807
|
+
};
|
|
15808
|
+
copyLoc(node, out);
|
|
15809
|
+
return out;
|
|
15810
|
+
}
|
|
15811
|
+
|
|
15812
|
+
case "MethodDefinition":{
|
|
15813
|
+
const fn = node.value;
|
|
15814
|
+
const isPrivate = node.key.type === "PrivateIdentifier";
|
|
15815
|
+
const out = {
|
|
15816
|
+
type: isPrivate ? "ClassPrivateMethod" : "ClassMethod",
|
|
15817
|
+
kind: node.kind,
|
|
15818
|
+
key: convertValue(node.key),
|
|
15819
|
+
computed: !!node.computed,
|
|
15820
|
+
static: !!node.static
|
|
15821
|
+
};
|
|
15822
|
+
copyLoc(node, out);
|
|
15823
|
+
convertFunctionParts(fn, out);
|
|
15824
|
+
if (node.accessibility !== undefined) out.accessibility = node.accessibility;
|
|
15825
|
+
if (node.override !== undefined) out.override = node.override;
|
|
15826
|
+
if (node.optional !== undefined) out.optional = node.optional;
|
|
15827
|
+
return out;
|
|
15828
|
+
}
|
|
15829
|
+
|
|
15830
|
+
case "PropertyDefinition":{
|
|
15831
|
+
const isPrivate = node.key.type === "PrivateIdentifier";
|
|
15832
|
+
const out = {
|
|
15833
|
+
type: isPrivate ? "ClassPrivateProperty" : "ClassProperty",
|
|
15834
|
+
key: convertValue(node.key),
|
|
15835
|
+
value: node.value == null ? null : convertValue(node.value),
|
|
15836
|
+
computed: !!node.computed,
|
|
15837
|
+
static: !!node.static
|
|
15838
|
+
};
|
|
15839
|
+
copyLoc(node, out);
|
|
15840
|
+
for (const key of [
|
|
15841
|
+
"typeAnnotation",
|
|
15842
|
+
"declare",
|
|
15843
|
+
"readonly",
|
|
15844
|
+
"accessibility",
|
|
15845
|
+
"optional",
|
|
15846
|
+
"definite",
|
|
15847
|
+
"override"])
|
|
15848
|
+
{
|
|
15849
|
+
if (node[key] !== undefined) out[key] = convertValue(node[key]);
|
|
15850
|
+
}
|
|
15851
|
+
return out;
|
|
15852
|
+
}
|
|
15853
|
+
|
|
15854
|
+
case "PrivateIdentifier":{
|
|
15855
|
+
const id = { type: "Identifier", name: node.name };
|
|
15856
|
+
copyLoc(node, id);
|
|
15857
|
+
const out = { type: "PrivateName", id };
|
|
15858
|
+
copyLoc(node, out);
|
|
15859
|
+
return out;
|
|
15860
|
+
}
|
|
15861
|
+
|
|
15862
|
+
case "ChainExpression":
|
|
15863
|
+
return convertChainLink(node.expression);
|
|
15864
|
+
|
|
15865
|
+
case "ImportExpression":{
|
|
15866
|
+
const importCallee = { type: "Import" };
|
|
15867
|
+
copyLoc(node, importCallee);
|
|
15868
|
+
const args = [convertValue(node.source)];
|
|
15869
|
+
if (node.options != null) args.push(convertValue(node.options));
|
|
15870
|
+
const out = {
|
|
15871
|
+
type: "CallExpression",
|
|
15872
|
+
callee: importCallee,
|
|
15873
|
+
arguments: args
|
|
15874
|
+
};
|
|
15875
|
+
copyLoc(node, out);
|
|
15876
|
+
return out;
|
|
15877
|
+
}
|
|
15878
|
+
|
|
15879
|
+
case "JSXText":{
|
|
15880
|
+
const out = { type: "JSXText", value: node.value };
|
|
15881
|
+
copyLoc(node, out);
|
|
15882
|
+
if (typeof node.raw === "string") out.extra = { raw: node.raw, rawValue: node.value };
|
|
15883
|
+
return out;
|
|
15884
|
+
}
|
|
15885
|
+
|
|
15886
|
+
case "TSTypeParameter":{
|
|
15887
|
+
const out = convertGeneric(node);
|
|
15888
|
+
if (isNode$2(out.name)) out.name = out.name.name;
|
|
15889
|
+
return out;
|
|
15890
|
+
}
|
|
15891
|
+
|
|
15892
|
+
case "TSInterfaceHeritage":
|
|
15893
|
+
return convertGeneric(node, "TSExpressionWithTypeArguments");
|
|
15894
|
+
|
|
15895
|
+
case "TSAbstractMethodDefinition":
|
|
15896
|
+
case "TSAbstractPropertyDefinition":
|
|
15897
|
+
case "TSParameterProperty":
|
|
15898
|
+
return fail$1(`Unsupported TypeScript construct in TSRX source: ${node.type}`, node);
|
|
15899
|
+
|
|
15900
|
+
case "JSXCodeBlock":
|
|
15901
|
+
case "JSXIfExpression":
|
|
15902
|
+
case "JSXForExpression":
|
|
15903
|
+
case "JSXSwitchExpression":
|
|
15904
|
+
case "JSXTryExpression":
|
|
15905
|
+
case "JSXStyleElement":
|
|
15906
|
+
return fail$1(
|
|
15907
|
+
`TSRX node ${node.type} survived desugaring; this is a bug in the frontend`,
|
|
15908
|
+
node
|
|
15909
|
+
);
|
|
15910
|
+
|
|
15911
|
+
default:
|
|
15912
|
+
return convertGeneric(node);
|
|
15913
|
+
}
|
|
15914
|
+
}
|
|
15915
|
+
|
|
15916
|
+
function toBabelFile(program) {
|
|
15917
|
+
const file = {
|
|
15918
|
+
type: "File",
|
|
15919
|
+
program: convertNode(program),
|
|
15920
|
+
comments: [],
|
|
15921
|
+
tokens: []
|
|
15922
|
+
};
|
|
15923
|
+
copyLoc(program, file);
|
|
15924
|
+
return file;
|
|
15925
|
+
}
|
|
15926
|
+
|
|
15927
|
+
/**
|
|
15928
|
+
* Solid's TSRX lazy-destructuring transform.
|
|
15929
|
+
*
|
|
15930
|
+
* This is intentionally local to the Babel frontend. `@tsrx/core` still owns
|
|
15931
|
+
* parsing and semantic analysis, but its framework-agnostic lazy transform
|
|
15932
|
+
* cannot express Solid's reactive object-rest view or JavaScript-correct lazy
|
|
15933
|
+
* defaults and updates.
|
|
15934
|
+
*
|
|
15935
|
+
* The scope and pattern traversal is adapted from @tsrx/core 0.1.61's
|
|
15936
|
+
* MIT-licensed `src/transform/lazy.js`.
|
|
15937
|
+
*/
|
|
15938
|
+
|
|
15939
|
+
|
|
15940
|
+
|
|
15941
|
+
|
|
15942
|
+
|
|
15943
|
+
|
|
15944
|
+
|
|
15945
|
+
|
|
15946
|
+
|
|
15947
|
+
|
|
15948
|
+
|
|
15949
|
+
|
|
15950
|
+
|
|
15951
|
+
|
|
15952
|
+
|
|
15953
|
+
|
|
15954
|
+
|
|
15955
|
+
|
|
15956
|
+
|
|
15957
|
+
|
|
15958
|
+
|
|
15959
|
+
|
|
15960
|
+
|
|
15961
|
+
|
|
15962
|
+
|
|
15963
|
+
|
|
15964
|
+
|
|
15965
|
+
|
|
15966
|
+
|
|
15967
|
+
|
|
15968
|
+
|
|
15969
|
+
|
|
15970
|
+
const FUNCTION_TYPES = new Set([
|
|
15971
|
+
"FunctionDeclaration",
|
|
15972
|
+
"FunctionExpression",
|
|
15973
|
+
"ArrowFunctionExpression"]
|
|
15974
|
+
);
|
|
15975
|
+
|
|
15976
|
+
const TYPE_KEYS = new Set([
|
|
15977
|
+
"typeAnnotation",
|
|
15978
|
+
"typeParameters",
|
|
15979
|
+
"typeArguments",
|
|
15980
|
+
"superTypeArguments",
|
|
15981
|
+
"returnType",
|
|
15982
|
+
"implements"]
|
|
15983
|
+
);
|
|
15984
|
+
|
|
15985
|
+
const SKIP_KEYS$1 = new Set([
|
|
15986
|
+
"type",
|
|
15987
|
+
"loc",
|
|
15988
|
+
"start",
|
|
15989
|
+
"end",
|
|
15990
|
+
"range",
|
|
15991
|
+
"metadata",
|
|
15992
|
+
"leadingComments",
|
|
15993
|
+
"trailingComments",
|
|
15994
|
+
"innerComments"]
|
|
15995
|
+
);
|
|
15996
|
+
|
|
15997
|
+
function isNode$1(value) {
|
|
15998
|
+
return (
|
|
15999
|
+
typeof value === "object" &&
|
|
16000
|
+
value !== null &&
|
|
16001
|
+
typeof value.type === "string");
|
|
16002
|
+
|
|
16003
|
+
}
|
|
16004
|
+
|
|
16005
|
+
function metadata(node) {
|
|
16006
|
+
return node.metadata ??= {};
|
|
16007
|
+
}
|
|
16008
|
+
|
|
16009
|
+
function withLoc$1(node, source) {
|
|
16010
|
+
if (source) {
|
|
16011
|
+
if (source.start !== undefined) node.start = source.start;
|
|
16012
|
+
if (source.end !== undefined) node.end = source.end;
|
|
16013
|
+
if (source.loc !== undefined) node.loc = source.loc;
|
|
16014
|
+
}
|
|
16015
|
+
return node;
|
|
16016
|
+
}
|
|
16017
|
+
|
|
16018
|
+
function cloneNode(value) {
|
|
16019
|
+
if (Array.isArray(value)) return value.map(cloneNode);
|
|
16020
|
+
if (typeof value === "object" && value !== null) {
|
|
16021
|
+
const clone = {};
|
|
16022
|
+
for (const key of Object.keys(value)) {
|
|
16023
|
+
clone[key] = cloneNode(value[key]);
|
|
16024
|
+
}
|
|
16025
|
+
return clone;
|
|
16026
|
+
}
|
|
16027
|
+
return value;
|
|
16028
|
+
}
|
|
16029
|
+
|
|
16030
|
+
function ident(name, source) {
|
|
16031
|
+
return withLoc$1({ type: "Identifier", name }, source);
|
|
16032
|
+
}
|
|
16033
|
+
|
|
16034
|
+
function literal(value, source) {
|
|
16035
|
+
return withLoc$1({ type: "Literal", value, raw: JSON.stringify(value) }, source);
|
|
16036
|
+
}
|
|
16037
|
+
|
|
16038
|
+
function undefinedExpression(source) {
|
|
16039
|
+
return withLoc$1(
|
|
16040
|
+
{ type: "UnaryExpression", operator: "void", prefix: true, argument: literal(0, source) },
|
|
16041
|
+
source
|
|
16042
|
+
);
|
|
16043
|
+
}
|
|
16044
|
+
|
|
16045
|
+
function member(object, property, computed, source) {
|
|
16046
|
+
return withLoc$1({ type: "MemberExpression", object, property, computed, optional: false }, source);
|
|
16047
|
+
}
|
|
16048
|
+
|
|
16049
|
+
function call(callee, args, source) {
|
|
16050
|
+
return withLoc$1({ type: "CallExpression", callee, arguments: args, optional: false }, source);
|
|
16051
|
+
}
|
|
16052
|
+
|
|
16053
|
+
function assignment(operator, left, right, source) {
|
|
16054
|
+
return withLoc$1({ type: "AssignmentExpression", operator, left, right }, source);
|
|
16055
|
+
}
|
|
16056
|
+
|
|
16057
|
+
function sequence(expressions, source) {
|
|
16058
|
+
return withLoc$1({ type: "SequenceExpression", expressions }, source);
|
|
16059
|
+
}
|
|
16060
|
+
|
|
16061
|
+
function conditional(test, consequent, alternate, source) {
|
|
16062
|
+
return withLoc$1({ type: "ConditionalExpression", test, consequent, alternate }, source);
|
|
16063
|
+
}
|
|
16064
|
+
|
|
16065
|
+
function binary(operator, left, right, source) {
|
|
16066
|
+
return withLoc$1({ type: "BinaryExpression", operator, left, right }, source);
|
|
16067
|
+
}
|
|
16068
|
+
|
|
16069
|
+
function logical(operator, left, right, source) {
|
|
16070
|
+
return withLoc$1({ type: "LogicalExpression", operator, left, right }, source);
|
|
16071
|
+
}
|
|
16072
|
+
|
|
16073
|
+
function variableDeclaration(kind, names, init) {
|
|
16074
|
+
return {
|
|
16075
|
+
type: "VariableDeclaration",
|
|
16076
|
+
kind,
|
|
16077
|
+
declarations: names.map((name, index) => ({
|
|
16078
|
+
type: "VariableDeclarator",
|
|
16079
|
+
id: ident(name),
|
|
16080
|
+
init: index === 0 && init ? init : null
|
|
16081
|
+
}))
|
|
16082
|
+
};
|
|
16083
|
+
}
|
|
16084
|
+
|
|
16085
|
+
function fail(message, node) {
|
|
16086
|
+
const start = node?.loc?.start;
|
|
16087
|
+
throw new SyntaxError(start ? `${message} (${start.line}:${start.column})` : message);
|
|
16088
|
+
}
|
|
16089
|
+
|
|
16090
|
+
const AUTHORED_LAZY_UNSUPPORTED =
|
|
16091
|
+
"Solid's TSRX frontend does not support authored lazy destructuring; keep property and accessor reads explicit";
|
|
16092
|
+
|
|
16093
|
+
/**
|
|
16094
|
+
* Reject parser-authored `&{}` / `&[]` before TSRX controls synthesize the
|
|
16095
|
+
* deferred patterns Solid needs for accessor-backed `@for` and `@catch`
|
|
16096
|
+
* callbacks.
|
|
16097
|
+
*/
|
|
16098
|
+
function rejectAuthoredLazyDestructuring(root) {
|
|
16099
|
+
const visit = (value) => {
|
|
16100
|
+
if (Array.isArray(value)) {
|
|
16101
|
+
for (const child of value) visit(child);
|
|
16102
|
+
return;
|
|
16103
|
+
}
|
|
16104
|
+
if (!isNode$1(value)) return;
|
|
16105
|
+
if ((value.type === "ObjectPattern" || value.type === "ArrayPattern") && value.lazy === true) {
|
|
16106
|
+
fail(AUTHORED_LAZY_UNSUPPORTED, value);
|
|
16107
|
+
}
|
|
16108
|
+
for (const key of Object.keys(value)) {
|
|
16109
|
+
if (!SKIP_KEYS$1.has(key)) visit(value[key]);
|
|
16110
|
+
}
|
|
16111
|
+
};
|
|
16112
|
+
visit(root);
|
|
16113
|
+
}
|
|
16114
|
+
|
|
16115
|
+
class LazyState {
|
|
16116
|
+
names = new Set();
|
|
16117
|
+
next = new Map();
|
|
16118
|
+
programTemps = [];
|
|
16119
|
+
tempScopes = [this.programTemps];
|
|
16120
|
+
|
|
16121
|
+
|
|
16122
|
+
usesArrayRest = false;
|
|
16123
|
+
topLevelGlobalThisBinding = false;
|
|
16124
|
+
|
|
16125
|
+
constructor(root) {
|
|
16126
|
+
this.collectNames(root);
|
|
16127
|
+
this.topLevelGlobalThisBinding = programBindsName(root, "globalThis");
|
|
16128
|
+
}
|
|
16129
|
+
|
|
16130
|
+
collectNames(value) {
|
|
16131
|
+
if (Array.isArray(value)) {
|
|
16132
|
+
for (const child of value) this.collectNames(child);
|
|
16133
|
+
return;
|
|
16134
|
+
}
|
|
16135
|
+
if (!isNode$1(value)) return;
|
|
16136
|
+
if (value.type === "Identifier" || value.type === "JSXIdentifier") {
|
|
16137
|
+
this.names.add(value.name);
|
|
16138
|
+
}
|
|
16139
|
+
for (const key of Object.keys(value)) {
|
|
16140
|
+
if (!SKIP_KEYS$1.has(key)) this.collectNames(value[key]);
|
|
16141
|
+
}
|
|
16142
|
+
}
|
|
16143
|
+
|
|
16144
|
+
name(prefix) {
|
|
16145
|
+
let index = this.next.get(prefix) ?? 0;
|
|
16146
|
+
let name;
|
|
16147
|
+
do name = `${prefix}${index++}`; while (
|
|
16148
|
+
this.names.has(name));
|
|
16149
|
+
this.next.set(prefix, index);
|
|
16150
|
+
this.names.add(name);
|
|
16151
|
+
return name;
|
|
16152
|
+
}
|
|
16153
|
+
|
|
16154
|
+
temp() {
|
|
16155
|
+
const name = this.name("__lazyValue");
|
|
16156
|
+
this.tempScopes[this.tempScopes.length - 1].push(name);
|
|
16157
|
+
return name;
|
|
16158
|
+
}
|
|
16159
|
+
|
|
16160
|
+
pushFunctionTemps() {
|
|
16161
|
+
this.tempScopes.push([]);
|
|
16162
|
+
}
|
|
16163
|
+
|
|
16164
|
+
popFunctionTemps() {
|
|
16165
|
+
if (this.tempScopes.length === 1) {
|
|
16166
|
+
return fail("Internal TSRX lazy-transform temporary-scope imbalance");
|
|
16167
|
+
}
|
|
16168
|
+
return this.tempScopes.pop();
|
|
16169
|
+
}
|
|
16170
|
+
|
|
16171
|
+
defaultRead(
|
|
16172
|
+
raw,
|
|
16173
|
+
fallback,
|
|
16174
|
+
bindings,
|
|
16175
|
+
selfName,
|
|
16176
|
+
source)
|
|
16177
|
+
{
|
|
16178
|
+
const tempName = this.temp();
|
|
16179
|
+
const temp = () => ident(tempName, source);
|
|
16180
|
+
const fallbackBindings = new Map(bindings);
|
|
16181
|
+
fallbackBindings.delete(selfName);
|
|
16182
|
+
return sequence(
|
|
16183
|
+
[
|
|
16184
|
+
assignment("=", temp(), raw, source),
|
|
16185
|
+
conditional(
|
|
16186
|
+
binary("===", temp(), undefinedExpression(source), source),
|
|
16187
|
+
transform(cloneNode(fallback), fallbackBindings, this),
|
|
16188
|
+
temp(),
|
|
16189
|
+
source
|
|
16190
|
+
)],
|
|
16191
|
+
|
|
16192
|
+
source
|
|
16193
|
+
);
|
|
16194
|
+
}
|
|
16195
|
+
|
|
16196
|
+
omitIdentifier() {
|
|
16197
|
+
this.omitName ??= this.name("__lazyOmit");
|
|
16198
|
+
return ident(this.omitName);
|
|
16199
|
+
}
|
|
16200
|
+
|
|
16201
|
+
arrayIdentifier(node) {
|
|
16202
|
+
if (this.topLevelGlobalThisBinding) {
|
|
16203
|
+
fail(
|
|
16204
|
+
"TSRX lazy array rest cannot safely access the intrinsic Array because this module binds `globalThis`; rename that top-level binding",
|
|
16205
|
+
node
|
|
16206
|
+
);
|
|
16207
|
+
}
|
|
16208
|
+
this.usesArrayRest = true;
|
|
16209
|
+
this.arrayName ??= this.name("__lazyArray");
|
|
16210
|
+
return ident(this.arrayName, node);
|
|
16211
|
+
}
|
|
16212
|
+
|
|
16213
|
+
finalize(program) {
|
|
16214
|
+
if (program.type !== "Program") {
|
|
16215
|
+
if (this.omitName || this.usesArrayRest || this.programTemps.length) {
|
|
16216
|
+
return fail("The TSRX lazy transform requires a Program root", program);
|
|
16217
|
+
}
|
|
16218
|
+
return program;
|
|
16219
|
+
}
|
|
16220
|
+
|
|
16221
|
+
const generated = [];
|
|
16222
|
+
if (this.arrayName) {
|
|
16223
|
+
generated.push(
|
|
16224
|
+
variableDeclaration(
|
|
16225
|
+
"const",
|
|
16226
|
+
[this.arrayName],
|
|
16227
|
+
member(ident("globalThis"), ident("Array"), false)
|
|
16228
|
+
)
|
|
16229
|
+
);
|
|
16230
|
+
}
|
|
16231
|
+
if (this.programTemps.length) generated.push(variableDeclaration("let", this.programTemps));
|
|
16232
|
+
|
|
16233
|
+
const body = program.body;
|
|
16234
|
+
let directiveEnd = 0;
|
|
16235
|
+
while (
|
|
16236
|
+
directiveEnd < body.length &&
|
|
16237
|
+
body[directiveEnd].type === "ExpressionStatement" &&
|
|
16238
|
+
typeof body[directiveEnd].directive === "string")
|
|
16239
|
+
{
|
|
16240
|
+
directiveEnd++;
|
|
16241
|
+
}
|
|
16242
|
+
let importEnd = directiveEnd;
|
|
16243
|
+
while (importEnd < body.length && body[importEnd].type === "ImportDeclaration") importEnd++;
|
|
16244
|
+
|
|
16245
|
+
const additions = [];
|
|
16246
|
+
if (this.omitName) {
|
|
16247
|
+
additions.push({
|
|
16248
|
+
type: "ImportDeclaration",
|
|
16249
|
+
specifiers: [
|
|
16250
|
+
{
|
|
16251
|
+
type: "ImportSpecifier",
|
|
16252
|
+
imported: ident("omit"),
|
|
16253
|
+
local: ident(this.omitName)
|
|
16254
|
+
}],
|
|
16255
|
+
|
|
16256
|
+
source: literal("solid-js")
|
|
16257
|
+
});
|
|
16258
|
+
}
|
|
16259
|
+
additions.push(...generated);
|
|
16260
|
+
if (additions.length) {
|
|
16261
|
+
program.body = [...body.slice(0, importEnd), ...additions, ...body.slice(importEnd)];
|
|
16262
|
+
}
|
|
16263
|
+
return program;
|
|
16264
|
+
}
|
|
16265
|
+
}
|
|
16266
|
+
|
|
16267
|
+
function programBindsName(root, name) {
|
|
16268
|
+
if (root.type !== "Program") return false;
|
|
16269
|
+
for (const statement of root.body) {
|
|
16270
|
+
const declaration =
|
|
16271
|
+
(statement.type === "ExportNamedDeclaration" ||
|
|
16272
|
+
statement.type === "ExportDefaultDeclaration") &&
|
|
16273
|
+
isNode$1(statement.declaration) ?
|
|
16274
|
+
statement.declaration :
|
|
16275
|
+
statement;
|
|
16276
|
+
if (declaration.type === "VariableDeclaration") {
|
|
16277
|
+
for (const item of declaration.declarations) {
|
|
16278
|
+
const names = new Set();
|
|
16279
|
+
patternNames(item.id, names);
|
|
16280
|
+
if (names.has(name)) return true;
|
|
16281
|
+
}
|
|
16282
|
+
} else if (
|
|
16283
|
+
(declaration.type === "FunctionDeclaration" || declaration.type === "ClassDeclaration") &&
|
|
16284
|
+
isNode$1(declaration.id) &&
|
|
16285
|
+
declaration.id.name === name)
|
|
16286
|
+
{
|
|
16287
|
+
return true;
|
|
16288
|
+
} else if (statement.type === "ImportDeclaration") {
|
|
16289
|
+
for (const specifier of statement.specifiers) {
|
|
16290
|
+
if (isNode$1(specifier.local) && specifier.local.name === name) return true;
|
|
16291
|
+
}
|
|
16292
|
+
}
|
|
16293
|
+
}
|
|
16294
|
+
return false;
|
|
16295
|
+
}
|
|
16296
|
+
|
|
16297
|
+
function assertWritable(binding, node) {
|
|
16298
|
+
if (binding.complexDefault) {
|
|
16299
|
+
fail(
|
|
16300
|
+
"A TSRX lazy binding nested beneath an ancestor default is read-only; assign to the source object explicitly",
|
|
16301
|
+
node
|
|
16302
|
+
);
|
|
16303
|
+
}
|
|
16304
|
+
}
|
|
16305
|
+
|
|
16306
|
+
function staticPropertyName(node) {
|
|
16307
|
+
if (node.type === "Identifier") return node.name;
|
|
16308
|
+
if (node.type === "Literal") return String(node.value);
|
|
16309
|
+
return null;
|
|
16310
|
+
}
|
|
16311
|
+
|
|
16312
|
+
function typePropertyKeys(typeAnnotation) {
|
|
16313
|
+
const keys = new Map();
|
|
16314
|
+
const type = typeAnnotation?.typeAnnotation;
|
|
16315
|
+
if (type?.type !== "TSTypeLiteral") return keys;
|
|
16316
|
+
for (const item of type.members ?? []) {
|
|
16317
|
+
if (item.type !== "TSPropertySignature" || !isNode$1(item.key)) continue;
|
|
16318
|
+
const name = staticPropertyName(item.key);
|
|
16319
|
+
if (name !== null && !keys.has(name)) keys.set(name, item.key);
|
|
16320
|
+
}
|
|
16321
|
+
return keys;
|
|
16322
|
+
}
|
|
16323
|
+
|
|
16324
|
+
function patternRange(pattern) {
|
|
16325
|
+
if (pattern.start === undefined || pattern.end === undefined || pattern.loc === undefined) {
|
|
16326
|
+
return null;
|
|
16327
|
+
}
|
|
16328
|
+
const annotation = pattern.typeAnnotation;
|
|
16329
|
+
return {
|
|
16330
|
+
type: "Identifier",
|
|
16331
|
+
start: pattern.start,
|
|
16332
|
+
end: annotation?.start ?? pattern.end,
|
|
16333
|
+
loc: {
|
|
16334
|
+
start: pattern.loc.start,
|
|
16335
|
+
end:
|
|
16336
|
+
annotation?.loc?.start ??
|
|
16337
|
+
pattern.loc.end
|
|
16338
|
+
}
|
|
16339
|
+
};
|
|
16340
|
+
}
|
|
16341
|
+
|
|
16342
|
+
function generatedPatternIdentifier(pattern, name, isTop) {
|
|
16343
|
+
const range = patternRange(pattern);
|
|
16344
|
+
const id = ident(name, range);
|
|
16345
|
+
if (range && range.start !== undefined && range.end !== undefined) {
|
|
16346
|
+
metadata(id).source_length = range.end - range.start;
|
|
16347
|
+
}
|
|
16348
|
+
if (isTop && isNode$1(pattern.typeAnnotation)) id.typeAnnotation = pattern.typeAnnotation;
|
|
16349
|
+
if (isTop) setParamTypeMappings(id, pattern);
|
|
16350
|
+
return id;
|
|
16351
|
+
}
|
|
16352
|
+
|
|
16353
|
+
function setParamTypeMappings(id, pattern) {
|
|
16354
|
+
if (pattern.type !== "ObjectPattern") return;
|
|
16355
|
+
const keys = typePropertyKeys(id.typeAnnotation);
|
|
16356
|
+
if (!keys.size) return;
|
|
16357
|
+
const mappings = [];
|
|
16358
|
+
for (const property of pattern.properties) {
|
|
16359
|
+
if (property.type === "RestElement" || property.computed) continue;
|
|
16360
|
+
const value = property.value;
|
|
16361
|
+
const actual = value.type === "AssignmentPattern" ? value.left : value;
|
|
16362
|
+
if (actual.type !== "Identifier" || actual.start === undefined) continue;
|
|
16363
|
+
const name = staticPropertyName(property.key);
|
|
16364
|
+
const generated = name === null ? undefined : keys.get(name);
|
|
16365
|
+
if (generated?.start !== undefined) {
|
|
16366
|
+
metadata(generated).disable_verification = true;
|
|
16367
|
+
mappings.push({ source: actual, generated });
|
|
16368
|
+
}
|
|
16369
|
+
}
|
|
16370
|
+
if (mappings.length) metadata(id).lazy_param_binding_mappings = mappings;
|
|
16371
|
+
}
|
|
16372
|
+
|
|
16373
|
+
function visitTopmostLazyPatterns(
|
|
16374
|
+
pattern,
|
|
16375
|
+
visit)
|
|
16376
|
+
{
|
|
16377
|
+
if (!pattern) return;
|
|
16378
|
+
if (pattern.type === "AssignmentPattern") {
|
|
16379
|
+
visitTopmostLazyPatterns(pattern.left, visit);
|
|
16380
|
+
return;
|
|
16381
|
+
}
|
|
16382
|
+
if (pattern.type === "RestElement") {
|
|
16383
|
+
visitTopmostLazyPatterns(pattern.argument, visit);
|
|
16384
|
+
return;
|
|
16385
|
+
}
|
|
16386
|
+
if (pattern.type !== "ObjectPattern" && pattern.type !== "ArrayPattern") return;
|
|
16387
|
+
if (pattern.lazy) {
|
|
16388
|
+
visit(pattern);
|
|
16389
|
+
return;
|
|
16390
|
+
}
|
|
16391
|
+
if (pattern.type === "ObjectPattern") {
|
|
16392
|
+
for (const property of pattern.properties) {
|
|
16393
|
+
visitTopmostLazyPatterns(
|
|
16394
|
+
property.type === "RestElement" ? property.argument : property.value,
|
|
16395
|
+
visit
|
|
16396
|
+
);
|
|
16397
|
+
}
|
|
16398
|
+
} else {
|
|
16399
|
+
for (const element of pattern.elements) {
|
|
16400
|
+
if (element) visitTopmostLazyPatterns(element, visit);
|
|
16401
|
+
}
|
|
16402
|
+
}
|
|
16403
|
+
}
|
|
16404
|
+
|
|
16405
|
+
function preallocate(root, state) {
|
|
16406
|
+
const assign = (pattern) => {
|
|
16407
|
+
visitTopmostLazyPatterns(pattern, (lazy) => {
|
|
16408
|
+
if (!metadata(lazy).lazy_id) metadata(lazy).lazy_id = state.name("__lazy");
|
|
16409
|
+
});
|
|
16410
|
+
};
|
|
16411
|
+
|
|
16412
|
+
const visit = (value) => {
|
|
16413
|
+
if (Array.isArray(value)) {
|
|
16414
|
+
let found = false;
|
|
16415
|
+
for (const child of value) if (visit(child)) found = true;
|
|
16416
|
+
return found;
|
|
16417
|
+
}
|
|
16418
|
+
if (!isNode$1(value)) return false;
|
|
16419
|
+
|
|
16420
|
+
const functionLike = FUNCTION_TYPES.has(value.type);
|
|
16421
|
+
if (functionLike) {
|
|
16422
|
+
for (const param of value.params) {
|
|
16423
|
+
assign(param.type === "AssignmentPattern" ? param.left : param);
|
|
16424
|
+
}
|
|
16425
|
+
}
|
|
16426
|
+
if (value.type === "VariableDeclarator") assign(value.id);
|
|
16427
|
+
if (value.type === "CatchClause" && isNode$1(value.param)) assign(value.param);
|
|
16428
|
+
if (
|
|
16429
|
+
value.type === "ExpressionStatement" &&
|
|
16430
|
+
isNode$1(value.expression) &&
|
|
16431
|
+
value.expression.type === "AssignmentExpression" &&
|
|
16432
|
+
value.expression.operator === "=")
|
|
16433
|
+
{
|
|
16434
|
+
assign(value.expression.left);
|
|
16435
|
+
}
|
|
16436
|
+
|
|
16437
|
+
let found =
|
|
16438
|
+
(value.type === "ObjectPattern" || value.type === "ArrayPattern") && value.lazy === true;
|
|
16439
|
+
for (const key of Object.keys(value)) {
|
|
16440
|
+
if (SKIP_KEYS$1.has(key)) continue;
|
|
16441
|
+
if (visit(value[key])) found = true;
|
|
16442
|
+
}
|
|
16443
|
+
if (functionLike && found) metadata(value).has_lazy_descendants = true;
|
|
16444
|
+
return found;
|
|
16445
|
+
};
|
|
16446
|
+
visit(root);
|
|
16447
|
+
}
|
|
16448
|
+
|
|
16449
|
+
function transformedEmbedded(
|
|
16450
|
+
node,
|
|
16451
|
+
bindings,
|
|
16452
|
+
state,
|
|
16453
|
+
selfName)
|
|
16454
|
+
{
|
|
16455
|
+
const effective = new Map(bindings);
|
|
16456
|
+
effective.delete(selfName);
|
|
16457
|
+
return transform(cloneNode(node), effective, state);
|
|
16458
|
+
}
|
|
16459
|
+
|
|
16460
|
+
function rootAccess(sourceName, accessor) {
|
|
16461
|
+
const source = (reference) => {
|
|
16462
|
+
const identifier = ident(sourceName, reference);
|
|
16463
|
+
return accessor ? call(identifier, [], reference) : identifier;
|
|
16464
|
+
};
|
|
16465
|
+
return {
|
|
16466
|
+
raw: (reference) => source(reference),
|
|
16467
|
+
value: (reference) => source(reference),
|
|
16468
|
+
plain: true,
|
|
16469
|
+
jsxCompatible: !accessor,
|
|
16470
|
+
complexDefault: false
|
|
16471
|
+
};
|
|
16472
|
+
}
|
|
16473
|
+
|
|
16474
|
+
function propertyAccess(parent, key, computed, state) {
|
|
16475
|
+
const property = (bindings, selfName, reference) =>
|
|
16476
|
+
computed ?
|
|
16477
|
+
transformedEmbedded(key, bindings, state, selfName) :
|
|
16478
|
+
ident(key.name, reference);
|
|
16479
|
+
return {
|
|
16480
|
+
raw: (reference, bindings, selfName) =>
|
|
16481
|
+
member(
|
|
16482
|
+
parent.raw(reference, bindings, selfName),
|
|
16483
|
+
property(bindings, selfName, reference),
|
|
16484
|
+
computed,
|
|
16485
|
+
reference
|
|
16486
|
+
),
|
|
16487
|
+
value: (reference, bindings, selfName) =>
|
|
16488
|
+
member(
|
|
16489
|
+
parent.value(reference, bindings, selfName),
|
|
16490
|
+
property(bindings, selfName, reference),
|
|
16491
|
+
computed,
|
|
16492
|
+
reference
|
|
16493
|
+
),
|
|
16494
|
+
plain: parent.plain,
|
|
16495
|
+
jsxCompatible: parent.jsxCompatible && !computed,
|
|
16496
|
+
complexDefault: parent.complexDefault || parent.directDefault !== undefined
|
|
16497
|
+
};
|
|
16498
|
+
}
|
|
16499
|
+
|
|
16500
|
+
function defaultAccess(parent, fallback, state) {
|
|
16501
|
+
return {
|
|
16502
|
+
raw: parent.raw,
|
|
16503
|
+
value: (reference, bindings, selfName) =>
|
|
16504
|
+
state.defaultRead(
|
|
16505
|
+
parent.value(reference, bindings, selfName),
|
|
16506
|
+
fallback,
|
|
16507
|
+
bindings,
|
|
16508
|
+
selfName,
|
|
16509
|
+
reference
|
|
16510
|
+
),
|
|
16511
|
+
plain: false,
|
|
16512
|
+
jsxCompatible: false,
|
|
16513
|
+
directDefault: fallback,
|
|
16514
|
+
complexDefault: parent.complexDefault || parent.directDefault !== undefined
|
|
16515
|
+
};
|
|
16516
|
+
}
|
|
16517
|
+
|
|
16518
|
+
function jsxNameFromMember(expression, source) {
|
|
16519
|
+
if (expression.type === "Identifier") {
|
|
16520
|
+
return withLoc$1({ type: "JSXIdentifier", name: expression.name }, source);
|
|
16521
|
+
}
|
|
16522
|
+
if (
|
|
16523
|
+
expression.type === "MemberExpression" &&
|
|
16524
|
+
!expression.computed &&
|
|
16525
|
+
isNode$1(expression.property) &&
|
|
16526
|
+
expression.property.type === "Identifier")
|
|
16527
|
+
{
|
|
16528
|
+
const object = jsxNameFromMember(expression.object, source);
|
|
16529
|
+
if (object) {
|
|
16530
|
+
return withLoc$1(
|
|
16531
|
+
{
|
|
16532
|
+
type: "JSXMemberExpression",
|
|
16533
|
+
object,
|
|
16534
|
+
property: withLoc$1(
|
|
16535
|
+
{ type: "JSXIdentifier", name: expression.property.name },
|
|
16536
|
+
expression.property
|
|
16537
|
+
)
|
|
16538
|
+
},
|
|
16539
|
+
source
|
|
16540
|
+
);
|
|
16541
|
+
}
|
|
16542
|
+
}
|
|
16543
|
+
return null;
|
|
16544
|
+
}
|
|
16545
|
+
|
|
16546
|
+
function registerBinding(
|
|
16547
|
+
name,
|
|
16548
|
+
sourceName,
|
|
16549
|
+
access,
|
|
16550
|
+
bindings)
|
|
16551
|
+
{
|
|
16552
|
+
bindings.set(name, {
|
|
16553
|
+
sourceName,
|
|
16554
|
+
read(reference, current) {
|
|
16555
|
+
return access.value(reference, current, name);
|
|
16556
|
+
},
|
|
16557
|
+
target(reference, current) {
|
|
16558
|
+
return access.raw(reference, current, name);
|
|
16559
|
+
},
|
|
16560
|
+
jsxName(reference, current) {
|
|
16561
|
+
return access.jsxCompatible ?
|
|
16562
|
+
jsxNameFromMember(access.raw(reference, current, name), reference) :
|
|
16563
|
+
null;
|
|
16564
|
+
},
|
|
16565
|
+
directDefault: access.directDefault,
|
|
16566
|
+
complexDefault: access.complexDefault
|
|
16567
|
+
});
|
|
16568
|
+
}
|
|
16569
|
+
|
|
16570
|
+
function collectBindingsAt(
|
|
16571
|
+
pattern,
|
|
16572
|
+
sourceName,
|
|
16573
|
+
access,
|
|
16574
|
+
bindings,
|
|
16575
|
+
state)
|
|
16576
|
+
{
|
|
16577
|
+
if (pattern.type === "AssignmentPattern") {
|
|
16578
|
+
collectBindingsAt(
|
|
16579
|
+
pattern.left,
|
|
16580
|
+
sourceName,
|
|
16581
|
+
defaultAccess(access, pattern.right, state),
|
|
16582
|
+
bindings,
|
|
16583
|
+
state
|
|
16584
|
+
);
|
|
16585
|
+
return;
|
|
16586
|
+
}
|
|
16587
|
+
if (pattern.type === "Identifier") {
|
|
16588
|
+
registerBinding(pattern.name, sourceName, access, bindings);
|
|
16589
|
+
return;
|
|
16590
|
+
}
|
|
16591
|
+
if (pattern.type === "ObjectPattern") {
|
|
16592
|
+
const properties = pattern.properties;
|
|
16593
|
+
const sourceKeys = properties.
|
|
16594
|
+
filter((property) => property.type !== "RestElement").
|
|
16595
|
+
map((property) => {
|
|
16596
|
+
const key = property.key;
|
|
16597
|
+
return property.computed ? key : literal(staticPropertyName(key) ?? "", key);
|
|
16598
|
+
});
|
|
16599
|
+
for (const property of properties) {
|
|
16600
|
+
if (property.type === "RestElement") {
|
|
16601
|
+
const argument = property.argument;
|
|
16602
|
+
if (argument.type !== "Identifier") {
|
|
16603
|
+
fail("TSRX lazy object rest currently requires an identifier binding", argument);
|
|
16604
|
+
}
|
|
16605
|
+
const name = argument.name;
|
|
16606
|
+
bindings.set(name, {
|
|
16607
|
+
sourceName,
|
|
16608
|
+
read(reference, current) {
|
|
16609
|
+
const effective = new Map(current);
|
|
16610
|
+
effective.delete(name);
|
|
16611
|
+
return call(
|
|
16612
|
+
state.omitIdentifier(),
|
|
16613
|
+
[
|
|
16614
|
+
access.value(reference, current, name),
|
|
16615
|
+
...sourceKeys.map((key) => transform(cloneNode(key), effective, state))],
|
|
16616
|
+
|
|
16617
|
+
reference
|
|
16618
|
+
);
|
|
16619
|
+
},
|
|
16620
|
+
target() {
|
|
16621
|
+
return null;
|
|
16622
|
+
},
|
|
16623
|
+
jsxName() {
|
|
16624
|
+
return null;
|
|
16625
|
+
},
|
|
16626
|
+
complexDefault: access.complexDefault
|
|
16627
|
+
});
|
|
16628
|
+
continue;
|
|
16629
|
+
}
|
|
16630
|
+
const key = property.key;
|
|
16631
|
+
const computed = !!property.computed || key.type !== "Identifier";
|
|
16632
|
+
collectBindingsAt(
|
|
16633
|
+
property.value,
|
|
16634
|
+
sourceName,
|
|
16635
|
+
propertyAccess(access, key, computed, state),
|
|
16636
|
+
bindings,
|
|
16637
|
+
state
|
|
16638
|
+
);
|
|
16639
|
+
}
|
|
16640
|
+
return;
|
|
16641
|
+
}
|
|
16642
|
+
if (pattern.type === "ArrayPattern") {
|
|
16643
|
+
const elements = pattern.elements;
|
|
16644
|
+
for (let index = 0; index < elements.length; index++) {
|
|
16645
|
+
const element = elements[index];
|
|
16646
|
+
if (!element) continue;
|
|
16647
|
+
if (element.type === "RestElement") {
|
|
16648
|
+
const argument = element.argument;
|
|
16649
|
+
if (argument.type !== "Identifier") {
|
|
16650
|
+
fail("TSRX lazy array rest currently requires an identifier binding", argument);
|
|
16651
|
+
}
|
|
16652
|
+
const name = argument.name;
|
|
16653
|
+
// Reserve and validate the intrinsic alias when the pattern is
|
|
16654
|
+
// registered, even if the rest binding is never read. The native
|
|
16655
|
+
// frontend plans helpers at binding time and must emit the same
|
|
16656
|
+
// `globalThis` shadowing diagnostic.
|
|
16657
|
+
state.arrayIdentifier(argument);
|
|
16658
|
+
bindings.set(name, {
|
|
16659
|
+
sourceName,
|
|
16660
|
+
read(reference, current) {
|
|
16661
|
+
const from = member(
|
|
16662
|
+
state.arrayIdentifier(reference),
|
|
16663
|
+
ident("from", reference),
|
|
16664
|
+
false,
|
|
16665
|
+
reference
|
|
16666
|
+
);
|
|
16667
|
+
const array = call(from, [access.value(reference, current, name)], reference);
|
|
16668
|
+
return call(
|
|
16669
|
+
member(array, ident("slice", reference), false, reference),
|
|
16670
|
+
[literal(index, reference)],
|
|
16671
|
+
reference
|
|
16672
|
+
);
|
|
16673
|
+
},
|
|
16674
|
+
target() {
|
|
16675
|
+
return null;
|
|
16676
|
+
},
|
|
16677
|
+
jsxName() {
|
|
16678
|
+
return null;
|
|
16679
|
+
},
|
|
16680
|
+
complexDefault: access.complexDefault
|
|
16681
|
+
});
|
|
16682
|
+
continue;
|
|
16683
|
+
}
|
|
16684
|
+
collectBindingsAt(
|
|
16685
|
+
element,
|
|
16686
|
+
sourceName,
|
|
16687
|
+
propertyAccess(access, literal(index, element), true, state),
|
|
16688
|
+
bindings,
|
|
16689
|
+
state
|
|
16690
|
+
);
|
|
16691
|
+
}
|
|
16692
|
+
}
|
|
16693
|
+
}
|
|
16694
|
+
|
|
16695
|
+
function collectBindings(
|
|
16696
|
+
pattern,
|
|
16697
|
+
sourceName,
|
|
16698
|
+
bindings,
|
|
16699
|
+
state)
|
|
16700
|
+
{
|
|
16701
|
+
collectBindingsAt(
|
|
16702
|
+
pattern,
|
|
16703
|
+
sourceName,
|
|
16704
|
+
rootAccess(sourceName, metadata(pattern).lazy_source_accessor === true),
|
|
16705
|
+
bindings,
|
|
16706
|
+
state
|
|
16707
|
+
);
|
|
16708
|
+
}
|
|
16709
|
+
|
|
16710
|
+
function collectBindingsFromStatements(
|
|
16711
|
+
statements,
|
|
16712
|
+
bindings,
|
|
16713
|
+
state)
|
|
16714
|
+
{
|
|
16715
|
+
for (const statement of statements) {
|
|
16716
|
+
const declaration =
|
|
16717
|
+
(statement.type === "ExportNamedDeclaration" ||
|
|
16718
|
+
statement.type === "ExportDefaultDeclaration") &&
|
|
16719
|
+
isNode$1(statement.declaration) ?
|
|
16720
|
+
statement.declaration :
|
|
16721
|
+
statement;
|
|
16722
|
+
if (declaration.type === "VariableDeclaration" && declaration.kind !== "var") {
|
|
16723
|
+
for (const item of declaration.declarations) {
|
|
16724
|
+
visitTopmostLazyPatterns(item.id, (lazy) => {
|
|
16725
|
+
const sourceName = metadata(lazy).lazy_id;
|
|
16726
|
+
if (sourceName) collectBindings(lazy, sourceName, bindings, state);
|
|
16727
|
+
});
|
|
16728
|
+
}
|
|
16729
|
+
} else if (
|
|
16730
|
+
statement.type === "ExpressionStatement" &&
|
|
16731
|
+
isNode$1(statement.expression) &&
|
|
16732
|
+
statement.expression.type === "AssignmentExpression" &&
|
|
16733
|
+
statement.expression.operator === "=")
|
|
16734
|
+
{
|
|
16735
|
+
visitTopmostLazyPatterns(statement.expression.left, (lazy) => {
|
|
16736
|
+
const sourceName = metadata(lazy).lazy_id;
|
|
16737
|
+
if (sourceName) collectBindings(lazy, sourceName, bindings, state);
|
|
16738
|
+
});
|
|
16739
|
+
}
|
|
16740
|
+
}
|
|
16741
|
+
}
|
|
16742
|
+
|
|
16743
|
+
|
|
16744
|
+
|
|
16745
|
+
|
|
16746
|
+
|
|
16747
|
+
|
|
16748
|
+
/**
|
|
16749
|
+
* Collect function/program-scoped `var` declarations before rewriting any
|
|
16750
|
+
* references in that scope. `var` crosses blocks, loops, switches, and catch
|
|
16751
|
+
* bodies, but never crosses a nested function, class, or class static block.
|
|
16752
|
+
*/
|
|
16753
|
+
function collectVarScopeBindings(statements, state) {
|
|
16754
|
+
const declared = new Set();
|
|
16755
|
+
const lazy = new Map();
|
|
16756
|
+
|
|
16757
|
+
const visit = (value) => {
|
|
16758
|
+
if (Array.isArray(value)) {
|
|
16759
|
+
for (const child of value) visit(child);
|
|
16760
|
+
return;
|
|
16761
|
+
}
|
|
16762
|
+
if (!isNode$1(value)) return;
|
|
16763
|
+
if (
|
|
16764
|
+
FUNCTION_TYPES.has(value.type) ||
|
|
16765
|
+
value.type === "ClassDeclaration" ||
|
|
16766
|
+
value.type === "ClassExpression" ||
|
|
16767
|
+
value.type === "StaticBlock" ||
|
|
16768
|
+
value.type === "ClassStaticBlock")
|
|
16769
|
+
{
|
|
16770
|
+
return;
|
|
16771
|
+
}
|
|
16772
|
+
if (value.type === "VariableDeclaration" && value.kind === "var") {
|
|
16773
|
+
for (const declaration of value.declarations) {
|
|
16774
|
+
patternNames(declaration.id, declared);
|
|
16775
|
+
visitTopmostLazyPatterns(declaration.id, (pattern) => {
|
|
16776
|
+
const sourceName = metadata(pattern).lazy_id;
|
|
16777
|
+
if (sourceName) collectBindings(pattern, sourceName, lazy, state);
|
|
16778
|
+
});
|
|
16779
|
+
}
|
|
16780
|
+
}
|
|
16781
|
+
for (const key of Object.keys(value)) {
|
|
16782
|
+
if (!SKIP_KEYS$1.has(key)) visit(value[key]);
|
|
16783
|
+
}
|
|
16784
|
+
};
|
|
16785
|
+
|
|
16786
|
+
visit(statements);
|
|
16787
|
+
return { declared, lazy };
|
|
16788
|
+
}
|
|
16789
|
+
|
|
16790
|
+
function replaceLazyInPattern(pattern, isTop = true) {
|
|
16791
|
+
if (pattern.type === "AssignmentPattern") {
|
|
16792
|
+
const left = replaceLazyInPattern(pattern.left, isTop);
|
|
16793
|
+
return left === pattern.left ? pattern : { ...pattern, left };
|
|
16794
|
+
}
|
|
16795
|
+
if (pattern.type === "RestElement") {
|
|
16796
|
+
const argument = replaceLazyInPattern(pattern.argument, false);
|
|
16797
|
+
return argument === pattern.argument ? pattern : { ...pattern, argument };
|
|
16798
|
+
}
|
|
16799
|
+
if (pattern.type !== "ObjectPattern" && pattern.type !== "ArrayPattern") return pattern;
|
|
16800
|
+
const sourceName = metadata(pattern).lazy_id;
|
|
16801
|
+
if (pattern.lazy && sourceName) return generatedPatternIdentifier(pattern, sourceName, isTop);
|
|
16802
|
+
if (pattern.type === "ObjectPattern") {
|
|
16803
|
+
let changed = false;
|
|
16804
|
+
const properties = pattern.properties.map((property) => {
|
|
16805
|
+
const key = property.type === "RestElement" ? "argument" : "value";
|
|
16806
|
+
const value = property[key];
|
|
16807
|
+
const replacement = replaceLazyInPattern(value, false);
|
|
16808
|
+
if (replacement === value) return property;
|
|
16809
|
+
changed = true;
|
|
16810
|
+
return { ...property, [key]: replacement };
|
|
16811
|
+
});
|
|
16812
|
+
return changed ? { ...pattern, properties } : pattern;
|
|
16813
|
+
}
|
|
16814
|
+
let changed = false;
|
|
16815
|
+
const elements = pattern.elements.map((element) => {
|
|
16816
|
+
if (!element) return element;
|
|
16817
|
+
const replacement = replaceLazyInPattern(element, false);
|
|
16818
|
+
if (replacement !== element) changed = true;
|
|
16819
|
+
return replacement;
|
|
16820
|
+
});
|
|
16821
|
+
return changed ? { ...pattern, elements } : pattern;
|
|
16822
|
+
}
|
|
16823
|
+
|
|
16824
|
+
function replaceLazyParams(params) {
|
|
16825
|
+
return params.map((param) => replaceLazyInPattern(param));
|
|
16826
|
+
}
|
|
16827
|
+
|
|
16828
|
+
function patternNames(pattern, names) {
|
|
16829
|
+
switch (pattern.type) {
|
|
16830
|
+
case "Identifier":
|
|
16831
|
+
names.add(pattern.name);
|
|
16832
|
+
return;
|
|
16833
|
+
case "AssignmentPattern":
|
|
16834
|
+
patternNames(pattern.left, names);
|
|
16835
|
+
return;
|
|
16836
|
+
case "RestElement":
|
|
16837
|
+
patternNames(pattern.argument, names);
|
|
16838
|
+
return;
|
|
16839
|
+
case "ObjectPattern":
|
|
16840
|
+
for (const property of pattern.properties) {
|
|
16841
|
+
patternNames(
|
|
16842
|
+
property.type === "RestElement" ? property.argument : property.value,
|
|
16843
|
+
names
|
|
16844
|
+
);
|
|
16845
|
+
}
|
|
16846
|
+
return;
|
|
16847
|
+
case "ArrayPattern":
|
|
16848
|
+
for (const element of pattern.elements) {
|
|
16849
|
+
if (element) patternNames(element, names);
|
|
16850
|
+
}
|
|
16851
|
+
}
|
|
16852
|
+
}
|
|
16853
|
+
|
|
16854
|
+
function collectShadowed(pattern, bindings, names) {
|
|
16855
|
+
const all = new Set();
|
|
16856
|
+
patternNames(pattern, all);
|
|
16857
|
+
for (const name of all) if (bindings.has(name)) names.add(name);
|
|
16858
|
+
}
|
|
16859
|
+
|
|
16860
|
+
function collectBlockShadowed(statements, bindings) {
|
|
16861
|
+
const names = new Set();
|
|
16862
|
+
for (const statement of statements) {
|
|
16863
|
+
const declaration =
|
|
16864
|
+
(statement.type === "ExportNamedDeclaration" ||
|
|
16865
|
+
statement.type === "ExportDefaultDeclaration") &&
|
|
16866
|
+
isNode$1(statement.declaration) ?
|
|
16867
|
+
statement.declaration :
|
|
16868
|
+
statement;
|
|
16869
|
+
if (declaration.type === "VariableDeclaration" && declaration.kind !== "var") {
|
|
16870
|
+
for (const item of declaration.declarations) {
|
|
16871
|
+
collectShadowed(item.id, bindings, names);
|
|
16872
|
+
}
|
|
16873
|
+
} else if (
|
|
16874
|
+
(declaration.type === "FunctionDeclaration" || declaration.type === "ClassDeclaration") &&
|
|
16875
|
+
isNode$1(declaration.id) &&
|
|
16876
|
+
bindings.has(declaration.id.name))
|
|
16877
|
+
{
|
|
16878
|
+
names.add(declaration.id.name);
|
|
16879
|
+
} else if (statement.type === "ImportDeclaration") {
|
|
16880
|
+
for (const specifier of statement.specifiers) {
|
|
16881
|
+
if (isNode$1(specifier.local) && bindings.has(specifier.local.name)) {
|
|
16882
|
+
names.add(specifier.local.name);
|
|
16883
|
+
}
|
|
16884
|
+
}
|
|
16885
|
+
}
|
|
16886
|
+
}
|
|
16887
|
+
return names;
|
|
16888
|
+
}
|
|
16889
|
+
|
|
16890
|
+
function without(bindings, names) {
|
|
16891
|
+
const result = new Map(bindings);
|
|
16892
|
+
for (const name of names) result.delete(name);
|
|
16893
|
+
return result;
|
|
16894
|
+
}
|
|
16895
|
+
|
|
16896
|
+
function transformValue(value, bindings, state) {
|
|
16897
|
+
if (Array.isArray(value)) return value.map((item) => transformValue(item, bindings, state));
|
|
16898
|
+
return isNode$1(value) ? transform(value, bindings, state) : value;
|
|
16899
|
+
}
|
|
16900
|
+
|
|
16901
|
+
function targetParts(target, source) {
|
|
16902
|
+
if (target.type !== "MemberExpression") {
|
|
16903
|
+
return fail("A writable TSRX lazy binding did not resolve to a member expression", source);
|
|
16904
|
+
}
|
|
16905
|
+
const property = target.property;
|
|
16906
|
+
return {
|
|
16907
|
+
object: target.object,
|
|
16908
|
+
key: target.computed ? property : literal(property.name, property)
|
|
16909
|
+
};
|
|
16910
|
+
}
|
|
16911
|
+
|
|
16912
|
+
function lowerDefaultedAssignment(
|
|
16913
|
+
node,
|
|
16914
|
+
binding,
|
|
16915
|
+
bindings,
|
|
16916
|
+
state)
|
|
16917
|
+
{
|
|
16918
|
+
if (!binding.directDefault) return fail("Missing default for TSRX lazy assignment", node);
|
|
16919
|
+
const left = node.left;
|
|
16920
|
+
const target = binding.target(left, bindings);
|
|
16921
|
+
if (!target) return fail("A TSRX lazy rest binding is read-only", left);
|
|
16922
|
+
const { object, key } = targetParts(target, left);
|
|
16923
|
+
const objectName = state.temp();
|
|
16924
|
+
const keyName = state.temp();
|
|
16925
|
+
const valueName = state.temp();
|
|
16926
|
+
const objectId = () => ident(objectName, left);
|
|
16927
|
+
const keyId = () => ident(keyName, left);
|
|
16928
|
+
const valueId = () => ident(valueName, left);
|
|
16929
|
+
const destination = () => member(objectId(), keyId(), true, left);
|
|
16930
|
+
const effective = new Map(bindings);
|
|
16931
|
+
effective.delete(left.name);
|
|
16932
|
+
const fallback = transform(cloneNode(binding.directDefault), effective, state);
|
|
16933
|
+
const right = transform(node.right, bindings, state);
|
|
16934
|
+
const operator = node.operator;
|
|
16935
|
+
const expressions = [
|
|
16936
|
+
assignment("=", objectId(), object, left),
|
|
16937
|
+
assignment("=", keyId(), key, left),
|
|
16938
|
+
assignment("=", valueId(), destination(), left),
|
|
16939
|
+
assignment(
|
|
16940
|
+
"=",
|
|
16941
|
+
valueId(),
|
|
16942
|
+
conditional(
|
|
16943
|
+
binary("===", valueId(), undefinedExpression(left), left),
|
|
16944
|
+
fallback,
|
|
16945
|
+
valueId(),
|
|
16946
|
+
left
|
|
16947
|
+
),
|
|
16948
|
+
left
|
|
16949
|
+
)];
|
|
16950
|
+
|
|
16951
|
+
|
|
16952
|
+
if (operator === "&&=" || operator === "||=" || operator === "??=") {
|
|
16953
|
+
expressions.push(
|
|
16954
|
+
logical(operator.slice(0, -1), valueId(), assignment("=", destination(), right, node), node)
|
|
16955
|
+
);
|
|
16956
|
+
} else {
|
|
16957
|
+
expressions.push(
|
|
16958
|
+
assignment("=", destination(), binary(operator.slice(0, -1), valueId(), right, node), node)
|
|
16959
|
+
);
|
|
16960
|
+
}
|
|
16961
|
+
return sequence(expressions, node);
|
|
16962
|
+
}
|
|
16963
|
+
|
|
16964
|
+
function lowerDefaultedUpdate(
|
|
16965
|
+
node,
|
|
16966
|
+
binding,
|
|
16967
|
+
bindings,
|
|
16968
|
+
state)
|
|
16969
|
+
{
|
|
16970
|
+
if (!binding.directDefault) return fail("Missing default for TSRX lazy update", node);
|
|
16971
|
+
const argument = node.argument;
|
|
16972
|
+
const target = binding.target(argument, bindings);
|
|
16973
|
+
if (!target) return fail("A TSRX lazy rest binding is read-only", argument);
|
|
16974
|
+
const { object, key } = targetParts(target, argument);
|
|
16975
|
+
const objectName = state.temp();
|
|
16976
|
+
const keyName = state.temp();
|
|
16977
|
+
const valueName = state.temp();
|
|
16978
|
+
const objectId = () => ident(objectName, argument);
|
|
16979
|
+
const keyId = () => ident(keyName, argument);
|
|
16980
|
+
const valueId = () => ident(valueName, argument);
|
|
16981
|
+
const destination = () => member(objectId(), keyId(), true, argument);
|
|
16982
|
+
const effective = new Map(bindings);
|
|
16983
|
+
effective.delete(argument.name);
|
|
16984
|
+
const fallback = transform(cloneNode(binding.directDefault), effective, state);
|
|
16985
|
+
const expressions = [
|
|
16986
|
+
assignment("=", objectId(), object, argument),
|
|
16987
|
+
assignment("=", keyId(), key, argument),
|
|
16988
|
+
assignment("=", valueId(), destination(), argument),
|
|
16989
|
+
assignment(
|
|
16990
|
+
"=",
|
|
16991
|
+
valueId(),
|
|
16992
|
+
conditional(
|
|
16993
|
+
binary("===", valueId(), undefinedExpression(argument), argument),
|
|
16994
|
+
fallback,
|
|
16995
|
+
valueId(),
|
|
16996
|
+
argument
|
|
16997
|
+
),
|
|
16998
|
+
argument
|
|
16999
|
+
)];
|
|
17000
|
+
|
|
17001
|
+
|
|
17002
|
+
if (node.prefix) {
|
|
17003
|
+
expressions.push(
|
|
17004
|
+
assignment(
|
|
17005
|
+
"=",
|
|
17006
|
+
destination(),
|
|
17007
|
+
withLoc$1(
|
|
17008
|
+
{
|
|
17009
|
+
type: "UpdateExpression",
|
|
17010
|
+
operator: node.operator,
|
|
17011
|
+
prefix: true,
|
|
17012
|
+
argument: valueId()
|
|
17013
|
+
},
|
|
17014
|
+
node
|
|
17015
|
+
),
|
|
17016
|
+
node
|
|
17017
|
+
)
|
|
17018
|
+
);
|
|
17019
|
+
} else {
|
|
17020
|
+
const oldName = state.temp();
|
|
17021
|
+
const oldId = () => ident(oldName, argument);
|
|
17022
|
+
expressions.push(
|
|
17023
|
+
assignment(
|
|
17024
|
+
"=",
|
|
17025
|
+
oldId(),
|
|
17026
|
+
withLoc$1(
|
|
17027
|
+
{
|
|
17028
|
+
type: "UpdateExpression",
|
|
17029
|
+
operator: node.operator,
|
|
17030
|
+
prefix: false,
|
|
17031
|
+
argument: valueId()
|
|
17032
|
+
},
|
|
17033
|
+
node
|
|
17034
|
+
),
|
|
17035
|
+
node
|
|
17036
|
+
),
|
|
17037
|
+
assignment("=", destination(), valueId(), node),
|
|
17038
|
+
oldId()
|
|
17039
|
+
);
|
|
17040
|
+
}
|
|
17041
|
+
return sequence(expressions, node);
|
|
17042
|
+
}
|
|
17043
|
+
|
|
17044
|
+
function dynamicJsxElement(node, bindings, state) {
|
|
17045
|
+
const opening = node.openingElement;
|
|
17046
|
+
const name = opening.name;
|
|
17047
|
+
let base = name;
|
|
17048
|
+
const properties = [];
|
|
17049
|
+
while (base.type === "JSXMemberExpression") {
|
|
17050
|
+
properties.unshift(base.property);
|
|
17051
|
+
base = base.object;
|
|
17052
|
+
}
|
|
17053
|
+
if (base.type !== "JSXIdentifier" || !/^[A-Z]/.test(base.name)) return null;
|
|
17054
|
+
const binding = bindings.get(base.name);
|
|
17055
|
+
if (!binding || binding.jsxName(base, bindings)) return null;
|
|
17056
|
+
|
|
17057
|
+
let expression = binding.read(base, bindings);
|
|
17058
|
+
for (const property of properties) {
|
|
17059
|
+
expression = member(expression, ident(property.name, property), false, property);
|
|
17060
|
+
}
|
|
17061
|
+
const dynamicName = withLoc$1({ type: "JSXIdentifier", name: "Dynamic" }, name);
|
|
17062
|
+
const componentAttribute = {
|
|
17063
|
+
type: "JSXAttribute",
|
|
17064
|
+
name: withLoc$1({ type: "JSXIdentifier", name: "component" }, name),
|
|
17065
|
+
value: withLoc$1({ type: "JSXExpressionContainer", expression }, name)
|
|
17066
|
+
};
|
|
17067
|
+
const nextOpening = {
|
|
17068
|
+
...opening,
|
|
17069
|
+
name: dynamicName,
|
|
17070
|
+
attributes: [
|
|
17071
|
+
componentAttribute,
|
|
17072
|
+
...(opening.attributes ?? []).map((attribute) =>
|
|
17073
|
+
transform(attribute, bindings, state)
|
|
17074
|
+
)]
|
|
17075
|
+
|
|
17076
|
+
};
|
|
17077
|
+
const closing = node.closingElement;
|
|
17078
|
+
return {
|
|
17079
|
+
...node,
|
|
17080
|
+
openingElement: nextOpening,
|
|
17081
|
+
closingElement: closing ? { ...closing, name: cloneNode(dynamicName) } : null,
|
|
17082
|
+
children: (node.children ?? []).map((child) => transform(child, bindings, state))
|
|
17083
|
+
};
|
|
17084
|
+
}
|
|
17085
|
+
|
|
17086
|
+
function addFunctionTemps(body, names) {
|
|
17087
|
+
if (!names.length) return body;
|
|
17088
|
+
const declaration = variableDeclaration("let", names);
|
|
17089
|
+
if (body.type !== "BlockStatement") {
|
|
17090
|
+
return {
|
|
17091
|
+
type: "BlockStatement",
|
|
17092
|
+
body: [declaration, withLoc$1({ type: "ReturnStatement", argument: body }, body)]
|
|
17093
|
+
};
|
|
17094
|
+
}
|
|
17095
|
+
const statements = body.body;
|
|
17096
|
+
let directiveEnd = 0;
|
|
17097
|
+
while (
|
|
17098
|
+
directiveEnd < statements.length &&
|
|
17099
|
+
statements[directiveEnd].type === "ExpressionStatement" &&
|
|
17100
|
+
typeof statements[directiveEnd].directive === "string")
|
|
17101
|
+
{
|
|
17102
|
+
directiveEnd++;
|
|
17103
|
+
}
|
|
17104
|
+
return {
|
|
17105
|
+
...body,
|
|
17106
|
+
body: [...statements.slice(0, directiveEnd), declaration, ...statements.slice(directiveEnd)]
|
|
17107
|
+
};
|
|
17108
|
+
}
|
|
17109
|
+
|
|
17110
|
+
function transform(node, bindings, state) {
|
|
17111
|
+
if (FUNCTION_TYPES.has(node.type)) {
|
|
17112
|
+
const shadowed = new Set();
|
|
17113
|
+
if (isNode$1(node.id)) collectShadowed(node.id, bindings, shadowed);
|
|
17114
|
+
for (const param of node.params) collectShadowed(param, bindings, shadowed);
|
|
17115
|
+
const outer = shadowed.size ? without(bindings, shadowed) : bindings;
|
|
17116
|
+
const own = new Map();
|
|
17117
|
+
let lazyParam = false;
|
|
17118
|
+
for (const param of node.params) {
|
|
17119
|
+
visitTopmostLazyPatterns(param, (lazy) => {
|
|
17120
|
+
const sourceName = metadata(lazy).lazy_id;
|
|
17121
|
+
if (!sourceName) return;
|
|
17122
|
+
lazyParam = true;
|
|
17123
|
+
collectBindings(lazy, sourceName, own, state);
|
|
17124
|
+
});
|
|
17125
|
+
}
|
|
17126
|
+
const inner = own.size ? new Map([...outer, ...own]) : outer;
|
|
17127
|
+
let paramsChanged = false;
|
|
17128
|
+
const params = node.params.map((param) => {
|
|
17129
|
+
if (param.type !== "AssignmentPattern") return param;
|
|
17130
|
+
const right = transform(param.right, inner, state);
|
|
17131
|
+
if (right === param.right) return param;
|
|
17132
|
+
paramsChanged = true;
|
|
17133
|
+
return { ...param, right };
|
|
17134
|
+
});
|
|
17135
|
+
if (!inner.size && !paramsChanged && !lazyParam && !metadata(node).has_lazy_descendants) {
|
|
17136
|
+
return node;
|
|
17137
|
+
}
|
|
17138
|
+
state.pushFunctionTemps();
|
|
17139
|
+
const functionBody = node.body;
|
|
17140
|
+
let bodyBindings = inner;
|
|
17141
|
+
if (functionBody.type === "BlockStatement") {
|
|
17142
|
+
const varScope = collectVarScopeBindings(functionBody.body, state);
|
|
17143
|
+
const unshadowed = varScope.declared.size ?
|
|
17144
|
+
without(bodyBindings, varScope.declared) :
|
|
17145
|
+
bodyBindings;
|
|
17146
|
+
bodyBindings = new Map([...unshadowed, ...own, ...varScope.lazy]);
|
|
17147
|
+
}
|
|
17148
|
+
const transformedBody = transform(functionBody, bodyBindings, state);
|
|
17149
|
+
const bodyTemps = state.popFunctionTemps();
|
|
17150
|
+
const body = addFunctionTemps(transformedBody, bodyTemps);
|
|
17151
|
+
const finalParams = lazyParam ? replaceLazyParams(params) : params;
|
|
17152
|
+
return body !== node.body || finalParams !== node.params ?
|
|
17153
|
+
{
|
|
17154
|
+
...node,
|
|
17155
|
+
params: finalParams,
|
|
17156
|
+
body,
|
|
17157
|
+
...(node.type === "ArrowFunctionExpression" && body.type === "BlockStatement" ?
|
|
17158
|
+
{ expression: false } :
|
|
17159
|
+
{})
|
|
17160
|
+
} :
|
|
17161
|
+
node;
|
|
17162
|
+
}
|
|
17163
|
+
|
|
17164
|
+
if (node.type === "Program") {
|
|
17165
|
+
const body = node.body;
|
|
17166
|
+
const varScope = collectVarScopeBindings(body, state);
|
|
17167
|
+
const varOuter = varScope.declared.size ? without(bindings, varScope.declared) : bindings;
|
|
17168
|
+
const withVar = varScope.lazy.size ? new Map([...varOuter, ...varScope.lazy]) : varOuter;
|
|
17169
|
+
const shadowed = collectBlockShadowed(body, withVar);
|
|
17170
|
+
const outer = shadowed.size ? without(withVar, shadowed) : withVar;
|
|
17171
|
+
const own = new Map();
|
|
17172
|
+
collectBindingsFromStatements(body, own, state);
|
|
17173
|
+
const inner = own.size ? new Map([...outer, ...own]) : outer;
|
|
17174
|
+
let changed = false;
|
|
17175
|
+
const next = body.map((statement) => {
|
|
17176
|
+
const result = transform(statement, inner, state);
|
|
17177
|
+
if (result !== statement) changed = true;
|
|
17178
|
+
return result;
|
|
17179
|
+
});
|
|
17180
|
+
return changed ? { ...node, body: next } : node;
|
|
17181
|
+
}
|
|
17182
|
+
|
|
17183
|
+
if (node.type === "BlockStatement") {
|
|
17184
|
+
const body = node.body;
|
|
17185
|
+
const shadowed = collectBlockShadowed(body, bindings);
|
|
17186
|
+
const outer = shadowed.size ? without(bindings, shadowed) : bindings;
|
|
17187
|
+
const own = new Map();
|
|
17188
|
+
collectBindingsFromStatements(body, own, state);
|
|
17189
|
+
const inner = own.size ? new Map([...outer, ...own]) : outer;
|
|
17190
|
+
let changed = false;
|
|
17191
|
+
const next = body.map((statement) => {
|
|
17192
|
+
const result = transform(statement, inner, state);
|
|
17193
|
+
if (result !== statement) changed = true;
|
|
17194
|
+
return result;
|
|
17195
|
+
});
|
|
17196
|
+
return changed ? { ...node, body: next } : node;
|
|
17197
|
+
}
|
|
17198
|
+
|
|
17199
|
+
if (node.type === "StaticBlock" || node.type === "ClassStaticBlock") {
|
|
17200
|
+
const body = node.body;
|
|
17201
|
+
const varScope = collectVarScopeBindings(body, state);
|
|
17202
|
+
const varOuter = varScope.declared.size ? without(bindings, varScope.declared) : bindings;
|
|
17203
|
+
const withVar = varScope.lazy.size ? new Map([...varOuter, ...varScope.lazy]) : varOuter;
|
|
17204
|
+
const shadowed = collectBlockShadowed(body, withVar);
|
|
17205
|
+
const outer = shadowed.size ? without(withVar, shadowed) : withVar;
|
|
17206
|
+
const own = new Map();
|
|
17207
|
+
collectBindingsFromStatements(body, own, state);
|
|
17208
|
+
const inner = own.size ? new Map([...outer, ...own]) : outer;
|
|
17209
|
+
let changed = false;
|
|
17210
|
+
const next = body.map((statement) => {
|
|
17211
|
+
const result = transform(statement, inner, state);
|
|
17212
|
+
if (result !== statement) changed = true;
|
|
17213
|
+
return result;
|
|
17214
|
+
});
|
|
17215
|
+
return changed ? { ...node, body: next } : node;
|
|
17216
|
+
}
|
|
17217
|
+
|
|
17218
|
+
if (node.type === "CatchClause") {
|
|
17219
|
+
const own = new Map();
|
|
17220
|
+
if (isNode$1(node.param)) {
|
|
17221
|
+
visitTopmostLazyPatterns(node.param, (lazy) => {
|
|
17222
|
+
const sourceName = metadata(lazy).lazy_id;
|
|
17223
|
+
if (sourceName) collectBindings(lazy, sourceName, own, state);
|
|
17224
|
+
});
|
|
17225
|
+
}
|
|
17226
|
+
const shadowed = new Set();
|
|
17227
|
+
if (isNode$1(node.param)) collectShadowed(node.param, bindings, shadowed);
|
|
17228
|
+
const outer = shadowed.size ? without(bindings, shadowed) : bindings;
|
|
17229
|
+
const inner = own.size ? new Map([...outer, ...own]) : outer;
|
|
17230
|
+
const param = isNode$1(node.param) ? replaceLazyInPattern(node.param, true) : node.param;
|
|
17231
|
+
const body = transform(node.body, inner, state);
|
|
17232
|
+
return param === node.param && body === node.body ? node : { ...node, param, body };
|
|
17233
|
+
}
|
|
17234
|
+
|
|
17235
|
+
if (node.type === "ForStatement") {
|
|
17236
|
+
const shadowed = new Set();
|
|
17237
|
+
const own = new Map();
|
|
17238
|
+
const init = node.init;
|
|
17239
|
+
if (init?.type === "VariableDeclaration") {
|
|
17240
|
+
for (const declaration of init.declarations) {
|
|
17241
|
+
if (init.kind !== "var") {
|
|
17242
|
+
visitTopmostLazyPatterns(declaration.id, (lazy) => {
|
|
17243
|
+
const sourceName = metadata(lazy).lazy_id;
|
|
17244
|
+
if (sourceName) collectBindings(lazy, sourceName, own, state);
|
|
17245
|
+
});
|
|
17246
|
+
collectShadowed(declaration.id, bindings, shadowed);
|
|
17247
|
+
}
|
|
17248
|
+
}
|
|
17249
|
+
}
|
|
17250
|
+
const outer = shadowed.size ? without(bindings, shadowed) : bindings;
|
|
17251
|
+
const inner = own.size ? new Map([...outer, ...own]) : outer;
|
|
17252
|
+
return {
|
|
17253
|
+
...node,
|
|
17254
|
+
init: init ? transform(init, inner, state) : init,
|
|
17255
|
+
test: isNode$1(node.test) ? transform(node.test, inner, state) : node.test,
|
|
17256
|
+
update: isNode$1(node.update) ? transform(node.update, inner, state) : node.update,
|
|
17257
|
+
body: transform(node.body, inner, state)
|
|
17258
|
+
};
|
|
17259
|
+
}
|
|
17260
|
+
|
|
17261
|
+
if (node.type === "ForOfStatement" || node.type === "ForInStatement") {
|
|
17262
|
+
const shadowed = new Set();
|
|
17263
|
+
const own = new Map();
|
|
17264
|
+
const left = node.left;
|
|
17265
|
+
if (left.type === "VariableDeclaration") {
|
|
17266
|
+
for (const declaration of left.declarations) {
|
|
17267
|
+
if (left.kind !== "var") {
|
|
17268
|
+
visitTopmostLazyPatterns(declaration.id, (lazy) => {
|
|
17269
|
+
const sourceName = metadata(lazy).lazy_id;
|
|
17270
|
+
if (sourceName) collectBindings(lazy, sourceName, own, state);
|
|
17271
|
+
});
|
|
17272
|
+
collectShadowed(declaration.id, bindings, shadowed);
|
|
17273
|
+
}
|
|
17274
|
+
}
|
|
17275
|
+
}
|
|
17276
|
+
const outer = shadowed.size ? without(bindings, shadowed) : bindings;
|
|
17277
|
+
const inner = own.size ? new Map([...outer, ...own]) : outer;
|
|
17278
|
+
return {
|
|
17279
|
+
...node,
|
|
17280
|
+
left: transform(left, inner, state),
|
|
17281
|
+
right: transform(node.right, inner, state),
|
|
17282
|
+
body: transform(node.body, inner, state)
|
|
17283
|
+
};
|
|
17284
|
+
}
|
|
17285
|
+
|
|
17286
|
+
if (node.type === "SwitchStatement") {
|
|
17287
|
+
const cases = node.cases;
|
|
17288
|
+
const statements = cases.flatMap((item) => item.consequent);
|
|
17289
|
+
const shadowed = collectBlockShadowed(statements, bindings);
|
|
17290
|
+
const outer = shadowed.size ? without(bindings, shadowed) : bindings;
|
|
17291
|
+
const own = new Map();
|
|
17292
|
+
collectBindingsFromStatements(statements, own, state);
|
|
17293
|
+
const inner = own.size ? new Map([...outer, ...own]) : outer;
|
|
17294
|
+
return {
|
|
17295
|
+
...node,
|
|
17296
|
+
discriminant: transform(node.discriminant, outer, state),
|
|
17297
|
+
cases: cases.map((item) => ({
|
|
17298
|
+
...item,
|
|
17299
|
+
test: isNode$1(item.test) ? transform(item.test, inner, state) : item.test,
|
|
17300
|
+
consequent: item.consequent.map((statement) =>
|
|
17301
|
+
transform(statement, inner, state)
|
|
17302
|
+
)
|
|
17303
|
+
}))
|
|
17304
|
+
};
|
|
17305
|
+
}
|
|
17306
|
+
|
|
17307
|
+
if (node.type === "ClassDeclaration" || node.type === "ClassExpression") {
|
|
17308
|
+
const shadowed = new Set();
|
|
17309
|
+
if (isNode$1(node.id)) collectShadowed(node.id, bindings, shadowed);
|
|
17310
|
+
const inner = shadowed.size ? without(bindings, shadowed) : bindings;
|
|
17311
|
+
return {
|
|
17312
|
+
...node,
|
|
17313
|
+
superClass: isNode$1(node.superClass) ?
|
|
17314
|
+
transform(node.superClass, bindings, state) :
|
|
17315
|
+
node.superClass,
|
|
17316
|
+
body: transform(node.body, inner, state)
|
|
17317
|
+
};
|
|
17318
|
+
}
|
|
17319
|
+
|
|
17320
|
+
if (
|
|
17321
|
+
node.type === "ExportNamedDeclaration" &&
|
|
17322
|
+
isNode$1(node.declaration) &&
|
|
17323
|
+
node.declaration.type === "VariableDeclaration")
|
|
17324
|
+
{
|
|
17325
|
+
for (const declaration of node.declaration.declarations) {
|
|
17326
|
+
visitTopmostLazyPatterns(declaration.id, (pattern) => {
|
|
17327
|
+
fail(
|
|
17328
|
+
"TSRX lazy bindings cannot be exported; export the source object or an explicit accessor instead",
|
|
17329
|
+
pattern
|
|
17330
|
+
);
|
|
17331
|
+
});
|
|
17332
|
+
}
|
|
17333
|
+
}
|
|
17334
|
+
|
|
17335
|
+
if (
|
|
17336
|
+
node.type === "ExportSpecifier" &&
|
|
17337
|
+
isNode$1(node.local) &&
|
|
17338
|
+
node.local.type === "Identifier" &&
|
|
17339
|
+
bindings.has(node.local.name))
|
|
17340
|
+
{
|
|
17341
|
+
return fail(
|
|
17342
|
+
"TSRX lazy bindings cannot be exported; export the source object or an explicit accessor instead",
|
|
17343
|
+
node.local
|
|
17344
|
+
);
|
|
17345
|
+
}
|
|
17346
|
+
|
|
17347
|
+
if (node.type === "JSXElement") {
|
|
17348
|
+
const dynamic = dynamicJsxElement(node, bindings, state);
|
|
17349
|
+
if (dynamic) return dynamic;
|
|
17350
|
+
}
|
|
17351
|
+
|
|
17352
|
+
if (
|
|
17353
|
+
node.type === "ExpressionStatement" &&
|
|
17354
|
+
isNode$1(node.expression) &&
|
|
17355
|
+
node.expression.type === "AssignmentExpression" &&
|
|
17356
|
+
node.expression.operator === "=" &&
|
|
17357
|
+
isNode$1(node.expression.left) && (
|
|
17358
|
+
node.expression.left.type === "ObjectPattern" ||
|
|
17359
|
+
node.expression.left.type === "ArrayPattern") &&
|
|
17360
|
+
node.expression.left.lazy)
|
|
17361
|
+
{
|
|
17362
|
+
const pattern = node.expression.left;
|
|
17363
|
+
const sourceName = metadata(pattern).lazy_id;
|
|
17364
|
+
if (sourceName) {
|
|
17365
|
+
const id = generatedPatternIdentifier(pattern, sourceName, true);
|
|
17366
|
+
return {
|
|
17367
|
+
type: "VariableDeclaration",
|
|
17368
|
+
kind: "const",
|
|
17369
|
+
declarations: [
|
|
17370
|
+
{
|
|
17371
|
+
type: "VariableDeclarator",
|
|
17372
|
+
id,
|
|
17373
|
+
init: transform(node.expression.right, bindings, state)
|
|
17374
|
+
}]
|
|
17375
|
+
|
|
17376
|
+
};
|
|
17377
|
+
}
|
|
17378
|
+
}
|
|
17379
|
+
|
|
17380
|
+
if (
|
|
17381
|
+
node.type === "ExpressionStatement" &&
|
|
17382
|
+
isNode$1(node.expression) &&
|
|
17383
|
+
node.expression.type === "AssignmentExpression" &&
|
|
17384
|
+
node.expression.operator === "=" &&
|
|
17385
|
+
isNode$1(node.expression.left) && (
|
|
17386
|
+
node.expression.left.type === "ObjectPattern" ||
|
|
17387
|
+
node.expression.left.type === "ArrayPattern") &&
|
|
17388
|
+
!node.expression.left.lazy)
|
|
17389
|
+
{
|
|
17390
|
+
const left = replaceLazyInPattern(node.expression.left);
|
|
17391
|
+
if (left !== node.expression.left) {
|
|
17392
|
+
return fail(
|
|
17393
|
+
"A lazy pattern nested inside a standalone destructuring assignment is not supported because its generated source binding cannot be scoped correctly; use a lazy variable declaration",
|
|
17394
|
+
node.expression.left
|
|
17395
|
+
);
|
|
17396
|
+
}
|
|
17397
|
+
}
|
|
17398
|
+
|
|
17399
|
+
if (
|
|
17400
|
+
node.type === "AssignmentExpression" &&
|
|
17401
|
+
isNode$1(node.left) &&
|
|
17402
|
+
node.left.type === "Identifier")
|
|
17403
|
+
{
|
|
17404
|
+
const binding = bindings.get(node.left.name);
|
|
17405
|
+
if (binding) {
|
|
17406
|
+
assertWritable(binding, node.left);
|
|
17407
|
+
if (node.operator !== "=" && binding.directDefault) {
|
|
17408
|
+
return lowerDefaultedAssignment(node, binding, bindings, state);
|
|
17409
|
+
}
|
|
17410
|
+
const target = binding.target(node.left, bindings);
|
|
17411
|
+
if (!target) return fail("A TSRX lazy rest binding is read-only", node.left);
|
|
17412
|
+
return {
|
|
17413
|
+
...node,
|
|
17414
|
+
left: target,
|
|
17415
|
+
right: transform(node.right, bindings, state)
|
|
17416
|
+
};
|
|
17417
|
+
}
|
|
17418
|
+
}
|
|
17419
|
+
|
|
17420
|
+
if (
|
|
17421
|
+
node.type === "UpdateExpression" &&
|
|
17422
|
+
isNode$1(node.argument) &&
|
|
17423
|
+
node.argument.type === "Identifier")
|
|
17424
|
+
{
|
|
17425
|
+
const binding = bindings.get(node.argument.name);
|
|
17426
|
+
if (binding) {
|
|
17427
|
+
assertWritable(binding, node.argument);
|
|
17428
|
+
if (binding.directDefault) {
|
|
17429
|
+
return lowerDefaultedUpdate(node, binding, bindings, state);
|
|
17430
|
+
}
|
|
17431
|
+
const target = binding.target(node.argument, bindings);
|
|
17432
|
+
if (!target) return fail("A TSRX lazy rest binding is read-only", node.argument);
|
|
17433
|
+
return { ...node, argument: target };
|
|
17434
|
+
}
|
|
17435
|
+
}
|
|
17436
|
+
|
|
17437
|
+
if (node.type === "VariableDeclarator" && isNode$1(node.id) && metadata(node.id).lazy_id) {
|
|
17438
|
+
const sourceName = metadata(node.id).lazy_id;
|
|
17439
|
+
return {
|
|
17440
|
+
...node,
|
|
17441
|
+
id: generatedPatternIdentifier(node.id, sourceName, true),
|
|
17442
|
+
init: isNode$1(node.init) ? transform(node.init, bindings, state) : node.init
|
|
17443
|
+
};
|
|
17444
|
+
}
|
|
17445
|
+
|
|
17446
|
+
if (
|
|
17447
|
+
node.type === "VariableDeclarator" &&
|
|
17448
|
+
isNode$1(node.id) && (
|
|
17449
|
+
node.id.type === "ObjectPattern" || node.id.type === "ArrayPattern") &&
|
|
17450
|
+
!node.id.lazy)
|
|
17451
|
+
{
|
|
17452
|
+
const id = replaceLazyInPattern(node.id);
|
|
17453
|
+
if (id !== node.id) {
|
|
17454
|
+
return {
|
|
17455
|
+
...node,
|
|
17456
|
+
id,
|
|
17457
|
+
init: isNode$1(node.init) ? transform(node.init, bindings, state) : node.init
|
|
17458
|
+
};
|
|
17459
|
+
}
|
|
17460
|
+
}
|
|
17461
|
+
|
|
17462
|
+
if (
|
|
17463
|
+
node.type === "Property" &&
|
|
17464
|
+
node.shorthand &&
|
|
17465
|
+
isNode$1(node.value) &&
|
|
17466
|
+
node.value.type === "Identifier")
|
|
17467
|
+
{
|
|
17468
|
+
const binding = bindings.get(node.value.name);
|
|
17469
|
+
if (binding) return { ...node, shorthand: false, value: binding.read(node.value, bindings) };
|
|
17470
|
+
}
|
|
17471
|
+
|
|
17472
|
+
if (node.type === "Identifier") {
|
|
17473
|
+
const binding = bindings.get(node.name);
|
|
17474
|
+
return binding ? binding.read(node, bindings) : node;
|
|
17475
|
+
}
|
|
17476
|
+
|
|
17477
|
+
if (node.type === "JSXIdentifier") return node;
|
|
17478
|
+
if (node.type === "MetaProperty") return node;
|
|
17479
|
+
|
|
17480
|
+
let changed = false;
|
|
17481
|
+
const clone = { ...node };
|
|
17482
|
+
for (const key of Object.keys(node)) {
|
|
17483
|
+
if (SKIP_KEYS$1.has(key) || TYPE_KEYS.has(key)) continue;
|
|
17484
|
+
if (
|
|
17485
|
+
key === "key" &&
|
|
17486
|
+
!node.computed && (
|
|
17487
|
+
node.type === "Property" ||
|
|
17488
|
+
node.type === "MethodDefinition" ||
|
|
17489
|
+
node.type === "PropertyDefinition"))
|
|
17490
|
+
{
|
|
17491
|
+
continue;
|
|
17492
|
+
}
|
|
17493
|
+
if (key === "property" && node.type === "MemberExpression" && !node.computed) continue;
|
|
17494
|
+
if (key === "property" && node.type === "JSXMemberExpression") continue;
|
|
17495
|
+
if (key === "name" && node.type === "JSXAttribute") continue;
|
|
17496
|
+
if (key === "id" && node.type === "VariableDeclarator") continue;
|
|
17497
|
+
if (
|
|
17498
|
+
(key === "local" || key === "imported" || key === "exported") &&
|
|
17499
|
+
/Specifier$/.test(node.type))
|
|
17500
|
+
{
|
|
17501
|
+
continue;
|
|
17502
|
+
}
|
|
17503
|
+
if (key === "label") continue;
|
|
17504
|
+
|
|
17505
|
+
if (
|
|
17506
|
+
key === "name" && (
|
|
17507
|
+
node.type === "JSXOpeningElement" || node.type === "JSXClosingElement") &&
|
|
17508
|
+
isNode$1(node.name))
|
|
17509
|
+
{
|
|
17510
|
+
const jsxName = rewriteJsxName(node.name, bindings);
|
|
17511
|
+
if (jsxName) {
|
|
17512
|
+
clone[key] = jsxName;
|
|
17513
|
+
changed = true;
|
|
17514
|
+
continue;
|
|
17515
|
+
}
|
|
17516
|
+
}
|
|
17517
|
+
const value = transformValue(node[key], bindings, state);
|
|
17518
|
+
if (value !== node[key]) {
|
|
17519
|
+
clone[key] = value;
|
|
17520
|
+
changed = true;
|
|
17521
|
+
}
|
|
17522
|
+
}
|
|
17523
|
+
return changed ? clone : node;
|
|
17524
|
+
}
|
|
17525
|
+
|
|
17526
|
+
function rewriteJsxName(name, bindings) {
|
|
17527
|
+
if (name.type === "JSXIdentifier") {
|
|
17528
|
+
if (!/^[A-Z]/.test(name.name)) return null;
|
|
17529
|
+
return bindings.get(name.name)?.jsxName(name, bindings) ?? null;
|
|
17530
|
+
}
|
|
17531
|
+
if (name.type === "JSXMemberExpression") {
|
|
17532
|
+
const object = rewriteJsxName(name.object, bindings);
|
|
17533
|
+
return object ? { ...name, object } : null;
|
|
17534
|
+
}
|
|
17535
|
+
return null;
|
|
17536
|
+
}
|
|
17537
|
+
|
|
17538
|
+
/** Apply Solid's local lazy transform to a fully desugared TSRX program. */
|
|
17539
|
+
function applyLazyTransforms(root) {
|
|
17540
|
+
const state = new LazyState(root);
|
|
17541
|
+
preallocate(root, state);
|
|
17542
|
+
return state.finalize(transform(root, new Map(), state));
|
|
17543
|
+
}
|
|
17544
|
+
|
|
17545
|
+
const SKIP_KEYS = new Set([
|
|
17546
|
+
"type",
|
|
17547
|
+
"loc",
|
|
17548
|
+
"start",
|
|
17549
|
+
"end",
|
|
17550
|
+
"range",
|
|
17551
|
+
"metadata",
|
|
17552
|
+
"css",
|
|
17553
|
+
"leadingComments",
|
|
17554
|
+
"trailingComments",
|
|
17555
|
+
"innerComments"]
|
|
17556
|
+
);
|
|
17557
|
+
|
|
17558
|
+
const FUNCTION_BOUNDARIES = new Set([
|
|
17559
|
+
"FunctionDeclaration",
|
|
17560
|
+
"FunctionExpression",
|
|
17561
|
+
"ArrowFunctionExpression",
|
|
17562
|
+
"ClassDeclaration",
|
|
17563
|
+
"ClassExpression"]
|
|
17564
|
+
);
|
|
17565
|
+
|
|
17566
|
+
function isNode(value) {
|
|
17567
|
+
return (
|
|
17568
|
+
typeof value === "object" &&
|
|
17569
|
+
value !== null &&
|
|
17570
|
+
typeof value.type === "string");
|
|
17571
|
+
|
|
17572
|
+
}
|
|
17573
|
+
|
|
17574
|
+
function isStyleElement(node) {
|
|
17575
|
+
return node.type === "JSXStyleElement";
|
|
17576
|
+
}
|
|
17577
|
+
|
|
17578
|
+
function isNativeRenderRoot(node) {
|
|
17579
|
+
return (
|
|
17580
|
+
(node.type === "JSXElement" || node.type === "JSXFragment") &&
|
|
17581
|
+
!!node.metadata?.native_tsrx);
|
|
17582
|
+
|
|
17583
|
+
}
|
|
17584
|
+
|
|
17585
|
+
function isNativeTsrxNode(node) {
|
|
17586
|
+
return (
|
|
17587
|
+
node?.type === "JSXCodeBlock" ||
|
|
17588
|
+
!!node && (
|
|
17589
|
+
node.type === "JSXElement" ||
|
|
17590
|
+
node.type === "JSXFragment" ||
|
|
17591
|
+
node.type === "JSXStyleElement") &&
|
|
17592
|
+
!!node.metadata?.native_tsrx);
|
|
17593
|
+
|
|
17594
|
+
}
|
|
17595
|
+
|
|
17596
|
+
function isStyleExpressionPosition(path) {
|
|
17597
|
+
const parent = path[path.length - 1];
|
|
17598
|
+
return !(
|
|
17599
|
+
isNativeTsrxNode(parent) ||
|
|
17600
|
+
parent?.type === "BlockStatement" ||
|
|
17601
|
+
parent?.type === "Program" ||
|
|
17602
|
+
parent?.type === "SwitchCase");
|
|
17603
|
+
|
|
17604
|
+
}
|
|
17605
|
+
|
|
17606
|
+
function structuralChildren(node) {
|
|
17607
|
+
switch (node.type) {
|
|
17608
|
+
case "JSXElement":
|
|
17609
|
+
case "JSXFragment":
|
|
17610
|
+
return (node.children ?? []).filter(isNode);
|
|
17611
|
+
case "JSXCodeBlock":
|
|
17612
|
+
return [
|
|
17613
|
+
...(node.body ?? []).filter(isNode),
|
|
17614
|
+
...(isNode(node.render) ? [node.render] : [])];
|
|
17615
|
+
|
|
17616
|
+
case "BlockStatement":
|
|
17617
|
+
return (node.body ?? []).filter(isNode);
|
|
17618
|
+
case "JSXIfExpression":
|
|
17619
|
+
case "IfStatement":
|
|
17620
|
+
return [node.consequent, node.alternate].filter(isNode);
|
|
17621
|
+
case "JSXForExpression":
|
|
17622
|
+
return [node.body, node.empty].filter(isNode);
|
|
17623
|
+
case "JSXSwitchExpression":
|
|
17624
|
+
case "SwitchStatement":
|
|
17625
|
+
return (node.cases ?? []).flatMap((switchCase) =>
|
|
17626
|
+
(switchCase.consequent ?? []).filter(isNode)
|
|
17627
|
+
);
|
|
17628
|
+
case "JSXTryExpression":
|
|
17629
|
+
case "TryStatement":
|
|
17630
|
+
return [node.block, node.pending, node.handler, node.finalizer].filter(isNode);
|
|
17631
|
+
case "CatchClause":
|
|
17632
|
+
return isNode(node.body) ? [node.body] : [];
|
|
17633
|
+
default:
|
|
17634
|
+
return [];
|
|
17635
|
+
}
|
|
17636
|
+
}
|
|
17637
|
+
|
|
17638
|
+
function collectRuntimeStyleElements(value, styles) {
|
|
17639
|
+
if (Array.isArray(value)) {
|
|
17640
|
+
for (const child of value) collectRuntimeStyleElements(child, styles);
|
|
17641
|
+
return;
|
|
17642
|
+
}
|
|
17643
|
+
if (isStyleElement(value)) {
|
|
17644
|
+
styles.push(value);
|
|
17645
|
+
return;
|
|
17646
|
+
}
|
|
17647
|
+
if (FUNCTION_BOUNDARIES.has(value.type)) return;
|
|
17648
|
+
|
|
17649
|
+
if ((value.type === "JSXElement" || value.type === "JSXFragment") && isNativeRenderRoot(value)) {
|
|
17650
|
+
collectRuntimeStyleElements(value.children ?? [], styles);
|
|
17651
|
+
return;
|
|
17652
|
+
}
|
|
17653
|
+
if (value.type === "BlockStatement") {
|
|
17654
|
+
collectRuntimeStyleElements(value.body ?? [], styles);
|
|
17655
|
+
return;
|
|
17656
|
+
}
|
|
17657
|
+
if (value.type === "JSXIfExpression" || value.type === "IfStatement") {
|
|
17658
|
+
if (isNode(value.consequent)) collectRuntimeStyleElements(value.consequent, styles);
|
|
17659
|
+
if (isNode(value.alternate)) collectRuntimeStyleElements(value.alternate, styles);
|
|
17660
|
+
return;
|
|
17661
|
+
}
|
|
17662
|
+
// This is an intentional ownership boundary in @tsrx/core: a style directly
|
|
17663
|
+
// rendered by an @for body is visited later as an unowned statement style.
|
|
17664
|
+
if (value.type === "JSXForExpression") return;
|
|
17665
|
+
if (value.type === "JSXSwitchExpression" || value.type === "SwitchStatement") {
|
|
17666
|
+
for (const switchCase of value.cases ?? []) {
|
|
17667
|
+
collectRuntimeStyleElements(switchCase.consequent ?? [], styles);
|
|
17668
|
+
}
|
|
17669
|
+
return;
|
|
17670
|
+
}
|
|
17671
|
+
if (value.type === "JSXTryExpression" || value.type === "TryStatement") {
|
|
17672
|
+
if (isNode(value.block)) collectRuntimeStyleElements(value.block, styles);
|
|
17673
|
+
const handler = isNode(value.handler) ? value.handler : undefined;
|
|
17674
|
+
if (handler && isNode(handler.body)) collectRuntimeStyleElements(handler.body, styles);
|
|
17675
|
+
if (isNode(value.finalizer)) collectRuntimeStyleElements(value.finalizer, styles);
|
|
17676
|
+
// `pending` is deliberately absent: core does not assign direct @pending
|
|
17677
|
+
// statement styles to the surrounding fragment.
|
|
17678
|
+
}
|
|
17679
|
+
}
|
|
17680
|
+
|
|
17681
|
+
function collectPrunableElements(
|
|
17682
|
+
value,
|
|
17683
|
+
elements,
|
|
17684
|
+
path = [])
|
|
17685
|
+
{
|
|
17686
|
+
if (Array.isArray(value)) {
|
|
17687
|
+
for (const child of value) collectPrunableElements(child, elements, path);
|
|
17688
|
+
return;
|
|
17689
|
+
}
|
|
17690
|
+
if (FUNCTION_BOUNDARIES.has(value.type) || isStyleElement(value)) return;
|
|
17691
|
+
|
|
17692
|
+
if (value.type === "JSXElement" && isNativeRenderRoot(value)) {
|
|
17693
|
+
const metadata = value.metadata ??= {};
|
|
17694
|
+
metadata.path = path;
|
|
17695
|
+
elements.push(value);
|
|
17696
|
+
}
|
|
17697
|
+
|
|
17698
|
+
const childPath = [...path, value];
|
|
17699
|
+
for (const child of structuralChildren(value)) {
|
|
17700
|
+
collectPrunableElements(child, elements, childPath);
|
|
17701
|
+
}
|
|
17702
|
+
}
|
|
17703
|
+
|
|
17704
|
+
function annotateRuntimeValue(value, hash, core) {
|
|
17705
|
+
if (isStyleElement(value)) return null;
|
|
17706
|
+
if (FUNCTION_BOUNDARIES.has(value.type)) return value;
|
|
17707
|
+
if (value.type === "JSXElement") {
|
|
17708
|
+
return core.annotateWithHash(value, hash, "class", false);
|
|
17709
|
+
}
|
|
17710
|
+
if (value.type === "JSXFragment") {
|
|
17711
|
+
value.children = annotateRuntimeList(
|
|
17712
|
+
value.children ?? [],
|
|
17713
|
+
hash,
|
|
17714
|
+
core
|
|
17715
|
+
);
|
|
17716
|
+
return value;
|
|
17717
|
+
}
|
|
17718
|
+
|
|
17719
|
+
mutateStructuralChildren(value, (child) => annotateRuntimeValue(child, hash, core));
|
|
17720
|
+
return value;
|
|
17721
|
+
}
|
|
17722
|
+
|
|
17723
|
+
function annotateRuntimeList(values, hash, core) {
|
|
17724
|
+
return values.
|
|
17725
|
+
map((value) => annotateRuntimeValue(value, hash, core)).
|
|
17726
|
+
filter((value) => value !== null);
|
|
17727
|
+
}
|
|
17728
|
+
|
|
17729
|
+
function mutateStructuralChildren(node, transform) {
|
|
17730
|
+
const mapList = (values) =>
|
|
17731
|
+
(values ?? []).map(transform).filter((value) => value !== null);
|
|
17732
|
+
const mapSlot = (key) => {
|
|
17733
|
+
const value = node[key];
|
|
17734
|
+
if (isNode(value)) node[key] = transform(value);
|
|
17735
|
+
};
|
|
17736
|
+
|
|
17737
|
+
switch (node.type) {
|
|
17738
|
+
case "JSXElement":
|
|
17739
|
+
case "JSXFragment":
|
|
17740
|
+
node.children = mapList(node.children);
|
|
17741
|
+
break;
|
|
17742
|
+
case "JSXCodeBlock":
|
|
17743
|
+
node.body = mapList(node.body);
|
|
17744
|
+
mapSlot("render");
|
|
17745
|
+
break;
|
|
17746
|
+
case "BlockStatement":
|
|
17747
|
+
node.body = mapList(node.body);
|
|
17748
|
+
break;
|
|
17749
|
+
case "JSXIfExpression":
|
|
17750
|
+
case "IfStatement":
|
|
17751
|
+
mapSlot("consequent");
|
|
17752
|
+
mapSlot("alternate");
|
|
17753
|
+
break;
|
|
17754
|
+
case "JSXForExpression":
|
|
17755
|
+
mapSlot("body");
|
|
17756
|
+
mapSlot("empty");
|
|
17757
|
+
break;
|
|
17758
|
+
case "JSXSwitchExpression":
|
|
17759
|
+
case "SwitchStatement":
|
|
17760
|
+
for (const switchCase of node.cases ?? []) {
|
|
17761
|
+
switchCase.consequent = mapList(switchCase.consequent);
|
|
17762
|
+
}
|
|
17763
|
+
break;
|
|
17764
|
+
case "JSXTryExpression":
|
|
17765
|
+
case "TryStatement":
|
|
17766
|
+
mapSlot("block");
|
|
17767
|
+
mapSlot("pending");
|
|
17768
|
+
mapSlot("handler");
|
|
17769
|
+
mapSlot("finalizer");
|
|
17770
|
+
break;
|
|
17771
|
+
case "CatchClause":
|
|
17772
|
+
mapSlot("body");
|
|
17773
|
+
break;
|
|
17774
|
+
}
|
|
17775
|
+
}
|
|
17776
|
+
|
|
17777
|
+
function cleanRuntimeStyles(node) {
|
|
17778
|
+
if (FUNCTION_BOUNDARIES.has(node.type)) return;
|
|
17779
|
+
mutateStructuralChildren(node, (child) => {
|
|
17780
|
+
if (isStyleElement(child)) return null;
|
|
17781
|
+
cleanRuntimeStyles(child);
|
|
17782
|
+
return child;
|
|
17783
|
+
});
|
|
17784
|
+
}
|
|
17785
|
+
|
|
17786
|
+
function withLoc(node, source) {
|
|
17787
|
+
if (source.start !== undefined) node.start = source.start;
|
|
17788
|
+
if (source.end !== undefined) node.end = source.end;
|
|
17789
|
+
if (source.loc !== undefined) node.loc = source.loc;
|
|
17790
|
+
return node;
|
|
17791
|
+
}
|
|
17792
|
+
|
|
17793
|
+
function wrapWithSetup(expression, statements) {
|
|
17794
|
+
const body = withLoc(
|
|
17795
|
+
{
|
|
17796
|
+
type: "BlockStatement",
|
|
17797
|
+
body: [...statements, withLoc({ type: "ReturnStatement", argument: expression }, expression)]
|
|
17798
|
+
},
|
|
17799
|
+
expression
|
|
17800
|
+
);
|
|
17801
|
+
const fn = withLoc(
|
|
17802
|
+
{
|
|
17803
|
+
type: "ArrowFunctionExpression",
|
|
17804
|
+
id: null,
|
|
17805
|
+
params: [],
|
|
17806
|
+
body,
|
|
17807
|
+
expression: false,
|
|
17808
|
+
async: false,
|
|
17809
|
+
generator: false
|
|
17810
|
+
},
|
|
17811
|
+
expression
|
|
17812
|
+
);
|
|
17813
|
+
return withLoc(
|
|
17814
|
+
{ type: "CallExpression", callee: fn, arguments: [], optional: false },
|
|
17815
|
+
expression
|
|
17816
|
+
);
|
|
17817
|
+
}
|
|
17818
|
+
|
|
17819
|
+
function collectIdentifierNames(node, names) {
|
|
17820
|
+
if (node.type === "Identifier" && typeof node.name === "string") names.add(node.name);
|
|
17821
|
+
for (const key of Object.keys(node)) {
|
|
17822
|
+
if (SKIP_KEYS.has(key)) continue;
|
|
17823
|
+
const value = node[key];
|
|
17824
|
+
if (Array.isArray(value)) {
|
|
17825
|
+
for (const child of value) if (isNode(child)) collectIdentifierNames(child, names);
|
|
17826
|
+
} else if (isNode(value)) {
|
|
17827
|
+
collectIdentifierNames(value, names);
|
|
17828
|
+
}
|
|
17829
|
+
}
|
|
17830
|
+
}
|
|
17831
|
+
|
|
17832
|
+
function createTempIdentifierFactory(program) {
|
|
17833
|
+
const names = new Set();
|
|
17834
|
+
collectIdentifierNames(program, names);
|
|
17835
|
+
let index = 0;
|
|
17836
|
+
return () => {
|
|
17837
|
+
let name;
|
|
17838
|
+
do {
|
|
17839
|
+
name = `_tsrx_style_ref_${++index}`;
|
|
17840
|
+
} while (names.has(name));
|
|
17841
|
+
names.add(name);
|
|
17842
|
+
return { type: "Identifier", name };
|
|
17843
|
+
};
|
|
17844
|
+
}
|
|
17845
|
+
|
|
17846
|
+
function createEmptyStyleElement(node) {
|
|
17847
|
+
const metadata = node.metadata ?? {};
|
|
17848
|
+
const cloneElementPart = (part) => {
|
|
17849
|
+
if (!isNode(part)) return part;
|
|
17850
|
+
return {
|
|
17851
|
+
...part,
|
|
17852
|
+
metadata: {
|
|
17853
|
+
path: [...(metadata.path ?? [])]
|
|
17854
|
+
}
|
|
17855
|
+
};
|
|
17856
|
+
};
|
|
17857
|
+
return {
|
|
17858
|
+
...node,
|
|
17859
|
+
type: "JSXElement",
|
|
17860
|
+
openingElement: cloneElementPart(node.openingElement),
|
|
17861
|
+
closingElement: cloneElementPart(node.closingElement),
|
|
17862
|
+
children: []
|
|
17863
|
+
};
|
|
17864
|
+
}
|
|
17865
|
+
|
|
17866
|
+
function prepareRuntimeStyle(
|
|
17867
|
+
owner,
|
|
17868
|
+
style,
|
|
17869
|
+
core,
|
|
17870
|
+
createTempIdentifier)
|
|
17871
|
+
{
|
|
17872
|
+
const stylesheet = core.getStyleElementStylesheet(style);
|
|
17873
|
+
if (!stylesheet) {
|
|
17874
|
+
throw new SyntaxError("A TSRX <style> element is missing its parsed stylesheet");
|
|
17875
|
+
}
|
|
17876
|
+
|
|
17877
|
+
core.analyzeCss(stylesheet);
|
|
17878
|
+
const metadata = owner.metadata ??= {};
|
|
17879
|
+
const styleClasses = new Map();
|
|
17880
|
+
const topScopedClasses = new Map();
|
|
17881
|
+
|
|
17882
|
+
const elements = [];
|
|
17883
|
+
collectPrunableElements(owner.children ?? [], elements);
|
|
17884
|
+
for (const element of elements) {
|
|
17885
|
+
core.pruneCss(stylesheet, element, styleClasses, topScopedClasses, stylesheet.hash);
|
|
17886
|
+
}
|
|
17887
|
+
|
|
17888
|
+
const refs = core.collectStyleRefAttributes(owner);
|
|
17889
|
+
if (refs.length > 0) {
|
|
17890
|
+
for (const [name, classInfo] of topScopedClasses) {
|
|
17891
|
+
styleClasses.set(
|
|
17892
|
+
name,
|
|
17893
|
+
classInfo?.selector ?? classInfo
|
|
17894
|
+
);
|
|
17895
|
+
}
|
|
17896
|
+
for (const element of elements) {
|
|
17897
|
+
core.pruneCss(stylesheet, element, styleClasses, topScopedClasses, stylesheet.hash);
|
|
17898
|
+
}
|
|
17899
|
+
}
|
|
17900
|
+
if (topScopedClasses.size > 0) metadata.topScopedClasses = topScopedClasses;
|
|
17901
|
+
|
|
17902
|
+
const setup =
|
|
17903
|
+
refs.length === 0 ?
|
|
17904
|
+
[] :
|
|
17905
|
+
core.createStyleRefSetupStatements(refs, core.createStyleClassMap(owner, stylesheet), {
|
|
17906
|
+
allowMutableRefTarget: true,
|
|
17907
|
+
createTempIdentifier
|
|
17908
|
+
});
|
|
17909
|
+
|
|
17910
|
+
mutateStructuralChildren(owner, (child) => annotateRuntimeValue(child, stylesheet.hash, core));
|
|
17911
|
+
cleanRuntimeStyles(owner);
|
|
17912
|
+
return { owner, stylesheet, setup };
|
|
17913
|
+
}
|
|
17914
|
+
|
|
17915
|
+
function prepareStyleOwner(
|
|
17916
|
+
owner,
|
|
17917
|
+
core,
|
|
17918
|
+
createTempIdentifier)
|
|
17919
|
+
{
|
|
17920
|
+
const styles = [];
|
|
17921
|
+
collectRuntimeStyleElements(owner.children ?? [], styles);
|
|
17922
|
+
if (styles.length > 1) {
|
|
17923
|
+
throw new SyntaxError("TSRX fragments can only have one style tag");
|
|
17924
|
+
}
|
|
17925
|
+
return styles.length === 1 ?
|
|
17926
|
+
prepareRuntimeStyle(owner, styles[0], core, createTempIdentifier) :
|
|
17927
|
+
null;
|
|
17928
|
+
}
|
|
17929
|
+
|
|
17930
|
+
function processTsrxStyles(program, core) {
|
|
17931
|
+
const stylesheets = [];
|
|
17932
|
+
const createTempIdentifier = createTempIdentifierFactory(program);
|
|
17933
|
+
|
|
17934
|
+
const visit = (node, path) => {
|
|
17935
|
+
if (isStyleElement(node)) {
|
|
17936
|
+
if (!isStyleExpressionPosition(path)) return createEmptyStyleElement(node);
|
|
17937
|
+
const stylesheet = core.getStyleElementStylesheet(node);
|
|
17938
|
+
if (!stylesheet) {
|
|
17939
|
+
throw new SyntaxError("A TSRX <style> expression is missing its parsed stylesheet");
|
|
17940
|
+
}
|
|
17941
|
+
core.analyzeCss(stylesheet);
|
|
17942
|
+
stylesheets.push(core.prepareStylesheetForRender(stylesheet, true));
|
|
17943
|
+
return core.createStyleClassMapFromStylesheet(stylesheet);
|
|
17944
|
+
}
|
|
17945
|
+
|
|
17946
|
+
if (node.type === "JSXCodeBlock" && isNode(node.render) && isNativeRenderRoot(node.render)) {
|
|
17947
|
+
// Core gives a code block's native element/fragment render one style
|
|
17948
|
+
// scope. A native element elsewhere is deliberately not an owner.
|
|
17949
|
+
const prepared = prepareStyleOwner(node.render, core, createTempIdentifier);
|
|
17950
|
+
if (prepared) {
|
|
17951
|
+
stylesheets.push(prepared.stylesheet);
|
|
17952
|
+
node.render = prepared.owner;
|
|
17953
|
+
node.body = [...(node.body ?? []), ...prepared.setup];
|
|
17954
|
+
}
|
|
17955
|
+
} else if (node.type === "JSXFragment" && isNativeRenderRoot(node)) {
|
|
17956
|
+
// Native fragments are owners in every expression/child position.
|
|
17957
|
+
const prepared = prepareStyleOwner(node, core, createTempIdentifier);
|
|
17958
|
+
if (prepared) {
|
|
17959
|
+
stylesheets.push(prepared.stylesheet);
|
|
17960
|
+
node = prepared.setup.length ?
|
|
17961
|
+
wrapWithSetup(prepared.owner, prepared.setup) :
|
|
17962
|
+
prepared.owner;
|
|
17963
|
+
}
|
|
17964
|
+
}
|
|
17965
|
+
|
|
17966
|
+
for (const key of Object.keys(node)) {
|
|
17967
|
+
if (SKIP_KEYS.has(key)) continue;
|
|
17968
|
+
const value = node[key];
|
|
17969
|
+
if (Array.isArray(value)) {
|
|
17970
|
+
node[key] = value.map((child) => isNode(child) ? visit(child, [...path, node]) : child);
|
|
17971
|
+
} else if (isNode(value)) {
|
|
17972
|
+
node[key] = visit(value, [...path, node]);
|
|
17973
|
+
}
|
|
17974
|
+
}
|
|
17975
|
+
return node;
|
|
17976
|
+
};
|
|
17977
|
+
|
|
17978
|
+
visit(program, []);
|
|
17979
|
+
return core.renderCssResult(stylesheets);
|
|
17980
|
+
}
|
|
17981
|
+
|
|
17982
|
+
/**
|
|
17983
|
+
* TSRX syntax frontend entry point.
|
|
17984
|
+
*
|
|
17985
|
+
* Routes `.tsrx` sources (or any source when `syntax: "tsrx"`) through
|
|
17986
|
+
* `@tsrx/core`'s parser + semantic analysis, processes scoped styles with
|
|
17987
|
+
* core's CSS helpers, desugars every TSRX construct to Solid builtIn JSX,
|
|
17988
|
+
* applies Solid's local deferred-pattern transform for generated control-flow
|
|
17989
|
+
* callbacks, and converts the result to a Babel `File` for the unchanged JSX
|
|
17990
|
+
* pipeline. Authored lazy destructuring is rejected for the Solid target.
|
|
17991
|
+
*
|
|
17992
|
+
* `@tsrx/core` is an optional peer dependency loaded lazily on first TSRX
|
|
17993
|
+
* routing, so plain JSX users never pay for it.
|
|
17994
|
+
*/
|
|
17995
|
+
|
|
17996
|
+
|
|
17997
|
+
|
|
17998
|
+
// The plugin ships as CJS; `require` of the ESM-only `@tsrx/core` is
|
|
17999
|
+
// supported natively on Node >= 22.12. No @types/node in this package.
|
|
18000
|
+
|
|
18001
|
+
|
|
18002
|
+
|
|
18003
|
+
|
|
18004
|
+
|
|
18005
|
+
|
|
18006
|
+
|
|
18007
|
+
|
|
18008
|
+
|
|
18009
|
+
|
|
18010
|
+
|
|
18011
|
+
let core;
|
|
18012
|
+
|
|
18013
|
+
function loadTsrxCore() {
|
|
18014
|
+
if (core) return core;
|
|
18015
|
+
if (typeof require !== "function") {
|
|
18016
|
+
throw new Error(
|
|
18017
|
+
"@solidjs/babel-plugin: TSRX support requires a CommonJS environment with `require` available."
|
|
18018
|
+
);
|
|
18019
|
+
}
|
|
18020
|
+
try {
|
|
18021
|
+
core = require("@tsrx/core");
|
|
18022
|
+
} catch (error) {
|
|
18023
|
+
const err = error;
|
|
18024
|
+
if (err.code === "MODULE_NOT_FOUND") {
|
|
18025
|
+
throw new Error(
|
|
18026
|
+
"@solidjs/babel-plugin: compiling .tsrx sources requires the optional peer dependency `@tsrx/core`. Install it with your package manager (e.g. `pnpm add -D @tsrx/core`)."
|
|
18027
|
+
);
|
|
18028
|
+
}
|
|
18029
|
+
if (err.code === "ERR_REQUIRE_ESM" || err.code === "ERR_REQUIRE_ASYNC_MODULE") {
|
|
18030
|
+
throw new Error(
|
|
18031
|
+
"@solidjs/babel-plugin: loading `@tsrx/core` synchronously requires Node.js >= 22.12 (require(esm) support)."
|
|
18032
|
+
);
|
|
18033
|
+
}
|
|
18034
|
+
throw error;
|
|
18035
|
+
}
|
|
18036
|
+
return core;
|
|
18037
|
+
}
|
|
18038
|
+
|
|
18039
|
+
|
|
18040
|
+
|
|
18041
|
+
/** Whether the given file should be parsed as TSRX under the configured
|
|
18042
|
+
* `syntax` option. */
|
|
18043
|
+
function isTsrxSource(syntax, filename) {
|
|
18044
|
+
const mode = syntax ?? "auto";
|
|
18045
|
+
if (mode === "tsrx") return true;
|
|
18046
|
+
if (mode === "jsx") return false;
|
|
18047
|
+
return typeof filename === "string" && filename.endsWith(".tsrx");
|
|
18048
|
+
}
|
|
18049
|
+
|
|
18050
|
+
/** Parse TSRX source text into a Babel `File` with all TSRX constructs
|
|
18051
|
+
* lowered to Solid builtIn JSX. */
|
|
18052
|
+
function parseTsrx(code, filename) {
|
|
18053
|
+
const tsrx = loadTsrxCore();
|
|
18054
|
+
const program = tsrx.parseModule(code, filename ?? "module.tsrx");
|
|
18055
|
+
rejectAuthoredLazyDestructuring(program);
|
|
18056
|
+
// Throws structured diagnostics (invalid returns, misplaced directives, …).
|
|
18057
|
+
tsrx.analyzeTsrx(program, filename ?? null);
|
|
18058
|
+
const styleResult = processTsrxStyles(program, tsrx);
|
|
18059
|
+
|
|
18060
|
+
// Desugar before the lazy transform: the lazy engine collects block-level
|
|
18061
|
+
// `let &[…]`/`const &{…}` bindings in its BlockStatement/Program handlers,
|
|
18062
|
+
// which only fire once `@{}` containers have become real blocks. Lazy
|
|
18063
|
+
// patterns themselves pass through the desugarer untouched.
|
|
18064
|
+
desugarProgram(program);
|
|
18065
|
+
|
|
18066
|
+
const transformed = applyLazyTransforms(program);
|
|
18067
|
+
// Keep this compatibility repair in place for trees produced by older
|
|
18068
|
+
// desugaring paths. The local engine itself never rewrites intrinsic names.
|
|
18069
|
+
restoreIntrinsicJsxNames(transformed);
|
|
18070
|
+
|
|
18071
|
+
const file = toBabelFile(transformed);
|
|
18072
|
+
// Babel's default AST clone preserves enumerable string keys. Program.enter
|
|
18073
|
+
// lifts this temporary payload into transform metadata and removes it from
|
|
18074
|
+
// the AST, avoiding mutable plugin-factory state (and concurrent-run races).
|
|
18075
|
+
file.tsrxStyle = styleResult;
|
|
18076
|
+
return file;
|
|
18077
|
+
}
|
|
18078
|
+
|
|
18079
|
+
var index = (
|
|
18080
|
+
_api,
|
|
18081
|
+
options = {}) =>
|
|
18082
|
+
|
|
18083
|
+
|
|
18084
|
+
|
|
18085
|
+
|
|
18086
|
+
|
|
18087
|
+
{
|
|
18088
|
+
return {
|
|
18089
|
+
name: "@solidjs/babel-plugin",
|
|
18090
|
+
inherits: SyntaxJSX.default,
|
|
18091
|
+
parserOverride(code, parserOpts, parse) {
|
|
18092
|
+
if (isTsrxSource(options.syntax, parserOpts?.sourceFileName)) {
|
|
18093
|
+
return parseTsrx(code, parserOpts?.sourceFileName);
|
|
18094
|
+
}
|
|
18095
|
+
return parse(code, parserOpts);
|
|
18096
|
+
},
|
|
14588
18097
|
visitor: {
|
|
14589
18098
|
JSXElement: transformJSX,
|
|
14590
18099
|
JSXFragment: transformJSX,
|