@immense/vue-pom-generator 1.0.62 → 1.0.64

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 CHANGED
@@ -1,39 +1,48 @@
1
- I'll examine the commits to generate accurate release notes.
2
-
3
- ● Based on the commit details, here are the release notes for v1.0.62:
1
+ Based on the commit message and changes, here are the release notes:
4
2
 
5
3
  ---
6
4
 
5
+ # v1.0.64
6
+
7
7
  ## Highlights
8
8
 
9
- - Fixed handler name preservation after Vue compiler transformations
10
- - Improved fallback logic to extract semantic names from author-written source code
11
- - Enhanced test coverage for handler attribute parsing edge cases
9
+ - **TypeScript template expression support** Compiler now parses TypeScript annotations in Vue
10
+ template expressions (e.g., `@row-click="(row: RowType) => ..."`), fixing crashes in Nuxt 4 +
11
+ TS codebases
12
+ - **Graceful submit-button fallback** – Submit buttons with dynamic labels now respect
13
+ `missingSemanticNameBehavior: "ignore"` and generate `SubmitButton` / `clickSubmit()` methods
14
+ instead of throwing
15
+ - **Improved TypeScript compatibility** – All three plugin compilation paths (dev-plugin,
16
+ build-plugin, vue-plugin) now support TypeScript expression syntax
12
17
 
13
18
  ## Changes
14
19
 
15
- **Bug Fixes**
16
- - Preserve original handler names when Vue compiler rewrites expressions during compilation
17
- - Extract semantic names from author source (`loc.content`) rather than transformed source when
18
- they differ
19
- - Add fallback expression parsing to handle cases where Vue's transformation breaks Babel AST
20
- parsing
21
-
22
- **Testing**
23
- - Added 38 new test cases for handler attribute transformation scenarios
24
- - Improved coverage for `utils.ts` edge cases with 36 additional tests
25
- - Fixed missing `SimpleExpressionNode` import in test files
20
+ ### Parser Enhancements
21
+ - Added `expressionPlugins: ["typescript"]` to all `compilerDom.compile()` call sites
22
+ (dev-plugin, build-plugin, vue-plugin)
23
+ - Vue plugin merges expression plugins with user-supplied `userCompilerOptions` to preserve
24
+ custom configuration
26
25
 
27
- ## Breaking Changes
26
+ ### Submit Button Handling
27
+ - Submit buttons with dynamic inner text (e.g., ternary expressions like `{{ isNew ? 'Create' :
28
+ 'Save' }}`) now honor `missingSemanticNameBehavior: "ignore"` option
29
+ - Falls back to literal `"submit"` identifier when semantic name cannot be derived, generating
30
+ `SubmitButton` / `clickSubmit()` POM surface
31
+ - Default behavior (throwing on missing semantic name) remains unchanged
28
32
 
29
- None
33
+ ### Testing
34
+ - Added 3 regression tests for TypeScript expression parsing and submit-button fallback behavior
35
+ - Test suite: 163 → 166 tests passing
36
+ - All validation passes: typecheck, eslint, build
30
37
 
31
38
  ## Pull Requests Included
32
39
 
