@immense/vue-pom-generator 1.0.64 → 1.0.66

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/RELEASE_NOTES.md CHANGED
@@ -1,48 +1,27 @@
1
- Based on the commit message and changes, here are the release notes:
1
+ ## Highlights
2
2
 
3
- ---
4
-
5
- # v1.0.64
6
-
7
- ## Highlights
8
-
9
- - **TypeScript template expression support** – Compiler now parses TypeScript annotations in Vue
10
- template expressions (e.g., `@row-click="(row: RowType) => ..."`), fixing crashes in Nuxt 4 +
11
- TS codebases
12
- - **Graceful submit-button fallback** – Submit buttons with dynamic labels now respect
13
- `missingSemanticNameBehavior: "ignore"` and generate `SubmitButton` / `clickSubmit()` methods
14
- instead of throwing
15
- - **Improved TypeScript compatibility** – All three plugin compilation paths (dev-plugin,
16
- build-plugin, vue-plugin) now support TypeScript expression syntax
3
+ - Fixed component child POM attachment bug
4
+ - Added comprehensive test coverage for class generation
17
5
 
18
6
  ## Changes
19
7
 
20
- ### Parser Enhancements
21
- - Added `expressionPlugins: ["typescript"]` to all `compilerDom.compile()` call sites
22
- (dev-plugin, build-plugin, vue-plugin)
23
- - Vue plugin merges expression plugins with user-supplied `userCompilerOptions` to preserve
24
- custom configuration
8
+ **Bug Fixes**
9
+ - Corrected logic for attaching child page object models to component classes
10
+ - Improved reliability of generated POM hierarchies
11
+
12
+ **Testing**
13
+ - Added 53 lines of test coverage for class generation scenarios
25
14
 
26
- ### Submit Button Handling
27
- - Submit buttons with dynamic inner text (e.g., ternary expressions like `{{ isNew ? 'Create' :
28
- 'Save' }}`) now honor `missingSemanticNameBehavior: "ignore"` option
29
- - Falls back to literal `"submit"` identifier when semantic name cannot be derived, generating
30
- `SubmitButton` / `clickSubmit()` POM surface
31
- - Default behavior (throwing on missing semantic name) remains unchanged
15
+ ## Breaking Changes
32
16
 
33
- ### Testing
34
- - Added 3 regression tests for TypeScript expression parsing and submit-button fallback behavior
35
- - Test suite: 163 → 166 tests passing
36
- - All validation passes: typecheck, eslint, build
17
+ None
37
18
 
38
19
  ## Pull Requests Included
39
20
 
