@markuplint/vue-parser 5.0.0-rc.0 → 5.0.0-rc.2

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.
@@ -8,11 +8,13 @@
8
8
 
9
9
  ```
10
10
  src/
11
- ├── index.ts — parser を再エクスポート
12
- ├── parser.ts — Parser<ASTNode, State> を拡張する VueParser クラス
13
- ├── index.spec.ts — VueParser の統合テスト
11
+ ├── index.ts — parser を再エクスポート
12
+ ├── parser.ts — Parser<ASTNode, State> を拡張する VueParser クラス
13
+ ├── component-scanner.ts — pretenders 自動スキャン用コンポーネントスキャナー(サブパスエクスポート)
14
+ ├── index.spec.ts — VueParser の統合テスト
15
+ ├── component-scanner.spec.ts — コンポーネントスキャナーのテスト
14
16
  └── vue-parser/
15
- └── index.ts — vue-eslint-parser ラッパー、ASTNode/ASTComment 型エクスポート
17
+ └── index.ts — vue-eslint-parser ラッパー、ASTNode/ASTComment 型エクスポート
16
18
  ```
17
19
 
18
20
  ## アーキテクチャ図
@@ -28,10 +30,12 @@ flowchart TD
28
30
  subgraph pkg ["@markuplint/vue-parser"]
29
31
  vueParser["VueParser\nextends Parser‹ASTNode, State›"]
30
32
  vueParseFn["vueParse()\nvue-eslint-parser ラッパー"]
33
+ compScanner["componentScanner\n(サブパス: ./component-scanner)"]
31
34
  end
32
35
 
33
36
  subgraph downstream ["下流"]
34
37
  mlCore["@markuplint/ml-core\n(MLASTDocument → MLDOM)"]
38
+ pretenders["@markuplint/pretenders\n(自動スキャン)"]
35
39
  end
36
40
 
37
41
  mlAst -->|"AST 型"| vueParser
@@ -40,6 +44,8 @@ flowchart TD
40
44
  vueParseFn -->|"ESLintProgram AST"| vueParser
41
45
 
42
46
  vueParser -->|"MLASTDocument を生成"| mlCore
47
+ vueParser -->|"parse()"| compScanner
48
+ compScanner -->|"ComponentScanResult"| pretenders
43
49
  ```
44
50
 
45
51
  ## VueParser クラス
@@ -249,12 +255,13 @@ Alpine.js では条件分岐とループに決まったパターン — `<templa
249
255
 
250
256
  ## 主要ソースファイル
251
257
 
252
- | ファイル | 用途 |
253
- | ------------------------- | ----------------------------------------------------------------- |
254
- | `src/parser.ts` | 全オーバーライドメソッドを持つ VueParser クラス |
255
- | `src/vue-parser/index.ts` | vue-eslint-parser ラッパーと型定義(ASTNode、ASTComment) |
256
- | `src/index.ts` | モジュールエントリーポイント、parser インスタンスを再エクスポート |
257
- | `src/index.spec.ts` | パース、ディレクティブ、名前空間をカバーする統合テスト |
258
+ | ファイル | 用途 |
259
+ | -------------------------- | ------------------------------------------------------------------------------------------------------------- |
260
+ | `src/parser.ts` | 全オーバーライドメソッドを持つ VueParser クラス |
261
+ | `src/vue-parser/index.ts` | vue-eslint-parser ラッパーと型定義(ASTNode、ASTComment) |
262
+ | `src/index.ts` | モジュールエントリーポイント、parser インスタンスを再エクスポート |
263
+ | `src/index.spec.ts` | パース、ディレクティブ、名前空間をカバーする統合テスト |
264
+ | `src/component-scanner.ts` | `@markuplint/pretenders` 自動スキャン用コンポーネントスキャナー(サブパスエクスポート `./component-scanner`) |
258
265
 
259
266
  ## 外部依存
260
267
 
@@ -277,14 +284,18 @@ flowchart TD
277
284
 
278
285
  subgraph pkg ["@markuplint/vue-parser"]
279
286
  vueParser["VueParser"]
287
+ compScanner["componentScanner\n(./component-scanner)"]
280
288
  end
281
289
 
