Skip to content

Commit 7ebf326

Browse files
authored
feat: <template lang="..."> to parse as raw text (#244)
* ignore template tag * Create real-dolphins-nail.md
1 parent 4df6505 commit 7ebf326

File tree

14 files changed

+2223
-66
lines changed

14 files changed

+2223
-66
lines changed

.changeset/real-dolphins-nail.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte-eslint-parser": minor
3+
---
4+
5+
feat: `<template lang="...">` to parse as raw text

docs/AST.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ See [ESTree] for the AST node of the script generated by `espree`.
1515
[variabledeclarator]: https://github.com/estree/estree/blob/master/es5.md#variabledeclarator
1616
[pattern]: https://github.com/estree/estree/blob/master/es5.md#patterns
1717

18-
See details: [../src/ast.ts](../src/ast.ts)
18+
See details: [../src/ast/*](../src/ast/)
1919

2020
## Common
2121

src/ast/base.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import type { Locations } from "./common";
2+
3+
// internals
4+
export interface BaseNode extends Locations {
5+
type: string;
6+
}

src/ast/common.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import type { BaseNode } from "./base";
2+
3+
export interface Position {
4+
/** >= 1 */
5+
line: number;
6+
/** >= 0 */
7+
column: number;
8+
}
9+
export type Range = [number, number];
10+
export interface SourceLocation {
11+
start: Position;
12+
end: Position;
13+
}
14+
export interface Locations {
15+
loc: SourceLocation;
16+
range: Range;
17+
}
18+
19+
export interface Token extends BaseNode {
20+
type:
21+
| "Boolean"
22+
| "Null"
23+
| "Identifier"
24+
| "Keyword"
25+
| "Punctuator"
26+
| "JSXIdentifier"
27+
| "JSXText"
28+
| "Numeric"
29+
| "String"
30+
| "RegularExpression"
31+
| "Template"
32+
// HTML
33+
| "HTMLText"
34+
| "HTMLIdentifier"
35+
| "MustacheKeyword"
36+
| "HTMLComment";
37+
value: string;
38+
}
39+
40+
export interface Comment extends BaseNode {
41+
type: "Line" | "Block";
42+
value: string;
43+
}

src/ast.ts renamed to src/ast/html.ts

Lines changed: 5 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,8 @@
11
import type ESTree from "estree";
2-
export type Range = [number, number];
2+
import type { BaseNode } from "./base";
3+
import type { Token, Comment } from "./common";
34

4-
export interface SourceLocation {
5-
start: Position;
6-
end: Position;
7-
}
8-
export interface Locations {
9-
loc: SourceLocation;
10-
range: Range;
11-
}
12-
13-
interface BaseNode extends Locations {
14-
type: string;
15-
}
16-
17-
export interface Token extends BaseNode {
18-
type:
19-
| "Boolean"
20-
| "Null"
21-
| "Identifier"
22-
| "Keyword"
23-
| "Punctuator"
24-
| "JSXIdentifier"
25-
| "JSXText"
26-
| "Numeric"
27-
| "String"
28-
| "RegularExpression"
29-
| "Template"
30-
// HTML
31-
| "HTMLText"
32-
| "HTMLIdentifier"
33-
| "MustacheKeyword"
34-
| "HTMLComment";
35-
value: string;
36-
}
37-
38-
export interface Comment extends BaseNode {
39-
type: "Line" | "Block";
40-
value: string;
41-
}
42-
43-
export interface Position {
44-
/** >= 1 */
45-
line: number;
46-
/** >= 0 */
47-
column: number;
48-
}
49-
50-
export type SvelteNode =
5+
export type SvelteHTMLNode =
516
| SvelteProgram
527
| SvelteScriptElement
538
| SvelteStyleElement
@@ -77,8 +32,7 @@ export type SvelteNode =
7732
| SvelteSpecialDirective
7833
| SvelteDirectiveKey
7934
| SvelteSpecialDirectiveKey
80-
| SvelteHTMLComment
81-
| SvelteReactiveStatement;
35+
| SvelteHTMLComment;
8236

8337
/** Node of Svelte program root */
8438
export interface SvelteProgram extends BaseNode {
@@ -95,6 +49,7 @@ export type SvelteElement =
9549
| SvelteHTMLElement
9650
| SvelteComponentElement
9751
| SvelteSpecialElement;
52+
9853
type BaseSvelteElement = BaseNode;
9954

10055
/** Node of `<script>` element. */
@@ -616,11 +571,3 @@ export interface SvelteSpecialDirective extends BaseNode {
616571
expression: ESTree.Expression;
617572
parent: SvelteStartTag /* & { parent: SvelteSpecialElement } */;
618573
}
619-
620-
/** Node of `$` statement. */
621-
export interface SvelteReactiveStatement extends BaseNode {
622-
type: "SvelteReactiveStatement";
623-
label: ESTree.Identifier & { name: "$" };
624-
body: ESTree.Statement;
625-
parent: ESTree.Node;
626-
}

src/ast/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import type { SvelteHTMLNode } from "./html";
2+
import type { SvelteScriptNode } from "./script";
3+
4+
export * from "./common";
5+
export * from "./html";
6+
export * from "./script";
7+
8+
export type SvelteNode = SvelteHTMLNode | SvelteScriptNode;

src/ast/script.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type ESTree from "estree";
2+
import type { BaseNode } from "./base";
3+
4+
export type SvelteScriptNode = SvelteReactiveStatement;
5+
6+
/** Node of `$` statement. */
7+
export interface SvelteReactiveStatement extends BaseNode {
8+
type: "SvelteReactiveStatement";
9+
label: ESTree.Identifier & { name: "$" };
10+
body: ESTree.Statement;
11+
parent: ESTree.Node;
12+
}

src/context/index.ts

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import type {
44
Comment,
55
Locations,
66
Position,
7+
SvelteElement,
8+
SvelteName,
79
SvelteScriptElement,
810
SvelteStyleElement,
911
Token,
@@ -145,6 +147,12 @@ export class Context {
145147

146148
let start = 0;
147149
for (const block of extractBlocks(code)) {
150+
if (block.tag === "template") {
151+
const lang = block.attrs.find((attr) => attr.key.name === "lang");
152+
if (!lang || !lang.value || lang.value.value === "html") {
153+
continue;
154+
}
155+
}
148156
this.blocks.push(block);
149157
templateCode +=
150158
code.slice(start, block.contentRange[0]) +
@@ -183,6 +191,10 @@ export class Context {
183191
};
184192
}
185193

194+
public getIndexFromLoc(loc: { line: number; column: number }): number {
195+
return this.locs.getIndexFromLoc(loc);
196+
}
197+
186198
/**
187199
* Get the location information of the given node.
188200
* @param node The node.
@@ -278,9 +290,14 @@ export class Context {
278290
}
279291

280292
public findBlock(
281-
element: SvelteScriptElement | SvelteStyleElement
293+
element: SvelteScriptElement | SvelteStyleElement | SvelteElement
282294
): Block | undefined {
283-
const tag = element.type === "SvelteScriptElement" ? "script" : "style";
295+
const tag =
296+
element.type === "SvelteScriptElement"
297+
? "script"
298+
: element.type === "SvelteStyleElement"
299+
? "style"
300+
: (element.name as SvelteName).name.toLowerCase();
284301
return this.blocks.find(
285302
(block) =>
286303
block.tag === tag &&
@@ -291,16 +308,17 @@ export class Context {
291308
}
292309

293310
type Block = {
294-
tag: "script" | "style";
311+
tag: "script" | "style" | "template";
295312
attrs: AttributeToken[];
296313
contentRange: [number, number];
297314
};
298315

299316
/** Extract <script> blocks */
300317
function* extractBlocks(code: string): IterableIterator<Block> {
301-
const startTagOpenRe = /<!--[\s\S]*?-->|<(script|style)([\s>])/giu;
318+
const startTagOpenRe = /<!--[\s\S]*?-->|<(script|style|template)([\s>])/giu;
302319
const endScriptTagRe = /<\/script>/giu;
303320
const endStyleTagRe = /<\/style>/giu;
321+
const endTemplateTagRe = /<\/template>/giu;
304322
let startTagOpenMatch;
305323
while ((startTagOpenMatch = startTagOpenRe.exec(code))) {
306324
const [, tag, nextChar] = startTagOpenMatch;
@@ -323,8 +341,13 @@ function* extractBlocks(code: string): IterableIterator<Block> {
323341
continue;
324342
}
325343
}
344+
const lowerTag = tag.toLowerCase() as "script" | "style" | "template";
326345
const endTagRe =
327-
tag.toLowerCase() === "script" ? endScriptTagRe : endStyleTagRe;
346+
lowerTag === "script"
347+
? endScriptTagRe
348+
: lowerTag === "style"
349+
? endStyleTagRe
350+
: endTemplateTagRe;
328351
endTagRe.lastIndex = startTagEnd;
329352
const endTagMatch = endTagRe.exec(code);
330353
if (endTagMatch) {
@@ -333,7 +356,7 @@ function* extractBlocks(code: string): IterableIterator<Block> {
333356
yield {
334357
contentRange,
335358
attrs,
336-
tag: tag as "script" | "style",
359+
tag: lowerTag,
337360
};
338361
startTagOpenRe.lastIndex = endTagRe.lastIndex;
339362
}

src/parser/converts/element.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,11 @@ function convertHTMLElement(
263263
},
264264
});
265265

266-
if (element.name.name === "script" || element.name.name === "style") {
266+
if (
267+
element.name.name === "script" ||
268+
element.name.name === "style" ||
269+
(element.name.name === "template" && ctx.findBlock(element))
270+
) {
267271
for (const child of element.children) {
268272
if (child.type === "SvelteText") {
269273
child.value = ctx.code.slice(...child.range);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<script>
2+
let objs = [{a: 1, b: 2}, {a: 2, b: 3}]
3+
</script>
4+
5+
<template lang="pug">
6+
+each("objs as obj")
7+
p("{...obj}") {obj.a}
8+
</template>

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy