@geajs/vite-plugin 1.4.1 → 1.4.2

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.
Files changed (2) hide show
  1. package/dist/index.mjs +459 -204
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -1,10 +1,11 @@
1
+ import { parse } from "@babel/parser";
1
2
  import _traverse from "@babel/traverse";
2
3
  import _generate from "@babel/generator";
3
4
  import * as t from "@babel/types";
4
- import { parse } from "@babel/parser";
5
5
  import { id, js, jsExpr, jsImport } from "eszter";
6
6
  import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
7
- import { dirname, relative, resolve } from "node:path";
7
+ import { dirname, posix, relative, resolve } from "node:path";
8
+ import { createHash } from "node:crypto";
8
9
  import { fileURLToPath } from "node:url";
9
10
  //#region src/utils/babel-interop.ts
10
11
  /**
@@ -277,215 +278,59 @@ function collectBindings(stmts, bindings) {
277
278
  let localName;
278
279
  if (t.isIdentifier(prop.value)) localName = prop.value.name;
279
280
  else continue;
280
- const mem = t.memberExpression(cloneExpr$2(decl.init), t.identifier(sourceKey));
281
+ const mem = t.memberExpression(cloneExpr$1(decl.init), t.identifier(sourceKey));
281
282
  bindings.set(localName, mem);
282
283
  }
283
- else if (t.isIdentifier(decl.id)) bindings.set(decl.id.name, cloneExpr$2(decl.init));
284
+ else if (t.isIdentifier(decl.id)) bindings.set(decl.id.name, cloneExpr$1(decl.init));
284
285
  }
285
286
  }
286
287
  }
287
288
  /** Shallow clone to avoid AST aliasing hazards when substituting. */
