@immense/vue-pom-generator 1.0.26 → 1.0.28

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,19 +1,27 @@
1
- ## Highlights
1
+ # v1.0.28
2
2
 
3
- - Fixed issue where radio options were incorrectly inferred as wrapper elements
4
- - Added test coverage for radio option inference logic
5
- - Improved PR workflow with automated release-notes preview comments
3
+ ## Highlights
4
+
5
+ - Fixed test ID generation to preserve simple member-expression patterns (e.g.,
6
+ `this.someProperty`)
7
+ - Added automated PR release notes preview comments via GitHub Actions workflow
8
+ - Enhanced test coverage for utility functions
6
9
 
7
10
  ## Changes
8
11
 
9
- **Bug Fixes**
10
- - Avoid inferring radio options as wrappers ([5f6d7bf])
12
+ ### Bug Fixes
13
+ - Preserve simple member-expression test IDs in transformed code
11
14
 
12
- **Testing**
13
- - Added test cases for utils coverage
15
+ ### CI/CD Improvements
16
+ - Added dual-strategy release notes generation via PR comments
17
+ - Copilot SDK-based workflow with comment upsert
18
+ - Copilot agentic workflow via gh-aw
19
+ - Release notes preview now posted automatically on PRs
14
20
 
15
- **Developer Experience**
16
- - Added PR release-notes preview comments (#1)
21
+ ### Testing
22
+ - Added 24+ test cases in `transform.test.ts`
23
+ - Added 48+ test cases in `utils-coverage.test.ts` for utility function coverage
24
+ - Enhanced validation of member-expression handling
17
25
 
18
26
  ## Breaking Changes
19
27
 
@@ -21,11 +29,11 @@
21
29
 
22
30
  ## Pull Requests Included
23
31
 
24
- - #1 [Add PR release-notes preview
25
- comments](https://github.com/immense/vue-pom-generator/pull/1) by @dkattan
32
+ - [#1](https://github.com/immense/vue-pom-generator/pull/1) Add PR release-notes preview
33
+ comments (@dkattan)
26
34
 
27
35
  ## Testing
28
36
 
29
- Added 11 lines of test coverage in `tests/utils-coverage.test.ts` to verify the radio options
30
- inference fix.
37
+ Comprehensive test coverage added for the member-expression fix with 72+ new test cases across
38
+ transform and utility modules.
31
39
 
package/dist/index.cjs CHANGED
@@ -1429,6 +1429,25 @@ function extractMemberPropertyName(member) {
1429
1429
  }
1430
1430
  return "";
1431
1431
  }
1432
+ function isCompilerGeneratedReferenceRoot(name) {
1433
+ return name.startsWith("_") || name.startsWith("$");
1434
+ }
1435
+ function tryGetPreservableDynamicReferenceExpression(node) {
1436
+ if (!node || typeof node !== "object") {
1437
+ return null;
1438
+ }
1439
+ if (types.isIdentifier(node)) {
1440
+ return isCompilerGeneratedReferenceRoot(node.name) ? null : node.name;
1441
+ }
1442
+ if (!types.isMemberExpression(node) || node.computed) {
1443
+ return null;
1444
+ }
1445
+ const objectExpression = tryGetPreservableDynamicReferenceExpression(node.object);
1446
+ if (!objectExpression || !types.isIdentifier(node.property)) {
1447
+ return null;
1448
+ }
1449
+ return `${objectExpression}.${node.property.name}`;
1450
+ }
1432
1451
  function normalizeHandlerName(name) {
1433
1452
  if (!name) {
1434
1453
  return "";
@@ -1531,6 +1550,17 @@ function tryGetExistingElementDataTestId(node, attributeName = "data-testid") {
1531
1550
  }
1532
1551
  return { value, isDynamic: false, isStaticLiteral: true };
1533
1552
  }
1553
+ const preservableReference = tryGetPreservableDynamicReferenceExpression(ast);
1554
+ if (preservableReference) {
1555
+ return {
1556
+ value: preservableReference,
1557
+ isDynamic: true,
1558
+ isStaticLiteral: false,
1559
+ template: `\${${preservableReference}}`,
1560
+ templateExpressionCount: 1,
1561
+ rawExpression: preservableReference
1562
+ };
1563
+ }
1534
1564
  const raw = (simpleExp.content ?? "").trim();
1535
1565
  if (!raw) {
1536
1566
  return null;
@@ -1558,6 +1588,17 @@ function tryGetExistingElementDataTestId(node, attributeName = "data-testid") {
1558
1588
  const sl = ast2;
1559
1589
  return { value: sl.value ?? "", isDynamic: false, isStaticLiteral: true };
1560
1590
  }
1591
+ const preservableReference2 = tryGetPreservableDynamicReferenceExpression(ast2);
1592
+ if (preservableReference2) {
1593
+ return {
1594
+ value: preservableReference2,
1595
+ isDynamic: true,
1596
+ isStaticLiteral: false,
1597
+ template: `\${${preservableReference2}}`,
1598
+ templateExpressionCount: 1,
1599
+ rawExpression: preservableReference2
1600
+ };
1601
+ }
1561
1602
  } catch {
1562
1603
  }
1563
1604
  return { value: raw, isDynamic: true, isStaticLiteral: false, rawExpression: raw };
@@ -1863,9 +1904,6 @@ Fix: either (1) include ${args.bestKeyPlaceholder} in your :${attrLabel} templat
1863
1904
  })();
