@geajs/vite-plugin 1.3.1 → 1.4.1
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 +1593 -149
- 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];
|
|
@@ -2734,8 +3008,21 @@ function buildInlinePropKeyedListBlock(options) {
|
|
|
2734
3008
|
__PATCH__: options.patchEntryArrow
|
|
2735
3009
|
});
|
|
2736
3010
|
replaceByKeyMarker(block, options.relMatches);
|
|
3011
|
+
if (options.ctx.embedded) rewriteObserveReconcileForEmbedded(block);
|
|
2737
3012
|
return block;
|
|
2738
3013
|
}
|
|
3014
|
+
function rewriteObserveReconcileForEmbedded(node) {
|
|
3015
|
+
if (!node || typeof node !== "object") return;
|
|
3016
|
+
if (Array.isArray(node)) {
|
|
3017
|
+
for (const value of node) rewriteObserveReconcileForEmbedded(value);
|
|
3018
|
+
return;
|
|
3019
|
+
}
|
|
3020
|
+
if (node.type === "CallExpression" && t.isIdentifier(node.callee, { name: "__kl_reconcile" }) && node.arguments.length >= 1 && t.isIdentifier(node.arguments[0], { name: "_value" })) node.arguments[0] = t.callExpression(t.identifier("__kl_resolve"), []);
|
|
3021
|
+
for (const key of Object.keys(node)) {
|
|
3022
|
+
if (key === "loc" || key === "start" || key === "end" || key === "type") continue;
|
|
3023
|
+
rewriteObserveReconcileForEmbedded(node[key]);
|
|
3024
|
+
}
|
|
3025
|
+
}
|
|
2739
3026
|
function isDirectIdKey(expr) {
|
|
2740
3027
|
if (!t.isArrowFunctionExpression(expr) || expr.params.length === 0) return false;
|
|
2741
3028
|
const firstParam = expr.params[0];
|
|
@@ -3405,54 +3692,6 @@ function normalizeEventAttrName(name) {
|
|
|
3405
3692
|
return toGeaEventType(name);
|
|
3406
3693
|
}
|
|
3407
3694
|
//#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
3695
|
//#region src/closure-codegen/generator/walk.ts
|
|
3457
3696
|
const OPTIONAL_TABLE_END_TAGS = new Set([
|
|
3458
3697
|
"colgroup",
|
|
@@ -3910,13 +4149,31 @@ function emitSlot(slot, stmts, ctx) {
|
|
|
3910
4149
|
pathOrGetter.value
|
|
3911
4150
|
])));
|
|
3912
4151
|
} else if (slot.kind === "style") {
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
4152
|
+
const styleExpr = slot.expr;
|
|
4153
|
+
const styleProps = t.isObjectExpression(styleExpr) && styleExpr.properties.length > 0 ? styleExpr.properties : null;
|
|
4154
|
+
if (styleProps !== null && styleProps.every((p) => t.isObjectProperty(p) && !p.computed && (t.isIdentifier(p.key) || t.isStringLiteral(p.key)))) {
|
|
4155
|
+
ctx.importsNeeded.add("reactiveStyleProp");
|
|
4156
|
+
for (const p of styleProps) {
|
|
4157
|
+
const keyName = t.isIdentifier(p.key) ? p.key.name : p.key.value;
|
|
4158
|
+
const kebabKey = String(keyName).replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
|
|
4159
|
+
const valSource = expressionToPathOrGetter(p.value, ctx);
|
|
4160
|
+
stmts.push(t.expressionStatement(t.callExpression(t.identifier("reactiveStyleProp"), [
|
|
4161
|
+
elId,
|
|
4162
|
+
t.identifier("d"),
|
|
4163
|
+
ctx.reactiveRoot,
|
|
4164
|
+
t.stringLiteral(kebabKey),
|
|
4165
|
+
valSource.value
|
|
4166
|
+
])));
|
|
4167
|
+
}
|
|
4168
|
+
} else {
|
|
4169
|
+
ctx.importsNeeded.add("reactiveStyle");
|
|
4170
|
+
stmts.push(t.expressionStatement(t.callExpression(t.identifier("reactiveStyle"), [
|
|
4171
|
+
elId,
|
|
4172
|
+
t.identifier("d"),
|
|
4173
|
+
ctx.reactiveRoot,
|
|
4174
|
+
pathOrGetter.value
|
|
4175
|
+
])));
|
|
4176
|
+
}
|
|
3920
4177
|
} else if (slot.kind === "value") {
|
|
3921
4178
|
ctx.importsNeeded.add("reactiveValueRead");
|
|
3922
4179
|
stmts.push(t.expressionStatement(t.callExpression(t.identifier("reactiveValueRead"), [
|
|
@@ -4107,29 +4364,734 @@ function isOneShotStringPropLocal(expr, ctx) {
|
|
|
4107
4364
|
return t.isIdentifier(expr) && ctx.oneShotStringPropLocals?.has(expr.name) === true;
|
|
4108
4365
|
}
|
|
4109
4366
|
//#endregion
|
|
4110
|
-
//#region src/closure-codegen/
|
|
4111
|
-
function
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4367
|
+
//#region src/closure-codegen/ir.ts
|
|
4368
|
+
function componentIrId(moduleId, exportName) {
|
|
4369
|
+
return `${moduleId}#${exportName}`;
|
|
4370
|
+
}
|
|
4371
|
+
function storeIrId(moduleId, className) {
|
|
4372
|
+
return `${moduleId}#${className}`;
|
|
4373
|
+
}
|
|
4374
|
+
function templateSpecToIr(spec, bindings = /* @__PURE__ */ new Map()) {
|
|
4375
|
+
return {
|
|
4376
|
+
html: spec.html,
|
|
4377
|
+
slots: spec.slots.map((slot) => slotToIr(slot, bindings))
|
|
4378
|
+
};
|
|
4379
|
+
}
|
|
4380
|
+
function storeFieldsToIr(classDecl) {
|
|
4381
|
+
const fields = [];
|
|
4382
|
+
for (const member of classDecl.body.body) {
|
|
4383
|
+
if (!t.isClassProperty(member) || member.static || member.computed || !t.isIdentifier(member.key)) continue;
|
|
4384
|
+
const field = {
|
|
4385
|
+
name: member.key.name,
|
|
4386
|
+
...member.value ? { initializer: generate(member.value).code } : {},
|
|
4387
|
+
...member.value ? shapeForExpression(member.value) : {}
|
|
4388
|
+
};
|
|
4389
|
+
if (field.shape?.kind === "array") {
|
|
4390
|
+
const elementTypeName = arrayElementTypeNameFromAnnotation(member);
|
|
4391
|
+
if (elementTypeName) field.shape = {
|
|
4392
|
+
...field.shape,
|
|
4393
|
+
elementTypeName
|
|
4394
|
+
};
|
|
4395
|
+
}
|
|
4396
|
+
fields.push(field);
|
|
4121
4397
|
}
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4398
|
+
return fields;
|
|
4399
|
+
}
|
|
4400
|
+
function arrayElementTypeNameFromAnnotation(member) {
|
|
4401
|
+
const annotation = member.typeAnnotation;
|
|
4402
|
+
if (!annotation || !t.isTSTypeAnnotation(annotation)) return void 0;
|
|
4403
|
+
return arrayElementTypeNameFromTSType(annotation.typeAnnotation);
|
|
4404
|
+
}
|
|
4405
|
+
function arrayElementTypeNameFromTSType(typeNode) {
|
|
4406
|
+
if (t.isTSArrayType(typeNode)) {
|
|
4407
|
+
const element = typeNode.elementType;
|
|
4408
|
+
if (t.isTSTypeReference(element) && t.isIdentifier(element.typeName)) return element.typeName.name;
|
|
4409
|
+
return;
|
|
4410
|
+
}
|
|
4411
|
+
if (t.isTSTypeReference(typeNode) && t.isIdentifier(typeNode.typeName)) {
|
|
4412
|
+
const containerName = typeNode.typeName.name;
|
|
4413
|
+
if (containerName !== "Array" && containerName !== "ReadonlyArray") return void 0;
|
|
4414
|
+
const args = typeNode.typeParameters?.params;
|
|
4415
|
+
if (!args || args.length !== 1) return void 0;
|
|
4416
|
+
const element = args[0];
|
|
4417
|
+
if (t.isTSTypeReference(element) && t.isIdentifier(element.typeName)) return element.typeName.name;
|
|
4418
|
+
return;
|
|
4419
|
+
}
|
|
4420
|
+
}
|
|
4421
|
+
const ARRAY_PRODUCING_METHODS = new Set([
|
|
4422
|
+
"filter",
|
|
4423
|
+
"map",
|
|
4424
|
+
"slice",
|
|
4425
|
+
"concat",
|
|
4426
|
+
"flat",
|
|
4427
|
+
"flatMap",
|
|
4428
|
+
"sort",
|
|
4429
|
+
"toSorted",
|
|
4430
|
+
"reverse",
|
|
4431
|
+
"toReversed"
|
|
4432
|
+
]);
|
|
4433
|
+
function storeGettersToIr(classDecl) {
|
|
4434
|
+
const getters = [];
|
|
4435
|
+
const fieldShapeByName = /* @__PURE__ */ new Map();
|
|
4436
|
+
for (const field of storeFieldsToIr(classDecl)) if (field.shape) fieldShapeByName.set(field.name, field.shape);
|
|
4437
|
+
for (const member of classDecl.body.body) {
|
|
4438
|
+
if (!t.isClassMethod(member) || member.static || member.computed || member.kind !== "get") continue;
|
|
4439
|
+
if (!t.isIdentifier(member.key)) continue;
|
|
4440
|
+
const returnType = member.returnType;
|
|
4441
|
+
const elementTypeName = returnType && t.isTSTypeAnnotation(returnType) ? arrayElementTypeNameFromTSType(returnType.typeAnnotation) : void 0;
|
|
4442
|
+
const deps = collectThisFieldReads(member.body);
|
|
4443
|
+
const elementShape = getterElementShape(member.body, deps, elementTypeName, fieldShapeByName);
|
|
4444
|
+
const returnsArray = !!elementTypeName || !!elementShape || getterBodyReturnsArray(member.body);
|
|
4445
|
+
const shape = returnsArray ? {
|
|
4446
|
+
kind: "array",
|
|
4447
|
+
...elementShape ? { element: elementShape } : {},
|
|
4448
|
+
...elementTypeName ? { elementTypeName } : {}
|
|
4449
|
+
} : void 0;
|
|
4450
|
+
const ops = storeStmtsToIr(member.body.body);
|
|
4451
|
+
const getter = {
|
|
4452
|
+
name: member.key.name,
|
|
4453
|
+
returnsArray,
|
|
4454
|
+
deps,
|
|
4455
|
+
body: generate(member.body).code,
|
|
4456
|
+
...elementTypeName ? { elementTypeName } : {},
|
|
4457
|
+
...shape ? { shape } : {},
|
|
4458
|
+
...ops ? { ops } : {},
|
|
4459
|
+
...sourceSpan(member) ? { sourceSpan: sourceSpan(member) } : {}
|
|
4460
|
+
};
|
|
4461
|
+
getters.push(getter);
|
|
4462
|
+
}
|
|
4463
|
+
return getters;
|
|
4464
|
+
}
|
|
4465
|
+
function getterElementShape(body, deps, elementTypeName, fieldShapeByName) {
|
|
4466
|
+
const arg = topLevelReturnArgument(body);
|
|
4467
|
+
const fromBody = arg ? elementShapeFromArrayExpression(arg, fieldShapeByName) : void 0;
|
|
4468
|
+
if (fromBody) return fromBody;
|
|
4469
|
+
if (elementTypeName) {
|
|
4470
|
+
for (const shape of fieldShapeByName.values()) if (shape.kind === "array" && shape.elementTypeName === elementTypeName && shape.element?.kind === "object") return shape.element;
|
|
4471
|
+
}
|
|
4472
|
+
for (const dep of deps) {
|
|
4473
|
+
const shape = fieldShapeByName.get(dep);
|
|
4474
|
+
if (shape?.kind === "array" && shape.element?.kind === "object") return shape.element;
|
|
4475
|
+
}
|
|
4476
|
+
}
|
|
4477
|
+
function elementShapeFromArrayExpression(expr, fieldShapeByName) {
|
|
4478
|
+
if (t.isArrayExpression(expr)) {
|
|
4479
|
+
const first = expr.elements.find((element) => !!element && !t.isSpreadElement(element));
|
|
4480
|
+
if (!first) return void 0;
|
|
4481
|
+
const shaped = shapeForExpression(first);
|
|
4482
|
+
return "shape" in shaped ? shaped.shape : void 0;
|
|
4483
|
+
}
|
|
4484
|
+
if (t.isCallExpression(expr) && t.isMemberExpression(expr.callee) && t.isIdentifier(expr.callee.property)) {
|
|
4485
|
+
const method = expr.callee.property.name;
|
|
4486
|
+
if (method === "map") {
|
|
4487
|
+
const objectLiteral = mapCallbackObjectLiteral(expr.arguments[0]);
|
|
4488
|
+
if (!objectLiteral) return void 0;
|
|
4489
|
+
const shaped = shapeForExpression(objectLiteral);
|
|
4490
|
+
return "shape" in shaped ? shaped.shape : void 0;
|
|
4491
|
+
}
|
|
4492
|
+
if (ARRAY_PRODUCING_METHODS.has(method)) return elementShapeFromArrayExpression(expr.callee.object, fieldShapeByName);
|
|
4493
|
+
}
|
|
4494
|
+
if (t.isMemberExpression(expr) && t.isThisExpression(expr.object) && t.isIdentifier(expr.property)) {
|
|
4495
|
+
const shape = fieldShapeByName.get(expr.property.name);
|
|
4496
|
+
if (shape?.kind === "array") return shape.element;
|
|
4497
|
+
}
|
|
4498
|
+
}
|
|
4499
|
+
function mapCallbackObjectLiteral(callback) {
|
|
4500
|
+
if (!callback || !t.isArrowFunctionExpression(callback) && !t.isFunctionExpression(callback)) return void 0;
|
|
4501
|
+
const body = callback.body;
|
|
4502
|
+
if (t.isObjectExpression(body)) return body;
|
|
4503
|
+
if (t.isBlockStatement(body)) {
|
|
4504
|
+
for (const statement of body.body) if (t.isReturnStatement(statement) && statement.argument && t.isObjectExpression(statement.argument)) return statement.argument;
|
|
4505
|
+
}
|
|
4506
|
+
}
|
|
4507
|
+
function topLevelReturnArgument(body) {
|
|
4508
|
+
let result;
|
|
4509
|
+
let done = false;
|
|
4510
|
+
const visit = (value) => {
|
|
4511
|
+
if (done || !value || typeof value !== "object") return;
|
|
4512
|
+
if (Array.isArray(value)) {
|
|
4513
|
+
for (const item of value) visit(item);
|
|
4514
|
+
return;
|
|
4515
|
+
}
|
|
4516
|
+
const node = value;
|
|
4517
|
+
const type = node.type;
|
|
4518
|
+
if (type === "FunctionExpression" || type === "ArrowFunctionExpression" || type === "FunctionDeclaration") return;
|
|
4519
|
+
if (type === "ReturnStatement") {
|
|
4520
|
+
result = node.argument;
|
|
4521
|
+
done = true;
|
|
4522
|
+
return;
|
|
4523
|
+
}
|
|
4524
|
+
for (const key of Object.keys(node)) {
|
|
4525
|
+
if (key === "loc" || key === "start" || key === "end" || key === "range") continue;
|
|
4526
|
+
visit(node[key]);
|
|
4527
|
+
}
|
|
4528
|
+
};
|
|
4529
|
+
visit(body);
|
|
4530
|
+
return result;
|
|
4531
|
+
}
|
|
4532
|
+
function getterBodyReturnsArray(body) {
|
|
4533
|
+
let found = false;
|
|
4534
|
+
const visit = (value) => {
|
|
4535
|
+
if (found || !value || typeof value !== "object") return;
|
|
4536
|
+
if (Array.isArray(value)) {
|
|
4537
|
+
for (const item of value) visit(item);
|
|
4538
|
+
return;
|
|
4539
|
+
}
|
|
4540
|
+
const node = value;
|
|
4541
|
+
const type = node.type;
|
|
4542
|
+
if (type === "FunctionExpression" || type === "ArrowFunctionExpression" || type === "FunctionDeclaration") return;
|
|
4543
|
+
if (type === "ReturnStatement" && isArrayProducingExpression(node.argument)) {
|
|
4544
|
+
found = true;
|
|
4545
|
+
return;
|
|
4546
|
+
}
|
|
4547
|
+
for (const key of Object.keys(node)) {
|
|
4548
|
+
if (key === "loc" || key === "start" || key === "end" || key === "range") continue;
|
|
4549
|
+
visit(node[key]);
|
|
4550
|
+
}
|
|
4551
|
+
};
|
|
4552
|
+
visit(body);
|
|
4553
|
+
return found;
|
|
4554
|
+
}
|
|
4555
|
+
function isArrayProducingExpression(expr) {
|
|
4556
|
+
if (!expr || typeof expr !== "object") return false;
|
|
4557
|
+
const node = expr;
|
|
4558
|
+
if (node.type === "ArrayExpression") return true;
|
|
4559
|
+
if (node.type === "TSAsExpression" || node.type === "TSNonNullExpression") return isArrayProducingExpression(node.expression);
|
|
4560
|
+
if (node.type === "CallExpression") {
|
|
4561
|
+
const callee = node.callee;
|
|
4562
|
+
const property = callee?.property;
|
|
4563
|
+
if (callee?.type === "MemberExpression" && property?.type === "Identifier") return ARRAY_PRODUCING_METHODS.has(property.name);
|
|
4564
|
+
}
|
|
4565
|
+
return false;
|
|
4566
|
+
}
|
|
4567
|
+
function collectThisFieldReads(node) {
|
|
4568
|
+
const names = /* @__PURE__ */ new Set();
|
|
4569
|
+
const visit = (value) => {
|
|
4570
|
+
if (!value || typeof value !== "object") return;
|
|
4571
|
+
if (Array.isArray(value)) {
|
|
4572
|
+
for (const item of value) visit(item);
|
|
4573
|
+
return;
|
|
4574
|
+
}
|
|
4575
|
+
const rec = value;
|
|
4576
|
+
const object = rec.object;
|
|
4577
|
+
const property = rec.property;
|
|
4578
|
+
if (rec.type === "MemberExpression" && object?.type === "ThisExpression" && rec.computed !== true && property?.type === "Identifier") names.add(property.name);
|
|
4579
|
+
for (const key of Object.keys(rec)) {
|
|
4580
|
+
if (key === "loc" || key === "start" || key === "end" || key === "range") continue;
|
|
4581
|
+
visit(rec[key]);
|
|
4582
|
+
}
|
|
4583
|
+
};
|
|
4584
|
+
visit(node);
|
|
4585
|
+
return [...names];
|
|
4586
|
+
}
|
|
4587
|
+
function storeMethodsToIr(classDecl, moduleAst) {
|
|
4588
|
+
const methods = [];
|
|
4589
|
+
const literalUnionAliases = moduleAst ? collectLiteralUnionAliasValueTypes(moduleAst) : void 0;
|
|
4590
|
+
for (const member of classDecl.body.body) {
|
|
4591
|
+
if (!t.isClassMethod(member) || member.static || member.computed || member.kind !== "method") continue;
|
|
4592
|
+
if (!t.isIdentifier(member.key)) continue;
|
|
4593
|
+
const params = [];
|
|
4594
|
+
let unsupportedParam = false;
|
|
4595
|
+
for (const param of member.params) {
|
|
4596
|
+
const assignment = t.isAssignmentPattern(param) ? param : null;
|
|
4597
|
+
const identifier = t.isIdentifier(param) ? param : assignment && t.isIdentifier(assignment.left) ? assignment.left : null;
|
|
4598
|
+
if (identifier) {
|
|
4599
|
+
const valueType = paramValueType(identifier, literalUnionAliases) ?? (assignment ? paramDefaultValueType(assignment.right) : void 0);
|
|
4600
|
+
params.push(valueType ? {
|
|
4601
|
+
name: identifier.name,
|
|
4602
|
+
valueType
|
|
4603
|
+
} : { name: identifier.name });
|
|
4604
|
+
} else {
|
|
4605
|
+
unsupportedParam = true;
|
|
4606
|
+
break;
|
|
4607
|
+
}
|
|
4608
|
+
}
|
|
4609
|
+
if (unsupportedParam) continue;
|
|
4610
|
+
const ops = storeStmtsToIr(member.body.body);
|
|
4611
|
+
methods.push({
|
|
4612
|
+
name: member.key.name,
|
|
4613
|
+
params,
|
|
4614
|
+
body: generate(member.body).code,
|
|
4615
|
+
...ops ? { ops } : {},
|
|
4616
|
+
...sourceSpan(member) ? { sourceSpan: sourceSpan(member) } : {}
|
|
4617
|
+
});
|
|
4618
|
+
}
|
|
4619
|
+
return methods;
|
|
4620
|
+
}
|
|
4621
|
+
function paramValueType(param, literalUnionAliases) {
|
|
4622
|
+
const annotation = param.typeAnnotation;
|
|
4623
|
+
if (!annotation || !t.isTSTypeAnnotation(annotation)) return void 0;
|
|
4624
|
+
const kind = annotation.typeAnnotation;
|
|
4625
|
+
if (t.isTSStringKeyword(kind)) return "string";
|
|
4626
|
+
if (t.isTSNumberKeyword(kind)) return "number";
|
|
4627
|
+
if (t.isTSBooleanKeyword(kind)) return "boolean";
|
|
4628
|
+
const inlineLiteral = literalUnionValueType(kind);
|
|
4629
|
+
if (inlineLiteral) return inlineLiteral;
|
|
4630
|
+
if (literalUnionAliases && t.isTSTypeReference(kind) && t.isIdentifier(kind.typeName)) return literalUnionAliases.get(kind.typeName.name);
|
|
4631
|
+
}
|
|
4632
|
+
function literalUnionValueType(kind) {
|
|
4633
|
+
if (t.isTSLiteralType(kind)) {
|
|
4634
|
+
if (t.isStringLiteral(kind.literal)) return "string";
|
|
4635
|
+
if (t.isNumericLiteral(kind.literal)) return "number";
|
|
4636
|
+
if (t.isBooleanLiteral(kind.literal)) return "boolean";
|
|
4637
|
+
return;
|
|
4638
|
+
}
|
|
4639
|
+
if (t.isTSUnionType(kind)) {
|
|
4640
|
+
let valueType;
|
|
4641
|
+
for (const member of kind.types) {
|
|
4642
|
+
const memberType = literalUnionValueType(member);
|
|
4643
|
+
if (!memberType || valueType && memberType !== valueType) return void 0;
|
|
4644
|
+
valueType = memberType;
|
|
4645
|
+
}
|
|
4646
|
+
return valueType;
|
|
4647
|
+
}
|
|
4648
|
+
}
|
|
4649
|
+
function collectLiteralUnionAliasValueTypes(ast) {
|
|
4650
|
+
const aliases = /* @__PURE__ */ new Map();
|
|
4651
|
+
for (const node of ast.program.body) {
|
|
4652
|
+
const alias = t.isTSTypeAliasDeclaration(node) ? node : t.isExportNamedDeclaration(node) && t.isTSTypeAliasDeclaration(node.declaration) ? node.declaration : null;
|
|
4653
|
+
if (!alias || !t.isIdentifier(alias.id)) continue;
|
|
4654
|
+
const valueType = literalUnionValueType(alias.typeAnnotation);
|
|
4655
|
+
if (valueType) aliases.set(alias.id.name, valueType);
|
|
4656
|
+
}
|
|
4657
|
+
return aliases;
|
|
4658
|
+
}
|
|
4659
|
+
function paramDefaultValueType(expr) {
|
|
4660
|
+
if (t.isStringLiteral(expr)) return "string";
|
|
4661
|
+
if (t.isNumericLiteral(expr)) return "number";
|
|
4662
|
+
if (t.isBooleanLiteral(expr)) return "boolean";
|
|
4663
|
+
}
|
|
4664
|
+
function storeStmtsToIr(statements) {
|
|
4665
|
+
const out = [];
|
|
4666
|
+
for (const statement of statements) {
|
|
4667
|
+
const converted = storeStmtToIr(statement);
|
|
4668
|
+
if (!converted) return null;
|
|
4669
|
+
out.push(...converted);
|
|
4670
|
+
}
|
|
4671
|
+
return out;
|
|
4672
|
+
}
|
|
4673
|
+
function storeStmtToIr(statement) {
|
|
4674
|
+
if (t.isBlockStatement(statement)) return storeStmtsToIr(statement.body);
|
|
4675
|
+
if (t.isVariableDeclaration(statement)) {
|
|
4676
|
+
const declarations = [];
|
|
4677
|
+
for (const declaration of statement.declarations) {
|
|
4678
|
+
if (!t.isIdentifier(declaration.id)) return null;
|
|
4679
|
+
const init = declaration.init ? storeExprToIr(declaration.init) : void 0;
|
|
4680
|
+
if (declaration.init && !init) return null;
|
|
4681
|
+
declarations.push({
|
|
4682
|
+
kind: "var",
|
|
4683
|
+
name: declaration.id.name,
|
|
4684
|
+
mutable: statement.kind !== "const",
|
|
4685
|
+
...init ? { init } : {}
|
|
4686
|
+
});
|
|
4687
|
+
}
|
|
4688
|
+
return declarations;
|
|
4689
|
+
}
|
|
4690
|
+
if (t.isExpressionStatement(statement)) {
|
|
4691
|
+
const expr = statement.expression;
|
|
4692
|
+
if (t.isAssignmentExpression(expr) && expr.operator === "=") {
|
|
4693
|
+
const target = storeExprToIr(expr.left);
|
|
4694
|
+
const value = storeExprToIr(expr.right);
|
|
4695
|
+
return target && value ? [{
|
|
4696
|
+
kind: "assign",
|
|
4697
|
+
target,
|
|
4698
|
+
value
|
|
4699
|
+
}] : null;
|
|
4700
|
+
}
|
|
4701
|
+
const converted = storeExprToIr(expr);
|
|
4702
|
+
return converted ? [{
|
|
4703
|
+
kind: "expr",
|
|
4704
|
+
expr: converted
|
|
4705
|
+
}] : null;
|
|
4706
|
+
}
|
|
4707
|
+
if (t.isIfStatement(statement)) {
|
|
4708
|
+
const test = storeExprToIr(statement.test);
|
|
4709
|
+
const consequent = storeStatementList(statement.consequent);
|
|
4710
|
+
const alternate = statement.alternate ? storeStatementList(statement.alternate) : void 0;
|
|
4711
|
+
if (!test || !consequent || statement.alternate && !alternate) return null;
|
|
4712
|
+
return [{
|
|
4713
|
+
kind: "if",
|
|
4714
|
+
test,
|
|
4715
|
+
consequent,
|
|
4716
|
+
...alternate ? { alternate } : {}
|
|
4717
|
+
}];
|
|
4718
|
+
}
|
|
4719
|
+
if (t.isForStatement(statement)) {
|
|
4720
|
+
const init = statement.init ? storeStmtToIr(t.isVariableDeclaration(statement.init) ? statement.init : t.expressionStatement(statement.init)) : void 0;
|
|
4721
|
+
const test = statement.test ? storeExprToIr(statement.test) : void 0;
|
|
4722
|
+
const update = statement.update ? storeExprToIr(statement.update) : void 0;
|
|
4723
|
+
const body = storeStatementList(statement.body);
|
|
4724
|
+
if (statement.init && (!init || init.length !== 1) || statement.test && !test || statement.update && !update || !body) return null;
|
|
4725
|
+
return [{
|
|
4726
|
+
kind: "for",
|
|
4727
|
+
...init ? { init: init[0] } : {},
|
|
4728
|
+
...test ? { test } : {},
|
|
4729
|
+
...update ? { update } : {},
|
|
4730
|
+
body
|
|
4731
|
+
}];
|
|
4732
|
+
}
|
|
4733
|
+
if (t.isReturnStatement(statement)) {
|
|
4734
|
+
const value = statement.argument ? storeExprToIr(statement.argument) : void 0;
|
|
4735
|
+
if (statement.argument && !value) return null;
|
|
4736
|
+
return [{
|
|
4737
|
+
kind: "return",
|
|
4738
|
+
...value ? { value } : {}
|
|
4739
|
+
}];
|
|
4740
|
+
}
|
|
4741
|
+
return null;
|
|
4742
|
+
}
|
|
4743
|
+
function storeStatementList(statement) {
|
|
4744
|
+
if (t.isBlockStatement(statement)) return storeStmtsToIr(statement.body);
|
|
4745
|
+
return storeStmtToIr(statement);
|
|
4746
|
+
}
|
|
4747
|
+
function storeExprToIr(expression) {
|
|
4748
|
+
if (t.isIdentifier(expression)) return {
|
|
4749
|
+
kind: "identifier",
|
|
4750
|
+
name: expression.name
|
|
4751
|
+
};
|
|
4752
|
+
if (t.isThisExpression(expression)) return { kind: "this" };
|
|
4753
|
+
if (t.isNumericLiteral(expression)) return {
|
|
4754
|
+
kind: "number",
|
|
4755
|
+
value: expression.value
|
|
4756
|
+
};
|
|
4757
|
+
if (t.isStringLiteral(expression)) return {
|
|
4758
|
+
kind: "string",
|
|
4759
|
+
value: expression.value
|
|
4760
|
+
};
|
|
4761
|
+
if (t.isBooleanLiteral(expression)) return {
|
|
4762
|
+
kind: "boolean",
|
|
4763
|
+
value: expression.value
|
|
4764
|
+
};
|
|
4765
|
+
if (t.isNullLiteral(expression)) return { kind: "null" };
|
|
4766
|
+
if (t.isMemberExpression(expression)) {
|
|
4767
|
+
const object = storeExprToIr(expression.object);
|
|
4768
|
+
if (!object) return null;
|
|
4769
|
+
if (expression.computed) {
|
|
4770
|
+
const index = storeExprToIr(expression.property);
|
|
4771
|
+
return index ? {
|
|
4772
|
+
kind: "index",
|
|
4773
|
+
object,
|
|
4774
|
+
index
|
|
4775
|
+
} : null;
|
|
4776
|
+
}
|
|
4777
|
+
return t.isIdentifier(expression.property) ? {
|
|
4778
|
+
kind: "member",
|
|
4779
|
+
object,
|
|
4780
|
+
property: expression.property.name
|
|
4781
|
+
} : null;
|
|
4782
|
+
}
|
|
4783
|
+
if (t.isCallExpression(expression)) {
|
|
4784
|
+
const callee = storeExprToIr(expression.callee);
|
|
4785
|
+
const args = expression.arguments.map((arg) => t.isSpreadElement(arg) ? null : storeExprToIr(arg));
|
|
4786
|
+
return callee && args.every((arg) => !!arg) ? {
|
|
4787
|
+
kind: "call",
|
|
4788
|
+
callee,
|
|
4789
|
+
args
|
|
4790
|
+
} : null;
|
|
4791
|
+
}
|
|
4792
|
+
if (t.isObjectExpression(expression)) {
|
|
4793
|
+
const fields = [];
|
|
4794
|
+
for (const property of expression.properties) {
|
|
4795
|
+
if (!t.isObjectProperty(property) || property.computed) return null;
|
|
4796
|
+
const name = objectPropertyName(property.key);
|
|
4797
|
+
const value = storeExprToIr(property.value);
|
|
4798
|
+
if (!name || !value) return null;
|
|
4799
|
+
fields.push({
|
|
4800
|
+
name,
|
|
4801
|
+
value
|
|
4802
|
+
});
|
|
4803
|
+
}
|
|
4804
|
+
return {
|
|
4805
|
+
kind: "object",
|
|
4806
|
+
fields
|
|
4807
|
+
};
|
|
4808
|
+
}
|
|
4809
|
+
if (t.isUnaryExpression(expression)) {
|
|
4810
|
+
const arg = storeExprToIr(expression.argument);
|
|
4811
|
+
return arg ? {
|
|
4812
|
+
kind: "unary",
|
|
4813
|
+
op: expression.operator,
|
|
4814
|
+
arg
|
|
4815
|
+
} : null;
|
|
4816
|
+
}
|
|
4817
|
+
if (t.isBinaryExpression(expression)) {
|
|
4818
|
+
const left = storeExprToIr(expression.left);
|
|
4819
|
+
const right = storeExprToIr(expression.right);
|
|
4820
|
+
return left && right ? {
|
|
4821
|
+
kind: "binary",
|
|
4822
|
+
op: expression.operator,
|
|
4823
|
+
left,
|
|
4824
|
+
right
|
|
4825
|
+
} : null;
|
|
4826
|
+
}
|
|
4827
|
+
if (t.isLogicalExpression(expression)) {
|
|
4828
|
+
const left = storeExprToIr(expression.left);
|
|
4829
|
+
const right = storeExprToIr(expression.right);
|
|
4830
|
+
return left && right ? {
|
|
4831
|
+
kind: "logical",
|
|
4832
|
+
op: expression.operator,
|
|
4833
|
+
left,
|
|
4834
|
+
right
|
|
4835
|
+
} : null;
|
|
4836
|
+
}
|
|
4837
|
+
if (t.isUpdateExpression(expression)) {
|
|
4838
|
+
const arg = storeExprToIr(expression.argument);
|
|
4839
|
+
return arg ? {
|
|
4840
|
+
kind: "update",
|
|
4841
|
+
op: expression.operator,
|
|
4842
|
+
arg,
|
|
4843
|
+
prefix: expression.prefix
|
|
4844
|
+
} : null;
|
|
4845
|
+
}
|
|
4846
|
+
return null;
|
|
4847
|
+
}
|
|
4848
|
+
function sourceSpan(node) {
|
|
4849
|
+
const span = {};
|
|
4850
|
+
if (typeof node.start === "number") span.start = node.start;
|
|
4851
|
+
if (typeof node.end === "number") span.end = node.end;
|
|
4852
|
+
return span.start === void 0 && span.end === void 0 ? void 0 : span;
|
|
4853
|
+
}
|
|
4854
|
+
function slotToIr(slot, bindings) {
|
|
4855
|
+
const expr = slot.expr ? substituteBindings(slot.expr, bindings) : null;
|
|
4856
|
+
return {
|
|
4857
|
+
index: slot.index,
|
|
4858
|
+
kind: slot.kind,
|
|
4859
|
+
walk: slot.walk,
|
|
4860
|
+
...slot.walkKinds ? { walkKinds: slot.walkKinds } : {},
|
|
4861
|
+
...expr ? { expr: generate(expr).code } : {},
|
|
4862
|
+
...expr ? expressionPathToIr(expr) : {},
|
|
4863
|
+
...expr ? expressionObjectFieldsToIr(expr) : {},
|
|
4864
|
+
...slot.payload ? { payload: slotPayloadToIr(slot, bindings) } : {},
|
|
4865
|
+
...slot.directText ? { directText: true } : {}
|
|
4866
|
+
};
|
|
4867
|
+
}
|
|
4868
|
+
function expressionPathToIr(expr) {
|
|
4869
|
+
const path = expressionPath(expr);
|
|
4870
|
+
return path && path.length > 0 ? { exprPath: path } : {};
|
|
4871
|
+
}
|
|
4872
|
+
function expressionPath(expr) {
|
|
4873
|
+
if (t.isIdentifier(expr)) return [expr.name];
|
|
4874
|
+
if (t.isThisExpression(expr)) return ["this"];
|
|
4875
|
+
if (t.isMemberExpression(expr) && !expr.computed) {
|
|
4876
|
+
const objectPath = expressionPath(expr.object);
|
|
4877
|
+
const property = t.isIdentifier(expr.property) ? expr.property.name : null;
|
|
4878
|
+
return objectPath && property ? [...objectPath, property] : null;
|
|
4879
|
+
}
|
|
4880
|
+
if (t.isOptionalMemberExpression(expr) && !expr.computed) {
|
|
4881
|
+
const objectPath = expressionPath(expr.object);
|
|
4882
|
+
const property = t.isIdentifier(expr.property) ? expr.property.name : null;
|
|
4883
|
+
return objectPath && property ? [...objectPath, property] : null;
|
|
4884
|
+
}
|
|
4885
|
+
return null;
|
|
4886
|
+
}
|
|
4887
|
+
function expressionObjectFieldsToIr(expr) {
|
|
4888
|
+
if (!t.isObjectExpression(expr)) return {};
|
|
4889
|
+
const fields = [];
|
|
4890
|
+
for (const property of expr.properties) {
|
|
4891
|
+
if (!t.isObjectProperty(property) || property.computed) continue;
|
|
4892
|
+
const name = objectPropertyName(property.key);
|
|
4893
|
+
if (!name) continue;
|
|
4894
|
+
fields.push({
|
|
4895
|
+
name,
|
|
4896
|
+
expr: generate(property.value).code,
|
|
4897
|
+
...expressionPathToIr(property.value)
|
|
4898
|
+
});
|
|
4899
|
+
}
|
|
4900
|
+
return fields.length > 0 ? { exprObjectFields: fields } : {};
|
|
4901
|
+
}
|
|
4902
|
+
function slotPayloadToIr(slot, bindings) {
|
|
4903
|
+
const payload = serializePayload(slot.payload, bindings);
|
|
4904
|
+
if (!isRecord(payload)) return payload;
|
|
4905
|
+
if (slot.kind === "keyed-list") {
|
|
4906
|
+
const cb = slot.payload?.mapCallback;
|
|
4907
|
+
const row = keyedListRowIr(cb);
|
|
4908
|
+
return row ? {
|
|
4909
|
+
...payload,
|
|
4910
|
+
...row
|
|
4911
|
+
} : payload;
|
|
4912
|
+
}
|
|
4913
|
+
if (slot.kind === "conditional") {
|
|
4914
|
+
const result = { ...payload };
|
|
4915
|
+
const consequent = jsxNodeToTemplateIr(slot.payload?.mkTrue, bindings);
|
|
4916
|
+
if (consequent) result.consequentTemplate = consequent;
|
|
4917
|
+
const alternate = jsxNodeToTemplateIr(slot.payload?.mkFalse, bindings);
|
|
4918
|
+
if (alternate) result.alternateTemplate = alternate;
|
|
4919
|
+
return result;
|
|
4920
|
+
}
|
|
4921
|
+
if (slot.kind === "mount") {
|
|
4922
|
+
const children = slot.payload?.children;
|
|
4923
|
+
const childrenTemplate = jsxChildrenToTemplateIr(children, bindings);
|
|
4924
|
+
if (childrenTemplate) return {
|
|
4925
|
+
...payload,
|
|
4926
|
+
childrenTemplate
|
|
4927
|
+
};
|
|
4928
|
+
}
|
|
4929
|
+
return payload;
|
|
4930
|
+
}
|
|
4931
|
+
function jsxNodeToTemplateIr(node, bindings) {
|
|
4932
|
+
if (!node) return null;
|
|
4933
|
+
if (t.isJSXElement(node) || t.isJSXFragment(node)) return templateSpecToIr(walkJsxToTemplate(node), bindings);
|
|
4934
|
+
if (t.isJSXExpressionContainer(node)) {
|
|
4935
|
+
const inner = node.expression;
|
|
4936
|
+
if (t.isJSXElement(inner) || t.isJSXFragment(inner)) return templateSpecToIr(walkJsxToTemplate(inner), bindings);
|
|
4937
|
+
if (isWalkableConditionalExpression(inner)) return wrapAsFragmentTemplate(inner, bindings);
|
|
4938
|
+
}
|
|
4939
|
+
if (isWalkableConditionalExpression(node)) return wrapAsFragmentTemplate(node, bindings);
|
|
4940
|
+
return null;
|
|
4941
|
+
}
|
|
4942
|
+
function isWalkableConditionalExpression(node) {
|
|
4943
|
+
if (t.isConditionalExpression(node)) return isJsxOrNullish(node.consequent) || isJsxOrNullish(node.alternate);
|
|
4944
|
+
if (t.isLogicalExpression(node) && node.operator === "&&") return isJsxOrNullish(node.right);
|
|
4945
|
+
return false;
|
|
4946
|
+
}
|
|
4947
|
+
function wrapAsFragmentTemplate(expression, bindings) {
|
|
4948
|
+
return templateSpecToIr(walkJsxToTemplate(t.jsxFragment(t.jsxOpeningFragment(), t.jsxClosingFragment(), [t.jsxExpressionContainer(expression)])), bindings);
|
|
4949
|
+
}
|
|
4950
|
+
function jsxChildrenToTemplateIr(children, bindings) {
|
|
4951
|
+
if (!Array.isArray(children) || children.length === 0) return null;
|
|
4952
|
+
if (!children.some((c) => t.isJSXElement(c) || t.isJSXFragment(c) || t.isJSXExpressionContainer(c) && !t.isJSXEmptyExpression(c.expression))) return null;
|
|
4953
|
+
return templateSpecToIr(walkJsxToTemplate(t.jsxFragment(t.jsxOpeningFragment(), t.jsxClosingFragment(), children)), bindings);
|
|
4954
|
+
}
|
|
4955
|
+
function keyedListRowIr(cb) {
|
|
4956
|
+
if (!t.isArrowFunctionExpression(cb) && !t.isFunctionExpression(cb)) return null;
|
|
4957
|
+
const body = callbackJsxBody(cb.body);
|
|
4958
|
+
if (!body) return null;
|
|
4959
|
+
const itemParam = callbackParamName(cb.params[0]);
|
|
4960
|
+
const indexParam = callbackParamName(cb.params[1]);
|
|
4961
|
+
return {
|
|
4962
|
+
...itemParam ? { itemParam } : {},
|
|
4963
|
+
...indexParam ? { indexParam } : {},
|
|
4964
|
+
rowTemplate: templateSpecToIr(walkJsxToTemplate(body))
|
|
4965
|
+
};
|
|
4966
|
+
}
|
|
4967
|
+
function callbackJsxBody(body) {
|
|
4968
|
+
if (t.isJSXElement(body) || t.isJSXFragment(body)) return body;
|
|
4969
|
+
if (!t.isBlockStatement(body)) return null;
|
|
4970
|
+
for (const statement of body.body) {
|
|
4971
|
+
if (!t.isReturnStatement(statement) || !statement.argument) continue;
|
|
4972
|
+
if (t.isJSXElement(statement.argument) || t.isJSXFragment(statement.argument)) return statement.argument;
|
|
4973
|
+
}
|
|
4974
|
+
return null;
|
|
4975
|
+
}
|
|
4976
|
+
function callbackParamName(param) {
|
|
4977
|
+
return t.isIdentifier(param) ? param.name : void 0;
|
|
4978
|
+
}
|
|
4979
|
+
function serializePayload(value, bindings) {
|
|
4980
|
+
if (value === null || value === void 0) return value;
|
|
4981
|
+
if (typeof value !== "object") return value;
|
|
4982
|
+
if (Array.isArray(value)) return value.map((child) => serializePayload(child, bindings));
|
|
4983
|
+
if (isBabelNode(value)) {
|
|
4984
|
+
const node = substitutePayloadNode(value, bindings);
|
|
4985
|
+
return {
|
|
4986
|
+
nodeType: node.type,
|
|
4987
|
+
code: generate(node).code
|
|
4988
|
+
};
|
|
4989
|
+
}
|
|
4990
|
+
const out = {};
|
|
4991
|
+
for (const [key, child] of Object.entries(value)) out[key] = serializePayload(child, bindings);
|
|
4992
|
+
return out;
|
|
4993
|
+
}
|
|
4994
|
+
function substitutePayloadNode(value, bindings) {
|
|
4995
|
+
if (bindings.size === 0) return value;
|
|
4996
|
+
if (t.isJSXAttribute(value) && value.value && t.isJSXExpressionContainer(value.value) && !t.isJSXEmptyExpression(value.value.expression)) return {
|
|
4997
|
+
...value,
|
|
4998
|
+
value: {
|
|
4999
|
+
...value.value,
|
|
5000
|
+
expression: substituteBindings(value.value.expression, bindings)
|
|
5001
|
+
}
|
|
5002
|
+
};
|
|
5003
|
+
if (t.isJSXExpressionContainer(value) && !t.isJSXEmptyExpression(value.expression)) return {
|
|
5004
|
+
...value,
|
|
5005
|
+
expression: substituteBindings(value.expression, bindings)
|
|
5006
|
+
};
|
|
5007
|
+
return substituteBindings(value, bindings);
|
|
5008
|
+
}
|
|
5009
|
+
function isBabelNode(value) {
|
|
5010
|
+
return !!value && typeof value === "object" && typeof value.type === "string";
|
|
5011
|
+
}
|
|
5012
|
+
function isRecord(value) {
|
|
5013
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
5014
|
+
}
|
|
5015
|
+
function shapeForExpression(value) {
|
|
5016
|
+
if (t.isStringLiteral(value)) return { shape: {
|
|
5017
|
+
kind: "literal",
|
|
5018
|
+
valueType: "string"
|
|
5019
|
+
} };
|
|
5020
|
+
if (t.isNumericLiteral(value)) return { shape: {
|
|
5021
|
+
kind: "literal",
|
|
5022
|
+
valueType: "number"
|
|
5023
|
+
} };
|
|
5024
|
+
if (t.isBooleanLiteral(value)) return { shape: {
|
|
5025
|
+
kind: "literal",
|
|
5026
|
+
valueType: "boolean"
|
|
5027
|
+
} };
|
|
5028
|
+
if (t.isNullLiteral(value)) return { shape: {
|
|
5029
|
+
kind: "literal",
|
|
5030
|
+
valueType: "null"
|
|
5031
|
+
} };
|
|
5032
|
+
if (t.isArrayExpression(value)) {
|
|
5033
|
+
const firstElement = value.elements.find((element) => !!element && !t.isSpreadElement(element));
|
|
5034
|
+
const shapedElement = firstElement ? shapeForExpression(firstElement) : {};
|
|
5035
|
+
const elementShape = "shape" in shapedElement ? shapedElement.shape : void 0;
|
|
5036
|
+
return { shape: {
|
|
5037
|
+
kind: "array",
|
|
5038
|
+
...elementShape ? { element: elementShape } : {}
|
|
5039
|
+
} };
|
|
5040
|
+
}
|
|
5041
|
+
if (t.isObjectExpression(value)) {
|
|
5042
|
+
const fields = [];
|
|
5043
|
+
for (const property of value.properties) {
|
|
5044
|
+
if (!t.isObjectProperty(property) || property.computed) continue;
|
|
5045
|
+
const name = objectPropertyName(property.key);
|
|
5046
|
+
if (!name) continue;
|
|
5047
|
+
fields.push({
|
|
5048
|
+
name,
|
|
5049
|
+
...property.value ? { initializer: generate(property.value).code } : {},
|
|
5050
|
+
...property.value ? shapeForExpression(property.value) : {}
|
|
5051
|
+
});
|
|
5052
|
+
}
|
|
5053
|
+
return { shape: {
|
|
5054
|
+
kind: "object",
|
|
5055
|
+
fields
|
|
5056
|
+
} };
|
|
5057
|
+
}
|
|
5058
|
+
return {};
|
|
5059
|
+
}
|
|
5060
|
+
function objectPropertyName(key) {
|
|
5061
|
+
if (t.isIdentifier(key)) return key.name;
|
|
5062
|
+
if (t.isStringLiteral(key)) return key.value;
|
|
5063
|
+
if (t.isNumericLiteral(key)) return String(key.value);
|
|
5064
|
+
return null;
|
|
5065
|
+
}
|
|
5066
|
+
//#endregion
|
|
5067
|
+
//#region src/closure-codegen/emit/emit-core.ts
|
|
5068
|
+
function compileJsxToBlock(jsxRoot, ctx) {
|
|
5069
|
+
const spec = walkJsxToTemplate(jsxRoot, {
|
|
5070
|
+
emitEventDataAttr: false,
|
|
5071
|
+
directFnComponents: ctx.directFnComponents,
|
|
5072
|
+
bindings: ctx.bindings
|
|
5073
|
+
});
|
|
5074
|
+
if (t.isJSXFragment(jsxRoot)) spec.html = "<span style=\"display:contents\">" + spec.html + "</span>";
|
|
5075
|
+
else if (!spec.html.startsWith("<") || spec.html.startsWith("<!--")) {
|
|
5076
|
+
spec.html = "<span style=\"display:contents\">" + spec.html + "</span>";
|
|
5077
|
+
for (const slot of spec.slots) slot.walk = [0, ...slot.walk];
|
|
5078
|
+
}
|
|
5079
|
+
if (ctx.irTemplates && ctx.currentIrComponent && ctx.currentIrRuntimeBase) ctx.irTemplates.push({
|
|
5080
|
+
component: ctx.currentIrComponent,
|
|
5081
|
+
runtimeBase: ctx.currentIrRuntimeBase,
|
|
5082
|
+
template: templateSpecToIr(spec, ctx.bindings)
|
|
5083
|
+
});
|
|
5084
|
+
const tplName = "_tpl" + ctx.tplCounter++;
|
|
5085
|
+
ctx.templateDecls.push(...emitTemplateDecl(spec.html, tplName));
|
|
5086
|
+
const stmts = [];
|
|
5087
|
+
stmts.push(t.variableDeclaration("const", [t.variableDeclarator(t.identifier("root"), emitTemplateCloneExpression(tplName, spec.html))]));
|
|
5088
|
+
const walkCache = /* @__PURE__ */ new Map();
|
|
5089
|
+
for (const slot of spec.slots) emitWalkCapture(slot, stmts, false, walkCache);
|
|
5090
|
+
const savedPending = ctx._pendingEvents;
|
|
5091
|
+
const savedInputValueExprByEventSlot = ctx._inputValueExprByEventSlot;
|
|
5092
|
+
const savedDocumentClickDelegateInstalled = ctx._documentClickDelegateInstalled;
|
|
5093
|
+
ctx._pendingEvents = [];
|
|
5094
|
+
ctx._inputValueExprByEventSlot = findInputValueReconciliations(spec);
|
|
4133
5095
|
ctx._documentClickDelegateInstalled = false;
|
|
4134
5096
|
for (const slot of spec.slots) emitSlot(slot, stmts, ctx);
|
|
4135
5097
|
const events = ctx._pendingEvents;
|
|
@@ -4431,6 +5393,11 @@ function rewriteFnComponent(fnDecl, parentCtx) {
|
|
|
4431
5393
|
fnCtx.directFnComponentParams = parentCtx.directFnComponentParams;
|
|
4432
5394
|
fnCtx.directFnStringProps = parentCtx.directFnStringProps;
|
|
4433
5395
|
fnCtx.directFnNoDisposer = parentCtx.directFnNoDisposer;
|
|
5396
|
+
if (parentCtx.irTemplates && fnName) {
|
|
5397
|
+
fnCtx.irTemplates = parentCtx.irTemplates;
|
|
5398
|
+
fnCtx.currentIrComponent = fnName;
|
|
5399
|
+
fnCtx.currentIrRuntimeBase = "reactive";
|
|
5400
|
+
}
|
|
4434
5401
|
if (fnCtx.oneShotProps) {
|
|
4435
5402
|
fnCtx._inKeyedListRow = true;
|
|
4436
5403
|
fnCtx._rowEventTypes = /* @__PURE__ */ new Set();
|
|
@@ -4856,6 +5823,8 @@ function transformFile(source, _filename, options = {}) {
|
|
|
4856
5823
|
};
|
|
4857
5824
|
}
|
|
4858
5825
|
const ctx = createEmitContext();
|
|
5826
|
+
ctx.irTemplates = [];
|
|
5827
|
+
ctx.embedded = options.embedded;
|
|
4859
5828
|
ctx.directFnComponents = collectDirectFnComponents(ast);
|
|
4860
5829
|
ctx.directFnComponentParams = collectDirectFnComponentParams(ast, ctx.directFnComponents);
|
|
4861
5830
|
ctx.directFnStringProps = collectDirectFnStringProps(ast, ctx.directFnComponents);
|
|
@@ -4864,6 +5833,7 @@ function transformFile(source, _filename, options = {}) {
|
|
|
4864
5833
|
for (const name of options.directClassComponents ?? []) ctx.directClassComponents.add(name);
|
|
4865
5834
|
ctx.directFactoryComponents = new Set(options.directFactoryComponents);
|
|
4866
5835
|
const rewritten = [];
|
|
5836
|
+
const reactiveComponentNames = /* @__PURE__ */ new Set();
|
|
4867
5837
|
let firstClassIdx = -1;
|
|
4868
5838
|
for (let i = 0; i < ast.program.body.length; i++) {
|
|
4869
5839
|
const node = ast.program.body[i];
|
|
@@ -4899,9 +5869,21 @@ function transformFile(source, _filename, options = {}) {
|
|
|
4899
5869
|
const useTinyReactiveComponent = options.enableTinyReactiveComponents !== false && !useStaticCompiledComponent && !useCompiledComponent && canUseTinyReactiveComponent(classDecl);
|
|
4900
5870
|
const useLeanReactiveComponent = !useStaticCompiledComponent && !useCompiledComponent && !useTinyReactiveComponent && canUseLeanReactiveComponent(classDecl);
|
|
4901
5871
|
const hasAfterRenderAsyncHook = hasOwnInstanceMethod(classDecl, "onAfterRenderAsync");
|
|
5872
|
+
const className = classDecl.id && classDecl.id.name || "<anonymous>";
|
|
5873
|
+
if (t.isIdentifier(classDecl.superClass, { name: "ReactiveComponent" })) reactiveComponentNames.add(className);
|
|
5874
|
+
const runtimeBase = runtimeBaseForComponent({
|
|
5875
|
+
useStaticCompiledComponent,
|
|
5876
|
+
useCompiledComponent,
|
|
5877
|
+
useTinyReactiveComponent,
|
|
5878
|
+
useLeanReactiveComponent
|
|
5879
|
+
});
|
|
5880
|
+
ctx.currentIrComponent = className;
|
|
5881
|
+
ctx.currentIrRuntimeBase = runtimeBase;
|
|
4902
5882
|
for (const m of methodsWithJsx) m.body.body = m.body.body.map((s) => lowerJsxInStatement(s, ctx));
|
|
4903
5883
|
if (!templateMethod) {
|
|
4904
|
-
rewritten.push(
|
|
5884
|
+
rewritten.push(className);
|
|
5885
|
+
ctx.currentIrComponent = void 0;
|
|
5886
|
+
ctx.currentIrRuntimeBase = void 0;
|
|
4905
5887
|
continue;
|
|
4906
5888
|
}
|
|
4907
5889
|
const paramBindings = [];
|
|
@@ -4921,14 +5903,26 @@ function transformFile(source, _filename, options = {}) {
|
|
|
4921
5903
|
ctx.importsNeeded.add(templateSymbol);
|
|
4922
5904
|
const method = buildCreateTemplateMethod(jsx, ctx, preceding, templateSymbol);
|
|
4923
5905
|
const useStaticElementComponent = useStaticCompiledComponent && isStaticBuiltinElementRoot(jsx) && !nodeContainsIdentifier$1(method.body, "d");
|
|
5906
|
+
if (useStaticElementComponent && ctx.irTemplates) {
|
|
5907
|
+
for (const template of ctx.irTemplates) if (template.component === className) template.runtimeBase = "static-element";
|
|
5908
|
+
}
|
|
4924
5909
|
if (useStaticElementComponent) method.params = [];
|
|
4925
5910
|
if (plainPropsParamName) ctx.bindings.delete(plainPropsParamName);
|
|
4926
5911
|
for (const k of paramBindings) ctx.bindings.delete(k);
|
|
5912
|
+
const isReactiveComponent = reactiveComponentNames.has(className);
|
|
4927
5913
|
const bodyItems = classDecl.body.body;
|
|
4928
5914
|
const templateIdx = bodyItems.indexOf(templateMethod);
|
|
4929
|
-
if (templateIdx >= 0)
|
|
5915
|
+
if (templateIdx >= 0) if (isReactiveComponent) {
|
|
5916
|
+
bodyItems.splice(templateIdx, 1);
|
|
5917
|
+
const keepAlive = mountedComponentKeepAliveStatements(jsx, ast);
|
|
5918
|
+
if (keepAlive.length > 0) ast.program.body.splice(i + 1, 0, ...keepAlive);
|
|
5919
|
+
} else bodyItems[templateIdx] = method;
|
|
4930
5920
|
let usesCompiledRuntimeBase = false;
|
|
4931
|
-
if (
|
|
5921
|
+
if (isReactiveComponent) {
|
|
5922
|
+
classDecl.superClass = null;
|
|
5923
|
+
usesCompiledRuntimeBase = false;
|
|
5924
|
+
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()));
|
|
5925
|
+
} else if (useStaticElementComponent) {
|
|
4932
5926
|
ctx.importsNeeded.add("CompiledStaticElementComponent");
|
|
4933
5927
|
classDecl.superClass = t.identifier("CompiledStaticElementComponent");
|
|
4934
5928
|
usesCompiledRuntimeBase = true;
|
|
@@ -4957,7 +5951,9 @@ function transformFile(source, _filename, options = {}) {
|
|
|
4957
5951
|
ctx.importsNeeded.add("scheduleAfterRenderAsync");
|
|
4958
5952
|
classDecl.body.body.push(buildAfterRenderAsyncRenderMethod());
|
|
4959
5953
|
}
|
|
4960
|
-
rewritten.push(
|
|
5954
|
+
rewritten.push(className);
|
|
5955
|
+
ctx.currentIrComponent = void 0;
|
|
5956
|
+
ctx.currentIrRuntimeBase = void 0;
|
|
4961
5957
|
continue;
|
|
4962
5958
|
}
|
|
4963
5959
|
if (fnDecl && isFunctionComponent(fnDecl)) {
|
|
@@ -4984,9 +5980,90 @@ function transformFile(source, _filename, options = {}) {
|
|
|
4984
5980
|
map: out.map,
|
|
4985
5981
|
changed: true,
|
|
4986
5982
|
rewritten,
|
|
4987
|
-
importsNeeded: Array.from(ctx.importsNeeded)
|
|
5983
|
+
importsNeeded: Array.from(ctx.importsNeeded),
|
|
5984
|
+
ir: buildModuleIr(_filename ?? "<unknown>", rewritten, ctx.irTemplates ?? [], ast, reactiveComponentNames)
|
|
5985
|
+
};
|
|
5986
|
+
}
|
|
5987
|
+
function mountedComponentKeepAliveStatements(jsx, ast) {
|
|
5988
|
+
const tags = /* @__PURE__ */ new Set();
|
|
5989
|
+
collectCapitalizedJsxTags(jsx, tags);
|
|
5990
|
+
if (tags.size === 0) return [];
|
|
5991
|
+
const imported = /* @__PURE__ */ new Set();
|
|
5992
|
+
for (const stmt of ast.program.body) {
|
|
5993
|
+
if (!t.isImportDeclaration(stmt)) continue;
|
|
5994
|
+
for (const spec of stmt.specifiers) imported.add(spec.local.name);
|
|
5995
|
+
}
|
|
5996
|
+
const kept = Array.from(tags).filter((tag) => imported.has(tag));
|
|
5997
|
+
if (kept.length === 0) return [];
|
|
5998
|
+
const keepArray = t.assignmentExpression("||=", t.memberExpression(t.identifier("globalThis"), t.identifier("__GEA_IR_KEEP__")), t.arrayExpression([]));
|
|
5999
|
+
return [t.expressionStatement(t.callExpression(t.memberExpression(t.parenthesizedExpression(keepArray), t.identifier("push")), kept.map((tag) => t.identifier(tag))))];
|
|
6000
|
+
}
|
|
6001
|
+
function collectCapitalizedJsxTags(node, tags) {
|
|
6002
|
+
if (!node || typeof node !== "object") return;
|
|
6003
|
+
if (Array.isArray(node)) {
|
|
6004
|
+
for (const child of node) collectCapitalizedJsxTags(child, tags);
|
|
6005
|
+
return;
|
|
6006
|
+
}
|
|
6007
|
+
if (t.isJSXElement(node)) {
|
|
6008
|
+
const name = node.openingElement.name;
|
|
6009
|
+
if (t.isJSXIdentifier(name) && /^[A-Z]/.test(name.name)) tags.add(name.name);
|
|
6010
|
+
}
|
|
6011
|
+
for (const key of Object.keys(node)) {
|
|
6012
|
+
if (key === "loc" || key === "start" || key === "end" || key === "type") continue;
|
|
6013
|
+
collectCapitalizedJsxTags(node[key], tags);
|
|
6014
|
+
}
|
|
6015
|
+
}
|
|
6016
|
+
function runtimeBaseForComponent(options) {
|
|
6017
|
+
if (options.useStaticCompiledComponent) return "static";
|
|
6018
|
+
if (options.useCompiledComponent) return "compiled";
|
|
6019
|
+
if (options.useTinyReactiveComponent) return "tiny-reactive";
|
|
6020
|
+
if (options.useLeanReactiveComponent) return "lean-reactive";
|
|
6021
|
+
return "reactive";
|
|
6022
|
+
}
|
|
6023
|
+
function buildModuleIr(moduleId, rewritten, templates, ast, reactiveComponentNames = /* @__PURE__ */ new Set()) {
|
|
6024
|
+
const components = [];
|
|
6025
|
+
for (const name of rewritten) {
|
|
6026
|
+
const record = templates.find((template) => template.component === name);
|
|
6027
|
+
if (!record) continue;
|
|
6028
|
+
const declaration = findClassDeclarationByName(ast, name);
|
|
6029
|
+
const reactiveState = declaration && reactiveComponentNames.has(name) ? (() => {
|
|
6030
|
+
const fields = storeFieldsToIr(declaration);
|
|
6031
|
+
const methods = storeMethodsToIr(declaration, ast);
|
|
6032
|
+
const getters = storeGettersToIr(declaration);
|
|
6033
|
+
return {
|
|
6034
|
+
fields,
|
|
6035
|
+
...methods.length > 0 ? { methods } : {},
|
|
6036
|
+
...getters.length > 0 ? { getters } : {}
|
|
6037
|
+
};
|
|
6038
|
+
})() : void 0;
|
|
6039
|
+
components.push({
|
|
6040
|
+
id: componentIrId(moduleId, name),
|
|
6041
|
+
module: moduleId,
|
|
6042
|
+
exportName: name,
|
|
6043
|
+
runtimeBase: record.runtimeBase,
|
|
6044
|
+
template: record.template,
|
|
6045
|
+
...reactiveState ? { reactiveState } : {},
|
|
6046
|
+
...declaration ? { sourceSpan: sourceSpan(declaration) } : {}
|
|
6047
|
+
});
|
|
6048
|
+
}
|
|
6049
|
+
return {
|
|
6050
|
+
module: {
|
|
6051
|
+
id: moduleId,
|
|
6052
|
+
file: moduleId,
|
|
6053
|
+
components: components.map((component) => component.id),
|
|
6054
|
+
stores: []
|
|
6055
|
+
},
|
|
6056
|
+
components
|
|
4988
6057
|
};
|
|
4989
6058
|
}
|
|
6059
|
+
function findClassDeclarationByName(ast, name) {
|
|
6060
|
+
for (const node of ast.program.body) {
|
|
6061
|
+
if (t.isClassDeclaration(node) && node.id?.name === name) return node;
|
|
6062
|
+
if (t.isExportDefaultDeclaration(node) && t.isClassDeclaration(node.declaration) && node.declaration.id?.name === name) return node.declaration;
|
|
6063
|
+
if (t.isExportNamedDeclaration(node) && t.isClassDeclaration(node.declaration) && node.declaration.id?.name === name) return node.declaration;
|
|
6064
|
+
}
|
|
6065
|
+
return null;
|
|
6066
|
+
}
|
|
4990
6067
|
function collectLocalClassComponents(ast) {
|
|
4991
6068
|
const names = /* @__PURE__ */ new Set();
|
|
4992
6069
|
for (const node of ast.program.body) {
|
|
@@ -5516,13 +6593,16 @@ function transform(ctx) {
|
|
|
5516
6593
|
}
|
|
5517
6594
|
}
|
|
5518
6595
|
});
|
|
6596
|
+
let ir;
|
|
5519
6597
|
if (hasJSX) {
|
|
5520
6598
|
const emitted = transformFile(code, sourceFile, {
|
|
5521
6599
|
directClassComponents: knownClassComponentImports,
|
|
5522
6600
|
directFactoryComponents: knownFactoryComponentImports,
|
|
5523
|
-
enableTinyReactiveComponents: !isServe
|
|
6601
|
+
enableTinyReactiveComponents: !isServe,
|
|
6602
|
+
embedded: ctx.embedded
|
|
5524
6603
|
});
|
|
5525
6604
|
if (emitted.changed) {
|
|
6605
|
+
ir = emitted.ir;
|
|
5526
6606
|
const reparsed = parseSource(emitted.code);
|
|
5527
6607
|
if (reparsed) {
|
|
5528
6608
|
ast.program.body = reparsed.ast.program.body;
|
|
@@ -5573,7 +6653,8 @@ function transform(ctx) {
|
|
|
5573
6653
|
}, code);
|
|
5574
6654
|
return {
|
|
5575
6655
|
code: output.code,
|
|
5576
|
-
map: output.map
|
|
6656
|
+
map: output.map,
|
|
6657
|
+
ir
|
|
5577
6658
|
};
|
|
5578
6659
|
} catch (error) {
|
|
5579
6660
|
if (error?.__geaCompileError) throw error;
|
|
@@ -5583,10 +6664,9 @@ function transform(ctx) {
|
|
|
5583
6664
|
}
|
|
5584
6665
|
//#endregion
|
|
5585
6666
|
//#region src/closure-codegen/transform/transform-store.ts
|
|
5586
|
-
function transformCompiledStoreModule(source) {
|
|
6667
|
+
function transformCompiledStoreModule(source, moduleId = "<unknown>", resolveImportPath) {
|
|
5587
6668
|
if (!source.includes("extends Store")) return null;
|
|
5588
6669
|
if (source.includes("CompiledStore")) return null;
|
|
5589
|
-
if (/\b(flushSync|silent|Store\.|new\s+Store\s*\()/.test(source)) return null;
|
|
5590
6670
|
let ast;
|
|
5591
6671
|
try {
|
|
5592
6672
|
ast = parse(source, {
|
|
@@ -5603,29 +6683,49 @@ function transformCompiledStoreModule(source) {
|
|
|
5603
6683
|
} catch {
|
|
5604
6684
|
return null;
|
|
5605
6685
|
}
|
|
5606
|
-
const imported = findStoreImport(ast);
|
|
6686
|
+
const imported = findStoreImport(ast, moduleId, resolveImportPath);
|
|
5607
6687
|
if (!imported) return null;
|
|
5608
|
-
const
|
|
5609
|
-
if (
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
const
|
|
5613
|
-
|
|
5614
|
-
|
|
6688
|
+
const classDecls = findStoreClasses(ast, imported.localName);
|
|
6689
|
+
if (classDecls.length === 0) return null;
|
|
6690
|
+
const constants = collectImportedLiteralConstants(ast, moduleId, resolveImportPath);
|
|
6691
|
+
const fallbackIrs = classDecls.map((classDecl) => buildStoreIr(classDecl, moduleId, "compiled", constants, ast));
|
|
6692
|
+
const fallbackKeepAlive = storeMethodFreeFunctionKeepAlive(ast, classDecls);
|
|
6693
|
+
const fallback = {
|
|
6694
|
+
code: fallbackKeepAlive ? `${source}${fallbackKeepAlive}` : source,
|
|
6695
|
+
changed: !!fallbackKeepAlive,
|
|
6696
|
+
ir: fallbackIrs[0],
|
|
6697
|
+
irs: fallbackIrs
|
|
6698
|
+
};
|
|
6699
|
+
if (/\b(flushSync|silent|Store\.|new\s+Store\s*\()/.test(source)) return fallback;
|
|
6700
|
+
if (!classDecls.every((classDecl) => isCompiledStoreSafeClass(classDecl))) return classDecls.length === 1 ? null : fallback;
|
|
6701
|
+
if (!classDecls.every((classDecl) => hasDefaultNewStore(ast, classDecl.id.name))) return fallback;
|
|
6702
|
+
if (classDecls.length === 1) {
|
|
6703
|
+
const leanResult = transformLeanDataSelectedStore(ast, classDecls[0], imported, moduleId, constants);
|
|
6704
|
+
if (leanResult) return {
|
|
6705
|
+
...leanResult,
|
|
6706
|
+
irs: leanResult.ir ? [leanResult.ir] : void 0
|
|
6707
|
+
};
|
|
6708
|
+
}
|
|
6709
|
+
const storeBases = classDecls.map((classDecl) => canUseLeanStore(classDecl) ? "CompiledLeanStore" : "CompiledStore");
|
|
6710
|
+
const storeIrs = classDecls.map((classDecl, index) => buildStoreIr(classDecl, moduleId, storeBases[index] === "CompiledLeanStore" ? "lean" : "compiled", constants, ast));
|
|
5615
6711
|
removeStoreSpecifier(imported.importDecl, imported.localName);
|
|
5616
6712
|
ast.program.body = ast.program.body.filter((node) => {
|
|
5617
6713
|
if (node !== imported.importDecl) return true;
|
|
5618
6714
|
return imported.importDecl.specifiers.length > 0;
|
|
5619
6715
|
});
|
|
5620
|
-
ast.program.body.unshift(t.importDeclaration([t.importSpecifier(t.identifier(storeBase), t.identifier(storeBase))], t.stringLiteral(COMPILER_RUNTIME_ID)));
|
|
5621
|
-
classDecl
|
|
6716
|
+
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)));
|
|
6717
|
+
classDecls.forEach((classDecl, index) => {
|
|
6718
|
+
classDecl.superClass = t.identifier(storeBases[index]);
|
|
6719
|
+
});
|
|
5622
6720
|
return {
|
|
5623
6721
|
code: generate(ast, {
|
|
5624
6722
|
retainLines: false,
|
|
5625
6723
|
compact: false,
|
|
5626
6724
|
jsescOption: { minimal: true }
|
|
5627
6725
|
}).code,
|
|
5628
|
-
changed: true
|
|
6726
|
+
changed: true,
|
|
6727
|
+
ir: storeIrs[0],
|
|
6728
|
+
irs: storeIrs
|
|
5629
6729
|
};
|
|
5630
6730
|
}
|
|
5631
6731
|
const LEAN_DATA_SELECTED_STORE_SOURCE = `
|
|
@@ -5754,7 +6854,7 @@ const __store = {
|
|
|
5754
6854
|
};
|
|
5755
6855
|
export default __store;
|
|
5756
6856
|
`;
|
|
5757
|
-
function transformLeanDataSelectedStore(ast, classDecl, imported) {
|
|
6857
|
+
function transformLeanDataSelectedStore(ast, classDecl, imported, moduleId, constants) {
|
|
5758
6858
|
if (!classDecl.id) return null;
|
|
5759
6859
|
const classIndex = ast.program.body.indexOf(classDecl);
|
|
5760
6860
|
if (classIndex < 0) return null;
|
|
@@ -5763,6 +6863,7 @@ function transformLeanDataSelectedStore(ast, classDecl, imported) {
|
|
|
5763
6863
|
const fields = collectLeanStoreFields(classDecl);
|
|
5764
6864
|
if (!fields) return null;
|
|
5765
6865
|
if (!isBenchmarkOperationStoreShape(classDecl)) return null;
|
|
6866
|
+
const storeIr = buildStoreIr(classDecl, moduleId, "lean", constants, ast);
|
|
5766
6867
|
const methodProps = buildLeanStoreMethods(classDecl);
|
|
5767
6868
|
if (!methodProps) return null;
|
|
5768
6869
|
removeStoreSpecifier(imported.importDecl, imported.localName);
|
|
@@ -5792,9 +6893,123 @@ function transformLeanDataSelectedStore(ast, classDecl, imported) {
|
|
|
5792
6893
|
compact: false,
|
|
5793
6894
|
jsescOption: { minimal: true }
|
|
5794
6895
|
}).code,
|
|
5795
|
-
changed: true
|
|
6896
|
+
changed: true,
|
|
6897
|
+
ir: storeIr
|
|
6898
|
+
};
|
|
6899
|
+
}
|
|
6900
|
+
function buildStoreIr(classDecl, moduleId, runtimeBase, constants = [], moduleAst) {
|
|
6901
|
+
const className = classDecl.id?.name ?? "<anonymous>";
|
|
6902
|
+
return {
|
|
6903
|
+
id: storeIrId(moduleId, className),
|
|
6904
|
+
module: moduleId,
|
|
6905
|
+
className,
|
|
6906
|
+
runtimeBase,
|
|
6907
|
+
fields: storeFieldsToIr(classDecl),
|
|
6908
|
+
methods: storeMethodsToIr(classDecl, moduleAst),
|
|
6909
|
+
...(() => {
|
|
6910
|
+
const getters = storeGettersToIr(classDecl);
|
|
6911
|
+
return getters.length > 0 ? { getters } : {};
|
|
6912
|
+
})(),
|
|
6913
|
+
...constants.length > 0 ? { constants } : {},
|
|
6914
|
+
...sourceSpan(classDecl) ? { sourceSpan: sourceSpan(classDecl) } : {}
|
|
5796
6915
|
};
|
|
5797
6916
|
}
|
|
6917
|
+
function collectImportedLiteralConstants(ast, moduleId, resolveImportPath) {
|
|
6918
|
+
if (!resolveImportPath) return [];
|
|
6919
|
+
const namesByFile = /* @__PURE__ */ new Map();
|
|
6920
|
+
for (const node of ast.program.body) {
|
|
6921
|
+
if (!t.isImportDeclaration(node) || typeof node.source.value !== "string") continue;
|
|
6922
|
+
const resolved = resolveImportPath(moduleId, node.source.value);
|
|
6923
|
+
if (!resolved) continue;
|
|
6924
|
+
for (const specifier of node.specifiers) {
|
|
6925
|
+
if (!t.isImportSpecifier(specifier) || !t.isIdentifier(specifier.imported)) continue;
|
|
6926
|
+
const names = namesByFile.get(resolved) ?? /* @__PURE__ */ new Set();
|
|
6927
|
+
names.add(specifier.imported.name);
|
|
6928
|
+
namesByFile.set(resolved, names);
|
|
6929
|
+
}
|
|
6930
|
+
}
|
|
6931
|
+
const constants = [];
|
|
6932
|
+
for (const [file, names] of namesByFile) constants.push(...literalConstantsFromFile(file, names));
|
|
6933
|
+
return constants;
|
|
6934
|
+
}
|
|
6935
|
+
function literalConstantsFromFile(file, names) {
|
|
6936
|
+
if (!existsSync(file)) return [];
|
|
6937
|
+
let ast;
|
|
6938
|
+
try {
|
|
6939
|
+
ast = parse(readFileSync(file, "utf8"), {
|
|
6940
|
+
sourceType: "module",
|
|
6941
|
+
plugins: [
|
|
6942
|
+
"typescript",
|
|
6943
|
+
"jsx",
|
|
6944
|
+
"classProperties"
|
|
6945
|
+
],
|
|
6946
|
+
errorRecovery: false
|
|
6947
|
+
});
|
|
6948
|
+
} catch {
|
|
6949
|
+
return [];
|
|
6950
|
+
}
|
|
6951
|
+
const constants = [];
|
|
6952
|
+
for (const node of ast.program.body) {
|
|
6953
|
+
if (!t.isExportNamedDeclaration(node) || !t.isVariableDeclaration(node.declaration)) continue;
|
|
6954
|
+
for (const declaration of node.declaration.declarations) {
|
|
6955
|
+
if (!t.isIdentifier(declaration.id) || !names.has(declaration.id.name) || !declaration.init) continue;
|
|
6956
|
+
const literal = literalConstant(declaration.id.name, declaration.init);
|
|
6957
|
+
if (literal) constants.push(literal);
|
|
6958
|
+
}
|
|
6959
|
+
}
|
|
6960
|
+
return constants;
|
|
6961
|
+
}
|
|
6962
|
+
function moduleFreeFunctionNames(ast) {
|
|
6963
|
+
const names = /* @__PURE__ */ new Set();
|
|
6964
|
+
for (const node of ast.program.body) if (t.isFunctionDeclaration(node) && node.id) names.add(node.id.name);
|
|
6965
|
+
else if (t.isExportNamedDeclaration(node) && node.declaration && t.isFunctionDeclaration(node.declaration) && node.declaration.id) names.add(node.declaration.id.name);
|
|
6966
|
+
return names;
|
|
6967
|
+
}
|
|
6968
|
+
function nodeReferencesIdentifier(node, name) {
|
|
6969
|
+
if (!node || typeof node !== "object") return false;
|
|
6970
|
+
if (Array.isArray(node)) {
|
|
6971
|
+
for (const child of node) if (nodeReferencesIdentifier(child, name)) return true;
|
|
6972
|
+
return false;
|
|
6973
|
+
}
|
|
6974
|
+
const record = node;
|
|
6975
|
+
if (record.type === "Identifier" && record.name === name) return true;
|
|
6976
|
+
for (const key of Object.keys(record)) {
|
|
6977
|
+
if (key === "type" || key === "loc" || key === "start" || key === "end" || key === "leadingComments" || key === "trailingComments") continue;
|
|
6978
|
+
if (nodeReferencesIdentifier(record[key], name)) return true;
|
|
6979
|
+
}
|
|
6980
|
+
return false;
|
|
6981
|
+
}
|
|
6982
|
+
function storeMethodFreeFunctionKeepAlive(ast, classDecls) {
|
|
6983
|
+
const freeFns = moduleFreeFunctionNames(ast);
|
|
6984
|
+
if (freeFns.size === 0) return "";
|
|
6985
|
+
const kept = [];
|
|
6986
|
+
for (const name of freeFns) if (classDecls.some((classDecl) => classDecl.body.body.some((member) => t.isClassMethod(member) && nodeReferencesIdentifier(member.body, name)))) kept.push(name);
|
|
6987
|
+
if (kept.length === 0) return "";
|
|
6988
|
+
return `\n;(globalThis.__GEA_IR_KEEP__ ||= []).push(${kept.join(", ")});\n`;
|
|
6989
|
+
}
|
|
6990
|
+
function literalConstant(name, value) {
|
|
6991
|
+
if (t.isStringLiteral(value)) return {
|
|
6992
|
+
name,
|
|
6993
|
+
value: value.value,
|
|
6994
|
+
valueType: "string"
|
|
6995
|
+
};
|
|
6996
|
+
if (t.isNumericLiteral(value)) return {
|
|
6997
|
+
name,
|
|
6998
|
+
value: String(value.value),
|
|
6999
|
+
valueType: "number"
|
|
7000
|
+
};
|
|
7001
|
+
if (t.isBooleanLiteral(value)) return {
|
|
7002
|
+
name,
|
|
7003
|
+
value: value.value ? "true" : "false",
|
|
7004
|
+
valueType: "boolean"
|
|
7005
|
+
};
|
|
7006
|
+
if (t.isNullLiteral(value)) return {
|
|
7007
|
+
name,
|
|
7008
|
+
value: "null",
|
|
7009
|
+
valueType: "null"
|
|
7010
|
+
};
|
|
7011
|
+
return null;
|
|
7012
|
+
}
|
|
5798
7013
|
function isBenchmarkOperationStoreShape(classDecl) {
|
|
5799
7014
|
const methods = /* @__PURE__ */ new Set();
|
|
5800
7015
|
for (const member of classDecl.body.body) {
|
|
@@ -5892,10 +7107,10 @@ function replaceThisExpressions(node, replacement) {
|
|
|
5892
7107
|
else replaceThisExpressions(value, replacement);
|
|
5893
7108
|
}
|
|
5894
7109
|
}
|
|
5895
|
-
function findStoreImport(ast) {
|
|
7110
|
+
function findStoreImport(ast, moduleId, resolveImportPath) {
|
|
5896
7111
|
for (const node of ast.program.body) {
|
|
5897
7112
|
if (!t.isImportDeclaration(node)) continue;
|
|
5898
|
-
if (
|
|
7113
|
+
if (!storeImportSourceProvidesStore(moduleId, node.source.value, resolveImportPath)) continue;
|
|
5899
7114
|
for (const spec of node.specifiers) {
|
|
5900
7115
|
if (!t.isImportSpecifier(spec)) continue;
|
|
5901
7116
|
if ((t.isIdentifier(spec.imported) ? spec.imported.name : spec.imported.value) === "Store") return {
|
|
@@ -5906,13 +7121,87 @@ function findStoreImport(ast) {
|
|
|
5906
7121
|
}
|
|
5907
7122
|
return null;
|
|
5908
7123
|
}
|
|
5909
|
-
|
|
5910
|
-
|
|
7124
|
+
const knownStoreImportSources = new Set([
|
|
7125
|
+
"gea",
|
|
7126
|
+
"@geajs/core",
|
|
7127
|
+
"gea-embedded"
|
|
7128
|
+
]);
|
|
7129
|
+
const storeExportCache = /* @__PURE__ */ new Map();
|
|
7130
|
+
function storeImportSourceProvidesStore(moduleId, source, resolveImportPath) {
|
|
7131
|
+
if (typeof source !== "string") return false;
|
|
7132
|
+
if (knownStoreImportSources.has(source)) return true;
|
|
7133
|
+
if (!resolveImportPath) return false;
|
|
7134
|
+
const resolved = resolveImportPath(moduleId, source);
|
|
7135
|
+
return !!resolved && moduleExportsStore(resolved, resolveImportPath, /* @__PURE__ */ new Set());
|
|
7136
|
+
}
|
|
7137
|
+
function moduleExportsStore(file, resolveImportPath, seen) {
|
|
7138
|
+
if (seen.has(file)) return false;
|
|
7139
|
+
const cached = storeExportCache.get(file);
|
|
7140
|
+
if (cached !== void 0) return cached;
|
|
7141
|
+
seen.add(file);
|
|
7142
|
+
if (!existsSync(file)) {
|
|
7143
|
+
storeExportCache.set(file, false);
|
|
7144
|
+
return false;
|
|
7145
|
+
}
|
|
7146
|
+
let ast;
|
|
7147
|
+
try {
|
|
7148
|
+
ast = parse(readFileSync(file, "utf8"), {
|
|
7149
|
+
sourceType: "module",
|
|
7150
|
+
plugins: [
|
|
7151
|
+
"typescript",
|
|
7152
|
+
"jsx",
|
|
7153
|
+
"classProperties"
|
|
7154
|
+
],
|
|
7155
|
+
errorRecovery: false
|
|
7156
|
+
});
|
|
7157
|
+
} catch {
|
|
7158
|
+
storeExportCache.set(file, false);
|
|
7159
|
+
return false;
|
|
7160
|
+
}
|
|
7161
|
+
for (const node of ast.program.body) {
|
|
7162
|
+
if (t.isExportNamedDeclaration(node)) {
|
|
7163
|
+
if (node.declaration) {
|
|
7164
|
+
if (t.isVariableDeclaration(node.declaration)) {
|
|
7165
|
+
for (const declaration of node.declaration.declarations) if (t.isIdentifier(declaration.id, { name: "Store" })) {
|
|
7166
|
+
storeExportCache.set(file, true);
|
|
7167
|
+
return true;
|
|
7168
|
+
}
|
|
7169
|
+
}
|
|
7170
|
+
if (t.isClassDeclaration(node.declaration) && t.isIdentifier(node.declaration.id, { name: "Store" })) {
|
|
7171
|
+
storeExportCache.set(file, true);
|
|
7172
|
+
return true;
|
|
7173
|
+
}
|
|
7174
|
+
}
|
|
7175
|
+
for (const specifier of node.specifiers) {
|
|
7176
|
+
if ((t.isIdentifier(specifier.exported) ? specifier.exported.name : specifier.exported.value) !== "Store") continue;
|
|
7177
|
+
if (!node.source || typeof node.source.value !== "string") {
|
|
7178
|
+
storeExportCache.set(file, true);
|
|
7179
|
+
return true;
|
|
7180
|
+
}
|
|
7181
|
+
const resolved = resolveImportPath(file, node.source.value);
|
|
7182
|
+
if (resolved && moduleExportsStore(resolved, resolveImportPath, seen)) {
|
|
7183
|
+
storeExportCache.set(file, true);
|
|
7184
|
+
return true;
|
|
7185
|
+
}
|
|
7186
|
+
}
|
|
7187
|
+
}
|
|
7188
|
+
if (t.isExportAllDeclaration(node) && typeof node.source.value === "string") {
|
|
7189
|
+
const resolved = resolveImportPath(file, node.source.value);
|
|
7190
|
+
if (resolved && moduleExportsStore(resolved, resolveImportPath, seen)) {
|
|
7191
|
+
storeExportCache.set(file, true);
|
|
7192
|
+
return true;
|
|
7193
|
+
}
|
|
7194
|
+
}
|
|
7195
|
+
}
|
|
7196
|
+
storeExportCache.set(file, false);
|
|
7197
|
+
return false;
|
|
7198
|
+
}
|
|
7199
|
+
function findStoreClasses(ast, storeName) {
|
|
7200
|
+
const found = [];
|
|
5911
7201
|
for (const node of ast.program.body) {
|
|
5912
7202
|
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;
|
|
7203
|
+
if (!decl || !decl.id || !t.isIdentifier(decl.superClass, { name: storeName })) continue;
|
|
7204
|
+
found.push(decl);
|
|
5916
7205
|
}
|
|
5917
7206
|
return found;
|
|
5918
7207
|
}
|
|
@@ -6820,11 +8109,21 @@ function shouldMinifyGeaSymbolsForBuild(config) {
|
|
|
6820
8109
|
const formats = lib.formats ?? [];
|
|
6821
8110
|
return formats.length > 0 && formats.every((format) => format === "iife" || format === "umd");
|
|
6822
8111
|
}
|
|
6823
|
-
function geaPlugin() {
|
|
8112
|
+
function geaPlugin(options = {}) {
|
|
8113
|
+
const envIrOutFile = process.env.GEA_IR_OUT || process.env.GEA_IR_FILE;
|
|
8114
|
+
const irOptions = options.ir ?? (envIrOutFile ? {
|
|
8115
|
+
enabled: true,
|
|
8116
|
+
outFile: envIrOutFile
|
|
8117
|
+
} : void 0);
|
|
6824
8118
|
const storeModules = /* @__PURE__ */ new Set();
|
|
6825
8119
|
const componentModules = /* @__PURE__ */ new Set();
|
|
6826
8120
|
let isServeCommand = false;
|
|
6827
8121
|
let shouldMinifyGeaSymbolKeys = false;
|
|
8122
|
+
let resolvedConfig = null;
|
|
8123
|
+
const irModules = /* @__PURE__ */ new Map();
|
|
8124
|
+
const irComponents = /* @__PURE__ */ new Map();
|
|
8125
|
+
const irStores = /* @__PURE__ */ new Map();
|
|
8126
|
+
const hostCapabilities = /* @__PURE__ */ new Set();
|
|
6828
8127
|
const storeRegistry = /* @__PURE__ */ new Map();
|
|
6829
8128
|
const resolveImportPath = (importer, source) => {
|
|
6830
8129
|
const base = resolve(dirname(importer), source);
|
|
@@ -6935,6 +8234,7 @@ function geaPlugin() {
|
|
|
6935
8234
|
name: "gea-plugin",
|
|
6936
8235
|
enforce: "pre",
|
|
6937
8236
|
configResolved(config) {
|
|
8237
|
+
resolvedConfig = config;
|
|
6938
8238
|
isServeCommand = config.command === "serve";
|
|
6939
8239
|
shouldMinifyGeaSymbolKeys = shouldMinifyGeaSymbolsForBuild(config);
|
|
6940
8240
|
},
|
|
@@ -6981,6 +8281,7 @@ function geaPlugin() {
|
|
|
6981
8281
|
if (!cleanId.match(/\.(js|jsx|ts|tsx)$/) || cleanId.includes("node_modules")) return null;
|
|
6982
8282
|
let transformedCode = code;
|
|
6983
8283
|
let changed = false;
|
|
8284
|
+
if (irOptions?.enabled) recordHostCapabilities(code);
|
|
6984
8285
|
if (code.includes("extends Store") || code.includes("new Store(")) {
|
|
6985
8286
|
storeModules.add(cleanId);
|
|
6986
8287
|
const storeClassName = extractStoreClassName(code);
|
|
@@ -6999,11 +8300,16 @@ function geaPlugin() {
|
|
|
6999
8300
|
transformedCode = observeResult.code;
|
|
7000
8301
|
changed = true;
|
|
7001
8302
|
}
|
|
7002
|
-
const storeResult = transformCompiledStoreModule(transformedCode);
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
8303
|
+
const storeResult = transformCompiledStoreModule(transformedCode, cleanId, resolveImportPath);
|
|
8304
|
+
for (const storeIr of storeResult?.irs ?? (storeResult?.ir ? [storeResult.ir] : [])) recordStoreIr(cleanId, storeIr);
|
|
8305
|
+
if (storeResult?.changed) {
|
|
8306
|
+
if (!/\bextends\s+(Component|ReactiveComponent)\b|\bmount\s*\(/.test(storeResult.code)) return {
|
|
8307
|
+
code: storeResult.code,
|
|
8308
|
+
map: null
|
|
8309
|
+
};
|
|
8310
|
+
transformedCode = storeResult.code;
|
|
8311
|
+
changed = true;
|
|
8312
|
+
}
|
|
7007
8313
|
const rootMountResult = transformStaticRootMount(transformedCode, cleanId, resolveImportPath);
|
|
7008
8314
|
if (rootMountResult?.changed) {
|
|
7009
8315
|
for (const file of rootMountResult.watchFiles ?? []) this.addWatchFile?.(file);
|
|
@@ -7018,6 +8324,7 @@ function geaPlugin() {
|
|
|
7018
8324
|
code: transformedCode,
|
|
7019
8325
|
isServe: isServeCommand,
|
|
7020
8326
|
isSSR,
|
|
8327
|
+
embedded: !!irOptions?.enabled,
|
|
7021
8328
|
hmrImportSource: HMR_RUNTIME_ID,
|
|
7022
8329
|
isStoreModule,
|
|
7023
8330
|
isComponentModule,
|
|
@@ -7027,7 +8334,15 @@ function geaPlugin() {
|
|
|
7027
8334
|
registerStoreModule: (fp) => storeModules.add(fp),
|
|
7028
8335
|
registerComponentModule: (fp) => componentModules.add(fp)
|
|
7029
8336
|
});
|
|
7030
|
-
if (result)
|
|
8337
|
+
if (result) {
|
|
8338
|
+
if (result.ir) recordComponentIr(cleanId, result.ir);
|
|
8339
|
+
if (result.ir?.components.some((component) => component.reactiveState)) return {
|
|
8340
|
+
code: result.code,
|
|
8341
|
+
map: result.map ?? null,
|
|
8342
|
+
moduleSideEffects: "no-treeshake"
|
|
8343
|
+
};
|
|
8344
|
+
return result;
|
|
8345
|
+
}
|
|
7031
8346
|
if (isServeCommand && !isSSR) {
|
|
7032
8347
|
const componentDeps = findComponentDeps(transformedCode, cleanId);
|
|
7033
8348
|
if (componentDeps.length > 0) {
|
|
@@ -7051,8 +8366,136 @@ function geaPlugin() {
|
|
|
7051
8366
|
code: next,
|
|
7052
8367
|
map: null
|
|
7053
8368
|
};
|
|
8369
|
+
},
|
|
8370
|
+
generateBundle(_options, bundle) {
|
|
8371
|
+
if (!irOptions?.enabled) return;
|
|
8372
|
+
const renderedIds = renderedModuleIds(bundle);
|
|
8373
|
+
const modules = Array.from(irModules.values()).filter((module) => {
|
|
8374
|
+
if (!renderedIds) return true;
|
|
8375
|
+
return renderedIds.has(cleanRollupModuleId(module.id)) || renderedIds.has(cleanRollupModuleId(module.file));
|
|
8376
|
+
});
|
|
8377
|
+
const componentIds = new Set(modules.flatMap((module) => module.components));
|
|
8378
|
+
const storeIds = new Set(modules.flatMap((module) => module.stores));
|
|
8379
|
+
const moduleById = new Map(Array.from(irModules.values()).map((module) => [module.id, module]));
|
|
8380
|
+
const pending = Array.from(componentIds);
|
|
8381
|
+
while (pending.length > 0) {
|
|
8382
|
+
const component = irComponents.get(pending.pop());
|
|
8383
|
+
if (!component) continue;
|
|
8384
|
+
for (const tag of collectMountTags(component.template.slots)) for (const candidate of irComponents.values()) {
|
|
8385
|
+
if (candidate.exportName !== tag || componentIds.has(candidate.id)) continue;
|
|
8386
|
+
componentIds.add(candidate.id);
|
|
8387
|
+
pending.push(candidate.id);
|
|
8388
|
+
const candidateModule = moduleById.get(candidate.module);
|
|
8389
|
+
if (candidateModule && !modules.includes(candidateModule)) modules.push(candidateModule);
|
|
8390
|
+
}
|
|
8391
|
+
}
|
|
8392
|
+
const irBundle = {
|
|
8393
|
+
schema: "gea-ir",
|
|
8394
|
+
version: 1,
|
|
8395
|
+
entry: geaIrEntryFromBundle(bundle) ?? geaIrConfiguredEntry(resolvedConfig),
|
|
8396
|
+
modules,
|
|
8397
|
+
components: Array.from(irComponents.values()).filter((component) => componentIds.has(component.id)),
|
|
8398
|
+
stores: Array.from(irStores.values()).filter((store) => storeIds.has(store.id)),
|
|
8399
|
+
hostCapabilities: Array.from(hostCapabilities).sort()
|
|
8400
|
+
};
|
|
8401
|
+
const source = JSON.stringify(irBundle, null, 2);
|
|
8402
|
+
const outFile = irOptions.outFile ?? "gea-ir.json";
|
|
8403
|
+
if (outFile.startsWith("/") || /^[A-Za-z]:[\\/]/.test(outFile)) {
|
|
8404
|
+
mkdirSync(dirname(outFile), { recursive: true });
|
|
8405
|
+
writeFileSync(outFile, source);
|
|
8406
|
+
} else this.emitFile({
|
|
8407
|
+
type: "asset",
|
|
8408
|
+
fileName: outFile,
|
|
8409
|
+
source
|
|
8410
|
+
});
|
|
7054
8411
|
}
|
|
7055
8412
|
};
|
|
8413
|
+
function collectMountTags(slots, tags = /* @__PURE__ */ new Set(), depth = 0) {
|
|
8414
|
+
if (depth > 8 || !Array.isArray(slots)) return tags;
|
|
8415
|
+
for (const slot of slots) {
|
|
8416
|
+
if (!slot || typeof slot !== "object") continue;
|
|
8417
|
+
const { kind, payload } = slot;
|
|
8418
|
+
if (!payload || typeof payload !== "object") continue;
|
|
8419
|
+
const record = payload;
|
|
8420
|
+
if (kind === "mount" && typeof record.tag === "string") tags.add(record.tag);
|
|
8421
|
+
for (const key of Object.keys(record)) {
|
|
8422
|
+
if (key === "attrs" || key === "children") continue;
|
|
8423
|
+
const value = record[key];
|
|
8424
|
+
if (value && typeof value === "object" && Array.isArray(value.slots)) collectMountTags(value.slots, tags, depth + 1);
|
|
8425
|
+
}
|
|
8426
|
+
}
|
|
8427
|
+
return tags;
|
|
8428
|
+
}
|
|
8429
|
+
function recordComponentIr(moduleId, ir) {
|
|
8430
|
+
const existing = irModules.get(moduleId) ?? {
|
|
8431
|
+
id: moduleId,
|
|
8432
|
+
file: moduleId,
|
|
8433
|
+
components: [],
|
|
8434
|
+
stores: []
|
|
8435
|
+
};
|
|
8436
|
+
const componentIds = new Set(existing.components);
|
|
8437
|
+
for (const component of ir.components) {
|
|
8438
|
+
irComponents.set(component.id, component);
|
|
8439
|
+
componentIds.add(component.id);
|
|
8440
|
+
}
|
|
8441
|
+
irModules.set(moduleId, {
|
|
8442
|
+
...existing,
|
|
8443
|
+
components: Array.from(componentIds)
|
|
8444
|
+
});
|
|
8445
|
+
}
|
|
8446
|
+
function recordStoreIr(moduleId, store) {
|
|
8447
|
+
const existing = irModules.get(moduleId) ?? {
|
|
8448
|
+
id: moduleId,
|
|
8449
|
+
file: moduleId,
|
|
8450
|
+
components: [],
|
|
8451
|
+
stores: []
|
|
8452
|
+
};
|
|
8453
|
+
const storeIds = new Set(existing.stores);
|
|
8454
|
+
irStores.set(store.id, store);
|
|
8455
|
+
storeIds.add(store.id);
|
|
8456
|
+
irModules.set(moduleId, {
|
|
8457
|
+
...existing,
|
|
8458
|
+
stores: Array.from(storeIds)
|
|
8459
|
+
});
|
|
8460
|
+
}
|
|
8461
|
+
function recordHostCapabilities(source) {
|
|
8462
|
+
if (/\bfetch\s*\(/.test(source)) hostCapabilities.add("fetch");
|
|
8463
|
+
if (source.includes("https://")) hostCapabilities.add("https");
|
|
8464
|
+
if (/\bApps\s*\./.test(source)) hostCapabilities.add("apps");
|
|
8465
|
+
if (/\b(?:BLE|BLEServer)\b|\bgea_embedded_ble_|\b__gea_embedded_ble_/.test(source)) hostCapabilities.add("ble");
|
|
8466
|
+
if (/\bWiFi\s*\./.test(source)) hostCapabilities.add("wifi");
|
|
8467
|
+
if (/\b(?:Accelerometer|accelerometer)\s*\.|\bgea_embedded_imu_/.test(source)) hostCapabilities.add("imu");
|
|
8468
|
+
if (/\baudioContext\s*\.|\b__gea_audioContext\b|\b__gea_Audio\b/.test(source)) hostCapabilities.add("audio");
|
|
8469
|
+
if (/\bscreen\s*\./.test(source)) hostCapabilities.add("screen");
|
|
8470
|
+
if (/\b__gea_embedded_image\b/.test(source)) hostCapabilities.add("image");
|
|
8471
|
+
if (/\b__gea_embedded_touch\b/.test(source)) hostCapabilities.add("touch");
|
|
8472
|
+
if (/\bdocument\s*\./.test(source)) hostCapabilities.add("dom");
|
|
8473
|
+
}
|
|
8474
|
+
}
|
|
8475
|
+
function renderedModuleIds(bundle) {
|
|
8476
|
+
const ids = /* @__PURE__ */ new Set();
|
|
8477
|
+
for (const item of Object.values(bundle)) {
|
|
8478
|
+
if (item.type !== "chunk") continue;
|
|
8479
|
+
if (item.facadeModuleId) ids.add(cleanRollupModuleId(item.facadeModuleId));
|
|
8480
|
+
if (item.modules && typeof item.modules === "object") for (const id of Object.keys(item.modules)) ids.add(cleanRollupModuleId(id));
|
|
8481
|
+
}
|
|
8482
|
+
return ids.size > 0 ? ids : null;
|
|
8483
|
+
}
|
|
8484
|
+
function cleanRollupModuleId(id) {
|
|
8485
|
+
return id.split("?")[0] ?? id;
|
|
8486
|
+
}
|
|
8487
|
+
function geaIrEntryFromBundle(bundle) {
|
|
8488
|
+
return Object.values(bundle).filter((item) => item.type === "chunk" && item.isEntry && item.fileName).map((item) => item.fileName).sort()[0] ?? null;
|
|
8489
|
+
}
|
|
8490
|
+
function geaIrConfiguredEntry(config) {
|
|
8491
|
+
const input = config?.build.rollupOptions.input;
|
|
8492
|
+
if (typeof input === "string") return input;
|
|
8493
|
+
if (Array.isArray(input)) return input[0] ? String(input[0]) : "";
|
|
8494
|
+
if (input && typeof input === "object") {
|
|
8495
|
+
const firstKey = Object.keys(input).sort()[0];
|
|
8496
|
+
return firstKey ? String(input[firstKey]) : "";
|
|
8497
|
+
}
|
|
8498
|
+
return "";
|
|
7056
8499
|
}
|
|
7057
8500
|
function resolveToFile(base) {
|
|
7058
8501
|
const exts = [
|
|
@@ -7105,6 +8548,7 @@ function compilerRuntimeSource(runtimePath) {
|
|
|
7105
8548
|
relationalClass,
|
|
7106
8549
|
relationalClassProp,
|
|
7107
8550
|
reactiveStyle,
|
|
8551
|
+
reactiveStyleProp,
|
|
7108
8552
|
reactiveValue,
|
|
7109
8553
|
reactiveValueRead,
|
|
7110
8554
|
delegateEvent,
|