@immense/vue-pom-generator 1.0.42 → 1.0.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/RELEASE_NOTES.md +16 -21
- package/class-generation/Pointer.ts +43 -2
- package/class-generation/index.ts +27 -4
- package/dist/class-generation/Pointer.d.ts +2 -0
- package/dist/class-generation/Pointer.d.ts.map +1 -1
- package/dist/index.cjs +311 -148
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +312 -149
- package/dist/index.mjs.map +1 -1
- package/dist/plugin/create-vue-pom-generator-plugins.d.ts.map +1 -1
- package/dist/plugin/support/build-plugin.d.ts +12 -2
- package/dist/plugin/support/build-plugin.d.ts.map +1 -1
- package/dist/plugin/support/dev-plugin.d.ts +2 -0
- package/dist/plugin/support/dev-plugin.d.ts.map +1 -1
- package/dist/plugin/support-plugins.d.ts +2 -0
- package/dist/plugin/support-plugins.d.ts.map +1 -1
- package/dist/plugin/types.d.ts +1 -1
- package/dist/plugin/types.d.ts.map +1 -1
- package/dist/tests/build-serve-parity.test.d.ts +2 -0
- package/dist/tests/build-serve-parity.test.d.ts.map +1 -0
- package/dist/tests/pointer.test.d.ts +2 -0
- package/dist/tests/pointer.test.d.ts.map +1 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -26,13 +26,13 @@ const path = require("node:path");
|
|
|
26
26
|
const process = require("node:process");
|
|
27
27
|
const node_url = require("node:url");
|
|
28
28
|
const fs = require("node:fs");
|
|
29
|
+
const compilerDom = require("@vue/compiler-dom");
|
|
30
|
+
const compilerSfc = require("@vue/compiler-sfc");
|
|
29
31
|
const parser = require("@babel/parser");
|
|
30
32
|
const jsdom = require("jsdom");
|
|
31
33
|
const compilerCore = require("@vue/compiler-core");
|
|
32
34
|
const types = require("@babel/types");
|
|
33
35
|
const node_perf_hooks = require("node:perf_hooks");
|
|
34
|
-
const compilerDom = require("@vue/compiler-dom");
|
|
35
|
-
const compilerSfc = require("@vue/compiler-sfc");
|
|
36
36
|
const virtualImport = require("vite-plugin-virtual");
|
|
37
37
|
const vue = require("@vitejs/plugin-vue");
|
|
38
38
|
var _documentCurrentScript = typeof document !== "undefined" ? document.currentScript : null;
|
|
@@ -3712,6 +3712,26 @@ function generateAggregatedCSharpFiles(componentHierarchyMap, outDir, options =
|
|
|
3712
3712
|
" protected IPage Page { get; }",
|
|
3713
3713
|
` protected ILocator LocatorByTestId(string testId) => Page.Locator($"[${testIdAttribute}=\\"{testId}\\"]");`,
|
|
3714
3714
|
" protected ILocator LocatorWithinTestIdByLabel(string rootTestId, string label, bool exact = true) => LocatorByTestId(rootTestId).GetByLabel(label, new() { Exact = exact });",
|
|
3715
|
+
" protected async Task<ILocator> ResolveEditableLocatorAsync(ILocator locator)",
|
|
3716
|
+
" {",
|
|
3717
|
+
' var isEditable = await locator.EvaluateAsync<bool>(@"el => {',
|
|
3718
|
+
" if (!el || !(el instanceof HTMLElement)) return false;",
|
|
3719
|
+
" const tagName = el.tagName.toLowerCase();",
|
|
3720
|
+
" return tagName === 'input' || tagName === 'textarea' || tagName === 'select' || el.isContentEditable;",
|
|
3721
|
+
' }");',
|
|
3722
|
+
" if (isEditable)",
|
|
3723
|
+
" {",
|
|
3724
|
+
" return locator;",
|
|
3725
|
+
" }",
|
|
3726
|
+
"",
|
|
3727
|
+
` var descendant = locator.Locator("input, textarea, select, [contenteditable=''], [contenteditable='true'], [contenteditable]:not([contenteditable='false'])").First;`,
|
|
3728
|
+
" if (await descendant.CountAsync() > 0)",
|
|
3729
|
+
" {",
|
|
3730
|
+
" return descendant;",
|
|
3731
|
+
" }",
|
|
3732
|
+
"",
|
|
3733
|
+
" return locator;",
|
|
3734
|
+
" }",
|
|
3715
3735
|
" protected async Task ClickWithinTestIdByLabelAsync(string rootTestId, string label, bool exact = true)",
|
|
3716
3736
|
" {",
|
|
3717
3737
|
" await LocatorWithinTestIdByLabel(rootTestId, label, exact).ClickAsync();",
|
|
@@ -3813,7 +3833,8 @@ function generateAggregatedCSharpFiles(componentHierarchyMap, outDir, options =
|
|
|
3813
3833
|
const callSuffix = pom.formattedDataTestId.includes("${") ? `(${args})` : "";
|
|
3814
3834
|
const emitActionCall = (locatorAccess) => {
|
|
3815
3835
|
if (pom.nativeRole === "input") {
|
|
3816
|
-
chunks.push(` await ${locatorAccess}
|
|
3836
|
+
chunks.push(` var editableLocator = await ResolveEditableLocatorAsync(${locatorAccess});`);
|
|
3837
|
+
chunks.push(" await editableLocator.FillAsync(text);");
|
|
3817
3838
|
} else if (pom.nativeRole === "select") {
|
|
3818
3839
|
chunks.push(` await ${locatorAccess}.SelectOptionAsync(value);`);
|
|
3819
3840
|
} else if (pom.nativeRole === "vselect") {
|
|
@@ -3841,7 +3862,8 @@ function generateAggregatedCSharpFiles(componentHierarchyMap, outDir, options =
|
|
|
3841
3862
|
chunks.push(" if (await locator.CountAsync() > 0)");
|
|
3842
3863
|
chunks.push(" {");
|
|
3843
3864
|
if (pom.nativeRole === "input") {
|
|
3844
|
-
chunks.push(" await locator
|
|
3865
|
+
chunks.push(" var editableLocator = await ResolveEditableLocatorAsync(locator);");
|
|
3866
|
+
chunks.push(" await editableLocator.FillAsync(text);");
|
|
3845
3867
|
} else if (pom.nativeRole === "select") {
|
|
3846
3868
|
chunks.push(" await locator.SelectOptionAsync(value);");
|
|
3847
3869
|
} else {
|
|
@@ -4065,7 +4087,8 @@ function generateViewObjectModelContent(componentName, dependencies, componentHi
|
|
|
4065
4087
|
if (!Object.prototype.hasOwnProperty.call(customPomClassIdentifierMap, a.className))
|
|
4066
4088
|
return false;
|
|
4067
4089
|
const scope = a.attachTo ?? "views";
|
|
4068
|
-
const
|
|
4090
|
+
const scopeMatchesBoth = scope === "both" || scope === "pagesAndComponents";
|
|
4091
|
+
const scopeOk = isView ? scope === "views" || scopeMatchesBoth : scope === "components" || scopeMatchesBoth;
|
|
4069
4092
|
if (!scopeOk)
|
|
4070
4093
|
return false;
|
|
4071
4094
|
return a.attachWhenUsesComponents.some((c) => hasChildComponent(c));
|
|
@@ -4768,148 +4791,6 @@ function getConstructor(childrenComponent, componentHierarchyMap, attachmentsFor
|
|
|
4768
4791
|
return `${content}
|
|
4769
4792
|
`;
|
|
4770
4793
|
}
|
|
4771
|
-
function summarizeHierarchyMap(componentHierarchyMap) {
|
|
4772
|
-
let interactiveComponentCount = 0;
|
|
4773
|
-
let dataTestIdCount = 0;
|
|
4774
|
-
for (const dependencies of componentHierarchyMap.values()) {
|
|
4775
|
-
const selectorCount = dependencies.dataTestIdSet?.size ?? 0;
|
|
4776
|
-
if (selectorCount > 0) {
|
|
4777
|
-
interactiveComponentCount += 1;
|
|
4778
|
-
dataTestIdCount += selectorCount;
|
|
4779
|
-
}
|
|
4780
|
-
}
|
|
4781
|
-
return {
|
|
4782
|
-
entryCount: componentHierarchyMap.size,
|
|
4783
|
-
interactiveComponentCount,
|
|
4784
|
-
dataTestIdCount
|
|
4785
|
-
};
|
|
4786
|
-
}
|
|
4787
|
-
function isLessRich(candidate, previous) {
|
|
4788
|
-
if (candidate.dataTestIdCount !== previous.dataTestIdCount) {
|
|
4789
|
-
return candidate.dataTestIdCount < previous.dataTestIdCount;
|
|
4790
|
-
}
|
|
4791
|
-
if (candidate.interactiveComponentCount !== previous.interactiveComponentCount) {
|
|
4792
|
-
return candidate.interactiveComponentCount < previous.interactiveComponentCount;
|
|
4793
|
-
}
|
|
4794
|
-
return candidate.entryCount < previous.entryCount;
|
|
4795
|
-
}
|
|
4796
|
-
function createBuildProcessorPlugin(options) {
|
|
4797
|
-
const {
|
|
4798
|
-
componentHierarchyMap,
|
|
4799
|
-
vueFilesPathMap,
|
|
4800
|
-
viewsDir,
|
|
4801
|
-
scanDirs,
|
|
4802
|
-
basePageClassPath,
|
|
4803
|
-
normalizedBasePagePath,
|
|
4804
|
-
outDir,
|
|
4805
|
-
emitLanguages,
|
|
4806
|
-
csharp,
|
|
4807
|
-
generateFixtures,
|
|
4808
|
-
customPomAttachments,
|
|
4809
|
-
projectRootRef,
|
|
4810
|
-
customPomDir,
|
|
4811
|
-
customPomImportAliases,
|
|
4812
|
-
customPomImportNameCollisionBehavior,
|
|
4813
|
-
testIdAttribute,
|
|
4814
|
-
routerAwarePoms,
|
|
4815
|
-
resolvedRouterEntry,
|
|
4816
|
-
routerType,
|
|
4817
|
-
routerModuleShims,
|
|
4818
|
-
loggerRef
|
|
4819
|
-
} = options;
|
|
4820
|
-
let lastGeneratedMetrics = {
|
|
4821
|
-
entryCount: 0,
|
|
4822
|
-
interactiveComponentCount: 0,
|
|
4823
|
-
dataTestIdCount: 0
|
|
4824
|
-
};
|
|
4825
|
-
return {
|
|
4826
|
-
name: "vue-pom-generator-build",
|
|
4827
|
-
// This plugin exists to generate code on build output; it is not needed during dev-server HMR.
|
|
4828
|
-
apply: "build",
|
|
4829
|
-
enforce: "pre",
|
|
4830
|
-
async buildStart() {
|
|
4831
|
-
if (!routerAwarePoms) {
|
|
4832
|
-
setRouteNameToComponentNameMap(/* @__PURE__ */ new Map());
|
|
4833
|
-
setResolveToComponentNameFn(() => null);
|
|
4834
|
-
return;
|
|
4835
|
-
}
|
|
4836
|
-
let result;
|
|
4837
|
-
if (routerType === "nuxt") {
|
|
4838
|
-
result = await introspectNuxtPages(projectRootRef.current);
|
|
4839
|
-
} else {
|
|
4840
|
-
if (!resolvedRouterEntry)
|
|
4841
|
-
throw new Error("[vue-pom-generator] router.entry is required when router introspection is enabled.");
|
|
4842
|
-
result = await parseRouterFileFromCwd(resolvedRouterEntry, {
|
|
4843
|
-
moduleShims: routerModuleShims,
|
|
4844
|
-
componentNaming: {
|
|
4845
|
-
projectRoot: projectRootRef.current,
|
|
4846
|
-
viewsDirAbs: path.isAbsolute(viewsDir) ? viewsDir : path.resolve(projectRootRef.current, viewsDir),
|
|
4847
|
-
scanDirs
|
|
4848
|
-
}
|
|
4849
|
-
});
|
|
4850
|
-
}
|
|
4851
|
-
const { routeNameMap, routePathMap } = result;
|
|
4852
|
-
setRouteNameToComponentNameMap(routeNameMap);
|
|
4853
|
-
setResolveToComponentNameFn((to) => {
|
|
4854
|
-
if (typeof to === "string") {
|
|
4855
|
-
return routePathMap.get(to) ?? null;
|
|
4856
|
-
}
|
|
4857
|
-
const maybe = to;
|
|
4858
|
-
if (typeof maybe.name === "string" && maybe.name.length) {
|
|
4859
|
-
const key = toPascalCase(maybe.name);
|
|
4860
|
-
return routeNameMap.get(key) ?? null;
|
|
4861
|
-
}
|
|
4862
|
-
if (typeof maybe.path === "string" && maybe.path.length) {
|
|
4863
|
-
return routePathMap.get(maybe.path) ?? null;
|
|
4864
|
-
}
|
|
4865
|
-
return null;
|
|
4866
|
-
});
|
|
4867
|
-
if (!fs.existsSync(basePageClassPath)) {
|
|
4868
|
-
this.error(`BasePage.ts not found at ${basePageClassPath}. Ensure it is included in the build.`);
|
|
4869
|
-
}
|
|
4870
|
-
this.addWatchFile(basePageClassPath);
|
|
4871
|
-
const pointerPath = path.resolve(path.dirname(basePageClassPath), "Pointer.ts");
|
|
4872
|
-
if (!fs.existsSync(pointerPath)) {
|
|
4873
|
-
this.error(`Pointer.ts not found at ${pointerPath}. Ensure it is included in the build.`);
|
|
4874
|
-
}
|
|
4875
|
-
this.addWatchFile(pointerPath);
|
|
4876
|
-
},
|
|
4877
|
-
async buildEnd(error) {
|
|
4878
|
-
if (error) {
|
|
4879
|
-
return;
|
|
4880
|
-
}
|
|
4881
|
-
const metrics = summarizeHierarchyMap(componentHierarchyMap);
|
|
4882
|
-
if (metrics.dataTestIdCount <= 0) {
|
|
4883
|
-
return;
|
|
4884
|
-
}
|
|
4885
|
-
if (isLessRich(metrics, lastGeneratedMetrics)) {
|
|
4886
|
-
return;
|
|
4887
|
-
}
|
|
4888
|
-
await generateFiles(componentHierarchyMap, vueFilesPathMap, normalizedBasePagePath, {
|
|
4889
|
-
outDir,
|
|
4890
|
-
emitLanguages,
|
|
4891
|
-
csharp,
|
|
4892
|
-
generateFixtures,
|
|
4893
|
-
customPomAttachments,
|
|
4894
|
-
projectRoot: projectRootRef.current,
|
|
4895
|
-
customPomDir,
|
|
4896
|
-
customPomImportAliases,
|
|
4897
|
-
customPomImportNameCollisionBehavior,
|
|
4898
|
-
testIdAttribute,
|
|
4899
|
-
vueRouterFluentChaining: routerAwarePoms,
|
|
4900
|
-
routerEntry: resolvedRouterEntry,
|
|
4901
|
-
routerType,
|
|
4902
|
-
viewsDir,
|
|
4903
|
-
scanDirs
|
|
4904
|
-
});
|
|
4905
|
-
lastGeneratedMetrics = metrics;
|
|
4906
|
-
loggerRef.current.info(`generated POMs (${metrics.entryCount} entries, ${metrics.interactiveComponentCount} interactive components, ${metrics.dataTestIdCount} selectors)`);
|
|
4907
|
-
},
|
|
4908
|
-
closeBundle() {
|
|
4909
|
-
loggerRef.current.info("build complete");
|
|
4910
|
-
}
|
|
4911
|
-
};
|
|
4912
|
-
}
|
|
4913
4794
|
const TESTID_CLICK_EVENT_NAME = "__testid_event__";
|
|
4914
4795
|
const TESTID_CLICK_EVENT_STRICT_FLAG = "__testid_click_event_strict__";
|
|
4915
4796
|
const CLICK_EVENT_NAME = TESTID_CLICK_EVENT_NAME;
|
|
@@ -5992,6 +5873,265 @@ Fix: remove the explicit ${attrLabel}, or change existingIdBehavior to "overwrit
|
|
|
5992
5873
|
}
|
|
5993
5874
|
};
|
|
5994
5875
|
}
|
|
5876
|
+
function summarizeHierarchyMap(componentHierarchyMap) {
|
|
5877
|
+
let interactiveComponentCount = 0;
|
|
5878
|
+
let dataTestIdCount = 0;
|
|
5879
|
+
for (const dependencies of componentHierarchyMap.values()) {
|
|
5880
|
+
const selectorCount = dependencies.dataTestIdSet?.size ?? 0;
|
|
5881
|
+
if (selectorCount > 0) {
|
|
5882
|
+
interactiveComponentCount += 1;
|
|
5883
|
+
dataTestIdCount += selectorCount;
|
|
5884
|
+
}
|
|
5885
|
+
}
|
|
5886
|
+
return {
|
|
5887
|
+
entryCount: componentHierarchyMap.size,
|
|
5888
|
+
interactiveComponentCount,
|
|
5889
|
+
dataTestIdCount
|
|
5890
|
+
};
|
|
5891
|
+
}
|
|
5892
|
+
function isLessRich(candidate, previous) {
|
|
5893
|
+
if (candidate.dataTestIdCount !== previous.dataTestIdCount) {
|
|
5894
|
+
return candidate.dataTestIdCount < previous.dataTestIdCount;
|
|
5895
|
+
}
|
|
5896
|
+
if (candidate.interactiveComponentCount !== previous.interactiveComponentCount) {
|
|
5897
|
+
return candidate.interactiveComponentCount < previous.interactiveComponentCount;
|
|
5898
|
+
}
|
|
5899
|
+
return candidate.entryCount < previous.entryCount;
|
|
5900
|
+
}
|
|
5901
|
+
function createBuildProcessorPlugin(options) {
|
|
5902
|
+
const {
|
|
5903
|
+
componentHierarchyMap,
|
|
5904
|
+
vueFilesPathMap,
|
|
5905
|
+
viewsDir,
|
|
5906
|
+
scanDirs,
|
|
5907
|
+
basePageClassPath,
|
|
5908
|
+
normalizedBasePagePath,
|
|
5909
|
+
outDir,
|
|
5910
|
+
emitLanguages,
|
|
5911
|
+
csharp,
|
|
5912
|
+
generateFixtures,
|
|
5913
|
+
customPomAttachments,
|
|
5914
|
+
projectRootRef,
|
|
5915
|
+
customPomDir,
|
|
5916
|
+
customPomImportAliases,
|
|
5917
|
+
customPomImportNameCollisionBehavior,
|
|
5918
|
+
testIdAttribute,
|
|
5919
|
+
nameCollisionBehavior,
|
|
5920
|
+
existingIdBehavior,
|
|
5921
|
+
nativeWrappers,
|
|
5922
|
+
excludedComponents,
|
|
5923
|
+
getWrapperSearchRoots,
|
|
5924
|
+
routerAwarePoms,
|
|
5925
|
+
resolvedRouterEntry,
|
|
5926
|
+
routerType,
|
|
5927
|
+
routerModuleShims,
|
|
5928
|
+
loggerRef
|
|
5929
|
+
} = options;
|
|
5930
|
+
let lastGeneratedMetrics = {
|
|
5931
|
+
entryCount: 0,
|
|
5932
|
+
interactiveComponentCount: 0,
|
|
5933
|
+
dataTestIdCount: 0
|
|
5934
|
+
};
|
|
5935
|
+
const getViewsDirAbs = () => path.isAbsolute(viewsDir) ? viewsDir : path.resolve(projectRootRef.current, viewsDir);
|
|
5936
|
+
const getScriptInfo = (source, filename) => {
|
|
5937
|
+
try {
|
|
5938
|
+
const { descriptor } = compilerSfc.parse(source, { filename });
|
|
5939
|
+
if (!descriptor.script && !descriptor.scriptSetup)
|
|
5940
|
+
return { bindings: void 0, isScriptSetup: false };
|
|
5941
|
+
const scriptBlock = compilerSfc.compileScript(descriptor, { id: filename });
|
|
5942
|
+
return { bindings: scriptBlock.bindings, isScriptSetup: !!descriptor.scriptSetup };
|
|
5943
|
+
} catch {
|
|
5944
|
+
return { bindings: void 0, isScriptSetup: false };
|
|
5945
|
+
}
|
|
5946
|
+
};
|
|
5947
|
+
const supplementHierarchyFromFilesystem = () => {
|
|
5948
|
+
const walkFilesRecursive = (rootDir) => {
|
|
5949
|
+
const out = [];
|
|
5950
|
+
const stack = [rootDir];
|
|
5951
|
+
while (stack.length) {
|
|
5952
|
+
const dir = stack.pop();
|
|
5953
|
+
if (!dir) continue;
|
|
5954
|
+
let entries = [];
|
|
5955
|
+
try {
|
|
5956
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
5957
|
+
} catch {
|
|
5958
|
+
continue;
|
|
5959
|
+
}
|
|
5960
|
+
for (const ent of entries) {
|
|
5961
|
+
if (ent.isDirectory()) {
|
|
5962
|
+
if (ent.name === "node_modules" || ent.name === ".git" || ent.name === "dist")
|
|
5963
|
+
continue;
|
|
5964
|
+
stack.push(path.join(dir, ent.name));
|
|
5965
|
+
continue;
|
|
5966
|
+
}
|
|
5967
|
+
if (ent.isFile() && ent.name.endsWith(".vue")) {
|
|
5968
|
+
out.push(path.join(dir, ent.name));
|
|
5969
|
+
}
|
|
5970
|
+
}
|
|
5971
|
+
}
|
|
5972
|
+
return out;
|
|
5973
|
+
};
|
|
5974
|
+
let supplemented = 0;
|
|
5975
|
+
for (const dir of scanDirs) {
|
|
5976
|
+
const absDir = path.resolve(projectRootRef.current, dir);
|
|
5977
|
+
if (!fs.existsSync(absDir))
|
|
5978
|
+
continue;
|
|
5979
|
+
for (const filePath of walkFilesRecursive(absDir)) {
|
|
5980
|
+
const absolutePath = path.resolve(filePath);
|
|
5981
|
+
const componentName = resolveComponentNameFromPath({
|
|
5982
|
+
filename: absolutePath,
|
|
5983
|
+
projectRoot: projectRootRef.current,
|
|
5984
|
+
viewsDirAbs: getViewsDirAbs(),
|
|
5985
|
+
scanDirs,
|
|
5986
|
+
extraRoots: [process.cwd()]
|
|
5987
|
+
});
|
|
5988
|
+
if (componentHierarchyMap.has(componentName))
|
|
5989
|
+
continue;
|
|
5990
|
+
let sfc = "";
|
|
5991
|
+
try {
|
|
5992
|
+
sfc = fs.readFileSync(absolutePath, "utf8");
|
|
5993
|
+
} catch {
|
|
5994
|
+
continue;
|
|
5995
|
+
}
|
|
5996
|
+
const { descriptor } = compilerSfc.parse(sfc, { filename: absolutePath });
|
|
5997
|
+
const template = descriptor.template?.content ?? "";
|
|
5998
|
+
if (!template.trim()) {
|
|
5999
|
+
vueFilesPathMap.set(componentName, absolutePath);
|
|
6000
|
+
componentHierarchyMap.set(componentName, {
|
|
6001
|
+
filePath: absolutePath,
|
|
6002
|
+
childrenComponentSet: /* @__PURE__ */ new Set(),
|
|
6003
|
+
usedComponentSet: /* @__PURE__ */ new Set(),
|
|
6004
|
+
dataTestIdSet: /* @__PURE__ */ new Set(),
|
|
6005
|
+
isView: false,
|
|
6006
|
+
methodsContent: ""
|
|
6007
|
+
});
|
|
6008
|
+
supplemented++;
|
|
6009
|
+
continue;
|
|
6010
|
+
}
|
|
6011
|
+
const { bindings: bindingMetadata, isScriptSetup } = getScriptInfo(sfc, absolutePath);
|
|
6012
|
+
vueFilesPathMap.set(componentName, absolutePath);
|
|
6013
|
+
try {
|
|
6014
|
+
compilerDom__namespace.compile(template, {
|
|
6015
|
+
filename: absolutePath,
|
|
6016
|
+
prefixIdentifiers: true,
|
|
6017
|
+
inline: isScriptSetup,
|
|
6018
|
+
bindingMetadata,
|
|
6019
|
+
nodeTransforms: [
|
|
6020
|
+
createTestIdTransform(
|
|
6021
|
+
componentName,
|
|
6022
|
+
componentHierarchyMap,
|
|
6023
|
+
nativeWrappers,
|
|
6024
|
+
excludedComponents,
|
|
6025
|
+
getViewsDirAbs(),
|
|
6026
|
+
{
|
|
6027
|
+
existingIdBehavior: existingIdBehavior ?? "preserve",
|
|
6028
|
+
testIdAttribute,
|
|
6029
|
+
nameCollisionBehavior,
|
|
6030
|
+
warn: (message) => loggerRef.current.warn(message),
|
|
6031
|
+
vueFilesPathMap,
|
|
6032
|
+
wrapperSearchRoots: getWrapperSearchRoots()
|
|
6033
|
+
}
|
|
6034
|
+
)
|
|
6035
|
+
]
|
|
6036
|
+
});
|
|
6037
|
+
} catch {
|
|
6038
|
+
}
|
|
6039
|
+
supplemented++;
|
|
6040
|
+
}
|
|
6041
|
+
}
|
|
6042
|
+
if (supplemented > 0) {
|
|
6043
|
+
loggerRef.current.info(`supplemented ${supplemented} components from filesystem walk (not in build graph)`);
|
|
6044
|
+
}
|
|
6045
|
+
};
|
|
6046
|
+
return {
|
|
6047
|
+
name: "vue-pom-generator-build",
|
|
6048
|
+
// This plugin exists to generate code on build output; it is not needed during dev-server HMR.
|
|
6049
|
+
apply: "build",
|
|
6050
|
+
enforce: "pre",
|
|
6051
|
+
async buildStart() {
|
|
6052
|
+
if (!routerAwarePoms) {
|
|
6053
|
+
setRouteNameToComponentNameMap(/* @__PURE__ */ new Map());
|
|
6054
|
+
setResolveToComponentNameFn(() => null);
|
|
6055
|
+
return;
|
|
6056
|
+
}
|
|
6057
|
+
let result;
|
|
6058
|
+
if (routerType === "nuxt") {
|
|
6059
|
+
result = await introspectNuxtPages(projectRootRef.current);
|
|
6060
|
+
} else {
|
|
6061
|
+
if (!resolvedRouterEntry)
|
|
6062
|
+
throw new Error("[vue-pom-generator] router.entry is required when router introspection is enabled.");
|
|
6063
|
+
result = await parseRouterFileFromCwd(resolvedRouterEntry, {
|
|
6064
|
+
moduleShims: routerModuleShims,
|
|
6065
|
+
componentNaming: {
|
|
6066
|
+
projectRoot: projectRootRef.current,
|
|
6067
|
+
viewsDirAbs: path.isAbsolute(viewsDir) ? viewsDir : path.resolve(projectRootRef.current, viewsDir),
|
|
6068
|
+
scanDirs
|
|
6069
|
+
}
|
|
6070
|
+
});
|
|
6071
|
+
}
|
|
6072
|
+
const { routeNameMap, routePathMap } = result;
|
|
6073
|
+
setRouteNameToComponentNameMap(routeNameMap);
|
|
6074
|
+
setResolveToComponentNameFn((to) => {
|
|
6075
|
+
if (typeof to === "string") {
|
|
6076
|
+
return routePathMap.get(to) ?? null;
|
|
6077
|
+
}
|
|
6078
|
+
const maybe = to;
|
|
6079
|
+
if (typeof maybe.name === "string" && maybe.name.length) {
|
|
6080
|
+
const key = toPascalCase(maybe.name);
|
|
6081
|
+
return routeNameMap.get(key) ?? null;
|
|
6082
|
+
}
|
|
6083
|
+
if (typeof maybe.path === "string" && maybe.path.length) {
|
|
6084
|
+
return routePathMap.get(maybe.path) ?? null;
|
|
6085
|
+
}
|
|
6086
|
+
return null;
|
|
6087
|
+
});
|
|
6088
|
+
if (!fs.existsSync(basePageClassPath)) {
|
|
6089
|
+
this.error(`BasePage.ts not found at ${basePageClassPath}. Ensure it is included in the build.`);
|
|
6090
|
+
}
|
|
6091
|
+
this.addWatchFile(basePageClassPath);
|
|
6092
|
+
const pointerPath = path.resolve(path.dirname(basePageClassPath), "Pointer.ts");
|
|
6093
|
+
if (!fs.existsSync(pointerPath)) {
|
|
6094
|
+
this.error(`Pointer.ts not found at ${pointerPath}. Ensure it is included in the build.`);
|
|
6095
|
+
}
|
|
6096
|
+
this.addWatchFile(pointerPath);
|
|
6097
|
+
},
|
|
6098
|
+
async buildEnd(error) {
|
|
6099
|
+
if (error) {
|
|
6100
|
+
return;
|
|
6101
|
+
}
|
|
6102
|
+
supplementHierarchyFromFilesystem();
|
|
6103
|
+
const metrics = summarizeHierarchyMap(componentHierarchyMap);
|
|
6104
|
+
if (metrics.dataTestIdCount <= 0) {
|
|
6105
|
+
return;
|
|
6106
|
+
}
|
|
6107
|
+
if (isLessRich(metrics, lastGeneratedMetrics)) {
|
|
6108
|
+
return;
|
|
6109
|
+
}
|
|
6110
|
+
await generateFiles(componentHierarchyMap, vueFilesPathMap, normalizedBasePagePath, {
|
|
6111
|
+
outDir,
|
|
6112
|
+
emitLanguages,
|
|
6113
|
+
csharp,
|
|
6114
|
+
generateFixtures,
|
|
6115
|
+
customPomAttachments,
|
|
6116
|
+
projectRoot: projectRootRef.current,
|
|
6117
|
+
customPomDir,
|
|
6118
|
+
customPomImportAliases,
|
|
6119
|
+
customPomImportNameCollisionBehavior,
|
|
6120
|
+
testIdAttribute,
|
|
6121
|
+
vueRouterFluentChaining: routerAwarePoms,
|
|
6122
|
+
routerEntry: resolvedRouterEntry,
|
|
6123
|
+
routerType,
|
|
6124
|
+
viewsDir,
|
|
6125
|
+
scanDirs
|
|
6126
|
+
});
|
|
6127
|
+
lastGeneratedMetrics = metrics;
|
|
6128
|
+
loggerRef.current.info(`generated POMs (${metrics.entryCount} entries, ${metrics.interactiveComponentCount} interactive components, ${metrics.dataTestIdCount} selectors)`);
|
|
6129
|
+
},
|
|
6130
|
+
closeBundle() {
|
|
6131
|
+
loggerRef.current.info("build complete");
|
|
6132
|
+
}
|
|
6133
|
+
};
|
|
6134
|
+
}
|
|
5995
6135
|
function createDevProcessorPlugin(options) {
|
|
5996
6136
|
const {
|
|
5997
6137
|
nativeWrappers,
|
|
@@ -6011,6 +6151,7 @@ function createDevProcessorPlugin(options) {
|
|
|
6011
6151
|
customPomImportAliases,
|
|
6012
6152
|
customPomImportNameCollisionBehavior,
|
|
6013
6153
|
nameCollisionBehavior = "suffix",
|
|
6154
|
+
existingIdBehavior,
|
|
6014
6155
|
testIdAttribute,
|
|
6015
6156
|
routerAwarePoms,
|
|
6016
6157
|
resolvedRouterEntry,
|
|
@@ -6088,6 +6229,17 @@ function createDevProcessorPlugin(options) {
|
|
|
6088
6229
|
});
|
|
6089
6230
|
return descriptor.template?.content ?? "";
|
|
6090
6231
|
};
|
|
6232
|
+
const getScriptInfo = (source, filename) => {
|
|
6233
|
+
try {
|
|
6234
|
+
const { descriptor } = compilerSfc.parse(source, { filename });
|
|
6235
|
+
if (!descriptor.script && !descriptor.scriptSetup)
|
|
6236
|
+
return { bindings: void 0, isScriptSetup: false };
|
|
6237
|
+
const scriptBlock = compilerSfc.compileScript(descriptor, { id: filename });
|
|
6238
|
+
return { bindings: scriptBlock.bindings, isScriptSetup: !!descriptor.scriptSetup };
|
|
6239
|
+
} catch {
|
|
6240
|
+
return { bindings: void 0, isScriptSetup: false };
|
|
6241
|
+
}
|
|
6242
|
+
};
|
|
6091
6243
|
const walkFilesRecursive = (rootDir) => {
|
|
6092
6244
|
const out = [];
|
|
6093
6245
|
const stack = [rootDir];
|
|
@@ -6147,9 +6299,12 @@ function createDevProcessorPlugin(options) {
|
|
|
6147
6299
|
const template = extractTemplateFromSfc(sfc, absolutePath);
|
|
6148
6300
|
if (!template.trim())
|
|
6149
6301
|
return { componentName, ms: node_perf_hooks.performance.now() - started, compiled: true };
|
|
6302
|
+
const { bindings: bindingMetadata, isScriptSetup } = getScriptInfo(sfc, absolutePath);
|
|
6150
6303
|
compilerDom__namespace.compile(template, {
|
|
6151
6304
|
filename: absolutePath,
|
|
6152
6305
|
prefixIdentifiers: true,
|
|
6306
|
+
inline: isScriptSetup,
|
|
6307
|
+
bindingMetadata,
|
|
6153
6308
|
nodeTransforms: [
|
|
6154
6309
|
createTestIdTransform(
|
|
6155
6310
|
componentName,
|
|
@@ -6158,7 +6313,7 @@ function createDevProcessorPlugin(options) {
|
|
|
6158
6313
|
excludedComponents,
|
|
6159
6314
|
getViewsDirAbs(),
|
|
6160
6315
|
{
|
|
6161
|
-
existingIdBehavior: "preserve",
|
|
6316
|
+
existingIdBehavior: existingIdBehavior ?? "preserve",
|
|
6162
6317
|
nameCollisionBehavior,
|
|
6163
6318
|
testIdAttribute,
|
|
6164
6319
|
warn: (message) => loggerRef.current.warn(message),
|
|
@@ -6400,6 +6555,7 @@ function createSupportPlugins(options) {
|
|
|
6400
6555
|
scanDirs,
|
|
6401
6556
|
getWrapperSearchRoots,
|
|
6402
6557
|
nameCollisionBehavior = "suffix",
|
|
6558
|
+
existingIdBehavior,
|
|
6403
6559
|
outDir,
|
|
6404
6560
|
emitLanguages,
|
|
6405
6561
|
csharp,
|
|
@@ -6453,6 +6609,11 @@ function createSupportPlugins(options) {
|
|
|
6453
6609
|
customPomImportAliases,
|
|
6454
6610
|
customPomImportNameCollisionBehavior,
|
|
6455
6611
|
testIdAttribute,
|
|
6612
|
+
nameCollisionBehavior,
|
|
6613
|
+
existingIdBehavior,
|
|
6614
|
+
nativeWrappers,
|
|
6615
|
+
excludedComponents,
|
|
6616
|
+
getWrapperSearchRoots,
|
|
6456
6617
|
routerAwarePoms,
|
|
6457
6618
|
routerType,
|
|
6458
6619
|
resolvedRouterEntry,
|
|
@@ -6477,6 +6638,7 @@ function createSupportPlugins(options) {
|
|
|
6477
6638
|
customPomImportAliases,
|
|
6478
6639
|
customPomImportNameCollisionBehavior,
|
|
6479
6640
|
nameCollisionBehavior,
|
|
6641
|
+
existingIdBehavior,
|
|
6480
6642
|
testIdAttribute,
|
|
6481
6643
|
routerAwarePoms,
|
|
6482
6644
|
routerType,
|
|
@@ -7058,6 +7220,7 @@ function createVuePomGeneratorPlugins(options = {}) {
|
|
|
7058
7220
|
scanDirs,
|
|
7059
7221
|
getWrapperSearchRoots: getWrapperSearchRootsAbs,
|
|
7060
7222
|
nameCollisionBehavior,
|
|
7223
|
+
existingIdBehavior,
|
|
7061
7224
|
outDir,
|
|
7062
7225
|
emitLanguages,
|
|
7063
7226
|
csharp,
|