@markuplint/astro-parser 5.0.0-rc.0 → 5.0.0-rc.1

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.
@@ -12,8 +12,10 @@ src/
12
12
  ├── parser.ts — Parser<Node> を拡張する AstroParser クラス
13
13
  ├── astro-parser.ts — astro-eslint-parser ラッパーと型の再エクスポート
14
14
  ├── detect-block-behavior.ts — .map()/.filter() のブロック動作検出
15
+ ├── component-scanner.ts — pretenders 自動スキャン用コンポーネントスキャナー(サブパスエクスポート)
15
16
  ├── parser.spec.ts — AstroParser 統合テスト
16
- └── astro-parser.spec.ts — astro-eslint-parser ラッパーテスト
17
+ ├── astro-parser.spec.ts — astro-eslint-parser ラッパーテスト
18
+ └── component-scanner.spec.ts — コンポーネントスキャナーのテスト
17
19
  ```
18
20
 
19
21
  ## アーキテクチャ図
@@ -31,10 +33,12 @@ flowchart TD
31
33
  astroParser["AstroParser\nextends Parser‹Node›"]
32
34
  astroParseFn["astroParse()\nastro-eslint-parser ラッパー"]
33
35
  detectBlock["detectBlockBehavior()\n.map()/.filter() 検出"]
36
+ compScanner["componentScanner\n(サブパス: ./component-scanner)"]
34
37
  end
35
38
 
36
39
  subgraph downstream ["下流"]
37
40
  mlCore["@markuplint/ml-core\n(MLASTDocument → MLDOM)"]
41
+ pretenders["@markuplint/pretenders\n(自動スキャン)"]
38
42
  end
39
43
 
40
44
  mlAst -->|"AST 型"| astroParser
@@ -44,6 +48,8 @@ flowchart TD
44
48
  astroParseFn -->|"RootNode.children"| astroParser
45
49
  detectBlock -->|"blockBehavior"| astroParser
46
50
  astroParser -->|"MLASTDocument を生成"| mlCore
51
+ astroParser -->|"parse()"| compScanner
52
+ compScanner -->|"ComponentScanResult"| pretenders
47
53
  ```
48
54
 
49
55
  ## AstroParser クラス
@@ -185,11 +191,12 @@ astro-eslint-parser → @astrojs/compiler → Astro 構文サポート
185
191
 
186
192
  ## 主要ソースファイル
187
193
 
188
- | ファイル | 用途 |
189
- | ----------------- | ------------------------------------------------------------------------------------- |
190
- | `parser.ts` | `AstroParser` クラス — 全オーバーライドメソッドと名前空間スコーピング |
191
- | `astro-parser.ts` | `astroParse()` ラッパー — `astro-eslint-parser` に委譲し、診断を `ParserError` に変換 |
192
- | `index.ts` | 公開 API — シングルトン `parser` インスタンスを再エクスポート |
194
+ | ファイル | 用途 |
195
+ | ---------------------- | ------------------------------------------------------------------------------------------------------------- |
196
+ | `parser.ts` | `AstroParser` クラス — 全オーバーライドメソッドと名前空間スコーピング |
197
+ | `astro-parser.ts` | `astroParse()` ラッパー — `astro-eslint-parser` に委譲し、診断を `ParserError` に変換 |
198
+ | `index.ts` | 公開 API — シングルトン `parser` インスタンスを再エクスポート |
199
+ | `component-scanner.ts` | `@markuplint/pretenders` 自動スキャン用コンポーネントスキャナー(サブパスエクスポート `./component-scanner`) |
193
200
 
194
201
  ## ドキュメントマップ
195
202
 
package/ARCHITECTURE.md CHANGED
@@ -12,8 +12,10 @@ src/
12
12
  ├── parser.ts — AstroParser class extending Parser<Node>
13
13
  ├── astro-parser.ts — astro-eslint-parser wrapper and type re-exports
14
14
  ├── detect-block-behavior.ts — Detects .map()/.filter() for block behavior
15
+ ├── component-scanner.ts — Component scanner for pretenders auto scan (subpath export)
15
16
  ├── parser.spec.ts — AstroParser integration tests
16
- └── astro-parser.spec.ts — astro-eslint-parser wrapper tests
17
+ ├── astro-parser.spec.ts — astro-eslint-parser wrapper tests
18
+ └── component-scanner.spec.ts — Tests for component scanner
17
19
  ```
18
20
 
19
21
  ## Architecture Diagram
@@ -31,10 +33,12 @@ flowchart TD
31
33
  astroParser["AstroParser\nextends Parser‹Node›"]
32
34
  astroParseFn["astroParse()\nastro-eslint-parser wrapper"]
33
35
  detectBlock["detectBlockBehavior()\n.map()/.filter() detection"]
36
+ compScanner["componentScanner\n(subpath: ./component-scanner)"]
34
37
  end
35
38
 
36
39
  subgraph downstream ["Downstream"]
37
40
  mlCore["@markuplint/ml-core\n(MLASTDocument → MLDOM)"]
41
+ pretenders["@markuplint/pretenders\n(auto scan)"]
38
42
  end
39
43
 
40
44
  mlAst -->|"AST types"| astroParser
@@ -44,6 +48,8 @@ flowchart TD
44
48
  astroParseFn -->|"RootNode.children"| astroParser
45
49
  detectBlock -->|"blockBehavior"| astroParser
46
50
  astroParser -->|"produces MLASTDocument"| mlCore
51
+ astroParser -->|"parse()"| compScanner
52
+ compScanner -->|"ComponentScanResult"| pretenders
47
53
  ```
