@fluixi/compiler 1.0.0-alpha.100
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/LICENSE +21 -0
- package/README.md +131 -0
- package/dist/analyze/expr-shape.cjs +62 -0
- package/dist/analyze/expr-shape.d.cts +14 -0
- package/dist/analyze/expr-shape.d.ts +15 -0
- package/dist/analyze/expr-shape.d.ts.map +1 -0
- package/dist/analyze/expr-shape.js +37 -0
- package/dist/analyze/expr-shape.mjs +41 -0
- package/dist/analyze/intrinsics.cjs +112 -0
- package/dist/analyze/intrinsics.d.cts +80 -0
- package/dist/analyze/intrinsics.d.ts +81 -0
- package/dist/analyze/intrinsics.d.ts.map +1 -0
- package/dist/analyze/intrinsics.js +126 -0
- package/dist/analyze/intrinsics.mjs +91 -0
- package/dist/analyze/paren.cjs +134 -0
- package/dist/analyze/paren.d.cts +23 -0
- package/dist/analyze/paren.d.ts +24 -0
- package/dist/analyze/paren.d.ts.map +1 -0
- package/dist/analyze/paren.js +168 -0
- package/dist/analyze/paren.mjs +113 -0
- package/dist/analyze/props-destructure.cjs +226 -0
- package/dist/analyze/props-destructure.d.cts +83 -0
- package/dist/analyze/props-destructure.d.ts +84 -0
- package/dist/analyze/props-destructure.d.ts.map +1 -0
- package/dist/analyze/props-destructure.js +272 -0
- package/dist/analyze/props-destructure.mjs +205 -0
- package/dist/analyze/reactive-bindings.cjs +210 -0
- package/dist/analyze/reactive-bindings.d.cts +42 -0
- package/dist/analyze/reactive-bindings.d.ts +43 -0
- package/dist/analyze/reactive-bindings.d.ts.map +1 -0
- package/dist/analyze/reactive-bindings.js +191 -0
- package/dist/analyze/reactive-bindings.mjs +187 -0
- package/dist/analyze/reactive-expr.cjs +38 -0
- package/dist/analyze/reactive-expr.d.cts +38 -0
- package/dist/analyze/reactive-expr.d.ts +39 -0
- package/dist/analyze/reactive-expr.d.ts.map +1 -0
- package/dist/analyze/reactive-expr.js +31 -0
- package/dist/analyze/reactive-expr.mjs +17 -0
- package/dist/analyze/static-graph.cjs +831 -0
- package/dist/analyze/static-graph.d.cts +102 -0
- package/dist/analyze/static-graph.d.ts +103 -0
- package/dist/analyze/static-graph.d.ts.map +1 -0
- package/dist/analyze/static-graph.js +871 -0
- package/dist/analyze/static-graph.mjs +813 -0
- package/dist/babel-I6BUWUCU.mjs +636 -0
- package/dist/chunk-3AICWNF7.mjs +92 -0
- package/dist/chunk-6CWJWGE2.mjs +2170 -0
- package/dist/chunk-C3XPDB4Y.mjs +16 -0
- package/dist/chunk-GX5XV6Z7.mjs +190 -0
- package/dist/chunk-HXEXPWJ2.mjs +999 -0
- package/dist/chunk-NU3W67UZ.mjs +584 -0
- package/dist/chunk-SKAVY75W.mjs +11 -0
- package/dist/codegen/backend.cjs +18 -0
- package/dist/codegen/backend.d.cts +35 -0
- package/dist/codegen/backend.d.ts +36 -0
- package/dist/codegen/backend.d.ts.map +1 -0
- package/dist/codegen/backend.js +1 -0
- package/dist/codegen/backend.mjs +0 -0
- package/dist/codegen/backends/imperative.cjs +577 -0
- package/dist/codegen/backends/imperative.d.cts +11 -0
- package/dist/codegen/backends/imperative.d.ts +12 -0
- package/dist/codegen/backends/imperative.d.ts.map +1 -0
- package/dist/codegen/backends/imperative.js +362 -0
- package/dist/codegen/backends/imperative.mjs +554 -0
- package/dist/codegen/contract.cjs +52 -0
- package/dist/codegen/contract.d.cts +24 -0
- package/dist/codegen/contract.d.ts +25 -0
- package/dist/codegen/contract.d.ts.map +1 -0
- package/dist/codegen/contract.js +30 -0
- package/dist/codegen/contract.mjs +31 -0
- package/dist/codegen/partial-template.cjs +176 -0
- package/dist/codegen/partial-template.d.cts +61 -0
- package/dist/codegen/partial-template.d.ts +62 -0
- package/dist/codegen/partial-template.d.ts.map +1 -0
- package/dist/codegen/partial-template.js +0 -0
- package/dist/codegen/partial-template.mjs +153 -0
- package/dist/codegen/serialize-static.cjs +125 -0
- package/dist/codegen/serialize-static.d.cts +38 -0
- package/dist/codegen/serialize-static.d.ts +39 -0
- package/dist/codegen/serialize-static.d.ts.map +1 -0
- package/dist/codegen/serialize-static.js +165 -0
- package/dist/codegen/serialize-static.mjs +104 -0
- package/dist/frontend/babel/build-ir-lit.cjs +1933 -0
- package/dist/frontend/babel/build-ir-lit.d.cts +26 -0
- package/dist/frontend/babel/build-ir-lit.d.ts +27 -0
- package/dist/frontend/babel/build-ir-lit.d.ts.map +1 -0
- package/dist/frontend/babel/build-ir-lit.js +13 -0
- package/dist/frontend/babel/build-ir-lit.mjs +1902 -0
- package/dist/frontend/babel/build-ir.cjs +1948 -0
- package/dist/frontend/babel/build-ir.d.cts +35 -0
- package/dist/frontend/babel/build-ir.d.ts +36 -0
- package/dist/frontend/babel/build-ir.d.ts.map +1 -0
- package/dist/frontend/babel/build-ir.js +124 -0
- package/dist/frontend/babel/build-ir.mjs +1919 -0
- package/dist/frontend/babel/index.cjs +2610 -0
- package/dist/frontend/babel/index.d.cts +33 -0
- package/dist/frontend/babel/index.d.ts +34 -0
- package/dist/frontend/babel/index.d.ts.map +1 -0
- package/dist/frontend/babel/index.js +65 -0
- package/dist/frontend/babel/index.mjs +2580 -0
- package/dist/frontend/babel/lower-template.cjs +1931 -0
- package/dist/frontend/babel/lower-template.d.cts +23 -0
- package/dist/frontend/babel/lower-template.d.ts +24 -0
- package/dist/frontend/babel/lower-template.d.ts.map +1 -0
- package/dist/frontend/babel/lower-template.js +64 -0
- package/dist/frontend/babel/lower-template.mjs +1902 -0
- package/dist/frontend/babel/plugin.cjs +2556 -0
- package/dist/frontend/babel/plugin.d.cts +95 -0
- package/dist/frontend/babel/plugin.d.ts +96 -0
- package/dist/frontend/babel/plugin.d.ts.map +1 -0
- package/dist/frontend/babel/plugin.js +523 -0
- package/dist/frontend/babel/plugin.mjs +2527 -0
- package/dist/frontend/babel/server-functions.cjs +110 -0
- package/dist/frontend/babel/server-functions.d.cts +10 -0
- package/dist/frontend/babel/server-functions.d.ts +11 -0
- package/dist/frontend/babel/server-functions.d.ts.map +1 -0
- package/dist/frontend/babel/server-functions.js +81 -0
- package/dist/frontend/babel/server-functions.mjs +89 -0
- package/dist/frontend/babel/types.cjs +18 -0
- package/dist/frontend/babel/types.d.cts +33 -0
- package/dist/frontend/babel/types.d.ts +34 -0
- package/dist/frontend/babel/types.d.ts.map +1 -0
- package/dist/frontend/babel/types.js +1 -0
- package/dist/frontend/babel/types.mjs +0 -0
- package/dist/frontend/types.cjs +18 -0
- package/dist/frontend/types.d.cts +25 -0
- package/dist/frontend/types.d.ts +26 -0
- package/dist/frontend/types.d.ts.map +1 -0
- package/dist/frontend/types.js +1 -0
- package/dist/frontend/types.mjs +0 -0
- package/dist/frontend/vocabulary.cjs +98 -0
- package/dist/frontend/vocabulary.d.cts +79 -0
- package/dist/frontend/vocabulary.d.ts +80 -0
- package/dist/frontend/vocabulary.d.ts.map +1 -0
- package/dist/frontend/vocabulary.js +124 -0
- package/dist/frontend/vocabulary.mjs +77 -0
- package/dist/index.cjs +1957 -0
- package/dist/index.d.cts +27 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.mjs +1949 -0
- package/dist/integrations.cjs +5705 -0
- package/dist/integrations.d.cts +215 -0
- package/dist/integrations.d.ts +216 -0
- package/dist/integrations.d.ts.map +1 -0
- package/dist/integrations.js +566 -0
- package/dist/integrations.mjs +810 -0
- package/dist/ir/nodes.cjs +18 -0
- package/dist/ir/nodes.d.cts +168 -0
- package/dist/ir/nodes.d.ts +169 -0
- package/dist/ir/nodes.d.ts.map +1 -0
- package/dist/ir/nodes.js +1 -0
- package/dist/ir/nodes.mjs +0 -0
- package/dist/lower/compile-template.cjs +1670 -0
- package/dist/lower/compile-template.d.cts +82 -0
- package/dist/lower/compile-template.d.ts +83 -0
- package/dist/lower/compile-template.d.ts.map +1 -0
- package/dist/lower/compile-template.js +79 -0
- package/dist/lower/compile-template.mjs +1662 -0
- package/dist/lower/entities.cjs +288 -0
- package/dist/lower/entities.d.cts +1 -0
- package/dist/lower/entities.d.ts +2 -0
- package/dist/lower/entities.d.ts.map +1 -0
- package/dist/lower/entities.js +54 -0
- package/dist/lower/entities.mjs +267 -0
- package/dist/lower/jsx.cjs +1101 -0
- package/dist/lower/jsx.d.cts +33 -0
- package/dist/lower/jsx.d.ts +34 -0
- package/dist/lower/jsx.d.ts.map +1 -0
- package/dist/lower/jsx.js +414 -0
- package/dist/lower/jsx.mjs +1078 -0
- package/dist/lower/template.cjs +1354 -0
- package/dist/lower/template.d.cts +53 -0
- package/dist/lower/template.d.ts +54 -0
- package/dist/lower/template.d.ts.map +1 -0
- package/dist/lower/template.js +542 -0
- package/dist/lower/template.mjs +1335 -0
- package/dist/lower/text.cjs +42 -0
- package/dist/lower/text.d.cts +10 -0
- package/dist/lower/text.d.ts +11 -0
- package/dist/lower/text.d.ts.map +1 -0
- package/dist/lower/text.js +31 -0
- package/dist/lower/text.mjs +21 -0
- package/dist/optimize/analyze-static.cjs +112 -0
- package/dist/optimize/analyze-static.d.cts +39 -0
- package/dist/optimize/analyze-static.d.ts +40 -0
- package/dist/optimize/analyze-static.d.ts.map +1 -0
- package/dist/optimize/analyze-static.js +131 -0
- package/dist/optimize/analyze-static.mjs +91 -0
- package/dist/optimize/collapse-strategies.cjs +90 -0
- package/dist/optimize/collapse-strategies.d.cts +30 -0
- package/dist/optimize/collapse-strategies.d.ts +31 -0
- package/dist/optimize/collapse-strategies.d.ts.map +1 -0
- package/dist/optimize/collapse-strategies.js +33 -0
- package/dist/optimize/collapse-strategies.mjs +67 -0
- package/dist/options.cjs +33 -0
- package/dist/options.d.cts +39 -0
- package/dist/options.d.ts +40 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +8 -0
- package/dist/options.mjs +12 -0
- package/dist/resolve/builtins.cjs +73 -0
- package/dist/resolve/builtins.d.cts +68 -0
- package/dist/resolve/builtins.d.ts +69 -0
- package/dist/resolve/builtins.d.ts.map +1 -0
- package/dist/resolve/builtins.js +64 -0
- package/dist/resolve/builtins.mjs +53 -0
- package/dist/resolve/component-globals.cjs +272 -0
- package/dist/resolve/component-globals.d.cts +88 -0
- package/dist/resolve/component-globals.d.ts +89 -0
- package/dist/resolve/component-globals.d.ts.map +1 -0
- package/dist/resolve/component-globals.js +160 -0
- package/dist/resolve/component-globals.mjs +249 -0
- package/dist/resolve/component-resolver.cjs +80 -0
- package/dist/resolve/component-resolver.d.cts +68 -0
- package/dist/resolve/component-resolver.d.ts +69 -0
- package/dist/resolve/component-resolver.d.ts.map +1 -0
- package/dist/resolve/component-resolver.js +95 -0
- package/dist/resolve/component-resolver.mjs +59 -0
- package/dist/resolve/load-directive.cjs +93 -0
- package/dist/resolve/load-directive.d.cts +53 -0
- package/dist/resolve/load-directive.d.ts +54 -0
- package/dist/resolve/load-directive.d.ts.map +1 -0
- package/dist/resolve/load-directive.js +93 -0
- package/dist/resolve/load-directive.mjs +72 -0
- package/dist/resolve/resolve-ir.cjs +108 -0
- package/dist/resolve/resolve-ir.d.cts +53 -0
- package/dist/resolve/resolve-ir.d.ts +54 -0
- package/dist/resolve/resolve-ir.d.ts.map +1 -0
- package/dist/resolve/resolve-ir.js +58 -0
- package/dist/resolve/resolve-ir.mjs +85 -0
- package/dist/resolve/write-globals.cjs +383 -0
- package/dist/resolve/write-globals.d.cts +36 -0
- package/dist/resolve/write-globals.d.ts +37 -0
- package/dist/resolve/write-globals.d.ts.map +1 -0
- package/dist/resolve/write-globals.js +169 -0
- package/dist/resolve/write-globals.mjs +362 -0
- package/dist/server-fns-VZLHMQTC.mjs +79 -0
- package/dist/server-functions-UAZKOLZW.mjs +82 -0
- package/dist/transform/bindings.cjs +71 -0
- package/dist/transform/bindings.d.cts +16 -0
- package/dist/transform/bindings.d.ts +17 -0
- package/dist/transform/bindings.d.ts.map +1 -0
- package/dist/transform/bindings.js +69 -0
- package/dist/transform/bindings.mjs +50 -0
- package/dist/transform/index.cjs +3837 -0
- package/dist/transform/index.d.cts +15 -0
- package/dist/transform/index.d.ts +16 -0
- package/dist/transform/index.d.ts.map +1 -0
- package/dist/transform/index.js +12 -0
- package/dist/transform/index.mjs +4882 -0
- package/dist/transform/intrinsics.cjs +261 -0
- package/dist/transform/intrinsics.d.cts +33 -0
- package/dist/transform/intrinsics.d.ts +34 -0
- package/dist/transform/intrinsics.d.ts.map +1 -0
- package/dist/transform/intrinsics.js +120 -0
- package/dist/transform/intrinsics.mjs +238 -0
- package/dist/transform/props.cjs +441 -0
- package/dist/transform/props.d.cts +45 -0
- package/dist/transform/props.d.ts +46 -0
- package/dist/transform/props.d.ts.map +1 -0
- package/dist/transform/props.js +221 -0
- package/dist/transform/props.mjs +1487 -0
- package/dist/transform/server-fn-id.cjs +35 -0
- package/dist/transform/server-fn-id.d.cts +9 -0
- package/dist/transform/server-fn-id.d.ts +10 -0
- package/dist/transform/server-fn-id.d.ts.map +1 -0
- package/dist/transform/server-fn-id.js +18 -0
- package/dist/transform/server-fn-id.mjs +14 -0
- package/dist/transform/server-fns.cjs +114 -0
- package/dist/transform/server-fns.d.cts +12 -0
- package/dist/transform/server-fns.d.ts +13 -0
- package/dist/transform/server-fns.d.ts.map +1 -0
- package/dist/transform/server-fns.js +94 -0
- package/dist/transform/server-fns.mjs +1160 -0
- package/dist/transform/source-locations.cjs +393 -0
- package/dist/transform/source-locations.d.cts +48 -0
- package/dist/transform/source-locations.d.ts +49 -0
- package/dist/transform/source-locations.d.ts.map +1 -0
- package/dist/transform/source-locations.js +303 -0
- package/dist/transform/source-locations.mjs +370 -0
- package/dist/transform/styles.cjs +606 -0
- package/dist/transform/styles.d.cts +237 -0
- package/dist/transform/styles.d.ts +238 -0
- package/dist/transform/styles.d.ts.map +1 -0
- package/dist/transform/styles.js +743 -0
- package/dist/transform/styles.mjs +671 -0
- package/dist/transform/templates.cjs +3806 -0
- package/dist/transform/templates.d.cts +82 -0
- package/dist/transform/templates.d.ts +83 -0
- package/dist/transform/templates.d.ts.map +1 -0
- package/dist/transform/templates.js +613 -0
- package/dist/transform/templates.mjs +4852 -0
- package/dist/transform-3W45L3EA.mjs +951 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -0
- package/dist/vite-styles.cjs +223 -0
- package/dist/vite-styles.d.cts +68 -0
- package/dist/vite-styles.d.ts +69 -0
- package/dist/vite-styles.d.ts.map +1 -0
- package/dist/vite-styles.js +241 -0
- package/dist/vite-styles.mjs +214 -0
- package/package.json +141 -0
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Babel front-end for the Fluixi compiler.
|
|
3
|
+
* @module @fluixi/babel-plugin-jsx
|
|
4
|
+
*
|
|
5
|
+
* This is a host adapter, not the compiler. It parses with babel and, for each
|
|
6
|
+
* JSX element/fragment and each `` html`...` `` template, hands the node to the
|
|
7
|
+
* shared pipeline: build IR, run the imperative backend, then splices the
|
|
8
|
+
* emitted code back into the program. Everything that decides *what* the output
|
|
9
|
+
* means (directives, control flow, component resolution, load strategies,
|
|
10
|
+
* reactivity, templates) lives in ../../{ir,resolve,optimize,codegen}, which
|
|
11
|
+
* import no babel at all.
|
|
12
|
+
*
|
|
13
|
+
* What stays here is genuinely host work: dispatching the visitors, collecting
|
|
14
|
+
* the runtime symbols the backend reported so the imports can be injected, and
|
|
15
|
+
* hoisting static templates to module scope.
|
|
16
|
+
*/
|
|
17
|
+
import { declare } from '@babel/helper-plugin-utils';
|
|
18
|
+
import { createComponentResolver, } from '../../resolve/component-resolver.js';
|
|
19
|
+
import { resolveComponentSources } from '../../resolve/resolve-ir.js';
|
|
20
|
+
import { collapseStrategies } from '../../optimize/collapse-strategies.js';
|
|
21
|
+
import { isDeferred } from '../../resolve/load-directive.js';
|
|
22
|
+
import { CORE_CONTROL_FLOW, ROUTER_COMPONENTS as ROUTER_COMPONENT_NAMES, } from '../../resolve/builtins.js';
|
|
23
|
+
import { types as t, template } from '@babel/core';
|
|
24
|
+
import { buildIR } from './build-ir.js';
|
|
25
|
+
import { buildIRFromLit } from './build-ir-lit.js';
|
|
26
|
+
import { imperativeBackend } from '../../codegen/backends/imperative.js';
|
|
27
|
+
// ============================================================================
|
|
28
|
+
// Constants
|
|
29
|
+
// ============================================================================
|
|
30
|
+
// Control-flow components that live in fluixi, NOT @fluixi/dom, they must
|
|
31
|
+
// be auto-imported from core (dom doesn't export them).
|
|
32
|
+
const CORE_ONLY_CONTROL_FLOW = new Set(CORE_CONTROL_FLOW);
|
|
33
|
+
// Router components auto-imported (from routerModule) the same way control flow is:
|
|
34
|
+
// use `<Router>`/`<Outlet>`/… in a template and the import is injected if absent.
|
|
35
|
+
const ROUTER_COMPONENTS = new Set(ROUTER_COMPONENT_NAMES);
|
|
36
|
+
// ============================================================================
|
|
37
|
+
// Main Plugin
|
|
38
|
+
// ============================================================================
|
|
39
|
+
export default declare((api, options = {}) => {
|
|
40
|
+
api.assertVersion(7);
|
|
41
|
+
const { delegateEvents = true, signalModule = '@fluixi/dom', controlFlowModule = '@fluixi/dom', routerModule = '@fluixi/core/router', reactiveModule = '@fluixi/reactive/signal', templateClone = true, partialTemplates = true,
|
|
42
|
+
// `both` by default: JSX and html`` are compiled out of the box, so
|
|
43
|
+
// `fluixi()` needs no `format` option. Injected imports are deduped, so a
|
|
44
|
+
// file mixing the two styles won't redeclare a binding.
|
|
45
|
+
format = 'both', litTag = 'html', resolve: resolveRules = [], } = options;
|
|
46
|
+
// Built once per plugin instance, not per file: the rules are static and the
|
|
47
|
+
// resolver memoises lookups, so every file in the build shares one cache.
|
|
48
|
+
const componentResolver = createComponentResolver(resolveRules);
|
|
49
|
+
const compileLit = format === 'lit' || format === 'both';
|
|
50
|
+
const pluginState = {
|
|
51
|
+
irImports: new Set(),
|
|
52
|
+
libModule: '@fluixi/core',
|
|
53
|
+
controlFlowModule,
|
|
54
|
+
routerModule,
|
|
55
|
+
templateClone,
|
|
56
|
+
partialTemplates,
|
|
57
|
+
hasJSX: false,
|
|
58
|
+
hasLitHTML: false,
|
|
59
|
+
needsControlFlowImport: false,
|
|
60
|
+
needsCreateMemo: false,
|
|
61
|
+
controlFlowComponents: new Set(),
|
|
62
|
+
resolvedComponents: new Map(),
|
|
63
|
+
deferredComponents: new Map(),
|
|
64
|
+
componentResolver,
|
|
65
|
+
delegatedEvents: new Set(),
|
|
66
|
+
staticTemplates: new Map(),
|
|
67
|
+
staticCounter: 0,
|
|
68
|
+
};
|
|
69
|
+
return {
|
|
70
|
+
name: '@fluixi/babel-plugin-jsx',
|
|
71
|
+
manipulateOptions(opts, parserOpts) {
|
|
72
|
+
// Enable JSX parsing
|
|
73
|
+
parserOpts.plugins.push('jsx', 'typescript');
|
|
74
|
+
},
|
|
75
|
+
pre(state) {
|
|
76
|
+
// Initialize plugin state
|
|
77
|
+
Object.assign(state, pluginState);
|
|
78
|
+
},
|
|
79
|
+
visitor: {
|
|
80
|
+
Program: {
|
|
81
|
+
enter(path, state) {
|
|
82
|
+
// Reset state for new file
|
|
83
|
+
Object.assign(state, {
|
|
84
|
+
hasJSX: false,
|
|
85
|
+
hasLitHTML: false,
|
|
86
|
+
hasLitIR: false,
|
|
87
|
+
needsControlFlowImport: false,
|
|
88
|
+
needsCreateMemo: false,
|
|
89
|
+
controlFlowComponents: new Set(),
|
|
90
|
+
resolvedComponents: new Map(),
|
|
91
|
+
deferredComponents: new Map(),
|
|
92
|
+
componentResolver,
|
|
93
|
+
delegatedEvents: new Set(),
|
|
94
|
+
staticTemplates: new Map(),
|
|
95
|
+
staticCounter: 0,
|
|
96
|
+
libModule: '@fluixi/core',
|
|
97
|
+
controlFlowModule,
|
|
98
|
+
routerModule,
|
|
99
|
+
templateClone,
|
|
100
|
+
partialTemplates,
|
|
101
|
+
irImports: new Set(),
|
|
102
|
+
needsCreateNativeElement: false,
|
|
103
|
+
needsInsert: false,
|
|
104
|
+
needsSpread: false,
|
|
105
|
+
needsCreateComponent: false,
|
|
106
|
+
needsMergeProps: false,
|
|
107
|
+
});
|
|
108
|
+
},
|
|
109
|
+
exit(path, state) {
|
|
110
|
+
const imports = [];
|
|
111
|
+
if (state.hasJSX || state.hasLitIR) {
|
|
112
|
+
if (state.irImports.size > 0) {
|
|
113
|
+
// Import exactly the symbols emit() reported, splitting control-flow
|
|
114
|
+
// components to the control-flow module.
|
|
115
|
+
const CF = new Set([
|
|
116
|
+
'Show', 'For', 'Index', 'Switch', 'Match',
|
|
117
|
+
'Dynamic', 'ErrorBoundary', 'Portal', 'Suspense',
|
|
118
|
+
]);
|
|
119
|
+
// Reactive primitives come from the signal core, not the dom module.
|
|
120
|
+
const REACTIVE = new Set([
|
|
121
|
+
'createMemo', 'createEffect', 'createRenderEffect', 'createRoot',
|
|
122
|
+
'createSignal', 'onCleanup', 'batch', 'untrack',
|
|
123
|
+
]);
|
|
124
|
+
const all = Array.from(state.irImports);
|
|
125
|
+
const spec = (n) => t.importSpecifier(t.identifier(n), t.identifier(n));
|
|
126
|
+
const unbound = (s) => !path.scope.hasBinding(s);
|
|
127
|
+
const reactive = all.filter((s) => REACTIVE.has(s) && unbound(s));
|
|
128
|
+
const core = all.filter((s) => !CF.has(s) && !REACTIVE.has(s) && unbound(s));
|
|
129
|
+
const cf = all.filter((s) => CF.has(s) && unbound(s));
|
|
130
|
+
if (reactive.length > 0) {
|
|
131
|
+
imports.push(t.importDeclaration(reactive.map(spec), t.stringLiteral(reactiveModule)));
|
|
132
|
+
}
|
|
133
|
+
if (core.length > 0) {
|
|
134
|
+
imports.push(t.importDeclaration(core.map(spec), t.stringLiteral(signalModule)));
|
|
135
|
+
}
|
|
136
|
+
if (cf.length > 0) {
|
|
137
|
+
imports.push(t.importDeclaration(cf.map(spec), t.stringLiteral(controlFlowModule)));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// createMemo (wraps conditionals/components) is a reactive primitive,
|
|
141
|
+
// so it comes from the reactive module, not dom.
|
|
142
|
+
if (state.needsCreateMemo && !path.scope.hasBinding('createMemo')) {
|
|
143
|
+
imports.push(t.importDeclaration([t.importSpecifier(t.identifier('createMemo'), t.identifier('createMemo'))], t.stringLiteral(reactiveModule)));
|
|
144
|
+
}
|
|
145
|
+
// Add control flow imports for auto-transformed components (Show, etc.)
|
|
146
|
+
// Only add components that aren't already bound in the file scope.
|
|
147
|
+
if (state.needsControlFlowImport &&
|
|
148
|
+
state.controlFlowComponents.size > 0) {
|
|
149
|
+
const unbound = Array.from(state.controlFlowComponents).filter((name) => !path.scope.hasBinding(name));
|
|
150
|
+
// Suspense/SuspenseList live in fluixi, not @fluixi/dom, so
|
|
151
|
+
// they must be auto-imported from core (importing them from the dom
|
|
152
|
+
// controlFlowModule would resolve to nothing). Everything else comes
|
|
153
|
+
// from controlFlowModule.
|
|
154
|
+
const coreModule = state.libModule ?? '@fluixi/core';
|
|
155
|
+
const fromRouter = unbound.filter((n) => ROUTER_COMPONENTS.has(n));
|
|
156
|
+
const fromCore = unbound.filter((n) => CORE_ONLY_CONTROL_FLOW.has(n));
|
|
157
|
+
const fromDom = unbound.filter((n) => !CORE_ONLY_CONTROL_FLOW.has(n) && !ROUTER_COMPONENTS.has(n));
|
|
158
|
+
const declFor = (names, mod) => t.importDeclaration(names.map((name) => t.importSpecifier(t.identifier(name), t.identifier(name))), t.stringLiteral(mod));
|
|
159
|
+
if (fromDom.length > 0)
|
|
160
|
+
imports.push(declFor(fromDom, controlFlowModule));
|
|
161
|
+
if (fromCore.length > 0)
|
|
162
|
+
imports.push(declFor(fromCore, coreModule));
|
|
163
|
+
if (fromRouter.length > 0)
|
|
164
|
+
imports.push(declFor(fromRouter, routerModule));
|
|
165
|
+
}
|
|
166
|
+
// Imports for tags matched by the `resolve` rules. Same binding guard as
|
|
167
|
+
// control flow: a hand-written import or a local of the same name wins, so
|
|
168
|
+
// enabling resolution can never change what an existing file means.
|
|
169
|
+
//
|
|
170
|
+
// Grouped by module so several components from one package share a single
|
|
171
|
+
// declaration, and emitted with the local name equal to the tag, the
|
|
172
|
+
// generated code refers to the tag, not to the export.
|
|
173
|
+
// Deferred components become value bindings, not imports: a literal
|
|
174
|
+
// `import()` is what lets the bundler split, hash and tree-shake the chunk
|
|
175
|
+
// as ordinary behaviour rather than as an integration.
|
|
176
|
+
const deferredDecls = [];
|
|
177
|
+
if (state.deferredComponents.size > 0) {
|
|
178
|
+
for (const [local, entry] of state.deferredComponents) {
|
|
179
|
+
if (path.scope.hasBinding(local))
|
|
180
|
+
continue;
|
|
181
|
+
deferredDecls.push(t.variableDeclaration('const', [
|
|
182
|
+
t.variableDeclarator(t.identifier(local), t.callExpression(t.identifier('deferred'), [
|
|
183
|
+
t.arrowFunctionExpression([], t.callExpression(t.import(), [t.stringLiteral(entry.module)])),
|
|
184
|
+
t.objectExpression([
|
|
185
|
+
t.objectProperty(t.identifier('strategy'), strategyLiteral(entry.strategy)),
|
|
186
|
+
t.objectProperty(t.identifier('export'), t.stringLiteral(entry.export)),
|
|
187
|
+
]),
|
|
188
|
+
])),
|
|
189
|
+
]));
|
|
190
|
+
}
|
|
191
|
+
if (deferredDecls.length > 0 && !path.scope.hasBinding('deferred')) {
|
|
192
|
+
imports.push(t.importDeclaration([t.importSpecifier(t.identifier('deferred'), t.identifier('deferred'))], t.stringLiteral(state.libModule ?? '@fluixi/core')));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (state.resolvedComponents.size > 0) {
|
|
196
|
+
const byModule = new Map();
|
|
197
|
+
for (const [local, resolved] of state.resolvedComponents) {
|
|
198
|
+
if (path.scope.hasBinding(local))
|
|
199
|
+
continue;
|
|
200
|
+
const list = byModule.get(resolved.module) ?? [];
|
|
201
|
+
list.push({ local, exported: resolved.export });
|
|
202
|
+
byModule.set(resolved.module, list);
|
|
203
|
+
}
|
|
204
|
+
for (const [mod, entries] of byModule) {
|
|
205
|
+
imports.push(t.importDeclaration(entries.map(({ local, exported }) => exported === 'default'
|
|
206
|
+
? t.importDefaultSpecifier(t.identifier(local))
|
|
207
|
+
: t.importSpecifier(t.identifier(local), t.identifier(exported))), t.stringLiteral(mod)));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Add event delegation setup if needed
|
|
211
|
+
if (delegateEvents && state.delegatedEvents.size > 0) {
|
|
212
|
+
imports.push(t.importDeclaration([
|
|
213
|
+
t.importSpecifier(t.identifier('delegateEvents'), t.identifier('delegateEvents')),
|
|
214
|
+
], t.stringLiteral(signalModule)));
|
|
215
|
+
// Add delegateEvents call at top of program
|
|
216
|
+
const eventsArray = t.arrayExpression(Array.from(state.delegatedEvents).map((event) => t.stringLiteral(event)));
|
|
217
|
+
const delegateCall = t.expressionStatement(t.callExpression(t.identifier('delegateEvents'), [eventsArray]));
|
|
218
|
+
path.node.body.unshift(delegateCall);
|
|
219
|
+
}
|
|
220
|
+
// Before imports are unshifted, so the
|
|
221
|
+
// final order is: imports, deferred bindings, everything else.
|
|
222
|
+
if (deferredDecls.length > 0) {
|
|
223
|
+
path.node.body.unshift(...deferredDecls);
|
|
224
|
+
}
|
|
225
|
+
// Static templates, parsed once per module rather than per instance.
|
|
226
|
+
if (state.staticTemplates.size > 0) {
|
|
227
|
+
const decls = [];
|
|
228
|
+
for (const [key, name] of state.staticTemplates) {
|
|
229
|
+
const svg = key.startsWith('svg:');
|
|
230
|
+
const html = svg ? key.slice(4) : key;
|
|
231
|
+
decls.push(t.variableDeclaration('const', [
|
|
232
|
+
t.variableDeclarator(t.identifier(name),
|
|
233
|
+
// Just the HTML. Parsing is deferred to `templateNode`, which
|
|
234
|
+
// knows whether this is a server render, a hydration or a fresh
|
|
235
|
+
// client render: a module-scope `createTemplate` would touch
|
|
236
|
+
// `document` at import time and break SSR outright.
|
|
237
|
+
t.stringLiteral(html)),
|
|
238
|
+
]));
|
|
239
|
+
}
|
|
240
|
+
path.node.body.unshift(...decls);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
// Add all imports at the top, deduped. When a file mixes inline JSX
|
|
244
|
+
// and html`` (format 'both'), the two injection paths can each emit an
|
|
245
|
+
// import for the same module/name: merge per-module and drop repeated
|
|
246
|
+
// specifiers so we never redeclare a binding.
|
|
247
|
+
if (imports.length > 0) {
|
|
248
|
+
path.node.body.unshift(...dedupeImports(imports));
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
// Both JSX forms take the one path: build IR, run the imperative backend,
|
|
253
|
+
// splice the emitted code back in. It handles the whole subtree, so nothing
|
|
254
|
+
// below this node needs its own visitor.
|
|
255
|
+
JSXElement(path, state) {
|
|
256
|
+
state.hasJSX = true;
|
|
257
|
+
path.replaceWith(emitViaIR(path.node, state));
|
|
258
|
+
},
|
|
259
|
+
JSXFragment(path, state) {
|
|
260
|
+
state.hasJSX = true;
|
|
261
|
+
path.replaceWith(emitViaIR(path.node, state));
|
|
262
|
+
},
|
|
263
|
+
TaggedTemplateExpression(path, state) {
|
|
264
|
+
// `html`...`` and `svg`...`` lower through the same IR and the same
|
|
265
|
+
// backend as JSX: one pipeline, two authoring syntaxes.
|
|
266
|
+
if (compileLit &&
|
|
267
|
+
t.isIdentifier(path.node.tag) &&
|
|
268
|
+
(path.node.tag.name === litTag || path.node.tag.name === 'svg')) {
|
|
269
|
+
path.replaceWith(emitLitViaIR(path.node, state));
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
};
|
|
274
|
+
});
|
|
275
|
+
// ============================================================================
|
|
276
|
+
// JSX Transformation
|
|
277
|
+
// ============================================================================
|
|
278
|
+
/**
|
|
279
|
+
* Two usages of one component in the same file share a binding, so their strategies
|
|
280
|
+
* have to agree. The earlier-loading one wins: the module is in whichever chunk loads
|
|
281
|
+
* first regardless, so deferring the other buys nothing, the same reasoning as the
|
|
282
|
+
* collapse pass, applied within a file.
|
|
283
|
+
*/
|
|
284
|
+
/**
|
|
285
|
+
* What to do with JSX or a template found inside an expression: resolve its
|
|
286
|
+
* component references and record what the module needs, exactly as the
|
|
287
|
+
* top-level node gets. The IR itself is emitted and dropped by the walk, so
|
|
288
|
+
* anything not taken off it here is lost: which is how `{(b) => <Input/>}`
|
|
289
|
+
* came out referring to a component nothing imported.
|
|
290
|
+
*/
|
|
291
|
+
function nestedHook(state) {
|
|
292
|
+
return (ir) => {
|
|
293
|
+
resolveComponentSources(ir, {
|
|
294
|
+
resolver: state.componentResolver,
|
|
295
|
+
modules: {
|
|
296
|
+
controlFlowModule: state.controlFlowModule,
|
|
297
|
+
coreModule: state.libModule,
|
|
298
|
+
routerModule: state.routerModule,
|
|
299
|
+
},
|
|
300
|
+
strategyFor: (node) => node.load,
|
|
301
|
+
});
|
|
302
|
+
collapseStrategies(ir);
|
|
303
|
+
collectRuntimeNeeds(ir, state);
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
/** The strategy as an object literal the runtime can read. */
|
|
307
|
+
function strategyLiteral(strategy) {
|
|
308
|
+
const props = [
|
|
309
|
+
t.objectProperty(t.identifier('kind'), t.stringLiteral(strategy.kind)),
|
|
310
|
+
];
|
|
311
|
+
if (strategy.kind === 'visible' && strategy.rootMargin) {
|
|
312
|
+
props.push(t.objectProperty(t.identifier('rootMargin'), t.stringLiteral(strategy.rootMargin)));
|
|
313
|
+
}
|
|
314
|
+
if (strategy.kind === 'interaction') {
|
|
315
|
+
props.push(t.objectProperty(t.identifier('events'), t.arrayExpression(strategy.events.map((e) => t.stringLiteral(e)))));
|
|
316
|
+
}
|
|
317
|
+
if (strategy.kind === 'media') {
|
|
318
|
+
props.push(t.objectProperty(t.identifier('query'), t.stringLiteral(strategy.query)));
|
|
319
|
+
}
|
|
320
|
+
return t.objectExpression(props);
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Hoist the backend's static templates to module scope and rewrite the emitted code to
|
|
324
|
+
* reference them. Deduped by HTML, so a subtree repeated in a file is parsed once.
|
|
325
|
+
*/
|
|
326
|
+
function adoptTemplates(code, templates, state) {
|
|
327
|
+
if (!templates || templates.length === 0)
|
|
328
|
+
return code;
|
|
329
|
+
const rename = new Map();
|
|
330
|
+
for (const tpl of templates) {
|
|
331
|
+
const key = `${tpl.svg ? 'svg:' : ''}${tpl.html}`;
|
|
332
|
+
let name = state.staticTemplates.get(key);
|
|
333
|
+
if (!name) {
|
|
334
|
+
name = `_tmpl$${state.staticTemplates.size}`;
|
|
335
|
+
state.staticTemplates.set(key, name);
|
|
336
|
+
}
|
|
337
|
+
rename.set(tpl.id, name);
|
|
338
|
+
}
|
|
339
|
+
// One pass, not one replacement per id. The backend's local ids and the hoisted names
|
|
340
|
+
// share the `_tmpl$N` namespace, so replacing them in sequence can rewrite a name that
|
|
341
|
+
// an earlier replacement just produced: which silently points a template at another
|
|
342
|
+
// template's HTML.
|
|
343
|
+
return code.replace(/_tmpl\$\d+/g, (id) => rename.get(id) ?? id);
|
|
344
|
+
}
|
|
345
|
+
function emitViaIR(node, state) {
|
|
346
|
+
// `used` collects runtime symbols emitted for JSX nested inside expressions
|
|
347
|
+
// (render-props, ternaries, fallback={<p/>}, …) so we import them too.
|
|
348
|
+
const used = new Set();
|
|
349
|
+
const ir = buildIR(node, used, nestedHook(state));
|
|
350
|
+
// The same passes the lit path runs. Without them `codegen: 'ir'` silently skipped
|
|
351
|
+
// resolution entirely: a resolved tag compiled to a reference with no import.
|
|
352
|
+
resolveComponentSources(ir, {
|
|
353
|
+
resolver: state.componentResolver,
|
|
354
|
+
modules: {
|
|
355
|
+
controlFlowModule: state.controlFlowModule,
|
|
356
|
+
coreModule: state.libModule,
|
|
357
|
+
routerModule: state.routerModule,
|
|
358
|
+
},
|
|
359
|
+
strategyFor: (n) => n.load,
|
|
360
|
+
});
|
|
361
|
+
collapseStrategies(ir);
|
|
362
|
+
const { code, imports, templates } = imperativeBackend.emit(ir, { templateClone: state.templateClone, partialTemplates: state.partialTemplates });
|
|
363
|
+
for (const s of imports)
|
|
364
|
+
used.add(s);
|
|
365
|
+
for (const s of used)
|
|
366
|
+
state.irImports.add(s);
|
|
367
|
+
collectRuntimeNeeds(ir, state);
|
|
368
|
+
const adopted = adoptTemplates(code, templates, state);
|
|
369
|
+
return template.expression(adopted, { placeholderPattern: false, plugins: ['typescript'] })();
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Merge injected import declarations so no module/name pair is imported twice.
|
|
373
|
+
* Named imports from the same module collapse into one declaration with unique
|
|
374
|
+
* specifiers; anything non-trivial (default/namespace/side-effect) passes through
|
|
375
|
+
* untouched. Order is preserved by first appearance.
|
|
376
|
+
*/
|
|
377
|
+
function dedupeImports(imports) {
|
|
378
|
+
const byModule = new Map();
|
|
379
|
+
const out = [];
|
|
380
|
+
for (const decl of imports) {
|
|
381
|
+
const source = decl.source.value;
|
|
382
|
+
const allNamed = decl.specifiers.every((s) => t.isImportSpecifier(s));
|
|
383
|
+
if (!allNamed) {
|
|
384
|
+
out.push(decl);
|
|
385
|
+
continue;
|
|
386
|
+
}
|
|
387
|
+
const existing = byModule.get(source);
|
|
388
|
+
if (!existing) {
|
|
389
|
+
const names = new Set(decl.specifiers.map((s) => (s.local.name)));
|
|
390
|
+
byModule.set(source, { decl, names });
|
|
391
|
+
out.push(decl);
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
for (const s of decl.specifiers) {
|
|
395
|
+
if (!existing.names.has(s.local.name)) {
|
|
396
|
+
existing.names.add(s.local.name);
|
|
397
|
+
existing.decl.specifiers.push(s);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
return out;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Lit-pipeline path: build IR from a `` html`...` `` template, emit through the
|
|
405
|
+
* imperative backend, reparse. Mirrors emitViaIR, the whole point is that lit
|
|
406
|
+
* and JSX share one IR + one backend. Collects runtime imports and the delegated
|
|
407
|
+
* events used so Program.exit wires them.
|
|
408
|
+
*/
|
|
409
|
+
function emitLitViaIR(node, state) {
|
|
410
|
+
const used = new Set();
|
|
411
|
+
const svg = t.isIdentifier(node.tag) && node.tag.name === 'svg';
|
|
412
|
+
const ir = buildIRFromLit(node, used, { svg, onNested: nestedHook(state) });
|
|
413
|
+
// Resolve pass: annotate each component reference with where it comes from, before
|
|
414
|
+
// codegen. Bindings are not checked here: Program.exit knows the whole file's scope
|
|
415
|
+
// and drops any injected import whose name turns out to be bound.
|
|
416
|
+
resolveComponentSources(ir, {
|
|
417
|
+
resolver: state.componentResolver,
|
|
418
|
+
modules: {
|
|
419
|
+
controlFlowModule: state.controlFlowModule,
|
|
420
|
+
coreModule: state.libModule,
|
|
421
|
+
routerModule: state.routerModule,
|
|
422
|
+
},
|
|
423
|
+
strategyFor: (node) => node.load,
|
|
424
|
+
});
|
|
425
|
+
// Demote deferred references whose module is already in this chunk: a lazy boundary
|
|
426
|
+
// around something already present adds a wrapper, a promise and a re-render to
|
|
427
|
+
// fetch nothing.
|
|
428
|
+
collapseStrategies(ir);
|
|
429
|
+
const { code, imports, templates } = imperativeBackend.emit(ir, { templateClone: state.templateClone, partialTemplates: state.partialTemplates });
|
|
430
|
+
for (const s of imports)
|
|
431
|
+
used.add(s);
|
|
432
|
+
for (const s of used)
|
|
433
|
+
state.irImports.add(s);
|
|
434
|
+
collectRuntimeNeeds(ir, state);
|
|
435
|
+
state.hasLitIR = true;
|
|
436
|
+
// The IR is emitted as a string and reparsed, so the resulting nodes carry no
|
|
437
|
+
// position: which is why compiled html`` had no source map at all. Give every
|
|
438
|
+
// generated node the template's own location so a breakpoint or stack frame
|
|
439
|
+
// lands on the template instead of nowhere.
|
|
440
|
+
const expression = template.expression(adoptTemplates(code, templates, state), {
|
|
441
|
+
placeholderPattern: false,
|
|
442
|
+
plugins: ['typescript'],
|
|
443
|
+
})();
|
|
444
|
+
inheritLocation(expression, node);
|
|
445
|
+
return expression;
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Copy a source position onto generated nodes that lack one.
|
|
449
|
+
*
|
|
450
|
+
* Coarse by construction: everything lowered from one template maps back to that
|
|
451
|
+
* template. Per-hole precision would mean carrying spans through the emit, which
|
|
452
|
+
* the string round-trip discards.
|
|
453
|
+
*/
|
|
454
|
+
function inheritLocation(target, source) {
|
|
455
|
+
if (!source.loc)
|
|
456
|
+
return;
|
|
457
|
+
const seen = new Set();
|
|
458
|
+
const walk = (node) => {
|
|
459
|
+
if (seen.has(node))
|
|
460
|
+
return;
|
|
461
|
+
seen.add(node);
|
|
462
|
+
if (!node.loc) {
|
|
463
|
+
node.loc = source.loc;
|
|
464
|
+
node.start = source.start;
|
|
465
|
+
node.end = source.end;
|
|
466
|
+
}
|
|
467
|
+
for (const key of t.VISITOR_KEYS[node.type] ?? []) {
|
|
468
|
+
const child = node[key];
|
|
469
|
+
if (Array.isArray(child)) {
|
|
470
|
+
for (const c of child)
|
|
471
|
+
if (c && typeof c === 'object' && 'type' in c)
|
|
472
|
+
walk(c);
|
|
473
|
+
}
|
|
474
|
+
else if (child && typeof child === 'object' && 'type' in child) {
|
|
475
|
+
walk(child);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
};
|
|
479
|
+
walk(target);
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Walk the lit IR for things Program.exit wires: delegated events (-> the
|
|
483
|
+
* delegateEvents([...]) call) and control-flow component names used as tags
|
|
484
|
+
* (-> auto-import from the control-flow module, like the inline JSX path).
|
|
485
|
+
*/
|
|
486
|
+
function collectRuntimeNeeds(node, state) {
|
|
487
|
+
if (node.kind === 'component' && node.source) {
|
|
488
|
+
// Provenance was decided by the resolve pass and recorded on the node; this only
|
|
489
|
+
// translates it into the two things Program.exit wires. Reading it here rather
|
|
490
|
+
// than re-resolving is the point: one decision, so import injection and every
|
|
491
|
+
// later pass cannot disagree.
|
|
492
|
+
if (node.source.origin === 'builtin') {
|
|
493
|
+
state.controlFlowComponents.add(node.name);
|
|
494
|
+
state.needsControlFlowImport = true;
|
|
495
|
+
}
|
|
496
|
+
else if (isDeferred(node.source.loading) && !state.resolvedComponents.has(node.name)) {
|
|
497
|
+
state.deferredComponents.set(node.name, {
|
|
498
|
+
module: node.source.module,
|
|
499
|
+
export: node.source.export,
|
|
500
|
+
strategy: node.source.loading,
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
else {
|
|
504
|
+
state.deferredComponents.delete(node.name);
|
|
505
|
+
state.resolvedComponents.set(node.name, {
|
|
506
|
+
module: node.source.module,
|
|
507
|
+
export: node.source.export,
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
if (node.kind === 'element' || node.kind === 'component' || node.kind === 'control') {
|
|
512
|
+
if ('props' in node) {
|
|
513
|
+
for (const p of node.props) {
|
|
514
|
+
if (p.kind === 'event' && p.event?.delegated)
|
|
515
|
+
state.delegatedEvents.add(p.event.name);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
if ('children' in node && node.children) {
|
|
520
|
+
for (const c of node.children)
|
|
521
|
+
collectRuntimeNeeds(c, state);
|
|
522
|
+
}
|
|
523
|
+
}
|