eslint-plugin-templ 0.0.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.
- package/LICENSE +7 -0
- package/README.md +53 -0
- package/dist/html-source-code.d.ts +116 -0
- package/dist/html-source-code.d.ts.map +1 -0
- package/dist/html-source-code.js +270 -0
- package/dist/html-source-code.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/parse-for-eslint.d.ts +4 -0
- package/dist/parse-for-eslint.d.ts.map +1 -0
- package/dist/parse-for-eslint.js +70 -0
- package/dist/parse-for-eslint.js.map +1 -0
- package/dist/run-templ-ast-to-json-binary.d.ts +2 -0
- package/dist/run-templ-ast-to-json-binary.d.ts.map +1 -0
- package/dist/run-templ-ast-to-json-binary.js +33 -0
- package/dist/run-templ-ast-to-json-binary.js.map +1 -0
- package/dist/templ-ast-to-eslint-ast.d.ts +7 -0
- package/dist/templ-ast-to-eslint-ast.d.ts.map +1 -0
- package/dist/templ-ast-to-eslint-ast.js +218 -0
- package/dist/templ-ast-to-eslint-ast.js.map +1 -0
- package/dist/templ-ast.d.ts +804 -0
- package/dist/templ-ast.d.ts.map +1 -0
- package/dist/templ-ast.js +207 -0
- package/dist/templ-ast.js.map +1 -0
- package/dist/templ-language.d.ts +24 -0
- package/dist/templ-language.d.ts.map +1 -0
- package/dist/templ-language.js +33 -0
- package/dist/templ-language.js.map +1 -0
- package/package.json +82 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright (c) 2025 Adam Vigneaux
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# eslint-plugin-templ
|
|
2
|
+
|
|
3
|
+
ESLint plugin for [Templ](https://templ.guide/) files.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
_Prerequisites:_ Node 20.6.0+ and ESLint 9.0.0+.
|
|
8
|
+
|
|
9
|
+
To get started, first install this plugin (for parsing Templ files) and the HTML ESLint plugin (for the HTML rules):
|
|
10
|
+
|
|
11
|
+
```shell
|
|
12
|
+
npm install --save-dev eslint-plugin-templ @html-eslint/eslint-plugin
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Then, in `eslint.config.js`, add an entry for `.templ` files:
|
|
16
|
+
|
|
17
|
+
```js
|
|
18
|
+
import { defineConfig } from "eslint/config";
|
|
19
|
+
import html from "@html-eslint/eslint-plugin";
|
|
20
|
+
import templ from "eslint-plugin-templ";
|
|
21
|
+
|
|
22
|
+
export default defineConfig([
|
|
23
|
+
{
|
|
24
|
+
files: ["**/*.templ"],
|
|
25
|
+
plugins: {
|
|
26
|
+
html,
|
|
27
|
+
templ,
|
|
28
|
+
},
|
|
29
|
+
extends: ["html/recommended"],
|
|
30
|
+
language: "templ/templ",
|
|
31
|
+
},
|
|
32
|
+
]);
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The above configuration enables HTML ESLint's recommended rules ([documentation](https://html-eslint.org/docs/rules)).
|
|
36
|
+
|
|
37
|
+
In VS Code settings, assuming you have [the ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) installed, you have to tell ESLint to run on `.templ` files:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
"eslint.validate": [
|
|
41
|
+
"templ"
|
|
42
|
+
]
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## About
|
|
46
|
+
|
|
47
|
+
Templ files can contain a mixture of Go, CSS, HTML, and JavaScript. To enable linting the HTML in `.templ` files with [HTML ESLint](https://html-eslint.org/), this plugin provides [an ESLint Language](https://eslint.org/docs/latest/extend/languages) that uses [the official Templ parser](https://pkg.go.dev/github.com/a-h/templ), converting the Templ AST into the AST expected by HTML ESLint.
|
|
48
|
+
|
|
49
|
+
Any non-HTML content, including inline Templ and Go expressions, are discarded so that ESLint rules only ever see HTML.
|
|
50
|
+
|
|
51
|
+
This plugin does not provide any rules.
|
|
52
|
+
|
|
53
|
+
If you encounter any parsing errors or broken rules, please [create an issue](https://github.com/AdamVig/eslint-plugin-templ/issues/new)!
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copied from https://github.com/yeonjuan/html-eslint/tree/main/packages/eslint-plugin/lib/languages and converted to TypeScript.
|
|
3
|
+
* @license
|
|
4
|
+
* MIT License
|
|
5
|
+
* Copyright (c) 2020 YeonJuan
|
|
6
|
+
*
|
|
7
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
* in the Software without restriction, including without limitation the rights
|
|
10
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
* furnished to do so, subject to the following conditions:
|
|
13
|
+
*
|
|
14
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
* copies or substantial portions of the Software.
|
|
16
|
+
*
|
|
17
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
* SOFTWARE.
|
|
24
|
+
*/
|
|
25
|
+
import type { Position, TraversalStep } from "@eslint/core";
|
|
26
|
+
import type { SourceLocation } from "@eslint/plugin-kit";
|
|
27
|
+
import type { AnyHTMLNode, CommentContent } from "@html-eslint/types";
|
|
28
|
+
import type { AST } from "eslint";
|
|
29
|
+
import { Directive, TextSourceCodeBase } from "@eslint/plugin-kit";
|
|
30
|
+
/**
|
|
31
|
+
* This is not a node generated by es-html-parser; it is created by utils's splitToLineNodes.
|
|
32
|
+
*/
|
|
33
|
+
export interface Line extends BaseNode {
|
|
34
|
+
type: "Line";
|
|
35
|
+
value: string;
|
|
36
|
+
hasTemplate: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface BaseNode {
|
|
39
|
+
parent?: BaseNode | null;
|
|
40
|
+
type: string;
|
|
41
|
+
range: AST.Range;
|
|
42
|
+
loc: AST.SourceLocation;
|
|
43
|
+
}
|
|
44
|
+
export declare const visitorKeys: {
|
|
45
|
+
Program: string[];
|
|
46
|
+
Document: string[];
|
|
47
|
+
Attribute: string[];
|
|
48
|
+
AttributeKey: never[];
|
|
49
|
+
AttributeValue: never[];
|
|
50
|
+
AttributeValueWrapperEnd: never[];
|
|
51
|
+
AttributeValueWrapperStart: never[];
|
|
52
|
+
CloseScriptTag: never[];
|
|
53
|
+
CloseStyleTag: never[];
|
|
54
|
+
CloseTag: never[];
|
|
55
|
+
Comment: string[];
|
|
56
|
+
CommentContent: never[];
|
|
57
|
+
CommentOpen: never[];
|
|
58
|
+
CommentClose: never[];
|
|
59
|
+
Doctype: string[];
|
|
60
|
+
DoctypeAttribute: string[];
|
|
61
|
+
DoctypeAttributeValue: never[];
|
|
62
|
+
DoctypeAttributeWrapperEnd: never[];
|
|
63
|
+
DoctypeAttributeWrapperStart: never[];
|
|
64
|
+
DoctypeOpen: never[];
|
|
65
|
+
DoctypeClose: never[];
|
|
66
|
+
OpenScriptTagEnd: never[];
|
|
67
|
+
OpenScriptTagStart: never[];
|
|
68
|
+
OpenStyleTagEnd: never[];
|
|
69
|
+
OpenStyleTagStart: never[];
|
|
70
|
+
OpenTagEnd: never[];
|
|
71
|
+
OpenTagStart: never[];
|
|
72
|
+
ScriptTag: string[];
|
|
73
|
+
ScriptTagContent: never[];
|
|
74
|
+
StyleTag: string[];
|
|
75
|
+
StyleTagContent: never[];
|
|
76
|
+
Tag: string[];
|
|
77
|
+
Text: never[];
|
|
78
|
+
RawContent: never[];
|
|
79
|
+
};
|
|
80
|
+
export declare class HTMLSourceCode extends TextSourceCodeBase {
|
|
81
|
+
comments: CommentContent[];
|
|
82
|
+
parentsMap: Map<AnyHTMLNode | AST.Program, AnyHTMLNode | AST.Program>;
|
|
83
|
+
lineStartIndices: number[];
|
|
84
|
+
constructor({ ast, text, comments, }: {
|
|
85
|
+
ast: AST.Program;
|
|
86
|
+
text: string;
|
|
87
|
+
comments: CommentContent[];
|
|
88
|
+
});
|
|
89
|
+
getRange(node: BaseNode): [number, number];
|
|
90
|
+
getLoc(node: BaseNode): import("@eslint/plugin-kit").SourceLocation;
|
|
91
|
+
getLines(): string[];
|
|
92
|
+
/**
|
|
93
|
+
* @see https://github.com/eslint/eslint/blob/f60f2764971a33e252be13e560dccf21f554dbf1/lib/languages/js/source-code/source-code.js#L745
|
|
94
|
+
* @param {Position} loc
|
|
95
|
+
* @returns {number}
|
|
96
|
+
*/
|
|
97
|
+
getIndexFromLoc(loc: Position): number;
|
|
98
|
+
/**
|
|
99
|
+
* @see https://github.com/eslint/eslint/blob/f60f2764971a33e252be13e560dccf21f554dbf1/lib/languages/js/source-code/source-code.js#L694
|
|
100
|
+
* @param {number} index
|
|
101
|
+
* @returns {Position}
|
|
102
|
+
*/
|
|
103
|
+
getLocFromIndex(index: number): Position;
|
|
104
|
+
getInlineConfigNodes(): CommentContent[];
|
|
105
|
+
getDisableDirectives(): {
|
|
106
|
+
problems: {
|
|
107
|
+
ruleId: null | string;
|
|
108
|
+
message: string;
|
|
109
|
+
loc: SourceLocation;
|
|
110
|
+
}[];
|
|
111
|
+
directives: Directive[];
|
|
112
|
+
};
|
|
113
|
+
traverse(): TraversalStep[];
|
|
114
|
+
getParent(node: AnyHTMLNode): AnyHTMLNode | AST.Program | undefined;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=html-source-code.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html-source-code.d.ts","sourceRoot":"","sources":["../src/html-source-code.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,KAAK,EAAiB,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAElC,OAAO,EAEL,SAAS,EACT,kBAAkB,EAEnB,MAAM,oBAAoB,CAAC;AAG5B;;GAEG;AACH,MAAM,WAAW,IAAK,SAAQ,QAAQ;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC;IACjB,GAAG,EAAE,GAAG,CAAC,cAAc,CAAC;CACzB;AAID,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+CvB,CAAC;AAiCF,qBAAa,cAAe,SAAQ,kBAAkB;IACpD,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,UAAU,EAAE,GAAG,CAAC,WAAW,GAAG,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC;IACtE,gBAAgB,EAAE,MAAM,EAAE,CAAC;gBAEf,EACV,GAAG,EACH,IAAI,EACJ,QAAQ,GACT,EAAE;QACD,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,cAAc,EAAE,CAAC;KAC5B;IAsBQ,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAI1C,MAAM,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,oBAAoB,EAAE,cAAc;IAI5E,QAAQ;IAKR;;;;OAIG;IACM,eAAe,CAAC,GAAG,EAAE,QAAQ,GAAG,MAAM;IA4C/C;;;;OAIG;IACM,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ;IA+BjD,oBAAoB;IAIpB,oBAAoB;;oBAKR,IAAI,GAAG,MAAM;qBACZ,MAAM;iBACV,cAAc;;;;IA+Cd,QAAQ;IA+CR,SAAS,CAAC,IAAI,EAAE,WAAW;CAGrC"}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copied from https://github.com/yeonjuan/html-eslint/tree/main/packages/eslint-plugin/lib/languages and converted to TypeScript.
|
|
3
|
+
* @license
|
|
4
|
+
* MIT License
|
|
5
|
+
* Copyright (c) 2020 YeonJuan
|
|
6
|
+
*
|
|
7
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
* in the Software without restriction, including without limitation the rights
|
|
10
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
* furnished to do so, subject to the following conditions:
|
|
13
|
+
*
|
|
14
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
* copies or substantial portions of the Software.
|
|
16
|
+
*
|
|
17
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
* SOFTWARE.
|
|
24
|
+
*/
|
|
25
|
+
import { ConfigCommentParser, Directive, TextSourceCodeBase, VisitNodeStep, } from "@eslint/plugin-kit";
|
|
26
|
+
import { NodeTypes } from "es-html-parser";
|
|
27
|
+
const NODE_TYPES = NodeTypes;
|
|
28
|
+
export const visitorKeys = {
|
|
29
|
+
Program: ["body"],
|
|
30
|
+
[NODE_TYPES.Document]: ["children"],
|
|
31
|
+
[NODE_TYPES.Attribute]: ["key", "startWrapper", "endWrapper", "value"],
|
|
32
|
+
[NODE_TYPES.AttributeKey]: [],
|
|
33
|
+
[NODE_TYPES.AttributeValue]: [],
|
|
34
|
+
[NODE_TYPES.AttributeValueWrapperEnd]: [],
|
|
35
|
+
[NODE_TYPES.AttributeValueWrapperStart]: [],
|
|
36
|
+
[NODE_TYPES.CloseScriptTag]: [],
|
|
37
|
+
[NODE_TYPES.CloseStyleTag]: [],
|
|
38
|
+
[NODE_TYPES.CloseTag]: [],
|
|
39
|
+
[NODE_TYPES.Comment]: ["open", "close", "value"],
|
|
40
|
+
[NODE_TYPES.CommentContent]: [],
|
|
41
|
+
[NODE_TYPES.CommentOpen]: [],
|
|
42
|
+
[NODE_TYPES.CommentClose]: [],
|
|
43
|
+
[NODE_TYPES.Doctype]: ["open", "close", "attributes"],
|
|
44
|
+
[NODE_TYPES.DoctypeAttribute]: ["startWrapper", "value", "endWrapper"],
|
|
45
|
+
[NODE_TYPES.DoctypeAttributeValue]: [],
|
|
46
|
+
[NODE_TYPES.DoctypeAttributeWrapperEnd]: [],
|
|
47
|
+
[NODE_TYPES.DoctypeAttributeWrapperStart]: [],
|
|
48
|
+
[NODE_TYPES.DoctypeOpen]: [],
|
|
49
|
+
[NODE_TYPES.DoctypeClose]: [],
|
|
50
|
+
[NODE_TYPES.OpenScriptTagEnd]: [],
|
|
51
|
+
[NODE_TYPES.OpenScriptTagStart]: [],
|
|
52
|
+
[NODE_TYPES.OpenStyleTagEnd]: [],
|
|
53
|
+
[NODE_TYPES.OpenStyleTagStart]: [],
|
|
54
|
+
[NODE_TYPES.OpenTagEnd]: [],
|
|
55
|
+
[NODE_TYPES.OpenTagStart]: [],
|
|
56
|
+
[NODE_TYPES.ScriptTag]: [
|
|
57
|
+
"attributes",
|
|
58
|
+
"openStart",
|
|
59
|
+
"openEnd",
|
|
60
|
+
"close",
|
|
61
|
+
"value",
|
|
62
|
+
],
|
|
63
|
+
[NODE_TYPES.ScriptTagContent]: [],
|
|
64
|
+
[NODE_TYPES.StyleTag]: [
|
|
65
|
+
"attributes",
|
|
66
|
+
"openStart",
|
|
67
|
+
"openEnd",
|
|
68
|
+
"close",
|
|
69
|
+
"value",
|
|
70
|
+
],
|
|
71
|
+
[NODE_TYPES.StyleTagContent]: [],
|
|
72
|
+
[NODE_TYPES.Tag]: ["openStart", "openEnd", "close", "children", "attributes"],
|
|
73
|
+
[NODE_TYPES.Text]: [],
|
|
74
|
+
[NODE_TYPES.RawContent]: [],
|
|
75
|
+
};
|
|
76
|
+
const STEP_PHASE = {
|
|
77
|
+
ENTER: 1,
|
|
78
|
+
EXIT: 2,
|
|
79
|
+
};
|
|
80
|
+
class HTMLTraversalStep extends VisitNodeStep {
|
|
81
|
+
constructor({ target, phase, args, }) {
|
|
82
|
+
super({ target, phase, args });
|
|
83
|
+
this.target = target;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const lineBreakPattern = /\r\n|[\r\n\u2028\u2029]/u;
|
|
87
|
+
function createGlobalLinebreakMatcher() {
|
|
88
|
+
return new RegExp(lineBreakPattern.source, "gu");
|
|
89
|
+
}
|
|
90
|
+
const INLINE_CONFIG = /^\s*(?:eslint(?:-enable|-disable(?:(?:-next)?-line)?)?)(?:\s|$)/u;
|
|
91
|
+
const commentParser = new ConfigCommentParser();
|
|
92
|
+
export class HTMLSourceCode extends TextSourceCodeBase {
|
|
93
|
+
comments;
|
|
94
|
+
parentsMap;
|
|
95
|
+
lineStartIndices;
|
|
96
|
+
constructor({ ast, text, comments, }) {
|
|
97
|
+
super({ ast, text });
|
|
98
|
+
/**
|
|
99
|
+
* @property
|
|
100
|
+
*/
|
|
101
|
+
this.ast = ast;
|
|
102
|
+
/**
|
|
103
|
+
* @property
|
|
104
|
+
*/
|
|
105
|
+
this.comments = comments;
|
|
106
|
+
this.parentsMap = new Map();
|
|
107
|
+
this.lineStartIndices = [0];
|
|
108
|
+
const lineEndingPattern = createGlobalLinebreakMatcher();
|
|
109
|
+
let match;
|
|
110
|
+
while ((match = lineEndingPattern.exec(this.text))) {
|
|
111
|
+
this.lineStartIndices.push(match.index + match[0].length);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
getRange(node) {
|
|
115
|
+
return node.range;
|
|
116
|
+
}
|
|
117
|
+
getLoc(node) {
|
|
118
|
+
return node.loc;
|
|
119
|
+
}
|
|
120
|
+
getLines() {
|
|
121
|
+
return this.lines;
|
|
122
|
+
}
|
|
123
|
+
// Copied from eslint source code
|
|
124
|
+
/**
|
|
125
|
+
* @see https://github.com/eslint/eslint/blob/f60f2764971a33e252be13e560dccf21f554dbf1/lib/languages/js/source-code/source-code.js#L745
|
|
126
|
+
* @param {Position} loc
|
|
127
|
+
* @returns {number}
|
|
128
|
+
*/
|
|
129
|
+
getIndexFromLoc(loc) {
|
|
130
|
+
if (typeof loc !== "object" ||
|
|
131
|
+
typeof loc.line !== "number" ||
|
|
132
|
+
typeof loc.column !== "number") {
|
|
133
|
+
throw new TypeError("Expected `loc` to be an object with numeric `line` and `column` properties.");
|
|
134
|
+
}
|
|
135
|
+
if (loc.line <= 0) {
|
|
136
|
+
throw new RangeError(`Line number out of range (line ${loc.line} requested). Line numbers should be 1-based.`);
|
|
137
|
+
}
|
|
138
|
+
if (loc.line > this.lineStartIndices.length) {
|
|
139
|
+
throw new RangeError(`Line number out of range (line ${loc.line} requested, but only ${this.lineStartIndices.length} lines present).`);
|
|
140
|
+
}
|
|
141
|
+
const lineStartIndex = this.lineStartIndices[loc.line - 1];
|
|
142
|
+
const lineEndIndex = (loc.line === this.lineStartIndices.length
|
|
143
|
+
? this.text.length
|
|
144
|
+
: this.lineStartIndices[loc.line]);
|
|
145
|
+
const positionIndex = lineStartIndex + loc.column;
|
|
146
|
+
if ((loc.line === this.lineStartIndices.length &&
|
|
147
|
+
positionIndex > lineEndIndex) ||
|
|
148
|
+
(loc.line < this.lineStartIndices.length && positionIndex >= lineEndIndex)) {
|
|
149
|
+
throw new RangeError(`Column number out of range (column ${loc.column} requested, but the length of line ${loc.line} is ${lineEndIndex - lineStartIndex}).`);
|
|
150
|
+
}
|
|
151
|
+
return positionIndex;
|
|
152
|
+
}
|
|
153
|
+
// Copied from eslint source code
|
|
154
|
+
/**
|
|
155
|
+
* @see https://github.com/eslint/eslint/blob/f60f2764971a33e252be13e560dccf21f554dbf1/lib/languages/js/source-code/source-code.js#L694
|
|
156
|
+
* @param {number} index
|
|
157
|
+
* @returns {Position}
|
|
158
|
+
*/
|
|
159
|
+
getLocFromIndex(index) {
|
|
160
|
+
if (typeof index !== "number") {
|
|
161
|
+
throw new TypeError("Expected `index` to be a number.");
|
|
162
|
+
}
|
|
163
|
+
if (index < 0 || index > this.text.length) {
|
|
164
|
+
throw new RangeError(`Index out of range (requested index ${index}, but source text has length ${this.text.length}).`);
|
|
165
|
+
}
|
|
166
|
+
if (index === this.text.length) {
|
|
167
|
+
return {
|
|
168
|
+
line: this.lines.length,
|
|
169
|
+
// @ts-expect-error (copied from html-eslint)
|
|
170
|
+
column: this.lines.at(-1).length,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
const lineNumber =
|
|
174
|
+
// @ts-expect-error (copied from html-eslint)
|
|
175
|
+
index >= this.lineStartIndices.at(-1)
|
|
176
|
+
? this.lineStartIndices.length
|
|
177
|
+
: this.lineStartIndices.findIndex((el) => index < el);
|
|
178
|
+
return {
|
|
179
|
+
line: lineNumber,
|
|
180
|
+
// @ts-expect-error (copied from html-eslint)
|
|
181
|
+
column: index - this.lineStartIndices[lineNumber - 1],
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
getInlineConfigNodes() {
|
|
185
|
+
return this.comments.filter((comment) => INLINE_CONFIG.test(comment.value));
|
|
186
|
+
}
|
|
187
|
+
getDisableDirectives() {
|
|
188
|
+
/**
|
|
189
|
+
* @type {{ruleId: null | string, message: string; loc: SourceLocation}[]}
|
|
190
|
+
*/
|
|
191
|
+
const problems = [];
|
|
192
|
+
/**
|
|
193
|
+
* @type {Directive[]}
|
|
194
|
+
*/
|
|
195
|
+
const directives = [];
|
|
196
|
+
this.getInlineConfigNodes().forEach((comment) => {
|
|
197
|
+
const parsed = commentParser.parseDirective(comment.value);
|
|
198
|
+
if (!parsed)
|
|
199
|
+
return;
|
|
200
|
+
const { label, value, justification } = parsed;
|
|
201
|
+
// `eslint-disable-line` directives are not allowed to span multiple lines as it would be confusing to which lines they apply
|
|
202
|
+
if (label === "eslint-disable-line" &&
|
|
203
|
+
comment.loc.start.line !== comment.loc.end.line) {
|
|
204
|
+
const message = `${label} comment should not span multiple lines.`;
|
|
205
|
+
problems.push({
|
|
206
|
+
ruleId: null,
|
|
207
|
+
message,
|
|
208
|
+
loc: comment.loc,
|
|
209
|
+
});
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
switch (label) {
|
|
213
|
+
case "eslint-disable":
|
|
214
|
+
case "eslint-enable":
|
|
215
|
+
case "eslint-disable-next-line":
|
|
216
|
+
case "eslint-disable-line": {
|
|
217
|
+
const directiveType = label.slice("eslint-".length);
|
|
218
|
+
directives.push(new Directive({
|
|
219
|
+
type: directiveType,
|
|
220
|
+
node: comment,
|
|
221
|
+
value,
|
|
222
|
+
justification,
|
|
223
|
+
}));
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
return { problems, directives };
|
|
228
|
+
}
|
|
229
|
+
traverse() {
|
|
230
|
+
const steps = [];
|
|
231
|
+
const visit = (node, parent) => {
|
|
232
|
+
// @ts-expect-error (copied from html-eslint)
|
|
233
|
+
this.parentsMap.set(node, parent);
|
|
234
|
+
// @ts-expect-error (copied from html-eslint)
|
|
235
|
+
node.parent = parent;
|
|
236
|
+
steps.push(new HTMLTraversalStep({
|
|
237
|
+
target: node,
|
|
238
|
+
phase: STEP_PHASE.ENTER,
|
|
239
|
+
args: [node, parent],
|
|
240
|
+
}));
|
|
241
|
+
// @ts-expect-error (copied from html-eslint)
|
|
242
|
+
for (const key of visitorKeys[node.type] || []) {
|
|
243
|
+
// @ts-expect-error (copied from html-eslint)
|
|
244
|
+
const child = node[key];
|
|
245
|
+
if (child) {
|
|
246
|
+
if (Array.isArray(child)) {
|
|
247
|
+
child.forEach((grandchild) => {
|
|
248
|
+
visit(grandchild, node);
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
visit(child, node);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
steps.push(new HTMLTraversalStep({
|
|
257
|
+
target: node,
|
|
258
|
+
phase: STEP_PHASE.EXIT,
|
|
259
|
+
args: [node, parent],
|
|
260
|
+
}));
|
|
261
|
+
};
|
|
262
|
+
// @ts-expect-error (copied from html-eslint)
|
|
263
|
+
visit(this.ast, null);
|
|
264
|
+
return steps;
|
|
265
|
+
}
|
|
266
|
+
getParent(node) {
|
|
267
|
+
return this.parentsMap.get(node);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=html-source-code.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html-source-code.js","sourceRoot":"","sources":["../src/html-source-code.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { TemplLanguage } from "./templ-language.ts";
|
|
2
|
+
declare const plugin: {
|
|
3
|
+
meta: {
|
|
4
|
+
name: any;
|
|
5
|
+
version: any;
|
|
6
|
+
namespace: string;
|
|
7
|
+
};
|
|
8
|
+
languages: {
|
|
9
|
+
templ: TemplLanguage;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
export default plugin;
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAKpD,QAAA,MAAM,MAAM;;;;;;;;;CASa,CAAC;AAE1B,eAAe,MAAM,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { ESLint } from "eslint";
|
|
3
|
+
import { TemplLanguage } from "./templ-language.js";
|
|
4
|
+
const pkg = JSON.parse(fs.readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
5
|
+
const plugin = {
|
|
6
|
+
meta: {
|
|
7
|
+
name: pkg.name,
|
|
8
|
+
version: pkg.version,
|
|
9
|
+
namespace: "templ",
|
|
10
|
+
},
|
|
11
|
+
languages: {
|
|
12
|
+
templ: new TemplLanguage(),
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
export default plugin;
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CACpB,EAAE,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CACrE,CAAC;AAEF,MAAM,MAAM,GAAG;IACb,IAAI,EAAE;QACJ,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,SAAS,EAAE,OAAO;KACnB;IACD,SAAS,EAAE;QACT,KAAK,EAAE,IAAI,aAAa,EAAE;KAC3B;CACsB,CAAC;AAE1B,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-for-eslint.d.ts","sourceRoot":"","sources":["../src/parse-for-eslint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoB,WAAW,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAKlC,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAoDrE"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { runTemplAstToJsonBinary } from "./run-templ-ast-to-json-binary.js";
|
|
2
|
+
import { convertToESLintAST } from "./templ-ast-to-eslint-ast.js";
|
|
3
|
+
import { validateTemplAST } from "./templ-ast.js";
|
|
4
|
+
export function parseForESLint(code) {
|
|
5
|
+
let stdout;
|
|
6
|
+
try {
|
|
7
|
+
stdout = runTemplAstToJsonBinary(code);
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
if (error instanceof Error) {
|
|
11
|
+
return createFatalError(error.message);
|
|
12
|
+
}
|
|
13
|
+
throw error;
|
|
14
|
+
}
|
|
15
|
+
// Parse JSON output
|
|
16
|
+
let parsedJSON;
|
|
17
|
+
try {
|
|
18
|
+
parsedJSON = JSON.parse(stdout);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
22
|
+
return createFatalError(`Failed to parse JSON output from templ-ast-to-json: ${message}`);
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
validateTemplAST(parsedJSON);
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
if (!(error instanceof Error)) {
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
return createFatalError(error.message);
|
|
32
|
+
}
|
|
33
|
+
const documentNode = convertToESLintAST(parsedJSON);
|
|
34
|
+
// Following html-eslint's approach: the Program body contains the DocumentNode
|
|
35
|
+
// instead of ESLint Statement nodes. This is the standard pattern for HTML parsers.
|
|
36
|
+
// See: https://github.com/yeonjuan/html-eslint/blob/main/packages/parser/lib/parser.js
|
|
37
|
+
const ast = {
|
|
38
|
+
type: "Program",
|
|
39
|
+
sourceType: "module",
|
|
40
|
+
// @ts-expect-error - html-eslint pattern: body contains DocumentNode, not Statement[]
|
|
41
|
+
body: [documentNode],
|
|
42
|
+
loc: documentNode.loc,
|
|
43
|
+
range: documentNode.range,
|
|
44
|
+
tokens: [],
|
|
45
|
+
comments: [],
|
|
46
|
+
};
|
|
47
|
+
return {
|
|
48
|
+
ok: true,
|
|
49
|
+
ast,
|
|
50
|
+
comments: [],
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Creates a fatal error result for errors that prevent parsing
|
|
55
|
+
* (e.g., binary not found, execution failed, invalid output).
|
|
56
|
+
* Uses line 1, column 0 since these errors aren't tied to specific code locations.
|
|
57
|
+
*/
|
|
58
|
+
function createFatalError(message) {
|
|
59
|
+
return {
|
|
60
|
+
ok: false,
|
|
61
|
+
errors: [
|
|
62
|
+
{
|
|
63
|
+
message,
|
|
64
|
+
line: 1,
|
|
65
|
+
column: 0,
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=parse-for-eslint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-for-eslint.js","sourceRoot":"","sources":["../src/parse-for-eslint.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAC5E,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,OAAO,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACzC,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;IAED,oBAAoB;IACpB,IAAI,UAAmB,CAAC;IACxB,IAAI,CAAC;QACH,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QACzE,OAAO,gBAAgB,CACrB,uDAAuD,OAAO,EAAE,CACjE,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,EAAE,CAAC;YAC9B,MAAM,KAAK,CAAC;QACd,CAAC;QACD,OAAO,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC;IAED,MAAM,YAAY,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAEpD,+EAA+E;IAC/E,oFAAoF;IACpF,uFAAuF;IACvF,MAAM,GAAG,GAAgB;QACvB,IAAI,EAAE,SAAS;QACf,UAAU,EAAE,QAAQ;QACpB,sFAAsF;QACtF,IAAI,EAAE,CAAC,YAAY,CAAC;QACpB,GAAG,EAAE,YAAY,CAAC,GAAG;QACrB,KAAK,EAAE,YAAY,CAAC,KAAK;QACzB,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE,EAAE;KACb,CAAC;IAEF,OAAO;QACL,EAAE,EAAE,IAAI;QACR,GAAG;QACH,QAAQ,EAAE,EAAE;KACb,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAS,gBAAgB,CAAC,OAAe;IACvC,OAAO;QACL,EAAE,EAAE,KAAK;QACT,MAAM,EAAE;YACN;gBACE,OAAO;gBACP,IAAI,EAAE,CAAC;gBACP,MAAM,EAAE,CAAC;aACV;SACF;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-templ-ast-to-json-binary.d.ts","sourceRoot":"","sources":["../src/run-templ-ast-to-json-binary.ts"],"names":[],"mappings":"AAGA,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAwB5D"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
export function runTemplAstToJsonBinary(code) {
|
|
4
|
+
const binaryPath = getBinaryPath();
|
|
5
|
+
try {
|
|
6
|
+
return execFileSync(binaryPath, [], {
|
|
7
|
+
input: code,
|
|
8
|
+
encoding: "utf8",
|
|
9
|
+
maxBuffer: 10 * 1024 * 1024, // 10MB
|
|
10
|
+
timeout: 2000, // 2 seconds
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
if (error instanceof Error) {
|
|
15
|
+
const message = "code" in error && error.code === "ENOENT"
|
|
16
|
+
? `templ-ast-to-json binary not found at ${binaryPath}. Please ensure the binary is built.`
|
|
17
|
+
: `templ-ast-to-json failed: ${"stderr" in error && typeof error.stderr === "string"
|
|
18
|
+
? error.stderr.trim()
|
|
19
|
+
: error.message}`;
|
|
20
|
+
throw new Error(message);
|
|
21
|
+
}
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function getBinaryPath() {
|
|
26
|
+
let os = process.platform;
|
|
27
|
+
if (os === "win32") {
|
|
28
|
+
os = "windows";
|
|
29
|
+
}
|
|
30
|
+
const packageName = `eslint-plugin-templ-${os}-${process.arch}`;
|
|
31
|
+
return fileURLToPath(import.meta.resolve(packageName));
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=run-templ-ast-to-json-binary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-templ-ast-to-json-binary.js","sourceRoot":"","sources":["../src/run-templ-ast-to-json-binary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IAEnC,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,UAAU,EAAE,EAAE,EAAE;YAClC,KAAK,EAAE,IAAI;YACX,QAAQ,EAAE,MAAM;YAChB,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,OAAO;YACpC,OAAO,EAAE,IAAI,EAAE,YAAY;SAC5B,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,MAAM,OAAO,GACX,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;gBACxC,CAAC,CAAC,yCAAyC,UAAU,sCAAsC;gBAC3F,CAAC,CAAC,6BACE,QAAQ,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ;oBACnD,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE;oBACrB,CAAC,CAAC,KAAK,CAAC,OACZ,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,aAAa;IACpB,IAAI,EAAE,GAAW,OAAO,CAAC,QAAQ,CAAC;IAClC,IAAI,EAAE,KAAK,OAAO,EAAE,CAAC;QACnB,EAAE,GAAG,SAAS,CAAC;IACjB,CAAC;IAED,MAAM,WAAW,GAAG,uBAAuB,EAAE,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;IAChE,OAAO,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conversion utilities for transforming templ AST to ESLint-compatible HTML AST
|
|
3
|
+
*/
|
|
4
|
+
import type { DocumentNode } from "es-html-parser";
|
|
5
|
+
import type { TemplAST } from "./templ-ast.ts";
|
|
6
|
+
export declare function convertToESLintAST(templAST: TemplAST): DocumentNode;
|
|
7
|
+
//# sourceMappingURL=templ-ast-to-eslint-ast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templ-ast-to-eslint-ast.d.ts","sourceRoot":"","sources":["../src/templ-ast-to-eslint-ast.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAKV,YAAY,EAKb,MAAM,gBAAgB,CAAC;AAGxB,OAAO,KAAK,EACV,QAAQ,EAQT,MAAM,gBAAgB,CAAC;AAExB,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,GAAG,YAAY,CAoCnE"}
|