@geajs/vite-plugin 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +8 -2
- package/dist/index.mjs +1571 -165
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import _generate from "@babel/generator";
|
|
|
3
3
|
import * as t from "@babel/types";
|
|
4
4
|
import { parse } from "@babel/parser";
|
|
5
5
|
import { id, js, jsExpr, jsImport } from "eszter";
|
|
6
|
-
import { existsSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
7
7
|
import { dirname, relative, resolve } from "node:path";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
9
|
//#region src/utils/babel-interop.ts
|
|
@@ -84,15 +84,27 @@ function parseSource(code) {
|
|
|
84
84
|
name = t.isIdentifier(varDecl.id) ? varDecl.id.name : null;
|
|
85
85
|
returnsJSX = nodeReturnsJSX(init.body);
|
|
86
86
|
}
|
|
87
|
-
if (name && returnsJSX) functionalComponentInfo = {
|
|
87
|
+
if (name && returnsJSX) functionalComponentInfo = {
|
|
88
|
+
name,
|
|
89
|
+
kind: "default"
|
|
90
|
+
};
|
|
88
91
|
},
|
|
89
92
|
ExportNamedDeclaration(path) {
|
|
90
93
|
const decl = path.node.declaration;
|
|
91
94
|
if (!decl) return;
|
|
92
|
-
|
|
95
|
+
const registerNamed = (name) => {
|
|
96
|
+
if (functionalComponentInfo) return;
|
|
97
|
+
functionalComponentInfo = {
|
|
98
|
+
name,
|
|
99
|
+
kind: "named"
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
if (t.isFunctionDeclaration(decl) && decl.id && nodeReturnsJSX(decl.body)) registerNamed(decl.id.name);
|
|
93
103
|
else if (t.isVariableDeclaration(decl)) for (const declarator of decl.declarations) {
|
|
94
104
|
if (!t.isIdentifier(declarator.id) || !declarator.init) continue;
|
|
95
|
-
if (t.isArrowFunctionExpression(declarator.init) || t.isFunctionExpression(declarator.init))
|
|
105
|
+
if (t.isArrowFunctionExpression(declarator.init) || t.isFunctionExpression(declarator.init)) {
|
|
106
|
+
if (nodeReturnsJSX(declarator.init.body)) registerNamed(declarator.id.name);
|
|
107
|
+
}
|
|
96
108
|
}
|
|
97
109
|
},
|
|
98
110
|
JSXElement() {
|
|
@@ -129,48 +141,44 @@ function bodyReturnsJSX(block) {
|
|
|
129
141
|
const ret = block.body.find((s) => t.isReturnStatement(s) && s.argument != null);
|
|
130
142
|
return !!ret && nodeReturnsJSX(ret.argument);
|
|
131
143
|
}
|
|
132
|
-
/** Throw a compile error if a named export returns JSX. */
|
|
133
|
-
function throwIfReturnsJSX(name, body) {
|
|
134
|
-
if (nodeReturnsJSX(body)) {
|
|
135
|
-
const err = /* @__PURE__ */ new Error(`[gea] Named JSX component export '${name}' is not supported. Use 'export default' or convert to a class extending Component. Only one component per file is allowed.`);
|
|
136
|
-
err.__geaCompileError = true;
|
|
137
|
-
throw err;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
144
|
//#endregion
|
|
141
145
|
//#region src/preprocess/functional-to-class.ts
|
|
142
146
|
/**
|
|
143
|
-
* Converts a functional component
|
|
147
|
+
* Converts a functional component into a class-based Gea component.
|
|
144
148
|
*
|
|
145
|
-
*
|
|
149
|
+
* Default-export variants:
|
|
146
150
|
* - `export default function Foo(props) { return <div/> }`
|
|
147
151
|
* - `export default (props) => <div/>`
|
|
148
152
|
* - `const Foo = (props) => <div/>; export default Foo`
|
|
149
153
|
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
154
|
+
* Named-export variants (info.kind === 'named'):
|
|
155
|
+
* - `export function Foo(props) { return <div/> }`
|
|
156
|
+
* - `export const Foo = (props) => <div/>`
|
|
157
|
+
*
|
|
158
|
+
* The result preserves the export shape:
|
|
159
|
+
* - default → `class Foo extends Component { template(props) { ... } }
|
|
160
|
+
* export default Foo`
|
|
161
|
+
* - named → `export class Foo extends Component { template(props) { ... } }`
|
|
155
162
|
*
|
|
156
163
|
* Mutates the AST in place.
|
|
157
164
|
*/
|
|
158
165
|
function convertFunctionalToClass(ast, info, imports) {
|
|
159
166
|
const name = info.name;
|
|
167
|
+
const kind = info.kind ?? "default";
|
|
160
168
|
let params = [t.identifier("props")];
|
|
161
169
|
let templateBody = [];
|
|
162
170
|
let removeVarDeclPath = null;
|
|
163
171
|
let exportPath = null;
|
|
164
|
-
|
|
172
|
+
const extractFunction = (fn) => {
|
|
173
|
+
if (fn.params.length > 0) params = fn.params.map((p) => t.cloneNode(p));
|
|
174
|
+
if (t.isBlockStatement(fn.body)) {
|
|
175
|
+
const returnIdx = fn.body.body.findIndex((s) => t.isReturnStatement(s) && s.argument);
|
|
176
|
+
if (returnIdx >= 0) templateBody = fn.body.body.slice(0, returnIdx + 1).map((s) => t.cloneNode(s));
|
|
177
|
+
} else templateBody = [t.returnStatement(t.cloneNode(fn.body))];
|
|
178
|
+
};
|
|
179
|
+
if (kind === "default") traverse(ast, { ExportDefaultDeclaration(path) {
|
|
165
180
|
exportPath = path;
|
|
166
181
|
const decl = path.node.declaration;
|
|
167
|
-
const extractFunction = (fn) => {
|
|
168
|
-
if (fn.params.length > 0) params = fn.params.map((p) => t.cloneNode(p));
|
|
169
|
-
if (t.isBlockStatement(fn.body)) {
|
|
170
|
-
const returnIdx = fn.body.body.findIndex((s) => t.isReturnStatement(s) && s.argument);
|
|
171
|
-
if (returnIdx >= 0) templateBody = fn.body.body.slice(0, returnIdx + 1).map((s) => t.cloneNode(s));
|
|
172
|
-
} else templateBody = [t.returnStatement(t.cloneNode(fn.body))];
|
|
173
|
-
};
|
|
174
182
|
if (t.isFunctionDeclaration(decl)) extractFunction(decl);
|
|
175
183
|
else if (t.isArrowFunctionExpression(decl)) extractFunction(decl);
|
|
176
184
|
else if (t.isIdentifier(decl)) {
|
|
@@ -184,6 +192,23 @@ function convertFunctionalToClass(ast, info, imports) {
|
|
|
184
192
|
}
|
|
185
193
|
path.stop();
|
|
186
194
|
} });
|
|
195
|
+
else traverse(ast, { ExportNamedDeclaration(path) {
|
|
196
|
+
const decl = path.node.declaration;
|
|
197
|
+
if (!decl) return;
|
|
198
|
+
if (t.isFunctionDeclaration(decl) && decl.id?.name === name) {
|
|
199
|
+
exportPath = path;
|
|
200
|
+
extractFunction(decl);
|
|
201
|
+
path.stop();
|
|
202
|
+
} else if (t.isVariableDeclaration(decl)) for (const declarator of decl.declarations) {
|
|
203
|
+
if (!t.isIdentifier(declarator.id, { name }) || !declarator.init) continue;
|
|
204
|
+
if (t.isArrowFunctionExpression(declarator.init) || t.isFunctionExpression(declarator.init)) {
|
|
205
|
+
exportPath = path;
|
|
206
|
+
extractFunction(declarator.init);
|
|
207
|
+
path.stop();
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
} });
|
|
187
212
|
if (templateBody.length === 0 || !exportPath) return;
|
|
188
213
|
const firstParam = params[0];
|
|
189
214
|
const firstStmt = templateBody[0];
|
|
@@ -200,7 +225,7 @@ function convertFunctionalToClass(ast, info, imports) {
|
|
|
200
225
|
if (removeVarDeclPath) removeVarDeclPath.remove();
|
|
201
226
|
const program = ast.program;
|
|
202
227
|
const idx = program.body.indexOf(exportPath.node);
|
|
203
|
-
if (idx >= 0) program.body[idx] = t.exportDefaultDeclaration(classDecl);
|
|
228
|
+
if (idx >= 0) program.body[idx] = kind === "named" ? t.exportNamedDeclaration(classDecl, []) : t.exportDefaultDeclaration(classDecl);
|
|
204
229
|
}
|
|
205
230
|
function ensureComponentImport(ast, imports) {
|
|
206
231
|
if (imports.get("Component")) return;
|
|
@@ -788,6 +813,54 @@ function tryExtractPathAndRoot(expr) {
|
|
|
788
813
|
return null;
|
|
789
814
|
}
|
|
790
815
|
//#endregion
|
|
816
|
+
//#region src/closure-codegen/generator/generator-jsx-helpers.ts
|
|
817
|
+
/** True for JSX elements, fragments, null, undefined, or string literals (things that can be rendered in a branch). */
|
|
818
|
+
function isJsxOrNullish(n) {
|
|
819
|
+
if (t.isJSXElement(n) || t.isJSXFragment(n)) return true;
|
|
820
|
+
if (t.isNullLiteral(n)) return true;
|
|
821
|
+
if (t.isIdentifier(n, { name: "undefined" })) return true;
|
|
822
|
+
return false;
|
|
823
|
+
}
|
|
824
|
+
/** True when `n` is `<expr>.map(arrow)` where the arrow's body returns JSX
|
|
825
|
+
* (directly or via a `return` in a BlockStatement). Used by the `&&` arm
|
|
826
|
+
* to promote `cond && xs.map(x => <JSX/>)` to a conditional slot whose
|
|
827
|
+
* truthy branch is a keyed-list. */
|
|
828
|
+
function isMapWithJsxBody(n) {
|
|
829
|
+
if (!t.isCallExpression(n) && !t.isOptionalCallExpression(n)) return false;
|
|
830
|
+
const callee = n.callee;
|
|
831
|
+
if (!t.isMemberExpression(callee) && !t.isOptionalMemberExpression(callee)) return false;
|
|
832
|
+
if (callee.computed) return false;
|
|
833
|
+
if (!t.isIdentifier(callee.property, { name: "map" })) return false;
|
|
834
|
+
const arg = n.arguments[0];
|
|
835
|
+
if (!arg) return false;
|
|
836
|
+
if (!t.isArrowFunctionExpression(arg) && !t.isFunctionExpression(arg)) return false;
|
|
837
|
+
const body = arg.body;
|
|
838
|
+
if (t.isJSXElement(body) || t.isJSXFragment(body)) return true;
|
|
839
|
+
if (t.isBlockStatement(body)) {
|
|
840
|
+
const ret = body.body.find((s) => t.isReturnStatement(s));
|
|
841
|
+
if (ret && ret.argument && (t.isJSXElement(ret.argument) || t.isJSXFragment(ret.argument))) return true;
|
|
842
|
+
}
|
|
843
|
+
return false;
|
|
844
|
+
}
|
|
845
|
+
/**
|
|
846
|
+
* Check if a class declaration has a `template()` method and return it.
|
|
847
|
+
* Returns null if the class does not have a template method (non-component).
|
|
848
|
+
*/
|
|
849
|
+
function findTemplateMethod(classDecl) {
|
|
850
|
+
for (const member of classDecl.body.body) if (t.isClassMethod(member) && t.isIdentifier(member.key, { name: "template" }) && !member.computed && !member.static) return member;
|
|
851
|
+
return null;
|
|
852
|
+
}
|
|
853
|
+
/**
|
|
854
|
+
* Extract the JSX root from a template() method. The method body is expected to
|
|
855
|
+
* be `template() { return <jsx />; }` — possibly with prop destructuring.
|
|
856
|
+
*/
|
|
857
|
+
function extractTemplateJsx(templateMethod) {
|
|
858
|
+
for (const stmt of templateMethod.body.body) if (t.isReturnStatement(stmt) && stmt.argument) {
|
|
859
|
+
if (t.isJSXElement(stmt.argument) || t.isJSXFragment(stmt.argument)) return stmt.argument;
|
|
860
|
+
}
|
|
861
|
+
return null;
|
|
862
|
+
}
|
|
863
|
+
//#endregion
|
|
791
864
|
//#region src/closure-codegen/emit/emit-conditional.ts
|
|
792
865
|
function emitConditionalSlot(slot, stmts, ctx) {
|
|
793
866
|
const anchorId = t.identifier("anchor" + slot.index);
|
|
@@ -828,6 +901,10 @@ function buildBranchFn(branchExpr, ctx) {
|
|
|
828
901
|
const block = compileJsxToBlock(branchExpr, ctx);
|
|
829
902
|
return t.arrowFunctionExpression([t.identifier("d")], block);
|
|
830
903
|
}
|
|
904
|
+
if (isNestableConditionalExpression(branchExpr)) {
|
|
905
|
+
const block = compileJsxToBlock(t.jsxFragment(t.jsxOpeningFragment(), t.jsxClosingFragment(), [t.jsxExpressionContainer(branchExpr)]), ctx);
|
|
906
|
+
return t.arrowFunctionExpression([t.identifier("d")], block);
|
|
907
|
+
}
|
|
831
908
|
if (t.isCallExpression(branchExpr) && branchExpr.arguments.length === 0 && branchExpr.callee.__geaHoistedIIFE && t.isBlockStatement(branchExpr.callee.body)) {
|
|
832
909
|
const block = branchExpr.callee.body;
|
|
833
910
|
const last = block.body[block.body.length - 1];
|
|
@@ -852,6 +929,11 @@ function buildBranchFn(branchExpr, ctx) {
|
|
|
852
929
|
if (t.isCallExpression(substituted) && t.isMemberExpression(substituted.callee) && !substituted.callee.computed && t.isIdentifier(substituted.callee.property, { name: "map" }) && substituted.arguments.length >= 1 && (t.isArrowFunctionExpression(substituted.arguments[0]) || t.isFunctionExpression(substituted.arguments[0]))) return buildMapBranchFn(substituted, ctx);
|
|
853
930
|
return t.arrowFunctionExpression([t.identifier("d")], t.callExpression(t.memberExpression(t.identifier("document"), t.identifier("createComment")), [t.stringLiteral("")]));
|
|
854
931
|
}
|
|
932
|
+
function isNestableConditionalExpression(node) {
|
|
933
|
+
if (t.isConditionalExpression(node)) return isJsxOrNullish(node.consequent) || isJsxOrNullish(node.alternate);
|
|
934
|
+
if (t.isLogicalExpression(node) && node.operator === "&&") return isJsxOrNullish(node.right);
|
|
935
|
+
return false;
|
|
936
|
+
}
|
|
855
937
|
/**
|
|
856
938
|
* Build a branch fn for a bare `xs.map(item => <jsx/>)` expression. Creates a
|
|
857
939
|
* `<span style="display:contents">` wrapper, inserts a comment anchor inside,
|
|
@@ -1636,6 +1718,7 @@ function createItemBodyReferencesItemInReactiveGetter(fn, itemName) {
|
|
|
1636
1718
|
"reactiveBoolAttr",
|
|
1637
1719
|
"reactiveClass",
|
|
1638
1720
|
"reactiveStyle",
|
|
1721
|
+
"reactiveStyleProp",
|
|
1639
1722
|
"reactiveValue",
|
|
1640
1723
|
"reactiveValueRead"
|
|
1641
1724
|
]);
|
|
@@ -2164,6 +2247,66 @@ const INLINE_PROP_LIST_SOURCE = `{
|
|
|
2164
2247
|
}
|
|
2165
2248
|
let __kl_prev = __kl_first;
|
|
2166
2249
|
const __kl_reconcile = (arr, changes) => {
|
|
2250
|
+
if (!Array.isArray(arr)) arr = [];
|
|
2251
|
+
if (changes && changes.length > 0) {
|
|
2252
|
+
let aipuPatchable = true;
|
|
2253
|
+
for (let i = 0; i < changes.length; i++) {
|
|
2254
|
+
const change = changes[i];
|
|
2255
|
+
const idx = change.arix;
|
|
2256
|
+
if (!change.aipu || idx < 0 || idx >= __kl_entries.length || (!change.itemDirty && __kl_entries[idx].key !== __kl_key(change.newValue, idx))) {
|
|
2257
|
+
aipuPatchable = false;
|
|
2258
|
+
break;
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
if (aipuPatchable) {
|
|
2262
|
+
for (let i = 0; i < changes.length; i++) {
|
|
2263
|
+
const idx = changes[i].arix;
|
|
2264
|
+
let superseded = false;
|
|
2265
|
+
for (let j = i + 1; j < changes.length; j++) {
|
|
2266
|
+
if (changes[j].arix === idx) {
|
|
2267
|
+
superseded = true;
|
|
2268
|
+
break;
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
if (superseded) continue;
|
|
2272
|
+
const item = changes[i].newValue;
|
|
2273
|
+
__kl_patch(__kl_entries[idx], item, idx);
|
|
2274
|
+
if (item && typeof item === "object") {
|
|
2275
|
+
item[GEA_DIRTY] = false;
|
|
2276
|
+
item[GEA_DIRTY_PROPS]?.clear();
|
|
2277
|
+
}
|
|
2278
|
+
__kl_entries[idx].item = __kl_unwrap(item);
|
|
2279
|
+
if (__kl_prev && __kl_prev.length === __kl_entries.length) __kl_prev[idx] = __kl_unwrap(item);
|
|
2280
|
+
}
|
|
2281
|
+
return;
|
|
2282
|
+
}
|
|
2283
|
+
let dirtyOnly = true;
|
|
2284
|
+
for (let i = 0; i < changes.length; i++) {
|
|
2285
|
+
const change = changes[i];
|
|
2286
|
+
if (change.aipu || change.type === "append" || change.type === "remove" || change.type === "delete" || change.type === "reorder") {
|
|
2287
|
+
dirtyOnly = false;
|
|
2288
|
+
break;
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
if (dirtyOnly) {
|
|
2292
|
+
const raw = arr[GEA_PROXY_RAW] || arr;
|
|
2293
|
+
if (__kl_entries.length === arr.length) {
|
|
2294
|
+
let patched = false;
|
|
2295
|
+
for (let i = 0; i < raw.length; i++) {
|
|
2296
|
+
const item = raw[i];
|
|
2297
|
+
if (item && typeof item === "object" && item[GEA_DIRTY]) {
|
|
2298
|
+
__kl_patch(__kl_entries[i], item, i);
|
|
2299
|
+
item[GEA_DIRTY] = false;
|
|
2300
|
+
item[GEA_DIRTY_PROPS]?.clear();
|
|
2301
|
+
__kl_entries[i].item = item;
|
|
2302
|
+
patched = true;
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
if (patched) return;
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
}
|
|
2309
|
+
const raw = arr[GEA_PROXY_RAW] || arr;
|
|
2167
2310
|
if (arr === __kl_prev && __kl_entries.length === arr.length) {
|
|
2168
2311
|
let structural = false;
|
|
2169
2312
|
let aipuOnly = changes && changes.length > 0;
|
|
@@ -2202,7 +2345,6 @@ const INLINE_PROP_LIST_SOURCE = `{
|
|
|
2202
2345
|
}
|
|
2203
2346
|
}
|
|
2204
2347
|
if (!structural) {
|
|
2205
|
-
const raw = arr[GEA_PROXY_RAW] || arr;
|
|
2206
2348
|
for (let i = 0; i < raw.length; i++) {
|
|
2207
2349
|
const item = raw[i];
|
|
2208
2350
|
if (item && typeof item === "object" && item[GEA_DIRTY]) {
|
|
@@ -2347,7 +2489,14 @@ const INLINE_PROP_LIST_SOURCE = `{
|
|
|
2347
2489
|
if (oldLen > 0 && newLen > 0 && __kl_container.childNodes.length === oldLen + (__kl_anchor ? 1 : 0)) {
|
|
2348
2490
|
let disjoint = true;
|
|
2349
2491
|
for (let i = 0; i < newLen; i++) {
|
|
2350
|
-
|
|
2492
|
+
let existing = null;
|
|
2493
|
+
for (let j = 0; j < oldLen; j++) {
|
|
2494
|
+
if (__kl_entries[j].key === newKeys[i]) {
|
|
2495
|
+
existing = __kl_entries[j];
|
|
2496
|
+
break;
|
|
2497
|
+
}
|
|
2498
|
+
}
|
|
2499
|
+
if (existing) {
|
|
2351
2500
|
disjoint = false;
|
|
2352
2501
|
break;
|
|
2353
2502
|
}
|
|
@@ -2375,7 +2524,13 @@ const INLINE_PROP_LIST_SOURCE = `{
|
|
|
2375
2524
|
const seenOld = new Array(oldLen).fill(false);
|
|
2376
2525
|
const nextEntries = new Array(newLen);
|
|
2377
2526
|
for (let i = 0; i < newLen; i++) {
|
|
2378
|
-
|
|
2527
|
+
let entry = null;
|
|
2528
|
+
for (let j = 0; j < oldLen; j++) {
|
|
2529
|
+
if (__kl_entries[j].key === newKeys[i]) {
|
|
2530
|
+
entry = __kl_entries[j];
|
|
2531
|
+
break;
|
|
2532
|
+
}
|
|
2533
|
+
}
|
|
2379
2534
|
if (entry) {
|
|
2380
2535
|
const oldIdx = entry._i;
|
|
2381
2536
|
seenOld[oldIdx] = true;
|
|
@@ -2404,7 +2559,7 @@ const INLINE_PROP_LIST_SOURCE = `{
|
|
|
2404
2559
|
|
|
2405
2560
|
if (__kl_root && typeof __kl_root.observe === "function") {
|
|
2406
2561
|
const off = __kl_root.observe(__PROP__, (_value, changes) => {
|
|
2407
|
-
__kl_reconcile(
|
|
2562
|
+
__kl_reconcile(_value, changes);
|
|
2408
2563
|
});
|
|
2409
2564
|
d.add(off);
|
|
2410
2565
|
}
|
|
@@ -2429,6 +2584,7 @@ const INLINE_PROP_LIST_COMPACT_ANCHORLESS_BLOCK = parse(`{
|
|
|
2429
2584
|
};
|
|
2430
2585
|
let __kl_prev = __kl_resolve();
|
|
2431
2586
|
let __kl_reconcile = (arr, changes) => {
|
|
2587
|
+
if (!Array.isArray(arr)) arr = [];
|
|
2432
2588
|
if (arr.length === 0) {
|
|
2433
2589
|
__kl_prev = arr;
|
|
2434
2590
|
return;
|
|
@@ -2475,6 +2631,65 @@ const INLINE_PROP_LIST_COMPACT_ANCHORLESS_BLOCK = parse(`{
|
|
|
2475
2631
|
__kl_entries = nextEntries;
|
|
2476
2632
|
};
|
|
2477
2633
|
const __kl_real_reconcile = (arr, changes) => {
|
|
2634
|
+
if (!Array.isArray(arr)) arr = [];
|
|
2635
|
+
if (changes && changes.length > 0) {
|
|
2636
|
+
let aipuPatchable = true;
|
|
2637
|
+
for (let i = 0; i < changes.length; i++) {
|
|
2638
|
+
const change = changes[i];
|
|
2639
|
+
const idx = change.arix;
|
|
2640
|
+
if (!change.aipu || idx < 0 || idx >= __kl_entries.length || (!change.itemDirty && __kl_entries[idx].key !== change.newValue.id)) {
|
|
2641
|
+
aipuPatchable = false;
|
|
2642
|
+
break;
|
|
2643
|
+
}
|
|
2644
|
+
}
|
|
2645
|
+
if (aipuPatchable) {
|
|
2646
|
+
for (let i = 0; i < changes.length; i++) {
|
|
2647
|
+
const idx = changes[i].arix;
|
|
2648
|
+
let superseded = false;
|
|
2649
|
+
for (let j = i + 1; j < changes.length; j++) {
|
|
2650
|
+
if (changes[j].arix === idx) {
|
|
2651
|
+
superseded = true;
|
|
2652
|
+
break;
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
if (superseded) continue;
|
|
2656
|
+
const item = changes[i].newValue;
|
|
2657
|
+
__kl_patch(__kl_entries[idx], item, idx);
|
|
2658
|
+
if (item && typeof item === "object") {
|
|
2659
|
+
item[GEA_DIRTY] = false;
|
|
2660
|
+
item[GEA_DIRTY_PROPS]?.clear();
|
|
2661
|
+
}
|
|
2662
|
+
__kl_entries[idx].item = __kl_raw(item);
|
|
2663
|
+
if (__kl_prev && __kl_prev.length === __kl_entries.length) __kl_prev[idx] = __kl_raw(item);
|
|
2664
|
+
}
|
|
2665
|
+
return;
|
|
2666
|
+
}
|
|
2667
|
+
let dirtyOnly = true;
|
|
2668
|
+
for (let i = 0; i < changes.length; i++) {
|
|
2669
|
+
const change = changes[i];
|
|
2670
|
+
if (change.aipu || change.type === "append" || change.type === "remove" || change.type === "delete" || change.type === "reorder") {
|
|
2671
|
+
dirtyOnly = false;
|
|
2672
|
+
break;
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
if (dirtyOnly) {
|
|
2676
|
+
const raw = __kl_raw(arr);
|
|
2677
|
+
if (__kl_entries.length === arr.length) {
|
|
2678
|
+
let patched = false;
|
|
2679
|
+
for (let i = 0; i < raw.length; i++) {
|
|
2680
|
+
const item = raw[i];
|
|
2681
|
+
if (item && typeof item === "object" && item[GEA_DIRTY]) {
|
|
2682
|
+
__kl_patch(__kl_entries[i], item, i);
|
|
2683
|
+
item[GEA_DIRTY] = false;
|
|
2684
|
+
item[GEA_DIRTY_PROPS]?.clear();
|
|
2685
|
+
__kl_entries[i].item = item;
|
|
2686
|
+
patched = true;
|
|
2687
|
+
}
|
|
2688
|
+
}
|
|
2689
|
+
if (patched) return;
|
|
2690
|
+
}
|
|
2691
|
+
}
|
|
2692
|
+
}
|
|
2478
2693
|
const raw = __kl_raw(arr);
|
|
2479
2694
|
if (arr === __kl_prev && __kl_entries.length === arr.length) {
|
|
2480
2695
|
let structural = false;
|
|
@@ -2577,7 +2792,7 @@ const INLINE_PROP_LIST_COMPACT_ANCHORLESS_BLOCK = parse(`{
|
|
|
2577
2792
|
|
|
2578
2793
|
if (__kl_root && typeof __kl_root.observe === "function") {
|
|
2579
2794
|
const off = __kl_root.observe(__PROP__, (_value, changes) => {
|
|
2580
|
-
__kl_reconcile(
|
|
2795
|
+
__kl_reconcile(_value, changes);
|
|
2581
2796
|
});
|
|
2582
2797
|
d.add(off);
|
|
2583
2798
|
}
|
|
@@ -2625,6 +2840,65 @@ const INLINE_PROP_LIST_COMPONENT_SOURCE = `{
|
|
|
2625
2840
|
}
|
|
2626
2841
|
let __kl_prev = __kl_first;
|
|
2627
2842
|
const __kl_reconcile = (arr, changes) => {
|
|
2843
|
+
if (!Array.isArray(arr)) arr = [];
|
|
2844
|
+
if (changes && changes.length > 0) {
|
|
2845
|
+
let aipuPatchable = true;
|
|
2846
|
+
for (let i = 0; i < changes.length; i++) {
|
|
2847
|
+
const change = changes[i];
|
|
2848
|
+
const idx = change.arix;
|
|
2849
|
+
if (!change.aipu || idx < 0 || idx >= __kl_entries.length || (!change.itemDirty && __kl_entries[idx].key !== __kl_key(change.newValue, idx))) {
|
|
2850
|
+
aipuPatchable = false;
|
|
2851
|
+
break;
|
|
2852
|
+
}
|
|
2853
|
+
}
|
|
2854
|
+
if (aipuPatchable) {
|
|
2855
|
+
for (let i = 0; i < changes.length; i++) {
|
|
2856
|
+
const idx = changes[i].arix;
|
|
2857
|
+
let superseded = false;
|
|
2858
|
+
for (let j = i + 1; j < changes.length; j++) {
|
|
2859
|
+
if (changes[j].arix === idx) {
|
|
2860
|
+
superseded = true;
|
|
2861
|
+
break;
|
|
2862
|
+
}
|
|
2863
|
+
}
|
|
2864
|
+
if (superseded) continue;
|
|
2865
|
+
const item = changes[i].newValue;
|
|
2866
|
+
__kl_patch(__kl_entries[idx], item, idx);
|
|
2867
|
+
if (item && typeof item === "object") {
|
|
2868
|
+
item[GEA_DIRTY] = false;
|
|
2869
|
+
item[GEA_DIRTY_PROPS]?.clear();
|
|
2870
|
+
}
|
|
2871
|
+
__kl_entries[idx].item = __kl_raw(item);
|
|
2872
|
+
if (__kl_prev && __kl_prev.length === __kl_entries.length) __kl_prev[idx] = __kl_raw(item);
|
|
2873
|
+
}
|
|
2874
|
+
return;
|
|
2875
|
+
}
|
|
2876
|
+
let dirtyOnly = true;
|
|
2877
|
+
for (let i = 0; i < changes.length; i++) {
|
|
2878
|
+
const change = changes[i];
|
|
2879
|
+
if (change.aipu || change.type === "append" || change.type === "remove" || change.type === "delete" || change.type === "reorder") {
|
|
2880
|
+
dirtyOnly = false;
|
|
2881
|
+
break;
|
|
2882
|
+
}
|
|
2883
|
+
}
|
|
2884
|
+
if (dirtyOnly) {
|
|
2885
|
+
const raw = __kl_raw(arr);
|
|
2886
|
+
if (__kl_entries.length === arr.length) {
|
|
2887
|
+
let patched = false;
|
|
2888
|
+
for (let i = 0; i < raw.length; i++) {
|
|
2889
|
+
const item = raw[i];
|
|
2890
|
+
if (item && typeof item === "object" && item[GEA_DIRTY]) {
|
|
2891
|
+
__kl_patch(__kl_entries[i], item, i);
|
|
2892
|
+
item[GEA_DIRTY] = false;
|
|
2893
|
+
item[GEA_DIRTY_PROPS]?.clear();
|
|
2894
|
+
__kl_entries[i].item = item;
|
|
2895
|
+
patched = true;
|
|
2896
|
+
}
|
|
2897
|
+
}
|
|
2898
|
+
if (patched) return;
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2901
|
+
}
|
|
2628
2902
|
const raw = __kl_raw(arr);
|
|
2629
2903
|
if (arr === __kl_prev && __kl_entries.length === arr.length) {
|
|
2630
2904
|
let structural = false;
|
|
@@ -2689,7 +2963,7 @@ const INLINE_PROP_LIST_COMPONENT_SOURCE = `{
|
|
|
2689
2963
|
};
|
|
2690
2964
|
if (__kl_root && typeof __kl_root.observe === "function") {
|
|
2691
2965
|
const off = __kl_root.observe(__PROP__, (_value, changes) => {
|
|
2692
|
-
__kl_reconcile(
|
|
2966
|
+
__kl_reconcile(_value, changes);
|
|
2693
2967
|
});
|
|
2694
2968
|
d.add(off);
|
|
2695
2969
|
}
|
|
@@ -2703,11 +2977,11 @@ const INLINE_PROP_LIST_COMPONENT_ANCHORLESS_BLOCK = parse(INLINE_PROP_LIST_COMPO
|
|
|
2703
2977
|
sourceType: "module",
|
|
2704
2978
|
plugins: ["optionalChaining"]
|
|
2705
2979
|
}).program.body[0];
|
|
2706
|
-
const INLINE_PROP_LIST_COMPONENT_ID_BLOCK = parse(INLINE_PROP_LIST_COMPONENT_SOURCE.replace(" const __kl_key = __KEY__;\n", "").replace("__kl_byKey.get(__kl_key(arr[i], i))", "__kl_byKey.get(arr[i].id)"), {
|
|
2980
|
+
const INLINE_PROP_LIST_COMPONENT_ID_BLOCK = parse(INLINE_PROP_LIST_COMPONENT_SOURCE.replace(" const __kl_key = __KEY__;\n", "").replace("__kl_byKey.get(__kl_key(arr[i], i))", "__kl_byKey.get(arr[i].id)").replaceAll("__kl_key(change.newValue, idx)", "change.newValue.id"), {
|
|
2707
2981
|
sourceType: "module",
|
|
2708
2982
|
plugins: ["optionalChaining"]
|
|
2709
2983
|
}).program.body[0];
|
|
2710
|
-
const INLINE_PROP_LIST_COMPONENT_ID_ANCHORLESS_BLOCK = parse(INLINE_PROP_LIST_COMPONENT_ANCHORLESS_SOURCE.replace(" const __kl_key = __KEY__;\n", "").replace("__kl_byKey.get(__kl_key(arr[i], i))", "__kl_byKey.get(arr[i].id)"), {
|
|
2984
|
+
const INLINE_PROP_LIST_COMPONENT_ID_ANCHORLESS_BLOCK = parse(INLINE_PROP_LIST_COMPONENT_ANCHORLESS_SOURCE.replace(" const __kl_key = __KEY__;\n", "").replace("__kl_byKey.get(__kl_key(arr[i], i))", "__kl_byKey.get(arr[i].id)").replaceAll("__kl_key(change.newValue, idx)", "change.newValue.id"), {
|
|
2711
2985
|
sourceType: "module",
|
|
2712
2986
|
plugins: ["optionalChaining"]
|
|
2713
2987
|
}).program.body[0];
|
|
@@ -3405,54 +3679,6 @@ function normalizeEventAttrName(name) {
|
|
|
3405
3679
|
return toGeaEventType(name);
|
|
3406
3680
|
}
|
|
3407
3681
|
//#endregion
|
|
3408
|
-
//#region src/closure-codegen/generator/generator-jsx-helpers.ts
|
|
3409
|
-
/** True for JSX elements, fragments, null, undefined, or string literals (things that can be rendered in a branch). */
|
|
3410
|
-
function isJsxOrNullish(n) {
|
|
3411
|
-
if (t.isJSXElement(n) || t.isJSXFragment(n)) return true;
|
|
3412
|
-
if (t.isNullLiteral(n)) return true;
|
|
3413
|
-
if (t.isIdentifier(n, { name: "undefined" })) return true;
|
|
3414
|
-
return false;
|
|
3415
|
-
}
|
|
3416
|
-
/** True when `n` is `<expr>.map(arrow)` where the arrow's body returns JSX
|
|
3417
|
-
* (directly or via a `return` in a BlockStatement). Used by the `&&` arm
|
|
3418
|
-
* to promote `cond && xs.map(x => <JSX/>)` to a conditional slot whose
|
|
3419
|
-
* truthy branch is a keyed-list. */
|
|
3420
|
-
function isMapWithJsxBody(n) {
|
|
3421
|
-
if (!t.isCallExpression(n) && !t.isOptionalCallExpression(n)) return false;
|
|
3422
|
-
const callee = n.callee;
|
|
3423
|
-
if (!t.isMemberExpression(callee) && !t.isOptionalMemberExpression(callee)) return false;
|
|
3424
|
-
if (callee.computed) return false;
|
|
3425
|
-
if (!t.isIdentifier(callee.property, { name: "map" })) return false;
|
|
3426
|
-
const arg = n.arguments[0];
|
|
3427
|
-
if (!arg) return false;
|
|
3428
|
-
if (!t.isArrowFunctionExpression(arg) && !t.isFunctionExpression(arg)) return false;
|
|
3429
|
-
const body = arg.body;
|
|
3430
|
-
if (t.isJSXElement(body) || t.isJSXFragment(body)) return true;
|
|
3431
|
-
if (t.isBlockStatement(body)) {
|
|
3432
|
-
const ret = body.body.find((s) => t.isReturnStatement(s));
|
|
3433
|
-
if (ret && ret.argument && (t.isJSXElement(ret.argument) || t.isJSXFragment(ret.argument))) return true;
|
|
3434
|
-
}
|
|
3435
|
-
return false;
|
|
3436
|
-
}
|
|
3437
|
-
/**
|
|
3438
|
-
* Check if a class declaration has a `template()` method and return it.
|
|
3439
|
-
* Returns null if the class does not have a template method (non-component).
|
|
3440
|
-
*/
|
|
3441
|
-
function findTemplateMethod(classDecl) {
|
|
3442
|
-
for (const member of classDecl.body.body) if (t.isClassMethod(member) && t.isIdentifier(member.key, { name: "template" }) && !member.computed && !member.static) return member;
|
|
3443
|
-
return null;
|
|
3444
|
-
}
|
|
3445
|
-
/**
|
|
3446
|
-
* Extract the JSX root from a template() method. The method body is expected to
|
|
3447
|
-
* be `template() { return <jsx />; }` — possibly with prop destructuring.
|
|
3448
|
-
*/
|
|
3449
|
-
function extractTemplateJsx(templateMethod) {
|
|
3450
|
-
for (const stmt of templateMethod.body.body) if (t.isReturnStatement(stmt) && stmt.argument) {
|
|
3451
|
-
if (t.isJSXElement(stmt.argument) || t.isJSXFragment(stmt.argument)) return stmt.argument;
|
|
3452
|
-
}
|
|
3453
|
-
return null;
|
|
3454
|
-
}
|
|
3455
|
-
//#endregion
|
|
3456
3682
|
//#region src/closure-codegen/generator/walk.ts
|
|
3457
3683
|
const OPTIONAL_TABLE_END_TAGS = new Set([
|
|
3458
3684
|
"colgroup",
|
|
@@ -3910,13 +4136,31 @@ function emitSlot(slot, stmts, ctx) {
|
|
|
3910
4136
|
pathOrGetter.value
|
|
3911
4137
|
])));
|
|
3912
4138
|
} else if (slot.kind === "style") {
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
4139
|
+
const styleExpr = slot.expr;
|
|
4140
|
+
const styleProps = t.isObjectExpression(styleExpr) && styleExpr.properties.length > 0 ? styleExpr.properties : null;
|
|
4141
|
+
if (styleProps !== null && styleProps.every((p) => t.isObjectProperty(p) && !p.computed && (t.isIdentifier(p.key) || t.isStringLiteral(p.key)))) {
|
|
4142
|
+
ctx.importsNeeded.add("reactiveStyleProp");
|
|
4143
|
+
for (const p of styleProps) {
|
|
4144
|
+
const keyName = t.isIdentifier(p.key) ? p.key.name : p.key.value;
|
|
4145
|
+
const kebabKey = String(keyName).replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
|
|
4146
|
+
const valSource = expressionToPathOrGetter(p.value, ctx);
|
|
4147
|
+
stmts.push(t.expressionStatement(t.callExpression(t.identifier("reactiveStyleProp"), [
|
|
4148
|
+
elId,
|
|
4149
|
+
t.identifier("d"),
|
|
4150
|
+
ctx.reactiveRoot,
|
|
4151
|
+
t.stringLiteral(kebabKey),
|
|
4152
|
+
valSource.value
|
|
4153
|
+
])));
|
|
4154
|
+
}
|
|
4155
|
+
} else {
|
|
4156
|
+
ctx.importsNeeded.add("reactiveStyle");
|
|
4157
|
+
stmts.push(t.expressionStatement(t.callExpression(t.identifier("reactiveStyle"), [
|
|
4158
|
+
elId,
|
|
4159
|
+
t.identifier("d"),
|
|
4160
|
+
ctx.reactiveRoot,
|
|
4161
|
+
pathOrGetter.value
|
|
4162
|
+
])));
|
|
4163
|
+
}
|
|
3920
4164
|
} else if (slot.kind === "value") {
|
|
3921
4165
|
ctx.importsNeeded.add("reactiveValueRead");
|
|
3922
4166
|
stmts.push(t.expressionStatement(t.callExpression(t.identifier("reactiveValueRead"), [
|
|
@@ -4107,37 +4351,742 @@ function isOneShotStringPropLocal(expr, ctx) {
|
|
|
4107
4351
|
return t.isIdentifier(expr) && ctx.oneShotStringPropLocals?.has(expr.name) === true;
|
|
4108
4352
|
}
|
|
4109
4353
|
//#endregion
|
|
4110
|
-
//#region src/closure-codegen/
|
|
4111
|
-
function
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4354
|
+
//#region src/closure-codegen/ir.ts
|
|
4355
|
+
function componentIrId(moduleId, exportName) {
|
|
4356
|
+
return `${moduleId}#${exportName}`;
|
|
4357
|
+
}
|
|
4358
|
+
function storeIrId(moduleId, className) {
|
|
4359
|
+
return `${moduleId}#${className}`;
|
|
4360
|
+
}
|
|
4361
|
+
function templateSpecToIr(spec, bindings = /* @__PURE__ */ new Map()) {
|
|
4362
|
+
return {
|
|
4363
|
+
html: spec.html,
|
|
4364
|
+
slots: spec.slots.map((slot) => slotToIr(slot, bindings))
|
|
4365
|
+
};
|
|
4366
|
+
}
|
|
4367
|
+
function storeFieldsToIr(classDecl) {
|
|
4368
|
+
const fields = [];
|
|
4369
|
+
for (const member of classDecl.body.body) {
|
|
4370
|
+
if (!t.isClassProperty(member) || member.static || member.computed || !t.isIdentifier(member.key)) continue;
|
|
4371
|
+
const field = {
|
|
4372
|
+
name: member.key.name,
|
|
4373
|
+
...member.value ? { initializer: generate(member.value).code } : {},
|
|
4374
|
+
...member.value ? shapeForExpression(member.value) : {}
|
|
4375
|
+
};
|
|
4376
|
+
if (field.shape?.kind === "array") {
|
|
4377
|
+
const elementTypeName = arrayElementTypeNameFromAnnotation(member);
|
|
4378
|
+
if (elementTypeName) field.shape = {
|
|
4379
|
+
...field.shape,
|
|
4380
|
+
elementTypeName
|
|
4381
|
+
};
|
|
4382
|
+
}
|
|
4383
|
+
fields.push(field);
|
|
4121
4384
|
}
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4385
|
+
return fields;
|
|
4386
|
+
}
|
|
4387
|
+
function arrayElementTypeNameFromAnnotation(member) {
|
|
4388
|
+
const annotation = member.typeAnnotation;
|
|
4389
|
+
if (!annotation || !t.isTSTypeAnnotation(annotation)) return void 0;
|
|
4390
|
+
return arrayElementTypeNameFromTSType(annotation.typeAnnotation);
|
|
4391
|
+
}
|
|
4392
|
+
function arrayElementTypeNameFromTSType(typeNode) {
|
|
4393
|
+
if (t.isTSArrayType(typeNode)) {
|
|
4394
|
+
const element = typeNode.elementType;
|
|
4395
|
+
if (t.isTSTypeReference(element) && t.isIdentifier(element.typeName)) return element.typeName.name;
|
|
4396
|
+
return;
|
|
4397
|
+
}
|
|
4398
|
+
if (t.isTSTypeReference(typeNode) && t.isIdentifier(typeNode.typeName)) {
|
|
4399
|
+
const containerName = typeNode.typeName.name;
|
|
4400
|
+
if (containerName !== "Array" && containerName !== "ReadonlyArray") return void 0;
|
|
4401
|
+
const args = typeNode.typeParameters?.params;
|
|
4402
|
+
if (!args || args.length !== 1) return void 0;
|
|
4403
|
+
const element = args[0];
|
|
4404
|
+
if (t.isTSTypeReference(element) && t.isIdentifier(element.typeName)) return element.typeName.name;
|
|
4405
|
+
return;
|
|
4406
|
+
}
|
|
4407
|
+
}
|
|
4408
|
+
const ARRAY_PRODUCING_METHODS = new Set([
|
|
4409
|
+
"filter",
|
|
4410
|
+
"map",
|
|
4411
|
+
"slice",
|
|
4412
|
+
"concat",
|
|
4413
|
+
"flat",
|
|
4414
|
+
"flatMap",
|
|
4415
|
+
"sort",
|
|
4416
|
+
"toSorted",
|
|
4417
|
+
"reverse",
|
|
4418
|
+
"toReversed"
|
|
4419
|
+
]);
|
|
4420
|
+
function storeGettersToIr(classDecl) {
|
|
4421
|
+
const getters = [];
|
|
4422
|
+
const fieldShapeByName = /* @__PURE__ */ new Map();
|
|
4423
|
+
for (const field of storeFieldsToIr(classDecl)) if (field.shape) fieldShapeByName.set(field.name, field.shape);
|
|
4424
|
+
for (const member of classDecl.body.body) {
|
|
4425
|
+
if (!t.isClassMethod(member) || member.static || member.computed || member.kind !== "get") continue;
|
|
4426
|
+
if (!t.isIdentifier(member.key)) continue;
|
|
4427
|
+
const returnType = member.returnType;
|
|
4428
|
+
const elementTypeName = returnType && t.isTSTypeAnnotation(returnType) ? arrayElementTypeNameFromTSType(returnType.typeAnnotation) : void 0;
|
|
4429
|
+
const deps = collectThisFieldReads(member.body);
|
|
4430
|
+
const elementShape = getterElementShape(member.body, deps, elementTypeName, fieldShapeByName);
|
|
4431
|
+
const returnsArray = !!elementTypeName || !!elementShape || getterBodyReturnsArray(member.body);
|
|
4432
|
+
const shape = returnsArray ? {
|
|
4433
|
+
kind: "array",
|
|
4434
|
+
...elementShape ? { element: elementShape } : {},
|
|
4435
|
+
...elementTypeName ? { elementTypeName } : {}
|
|
4436
|
+
} : void 0;
|
|
4437
|
+
const ops = storeStmtsToIr(member.body.body);
|
|
4438
|
+
const getter = {
|
|
4439
|
+
name: member.key.name,
|
|
4440
|
+
returnsArray,
|
|
4441
|
+
deps,
|
|
4442
|
+
body: generate(member.body).code,
|
|
4443
|
+
...elementTypeName ? { elementTypeName } : {},
|
|
4444
|
+
...shape ? { shape } : {},
|
|
4445
|
+
...ops ? { ops } : {},
|
|
4446
|
+
...sourceSpan(member) ? { sourceSpan: sourceSpan(member) } : {}
|
|
4447
|
+
};
|
|
4448
|
+
getters.push(getter);
|
|
4449
|
+
}
|
|
4450
|
+
return getters;
|
|
4451
|
+
}
|
|
4452
|
+
function getterElementShape(body, deps, elementTypeName, fieldShapeByName) {
|
|
4453
|
+
const arg = topLevelReturnArgument(body);
|
|
4454
|
+
const fromBody = arg ? elementShapeFromArrayExpression(arg, fieldShapeByName) : void 0;
|
|
4455
|
+
if (fromBody) return fromBody;
|
|
4456
|
+
if (elementTypeName) {
|
|
4457
|
+
for (const shape of fieldShapeByName.values()) if (shape.kind === "array" && shape.elementTypeName === elementTypeName && shape.element?.kind === "object") return shape.element;
|
|
4458
|
+
}
|
|
4459
|
+
for (const dep of deps) {
|
|
4460
|
+
const shape = fieldShapeByName.get(dep);
|
|
4461
|
+
if (shape?.kind === "array" && shape.element?.kind === "object") return shape.element;
|
|
4462
|
+
}
|
|
4463
|
+
}
|
|
4464
|
+
function elementShapeFromArrayExpression(expr, fieldShapeByName) {
|
|
4465
|
+
if (t.isArrayExpression(expr)) {
|
|
4466
|
+
const first = expr.elements.find((element) => !!element && !t.isSpreadElement(element));
|
|
4467
|
+
if (!first) return void 0;
|
|
4468
|
+
const shaped = shapeForExpression(first);
|
|
4469
|
+
return "shape" in shaped ? shaped.shape : void 0;
|
|
4470
|
+
}
|
|
4471
|
+
if (t.isCallExpression(expr) && t.isMemberExpression(expr.callee) && t.isIdentifier(expr.callee.property)) {
|
|
4472
|
+
const method = expr.callee.property.name;
|
|
4473
|
+
if (method === "map") {
|
|
4474
|
+
const objectLiteral = mapCallbackObjectLiteral(expr.arguments[0]);
|
|
4475
|
+
if (!objectLiteral) return void 0;
|
|
4476
|
+
const shaped = shapeForExpression(objectLiteral);
|
|
4477
|
+
return "shape" in shaped ? shaped.shape : void 0;
|
|
4478
|
+
}
|
|
4479
|
+
if (ARRAY_PRODUCING_METHODS.has(method)) return elementShapeFromArrayExpression(expr.callee.object, fieldShapeByName);
|
|
4480
|
+
}
|
|
4481
|
+
if (t.isMemberExpression(expr) && t.isThisExpression(expr.object) && t.isIdentifier(expr.property)) {
|
|
4482
|
+
const shape = fieldShapeByName.get(expr.property.name);
|
|
4483
|
+
if (shape?.kind === "array") return shape.element;
|
|
4484
|
+
}
|
|
4485
|
+
}
|
|
4486
|
+
function mapCallbackObjectLiteral(callback) {
|
|
4487
|
+
if (!callback || !t.isArrowFunctionExpression(callback) && !t.isFunctionExpression(callback)) return void 0;
|
|
4488
|
+
const body = callback.body;
|
|
4489
|
+
if (t.isObjectExpression(body)) return body;
|
|
4490
|
+
if (t.isBlockStatement(body)) {
|
|
4491
|
+
for (const statement of body.body) if (t.isReturnStatement(statement) && statement.argument && t.isObjectExpression(statement.argument)) return statement.argument;
|
|
4492
|
+
}
|
|
4493
|
+
}
|
|
4494
|
+
function topLevelReturnArgument(body) {
|
|
4495
|
+
let result;
|
|
4496
|
+
let done = false;
|
|
4497
|
+
const visit = (value) => {
|
|
4498
|
+
if (done || !value || typeof value !== "object") return;
|
|
4499
|
+
if (Array.isArray(value)) {
|
|
4500
|
+
for (const item of value) visit(item);
|
|
4501
|
+
return;
|
|
4502
|
+
}
|
|
4503
|
+
const node = value;
|
|
4504
|
+
const type = node.type;
|
|
4505
|
+
if (type === "FunctionExpression" || type === "ArrowFunctionExpression" || type === "FunctionDeclaration") return;
|
|
4506
|
+
if (type === "ReturnStatement") {
|
|
4507
|
+
result = node.argument;
|
|
4508
|
+
done = true;
|
|
4509
|
+
return;
|
|
4510
|
+
}
|
|
4511
|
+
for (const key of Object.keys(node)) {
|
|
4512
|
+
if (key === "loc" || key === "start" || key === "end" || key === "range") continue;
|
|
4513
|
+
visit(node[key]);
|
|
4514
|
+
}
|
|
4515
|
+
};
|
|
4516
|
+
visit(body);
|
|
4517
|
+
return result;
|
|
4518
|
+
}
|
|
4519
|
+
function getterBodyReturnsArray(body) {
|
|
4520
|
+
let found = false;
|
|
4521
|
+
const visit = (value) => {
|
|
4522
|
+
if (found || !value || typeof value !== "object") return;
|
|
4523
|
+
if (Array.isArray(value)) {
|
|
4524
|
+
for (const item of value) visit(item);
|
|
4525
|
+
return;
|
|
4526
|
+
}
|
|
4527
|
+
const node = value;
|
|
4528
|
+
const type = node.type;
|
|
4529
|
+
if (type === "FunctionExpression" || type === "ArrowFunctionExpression" || type === "FunctionDeclaration") return;
|
|
4530
|
+
if (type === "ReturnStatement" && isArrayProducingExpression(node.argument)) {
|
|
4531
|
+
found = true;
|
|
4532
|
+
return;
|
|
4533
|
+
}
|
|
4534
|
+
for (const key of Object.keys(node)) {
|
|
4535
|
+
if (key === "loc" || key === "start" || key === "end" || key === "range") continue;
|
|
4536
|
+
visit(node[key]);
|
|
4537
|
+
}
|
|
4538
|
+
};
|
|
4539
|
+
visit(body);
|
|
4540
|
+
return found;
|
|
4541
|
+
}
|
|
4542
|
+
function isArrayProducingExpression(expr) {
|
|
4543
|
+
if (!expr || typeof expr !== "object") return false;
|
|
4544
|
+
const node = expr;
|
|
4545
|
+
if (node.type === "ArrayExpression") return true;
|
|
4546
|
+
if (node.type === "TSAsExpression" || node.type === "TSNonNullExpression") return isArrayProducingExpression(node.expression);
|
|
4547
|
+
if (node.type === "CallExpression") {
|
|
4548
|
+
const callee = node.callee;
|
|
4549
|
+
const property = callee?.property;
|
|
4550
|
+
if (callee?.type === "MemberExpression" && property?.type === "Identifier") return ARRAY_PRODUCING_METHODS.has(property.name);
|
|
4551
|
+
}
|
|
4552
|
+
return false;
|
|
4553
|
+
}
|
|
4554
|
+
function collectThisFieldReads(node) {
|
|
4555
|
+
const names = /* @__PURE__ */ new Set();
|
|
4556
|
+
const visit = (value) => {
|
|
4557
|
+
if (!value || typeof value !== "object") return;
|
|
4558
|
+
if (Array.isArray(value)) {
|
|
4559
|
+
for (const item of value) visit(item);
|
|
4560
|
+
return;
|
|
4561
|
+
}
|
|
4562
|
+
const rec = value;
|
|
4563
|
+
const object = rec.object;
|
|
4564
|
+
const property = rec.property;
|
|
4565
|
+
if (rec.type === "MemberExpression" && object?.type === "ThisExpression" && rec.computed !== true && property?.type === "Identifier") names.add(property.name);
|
|
4566
|
+
for (const key of Object.keys(rec)) {
|
|
4567
|
+
if (key === "loc" || key === "start" || key === "end" || key === "range") continue;
|
|
4568
|
+
visit(rec[key]);
|
|
4569
|
+
}
|
|
4570
|
+
};
|
|
4571
|
+
visit(node);
|
|
4572
|
+
return [...names];
|
|
4573
|
+
}
|
|
4574
|
+
function storeMethodsToIr(classDecl, moduleAst) {
|
|
4575
|
+
const methods = [];
|
|
4576
|
+
const literalUnionAliases = moduleAst ? collectLiteralUnionAliasValueTypes(moduleAst) : void 0;
|
|
4577
|
+
for (const member of classDecl.body.body) {
|
|
4578
|
+
if (!t.isClassMethod(member) || member.static || member.computed || member.kind !== "method") continue;
|
|
4579
|
+
if (!t.isIdentifier(member.key)) continue;
|
|
4580
|
+
const params = [];
|
|
4581
|
+
let unsupportedParam = false;
|
|
4582
|
+
for (const param of member.params) {
|
|
4583
|
+
const assignment = t.isAssignmentPattern(param) ? param : null;
|
|
4584
|
+
const identifier = t.isIdentifier(param) ? param : assignment && t.isIdentifier(assignment.left) ? assignment.left : null;
|
|
4585
|
+
if (identifier) {
|
|
4586
|
+
const valueType = paramValueType(identifier, literalUnionAliases) ?? (assignment ? paramDefaultValueType(assignment.right) : void 0);
|
|
4587
|
+
params.push(valueType ? {
|
|
4588
|
+
name: identifier.name,
|
|
4589
|
+
valueType
|
|
4590
|
+
} : { name: identifier.name });
|
|
4591
|
+
} else {
|
|
4592
|
+
unsupportedParam = true;
|
|
4593
|
+
break;
|
|
4594
|
+
}
|
|
4595
|
+
}
|
|
4596
|
+
if (unsupportedParam) continue;
|
|
4597
|
+
const ops = storeStmtsToIr(member.body.body);
|
|
4598
|
+
methods.push({
|
|
4599
|
+
name: member.key.name,
|
|
4600
|
+
params,
|
|
4601
|
+
body: generate(member.body).code,
|
|
4602
|
+
...ops ? { ops } : {},
|
|
4603
|
+
...sourceSpan(member) ? { sourceSpan: sourceSpan(member) } : {}
|
|
4604
|
+
});
|
|
4605
|
+
}
|
|
4606
|
+
return methods;
|
|
4607
|
+
}
|
|
4608
|
+
function paramValueType(param, literalUnionAliases) {
|
|
4609
|
+
const annotation = param.typeAnnotation;
|
|
4610
|
+
if (!annotation || !t.isTSTypeAnnotation(annotation)) return void 0;
|
|
4611
|
+
const kind = annotation.typeAnnotation;
|
|
4612
|
+
if (t.isTSStringKeyword(kind)) return "string";
|
|
4613
|
+
if (t.isTSNumberKeyword(kind)) return "number";
|
|
4614
|
+
if (t.isTSBooleanKeyword(kind)) return "boolean";
|
|
4615
|
+
const inlineLiteral = literalUnionValueType(kind);
|
|
4616
|
+
if (inlineLiteral) return inlineLiteral;
|
|
4617
|
+
if (literalUnionAliases && t.isTSTypeReference(kind) && t.isIdentifier(kind.typeName)) return literalUnionAliases.get(kind.typeName.name);
|
|
4618
|
+
}
|
|
4619
|
+
function literalUnionValueType(kind) {
|
|
4620
|
+
if (t.isTSLiteralType(kind)) {
|
|
4621
|
+
if (t.isStringLiteral(kind.literal)) return "string";
|
|
4622
|
+
if (t.isNumericLiteral(kind.literal)) return "number";
|
|
4623
|
+
if (t.isBooleanLiteral(kind.literal)) return "boolean";
|
|
4624
|
+
return;
|
|
4625
|
+
}
|
|
4626
|
+
if (t.isTSUnionType(kind)) {
|
|
4627
|
+
let valueType;
|
|
4628
|
+
for (const member of kind.types) {
|
|
4629
|
+
const memberType = literalUnionValueType(member);
|
|
4630
|
+
if (!memberType || valueType && memberType !== valueType) return void 0;
|
|
4631
|
+
valueType = memberType;
|
|
4632
|
+
}
|
|
4633
|
+
return valueType;
|
|
4634
|
+
}
|
|
4635
|
+
}
|
|
4636
|
+
function collectLiteralUnionAliasValueTypes(ast) {
|
|
4637
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
4638
|
+
for (const node of ast.program.body) {
|
|
4639
|
+
const alias = t.isTSTypeAliasDeclaration(node) ? node : t.isExportNamedDeclaration(node) && t.isTSTypeAliasDeclaration(node.declaration) ? node.declaration : null;
|
|
4640
|
+
if (!alias || !t.isIdentifier(alias.id)) continue;
|
|
4641
|
+
const valueType = literalUnionValueType(alias.typeAnnotation);
|
|
4642
|
+
if (valueType) aliases.set(alias.id.name, valueType);
|
|
4643
|
+
}
|
|
4644
|
+
return aliases;
|
|
4645
|
+
}
|
|
4646
|
+
function paramDefaultValueType(expr) {
|
|
4647
|
+
if (t.isStringLiteral(expr)) return "string";
|
|
4648
|
+
if (t.isNumericLiteral(expr)) return "number";
|
|
4649
|
+
if (t.isBooleanLiteral(expr)) return "boolean";
|
|
4650
|
+
}
|
|
4651
|
+
function storeStmtsToIr(statements) {
|
|
4652
|
+
const out = [];
|
|
4653
|
+
for (const statement of statements) {
|
|
4654
|
+
const converted = storeStmtToIr(statement);
|
|
4655
|
+
if (!converted) return null;
|
|
4656
|
+
out.push(...converted);
|
|
4657
|
+
}
|
|
4658
|
+
return out;
|
|
4659
|
+
}
|
|
4660
|
+
function storeStmtToIr(statement) {
|
|
4661
|
+
if (t.isBlockStatement(statement)) return storeStmtsToIr(statement.body);
|
|
4662
|
+
if (t.isVariableDeclaration(statement)) {
|
|
4663
|
+
const declarations = [];
|
|
4664
|
+
for (const declaration of statement.declarations) {
|
|
4665
|
+
if (!t.isIdentifier(declaration.id)) return null;
|
|
4666
|
+
const init = declaration.init ? storeExprToIr(declaration.init) : void 0;
|
|
4667
|
+
if (declaration.init && !init) return null;
|
|
4668
|
+
declarations.push({
|
|
4669
|
+
kind: "var",
|
|
4670
|
+
name: declaration.id.name,
|
|
4671
|
+
mutable: statement.kind !== "const",
|
|
4672
|
+
...init ? { init } : {}
|
|
4673
|
+
});
|
|
4674
|
+
}
|
|
4675
|
+
return declarations;
|
|
4676
|
+
}
|
|
4677
|
+
if (t.isExpressionStatement(statement)) {
|
|
4678
|
+
const expr = statement.expression;
|
|
4679
|
+
if (t.isAssignmentExpression(expr) && expr.operator === "=") {
|
|
4680
|
+
const target = storeExprToIr(expr.left);
|
|
4681
|
+
const value = storeExprToIr(expr.right);
|
|
4682
|
+
return target && value ? [{
|
|
4683
|
+
kind: "assign",
|
|
4684
|
+
target,
|
|
4685
|
+
value
|
|
4686
|
+
}] : null;
|
|
4687
|
+
}
|
|
4688
|
+
const converted = storeExprToIr(expr);
|
|
4689
|
+
return converted ? [{
|
|
4690
|
+
kind: "expr",
|
|
4691
|
+
expr: converted
|
|
4692
|
+
}] : null;
|
|
4693
|
+
}
|
|
4694
|
+
if (t.isIfStatement(statement)) {
|
|
4695
|
+
const test = storeExprToIr(statement.test);
|
|
4696
|
+
const consequent = storeStatementList(statement.consequent);
|
|
4697
|
+
const alternate = statement.alternate ? storeStatementList(statement.alternate) : void 0;
|
|
4698
|
+
if (!test || !consequent || statement.alternate && !alternate) return null;
|
|
4699
|
+
return [{
|
|
4700
|
+
kind: "if",
|
|
4701
|
+
test,
|
|
4702
|
+
consequent,
|
|
4703
|
+
...alternate ? { alternate } : {}
|
|
4704
|
+
}];
|
|
4705
|
+
}
|
|
4706
|
+
if (t.isForStatement(statement)) {
|
|
4707
|
+
const init = statement.init ? storeStmtToIr(t.isVariableDeclaration(statement.init) ? statement.init : t.expressionStatement(statement.init)) : void 0;
|
|
4708
|
+
const test = statement.test ? storeExprToIr(statement.test) : void 0;
|
|
4709
|
+
const update = statement.update ? storeExprToIr(statement.update) : void 0;
|
|
4710
|
+
const body = storeStatementList(statement.body);
|
|
4711
|
+
if (statement.init && (!init || init.length !== 1) || statement.test && !test || statement.update && !update || !body) return null;
|
|
4712
|
+
return [{
|
|
4713
|
+
kind: "for",
|
|
4714
|
+
...init ? { init: init[0] } : {},
|
|
4715
|
+
...test ? { test } : {},
|
|
4716
|
+
...update ? { update } : {},
|
|
4717
|
+
body
|
|
4718
|
+
}];
|
|
4719
|
+
}
|
|
4720
|
+
if (t.isReturnStatement(statement)) {
|
|
4721
|
+
const value = statement.argument ? storeExprToIr(statement.argument) : void 0;
|
|
4722
|
+
if (statement.argument && !value) return null;
|
|
4723
|
+
return [{
|
|
4724
|
+
kind: "return",
|
|
4725
|
+
...value ? { value } : {}
|
|
4726
|
+
}];
|
|
4727
|
+
}
|
|
4728
|
+
return null;
|
|
4729
|
+
}
|
|
4730
|
+
function storeStatementList(statement) {
|
|
4731
|
+
if (t.isBlockStatement(statement)) return storeStmtsToIr(statement.body);
|
|
4732
|
+
return storeStmtToIr(statement);
|
|
4733
|
+
}
|
|
4734
|
+
function storeExprToIr(expression) {
|
|
4735
|
+
if (t.isIdentifier(expression)) return {
|
|
4736
|
+
kind: "identifier",
|
|
4737
|
+
name: expression.name
|
|
4738
|
+
};
|
|
4739
|
+
if (t.isThisExpression(expression)) return { kind: "this" };
|
|
4740
|
+
if (t.isNumericLiteral(expression)) return {
|
|
4741
|
+
kind: "number",
|
|
4742
|
+
value: expression.value
|
|
4743
|
+
};
|
|
4744
|
+
if (t.isStringLiteral(expression)) return {
|
|
4745
|
+
kind: "string",
|
|
4746
|
+
value: expression.value
|
|
4747
|
+
};
|
|
4748
|
+
if (t.isBooleanLiteral(expression)) return {
|
|
4749
|
+
kind: "boolean",
|
|
4750
|
+
value: expression.value
|
|
4751
|
+
};
|
|
4752
|
+
if (t.isNullLiteral(expression)) return { kind: "null" };
|
|
4753
|
+
if (t.isMemberExpression(expression)) {
|
|
4754
|
+
const object = storeExprToIr(expression.object);
|
|
4755
|
+
if (!object) return null;
|
|
4756
|
+
if (expression.computed) {
|
|
4757
|
+
const index = storeExprToIr(expression.property);
|
|
4758
|
+
return index ? {
|
|
4759
|
+
kind: "index",
|
|
4760
|
+
object,
|
|
4761
|
+
index
|
|
4762
|
+
} : null;
|
|
4763
|
+
}
|
|
4764
|
+
return t.isIdentifier(expression.property) ? {
|
|
4765
|
+
kind: "member",
|
|
4766
|
+
object,
|
|
4767
|
+
property: expression.property.name
|
|
4768
|
+
} : null;
|
|
4769
|
+
}
|
|
4770
|
+
if (t.isCallExpression(expression)) {
|
|
4771
|
+
const callee = storeExprToIr(expression.callee);
|
|
4772
|
+
const args = expression.arguments.map((arg) => t.isSpreadElement(arg) ? null : storeExprToIr(arg));
|
|
4773
|
+
return callee && args.every((arg) => !!arg) ? {
|
|
4774
|
+
kind: "call",
|
|
4775
|
+
callee,
|
|
4776
|
+
args
|
|
4777
|
+
} : null;
|
|
4778
|
+
}
|
|
4779
|
+
if (t.isObjectExpression(expression)) {
|
|
4780
|
+
const fields = [];
|
|
4781
|
+
for (const property of expression.properties) {
|
|
4782
|
+
if (!t.isObjectProperty(property) || property.computed) return null;
|
|
4783
|
+
const name = objectPropertyName(property.key);
|
|
4784
|
+
const value = storeExprToIr(property.value);
|
|
4785
|
+
if (!name || !value) return null;
|
|
4786
|
+
fields.push({
|
|
4787
|
+
name,
|
|
4788
|
+
value
|
|
4789
|
+
});
|
|
4790
|
+
}
|
|
4791
|
+
return {
|
|
4792
|
+
kind: "object",
|
|
4793
|
+
fields
|
|
4794
|
+
};
|
|
4795
|
+
}
|
|
4796
|
+
if (t.isUnaryExpression(expression)) {
|
|
4797
|
+
const arg = storeExprToIr(expression.argument);
|
|
4798
|
+
return arg ? {
|
|
4799
|
+
kind: "unary",
|
|
4800
|
+
op: expression.operator,
|
|
4801
|
+
arg
|
|
4802
|
+
} : null;
|
|
4803
|
+
}
|
|
4804
|
+
if (t.isBinaryExpression(expression)) {
|
|
4805
|
+
const left = storeExprToIr(expression.left);
|
|
4806
|
+
const right = storeExprToIr(expression.right);
|
|
4807
|
+
return left && right ? {
|
|
4808
|
+
kind: "binary",
|
|
4809
|
+
op: expression.operator,
|
|
4810
|
+
left,
|
|
4811
|
+
right
|
|
4812
|
+
} : null;
|
|
4813
|
+
}
|
|
4814
|
+
if (t.isLogicalExpression(expression)) {
|
|
4815
|
+
const left = storeExprToIr(expression.left);
|
|
4816
|
+
const right = storeExprToIr(expression.right);
|
|
4817
|
+
return left && right ? {
|
|
4818
|
+
kind: "logical",
|
|
4819
|
+
op: expression.operator,
|
|
4820
|
+
left,
|
|
4821
|
+
right
|
|
4822
|
+
} : null;
|
|
4823
|
+
}
|
|
4824
|
+
if (t.isUpdateExpression(expression)) {
|
|
4825
|
+
const arg = storeExprToIr(expression.argument);
|
|
4826
|
+
return arg ? {
|
|
4827
|
+
kind: "update",
|
|
4828
|
+
op: expression.operator,
|
|
4829
|
+
arg,
|
|
4830
|
+
prefix: expression.prefix
|
|
4831
|
+
} : null;
|
|
4832
|
+
}
|
|
4833
|
+
return null;
|
|
4834
|
+
}
|
|
4835
|
+
function sourceSpan(node) {
|
|
4836
|
+
const span = {};
|
|
4837
|
+
if (typeof node.start === "number") span.start = node.start;
|
|
4838
|
+
if (typeof node.end === "number") span.end = node.end;
|
|
4839
|
+
return span.start === void 0 && span.end === void 0 ? void 0 : span;
|
|
4840
|
+
}
|
|
4841
|
+
function slotToIr(slot, bindings) {
|
|
4842
|
+
const expr = slot.expr ? substituteBindings(slot.expr, bindings) : null;
|
|
4843
|
+
return {
|
|
4844
|
+
index: slot.index,
|
|
4845
|
+
kind: slot.kind,
|
|
4846
|
+
walk: slot.walk,
|
|
4847
|
+
...slot.walkKinds ? { walkKinds: slot.walkKinds } : {},
|
|
4848
|
+
...expr ? { expr: generate(expr).code } : {},
|
|
4849
|
+
...expr ? expressionPathToIr(expr) : {},
|
|
4850
|
+
...expr ? expressionObjectFieldsToIr(expr) : {},
|
|
4851
|
+
...slot.payload ? { payload: slotPayloadToIr(slot, bindings) } : {},
|
|
4852
|
+
...slot.directText ? { directText: true } : {}
|
|
4853
|
+
};
|
|
4854
|
+
}
|
|
4855
|
+
function expressionPathToIr(expr) {
|
|
4856
|
+
const path = expressionPath(expr);
|
|
4857
|
+
return path && path.length > 0 ? { exprPath: path } : {};
|
|
4858
|
+
}
|
|
4859
|
+
function expressionPath(expr) {
|
|
4860
|
+
if (t.isIdentifier(expr)) return [expr.name];
|
|
4861
|
+
if (t.isThisExpression(expr)) return ["this"];
|
|
4862
|
+
if (t.isMemberExpression(expr) && !expr.computed) {
|
|
4863
|
+
const objectPath = expressionPath(expr.object);
|
|
4864
|
+
const property = t.isIdentifier(expr.property) ? expr.property.name : null;
|
|
4865
|
+
return objectPath && property ? [...objectPath, property] : null;
|
|
4866
|
+
}
|
|
4867
|
+
if (t.isOptionalMemberExpression(expr) && !expr.computed) {
|
|
4868
|
+
const objectPath = expressionPath(expr.object);
|
|
4869
|
+
const property = t.isIdentifier(expr.property) ? expr.property.name : null;
|
|
4870
|
+
return objectPath && property ? [...objectPath, property] : null;
|
|
4871
|
+
}
|
|
4872
|
+
return null;
|
|
4873
|
+
}
|
|
4874
|
+
function expressionObjectFieldsToIr(expr) {
|
|
4875
|
+
if (!t.isObjectExpression(expr)) return {};
|
|
4876
|
+
const fields = [];
|
|
4877
|
+
for (const property of expr.properties) {
|
|
4878
|
+
if (!t.isObjectProperty(property) || property.computed) continue;
|
|
4879
|
+
const name = objectPropertyName(property.key);
|
|
4880
|
+
if (!name) continue;
|
|
4881
|
+
fields.push({
|
|
4882
|
+
name,
|
|
4883
|
+
expr: generate(property.value).code,
|
|
4884
|
+
...expressionPathToIr(property.value)
|
|
4885
|
+
});
|
|
4886
|
+
}
|
|
4887
|
+
return fields.length > 0 ? { exprObjectFields: fields } : {};
|
|
4888
|
+
}
|
|
4889
|
+
function slotPayloadToIr(slot, bindings) {
|
|
4890
|
+
const payload = serializePayload(slot.payload, bindings);
|
|
4891
|
+
if (!isRecord(payload)) return payload;
|
|
4892
|
+
if (slot.kind === "keyed-list") {
|
|
4893
|
+
const cb = slot.payload?.mapCallback;
|
|
4894
|
+
const row = keyedListRowIr(cb);
|
|
4895
|
+
return row ? {
|
|
4896
|
+
...payload,
|
|
4897
|
+
...row
|
|
4898
|
+
} : payload;
|
|
4899
|
+
}
|
|
4900
|
+
if (slot.kind === "conditional") {
|
|
4901
|
+
const result = { ...payload };
|
|
4902
|
+
const consequent = jsxNodeToTemplateIr(slot.payload?.mkTrue, bindings);
|
|
4903
|
+
if (consequent) result.consequentTemplate = consequent;
|
|
4904
|
+
const alternate = jsxNodeToTemplateIr(slot.payload?.mkFalse, bindings);
|
|
4905
|
+
if (alternate) result.alternateTemplate = alternate;
|
|
4906
|
+
return result;
|
|
4907
|
+
}
|
|
4908
|
+
if (slot.kind === "mount") {
|
|
4909
|
+
const children = slot.payload?.children;
|
|
4910
|
+
const childrenTemplate = jsxChildrenToTemplateIr(children, bindings);
|
|
4911
|
+
if (childrenTemplate) return {
|
|
4912
|
+
...payload,
|
|
4913
|
+
childrenTemplate
|
|
4914
|
+
};
|
|
4915
|
+
}
|
|
4916
|
+
return payload;
|
|
4917
|
+
}
|
|
4918
|
+
function jsxNodeToTemplateIr(node, bindings) {
|
|
4919
|
+
if (!node) return null;
|
|
4920
|
+
if (t.isJSXElement(node) || t.isJSXFragment(node)) return templateSpecToIr(walkJsxToTemplate(node), bindings);
|
|
4921
|
+
if (t.isJSXExpressionContainer(node)) {
|
|
4922
|
+
const inner = node.expression;
|
|
4923
|
+
if (t.isJSXElement(inner) || t.isJSXFragment(inner)) return templateSpecToIr(walkJsxToTemplate(inner), bindings);
|
|
4924
|
+
if (isWalkableConditionalExpression(inner)) return wrapAsFragmentTemplate(inner, bindings);
|
|
4925
|
+
}
|
|
4926
|
+
if (isWalkableConditionalExpression(node)) return wrapAsFragmentTemplate(node, bindings);
|
|
4927
|
+
return null;
|
|
4928
|
+
}
|
|
4929
|
+
function isWalkableConditionalExpression(node) {
|
|
4930
|
+
if (t.isConditionalExpression(node)) return isJsxOrNullish(node.consequent) || isJsxOrNullish(node.alternate);
|
|
4931
|
+
if (t.isLogicalExpression(node) && node.operator === "&&") return isJsxOrNullish(node.right);
|
|
4932
|
+
return false;
|
|
4933
|
+
}
|
|
4934
|
+
function wrapAsFragmentTemplate(expression, bindings) {
|
|
4935
|
+
return templateSpecToIr(walkJsxToTemplate(t.jsxFragment(t.jsxOpeningFragment(), t.jsxClosingFragment(), [t.jsxExpressionContainer(expression)])), bindings);
|
|
4936
|
+
}
|
|
4937
|
+
function jsxChildrenToTemplateIr(children, bindings) {
|
|
4938
|
+
if (!Array.isArray(children) || children.length === 0) return null;
|
|
4939
|
+
if (!children.some((c) => t.isJSXElement(c) || t.isJSXFragment(c) || t.isJSXExpressionContainer(c) && !t.isJSXEmptyExpression(c.expression))) return null;
|
|
4940
|
+
return templateSpecToIr(walkJsxToTemplate(t.jsxFragment(t.jsxOpeningFragment(), t.jsxClosingFragment(), children)), bindings);
|
|
4941
|
+
}
|
|
4942
|
+
function keyedListRowIr(cb) {
|
|
4943
|
+
if (!t.isArrowFunctionExpression(cb) && !t.isFunctionExpression(cb)) return null;
|
|
4944
|
+
const body = callbackJsxBody(cb.body);
|
|
4945
|
+
if (!body) return null;
|
|
4946
|
+
const itemParam = callbackParamName(cb.params[0]);
|
|
4947
|
+
const indexParam = callbackParamName(cb.params[1]);
|
|
4948
|
+
return {
|
|
4949
|
+
...itemParam ? { itemParam } : {},
|
|
4950
|
+
...indexParam ? { indexParam } : {},
|
|
4951
|
+
rowTemplate: templateSpecToIr(walkJsxToTemplate(body))
|
|
4952
|
+
};
|
|
4953
|
+
}
|
|
4954
|
+
function callbackJsxBody(body) {
|
|
4955
|
+
if (t.isJSXElement(body) || t.isJSXFragment(body)) return body;
|
|
4956
|
+
if (!t.isBlockStatement(body)) return null;
|
|
4957
|
+
for (const statement of body.body) {
|
|
4958
|
+
if (!t.isReturnStatement(statement) || !statement.argument) continue;
|
|
4959
|
+
if (t.isJSXElement(statement.argument) || t.isJSXFragment(statement.argument)) return statement.argument;
|
|
4960
|
+
}
|
|
4961
|
+
return null;
|
|
4962
|
+
}
|
|
4963
|
+
function callbackParamName(param) {
|
|
4964
|
+
return t.isIdentifier(param) ? param.name : void 0;
|
|
4965
|
+
}
|
|
4966
|
+
function serializePayload(value, bindings) {
|
|
4967
|
+
if (value === null || value === void 0) return value;
|
|
4968
|
+
if (typeof value !== "object") return value;
|
|
4969
|
+
if (Array.isArray(value)) return value.map((child) => serializePayload(child, bindings));
|
|
4970
|
+
if (isBabelNode(value)) {
|
|
4971
|
+
const node = substitutePayloadNode(value, bindings);
|
|
4972
|
+
return {
|
|
4973
|
+
nodeType: node.type,
|
|
4974
|
+
code: generate(node).code
|
|
4975
|
+
};
|
|
4976
|
+
}
|
|
4977
|
+
const out = {};
|
|
4978
|
+
for (const [key, child] of Object.entries(value)) out[key] = serializePayload(child, bindings);
|
|
4979
|
+
return out;
|
|
4980
|
+
}
|
|
4981
|
+
function substitutePayloadNode(value, bindings) {
|
|
4982
|
+
if (bindings.size === 0) return value;
|
|
4983
|
+
if (t.isJSXAttribute(value) && value.value && t.isJSXExpressionContainer(value.value) && !t.isJSXEmptyExpression(value.value.expression)) return {
|
|
4984
|
+
...value,
|
|
4985
|
+
value: {
|
|
4986
|
+
...value.value,
|
|
4987
|
+
expression: substituteBindings(value.value.expression, bindings)
|
|
4988
|
+
}
|
|
4989
|
+
};
|
|
4990
|
+
if (t.isJSXExpressionContainer(value) && !t.isJSXEmptyExpression(value.expression)) return {
|
|
4991
|
+
...value,
|
|
4992
|
+
expression: substituteBindings(value.expression, bindings)
|
|
4993
|
+
};
|
|
4994
|
+
return substituteBindings(value, bindings);
|
|
4995
|
+
}
|
|
4996
|
+
function isBabelNode(value) {
|
|
4997
|
+
return !!value && typeof value === "object" && typeof value.type === "string";
|
|
4998
|
+
}
|
|
4999
|
+
function isRecord(value) {
|
|
5000
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
5001
|
+
}
|
|
5002
|
+
function shapeForExpression(value) {
|
|
5003
|
+
if (t.isStringLiteral(value)) return { shape: {
|
|
5004
|
+
kind: "literal",
|
|
5005
|
+
valueType: "string"
|
|
5006
|
+
} };
|
|
5007
|
+
if (t.isNumericLiteral(value)) return { shape: {
|
|
5008
|
+
kind: "literal",
|
|
5009
|
+
valueType: "number"
|
|
5010
|
+
} };
|
|
5011
|
+
if (t.isBooleanLiteral(value)) return { shape: {
|
|
5012
|
+
kind: "literal",
|
|
5013
|
+
valueType: "boolean"
|
|
5014
|
+
} };
|
|
5015
|
+
if (t.isNullLiteral(value)) return { shape: {
|
|
5016
|
+
kind: "literal",
|
|
5017
|
+
valueType: "null"
|
|
5018
|
+
} };
|
|
5019
|
+
if (t.isArrayExpression(value)) {
|
|
5020
|
+
const firstElement = value.elements.find((element) => !!element && !t.isSpreadElement(element));
|
|
5021
|
+
const shapedElement = firstElement ? shapeForExpression(firstElement) : {};
|
|
5022
|
+
const elementShape = "shape" in shapedElement ? shapedElement.shape : void 0;
|
|
5023
|
+
return { shape: {
|
|
5024
|
+
kind: "array",
|
|
5025
|
+
...elementShape ? { element: elementShape } : {}
|
|
5026
|
+
} };
|
|
5027
|
+
}
|
|
5028
|
+
if (t.isObjectExpression(value)) {
|
|
5029
|
+
const fields = [];
|
|
5030
|
+
for (const property of value.properties) {
|
|
5031
|
+
if (!t.isObjectProperty(property) || property.computed) continue;
|
|
5032
|
+
const name = objectPropertyName(property.key);
|
|
5033
|
+
if (!name) continue;
|
|
5034
|
+
fields.push({
|
|
5035
|
+
name,
|
|
5036
|
+
...property.value ? { initializer: generate(property.value).code } : {},
|
|
5037
|
+
...property.value ? shapeForExpression(property.value) : {}
|
|
5038
|
+
});
|
|
5039
|
+
}
|
|
5040
|
+
return { shape: {
|
|
5041
|
+
kind: "object",
|
|
5042
|
+
fields
|
|
5043
|
+
} };
|
|
5044
|
+
}
|
|
5045
|
+
return {};
|
|
5046
|
+
}
|
|
5047
|
+
function objectPropertyName(key) {
|
|
5048
|
+
if (t.isIdentifier(key)) return key.name;
|
|
5049
|
+
if (t.isStringLiteral(key)) return key.value;
|
|
5050
|
+
if (t.isNumericLiteral(key)) return String(key.value);
|
|
5051
|
+
return null;
|
|
5052
|
+
}
|
|
5053
|
+
//#endregion
|
|
5054
|
+
//#region src/closure-codegen/emit/emit-core.ts
|
|
5055
|
+
function compileJsxToBlock(jsxRoot, ctx) {
|
|
5056
|
+
const spec = walkJsxToTemplate(jsxRoot, {
|
|
5057
|
+
emitEventDataAttr: false,
|
|
5058
|
+
directFnComponents: ctx.directFnComponents,
|
|
5059
|
+
bindings: ctx.bindings
|
|
5060
|
+
});
|
|
5061
|
+
if (t.isJSXFragment(jsxRoot)) spec.html = "<span style=\"display:contents\">" + spec.html + "</span>";
|
|
5062
|
+
else if (!spec.html.startsWith("<") || spec.html.startsWith("<!--")) {
|
|
5063
|
+
spec.html = "<span style=\"display:contents\">" + spec.html + "</span>";
|
|
5064
|
+
for (const slot of spec.slots) slot.walk = [0, ...slot.walk];
|
|
5065
|
+
}
|
|
5066
|
+
if (ctx.irTemplates && ctx.currentIrComponent && ctx.currentIrRuntimeBase) ctx.irTemplates.push({
|
|
5067
|
+
component: ctx.currentIrComponent,
|
|
5068
|
+
runtimeBase: ctx.currentIrRuntimeBase,
|
|
5069
|
+
template: templateSpecToIr(spec, ctx.bindings)
|
|
5070
|
+
});
|
|
5071
|
+
const tplName = "_tpl" + ctx.tplCounter++;
|
|
5072
|
+
ctx.templateDecls.push(...emitTemplateDecl(spec.html, tplName));
|
|
5073
|
+
const stmts = [];
|
|
5074
|
+
stmts.push(t.variableDeclaration("const", [t.variableDeclarator(t.identifier("root"), emitTemplateCloneExpression(tplName, spec.html))]));
|
|
5075
|
+
const walkCache = /* @__PURE__ */ new Map();
|
|
5076
|
+
for (const slot of spec.slots) emitWalkCapture(slot, stmts, false, walkCache);
|
|
5077
|
+
const savedPending = ctx._pendingEvents;
|
|
5078
|
+
const savedInputValueExprByEventSlot = ctx._inputValueExprByEventSlot;
|
|
5079
|
+
const savedDocumentClickDelegateInstalled = ctx._documentClickDelegateInstalled;
|
|
5080
|
+
ctx._pendingEvents = [];
|
|
5081
|
+
ctx._inputValueExprByEventSlot = findInputValueReconciliations(spec);
|
|
5082
|
+
ctx._documentClickDelegateInstalled = false;
|
|
5083
|
+
for (const slot of spec.slots) emitSlot(slot, stmts, ctx);
|
|
5084
|
+
const events = ctx._pendingEvents;
|
|
5085
|
+
ctx._pendingEvents = savedPending;
|
|
5086
|
+
ctx._inputValueExprByEventSlot = savedInputValueExprByEventSlot;
|
|
5087
|
+
if (events.length > 0) {
|
|
5088
|
+
const groups = /* @__PURE__ */ new Map();
|
|
5089
|
+
for (const e of events) {
|
|
4141
5090
|
const arr = groups.get(e.eventType);
|
|
4142
5091
|
if (arr) arr.push(e);
|
|
4143
5092
|
else groups.set(e.eventType, [e]);
|
|
@@ -4431,6 +5380,11 @@ function rewriteFnComponent(fnDecl, parentCtx) {
|
|
|
4431
5380
|
fnCtx.directFnComponentParams = parentCtx.directFnComponentParams;
|
|
4432
5381
|
fnCtx.directFnStringProps = parentCtx.directFnStringProps;
|
|
4433
5382
|
fnCtx.directFnNoDisposer = parentCtx.directFnNoDisposer;
|
|
5383
|
+
if (parentCtx.irTemplates && fnName) {
|
|
5384
|
+
fnCtx.irTemplates = parentCtx.irTemplates;
|
|
5385
|
+
fnCtx.currentIrComponent = fnName;
|
|
5386
|
+
fnCtx.currentIrRuntimeBase = "reactive";
|
|
5387
|
+
}
|
|
4434
5388
|
if (fnCtx.oneShotProps) {
|
|
4435
5389
|
fnCtx._inKeyedListRow = true;
|
|
4436
5390
|
fnCtx._rowEventTypes = /* @__PURE__ */ new Set();
|
|
@@ -4856,6 +5810,7 @@ function transformFile(source, _filename, options = {}) {
|
|
|
4856
5810
|
};
|
|
4857
5811
|
}
|
|
4858
5812
|
const ctx = createEmitContext();
|
|
5813
|
+
ctx.irTemplates = [];
|
|
4859
5814
|
ctx.directFnComponents = collectDirectFnComponents(ast);
|
|
4860
5815
|
ctx.directFnComponentParams = collectDirectFnComponentParams(ast, ctx.directFnComponents);
|
|
4861
5816
|
ctx.directFnStringProps = collectDirectFnStringProps(ast, ctx.directFnComponents);
|
|
@@ -4864,6 +5819,7 @@ function transformFile(source, _filename, options = {}) {
|
|
|
4864
5819
|
for (const name of options.directClassComponents ?? []) ctx.directClassComponents.add(name);
|
|
4865
5820
|
ctx.directFactoryComponents = new Set(options.directFactoryComponents);
|
|
4866
5821
|
const rewritten = [];
|
|
5822
|
+
const reactiveComponentNames = /* @__PURE__ */ new Set();
|
|
4867
5823
|
let firstClassIdx = -1;
|
|
4868
5824
|
for (let i = 0; i < ast.program.body.length; i++) {
|
|
4869
5825
|
const node = ast.program.body[i];
|
|
@@ -4899,9 +5855,21 @@ function transformFile(source, _filename, options = {}) {
|
|
|
4899
5855
|
const useTinyReactiveComponent = options.enableTinyReactiveComponents !== false && !useStaticCompiledComponent && !useCompiledComponent && canUseTinyReactiveComponent(classDecl);
|
|
4900
5856
|
const useLeanReactiveComponent = !useStaticCompiledComponent && !useCompiledComponent && !useTinyReactiveComponent && canUseLeanReactiveComponent(classDecl);
|
|
4901
5857
|
const hasAfterRenderAsyncHook = hasOwnInstanceMethod(classDecl, "onAfterRenderAsync");
|
|
5858
|
+
const className = classDecl.id && classDecl.id.name || "<anonymous>";
|
|
5859
|
+
if (t.isIdentifier(classDecl.superClass, { name: "ReactiveComponent" })) reactiveComponentNames.add(className);
|
|
5860
|
+
const runtimeBase = runtimeBaseForComponent({
|
|
5861
|
+
useStaticCompiledComponent,
|
|
5862
|
+
useCompiledComponent,
|
|
5863
|
+
useTinyReactiveComponent,
|
|
5864
|
+
useLeanReactiveComponent
|
|
5865
|
+
});
|
|
5866
|
+
ctx.currentIrComponent = className;
|
|
5867
|
+
ctx.currentIrRuntimeBase = runtimeBase;
|
|
4902
5868
|
for (const m of methodsWithJsx) m.body.body = m.body.body.map((s) => lowerJsxInStatement(s, ctx));
|
|
4903
5869
|
if (!templateMethod) {
|
|
4904
|
-
rewritten.push(
|
|
5870
|
+
rewritten.push(className);
|
|
5871
|
+
ctx.currentIrComponent = void 0;
|
|
5872
|
+
ctx.currentIrRuntimeBase = void 0;
|
|
4905
5873
|
continue;
|
|
4906
5874
|
}
|
|
4907
5875
|
const paramBindings = [];
|
|
@@ -4921,14 +5889,26 @@ function transformFile(source, _filename, options = {}) {
|
|
|
4921
5889
|
ctx.importsNeeded.add(templateSymbol);
|
|
4922
5890
|
const method = buildCreateTemplateMethod(jsx, ctx, preceding, templateSymbol);
|
|
4923
5891
|
const useStaticElementComponent = useStaticCompiledComponent && isStaticBuiltinElementRoot(jsx) && !nodeContainsIdentifier$1(method.body, "d");
|
|
5892
|
+
if (useStaticElementComponent && ctx.irTemplates) {
|
|
5893
|
+
for (const template of ctx.irTemplates) if (template.component === className) template.runtimeBase = "static-element";
|
|
5894
|
+
}
|
|
4924
5895
|
if (useStaticElementComponent) method.params = [];
|
|
4925
5896
|
if (plainPropsParamName) ctx.bindings.delete(plainPropsParamName);
|
|
4926
5897
|
for (const k of paramBindings) ctx.bindings.delete(k);
|
|
5898
|
+
const isReactiveComponent = reactiveComponentNames.has(className);
|
|
4927
5899
|
const bodyItems = classDecl.body.body;
|
|
4928
5900
|
const templateIdx = bodyItems.indexOf(templateMethod);
|
|
4929
|
-
if (templateIdx >= 0)
|
|
5901
|
+
if (templateIdx >= 0) if (isReactiveComponent) {
|
|
5902
|
+
bodyItems.splice(templateIdx, 1);
|
|
5903
|
+
const keepAlive = mountedComponentKeepAliveStatements(jsx, ast);
|
|
5904
|
+
if (keepAlive.length > 0) ast.program.body.splice(i + 1, 0, ...keepAlive);
|
|
5905
|
+
} else bodyItems[templateIdx] = method;
|
|
4930
5906
|
let usesCompiledRuntimeBase = false;
|
|
4931
|
-
if (
|
|
5907
|
+
if (isReactiveComponent) {
|
|
5908
|
+
classDecl.superClass = null;
|
|
5909
|
+
usesCompiledRuntimeBase = false;
|
|
5910
|
+
if (!classDecl.body.body.some((member) => (t.isClassProperty(member) || t.isClassMethod(member)) && !member.computed && t.isIdentifier(member.key, { name: "el" })) && nodeContainsThisMember(classDecl, "el")) classDecl.body.body.unshift(t.classProperty(t.identifier("el"), t.nullLiteral()));
|
|
5911
|
+
} else if (useStaticElementComponent) {
|
|
4932
5912
|
ctx.importsNeeded.add("CompiledStaticElementComponent");
|
|
4933
5913
|
classDecl.superClass = t.identifier("CompiledStaticElementComponent");
|
|
4934
5914
|
usesCompiledRuntimeBase = true;
|
|
@@ -4957,7 +5937,9 @@ function transformFile(source, _filename, options = {}) {
|
|
|
4957
5937
|
ctx.importsNeeded.add("scheduleAfterRenderAsync");
|
|
4958
5938
|
classDecl.body.body.push(buildAfterRenderAsyncRenderMethod());
|
|
4959
5939
|
}
|
|
4960
|
-
rewritten.push(
|
|
5940
|
+
rewritten.push(className);
|
|
5941
|
+
ctx.currentIrComponent = void 0;
|
|
5942
|
+
ctx.currentIrRuntimeBase = void 0;
|
|
4961
5943
|
continue;
|
|
4962
5944
|
}
|
|
4963
5945
|
if (fnDecl && isFunctionComponent(fnDecl)) {
|
|
@@ -4984,9 +5966,90 @@ function transformFile(source, _filename, options = {}) {
|
|
|
4984
5966
|
map: out.map,
|
|
4985
5967
|
changed: true,
|
|
4986
5968
|
rewritten,
|
|
4987
|
-
importsNeeded: Array.from(ctx.importsNeeded)
|
|
5969
|
+
importsNeeded: Array.from(ctx.importsNeeded),
|
|
5970
|
+
ir: buildModuleIr(_filename ?? "<unknown>", rewritten, ctx.irTemplates ?? [], ast, reactiveComponentNames)
|
|
5971
|
+
};
|
|
5972
|
+
}
|
|
5973
|
+
function mountedComponentKeepAliveStatements(jsx, ast) {
|
|
5974
|
+
const tags = /* @__PURE__ */ new Set();
|
|
5975
|
+
collectCapitalizedJsxTags(jsx, tags);
|
|
5976
|
+
if (tags.size === 0) return [];
|
|
5977
|
+
const imported = /* @__PURE__ */ new Set();
|
|
5978
|
+
for (const stmt of ast.program.body) {
|
|
5979
|
+
if (!t.isImportDeclaration(stmt)) continue;
|
|
5980
|
+
for (const spec of stmt.specifiers) imported.add(spec.local.name);
|
|
5981
|
+
}
|
|
5982
|
+
const kept = Array.from(tags).filter((tag) => imported.has(tag));
|
|
5983
|
+
if (kept.length === 0) return [];
|
|
5984
|
+
const keepArray = t.assignmentExpression("||=", t.memberExpression(t.identifier("globalThis"), t.identifier("__GEA_IR_KEEP__")), t.arrayExpression([]));
|
|
5985
|
+
return [t.expressionStatement(t.callExpression(t.memberExpression(t.parenthesizedExpression(keepArray), t.identifier("push")), kept.map((tag) => t.identifier(tag))))];
|
|
5986
|
+
}
|
|
5987
|
+
function collectCapitalizedJsxTags(node, tags) {
|
|
5988
|
+
if (!node || typeof node !== "object") return;
|
|
5989
|
+
if (Array.isArray(node)) {
|
|
5990
|
+
for (const child of node) collectCapitalizedJsxTags(child, tags);
|
|
5991
|
+
return;
|
|
5992
|
+
}
|
|
5993
|
+
if (t.isJSXElement(node)) {
|
|
5994
|
+
const name = node.openingElement.name;
|
|
5995
|
+
if (t.isJSXIdentifier(name) && /^[A-Z]/.test(name.name)) tags.add(name.name);
|
|
5996
|
+
}
|
|
5997
|
+
for (const key of Object.keys(node)) {
|
|
5998
|
+
if (key === "loc" || key === "start" || key === "end" || key === "type") continue;
|
|
5999
|
+
collectCapitalizedJsxTags(node[key], tags);
|
|
6000
|
+
}
|
|
6001
|
+
}
|
|
6002
|
+
function runtimeBaseForComponent(options) {
|
|
6003
|
+
if (options.useStaticCompiledComponent) return "static";
|
|
6004
|
+
if (options.useCompiledComponent) return "compiled";
|
|
6005
|
+
if (options.useTinyReactiveComponent) return "tiny-reactive";
|
|
6006
|
+
if (options.useLeanReactiveComponent) return "lean-reactive";
|
|
6007
|
+
return "reactive";
|
|
6008
|
+
}
|
|
6009
|
+
function buildModuleIr(moduleId, rewritten, templates, ast, reactiveComponentNames = /* @__PURE__ */ new Set()) {
|
|
6010
|
+
const components = [];
|
|
6011
|
+
for (const name of rewritten) {
|
|
6012
|
+
const record = templates.find((template) => template.component === name);
|
|
6013
|
+
if (!record) continue;
|
|
6014
|
+
const declaration = findClassDeclarationByName(ast, name);
|
|
6015
|
+
const reactiveState = declaration && reactiveComponentNames.has(name) ? (() => {
|
|
6016
|
+
const fields = storeFieldsToIr(declaration);
|
|
6017
|
+
const methods = storeMethodsToIr(declaration, ast);
|
|
6018
|
+
const getters = storeGettersToIr(declaration);
|
|
6019
|
+
return {
|
|
6020
|
+
fields,
|
|
6021
|
+
...methods.length > 0 ? { methods } : {},
|
|
6022
|
+
...getters.length > 0 ? { getters } : {}
|
|
6023
|
+
};
|
|
6024
|
+
})() : void 0;
|
|
6025
|
+
components.push({
|
|
6026
|
+
id: componentIrId(moduleId, name),
|
|
6027
|
+
module: moduleId,
|
|
6028
|
+
exportName: name,
|
|
6029
|
+
runtimeBase: record.runtimeBase,
|
|
6030
|
+
template: record.template,
|
|
6031
|
+
...reactiveState ? { reactiveState } : {},
|
|
6032
|
+
...declaration ? { sourceSpan: sourceSpan(declaration) } : {}
|
|
6033
|
+
});
|
|
6034
|
+
}
|
|
6035
|
+
return {
|
|
6036
|
+
module: {
|
|
6037
|
+
id: moduleId,
|
|
6038
|
+
file: moduleId,
|
|
6039
|
+
components: components.map((component) => component.id),
|
|
6040
|
+
stores: []
|
|
6041
|
+
},
|
|
6042
|
+
components
|
|
4988
6043
|
};
|
|
4989
6044
|
}
|
|
6045
|
+
function findClassDeclarationByName(ast, name) {
|
|
6046
|
+
for (const node of ast.program.body) {
|
|
6047
|
+
if (t.isClassDeclaration(node) && node.id?.name === name) return node;
|
|
6048
|
+
if (t.isExportDefaultDeclaration(node) && t.isClassDeclaration(node.declaration) && node.declaration.id?.name === name) return node.declaration;
|
|
6049
|
+
if (t.isExportNamedDeclaration(node) && t.isClassDeclaration(node.declaration) && node.declaration.id?.name === name) return node.declaration;
|
|
6050
|
+
}
|
|
6051
|
+
return null;
|
|
6052
|
+
}
|
|
4990
6053
|
function collectLocalClassComponents(ast) {
|
|
4991
6054
|
const names = /* @__PURE__ */ new Set();
|
|
4992
6055
|
for (const node of ast.program.body) {
|
|
@@ -5516,6 +6579,7 @@ function transform(ctx) {
|
|
|
5516
6579
|
}
|
|
5517
6580
|
}
|
|
5518
6581
|
});
|
|
6582
|
+
let ir;
|
|
5519
6583
|
if (hasJSX) {
|
|
5520
6584
|
const emitted = transformFile(code, sourceFile, {
|
|
5521
6585
|
directClassComponents: knownClassComponentImports,
|
|
@@ -5523,6 +6587,7 @@ function transform(ctx) {
|
|
|
5523
6587
|
enableTinyReactiveComponents: !isServe
|
|
5524
6588
|
});
|
|
5525
6589
|
if (emitted.changed) {
|
|
6590
|
+
ir = emitted.ir;
|
|
5526
6591
|
const reparsed = parseSource(emitted.code);
|
|
5527
6592
|
if (reparsed) {
|
|
5528
6593
|
ast.program.body = reparsed.ast.program.body;
|
|
@@ -5573,7 +6638,8 @@ function transform(ctx) {
|
|
|
5573
6638
|
}, code);
|
|
5574
6639
|
return {
|
|
5575
6640
|
code: output.code,
|
|
5576
|
-
map: output.map
|
|
6641
|
+
map: output.map,
|
|
6642
|
+
ir
|
|
5577
6643
|
};
|
|
5578
6644
|
} catch (error) {
|
|
5579
6645
|
if (error?.__geaCompileError) throw error;
|
|
@@ -5583,10 +6649,9 @@ function transform(ctx) {
|
|
|
5583
6649
|
}
|
|
5584
6650
|
//#endregion
|
|
5585
6651
|
//#region src/closure-codegen/transform/transform-store.ts
|
|
5586
|
-
function transformCompiledStoreModule(source) {
|
|
6652
|
+
function transformCompiledStoreModule(source, moduleId = "<unknown>", resolveImportPath) {
|
|
5587
6653
|
if (!source.includes("extends Store")) return null;
|
|
5588
6654
|
if (source.includes("CompiledStore")) return null;
|
|
5589
|
-
if (/\b(flushSync|silent|Store\.|new\s+Store\s*\()/.test(source)) return null;
|
|
5590
6655
|
let ast;
|
|
5591
6656
|
try {
|
|
5592
6657
|
ast = parse(source, {
|
|
@@ -5603,29 +6668,48 @@ function transformCompiledStoreModule(source) {
|
|
|
5603
6668
|
} catch {
|
|
5604
6669
|
return null;
|
|
5605
6670
|
}
|
|
5606
|
-
const imported = findStoreImport(ast);
|
|
6671
|
+
const imported = findStoreImport(ast, moduleId, resolveImportPath);
|
|
5607
6672
|
if (!imported) return null;
|
|
5608
|
-
const
|
|
5609
|
-
if (
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
const
|
|
5613
|
-
|
|
5614
|
-
|
|
6673
|
+
const classDecls = findStoreClasses(ast, imported.localName);
|
|
6674
|
+
if (classDecls.length === 0) return null;
|
|
6675
|
+
const constants = collectImportedLiteralConstants(ast, moduleId, resolveImportPath);
|
|
6676
|
+
const fallbackIrs = classDecls.map((classDecl) => buildStoreIr(classDecl, moduleId, "compiled", constants, ast));
|
|
6677
|
+
const fallback = {
|
|
6678
|
+
code: source,
|
|
6679
|
+
changed: false,
|
|
6680
|
+
ir: fallbackIrs[0],
|
|
6681
|
+
irs: fallbackIrs
|
|
6682
|
+
};
|
|
6683
|
+
if (/\b(flushSync|silent|Store\.|new\s+Store\s*\()/.test(source)) return fallback;
|
|
6684
|
+
if (!classDecls.every((classDecl) => isCompiledStoreSafeClass(classDecl))) return classDecls.length === 1 ? null : fallback;
|
|
6685
|
+
if (!classDecls.every((classDecl) => hasDefaultNewStore(ast, classDecl.id.name))) return fallback;
|
|
6686
|
+
if (classDecls.length === 1) {
|
|
6687
|
+
const leanResult = transformLeanDataSelectedStore(ast, classDecls[0], imported, moduleId, constants);
|
|
6688
|
+
if (leanResult) return {
|
|
6689
|
+
...leanResult,
|
|
6690
|
+
irs: leanResult.ir ? [leanResult.ir] : void 0
|
|
6691
|
+
};
|
|
6692
|
+
}
|
|
6693
|
+
const storeBases = classDecls.map((classDecl) => canUseLeanStore(classDecl) ? "CompiledLeanStore" : "CompiledStore");
|
|
6694
|
+
const storeIrs = classDecls.map((classDecl, index) => buildStoreIr(classDecl, moduleId, storeBases[index] === "CompiledLeanStore" ? "lean" : "compiled", constants, ast));
|
|
5615
6695
|
removeStoreSpecifier(imported.importDecl, imported.localName);
|
|
5616
6696
|
ast.program.body = ast.program.body.filter((node) => {
|
|
5617
6697
|
if (node !== imported.importDecl) return true;
|
|
5618
6698
|
return imported.importDecl.specifiers.length > 0;
|
|
5619
6699
|
});
|
|
5620
|
-
ast.program.body.unshift(t.importDeclaration([t.importSpecifier(t.identifier(storeBase), t.identifier(storeBase))], t.stringLiteral(COMPILER_RUNTIME_ID)));
|
|
5621
|
-
classDecl
|
|
6700
|
+
for (const storeBase of [...new Set(storeBases)]) ast.program.body.unshift(t.importDeclaration([t.importSpecifier(t.identifier(storeBase), t.identifier(storeBase))], t.stringLiteral(COMPILER_RUNTIME_ID)));
|
|
6701
|
+
classDecls.forEach((classDecl, index) => {
|
|
6702
|
+
classDecl.superClass = t.identifier(storeBases[index]);
|
|
6703
|
+
});
|
|
5622
6704
|
return {
|
|
5623
6705
|
code: generate(ast, {
|
|
5624
6706
|
retainLines: false,
|
|
5625
6707
|
compact: false,
|
|
5626
6708
|
jsescOption: { minimal: true }
|
|
5627
6709
|
}).code,
|
|
5628
|
-
changed: true
|
|
6710
|
+
changed: true,
|
|
6711
|
+
ir: storeIrs[0],
|
|
6712
|
+
irs: storeIrs
|
|
5629
6713
|
};
|
|
5630
6714
|
}
|
|
5631
6715
|
const LEAN_DATA_SELECTED_STORE_SOURCE = `
|
|
@@ -5754,7 +6838,7 @@ const __store = {
|
|
|
5754
6838
|
};
|
|
5755
6839
|
export default __store;
|
|
5756
6840
|
`;
|
|
5757
|
-
function transformLeanDataSelectedStore(ast, classDecl, imported) {
|
|
6841
|
+
function transformLeanDataSelectedStore(ast, classDecl, imported, moduleId, constants) {
|
|
5758
6842
|
if (!classDecl.id) return null;
|
|
5759
6843
|
const classIndex = ast.program.body.indexOf(classDecl);
|
|
5760
6844
|
if (classIndex < 0) return null;
|
|
@@ -5763,6 +6847,7 @@ function transformLeanDataSelectedStore(ast, classDecl, imported) {
|
|
|
5763
6847
|
const fields = collectLeanStoreFields(classDecl);
|
|
5764
6848
|
if (!fields) return null;
|
|
5765
6849
|
if (!isBenchmarkOperationStoreShape(classDecl)) return null;
|
|
6850
|
+
const storeIr = buildStoreIr(classDecl, moduleId, "lean", constants, ast);
|
|
5766
6851
|
const methodProps = buildLeanStoreMethods(classDecl);
|
|
5767
6852
|
if (!methodProps) return null;
|
|
5768
6853
|
removeStoreSpecifier(imported.importDecl, imported.localName);
|
|
@@ -5792,9 +6877,95 @@ function transformLeanDataSelectedStore(ast, classDecl, imported) {
|
|
|
5792
6877
|
compact: false,
|
|
5793
6878
|
jsescOption: { minimal: true }
|
|
5794
6879
|
}).code,
|
|
5795
|
-
changed: true
|
|
6880
|
+
changed: true,
|
|
6881
|
+
ir: storeIr
|
|
6882
|
+
};
|
|
6883
|
+
}
|
|
6884
|
+
function buildStoreIr(classDecl, moduleId, runtimeBase, constants = [], moduleAst) {
|
|
6885
|
+
const className = classDecl.id?.name ?? "<anonymous>";
|
|
6886
|
+
return {
|
|
6887
|
+
id: storeIrId(moduleId, className),
|
|
6888
|
+
module: moduleId,
|
|
6889
|
+
className,
|
|
6890
|
+
runtimeBase,
|
|
6891
|
+
fields: storeFieldsToIr(classDecl),
|
|
6892
|
+
methods: storeMethodsToIr(classDecl, moduleAst),
|
|
6893
|
+
...(() => {
|
|
6894
|
+
const getters = storeGettersToIr(classDecl);
|
|
6895
|
+
return getters.length > 0 ? { getters } : {};
|
|
6896
|
+
})(),
|
|
6897
|
+
...constants.length > 0 ? { constants } : {},
|
|
6898
|
+
...sourceSpan(classDecl) ? { sourceSpan: sourceSpan(classDecl) } : {}
|
|
5796
6899
|
};
|
|
5797
6900
|
}
|
|
6901
|
+
function collectImportedLiteralConstants(ast, moduleId, resolveImportPath) {
|
|
6902
|
+
if (!resolveImportPath) return [];
|
|
6903
|
+
const namesByFile = /* @__PURE__ */ new Map();
|
|
6904
|
+
for (const node of ast.program.body) {
|
|
6905
|
+
if (!t.isImportDeclaration(node) || typeof node.source.value !== "string") continue;
|
|
6906
|
+
const resolved = resolveImportPath(moduleId, node.source.value);
|
|
6907
|
+
if (!resolved) continue;
|
|
6908
|
+
for (const specifier of node.specifiers) {
|
|
6909
|
+
if (!t.isImportSpecifier(specifier) || !t.isIdentifier(specifier.imported)) continue;
|
|
6910
|
+
const names = namesByFile.get(resolved) ?? /* @__PURE__ */ new Set();
|
|
6911
|
+
names.add(specifier.imported.name);
|
|
6912
|
+
namesByFile.set(resolved, names);
|
|
6913
|
+
}
|
|
6914
|
+
}
|
|
6915
|
+
const constants = [];
|
|
6916
|
+
for (const [file, names] of namesByFile) constants.push(...literalConstantsFromFile(file, names));
|
|
6917
|
+
return constants;
|
|
6918
|
+
}
|
|
6919
|
+
function literalConstantsFromFile(file, names) {
|
|
6920
|
+
if (!existsSync(file)) return [];
|
|
6921
|
+
let ast;
|
|
6922
|
+
try {
|
|
6923
|
+
ast = parse(readFileSync(file, "utf8"), {
|
|
6924
|
+
sourceType: "module",
|
|
6925
|
+
plugins: [
|
|
6926
|
+
"typescript",
|
|
6927
|
+
"jsx",
|
|
6928
|
+
"classProperties"
|
|
6929
|
+
],
|
|
6930
|
+
errorRecovery: false
|
|
6931
|
+
});
|
|
6932
|
+
} catch {
|
|
6933
|
+
return [];
|
|
6934
|
+
}
|
|
6935
|
+
const constants = [];
|
|
6936
|
+
for (const node of ast.program.body) {
|
|
6937
|
+
if (!t.isExportNamedDeclaration(node) || !t.isVariableDeclaration(node.declaration)) continue;
|
|
6938
|
+
for (const declaration of node.declaration.declarations) {
|
|
6939
|
+
if (!t.isIdentifier(declaration.id) || !names.has(declaration.id.name) || !declaration.init) continue;
|
|
6940
|
+
const literal = literalConstant(declaration.id.name, declaration.init);
|
|
6941
|
+
if (literal) constants.push(literal);
|
|
6942
|
+
}
|
|
6943
|
+
}
|
|
6944
|
+
return constants;
|
|
6945
|
+
}
|
|
6946
|
+
function literalConstant(name, value) {
|
|
6947
|
+
if (t.isStringLiteral(value)) return {
|
|
6948
|
+
name,
|
|
6949
|
+
value: value.value,
|
|
6950
|
+
valueType: "string"
|
|
6951
|
+
};
|
|
6952
|
+
if (t.isNumericLiteral(value)) return {
|
|
6953
|
+
name,
|
|
6954
|
+
value: String(value.value),
|
|
6955
|
+
valueType: "number"
|
|
6956
|
+
};
|
|
6957
|
+
if (t.isBooleanLiteral(value)) return {
|
|
6958
|
+
name,
|
|
6959
|
+
value: value.value ? "true" : "false",
|
|
6960
|
+
valueType: "boolean"
|
|
6961
|
+
};
|
|
6962
|
+
if (t.isNullLiteral(value)) return {
|
|
6963
|
+
name,
|
|
6964
|
+
value: "null",
|
|
6965
|
+
valueType: "null"
|
|
6966
|
+
};
|
|
6967
|
+
return null;
|
|
6968
|
+
}
|
|
5798
6969
|
function isBenchmarkOperationStoreShape(classDecl) {
|
|
5799
6970
|
const methods = /* @__PURE__ */ new Set();
|
|
5800
6971
|
for (const member of classDecl.body.body) {
|
|
@@ -5892,10 +7063,10 @@ function replaceThisExpressions(node, replacement) {
|
|
|
5892
7063
|
else replaceThisExpressions(value, replacement);
|
|
5893
7064
|
}
|
|
5894
7065
|
}
|
|
5895
|
-
function findStoreImport(ast) {
|
|
7066
|
+
function findStoreImport(ast, moduleId, resolveImportPath) {
|
|
5896
7067
|
for (const node of ast.program.body) {
|
|
5897
7068
|
if (!t.isImportDeclaration(node)) continue;
|
|
5898
|
-
if (
|
|
7069
|
+
if (!storeImportSourceProvidesStore(moduleId, node.source.value, resolveImportPath)) continue;
|
|
5899
7070
|
for (const spec of node.specifiers) {
|
|
5900
7071
|
if (!t.isImportSpecifier(spec)) continue;
|
|
5901
7072
|
if ((t.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value) === "Store") return {
|
|
@@ -5906,13 +7077,87 @@ function findStoreImport(ast) {
|
|
|
5906
7077
|
}
|
|
5907
7078
|
return null;
|
|
5908
7079
|
}
|
|
5909
|
-
|
|
5910
|
-
|
|
7080
|
+
const knownStoreImportSources = new Set([
|
|
7081
|
+
"gea",
|
|
7082
|
+
"@geajs/core",
|
|
7083
|
+
"gea-embedded"
|
|
7084
|
+
]);
|
|
7085
|
+
const storeExportCache = /* @__PURE__ */ new Map();
|
|
7086
|
+
function storeImportSourceProvidesStore(moduleId, source, resolveImportPath) {
|
|
7087
|
+
if (typeof source !== "string") return false;
|
|
7088
|
+
if (knownStoreImportSources.has(source)) return true;
|
|
7089
|
+
if (!resolveImportPath) return false;
|
|
7090
|
+
const resolved = resolveImportPath(moduleId, source);
|
|
7091
|
+
return !!resolved && moduleExportsStore(resolved, resolveImportPath, /* @__PURE__ */ new Set());
|
|
7092
|
+
}
|
|
7093
|
+
function moduleExportsStore(file, resolveImportPath, seen) {
|
|
7094
|
+
if (seen.has(file)) return false;
|
|
7095
|
+
const cached = storeExportCache.get(file);
|
|
7096
|
+
if (cached !== void 0) return cached;
|
|
7097
|
+
seen.add(file);
|
|
7098
|
+
if (!existsSync(file)) {
|
|
7099
|
+
storeExportCache.set(file, false);
|
|
7100
|
+
return false;
|
|
7101
|
+
}
|
|
7102
|
+
let ast;
|
|
7103
|
+
try {
|
|
7104
|
+
ast = parse(readFileSync(file, "utf8"), {
|
|
7105
|
+
sourceType: "module",
|
|
7106
|
+
plugins: [
|
|
7107
|
+
"typescript",
|
|
7108
|
+
"jsx",
|
|
7109
|
+
"classProperties"
|
|
7110
|
+
],
|
|
7111
|
+
errorRecovery: false
|
|
7112
|
+
});
|
|
7113
|
+
} catch {
|
|
7114
|
+
storeExportCache.set(file, false);
|
|
7115
|
+
return false;
|
|
7116
|
+
}
|
|
7117
|
+
for (const node of ast.program.body) {
|
|
7118
|
+
if (t.isExportNamedDeclaration(node)) {
|
|
7119
|
+
if (node.declaration) {
|
|
7120
|
+
if (t.isVariableDeclaration(node.declaration)) {
|
|
7121
|
+
for (const declaration of node.declaration.declarations) if (t.isIdentifier(declaration.id, { name: "Store" })) {
|
|
7122
|
+
storeExportCache.set(file, true);
|
|
7123
|
+
return true;
|
|
7124
|
+
}
|
|
7125
|
+
}
|
|
7126
|
+
if (t.isClassDeclaration(node.declaration) && t.isIdentifier(node.declaration.id, { name: "Store" })) {
|
|
7127
|
+
storeExportCache.set(file, true);
|
|
7128
|
+
return true;
|
|
7129
|
+
}
|
|
7130
|
+
}
|
|
7131
|
+
for (const specifier of node.specifiers) {
|
|
7132
|
+
if ((t.isIdentifier(specifier.exported) ? specifier.exported.name : specifier.exported.value) !== "Store") continue;
|
|
7133
|
+
if (!node.source || typeof node.source.value !== "string") {
|
|
7134
|
+
storeExportCache.set(file, true);
|
|
7135
|
+
return true;
|
|
7136
|
+
}
|
|
7137
|
+
const resolved = resolveImportPath(file, node.source.value);
|
|
7138
|
+
if (resolved && moduleExportsStore(resolved, resolveImportPath, seen)) {
|
|
7139
|
+
storeExportCache.set(file, true);
|
|
7140
|
+
return true;
|
|
7141
|
+
}
|
|
7142
|
+
}
|
|
7143
|
+
}
|
|
7144
|
+
if (t.isExportAllDeclaration(node) && typeof node.source.value === "string") {
|
|
7145
|
+
const resolved = resolveImportPath(file, node.source.value);
|
|
7146
|
+
if (resolved && moduleExportsStore(resolved, resolveImportPath, seen)) {
|
|
7147
|
+
storeExportCache.set(file, true);
|
|
7148
|
+
return true;
|
|
7149
|
+
}
|
|
7150
|
+
}
|
|
7151
|
+
}
|
|
7152
|
+
storeExportCache.set(file, false);
|
|
7153
|
+
return false;
|
|
7154
|
+
}
|
|
7155
|
+
function findStoreClasses(ast, storeName) {
|
|
7156
|
+
const found = [];
|
|
5911
7157
|
for (const node of ast.program.body) {
|
|
5912
7158
|
const decl = t.isClassDeclaration(node) ? node : t.isExportNamedDeclaration(node) && t.isClassDeclaration(node.declaration) ? node.declaration : null;
|
|
5913
|
-
if (!decl || !t.isIdentifier(decl.superClass, { name: storeName })) continue;
|
|
5914
|
-
|
|
5915
|
-
found = decl;
|
|
7159
|
+
if (!decl || !decl.id || !t.isIdentifier(decl.superClass, { name: storeName })) continue;
|
|
7160
|
+
found.push(decl);
|
|
5916
7161
|
}
|
|
5917
7162
|
return found;
|
|
5918
7163
|
}
|
|
@@ -6066,7 +7311,8 @@ function transformStaticRootMount(source, filePath, resolveImportPath) {
|
|
|
6066
7311
|
compact: false,
|
|
6067
7312
|
jsescOption: { minimal: true }
|
|
6068
7313
|
}).code,
|
|
6069
|
-
changed: true
|
|
7314
|
+
changed: true,
|
|
7315
|
+
watchFiles: [resolved, ...factory.watchFiles]
|
|
6070
7316
|
};
|
|
6071
7317
|
}
|
|
6072
7318
|
function collectDefaultImports(ast) {
|
|
@@ -6162,6 +7408,7 @@ function createStaticTemplateFactory(componentPath, tplName, mountFilePath, reso
|
|
|
6162
7408
|
const jsx = templateMethod ? extractTemplateJsx(templateMethod) : null;
|
|
6163
7409
|
if (!jsx || !isBuiltinElementRoot(jsx)) return null;
|
|
6164
7410
|
const ctx = createEmitContext();
|
|
7411
|
+
const watchFiles = /* @__PURE__ */ new Set();
|
|
6165
7412
|
ctx.directFnComponents = collectDirectFnComponents(ast);
|
|
6166
7413
|
ctx.directFnComponentParams = collectDirectFnComponentParams(ast, ctx.directFnComponents);
|
|
6167
7414
|
ctx.directFnNoDisposer = /* @__PURE__ */ new Set();
|
|
@@ -6169,7 +7416,7 @@ function createStaticTemplateFactory(componentPath, tplName, mountFilePath, reso
|
|
|
6169
7416
|
ctx.directClassComponents = /* @__PURE__ */ new Set();
|
|
6170
7417
|
ctx.directFactoryComponents = /* @__PURE__ */ new Set();
|
|
6171
7418
|
const importedFns = [];
|
|
6172
|
-
if (!collectImportedStaticFunctionComponents(ast, componentPath, resolveImportPath, ctx, importedFns)) return null;
|
|
7419
|
+
if (!collectImportedStaticFunctionComponents(ast, componentPath, resolveImportPath, ctx, importedFns, watchFiles)) return null;
|
|
6173
7420
|
ctx.directFnStringProps = collectDirectFnStringProps(ast, ctx.directFnComponents);
|
|
6174
7421
|
if (nodeContainsAnyIdentifier(jsx, collectRootModuleBindings(ast, classDecl, ctx.directFnComponents))) return null;
|
|
6175
7422
|
const importedFnDecls = [];
|
|
@@ -6217,7 +7464,8 @@ function createStaticTemplateFactory(componentPath, tplName, mountFilePath, reso
|
|
|
6217
7464
|
factoryDecl
|
|
6218
7465
|
],
|
|
6219
7466
|
mountExpression: t.callExpression(t.identifier(tplName + "_create"), disposerArg),
|
|
6220
|
-
importsNeeded: ctx.importsNeeded
|
|
7467
|
+
importsNeeded: ctx.importsNeeded,
|
|
7468
|
+
watchFiles: [...watchFiles]
|
|
6221
7469
|
};
|
|
6222
7470
|
}
|
|
6223
7471
|
function collectCopiedImports(ast, componentPath, mountFilePath, resolveImportPath, compiledImportNames) {
|
|
@@ -6246,7 +7494,7 @@ function toRelativeImportSource(fromFile, targetFile) {
|
|
|
6246
7494
|
if (!source.startsWith(".")) source = "./" + source;
|
|
6247
7495
|
return source;
|
|
6248
7496
|
}
|
|
6249
|
-
function collectImportedStaticFunctionComponents(ast, importerPath, resolveImportPath, ctx, importedFns) {
|
|
7497
|
+
function collectImportedStaticFunctionComponents(ast, importerPath, resolveImportPath, ctx, importedFns, watchFiles) {
|
|
6250
7498
|
for (const stmt of ast.program.body) {
|
|
6251
7499
|
if (!t.isImportDeclaration(stmt)) continue;
|
|
6252
7500
|
if (stmt.source.value === "@geajs/core") continue;
|
|
@@ -6256,6 +7504,7 @@ function collectImportedStaticFunctionComponents(ast, importerPath, resolveImpor
|
|
|
6256
7504
|
if (componentSpecs.length === 0) continue;
|
|
6257
7505
|
const resolved = resolveImportPath(importerPath, stmt.source.value);
|
|
6258
7506
|
if (!resolved) return false;
|
|
7507
|
+
watchFiles.add(resolved);
|
|
6259
7508
|
const imported = readImportModule(resolved);
|
|
6260
7509
|
if (!imported) return false;
|
|
6261
7510
|
for (const spec of componentSpecs) {
|
|
@@ -6816,11 +8065,21 @@ function shouldMinifyGeaSymbolsForBuild(config) {
|
|
|
6816
8065
|
const formats = lib.formats ?? [];
|
|
6817
8066
|
return formats.length > 0 && formats.every((format) => format === "iife" || format === "umd");
|
|
6818
8067
|
}
|
|
6819
|
-
function geaPlugin() {
|
|
8068
|
+
function geaPlugin(options = {}) {
|
|
8069
|
+
const envIrOutFile = process.env.GEA_IR_OUT || process.env.GEA_IR_FILE;
|
|
8070
|
+
const irOptions = options.ir ?? (envIrOutFile ? {
|
|
8071
|
+
enabled: true,
|
|
8072
|
+
outFile: envIrOutFile
|
|
8073
|
+
} : void 0);
|
|
6820
8074
|
const storeModules = /* @__PURE__ */ new Set();
|
|
6821
8075
|
const componentModules = /* @__PURE__ */ new Set();
|
|
6822
8076
|
let isServeCommand = false;
|
|
6823
8077
|
let shouldMinifyGeaSymbolKeys = false;
|
|
8078
|
+
let resolvedConfig = null;
|
|
8079
|
+
const irModules = /* @__PURE__ */ new Map();
|
|
8080
|
+
const irComponents = /* @__PURE__ */ new Map();
|
|
8081
|
+
const irStores = /* @__PURE__ */ new Map();
|
|
8082
|
+
const hostCapabilities = /* @__PURE__ */ new Set();
|
|
6824
8083
|
const storeRegistry = /* @__PURE__ */ new Map();
|
|
6825
8084
|
const resolveImportPath = (importer, source) => {
|
|
6826
8085
|
const base = resolve(dirname(importer), source);
|
|
@@ -6931,6 +8190,7 @@ function geaPlugin() {
|
|
|
6931
8190
|
name: "gea-plugin",
|
|
6932
8191
|
enforce: "pre",
|
|
6933
8192
|
configResolved(config) {
|
|
8193
|
+
resolvedConfig = config;
|
|
6934
8194
|
isServeCommand = config.command === "serve";
|
|
6935
8195
|
shouldMinifyGeaSymbolKeys = shouldMinifyGeaSymbolsForBuild(config);
|
|
6936
8196
|
},
|
|
@@ -6977,6 +8237,7 @@ function geaPlugin() {
|
|
|
6977
8237
|
if (!cleanId.match(/\.(js|jsx|ts|tsx)$/) || cleanId.includes("node_modules")) return null;
|
|
6978
8238
|
let transformedCode = code;
|
|
6979
8239
|
let changed = false;
|
|
8240
|
+
if (irOptions?.enabled) recordHostCapabilities(code);
|
|
6980
8241
|
if (code.includes("extends Store") || code.includes("new Store(")) {
|
|
6981
8242
|
storeModules.add(cleanId);
|
|
6982
8243
|
const storeClassName = extractStoreClassName(code);
|
|
@@ -6989,22 +8250,30 @@ function geaPlugin() {
|
|
|
6989
8250
|
}
|
|
6990
8251
|
}
|
|
6991
8252
|
if (/\bclass\s+Component\s+extends\s+Store\b/.test(code)) return null;
|
|
6992
|
-
if (!
|
|
8253
|
+
if (!isSSR) {
|
|
6993
8254
|
const observeResult = transformDottedObserveCalls(transformedCode);
|
|
6994
8255
|
if (observeResult?.changed) {
|
|
6995
8256
|
transformedCode = observeResult.code;
|
|
6996
8257
|
changed = true;
|
|
6997
8258
|
}
|
|
6998
|
-
const storeResult = transformCompiledStoreModule(transformedCode);
|
|
6999
|
-
|
|
7000
|
-
|
|
7001
|
-
|
|
7002
|
-
|
|
8259
|
+
const storeResult = transformCompiledStoreModule(transformedCode, cleanId, resolveImportPath);
|
|
8260
|
+
for (const storeIr of storeResult?.irs ?? (storeResult?.ir ? [storeResult.ir] : [])) recordStoreIr(cleanId, storeIr);
|
|
8261
|
+
if (storeResult?.changed) {
|
|
8262
|
+
if (!/\bextends\s+(Component|ReactiveComponent)\b|\bmount\s*\(/.test(storeResult.code)) return {
|
|
8263
|
+
code: storeResult.code,
|
|
8264
|
+
map: null
|
|
8265
|
+
};
|
|
8266
|
+
transformedCode = storeResult.code;
|
|
8267
|
+
changed = true;
|
|
8268
|
+
}
|
|
7003
8269
|
const rootMountResult = transformStaticRootMount(transformedCode, cleanId, resolveImportPath);
|
|
7004
|
-
if (rootMountResult?.changed)
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
8270
|
+
if (rootMountResult?.changed) {
|
|
8271
|
+
for (const file of rootMountResult.watchFiles ?? []) this.addWatchFile?.(file);
|
|
8272
|
+
return {
|
|
8273
|
+
code: rootMountResult.code,
|
|
8274
|
+
map: null
|
|
8275
|
+
};
|
|
8276
|
+
}
|
|
7008
8277
|
}
|
|
7009
8278
|
const result = transform({
|
|
7010
8279
|
sourceFile: cleanId,
|
|
@@ -7020,7 +8289,15 @@ function geaPlugin() {
|
|
|
7020
8289
|
registerStoreModule: (fp) => storeModules.add(fp),
|
|
7021
8290
|
registerComponentModule: (fp) => componentModules.add(fp)
|
|
7022
8291
|
});
|
|
7023
|
-
if (result)
|
|
8292
|
+
if (result) {
|
|
8293
|
+
if (result.ir) recordComponentIr(cleanId, result.ir);
|
|
8294
|
+
if (result.ir?.components.some((component) => component.reactiveState)) return {
|
|
8295
|
+
code: result.code,
|
|
8296
|
+
map: result.map ?? null,
|
|
8297
|
+
moduleSideEffects: "no-treeshake"
|
|
8298
|
+
};
|
|
8299
|
+
return result;
|
|
8300
|
+
}
|
|
7024
8301
|
if (isServeCommand && !isSSR) {
|
|
7025
8302
|
const componentDeps = findComponentDeps(transformedCode, cleanId);
|
|
7026
8303
|
if (componentDeps.length > 0) {
|
|
@@ -7044,8 +8321,136 @@ function geaPlugin() {
|
|
|
7044
8321
|
code: next,
|
|
7045
8322
|
map: null
|
|
7046
8323
|
};
|
|
8324
|
+
},
|
|
8325
|
+
generateBundle(_options, bundle) {
|
|
8326
|
+
if (!irOptions?.enabled) return;
|
|
8327
|
+
const renderedIds = renderedModuleIds(bundle);
|
|
8328
|
+
const modules = Array.from(irModules.values()).filter((module) => {
|
|
8329
|
+
if (!renderedIds) return true;
|
|
8330
|
+
return renderedIds.has(cleanRollupModuleId(module.id)) || renderedIds.has(cleanRollupModuleId(module.file));
|
|
8331
|
+
});
|
|
8332
|
+
const componentIds = new Set(modules.flatMap((module) => module.components));
|
|
8333
|
+
const storeIds = new Set(modules.flatMap((module) => module.stores));
|
|
8334
|
+
const moduleById = new Map(Array.from(irModules.values()).map((module) => [module.id, module]));
|
|
8335
|
+
const pending = Array.from(componentIds);
|
|
8336
|
+
while (pending.length > 0) {
|
|
8337
|
+
const component = irComponents.get(pending.pop());
|
|
8338
|
+
if (!component) continue;
|
|
8339
|
+
for (const tag of collectMountTags(component.template.slots)) for (const candidate of irComponents.values()) {
|
|
8340
|
+
if (candidate.exportName !== tag || componentIds.has(candidate.id)) continue;
|
|
8341
|
+
componentIds.add(candidate.id);
|
|
8342
|
+
pending.push(candidate.id);
|
|
8343
|
+
const candidateModule = moduleById.get(candidate.module);
|
|
8344
|
+
if (candidateModule && !modules.includes(candidateModule)) modules.push(candidateModule);
|
|
8345
|
+
}
|
|
8346
|
+
}
|
|
8347
|
+
const irBundle = {
|
|
8348
|
+
schema: "gea-ir",
|
|
8349
|
+
version: 1,
|
|
8350
|
+
entry: geaIrEntryFromBundle(bundle) ?? geaIrConfiguredEntry(resolvedConfig),
|
|
8351
|
+
modules,
|
|
8352
|
+
components: Array.from(irComponents.values()).filter((component) => componentIds.has(component.id)),
|
|
8353
|
+
stores: Array.from(irStores.values()).filter((store) => storeIds.has(store.id)),
|
|
8354
|
+
hostCapabilities: Array.from(hostCapabilities).sort()
|
|
8355
|
+
};
|
|
8356
|
+
const source = JSON.stringify(irBundle, null, 2);
|
|
8357
|
+
const outFile = irOptions.outFile ?? "gea-ir.json";
|
|
8358
|
+
if (outFile.startsWith("/") || /^[A-Za-z]:[\\/]/.test(outFile)) {
|
|
8359
|
+
mkdirSync(dirname(outFile), { recursive: true });
|
|
8360
|
+
writeFileSync(outFile, source);
|
|
8361
|
+
} else this.emitFile({
|
|
8362
|
+
type: "asset",
|
|
8363
|
+
fileName: outFile,
|
|
8364
|
+
source
|
|
8365
|
+
});
|
|
7047
8366
|
}
|
|
7048
8367
|
};
|
|
8368
|
+
function collectMountTags(slots, tags = /* @__PURE__ */ new Set(), depth = 0) {
|
|
8369
|
+
if (depth > 8 || !Array.isArray(slots)) return tags;
|
|
8370
|
+
for (const slot of slots) {
|
|
8371
|
+
if (!slot || typeof slot !== "object") continue;
|
|
8372
|
+
const { kind, payload } = slot;
|
|
8373
|
+
if (!payload || typeof payload !== "object") continue;
|
|
8374
|
+
const record = payload;
|
|
8375
|
+
if (kind === "mount" && typeof record.tag === "string") tags.add(record.tag);
|
|
8376
|
+
for (const key of Object.keys(record)) {
|
|
8377
|
+
if (key === "attrs" || key === "children") continue;
|
|
8378
|
+
const value = record[key];
|
|
8379
|
+
if (value && typeof value === "object" && Array.isArray(value.slots)) collectMountTags(value.slots, tags, depth + 1);
|
|
8380
|
+
}
|
|
8381
|
+
}
|
|
8382
|
+
return tags;
|
|
8383
|
+
}
|
|
8384
|
+
function recordComponentIr(moduleId, ir) {
|
|
8385
|
+
const existing = irModules.get(moduleId) ?? {
|
|
8386
|
+
id: moduleId,
|
|
8387
|
+
file: moduleId,
|
|
8388
|
+
components: [],
|
|
8389
|
+
stores: []
|
|
8390
|
+
};
|
|
8391
|
+
const componentIds = new Set(existing.components);
|
|
8392
|
+
for (const component of ir.components) {
|
|
8393
|
+
irComponents.set(component.id, component);
|
|
8394
|
+
componentIds.add(component.id);
|
|
8395
|
+
}
|
|
8396
|
+
irModules.set(moduleId, {
|
|
8397
|
+
...existing,
|
|
8398
|
+
components: Array.from(componentIds)
|
|
8399
|
+
});
|
|
8400
|
+
}
|
|
8401
|
+
function recordStoreIr(moduleId, store) {
|
|
8402
|
+
const existing = irModules.get(moduleId) ?? {
|
|
8403
|
+
id: moduleId,
|
|
8404
|
+
file: moduleId,
|
|
8405
|
+
components: [],
|
|
8406
|
+
stores: []
|
|
8407
|
+
};
|
|
8408
|
+
const storeIds = new Set(existing.stores);
|
|
8409
|
+
irStores.set(store.id, store);
|
|
8410
|
+
storeIds.add(store.id);
|
|
8411
|
+
irModules.set(moduleId, {
|
|
8412
|
+
...existing,
|
|
8413
|
+
stores: Array.from(storeIds)
|
|
8414
|
+
});
|
|
8415
|
+
}
|
|
8416
|
+
function recordHostCapabilities(source) {
|
|
8417
|
+
if (/\bfetch\s*\(/.test(source)) hostCapabilities.add("fetch");
|
|
8418
|
+
if (source.includes("https://")) hostCapabilities.add("https");
|
|
8419
|
+
if (/\bApps\s*\./.test(source)) hostCapabilities.add("apps");
|
|
8420
|
+
if (/\b(?:BLE|BLEServer)\b|\bgea_embedded_ble_|\b__gea_embedded_ble_/.test(source)) hostCapabilities.add("ble");
|
|
8421
|
+
if (/\bWiFi\s*\./.test(source)) hostCapabilities.add("wifi");
|
|
8422
|
+
if (/\b(?:Accelerometer|accelerometer)\s*\.|\bgea_embedded_imu_/.test(source)) hostCapabilities.add("imu");
|
|
8423
|
+
if (/\baudioContext\s*\.|\b__gea_audioContext\b|\b__gea_Audio\b/.test(source)) hostCapabilities.add("audio");
|
|
8424
|
+
if (/\bscreen\s*\./.test(source)) hostCapabilities.add("screen");
|
|
8425
|
+
if (/\b__gea_embedded_image\b/.test(source)) hostCapabilities.add("image");
|
|
8426
|
+
if (/\b__gea_embedded_touch\b/.test(source)) hostCapabilities.add("touch");
|
|
8427
|
+
if (/\bdocument\s*\./.test(source)) hostCapabilities.add("dom");
|
|
8428
|
+
}
|
|
8429
|
+
}
|
|
8430
|
+
function renderedModuleIds(bundle) {
|
|
8431
|
+
const ids = /* @__PURE__ */ new Set();
|
|
8432
|
+
for (const item of Object.values(bundle)) {
|
|
8433
|
+
if (item.type !== "chunk") continue;
|
|
8434
|
+
if (item.facadeModuleId) ids.add(cleanRollupModuleId(item.facadeModuleId));
|
|
8435
|
+
if (item.modules && typeof item.modules === "object") for (const id of Object.keys(item.modules)) ids.add(cleanRollupModuleId(id));
|
|
8436
|
+
}
|
|
8437
|
+
return ids.size > 0 ? ids : null;
|
|
8438
|
+
}
|
|
8439
|
+
function cleanRollupModuleId(id) {
|
|
8440
|
+
return id.split("?")[0] ?? id;
|
|
8441
|
+
}
|
|
8442
|
+
function geaIrEntryFromBundle(bundle) {
|
|
8443
|
+
return Object.values(bundle).filter((item) => item.type === "chunk" && item.isEntry && item.fileName).map((item) => item.fileName).sort()[0] ?? null;
|
|
8444
|
+
}
|
|
8445
|
+
function geaIrConfiguredEntry(config) {
|
|
8446
|
+
const input = config?.build.rollupOptions.input;
|
|
8447
|
+
if (typeof input === "string") return input;
|
|
8448
|
+
if (Array.isArray(input)) return input[0] ? String(input[0]) : "";
|
|
8449
|
+
if (input && typeof input === "object") {
|
|
8450
|
+
const firstKey = Object.keys(input).sort()[0];
|
|
8451
|
+
return firstKey ? String(input[firstKey]) : "";
|
|
8452
|
+
}
|
|
8453
|
+
return "";
|
|
7049
8454
|
}
|
|
7050
8455
|
function resolveToFile(base) {
|
|
7051
8456
|
const exts = [
|
|
@@ -7098,6 +8503,7 @@ function compilerRuntimeSource(runtimePath) {
|
|
|
7098
8503
|
relationalClass,
|
|
7099
8504
|
relationalClassProp,
|
|
7100
8505
|
reactiveStyle,
|
|
8506
|
+
reactiveStyleProp,
|
|
7101
8507
|
reactiveValue,
|
|
7102
8508
|
reactiveValueRead,
|
|
7103
8509
|
delegateEvent,
|