@geajs/vite-plugin 1.0.0 → 1.0.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.js +299 -69
  2. package/package.json +3 -1
package/dist/index.js CHANGED
@@ -1766,7 +1766,10 @@ function collectTextChildren(node, stateRefs, stateProps) {
1766
1766
  return { textTemplate, textExpressions, shouldBuildTextTemplate };
1767
1767
  }
1768
1768
  function analyzeChildren(node, tagName, elementPath, bindings, propBindings, arrayMaps, stateProps, stateRefs, textTemplate, textExpressions, shouldBuildTextTemplate, walk, onUnresolvedMap, classBody2, propsParamName, destructuredPropNames, templateSetupContext, rerenderPropNames, rerenderConditions, conditionalSlots) {
1769
- node.children.forEach((child, index) => {
1769
+ const directChildren = getDirectChildElements(node.children);
1770
+ let directChildCursor = 0;
1771
+ for (let index = 0; index < node.children.length; index++) {
1772
+ const child = node.children[index];
1770
1773
  if (t7.isJSXExpressionContainer(child) && !t7.isJSXEmptyExpression(child.expression)) {
1771
1774
  const expr = child.expression;
1772
1775
  if (isMapCall(expr)) {
@@ -1822,11 +1825,14 @@ function analyzeChildren(node, tagName, elementPath, bindings, propBindings, arr
1822
1825
  hasNestedMapCall
1823
1826
  );
1824
1827
  }
1828
+ } else if (t7.isJSXElement(child)) {
1829
+ const seg = directChildren[directChildCursor]?.selectorSegment;
1830
+ directChildCursor++;
1831
+ walk(child, seg ? [...elementPath, seg] : elementPath);
1832
+ } else if (t7.isJSXFragment(child)) {
1833
+ walk(child, elementPath);
1825
1834
  }
1826
- });
1827
- getDirectChildElements(node.children).forEach((child) => {
1828
- walk(child.node, [...elementPath, child.selectorSegment]);
1829
- });
1835
+ }
1830
1836
  }
1831
1837
  function isMapCall(expr) {
1832
1838
  return t7.isCallExpression(expr) && t7.isMemberExpression(expr.callee) && t7.isIdentifier(expr.callee.property) && expr.callee.property.name === "map";
@@ -2896,23 +2902,22 @@ function transformJSXExpression(expr, ctx, skipEvents = false) {
2896
2902
  return expr;
2897
2903
  }
2898
2904
  }
