@immense/vue-pom-generator 1.0.29 → 1.0.31
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 +11 -7
- package/RELEASE_NOTES.md +40 -26
- package/class-generation/index.ts +9 -0
- package/dist/index.cjs +323 -91
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +324 -92
- package/dist/index.mjs.map +1 -1
- package/dist/plugin/create-vue-pom-generator-plugins.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 +25 -13
- package/dist/plugin/types.d.ts.map +1 -1
- package/dist/plugin/vue-plugin.d.ts +1 -0
- package/dist/plugin/vue-plugin.d.ts.map +1 -1
- package/dist/transform.d.ts +1 -0
- package/dist/transform.d.ts.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { pathToFileURL, fileURLToPath } from "node:url";
|
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import { JSDOM } from "jsdom";
|
|
6
6
|
import { NodeTypes, stringifyExpression, ConstantTypes, createSimpleExpression } from "@vue/compiler-core";
|
|
7
|
-
import { isArrayExpression, isStringLiteral, isTemplateLiteral, isAssignmentExpression, isIdentifier, isMemberExpression, isCallExpression, isExpressionStatement, isOptionalMemberExpression, isObjectExpression, isFile,
|
|
7
|
+
import { isArrayExpression, isStringLiteral, isTemplateLiteral, isAssignmentExpression, isIdentifier, isMemberExpression, isCallExpression, isExpressionStatement, isArrowFunctionExpression, isOptionalMemberExpression, isObjectExpression, isFile, isBlockStatement, isOptionalCallExpression, isLogicalExpression, isConditionalExpression, isSequenceExpression, isAssignmentPattern, isRestElement, isObjectPattern, isObjectProperty, isProgram, VISITOR_KEYS, isBooleanLiteral, isNumericLiteral, isNullLiteral } from "@babel/types";
|
|
8
8
|
import { parseExpression, parse } from "@babel/parser";
|
|
9
9
|
import { performance } from "node:perf_hooks";
|
|
10
10
|
import * as compilerDom from "@vue/compiler-dom";
|
|
@@ -565,6 +565,124 @@ function getTemplateSlotScope(node) {
|
|
|
565
565
|
}
|
|
566
566
|
return null;
|
|
567
567
|
}
|
|
568
|
+
function isSimpleScopeIdentifier(value) {
|
|
569
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(value);
|
|
570
|
+
}
|
|
571
|
+
function buildSlotScopeFallbackKeyExpression(identifier) {
|
|
572
|
+
return `${identifier}.key ?? ${identifier}.data?.id ?? ${identifier}.id ?? ${identifier}.value ?? ${identifier}`;
|
|
573
|
+
}
|
|
574
|
+
function tryGetBindingIdentifierName(node) {
|
|
575
|
+
if (!node) {
|
|
576
|
+
return null;
|
|
577
|
+
}
|
|
578
|
+
if (isIdentifier(node)) {
|
|
579
|
+
return node.name;
|
|
580
|
+
}
|
|
581
|
+
if (isAssignmentPattern(node)) {
|
|
582
|
+
return tryGetBindingIdentifierName(node.left);
|
|
583
|
+
}
|
|
584
|
+
if (isRestElement(node)) {
|
|
585
|
+
return tryGetBindingIdentifierName(node.argument);
|
|
586
|
+
}
|
|
587
|
+
return null;
|
|
588
|
+
}
|
|
589
|
+
function getSlotScopeObjectPropertyKeyName(node) {
|
|
590
|
+
if (isIdentifier(node)) {
|
|
591
|
+
return node.name;
|
|
592
|
+
}
|
|
593
|
+
if (isStringLiteral(node)) {
|
|
594
|
+
return node.value;
|
|
595
|
+
}
|
|
596
|
+
return null;
|
|
597
|
+
}
|
|
598
|
+
function tryGetSlotScopeKeyCandidate(node) {
|
|
599
|
+
if (!node) {
|
|
600
|
+
return null;
|
|
601
|
+
}
|
|
602
|
+
if (isIdentifier(node)) {
|
|
603
|
+
return {
|
|
604
|
+
priority: 2,
|
|
605
|
+
expression: buildSlotScopeFallbackKeyExpression(node.name)
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
if (isAssignmentPattern(node)) {
|
|
609
|
+
return tryGetSlotScopeKeyCandidate(node.left);
|
|
610
|
+
}
|
|
611
|
+
if (isRestElement(node)) {
|
|
612
|
+
return tryGetSlotScopeKeyCandidate(node.argument);
|
|
613
|
+
}
|
|
614
|
+
if (!isObjectPattern(node)) {
|
|
615
|
+
return null;
|
|
616
|
+
}
|
|
617
|
+
let best = null;
|
|
618
|
+
for (const property of node.properties) {
|
|
619
|
+
let candidate = null;
|
|
620
|
+
if (isRestElement(property)) {
|
|
621
|
+
candidate = tryGetSlotScopeKeyCandidate(property.argument);
|
|
622
|
+
if (candidate) {
|
|
623
|
+
candidate = { ...candidate, priority: Math.max(candidate.priority, 2) };
|
|
624
|
+
}
|
|
625
|
+
} else if (isObjectProperty(property)) {
|
|
626
|
+
const keyName = getSlotScopeObjectPropertyKeyName(property.key);
|
|
627
|
+
const bindingName = tryGetBindingIdentifierName(property.value) ?? tryGetBindingIdentifierName(property.key);
|
|
628
|
+
if (bindingName) {
|
|
629
|
+
if (keyName === "key" || bindingName === "key") {
|
|
630
|
+
candidate = {
|
|
631
|
+
priority: 0,
|
|
632
|
+
expression: bindingName
|
|
633
|
+
};
|
|
634
|
+
} else {
|
|
635
|
+
candidate = {
|
|
636
|
+
priority: keyName === "data" ? 1 : 2,
|
|
637
|
+
expression: buildSlotScopeFallbackKeyExpression(bindingName)
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
if (candidate && (!best || candidate.priority < best.priority)) {
|
|
643
|
+
best = candidate;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
return best;
|
|
647
|
+
}
|
|
648
|
+
function tryGetTemplateSlotScopeKeyExpression(scope) {
|
|
649
|
+
const trimmed = scope.trim();
|
|
650
|
+
if (!trimmed) {
|
|
651
|
+
return null;
|
|
652
|
+
}
|
|
653
|
+
if (isSimpleScopeIdentifier(trimmed)) {
|
|
654
|
+
return buildSlotScopeFallbackKeyExpression(trimmed);
|
|
655
|
+
}
|
|
656
|
+
try {
|
|
657
|
+
const parsed = parse(`(${trimmed}) => {}`, {
|
|
658
|
+
sourceType: "module",
|
|
659
|
+
plugins: ["typescript"]
|
|
660
|
+
});
|
|
661
|
+
const statement = parsed.program.body[0];
|
|
662
|
+
if (statement && isExpressionStatement(statement) && isArrowFunctionExpression(statement.expression)) {
|
|
663
|
+
return tryGetSlotScopeKeyCandidate(statement.expression.params[0])?.expression ?? null;
|
|
664
|
+
}
|
|
665
|
+
} catch {
|
|
666
|
+
}
|
|
667
|
+
if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
|
|
668
|
+
const inner = trimmed.slice(1, -1).trim();
|
|
669
|
+
let cutIdx = -1;
|
|
670
|
+
const commaIdx = inner.indexOf(",");
|
|
671
|
+
const colonIdx = inner.indexOf(":");
|
|
672
|
+
if (commaIdx !== -1 && colonIdx !== -1) {
|
|
673
|
+
cutIdx = Math.min(commaIdx, colonIdx);
|
|
674
|
+
} else if (commaIdx !== -1) {
|
|
675
|
+
cutIdx = commaIdx;
|
|
676
|
+
} else if (colonIdx !== -1) {
|
|
677
|
+
cutIdx = colonIdx;
|
|
678
|
+
}
|
|
679
|
+
const first = (cutIdx === -1 ? inner : inner.slice(0, cutIdx)).trim();
|
|
680
|
+
if (first && isSimpleScopeIdentifier(first)) {
|
|
681
|
+
return buildSlotScopeFallbackKeyExpression(first);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
return trimmed;
|
|
685
|
+
}
|
|
568
686
|
function nodeHasToDirective(node) {
|
|
569
687
|
const toDirective = findDirectiveByName(node, "bind", "to");
|
|
570
688
|
if (toDirective?.exp) {
|
|
@@ -640,25 +758,7 @@ function getContainedInSlotDataKeyValue(node, hierarchyMap2) {
|
|
|
640
758
|
if (parent.type === NodeTypes.ELEMENT && parent.tag === "template") {
|
|
641
759
|
const scope = getTemplateSlotScope(parent);
|
|
642
760
|
if (scope) {
|
|
643
|
-
|
|
644
|
-
if (key.startsWith("{") && key.endsWith("}")) {
|
|
645
|
-
const inner = key.slice(1, -1).trim();
|
|
646
|
-
let cutIdx = -1;
|
|
647
|
-
const commaIdx = inner.indexOf(",");
|
|
648
|
-
const colonIdx = inner.indexOf(":");
|
|
649
|
-
if (commaIdx !== -1 && colonIdx !== -1) {
|
|
650
|
-
cutIdx = Math.min(commaIdx, colonIdx);
|
|
651
|
-
} else if (commaIdx !== -1) {
|
|
652
|
-
cutIdx = commaIdx;
|
|
653
|
-
} else if (colonIdx !== -1) {
|
|
654
|
-
cutIdx = colonIdx;
|
|
655
|
-
}
|
|
656
|
-
const first = (cutIdx === -1 ? inner : inner.slice(0, cutIdx)).trim();
|
|
657
|
-
if (first) {
|
|
658
|
-
key = first;
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
return key;
|
|
761
|
+
return tryGetTemplateSlotScopeKeyExpression(scope);
|
|
662
762
|
}
|
|
663
763
|
}
|
|
664
764
|
parent = getParent(hierarchyMap2, parent);
|
|
@@ -1309,11 +1409,11 @@ function getStableClickHandlerNameFromExpression(exp) {
|
|
|
1309
1409
|
return extractNameFromCallee(callee);
|
|
1310
1410
|
}
|
|
1311
1411
|
if (isAssignmentExpression(exp)) {
|
|
1312
|
-
const left = exp.left;
|
|
1313
|
-
if (
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1412
|
+
const left = getAssignmentTargetNameFromBabel(exp.left);
|
|
1413
|
+
if (left) {
|
|
1414
|
+
const right = getStableAssignmentValueSuffixFromBabel(exp.right);
|
|
1415
|
+
return `Set${toPascalCase(left)}${right}`;
|
|
1416
|
+
}
|
|
1317
1417
|
return "";
|
|
1318
1418
|
}
|
|
1319
1419
|
if (isOptionalMemberExpression(exp)) {
|
|
@@ -1388,6 +1488,71 @@ function extractMemberPropertyName(member) {
|
|
|
1388
1488
|
}
|
|
1389
1489
|
return "";
|
|
1390
1490
|
}
|
|
1491
|
+
function getLastIdentifierFromMemberChainBabel(node) {
|
|
1492
|
+
if (!node) {
|
|
1493
|
+
return "";
|
|
1494
|
+
}
|
|
1495
|
+
if (isIdentifier(node)) {
|
|
1496
|
+
return node.name;
|
|
1497
|
+
}
|
|
1498
|
+
if (isMemberExpression(node) || isOptionalMemberExpression(node)) {
|
|
1499
|
+
if (!node.computed) {
|
|
1500
|
+
if (isIdentifier(node.property)) {
|
|
1501
|
+
return node.property.name;
|
|
1502
|
+
}
|
|
1503
|
+
} else if (isStringLiteral(node.property)) {
|
|
1504
|
+
return node.property.value;
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
return "";
|
|
1508
|
+
}
|
|
1509
|
+
function getAssignmentTargetNameFromBabel(node) {
|
|
1510
|
+
if (!node) {
|
|
1511
|
+
return "";
|
|
1512
|
+
}
|
|
1513
|
+
if (isIdentifier(node)) {
|
|
1514
|
+
return node.name;
|
|
1515
|
+
}
|
|
1516
|
+
if (isMemberExpression(node) || isOptionalMemberExpression(node)) {
|
|
1517
|
+
if (!node.computed && isIdentifier(node.property) && node.property.name === "value") {
|
|
1518
|
+
return getLastIdentifierFromMemberChainBabel(node.object);
|
|
1519
|
+
}
|
|
1520
|
+
return getLastIdentifierFromMemberChainBabel(node);
|
|
1521
|
+
}
|
|
1522
|
+
return "";
|
|
1523
|
+
}
|
|
1524
|
+
function getStableAssignmentValueSuffixFromBabel(node) {
|
|
1525
|
+
if (!node) {
|
|
1526
|
+
return "";
|
|
1527
|
+
}
|
|
1528
|
+
if (isBooleanLiteral(node)) {
|
|
1529
|
+
return node.value ? "True" : "False";
|
|
1530
|
+
}
|
|
1531
|
+
if (isNumericLiteral(node)) {
|
|
1532
|
+
return `Value${String(node.value)}`;
|
|
1533
|
+
}
|
|
1534
|
+
if (isNullLiteral(node)) {
|
|
1535
|
+
return "Null";
|
|
1536
|
+
}
|
|
1537
|
+
if (isStringLiteral(node)) {
|
|
1538
|
+
const cleaned = (node.value ?? "").trim();
|
|
1539
|
+
return cleaned ? toPascalCase(cleaned.slice(0, 24)) : "";
|
|
1540
|
+
}
|
|
1541
|
+
if (isTemplateLiteral(node) && node.expressions.length === 0) {
|
|
1542
|
+
const value = node.quasis.map((q) => q.value?.cooked ?? "").join("").trim();
|
|
1543
|
+
return value ? toPascalCase(value.slice(0, 24)) : "";
|
|
1544
|
+
}
|
|
1545
|
+
if (isMemberExpression(node) || isOptionalMemberExpression(node)) {
|
|
1546
|
+
const name = getLastIdentifierFromMemberChainBabel(node);
|
|
1547
|
+
return name ? toPascalCase(name.slice(0, 24)) : "";
|
|
1548
|
+
}
|
|
1549
|
+
if (isIdentifier(node)) {
|
|
1550
|
+
const firstChar = node.name.charAt(0);
|
|
1551
|
+
const isUpperAlpha = firstChar !== "" && firstChar === firstChar.toUpperCase() && firstChar !== firstChar.toLowerCase();
|
|
1552
|
+
return isUpperAlpha ? toPascalCase(node.name.slice(0, 24)) : "";
|
|
1553
|
+
}
|
|
1554
|
+
return "";
|
|
1555
|
+
}
|
|
1391
1556
|
function isCompilerGeneratedReferenceRoot(name) {
|
|
1392
1557
|
return name.startsWith("_") || name.startsWith("$");
|
|
1393
1558
|
}
|
|
@@ -3199,6 +3364,10 @@ function escapeGitAttributesPattern(value) {
|
|
|
3199
3364
|
}
|
|
3200
3365
|
return output;
|
|
3201
3366
|
}
|
|
3367
|
+
function pathUsesGeneratedHeuristic(filePath) {
|
|
3368
|
+
const normalized = path.normalize(filePath);
|
|
3369
|
+
return normalized.split(path.sep).includes("__generated__");
|
|
3370
|
+
}
|
|
3202
3371
|
function buildManagedGitAttributesBlock(entries) {
|
|
3203
3372
|
return [
|
|
3204
3373
|
GENERATED_GITATTRIBUTES_BLOCK_START,
|
|
@@ -3246,6 +3415,9 @@ function buildGeneratedGitAttributesFiles(generatedFilePaths) {
|
|
|
3246
3415
|
if (path.basename(resolvedFilePath) === ".gitattributes") {
|
|
3247
3416
|
continue;
|
|
3248
3417
|
}
|
|
3418
|
+
if (pathUsesGeneratedHeuristic(resolvedFilePath)) {
|
|
3419
|
+
continue;
|
|
3420
|
+
}
|
|
3249
3421
|
const dir = path.dirname(resolvedFilePath);
|
|
3250
3422
|
const entry = `${escapeGitAttributesPattern(path.basename(resolvedFilePath))} linguist-generated`;
|
|
3251
3423
|
const entries = entriesByDir.get(dir) ?? /* @__PURE__ */ new Set();
|
|
@@ -4322,15 +4494,57 @@ function createBuildProcessorPlugin(options) {
|
|
|
4322
4494
|
const TESTID_CLICK_EVENT_NAME = "__testid_event__";
|
|
4323
4495
|
const TESTID_CLICK_EVENT_STRICT_FLAG = "__testid_click_event_strict__";
|
|
4324
4496
|
const CLICK_EVENT_NAME = TESTID_CLICK_EVENT_NAME;
|
|
4325
|
-
const
|
|
4326
|
-
const
|
|
4327
|
-
|
|
4497
|
+
const inferredNativeWrapperConfigByLookup = /* @__PURE__ */ new Map();
|
|
4498
|
+
const inferredSfcPathByLookup = /* @__PURE__ */ new Map();
|
|
4499
|
+
const indexedVueSfcPathsByRoots = /* @__PURE__ */ new Map();
|
|
4328
4500
|
function toKebabCaseTag(tag) {
|
|
4329
|
-
|
|
4501
|
+
let result = "";
|
|
4502
|
+
let previousWasSeparator = false;
|
|
4503
|
+
for (let i = 0; i < tag.length; i += 1) {
|
|
4504
|
+
const ch = tag[i];
|
|
4505
|
+
const code = ch.charCodeAt(0);
|
|
4506
|
+
if (ch === "_" || ch === "-" || ch === "." || ch === " " || ch === " " || ch === "\n" || ch === "\r") {
|
|
4507
|
+
if (result && !previousWasSeparator) {
|
|
4508
|
+
result += "-";
|
|
4509
|
+
}
|
|
4510
|
+
previousWasSeparator = true;
|
|
4511
|
+
continue;
|
|
4512
|
+
}
|
|
4513
|
+
const previous = i > 0 ? tag[i - 1] : "";
|
|
4514
|
+
const previousCode = previous ? previous.charCodeAt(0) : 0;
|
|
4515
|
+
const hasPrevious = i > 0;
|
|
4516
|
+
const shouldInsertSeparator = hasPrevious && isAsciiUppercaseLetterCode(code) && (isAsciiLetterCode(previousCode) || isAsciiDigitCode(previousCode)) && !previousWasSeparator;
|
|
4517
|
+
if (shouldInsertSeparator) {
|
|
4518
|
+
result += "-";
|
|
4519
|
+
}
|
|
4520
|
+
result += ch.toLowerCase();
|
|
4521
|
+
previousWasSeparator = false;
|
|
4522
|
+
}
|
|
4523
|
+
return result;
|
|
4330
4524
|
}
|
|
4331
|
-
function
|
|
4332
|
-
|
|
4333
|
-
|
|
4525
|
+
function normalizeSearchRoots(wrapperSearchRoots) {
|
|
4526
|
+
const normalized = /* @__PURE__ */ new Set();
|
|
4527
|
+
for (const root of wrapperSearchRoots) {
|
|
4528
|
+
const resolved = path.resolve(root);
|
|
4529
|
+
try {
|
|
4530
|
+
if (!fs.existsSync(resolved) || !fs.statSync(resolved).isDirectory()) {
|
|
4531
|
+
continue;
|
|
4532
|
+
}
|
|
4533
|
+
normalized.add(path.normalize(fs.realpathSync(resolved)));
|
|
4534
|
+
} catch {
|
|
4535
|
+
continue;
|
|
4536
|
+
}
|
|
4537
|
+
}
|
|
4538
|
+
return [...normalized];
|
|
4539
|
+
}
|
|
4540
|
+
function buildSearchRootsKey(searchRoots) {
|
|
4541
|
+
return searchRoots.join("\n");
|
|
4542
|
+
}
|
|
4543
|
+
function buildVueSfcPathIndex(searchRoots) {
|
|
4544
|
+
const indexKey = buildSearchRootsKey(searchRoots);
|
|
4545
|
+
const existingIndex = indexedVueSfcPathsByRoots.get(indexKey);
|
|
4546
|
+
if (existingIndex) {
|
|
4547
|
+
return existingIndex;
|
|
4334
4548
|
}
|
|
4335
4549
|
const index = /* @__PURE__ */ new Map();
|
|
4336
4550
|
const ignoredDirNames = /* @__PURE__ */ new Set([
|
|
@@ -4348,22 +4562,6 @@ function buildVueSfcPathIndex() {
|
|
|
4348
4562
|
"out",
|
|
4349
4563
|
"tmp"
|
|
4350
4564
|
]);
|
|
4351
|
-
const cwd = process.cwd();
|
|
4352
|
-
const parent = path.resolve(cwd, "..");
|
|
4353
|
-
const searchRoots = /* @__PURE__ */ new Set();
|
|
4354
|
-
const enqueueIfDirectory = (dirPath) => {
|
|
4355
|
-
try {
|
|
4356
|
-
if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
|
|
4357
|
-
searchRoots.add(dirPath);
|
|
4358
|
-
}
|
|
4359
|
-
} catch {
|
|
4360
|
-
}
|
|
4361
|
-
};
|
|
4362
|
-
for (const root of [cwd, parent]) {
|
|
4363
|
-
for (const rel of ["src", "components", "app", "shared", "packages", "libs"]) {
|
|
4364
|
-
enqueueIfDirectory(path.resolve(root, rel));
|
|
4365
|
-
}
|
|
4366
|
-
}
|
|
4367
4565
|
const stack = [...searchRoots];
|
|
4368
4566
|
const seenDirs = /* @__PURE__ */ new Set();
|
|
4369
4567
|
while (stack.length > 0) {
|
|
@@ -4396,52 +4594,58 @@ function buildVueSfcPathIndex() {
|
|
|
4396
4594
|
index.set(entry.name, matches);
|
|
4397
4595
|
}
|
|
4398
4596
|
}
|
|
4399
|
-
|
|
4597
|
+
indexedVueSfcPathsByRoots.set(indexKey, index);
|
|
4400
4598
|
return index;
|
|
4401
4599
|
}
|
|
4402
|
-
function tryResolveSfcPathForTag(tag, vueFilesPathMap) {
|
|
4403
|
-
if (inferredSfcPathByTag.has(tag)) {
|
|
4404
|
-
return inferredSfcPathByTag.get(tag) ?? null;
|
|
4405
|
-
}
|
|
4600
|
+
function tryResolveSfcPathForTag(tag, vueFilesPathMap, wrapperSearchRoots = []) {
|
|
4406
4601
|
const registeredPath = vueFilesPathMap?.get(tag);
|
|
4602
|
+
const normalizedSearchRoots = normalizeSearchRoots(wrapperSearchRoots);
|
|
4603
|
+
const lookupKey = `${tag}
|
|
4604
|
+
${registeredPath ?? ""}
|
|
4605
|
+
${buildSearchRootsKey(normalizedSearchRoots)}`;
|
|
4606
|
+
if (inferredSfcPathByLookup.has(lookupKey)) {
|
|
4607
|
+
return inferredSfcPathByLookup.get(lookupKey) ?? null;
|
|
4608
|
+
}
|
|
4407
4609
|
const candidateNames = [`${tag}.vue`, `${toKebabCaseTag(tag)}.vue`];
|
|
4408
4610
|
const directCandidates = [
|
|
4409
4611
|
registeredPath ? path.resolve(process.cwd(), registeredPath) : null,
|
|
4410
|
-
...
|
|
4411
|
-
path.resolve(process.cwd(), "src/components", fileName),
|
|
4412
|
-
path.resolve(process.cwd(), "components", fileName),
|
|
4413
|
-
path.resolve(process.cwd(), "app/components", fileName),
|
|
4414
|
-
path.resolve(process.cwd(), "shared/ui/src/components", fileName),
|
|
4415
|
-
path.resolve(process.cwd(), "..", "shared/ui/src/components", fileName)
|
|
4416
|
-
])
|
|
4612
|
+
...normalizedSearchRoots.flatMap((root) => candidateNames.map((fileName) => path.join(root, fileName)))
|
|
4417
4613
|
].filter((value) => !!value);
|
|
4418
4614
|
const directMatch = directCandidates.find((candidatePath) => fs.existsSync(candidatePath));
|
|
4419
4615
|
if (directMatch) {
|
|
4420
|
-
|
|
4616
|
+
inferredSfcPathByLookup.set(lookupKey, directMatch);
|
|
4421
4617
|
return directMatch;
|
|
4422
4618
|
}
|
|
4423
|
-
|
|
4619
|
+
if (normalizedSearchRoots.length === 0) {
|
|
4620
|
+
inferredSfcPathByLookup.set(lookupKey, null);
|
|
4621
|
+
return null;
|
|
4622
|
+
}
|
|
4623
|
+
const index = buildVueSfcPathIndex(normalizedSearchRoots);
|
|
4424
4624
|
const scorePath = (candidatePath) => {
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
}
|
|
4432
|
-
return score;
|
|
4625
|
+
const rootIndex = normalizedSearchRoots.findIndex((root) => {
|
|
4626
|
+
return candidatePath === root || candidatePath.startsWith(root + path.sep);
|
|
4627
|
+
});
|
|
4628
|
+
const effectiveRootIndex = rootIndex === -1 ? Number.MAX_SAFE_INTEGER : rootIndex;
|
|
4629
|
+
const relativeLength = rootIndex === -1 ? candidatePath.length : path.relative(normalizedSearchRoots[rootIndex], candidatePath).length;
|
|
4630
|
+
return [effectiveRootIndex, relativeLength, candidatePath];
|
|
4433
4631
|
};
|
|
4632
|
+
let bestMatch = null;
|
|
4633
|
+
let bestScore = null;
|
|
4434
4634
|
for (const fileName of candidateNames) {
|
|
4435
4635
|
const matches = index.get(fileName);
|
|
4436
4636
|
if (!matches?.length) {
|
|
4437
4637
|
continue;
|
|
4438
4638
|
}
|
|
4439
|
-
const
|
|
4440
|
-
|
|
4441
|
-
|
|
4639
|
+
for (const match of matches) {
|
|
4640
|
+
const score = scorePath(match);
|
|
4641
|
+
if (!bestScore || score[0] < bestScore[0] || score[0] === bestScore[0] && score[1] < bestScore[1] || score[0] === bestScore[0] && score[1] === bestScore[1] && score[2] < bestScore[2]) {
|
|
4642
|
+
bestScore = score;
|
|
4643
|
+
bestMatch = match;
|
|
4644
|
+
}
|
|
4645
|
+
}
|
|
4442
4646
|
}
|
|
4443
|
-
|
|
4444
|
-
return
|
|
4647
|
+
inferredSfcPathByLookup.set(lookupKey, bestMatch);
|
|
4648
|
+
return bestMatch;
|
|
4445
4649
|
}
|
|
4446
4650
|
function trimLeadingSeparators(value) {
|
|
4447
4651
|
if (!value) {
|
|
@@ -4556,7 +4760,7 @@ function tryExtractStableHintFromConditionalExpressionSource(source) {
|
|
|
4556
4760
|
return null;
|
|
4557
4761
|
}
|
|
4558
4762
|
}
|
|
4559
|
-
function tryInferNativeWrapperRoleFromSfc(tag, vueFilesPathMap, seenTags = /* @__PURE__ */ new Set()) {
|
|
4763
|
+
function tryInferNativeWrapperRoleFromSfc(tag, vueFilesPathMap, wrapperSearchRoots = [], seenTags = /* @__PURE__ */ new Set()) {
|
|
4560
4764
|
const first = tag.charCodeAt(0);
|
|
4561
4765
|
const isUpper = isAsciiUppercaseLetterCode(first);
|
|
4562
4766
|
if (!isUpper)
|
|
@@ -4564,19 +4768,23 @@ function tryInferNativeWrapperRoleFromSfc(tag, vueFilesPathMap, seenTags = /* @_
|
|
|
4564
4768
|
if (seenTags.has(tag)) {
|
|
4565
4769
|
return null;
|
|
4566
4770
|
}
|
|
4567
|
-
const
|
|
4771
|
+
const normalizedSearchRoots = normalizeSearchRoots(wrapperSearchRoots);
|
|
4772
|
+
const cacheKey = `${tag}
|
|
4773
|
+
${vueFilesPathMap?.get(tag) ?? ""}
|
|
4774
|
+
${buildSearchRootsKey(normalizedSearchRoots)}`;
|
|
4775
|
+
const cached = inferredNativeWrapperConfigByLookup.get(cacheKey);
|
|
4568
4776
|
if (cached)
|
|
4569
4777
|
return cached.role ? cached : null;
|
|
4570
|
-
const filePath = tryResolveSfcPathForTag(tag, vueFilesPathMap);
|
|
4778
|
+
const filePath = tryResolveSfcPathForTag(tag, vueFilesPathMap, normalizedSearchRoots);
|
|
4571
4779
|
if (!filePath) {
|
|
4572
|
-
|
|
4780
|
+
inferredNativeWrapperConfigByLookup.set(cacheKey, { role: "" });
|
|
4573
4781
|
return null;
|
|
4574
4782
|
}
|
|
4575
4783
|
let source = "";
|
|
4576
4784
|
try {
|
|
4577
4785
|
source = fs.readFileSync(filePath, "utf8");
|
|
4578
4786
|
} catch {
|
|
4579
|
-
|
|
4787
|
+
inferredNativeWrapperConfigByLookup.set(cacheKey, { role: "" });
|
|
4580
4788
|
return null;
|
|
4581
4789
|
}
|
|
4582
4790
|
let template = "";
|
|
@@ -4584,11 +4792,11 @@ function tryInferNativeWrapperRoleFromSfc(tag, vueFilesPathMap, seenTags = /* @_
|
|
|
4584
4792
|
const { descriptor } = parse$1(source, { filename: filePath });
|
|
4585
4793
|
template = descriptor.template?.content ?? "";
|
|
4586
4794
|
} catch {
|
|
4587
|
-
|
|
4795
|
+
inferredNativeWrapperConfigByLookup.set(cacheKey, { role: "" });
|
|
4588
4796
|
return null;
|
|
4589
4797
|
}
|
|
4590
4798
|
if (!template.trim()) {
|
|
4591
|
-
|
|
4799
|
+
inferredNativeWrapperConfigByLookup.set(cacheKey, { role: "" });
|
|
4592
4800
|
return null;
|
|
4593
4801
|
}
|
|
4594
4802
|
try {
|
|
@@ -4607,6 +4815,7 @@ function tryInferNativeWrapperRoleFromSfc(tag, vueFilesPathMap, seenTags = /* @_
|
|
|
4607
4815
|
});
|
|
4608
4816
|
return (typeAttr?.value?.content ?? "").toLowerCase();
|
|
4609
4817
|
};
|
|
4818
|
+
let inferRoleFromNode;
|
|
4610
4819
|
const inferRoleFromElement = (element) => {
|
|
4611
4820
|
const elementTag = (element.tag || "").toLowerCase();
|
|
4612
4821
|
const inputType = getStaticTypeAttribute(element);
|
|
@@ -4626,7 +4835,7 @@ function tryInferNativeWrapperRoleFromSfc(tag, vueFilesPathMap, seenTags = /* @_
|
|
|
4626
4835
|
if (elementTag === "button" || elementTag === "ubutton")
|
|
4627
4836
|
return { role: "button" };
|
|
4628
4837
|
if (isComponentLikeTag(element.tag) && element.tag !== tag) {
|
|
4629
|
-
const nested = tryInferNativeWrapperRoleFromSfc(element.tag, vueFilesPathMap, nextSeen);
|
|
4838
|
+
const nested = tryInferNativeWrapperRoleFromSfc(element.tag, vueFilesPathMap, normalizedSearchRoots, nextSeen);
|
|
4630
4839
|
if (nested)
|
|
4631
4840
|
return nested;
|
|
4632
4841
|
}
|
|
@@ -4637,7 +4846,7 @@ function tryInferNativeWrapperRoleFromSfc(tag, vueFilesPathMap, seenTags = /* @_
|
|
|
4637
4846
|
}
|
|
4638
4847
|
return null;
|
|
4639
4848
|
};
|
|
4640
|
-
|
|
4849
|
+
inferRoleFromNode = (node) => {
|
|
4641
4850
|
if (!node || typeof node !== "object")
|
|
4642
4851
|
return null;
|
|
4643
4852
|
if (node.type === NodeTypes.ELEMENT) {
|
|
@@ -4662,14 +4871,14 @@ function tryInferNativeWrapperRoleFromSfc(tag, vueFilesPathMap, seenTags = /* @_
|
|
|
4662
4871
|
};
|
|
4663
4872
|
const inferred = inferRoleFromNode(ast);
|
|
4664
4873
|
if (inferred) {
|
|
4665
|
-
|
|
4874
|
+
inferredNativeWrapperConfigByLookup.set(cacheKey, inferred);
|
|
4666
4875
|
return inferred;
|
|
4667
4876
|
}
|
|
4668
4877
|
} catch {
|
|
4669
|
-
|
|
4878
|
+
inferredNativeWrapperConfigByLookup.set(cacheKey, { role: "" });
|
|
4670
4879
|
return null;
|
|
4671
4880
|
}
|
|
4672
|
-
|
|
4881
|
+
inferredNativeWrapperConfigByLookup.set(cacheKey, { role: "" });
|
|
4673
4882
|
return null;
|
|
4674
4883
|
}
|
|
4675
4884
|
function tryWrapClickDirectiveForTestEvents(element, testIdAttribute) {
|
|
@@ -4844,6 +5053,7 @@ function createTestIdTransform(componentName, componentHierarchyMap, nativeWrapp
|
|
|
4844
5053
|
const nameCollisionBehavior = options.nameCollisionBehavior ?? "suffix";
|
|
4845
5054
|
const warn = options.warn;
|
|
4846
5055
|
const vueFilesPathMap = options.vueFilesPathMap;
|
|
5056
|
+
const wrapperSearchRoots = options.wrapperSearchRoots ?? [];
|
|
4847
5057
|
const safeRealpath = (p) => {
|
|
4848
5058
|
try {
|
|
4849
5059
|
return fs.existsSync(p) ? fs.realpathSync(p) : p;
|
|
@@ -4969,7 +5179,7 @@ function createTestIdTransform(componentName, componentHierarchyMap, nativeWrapp
|
|
|
4969
5179
|
dependencies.usedComponentSet.add(element.tag);
|
|
4970
5180
|
}
|
|
4971
5181
|
if (!nativeWrappers[element.tag]) {
|
|
4972
|
-
const inferred = tryInferNativeWrapperRoleFromSfc(element.tag, vueFilesPathMap);
|
|
5182
|
+
const inferred = tryInferNativeWrapperRoleFromSfc(element.tag, vueFilesPathMap, wrapperSearchRoots);
|
|
4973
5183
|
if (inferred?.role) {
|
|
4974
5184
|
nativeWrappers[element.tag] = { role: inferred.role, inferred: true };
|
|
4975
5185
|
} else if (element.tag.endsWith("Button") || element.tag === "AylaButton") {
|
|
@@ -5260,6 +5470,7 @@ function createDevProcessorPlugin(options) {
|
|
|
5260
5470
|
excludedComponents,
|
|
5261
5471
|
viewsDir,
|
|
5262
5472
|
scanDirs,
|
|
5473
|
+
getWrapperSearchRoots,
|
|
5263
5474
|
projectRootRef,
|
|
5264
5475
|
normalizedBasePagePath,
|
|
5265
5476
|
basePageClassPath,
|
|
@@ -5410,7 +5621,11 @@ function createDevProcessorPlugin(options) {
|
|
|
5410
5621
|
nativeWrappers,
|
|
5411
5622
|
excludedComponents,
|
|
5412
5623
|
getViewsDirAbs(),
|
|
5413
|
-
{
|
|
5624
|
+
{
|
|
5625
|
+
existingIdBehavior: "preserve",
|
|
5626
|
+
testIdAttribute,
|
|
5627
|
+
wrapperSearchRoots: getWrapperSearchRoots()
|
|
5628
|
+
}
|
|
5414
5629
|
)
|
|
5415
5630
|
]
|
|
5416
5631
|
});
|
|
@@ -5635,6 +5850,7 @@ function createSupportPlugins(options) {
|
|
|
5635
5850
|
excludedComponents,
|
|
5636
5851
|
viewsDir,
|
|
5637
5852
|
scanDirs,
|
|
5853
|
+
getWrapperSearchRoots,
|
|
5638
5854
|
outDir,
|
|
5639
5855
|
emitLanguages,
|
|
5640
5856
|
csharp,
|
|
@@ -5697,6 +5913,7 @@ function createSupportPlugins(options) {
|
|
|
5697
5913
|
excludedComponents,
|
|
5698
5914
|
viewsDir,
|
|
5699
5915
|
scanDirs,
|
|
5916
|
+
getWrapperSearchRoots,
|
|
5700
5917
|
projectRootRef,
|
|
5701
5918
|
normalizedBasePagePath,
|
|
5702
5919
|
basePageClassPath,
|
|
@@ -5869,6 +6086,7 @@ function createVuePluginWithTestIds(options) {
|
|
|
5869
6086
|
testIdAttribute,
|
|
5870
6087
|
loggerRef,
|
|
5871
6088
|
scanDirs = ["src"],
|
|
6089
|
+
getWrapperSearchRoots,
|
|
5872
6090
|
getProjectRoot
|
|
5873
6091
|
} = options;
|
|
5874
6092
|
const getComponentNameFromPath = (filename) => {
|
|
@@ -5937,7 +6155,8 @@ function createVuePluginWithTestIds(options) {
|
|
|
5937
6155
|
testIdAttribute,
|
|
5938
6156
|
nameCollisionBehavior,
|
|
5939
6157
|
warn: (message) => loggerRef.current.warn(message),
|
|
5940
|
-
vueFilesPathMap
|
|
6158
|
+
vueFilesPathMap,
|
|
6159
|
+
wrapperSearchRoots: getWrapperSearchRoots()
|
|
5941
6160
|
}
|
|
5942
6161
|
)
|
|
5943
6162
|
);
|
|
@@ -5966,7 +6185,8 @@ function createVuePluginWithTestIds(options) {
|
|
|
5966
6185
|
testIdAttribute,
|
|
5967
6186
|
nameCollisionBehavior,
|
|
5968
6187
|
warn: (message) => loggerRef.current.warn(message),
|
|
5969
|
-
vueFilesPathMap
|
|
6188
|
+
vueFilesPathMap,
|
|
6189
|
+
wrapperSearchRoots: getWrapperSearchRoots()
|
|
5970
6190
|
}
|
|
5971
6191
|
);
|
|
5972
6192
|
perFileTransform.set(componentName, transform);
|
|
@@ -6034,6 +6254,13 @@ function assertNonEmptyString(value, name) {
|
|
|
6034
6254
|
throw new Error(`${name} must be a non-empty string.`);
|
|
6035
6255
|
}
|
|
6036
6256
|
}
|
|
6257
|
+
function assertNonEmptyStringArray(value, name) {
|
|
6258
|
+
if (!value)
|
|
6259
|
+
return;
|
|
6260
|
+
for (const [index, entry] of value.entries()) {
|
|
6261
|
+
assertNonEmptyString(entry, `${name}[${index}]`);
|
|
6262
|
+
}
|
|
6263
|
+
}
|
|
6037
6264
|
function assertRouterModuleShims(value, name) {
|
|
6038
6265
|
if (!value)
|
|
6039
6266
|
return;
|
|
@@ -6096,11 +6323,12 @@ function createVuePomGeneratorPlugins(options = {}) {
|
|
|
6096
6323
|
const vueOptions = options.vueOptions;
|
|
6097
6324
|
const viewsDir = injection.viewsDir ?? "src/views";
|
|
6098
6325
|
const scanDirs = injection.scanDirs ?? ["src"];
|
|
6326
|
+
const wrapperSearchRoots = injection.wrapperSearchRoots ?? [];
|
|
6099
6327
|
const nativeWrappers = injection.nativeWrappers ?? {};
|
|
6100
6328
|
const excludedComponents = injection.excludeComponents ?? [];
|
|
6101
6329
|
const testIdAttribute = (injection.attribute ?? "data-testid").trim() || "data-testid";
|
|
6102
6330
|
const existingIdBehavior = injection.existingIdBehavior ?? "preserve";
|
|
6103
|
-
const outDir = (generationOptions?.outDir ?? "tests/playwright/
|
|
6331
|
+
const outDir = (generationOptions?.outDir ?? "tests/playwright/__generated__").trim();
|
|
6104
6332
|
const emitLanguages = generationOptions?.emit && generationOptions.emit.length ? generationOptions.emit : ["ts"];
|
|
6105
6333
|
const nameCollisionBehavior = generationOptions?.nameCollisionBehavior ?? "suffix";
|
|
6106
6334
|
const routerEntry = generationOptions?.router?.entry;
|
|
@@ -6126,6 +6354,7 @@ function createVuePomGeneratorPlugins(options = {}) {
|
|
|
6126
6354
|
loggerRef.current = createLogger({ verbosity, viteLogger: config.logger });
|
|
6127
6355
|
assertNonEmptyString(testIdAttribute, "[vue-pom-generator] injection.attribute");
|
|
6128
6356
|
assertNonEmptyString(viewsDir, "[vue-pom-generator] injection.viewsDir");
|
|
6357
|
+
assertNonEmptyStringArray(wrapperSearchRoots, "[vue-pom-generator] injection.wrapperSearchRoots");
|
|
6129
6358
|
if (generationEnabled) {
|
|
6130
6359
|
assertNonEmptyString(outDir, "[vue-pom-generator] generation.outDir");
|
|
6131
6360
|
assertRouterModuleShims(routerModuleShims, "[vue-pom-generator] generation.router.moduleShims");
|
|
@@ -6138,6 +6367,7 @@ function createVuePomGeneratorPlugins(options = {}) {
|
|
|
6138
6367
|
}
|
|
6139
6368
|
};
|
|
6140
6369
|
const getViewsDirAbs = () => resolveFromProjectRoot(projectRootRef.current, viewsDir);
|
|
6370
|
+
const getWrapperSearchRootsAbs = () => wrapperSearchRoots.map((root) => resolveFromProjectRoot(projectRootRef.current, root));
|
|
6141
6371
|
const componentTestIds = /* @__PURE__ */ new Map();
|
|
6142
6372
|
const elementMetadata = /* @__PURE__ */ new Map();
|
|
6143
6373
|
const semanticNameMap = /* @__PURE__ */ new Map();
|
|
@@ -6157,6 +6387,7 @@ function createVuePomGeneratorPlugins(options = {}) {
|
|
|
6157
6387
|
testIdAttribute,
|
|
6158
6388
|
loggerRef,
|
|
6159
6389
|
scanDirs,
|
|
6390
|
+
getWrapperSearchRoots: getWrapperSearchRootsAbs,
|
|
6160
6391
|
getProjectRoot: () => projectRootRef.current
|
|
6161
6392
|
});
|
|
6162
6393
|
const routerAwarePoms = typeof routerEntry === "string" && routerEntry.trim().length > 0 || routerType === "nuxt";
|
|
@@ -6168,6 +6399,7 @@ function createVuePomGeneratorPlugins(options = {}) {
|
|
|
6168
6399
|
excludedComponents,
|
|
6169
6400
|
viewsDir,
|
|
6170
6401
|
scanDirs,
|
|
6402
|
+
getWrapperSearchRoots: getWrapperSearchRootsAbs,
|
|
6171
6403
|
outDir,
|
|
6172
6404
|
emitLanguages,
|
|
6173
6405
|
csharp,
|