@markuplint/vue-parser 5.3.0 → 5.5.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/CHANGELOG.md +15 -0
- package/README.md +2 -0
- package/lib/parser.d.ts +4 -3
- package/lib/parser.js +67 -4
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,21 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [5.5.0](https://github.com/markuplint/markuplint/compare/v5.4.0...v5.5.0) (2026-11-10)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **vue-parser:** treat a style and a script of the template as code that the compiler removes ([44315f6](https://github.com/markuplint/markuplint/commit/44315f692b852ec85f282d2632cf71e09f830594))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# [5.4.0](https://github.com/markuplint/markuplint/compare/v5.3.0...v5.4.0) (2026-10-29)
|
|
14
|
+
|
|
15
|
+
**Note:** Version bump only for package @markuplint/vue-parser
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
6
21
|
# [5.3.0](https://github.com/markuplint/markuplint/compare/v5.2.0...v5.3.0) (2026-10-21)
|
|
7
22
|
|
|
8
23
|
### Bug Fixes
|
package/README.md
CHANGED
|
@@ -24,4 +24,6 @@ Add `parser` option to your [configuration](https://markuplint.dev/configuration
|
|
|
24
24
|
}
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
+
Vue removes a `<style>` and a `<script>` from a template, so no rule checks one and, when you set `severity.parseError`, each is reported as the parse error `vue-ignored-side-effect-tag`. See [`parse-error`](https://markuplint.dev/docs/migration/v4-to-v5/rules/parse-error).
|
|
28
|
+
|
|
27
29
|
`parserOptions` option work in progress. In the current, the setting is `{ "sourceType": "module" }` that hard coded.
|
package/lib/parser.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ASTNode, ASTComment } from './vue-parser/index.js';
|
|
2
|
-
import type { MLASTParentNode, MLASTNodeTreeItem } from '@markuplint/ml-ast';
|
|
2
|
+
import type { MLASTParentNode, MLASTNodeTreeItem, MLASTParseError } from '@markuplint/ml-ast';
|
|
3
3
|
import { ParserError, Parser } from '@markuplint/parser-utils';
|
|
4
4
|
type State = {
|
|
5
5
|
comments: readonly ASTComment[];
|
|
@@ -30,6 +30,7 @@ declare class VueParser extends Parser<ASTNode, State> {
|
|
|
30
30
|
tokenize(): {
|
|
31
31
|
readonly ast: ASTNode[];
|
|
32
32
|
readonly isFragment: boolean;
|
|
33
|
+
readonly parseErrors?: readonly MLASTParseError[];
|
|
33
34
|
};
|
|
34
35
|
parseError(error: any): ParserError;
|
|
35
36
|
nodeize(originNode: ASTNode, parentNode: MLASTParentNode | null, depth: number): readonly MLASTNodeTreeItem[];
|
|
@@ -68,9 +69,9 @@ declare class VueParser extends Parser<ASTNode, State> {
|
|
|
68
69
|
* The user's `authoredElementName` replaces all of this, as it replaces any default of a parser.
|
|
69
70
|
*
|
|
70
71
|
* @see https://vuejs.org/guide/essentials/component-basics#using-a-component
|
|
71
|
-
* @see https://vuejs.org/api/built-in-components.html
|
|
72
|
+
* @see https://vuejs.org/api/built-in-components.html#built-in-components
|
|
72
73
|
* @see https://vuejs.org/api/built-in-special-elements.html#built-in-special-elements
|
|
73
|
-
* @see https://github.com/vuejs/core/blob/main/packages/compiler-core/src/parser.ts
|
|
74
|
+
* @see https://github.com/vuejs/core/blob/main/packages/compiler-core/src/parser.ts#isComponent
|
|
74
75
|
*/
|
|
75
76
|
detectElementType(nodeName: string): import("@markuplint/ml-ast").ElementType;
|
|
76
77
|
/**
|
package/lib/parser.js
CHANGED
|
@@ -5,7 +5,7 @@ import { vueParse } from './vue-parser/index.js';
|
|
|
5
5
|
* The built-in components, as written or in kebab-case: `isBuiltInType(tag, name)` of Vue is
|
|
6
6
|
* `tag === name || tag === hyphenate(name)`.
|
|
7
7
|
*
|
|
8
|
-
* @see https://vuejs.org/api/built-in-components.html
|
|
8
|
+
* @see https://vuejs.org/api/built-in-components.html#built-in-components
|
|
9
9
|
*/
|
|
10
10
|
const BUILT_IN_COMPONENTS = [
|
|
11
11
|
'Transition',
|
|
@@ -19,6 +19,55 @@ const BUILT_IN_COMPONENTS = [
|
|
|
19
19
|
'Suspense',
|
|
20
20
|
'suspense',
|
|
21
21
|
];
|
|
22
|
+
/**
|
|
23
|
+
* Whether the element is a `<style>` or a `<script>` that Vue's compiler removes from a client template.
|
|
24
|
+
*
|
|
25
|
+
* > Tags with side effect (<script> and <style>) are ignored in client component templates.
|
|
26
|
+
*
|
|
27
|
+
* `ignoreSideEffectTags` of `@vue/compiler-dom` removes the element whose `tag` is `script` or `style`
|
|
28
|
+
* and whose `tagType` is `ELEMENT`: a name with a capital letter (`<Style>`) is a component
|
|
29
|
+
* (`isComponent` of `@vue/compiler-core`). The parser of `vue-eslint-parser` lower-cases `name` and
|
|
30
|
+
* keeps `rawName`, so `rawName` is what tells them apart.
|
|
31
|
+
*
|
|
32
|
+
* @see https://github.com/vuejs/core/blob/main/packages/compiler-dom/src/transforms/ignoreSideEffectTags.ts#ignoreSideEffectTags
|
|
33
|
+
* @see https://github.com/vuejs/core/blob/main/packages/compiler-dom/src/errors.ts#DOMErrorMessages
|
|
34
|
+
* @param element - The element of the template
|
|
35
|
+
* @returns `true` if the compiler removes the element
|
|
36
|
+
*/
|
|
37
|
+
function isIgnoredSideEffectTag(element) {
|
|
38
|
+
return element.rawName === 'style' || element.rawName === 'script';
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Collects the non-fatal parse errors for the elements that the compiler removes, in the order of the source.
|
|
42
|
+
* It does not look inside one: the compiler removes it with its content.
|
|
43
|
+
*
|
|
44
|
+
* @param nodes - The nodes of a level of the template
|
|
45
|
+
* @param rawCode - The source that the ranges of `nodes` are positions in
|
|
46
|
+
* @returns The parse errors, whose positions cover the whole element
|
|
47
|
+
*/
|
|
48
|
+
function collectIgnoredSideEffectTags(nodes, rawCode) {
|
|
49
|
+
const errors = [];
|
|
50
|
+
for (const node of nodes) {
|
|
51
|
+
if (node.type !== 'VElement') {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (isIgnoredSideEffectTag(node)) {
|
|
55
|
+
errors.push({
|
|
56
|
+
code: 'vue-ignored-side-effect-tag',
|
|
57
|
+
startOffset: node.range[0],
|
|
58
|
+
startLine: node.loc.start.line,
|
|
59
|
+
startCol: node.loc.start.column + 1,
|
|
60
|
+
endOffset: node.range[1],
|
|
61
|
+
endLine: node.loc.end.line,
|
|
62
|
+
endCol: node.loc.end.column + 1,
|
|
63
|
+
raw: rawCode.slice(node.range[0], node.range[1]),
|
|
64
|
+
});
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
errors.push(...collectIgnoredSideEffectTags(node.children, rawCode));
|
|
68
|
+
}
|
|
69
|
+
return errors;
|
|
70
|
+
}
|
|
22
71
|
/**
|
|
23
72
|
* Directive resolution is intentionally not performed by this parser:
|
|
24
73
|
* `directivePatterns` declared in `@markuplint/vue-spec` are applied later by
|
|
@@ -60,9 +109,12 @@ class VueParser extends Parser {
|
|
|
60
109
|
if (ast.templateBody?.comments) {
|
|
61
110
|
this.state.comments = ast.templateBody.comments;
|
|
62
111
|
}
|
|
112
|
+
const children = ast.templateBody?.children ?? [];
|
|
113
|
+
const parseErrors = collectIgnoredSideEffectTags(children, this.rawCode);
|
|
63
114
|
return {
|
|
64
|
-
ast:
|
|
115
|
+
ast: children,
|
|
65
116
|
isFragment: true,
|
|
117
|
+
...(parseErrors.length > 0 ? { parseErrors } : {}),
|
|
66
118
|
};
|
|
67
119
|
}
|
|
68
120
|
parseError(error) {
|
|
@@ -81,6 +133,17 @@ class VueParser extends Parser {
|
|
|
81
133
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
82
134
|
originNode, parentNode, depth) {
|
|
83
135
|
const token = this.sliceFragment(originNode.range[0], originNode.range[1]);
|
|
136
|
+
// The compiler removes it, so neither its content nor where it is written reaches the DOM:
|
|
137
|
+
// it is a block of code that no rule reads, and `tokenize` reports it as a parse error.
|
|
138
|
+
if (originNode.type === 'VElement' && isIgnoredSideEffectTag(originNode)) {
|
|
139
|
+
return this.visitPsBlock({
|
|
140
|
+
...token,
|
|
141
|
+
depth,
|
|
142
|
+
parentNode,
|
|
143
|
+
nodeName: originNode.rawName,
|
|
144
|
+
isFragment: false,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
84
147
|
switch (originNode.type) {
|
|
85
148
|
case 'VText': {
|
|
86
149
|
return this.visitText({
|
|
@@ -199,9 +262,9 @@ class VueParser extends Parser {
|
|
|
199
262
|
* The user's `authoredElementName` replaces all of this, as it replaces any default of a parser.
|
|
200
263
|
*
|
|
201
264
|
* @see https://vuejs.org/guide/essentials/component-basics#using-a-component
|
|
202
|
-
* @see https://vuejs.org/api/built-in-components.html
|
|
265
|
+
* @see https://vuejs.org/api/built-in-components.html#built-in-components
|
|
203
266
|
* @see https://vuejs.org/api/built-in-special-elements.html#built-in-special-elements
|
|
204
|
-
* @see https://github.com/vuejs/core/blob/main/packages/compiler-core/src/parser.ts
|
|
267
|
+
* @see https://github.com/vuejs/core/blob/main/packages/compiler-core/src/parser.ts#isComponent
|
|
205
268
|
*/
|
|
206
269
|
detectElementType(nodeName) {
|
|
207
270
|
return super.detectElementType(nodeName, [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markuplint/vue-parser",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.5.0",
|
|
4
4
|
"description": "Vue parser for markuplint",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -32,11 +32,11 @@
|
|
|
32
32
|
"clean": "tsc --build --clean tsconfig.build.json"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@markuplint/html-parser": "5.
|
|
36
|
-
"@markuplint/ml-ast": "5.
|
|
37
|
-
"@markuplint/parser-utils": "5.
|
|
35
|
+
"@markuplint/html-parser": "5.5.0",
|
|
36
|
+
"@markuplint/ml-ast": "5.5.0",
|
|
37
|
+
"@markuplint/parser-utils": "5.5.0",
|
|
38
38
|
"@vue/shared": "^3.5.44",
|
|
39
39
|
"vue-eslint-parser": "^10.4.1"
|
|
40
40
|
},
|
|
41
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "fedebcfd56eaec4642e68643b2f9e10750d810e1"
|
|
42
42
|
}
|