282
290
  subgraph downstream ["下流"]
283
291
  mlCore["@markuplint/ml-core\n(MLASTDocument → MLDOM)"]
292
+ pretenders["@markuplint/pretenders\n(自動スキャン)"]
284
293
  end
285
294
 
286
295
  upstream -->|"型、パース"| vueParser
287
296
  vueParser -->|"MLASTDocument を生成"| mlCore
297
+ vueParser -->|"parse()"| compScanner
298
+ compScanner -->|"ComponentScanResult"| pretenders
288
299
  ```
289
300
 
290
301
  ### 上流
@@ -296,6 +307,7 @@ flowchart TD
296
307
  ### 下流
297
308
 
298
309
  - **`@markuplint/ml-core`** -- `VueParser` が生成する `MLASTDocument` を消費し、ルール評価のための MLDOM を構築
310
+ - **`@markuplint/pretenders`** -- `./component-scanner` を動的インポートし、ルート要素・属性・スロット情報を抽出して自動スキャンに利用
299
311
 
300
312
  ## ドキュメントマップ
301
313
 
package/ARCHITECTURE.md CHANGED
@@ -8,11 +8,13 @@
8
8
 
9
9
  ```
10
10
  src/
11
- ├── index.ts — Re-exports parser
12
- ├── parser.ts — VueParser class extending Parser<ASTNode, State>
13
- ├── index.spec.ts — Integration tests for VueParser
11
+ ├── index.ts — Re-exports parser
12
+ ├── parser.ts — VueParser class extending Parser<ASTNode, State>
13
+ ├── component-scanner.ts — Component scanner for pretenders auto scan (subpath export)
14
+ ├── index.spec.ts — Integration tests for VueParser
15
+ ├── component-scanner.spec.ts — Tests for component scanner
14
16
  └── vue-parser/
15
- └── index.ts — vue-eslint-parser wrapper, ASTNode/ASTComment type exports
17
+ └── index.ts — vue-eslint-parser wrapper, ASTNode/ASTComment type exports
16
18
  ```
17
19
 
18
20
  ## Architecture Diagram
@@ -28,10 +30,12 @@ flowchart TD
28
30
  subgraph pkg ["@markuplint/vue-parser"]
29
31
  vueParser["VueParser\nextends Parser‹ASTNode, State›"]
30
32
  vueParseFn["vueParse()\nvue-eslint-parser wrapper"]
33
+ compScanner["componentScanner\n(subpath: ./component-scanner)"]
31
34
  end
32
35
 
33
36
  subgraph downstream ["Downstream"]
34
37
  mlCore["@markuplint/ml-core\n(MLASTDocument → MLDOM)"]
38
+ pretenders["@markuplint/pretenders\n(auto scan)"]
35
39
  end
36
40
 
37
41
  mlAst -->|"AST types"| vueParser
@@ -40,6 +44,8 @@ flowchart TD
40
44
  vueParseFn -->|"ESLintProgram AST"| vueParser
41
45
 
42
46
  vueParser -->|"produces MLASTDocument"| mlCore
47
+ vueParser -->|"parse()"| compScanner
48
+ compScanner -->|"ComponentScanResult"| pretenders
43
49
  ```
44
50
 
45
51
  ## VueParser Class
