@immense/vue-pom-generator 1.0.42 → 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/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,
@@ -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];
@@ -6106,9 +6235,12 @@ 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 };
6238
+ const { bindings: bindingMetadata, isScriptSetup } = getScriptInfo(sfc, absolutePath);
6109
6239
  compilerDom.compile(template, {
6110
6240
  filename: absolutePath,
6111
6241
  prefixIdentifiers: true,
6242
+ inline: isScriptSetup,
6243
+ bindingMetadata,
6112
6244
  nodeTransforms: [
6113
6245
  createTestIdTransform(
6114
6246
  componentName,
@@ -6117,7 +6249,7 @@ function createDevProcessorPlugin(options) {
6117
6249
  excludedComponents,
6118
6250
  getViewsDirAbs(),
6119
6251
  {
6120
- existingIdBehavior: "preserve",
6252
+ existingIdBehavior: existingIdBehavior ?? "preserve",
6121
6253
  nameCollisionBehavior,
6122
6254
  testIdAttribute,
6123
6255
  warn: (message) => loggerRef.current.warn(message),
@@ -6359,6 +6491,7 @@ function createSupportPlugins(options) {
6359
6491
  scanDirs,
6360
6492
  getWrapperSearchRoots,
6361
6493
  nameCollisionBehavior = "suffix",
6494
+ existingIdBehavior,
6362
6495
  outDir,
6363
6496
  emitLanguages,
6364
6497
  csharp,
@@ -6412,6 +6545,11 @@ function createSupportPlugins(options) {
6412
6545
  customPomImportAliases,
6413
6546
  customPomImportNameCollisionBehavior,
6414
6547
  testIdAttribute,
6548
+ nameCollisionBehavior,
6549
+ existingIdBehavior,
6550
+ nativeWrappers,
6551
+ excludedComponents,
6552
+ getWrapperSearchRoots,
6415
6553
  routerAwarePoms,
6416
6554
  routerType,
6417
6555
  resolvedRouterEntry,
@@ -6436,6 +6574,7 @@ function createSupportPlugins(options) {
6436
6574
  customPomImportAliases,
6437
6575
  customPomImportNameCollisionBehavior,
6438
6576
  nameCollisionBehavior,
6577
+ existingIdBehavior,
6439
6578
  testIdAttribute,
6440
6579
  routerAwarePoms,
6441
6580
  routerType,
@@ -7017,6 +7156,7 @@ function createVuePomGeneratorPlugins(options = {}) {
7017
7156
  scanDirs,
7018
7157
  getWrapperSearchRoots: getWrapperSearchRootsAbs,
7019
7158
  nameCollisionBehavior,
7159
+ existingIdBehavior,
7020
7160
  outDir,
7021
7161
  emitLanguages,
7022
7162
  csharp,