@markuplint/svelte-parser 5.0.0-rc.4 → 5.0.0-rc.5
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/component-scanner.js +3 -9
- package/lib/parse-block.d.ts +0 -11
- package/lib/parse-block.js +3 -14
- package/lib/parser.d.ts +7 -26
- package/lib/parser.js +10 -54
- package/lib/svelte-parser/index.d.ts +3 -11
- package/lib/svelte-parser/index.js +3 -5
- package/lib/sveltekit-parser.d.ts +5 -0
- package/lib/sveltekit-parser.js +5 -0
- package/package.json +7 -7
package/lib/component-scanner.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import { parser } from './parser.js';
|
|
2
|
-
/**
|
|
3
|
-
* Extracts root element information from a parsed MLAST document.
|
|
4
|
-
*/
|
|
5
2
|
function extractComponentInfo(doc) {
|
|
6
3
|
const root = doc.nodeList.find((n) => n.type === 'starttag' && n.depth === 0 && !n.isFragment);
|
|
7
4
|
if (!root) {
|
|
@@ -29,9 +26,8 @@ function extractComponentInfo(doc) {
|
|
|
29
26
|
};
|
|
30
27
|
}
|
|
31
28
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* Supports:
|
|
29
|
+
* Slot usage can take several forms whose mapping to psblock node names is
|
|
30
|
+
* not derivable from this code:
|
|
35
31
|
* - Svelte 4: `<slot>` element (parsed as psblock `#ps:SlotElement`)
|
|
36
32
|
* - Svelte 5: `{@render children()}` (parsed as psblock `#ps:RenderTag`)
|
|
37
33
|
* - Standard `<slot>` elements
|
|
@@ -41,7 +37,6 @@ function detectSlots(doc) {
|
|
|
41
37
|
(n.type === 'psblock' && (n.nodeName === '#ps:SlotElement' || n.nodeName === '#ps:RenderTag')));
|
|
42
38
|
}
|
|
43
39
|
/**
|
|
44
|
-
* Extracts the instance `<script>` block from a Svelte component source.
|
|
45
40
|
* Prefers the instance script over `<script context="module">`.
|
|
46
41
|
*/
|
|
47
42
|
function extractSvelteScript(source) {
|
|
@@ -63,9 +58,8 @@ function extractSvelteScript(source) {
|
|
|
63
58
|
offset: contentStart,
|
|
64
59
|
};
|
|
65
60
|
if (!isModule) {
|
|
66
|
-
return block;
|
|
61
|
+
return block;
|
|
67
62
|
}
|
|
68
|
-
// Remember module script as fallback
|
|
69
63
|
moduleBlock ??= block;
|
|
70
64
|
}
|
|
71
65
|
return moduleBlock;
|
package/lib/parse-block.d.ts
CHANGED
|
@@ -1,17 +1,6 @@
|
|
|
1
1
|
import type { SvelteParser } from './parser.js';
|
|
2
2
|
import type { ChildToken, Token } from '@markuplint/parser-utils';
|
|
3
3
|
import type { SvelteBlock } from './svelte-parser/index.js';
|
|
4
|
-
/**
|
|
5
|
-
* Extracts the open and close tag tokens from a Svelte block construct
|
|
6
|
-
* (e.g., `{#each}...{/each}`, `{#key}...{/key}`).
|
|
7
|
-
* Locates the closing `{/xxx}` tag via regex and computes the opening token
|
|
8
|
-
* based on the block's child fragment boundaries.
|
|
9
|
-
*
|
|
10
|
-
* @param parser - The SvelteParser instance used to slice source fragments
|
|
11
|
-
* @param token - The child token representing the entire block range
|
|
12
|
-
* @param originBlockNode - The Svelte AST block node being parsed
|
|
13
|
-
* @returns An object containing the `openToken` and `closeToken` for the block
|
|
14
|
-
*/
|
|
15
4
|
export declare function parseBlock(parser: SvelteParser, token: ChildToken, originBlockNode: SvelteBlock): {
|
|
16
5
|
openToken: Token;
|
|
17
6
|
closeToken: Token;
|
package/lib/parse-block.js
CHANGED
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Extracts the open and close tag tokens from a Svelte block construct
|
|
3
|
-
* (e.g., `{#each}...{/each}`, `{#key}...{/key}`).
|
|
4
|
-
* Locates the closing `{/xxx}` tag via regex and computes the opening token
|
|
5
|
-
* based on the block's child fragment boundaries.
|
|
6
|
-
*
|
|
7
|
-
* @param parser - The SvelteParser instance used to slice source fragments
|
|
8
|
-
* @param token - The child token representing the entire block range
|
|
9
|
-
* @param originBlockNode - The Svelte AST block node being parsed
|
|
10
|
-
* @returns An object containing the `openToken` and `closeToken` for the block
|
|
11
|
-
*/
|
|
12
1
|
export function parseBlock(
|
|
13
2
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
14
3
|
parser, token,
|
|
@@ -16,6 +5,9 @@ parser, token,
|
|
|
16
5
|
originBlockNode) {
|
|
17
6
|
const range = token.raw;
|
|
18
7
|
/**
|
|
8
|
+
* The close tag is the final `{/xxx}`; intermediate `{:xxx}` clauses
|
|
9
|
+
* (e.g. `{:else}`, `{:then}`) must not be matched, hence the `$` anchor.
|
|
10
|
+
*
|
|
19
11
|
* `{#xxx}...{:xxx}...{/xxx}`
|
|
20
12
|
* find___^
|
|
21
13
|
*/
|
|
@@ -24,9 +16,6 @@ originBlockNode) {
|
|
|
24
16
|
if (eachCloseStartIndex == null) {
|
|
25
17
|
throw new SyntaxError('Block close tag not found');
|
|
26
18
|
}
|
|
27
|
-
/**
|
|
28
|
-
* `{/xxx}`
|
|
29
|
-
*/
|
|
30
19
|
const closeToken = parser.sliceFragment(token.offset + eachCloseStartIndex, originBlockNode.end);
|
|
31
20
|
const fragment = originBlockNode.type === 'IfBlock'
|
|
32
21
|
? originBlockNode.consequent.nodes
|
package/lib/parser.d.ts
CHANGED
|
@@ -18,35 +18,11 @@ export declare class SvelteParser extends Parser<SvelteNode> {
|
|
|
18
18
|
};
|
|
19
19
|
parse(raw: string, options?: ParseOptions): import("@markuplint/ml-ast").MLASTDocument;
|
|
20
20
|
parseError(error: any): ParserError;
|
|
21
|
-
/**
|
|
22
|
-
* Converts a Svelte AST node into markuplint node tree items.
|
|
23
|
-
* Dispatches on the node type to handle Text, Comment, ExpressionTag,
|
|
24
|
-
* elements (Component, RegularElement), and control flow blocks
|
|
25
|
-
* (IfBlock, EachBlock, AwaitBlock, KeyBlock, SnippetBlock).
|
|
26
|
-
*
|
|
27
|
-
* @param originNode - The Svelte AST node to convert
|
|
28
|
-
* @param parentNode - The parent node in the markuplint tree, or null for root nodes
|
|
29
|
-
* @param depth - The nesting depth of the node
|
|
30
|
-
* @returns An array of markuplint node tree items
|
|
31
|
-
*/
|
|
32
21
|
nodeize(originNode: SvelteNode, parentNode: MLASTParentNode | null, depth: number): readonly MLASTNodeTreeItem[];
|
|
33
|
-
/**
|
|
34
|
-
* Visits a text token, converting `<script>` tags embedded in Svelte template
|
|
35
|
-
* text into preprocessor-specific blocks rather than treating them as raw text.
|
|
36
|
-
*
|
|
37
|
-
* @param token - The child token representing the text content
|
|
38
|
-
* @returns An array of markuplint node tree items
|
|
39
|
-
*/
|
|
40
22
|
visitText(token: ChildToken): readonly MLASTNodeTreeItem[];
|
|
41
23
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* or contains multiple nodes.
|
|
45
|
-
*
|
|
46
|
-
* @param token - The child token with node name and fragment flag
|
|
47
|
-
* @param childNodes - The child Svelte AST nodes within the block
|
|
48
|
-
* @param blockBehavior - The block behavior, or null
|
|
49
|
-
* @returns A single-element tuple containing the preprocessor-specific block
|
|
24
|
+
* Invariant: exactly one block node must be produced; an empty or
|
|
25
|
+
* multi-node result indicates a parse error.
|
|
50
26
|
*/
|
|
51
27
|
visitPsBlock(token: ChildToken & {
|
|
52
28
|
readonly nodeName: string;
|
|
@@ -68,6 +44,11 @@ export declare class SvelteParser extends Parser<SvelteNode> {
|
|
|
68
44
|
* Directive resolution (`bind:`, `class:`, `on:`, etc.) and IDL attribute
|
|
69
45
|
* mapping are now handled declaratively by svelte-spec's directivePatterns
|
|
70
46
|
* and ml-core's acceptedAttrNames.
|
|
47
|
+
* Because directivePatterns are applied later by ml-core's MLAttr
|
|
48
|
+
* constructor, the attribute returned here carries only parser-detectable
|
|
49
|
+
* flags; for example, `on:click` without a value shows
|
|
50
|
+
* `isDynamicValue: false` at the parser level but resolves to `true`
|
|
51
|
+
* at the core level.
|
|
71
52
|
*
|
|
72
53
|
* @param token - The token representing the attribute
|
|
73
54
|
* @returns The parsed attribute node with Svelte-specific metadata
|
package/lib/parser.js
CHANGED
|
@@ -47,17 +47,6 @@ export class SvelteParser extends Parser {
|
|
|
47
47
|
}
|
|
48
48
|
return super.parseError(error);
|
|
49
49
|
}
|
|
50
|
-
/**
|
|
51
|
-
* Converts a Svelte AST node into markuplint node tree items.
|
|
52
|
-
* Dispatches on the node type to handle Text, Comment, ExpressionTag,
|
|
53
|
-
* elements (Component, RegularElement), and control flow blocks
|
|
54
|
-
* (IfBlock, EachBlock, AwaitBlock, KeyBlock, SnippetBlock).
|
|
55
|
-
*
|
|
56
|
-
* @param originNode - The Svelte AST node to convert
|
|
57
|
-
* @param parentNode - The parent node in the markuplint tree, or null for root nodes
|
|
58
|
-
* @param depth - The nesting depth of the node
|
|
59
|
-
* @returns An array of markuplint node tree items
|
|
60
|
-
*/
|
|
61
50
|
nodeize(
|
|
62
51
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
63
52
|
originNode, parentNode, depth) {
|
|
@@ -215,13 +204,6 @@ export class SvelteParser extends Parser {
|
|
|
215
204
|
}
|
|
216
205
|
}
|
|
217
206
|
}
|
|
218
|
-
/**
|
|
219
|
-
* Visits a text token, converting `<script>` tags embedded in Svelte template
|
|
220
|
-
* text into preprocessor-specific blocks rather than treating them as raw text.
|
|
221
|
-
*
|
|
222
|
-
* @param token - The child token representing the text content
|
|
223
|
-
* @returns An array of markuplint node tree items
|
|
224
|
-
*/
|
|
225
207
|
visitText(token) {
|
|
226
208
|
const nodes = super.visitText(token, {
|
|
227
209
|
researchTags: false,
|
|
@@ -240,14 +222,8 @@ export class SvelteParser extends Parser {
|
|
|
240
222
|
});
|
|
241
223
|
}
|
|
242
224
|
/**
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
* or contains multiple nodes.
|
|
246
|
-
*
|
|
247
|
-
* @param token - The child token with node name and fragment flag
|
|
248
|
-
* @param childNodes - The child Svelte AST nodes within the block
|
|
249
|
-
* @param blockBehavior - The block behavior, or null
|
|
250
|
-
* @returns A single-element tuple containing the preprocessor-specific block
|
|
225
|
+
* Invariant: exactly one block node must be produced; an empty or
|
|
226
|
+
* multi-node result indicates a parse error.
|
|
251
227
|
*/
|
|
252
228
|
visitPsBlock(token, childNodes = [], blockBehavior = null) {
|
|
253
229
|
const nodes = super.visitPsBlock(token, childNodes, blockBehavior);
|
|
@@ -284,6 +260,11 @@ export class SvelteParser extends Parser {
|
|
|
284
260
|
* Directive resolution (`bind:`, `class:`, `on:`, etc.) and IDL attribute
|
|
285
261
|
* mapping are now handled declaratively by svelte-spec's directivePatterns
|
|
286
262
|
* and ml-core's acceptedAttrNames.
|
|
263
|
+
* Because directivePatterns are applied later by ml-core's MLAttr
|
|
264
|
+
* constructor, the attribute returned here carries only parser-detectable
|
|
265
|
+
* flags; for example, `on:click` without a value shows
|
|
266
|
+
* `isDynamicValue: false` at the parser level but resolves to `true`
|
|
267
|
+
* at the core level.
|
|
287
268
|
*
|
|
288
269
|
* @param token - The token representing the attribute
|
|
289
270
|
* @returns The parsed attribute node with Svelte-specific metadata
|
|
@@ -329,15 +310,6 @@ export class SvelteParser extends Parser {
|
|
|
329
310
|
detectElementType(nodeName) {
|
|
330
311
|
return super.detectElementType(nodeName, /^[A-Z]|\./);
|
|
331
312
|
}
|
|
332
|
-
/**
|
|
333
|
-
* Parses a Svelte `{#await}` block into its constituent preprocessor-specific blocks:
|
|
334
|
-
* the await expression, optional `{:then}` branch, optional `{:catch}` branch,
|
|
335
|
-
* and the closing `{/await}` tag.
|
|
336
|
-
*
|
|
337
|
-
* @param token - The child token representing the entire await block
|
|
338
|
-
* @param originBlockNode - The Svelte AST AwaitBlock node
|
|
339
|
-
* @returns An array of preprocessor-specific block nodes
|
|
340
|
-
*/
|
|
341
313
|
#parseAwaitBlock(token,
|
|
342
314
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
343
315
|
originBlockNode) {
|
|
@@ -473,15 +445,6 @@ export class SvelteParser extends Parser {
|
|
|
473
445
|
})[0]);
|
|
474
446
|
return expressions;
|
|
475
447
|
}
|
|
476
|
-
/**
|
|
477
|
-
* Parses a Svelte `{#each}` block into its constituent preprocessor-specific blocks:
|
|
478
|
-
* the each expression, optional `{:else}` fallback branch,
|
|
479
|
-
* and the closing `{/each}` tag.
|
|
480
|
-
*
|
|
481
|
-
* @param token - The child token representing the entire each block
|
|
482
|
-
* @param originBlockNode - The Svelte AST EachBlock node
|
|
483
|
-
* @returns An array of preprocessor-specific block nodes
|
|
484
|
-
*/
|
|
485
448
|
#parseEachBlock(token,
|
|
486
449
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
487
450
|
originBlockNode) {
|
|
@@ -540,16 +503,6 @@ export class SvelteParser extends Parser {
|
|
|
540
503
|
}, undefined, { type: 'end', expression: closeToken.raw })[0]);
|
|
541
504
|
return expressions;
|
|
542
505
|
}
|
|
543
|
-
/**
|
|
544
|
-
* Recursively traverses a Svelte `{#if}` block and its chained `{:else if}` / `{:else}`
|
|
545
|
-
* branches, producing a flat list of token segments with their conditional type labels
|
|
546
|
-
* and child node arrays.
|
|
547
|
-
*
|
|
548
|
-
* @param originBlockNode - The Svelte AST IfBlock node to traverse
|
|
549
|
-
* @param start - The source offset where this block segment begins
|
|
550
|
-
* @param type - The conditional branch type: 'if', 'elseif', or 'else'
|
|
551
|
-
* @returns A flat array of token segments with children and type labels
|
|
552
|
-
*/
|
|
553
506
|
#traverseIfBlock(
|
|
554
507
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
555
508
|
originBlockNode, start, type = 'if') {
|
|
@@ -578,6 +531,9 @@ export class SvelteParser extends Parser {
|
|
|
578
531
|
const start = result.at(-1)?.children.at(-1)?.end ?? originBlockNode.end;
|
|
579
532
|
const end = originBlockNode.end;
|
|
580
533
|
const tag = this.sliceFragment(start, end);
|
|
534
|
+
// The raw content is empty in recursive `elseif` calls because the
|
|
535
|
+
// outermost call emits the single `{/if}` closer; pushing only
|
|
536
|
+
// non-empty tags avoids duplicating the closer.
|
|
581
537
|
if (tag.raw) {
|
|
582
538
|
result.push({ ...tag, children: [], type: '/if' });
|
|
583
539
|
}
|
|
@@ -1,23 +1,15 @@
|
|
|
1
1
|
import type { AST } from 'svelte/compiler';
|
|
2
|
-
/** Union of Svelte AST node types that can appear as children in a Svelte template fragment. */
|
|
3
2
|
export type SvelteNode = AST.Text | AST.Comment | AST.Tag | AST.ElementLike | AST.Block;
|
|
4
|
-
/** Represents a Svelte `{#if}` block with consequent, alternate, and elseif branches. */
|
|
5
3
|
export type SvelteIfBlock = AST.IfBlock;
|
|
6
|
-
/** Represents a Svelte `{#each}` block with iteration body and optional fallback. */
|
|
7
4
|
export type SvelteEachBlock = AST.EachBlock;
|
|
8
|
-
/** Represents a Svelte `{#await}` block with pending, then, and catch branches. */
|
|
9
5
|
export type SvelteAwaitBlock = AST.AwaitBlock;
|
|
10
6
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* @param template - The raw Svelte template source code
|
|
15
|
-
* @returns An array of top-level Svelte AST nodes from the template fragment
|
|
7
|
+
* The `modern: true` option opts into Svelte 5's modern AST format,
|
|
8
|
+
* which is required to receive Svelte 5 node types such as
|
|
9
|
+
* `SnippetBlock`, `RenderTag`, and `SvelteBoundary`.
|
|
16
10
|
*/
|
|
17
11
|
export declare function svelteParse(template: string): SvelteNode[];
|
|
18
|
-
/** Union of all Svelte directive and attribute types that can appear on elements. */
|
|
19
12
|
export type SvelteDirective = Directive | AST.Attribute | AST.SpreadAttribute;
|
|
20
|
-
/** Union of all Svelte block types that have opening/closing tag syntax. */
|
|
21
13
|
export type SvelteBlock = AST.EachBlock | AST.IfBlock | AST.AwaitBlock | AST.KeyBlock | AST.SnippetBlock | AST.SvelteBoundary;
|
|
22
14
|
type Directive = AST.AnimateDirective | AST.BindDirective | AST.ClassDirective | AST.LetDirective | AST.OnDirective | AST.StyleDirective | AST.TransitionDirective | AST.UseDirective;
|
|
23
15
|
export {};
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { parse } from 'svelte/compiler';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* @param template - The raw Svelte template source code
|
|
7
|
-
* @returns An array of top-level Svelte AST nodes from the template fragment
|
|
3
|
+
* The `modern: true` option opts into Svelte 5's modern AST format,
|
|
4
|
+
* which is required to receive Svelte 5 node types such as
|
|
5
|
+
* `SnippetBlock`, `RenderTag`, and `SvelteBoundary`.
|
|
8
6
|
*/
|
|
9
7
|
export function svelteParse(template) {
|
|
10
8
|
const ast = parse(template, { modern: true });
|
|
@@ -4,6 +4,11 @@ import { HtmlParser } from '@markuplint/html-parser';
|
|
|
4
4
|
* Extends the standard HTML parser to handle SvelteKit placeholder tags
|
|
5
5
|
* such as `%sveltekit.head%` and `%sveltekit.body%`, which are treated
|
|
6
6
|
* as opaque preprocessor-specific blocks.
|
|
7
|
+
*
|
|
8
|
+
* Unlike `SvelteParser`, the app template is plain HTML whose `%sveltekit.*%`
|
|
9
|
+
* placeholders are replaced by SvelteKit at build time, so the template engine
|
|
10
|
+
* parser pattern (extending `HtmlParser` with `ignoreTags`) is the correct
|
|
11
|
+
* architectural choice and `svelte/compiler` is intentionally not involved.
|
|
7
12
|
*/
|
|
8
13
|
declare class SvelteKitTemplateParser extends HtmlParser {
|
|
9
14
|
constructor();
|
package/lib/sveltekit-parser.js
CHANGED
|
@@ -4,6 +4,11 @@ import { HtmlParser } from '@markuplint/html-parser';
|
|
|
4
4
|
* Extends the standard HTML parser to handle SvelteKit placeholder tags
|
|
5
5
|
* such as `%sveltekit.head%` and `%sveltekit.body%`, which are treated
|
|
6
6
|
* as opaque preprocessor-specific blocks.
|
|
7
|
+
*
|
|
8
|
+
* Unlike `SvelteParser`, the app template is plain HTML whose `%sveltekit.*%`
|
|
9
|
+
* placeholders are replaced by SvelteKit at build time, so the template engine
|
|
10
|
+
* parser pattern (extending `HtmlParser` with `ignoreTags`) is the correct
|
|
11
|
+
* architectural choice and `svelte/compiler` is intentionally not involved.
|
|
7
12
|
*/
|
|
8
13
|
class SvelteKitTemplateParser extends HtmlParser {
|
|
9
14
|
constructor() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markuplint/svelte-parser",
|
|
3
|
-
"version": "5.0.0-rc.
|
|
3
|
+
"version": "5.0.0-rc.5",
|
|
4
4
|
"description": "Svelte parser for markuplint",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"author": "Yusuke Hirao <yusukehirao@me.com>",
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"engines": {
|
|
13
|
-
"node": ">=
|
|
13
|
+
"node": ">=24"
|
|
14
14
|
},
|
|
15
15
|
"type": "module",
|
|
16
16
|
"exports": {
|
|
@@ -40,10 +40,10 @@
|
|
|
40
40
|
"clean": "tsc --build --clean tsconfig.build.json"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@markuplint/html-parser": "5.0.0-rc.
|
|
44
|
-
"@markuplint/ml-ast": "5.0.0-rc.
|
|
45
|
-
"@markuplint/parser-utils": "5.0.0-rc.
|
|
46
|
-
"svelte": "5.55.
|
|
43
|
+
"@markuplint/html-parser": "5.0.0-rc.5",
|
|
44
|
+
"@markuplint/ml-ast": "5.0.0-rc.5",
|
|
45
|
+
"@markuplint/parser-utils": "5.0.0-rc.5",
|
|
46
|
+
"svelte": "5.55.7"
|
|
47
47
|
},
|
|
48
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "8d87463af2ff3f1b83fb28da20f1819362cf3555"
|
|
49
49
|
}
|