@@ -249,12 +255,13 @@ The current Vue parser handles these directives at the attribute level only (`is
249
255
 
250
256
  ## Key Source Files
251
257
 
252
- | File | Purpose |
253
- | ------------------------- | -------------------------------------------------------------------- |
254
- | `src/parser.ts` | VueParser class with all override methods |
255
- | `src/vue-parser/index.ts` | vue-eslint-parser wrapper and type definitions (ASTNode, ASTComment) |
256
- | `src/index.ts` | Module entry point, re-exports parser instance |
257
- | `src/index.spec.ts` | Integration tests covering parsing, directives, namespaces |
258
+ | File | Purpose |
259
+ | -------------------------- | ----------------------------------------------------------------------------------------------- |
260
+ | `src/parser.ts` | VueParser class with all override methods |
261
+ | `src/vue-parser/index.ts` | vue-eslint-parser wrapper and type definitions (ASTNode, ASTComment) |
262
+ | `src/index.ts` | Module entry point, re-exports parser instance |
263
+ | `src/index.spec.ts` | Integration tests covering parsing, directives, namespaces |
264
+ | `src/component-scanner.ts` | Component scanner for `@markuplint/pretenders` auto scan (subpath export `./component-scanner`) |
258
265
 
259
266
  ## External Dependencies
260
267
 
@@ -277,14 +284,18 @@ flowchart TD
277
284
 
278
285
  subgraph pkg ["@markuplint/vue-parser"]
279
286
  vueParser["VueParser"]
287
+ compScanner["componentScanner\n(./component-scanner)"]
280
288
  end
281
289
 
282
290
  subgraph downstream ["Downstream"]
283
291
  mlCore["@markuplint/ml-core\n(MLASTDocument → MLDOM)"]
292
+ pretenders["@markuplint/pretenders\n(auto scan)"]
284
293
  end
285
294
 
286
295
  upstream -->|"types, parsing"| vueParser
287
296
  vueParser -->|"produces MLASTDocument"| mlCore
297
+ vueParser -->|"parse()"| compScanner
298
+ compScanner -->|"ComponentScanResult"| pretenders
288
299
  ```
289
300
 
290
301
  ### Upstream
@@ -296,6 +307,7 @@ flowchart TD
296
307
  ### Downstream
297
308
 
298
309
  - **`@markuplint/ml-core`** -- Consumes the `MLASTDocument` produced by `VueParser` and constructs the MLDOM for rule evaluation
310
+ - **`@markuplint/pretenders`** -- Dynamically imports `./component-scanner` to extract root element, attributes, and slot information for auto scan
299
311
 
300
312
  ## Documentation Map
301
313
 
package/CHANGELOG.md CHANGED
@@ -3,6 +3,25 @@
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.0.0-rc.2](https://github.com/markuplint/markuplint/compare/v5.0.0-rc.1...v5.0.0-rc.2) (2026-04-15)
7
+
8
+ **Note:** Version bump only for package @markuplint/vue-parser
9
+
10
+ # [5.0.0-rc.1](https://github.com/markuplint/markuplint/compare/v5.0.0-rc.0...v5.0.0-rc.1) (2026-03-27)
11
+
12
+ - feat!: adapt framework parsers to UUID-based node references ([6d543b8](https://github.com/markuplint/markuplint/commit/6d543b8c11506fe113d0ceeae3526f552f4ee26d))
13
+
14
+ ### Features
15
+
16
+ - **vue-parser:** add component-scanner subpath export for pretenders auto scan ([ac8e0f5](https://github.com/markuplint/markuplint/commit/ac8e0f52be19cc0714593e26066f2f8cef9c96cd))
17
+
18
+ ### BREAKING CHANGES
19
+
20
+ - Parser output no longer contains parentNode/pairNode
21
+ object references. Use parentNodeUuid/pairNodeUuid string fields instead.
22
+
23
+ Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
24
+
6
25
  # [5.0.0-rc.0](https://github.com/markuplint/markuplint/compare/v5.0.0-alpha.3...v5.0.0-rc.0) (2026-03-12)
7
26
 
8
27
  **Note:** Version bump only for package @markuplint/vue-parser
package/SKILL.md CHANGED
@@ -20,6 +20,7 @@ detection, update vue-eslint-parser version support, and fix comment injection.
20
20
  | `modify-element-type-detection` | Update detectElementType() matchers |
21
21
  | `update-vue-version-support` | Handle vue-eslint-parser API changes |
22
22
  | `fix-comment-injection` | Fix template comment injection in flattenNodes() |
23
+ | `update-component-scanner` | Update component-scanner for pretenders auto scan |
23
24
 
24
25
  If omitted, defaults to `add-directive`.
25
26
 
@@ -127,6 +128,29 @@ Fix template comment injection in `flattenNodes()`. Follow recipe #4 in `docs/ma
127
128
  2. Test with Vue templates containing HTML comments (`<!-- -->`), bogus comments (`<!...>`), and mixed content
128
129
  3. Test: `yarn test --scope @markuplint/vue-parser`
129
130
 
131
+ ## Task: update-component-scanner
132
+
133
+ Update `src/component-scanner.ts` when Vue slot syntax or script block handling changes.
134
+
135
+ ### When to update
136
+
137
+ - New slot-like syntax is added to Vue (e.g., a new built-in component that acts as a slot)
138
+ - `<script setup>` extraction logic needs to change (e.g., new script attributes)
139
+ - The `extractComponentInfo` shared logic needs a fix (also update svelte-parser and astro-parser)
140
+
141
+ ### Step 1: Make the change
142
+
143
+ 1. Read `src/component-scanner.ts`
144
+ 2. Modify `detectSlots()` for new slot patterns, or `extractVueScriptSetup()` for script changes
145
+ 3. If modifying `extractComponentInfo()`, apply the same change to all three parsers (vue, svelte, astro)
146
+
147
+ ### Step 2: Verify
148
+
149
+ 1. Update tests in `src/component-scanner.spec.ts`
150
+ 2. Build: `yarn build --scope @markuplint/vue-parser`
151
+ 3. Test: `npx vitest run packages/@markuplint/vue-parser/src/component-scanner.spec.ts`
152
+ 4. Run pretenders integration tests: `npx vitest run packages/@markuplint/pretenders`
153
+
130
154
  ## Rules
131
155
 
132
156
  1. **Use vue-eslint-parser** for all template parsing — never parse Vue templates manually.
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Result of scanning a single component file for its root element information.
3
+ */
4
+ export interface ComponentScanResult {
5
+ readonly rootElement: string | null;
6
+ readonly attrs: readonly ComponentScanAttr[];
7
+ readonly hasSlots: boolean;
8
+ readonly scriptSource?: ComponentScanScriptSource;
9
+ readonly namespace?: 'svg';
10
+ readonly line?: number;
11
+ readonly col?: number;
12
+ }
13
+ /**
14
+ * A static attribute extracted from a component's root element.
15
+ */
16
+ export interface ComponentScanAttr {
17
+ readonly name: string;
18
+ readonly value?: string;
19
+ }
20
+ /**
21
+ * A script/ESM source block extracted from a component file.
22
+ */
23
+ export interface ComponentScanScriptSource {
24
+ readonly content: string;
25
+ readonly offset: number;
26
+ }
27
+ /**
28
+ * Component scanner for Vue SFC files.
29
+ *
30
+ * Parses a Vue component using markuplint's Vue parser, extracts the root
31
+ * element at depth=0, detects static attributes, slot usage, and the
32
+ * `<script setup>` block for import analysis.
33
+ */
34
+ export declare const componentScanner: {
35
+ scanComponent(sourceCode: string): ComponentScanResult | null;
36
+ extractScriptSource(sourceCode: string): ComponentScanScriptSource | null;
37
+ };
@@ -0,0 +1,89 @@
1
+ import { parser } from './parser.js';
2
+ /**
3
+ * Extracts root element information from a parsed MLAST document.
4
+ */
5
+ function extractComponentInfo(doc) {
6
+ const root = doc.nodeList.find((n) => n.type === 'starttag' && n.depth === 0 && !n.isFragment);
7
+ if (!root) {
8
+ return null;
9
+ }
10
+ const attrs = [];
11
+ for (const attr of root.attributes) {
12
+ if (attr.type !== 'attr') {
13
+ continue;
14
+ }
15
+ const value = attr.value.raw;
16
+ if (value === '') {
17
+ attrs.push({ name: attr.nodeName });
18
+ }
19
+ else {
20
+ attrs.push({ name: attr.nodeName, value });
21
+ }
22
+ }
23
+ return {
24
+ rootElement: root.nodeName,
25
+ attrs,
26
+ namespace: root.namespace === 'http://www.w3.org/2000/svg' ? 'svg' : undefined,
27
+ line: root.line,
28
+ col: root.col,
29
+ };
30
+ }
31
+ /**
32
+ * Detects whether the parsed Vue template contains `<slot>` elements.
33
+ */
34
+ function detectSlots(doc) {
35
+ return doc.nodeList.some(n => n.type === 'starttag' && n.nodeName === 'slot');
36
+ }
37
+ /**
38
+ * Extracts the `<script setup>` block from a Vue SFC source.
39
+ */
40
+ function extractVueScriptSetup(source) {
41
+ const re = /<script\s[^>]*?\bsetup\b[^>]*>/i;
42
+ const match = re.exec(source);
43
+ if (!match) {
44
+ return null;
45
+ }
46
+ const startTag = match[0];
47
+ const contentStart = match.index + startTag.length;
48
+ const endTagRe = /<\/script\s*>/i;
49
+ const remaining = source.slice(contentStart);
50
+ const endMatch = endTagRe.exec(remaining);
51
+ if (!endMatch) {
52
+ return null;
53
+ }
54
+ return {
55
+ content: remaining.slice(0, endMatch.index),
56
+ offset: contentStart,
57
+ };
58
+ }
59
+ /**
60
+ * Component scanner for Vue SFC files.
61
+ *
62
+ * Parses a Vue component using markuplint's Vue parser, extracts the root
63
+ * element at depth=0, detects static attributes, slot usage, and the
64
+ * `<script setup>` block for import analysis.
65
+ */
66
+ export const componentScanner = {
67
+ scanComponent(sourceCode) {
68
+ let doc;
69
+ try {
70
+ doc = parser.parse(sourceCode);
71
+ }
72
+ catch (error) {
73
+ if (error instanceof SyntaxError || (error instanceof Error && error.constructor.name === 'ParserError')) {
74
+ return null;
75
+ }
76
+ throw error;
77
+ }
78
+ const info = extractComponentInfo(doc);
79
+ if (!info) {
80
+ return null;
81
+ }
82
+ const hasSlots = detectSlots(doc);
83
+ const scriptSource = extractVueScriptSetup(sourceCode) ?? undefined;
84
+ return { ...info, hasSlots, scriptSource };
85
+ },
86
+ extractScriptSource(sourceCode) {
87
+ return extractVueScriptSetup(sourceCode);
88
+ },
89
+ };
package/lib/parser.js CHANGED
@@ -114,7 +114,7 @@ class VueParser extends Parser {
114
114
  const comment = this.visitComment({
115
115
  ...token,
116
116
  depth: node.depth,
117
- parentNode: node.parentNode,
117
+ parentNode: node.parentNode ?? null,
118
118
  }, {
119
119
  isBogus: betweenComment.type === 'HTMLBogusComment',
120
120
  })[0];
package/package.json CHANGED
@@ -1,8 +1,12 @@
1
1
  {
2
2
  "name": "@markuplint/vue-parser",
3
- "version": "5.0.0-rc.0",
3
+ "version": "5.0.0-rc.2",
4
4
  "description": "Vue parser for markuplint",
5
- "repository": "git@github.com:markuplint/markuplint.git",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/markuplint/markuplint.git",
8
+ "directory": "packages/@markuplint/vue-parser"
9
+ },
6
10
  "author": "Yusuke Hirao <yusukehirao@me.com>",
7
11
  "license": "MIT",
8
12
  "engines": {
@@ -13,6 +17,10 @@
13
17
  ".": {
14
18
  "import": "./lib/index.js",
15
19
  "types": "./lib/index.d.ts"
20
+ },
21
+ "./component-scanner": {
22
+ "import": "./lib/component-scanner.js",
23
+ "types": "./lib/component-scanner.d.ts"
16
24
  }
17
25
  },
18
26
  "publishConfig": {
@@ -24,10 +32,10 @@
24
32
  "clean": "tsc --build --clean tsconfig.build.json"
25
33
  },
26
34
  "dependencies": {
27
- "@markuplint/html-parser": "5.0.0-rc.0",
28
- "@markuplint/ml-ast": "5.0.0-rc.0",
29
- "@markuplint/parser-utils": "5.0.0-rc.0",
35
+ "@markuplint/html-parser": "5.0.0-rc.2",
36
+ "@markuplint/ml-ast": "5.0.0-rc.2",
37
+ "@markuplint/parser-utils": "5.0.0-rc.2",
30
38
  "vue-eslint-parser": "10.4.0"
31
39
  },
32
- "gitHead": "ebf4d7cfca0c259aead3b292c6b8a202db4cd802"
40
+ "gitHead": "e43763858d9234c417053becc73dbd088c1e7ea6"
33
41
  }