@immense/vue-pom-generator 1.0.41 → 1.0.43
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 +22 -26
- package/dist/index.cjs +369 -223
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +370 -224
- 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/tests/build-serve-parity.test.d.ts +2 -0
- package/dist/tests/build-serve-parity.test.d.ts.map +1 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2,14 +2,14 @@ import path from "node:path";
|
|
|
2
2
|
import process from "node:process";
|
|
3
3
|
import { pathToFileURL, fileURLToPath } from "node:url";
|
|
4
4
|
import fs from "node:fs";
|
|
5
|
+
import * as compilerDom from "@vue/compiler-dom";
|
|
6
|
+
import { parse as parse$2 } from "@vue/compiler-dom";
|
|
7
|
+
import { parse as parse$1, compileScript } from "@vue/compiler-sfc";
|
|
5
8
|
import { parseExpression, parse } from "@babel/parser";
|
|
6
9
|
import { JSDOM } from "jsdom";
|
|
7
10
|
import { NodeTypes, stringifyExpression, ConstantTypes, createSimpleExpression } from "@vue/compiler-core";
|
|
8
11
|
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";
|
|
9
12
|
import { performance } from "node:perf_hooks";
|
|
10
|
-
import * as compilerDom from "@vue/compiler-dom";
|
|
11
|
-
import { parse as parse$2 } from "@vue/compiler-dom";
|
|
12
|
-
import { parse as parse$1 } from "@vue/compiler-sfc";
|
|
13
13
|
import virtualImport from "vite-plugin-virtual";
|
|
14
14
|
import vue from "@vitejs/plugin-vue";
|
|
15
15
|
const VUE_POM_GENERATOR_LOG_PREFIX = "[vue-pom-generator]";
|
|
@@ -4727,148 +4727,6 @@ function getConstructor(childrenComponent, componentHierarchyMap, attachmentsFor
|
|
|
4727
4727
|
return `${content}
|
|
4728
4728
|
`;
|
|
4729
4729
|
}
|
|
4730
|
-
function summarizeHierarchyMap(componentHierarchyMap) {
|
|
4731
|
-
let interactiveComponentCount = 0;
|
|
4732
|
-
let dataTestIdCount = 0;
|
|
4733
|
-
for (const dependencies of componentHierarchyMap.values()) {
|
|
4734
|
-
const selectorCount = dependencies.dataTestIdSet?.size ?? 0;
|
|
4735
|
-
if (selectorCount > 0) {
|
|
4736
|
-
interactiveComponentCount += 1;
|
|
4737
|
-
dataTestIdCount += selectorCount;
|
|
4738
|
-
}
|
|
4739
|
-
}
|
|
4740
|
-
return {
|
|
4741
|
-
entryCount: componentHierarchyMap.size,
|
|
4742
|
-
interactiveComponentCount,
|
|
4743
|
-
dataTestIdCount
|
|
4744
|
-
};
|
|
4745
|
-
}
|
|
4746
|
-
function isLessRich(candidate, previous) {
|
|
4747
|
-
if (candidate.dataTestIdCount !== previous.dataTestIdCount) {
|
|
4748
|
-
return candidate.dataTestIdCount < previous.dataTestIdCount;
|
|
4749
|
-
}
|
|
4750
|
-
if (candidate.interactiveComponentCount !== previous.interactiveComponentCount) {
|
|
4751
|
-
return candidate.interactiveComponentCount < previous.interactiveComponentCount;
|
|
4752
|
-
}
|
|
4753
|
-
return candidate.entryCount < previous.entryCount;
|
|
4754
|
-
}
|
|
4755
|
-
function createBuildProcessorPlugin(options) {
|
|
4756
|
-
const {
|
|
4757
|
-
componentHierarchyMap,
|
|
4758
|
-
vueFilesPathMap,
|
|
4759
|
-
viewsDir,
|
|
4760
|
-
scanDirs,
|
|
4761
|
-
basePageClassPath,
|
|
4762
|
-
normalizedBasePagePath,
|
|
4763
|
-
outDir,
|
|
4764
|
-
emitLanguages,
|
|
4765
|
-
csharp,
|
|
4766
|
-
generateFixtures,
|
|
4767
|
-
customPomAttachments,
|
|
4768
|
-
projectRootRef,
|
|
4769
|
-
customPomDir,
|
|
4770
|
-
customPomImportAliases,
|
|
4771
|
-
customPomImportNameCollisionBehavior,
|
|
4772
|
-
testIdAttribute,
|
|
4773
|
-
routerAwarePoms,
|
|
4774
|
-
resolvedRouterEntry,
|
|
4775
|
-
routerType,
|
|
4776
|
-
routerModuleShims,
|
|
4777
|
-
loggerRef
|
|
4778
|
-
} = options;
|
|
4779
|
-
let lastGeneratedMetrics = {
|
|
4780
|
-
entryCount: 0,
|
|
4781
|
-
interactiveComponentCount: 0,
|
|
4782
|
-
dataTestIdCount: 0
|
|
4783
|
-
};
|
|
4784
|
-
return {
|
|
4785
|
-
name: "vue-pom-generator-build",
|
|
4786
|
-
// This plugin exists to generate code on build output; it is not needed during dev-server HMR.
|
|
4787
|
-
apply: "build",
|
|
4788
|
-
enforce: "pre",
|
|
4789
|
-
async buildStart() {
|
|
4790
|
-
if (!routerAwarePoms) {
|
|
4791
|
-
setRouteNameToComponentNameMap(/* @__PURE__ */ new Map());
|
|
4792
|
-
setResolveToComponentNameFn(() => null);
|
|
4793
|
-
return;
|
|
4794
|
-
}
|
|
4795
|
-
let result;
|
|
4796
|
-
if (routerType === "nuxt") {
|
|
4797
|
-
result = await introspectNuxtPages(projectRootRef.current);
|
|
4798
|
-
} else {
|
|
4799
|
-
if (!resolvedRouterEntry)
|
|
4800
|
-
throw new Error("[vue-pom-generator] router.entry is required when router introspection is enabled.");
|
|
4801
|
-
result = await parseRouterFileFromCwd(resolvedRouterEntry, {
|
|
4802
|
-
moduleShims: routerModuleShims,
|
|
4803
|
-
componentNaming: {
|
|
4804
|
-
projectRoot: projectRootRef.current,
|
|
4805
|
-
viewsDirAbs: path.isAbsolute(viewsDir) ? viewsDir : path.resolve(projectRootRef.current, viewsDir),
|
|
4806
|
-
scanDirs
|
|
4807
|
-
}
|
|
4808
|
-
});
|
|
4809
|
-
}
|
|
4810
|
-
const { routeNameMap, routePathMap } = result;
|
|
4811
|
-
setRouteNameToComponentNameMap(routeNameMap);
|
|
4812
|
-
setResolveToComponentNameFn((to) => {
|
|
4813
|
-
if (typeof to === "string") {
|
|
4814
|
-
return routePathMap.get(to) ?? null;
|
|
4815
|
-
}
|
|
4816
|
-
const maybe = to;
|
|
4817
|
-
if (typeof maybe.name === "string" && maybe.name.length) {
|
|
4818
|
-
const key = toPascalCase(maybe.name);
|
|
4819
|
-
return routeNameMap.get(key) ?? null;
|
|
4820
|
-
}
|
|
4821
|
-
if (typeof maybe.path === "string" && maybe.path.length) {
|
|
4822
|
-
return routePathMap.get(maybe.path) ?? null;
|
|
4823
|
-
}
|
|
4824
|
-
return null;
|
|
4825
|
-
});
|
|
4826
|
-
if (!fs.existsSync(basePageClassPath)) {
|
|
4827
|
-
this.error(`BasePage.ts not found at ${basePageClassPath}. Ensure it is included in the build.`);
|
|
4828
|
-
}
|
|
4829
|
-
this.addWatchFile(basePageClassPath);
|
|
4830
|
-
const pointerPath = path.resolve(path.dirname(basePageClassPath), "Pointer.ts");
|
|
4831
|
-
if (!fs.existsSync(pointerPath)) {
|
|
4832
|
-
this.error(`Pointer.ts not found at ${pointerPath}. Ensure it is included in the build.`);
|
|
4833
|
-
}
|
|
4834
|
-
this.addWatchFile(pointerPath);
|
|
4835
|
-
},
|
|
4836
|
-
async buildEnd(error) {
|
|
4837
|
-
if (error) {
|
|
4838
|
-
return;
|
|
4839
|
-
}
|
|
4840
|
-
const metrics = summarizeHierarchyMap(componentHierarchyMap);
|
|
4841
|
-
if (metrics.dataTestIdCount <= 0) {
|
|
4842
|
-
return;
|
|
4843
|
-
}
|
|
4844
|
-
if (isLessRich(metrics, lastGeneratedMetrics)) {
|
|
4845
|
-
return;
|
|
4846
|
-
}
|
|
4847
|
-
await generateFiles(componentHierarchyMap, vueFilesPathMap, normalizedBasePagePath, {
|
|
4848
|
-
outDir,
|
|
4849
|
-
emitLanguages,
|
|
4850
|
-
csharp,
|
|
4851
|
-
generateFixtures,
|
|
4852
|
-
customPomAttachments,
|
|
4853
|
-
projectRoot: projectRootRef.current,
|
|
4854
|
-
customPomDir,
|
|
4855
|
-
customPomImportAliases,
|
|
4856
|
-
customPomImportNameCollisionBehavior,
|
|
4857
|
-
testIdAttribute,
|
|
4858
|
-
vueRouterFluentChaining: routerAwarePoms,
|
|
4859
|
-
routerEntry: resolvedRouterEntry,
|
|
4860
|
-
routerType,
|
|
4861
|
-
viewsDir,
|
|
4862
|
-
scanDirs
|
|
4863
|
-
});
|
|
4864
|
-
lastGeneratedMetrics = metrics;
|
|
4865
|
-
loggerRef.current.info(`generated POMs (${metrics.entryCount} entries, ${metrics.interactiveComponentCount} interactive components, ${metrics.dataTestIdCount} selectors)`);
|
|
4866
|
-
},
|
|
4867
|
-
closeBundle() {
|
|
4868
|
-
loggerRef.current.info("build complete");
|
|
4869
|
-
}
|
|
4870
|
-
};
|
|
4871
|
-
}
|
|
4872
4730
|
const TESTID_CLICK_EVENT_NAME = "__testid_event__";
|
|
4873
4731
|
const TESTID_CLICK_EVENT_STRICT_FLAG = "__testid_click_event_strict__";
|
|
4874
4732
|
const CLICK_EVENT_NAME = TESTID_CLICK_EVENT_NAME;
|
|
@@ -5951,6 +5809,265 @@ Fix: remove the explicit ${attrLabel}, or change existingIdBehavior to "overwrit
|
|
|
5951
5809
|
}
|
|
5952
5810
|
};
|
|
5953
5811
|
}
|
|
5812
|
+
function summarizeHierarchyMap(componentHierarchyMap) {
|
|
5813
|
+
let interactiveComponentCount = 0;
|
|
5814
|
+
let dataTestIdCount = 0;
|
|
5815
|
+
for (const dependencies of componentHierarchyMap.values()) {
|
|
5816
|
+
const selectorCount = dependencies.dataTestIdSet?.size ?? 0;
|
|
5817
|
+
if (selectorCount > 0) {
|
|
5818
|
+
interactiveComponentCount += 1;
|
|
5819
|
+
dataTestIdCount += selectorCount;
|
|
5820
|
+
}
|
|
5821
|
+
}
|
|
5822
|
+
return {
|
|
5823
|
+
entryCount: componentHierarchyMap.size,
|
|
5824
|
+
interactiveComponentCount,
|
|
5825
|
+
dataTestIdCount
|
|
5826
|
+
};
|
|
5827
|
+
}
|
|
5828
|
+
function isLessRich(candidate, previous) {
|
|
5829
|
+
if (candidate.dataTestIdCount !== previous.dataTestIdCount) {
|
|
5830
|
+
return candidate.dataTestIdCount < previous.dataTestIdCount;
|
|
5831
|
+
}
|
|
5832
|
+
if (candidate.interactiveComponentCount !== previous.interactiveComponentCount) {
|
|
5833
|
+
return candidate.interactiveComponentCount < previous.interactiveComponentCount;
|
|
5834
|
+
}
|
|
5835
|
+
return candidate.entryCount < previous.entryCount;
|
|
5836
|
+
}
|
|
5837
|
+
function createBuildProcessorPlugin(options) {
|
|
5838
|
+
const {
|
|
5839
|
+
componentHierarchyMap,
|
|
5840
|
+
vueFilesPathMap,
|
|
5841
|
+
viewsDir,
|
|
5842
|
+
scanDirs,
|
|
5843
|
+
basePageClassPath,
|
|
5844
|
+
normalizedBasePagePath,
|
|
5845
|
+
outDir,
|
|
5846
|
+
emitLanguages,
|
|
5847
|
+
csharp,
|
|
5848
|
+
generateFixtures,
|
|
5849
|
+
customPomAttachments,
|
|
5850
|
+
projectRootRef,
|
|
5851
|
+
customPomDir,
|
|
5852
|
+
customPomImportAliases,
|
|
5853
|
+
customPomImportNameCollisionBehavior,
|
|
5854
|
+
testIdAttribute,
|
|
5855
|
+
nameCollisionBehavior,
|
|
5856
|
+
existingIdBehavior,
|
|
5857
|
+
nativeWrappers,
|
|
5858
|
+
excludedComponents,
|
|
5859
|
+
getWrapperSearchRoots,
|
|
5860
|
+
routerAwarePoms,
|
|
5861
|
+
resolvedRouterEntry,
|
|
5862
|
+
routerType,
|
|
5863
|
+
routerModuleShims,
|
|
5864
|
+
loggerRef
|
|
5865
|
+
} = options;
|
|
5866
|
+
let lastGeneratedMetrics = {
|
|
5867
|
+
entryCount: 0,
|
|
5868
|
+
interactiveComponentCount: 0,
|
|
5869
|
+
dataTestIdCount: 0
|
|
5870
|
+
};
|
|
5871
|
+
const getViewsDirAbs = () => path.isAbsolute(viewsDir) ? viewsDir : path.resolve(projectRootRef.current, viewsDir);
|
|
5872
|
+
const getScriptInfo = (source, filename) => {
|
|
5873
|
+
try {
|
|
5874
|
+
const { descriptor } = parse$1(source, { filename });
|
|
5875
|
+
if (!descriptor.script && !descriptor.scriptSetup)
|
|
5876
|
+
return { bindings: void 0, isScriptSetup: false };
|
|
5877
|
+
const scriptBlock = compileScript(descriptor, { id: filename });
|
|
5878
|
+
return { bindings: scriptBlock.bindings, isScriptSetup: !!descriptor.scriptSetup };
|
|
5879
|
+
} catch {
|
|
5880
|
+
return { bindings: void 0, isScriptSetup: false };
|
|
5881
|
+
}
|
|
5882
|
+
};
|
|
5883
|
+
const supplementHierarchyFromFilesystem = () => {
|
|
5884
|
+
const walkFilesRecursive = (rootDir) => {
|
|
5885
|
+
const out = [];
|
|
5886
|
+
const stack = [rootDir];
|
|
5887
|
+
while (stack.length) {
|
|
5888
|
+
const dir = stack.pop();
|
|
5889
|
+
if (!dir) continue;
|
|
5890
|
+
let entries = [];
|
|
5891
|
+
try {
|
|
5892
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
5893
|
+
} catch {
|
|
5894
|
+
continue;
|
|
5895
|
+
}
|
|
5896
|
+
for (const ent of entries) {
|
|
5897
|
+
if (ent.isDirectory()) {
|
|
5898
|
+
if (ent.name === "node_modules" || ent.name === ".git" || ent.name === "dist")
|
|
5899
|
+
continue;
|
|
5900
|
+
stack.push(path.join(dir, ent.name));
|
|
5901
|
+
continue;
|
|
5902
|
+
}
|
|
5903
|
+
if (ent.isFile() && ent.name.endsWith(".vue")) {
|
|
5904
|
+
out.push(path.join(dir, ent.name));
|
|
5905
|
+
}
|
|
5906
|
+
}
|
|
5907
|
+
}
|
|
5908
|
+
return out;
|
|
5909
|
+
};
|
|
5910
|
+
let supplemented = 0;
|
|
5911
|
+
for (const dir of scanDirs) {
|
|
5912
|
+
const absDir = path.resolve(projectRootRef.current, dir);
|
|
5913
|
+
if (!fs.existsSync(absDir))
|
|
5914
|
+
continue;
|
|
5915
|
+
for (const filePath of walkFilesRecursive(absDir)) {
|
|
5916
|
+
const absolutePath = path.resolve(filePath);
|
|
5917
|
+
const componentName = resolveComponentNameFromPath({
|
|
5918
|
+
filename: absolutePath,
|
|
5919
|
+
projectRoot: projectRootRef.current,
|
|
5920
|
+
viewsDirAbs: getViewsDirAbs(),
|
|
5921
|
+
scanDirs,
|
|
5922
|
+
extraRoots: [process.cwd()]
|
|
5923
|
+
});
|
|
5924
|
+
if (componentHierarchyMap.has(componentName))
|
|
5925
|
+
continue;
|
|
5926
|
+
let sfc = "";
|
|
5927
|
+
try {
|
|
5928
|
+
sfc = fs.readFileSync(absolutePath, "utf8");
|
|
5929
|
+
} catch {
|
|
5930
|
+
continue;
|
|
5931
|
+
}
|
|
5932
|
+
const { descriptor } = parse$1(sfc, { filename: absolutePath });
|
|
5933
|
+
const template = descriptor.template?.content ?? "";
|
|
5934
|
+
if (!template.trim()) {
|
|
5935
|
+
vueFilesPathMap.set(componentName, absolutePath);
|
|
5936
|
+
componentHierarchyMap.set(componentName, {
|
|
5937
|
+
filePath: absolutePath,
|
|
5938
|
+
childrenComponentSet: /* @__PURE__ */ new Set(),
|
|
5939
|
+
usedComponentSet: /* @__PURE__ */ new Set(),
|
|
5940
|
+
dataTestIdSet: /* @__PURE__ */ new Set(),
|
|
5941
|
+
isView: false,
|
|
5942
|
+
methodsContent: ""
|
|
5943
|
+
});
|
|
5944
|
+
supplemented++;
|
|
5945
|
+
continue;
|
|
5946
|
+
}
|
|
5947
|
+
const { bindings: bindingMetadata, isScriptSetup } = getScriptInfo(sfc, absolutePath);
|
|
5948
|
+
vueFilesPathMap.set(componentName, absolutePath);
|
|
5949
|
+
try {
|
|
5950
|
+
compilerDom.compile(template, {
|
|
5951
|
+
filename: absolutePath,
|
|
5952
|
+
prefixIdentifiers: true,
|
|
5953
|
+
inline: isScriptSetup,
|
|
5954
|
+
bindingMetadata,
|
|
5955
|
+
nodeTransforms: [
|
|
5956
|
+
createTestIdTransform(
|
|
5957
|
+
componentName,
|
|
5958
|
+
componentHierarchyMap,
|
|
5959
|
+
nativeWrappers,
|
|
5960
|
+
excludedComponents,
|
|
5961
|
+
getViewsDirAbs(),
|
|
5962
|
+
{
|
|
5963
|
+
existingIdBehavior: existingIdBehavior ?? "preserve",
|
|
5964
|
+
testIdAttribute,
|
|
5965
|
+
nameCollisionBehavior,
|
|
5966
|
+
warn: (message) => loggerRef.current.warn(message),
|
|
5967
|
+
vueFilesPathMap,
|
|
5968
|
+
wrapperSearchRoots: getWrapperSearchRoots()
|
|
5969
|
+
}
|
|
5970
|
+
)
|
|
5971
|
+
]
|
|
5972
|
+
});
|
|
5973
|
+
} catch {
|
|
5974
|
+
}
|
|
5975
|
+
supplemented++;
|
|
5976
|
+
}
|
|
5977
|
+
}
|
|
5978
|
+
if (supplemented > 0) {
|
|
5979
|
+
loggerRef.current.info(`supplemented ${supplemented} components from filesystem walk (not in build graph)`);
|
|
5980
|
+
}
|
|
5981
|
+
};
|
|
5982
|
+
return {
|
|
5983
|
+
name: "vue-pom-generator-build",
|
|
5984
|
+
// This plugin exists to generate code on build output; it is not needed during dev-server HMR.
|
|
5985
|
+
apply: "build",
|
|
5986
|
+
enforce: "pre",
|
|
5987
|
+
async buildStart() {
|
|
5988
|
+
if (!routerAwarePoms) {
|
|
5989
|
+
setRouteNameToComponentNameMap(/* @__PURE__ */ new Map());
|
|
5990
|
+
setResolveToComponentNameFn(() => null);
|
|
5991
|
+
return;
|
|
5992
|
+
}
|
|
5993
|
+
let result;
|
|
5994
|
+
if (routerType === "nuxt") {
|
|
5995
|
+
result = await introspectNuxtPages(projectRootRef.current);
|
|
5996
|
+
} else {
|
|
5997
|
+
if (!resolvedRouterEntry)
|
|
5998
|
+
throw new Error("[vue-pom-generator] router.entry is required when router introspection is enabled.");
|
|
5999
|
+
result = await parseRouterFileFromCwd(resolvedRouterEntry, {
|
|
6000
|
+
moduleShims: routerModuleShims,
|
|
6001
|
+
componentNaming: {
|
|
6002
|
+
projectRoot: projectRootRef.current,
|
|
6003
|
+
viewsDirAbs: path.isAbsolute(viewsDir) ? viewsDir : path.resolve(projectRootRef.current, viewsDir),
|
|
6004
|
+
scanDirs
|
|
6005
|
+
}
|
|
6006
|
+
});
|
|
6007
|
+
}
|
|
6008
|
+
const { routeNameMap, routePathMap } = result;
|
|
6009
|
+
setRouteNameToComponentNameMap(routeNameMap);
|
|
6010
|
+
setResolveToComponentNameFn((to) => {
|
|
6011
|
+
if (typeof to === "string") {
|
|
6012
|
+
return routePathMap.get(to) ?? null;
|
|
6013
|
+
}
|
|
6014
|
+
const maybe = to;
|
|
6015
|
+
if (typeof maybe.name === "string" && maybe.name.length) {
|
|
6016
|
+
const key = toPascalCase(maybe.name);
|
|
6017
|
+
return routeNameMap.get(key) ?? null;
|
|
6018
|
+
}
|
|
6019
|
+
if (typeof maybe.path === "string" && maybe.path.length) {
|
|
6020
|
+
return routePathMap.get(maybe.path) ?? null;
|
|
6021
|
+
}
|
|
6022
|
+
return null;
|
|
6023
|
+
});
|
|
6024
|
+
if (!fs.existsSync(basePageClassPath)) {
|
|
6025
|
+
this.error(`BasePage.ts not found at ${basePageClassPath}. Ensure it is included in the build.`);
|
|
6026
|
+
}
|
|
6027
|
+
this.addWatchFile(basePageClassPath);
|
|
6028
|
+
const pointerPath = path.resolve(path.dirname(basePageClassPath), "Pointer.ts");
|
|
6029
|
+
if (!fs.existsSync(pointerPath)) {
|
|
6030
|
+
this.error(`Pointer.ts not found at ${pointerPath}. Ensure it is included in the build.`);
|
|
6031
|
+
}
|
|
6032
|
+
this.addWatchFile(pointerPath);
|
|
6033
|
+
},
|
|
6034
|
+
async buildEnd(error) {
|
|
6035
|
+
if (error) {
|
|
6036
|
+
return;
|
|
6037
|
+
}
|
|
6038
|
+
supplementHierarchyFromFilesystem();
|
|
6039
|
+
const metrics = summarizeHierarchyMap(componentHierarchyMap);
|
|
6040
|
+
if (metrics.dataTestIdCount <= 0) {
|
|
6041
|
+
return;
|
|
6042
|
+
}
|
|
6043
|
+
if (isLessRich(metrics, lastGeneratedMetrics)) {
|
|
6044
|
+
return;
|
|
6045
|
+
}
|
|
6046
|
+
await generateFiles(componentHierarchyMap, vueFilesPathMap, normalizedBasePagePath, {
|
|
6047
|
+
outDir,
|
|
6048
|
+
emitLanguages,
|
|
6049
|
+
csharp,
|
|
6050
|
+
generateFixtures,
|
|
6051
|
+
customPomAttachments,
|
|
6052
|
+
projectRoot: projectRootRef.current,
|
|
6053
|
+
customPomDir,
|
|
6054
|
+
customPomImportAliases,
|
|
6055
|
+
customPomImportNameCollisionBehavior,
|
|
6056
|
+
testIdAttribute,
|
|
6057
|
+
vueRouterFluentChaining: routerAwarePoms,
|
|
6058
|
+
routerEntry: resolvedRouterEntry,
|
|
6059
|
+
routerType,
|
|
6060
|
+
viewsDir,
|
|
6061
|
+
scanDirs
|
|
6062
|
+
});
|
|
6063
|
+
lastGeneratedMetrics = metrics;
|
|
6064
|
+
loggerRef.current.info(`generated POMs (${metrics.entryCount} entries, ${metrics.interactiveComponentCount} interactive components, ${metrics.dataTestIdCount} selectors)`);
|
|
6065
|
+
},
|
|
6066
|
+
closeBundle() {
|
|
6067
|
+
loggerRef.current.info("build complete");
|
|
6068
|
+
}
|
|
6069
|
+
};
|
|
6070
|
+
}
|
|
5954
6071
|
function createDevProcessorPlugin(options) {
|
|
5955
6072
|
const {
|
|
5956
6073
|
nativeWrappers,
|
|
@@ -5970,6 +6087,7 @@ function createDevProcessorPlugin(options) {
|
|
|
5970
6087
|
customPomImportAliases,
|
|
5971
6088
|
customPomImportNameCollisionBehavior,
|
|
5972
6089
|
nameCollisionBehavior = "suffix",
|
|
6090
|
+
existingIdBehavior,
|
|
5973
6091
|
testIdAttribute,
|
|
5974
6092
|
routerAwarePoms,
|
|
5975
6093
|
resolvedRouterEntry,
|
|
@@ -5996,7 +6114,7 @@ function createDevProcessorPlugin(options) {
|
|
|
5996
6114
|
return;
|
|
5997
6115
|
scheduleVueFileRegen(ctx.file, "hmr");
|
|
5998
6116
|
},
|
|
5999
|
-
configureServer(server) {
|
|
6117
|
+
async configureServer(server) {
|
|
6000
6118
|
const getViewsDirAbs = () => path.isAbsolute(viewsDir) ? viewsDir : path.resolve(projectRootRef.current, viewsDir);
|
|
6001
6119
|
const routerInitPromise = (async () => {
|
|
6002
6120
|
if (!routerAwarePoms) {
|
|
@@ -6047,6 +6165,17 @@ function createDevProcessorPlugin(options) {
|
|
|
6047
6165
|
});
|
|
6048
6166
|
return descriptor.template?.content ?? "";
|
|
6049
6167
|
};
|
|
6168
|
+
const getScriptInfo = (source, filename) => {
|
|
6169
|
+
try {
|
|
6170
|
+
const { descriptor } = parse$1(source, { filename });
|
|
6171
|
+
if (!descriptor.script && !descriptor.scriptSetup)
|
|
6172
|
+
return { bindings: void 0, isScriptSetup: false };
|
|
6173
|
+
const scriptBlock = compileScript(descriptor, { id: filename });
|
|
6174
|
+
return { bindings: scriptBlock.bindings, isScriptSetup: !!descriptor.scriptSetup };
|
|
6175
|
+
} catch {
|
|
6176
|
+
return { bindings: void 0, isScriptSetup: false };
|
|
6177
|
+
}
|
|
6178
|
+
};
|
|
6050
6179
|
const walkFilesRecursive = (rootDir) => {
|
|
6051
6180
|
const out = [];
|
|
6052
6181
|
const stack = [rootDir];
|
|
@@ -6073,8 +6202,8 @@ function createDevProcessorPlugin(options) {
|
|
|
6073
6202
|
}
|
|
6074
6203
|
return out;
|
|
6075
6204
|
};
|
|
6076
|
-
|
|
6077
|
-
|
|
6205
|
+
let snapshotHierarchy = /* @__PURE__ */ new Map();
|
|
6206
|
+
let snapshotVuePathMap = /* @__PURE__ */ new Map();
|
|
6078
6207
|
const filePathToComponentName = /* @__PURE__ */ new Map();
|
|
6079
6208
|
const getComponentNameForFile = (filePath) => {
|
|
6080
6209
|
const normalized = path.resolve(filePath);
|
|
@@ -6091,12 +6220,12 @@ function createDevProcessorPlugin(options) {
|
|
|
6091
6220
|
filePathToComponentName.set(normalized, name);
|
|
6092
6221
|
return name;
|
|
6093
6222
|
};
|
|
6094
|
-
const compileVueFileIntoSnapshot = (filePath) => {
|
|
6223
|
+
const compileVueFileIntoSnapshot = (filePath, targetHierarchy = snapshotHierarchy, targetVuePathMap = snapshotVuePathMap) => {
|
|
6095
6224
|
const started = performance.now();
|
|
6096
6225
|
const absolutePath = path.resolve(filePath);
|
|
6097
6226
|
const componentName = getComponentNameForFile(absolutePath);
|
|
6098
|
-
|
|
6099
|
-
|
|
6227
|
+
targetVuePathMap.set(componentName, absolutePath);
|
|
6228
|
+
targetHierarchy.delete(componentName);
|
|
6100
6229
|
let sfc = "";
|
|
6101
6230
|
try {
|
|
6102
6231
|
sfc = fs.readFileSync(absolutePath, "utf8");
|
|
@@ -6106,36 +6235,36 @@ function createDevProcessorPlugin(options) {
|
|
|
6106
6235
|
const template = extractTemplateFromSfc(sfc, absolutePath);
|
|
6107
6236
|
if (!template.trim())
|
|
6108
6237
|
return { componentName, ms: performance.now() - started, compiled: true };
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
-
|
|
6130
|
-
|
|
6131
|
-
|
|
6132
|
-
}
|
|
6238
|
+
const { bindings: bindingMetadata, isScriptSetup } = getScriptInfo(sfc, absolutePath);
|
|
6239
|
+
compilerDom.compile(template, {
|
|
6240
|
+
filename: absolutePath,
|
|
6241
|
+
prefixIdentifiers: true,
|
|
6242
|
+
inline: isScriptSetup,
|
|
6243
|
+
bindingMetadata,
|
|
6244
|
+
nodeTransforms: [
|
|
6245
|
+
createTestIdTransform(
|
|
6246
|
+
componentName,
|
|
6247
|
+
targetHierarchy,
|
|
6248
|
+
nativeWrappers,
|
|
6249
|
+
excludedComponents,
|
|
6250
|
+
getViewsDirAbs(),
|
|
6251
|
+
{
|
|
6252
|
+
existingIdBehavior: existingIdBehavior ?? "preserve",
|
|
6253
|
+
nameCollisionBehavior,
|
|
6254
|
+
testIdAttribute,
|
|
6255
|
+
warn: (message) => loggerRef.current.warn(message),
|
|
6256
|
+
vueFilesPathMap: targetVuePathMap,
|
|
6257
|
+
wrapperSearchRoots: getWrapperSearchRoots()
|
|
6258
|
+
}
|
|
6259
|
+
)
|
|
6260
|
+
]
|
|
6261
|
+
});
|
|
6133
6262
|
return { componentName, ms: performance.now() - started, compiled: true };
|
|
6134
6263
|
};
|
|
6135
6264
|
const fullRebuildSnapshotFromFilesystem = () => {
|
|
6136
6265
|
const t0 = performance.now();
|
|
6137
|
-
|
|
6138
|
-
|
|
6266
|
+
const nextHierarchy = /* @__PURE__ */ new Map();
|
|
6267
|
+
const nextVuePathMap = /* @__PURE__ */ new Map();
|
|
6139
6268
|
filePathToComponentName.clear();
|
|
6140
6269
|
let totalVueFiles = 0;
|
|
6141
6270
|
let compiledCount = 0;
|
|
@@ -6146,11 +6275,13 @@ function createDevProcessorPlugin(options) {
|
|
|
6146
6275
|
const vueFiles = walkFilesRecursive(absDir);
|
|
6147
6276
|
totalVueFiles += vueFiles.length;
|
|
6148
6277
|
for (const file of vueFiles) {
|
|
6149
|
-
const res = compileVueFileIntoSnapshot(file);
|
|
6278
|
+
const res = compileVueFileIntoSnapshot(file, nextHierarchy, nextVuePathMap);
|
|
6150
6279
|
if (res.compiled)
|
|
6151
6280
|
compiledCount++;
|
|
6152
6281
|
}
|
|
6153
6282
|
}
|
|
6283
|
+
snapshotHierarchy = nextHierarchy;
|
|
6284
|
+
snapshotVuePathMap = nextVuePathMap;
|
|
6154
6285
|
const t1 = performance.now();
|
|
6155
6286
|
logInfo(`initial scan: found ${totalVueFiles} .vue files in ${scanDirs.join(", ")}`);
|
|
6156
6287
|
logInfo(`initial compile: ${compiledCount}/${totalVueFiles} files in ${formatMs(t1 - t0)} (components=${snapshotHierarchy.size})`);
|
|
@@ -6177,6 +6308,10 @@ function createDevProcessorPlugin(options) {
|
|
|
6177
6308
|
const t1 = performance.now();
|
|
6178
6309
|
logInfo(`generate(${reason}): components=${snapshotHierarchy.size} in ${formatMs(t1 - t0)}`);
|
|
6179
6310
|
};
|
|
6311
|
+
let timer = null;
|
|
6312
|
+
let maxWaitTimer = null;
|
|
6313
|
+
const pendingChangedVueFiles = /* @__PURE__ */ new Set();
|
|
6314
|
+
const pendingDeletedComponents = /* @__PURE__ */ new Set();
|
|
6180
6315
|
const initialBuildPromise = (async () => {
|
|
6181
6316
|
const t0 = performance.now();
|
|
6182
6317
|
await routerInitPromise;
|
|
@@ -6185,13 +6320,44 @@ function createDevProcessorPlugin(options) {
|
|
|
6185
6320
|
const t1 = performance.now();
|
|
6186
6321
|
logInfo(`startup total: ${formatMs(t1 - t0)}`);
|
|
6187
6322
|
})();
|
|
6323
|
+
const logGenerationError = (reason, message) => {
|
|
6324
|
+
server.config.logger.error(`[vue-pom-generator] dev generation failed during ${reason}: ${message}`);
|
|
6325
|
+
};
|
|
6326
|
+
const regenerateFromPending = async (reason) => {
|
|
6327
|
+
const t0 = performance.now();
|
|
6328
|
+
await initialBuildPromise;
|
|
6329
|
+
const nextHierarchy = new Map(snapshotHierarchy);
|
|
6330
|
+
const nextVuePathMap = new Map(snapshotVuePathMap);
|
|
6331
|
+
for (const componentName of pendingDeletedComponents) {
|
|
6332
|
+
nextHierarchy.delete(componentName);
|
|
6333
|
+
nextVuePathMap.delete(componentName);
|
|
6334
|
+
}
|
|
6335
|
+
const files = Array.from(pendingChangedVueFiles);
|
|
6336
|
+
const deletedCount = pendingDeletedComponents.size;
|
|
6337
|
+
pendingChangedVueFiles.clear();
|
|
6338
|
+
pendingDeletedComponents.clear();
|
|
6339
|
+
let compileMs = 0;
|
|
6340
|
+
for (const f of files) {
|
|
6341
|
+
const res = compileVueFileIntoSnapshot(f, nextHierarchy, nextVuePathMap);
|
|
6342
|
+
compileMs += res.ms;
|
|
6343
|
+
}
|
|
6344
|
+
snapshotHierarchy = nextHierarchy;
|
|
6345
|
+
snapshotVuePathMap = nextVuePathMap;
|
|
6346
|
+
const t1 = performance.now();
|
|
6347
|
+
generateAggregatedFromSnapshot(reason);
|
|
6348
|
+
const t2 = performance.now();
|
|
6349
|
+
return {
|
|
6350
|
+
files,
|
|
6351
|
+
deletedCount,
|
|
6352
|
+
compileMs,
|
|
6353
|
+
preGenerateMs: t1 - t0,
|
|
6354
|
+
generateMs: t2 - t1,
|
|
6355
|
+
totalMs: t2 - t0
|
|
6356
|
+
};
|
|
6357
|
+
};
|
|
6188
6358
|
const watchedVueGlobs = scanDirs.map((dir) => path.resolve(projectRootRef.current, dir, "**", "*.vue"));
|
|
6189
6359
|
const watchedPluginGlob = path.resolve(projectRootRef.current, "vite-plugins", "vue-pom-generator", "**", "*.ts");
|
|
6190
6360
|
server.watcher.add([...watchedVueGlobs, watchedPluginGlob, basePageClassPath]);
|
|
6191
|
-
let timer = null;
|
|
6192
|
-
let maxWaitTimer = null;
|
|
6193
|
-
const pendingChangedVueFiles = /* @__PURE__ */ new Set();
|
|
6194
|
-
const pendingDeletedComponents = /* @__PURE__ */ new Set();
|
|
6195
6361
|
scheduleVueFileRegenLocal = (filePath, source) => {
|
|
6196
6362
|
pendingChangedVueFiles.add(filePath);
|
|
6197
6363
|
logDebug(`queued(${source}): files=${pendingChangedVueFiles.size} deleted=${pendingDeletedComponents.size}`);
|
|
@@ -6208,29 +6374,14 @@ function createDevProcessorPlugin(options) {
|
|
|
6208
6374
|
timer = null;
|
|
6209
6375
|
}
|
|
6210
6376
|
maxWaitTimer = null;
|
|
6211
|
-
void (
|
|
6212
|
-
const t0 = performance.now();
|
|
6213
|
-
await initialBuildPromise;
|
|
6214
|
-
for (const componentName of pendingDeletedComponents) {
|
|
6215
|
-
snapshotHierarchy.delete(componentName);
|
|
6216
|
-
snapshotVuePathMap.delete(componentName);
|
|
6217
|
-
}
|
|
6218
|
-
const files = Array.from(pendingChangedVueFiles);
|
|
6219
|
-
const deletedCount = pendingDeletedComponents.size;
|
|
6220
|
-
pendingChangedVueFiles.clear();
|
|
6221
|
-
pendingDeletedComponents.clear();
|
|
6222
|
-
let compileMs = 0;
|
|
6223
|
-
for (const f of files) {
|
|
6224
|
-
const res = compileVueFileIntoSnapshot(f);
|
|
6225
|
-
compileMs += res.ms;
|
|
6226
|
-
}
|
|
6227
|
-
const t1 = performance.now();
|
|
6228
|
-
generateAggregatedFromSnapshot("max-wait");
|
|
6229
|
-
const t2 = performance.now();
|
|
6377
|
+
void regenerateFromPending("max-wait").then(({ files, deletedCount, compileMs, preGenerateMs, generateMs, totalMs }) => {
|
|
6230
6378
|
logInfo(
|
|
6231
|
-
`max-wait: files=${files.length} deleted=${deletedCount} compile=${formatMs(compileMs)} wall=${formatMs(
|
|
6379
|
+
`max-wait: files=${files.length} deleted=${deletedCount} compile=${formatMs(compileMs)} wall=${formatMs(preGenerateMs)} gen=${formatMs(generateMs)} total=${formatMs(totalMs)}`
|
|
6232
6380
|
);
|
|
6233
|
-
})()
|
|
6381
|
+
}).catch((error) => {
|
|
6382
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6383
|
+
logGenerationError("max-wait", message);
|
|
6384
|
+
});
|
|
6234
6385
|
}, MAX_WAIT_MS);
|
|
6235
6386
|
}
|
|
6236
6387
|
if (wasEmpty) {
|
|
@@ -6246,31 +6397,17 @@ function createDevProcessorPlugin(options) {
|
|
|
6246
6397
|
clearTimeout(maxWaitTimer);
|
|
6247
6398
|
maxWaitTimer = null;
|
|
6248
6399
|
}
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
await initialBuildPromise;
|
|
6252
|
-
for (const componentName of pendingDeletedComponents) {
|
|
6253
|
-
snapshotHierarchy.delete(componentName);
|
|
6254
|
-
snapshotVuePathMap.delete(componentName);
|
|
6255
|
-
}
|
|
6256
|
-
const files = Array.from(pendingChangedVueFiles);
|
|
6257
|
-
const deletedCount = pendingDeletedComponents.size;
|
|
6258
|
-
pendingChangedVueFiles.clear();
|
|
6259
|
-
pendingDeletedComponents.clear();
|
|
6260
|
-
let compileMs = 0;
|
|
6261
|
-
for (const f of files) {
|
|
6262
|
-
const res = compileVueFileIntoSnapshot(f);
|
|
6263
|
-
compileMs += res.ms;
|
|
6264
|
-
}
|
|
6265
|
-
const t1 = performance.now();
|
|
6266
|
-
generateAggregatedFromSnapshot(files.length || deletedCount ? "batched" : "noop");
|
|
6267
|
-
const t2 = performance.now();
|
|
6400
|
+
const reason = pendingChangedVueFiles.size || pendingDeletedComponents.size ? "batched" : "noop";
|
|
6401
|
+
void regenerateFromPending(reason).then(({ files, deletedCount, compileMs, preGenerateMs, generateMs, totalMs }) => {
|
|
6268
6402
|
if (files.length || deletedCount) {
|
|
6269
6403
|
logInfo(
|
|
6270
|
-
`batched: files=${files.length} deleted=${deletedCount} compile=${formatMs(compileMs)} wall=${formatMs(
|
|
6404
|
+
`batched: files=${files.length} deleted=${deletedCount} compile=${formatMs(compileMs)} wall=${formatMs(preGenerateMs)} gen=${formatMs(generateMs)} total=${formatMs(totalMs)}`
|
|
6271
6405
|
);
|
|
6272
6406
|
}
|
|
6273
|
-
})()
|
|
6407
|
+
}).catch((error) => {
|
|
6408
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6409
|
+
logGenerationError(reason, message);
|
|
6410
|
+
});
|
|
6274
6411
|
}, 75);
|
|
6275
6412
|
}
|
|
6276
6413
|
server.watcher.on("change", async (changedPath) => {
|
|
@@ -6322,6 +6459,7 @@ function createDevProcessorPlugin(options) {
|
|
|
6322
6459
|
});
|
|
6323
6460
|
setTimeout(() => {
|
|
6324
6461
|
}, 250);
|
|
6462
|
+
await initialBuildPromise;
|
|
6325
6463
|
}
|
|
6326
6464
|
};
|
|
6327
6465
|
}
|
|
@@ -6353,6 +6491,7 @@ function createSupportPlugins(options) {
|
|
|
6353
6491
|
scanDirs,
|
|
6354
6492
|
getWrapperSearchRoots,
|
|
6355
6493
|
nameCollisionBehavior = "suffix",
|
|
6494
|
+
existingIdBehavior,
|
|
6356
6495
|
outDir,
|
|
6357
6496
|
emitLanguages,
|
|
6358
6497
|
csharp,
|
|
@@ -6406,6 +6545,11 @@ function createSupportPlugins(options) {
|
|
|
6406
6545
|
customPomImportAliases,
|
|
6407
6546
|
customPomImportNameCollisionBehavior,
|
|
6408
6547
|
testIdAttribute,
|
|
6548
|
+
nameCollisionBehavior,
|
|
6549
|
+
existingIdBehavior,
|
|
6550
|
+
nativeWrappers,
|
|
6551
|
+
excludedComponents,
|
|
6552
|
+
getWrapperSearchRoots,
|
|
6409
6553
|
routerAwarePoms,
|
|
6410
6554
|
routerType,
|
|
6411
6555
|
resolvedRouterEntry,
|
|
@@ -6430,6 +6574,7 @@ function createSupportPlugins(options) {
|
|
|
6430
6574
|
customPomImportAliases,
|
|
6431
6575
|
customPomImportNameCollisionBehavior,
|
|
6432
6576
|
nameCollisionBehavior,
|
|
6577
|
+
existingIdBehavior,
|
|
6433
6578
|
testIdAttribute,
|
|
6434
6579
|
routerAwarePoms,
|
|
6435
6580
|
routerType,
|
|
@@ -7011,6 +7156,7 @@ function createVuePomGeneratorPlugins(options = {}) {
|
|
|
7011
7156
|
scanDirs,
|
|
7012
7157
|
getWrapperSearchRoots: getWrapperSearchRootsAbs,
|
|
7013
7158
|
nameCollisionBehavior,
|
|
7159
|
+
existingIdBehavior,
|
|
7014
7160
|
outDir,
|
|
7015
7161
|
emitLanguages,
|
|
7016
7162
|
csharp,
|