33
- None (direct commits to main)
40
+ - fix: parse TypeScript template expressions + allow submit-button fallback
41
+ [#20](https://github.com/immense/vue-pom-generator/pull/20)
34
42
 
35
43
  ## Testing
36
44
 
37
- All changes include comprehensive test coverage. Added 75+ new test cases covering handler
38
- attribute parsing, Vue compiler transformations, and semantic name extraction edge cases.
45
+ Validated on Nuxt 4 + Vue 3 + TypeScript codebase. Three new regression tests added covering
46
+ TypeScript expression parsing and submit-button fallback scenarios. Full test suite passes (166
47
+ tests).
39
48
 
@@ -24,7 +24,6 @@ import {
24
24
  isParameterizedPomPattern,
25
25
  orderPomPatternParameters,
26
26
  toCSharpPomPatternExpression,
27
- toTypeScriptPomPatternExpression,
28
27
  uniquePomStringPatterns,
29
28
  type PomStringPattern,
30
29
  } from "../pom-patterns";
@@ -1604,14 +1603,57 @@ function prepareViewObjectModelClass(
1604
1603
  testIdAttribute,
1605
1604
  } = options;
1606
1605
 
1606
+ const normalizeTrackedComponentRef = (value: string): string => {
1607
+ return value.endsWith(".vue") ? value.slice(0, -4) : value;
1608
+ };
1609
+
1610
+ const resolveTrackedComponentRef = (value: string): string | null => {
1611
+ const normalizedValue = normalizeTrackedComponentRef(value);
1612
+ if (componentHierarchyMap.has(value)) {
1613
+ return value;
1614
+ }
1615
+ if (componentHierarchyMap.has(normalizedValue)) {
1616
+ return normalizedValue;
1617
+ }
1618
+
1619
+ let match: string | null = null;
1620
+ for (const [candidateName, candidateDeps] of componentHierarchyMap.entries()) {
1621
+ const normalizedCandidate = normalizeTrackedComponentRef(candidateName);
1622
+ const candidateBaseName = path.parse(candidateDeps.filePath).name;
1623
+ if (normalizedCandidate !== normalizedValue && candidateBaseName !== normalizedValue) {
1624
+ continue;
1625
+ }
1626
+ if (match && match !== candidateName) {
1627
+ return null;
1628
+ }
1629
+ match = candidateName;
1630
+ }
1631
+ return match;
1632
+ };
1633
+
1634
+ const rawComponentRefsForInstances = isView
1635
+ ? (usedComponentSet?.size ? usedComponentSet : childrenComponentSet)
1636
+ : childrenComponentSet;
1637
+ const componentRefsForInstances = new Set<string>();
1638
+ for (const ref of rawComponentRefsForInstances) {
1639
+ componentRefsForInstances.add(resolveTrackedComponentRef(ref) ?? normalizeTrackedComponentRef(ref));
1640
+ }
1641
+
1607
1642
  const hasChildComponent = (needle: string) => {
1608
- const haystack = usedComponentSet?.size ? usedComponentSet : childrenComponentSet;
1609
- for (const child of haystack) {
1610
- if (child === needle)
1643
+ const normalizedNeedle = normalizeTrackedComponentRef(needle);
1644
+ for (const child of rawComponentRefsForInstances) {
1645
+ const resolvedChild = resolveTrackedComponentRef(child);
1646
+ if (normalizeTrackedComponentRef(child) === normalizedNeedle)
1611
1647
  return true;
1612
- if (child === `${needle}.vue`)
1648
+ if (resolvedChild && normalizeTrackedComponentRef(resolvedChild) === normalizedNeedle)
1613
1649
  return true;
1614
- if (child.endsWith(".vue") && child.slice(0, -4) === needle)
1650
+ if (resolvedChild) {
1651
+ const resolvedDeps = componentHierarchyMap.get(resolvedChild);
1652
+ if (resolvedDeps && path.parse(resolvedDeps.filePath).name === normalizedNeedle) {
1653
+ return true;
1654
+ }
1655
+ }
1656
+ if (child === `${needle}.vue`)
1615
1657
  return true;
1616
1658
  }
1617
1659
  return false;
@@ -1648,10 +1690,6 @@ function prepareViewObjectModelClass(
1648
1690
  ? getWidgetInstancesForView(componentName, dependencies.dataTestIdSet, customPomAvailableClassIdentifiers)
1649
1691
  : [];
1650
1692
 
1651
- const componentRefsForInstances = isView
1652
- ? (usedComponentSet?.size ? usedComponentSet : childrenComponentSet)
1653
- : childrenComponentSet;
1654
-
1655
1693
  const className = toPascalCaseLocal(componentName);
1656
1694
  const childInstancePropertyNames = Array.from(componentRefsForInstances)
1657
1695
  .filter(child => componentHierarchyMap.has(child) && componentHierarchyMap.get(child)?.dataTestIdSet.size)
@@ -1964,7 +2002,7 @@ function sliceNodeSource(source: string, node: { start?: number | null; end?: nu
1964
2002
 
1965
2003
  function getTypeAnnotationSource(
1966
2004
  source: string,
1967
- node: { typeAnnotation?: unknown },
2005
+ node: { typeAnnotation?: object | null },
1968
2006
  ): string | undefined {
1969
2007
  const rawTypeAnnotation = node.typeAnnotation;
1970
2008
  if (!rawTypeAnnotation || typeof rawTypeAnnotation !== "object" || !("type" in rawTypeAnnotation) || rawTypeAnnotation.type !== "TSTypeAnnotation" || !("typeAnnotation" in rawTypeAnnotation)) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../class-generation/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAkC,oCAAoC,EAAE,MAAM,sBAAsB,CAAC;AAyC5G,OAAO,EACL,sBAAsB,EAOvB,MAAM,UAAU,CAAC;AAQlB,OAAO,EAAE,oCAAoC,EAAE,CAAC;AA2ChD,UAAU,SAAS;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAID,UAAU,mBAAmB;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,wBAAwB,EAAE,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,EAAE,OAAO,GAAG,YAAY,GAAG,MAAM,GAAG,oBAAoB,CAAC;IAClE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AASD,MAAM,MAAM,yBAAyB,GAAG,YAAY,GAAG,OAAO,CAAC;AAqW/D,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;;;;;;;;;;;;OAeG;IACH,gBAAgB,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAE1D;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gFAAgF;IAChF,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;;;;;OAOG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEhD;;;;;OAKG;IACH,oCAAoC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IAEzD;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAE7C,yEAAyE;IACzE,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,uDAAuD;IACvD,aAAa,CAAC,EAAE,KAAK,CAAC,IAAI,GAAG,QAAQ,CAAC,CAAC;IAEvC;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,yBAAyB,CAAC;IAEtD,6BAA6B;IAC7B,MAAM,CAAC,EAAE;QACP,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IAEF,6EAA6E;IAC7E,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC,2FAA2F;IAC3F,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,mDAAmD;IACnD,UAAU,CAAC,EAAE,YAAY,GAAG,MAAM,CAAC;IAEnC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAEtB,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CAClD;AAsCD,wBAAsB,aAAa,CACjC,qBAAqB,EAAE,GAAG,CAAC,MAAM,EAAE,sBAAsB,CAAC,EAC1D,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EACpC,iBAAiB,EAAE,MAAM,EACzB,OAAO,GAAE,oBAAyB,iBAoGnC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../class-generation/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAkC,oCAAoC,EAAE,MAAM,sBAAsB,CAAC;AAwC5G,OAAO,EACL,sBAAsB,EAOvB,MAAM,UAAU,CAAC;AAQlB,OAAO,EAAE,oCAAoC,EAAE,CAAC;AA2ChD,UAAU,SAAS;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAID,UAAU,mBAAmB;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,wBAAwB,EAAE,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,EAAE,OAAO,GAAG,YAAY,GAAG,MAAM,GAAG,oBAAoB,CAAC;IAClE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AASD,MAAM,MAAM,yBAAyB,GAAG,YAAY,GAAG,OAAO,CAAC;AAqW/D,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;;;;;;;;;;;;OAeG;IACH,gBAAgB,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAE1D;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gFAAgF;IAChF,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;;;;;OAOG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEhD;;;;;OAKG;IACH,oCAAoC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IAEzD;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAE7C,yEAAyE;IACzE,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,uDAAuD;IACvD,aAAa,CAAC,EAAE,KAAK,CAAC,IAAI,GAAG,QAAQ,CAAC,CAAC;IAEvC;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,yBAAyB,CAAC;IAEtD,6BAA6B;IAC7B,MAAM,CAAC,EAAE;QACP,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IAEF,6EAA6E;IAC7E,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC,2FAA2F;IAC3F,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,mDAAmD;IACnD,UAAU,CAAC,EAAE,YAAY,GAAG,MAAM,CAAC;IAEnC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAEtB,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CAClD;AAsCD,wBAAsB,aAAa,CACjC,qBAAqB,EAAE,GAAG,CAAC,MAAM,EAAE,sBAAsB,CAAC,EAC1D,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EACpC,iBAAiB,EAAE,MAAM,EACzB,OAAO,GAAE,oBAAyB,iBAoGnC"}
package/dist/index.cjs CHANGED
@@ -258,6 +258,7 @@ function resolveGenerationSupportOptions(options) {
258
258
  customPomImportAliases: options.customPomImportAliases,
259
259
  customPomImportNameCollisionBehavior: options.customPomImportNameCollisionBehavior ?? "error",
260
260
  nameCollisionBehavior: options.nameCollisionBehavior ?? "error",
261
+ missingSemanticNameBehavior: options.missingSemanticNameBehavior ?? "error",
261
262
  existingIdBehavior: options.existingIdBehavior ?? "error",
262
263
  testIdAttribute: (options.testIdAttribute ?? "data-testid").trim() || "data-testid",
263
264
  accessibilityAudit: options.accessibilityAudit ?? false,
@@ -5493,14 +5494,51 @@ function prepareViewObjectModelClass(componentName, dependencies, componentHiera
5493
5494
  customPomAttachments = [],
5494
5495
  testIdAttribute
5495
5496
  } = options;
5497
+ const normalizeTrackedComponentRef = (value) => {
5498
+ return value.endsWith(".vue") ? value.slice(0, -4) : value;
5499
+ };
5500
+ const resolveTrackedComponentRef = (value) => {
5501
+ const normalizedValue = normalizeTrackedComponentRef(value);
5502
+ if (componentHierarchyMap.has(value)) {
5503
+ return value;
5504
+ }
5505
+ if (componentHierarchyMap.has(normalizedValue)) {
5506
+ return normalizedValue;
5507
+ }
5508
+ let match = null;
5509
+ for (const [candidateName, candidateDeps] of componentHierarchyMap.entries()) {
5510
+ const normalizedCandidate = normalizeTrackedComponentRef(candidateName);
5511
+ const candidateBaseName = path.parse(candidateDeps.filePath).name;
5512
+ if (normalizedCandidate !== normalizedValue && candidateBaseName !== normalizedValue) {
5513
+ continue;
5514
+ }
5515
+ if (match && match !== candidateName) {
5516
+ return null;
5517
+ }
5518
+ match = candidateName;
5519
+ }
5520
+ return match;
5521
+ };
5522
+ const rawComponentRefsForInstances = isView ? usedComponentSet?.size ? usedComponentSet : childrenComponentSet : childrenComponentSet;
5523
+ const componentRefsForInstances = /* @__PURE__ */ new Set();
5524
+ for (const ref of rawComponentRefsForInstances) {
5525
+ componentRefsForInstances.add(resolveTrackedComponentRef(ref) ?? normalizeTrackedComponentRef(ref));
5526
+ }
5496
5527
  const hasChildComponent = (needle) => {
5497
- const haystack = usedComponentSet?.size ? usedComponentSet : childrenComponentSet;
5498
- for (const child of haystack) {
5499
- if (child === needle)
5528
+ const normalizedNeedle = normalizeTrackedComponentRef(needle);
5529
+ for (const child of rawComponentRefsForInstances) {
5530
+ const resolvedChild = resolveTrackedComponentRef(child);
5531
+ if (normalizeTrackedComponentRef(child) === normalizedNeedle)
5500
5532
  return true;
5501
- if (child === `${needle}.vue`)
5533
+ if (resolvedChild && normalizeTrackedComponentRef(resolvedChild) === normalizedNeedle)
5502
5534
  return true;
5503
- if (child.endsWith(".vue") && child.slice(0, -4) === needle)
5535
+ if (resolvedChild) {
5536
+ const resolvedDeps = componentHierarchyMap.get(resolvedChild);
5537
+ if (resolvedDeps && path.parse(resolvedDeps.filePath).name === normalizedNeedle) {
5538
+ return true;
5539
+ }
5540
+ }
5541
+ if (child === `${needle}.vue`)
5504
5542
  return true;
5505
5543
  }
5506
5544
  return false;
@@ -5524,7 +5562,6 @@ function prepareViewObjectModelClass(componentName, dependencies, componentHiera
5524
5562
  methodSignatures: a.flatten ? customPomMethodSignaturesByClass.get(a.className) ?? /* @__PURE__ */ new Map() : /* @__PURE__ */ new Map()
5525
5563
  }));
5526
5564
  const widgetInstances = isView ? getWidgetInstancesForView(componentName, dependencies.dataTestIdSet, customPomAvailableClassIdentifiers) : [];
5527
- const componentRefsForInstances = isView ? usedComponentSet?.size ? usedComponentSet : childrenComponentSet : childrenComponentSet;
5528
5565
  const className = toPascalCaseLocal(componentName);
5529
5566
  const childInstancePropertyNames = Array.from(componentRefsForInstances).filter((child) => componentHierarchyMap.has(child) && componentHierarchyMap.get(child)?.dataTestIdSet.size).map((child) => child.split(".vue")[0]);
5530
5567
  const blockedViewPassthroughMethodNames = new Set(
@@ -7040,6 +7077,7 @@ function createTestIdTransform(componentName, componentHierarchyMap, nativeWrapp
7040
7077
  const existingIdBehavior = options.existingIdBehavior ?? "error";
7041
7078
  const testIdAttribute = (options.testIdAttribute || "data-testid").trim() || "data-testid";
7042
7079
  const nameCollisionBehavior = options.nameCollisionBehavior ?? "error";
7080
+ const missingSemanticNameBehavior = options.missingSemanticNameBehavior ?? "error";
7043
7081
  const warn = options.warn;
7044
7082
  const vueFilesPathMap = options.vueFilesPathMap;
7045
7083
  const wrapperSearchRoots = options.wrapperSearchRoots ?? [];
@@ -7483,13 +7521,16 @@ Fix: remove the explicit ${attrLabel}, or change existingIdBehavior to "overwrit
7483
7521
  }
7484
7522
  const isSubmit = element.props.find((p) => p.type === compilerCore.NodeTypes.ATTRIBUTE && p.name === "type")?.value?.content === "submit";
7485
7523
  if (isSubmit) {
7486
- const identifier = getStaticIdOrNameHint(element) || innerText;
7524
+ let identifier = getStaticIdOrNameHint(element) || innerText;
7487
7525
  if (!identifier) {
7488
- const loc = element.loc?.start;
7489
- const locationHint = loc ? `${loc.line}:${loc.column}` : "unknown";
7490
- throw new Error(
7491
- `[vue-pom-generator] submit button appears identifiable but no usable identity could be derived in ${componentName} (${context.filename ?? "unknown"}:${locationHint}) — id/name were missing/empty and innerText was also missing/invalid`
7492
- );
7526
+ if (missingSemanticNameBehavior === "error") {
7527
+ const loc = element.loc?.start;
7528
+ const locationHint = loc ? `${loc.line}:${loc.column}` : "unknown";
7529
+ throw new Error(
7530
+ `[vue-pom-generator] submit button appears identifiable but no usable identity could be derived in ${componentName} (${context.filename ?? "unknown"}:${locationHint}) — id/name were missing/empty and innerText was also missing/invalid. Fix: give the button a static id/name, a static inner text, or set missingSemanticNameBehavior = "ignore" to fall back to the generic "submit" identifier.`
7531
+ );
7532
+ }
7533
+ identifier = "submit";
7493
7534
  }
7494
7535
  const testId = getSubmitDataTestId(identifier);
7495
7536
  applyResolvedDataTestIdForElement({
@@ -7556,6 +7597,7 @@ function createBuildProcessorPlugin(options) {
7556
7597
  customPomImportNameCollisionBehavior,
7557
7598
  testIdAttribute,
7558
7599
  nameCollisionBehavior,
7600
+ missingSemanticNameBehavior,
7559
7601
  existingIdBehavior,
7560
7602
  routerAwarePoms,
7561
7603
  routerType,
@@ -7651,6 +7693,9 @@ function createBuildProcessorPlugin(options) {
7651
7693
  prefixIdentifiers: true,
7652
7694
  inline: isScriptSetup,
7653
7695
  bindingMetadata,
7696
+ // See dev-plugin.ts — same rationale: enable TS in template
7697
+ // expressions so `(row: RowType) => ...` handlers parse.
7698
+ expressionPlugins: ["typescript"],
7654
7699
  nodeTransforms: [
7655
7700
  createTestIdTransform(
7656
7701
  componentName,
@@ -7662,6 +7707,7 @@ function createBuildProcessorPlugin(options) {
7662
7707
  existingIdBehavior: existingIdBehavior ?? "error",
7663
7708
  testIdAttribute,
7664
7709
  nameCollisionBehavior,
7710
+ missingSemanticNameBehavior,
7665
7711
  warn: (message) => loggerRef.current.warn(message),
7666
7712
  vueFilesPathMap,
7667
7713
  wrapperSearchRoots: getWrapperSearchRoots()
@@ -7809,6 +7855,7 @@ function createDevProcessorPlugin(options) {
7809
7855
  customPomImportAliases,
7810
7856
  customPomImportNameCollisionBehavior,
7811
7857
  nameCollisionBehavior,
7858
+ missingSemanticNameBehavior,
7812
7859
  existingIdBehavior,
7813
7860
  testIdAttribute,
7814
7861
  routerAwarePoms,
@@ -7993,6 +8040,12 @@ function createDevProcessorPlugin(options) {
7993
8040
  prefixIdentifiers: true,
7994
8041
  inline: isScriptSetup,
7995
8042
  bindingMetadata,
8043
+ // Vue templates may contain TypeScript type annotations in expressions
8044
+ // (e.g. `@row-click="(row: RowType) => navigateTo(...)"` in Nuxt + TS
8045
+ // apps). Without this flag, Vue's internal processExpression step
8046
+ // delegates to @babel/parser without the TS plugin and crashes on
8047
+ // "Unexpected token, expected ','".
8048
+ expressionPlugins: ["typescript"],
7996
8049
  nodeTransforms: [
7997
8050
  createTestIdTransform(
7998
8051
  componentName,
@@ -8003,6 +8056,7 @@ function createDevProcessorPlugin(options) {
8003
8056
  {
8004
8057
  existingIdBehavior: existingIdBehavior ?? "error",
8005
8058
  nameCollisionBehavior,
8059
+ missingSemanticNameBehavior,
8006
8060
  testIdAttribute,
8007
8061
  warn: (message) => loggerRef.current.warn(message),
8008
8062
  vueFilesPathMap: provisionalVuePathMap,
@@ -8750,6 +8804,7 @@ function createVuePluginWithTestIds(options) {
8750
8804
  vueOptions,
8751
8805
  existingIdBehavior,
8752
8806
  nameCollisionBehavior,
8807
+ missingSemanticNameBehavior = "error",
8753
8808
  nativeWrappers,
8754
8809
  elementMetadata,
8755
8810
  semanticNameMap,
@@ -8830,6 +8885,7 @@ function createVuePluginWithTestIds(options) {
8830
8885
  existingIdBehavior,
8831
8886
  testIdAttribute,
8832
8887
  nameCollisionBehavior,
8888
+ missingSemanticNameBehavior,
8833
8889
  warn: (message) => loggerRef.current.warn(message),
8834
8890
  vueFilesPathMap,
8835
8891
  wrapperSearchRoots: getWrapperSearchRoots()
@@ -8884,6 +8940,7 @@ function createVuePluginWithTestIds(options) {
8884
8940
  existingIdBehavior,
8885
8941
  testIdAttribute,
8886
8942
  nameCollisionBehavior,
8943
+ missingSemanticNameBehavior,
8887
8944
  warn: (message) => loggerRef.current.warn(message),
8888
8945
  vueFilesPathMap,
8889
8946
  wrapperSearchRoots: getWrapperSearchRoots()
@@ -8931,9 +8988,16 @@ function createVuePluginWithTestIds(options) {
8931
8988
  const compile = compilerDom2.compile;
8932
8989
  const { descriptor } = parse(code, { filename: cleanPath });
8933
8990
  if (descriptor.template) {
8991
+ const mergedExpressionPlugins = Array.from(
8992
+ /* @__PURE__ */ new Set([
8993
+ "typescript",
8994
+ ...userCompilerOptions.expressionPlugins ?? []
8995
+ ])
8996
+ );
8934
8997
  compile(descriptor.template.content, {
8935
8998
  ...userCompilerOptions,
8936
8999
  filename: cleanPath,
9000
+ expressionPlugins: mergedExpressionPlugins,
8937
9001
  nodeTransforms: getNodeTransforms(cleanPath, componentName)
8938
9002
  });
8939
9003
  loggerRef.current.debug(`Metadata collected for ${cleanPath}`);
@@ -9230,6 +9294,7 @@ function createVuePomGeneratorPlugins(options = {}) {
9230
9294
  customPomImportAliases: resolvedCustomPomImportAliases,
9231
9295
  customPomImportNameCollisionBehavior: customPoms?.importNameCollisionBehavior,
9232
9296
  nameCollisionBehavior: generationOptions?.nameCollisionBehavior,
9297
+ missingSemanticNameBehavior: generationOptions?.missingSemanticNameBehavior,
9233
9298
  existingIdBehavior: resolvedInjectionOptions.existingIdBehavior,
9234
9299
  testIdAttribute,
9235
9300
  accessibilityAudit: generationOptions?.accessibilityAudit,
@@ -9318,6 +9383,7 @@ function createVuePomGeneratorPlugins(options = {}) {
9318
9383
  vueOptions,
9319
9384
  existingIdBehavior: resolvedGenerationOptions.existingIdBehavior,
9320
9385
  nameCollisionBehavior: resolvedGenerationOptions.nameCollisionBehavior,
9386
+ missingSemanticNameBehavior: resolvedGenerationOptions.missingSemanticNameBehavior,
9321
9387
  nativeWrappers,
9322
9388
  elementMetadata,
9323
9389
  semanticNameMap,