@immense/vue-pom-generator 1.0.31 → 1.0.32
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 +20 -39
- package/class-generation/index.ts +19 -3
- package/dist/class-generation/index.d.ts.map +1 -1
- package/dist/index.cjs +20 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +20 -5
- package/dist/index.mjs.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/package.json +1 -1
package/RELEASE_NOTES.md
CHANGED
|
@@ -1,57 +1,38 @@
|
|
|
1
|
-
●
|
|
2
|
-
diffs:
|
|
3
|
-
|
|
4
|
-
● Let me look at specific key changes to understand what was fixed:
|
|
5
|
-
|
|
6
|
-
● Based on the commit and PR details, here are the release notes:
|
|
7
|
-
|
|
8
|
-
---
|
|
1
|
+
● # Release Notes: v1.0.32
|
|
9
2
|
|
|
10
3
|
## Highlights
|
|
11
4
|
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
POMs
|
|
18
|
-
- Added comprehensive utility functions for analyzing assignment patterns, object destructuring,
|
|
19
|
-
and binding identifiers
|
|
5
|
+
- Fixed handling of missing helpers and keyed ID branches in class generation
|
|
6
|
+
- Added robust error tolerance for edge cases in Vue component transformation
|
|
7
|
+
- Expanded test coverage with 109 new test lines across generated TypeScript and utility
|
|
8
|
+
coverage tests
|
|
9
|
+
- Introduced PR release-notes preview comments via GitHub Actions
|
|
20
10
|
|
|
21
11
|
## Changes
|
|
22
12
|
|
|
23
|
-
**
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
- `.gitattributes` entries are now only generated when using custom output directories outside
|
|
27
|
-
`__generated__`
|
|
13
|
+
**Bug Fixes**
|
|
14
|
+
- Tolerate missing helpers and keyed ID branches in class generation logic
|
|
15
|
+
(`class-generation/index.ts`, `utils.ts`)
|
|
28
16
|
|
|
29
|
-
**
|
|
30
|
-
-
|
|
31
|
-
|
|
32
|
-
-
|
|
33
|
-
- Better handling of assignment patterns, rest elements, and object properties
|
|
17
|
+
**Testing**
|
|
18
|
+
- Added comprehensive tests for generated TypeScript output (`tests/generated-tsc.test.ts`: +74
|
|
19
|
+
lines)
|
|
20
|
+
- Expanded utility function coverage tests (`tests/utils-coverage.test.ts`: +35 lines)
|
|
34
21
|
|
|
35
|
-
**
|
|
36
|
-
- Added
|
|
37
|
-
`utils-coverage.test.ts`
|
|
38
|
-
- Expanded Babel type guards usage for more precise AST node detection
|
|
39
|
-
- Refactored slot scope analysis with dedicated helper functions
|
|
22
|
+
**CI/Automation**
|
|
23
|
+
- Added automated PR release-notes preview comments to pull requests
|
|
40
24
|
|
|
41
25
|
## Breaking Changes
|
|
42
26
|
|
|
43
|
-
|
|
44
|
-
`tests/playwright/__generated__`. If you're relying on the default, generated files will move to
|
|
45
|
-
the new location. To preserve the old behavior, explicitly set `generation.outDir:
|
|
46
|
-
"tests/playwright/generated"` in your config.
|
|
27
|
+
None
|
|
47
28
|
|
|
48
29
|
## Pull Requests Included
|
|
49
30
|
|
|
50
|
-
- [#1 Add PR release-notes preview
|
|
51
|
-
comments
|
|
31
|
+
- [#1](https://github.com/immense/vue-pom-generator/pull/1) Add PR release-notes preview
|
|
32
|
+
comments (@dkattan)
|
|
52
33
|
|
|
53
34
|
## Testing
|
|
54
35
|
|
|
55
|
-
|
|
56
|
-
|
|
36
|
+
Significant test additions: 74 lines in generated TypeScript tests and 35 lines in utility
|
|
37
|
+
coverage tests validate the fix for missing helpers and keyed ID branches.
|
|
57
38
|
|
|
@@ -407,6 +407,7 @@ interface GenerateContentOptions {
|
|
|
407
407
|
customPomDir?: string;
|
|
408
408
|
customPomImportAliases?: Record<string, string>;
|
|
409
409
|
customPomClassIdentifierMap?: Record<string, string>;
|
|
410
|
+
customPomAvailableClassIdentifiers?: Set<string>;
|
|
410
411
|
|
|
411
412
|
/** Attribute name to treat as the test id. Defaults to `data-testid`. */
|
|
412
413
|
testIdAttribute?: string;
|
|
@@ -1153,8 +1154,14 @@ function generateViewObjectModelContent(
|
|
|
1153
1154
|
return false;
|
|
1154
1155
|
};
|
|
1155
1156
|
|
|
1157
|
+
const customPomClassIdentifierMap = options.customPomClassIdentifierMap ?? {};
|
|
1158
|
+
const customPomAvailableClassIdentifiers = options.customPomAvailableClassIdentifiers ?? new Set<string>();
|
|
1159
|
+
|
|
1156
1160
|
const attachmentsForThisClass = customPomAttachments
|
|
1157
1161
|
.filter((a) => {
|
|
1162
|
+
if (!Object.prototype.hasOwnProperty.call(customPomClassIdentifierMap, a.className))
|
|
1163
|
+
return false;
|
|
1164
|
+
|
|
1158
1165
|
const scope = a.attachTo ?? "views";
|
|
1159
1166
|
const scopeOk = isView
|
|
1160
1167
|
? (scope === "views" || scope === "both")
|
|
@@ -1164,7 +1171,7 @@ function generateViewObjectModelContent(
|
|
|
1164
1171
|
return a.attachWhenUsesComponents.some(c => hasChildComponent(c));
|
|
1165
1172
|
})
|
|
1166
1173
|
.map(a => ({
|
|
1167
|
-
className:
|
|
1174
|
+
className: customPomClassIdentifierMap[a.className]!,
|
|
1168
1175
|
propertyName: a.propertyName,
|
|
1169
1176
|
}));
|
|
1170
1177
|
|
|
@@ -1218,7 +1225,7 @@ function generateViewObjectModelContent(
|
|
|
1218
1225
|
content += `\nexport class ${className} extends BasePage {\n`;
|
|
1219
1226
|
|
|
1220
1227
|
const widgetInstances = isView
|
|
1221
|
-
? getWidgetInstancesForView(componentName, dependencies.dataTestIdSet)
|
|
1228
|
+
? getWidgetInstancesForView(componentName, dependencies.dataTestIdSet, customPomAvailableClassIdentifiers)
|
|
1222
1229
|
: [];
|
|
1223
1230
|
|
|
1224
1231
|
// For views, `childrenComponentSet` only includes component tags on which we applied a data-testid.
|
|
@@ -1489,6 +1496,7 @@ async function generateAggregatedFiles(
|
|
|
1489
1496
|
};
|
|
1490
1497
|
|
|
1491
1498
|
const customPomClassIdentifierMap = addCustomPomImports();
|
|
1499
|
+
const customPomAvailableClassIdentifiers = new Set(Object.values(customPomClassIdentifierMap ?? {}));
|
|
1492
1500
|
|
|
1493
1501
|
// Collect any navigation return types referenced by generated methods so we can emit
|
|
1494
1502
|
// stub classes when the destination view has no generated test ids (and therefore no
|
|
@@ -1690,6 +1698,7 @@ async function generateAggregatedFiles(
|
|
|
1690
1698
|
|
|
1691
1699
|
customPomAttachments: options.customPomAttachments ?? [],
|
|
1692
1700
|
customPomClassIdentifierMap,
|
|
1701
|
+
customPomAvailableClassIdentifiers,
|
|
1693
1702
|
testIdAttribute: options.testIdAttribute,
|
|
1694
1703
|
vueRouterFluentChaining: options.vueRouterFluentChaining,
|
|
1695
1704
|
routeMetaByComponent: options.routeMetaByComponent,
|
|
@@ -1817,7 +1826,11 @@ interface WidgetInstance {
|
|
|
1817
1826
|
testId: string;
|
|
1818
1827
|
}
|
|
1819
1828
|
|
|
1820
|
-
function getWidgetInstancesForView(
|
|
1829
|
+
function getWidgetInstancesForView(
|
|
1830
|
+
componentName: string,
|
|
1831
|
+
dataTestIdSet: Set<IDataTestId>,
|
|
1832
|
+
availableClassIdentifiers: Set<string>,
|
|
1833
|
+
): WidgetInstance[] {
|
|
1821
1834
|
const out: WidgetInstance[] = [];
|
|
1822
1835
|
const usedPropNames = new Set<string>();
|
|
1823
1836
|
|
|
@@ -1858,6 +1871,9 @@ function getWidgetInstancesForView(componentName: string, dataTestIdSet: Set<IDa
|
|
|
1858
1871
|
continue;
|
|
1859
1872
|
}
|
|
1860
1873
|
|
|
1874
|
+
if (!availableClassIdentifiers.has(className))
|
|
1875
|
+
continue;
|
|
1876
|
+
|
|
1861
1877
|
// Prefer stripping the view prefix (e.g. PreferencesPage-) for cleaner member names.
|
|
1862
1878
|
const viewPrefix = `${componentName}-`;
|
|
1863
1879
|
const descriptorRaw = stem.startsWith(viewPrefix) ? stem.slice(viewPrefix.length) : stem;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../class-generation/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,oCAAoC,EAAE,MAAM,sBAAsB,CAAC;AAE5E,OAAO,EAAE,sBAAsB,EAAoE,MAAM,UAAU,CAAC;AAQpH,OAAO,EAAE,oCAAoC,EAAE,CAAC;AA8ChD,UAAU,SAAS;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAyOD,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;;;;;;;;OAWG;IACH,gBAAgB,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAE1D;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;;;;OAOG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEhD;;;;;OAKG;IACH,oCAAoC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IAEzD;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,KAAK,CAAC;QAC3B,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;QACrB,wBAAwB,EAAE,MAAM,EAAE,CAAC;QAEnC;;;WAGG;QACH,QAAQ,CAAC,EAAE,OAAO,GAAG,YAAY,GAAG,MAAM,CAAC;KAC5C,CAAC,CAAC;IAEH,yEAAyE;IACzE,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,uDAAuD;IACvD,aAAa,CAAC,EAAE,KAAK,CAAC,IAAI,GAAG,QAAQ,CAAC,CAAC;IAEvC,6BAA6B;IAC7B,MAAM,CAAC,EAAE;QACP,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IAEF,6EAA6E;IAC7E,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC,2FAA2F;IAC3F,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,mDAAmD;IACnD,UAAU,CAAC,EAAE,YAAY,GAAG,MAAM,CAAC;IAEnC,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CAClD;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../class-generation/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,oCAAoC,EAAE,MAAM,sBAAsB,CAAC;AAE5E,OAAO,EAAE,sBAAsB,EAAoE,MAAM,UAAU,CAAC;AAQpH,OAAO,EAAE,oCAAoC,EAAE,CAAC;AA8ChD,UAAU,SAAS;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAyOD,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;;;;;;;;OAWG;IACH,gBAAgB,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAE1D;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;;;;OAOG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEhD;;;;;OAKG;IACH,oCAAoC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IAEzD;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,KAAK,CAAC;QAC3B,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;QACrB,wBAAwB,EAAE,MAAM,EAAE,CAAC;QAEnC;;;WAGG;QACH,QAAQ,CAAC,EAAE,OAAO,GAAG,YAAY,GAAG,MAAM,CAAC;KAC5C,CAAC,CAAC;IAEH,yEAAyE;IACzE,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,uDAAuD;IACvD,aAAa,CAAC,EAAE,KAAK,CAAC,IAAI,GAAG,QAAQ,CAAC,CAAC;IAEvC,6BAA6B;IAC7B,MAAM,CAAC,EAAE;QACP,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IAEF,6EAA6E;IAC7E,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC,2FAA2F;IAC3F,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,mDAAmD;IACnD,UAAU,CAAC,EAAE,YAAY,GAAG,MAAM,CAAC;IAEnC,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CAClD;AAwCD,wBAAsB,aAAa,CACjC,qBAAqB,EAAE,GAAG,CAAC,MAAM,EAAE,sBAAsB,CAAC,EAC1D,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EACpC,iBAAiB,EAAE,MAAM,EACzB,OAAO,GAAE,oBAAyB,iBA2EnC"}
|
package/dist/index.cjs
CHANGED
|
@@ -1859,6 +1859,12 @@ function applyResolvedDataTestId(args) {
|
|
|
1859
1859
|
const existingIdBehavior = args.existingIdBehavior ?? "preserve";
|
|
1860
1860
|
const nameCollisionBehavior = args.nameCollisionBehavior ?? "suffix";
|
|
1861
1861
|
const warn = args.warn;
|
|
1862
|
+
const getBestKeyAccessCandidates = (expr) => {
|
|
1863
|
+
if (!expr) {
|
|
1864
|
+
return [];
|
|
1865
|
+
}
|
|
1866
|
+
return expr.split("??").map((part) => part.trim()).filter(Boolean);
|
|
1867
|
+
};
|
|
1862
1868
|
let dataTestId = args.preferredGeneratedValue;
|
|
1863
1869
|
let fromExisting = false;
|
|
1864
1870
|
const existing = tryGetExistingElementDataTestId(args.element, testIdAttribute);
|
|
@@ -1881,6 +1887,7 @@ Bulk cleanup: run ESLint with the @immense/vue-pom-generator/remove-existing-tes
|
|
|
1881
1887
|
if (existingIdBehavior === "preserve") {
|
|
1882
1888
|
if (existing.isDynamic) {
|
|
1883
1889
|
if (existing.template) {
|
|
1890
|
+
const existingTemplate = existing.template;
|
|
1884
1891
|
if ((existing.templateExpressionCount ?? 0) !== 1) {
|
|
1885
1892
|
throw new Error(
|
|
1886
1893
|
`[vue-pom-generator] Existing ${attrLabel} is a template literal with multiple interpolations and cannot be preserved safely.
|
|
@@ -1891,8 +1898,8 @@ Existing ${attrLabel}: ${JSON.stringify(existing.value)}
|
|
|
1891
1898
|
Fix: reduce the template to a single key-based interpolation, or remove the explicit ${attrLabel} so it can be auto-generated.`
|
|
1892
1899
|
);
|
|
1893
1900
|
}
|
|
1894
|
-
const hasExact = args.bestKeyPlaceholder &&
|
|
1895
|
-
const hasVarAccess = args.bestKeyVariable
|
|
1901
|
+
const hasExact = args.bestKeyPlaceholder && existingTemplate.includes(args.bestKeyPlaceholder);
|
|
1902
|
+
const hasVarAccess = getBestKeyAccessCandidates(args.bestKeyVariable).some((candidate) => existingTemplate.includes(candidate));
|
|
1896
1903
|
if (!hasExact && !hasVarAccess && args.bestKeyPlaceholder) {
|
|
1897
1904
|
throw new Error(
|
|
1898
1905
|
`[vue-pom-generator] Existing ${attrLabel} appears to be missing the key placeholder needed to keep it unique.
|
|
@@ -3883,14 +3890,18 @@ function generateViewObjectModelContent(componentName, dependencies, componentHi
|
|
|
3883
3890
|
}
|
|
3884
3891
|
return false;
|
|
3885
3892
|
};
|
|
3893
|
+
const customPomClassIdentifierMap = options.customPomClassIdentifierMap ?? {};
|
|
3894
|
+
const customPomAvailableClassIdentifiers = options.customPomAvailableClassIdentifiers ?? /* @__PURE__ */ new Set();
|
|
3886
3895
|
const attachmentsForThisClass = customPomAttachments.filter((a) => {
|
|
3896
|
+
if (!Object.prototype.hasOwnProperty.call(customPomClassIdentifierMap, a.className))
|
|
3897
|
+
return false;
|
|
3887
3898
|
const scope = a.attachTo ?? "views";
|
|
3888
3899
|
const scopeOk = isView ? scope === "views" || scope === "both" : scope === "components" || scope === "both";
|
|
3889
3900
|
if (!scopeOk)
|
|
3890
3901
|
return false;
|
|
3891
3902
|
return a.attachWhenUsesComponents.some((c) => hasChildComponent(c));
|
|
3892
3903
|
}).map((a) => ({
|
|
3893
|
-
className:
|
|
3904
|
+
className: customPomClassIdentifierMap[a.className],
|
|
3894
3905
|
propertyName: a.propertyName
|
|
3895
3906
|
}));
|
|
3896
3907
|
let content = "";
|
|
@@ -3930,7 +3941,7 @@ function generateViewObjectModelContent(componentName, dependencies, componentHi
|
|
|
3930
3941
|
content += `
|
|
3931
3942
|
export class ${className} extends BasePage {
|
|
3932
3943
|
`;
|
|
3933
|
-
const widgetInstances = isView ? getWidgetInstancesForView(componentName, dependencies.dataTestIdSet) : [];
|
|
3944
|
+
const widgetInstances = isView ? getWidgetInstancesForView(componentName, dependencies.dataTestIdSet, customPomAvailableClassIdentifiers) : [];
|
|
3934
3945
|
const componentRefsForInstances = isView ? usedComponentSet?.size ? usedComponentSet : childrenComponentSet : childrenComponentSet;
|
|
3935
3946
|
if (isView && (componentRefsForInstances.size > 0 || attachmentsForThisClass.length > 0 || widgetInstances.length > 0)) {
|
|
3936
3947
|
content += getComponentInstances(componentRefsForInstances, componentHierarchyMap, attachmentsForThisClass, widgetInstances);
|
|
@@ -4088,6 +4099,7 @@ Fix by setting generation.playwright.customPoms.importAliases["${exportName}"] t
|
|
|
4088
4099
|
return customPomClassIdentifierMap2;
|
|
4089
4100
|
};
|
|
4090
4101
|
const customPomClassIdentifierMap = addCustomPomImports();
|
|
4102
|
+
const customPomAvailableClassIdentifiers = new Set(Object.values(customPomClassIdentifierMap ?? {}));
|
|
4091
4103
|
const referencedTargets = /* @__PURE__ */ new Set();
|
|
4092
4104
|
for (const [, deps] of items) {
|
|
4093
4105
|
for (const dt of deps.dataTestIdSet) {
|
|
@@ -4240,6 +4252,7 @@ Fix by setting generation.playwright.customPoms.importAliases["${exportName}"] t
|
|
|
4240
4252
|
aggregated: true,
|
|
4241
4253
|
customPomAttachments: options.customPomAttachments ?? [],
|
|
4242
4254
|
customPomClassIdentifierMap,
|
|
4255
|
+
customPomAvailableClassIdentifiers,
|
|
4243
4256
|
testIdAttribute: options.testIdAttribute,
|
|
4244
4257
|
vueRouterFluentChaining: options.vueRouterFluentChaining,
|
|
4245
4258
|
routeMetaByComponent: options.routeMetaByComponent
|
|
@@ -4334,7 +4347,7 @@ function toPascalCaseLocal(str) {
|
|
|
4334
4347
|
return preserveInternalCaps ? upperFirst(word) : upperFirst(word.toLowerCase());
|
|
4335
4348
|
}).join("");
|
|
4336
4349
|
}
|
|
4337
|
-
function getWidgetInstancesForView(componentName, dataTestIdSet) {
|
|
4350
|
+
function getWidgetInstancesForView(componentName, dataTestIdSet, availableClassIdentifiers) {
|
|
4338
4351
|
const out = [];
|
|
4339
4352
|
const usedPropNames = /* @__PURE__ */ new Set();
|
|
4340
4353
|
const ensureUnique = (base) => {
|
|
@@ -4365,6 +4378,8 @@ function getWidgetInstancesForView(componentName, dataTestIdSet) {
|
|
|
4365
4378
|
} else {
|
|
4366
4379
|
continue;
|
|
4367
4380
|
}
|
|
4381
|
+
if (!availableClassIdentifiers.has(className))
|
|
4382
|
+
continue;
|
|
4368
4383
|
const viewPrefix = `${componentName}-`;
|
|
4369
4384
|
const descriptorRaw = stem.startsWith(viewPrefix) ? stem.slice(viewPrefix.length) : stem;
|
|
4370
4385
|
const descriptorPascal = toPascalCaseLocal(descriptorRaw);
|