@markuplint/vue-parser 4.6.22 → 5.0.0-alpha.0

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/lib/parser.js CHANGED
@@ -1,5 +1,11 @@
1
1
  import { ParserError, Parser } from '@markuplint/parser-utils';
2
2
  import { vueParse } from './vue-parser/index.js';
3
+ /**
4
+ * Parser implementation for Vue SFC templates.
5
+ * Extends the base Parser to handle Vue elements, text nodes, expression containers,
6
+ * directives (`v-bind`, `v-on`, `v-model`, `v-slot`), and template comments.
7
+ * Recognizes Vue built-in components and PascalCase user components.
8
+ */
3
9
  class VueParser extends Parser {
4
10
  constructor() {
5
11
  super({
@@ -7,7 +13,6 @@ class VueParser extends Parser {
7
13
  }, {
8
14
  comments: [],
9
15
  });
10
- this.duplicatableAttrs = new Set(['class', 'style']);
11
16
  }
12
17
  tokenize() {
13
18
  const ast = vueParse(this.rawCode);
@@ -29,6 +34,16 @@ class VueParser extends Parser {
29
34
  }
30
35
  return super.parseError(error);
31
36
  }
37
+ /**
38
+ * Converts a Vue AST node into markuplint node tree items.
39
+ * Handles VText (text nodes), VExpressionContainer (template expressions),
40
+ * and VElement (elements with start/end tags and children).
41
+ *
42
+ * @param originNode - The Vue AST node to convert
43
+ * @param parentNode - The parent node in the markuplint tree, or null for root nodes
44
+ * @param depth - The nesting depth of the node
45
+ * @returns An array of markuplint node tree items
46
+ */
32
47
  nodeize(
33
48
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
34
49
  originNode, parentNode, depth) {
@@ -57,7 +72,6 @@ class VueParser extends Parser {
57
72
  depth,
58
73
  parentNode,
59
74
  nodeName: originNode.name,
60
- namespace: originNode.namespace,
61
75
  }, originNode.children, {
62
76
  createEndTagToken: () => {
63
77
  if (!originNode.endTag) {
@@ -74,14 +88,26 @@ class VueParser extends Parser {
74
88
  }
75
89
  }
76
90
  }
91
+ /**
92
+ * Extends the base flattening to inject Vue template comments between sibling nodes.
93
+ * Comments from the vue-eslint-parser are inserted at the correct positions
94
+ * based on their source offsets relative to adjacent nodes.
95
+ *
96
+ * @param nodeTree - The hierarchical node tree to flatten
97
+ * @returns A flat list of nodes including interleaved comments
98
+ */
77
99
  flattenNodes(nodeTree) {
78
100
  const nodeList = super.flattenNodes(nodeTree);
79
101
  const newNodeList = [];
80
102
  let prevNode = null;
81
103
  for (const node of nodeList) {
82
- const lastOffset = prevNode?.endOffset ?? node.parentNode?.endOffset ?? 0;
104
+ const lastOffset = prevNode
105
+ ? prevNode.offset + prevNode.raw.length
106
+ : node.parentNode
107
+ ? node.parentNode.offset + node.parentNode.raw.length
108
+ : 0;
83
109
  const betweenComment = this.state.comments.find(comment => {
84
- return lastOffset <= comment.range[0] && comment.range[1] <= node.startOffset;
110
+ return lastOffset <= comment.range[0] && comment.range[1] <= node.offset;
85
111
  });
86
112
  if (betweenComment) {
87
113
  const token = this.sliceFragment(betweenComment.range[0], betweenComment.range[1]);
@@ -111,100 +137,6 @@ class VueParser extends Parser {
111
137
  concatText: false,
112
138
  });
113
139
  }
114
- visitAttr(token) {
115
- const attr = super.visitAttr(token);
116
- if (attr.type === 'spread') {
117
- return attr;
118
- }
119
- {
120
- /**
121
- * `v-on`
122
- */
123
- const [, directive, potentialName] = attr.name.raw.match(/^(v-on:|@)([^.]+)(?:\.([^.]+))?$/i) ?? [];
124
- if (directive && potentialName) {
125
- return {
126
- ...attr,
127
- potentialName: `on${potentialName.toLowerCase()}`,
128
- isDynamicValue: true,
129
- };
130
- }
131
- }
132
- {
133
- /**
134
- * `v-bind`
135
- */
136
- const [, directive, potentialName, modifier] = attr.name.raw.match(/^(v-bind:|:)([^.]+)(?:\.([^.]+))?$/i) ?? [];
137
- if (directive && potentialName) {
138
- if (this.duplicatableAttrs.has(potentialName.toLowerCase())) {
139
- this.updateAttr(attr, { isDuplicatable: true });
140
- }
141
- if (!modifier) {
142
- return {
143
- ...attr,
144
- potentialName,
145
- isDynamicValue: true,
146
- };
147
- }
148
- switch (modifier) {
149
- case '.attr': {
150
- return {
151
- ...attr,
152
- potentialName,
153
- isDynamicValue: true,
154
- };
155
- }
156
- /* eslint-disable unicorn/no-useless-switch-case */
157
- case '.prop':
158
- case '.camel':
159
- default: {
160
- const name = `v-bind:${potentialName}${modifier ?? ''}`;
161
- return {
162
- ...attr,
163
- potentialName: attr.name.raw === name ? undefined : name,
164
- isDirective: true,
165
- };
166
- }
167
- /* eslint-enable unicorn/no-useless-switch-case */
168
- }
169
- }
170
- }
171
- {
172
- /**
173
- * `v-model`
174
- */
175
- const [, directive] = attr.name.raw.match(/^(v-model)(?:\.([^.]+))?$/i) ?? [];
176
- if (directive) {
177
- return {
178
- ...attr,
179
- isDirective: true,
180
- };
181
- }
182
- }
183
- {
184
- /**
185
- * `v-slot`
186
- */
187
- const slotName = (attr.name.raw.match(/^(v-slot:|#)(.+)$/i) ?? [])[2];
188
- const name = `v-slot:${slotName}`;
189
- if (slotName) {
190
- return {
191
- ...attr,
192
- potentialName: attr.name.raw === name ? undefined : name,
193
- isDirective: true,
194
- };
195
- }
196
- }
197
- /**
198
- * If directives
199
- */
200
- if (attr.name.raw.startsWith('v-')) {
201
- return {
202
- ...attr,
203
- isDirective: true,
204
- };
205
- }
206
- return attr;
207
- }
208
140
  /**
209
141
  * > In SFCs, it's recommended to use `PascalCase` tag names
210
142
  * > for child components to differentiate from native HTML elements.
@@ -1,5 +1,17 @@
1
1
  import * as VueESLintParser from 'vue-eslint-parser';
2
+ /** The top-level AST produced by vue-eslint-parser, containing template body and comments. */
2
3
  export type VueTokens = VueESLintParser.AST.ESLintProgram;
4
+ /**
5
+ * Parses a Vue SFC template string into a vue-eslint-parser AST.
6
+ *
7
+ * @param vueTemplate - The raw Vue template source code
8
+ * @returns The parsed AST program node containing the template body
9
+ */
3
10
  export declare function vueParse(vueTemplate: string): VueTokens;
4
- export type ASTNode = VueESLintParser.AST.VElement | VueESLintParser.AST.VText | VueESLintParser.AST.VExpressionContainer;
11
+ export type VElement = VueESLintParser.AST.VElement;
12
+ export type VText = VueESLintParser.AST.VText;
13
+ export type VExpressionContainer = VueESLintParser.AST.VExpressionContainer;
14
+ /** Union of AST node types that can appear as children in a Vue template. */
15
+ export type ASTNode = VElement | VText | VExpressionContainer;
16
+ /** Represents a comment token in the Vue template AST with location information. */
5
17
  export type ASTComment = VueESLintParser.AST.Token & VueESLintParser.AST.HasLocation;
@@ -1,4 +1,10 @@
1
1
  import * as VueESLintParser from 'vue-eslint-parser';
2
+ /**
3
+ * Parses a Vue SFC template string into a vue-eslint-parser AST.
4
+ *
5
+ * @param vueTemplate - The raw Vue template source code
6
+ * @returns The parsed AST program node containing the template body
7
+ */
2
8
  export function vueParse(vueTemplate) {
3
9
  const ast = VueESLintParser.parse(vueTemplate, { parser: false });
4
10
  return ast;
package/package.json CHANGED
@@ -1,10 +1,13 @@
1
1
  {
2
2
  "name": "@markuplint/vue-parser",
3
- "version": "4.6.22",
3
+ "version": "5.0.0-alpha.0",
4
4
  "description": "Vue parser for markuplint",
5
5
  "repository": "git@github.com:markuplint/markuplint.git",
6
6
  "author": "Yusuke Hirao <yusukehirao@me.com>",
7
7
  "license": "MIT",
8
+ "engines": {
9
+ "node": ">=22"
10
+ },
8
11
  "type": "module",
9
12
  "exports": {
10
13
  ".": {
@@ -21,10 +24,10 @@
21
24
  "clean": "tsc --build --clean tsconfig.build.json"
22
25
  },
23
26
  "dependencies": {
24
- "@markuplint/html-parser": "4.6.22",
25
- "@markuplint/ml-ast": "4.4.10",
26
- "@markuplint/parser-utils": "4.8.10",
27
- "vue-eslint-parser": "10.2.0"
27
+ "@markuplint/html-parser": "5.0.0-alpha.0",
28
+ "@markuplint/ml-ast": "5.0.0-alpha.0",
29
+ "@markuplint/parser-utils": "5.0.0-alpha.0",
30
+ "vue-eslint-parser": "10.4.0"
28
31
  },
29
- "gitHead": "6213ea30269ef404f030e67bbcc7fc7443ec1060"
32
+ "gitHead": "13dcfc84ec83d87360c720e253383b60767e1b56"
30
33
  }