@immense/vue-pom-generator 1.0.66 → 1.0.68
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/AGENTS.md +21 -0
- package/README.md +1 -0
- package/RELEASE_NOTES.md +16 -9
- package/class-generation/index.ts +16 -5
- package/dist/class-generation/index.d.ts.map +1 -1
- package/dist/compiler-metadata-utils.d.ts.map +1 -1
- package/dist/index.cjs +309 -97
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +309 -97
- package/dist/index.mjs.map +1 -1
- package/dist/manifest-generator.d.ts +2 -0
- package/dist/manifest-generator.d.ts.map +1 -1
- package/dist/metadata-collector.d.ts +2 -0
- package/dist/metadata-collector.d.ts.map +1 -1
- package/dist/plugin/create-vue-pom-generator-plugins.d.ts.map +1 -1
- package/dist/plugin/internal/build-plugin.d.ts.map +1 -0
- package/dist/plugin/internal/dev-plugin.d.ts.map +1 -0
- package/dist/plugin/internal/virtual-modules.d.ts.map +1 -0
- package/dist/plugin/{support-plugins.d.ts → internal-plugins.d.ts} +14 -3
- package/dist/plugin/internal-plugins.d.ts.map +1 -0
- package/dist/plugin/path-utils.d.ts +12 -0
- package/dist/plugin/path-utils.d.ts.map +1 -1
- package/dist/plugin/runtime/annotator/client.d.ts +67 -0
- package/dist/plugin/runtime/annotator/client.d.ts.map +1 -0
- package/dist/plugin/runtime/annotator/format.d.ts +13 -0
- package/dist/plugin/runtime/annotator/format.d.ts.map +1 -0
- package/dist/plugin/runtime/annotator/plugin.d.ts +12 -0
- package/dist/plugin/runtime/annotator/plugin.d.ts.map +1 -0
- package/dist/plugin/runtime/annotator/styles.d.ts +3 -0
- package/dist/plugin/runtime/annotator/styles.d.ts.map +1 -0
- package/dist/plugin/runtime/annotator/vue-detector.d.ts +12 -0
- package/dist/plugin/runtime/annotator/vue-detector.d.ts.map +1 -0
- package/dist/plugin/types.d.ts +58 -3
- package/dist/plugin/types.d.ts.map +1 -1
- package/dist/plugin/vue-plugin.d.ts +4 -0
- package/dist/plugin/vue-plugin.d.ts.map +1 -1
- package/dist/tests/path-utils-scope.test.d.ts +2 -0
- package/dist/tests/path-utils-scope.test.d.ts.map +1 -0
- package/dist/transform.d.ts +4 -0
- package/dist/transform.d.ts.map +1 -1
- package/dist/utils.d.ts +19 -0
- package/dist/utils.d.ts.map +1 -1
- package/package.json +3 -1
- package/plugin/runtime/annotator/client.ts +1005 -0
- package/plugin/runtime/annotator/format.ts +76 -0
- package/plugin/runtime/annotator/plugin.ts +109 -0
- package/plugin/runtime/annotator/styles.ts +379 -0
- package/plugin/runtime/annotator/vue-detector.ts +216 -0
- package/dist/plugin/support/build-plugin.d.ts.map +0 -1
- package/dist/plugin/support/dev-plugin.d.ts.map +0 -1
- package/dist/plugin/support/virtual-modules.d.ts.map +0 -1
- package/dist/plugin/support-plugins.d.ts.map +0 -1
- /package/dist/plugin/{support → internal}/build-plugin.d.ts +0 -0
- /package/dist/plugin/{support → internal}/dev-plugin.d.ts +0 -0
- /package/dist/plugin/{support → internal}/virtual-modules.d.ts +0 -0
package/dist/index.mjs
CHANGED
|
@@ -645,7 +645,7 @@ function createInlineParameter(name, options = {}) {
|
|
|
645
645
|
initializer: options.initializer
|
|
646
646
|
};
|
|
647
647
|
}
|
|
648
|
-
function removeByKeySegment
|
|
648
|
+
function removeByKeySegment(value) {
|
|
649
649
|
const idx = value.lastIndexOf("ByKey");
|
|
650
650
|
if (idx < 0) {
|
|
651
651
|
return value;
|
|
@@ -849,13 +849,13 @@ function generateGetElementByDataTestId(componentName, methodName, nativeRole, s
|
|
|
849
849
|
const roleSuffix = upperFirst$1(nativeRole || "Element");
|
|
850
850
|
const baseName = upperFirst$1(methodName);
|
|
851
851
|
const numericSuffix = baseName.startsWith(roleSuffix) ? baseName.slice(roleSuffix.length) : "";
|
|
852
|
-
const
|
|
853
|
-
const propertyName =
|
|
852
|
+
const hasRoleSuffix = baseName.endsWith(roleSuffix) || baseName.startsWith(roleSuffix) && isAllDigits(numericSuffix);
|
|
853
|
+
const propertyName = hasRoleSuffix ? `${baseName}` : `${baseName}${roleSuffix}`;
|
|
854
854
|
const selectorParams = orderPomPatternParameters(parameters, [selector]);
|
|
855
855
|
const indexedVariable = getIndexedPomPatternVariable(selector);
|
|
856
856
|
if (indexedVariable) {
|
|
857
857
|
const keyType = getPomParameter(selectorParams, indexedVariable)?.typeExpression || "string";
|
|
858
|
-
const keyedPropertyName = getterNameOverride ?? removeByKeySegment
|
|
858
|
+
const keyedPropertyName = getterNameOverride ?? removeByKeySegment(propertyName);
|
|
859
859
|
return [
|
|
860
860
|
createClassGetter({
|
|
861
861
|
name: keyedPropertyName,
|
|
@@ -2894,7 +2894,7 @@ Fix: either (1) include ${bestKeyPreservePlaceholder} in your :${attrLabel} temp
|
|
|
2894
2894
|
}
|
|
2895
2895
|
return value.slice(0, idx) + value.slice(idx + "ByKey".length);
|
|
2896
2896
|
};
|
|
2897
|
-
const
|
|
2897
|
+
const hasRoleSuffix = (baseName, roleSuffix) => {
|
|
2898
2898
|
if (baseName.endsWith(roleSuffix)) {
|
|
2899
2899
|
return true;
|
|
2900
2900
|
}
|
|
@@ -2904,13 +2904,13 @@ Fix: either (1) include ${bestKeyPreservePlaceholder} in your :${attrLabel} temp
|
|
|
2904
2904
|
const getPrimaryGetterName = (primaryMethodName) => {
|
|
2905
2905
|
const roleSuffix = upperFirst(normalizedRole || "Element");
|
|
2906
2906
|
const baseName = upperFirst(primaryMethodName);
|
|
2907
|
-
const propertyName =
|
|
2907
|
+
const propertyName = hasRoleSuffix(baseName, roleSuffix) ? baseName : `${baseName}${roleSuffix}`;
|
|
2908
2908
|
return selectorIsParameterized ? removeByKeySegment2(propertyName) : propertyName;
|
|
2909
2909
|
};
|
|
2910
2910
|
const getPrimaryGetterNameCandidates = (primaryMethodName) => {
|
|
2911
2911
|
const roleSuffix = upperFirst(normalizedRole || "Element");
|
|
2912
2912
|
const baseName = upperFirst(primaryMethodName);
|
|
2913
|
-
const propertyName =
|
|
2913
|
+
const propertyName = hasRoleSuffix(baseName, roleSuffix) ? baseName : `${baseName}${roleSuffix}`;
|
|
2914
2914
|
if (!selectorIsParameterized) {
|
|
2915
2915
|
return { primary: propertyName };
|
|
2916
2916
|
}
|
|
@@ -3037,7 +3037,7 @@ Fix: either (1) include ${bestKeyPreservePlaceholder} in your :${attrLabel} temp
|
|
|
3037
3037
|
if (conflicts && nameCollisionBehavior === "error") {
|
|
3038
3038
|
const roleSuffix = upperFirst(normalizedRole || "Element");
|
|
3039
3039
|
const baseNameUpper = upperFirst(baseWithSuffix);
|
|
3040
|
-
if (!
|
|
3040
|
+
if (!hasRoleSuffix(baseNameUpper, roleSuffix)) {
|
|
3041
3041
|
const baseWithRoleSuffix = `${baseWithSuffix}${roleSuffix}`;
|
|
3042
3042
|
const candidateWithRoleSuffix = selectorIsParameterized ? `${baseWithRoleSuffix}ByKey` : baseWithRoleSuffix;
|
|
3043
3043
|
const actionNameWithRoleSuffix = getPrimaryActionMethodName(candidateWithRoleSuffix);
|
|
@@ -3147,12 +3147,32 @@ Fix: make the element identifiable (e.g. add id/name/inner text or use a more sp
|
|
|
3147
3147
|
alternateSelectors: void 0,
|
|
3148
3148
|
mergeKey: args.pomMergeKey,
|
|
3149
3149
|
parameters: normalizedParameters,
|
|
3150
|
-
keyValuesOverride: args.keyValuesOverride ?? null
|
|
3150
|
+
keyValuesOverride: args.keyValuesOverride ?? null,
|
|
3151
|
+
generatedActionName: getPrimaryActionMethodName(methodName),
|
|
3152
|
+
generatedPropertyName: getterNameOverride ?? getPrimaryGetterName(methodName)
|
|
3151
3153
|
// emitPrimary defaults to true; special cases (including merge) may set it to false below.
|
|
3152
3154
|
};
|
|
3153
3155
|
if (mergedIntoExisting && dataTestIdEntry.pom) {
|
|
3154
3156
|
dataTestIdEntry.pom.emitPrimary = false;
|
|
3155
3157
|
}
|
|
3158
|
+
if (addHtmlAttribute && args.annotatorMetadata && dataTestIdEntry.pom) {
|
|
3159
|
+
const filename = args.contextFilename?.trim();
|
|
3160
|
+
if (!filename) {
|
|
3161
|
+
throw new Error(`[vue-pom-generator] runtime.annotator.enabled requires contextFilename for ${args.componentName}.`);
|
|
3162
|
+
}
|
|
3163
|
+
const sourceLocation = args.element.loc?.start;
|
|
3164
|
+
if (!sourceLocation) {
|
|
3165
|
+
throw new Error(`[vue-pom-generator] runtime.annotator.enabled requires element source locations for ${args.componentName}.`);
|
|
3166
|
+
}
|
|
3167
|
+
const metadataAttributePrefix = args.annotatorMetadata.metadataAttributePrefix;
|
|
3168
|
+
upsertAttribute(args.element, args.annotatorMetadata.sourceAttribute, staticAttributeValue(`${filename}:${sourceLocation.line}:${sourceLocation.column}`));
|
|
3169
|
+
upsertAttribute(args.element, `${metadataAttributePrefix}-component`, staticAttributeValue(args.componentName));
|
|
3170
|
+
upsertAttribute(args.element, `${metadataAttributePrefix}-tag`, staticAttributeValue(args.element.tag));
|
|
3171
|
+
upsertAttribute(args.element, `${metadataAttributePrefix}-testid`, runtimeDataTestId);
|
|
3172
|
+
upsertAttribute(args.element, `${metadataAttributePrefix}-action`, staticAttributeValue(buildPomGeneratedActionName(dataTestIdEntry.pom)));
|
|
3173
|
+
upsertAttribute(args.element, `${metadataAttributePrefix}-property`, staticAttributeValue(buildPomGeneratedPropertyName(dataTestIdEntry.pom)));
|
|
3174
|
+
upsertAttribute(args.element, `${metadataAttributePrefix}-role`, staticAttributeValue(normalizedRole));
|
|
3175
|
+
}
|
|
3156
3176
|
args.dependencies.childrenComponentSet.add(childComponentName);
|
|
3157
3177
|
args.dependencies.usedComponentSet.add(childComponentName);
|
|
3158
3178
|
args.dependencies.dataTestIdSet.add(dataTestIdEntry);
|
|
@@ -3351,7 +3371,7 @@ Fix: make the element identifiable (e.g. add id/name/inner text or use a more sp
|
|
|
3351
3371
|
registerGeneratedMethodSignature(generatedName2, createPomMethodSignature([createPomParameterSpec("annotationText", `string = ""`)]));
|
|
3352
3372
|
}
|
|
3353
3373
|
}
|
|
3354
|
-
return { selectorValue: dataTestId, runtimeValue: runtimeDataTestId, fromExisting };
|
|
3374
|
+
return { selectorValue: dataTestId, runtimeValue: runtimeDataTestId, fromExisting, entry: dataTestIdEntry };
|
|
3355
3375
|
}
|
|
3356
3376
|
const generatedName = ensureUniqueGeneratedName(`select${upperFirst(methodName || "Radio")}`);
|
|
3357
3377
|
if (dataTestIdEntry.pom) {
|
|
@@ -3378,7 +3398,7 @@ Fix: make the element identifiable (e.g. add id/name/inner text or use a more sp
|
|
|
3378
3398
|
createPomParameterSpec("annotationText", `string = ""`)
|
|
3379
3399
|
]));
|
|
3380
3400
|
}
|
|
3381
|
-
return { selectorValue: dataTestId, runtimeValue: runtimeDataTestId, fromExisting };
|
|
3401
|
+
return { selectorValue: dataTestId, runtimeValue: runtimeDataTestId, fromExisting, entry: dataTestIdEntry };
|
|
3382
3402
|
}
|
|
3383
3403
|
const staticKeyValues = args.keyValuesOverride ?? null;
|
|
3384
3404
|
const needsKey = hasPomParameter(normalizedParameters, "key") && selectorIsParameterized;
|
|
@@ -3412,7 +3432,7 @@ Fix: make the element identifiable (e.g. add id/name/inner text or use a more sp
|
|
|
3412
3432
|
]));
|
|
3413
3433
|
}
|
|
3414
3434
|
}
|
|
3415
|
-
return { selectorValue: dataTestId, runtimeValue: runtimeDataTestId, fromExisting };
|
|
3435
|
+
return { selectorValue: dataTestId, runtimeValue: runtimeDataTestId, fromExisting, entry: dataTestIdEntry };
|
|
3416
3436
|
}
|
|
3417
3437
|
if (dataTestIdEntry.pom) {
|
|
3418
3438
|
if (dataTestIdEntry.pom.emitPrimary !== false) {
|
|
@@ -3426,7 +3446,66 @@ Fix: make the element identifiable (e.g. add id/name/inner text or use a more sp
|
|
|
3426
3446
|
const generatedName = getGeneratedMethodName();
|
|
3427
3447
|
registerGeneratedMethodSignature(generatedName, signature);
|
|
3428
3448
|
}
|
|
3429
|
-
return { selectorValue: dataTestId, runtimeValue: runtimeDataTestId, fromExisting };
|
|
3449
|
+
return { selectorValue: dataTestId, runtimeValue: runtimeDataTestId, fromExisting, entry: dataTestIdEntry };
|
|
3450
|
+
}
|
|
3451
|
+
function requireStructuredPomName(value, fieldName, pom) {
|
|
3452
|
+
const normalized = value?.trim();
|
|
3453
|
+
if (normalized) {
|
|
3454
|
+
return normalized;
|
|
3455
|
+
}
|
|
3456
|
+
throw new Error(`[vue-pom-generator] Missing ${fieldName} for POM spec ${pom.methodName}.`);
|
|
3457
|
+
}
|
|
3458
|
+
function buildPomGeneratedPropertyName(pom) {
|
|
3459
|
+
return requireStructuredPomName(pom.generatedPropertyName, "generatedPropertyName", pom);
|
|
3460
|
+
}
|
|
3461
|
+
function buildPomGeneratedActionName(pom) {
|
|
3462
|
+
return requireStructuredPomName(pom.generatedActionName, "generatedActionName", pom);
|
|
3463
|
+
}
|
|
3464
|
+
const STANDALONE_WRAPPER_FALLBACK_ROLES = /* @__PURE__ */ new Set([
|
|
3465
|
+
"button",
|
|
3466
|
+
"input",
|
|
3467
|
+
"select",
|
|
3468
|
+
"vselect",
|
|
3469
|
+
"checkbox",
|
|
3470
|
+
"toggle",
|
|
3471
|
+
"radio"
|
|
3472
|
+
]);
|
|
3473
|
+
function stripTrailingAsciiDigits(value) {
|
|
3474
|
+
let end = value.length;
|
|
3475
|
+
while (end > 0 && isAsciiDigitCode(value.charCodeAt(end - 1))) {
|
|
3476
|
+
end -= 1;
|
|
3477
|
+
}
|
|
3478
|
+
return value.slice(0, end);
|
|
3479
|
+
}
|
|
3480
|
+
function matchesStandaloneWrapperFallbackMethodName(methodName, componentClassName) {
|
|
3481
|
+
let normalizedMethodName = methodName;
|
|
3482
|
+
if (normalizedMethodName.endsWith("ByKey")) {
|
|
3483
|
+
normalizedMethodName = normalizedMethodName.slice(0, -"ByKey".length);
|
|
3484
|
+
}
|
|
3485
|
+
normalizedMethodName = stripTrailingAsciiDigits(normalizedMethodName);
|
|
3486
|
+
return normalizedMethodName === componentClassName;
|
|
3487
|
+
}
|
|
3488
|
+
function shouldSuppressStandaloneWrapperFallbackSurface(componentName, dependencies) {
|
|
3489
|
+
if (dependencies.isView || (dependencies.pomExtraMethods?.length ?? 0) > 0) {
|
|
3490
|
+
return false;
|
|
3491
|
+
}
|
|
3492
|
+
const entries = Array.from(dependencies.dataTestIdSet ?? []);
|
|
3493
|
+
if (!entries.length) {
|
|
3494
|
+
return false;
|
|
3495
|
+
}
|
|
3496
|
+
const primaryEntries = entries.filter((entry) => {
|
|
3497
|
+
return !!entry.pom && entry.pom.emitPrimary !== false;
|
|
3498
|
+
});
|
|
3499
|
+
if (!primaryEntries.length || primaryEntries.length !== entries.length) {
|
|
3500
|
+
return false;
|
|
3501
|
+
}
|
|
3502
|
+
const componentClassName = toPascalCase(componentName.endsWith(".vue") ? componentName.slice(0, -4) : componentName);
|
|
3503
|
+
if (!componentClassName) {
|
|
3504
|
+
return false;
|
|
3505
|
+
}
|
|
3506
|
+
return primaryEntries.every(({ pom }) => {
|
|
3507
|
+
return STANDALONE_WRAPPER_FALLBACK_ROLES.has(pom.nativeRole) && matchesStandaloneWrapperFallbackMethodName(pom.methodName, componentClassName);
|
|
3508
|
+
});
|
|
3430
3509
|
}
|
|
3431
3510
|
function safeRealpath(value) {
|
|
3432
3511
|
try {
|
|
@@ -3443,6 +3522,14 @@ function safeRealpath(value) {
|
|
|
3443
3522
|
const resolvedParent = safeRealpath(parent);
|
|
3444
3523
|
return resolvedParent === parent ? value : path.join(resolvedParent, path.basename(value));
|
|
3445
3524
|
}
|
|
3525
|
+
function normalizeScopePath(value, pathImpl = path) {
|
|
3526
|
+
return pathImpl.normalize(value);
|
|
3527
|
+
}
|
|
3528
|
+
function isNormalizedPathWithinDir(filePathAbs, dirPathAbs, pathImpl = path) {
|
|
3529
|
+
const normalizedFileAbs = normalizeScopePath(filePathAbs, pathImpl);
|
|
3530
|
+
const normalizedDirAbs = normalizeScopePath(dirPathAbs, pathImpl);
|
|
3531
|
+
return normalizedFileAbs === normalizedDirAbs || normalizedFileAbs.startsWith(`${normalizedDirAbs}${pathImpl.sep}`);
|
|
3532
|
+
}
|
|
3446
3533
|
function isPathWithinDir(filePathAbs, dirPathAbs) {
|
|
3447
3534
|
const fileAbs = path.resolve(filePathAbs);
|
|
3448
3535
|
const dirAbs = path.resolve(dirPathAbs);
|
|
@@ -3472,6 +3559,43 @@ function resolveComponentNameFromPath(options) {
|
|
|
3472
3559
|
}
|
|
3473
3560
|
return toPascalCase(path.parse(normalizedAbsFilename).name);
|
|
3474
3561
|
}
|
|
3562
|
+
function isFileInConfiguredSourceScope(options) {
|
|
3563
|
+
const { filename, projectRoot, viewsDirAbs, sourceDirs, extraRoots = [], pathImpl = path } = options;
|
|
3564
|
+
if (!filename) {
|
|
3565
|
+
return false;
|
|
3566
|
+
}
|
|
3567
|
+
const cleanFilename = filename.includes("?") ? filename.substring(0, filename.indexOf("?")) : filename;
|
|
3568
|
+
const normalizedProjectRoot = normalizeScopePath(projectRoot, pathImpl);
|
|
3569
|
+
const normalizedAbsFilename = normalizeScopePath(
|
|
3570
|
+
pathImpl.isAbsolute(cleanFilename) ? cleanFilename : pathImpl.resolve(normalizedProjectRoot, cleanFilename),
|
|
3571
|
+
pathImpl
|
|
3572
|
+
);
|
|
3573
|
+
if (normalizedAbsFilename.includes(`${pathImpl.sep}node_modules${pathImpl.sep}`) || normalizedAbsFilename.includes("/node_modules/")) {
|
|
3574
|
+
return false;
|
|
3575
|
+
}
|
|
3576
|
+
const normalizedViewsDirAbs = normalizeScopePath(viewsDirAbs, pathImpl);
|
|
3577
|
+
if (isNormalizedPathWithinDir(normalizedAbsFilename, normalizedViewsDirAbs, pathImpl)) {
|
|
3578
|
+
return true;
|
|
3579
|
+
}
|
|
3580
|
+
const rootsToTry = Array.from(/* @__PURE__ */ new Set([
|
|
3581
|
+
normalizedProjectRoot,
|
|
3582
|
+
...extraRoots.map((root) => normalizeScopePath(root, pathImpl))
|
|
3583
|
+
]));
|
|
3584
|
+
return sourceDirs.some((dir) => {
|
|
3585
|
+
return rootsToTry.some((root) => {
|
|
3586
|
+
const normalizedAbsDir = normalizeScopePath(pathImpl.resolve(root, dir), pathImpl);
|
|
3587
|
+
if (isNormalizedPathWithinDir(normalizedAbsFilename, normalizedAbsDir, pathImpl)) {
|
|
3588
|
+
return true;
|
|
3589
|
+
}
|
|
3590
|
+
if (dir.startsWith("app/") && pathImpl.basename(root) === "app") {
|
|
3591
|
+
const relativeDir = dir.substring(4);
|
|
3592
|
+
const normalizedAbsDirAlt = normalizeScopePath(pathImpl.resolve(root, relativeDir), pathImpl);
|
|
3593
|
+
return isNormalizedPathWithinDir(normalizedAbsFilename, normalizedAbsDirAlt, pathImpl);
|
|
3594
|
+
}
|
|
3595
|
+
return false;
|
|
3596
|
+
});
|
|
3597
|
+
});
|
|
3598
|
+
}
|
|
3475
3599
|
let routerIntrospectionQueue = Promise.resolve();
|
|
3476
3600
|
async function runRouterIntrospectionExclusive(fn) {
|
|
3477
3601
|
const prev = routerIntrospectionQueue.catch(() => void 0);
|
|
@@ -4726,6 +4850,11 @@ async function generateFiles(componentHierarchyMap, vueFilesPathMap, basePageCla
|
|
|
4726
4850
|
componentDirs,
|
|
4727
4851
|
layoutDirs
|
|
4728
4852
|
}) : void 0);
|
|
4853
|
+
const emittableComponentHierarchyMap = new Map(
|
|
4854
|
+
Array.from(componentHierarchyMap.entries()).filter(([componentName, dependencies]) => {
|
|
4855
|
+
return !shouldSuppressStandaloneWrapperFallbackSurface(componentName, dependencies);
|
|
4856
|
+
})
|
|
4857
|
+
);
|
|
4729
4858
|
const generatedFilePaths = [];
|
|
4730
4859
|
const writeGeneratedFile = (file) => {
|
|
4731
4860
|
const resolvedFilePath = path.resolve(file.filePath);
|
|
@@ -4733,7 +4862,7 @@ async function generateFiles(componentHierarchyMap, vueFilesPathMap, basePageCla
|
|
|
4733
4862
|
generatedFilePaths.push(resolvedFilePath);
|
|
4734
4863
|
};
|
|
4735
4864
|
if (emitLanguages.includes("ts")) {
|
|
4736
|
-
const files = typescriptOutputStructure === "split" ? await generateSplitTypeScriptFiles(
|
|
4865
|
+
const files = typescriptOutputStructure === "split" ? await generateSplitTypeScriptFiles(emittableComponentHierarchyMap, vueFilesPathMap, basePageClassPath, outDir, {
|
|
4737
4866
|
customPomAttachments,
|
|
4738
4867
|
projectRoot,
|
|
4739
4868
|
customPomDir,
|
|
@@ -4743,7 +4872,7 @@ async function generateFiles(componentHierarchyMap, vueFilesPathMap, basePageCla
|
|
|
4743
4872
|
testIdAttribute,
|
|
4744
4873
|
routeMetaByComponent,
|
|
4745
4874
|
vueRouterFluentChaining
|
|
4746
|
-
}) : await generateAggregatedFiles(
|
|
4875
|
+
}) : await generateAggregatedFiles(emittableComponentHierarchyMap, vueFilesPathMap, basePageClassPath, outDir, {
|
|
4747
4876
|
customPomAttachments,
|
|
4748
4877
|
projectRoot,
|
|
4749
4878
|
customPomDir,
|
|
@@ -4757,7 +4886,7 @@ async function generateFiles(componentHierarchyMap, vueFilesPathMap, basePageCla
|
|
|
4757
4886
|
for (const file of files) {
|
|
4758
4887
|
writeGeneratedFile(file);
|
|
4759
4888
|
}
|
|
4760
|
-
const fixtureRegistryFile = maybeGenerateFixtureRegistry(
|
|
4889
|
+
const fixtureRegistryFile = maybeGenerateFixtureRegistry(emittableComponentHierarchyMap, {
|
|
4761
4890
|
generateFixtures,
|
|
4762
4891
|
pomOutDir: outDir,
|
|
4763
4892
|
projectRoot,
|
|
@@ -4768,7 +4897,7 @@ async function generateFiles(componentHierarchyMap, vueFilesPathMap, basePageCla
|
|
|
4768
4897
|
}
|
|
4769
4898
|
}
|
|
4770
4899
|
if (emitLanguages.includes("csharp")) {
|
|
4771
|
-
const csFiles = generateAggregatedCSharpFiles(
|
|
4900
|
+
const csFiles = generateAggregatedCSharpFiles(emittableComponentHierarchyMap, outDir, {
|
|
4772
4901
|
testIdAttribute,
|
|
4773
4902
|
csharp
|
|
4774
4903
|
});
|
|
@@ -5505,7 +5634,12 @@ function prepareViewObjectModelClass(componentName, dependencies, componentHiera
|
|
|
5505
5634
|
const rawComponentRefsForInstances = isView ? usedComponentSet?.size ? usedComponentSet : childrenComponentSet : childrenComponentSet;
|
|
5506
5635
|
const componentRefsForInstances = /* @__PURE__ */ new Set();
|
|
5507
5636
|
for (const ref of rawComponentRefsForInstances) {
|
|
5508
|
-
|
|
5637
|
+
const resolvedRef = resolveTrackedComponentRef(ref) ?? normalizeTrackedComponentRef(ref);
|
|
5638
|
+
const resolvedDependencies = componentHierarchyMap.get(resolvedRef);
|
|
5639
|
+
if (!resolvedDependencies?.dataTestIdSet.size) {
|
|
5640
|
+
continue;
|
|
5641
|
+
}
|
|
5642
|
+
componentRefsForInstances.add(resolvedRef);
|
|
5509
5643
|
}
|
|
5510
5644
|
const hasChildComponent = (needle) => {
|
|
5511
5645
|
const normalizedNeedle = normalizeTrackedComponentRef(needle);
|
|
@@ -7064,6 +7198,7 @@ function createTestIdTransform(componentName, componentHierarchyMap, nativeWrapp
|
|
|
7064
7198
|
const warn = options.warn;
|
|
7065
7199
|
const vueFilesPathMap = options.vueFilesPathMap;
|
|
7066
7200
|
const wrapperSearchRoots = options.wrapperSearchRoots ?? [];
|
|
7201
|
+
const annotatorMetadata = options.annotatorMetadata ?? null;
|
|
7067
7202
|
const safeRealpath2 = (p) => {
|
|
7068
7203
|
try {
|
|
7069
7204
|
return fs.existsSync(p) ? fs.realpathSync(p) : p;
|
|
@@ -7327,7 +7462,8 @@ function createTestIdTransform(componentName, componentHierarchyMap, nativeWrapp
|
|
|
7327
7462
|
testIdAttribute,
|
|
7328
7463
|
existingIdBehavior,
|
|
7329
7464
|
nameCollisionBehavior,
|
|
7330
|
-
warn
|
|
7465
|
+
warn,
|
|
7466
|
+
annotatorMetadata
|
|
7331
7467
|
});
|
|
7332
7468
|
};
|
|
7333
7469
|
const { nativeWrappersValue, optionDataTestIdPrefixValue, semanticNameHint } = getNativeWrapperTransformInfo(element, componentName, nativeWrappers);
|
|
@@ -8318,48 +8454,6 @@ function collectAccessibilityReviewWarnings(manifest) {
|
|
|
8318
8454
|
}
|
|
8319
8455
|
return warnings;
|
|
8320
8456
|
}
|
|
8321
|
-
function removeByKeySegment(value) {
|
|
8322
|
-
const idx = value.indexOf("ByKey");
|
|
8323
|
-
if (idx < 0) {
|
|
8324
|
-
return value;
|
|
8325
|
-
}
|
|
8326
|
-
return value.slice(0, idx) + value.slice(idx + "ByKey".length);
|
|
8327
|
-
}
|
|
8328
|
-
function hasRoleSuffix(baseName, roleSuffix) {
|
|
8329
|
-
if (baseName.endsWith(roleSuffix)) {
|
|
8330
|
-
return true;
|
|
8331
|
-
}
|
|
8332
|
-
const re = new RegExp(`^${roleSuffix}\\d+$`);
|
|
8333
|
-
return re.test(baseName);
|
|
8334
|
-
}
|
|
8335
|
-
function getGeneratedPropertyName(pom) {
|
|
8336
|
-
if (pom.getterNameOverride) {
|
|
8337
|
-
return pom.getterNameOverride;
|
|
8338
|
-
}
|
|
8339
|
-
const roleSuffix = upperFirst(pom.nativeRole || "Element");
|
|
8340
|
-
const baseName = upperFirst(pom.methodName);
|
|
8341
|
-
const propertyName = hasRoleSuffix(baseName, roleSuffix) ? baseName : `${baseName}${roleSuffix}`;
|
|
8342
|
-
return pom.selector.patternKind === "parameterized" ? removeByKeySegment(propertyName) : propertyName;
|
|
8343
|
-
}
|
|
8344
|
-
function getGeneratedActionName(entry, pom) {
|
|
8345
|
-
const methodNameUpper = upperFirst(pom.methodName);
|
|
8346
|
-
const radioMethodNameUpper = upperFirst(pom.methodName || "Radio");
|
|
8347
|
-
const isNavigation = !!entry.targetPageObjectModelClass;
|
|
8348
|
-
if (isNavigation) {
|
|
8349
|
-
return `goTo${methodNameUpper}`;
|
|
8350
|
-
}
|
|
8351
|
-
switch (pom.nativeRole) {
|
|
8352
|
-
case "input":
|
|
8353
|
-
return `type${methodNameUpper}`;
|
|
8354
|
-
case "select":
|
|
8355
|
-
case "vselect":
|
|
8356
|
-
return `select${methodNameUpper}`;
|
|
8357
|
-
case "radio":
|
|
8358
|
-
return `select${radioMethodNameUpper}`;
|
|
8359
|
-
default:
|
|
8360
|
-
return `click${methodNameUpper}`;
|
|
8361
|
-
}
|
|
8362
|
-
}
|
|
8363
8457
|
function matchesPrimarySelector(extraMethod, pom) {
|
|
8364
8458
|
if (extraMethod.selector.kind !== "testId") {
|
|
8365
8459
|
return false;
|
|
@@ -8370,7 +8464,7 @@ function getManifestEntry(componentName, entry, componentMetadata, extraMethods)
|
|
|
8370
8464
|
const testId = entry.selectorValue.formatted;
|
|
8371
8465
|
const metadata = componentMetadata?.get(testId);
|
|
8372
8466
|
const pom = entry.pom;
|
|
8373
|
-
const generatedActionName = pom ?
|
|
8467
|
+
const generatedActionName = pom ? buildPomGeneratedActionName(pom) : null;
|
|
8374
8468
|
const extraActionNames = pom ? extraMethods.filter((extraMethod) => matchesPrimarySelector(extraMethod, pom)).map((extraMethod) => extraMethod.name).sort((a, b) => a.localeCompare(b)) : [];
|
|
8375
8469
|
const generatedActionNames = Array.from(/* @__PURE__ */ new Set([
|
|
8376
8470
|
...generatedActionName ? [generatedActionName] : [],
|
|
@@ -8388,13 +8482,15 @@ function getManifestEntry(componentName, entry, componentMetadata, extraMethods)
|
|
|
8388
8482
|
}) : componentName,
|
|
8389
8483
|
inferredRole: pom?.nativeRole ?? null,
|
|
8390
8484
|
...accessibility ? { accessibility } : {},
|
|
8391
|
-
generatedPropertyName: pom ?
|
|
8485
|
+
generatedPropertyName: pom ? buildPomGeneratedPropertyName(pom) : null,
|
|
8392
8486
|
generatedActionName,
|
|
8393
8487
|
generatedActionNames,
|
|
8394
8488
|
emitPrimary: pom?.emitPrimary !== false,
|
|
8395
8489
|
...entry.targetPageObjectModelClass ? { targetPageObjectModelClass: entry.targetPageObjectModelClass } : {},
|
|
8396
8490
|
...metadata?.tag ? { sourceTag: metadata.tag } : {},
|
|
8397
8491
|
...metadata ? { sourceTagType: metadata.tagType } : {},
|
|
8492
|
+
...metadata?.sourceLine !== void 0 ? { sourceLine: metadata.sourceLine } : {},
|
|
8493
|
+
...metadata?.sourceColumn !== void 0 ? { sourceColumn: metadata.sourceColumn } : {},
|
|
8398
8494
|
...metadata?.patchFlag !== void 0 ? { patchFlag: metadata.patchFlag } : {},
|
|
8399
8495
|
...metadata?.dynamicProps?.length ? { dynamicProps: metadata.dynamicProps } : {},
|
|
8400
8496
|
...metadata?.hasClickHandler !== void 0 ? { hasClickHandler: metadata.hasClickHandler } : {},
|
|
@@ -8404,7 +8500,7 @@ function getManifestEntry(componentName, entry, componentMetadata, extraMethods)
|
|
|
8404
8500
|
};
|
|
8405
8501
|
}
|
|
8406
8502
|
function buildPomManifest(componentHierarchyMap, elementMetadata) {
|
|
8407
|
-
const manifestEntries = Array.from(componentHierarchyMap.entries()).sort((a, b) => a[0].localeCompare(b[0])).map(([componentName, dependencies]) => {
|
|
8503
|
+
const manifestEntries = Array.from(componentHierarchyMap.entries()).filter(([componentName, dependencies]) => !shouldSuppressStandaloneWrapperFallbackSurface(componentName, dependencies)).sort((a, b) => a[0].localeCompare(b[0])).map(([componentName, dependencies]) => {
|
|
8408
8504
|
const entries = Array.from(dependencies.dataTestIdSet).sort((a, b) => a.selectorValue.formatted.localeCompare(b.selectorValue.formatted)).map((entry) => getManifestEntry(componentName, entry, elementMetadata.get(componentName), dependencies.pomExtraMethods ?? []));
|
|
8409
8505
|
if (!entries.length) {
|
|
8410
8506
|
return null;
|
|
@@ -8420,9 +8516,15 @@ function buildPomManifest(componentHierarchyMap, elementMetadata) {
|
|
|
8420
8516
|
}).filter((entry) => entry !== null);
|
|
8421
8517
|
return Object.fromEntries(manifestEntries);
|
|
8422
8518
|
}
|
|
8423
|
-
function buildTestIdManifest(
|
|
8519
|
+
function buildTestIdManifest(componentHierarchyMap) {
|
|
8424
8520
|
return Object.fromEntries(
|
|
8425
|
-
|
|
8521
|
+
Array.from(componentHierarchyMap.entries()).sort((a, b) => a[0].localeCompare(b[0])).map(([componentName, dependencies]) => {
|
|
8522
|
+
const testIds = Array.from(dependencies.dataTestIdSet).map((entry) => entry.selectorValue.formatted).filter(Boolean);
|
|
8523
|
+
if (!testIds.length) {
|
|
8524
|
+
return null;
|
|
8525
|
+
}
|
|
8526
|
+
return [componentName, Array.from(new Set(testIds)).sort((a, b) => a.localeCompare(b))];
|
|
8527
|
+
}).filter((entry) => entry !== null)
|
|
8426
8528
|
);
|
|
8427
8529
|
}
|
|
8428
8530
|
function writeConstJson(value) {
|
|
@@ -8432,7 +8534,7 @@ function writeConstJson(value) {
|
|
|
8432
8534
|
}
|
|
8433
8535
|
function generateTestIdsModule(componentHierarchyMap, elementMetadata) {
|
|
8434
8536
|
const pomManifest = buildPomManifest(componentHierarchyMap, elementMetadata);
|
|
8435
|
-
const testIdManifest = buildTestIdManifest(
|
|
8537
|
+
const testIdManifest = buildTestIdManifest(componentHierarchyMap);
|
|
8436
8538
|
return renderSourceFile("virtual-testids.ts", (sourceFile) => {
|
|
8437
8539
|
sourceFile.addStatements("// Virtual module: test id manifest");
|
|
8438
8540
|
sourceFile.addVariableStatement({
|
|
@@ -8518,7 +8620,89 @@ function createTestIdsVirtualModulesPlugin(componentHierarchyMap, elementMetadat
|
|
|
8518
8620
|
}
|
|
8519
8621
|
};
|
|
8520
8622
|
}
|
|
8521
|
-
|
|
8623
|
+
const ANNOTATOR_CLIENT_VIRTUAL_ID = "virtual:vue-pom-generator/annotator-client";
|
|
8624
|
+
const ANNOTATOR_CLIENT_RESOLVED_ID = `\0${ANNOTATOR_CLIENT_VIRTUAL_ID}`;
|
|
8625
|
+
const DEFAULT_ENTRY_SUFFIXES = [
|
|
8626
|
+
"/src/main.ts",
|
|
8627
|
+
"/src/main.js",
|
|
8628
|
+
"/src/main.mts",
|
|
8629
|
+
"/src/main.tsx",
|
|
8630
|
+
"/src/main.jsx"
|
|
8631
|
+
];
|
|
8632
|
+
function toFsImportPath(filePath) {
|
|
8633
|
+
return `/@fs/${filePath.replace(/\\/g, "/")}`;
|
|
8634
|
+
}
|
|
8635
|
+
function resolveAnnotatorClientPath() {
|
|
8636
|
+
const candidates = [
|
|
8637
|
+
fileURLToPath(new URL("./client.ts", import.meta.url)),
|
|
8638
|
+
fileURLToPath(new URL("../plugin/runtime/annotator/client.ts", import.meta.url))
|
|
8639
|
+
];
|
|
8640
|
+
const resolved = candidates.find((candidate) => fs.existsSync(candidate));
|
|
8641
|
+
if (!resolved) {
|
|
8642
|
+
throw new Error("[vue-pom-generator] Unable to locate annotator client source.");
|
|
8643
|
+
}
|
|
8644
|
+
return path.resolve(resolved);
|
|
8645
|
+
}
|
|
8646
|
+
function createAnnotatorUiPlugin(options) {
|
|
8647
|
+
const clientPath = resolveAnnotatorClientPath();
|
|
8648
|
+
const clientImportPath = toFsImportPath(clientPath);
|
|
8649
|
+
const clientOptions = JSON.stringify({
|
|
8650
|
+
sourceAttribute: options.sourceAttribute,
|
|
8651
|
+
metadataAttributePrefix: options.metadataAttributePrefix,
|
|
8652
|
+
outputDetail: options.outputDetail,
|
|
8653
|
+
copyToClipboard: options.copyToClipboard,
|
|
8654
|
+
showComponentTree: options.showComponentTree
|
|
8655
|
+
});
|
|
8656
|
+
return {
|
|
8657
|
+
name: "vue-pom-generator:annotator-ui",
|
|
8658
|
+
apply: "serve",
|
|
8659
|
+
resolveId(id) {
|
|
8660
|
+
if (id === ANNOTATOR_CLIENT_VIRTUAL_ID) {
|
|
8661
|
+
return ANNOTATOR_CLIENT_RESOLVED_ID;
|
|
8662
|
+
}
|
|
8663
|
+
},
|
|
8664
|
+
load(id) {
|
|
8665
|
+
if (id !== ANNOTATOR_CLIENT_RESOLVED_ID) {
|
|
8666
|
+
return null;
|
|
8667
|
+
}
|
|
8668
|
+
return [
|
|
8669
|
+
`import { mountAnnotatorClient } from ${JSON.stringify(clientImportPath)};`,
|
|
8670
|
+
`mountAnnotatorClient(${clientOptions});`,
|
|
8671
|
+
""
|
|
8672
|
+
].join("\n");
|
|
8673
|
+
},
|
|
8674
|
+
transform(code, id) {
|
|
8675
|
+
if (!options.enabled) {
|
|
8676
|
+
return null;
|
|
8677
|
+
}
|
|
8678
|
+
const normalizedId = id.replace(/\\/g, "/");
|
|
8679
|
+
if (!DEFAULT_ENTRY_SUFFIXES.some((suffix) => normalizedId.endsWith(suffix))) {
|
|
8680
|
+
return null;
|
|
8681
|
+
}
|
|
8682
|
+
if (code.includes(ANNOTATOR_CLIENT_VIRTUAL_ID)) {
|
|
8683
|
+
return null;
|
|
8684
|
+
}
|
|
8685
|
+
return {
|
|
8686
|
+
code: `import ${JSON.stringify(ANNOTATOR_CLIENT_VIRTUAL_ID)};
|
|
8687
|
+
${code}`,
|
|
8688
|
+
map: null
|
|
8689
|
+
};
|
|
8690
|
+
},
|
|
8691
|
+
transformIndexHtml() {
|
|
8692
|
+
if (!options.enabled) {
|
|
8693
|
+
return void 0;
|
|
8694
|
+
}
|
|
8695
|
+
const tag = {
|
|
8696
|
+
tag: "script",
|
|
8697
|
+
attrs: { type: "module" },
|
|
8698
|
+
children: `import ${JSON.stringify(ANNOTATOR_CLIENT_VIRTUAL_ID)};`,
|
|
8699
|
+
injectTo: "body"
|
|
8700
|
+
};
|
|
8701
|
+
return [tag];
|
|
8702
|
+
}
|
|
8703
|
+
};
|
|
8704
|
+
}
|
|
8705
|
+
function createInternalPlugins(options) {
|
|
8522
8706
|
const {
|
|
8523
8707
|
componentHierarchyMap,
|
|
8524
8708
|
elementMetadata,
|
|
@@ -8534,7 +8718,8 @@ function createSupportPlugins(options) {
|
|
|
8534
8718
|
generation,
|
|
8535
8719
|
projectRootRef,
|
|
8536
8720
|
basePageClassPath: basePageClassPathOverride,
|
|
8537
|
-
loggerRef
|
|
8721
|
+
loggerRef,
|
|
8722
|
+
annotatorRuntime
|
|
8538
8723
|
} = options;
|
|
8539
8724
|
const {
|
|
8540
8725
|
outDir,
|
|
@@ -8608,7 +8793,13 @@ function createSupportPlugins(options) {
|
|
|
8608
8793
|
loggerRef
|
|
8609
8794
|
});
|
|
8610
8795
|
const virtualModules = createTestIdsVirtualModulesPlugin(componentHierarchyMap, elementMetadata);
|
|
8611
|
-
|
|
8796
|
+
const annotatorUiPlugin = createAnnotatorUiPlugin({
|
|
8797
|
+
...annotatorRuntime.ui,
|
|
8798
|
+
enabled: annotatorRuntime.enabled && annotatorRuntime.ui.enabled,
|
|
8799
|
+
sourceAttribute: annotatorRuntime.sourceAttribute,
|
|
8800
|
+
metadataAttributePrefix: annotatorRuntime.metadataAttributePrefix
|
|
8801
|
+
});
|
|
8802
|
+
return [tsProcessor, devProcessor, virtualModules, annotatorUiPlugin];
|
|
8612
8803
|
}
|
|
8613
8804
|
function findDataTestIdProp(element, attributeName = "data-testid") {
|
|
8614
8805
|
return element.props.find(
|
|
@@ -8728,7 +8919,9 @@ function tryCreateElementMetadata(args) {
|
|
|
8728
8919
|
staticAriaLabel: findStaticAttributeValue(element, "aria-label"),
|
|
8729
8920
|
staticRole: findStaticAttributeValue(element, "role"),
|
|
8730
8921
|
staticTitle: findStaticAttributeValue(element, "title"),
|
|
8731
|
-
staticTextContent: collectStaticTextContent(element.children)
|
|
8922
|
+
staticTextContent: collectStaticTextContent(element.children),
|
|
8923
|
+
sourceLine: element.loc?.start.line,
|
|
8924
|
+
sourceColumn: element.loc?.start.column
|
|
8732
8925
|
};
|
|
8733
8926
|
return metadata;
|
|
8734
8927
|
}
|
|
@@ -8800,7 +8993,8 @@ function createVuePluginWithTestIds(options) {
|
|
|
8800
8993
|
loggerRef,
|
|
8801
8994
|
getSourceDirs,
|
|
8802
8995
|
getWrapperSearchRoots,
|
|
8803
|
-
getProjectRoot
|
|
8996
|
+
getProjectRoot,
|
|
8997
|
+
annotatorMetadata
|
|
8804
8998
|
} = options;
|
|
8805
8999
|
const lastAccessibilityWarningSignatureByComponent = /* @__PURE__ */ new Map();
|
|
8806
9000
|
const getComponentNameFromPath = (filename) => {
|
|
@@ -8817,27 +9011,15 @@ function createVuePluginWithTestIds(options) {
|
|
|
8817
9011
|
return false;
|
|
8818
9012
|
const cleanPath = filename.includes("?") ? filename.substring(0, filename.indexOf("?")) : filename;
|
|
8819
9013
|
const projectRoot = getProjectRoot();
|
|
8820
|
-
const
|
|
8821
|
-
|
|
8822
|
-
|
|
8823
|
-
|
|
8824
|
-
|
|
8825
|
-
|
|
8826
|
-
const rootsToTry = [projectRoot, process.cwd()];
|
|
8827
|
-
const matched = getSourceDirs().some((dir) => {
|
|
8828
|
-
return rootsToTry.some((root) => {
|
|
8829
|
-
const absDir = path.resolve(root, dir);
|
|
8830
|
-
if (absFilename.startsWith(absDir + path.sep) || absFilename === absDir)
|
|
8831
|
-
return true;
|
|
8832
|
-
if (dir.startsWith("app/") && root.endsWith("/app")) {
|
|
8833
|
-
const relativeDir = dir.substring(4);
|
|
8834
|
-
const absDirAlt = path.resolve(root, relativeDir);
|
|
8835
|
-
return absFilename.startsWith(absDirAlt + path.sep) || absFilename === absDirAlt;
|
|
8836
|
-
}
|
|
8837
|
-
return false;
|
|
8838
|
-
});
|
|
9014
|
+
const matched = isFileInConfiguredSourceScope({
|
|
9015
|
+
filename,
|
|
9016
|
+
projectRoot,
|
|
9017
|
+
viewsDirAbs: getViewsDirAbs(),
|
|
9018
|
+
sourceDirs: getSourceDirs(),
|
|
9019
|
+
extraRoots: [process.cwd()]
|
|
8839
9020
|
});
|
|
8840
9021
|
if (cleanPath.endsWith(".vue") && !matched) {
|
|
9022
|
+
const absFilename = path.normalize(path.isAbsolute(cleanPath) ? cleanPath : path.resolve(projectRoot, cleanPath));
|
|
8841
9023
|
loggerRef.current.debug(`[isFileInScope] REJECTED: ${absFilename} (Clean: ${cleanPath})`);
|
|
8842
9024
|
}
|
|
8843
9025
|
return matched;
|
|
@@ -8871,7 +9053,8 @@ function createVuePluginWithTestIds(options) {
|
|
|
8871
9053
|
missingSemanticNameBehavior,
|
|
8872
9054
|
warn: (message) => loggerRef.current.warn(message),
|
|
8873
9055
|
vueFilesPathMap,
|
|
8874
|
-
wrapperSearchRoots: getWrapperSearchRoots()
|
|
9056
|
+
wrapperSearchRoots: getWrapperSearchRoots(),
|
|
9057
|
+
annotatorMetadata
|
|
8875
9058
|
}
|
|
8876
9059
|
)
|
|
8877
9060
|
);
|
|
@@ -8926,7 +9109,8 @@ function createVuePluginWithTestIds(options) {
|
|
|
8926
9109
|
missingSemanticNameBehavior,
|
|
8927
9110
|
warn: (message) => loggerRef.current.warn(message),
|
|
8928
9111
|
vueFilesPathMap,
|
|
8929
|
-
wrapperSearchRoots: getWrapperSearchRoots()
|
|
9112
|
+
wrapperSearchRoots: getWrapperSearchRoots(),
|
|
9113
|
+
annotatorMetadata
|
|
8930
9114
|
}
|
|
8931
9115
|
);
|
|
8932
9116
|
perFileTransform.set(componentName, transform);
|
|
@@ -9071,6 +9255,12 @@ function assertOneOf(value, allowed, name) {
|
|
|
9071
9255
|
}
|
|
9072
9256
|
throw new TypeError(`${name} must be one of: ${allowed.join(", ")}.`);
|
|
9073
9257
|
}
|
|
9258
|
+
function assertDataAttributeName(value, name) {
|
|
9259
|
+
assertNonEmptyString(value, name);
|
|
9260
|
+
if (!value.startsWith("data-")) {
|
|
9261
|
+
throw new TypeError(`${name} must start with "data-".`);
|
|
9262
|
+
}
|
|
9263
|
+
}
|
|
9074
9264
|
function readPackageJson(projectRoot) {
|
|
9075
9265
|
const packageJsonPath = path.join(projectRoot, "package.json");
|
|
9076
9266
|
if (!fs.existsSync(packageJsonPath)) {
|
|
@@ -9234,6 +9424,19 @@ function createVuePomGeneratorPlugins(options = {}) {
|
|
|
9234
9424
|
const generationEnabled = generationOptions !== null;
|
|
9235
9425
|
const vueGenerationOptions = generationOptions;
|
|
9236
9426
|
const verbosity = options.logging?.verbosity ?? "warn";
|
|
9427
|
+
const annotatorRuntimeOptions = options.runtime?.annotator;
|
|
9428
|
+
const annotatorUiRuntimeOptions = annotatorRuntimeOptions?.ui;
|
|
9429
|
+
const resolvedAnnotatorRuntimeOptions = {
|
|
9430
|
+
enabled: annotatorRuntimeOptions?.enabled === true,
|
|
9431
|
+
sourceAttribute: annotatorRuntimeOptions?.sourceAttribute ?? "data-v-inspector",
|
|
9432
|
+
metadataAttributePrefix: annotatorRuntimeOptions?.metadataAttributePrefix ?? "data-v-pom",
|
|
9433
|
+
ui: {
|
|
9434
|
+
enabled: annotatorUiRuntimeOptions?.enabled === true,
|
|
9435
|
+
outputDetail: annotatorUiRuntimeOptions?.outputDetail ?? "forensic",
|
|
9436
|
+
copyToClipboard: annotatorUiRuntimeOptions?.copyToClipboard ?? false,
|
|
9437
|
+
showComponentTree: annotatorUiRuntimeOptions?.showComponentTree ?? true
|
|
9438
|
+
}
|
|
9439
|
+
};
|
|
9237
9440
|
const vueOptions = options.vueOptions;
|
|
9238
9441
|
const resolvedInjectionOptionsRef = {
|
|
9239
9442
|
current: resolveInjectionSupportOptions({
|
|
@@ -9337,6 +9540,10 @@ function createVuePomGeneratorPlugins(options = {}) {
|
|
|
9337
9540
|
assertNonEmptyStringArray(getComponentDirs(), "[vue-pom-generator] injection.componentDirs");
|
|
9338
9541
|
assertNonEmptyStringArray(getLayoutDirs(), "[vue-pom-generator] injection.layoutDirs");
|
|
9339
9542
|
assertNonEmptyStringArray(getWrapperSearchRoots(), "[vue-pom-generator] injection.wrapperSearchRoots");
|
|
9543
|
+
if (resolvedAnnotatorRuntimeOptions.enabled) {
|
|
9544
|
+
assertDataAttributeName(resolvedAnnotatorRuntimeOptions.sourceAttribute, "[vue-pom-generator] runtime.annotator.sourceAttribute");
|
|
9545
|
+
assertDataAttributeName(resolvedAnnotatorRuntimeOptions.metadataAttributePrefix, "[vue-pom-generator] runtime.annotator.metadataAttributePrefix");
|
|
9546
|
+
}
|
|
9340
9547
|
if (generationEnabled) {
|
|
9341
9548
|
assertNonEmptyString(resolvedGenerationOptions.outDir, "[vue-pom-generator] generation.outDir");
|
|
9342
9549
|
assertOneOf(resolvedGenerationOptions.typescriptOutputStructure, ["aggregated", "split"], "[vue-pom-generator] generation.playwright.outputStructure");
|
|
@@ -9379,10 +9586,14 @@ function createVuePomGeneratorPlugins(options = {}) {
|
|
|
9379
9586
|
loggerRef,
|
|
9380
9587
|
getSourceDirs,
|
|
9381
9588
|
getWrapperSearchRoots: getWrapperSearchRootsAbs,
|
|
9382
|
-
getProjectRoot: () => projectRootRef.current
|
|
9589
|
+
getProjectRoot: () => projectRootRef.current,
|
|
9590
|
+
annotatorMetadata: resolvedAnnotatorRuntimeOptions.enabled ? {
|
|
9591
|
+
sourceAttribute: resolvedAnnotatorRuntimeOptions.sourceAttribute,
|
|
9592
|
+
metadataAttributePrefix: resolvedAnnotatorRuntimeOptions.metadataAttributePrefix
|
|
9593
|
+
} : null
|
|
9383
9594
|
});
|
|
9384
9595
|
templateCompilerOptionsForResolvedPlugin = templateCompilerOptions;
|
|
9385
|
-
const
|
|
9596
|
+
const internalPlugins = createInternalPlugins({
|
|
9386
9597
|
componentHierarchyMap,
|
|
9387
9598
|
elementMetadata,
|
|
9388
9599
|
vueFilesPathMap,
|
|
@@ -9397,7 +9608,8 @@ function createVuePomGeneratorPlugins(options = {}) {
|
|
|
9397
9608
|
generation: resolvedGenerationOptions,
|
|
9398
9609
|
projectRootRef,
|
|
9399
9610
|
basePageClassPath: basePageClassPathOverride,
|
|
9400
|
-
loggerRef
|
|
9611
|
+
loggerRef,
|
|
9612
|
+
annotatorRuntime: resolvedAnnotatorRuntimeOptions
|
|
9401
9613
|
});
|
|
9402
9614
|
if (isNuxt) {
|
|
9403
9615
|
loggerRef.current.info("Nuxt environment detected. Skipping internal @vitejs/plugin-vue to avoid conflicts.");
|
|
@@ -9408,7 +9620,7 @@ function createVuePomGeneratorPlugins(options = {}) {
|
|
|
9408
9620
|
configPlugin,
|
|
9409
9621
|
metadataCollectorPlugin,
|
|
9410
9622
|
...usesExternalVuePlugin ? [] : [internalVuePlugin],
|
|
9411
|
-
...
|
|
9623
|
+
...internalPlugins
|
|
9412
9624
|
];
|
|
9413
9625
|
if (!generationEnabled) {
|
|
9414
9626
|
const virtualModules = createTestIdsVirtualModulesPlugin(componentHierarchyMap, elementMetadata);
|