1864
1905
  const tryMergeWithExistingPrimary = (candidateActionName) => {
1865
1906
  const mergeKey = (args.pomMergeKey ?? "").trim();
1866
- if (!mergeKey) {
1867
- return false;
1868
- }
1869
1907
  if (isKeyed) {
1870
1908
  return false;
1871
1909
  }
@@ -1874,7 +1912,15 @@ Fix: either (1) include ${args.bestKeyPlaceholder} in your :${attrLabel} templat
1874
1912
  if (!existingEntry || !existingPom) {
1875
1913
  return false;
1876
1914
  }
1877
- if ((existingPom.mergeKey ?? "").trim() !== mergeKey) {
1915
+ const existingSelectors = [
1916
+ existingPom.formattedDataTestId,
1917
+ ...existingPom.alternateFormattedDataTestIds ?? []
1918
+ ];
1919
+ const sharesSelectorIdentity = existingSelectors.includes(formattedDataTestIdForPom);
1920
+ if (!mergeKey && !sharesSelectorIdentity) {
1921
+ return false;
1922
+ }
1923
+ if (mergeKey && (existingPom.mergeKey ?? "").trim() !== mergeKey && !sharesSelectorIdentity) {
1878
1924
  return false;
1879
1925
  }
1880
1926
  if (existingPom.nativeRole !== normalizedRole) {
@@ -4840,8 +4886,46 @@ function createTestIdTransform(componentName, componentHierarchyMap, nativeWrapp
4840
4886
  const normalizedViewsDirAbs = path.normalize(safeRealpath(path.resolve(viewsDirAbs)));
4841
4887
  const generatedMethodContentByComponent = /* @__PURE__ */ new Map();
4842
4888
  const lastConditionalHintByParent = /* @__PURE__ */ new WeakMap();
4889
+ const lastConditionalMergeGroupByParent = /* @__PURE__ */ new WeakMap();
4843
4890
  const conditionalHintByElement = /* @__PURE__ */ new WeakMap();
4844
4891
  const conditionalHintByIfBranch = /* @__PURE__ */ new WeakMap();
4892
+ const conditionalMergeGroupByElement = /* @__PURE__ */ new WeakMap();
4893
+ const conditionalMergeGroupByElementLoc = /* @__PURE__ */ new Map();
4894
+ const conditionalMergeGroupByIfBranch = /* @__PURE__ */ new WeakMap();
4895
+ let conditionalMergeGroupCounter = 0;
4896
+ const getElementLocationKey = (element) => {
4897
+ const startOffset = element.loc?.start.offset;
4898
+ const endOffset = element.loc?.end.offset;
4899
+ if (typeof startOffset !== "number" || typeof endOffset !== "number") {
4900
+ return null;
4901
+ }
4902
+ return `${element.tag}:${startOffset}:${endOffset}`;
4903
+ };
4904
+ const markConditionalMergeGroup = (nodes, mergeGroupKey) => {
4905
+ for (const child of nodes) {
4906
+ if (child.type === compilerCore.NodeTypes.ELEMENT) {
4907
+ const element = child;
4908
+ conditionalMergeGroupByElement.set(element, mergeGroupKey);
4909
+ const elementLocationKey = getElementLocationKey(element);
4910
+ if (elementLocationKey) {
4911
+ conditionalMergeGroupByElementLoc.set(elementLocationKey, mergeGroupKey);
4912
+ }
4913
+ markConditionalMergeGroup(element.children, mergeGroupKey);
4914
+ continue;
4915
+ }
4916
+ if (child.type === compilerCore.NodeTypes.IF) {
4917
+ const ifNode = child;
4918
+ for (const branch of ifNode.branches ?? []) {
4919
+ markConditionalMergeGroup(branch.children, mergeGroupKey);
4920
+ }
4921
+ continue;
4922
+ }
4923
+ if (child.type === compilerCore.NodeTypes.IF_BRANCH || child.type === compilerCore.NodeTypes.FOR) {
4924
+ const branchLike = child;
4925
+ markConditionalMergeGroup(branchLike.children ?? [], mergeGroupKey);
4926
+ }
4927
+ }
4928
+ };
4845
4929
  return (node, context) => {
4846
4930
  if (excludedComponents.includes(componentName)) {
4847
4931
  return;
@@ -4849,8 +4933,15 @@ function createTestIdTransform(componentName, componentHierarchyMap, nativeWrapp
4849
4933
  if (node.type === compilerCore.NodeTypes.IF) {
4850
4934
  const ifNode = node;
4851
4935
  const branches = ifNode.branches ?? [];
4936
+ const mergeGroupKey = `if-group:${++conditionalMergeGroupCounter}`;
4937
+ const ifParentKey = context?.parent ? context.parent : null;
4938
+ if (ifParentKey) {
4939
+ lastConditionalMergeGroupByParent.set(ifParentKey, mergeGroupKey);
4940
+ }
4852
4941
  let lastHint = null;
4853
4942
  for (const branch of branches) {
4943
+ conditionalMergeGroupByIfBranch.set(branch, mergeGroupKey);
4944
+ markConditionalMergeGroup(branch.children ?? [], mergeGroupKey);
4854
4945
  const cond = branch.condition ?? null;
4855
4946
  if (!cond) {
4856
4947
  const hint = lastHint ? `else ${lastHint}` : "else";
@@ -4929,10 +5020,28 @@ function createTestIdTransform(componentName, componentHierarchyMap, nativeWrapp
4929
5020
  const bestKeyPlaceholder = isSlotKey ? `\${${bestKeyInferred}}` : bestKeyInferred;
4930
5021
  const bestKeyVariable = isSlotKey ? bestKeyInferred : null;
4931
5022
  const keyValuesOverride = tryGetContainedInStaticVForSourceLiteralValues(context);
4932
- const parentKey = !parentIsRoot && context?.parent ? context.parent : null;
5023
+ const parentKey = context?.parent ? context.parent : null;
4933
5024
  const conditional = getConditionalDirectiveInfo(element);
4934
5025
  let conditionalHint = null;
5026
+ const elementLocationKey = getElementLocationKey(element);
5027
+ let conditionalMergeGroupKey = (elementLocationKey ? conditionalMergeGroupByElementLoc.get(elementLocationKey) ?? null : null) ?? conditionalMergeGroupByElement.get(element) ?? null;
5028
+ if (!conditionalMergeGroupKey && context?.parent?.type === compilerCore.NodeTypes.IF_BRANCH) {
5029
+ const branch = context.parent;
5030
+ conditionalMergeGroupKey = conditionalMergeGroupByIfBranch.get(branch) ?? null;
5031
+ }
4935
5032
  if (conditional && (conditional.kind === "if" || conditional.kind === "else-if")) {
5033
+ if (parentKey) {
5034
+ if (!conditionalMergeGroupKey) {
5035
+ if (conditional.kind === "if") {
5036
+ conditionalMergeGroupKey = `if-group:${++conditionalMergeGroupCounter}`;
5037
+ } else {
5038
+ conditionalMergeGroupKey = lastConditionalMergeGroupByParent.get(parentKey) ?? null;
5039
+ }
5040
+ }
5041
+ if (conditionalMergeGroupKey) {
5042
+ lastConditionalMergeGroupByParent.set(parentKey, conditionalMergeGroupKey);
5043
+ }
5044
+ }
4936
5045
  conditionalHint = tryExtractStableHintFromConditionalExpressionSource(conditional.source);
4937
5046
  if (conditionalHint && parentKey) {
4938
5047
  lastConditionalHintByParent.set(parentKey, conditionalHint);
@@ -4941,6 +5050,7 @@ function createTestIdTransform(componentName, componentHierarchyMap, nativeWrapp
4941
5050
  if (parentKey) {
4942
5051
  const previousHint = lastConditionalHintByParent.get(parentKey) ?? null;
4943
5052
  conditionalHint = previousHint ? `else ${previousHint}` : null;
5053
+ conditionalMergeGroupKey = lastConditionalMergeGroupByParent.get(parentKey) ?? null;
4944
5054
  }
4945
5055
  }
4946
5056
  if (!conditionalHint && context?.parent?.type === compilerCore.NodeTypes.IF_BRANCH) {
@@ -5048,11 +5158,13 @@ Fix: remove the explicit ${attrLabel}, or change existingIdBehavior to "overwrit
5048
5158
  const nativeRole = nativeWrappers[element.tag]?.role ?? element.tag;
5049
5159
  const primarySemanticHint = semanticNameHint || conditionalHint || void 0;
5050
5160
  const alternates = nameCollisionBehavior === "error" && semanticNameHint && conditionalHint ? [`${semanticNameHint} ${conditionalHint}`] : void 0;
5161
+ const pomMergeKey = semanticNameHint && conditionalMergeGroupKey ? `wrapper:ifgroup:${conditionalMergeGroupKey}:model:${semanticNameHint}` : void 0;
5051
5162
  applyResolvedDataTestIdForElement({
5052
5163
  preferredGeneratedValue: nativeWrappersValue,
5053
5164
  nativeRoleOverride: nativeRole,
5054
5165
  semanticNameHint: primarySemanticHint,
5055
- semanticNameHintAlternates: alternates
5166
+ semanticNameHintAlternates: alternates,
5167
+ pomMergeKey
5056
5168
  });
5057
5169
  return;
5058
5170
  }