48
54
 
49
55
  ## AstroParser Class
@@ -185,11 +191,12 @@ astro-eslint-parser → @astrojs/compiler → Astro syntax support
185
191
 
186
192
  ## Key Source Files
187
193
 
188
- | File | Purpose |
189
- | ----------------- | -------------------------------------------------------------------------------------------------- |
190
- | `parser.ts` | `AstroParser` class — all override methods and namespace scoping |
191
- | `astro-parser.ts` | `astroParse()` wrapper — delegates to `astro-eslint-parser`, converts diagnostics to `ParserError` |
192
- | `index.ts` | Public API — re-exports the singleton `parser` instance |
194
+ | File | Purpose |
195
+ | ---------------------- | -------------------------------------------------------------------------------------------------- |
196
+ | `parser.ts` | `AstroParser` class — all override methods and namespace scoping |
197
+ | `astro-parser.ts` | `astroParse()` wrapper — delegates to `astro-eslint-parser`, converts diagnostics to `ParserError` |
198
+ | `index.ts` | Public API — re-exports the singleton `parser` instance |
199
+ | `component-scanner.ts` | Component scanner for `@markuplint/pretenders` auto scan (subpath export `./component-scanner`) |
193
200
 
194
201
  ## Documentation Map
195
202
 
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.0.0-rc.1](https://github.com/markuplint/markuplint/compare/v5.0.0-rc.0...v5.0.0-rc.1) (2026-03-27)
7
+
8
+ - feat!: adapt framework parsers to UUID-based node references ([6d543b8](https://github.com/markuplint/markuplint/commit/6d543b8c11506fe113d0ceeae3526f552f4ee26d))
9
+
10
+ ### Features
11
+
12
+ - **astro-parser:** add component-scanner subpath export for pretenders auto scan ([3d85bc5](https://github.com/markuplint/markuplint/commit/3d85bc5f5904c0157415de175227eedf89539cda))
13
+
14
+ ### BREAKING CHANGES
15
+
16
+ - Parser output no longer contains parentNode/pairNode
17
+ object references. Use parentNodeUuid/pairNodeUuid string fields instead.
18
+
19
+ Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
20
+
6
21
  # [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
22
 
8
23
  **Note:** Version bump only for package @markuplint/astro-parser
package/SKILL.md CHANGED
@@ -19,6 +19,7 @@ modify namespace scoping, update expression handling, and manage astro-eslint-pa
19
19
  | `add-directive` | Add a new Astro template directive |
20
20
  | `modify-namespace-scoping` | Modify SVG/XHTML namespace scoping logic |
21
21
  | `update-expression-handling` | Update expression splitting or MustacheTag handling |
22
+ | `update-component-scanner` | Update component-scanner for pretenders auto scan |
22
23
 
23
24
  If omitted, defaults to `add-directive`.
24
25
 
@@ -100,6 +101,29 @@ Update expression splitting or MustacheTag handling. Follow recipe #3 in `docs/m
100
101
  2. Test with expressions containing nested HTML (e.g., `{list.map(item => <li>{item}</li>)}`)
101
102
  3. Test: `yarn test --scope @markuplint/astro-parser`
102
103
 
104
+ ## Task: update-component-scanner
105
+
106
+ Update `src/component-scanner.ts` when Astro slot syntax or frontmatter handling changes.
107
+
108
+ ### When to update
109
+
110
+ - New slot-like syntax is added to Astro
111
+ - Frontmatter delimiter handling needs to change
112
+ - The `extractComponentInfo` shared logic needs a fix (also update vue-parser and svelte-parser)
113
+
114
+ ### Step 1: Make the change
115
+
116
+ 1. Read `src/component-scanner.ts`
117
+ 2. Modify `detectSlots()` for new slot patterns, or `extractAstroFrontmatter()` for frontmatter changes
118
+ 3. If modifying `extractComponentInfo()`, apply the same change to all three parsers (vue, svelte, astro)
119
+
120
+ ### Step 2: Verify
121
+
122
+ 1. Update tests in `src/component-scanner.spec.ts`
123
+ 2. Build: `yarn build --scope @markuplint/astro-parser`
124
+ 3. Test: `npx vitest run packages/@markuplint/astro-parser/src/component-scanner.spec.ts`
125
+ 4. Run pretenders integration tests: `npx vitest run packages/@markuplint/pretenders`
126
+
103
127
  ## Rules
104
128
 
105
129
  1. **Delegate tokenization to astro-eslint-parser** — never parse Astro syntax manually; always use `astroParse()`.
@@ -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 Astro component files.
29
+ *
30
+ * Parses an Astro component using markuplint's Astro parser, extracts the root
31
+ * element at depth=0, detects static attributes, slot usage, and the
32
+ * frontmatter 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,88 @@
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 Astro 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 frontmatter block (`---...---`) from an Astro component source.
39
+ */
40
+ function extractAstroFrontmatter(source) {
41
+ const re = /^(?:\s*\n)?---\r?\n/;
42
+ const startMatch = re.exec(source);
43
+ if (!startMatch) {
44
+ return null;
45
+ }
46
+ const contentStart = startMatch[0].length;
47
+ const afterStart = source.slice(contentStart);
48
+ const endRe = /\r?\n---\r?\n/;
49
+ const endMatch = endRe.exec(afterStart);
50
+ if (!endMatch) {
51
+ return null;
52
+ }
53
+ return {
54
+ content: afterStart.slice(0, endMatch.index),
55
+ offset: contentStart,
56
+ };
57
+ }
58
+ /**
59
+ * Component scanner for Astro component files.
60
+ *
61
+ * Parses an Astro component using markuplint's Astro parser, extracts the root
62
+ * element at depth=0, detects static attributes, slot usage, and the
63
+ * frontmatter block for import analysis.
64
+ */
65
+ export const componentScanner = {
66
+ scanComponent(sourceCode) {
67
+ let doc;
68
+ try {
69
+ doc = parser.parse(sourceCode);
70
+ }
71
+ catch (error) {
72
+ if (error instanceof SyntaxError || (error instanceof Error && error.constructor.name === 'ParserError')) {
73
+ return null;
74
+ }
75
+ throw error;
76
+ }
77
+ const info = extractComponentInfo(doc);
78
+ if (!info) {
79
+ return null;
80
+ }
81
+ const hasSlots = detectSlots(doc);
82
+ const scriptSource = extractAstroFrontmatter(sourceCode) ?? undefined;
83
+ return { ...info, hasSlots, scriptSource };
84
+ },
85
+ extractScriptSource(sourceCode) {
86
+ return extractAstroFrontmatter(sourceCode);
87
+ },
88
+ };
package/lib/parser.js CHANGED
@@ -160,7 +160,7 @@ class AstroParser extends Parser {
160
160
  if (!startTagNode || startTagNode.type !== 'starttag') {
161
161
  throw new ParserError('Not found start tag', startTagNode ?? token);
162
162
  }
163
- return super.visitElement(startTagNode, childNodes, {
163
+ return super.visitElement({ ...startTagNode, parentNode: startTagNode.parentNode ?? null }, childNodes, {
164
164
  // https://docs.astro.build/en/basics/astro-syntax/#fragments
165
165
  namelessFragment: true,
166
166
  createEndTagToken: () => {
@@ -171,7 +171,7 @@ class AstroParser extends Parser {
171
171
  if (endTagNode?.type !== 'endtag') {
172
172
  return null;
173
173
  }
174
- return endTagNode ?? null;
174
+ return { ...endTagNode, parentNode: endTagNode.parentNode ?? null };
175
175
  },
176
176
  });
177
177
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markuplint/astro-parser",
3
- "version": "5.0.0-rc.0",
3
+ "version": "5.0.0-rc.1",
4
4
  "description": "astro parser for markuplint",
5
5
  "repository": "git@github.com:markuplint/markuplint.git",
6
6
  "author": "Yusuke Hirao <yusukehirao@me.com>",
@@ -13,6 +13,10 @@
13
13
  ".": {
14
14
  "import": "./lib/index.js",
15
15
  "types": "./lib/index.d.ts"
16
+ },
17
+ "./component-scanner": {
18
+ "import": "./lib/component-scanner.js",
19
+ "types": "./lib/component-scanner.d.ts"
16
20
  }
17
21
  },
18
22
  "publishConfig": {
@@ -24,12 +28,12 @@
24
28
  "clean": "tsc --build --clean tsconfig.build.json"
25
29
  },
26
30
  "dependencies": {
27
- "@markuplint/ml-ast": "5.0.0-rc.0",
28
- "@markuplint/parser-utils": "5.0.0-rc.0",
29
- "astro-eslint-parser": "1.3.0"
31
+ "@markuplint/ml-ast": "5.0.0-rc.1",
32
+ "@markuplint/parser-utils": "5.0.0-rc.1",
33
+ "astro-eslint-parser": "1.4.0"
30
34
  },
31
35
  "devDependencies": {
32
- "@astrojs/compiler": "3.0.0"
36
+ "@astrojs/compiler": "3.0.1"
33
37
  },
34
- "gitHead": "ebf4d7cfca0c259aead3b292c6b8a202db4cd802"
38
+ "gitHead": "0d6b4324d9a7d6b9e1ba57d4a57e45d36975cba9"
35
39
  }