@immense/vue-pom-generator 1.0.38 → 1.0.39
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/README.md +953 -165
- package/RELEASE_NOTES.md +19 -30
- package/class-generation/index.ts +232 -29
- package/dist/class-generation/index.d.ts +8 -10
- package/dist/class-generation/index.d.ts.map +1 -1
- package/dist/index.cjs +161 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +161 -10
- package/dist/index.mjs.map +1 -1
- package/dist/plugin/support/build-plugin.d.ts +1 -0
- package/dist/plugin/support/build-plugin.d.ts.map +1 -1
- package/dist/plugin/support/dev-plugin.d.ts +1 -0
- package/dist/plugin/support/dev-plugin.d.ts.map +1 -1
- package/dist/plugin/support-plugins.d.ts +1 -0
- package/dist/plugin/support-plugins.d.ts.map +1 -1
- package/dist/plugin/types.d.ts +3 -1
- package/dist/plugin/types.d.ts.map +1 -1
- package/package.json +1 -1
package/RELEASE_NOTES.md
CHANGED
|
@@ -1,51 +1,40 @@
|
|
|
1
|
-
●
|
|
2
|
-
fixture overrides in Playwright test fixtures.
|
|
3
|
-
|
|
4
|
-
```markdown
|
|
5
|
-
# Release v1.0.38
|
|
1
|
+
● # Release Notes: v1.0.39
|
|
6
2
|
|
|
7
3
|
## Highlights
|
|
8
4
|
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
|
|
5
|
+
- **Flattened helper attachments**: New capability in class generation for handling helper
|
|
6
|
+
attachments in a flattened structure
|
|
7
|
+
- **Extensive documentation updates**: README expanded with over 1,100 new lines of
|
|
8
|
+
documentation
|
|
9
|
+
- **Enhanced test coverage**: Added 89 lines of new tests for generated TypeScript compilation
|
|
10
|
+
- **PR automation**: Added release notes preview comments on pull requests
|
|
13
11
|
|
|
14
12
|
## Changes
|
|
15
13
|
|
|
16
|
-
###
|
|
17
|
-
|
|
18
|
-
- Fixtures now automatically prefer matching handwritten override classes from the `overrides/`
|
|
19
|
-
directory
|
|
20
|
-
- Override directory location is inferred as sibling to `generation.playwright.customPoms.dir`
|
|
21
|
-
- Generated fixtures import and instantiate override classes when available (e.g.,
|
|
22
|
-
`tests/playwright/pom/overrides/<ClassName>.ts`)
|
|
23
|
-
- Added runtime detection of override files via filesystem checks during generation
|
|
14
|
+
### Features
|
|
15
|
+
- Add flattened helper attachments support in class generation (`class-generation/index.ts`)
|
|
24
16
|
|
|
25
17
|
### Documentation
|
|
26
|
-
|
|
27
|
-
- Added fixture override convention documentation to README
|
|
28
|
-
- Updated plugin type definitions with fixture override behavior
|
|
29
|
-
- Documented override directory structure and lookup rules
|
|
18
|
+
- Significantly expanded README with detailed documentation (+1,118 lines)
|
|
30
19
|
|
|
31
20
|
### Testing
|
|
21
|
+
- Enhanced `tests/generated-tsc.test.ts` with additional test cases (+89 lines)
|
|
32
22
|
|
|
33
|
-
|
|
34
|
-
-
|
|
35
|
-
|
|
23
|
+
### Tooling
|
|
24
|
+
- Added PR release-notes preview comment automation
|
|
25
|
+
- Minor updates to plugin type definitions and support files
|
|
36
26
|
|
|
37
27
|
## Breaking Changes
|
|
38
28
|
|
|
39
|
-
None
|
|
29
|
+
None
|
|
40
30
|
|
|
41
31
|
## Pull Requests Included
|
|
42
32
|
|
|
43
|
-
- #1 Add PR release-notes preview comments https://github.com/immense/vue-pom-generator/pull/1
|
|
44
|
-
|
|
33
|
+
- #1 Add PR release-notes preview comments (https://github.com/immense/vue-pom-generator/pull/1)
|
|
34
|
+
by @dkattan
|
|
45
35
|
|
|
46
36
|
## Testing
|
|
47
37
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
```
|
|
38
|
+
Tests updated and expanded to cover new flattened helper attachments functionality. Added 89
|
|
39
|
+
lines of test coverage in `tests/generated-tsc.test.ts`.
|
|
51
40
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { parse } from "@babel/parser";
|
|
2
|
+
import type { ClassMethod } from "@babel/types";
|
|
1
3
|
import fs from "node:fs";
|
|
2
4
|
import path from "node:path";
|
|
3
5
|
import process from "node:process";
|
|
@@ -62,6 +64,28 @@ interface RouteMeta {
|
|
|
62
64
|
template: string;
|
|
63
65
|
}
|
|
64
66
|
|
|
67
|
+
interface CustomPomMethodSignature {
|
|
68
|
+
params: string;
|
|
69
|
+
argNames: string[];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
type CustomPomMethodSignatureMap = Map<string, CustomPomMethodSignature>;
|
|
73
|
+
|
|
74
|
+
interface CustomPomAttachment {
|
|
75
|
+
className: string;
|
|
76
|
+
propertyName: string;
|
|
77
|
+
attachWhenUsesComponents: string[];
|
|
78
|
+
attachTo?: "views" | "components" | "both";
|
|
79
|
+
flatten?: boolean;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
interface ResolvedCustomPomAttachment {
|
|
83
|
+
className: string;
|
|
84
|
+
propertyName: string;
|
|
85
|
+
flatten: boolean;
|
|
86
|
+
methodSignatures: CustomPomMethodSignatureMap;
|
|
87
|
+
}
|
|
88
|
+
|
|
65
89
|
async function getRouteMetaByComponent(
|
|
66
90
|
projectRoot?: string,
|
|
67
91
|
routerEntry?: string,
|
|
@@ -368,17 +392,7 @@ export interface GenerateFilesOptions {
|
|
|
368
392
|
* aggregated output (e.g. via `tests/playwright/pom/custom/*.ts` inlining), but we only attach them to
|
|
369
393
|
* view classes that actually use certain components.
|
|
370
394
|
*/
|
|
371
|
-
customPomAttachments?:
|
|
372
|
-
className: string;
|
|
373
|
-
propertyName: string;
|
|
374
|
-
attachWhenUsesComponents: string[];
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* Controls whether this attachment is applied to views, components, or both.
|
|
378
|
-
* Defaults to "views" for backwards compatibility.
|
|
379
|
-
*/
|
|
380
|
-
attachTo?: "views" | "components" | "both";
|
|
381
|
-
}>;
|
|
395
|
+
customPomAttachments?: CustomPomAttachment[];
|
|
382
396
|
|
|
383
397
|
/** Attribute name to treat as the test id. Defaults to `data-testid`. */
|
|
384
398
|
testIdAttribute?: string;
|
|
@@ -412,23 +426,14 @@ interface GenerateContentOptions {
|
|
|
412
426
|
/** When true, omit file headers/import blocks that should be shared in an aggregated file. */
|
|
413
427
|
aggregated?: boolean;
|
|
414
428
|
|
|
415
|
-
customPomAttachments?:
|
|
416
|
-
className: string;
|
|
417
|
-
propertyName: string;
|
|
418
|
-
attachWhenUsesComponents: string[];
|
|
419
|
-
|
|
420
|
-
/**
|
|
421
|
-
* Controls whether this attachment is applied to views, components, or both.
|
|
422
|
-
* Defaults to "views" for backwards compatibility.
|
|
423
|
-
*/
|
|
424
|
-
attachTo?: "views" | "components" | "both";
|
|
425
|
-
}>;
|
|
429
|
+
customPomAttachments?: CustomPomAttachment[];
|
|
426
430
|
|
|
427
431
|
projectRoot?: string;
|
|
428
432
|
customPomDir?: string;
|
|
429
433
|
customPomImportAliases?: Record<string, string>;
|
|
430
434
|
customPomClassIdentifierMap?: Record<string, string>;
|
|
431
435
|
customPomAvailableClassIdentifiers?: Set<string>;
|
|
436
|
+
customPomMethodSignaturesByClass?: Map<string, CustomPomMethodSignatureMap>;
|
|
432
437
|
|
|
433
438
|
/** Attribute name to treat as the test id. Defaults to `data-testid`. */
|
|
434
439
|
testIdAttribute?: string;
|
|
@@ -1216,6 +1221,7 @@ function generateViewObjectModelContent(
|
|
|
1216
1221
|
|
|
1217
1222
|
const customPomClassIdentifierMap = options.customPomClassIdentifierMap ?? {};
|
|
1218
1223
|
const customPomAvailableClassIdentifiers = options.customPomAvailableClassIdentifiers ?? new Set<string>();
|
|
1224
|
+
const customPomMethodSignaturesByClass = options.customPomMethodSignaturesByClass ?? new Map<string, CustomPomMethodSignatureMap>();
|
|
1219
1225
|
|
|
1220
1226
|
const attachmentsForThisClass = customPomAttachments
|
|
1221
1227
|
.filter((a) => {
|
|
@@ -1233,6 +1239,10 @@ function generateViewObjectModelContent(
|
|
|
1233
1239
|
.map(a => ({
|
|
1234
1240
|
className: customPomClassIdentifierMap[a.className]!,
|
|
1235
1241
|
propertyName: a.propertyName,
|
|
1242
|
+
flatten: a.flatten ?? false,
|
|
1243
|
+
methodSignatures: a.flatten
|
|
1244
|
+
? (customPomMethodSignaturesByClass.get(a.className) ?? new Map<string, CustomPomMethodSignature>())
|
|
1245
|
+
: new Map<string, CustomPomMethodSignature>(),
|
|
1236
1246
|
}));
|
|
1237
1247
|
|
|
1238
1248
|
let content: string = "";
|
|
@@ -1295,6 +1305,19 @@ function generateViewObjectModelContent(
|
|
|
1295
1305
|
const componentRefsForInstances = isView
|
|
1296
1306
|
? (usedComponentSet?.size ? usedComponentSet : childrenComponentSet)
|
|
1297
1307
|
: childrenComponentSet;
|
|
1308
|
+
const childInstancePropertyNames = Array.from(componentRefsForInstances)
|
|
1309
|
+
.filter(child => componentHierarchyMap.has(child) && componentHierarchyMap.get(child)?.dataTestIdSet.size)
|
|
1310
|
+
.map(child => child.split(".vue")[0]);
|
|
1311
|
+
const blockedViewPassthroughMethodNames = new Set(
|
|
1312
|
+
attachmentsForThisClass
|
|
1313
|
+
.filter(a => a.flatten)
|
|
1314
|
+
.flatMap(a => Array.from(a.methodSignatures.keys())),
|
|
1315
|
+
);
|
|
1316
|
+
const reservedAttachmentPassthroughNames = new Set<string>([
|
|
1317
|
+
...attachmentsForThisClass.map(a => a.propertyName),
|
|
1318
|
+
...widgetInstances.map(w => w.propertyName),
|
|
1319
|
+
...childInstancePropertyNames,
|
|
1320
|
+
]);
|
|
1298
1321
|
|
|
1299
1322
|
// Only views get child component instance fields by default.
|
|
1300
1323
|
// Components will only get a constructor/fields when they have explicit custom attachments
|
|
@@ -1307,6 +1330,7 @@ function generateViewObjectModelContent(
|
|
|
1307
1330
|
content += getComponentInstances(new Set(), componentHierarchyMap, attachmentsForThisClass);
|
|
1308
1331
|
content += getConstructor(new Set(), componentHierarchyMap, attachmentsForThisClass, [], { testIdAttribute });
|
|
1309
1332
|
}
|
|
1333
|
+
content += getAttachmentPassthroughMethods(componentName, dependencies, attachmentsForThisClass, reservedAttachmentPassthroughNames);
|
|
1310
1334
|
|
|
1311
1335
|
// Ergonomics: when a view is primarily composed of a single component POM (e.g. a form),
|
|
1312
1336
|
// allow calling that component's methods directly on the page class.
|
|
@@ -1322,7 +1346,7 @@ function generateViewObjectModelContent(
|
|
|
1322
1346
|
// around a single child component POM. This prevents "layout" components (Page, PageHeader,
|
|
1323
1347
|
// etc.) from injecting lots of noisy passthrough APIs into every view.
|
|
1324
1348
|
if (isView && componentRefsForInstances.size === 1) {
|
|
1325
|
-
content += getViewPassthroughMethods(componentName, dependencies, componentRefsForInstances, componentHierarchyMap);
|
|
1349
|
+
content += getViewPassthroughMethods(componentName, dependencies, componentRefsForInstances, componentHierarchyMap, blockedViewPassthroughMethodNames);
|
|
1326
1350
|
}
|
|
1327
1351
|
|
|
1328
1352
|
if (isView && options.vueRouterFluentChaining) {
|
|
@@ -1343,6 +1367,7 @@ function getViewPassthroughMethods(
|
|
|
1343
1367
|
viewDependencies: IComponentDependencies,
|
|
1344
1368
|
childrenComponentSet: Set<string>,
|
|
1345
1369
|
componentHierarchyMap: Map<string, IComponentDependencies>,
|
|
1370
|
+
blockedMethodNames: Set<string> = new Set(),
|
|
1346
1371
|
) {
|
|
1347
1372
|
const existingOnView = viewDependencies.generatedMethods ?? new Map<string, { params: string; argNames: string[] } | null>();
|
|
1348
1373
|
|
|
@@ -1366,7 +1391,7 @@ function getViewPassthroughMethods(
|
|
|
1366
1391
|
continue; // ambiguous on the child itself
|
|
1367
1392
|
|
|
1368
1393
|
// If the view already has this method name, never generate a pass-through.
|
|
1369
|
-
if (existingOnView.has(name))
|
|
1394
|
+
if (existingOnView.has(name) || blockedMethodNames.has(name))
|
|
1370
1395
|
continue;
|
|
1371
1396
|
|
|
1372
1397
|
const list = methodToChildren.get(name) ?? [];
|
|
@@ -1406,6 +1431,169 @@ function getViewPassthroughMethods(
|
|
|
1406
1431
|
].join("\n");
|
|
1407
1432
|
}
|
|
1408
1433
|
|
|
1434
|
+
function getAttachmentPassthroughMethods(
|
|
1435
|
+
ownerName: string,
|
|
1436
|
+
ownerDependencies: IComponentDependencies,
|
|
1437
|
+
attachmentsForThisClass: ResolvedCustomPomAttachment[],
|
|
1438
|
+
reservedMemberNames: Set<string>,
|
|
1439
|
+
) {
|
|
1440
|
+
if (!attachmentsForThisClass.some(a => a.flatten && a.methodSignatures.size > 0)) {
|
|
1441
|
+
return "";
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
const existingOnClass = ownerDependencies.generatedMethods ?? new Map<string, { params: string; argNames: string[] } | null>();
|
|
1445
|
+
const methodToAttachments = new Map<string, Array<{ propertyName: string; params: string; argNames: string[] }>>();
|
|
1446
|
+
|
|
1447
|
+
for (const attachment of attachmentsForThisClass) {
|
|
1448
|
+
if (!attachment.flatten) {
|
|
1449
|
+
continue;
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
for (const [methodName, signature] of attachment.methodSignatures.entries()) {
|
|
1453
|
+
if (methodName === "constructor" || existingOnClass.has(methodName) || reservedMemberNames.has(methodName)) {
|
|
1454
|
+
continue;
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
const list = methodToAttachments.get(methodName) ?? [];
|
|
1458
|
+
list.push({
|
|
1459
|
+
propertyName: attachment.propertyName,
|
|
1460
|
+
params: signature.params,
|
|
1461
|
+
argNames: signature.argNames,
|
|
1462
|
+
});
|
|
1463
|
+
methodToAttachments.set(methodName, list);
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
const sorted = Array.from(methodToAttachments.entries()).sort((a, b) => a[0].localeCompare(b[0]));
|
|
1468
|
+
const lines: string[] = [];
|
|
1469
|
+
|
|
1470
|
+
for (const [methodName, candidates] of sorted) {
|
|
1471
|
+
if (candidates.length !== 1) {
|
|
1472
|
+
continue;
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
const { propertyName, params, argNames } = candidates[0];
|
|
1476
|
+
const callArgs = argNames.join(", ");
|
|
1477
|
+
const invocation = callArgs
|
|
1478
|
+
? `this.${propertyName}.${methodName}(${callArgs})`
|
|
1479
|
+
: `this.${propertyName}.${methodName}()`;
|
|
1480
|
+
|
|
1481
|
+
lines.push(
|
|
1482
|
+
"",
|
|
1483
|
+
` ${methodName}(${params}) {`,
|
|
1484
|
+
` return ${invocation};`,
|
|
1485
|
+
" }",
|
|
1486
|
+
);
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
if (!lines.length) {
|
|
1490
|
+
return "";
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
return [
|
|
1494
|
+
"",
|
|
1495
|
+
` // Passthrough methods composed from custom helper attachments of ${ownerName}.`,
|
|
1496
|
+
...lines,
|
|
1497
|
+
"",
|
|
1498
|
+
].join("\n");
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
function sliceNodeSource(source: string, node: { start?: number | null; end?: number | null }): string | null {
|
|
1502
|
+
if (node.start == null || node.end == null) {
|
|
1503
|
+
return null;
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
const snippet = source.slice(node.start, node.end).trim();
|
|
1507
|
+
return snippet.length ? snippet : null;
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
function getCustomPomCallArgumentName(param: ClassMethod["params"][number]): string | null {
|
|
1511
|
+
if (param.type === "Identifier") {
|
|
1512
|
+
return param.name;
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
if (param.type === "AssignmentPattern") {
|
|
1516
|
+
return param.left.type === "Identifier" ? param.left.name : null;
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
if (param.type === "RestElement") {
|
|
1520
|
+
return param.argument.type === "Identifier" ? `...${param.argument.name}` : null;
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
return null;
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
function extractCustomPomMethodSignatures(source: string, exportName: string): CustomPomMethodSignatureMap {
|
|
1527
|
+
const signatures: CustomPomMethodSignatureMap = new Map();
|
|
1528
|
+
|
|
1529
|
+
let ast: ReturnType<typeof parse>;
|
|
1530
|
+
try {
|
|
1531
|
+
ast = parse(source, {
|
|
1532
|
+
sourceType: "module",
|
|
1533
|
+
plugins: ["typescript", "jsx"],
|
|
1534
|
+
});
|
|
1535
|
+
}
|
|
1536
|
+
catch {
|
|
1537
|
+
return signatures;
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
for (const statement of ast.program.body) {
|
|
1541
|
+
if (statement.type !== "ExportNamedDeclaration" || !statement.declaration || statement.declaration.type !== "ClassDeclaration") {
|
|
1542
|
+
continue;
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
const declaration = statement.declaration;
|
|
1546
|
+
if (declaration.id?.name !== exportName) {
|
|
1547
|
+
continue;
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
for (const member of declaration.body.body) {
|
|
1551
|
+
if (member.type !== "ClassMethod" || member.kind !== "method" || member.static || member.computed) {
|
|
1552
|
+
continue;
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
if (member.accessibility === "private" || member.accessibility === "protected") {
|
|
1556
|
+
continue;
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
if (member.key.type !== "Identifier") {
|
|
1560
|
+
continue;
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
const params: string[] = [];
|
|
1564
|
+
const argNames: string[] = [];
|
|
1565
|
+
let supported = true;
|
|
1566
|
+
|
|
1567
|
+
member.params.forEach((param) => {
|
|
1568
|
+
if (!supported) {
|
|
1569
|
+
return;
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
const paramSource = sliceNodeSource(source, param);
|
|
1573
|
+
const argName = getCustomPomCallArgumentName(param);
|
|
1574
|
+
if (!paramSource || !argName) {
|
|
1575
|
+
supported = false;
|
|
1576
|
+
return;
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
params.push(paramSource);
|
|
1580
|
+
argNames.push(argName);
|
|
1581
|
+
});
|
|
1582
|
+
|
|
1583
|
+
if (!supported) {
|
|
1584
|
+
continue;
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
signatures.set(member.key.name, {
|
|
1588
|
+
params: params.join(", "),
|
|
1589
|
+
argNames,
|
|
1590
|
+
});
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
return signatures;
|
|
1595
|
+
}
|
|
1596
|
+
|
|
1409
1597
|
function ensureDir(dir: string) {
|
|
1410
1598
|
const normalized = dir.replace(/\\/g, "/");
|
|
1411
1599
|
if (!fs.existsSync(normalized)) {
|
|
@@ -1489,6 +1677,7 @@ async function generateAggregatedFiles(
|
|
|
1489
1677
|
]);
|
|
1490
1678
|
const usedImportIdentifiers = new Set<string>();
|
|
1491
1679
|
const customPomClassIdentifierMap: Record<string, string> = {};
|
|
1680
|
+
const customPomMethodSignaturesByClass = new Map<string, CustomPomMethodSignatureMap>();
|
|
1492
1681
|
|
|
1493
1682
|
const ensureUniqueIdentifier = (base: string) => {
|
|
1494
1683
|
let candidate = base;
|
|
@@ -1507,7 +1696,10 @@ async function generateAggregatedFiles(
|
|
|
1507
1696
|
: path.resolve(projectRoot, customDirRelOrAbs);
|
|
1508
1697
|
|
|
1509
1698
|
if (!fs.existsSync(customDirAbs)) {
|
|
1510
|
-
return
|
|
1699
|
+
return {
|
|
1700
|
+
classIdentifierMap: customPomClassIdentifierMap,
|
|
1701
|
+
methodSignaturesByClass: customPomMethodSignaturesByClass,
|
|
1702
|
+
};
|
|
1511
1703
|
}
|
|
1512
1704
|
|
|
1513
1705
|
const files = fs.readdirSync(customDirAbs)
|
|
@@ -1540,8 +1732,13 @@ async function generateAggregatedFiles(
|
|
|
1540
1732
|
localIdentifier = ensureUniqueIdentifier(requested);
|
|
1541
1733
|
}
|
|
1542
1734
|
|
|
1543
|
-
customPomClassIdentifierMap[exportName] = localIdentifier;
|
|
1544
1735
|
const customFileAbs = path.join(customDirAbs, file);
|
|
1736
|
+
customPomClassIdentifierMap[exportName] = localIdentifier;
|
|
1737
|
+
const customPomMethodSignatures = extractCustomPomMethodSignatures(fs.readFileSync(customFileAbs, "utf8"), exportName);
|
|
1738
|
+
if (customPomMethodSignatures.size > 0) {
|
|
1739
|
+
customPomMethodSignaturesByClass.set(exportName, customPomMethodSignatures);
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1545
1742
|
const fromOutputDir = outputDir;
|
|
1546
1743
|
const importPath = stripExtension(toPosixRelativePath(fromOutputDir, customFileAbs));
|
|
1547
1744
|
if (localIdentifier !== exportName) {
|
|
@@ -1552,11 +1749,16 @@ async function generateAggregatedFiles(
|
|
|
1552
1749
|
}
|
|
1553
1750
|
}
|
|
1554
1751
|
|
|
1555
|
-
return
|
|
1752
|
+
return {
|
|
1753
|
+
classIdentifierMap: customPomClassIdentifierMap,
|
|
1754
|
+
methodSignaturesByClass: customPomMethodSignaturesByClass,
|
|
1755
|
+
};
|
|
1556
1756
|
};
|
|
1557
1757
|
|
|
1558
|
-
const
|
|
1559
|
-
const
|
|
1758
|
+
const customPomImportResolution = addCustomPomImports();
|
|
1759
|
+
const customPomClassIdentifierMap = customPomImportResolution?.classIdentifierMap ?? {};
|
|
1760
|
+
const customPomMethodSignaturesByClass = customPomImportResolution?.methodSignaturesByClass ?? new Map<string, CustomPomMethodSignatureMap>();
|
|
1761
|
+
const customPomAvailableClassIdentifiers = new Set(Object.values(customPomClassIdentifierMap));
|
|
1560
1762
|
|
|
1561
1763
|
// Collect any navigation return types referenced by generated methods so we can emit
|
|
1562
1764
|
// stub classes when the destination view has no generated test ids (and therefore no
|
|
@@ -1759,6 +1961,7 @@ async function generateAggregatedFiles(
|
|
|
1759
1961
|
customPomAttachments: options.customPomAttachments ?? [],
|
|
1760
1962
|
customPomClassIdentifierMap,
|
|
1761
1963
|
customPomAvailableClassIdentifiers,
|
|
1964
|
+
customPomMethodSignaturesByClass,
|
|
1762
1965
|
testIdAttribute: options.testIdAttribute,
|
|
1763
1966
|
vueRouterFluentChaining: options.vueRouterFluentChaining,
|
|
1764
1967
|
routeMetaByComponent: options.routeMetaByComponent,
|
|
@@ -4,6 +4,13 @@ export { generateViewObjectModelMethodContent };
|
|
|
4
4
|
interface RouteMeta {
|
|
5
5
|
template: string;
|
|
6
6
|
}
|
|
7
|
+
interface CustomPomAttachment {
|
|
8
|
+
className: string;
|
|
9
|
+
propertyName: string;
|
|
10
|
+
attachWhenUsesComponents: string[];
|
|
11
|
+
attachTo?: "views" | "components" | "both";
|
|
12
|
+
flatten?: boolean;
|
|
13
|
+
}
|
|
7
14
|
export interface GenerateFilesOptions {
|
|
8
15
|
/**
|
|
9
16
|
* Output directory for generated files.
|
|
@@ -61,16 +68,7 @@ export interface GenerateFilesOptions {
|
|
|
61
68
|
* aggregated output (e.g. via `tests/playwright/pom/custom/*.ts` inlining), but we only attach them to
|
|
62
69
|
* view classes that actually use certain components.
|
|
63
70
|
*/
|
|
64
|
-
customPomAttachments?:
|
|
65
|
-
className: string;
|
|
66
|
-
propertyName: string;
|
|
67
|
-
attachWhenUsesComponents: string[];
|
|
68
|
-
/**
|
|
69
|
-
* Controls whether this attachment is applied to views, components, or both.
|
|
70
|
-
* Defaults to "views" for backwards compatibility.
|
|
71
|
-
*/
|
|
72
|
-
attachTo?: "views" | "components" | "both";
|
|
73
|
-
}>;
|
|
71
|
+
customPomAttachments?: CustomPomAttachment[];
|
|
74
72
|
/** Attribute name to treat as the test id. Defaults to `data-testid`. */
|
|
75
73
|
testIdAttribute?: string;
|
|
76
74
|
/** Which POM languages to emit. Defaults to ["ts"]. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../class-generation/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../class-generation/index.ts"],"names":[],"mappings":"AAMA,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;AASD,UAAU,mBAAmB;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,wBAAwB,EAAE,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,EAAE,OAAO,GAAG,YAAY,GAAG,MAAM,CAAC;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AA8PD,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;;;;;;;;;;;;OAeG;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,mBAAmB,EAAE,CAAC;IAE7C,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,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IAEpB,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CAClD;AA+BD,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,iBAmFnC"}
|