40
- - fix: parse TypeScript template expressions + allow submit-button fallback
41
- [#20](https://github.com/immense/vue-pom-generator/pull/20)
21
+ Unable to determine specific PR for commit `e1f328c` from available metadata.
42
22
 
43
23
  ## Testing
44
24
 
45
- Validated on Nuxt 4 + Vue 3 + TypeScript codebase. Three new regression tests added covering
46
- TypeScript expression parsing and submit-button fallback scenarios. Full test suite passes (166
47
- tests).
25
+ Added new test cases in `tests/class-generation-coverage.test.ts` covering component child POM
26
+ attachment scenarios.
48
27
 
@@ -1710,9 +1710,9 @@ function prepareViewObjectModelClass(
1710
1710
  members.push(...getComponentInstances(componentRefsForInstances, componentHierarchyMap, attachmentsForThisClass, widgetInstances));
1711
1711
  members.push(getConstructor(componentRefsForInstances, componentHierarchyMap, attachmentsForThisClass, widgetInstances, { testIdAttribute }));
1712
1712
  }
1713
- if (!isView && attachmentsForThisClass.length > 0) {
1714
- members.push(...getComponentInstances(new Set(), componentHierarchyMap, attachmentsForThisClass));
1715
- members.push(getConstructor(new Set(), componentHierarchyMap, attachmentsForThisClass, [], { testIdAttribute }));
1713
+ if (!isView && (componentRefsForInstances.size > 0 || attachmentsForThisClass.length > 0)) {
1714
+ members.push(...getComponentInstances(componentRefsForInstances, componentHierarchyMap, attachmentsForThisClass));
1715
+ members.push(getConstructor(componentRefsForInstances, componentHierarchyMap, attachmentsForThisClass, [], { testIdAttribute }));
1716
1716
  }
1717
1717
 
1718
1718
  members.push(
@@ -1771,7 +1771,10 @@ function generateViewObjectModelContent(
1771
1771
  const basePageImport = path.relative(fromAbs, toAbs).replace(/\\/g, "/");
1772
1772
  const basePageImportNoExt = stripExtension(basePageImport).replace(/\\/g, "/");
1773
1773
  const basePageImportSpecifier = basePageImportNoExt.startsWith(".") ? basePageImportNoExt : `./${basePageImportNoExt}`;
1774
- const needsPlaywrightPageImport = prepared.isView || prepared.attachmentsForThisClass.length > 0;
1774
+ const needsPlaywrightPageImport = prepared.isView
1775
+ || prepared.attachmentsForThisClass.length > 0
1776
+ || prepared.componentRefsForInstances.size > 0
1777
+ || prepared.widgetInstances.length > 0;
1775
1778
  const customPomImportSpecifiersByClass = options.customPomImportSpecifiersByClass ?? {};
1776
1779
 
1777
1780
  const customImports = Array.from(
package/dist/index.cjs CHANGED
@@ -1895,6 +1895,12 @@ function nodeHandlerAttributeInfo(node) {
1895
1895
  const n = node2;
1896
1896
  return typeof n.computed === "boolean" && typeof n.key === "object" && n.key !== null && typeof n.value === "object" && n.value !== null;
1897
1897
  };
1898
+ const isLogicalExpressionNode = (node2) => {
1899
+ if (!isNodeType2(node2, "LogicalExpression"))
1900
+ return false;
1901
+ const n = node2;
1902
+ return typeof n.operator === "string" && typeof n.left === "object" && n.left !== null && typeof n.right === "object" && n.right !== null;
1903
+ };
1898
1904
  const getLastIdentifierFromMemberChain = (node2) => {
1899
1905
  if (!node2)
1900
1906
  return null;
@@ -2065,48 +2071,66 @@ function nodeHandlerAttributeInfo(node) {
2065
2071
  const semanticNameHint2 = suffix ? `${toPascalCase(name)}${suffix}` : toPascalCase(name);
2066
2072
  return semanticNameHint2;
2067
2073
  };
2074
+ const unwrapSemanticHelperCall = (candidateExpr) => {
2075
+ if (!isCallExpressionNode(candidateExpr)) {
2076
+ return null;
2077
+ }
2078
+ const calleeName = getLastIdentifierFromMemberChain(candidateExpr.callee);
2079
+ if (calleeName !== "_unref" && calleeName !== "unref" && calleeName !== "_withModifiers" && calleeName !== "withModifiers") {
2080
+ return null;
2081
+ }
2082
+ const firstArg = candidateExpr.arguments[0];
2083
+ return typeof firstArg === "object" && firstArg !== null ? firstArg : null;
2084
+ };
2068
2085
  const resolveSemanticName = (candidateExpr) => {
2069
2086
  if (!candidateExpr) {
2070
2087
  return null;
2071
2088
  }
2089
+ const unwrappedHelperCandidate = unwrapSemanticHelperCall(candidateExpr);
2090
+ if (unwrappedHelperCandidate) {
2091
+ return resolveSemanticName(unwrappedHelperCandidate);
2092
+ }
2072
2093
  const direct = getLastIdentifierFromMemberChain(candidateExpr);
2073
2094
  if (direct) {
2074
2095
  return toPascalCase(direct);
2075
2096
  }
2097
+ const directCall = tryFromCallExpression(candidateExpr);
2098
+ if (directCall) {
2099
+ return directCall;
2100
+ }
2101
+ if (isAssignmentExpressionNode(candidateExpr)) {
2102
+ const lhs = getAssignmentTargetName(candidateExpr.left);
2103
+ if (lhs) {
2104
+ const rhs = stableWordFromValue(candidateExpr.right);
2105
+ return `Set${toPascalCase(lhs)}${rhs ?? ""}`;
2106
+ }
2107
+ }
2108
+ if (isLogicalExpressionNode(candidateExpr) && candidateExpr.operator === "&&") {
2109
+ return resolveSemanticName(candidateExpr.right);
2110
+ }
2076
2111
  if (isArrowFunctionExpressionNode(candidateExpr)) {
2077
2112
  const body = candidateExpr.body;
2078
- const directCall = tryFromCallExpression(body);
2079
- if (directCall) {
2080
- return directCall;
2081
- }
2082
- if (isAssignmentExpressionNode(body)) {
2083
- const lhs = getAssignmentTargetName(body.left);
2084
- if (lhs) {
2085
- const rhs = stableWordFromValue(body.right);
2086
- return `Set${toPascalCase(lhs)}${rhs ?? ""}`;
2087
- }
2088
- }
2089
2113
  if (isBlockStatementNode(body)) {
2090
2114
  const stmts = body.body ?? [];
2091
2115
  if (stmts.length > 0) {
2092
2116
  const firstStmt = stmts[0];
2093
2117
  if (isReturnStatementNode(firstStmt)) {
2094
- const fromReturn = tryFromCallExpression(firstStmt.argument ?? null);
2118
+ const fromReturn = resolveSemanticName(firstStmt.argument ?? null);
2095
2119
  if (fromReturn) {
2096
2120
  return fromReturn;
2097
2121
  }
2098
2122
  }
2099
2123
  if (isExpressionStatementNode(firstStmt)) {
2100
- const fromExpr = tryFromCallExpression(firstStmt.expression ?? null);
2124
+ const fromExpr = resolveSemanticName(firstStmt.expression ?? null);
2101
2125
  if (fromExpr) {
2102
2126
  return fromExpr;
2103
2127
  }
2104
2128
  }
2105
2129
  }
2106
2130
  }
2107
- const bodyName = getLastIdentifierFromMemberChain(body);
2131
+ const bodyName = resolveSemanticName(body);
2108
2132
  if (bodyName) {
2109
- return toPascalCase(bodyName);
2133
+ return bodyName;
2110
2134
  }
2111
2135
  }
2112
2136
  return null;
@@ -5577,9 +5601,9 @@ function prepareViewObjectModelClass(componentName, dependencies, componentHiera
5577
5601
  members.push(...getComponentInstances(componentRefsForInstances, componentHierarchyMap, attachmentsForThisClass, widgetInstances));
5578
5602
  members.push(getConstructor(componentRefsForInstances, componentHierarchyMap, attachmentsForThisClass, widgetInstances, { testIdAttribute }));
5579
5603
  }
5580
- if (!isView && attachmentsForThisClass.length > 0) {
5581
- members.push(...getComponentInstances(/* @__PURE__ */ new Set(), componentHierarchyMap, attachmentsForThisClass));
5582
- members.push(getConstructor(/* @__PURE__ */ new Set(), componentHierarchyMap, attachmentsForThisClass, [], { testIdAttribute }));
5604
+ if (!isView && (componentRefsForInstances.size > 0 || attachmentsForThisClass.length > 0)) {
5605
+ members.push(...getComponentInstances(componentRefsForInstances, componentHierarchyMap, attachmentsForThisClass));
5606
+ members.push(getConstructor(componentRefsForInstances, componentHierarchyMap, attachmentsForThisClass, [], { testIdAttribute }));
5583
5607
  }
5584
5608
  members.push(
5585
5609
  ...getAttachmentPassthroughMethods(componentName, dependencies, attachmentsForThisClass, reservedAttachmentPassthroughNames)
@@ -5623,7 +5647,7 @@ function generateViewObjectModelContent(componentName, dependencies, componentHi
5623
5647
  const basePageImport = path.relative(fromAbs, toAbs).replace(/\\/g, "/");
5624
5648
  const basePageImportNoExt = stripExtension(basePageImport).replace(/\\/g, "/");
5625
5649
  const basePageImportSpecifier = basePageImportNoExt.startsWith(".") ? basePageImportNoExt : `./${basePageImportNoExt}`;
5626
- const needsPlaywrightPageImport = prepared.isView || prepared.attachmentsForThisClass.length > 0;
5650
+ const needsPlaywrightPageImport = prepared.isView || prepared.attachmentsForThisClass.length > 0 || prepared.componentRefsForInstances.size > 0 || prepared.widgetInstances.length > 0;
5627
5651
  const customPomImportSpecifiersByClass = options.customPomImportSpecifiersByClass ?? {};
5628
5652
  const customImports = Array.from(
5629
5653
  /* @__PURE__ */ new Set([