288
- function cloneExpr$2(expr) {
289
+ function cloneExpr$1(expr) {
289
290
  return t.cloneNode(expr);
290
291
  }
291
292
  //#endregion
292
293
  //#region src/closure-codegen/emit/emit-substitution.ts
293
- function cloneExpr$1(expr) {
294
- return t.cloneNode(expr);
295
- }
296
- /**
297
- * Walk an expression tree and replace Identifier references that match a
298
- * binding with the bound expression (also recursively). Used to rewrite
299
- * JSX-expression member chains so their root is the real reactive source.
300
- * Returns a new expression; does not mutate input.
301
- */
294
+ /** Resolve template aliases at free read/write sites, preserving lexical scope. */
302
295
  function substituteBindings(expr, bindings) {
303
296
  if (!expr) return expr;
304
297
  if (t.isTSAsExpression(expr) || t.isTSTypeAssertion(expr) || t.isTSNonNullExpression(expr) || t.isTSInstantiationExpression(expr)) return substituteBindings(expr.expression, bindings);
305
298
  if (bindings.size === 0) return expr;
306
- if (t.isIdentifier(expr)) {
307
- const b = bindings.get(expr.name);
308
- if (b) {
309
- const scoped = new Map(bindings);
310
- scoped.delete(expr.name);
311
- return substituteBindings(cloneExpr$1(b), scoped);
299
+ const node = t.cloneNode(expr, true);
300
+ const statement = t.isStatement(node);
301
+ const container = t.isJSXExpressionContainer(node);
302
+ if (container && t.isJSXEmptyExpression(node.expression)) return node;
303
+ if (!statement && !container && !t.isExpression(node)) return node;
304
+ const file = t.file(t.program([statement ? node : t.expressionStatement(container ? node.expression : node)]));
305
+ traverse(file, { Identifier(path) {
306
+ const name = path.node.name;
307
+ if (!bindings.has(name) || path.scope.getBinding(name)) return;
308
+ if (!path.isReferencedIdentifier() && !isAssignmentTarget(path)) return;
309
+ const remaining = new Map(bindings);
310
+ remaining.delete(name);
311
+ const replacement = substituteBindings(bindings.get(name), remaining);
312
+ path.replaceWith(t.cloneNode(replacement, true));
313
+ path.skip();
314
+ } });
315
+ const result = statement ? file.program.body[0] : file.program.body[0].expression;
316
+ return container ? {
317
+ ...node,
318
+ expression: result
319
+ } : result;
320
+ }
321
+ /** Assignment patterns write references; labels and declarations do not. */
322
+ function isAssignmentTarget(path) {
323
+ let target = path;
324
+ while (target.parentPath) {
325
+ const parent = target.parentPath;
326
+ if (parent.isObjectProperty() && target.key === "value" || parent.isObjectPattern() || parent.isArrayPattern() || parent.isRestElement() && target.key === "argument" || parent.isAssignmentPattern() && target.key === "left") {
327
+ target = parent;
328
+ continue;
312
329
  }
313
- return expr;
330
+ return (parent.isAssignmentExpression() || parent.isForInStatement() || parent.isForOfStatement()) && target.key === "left" || parent.isUpdateExpression() && target.key === "argument";
314
331
  }
315
- if (t.isMemberExpression(expr)) return {
316
- ...expr,
317
- object: substituteBindings(expr.object, bindings),
318
- property: expr.computed ? substituteBindings(expr.property, bindings) : expr.property
319
- };
320
- if (t.isCallExpression(expr)) return {
321
- ...expr,
322
- callee: substituteBindings(expr.callee, bindings),
323
- arguments: expr.arguments.map((a) => substituteBindings(a, bindings))
324
- };
325
- if (t.isBinaryExpression(expr) || t.isLogicalExpression(expr)) return {
326
- ...expr,
327
- left: substituteBindings(expr.left, bindings),
328
- right: substituteBindings(expr.right, bindings)
329
- };
330
- if (t.isConditionalExpression(expr)) return {
331
- ...expr,
332
- test: substituteBindings(expr.test, bindings),
333
- consequent: substituteBindings(expr.consequent, bindings),
334
- alternate: substituteBindings(expr.alternate, bindings)
335
- };
336
- if (t.isUnaryExpression(expr) || t.isUpdateExpression(expr)) return {
337
- ...expr,
338
- argument: substituteBindings(expr.argument, bindings)
339
- };
340
- if (t.isTemplateLiteral(expr)) return {
341
- ...expr,
342
- expressions: expr.expressions.map((e) => substituteBindings(e, bindings))
343
- };
344
- if (t.isOptionalMemberExpression(expr)) return {
345
- ...expr,
346
- object: substituteBindings(expr.object, bindings),
347
- property: expr.computed ? substituteBindings(expr.property, bindings) : expr.property
348
- };
349
- if (t.isOptionalCallExpression(expr)) return {
350
- ...expr,
351
- callee: substituteBindings(expr.callee, bindings),
352
- arguments: expr.arguments.map((a) => substituteBindings(a, bindings))
353
- };
354
- if (t.isArrowFunctionExpression(expr) || t.isFunctionExpression(expr)) {
355
- const paramNames = /* @__PURE__ */ new Set();
356
- for (const p of expr.params) if (t.isIdentifier(p)) paramNames.add(p.name);
357
- else if (t.isObjectPattern(p)) {
358
- for (const prop of p.properties) if (t.isObjectProperty(prop) && t.isIdentifier(prop.value)) paramNames.add(prop.value.name);
359
- }
360
- const shadowed = new Map(bindings);
361
- for (const k of paramNames) shadowed.delete(k);
362
- if (shadowed.size === 0) return expr;
363
- return {
364
- ...expr,
365
- body: substituteBindings(expr.body, shadowed)
366
- };
367
- }
368
- if (t.isBlockStatement(expr)) return {
369
- ...expr,
370
- body: expr.body.map((s) => substituteBindings(s, bindings))
371
- };
372
- if (t.isExpressionStatement(expr)) return {
373
- ...expr,
374
- expression: substituteBindings(expr.expression, bindings)
375
- };
376
- if (t.isReturnStatement(expr)) return expr.argument ? {
377
- ...expr,
378
- argument: substituteBindings(expr.argument, bindings)
379
- } : expr;
380
- if (t.isIfStatement(expr)) return {
381
- ...expr,
382
- test: substituteBindings(expr.test, bindings),
383
- consequent: substituteBindings(expr.consequent, bindings),
384
- alternate: expr.alternate ? substituteBindings(expr.alternate, bindings) : null
385
- };
386
- if (t.isVariableDeclaration(expr)) return {
387
- ...expr,
388
- declarations: expr.declarations.map((d) => ({
389
- ...d,
390
- init: d.init ? substituteBindings(d.init, bindings) : null
391
- }))
392
- };
393
- if (t.isTryStatement(expr)) return {
394
- ...expr,
395
- block: substituteBindings(expr.block, bindings),
396
- handler: expr.handler ? {
397
- ...expr.handler,
398
- body: substituteBindings(expr.handler.body, bindings)
399
- } : null,
400
- finalizer: expr.finalizer ? substituteBindings(expr.finalizer, bindings) : null
401
- };
402
- if (t.isForStatement(expr) || t.isForInStatement(expr) || t.isForOfStatement(expr)) return {
403
- ...expr,
404
- body: substituteBindings(expr.body, bindings)
405
- };
406
- if (t.isWhileStatement(expr) || t.isDoWhileStatement(expr)) return {
407
- ...expr,
408
- test: substituteBindings(expr.test, bindings),
409
- body: substituteBindings(expr.body, bindings)
410
- };
411
- if (t.isSwitchStatement(expr)) return {
412
- ...expr,
413
- discriminant: substituteBindings(expr.discriminant, bindings),
414
- cases: expr.cases.map((c) => ({
415
- ...c,
416
- consequent: c.consequent.map((s) => substituteBindings(s, bindings))
417
- }))
418
- };
419
- if (t.isArrayExpression(expr)) return {
420
- ...expr,
421
- elements: expr.elements.map((e) => e ? substituteBindings(e, bindings) : e)
422
- };
423
- if (t.isObjectExpression(expr)) return {
424
- ...expr,
425
- properties: expr.properties.map((p) => t.isObjectProperty(p) ? {
426
- ...p,
427
- value: substituteBindings(p.value, bindings)
428
- } : p)
429
- };
430
- if (t.isSpreadElement(expr)) return {
431
- ...expr,
432
- argument: substituteBindings(expr.argument, bindings)
433
- };
434
- if (t.isNewExpression(expr)) return {
435
- ...expr,
436
- callee: substituteBindings(expr.callee, bindings),
437
- arguments: expr.arguments.map((a) => substituteBindings(a, bindings))
438
- };
439
- if (t.isSequenceExpression(expr)) return {
440
- ...expr,
441
- expressions: expr.expressions.map((e) => substituteBindings(e, bindings))
442
- };
443
- if (t.isAssignmentExpression(expr)) return {
444
- ...expr,
445
- right: substituteBindings(expr.right, bindings)
446
- };
447
- if (t.isJSXElement(expr)) {
448
- const newOpening = {
449
- ...expr.openingElement,
450
- attributes: expr.openingElement.attributes.map((a) => {
451
- if (t.isJSXAttribute(a) && a.value && t.isJSXExpressionContainer(a.value) && !t.isJSXEmptyExpression(a.value.expression)) return {
452
- ...a,
453
- value: {
454
- ...a.value,
455
- expression: substituteBindings(a.value.expression, bindings)
456
- }
457
- };
458
- return a;
459
- })
460
- };
461
- const newChildren = expr.children.map((c) => substituteBindings(c, bindings));
462
- return {
463
- ...expr,
464
- openingElement: newOpening,
465
- children: newChildren
466
- };
467
- }
468
- if (t.isJSXFragment(expr)) return {
469
- ...expr,
470
- children: expr.children.map((c) => substituteBindings(c, bindings))
471
- };
472
- if (t.isJSXExpressionContainer(expr) && !t.isJSXEmptyExpression(expr.expression)) return {
473
- ...expr,
474
- expression: substituteBindings(expr.expression, bindings)
475
- };
476
- if (t.isJSXText(expr) || t.isJSXSpreadChild(expr) || t.isJSXEmptyExpression(expr)) return expr;
477
- return expr;
332
+ return false;
478
333
  }
479
- /**
480
- * Compile a JSX element/fragment into a clone-and-wire expression.
481
- *
482
- * Returns a BlockStatement that:
483
- * - declares `const root = (_tpl<N>_root || (_tpl<N>_root = _tpl<N>_create())).cloneNode(true)`
484
- * - wires all slots
485
- * - returns `root`
486
- *
487
- * Side effect: adds the lazy template root cache to `ctx.templateDecls`.
488
- */
489
334
  //#endregion
490
335
  //#region src/closure-codegen/emit/template-decl.ts
491
336
  const SVG_TEMPLATE_ROOT_TAGS = new Set([
@@ -621,6 +466,27 @@ function emitWalkExpr(root, walk, walkKinds) {
621
466
  return out;
622
467
  }
623
468
  //#endregion
469
+ //#region src/closure-codegen/keyed-list/keyed-list-item-reader.ts
470
+ /** Read through the row observable so primitive replacements remain reactive too. */
471
+ function useObservableItem(createItem, importsNeeded) {
472
+ if (!t.isArrowFunctionExpression(createItem)) throw new Error("Expected a keyed-list row factory");
473
+ const item = createItem.params[0];
474
+ const names = /* @__PURE__ */ new Set();
475
+ t.traverseFast(createItem, (node) => {
476
+ if (t.isIdentifier(node)) names.add(node.name);
477
+ });
478
+ let name = "__geaItemObservable";
479
+ while (names.has(name)) name += "_";
480
+ const observable = t.identifier(name);
481
+ const read = t.callExpression(t.identifier("readItem"), [observable]);
482
+ const bindings = /* @__PURE__ */ new Map();
483
+ if (t.isIdentifier(item)) bindings.set(item.name, read);
484
+ else for (const name of Object.keys(t.getBindingIdentifiers(item))) bindings.set(name, t.callExpression(t.arrowFunctionExpression([t.cloneNode(item, true)], t.identifier(name)), [t.cloneNode(read, true)]));
485
+ createItem.body = substituteBindings(createItem.body, bindings);
486
+ createItem.params[0] = observable;
487
+ importsNeeded.add("readItem");
488
+ }
489
+ //#endregion
624
490
  //#region src/closure-codegen/emit/emit-map-branch.ts
625
491
  function buildMapBranchFn(mapExpr, ctx) {
626
492
  const arrowExpr = mapExpr.arguments[0];
@@ -644,7 +510,7 @@ function buildMapBranchFn(mapExpr, ctx) {
644
510
  t.identifier("d")
645
511
  ], createItemBlock);
646
512
  ctx.importsNeeded.add("createItemObservable");
647
- ctx.importsNeeded.add("createItemProxy");
513
+ useObservableItem(createItemFn, ctx.importsNeeded);
648
514
  ctx.importsNeeded.add("_rescue");
649
515
  ctx.importsNeeded.add("GEA_PROXY_RAW");
650
516
  const listId = "L" + ctx.listCounter++;
@@ -658,7 +524,7 @@ function buildMapBranchFn(mapExpr, ctx) {
658
524
  t.identifier(rqName),
659
525
  t.callExpression(t.identifier("String"), [t.identifier("__k")]),
660
526
  t.identifier(itemParam)
661
- ]))]), t.ifStatement(t.identifier("__r"), t.blockStatement([t.returnStatement(t.identifier("__r"))])), t.variableDeclaration("const", [t.variableDeclarator(t.identifier("__rd"), t.callExpression(t.memberExpression(t.identifier("d"), t.identifier("child")), []))]), t.variableDeclaration("const", [t.variableDeclarator(t.identifier("__obs"), t.callExpression(t.identifier("createItemObservable"), [t.identifier(itemParam)]))]), t.variableDeclaration("const", [t.variableDeclarator(t.identifier("__li"), t.conditionalExpression(t.logicalExpression("&&", t.binaryExpression("!==", t.identifier(itemParam), t.nullLiteral()), t.binaryExpression("===", t.unaryExpression("typeof", t.identifier(itemParam)), t.stringLiteral("object"))), t.callExpression(t.identifier("createItemProxy"), [t.identifier("__obs")]), t.identifier(itemParam)))]), t.variableDeclaration("const", [t.variableDeclarator(t.identifier("__el"), t.callExpression(t.identifier(ciName), [
527
+ ]))]), t.ifStatement(t.identifier("__r"), t.blockStatement([t.returnStatement(t.identifier("__r"))])), t.variableDeclaration("const", [t.variableDeclarator(t.identifier("__rd"), t.callExpression(t.memberExpression(t.identifier("d"), t.identifier("child")), []))]), t.variableDeclaration("const", [t.variableDeclarator(t.identifier("__obs"), t.callExpression(t.identifier("createItemObservable"), [t.identifier(itemParam)]))]), t.variableDeclaration("const", [t.variableDeclarator(t.identifier("__li"), t.identifier("__obs"))]), t.variableDeclaration("const", [t.variableDeclarator(t.identifier("__el"), t.callExpression(t.identifier(ciName), [
662
528
  t.identifier("__li"),
663
529
  t.identifier(idxParam),
664
530
  t.identifier("__rd")
@@ -2125,7 +1991,7 @@ function buildCreateEntryArrow(options, itemId, idxId) {
2125
1991
  }
2126
1992
  const obsId = t.identifier("__obs");
2127
1993
  const liveItemId = t.identifier("__li");
2128
- if (needsItemProxy) createEntryStmts.push(t.variableDeclaration("const", [t.variableDeclarator(obsId, t.callExpression(t.identifier("createItemObservable"), [itemId]))]), t.variableDeclaration("const", [t.variableDeclarator(liveItemId, t.conditionalExpression(t.logicalExpression("&&", t.binaryExpression("!==", itemId, t.nullLiteral()), t.binaryExpression("===", t.unaryExpression("typeof", itemId), t.stringLiteral("object"))), t.callExpression(t.identifier("createItemProxy"), [obsId]), itemId))]));
1994
+ if (needsItemProxy) createEntryStmts.push(t.variableDeclaration("const", [t.variableDeclarator(obsId, t.callExpression(t.identifier("createItemObservable"), [itemId]))]), t.variableDeclaration("const", [t.variableDeclarator(liveItemId, obsId)]));
2129
1995
  else createEntryStmts.push(t.variableDeclaration("const", [t.variableDeclarator(obsId, t.nullLiteral())]), t.variableDeclaration("const", [t.variableDeclarator(liveItemId, itemId)]));
2130
1996
  const elementId = t.identifier("__el");
2131
1997
  createEntryStmts.push(t.variableDeclaration("const", [t.variableDeclarator(elementId, t.callExpression(t.identifier(ciName), [
@@ -2150,7 +2016,7 @@ function buildSimpleCreateEntryArrow(options, itemId, idxId) {
2150
2016
  const liveItemId = t.identifier("__li");
2151
2017
  const createEntryStmts = [t.variableDeclaration("const", [t.variableDeclarator(kId, keyExprWith(options, itemId, idxId))])];
2152
2018
  if (needsRowDisposer) createEntryStmts.push(t.variableDeclaration("const", [t.variableDeclarator(rowDId, t.callExpression(t.memberExpression(t.identifier("d"), t.identifier("child")), []))]));
2153
- if (needsItemProxy) createEntryStmts.push(t.variableDeclaration("const", [t.variableDeclarator(obsId, t.callExpression(t.identifier("createItemObservable"), [itemId]))]), t.variableDeclaration("const", [t.variableDeclarator(liveItemId, t.conditionalExpression(t.logicalExpression("&&", t.binaryExpression("!==", itemId, t.nullLiteral()), t.binaryExpression("===", t.unaryExpression("typeof", itemId), t.stringLiteral("object"))), t.callExpression(t.identifier("createItemProxy"), [obsId]), itemId))]));
2019
+ if (needsItemProxy) createEntryStmts.push(t.variableDeclaration("const", [t.variableDeclarator(obsId, t.callExpression(t.identifier("createItemObservable"), [itemId]))]), t.variableDeclaration("const", [t.variableDeclarator(liveItemId, obsId)]));
2154
2020
  const createArgs = [needsItemProxy ? liveItemId : itemId, idxId];
2155
2021
  if (needsRowDisposer) createArgs.push(rowDId);
2156
2022
  createEntryStmts.push(t.variableDeclaration("const", [t.variableDeclarator(elementId, t.callExpression(t.identifier(ciName), createArgs))]));
@@ -3163,7 +3029,7 @@ function emitKeyedListSlot(slot, stmts, ctx) {
3163
3029
  const needsRowDisposer = !(patchRowExpr && t.isIdentifier(itemParam) && !createItemBodyReferencesRowDisposer(createItem));
3164
3030
  if (needsItemProxy) {
3165
3031
  ctx.importsNeeded.add("createItemObservable");
3166
- ctx.importsNeeded.add("createItemProxy");
3032
+ useObservableItem(createItem, ctx.importsNeeded);
3167
3033
  }
3168
3034
  const ciName = "__ki_" + listId;
3169
3035
  const prName = "__kp_" + listId;
@@ -5446,6 +5312,185 @@ function rewriteFnComponent(fnDecl, parentCtx) {
5446
5312
  else fnDecl.params[1] = t.identifier("d");
5447
5313
  fnDecl.body.body = newBody;
5448
5314
  }
5315
+ //#endregion
5316
+ //#region src/closure-codegen/transform/transform-component-props.ts
5317
+ /**
5318
+ * Best-effort props-shape inference for compiled component classes.
5319
+ *
5320
+ * PROBLEM: the codegen rewrites `class HomeView extends Component { ... }`
5321
+ * into `class HomeView extends CompiledComponent { ... }` with no type
5322
+ * argument. `CompiledComponent<P extends Record<string, any> = Record<string,
5323
+ * any>>` then defaults `P` to `Record<string, any>`, so every
5324
+ * `this.props.x` read inside the class infers as `any` — even though the
5325
+ * original JSX call site (`<HomeView app={this} />`) fully determines the
5326
+ * real shape.
5327
+ *
5328
+ * FIX: scan the module for JSX usages of each locally-declared component and
5329
+ * synthesize a `{ attr: Type; ... }` literal from what's actually passed, so
5330
+ * callers can thread it onto the rewritten `extends CompiledXxx<...>` clause.
5331
+ *
5332
+ * This has no type checker to lean on — only the attribute value's own AST
5333
+ * shape. Only a few forms are classified:
5334
+ * - `this` → the name of the enclosing class
5335
+ * - string / template (static) → `string`
5336
+ * - number / boolean / null literal → their primitive type
5337
+ * Anything else (a spread attribute, JSX children, an arbitrary expression)
5338
+ * makes that JSX usage "unresolvable", and the whole component is skipped —
5339
+ * emitting a narrower-than-reality type would be worse than emitting none,
5340
+ * since geatsc has no boxing to fall back on.
5341
+ */
5342
+ /**
5343
+ * Names among `componentNames` that appear as a JSX opening-element tag
5344
+ * anywhere in this module — regardless of whether the usage is resolvable
5345
+ * into a props shape (unlike `inferComponentPropsTypes`, which drops
5346
+ * unresolvable or props-less usages entirely).
5347
+ *
5348
+ * Used to distinguish "used here, but with a shape we couldn't infer" from
5349
+ * "never used as JSX in this file at all" — only the latter is safe grounds
5350
+ * for treating a class as provably propless. See `applyPropsTypeArgument`
5351
+ * in transform.ts for how this combines with `classPropsReadsAreCovered`.
5352
+ */
5353
+ function collectComponentsUsedAsJsx(ast, componentNames) {
5354
+ const used = /* @__PURE__ */ new Set();
5355
+ if (componentNames.size === 0) return used;
5356
+ traverse(ast, {
5357
+ noScope: true,
5358
+ JSXElement(path) {
5359
+ const name = path.node.openingElement.name;
5360
+ if (t.isJSXIdentifier(name) && componentNames.has(name.name)) used.add(name.name);
5361
+ }
5362
+ });
5363
+ return used;
5364
+ }
5365
+ function inferComponentPropsTypes(ast, componentNames) {
5366
+ if (componentNames.size === 0) return /* @__PURE__ */ new Map();
5367
+ const usages = /* @__PURE__ */ new Map();
5368
+ const getUsage = (name) => {
5369
+ let usage = usages.get(name);
5370
+ if (!usage) {
5371
+ usage = {
5372
+ attrs: /* @__PURE__ */ new Map(),
5373
+ siteCount: 0,
5374
+ unresolvable: false
5375
+ };
5376
+ usages.set(name, usage);
5377
+ }
5378
+ return usage;
5379
+ };
5380
+ traverse(ast, {
5381
+ noScope: true,
5382
+ JSXElement(path) {
5383
+ const opening = path.node.openingElement;
5384
+ const name = opening.name;
5385
+ if (!t.isJSXIdentifier(name) || !componentNames.has(name.name)) return;
5386
+ const usage = getUsage(name.name);
5387
+ usage.siteCount++;
5388
+ if ((path.node.children ?? []).filter((child) => !(t.isJSXText(child) && /^\s*$/.test(child.value))).length > 0) usage.unresolvable = true;
5389
+ const enclosingClassName = findEnclosingClassName(path);
5390
+ for (const attr of opening.attributes) {
5391
+ if (!t.isJSXAttribute(attr) || !t.isJSXIdentifier(attr.name)) {
5392
+ usage.unresolvable = true;
5393
+ continue;
5394
+ }
5395
+ const attrName = attr.name.name;
5396
+ const typeStr = classifyAttrValue(attr.value, enclosingClassName);
5397
+ if (typeStr == null) {
5398
+ usage.unresolvable = true;
5399
+ continue;
5400
+ }
5401
+ let observation = usage.attrs.get(attrName);
5402
+ if (!observation) {
5403
+ observation = {
5404
+ types: /* @__PURE__ */ new Set(),
5405
+ seenCount: 0
5406
+ };
5407
+ usage.attrs.set(attrName, observation);
5408
+ }
5409
+ observation.types.add(typeStr);
5410
+ observation.seenCount++;
5411
+ }
5412
+ }
5413
+ });
5414
+ const result = /* @__PURE__ */ new Map();
5415
+ for (const [name, usage] of usages) {
5416
+ if (usage.unresolvable || usage.siteCount === 0 || usage.attrs.size === 0) continue;
5417
+ const members = [...usage.attrs.entries()].map(([attrName, observation]) => {
5418
+ const required = observation.seenCount === usage.siteCount;
5419
+ const member = t.tsPropertySignature(t.identifier(attrName), t.tsTypeAnnotation(unionOfTypeStrings(observation.types)));
5420
+ member.optional = !required;
5421
+ return member;
5422
+ });
5423
+ result.set(name, t.tsTypeLiteral(members));
5424
+ }
5425
+ return result;
5426
+ }
5427
+ /**
5428
+ * Guard against emitting a props type narrower than what the class body
5429
+ * actually reads. `classDecl` must already reflect the fully-lowered body
5430
+ * (template method compiled in place) — this scans every `this.props.<key>`
5431
+ * read in the class and requires each key to be present in `propsType`.
5432
+ * Only guards against the codegen NARROWING props out from under real reads;
5433
+ * it does not otherwise validate the inferred shape.
5434
+ */
5435
+ function classPropsReadsAreCovered(classDecl, propsType) {
5436
+ const allowed = /* @__PURE__ */ new Set();
5437
+ for (const member of propsType.members) if (t.isTSPropertySignature(member) && t.isIdentifier(member.key)) allowed.add(member.key.name);
5438
+ let covered = true;
5439
+ const isPropsMember = (node) => (t.isMemberExpression(node) || t.isOptionalMemberExpression(node)) && !node.computed && t.isIdentifier(node.property, { name: "props" }) && t.isThisExpression(node.object);
5440
+ const visit = (node) => {
5441
+ if (!covered || !node || typeof node !== "object") return;
5442
+ if (Array.isArray(node)) {
5443
+ for (const child of node) visit(child);
5444
+ return;
5445
+ }
5446
+ if ((t.isMemberExpression(node) || t.isOptionalMemberExpression(node)) && !node.computed && t.isIdentifier(node.property) && isPropsMember(node.object)) {
5447
+ if (!allowed.has(node.property.name)) covered = false;
5448
+ return;
5449
+ }
5450
+ for (const key of Object.keys(node)) {
5451
+ if (key === "loc" || key === "start" || key === "end" || key === "type") continue;
5452
+ visit(node[key]);
5453
+ }
5454
+ };
5455
+ visit(classDecl.body.body);
5456
+ return covered;
5457
+ }
5458
+ function findEnclosingClassName(path) {
5459
+ let current = path.parentPath;
5460
+ while (current) {
5461
+ if (current.isFunctionExpression() || current.isFunctionDeclaration()) return null;
5462
+ if (current.isClassDeclaration()) return current.node.id ? current.node.id.name : null;
5463
+ current = current.parentPath;
5464
+ }
5465
+ return null;
5466
+ }
5467
+ function classifyAttrValue(value, enclosingClassName) {
5468
+ if (value == null) return "boolean";
5469
+ if (t.isStringLiteral(value)) return "string";
5470
+ const expr = t.isJSXExpressionContainer(value) ? value.expression : null;
5471
+ if (!expr || t.isJSXEmptyExpression(expr)) return null;
5472
+ if (t.isThisExpression(expr)) return enclosingClassName;
5473
+ if (t.isStringLiteral(expr)) return "string";
5474
+ if (t.isNumericLiteral(expr)) return "number";
5475
+ if (t.isBooleanLiteral(expr)) return "boolean";
5476
+ if (t.isNullLiteral(expr)) return "null";
5477
+ if (t.isTemplateLiteral(expr) && expr.expressions.length === 0) return "string";
5478
+ return null;
5479
+ }
5480
+ function unionOfTypeStrings(types) {
5481
+ const nodes = [...types].sort().map(typeStringToNode);
5482
+ if (nodes.length === 1) return nodes[0];
5483
+ return t.tsUnionType(nodes);
5484
+ }
5485
+ function typeStringToNode(typeStr) {
5486
+ switch (typeStr) {
5487
+ case "string": return t.tsStringKeyword();
5488
+ case "number": return t.tsNumberKeyword();
5489
+ case "boolean": return t.tsBooleanKeyword();
5490
+ case "null": return t.tsNullKeyword();
5491
+ default: return t.tsTypeReference(t.identifier(typeStr));
5492
+ }
5493
+ }
5449
5494
  const RESOLVED_RECONCILE_ID = "\0virtual:gea-reconcile";
5450
5495
  const HMR_RUNTIME_ID = "virtual:gea-hmr";
5451
5496
  const RESOLVED_HMR_RUNTIME_ID = "\0" + HMR_RUNTIME_ID;
@@ -5829,9 +5874,12 @@ function transformFile(source, _filename, options = {}) {
5829
5874
  ctx.directFnComponentParams = collectDirectFnComponentParams(ast, ctx.directFnComponents);
5830
5875
  ctx.directFnStringProps = collectDirectFnStringProps(ast, ctx.directFnComponents);
5831
5876
  ctx.directFnNoDisposer = /* @__PURE__ */ new Set();
5832
- ctx.directClassComponents = collectLocalClassComponents(ast);
5877
+ const localComponentNames = collectLocalClassComponents(ast);
5878
+ ctx.directClassComponents = new Set(localComponentNames);
5833
5879
  for (const name of options.directClassComponents ?? []) ctx.directClassComponents.add(name);
5834
5880
  ctx.directFactoryComponents = new Set(options.directFactoryComponents);
5881
+ const componentPropsShapes = inferComponentPropsTypes(ast, localComponentNames);
5882
+ const componentsUsedAsJsx = collectComponentsUsedAsJsx(ast, localComponentNames);
5835
5883
  const rewritten = [];
5836
5884
  const reactiveComponentNames = /* @__PURE__ */ new Set();
5837
5885
  let firstClassIdx = -1;
@@ -5934,18 +5982,22 @@ function transformFile(source, _filename, options = {}) {
5934
5982
  ctx.importsNeeded.add("CompiledComponent");
5935
5983
  classDecl.superClass = t.identifier("CompiledComponent");
5936
5984
  usesCompiledRuntimeBase = true;
5985
+ applyPropsTypeArgument(classDecl, className, componentPropsShapes, componentsUsedAsJsx);
5937
5986
  } else if (useTinyReactiveComponent) {
5938
5987
  ctx.importsNeeded.add("CompiledTinyReactiveComponent");
5939
5988
  classDecl.superClass = t.identifier("CompiledTinyReactiveComponent");
5940
5989
  usesCompiledRuntimeBase = true;
5990
+ applyPropsTypeArgument(classDecl, className, componentPropsShapes, componentsUsedAsJsx);
5941
5991
  } else if (useLeanReactiveComponent) {
5942
5992
  ctx.importsNeeded.add("CompiledLeanReactiveComponent");
5943
5993
  classDecl.superClass = t.identifier("CompiledLeanReactiveComponent");
5944
5994
  usesCompiledRuntimeBase = true;
5995
+ applyPropsTypeArgument(classDecl, className, componentPropsShapes, componentsUsedAsJsx);
5945
5996
  } else if (t.isIdentifier(classDecl.superClass, { name: "Component" })) {
5946
5997
  ctx.importsNeeded.add("CompiledReactiveComponent");
5947
5998
  classDecl.superClass = t.identifier("CompiledReactiveComponent");
5948
5999
  usesCompiledRuntimeBase = true;
6000
+ applyPropsTypeArgument(classDecl, className, componentPropsShapes, componentsUsedAsJsx);
5949
6001
  }
5950
6002
  if (usesCompiledRuntimeBase && hasAfterRenderAsyncHook && !hasOwnInstanceMethod(classDecl, "render")) {
5951
6003
  ctx.importsNeeded.add("scheduleAfterRenderAsync");
@@ -6064,6 +6116,70 @@ function findClassDeclarationByName(ast, name) {
6064
6116
  }
6065
6117
  return null;
6066
6118
  }
6119
+ /**
6120
+ * Thread an inferred props shape onto the rewritten `extends CompiledXxx`
6121
+ * clause as an explicit type argument, e.g. `CompiledComponent<{ app: App }>`.
6122
+ *
6123
+ * Two guards keep this from ever emitting a WRONG type (never just an
6124
+ * incomplete one):
6125
+ * - If the hand-written source already annotated `extends Component<...>`,
6126
+ * that `superTypeParameters` node survives the `superClass` identifier
6127
+ * swap above untouched — do not override the author's own type.
6128
+ * - If the class body reads a `this.props.<key>` that the inferred shape
6129
+ * doesn't cover (e.g. a caller in another file passes it, invisible to
6130
+ * this per-file scan), leave the class with no type argument so it keeps
6131
+ * the permissive `Record<string, any>` default rather than breaking.
6132
+ *
6133
+ * A class with NO JSX usage site in this file at all (a root component,
6134
+ * mounted by the runtime rather than written as `<App/>` anywhere) gets no
6135
+ * entry in `componentPropsShapes` — inference only ever runs over observed
6136
+ * call sites, so an unobserved component produces no shape, resolvable or
6137
+ * not. Falling back to the permissive `Record<string, any>` default in that
6138
+ * case isn't merely imprecise, it's backwards: silence at every call site is
6139
+ * exactly the evidence that the class takes no props, so the honest emission
6140
+ * is an explicit empty type — `{}` — not the default's promise that it might
6141
+ * accept arbitrary ones.
6142
+ *
6143
+ * Emitting that empty type is gated the same way as the shape-inference path
6144
+ * above, by the SAME two-guard standard, instantiated for the "no props"
6145
+ * claim instead of an inferred one:
6146
+ * - `!componentsUsedAsJsx.has(className)` — the per-file JSX-usage guard.
6147
+ * This is a per-file scan, so it cannot see a caller in ANOTHER file
6148
+ * that writes `<App foo={x}/>`. That is sound here for a reason the
6149
+ * general shape-inference path above does not get to rely on: the guard
6150
+ * below additionally requires the class to read NO `this.props.<key>` at
6151
+ * all, in its own body. A component that genuinely uses props always
6152
+ * reads at least one, so a cross-file caller passing real data to a
6153
+ * class that reads none of it would itself be dead-argument surface on
6154
+ * the CALLER, not a case this class's compiled shape needs to accept.
6155
+ * Nothing here can silently misbehave: the only externally-visible
6156
+ * effect of a stricter-than-{} … Record<string, any> narrowing is that
6157
+ * TypeScript itself would flag an excess/unknown prop at that other JSX
6158
+ * call site — a loud compile error, not silent wrong behavior, and
6159
+ * exactly the category of bug an empty props type exists to catch.
6160
+ * - `classPropsReadsAreCovered(classDecl, <empty type>)` — reuses the
6161
+ * existing reads-coverage guard against a zero-member shape, i.e. "this
6162
+ * class's body contains no `this.props.<key>` read whatsoever." This is
6163
+ * strictly stronger than the non-empty-shape case (which only requires
6164
+ * coverage of the OBSERVED keys) — here NO key may be read, observed or
6165
+ * not — so it still catches the shape-inference guard's original worry
6166
+ * (a real prop consumed only via a cross-file call site) as a special
6167
+ * case: if the body read that prop, this guard fails and the permissive
6168
+ * default is kept, exactly as before.
6169
+ */
6170
+ function applyPropsTypeArgument(classDecl, className, componentPropsShapes, componentsUsedAsJsx) {
6171
+ if (classDecl.superTypeParameters) return;
6172
+ const propsType = componentPropsShapes.get(className);
6173
+ if (propsType) {
6174
+ if (!classPropsReadsAreCovered(classDecl, propsType)) return;
6175
+ classDecl.superTypeParameters = t.tsTypeParameterInstantiation([propsType]);
6176
+ return;
6177
+ }
6178
+ if (componentsUsedAsJsx.has(className)) return;
6179
+ const emptyPropsType = t.tsTypeLiteral([]);
6180
+ if (!classPropsReadsAreCovered(classDecl, emptyPropsType)) return;
6181
+ classDecl.superTypeParameters = t.tsTypeParameterInstantiation([emptyPropsType]);
6182
+ }
6067
6183
  function collectLocalClassComponents(ast) {
6068
6184
  const names = /* @__PURE__ */ new Set();
6069
6185
  for (const node of ast.program.body) {
@@ -6384,10 +6500,12 @@ function injectHMR(ast, componentClassNames, defaultExportClassName, componentIm
6384
6500
  hmrStmts.push(js`const __moduleExports = ${t.objectExpression(exportProperties)};`);
6385
6501
  hmrStmts.push(js`registerHotModule(${jsExpr`${importMeta()}.url`}, __moduleExports);`);
6386
6502
  const acceptBody = [t.variableDeclaration("const", [t.variableDeclarator(t.identifier("__updatedModule"), t.logicalExpression("||", t.identifier("newModule"), t.identifier("__moduleExports")))]), t.expressionStatement(t.callExpression(t.identifier("registerHotModule"), [t.memberExpression(importMeta(), t.identifier("url")), t.identifier("__updatedModule")]))];
6503
+ acceptBody.push(js`let __patched = false;`);
6387
6504
  for (const cn of componentClassNames) {
6388
6505
  const key = cn === defaultExportClassName ? "default" : cn;
6389
- acceptBody.push(t.expressionStatement(t.callExpression(t.identifier("handleComponentUpdate"), [t.memberExpression(importMeta(), t.identifier("url")), t.objectExpression([t.objectProperty(t.identifier("default"), t.memberExpression(t.identifier("__updatedModule"), t.identifier(key)))])])));
6506
+ acceptBody.push(t.expressionStatement(t.assignmentExpression("=", t.identifier("__patched"), t.logicalExpression("||", t.callExpression(t.identifier("handleComponentUpdate"), [t.memberExpression(importMeta(), t.identifier("url")), t.objectExpression([t.objectProperty(t.identifier("default"), t.memberExpression(t.identifier("__updatedModule"), t.identifier(key)))])]), t.identifier("__patched")))));
6390
6507
  }
6508
+ acceptBody.push(t.ifStatement(t.unaryExpression("!", t.identifier("__patched")), t.expressionStatement(t.callExpression(t.memberExpression(hot(), t.identifier("invalidate")), []))));
6391
6509
  hmrStmts.push(t.expressionStatement(t.callExpression(t.memberExpression(hot(), t.identifier("accept")), [t.arrowFunctionExpression([t.identifier("newModule")], t.blockStatement(acceptBody))])));
6392
6510
  hmrStmts.push(...createAccepts(componentImports, proxyDep, shouldSkipDepAccept));
6393
6511
  for (const cn of componentClassNames) {
@@ -8124,6 +8242,7 @@ function geaPlugin(options = {}) {
8124
8242
  const irComponents = /* @__PURE__ */ new Map();
8125
8243
  const irStores = /* @__PURE__ */ new Map();
8126
8244
  const hostCapabilities = /* @__PURE__ */ new Set();
8245
+ const staticModuleShapes = /* @__PURE__ */ new Map();
8127
8246
  const storeRegistry = /* @__PURE__ */ new Map();
8128
8247
  const resolveImportPath = (importer, source) => {
8129
8248
  const base = resolve(dirname(importer), source);
@@ -8281,7 +8400,10 @@ function geaPlugin(options = {}) {
8281
8400
  if (!cleanId.match(/\.(js|jsx|ts|tsx)$/) || cleanId.includes("node_modules")) return null;
8282
8401
  let transformedCode = code;
8283
8402
  let changed = false;
8284
- if (irOptions?.enabled) recordHostCapabilities(code);
8403
+ if (irOptions?.enabled) {
8404
+ recordHostCapabilities(code);
8405
+ staticModuleShapes.set(cleanId, collectStaticModuleShape(code));
8406
+ }
8285
8407
  if (code.includes("extends Store") || code.includes("new Store(")) {
8286
8408
  storeModules.add(cleanId);
8287
8409
  const storeClassName = extractStoreClassName(code);
@@ -8367,7 +8489,7 @@ function geaPlugin(options = {}) {
8367
8489
  map: null
8368
8490
  };
8369
8491
  },
8370
- generateBundle(_options, bundle) {
8492
+ async generateBundle(_options, bundle) {
8371
8493
  if (!irOptions?.enabled) return;
8372
8494
  const renderedIds = renderedModuleIds(bundle);
8373
8495
  const modules = Array.from(irModules.values()).filter((module) => {
@@ -8389,12 +8511,23 @@ function geaPlugin(options = {}) {
8389
8511
  if (candidateModule && !modules.includes(candidateModule)) modules.push(candidateModule);
8390
8512
  }
8391
8513
  }
8514
+ const liveComponents = Array.from(irComponents.values()).filter((component) => componentIds.has(component.id));
8515
+ const logicalRoutes = await collectLogicalModuleRoutes({
8516
+ entries: entryFacadeModuleIds(bundle),
8517
+ root: resolvedConfig?.root,
8518
+ moduleShapes: staticModuleShapes,
8519
+ resolveModule: async (specifier, importer) => {
8520
+ const resolved = await this.resolve(specifier, importer, { skipSelf: true });
8521
+ return resolved && !resolved.external ? cleanRollupModuleId(resolved.id) : null;
8522
+ }
8523
+ });
8524
+ const components = liveComponents.map((component) => attachRootRendererAuthority(component, logicalRoutes, staticModuleShapes));
8392
8525
  const irBundle = {
8393
8526
  schema: "gea-ir",
8394
8527
  version: 1,
8395
8528
  entry: geaIrEntryFromBundle(bundle) ?? geaIrConfiguredEntry(resolvedConfig),
8396
8529
  modules,
8397
- components: Array.from(irComponents.values()).filter((component) => componentIds.has(component.id)),
8530
+ components,
8398
8531
  stores: Array.from(irStores.values()).filter((store) => storeIds.has(store.id)),
8399
8532
  hostCapabilities: Array.from(hostCapabilities).sort()
8400
8533
  };
@@ -8472,6 +8605,105 @@ function geaPlugin(options = {}) {
8472
8605
  if (/\bdocument\s*\./.test(source)) hostCapabilities.add("dom");
8473
8606
  }
8474
8607
  }
8608
+ function collectStaticModuleShape(source) {
8609
+ const specifiers = /* @__PURE__ */ new Set();
8610
+ const exportsByLocalName = /* @__PURE__ */ new Map();
8611
+ const addExport = (localName, exportName) => {
8612
+ const names = exportsByLocalName.get(localName) ?? /* @__PURE__ */ new Set();
8613
+ names.add(exportName);
8614
+ exportsByLocalName.set(localName, names);
8615
+ };
8616
+ try {
8617
+ const ast = parse(source, {
8618
+ sourceType: "module",
8619
+ plugins: [
8620
+ "typescript",
8621
+ "jsx",
8622
+ "classProperties",
8623
+ "classPrivateProperties",
8624
+ "classPrivateMethods"
8625
+ ]
8626
+ });
8627
+ for (const statement of ast.program.body) {
8628
+ if ((statement.type === "ImportDeclaration" || statement.type === "ExportNamedDeclaration" || statement.type === "ExportAllDeclaration") && statement.source?.value) specifiers.add(statement.source.value);
8629
+ if (statement.type === "ExportNamedDeclaration") {
8630
+ const declaration = statement.declaration;
8631
+ if ((declaration?.type === "ClassDeclaration" || declaration?.type === "FunctionDeclaration") && declaration.id) addExport(declaration.id.name, declaration.id.name);
8632
+ else if (declaration?.type === "VariableDeclaration") {
8633
+ for (const declarator of declaration.declarations) if (declarator.id.type === "Identifier") addExport(declarator.id.name, declarator.id.name);
8634
+ }
8635
+ if (!statement.source) for (const specifier of statement.specifiers) {
8636
+ if (specifier.type !== "ExportSpecifier") continue;
8637
+ addExport(specifier.local.type === "Identifier" ? specifier.local.name : specifier.local.value, specifier.exported.type === "Identifier" ? specifier.exported.name : specifier.exported.value);
8638
+ }
8639
+ } else if (statement.type === "ExportDefaultDeclaration") {
8640
+ const declaration = statement.declaration;
8641
+ if ((declaration.type === "ClassDeclaration" || declaration.type === "FunctionDeclaration") && declaration.id) addExport(declaration.id.name, "default");
8642
+ else if (declaration.type === "Identifier") addExport(declaration.name, "default");
8643
+ }
8644
+ }
8645
+ } catch {}
8646
+ return {
8647
+ specifiers: [...specifiers].sort(),
8648
+ exportsByLocalName: new Map([...exportsByLocalName].map(([localName, exportNames]) => [localName, new Set([...exportNames].sort())]))
8649
+ };
8650
+ }
8651
+ /** Logical source coordinates are relative to the project, never to its checkout. */
8652
+ async function collectLogicalModuleRoutes(input) {
8653
+ let root = input.root ?? (input.entries[0] ? dirname(input.entries[0]) : "/");
8654
+ if (!input.root) while (input.entries.some((entry) => relative(root, entry).startsWith("../"))) root = dirname(root);
8655
+ const routes = /* @__PURE__ */ new Map();
8656
+ const owners = /* @__PURE__ */ new Map();
8657
+ const pending = [];
8658
+ const add = (moduleId, fallback) => {
8659
+ moduleId = cleanRollupModuleId(moduleId);
8660
+ if (routes.has(moduleId)) return;
8661
+ const local = relative(root, moduleId).replace(/\\/g, "/");
8662
+ const route = !local.startsWith("../") && !moduleId.startsWith("\0") ? `/${local}` : fallback;
8663
+ if (!route) return;
8664
+ const owner = owners.get(route);
8665
+ if (owner && owner !== moduleId) throw new Error(`Ambiguous Gea renderer module coordinate: ${route}`);
8666
+ owners.set(route, moduleId);
8667
+ routes.set(moduleId, new Set([route]));
8668
+ pending.push(moduleId);
8669
+ };
8670
+ for (const entry of input.entries) add(entry, `/${relative(root, entry).replace(/\\/g, "/")}`);
8671
+ while (pending.length > 0) {
8672
+ const moduleId = pending.shift();
8673
+ const route = [...routes.get(moduleId)][0];
8674
+ for (const specifier of input.moduleShapes.get(moduleId)?.specifiers ?? []) {
8675
+ const target = await input.resolveModule(specifier, moduleId);
8676
+ if (!target) continue;
8677
+ add(target, specifier.startsWith("./") || specifier.startsWith("../") ? posix.join(posix.dirname(route), specifier) : specifier.startsWith("/") ? null : `/@modules/${specifier}`);
8678
+ }
8679
+ }
8680
+ return routes;
8681
+ }
8682
+ function attachRootRendererAuthority(component, logicalRoutes, moduleShapes) {
8683
+ const moduleId = cleanRollupModuleId(component.module);
8684
+ const routes = logicalRoutes.get(moduleId);
8685
+ const exportNames = moduleShapes.get(moduleId)?.exportsByLocalName.get(component.exportName);
8686
+ if (!routes?.size || !exportNames?.size) return component;
8687
+ const candidates = [...routes].flatMap((moduleSpecifier) => [...exportNames].map((exportName) => ({
8688
+ moduleSpecifier,
8689
+ exportName
8690
+ })));
8691
+ candidates.sort((left, right) => {
8692
+ return (left.exportName === component.exportName ? 0 : 1) - (right.exportName === component.exportName ? 0 : 1) || left.moduleSpecifier.length - right.moduleSpecifier.length || `${left.moduleSpecifier}#${left.exportName}`.localeCompare(`${right.moduleSpecifier}#${right.exportName}`);
8693
+ });
8694
+ const coordinate = candidates[0];
8695
+ const digest = createHash("sha256").update(`${coordinate.moduleSpecifier}\u0000${coordinate.exportName}`).digest("hex");
8696
+ return {
8697
+ ...component,
8698
+ rootRendererAuthority: {
8699
+ component: coordinate,
8700
+ rendererResourceId: `gea-renderer:v1:${digest}`
8701
+ }
8702
+ };
8703
+ }
8704
+ function entryFacadeModuleIds(bundle) {
8705
+ return Object.values(bundle).filter((item) => item.type === "chunk" && item.isEntry && item.facadeModuleId).map((item) => cleanRollupModuleId(item.facadeModuleId)).sort();
8706
+ }
8475
8707
  function renderedModuleIds(bundle) {
8476
8708
  const ids = /* @__PURE__ */ new Set();
8477
8709
  for (const item of Object.values(bundle)) {
@@ -8524,7 +8756,29 @@ function compilerRuntimePathFromCoreEntry(entry) {
8524
8756
  if (clean.endsWith("/dist/index.mjs")) return clean.slice(0, -15) + "/dist/compiler-runtime.mjs";
8525
8757
  return null;
8526
8758
  }
8759
+ function compilerRuntimeExportLines(runtimePath) {
8760
+ if (!runtimePath.endsWith(".ts")) return null;
8761
+ let source;
8762
+ try {
8763
+ source = readFileSync(runtimePath, "utf8");
8764
+ } catch {
8765
+ return null;
8766
+ }
8767
+ const dir = dirname(runtimePath);
8768
+ const lines = [];
8769
+ const EXPORT_FROM_RE = /export\s*\{([^}]*)\}\s*from\s*['"](\.[^'"]+)['"]/g;
8770
+ let match;
8771
+ while (match = EXPORT_FROM_RE.exec(source)) {
8772
+ const names = match[1];
8773
+ const relativeSpecifier = match[2];
8774
+ const absoluteSpecifier = normalizeImportPath(resolve(dir, relativeSpecifier));
8775
+ lines.push(`export {${names}} from ${JSON.stringify(absoluteSpecifier)}`);
8776
+ }
8777
+ return lines.length > 0 ? lines : null;
8778
+ }
8527
8779
  function compilerRuntimeSource(runtimePath) {
8780
+ const perSubmoduleLines = compilerRuntimeExportLines(runtimePath);
8781
+ if (perSubmoduleLines) return `${perSubmoduleLines.join("\n")}\n`;
8528
8782
  const path = normalizeImportPath(runtimePath);
8529
8783
  return `export {
8530
8784
  NOOP_DISPOSER,
@@ -8567,6 +8821,7 @@ function compilerRuntimeSource(runtimePath) {
8567
8821
  GEA_DIRTY_PROPS,
8568
8822
  createItemObservable,
8569
8823
  createItemProxy,
8824
+ readItem,
8570
8825
  _rescue,
8571
8826
  GEA_CREATE_TEMPLATE,
8572
8827
  GEA_PARENT_COMPONENT,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geajs/vite-plugin",
3
- "version": "1.4.1",
3
+ "version": "1.4.2",
4
4
  "description": "Vite plugin for Gea framework - JSX/TSX transform, reactivity, HMR",
5
5
  "type": "module",
6
6
  "main": "./dist/index.mjs",