2899
- function collectComponentTags(node, imports, instanceTags, registrationTags, registrationOnly = false) {
2900
- const allTags = registrationTags || new Set(instanceTags);
2901
- const visitExpr = (expr, inMapCallback = false) => {
2902
- if (t9.isJSXElement(expr)) collectComponentTags(expr, imports, instanceTags, allTags, inMapCallback);
2903
- else if (t9.isJSXFragment(expr)) collectComponentTags(expr, imports, instanceTags, allTags, inMapCallback);
2905
+ function collectComponentTags(node, imports, instanceTags, inMapCallback = false) {
2906
+ const visitExpr = (expr, inMap = false) => {
2907
+ if (t9.isJSXElement(expr)) collectComponentTags(expr, imports, instanceTags, inMap);
2908
+ else if (t9.isJSXFragment(expr)) collectComponentTags(expr, imports, instanceTags, inMap);
2904
2909
  else if (t9.isLogicalExpression(expr)) {
2905
- visitExpr(expr.left, inMapCallback);
2906
- visitExpr(expr.right, inMapCallback);
2910
+ visitExpr(expr.left, inMap);
2911
+ visitExpr(expr.right, inMap);
2907
2912
  } else if (t9.isConditionalExpression(expr)) {
2908
- visitExpr(expr.consequent, inMapCallback);
2909
- visitExpr(expr.alternate, inMapCallback);
2913
+ visitExpr(expr.consequent, inMap);
2914
+ visitExpr(expr.alternate, inMap);
2910
2915
  } else if (t9.isCallExpression(expr)) {
2911
2916
  expr.arguments.forEach((arg) => {
2912
2917
  if (!t9.isArrowFunctionExpression(arg) && !t9.isFunctionExpression(arg)) return;
2913
2918
  const body = arg.body;
2914
- if (t9.isJSXElement(body)) collectComponentTags(body, imports, instanceTags, allTags, true);
2915
- else if (t9.isJSXFragment(body)) collectComponentTags(body, imports, instanceTags, allTags, true);
2919
+ if (t9.isJSXElement(body)) collectComponentTags(body, imports, instanceTags, true);
2920
+ else if (t9.isJSXFragment(body)) collectComponentTags(body, imports, instanceTags, true);
2916
2921
  else if (t9.isBlockStatement(body)) {
2917
2922
  const ret = body.body.find((s) => t9.isReturnStatement(s) && s.argument != null);
2918
2923
  if (ret?.argument) visitExpr(ret.argument, true);
@@ -2923,28 +2928,27 @@ function collectComponentTags(node, imports, instanceTags, registrationTags, reg
2923
2928
  if (t9.isJSXElement(node)) {
2924
2929
  const tag = getJSXTagName(node.openingElement.name);
2925
2930
  if (tag && isComponentTag(tag) && imports.has(tag)) {
2926
- allTags.add(tag);
2927
- if (!registrationOnly) instanceTags.push(tag);
2931
+ if (!inMapCallback) instanceTags.push(tag);
2928
2932
  }
2929
2933
  node.children.forEach((c) => {
2930
- if (t9.isJSXElement(c)) collectComponentTags(c, imports, instanceTags, allTags, registrationOnly);
2931
- else if (t9.isJSXFragment(c)) collectComponentTags(c, imports, instanceTags, allTags, registrationOnly);
2934
+ if (t9.isJSXElement(c)) collectComponentTags(c, imports, instanceTags, inMapCallback);
2935
+ else if (t9.isJSXFragment(c)) collectComponentTags(c, imports, instanceTags, inMapCallback);
2932
2936
  else if (t9.isJSXExpressionContainer(c) && !t9.isJSXEmptyExpression(c.expression)) {
2933
2937
  const expr = c.expression;
2934
- if (t9.isJSXElement(expr)) collectComponentTags(expr, imports, instanceTags, allTags, registrationOnly);
2935
- else if (t9.isJSXFragment(expr)) collectComponentTags(expr, imports, instanceTags, allTags, registrationOnly);
2936
- else visitExpr(expr, registrationOnly);
2938
+ if (t9.isJSXElement(expr)) collectComponentTags(expr, imports, instanceTags, inMapCallback);
2939
+ else if (t9.isJSXFragment(expr)) collectComponentTags(expr, imports, instanceTags, inMapCallback);
2940
+ else visitExpr(expr, inMapCallback);
2937
2941
  }
2938
2942
  });
2939
2943
  } else {
2940
2944
  node.children.forEach((c) => {
2941
- if (t9.isJSXElement(c)) collectComponentTags(c, imports, instanceTags, allTags, registrationOnly);
2942
- else if (t9.isJSXFragment(c)) collectComponentTags(c, imports, instanceTags, allTags, registrationOnly);
2945
+ if (t9.isJSXElement(c)) collectComponentTags(c, imports, instanceTags, inMapCallback);
2946
+ else if (t9.isJSXFragment(c)) collectComponentTags(c, imports, instanceTags, inMapCallback);
2943
2947
  else if (t9.isJSXExpressionContainer(c) && !t9.isJSXEmptyExpression(c.expression)) {
2944
2948
  const expr = c.expression;
2945
- if (t9.isJSXElement(expr)) collectComponentTags(expr, imports, instanceTags, allTags, registrationOnly);
2946
- else if (t9.isJSXFragment(expr)) collectComponentTags(expr, imports, instanceTags, allTags, registrationOnly);
2947
- else visitExpr(expr, registrationOnly);
2949
+ if (t9.isJSXElement(expr)) collectComponentTags(expr, imports, instanceTags, inMapCallback);
2950
+ else if (t9.isJSXFragment(expr)) collectComponentTags(expr, imports, instanceTags, inMapCallback);
2951
+ else visitExpr(expr, inMapCallback);
2948
2952
  }
2949
2953
  });
2950
2954
  }
@@ -3006,6 +3010,27 @@ function processElement(node, parts, ctx, elementPath = []) {
3006
3010
  return;
3007
3011
  }
3008
3012
  }
3013
+ if (isComp && (!ctx.inMapCallback || elementPath.length > 0)) {
3014
+ const propsEntries = [];
3015
+ for (const attr of node.openingElement.attributes) {
3016
+ if (!t9.isJSXAttribute(attr) || !t9.isJSXIdentifier(attr.name)) continue;
3017
+ const name = attr.name.name;
3018
+ if (name === "key") continue;
3019
+ let value;
3020
+ if (attr.value === null) value = t9.booleanLiteral(true);
3021
+ else if (t9.isStringLiteral(attr.value)) value = attr.value;
3022
+ else if (t9.isJSXExpressionContainer(attr.value) && !t9.isJSXEmptyExpression(attr.value.expression))
3023
+ value = attr.value.expression;
3024
+ else continue;
3025
+ propsEntries.push(t9.objectProperty(t9.identifier(name), value));
3026
+ }
3027
+ pushString(parts, "");
3028
+ parts.push({
3029
+ type: "expression",
3030
+ value: t9.newExpression(t9.identifier(tagName), [t9.objectExpression(propsEntries)])
3031
+ });
3032
+ return;
3033
+ }
3009
3034
  const effectiveTag = isComp ? pascalToKebabCase(tagName) : tagName;
3010
3035
  const propContext = getPropContext(ctx.templateSetupContext?.params);
3011
3036
  const rootClassSelector = elementPath.length === 0 ? getRootClassSelector(node) : null;
@@ -3834,12 +3859,62 @@ function getPropsBuilderMethodName(child) {
3834
3859
  function getEnsureChildMethodName(child) {
3835
3860
  return `__ensureChild_${child.instanceVar.replace(/^_/, "")}`;
3836
3861
  }
3862
+ function collectBindingNames(stmt) {
3863
+ if (t11.isVariableDeclaration(stmt)) {
3864
+ const names = [];
3865
+ const collect = (node) => {
3866
+ if (t11.isIdentifier(node)) names.push(node.name);
3867
+ else if (t11.isObjectPattern(node))
3868
+ node.properties.forEach(
3869
+ (p) => collect(t11.isRestElement(p) ? p.argument : p.value)
3870
+ );
3871
+ else if (t11.isArrayPattern(node)) node.elements.forEach((e) => e && collect(e));
3872
+ };
3873
+ stmt.declarations.forEach((d) => collect(d.id));
3874
+ return names;
3875
+ }
3876
+ return [];
3877
+ }
3878
+ function collectTestIdentifiers(node) {
3879
+ const names = /* @__PURE__ */ new Set();
3880
+ const visit = (n) => {
3881
+ if (t11.isIdentifier(n)) names.add(n.name);
3882
+ for (const key of t11.VISITOR_KEYS[n.type] || []) {
3883
+ const child = n[key];
3884
+ if (Array.isArray(child)) child.forEach((c) => c?.type && visit(c));
3885
+ else if (child?.type) visit(child);
3886
+ }
3887
+ };
3888
+ visit(node);
3889
+ return names;
3890
+ }
3837
3891
  function buildPropsBuilderMethod(child) {
3838
- const setupStmts = (child.setupStatements || []).map(
3839
- (statement) => t11.cloneNode(statement, true)
3840
- );
3892
+ const propsStmtClones = (child.setupStatements || []).map((statement) => t11.cloneNode(statement, true));
3841
3893
  const returnStmt = t11.returnStatement(t11.cloneNode(child.propsExpression, true));
3842
- const prunedSetup = pruneUnusedSetupDestructuring(setupStmts, [returnStmt]);
3894
+ const propsIdentifiers = collectTestIdentifiers(returnStmt);
3895
+ for (const stmt of propsStmtClones) {
3896
+ for (const name of collectTestIdentifiers(stmt)) propsIdentifiers.add(name);
3897
+ }
3898
+ const relevantGuards = (child.earlyReturnGuards || []).filter((guard) => {
3899
+ const testRefs = collectTestIdentifiers(guard.test);
3900
+ return [...testRefs].some((name) => propsIdentifiers.has(name));
3901
+ });
3902
+ const existingBindings = new Set(propsStmtClones.flatMap(collectBindingNames));
3903
+ const guardStmtClones = relevantGuards.length > 0 ? (child.guardSetupStatements || []).filter((s) => !collectBindingNames(s).every((n) => existingBindings.has(n))).map((s) => t11.cloneNode(s, true)) : [];
3904
+ const setupStmts = [...guardStmtClones, ...propsStmtClones];
3905
+ const guardNodes = relevantGuards.map((g) => g.test);
3906
+ const prunedSetup = pruneUnusedSetupDestructuring(setupStmts, [returnStmt, ...guardNodes]);
3907
+ for (const guard of relevantGuards) {
3908
+ const guardStmt = t11.ifStatement(t11.cloneNode(guard.test, true), t11.returnStatement(t11.objectExpression([])));
3909
+ const testRefs = collectTestIdentifiers(guard.test);
3910
+ let insertIndex = 0;
3911
+ for (let i = 0; i < prunedSetup.length; i++) {
3912
+ if (collectBindingNames(prunedSetup[i]).some((name) => testRefs.has(name))) {
3913
+ insertIndex = i + 1;
3914
+ }
3915
+ }
3916
+ prunedSetup.splice(insertIndex, 0, guardStmt);
3917
+ }
3843
3918
  return appendToBody(jsMethod2`${id4(getPropsBuilderMethodName(child))}() {}`, ...prunedSetup, returnStmt);
3844
3919
  }
3845
3920
  function buildEnsureMethod(child) {
@@ -4328,7 +4403,7 @@ function hoistStoreReads(entries, storeVar) {
4328
4403
  }));
4329
4404
  return { hoists: Array.from(hoistMap.values()), patchedEntries };
4330
4405
  }
4331
- function generateCreateItemMethod(arrayMap) {
4406
+ function generateCreateItemMethod(arrayMap, templatePropNames, wholeParamName) {
4332
4407
  if (!arrayMap.itemTemplate) return null;
4333
4408
  const arrayPath = pathPartsToString(arrayMap.arrayPathParts || normalizePathParts(arrayMap.arrayPath || ""));
4334
4409
  const arrayName = arrayPath.replace(/\./g, "");
@@ -4337,7 +4412,18 @@ function generateCreateItemMethod(arrayMap) {
4337
4412
  const renderMethodName = `render${capName}Item`;
4338
4413
  const containerProp = `__${arrayPath.replace(/\./g, "_")}_container`;
4339
4414
  const itemIdProperty = arrayMap.itemIdProperty;
4340
- const { entries, requiresRerender } = collectPatchEntries(arrayMap);
4415
+ let { entries, requiresRerender } = collectPatchEntries(arrayMap);
4416
+ const propNames = templatePropNames ?? /* @__PURE__ */ new Set();
4417
+ if (propNames.size > 0 || wholeParamName) {
4418
+ entries = entries.map((e) => ({
4419
+ ...e,
4420
+ expression: replacePropRefsInExpression(
4421
+ t14.cloneNode(e.expression, true),
4422
+ propNames,
4423
+ wholeParamName
4424
+ )
4425
+ }));
4426
+ }
4341
4427
  if (requiresRerender) {
4342
4428
  const createMethod = jsMethod4`${id7(methodName)}(item) {}`;
4343
4429
  if (arrayMap.indexVariable) createMethod.params.push(t14.identifier("__idx"));
@@ -5448,7 +5534,6 @@ function generateRenderItemMethod(arrayMap, imports, eventHandlers, eventIdCount
5448
5534
  ctx.mapRootEventToken
5449
5535
  );
5450
5536
  const methodName = `render${arrayPath.charAt(0).toUpperCase() + arrayPath.slice(1).replace(/\./g, "")}Item`;
5451
- wrapped.expressions = wrapped.expressions.map((expr) => unwrapComparisonOperands(expr));
5452
5537
  const propNames = /* @__PURE__ */ new Set();
5453
5538
  let wholeParam;
5454
5539
  if (classBody2) {
@@ -5464,6 +5549,9 @@ function generateRenderItemMethod(arrayMap, imports, eventHandlers, eventIdCount
5464
5549
  wholeParam = templateMethod.params[0].name;
5465
5550
  }
5466
5551
  }
5552
+ wrapped.expressions = wrapped.expressions.map(
5553
+ (expr) => replacePropRefsInExpression(unwrapComparisonOperands(expr), propNames, wholeParam)
5554
+ );
5467
5555
  const handlerRegStmts = buildHandlerRegistrationStatements(
5468
5556
  handlerPropsInMap,
5469
5557
  arrayMap.itemVariable,
@@ -5498,7 +5586,7 @@ function generateRenderItemMethod(arrayMap, imports, eventHandlers, eventIdCount
5498
5586
  }
5499
5587
  function insertItemMarker(tl, itemVar, itemIdProperty, containerBindingId, eventToken) {
5500
5588
  const first = tl.quasis[0].value.raw;
5501
- const tagMatch = first.match(/^(<\w+)(\s|>)/);
5589
+ const tagMatch = first.match(/^(<[\w-]+)(\s|>)/);
5502
5590
  let rewrittenFirst;
5503
5591
  const itemIdExpr = itemIdProperty ? t16.memberExpression(t16.identifier(itemVar), t16.identifier(itemIdProperty)) : t16.callExpression(t16.identifier("String"), [t16.identifier(itemVar)]);
5504
5592
  if (tagMatch) {
@@ -5508,17 +5596,17 @@ function insertItemMarker(tl, itemVar, itemIdProperty, containerBindingId, event
5508
5596
  rewrittenFirst = `${tagMatch[1]} data-gea-item-id="`;
5509
5597
  }
5510
5598
  } else {
5511
- const nameMatch = first.match(/^<(\w+)/);
5599
+ const nameMatch = first.match(/^<([\w-]+)/);
5512
5600
  if (containerBindingId) {
5513
5601
  rewrittenFirst = nameMatch ? `${nameMatch[0]} id="` : first;
5514
5602
  } else {
5515
5603
  rewrittenFirst = nameMatch ? `${nameMatch[0]} data-gea-item-id="` : first;
5516
5604
  }
5517
5605
  }
5518
- if (!tagMatch && !first.match(/^<(\w+)/)) {
5606
+ if (!tagMatch && !first.match(/^<([\w-]+)/)) {
5519
5607
  return tl;
5520
5608
  }
5521
- const remainder = (tagMatch ? first.substring(tagMatch[1].length) : first.substring(first.match(/^<(\w+)/)[0].length)) || "";
5609
+ const remainder = (tagMatch ? first.substring(tagMatch[1].length) : first.substring(first.match(/^<([\w-]+)/)[0].length)) || "";
5522
5610
  const eventAttr = eventToken ? ` data-gea-event="${eventToken}"` : "";
5523
5611
  if (containerBindingId) {
5524
5612
  const idValueExpr = t16.binaryExpression(
@@ -5577,7 +5665,7 @@ function getComponentArrayBuildMethodName(arrayPropName) {
5577
5665
  function getComponentArrayRefreshMethodName(arrayPropName) {
5578
5666
  return `__refresh${getArrayCapName2(arrayPropName)}Items`;
5579
5667
  }
5580
- function generateComponentArrayMethods(um, arrayPropName, imports, propNames, _classBody, storeArrayAccess, wholeParamName) {
5668
+ function generateComponentArrayMethods(um, arrayPropName, imports, propNames, _classBody, storeArrayAccess, wholeParamName, templateSetupContext) {
5581
5669
  const comp = isUnresolvedMapWithComponentChild(um, imports);
5582
5670
  if (!comp) return [];
5583
5671
  const itemTemplate = um.itemTemplate;
@@ -5600,7 +5688,7 @@ function generateComponentArrayMethods(um, arrayPropName, imports, propNames, _c
5600
5688
  /* @__PURE__ */ new Map(),
5601
5689
  void 0,
5602
5690
  void 0,
5603
- void 0,
5691
+ templateSetupContext,
5604
5692
  transformExpr,
5605
5693
  transformFrag
5606
5694
  );
@@ -5662,8 +5750,9 @@ function generateComponentArrayMethods(um, arrayPropName, imports, propNames, _c
5662
5750
  const itemPropsCall = t17.callExpression(t17.memberExpression(t17.thisExpression(), t17.identifier(itemPropsMethodName)), [
5663
5751
  t17.identifier("opt")
5664
5752
  ]);
5753
+ const itemPropsSetup = collectTemplateSetupStatements(finalPropsExpr, templateSetupContext);
5665
5754
  const itemPropsMethod = jsMethod7`${id10(itemPropsMethodName)}(opt) {}`;
5666
- itemPropsMethod.body.body.push(t17.returnStatement(finalPropsExpr));
5755
+ itemPropsMethod.body.body.push(...itemPropsSetup, t17.returnStatement(finalPropsExpr));
5667
5756
  const buildMethod = jsMethod7`${id10(buildMethodName)}() {}`;
5668
5757
  buildMethod.body.body.push(
5669
5758
  ...arrSetupStatements,
@@ -6114,6 +6203,18 @@ function applyStaticReactivity(ast, originalAST, className, sourceFile, imports,
6114
6203
  }
6115
6204
  }
6116
6205
  const propNames = getTemplatePropNames(classPath.node.body);
6206
+ const tmplBody = templateMethod?.body.body ?? [];
6207
+ let tmplReturnIdx = -1;
6208
+ for (let ri = tmplBody.length - 1; ri >= 0; ri--) {
6209
+ if (t18.isReturnStatement(tmplBody[ri])) {
6210
+ tmplReturnIdx = ri;
6211
+ break;
6212
+ }
6213
+ }
6214
+ const tmplSetupCtx = templateMethod ? {
6215
+ params: templateMethod.params,
6216
+ statements: tmplReturnIdx >= 0 ? tmplBody.slice(0, tmplReturnIdx) : []
6217
+ } : void 0;
6117
6218
  const methods = generateComponentArrayMethods(
6118
6219
  um,
6119
6220
  arrayPropName,
@@ -6121,7 +6222,8 @@ function applyStaticReactivity(ast, originalAST, className, sourceFile, imports,
6121
6222
  propNames,
6122
6223
  classPath.node.body,
6123
6224
  storeArrayAccess,
6124
- getTemplateParamIdentifier(classPath.node.body)
6225
+ getTemplateParamIdentifier(classPath.node.body),
6226
+ tmplSetupCtx
6125
6227
  );
6126
6228
  if (methods.length > 0 && templateMethod) {
6127
6229
  methods.forEach((method2) => classPath.node.body.body.push(method2));
@@ -6226,7 +6328,7 @@ function applyStaticReactivity(ast, originalAST, className, sourceFile, imports,
6226
6328
  classPath.node.body.body.push(method);
6227
6329
  applied = true;
6228
6330
  }
6229
- const createMethod = generateCreateItemMethod(syntheticBinding);
6331
+ const createMethod = generateCreateItemMethod(syntheticBinding, templatePropNames, templateWholeParam);
6230
6332
  if (createMethod) classPath.node.body.body.push(createMethod);
6231
6333
  if (handlerPropsInMap.length > 0 && um.computationExpr) {
6232
6334
  if (arrayPropName) {
@@ -6350,10 +6452,29 @@ function applyStaticReactivity(ast, originalAST, className, sourceFile, imports,
6350
6452
  const ownClassMethodNames = new Set(
6351
6453
  classPath.node.body.body.filter((m) => t18.isClassMethod(m) && t18.isIdentifier(m.key)).map((m) => m.key.name)
6352
6454
  );
6455
+ const componentGetterStoreDeps = /* @__PURE__ */ new Map();
6456
+ for (const member of classPath.node.body.body) {
6457
+ if (!t18.isClassMethod(member) || member.kind !== "get" || !t18.isIdentifier(member.key)) continue;
6458
+ const deps = [];
6459
+ const program9 = t18.program(member.body.body.map((s) => t18.cloneNode(s, true)));
6460
+ traverse10(program9, {
6461
+ noScope: true,
6462
+ MemberExpression(mePath) {
6463
+ if (!t18.isIdentifier(mePath.node.object)) return;
6464
+ const objName = mePath.node.object.name;
6465
+ const ref = stateRefs.get(objName);
6466
+ if (!ref || ref.kind !== "imported") return;
6467
+ if (!t18.isIdentifier(mePath.node.property)) return;
6468
+ deps.push({ storeVar: objName, pathParts: [mePath.node.property.name] });
6469
+ }
6470
+ });
6471
+ if (deps.length > 0) componentGetterStoreDeps.set(member.key.name, deps);
6472
+ }
6353
6473
  for (const [observeKey, propPath] of stateProps) {
6354
6474
  const { storeVar } = parseObserveKey(observeKey);
6355
6475
  if (hasOnPropChange && !storeVar && propPath[0] === "props") continue;
6356
- if (!storeVar && propPath.length === 1 && ownClassMethodNames.has(propPath[0])) continue;
6476
+ if (!storeVar && propPath.length === 1 && ownClassMethodNames.has(propPath[0]) && !componentGetterStoreDeps.has(propPath[0]))
6477
+ continue;
6357
6478
  const alreadyHandled = handledPaths.has(observeKey);
6358
6479
  const conditionalSlotIndices = conditionalSlotObserveIndices.get(observeKey) || [];
6359
6480
  const arrayHandled = analysis.arrayMaps.some(
@@ -6568,7 +6689,7 @@ function applyStaticReactivity(ast, originalAST, className, sourceFile, imports,
6568
6689
  replaceInlineMapWithRenderCall(classPath, arrayMap, renderMethodName);
6569
6690
  replaceMapInConditionalSlots(analysis.conditionalSlots || [], arrayMap, renderMethodName);
6570
6691
  }
6571
- const createMethod = generateCreateItemMethod(arrayMap);
6692
+ const createMethod = generateCreateItemMethod(arrayMap, templatePropNames, templateWholeParam);
6572
6693
  if (createMethod) {
6573
6694
  classPath.node.body.body.push(createMethod);
6574
6695
  }
@@ -6585,7 +6706,8 @@ function applyStaticReactivity(ast, originalAST, className, sourceFile, imports,
6585
6706
  classPath.node.body,
6586
6707
  analysis.conditionalSlots,
6587
6708
  templatePropNames2,
6588
- getTemplateParamIdentifier(classPath.node.body)
6709
+ getTemplateParamIdentifier(classPath.node.body),
6710
+ getTemplateSetupContext(classPath.node.body)
6589
6711
  );
6590
6712
  }
6591
6713
  if (analysis.arrayMaps.length > 0) {
@@ -6617,7 +6739,43 @@ function applyStaticReactivity(ast, originalAST, className, sourceFile, imports,
6617
6739
  const { parts, storeVar } = parseObserveKey(observeKey);
6618
6740
  if (!storeVar) {
6619
6741
  if (hasOnPropChange && parts[0] === "props") return;
6620
- if (parts.length === 1 && ownClassMethodNames.has(parts[0])) return;
6742
+ if (parts.length === 1 && ownClassMethodNames.has(parts[0])) {
6743
+ const compGetterDeps = componentGetterStoreDeps.get(parts[0]);
6744
+ if (compGetterDeps && compGetterDeps.length > 0) {
6745
+ const originalMethodName = getObserveMethodName(parts);
6746
+ const wrapperMethodName = `${originalMethodName}__via`;
6747
+ if (!classPath.node.body.body.some(
6748
+ (m) => t18.isClassMethod(m) && t18.isIdentifier(m.key) && m.key.name === wrapperMethodName
6749
+ )) {
6750
+ classPath.node.body.body.push(
6751
+ t18.classMethod(
6752
+ "method",
6753
+ t18.identifier(wrapperMethodName),
6754
+ [t18.identifier("_v"), t18.identifier("change")],
6755
+ t18.blockStatement([
6756
+ t18.expressionStatement(
6757
+ t18.callExpression(
6758
+ t18.memberExpression(t18.thisExpression(), t18.identifier(originalMethodName)),
6759
+ [
6760
+ t18.memberExpression(t18.thisExpression(), t18.identifier(parts[0])),
6761
+ t18.identifier("change")
6762
+ ]
6763
+ )
6764
+ )
6765
+ ])
6766
+ )
6767
+ );
6768
+ }
6769
+ for (const dep of compGetterDeps) {
6770
+ const depKey = buildObserveKey(dep.pathParts, dep.storeVar) + `__getter_${parts[0]}`;
6771
+ ensureStoreGroup(dep.storeVar).observeHandlers.set(depKey, {
6772
+ pathParts: dep.pathParts,
6773
+ methodName: wrapperMethodName
6774
+ });
6775
+ }
6776
+ }
6777
+ return;
6778
+ }
6621
6779
  localObserveHandlers.set(observeKey, { pathParts: parts, methodName: getObserveMethodName(parts) });
6622
6780
  return;
6623
6781
  }
@@ -6637,13 +6795,10 @@ function applyStaticReactivity(ast, originalAST, className, sourceFile, imports,
6637
6795
  [t18.identifier("_v"), t18.identifier("change")],
6638
6796
  t18.blockStatement([
6639
6797
  t18.expressionStatement(
6640
- t18.callExpression(
6641
- t18.memberExpression(t18.thisExpression(), t18.identifier(originalMethodName)),
6642
- [
6643
- t18.memberExpression(t18.identifier(storeVar), t18.identifier(parts[0])),
6644
- t18.identifier("change")
6645
- ]
6646
- )
6798
+ t18.callExpression(t18.memberExpression(t18.thisExpression(), t18.identifier(originalMethodName)), [
6799
+ t18.memberExpression(t18.identifier(storeVar), t18.identifier(parts[0])),
6800
+ t18.identifier("change")
6801
+ ])
6647
6802
  )
6648
6803
  ])
6649
6804
  )
@@ -7288,7 +7443,7 @@ function mergeKeyGuards(stmts) {
7288
7443
  }
7289
7444
  return result;
7290
7445
  }
7291
- function generateConditionalPatchMethods(classBody2, slots, templatePropNames, wholeParamName) {
7446
+ function generateConditionalPatchMethods(classBody2, slots, templatePropNames, wholeParamName, templateSetupContext) {
7292
7447
  const seenVarNames = /* @__PURE__ */ new Set();
7293
7448
  const allSetupStatements = [];
7294
7449
  for (const slot of slots) {
@@ -7344,10 +7499,13 @@ function generateConditionalPatchMethods(classBody2, slots, templatePropNames, w
7344
7499
  const buildHtmlFn = (htmlExpr) => {
7345
7500
  if (!htmlExpr) return t18.nullLiteral();
7346
7501
  const clonedHtmlExpr = rpExpr(t18.cloneNode(htmlExpr, true));
7347
- const htmlSetup = pruneDeadParamDestructuring(
7502
+ const fromTemplate = templateSetupContext != null ? collectTemplateSetupStatements(clonedHtmlExpr, templateSetupContext) : [];
7503
+ const fromSlotsOnly = pruneDeadParamDestructuring(
7348
7504
  rpStmts(allSetupStatements.map((s) => t18.cloneNode(s, true))),
7349
7505
  [clonedHtmlExpr]
7350
7506
  );
7507
+ const htmlSetupRaw = fromTemplate.length > 0 ? fromTemplate : fromSlotsOnly;
7508
+ const htmlSetup = rpStmts(htmlSetupRaw.map((s) => t18.cloneNode(s, true)));
7351
7509
  if (htmlSetup.length > 0) {
7352
7510
  return t18.arrowFunctionExpression([], t18.blockStatement([...htmlSetup, t18.returnStatement(clonedHtmlExpr)]));
7353
7511
  }
@@ -7389,6 +7547,20 @@ function getTemplateParamIdentifier(classBody2) {
7389
7547
  if (t18.isTSParameterProperty(p) && t18.isIdentifier(p.parameter)) return p.parameter.name;
7390
7548
  return void 0;
7391
7549
  }
7550
+ function getTemplateSetupContext(classBody2) {
7551
+ const templateMethod = classBody2.body.find(
7552
+ (m) => t18.isClassMethod(m) && t18.isIdentifier(m.key) && m.key.name === "template"
7553
+ );
7554
+ if (!templateMethod?.body || !t18.isBlockStatement(templateMethod.body)) return void 0;
7555
+ const retIdx = templateMethod.body.body.findIndex((s) => t18.isReturnStatement(s) && s.argument != null);
7556
+ if (retIdx < 0) return void 0;
7557
+ return {
7558
+ params: templateMethod.params.filter(
7559
+ (param) => !t18.isTSParameterProperty(param)
7560
+ ),
7561
+ statements: templateMethod.body.body.slice(0, retIdx)
7562
+ };
7563
+ }
7392
7564
  function collectPropNamesFromItemTemplate(itemTemplate, templatePropNames) {
7393
7565
  if (!itemTemplate) return [];
7394
7566
  const used = /* @__PURE__ */ new Set();
@@ -7444,7 +7616,7 @@ function injectMapItemAttrsIntoTemplate(templateMethod, mapInfos) {
7444
7616
  const rootTL = findRootTemplateLiteral(t18.isBlockStatement(fn.body) ? fn.body : fn.body);
7445
7617
  if (!rootTL) return;
7446
7618
  const first = rootTL.quasis[0].value.raw;
7447
- const tagMatch = first.match(/^(<\w+)/);
7619
+ const tagMatch = first.match(/^(<[\w-]+)/);
7448
7620
  if (!tagMatch) return;
7449
7621
  const tagPart = tagMatch[1];
7450
7622
  const remainder = first.substring(tagPart.length);
@@ -7884,7 +8056,7 @@ function analyzeStoreGetters(sourceFile, storeImports) {
7884
8056
  import { createRequire as createRequire13 } from "module";
7885
8057
  var require14 = createRequire13(import.meta.url);
7886
8058
  var traverse12 = require14("@babel/traverse").default;
7887
- function transformComponentFile(ast, imports, storeImports, className, sourceFile, originalAST, compImportsUsedAsTags) {
8059
+ function transformComponentFile(ast, imports, storeImports, className, sourceFile, originalAST, compImportsUsedAsTags, knownComponentImports = /* @__PURE__ */ new Set()) {
7888
8060
  let transformed = false;
7889
8061
  const stateRefs = collectStateReferences(originalAST, storeImports);
7890
8062
  const storeGetterDeps = analyzeStoreGetters(sourceFile, storeImports);
@@ -7912,12 +8084,10 @@ function transformComponentFile(ast, imports, storeImports, className, sourceFil
7912
8084
  const body = path.node.body.body;
7913
8085
  const retStmt = body.find((s) => t20.isReturnStatement(s) && s.argument !== null);
7914
8086
  if (!retStmt?.argument) return;
8087
+ const allComponentTags = new Set(knownComponentImports);
7915
8088
  const instanceTags = [];
7916
- const allComponentTags = /* @__PURE__ */ new Set();
7917
- if (t20.isJSXElement(retStmt.argument))
7918
- collectComponentTags(retStmt.argument, imports, instanceTags, allComponentTags);
7919
- else if (t20.isJSXFragment(retStmt.argument))
7920
- collectComponentTags(retStmt.argument, imports, instanceTags, allComponentTags);
8089
+ if (t20.isJSXElement(retStmt.argument)) collectComponentTags(retStmt.argument, imports, instanceTags);
8090
+ else if (t20.isJSXFragment(retStmt.argument)) collectComponentTags(retStmt.argument, imports, instanceTags);
7921
8091
  const componentInstances = /* @__PURE__ */ new Map();
7922
8092
  const tagCounts = /* @__PURE__ */ new Map();
7923
8093
  instanceTags.forEach((tag, dfsIndex) => {
@@ -8027,10 +8197,11 @@ function transformComponentFile(ast, imports, storeImports, className, sourceFil
8027
8197
  transformed = appendCompiledEventMethods(earlyClassPath.node.body, earlyReturnCtx.eventHandlers, []) || transformed;
8028
8198
  }
8029
8199
  }
8030
- for (let i = 0; i < conditionalSlotInfos.length; i++) {
8031
- if (analysis.conditionalSlots[i]) {
8032
- analysis.conditionalSlots[i].truthyHtmlExpr = conditionalSlotInfos[i].truthyHtmlExpr;
8033
- analysis.conditionalSlots[i].falsyHtmlExpr = conditionalSlotInfos[i].falsyHtmlExpr;
8200
+ for (const info of conditionalSlotInfos) {
8201
+ const slot = analysis.conditionalSlots.find((s) => s.slotId === info.slotId);
8202
+ if (slot) {
8203
+ slot.truthyHtmlExpr = info.truthyHtmlExpr;
8204
+ slot.falsyHtmlExpr = info.falsyHtmlExpr;
8034
8205
  }
8035
8206
  }
8036
8207
  if (stateChildSlots.length > 0) {
@@ -8063,10 +8234,46 @@ function transformComponentFile(ast, imports, storeImports, className, sourceFil
8063
8234
  }
8064
8235
  }
8065
8236
  }
8237
+ const preReturnStmts = returnIndex >= 0 ? body.slice(0, returnIndex) : [];
8238
+ const earlyReturnGuards = preReturnStmts.filter(
8239
+ (s) => t20.isIfStatement(s) && (t20.isReturnStatement(s.consequent) || t20.isBlockStatement(s.consequent) && s.consequent.body.some((b) => t20.isReturnStatement(b)), true)
8240
+ );
8241
+ let guardSetupStatements = [];
8242
+ if (earlyReturnGuards.length > 0) {
8243
+ const guardIdents = /* @__PURE__ */ new Set();
8244
+ for (const guard of earlyReturnGuards) {
8245
+ const walk = (node) => {
8246
+ if (t20.isIdentifier(node)) guardIdents.add(node.name);
8247
+ for (const key of t20.VISITOR_KEYS[node.type] || []) {
8248
+ const child = node[key];
8249
+ if (Array.isArray(child)) child.forEach((c) => c?.type && walk(c));
8250
+ else if (child?.type) walk(child);
8251
+ }
8252
+ };
8253
+ walk(guard.test);
8254
+ }
8255
+ const declBindsGuardIdent = (pattern) => {
8256
+ if (t20.isIdentifier(pattern)) return guardIdents.has(pattern.name);
8257
+ if (t20.isObjectPattern(pattern))
8258
+ return pattern.properties.some(
8259
+ (p) => t20.isRestElement(p) ? declBindsGuardIdent(p.argument) : declBindsGuardIdent(p.value)
8260
+ );
8261
+ if (t20.isArrayPattern(pattern)) return pattern.elements.some((e) => e && declBindsGuardIdent(e));
8262
+ return false;
8263
+ };
8264
+ guardSetupStatements = preReturnStmts.filter((s) => {
8265
+ if (!t20.isVariableDeclaration(s)) return false;
8266
+ return s.declarations.some((d) => declBindsGuardIdent(d.id));
8267
+ });
8268
+ }
8066
8269
  const allChildren = Array.from(componentInstances.values()).flat();
8067
8270
  for (const child of allChildren) {
8068
8271
  const mappings = directMappingsMap.get(child.instanceVar);
8069
8272
  if (mappings) child.directMappings = mappings;
8273
+ if (earlyReturnGuards.length > 0) {
8274
+ child.earlyReturnGuards = earlyReturnGuards;
8275
+ child.guardSetupStatements = guardSetupStatements;
8276
+ }
8070
8277
  }
8071
8278
  injectChildComponents(ast, componentInstances, directForwardingSet);
8072
8279
  compiledChildren.push(...allChildren);
@@ -8103,6 +8310,7 @@ function transformComponentFile(ast, imports, storeImports, className, sourceFil
8103
8310
  eventIdCounter,
8104
8311
  preTransformAnalysis
8105
8312
  ) || transformed;
8313
+ transformRemainingJSX(ast, imports);
8106
8314
  return transformed;
8107
8315
  }
8108
8316
  function transformNonComponentJSX(ast, imports) {
@@ -8584,6 +8792,7 @@ function isComponentImportSource(source) {
8584
8792
  }
8585
8793
  function geaPlugin() {
8586
8794
  const storeModules = /* @__PURE__ */ new Set();
8795
+ const componentModules = /* @__PURE__ */ new Set();
8587
8796
  const resolveImportPath3 = (importer, source) => {
8588
8797
  const base = resolve3(dirname3(importer), source);
8589
8798
  const candidates = [
@@ -8620,6 +8829,20 @@ function geaPlugin() {
8620
8829
  return false;
8621
8830
  }
8622
8831
  };
8832
+ const isComponentModule = (filePath) => {
8833
+ if (componentModules.has(filePath)) return true;
8834
+ if (!existsSync3(filePath)) return false;
8835
+ try {
8836
+ const source = readFileSync3(filePath, "utf8");
8837
+ if (source.includes("extends Component")) {
8838
+ componentModules.add(filePath);
8839
+ return true;
8840
+ }
8841
+ return false;
8842
+ } catch {
8843
+ return false;
8844
+ }
8845
+ };
8623
8846
  const envPath = existsSync3(resolve3(pluginDir, "gea-env.d.ts")) ? resolve3(pluginDir, "gea-env.d.ts") : resolve3(pluginDir, "..", "gea-env.d.ts");
8624
8847
  return {
8625
8848
  name: "gea-plugin",
@@ -8679,6 +8902,9 @@ function geaPlugin() {
8679
8902
  imports = freshParsed.imports;
8680
8903
  }
8681
8904
  }
8905
+ if (componentClassNames.length > 0) {
8906
+ componentModules.add(cleanId);
8907
+ }
8682
8908
  let transformed = false;
8683
8909
  const componentImportSet = /* @__PURE__ */ new Set();
8684
8910
  const componentImportsUsedAsTags = /* @__PURE__ */ new Set();
@@ -8689,6 +8915,7 @@ function geaPlugin() {
8689
8915
  });
8690
8916
  const componentImports = Array.from(componentImportSet);
8691
8917
  const storeImports = /* @__PURE__ */ new Map();
8918
+ const knownComponentImports = /* @__PURE__ */ new Set();
8692
8919
  const namedImportSources = /* @__PURE__ */ new Map();
8693
8920
  traverse14(ast, {
8694
8921
  ExportDefaultDeclaration() {
@@ -8698,8 +8925,10 @@ function geaPlugin() {
8698
8925
  const source = path.node.source.value;
8699
8926
  if (!isComponentImportSource(source)) return;
8700
8927
  const resolvedImport = source.startsWith(".") ? resolveImportPath3(cleanId, source) : null;
8928
+ const isComp = resolvedImport ? isComponentModule(resolvedImport) : false;
8701
8929
  path.node.specifiers.forEach(
8702
8930
  (spec) => {
8931
+ if (isComp) knownComponentImports.add(spec.local.name);
8703
8932
  if (spec.type === "ImportDefaultSpecifier") {
8704
8933
  if (resolvedImport && !isStoreModule(resolvedImport)) return;
8705
8934
  storeImports.set(spec.local.name, source);
@@ -8733,7 +8962,8 @@ function geaPlugin() {
8733
8962
  cn,
8734
8963
  cleanId,
8735
8964
  originalAST,
8736
- componentImportsUsedAsTags
8965
+ componentImportsUsedAsTags,
8966
+ knownComponentImports
8737
8967
  );
8738
8968
  if (result) transformed = true;
8739
8969
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geajs/vite-plugin",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Vite plugin for Gea framework - JSX/TSX transform, reactivity, HMR",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -45,6 +45,7 @@
45
45
  "test:coverage": "c8 --reporter=text --reporter=lcov tsx --test tests/**/*.test.ts"
46
46
  },
47
47
  "dependencies": {
48
+ "@acemir/cssom": "^0.9.31",
48
49
  "@babel/generator": "^7.23.0",
49
50
  "@babel/parser": "^7.23.0",
50
51
  "@babel/traverse": "^7.23.0",
@@ -54,6 +55,7 @@
54
55
  "devDependencies": {
55
56
  "@types/node": "^25.4.0",
56
57
  "c8": "^11.0.0",
58
+ "cssstyle": "^6.2.0",
57
59
  "jsdom": "^28.1.0",
58
60
  "tsup": "^8.5.1",
59
61
  "tsx": "^4.21.0",