astro-eslint-parser 0.0.15 → 0.0.16
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/README.md +22 -17
- package/lib/astro/index.d.ts +12 -16
- package/lib/astro/index.js +88 -102
- package/lib/context/script.d.ts +8 -1
- package/lib/context/script.js +27 -1
- package/lib/parser/astro-parser/parse.js +14 -5
- package/lib/parser/process-template.js +34 -48
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -15,6 +15,8 @@ You can check it on [Online DEMO](https://ota-meshi.github.io/astro-eslint-parse
|
|
|
15
15
|
|
|
16
16
|
This parser is in the ***experimental stages*** of development.
|
|
17
17
|
|
|
18
|
+
At least it works fine with a [fork of the `astro.build` repository](https://github.com/ota-meshi/astro.build/tree/eslint).
|
|
19
|
+
|
|
18
20
|
⚠ Currently this parser relies heavily on the internal API of [@astrojs/compiler]. It may stop working in a future update of [@astrojs/compiler]. ⚠
|
|
19
21
|
|
|
20
22
|
[@astrojs/compiler]: https://github.com/withastro/compiler
|
|
@@ -37,25 +39,28 @@ npm install --save-dev eslint astro-eslint-parser
|
|
|
37
39
|
## 📖 Usage
|
|
38
40
|
|
|
39
41
|
1. Write `overrides.parser` option into your `.eslintrc.*` file.
|
|
40
|
-
2. Use glob patterns or `--ext .astro` CLI option.
|
|
41
42
|
|
|
42
|
-
```json
|
|
43
|
-
{
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
```
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"extends": "eslint:recommended",
|
|
46
|
+
"overrides": [
|
|
47
|
+
{
|
|
48
|
+
"files": ["*.astro"],
|
|
49
|
+
"parser": "astro-eslint-parser"
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
```
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
$ eslint src
|
|
58
|
-
|
|
55
|
+
2. If you have specified the extension in the CLI, add `.astro` as well.
|
|
56
|
+
|
|
57
|
+
```console
|
|
58
|
+
$ eslint "src/**/*.{js,astro}"
|
|
59
|
+
# or
|
|
60
|
+
$ eslint src --ext .js,.astro
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The commit diff [here](https://github.com/ota-meshi/astro.build/commit/7f291ac15e6d97cc20a64b8f97dcbd85379759b5) is an example of introducing this parser to the `astro.build` repository.
|
|
59
64
|
|
|
60
65
|
## 🔧 Options
|
|
61
66
|
|
package/lib/astro/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AttributeNode, CommentNode,
|
|
1
|
+
import type { AttributeNode, CommentNode, Node, ParentNode, TagLikeNode } from "@astrojs/compiler/types";
|
|
2
2
|
import type { Context } from "../context";
|
|
3
3
|
/**
|
|
4
4
|
* Checks if the given node is TagLikeNode
|
|
@@ -15,35 +15,27 @@ export declare function walk(parent: ParentNode, code: string, enter: (n: Node |
|
|
|
15
15
|
/**
|
|
16
16
|
* Get end offset of start tag
|
|
17
17
|
*/
|
|
18
|
-
export declare function
|
|
19
|
-
/**
|
|
20
|
-
* Get end offset of tag
|
|
21
|
-
*/
|
|
22
|
-
export declare function getTagEndOffset(node: TagLikeNode, ctx: Context): number;
|
|
23
|
-
/**
|
|
24
|
-
* Get end offset of Expression
|
|
25
|
-
*/
|
|
26
|
-
export declare function getExpressionEndOffset(node: ExpressionNode, ctx: Context): number;
|
|
18
|
+
export declare function calcStartTagEndOffset(node: TagLikeNode, ctx: Context): number;
|
|
27
19
|
/**
|
|
28
20
|
* Get end offset of attribute
|
|
29
21
|
*/
|
|
30
|
-
export declare function
|
|
22
|
+
export declare function calcAttributeEndOffset(node: AttributeNode, ctx: Context): number;
|
|
31
23
|
/**
|
|
32
24
|
* Get start offset of attribute value
|
|
33
25
|
*/
|
|
34
|
-
export declare function
|
|
26
|
+
export declare function calcAttributeValueStartOffset(node: AttributeNode, ctx: Context): number;
|
|
35
27
|
/**
|
|
36
|
-
* Get end offset of
|
|
28
|
+
* Get end offset of tag
|
|
37
29
|
*/
|
|
38
|
-
export declare function
|
|
30
|
+
export declare function getEndOffset(node: Node, ctx: Context): number;
|
|
39
31
|
/**
|
|
40
32
|
* Get content end offset
|
|
41
33
|
*/
|
|
42
|
-
export declare function
|
|
34
|
+
export declare function calcContentEndOffset(parent: ParentNode, ctx: Context): number;
|
|
43
35
|
/**
|
|
44
36
|
* If the given tag is a self-close tag, get the self-closing tag.
|
|
45
37
|
*/
|
|
46
|
-
export declare function getSelfClosingTag(node: TagLikeNode,
|
|
38
|
+
export declare function getSelfClosingTag(node: TagLikeNode, ctx: Context): null | {
|
|
47
39
|
offset: number;
|
|
48
40
|
end: "/>" | ">";
|
|
49
41
|
};
|
|
@@ -54,6 +46,10 @@ export declare function getEndTag(node: TagLikeNode, ctx: Context): null | {
|
|
|
54
46
|
offset: number;
|
|
55
47
|
tag: string;
|
|
56
48
|
};
|
|
49
|
+
/**
|
|
50
|
+
* Get end offset of comment
|
|
51
|
+
*/
|
|
52
|
+
export declare function calcCommentEndOffset(node: CommentNode, ctx: Context): number;
|
|
57
53
|
/**
|
|
58
54
|
* Skip spaces
|
|
59
55
|
*/
|
package/lib/astro/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.skipSpaces = exports.
|
|
3
|
+
exports.skipSpaces = exports.calcCommentEndOffset = exports.getEndTag = exports.getSelfClosingTag = exports.calcContentEndOffset = exports.getEndOffset = exports.calcAttributeValueStartOffset = exports.calcAttributeEndOffset = exports.calcStartTagEndOffset = exports.walk = exports.walkElements = exports.isParent = exports.isTag = void 0;
|
|
4
4
|
const errors_1 = require("../errors");
|
|
5
5
|
/**
|
|
6
6
|
* Checks if the given node is TagLikeNode
|
|
@@ -49,11 +49,11 @@ exports.walk = walk;
|
|
|
49
49
|
/**
|
|
50
50
|
* Get end offset of start tag
|
|
51
51
|
*/
|
|
52
|
-
function
|
|
52
|
+
function calcStartTagEndOffset(node, ctx) {
|
|
53
53
|
const lastAttr = node.attributes[node.attributes.length - 1];
|
|
54
54
|
let beforeCloseIndex;
|
|
55
55
|
if (lastAttr) {
|
|
56
|
-
beforeCloseIndex =
|
|
56
|
+
beforeCloseIndex = calcAttributeEndOffset(lastAttr, ctx);
|
|
57
57
|
}
|
|
58
58
|
else {
|
|
59
59
|
const info = getTokenInfo(ctx, [`<${node.name}`], node.position.start.offset);
|
|
@@ -62,63 +62,20 @@ function getStartTagEndOffset(node, ctx) {
|
|
|
62
62
|
const info = getTokenInfo(ctx, [[">", "/>"]], beforeCloseIndex);
|
|
63
63
|
return info.index + info.match.length;
|
|
64
64
|
}
|
|
65
|
-
exports.
|
|
66
|
-
/**
|
|
67
|
-
* Get end offset of tag
|
|
68
|
-
*/
|
|
69
|
-
function getTagEndOffset(node, ctx) {
|
|
70
|
-
var _a;
|
|
71
|
-
if (((_a = node.position.end) === null || _a === void 0 ? void 0 : _a.offset) != null) {
|
|
72
|
-
return node.position.end.offset;
|
|
73
|
-
}
|
|
74
|
-
let beforeIndex;
|
|
75
|
-
if (node.children.length) {
|
|
76
|
-
const lastChild = node.children[node.children.length - 1];
|
|
77
|
-
beforeIndex = getEndOffset(lastChild, ctx);
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
beforeIndex = getStartTagEndOffset(node, ctx);
|
|
81
|
-
}
|
|
82
|
-
beforeIndex = skipSpaces(ctx.code, beforeIndex);
|
|
83
|
-
if (ctx.code.startsWith(`</${node.name}`, beforeIndex)) {
|
|
84
|
-
beforeIndex = beforeIndex + 2 + node.name.length;
|
|
85
|
-
const info = getTokenInfo(ctx, [">"], beforeIndex);
|
|
86
|
-
return info.index + info.match.length;
|
|
87
|
-
}
|
|
88
|
-
return beforeIndex;
|
|
89
|
-
}
|
|
90
|
-
exports.getTagEndOffset = getTagEndOffset;
|
|
91
|
-
/**
|
|
92
|
-
* Get end offset of Expression
|
|
93
|
-
*/
|
|
94
|
-
function getExpressionEndOffset(node, ctx) {
|
|
95
|
-
var _a;
|
|
96
|
-
if (((_a = node.position.end) === null || _a === void 0 ? void 0 : _a.offset) != null) {
|
|
97
|
-
return node.position.end.offset;
|
|
98
|
-
}
|
|
99
|
-
if (node.children.length) {
|
|
100
|
-
const lastChild = node.children[node.children.length - 1];
|
|
101
|
-
const beforeIndex = getEndOffset(lastChild, ctx);
|
|
102
|
-
const info = getTokenInfo(ctx, ["}"], beforeIndex);
|
|
103
|
-
return info.index + info.match.length;
|
|
104
|
-
}
|
|
105
|
-
const info = getTokenInfo(ctx, ["{", "}"], node.position.start.offset);
|
|
106
|
-
return info.index + info.match.length;
|
|
107
|
-
}
|
|
108
|
-
exports.getExpressionEndOffset = getExpressionEndOffset;
|
|
65
|
+
exports.calcStartTagEndOffset = calcStartTagEndOffset;
|
|
109
66
|
/**
|
|
110
67
|
* Get end offset of attribute
|
|
111
68
|
*/
|
|
112
|
-
function
|
|
69
|
+
function calcAttributeEndOffset(node, ctx) {
|
|
113
70
|
let info;
|
|
114
71
|
if (node.kind === "empty") {
|
|
115
72
|
info = getTokenInfo(ctx, [node.name], node.position.start.offset);
|
|
116
73
|
}
|
|
117
74
|
else if (node.kind === "quoted") {
|
|
118
|
-
info = getTokenInfo(ctx, [[`"${node.value}"`, `'${node.value}'`, node.value]],
|
|
75
|
+
info = getTokenInfo(ctx, [[`"${node.value}"`, `'${node.value}'`, node.value]], calcAttributeValueStartOffset(node, ctx));
|
|
119
76
|
}
|
|
120
77
|
else if (node.kind === "expression") {
|
|
121
|
-
info = getTokenInfo(ctx, ["{", node.value, "}"],
|
|
78
|
+
info = getTokenInfo(ctx, ["{", node.value, "}"], calcAttributeValueStartOffset(node, ctx));
|
|
122
79
|
}
|
|
123
80
|
else if (node.kind === "shorthand") {
|
|
124
81
|
info = getTokenInfo(ctx, ["{", node.name, "}"], node.position.start.offset);
|
|
@@ -127,18 +84,18 @@ function getAttributeEndOffset(node, ctx) {
|
|
|
127
84
|
info = getTokenInfo(ctx, ["{", "...", node.name, "}"], node.position.start.offset);
|
|
128
85
|
}
|
|
129
86
|
else if (node.kind === "template-literal") {
|
|
130
|
-
info = getTokenInfo(ctx, [`\`${node.value}\``],
|
|
87
|
+
info = getTokenInfo(ctx, [`\`${node.value}\``], calcAttributeValueStartOffset(node, ctx));
|
|
131
88
|
}
|
|
132
89
|
else {
|
|
133
90
|
throw new errors_1.ParseError(`Unknown attr kind: ${node.kind}`, node.position.start.offset, ctx);
|
|
134
91
|
}
|
|
135
92
|
return info.index + info.match.length;
|
|
136
93
|
}
|
|
137
|
-
exports.
|
|
94
|
+
exports.calcAttributeEndOffset = calcAttributeEndOffset;
|
|
138
95
|
/**
|
|
139
96
|
* Get start offset of attribute value
|
|
140
97
|
*/
|
|
141
|
-
function
|
|
98
|
+
function calcAttributeValueStartOffset(node, ctx) {
|
|
142
99
|
let info;
|
|
143
100
|
if (node.kind === "quoted") {
|
|
144
101
|
info = getTokenInfo(ctx, [node.name, "=", [`"`, `'`, node.value]], node.position.start.offset);
|
|
@@ -154,22 +111,46 @@ function getAttributeValueStartOffset(node, ctx) {
|
|
|
154
111
|
}
|
|
155
112
|
return info.index;
|
|
156
113
|
}
|
|
157
|
-
exports.
|
|
114
|
+
exports.calcAttributeValueStartOffset = calcAttributeValueStartOffset;
|
|
158
115
|
/**
|
|
159
|
-
* Get end offset of
|
|
116
|
+
* Get end offset of tag
|
|
160
117
|
*/
|
|
161
|
-
function
|
|
162
|
-
|
|
163
|
-
|
|
118
|
+
function getEndOffset(node, ctx) {
|
|
119
|
+
var _a;
|
|
120
|
+
if (((_a = node.position.end) === null || _a === void 0 ? void 0 : _a.offset) != null) {
|
|
121
|
+
return node.position.end.offset;
|
|
122
|
+
}
|
|
123
|
+
if (isTag(node))
|
|
124
|
+
return calcTagEndOffset(node, ctx);
|
|
125
|
+
if (node.type === "expression")
|
|
126
|
+
return calcExpressionEndOffset(node, ctx);
|
|
127
|
+
if (node.type === "comment")
|
|
128
|
+
return calcCommentEndOffset(node, ctx);
|
|
129
|
+
if (node.type === "frontmatter") {
|
|
130
|
+
const start = node.position.start.offset;
|
|
131
|
+
return ctx.code.indexOf("---", start + 3) + 3;
|
|
132
|
+
}
|
|
133
|
+
if (node.type === "doctype") {
|
|
134
|
+
const start = node.position.start.offset;
|
|
135
|
+
return ctx.code.indexOf(">", start) + 1;
|
|
136
|
+
}
|
|
137
|
+
if (node.type === "text") {
|
|
138
|
+
const start = node.position.start.offset;
|
|
139
|
+
return start + node.value.length;
|
|
140
|
+
}
|
|
141
|
+
if (node.type === "root") {
|
|
142
|
+
return ctx.code.length;
|
|
143
|
+
}
|
|
144
|
+
throw new Error(`unknown type: ${node.type}`);
|
|
164
145
|
}
|
|
165
|
-
exports.
|
|
146
|
+
exports.getEndOffset = getEndOffset;
|
|
166
147
|
/**
|
|
167
148
|
* Get content end offset
|
|
168
149
|
*/
|
|
169
|
-
function
|
|
150
|
+
function calcContentEndOffset(parent, ctx) {
|
|
170
151
|
const code = ctx.code;
|
|
171
152
|
if (isTag(parent)) {
|
|
172
|
-
const end =
|
|
153
|
+
const end = getEndOffset(parent, ctx);
|
|
173
154
|
if (code[end - 1] !== ">") {
|
|
174
155
|
return end;
|
|
175
156
|
}
|
|
@@ -181,7 +162,7 @@ function getContentEndOffset(parent, ctx) {
|
|
|
181
162
|
return end;
|
|
182
163
|
}
|
|
183
164
|
else if (parent.type === "expression") {
|
|
184
|
-
const end =
|
|
165
|
+
const end = getEndOffset(parent, ctx);
|
|
185
166
|
return code.lastIndexOf("}", end);
|
|
186
167
|
}
|
|
187
168
|
else if (parent.type === "root") {
|
|
@@ -189,33 +170,28 @@ function getContentEndOffset(parent, ctx) {
|
|
|
189
170
|
}
|
|
190
171
|
throw new Error(`unknown type: ${parent.type}`);
|
|
191
172
|
}
|
|
192
|
-
exports.
|
|
173
|
+
exports.calcContentEndOffset = calcContentEndOffset;
|
|
193
174
|
/**
|
|
194
175
|
* If the given tag is a self-close tag, get the self-closing tag.
|
|
195
176
|
*/
|
|
196
|
-
function getSelfClosingTag(node,
|
|
177
|
+
function getSelfClosingTag(node, ctx) {
|
|
197
178
|
if (node.children.length > 0) {
|
|
198
179
|
return null;
|
|
199
180
|
}
|
|
200
181
|
const code = ctx.code;
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
else {
|
|
208
|
-
const next = parent.children[childIndex + 1];
|
|
209
|
-
nextElementIndex = next.position.start.offset;
|
|
182
|
+
const startTagEndOffset = calcStartTagEndOffset(node, ctx);
|
|
183
|
+
if (code.startsWith("/>", startTagEndOffset - 2)) {
|
|
184
|
+
return {
|
|
185
|
+
offset: startTagEndOffset,
|
|
186
|
+
end: "/>",
|
|
187
|
+
};
|
|
210
188
|
}
|
|
211
|
-
|
|
212
|
-
if (code.slice(endOffset, nextElementIndex).trim()) {
|
|
213
|
-
// has end tag
|
|
189
|
+
if (code.startsWith(`</${node.name}`, startTagEndOffset)) {
|
|
214
190
|
return null;
|
|
215
191
|
}
|
|
216
192
|
return {
|
|
217
|
-
offset:
|
|
218
|
-
end:
|
|
193
|
+
offset: startTagEndOffset,
|
|
194
|
+
end: ">",
|
|
219
195
|
};
|
|
220
196
|
}
|
|
221
197
|
exports.getSelfClosingTag = getSelfClosingTag;
|
|
@@ -229,7 +205,7 @@ function getEndTag(node, ctx) {
|
|
|
229
205
|
beforeIndex = getEndOffset(lastChild, ctx);
|
|
230
206
|
}
|
|
231
207
|
else {
|
|
232
|
-
beforeIndex =
|
|
208
|
+
beforeIndex = calcStartTagEndOffset(node, ctx);
|
|
233
209
|
}
|
|
234
210
|
beforeIndex = skipSpaces(ctx.code, beforeIndex);
|
|
235
211
|
if (ctx.code.startsWith(`</${node.name}`, beforeIndex)) {
|
|
@@ -245,36 +221,46 @@ function getEndTag(node, ctx) {
|
|
|
245
221
|
return null;
|
|
246
222
|
}
|
|
247
223
|
exports.getEndTag = getEndTag;
|
|
224
|
+
/**
|
|
225
|
+
* Get end offset of comment
|
|
226
|
+
*/
|
|
227
|
+
function calcCommentEndOffset(node, ctx) {
|
|
228
|
+
const info = getTokenInfo(ctx, ["<!--", node.value, "-->"], node.position.start.offset);
|
|
229
|
+
return info.index + info.match.length;
|
|
230
|
+
}
|
|
231
|
+
exports.calcCommentEndOffset = calcCommentEndOffset;
|
|
248
232
|
/**
|
|
249
233
|
* Get end offset of tag
|
|
250
234
|
*/
|
|
251
|
-
function
|
|
252
|
-
|
|
253
|
-
if (
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if (isTag(node))
|
|
257
|
-
return getTagEndOffset(node, ctx);
|
|
258
|
-
if (node.type === "expression")
|
|
259
|
-
return getExpressionEndOffset(node, ctx);
|
|
260
|
-
if (node.type === "comment")
|
|
261
|
-
return getCommentEndOffset(node, ctx);
|
|
262
|
-
if (node.type === "frontmatter") {
|
|
263
|
-
const start = node.position.start.offset;
|
|
264
|
-
return ctx.code.indexOf("---", start + 3) + 3;
|
|
235
|
+
function calcTagEndOffset(node, ctx) {
|
|
236
|
+
let beforeIndex;
|
|
237
|
+
if (node.children.length) {
|
|
238
|
+
const lastChild = node.children[node.children.length - 1];
|
|
239
|
+
beforeIndex = getEndOffset(lastChild, ctx);
|
|
265
240
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
return ctx.code.indexOf(">", start) + 1;
|
|
241
|
+
else {
|
|
242
|
+
beforeIndex = calcStartTagEndOffset(node, ctx);
|
|
269
243
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
244
|
+
beforeIndex = skipSpaces(ctx.code, beforeIndex);
|
|
245
|
+
if (ctx.code.startsWith(`</${node.name}`, beforeIndex)) {
|
|
246
|
+
beforeIndex = beforeIndex + 2 + node.name.length;
|
|
247
|
+
const info = getTokenInfo(ctx, [">"], beforeIndex);
|
|
248
|
+
return info.index + info.match.length;
|
|
273
249
|
}
|
|
274
|
-
|
|
275
|
-
|
|
250
|
+
return beforeIndex;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Get end offset of Expression
|
|
254
|
+
*/
|
|
255
|
+
function calcExpressionEndOffset(node, ctx) {
|
|
256
|
+
if (node.children.length) {
|
|
257
|
+
const lastChild = node.children[node.children.length - 1];
|
|
258
|
+
const beforeIndex = getEndOffset(lastChild, ctx);
|
|
259
|
+
const info = getTokenInfo(ctx, ["}"], beforeIndex);
|
|
260
|
+
return info.index + info.match.length;
|
|
276
261
|
}
|
|
277
|
-
|
|
262
|
+
const info = getTokenInfo(ctx, ["{", "}"], node.position.start.offset);
|
|
263
|
+
return info.index + info.match.length;
|
|
278
264
|
}
|
|
279
265
|
/**
|
|
280
266
|
* Get token info
|
package/lib/context/script.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import type { Context } from ".";
|
|
2
2
|
import type { ESLintExtendedProgram } from "../parser";
|
|
3
3
|
import type { TSESTree } from "@typescript-eslint/types";
|
|
4
|
+
declare class RestoreNodeProcessContext {
|
|
5
|
+
readonly result: ESLintExtendedProgram;
|
|
6
|
+
readonly removeTokens: Set<(token: TSESTree.Token) => boolean>;
|
|
7
|
+
constructor(result: ESLintExtendedProgram);
|
|
8
|
+
addRemoveToken(test: (token: TSESTree.Token) => boolean): void;
|
|
9
|
+
}
|
|
4
10
|
export declare class ScriptContext {
|
|
5
11
|
private readonly ctx;
|
|
6
12
|
script: string;
|
|
@@ -14,7 +20,7 @@ export declare class ScriptContext {
|
|
|
14
20
|
appendOriginal(index: number): void;
|
|
15
21
|
appendScript(fragment: string): void;
|
|
16
22
|
addToken(type: TSESTree.Token["type"], range: TSESTree.Range): void;
|
|
17
|
-
addRestoreNodeProcess(process: (node: TSESTree.Node,
|
|
23
|
+
addRestoreNodeProcess(process: (node: TSESTree.Node, context: RestoreNodeProcessContext, parent: TSESTree.Node) => boolean): void;
|
|
18
24
|
/**
|
|
19
25
|
* Restore AST nodes
|
|
20
26
|
*/
|
|
@@ -22,3 +28,4 @@ export declare class ScriptContext {
|
|
|
22
28
|
private remapLocation;
|
|
23
29
|
private getRemapRange;
|
|
24
30
|
}
|
|
31
|
+
export {};
|
package/lib/context/script.js
CHANGED
|
@@ -3,6 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ScriptContext = void 0;
|
|
4
4
|
const traverse_1 = require("../traverse");
|
|
5
5
|
const errors_1 = require("../errors");
|
|
6
|
+
class RestoreNodeProcessContext {
|
|
7
|
+
constructor(result) {
|
|
8
|
+
this.removeTokens = new Set();
|
|
9
|
+
this.result = result;
|
|
10
|
+
}
|
|
11
|
+
addRemoveToken(test) {
|
|
12
|
+
this.removeTokens.add(test);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
6
15
|
class ScriptContext {
|
|
7
16
|
constructor(ctx) {
|
|
8
17
|
this.script = "";
|
|
@@ -38,6 +47,7 @@ class ScriptContext {
|
|
|
38
47
|
/**
|
|
39
48
|
* Restore AST nodes
|
|
40
49
|
*/
|
|
50
|
+
// eslint-disable-next-line complexity -- X(
|
|
41
51
|
restore(result) {
|
|
42
52
|
const last = result.ast.body[result.ast.body.length - 1];
|
|
43
53
|
if (last.type !== "ExpressionStatement") {
|
|
@@ -77,11 +87,27 @@ class ScriptContext {
|
|
|
77
87
|
for (const token of result.ast.comments || []) {
|
|
78
88
|
this.remapLocation(token);
|
|
79
89
|
}
|
|
90
|
+
const context = new RestoreNodeProcessContext(result);
|
|
80
91
|
let restoreNodeProcesses = this.restoreNodeProcesses;
|
|
81
92
|
for (const [node, parent] of traversed) {
|
|
82
93
|
if (!parent)
|
|
83
94
|
continue;
|
|
84
|
-
restoreNodeProcesses = restoreNodeProcesses.filter((proc) => !proc(node,
|
|
95
|
+
restoreNodeProcesses = restoreNodeProcesses.filter((proc) => !proc(node, context, parent));
|
|
96
|
+
}
|
|
97
|
+
if (context.removeTokens.size) {
|
|
98
|
+
const tokens = result.ast.tokens || [];
|
|
99
|
+
for (let index = tokens.length - 1; index >= 0; index--) {
|
|
100
|
+
const token = tokens[index];
|
|
101
|
+
for (const rt of context.removeTokens) {
|
|
102
|
+
if (rt(token)) {
|
|
103
|
+
tokens.splice(index, 1);
|
|
104
|
+
context.removeTokens.delete(rt);
|
|
105
|
+
if (!context.removeTokens.size) {
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
85
111
|
}
|
|
86
112
|
// Adjust program node location
|
|
87
113
|
const first = result.ast.body[0];
|
|
@@ -140,16 +140,22 @@ function fixLocations(node, ctx) {
|
|
|
140
140
|
start += 1;
|
|
141
141
|
start += node.name.length;
|
|
142
142
|
if (!node.attributes.length) {
|
|
143
|
-
start = (0, astro_1.
|
|
143
|
+
start = (0, astro_1.calcStartTagEndOffset)(node, ctx);
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
146
|
else if (node.type === "attribute") {
|
|
147
147
|
fixLocationForAttr(node, ctx, start);
|
|
148
|
-
start = (0, astro_1.
|
|
148
|
+
start = (0, astro_1.calcAttributeEndOffset)(node, ctx);
|
|
149
|
+
if (node.position.end) {
|
|
150
|
+
node.position.end.offset = start;
|
|
151
|
+
}
|
|
149
152
|
}
|
|
150
153
|
else if (node.type === "comment") {
|
|
151
154
|
node.position.start.offset = tokenIndex(ctx, "<!--", start);
|
|
152
|
-
start = (0, astro_1.
|
|
155
|
+
start = (0, astro_1.calcCommentEndOffset)(node, ctx);
|
|
156
|
+
if (node.position.end) {
|
|
157
|
+
node.position.end.offset = start;
|
|
158
|
+
}
|
|
153
159
|
}
|
|
154
160
|
else if (node.type === "text") {
|
|
155
161
|
if (parent.type === "element" &&
|
|
@@ -193,6 +199,9 @@ function fixLocations(node, ctx) {
|
|
|
193
199
|
node.value = ctx.code.slice(node.position.start.offset, start);
|
|
194
200
|
}
|
|
195
201
|
}
|
|
202
|
+
if (node.position.end) {
|
|
203
|
+
node.position.end.offset = start;
|
|
204
|
+
}
|
|
196
205
|
}
|
|
197
206
|
else if (node.type === "expression") {
|
|
198
207
|
start = node.position.start.offset = tokenIndex(ctx, "{", start);
|
|
@@ -217,7 +226,7 @@ function fixLocations(node, ctx) {
|
|
|
217
226
|
if (node.type === "attribute") {
|
|
218
227
|
const attributes = parent.attributes;
|
|
219
228
|
if (attributes[attributes.length - 1] === node) {
|
|
220
|
-
start = (0, astro_1.
|
|
229
|
+
start = (0, astro_1.calcStartTagEndOffset)(parent, ctx);
|
|
221
230
|
}
|
|
222
231
|
}
|
|
223
232
|
else if (node.type === "expression") {
|
|
@@ -227,7 +236,7 @@ function fixLocations(node, ctx) {
|
|
|
227
236
|
node.type === "element" ||
|
|
228
237
|
node.type === "component" ||
|
|
229
238
|
node.type === "custom-element") {
|
|
230
|
-
if (!(0, astro_1.getSelfClosingTag)(node,
|
|
239
|
+
if (!(0, astro_1.getSelfClosingTag)(node, ctx)) {
|
|
231
240
|
const closeTagStart = tokenIndexSafe(ctx.code, `</${node.name}`, start);
|
|
232
241
|
if (closeTagStart != null) {
|
|
233
242
|
start = closeTagStart + 2 + node.name.length;
|
|
@@ -24,12 +24,12 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
24
24
|
const start = node.position.start.offset;
|
|
25
25
|
script.appendOriginal(start);
|
|
26
26
|
script.skipOriginalOffset(3);
|
|
27
|
-
const end = node
|
|
27
|
+
const end = (0, astro_1.getEndOffset)(node, ctx);
|
|
28
28
|
script.appendOriginal(end - 3);
|
|
29
29
|
script.appendScript(";<>");
|
|
30
30
|
fragmentOpened = true;
|
|
31
31
|
script.skipOriginalOffset(3);
|
|
32
|
-
script.addRestoreNodeProcess((_scriptNode, result) => {
|
|
32
|
+
script.addRestoreNodeProcess((_scriptNode, { result }) => {
|
|
33
33
|
for (let index = 0; index < result.ast.body.length; index++) {
|
|
34
34
|
const st = result.ast.body[index];
|
|
35
35
|
if (st.type === types_1.AST_NODE_TYPES.EmptyStatement) {
|
|
@@ -107,7 +107,7 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
107
107
|
start + colonIndex + 1,
|
|
108
108
|
start + attr.name.length,
|
|
109
109
|
]);
|
|
110
|
-
script.addRestoreNodeProcess((scriptNode,
|
|
110
|
+
script.addRestoreNodeProcess((scriptNode, context) => {
|
|
111
111
|
if (scriptNode.type ===
|
|
112
112
|
types_1.AST_NODE_TYPES.JSXAttribute &&
|
|
113
113
|
scriptNode.range[0] === start) {
|
|
@@ -119,17 +119,10 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
119
119
|
scriptNode.name = nsn;
|
|
120
120
|
nsn.namespace.parent = nsn;
|
|
121
121
|
nsn.name.parent = nsn;
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
baseNameNode.range[0] &&
|
|
127
|
-
token.range[1] ===
|
|
128
|
-
baseNameNode.range[1]) {
|
|
129
|
-
tokens.splice(index, 1);
|
|
130
|
-
break;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
122
|
+
context.addRemoveToken((token) => token.range[0] ===
|
|
123
|
+
baseNameNode.range[0] &&
|
|
124
|
+
token.range[1] ===
|
|
125
|
+
baseNameNode.range[1]);
|
|
133
126
|
return true;
|
|
134
127
|
}
|
|
135
128
|
return false;
|
|
@@ -162,8 +155,8 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
162
155
|
}
|
|
163
156
|
else if (attr.kind === "template-literal") {
|
|
164
157
|
const attrStart = attr.position.start.offset;
|
|
165
|
-
const start = (0, astro_1.
|
|
166
|
-
const end = (0, astro_1.
|
|
158
|
+
const start = (0, astro_1.calcAttributeValueStartOffset)(attr, ctx);
|
|
159
|
+
const end = (0, astro_1.calcAttributeEndOffset)(attr, ctx);
|
|
167
160
|
script.appendOriginal(start);
|
|
168
161
|
script.appendScript("{");
|
|
169
162
|
script.appendOriginal(end);
|
|
@@ -181,7 +174,7 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
181
174
|
}
|
|
182
175
|
}
|
|
183
176
|
// Process for start tag close
|
|
184
|
-
const closing = (0, astro_1.getSelfClosingTag)(node,
|
|
177
|
+
const closing = (0, astro_1.getSelfClosingTag)(node, ctx);
|
|
185
178
|
if (closing && closing.end === ">") {
|
|
186
179
|
script.appendOriginal(closing.offset - 1);
|
|
187
180
|
script.appendScript("/");
|
|
@@ -214,7 +207,8 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
214
207
|
}
|
|
215
208
|
else if (node.type === "comment") {
|
|
216
209
|
const start = node.position.start.offset;
|
|
217
|
-
const
|
|
210
|
+
const end = (0, astro_1.getEndOffset)(node, ctx);
|
|
211
|
+
const length = end - start;
|
|
218
212
|
script.appendOriginal(start);
|
|
219
213
|
let targetType;
|
|
220
214
|
if (fragmentOpened) {
|
|
@@ -228,7 +222,7 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
228
222
|
targetType = types_1.AST_NODE_TYPES.ExpressionStatement;
|
|
229
223
|
script.skipOriginalOffset(length);
|
|
230
224
|
}
|
|
231
|
-
script.addRestoreNodeProcess((scriptNode,
|
|
225
|
+
script.addRestoreNodeProcess((scriptNode, context) => {
|
|
232
226
|
if (scriptNode.range[0] === start &&
|
|
233
227
|
scriptNode.type === targetType) {
|
|
234
228
|
delete scriptNode.children;
|
|
@@ -238,26 +232,11 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
238
232
|
const commentNode = scriptNode;
|
|
239
233
|
commentNode.type = "AstroHTMLComment";
|
|
240
234
|
commentNode.value = node.value;
|
|
241
|
-
if (
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
token.range[1] === scriptNode.range[1],
|
|
247
|
-
]);
|
|
248
|
-
const tokens = result.ast.tokens || [];
|
|
249
|
-
for (let index = tokens.length - 1; index >= 0; index--) {
|
|
250
|
-
const token = tokens[index];
|
|
251
|
-
for (const rt of removeTokenSet) {
|
|
252
|
-
if (rt(token)) {
|
|
253
|
-
tokens.splice(index, 1);
|
|
254
|
-
removeTokenSet.delete(rt);
|
|
255
|
-
if (!removeTokenSet.size) {
|
|
256
|
-
break;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
235
|
+
if (targetType === types_1.AST_NODE_TYPES.JSXFragment) {
|
|
236
|
+
context.addRemoveToken((token) => token.value === "<" &&
|
|
237
|
+
token.range[0] === scriptNode.range[0]);
|
|
238
|
+
context.addRemoveToken((token) => token.value === ">" &&
|
|
239
|
+
token.range[1] === scriptNode.range[1]);
|
|
261
240
|
}
|
|
262
241
|
return true;
|
|
263
242
|
}
|
|
@@ -270,19 +249,22 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
270
249
|
}
|
|
271
250
|
else if (node.type === "doctype") {
|
|
272
251
|
const start = node.position.start.offset;
|
|
273
|
-
const end = node
|
|
252
|
+
const end = (0, astro_1.getEndOffset)(node, ctx);
|
|
253
|
+
const length = end - start;
|
|
274
254
|
script.appendOriginal(start);
|
|
275
255
|
let targetType;
|
|
276
256
|
if (fragmentOpened) {
|
|
277
|
-
script.
|
|
257
|
+
script.appendOriginal(start + 1);
|
|
258
|
+
script.appendScript(`></`);
|
|
259
|
+
script.skipOriginalOffset(length - 2);
|
|
278
260
|
targetType = types_1.AST_NODE_TYPES.JSXFragment;
|
|
279
261
|
}
|
|
280
262
|
else {
|
|
281
263
|
script.appendScript(`0;`);
|
|
282
264
|
targetType = types_1.AST_NODE_TYPES.ExpressionStatement;
|
|
265
|
+
script.skipOriginalOffset(length);
|
|
283
266
|
}
|
|
284
|
-
script.
|
|
285
|
-
script.addRestoreNodeProcess((scriptNode) => {
|
|
267
|
+
script.addRestoreNodeProcess((scriptNode, context) => {
|
|
286
268
|
if (scriptNode.range[0] === start &&
|
|
287
269
|
scriptNode.type === targetType) {
|
|
288
270
|
delete scriptNode.children;
|
|
@@ -291,6 +273,12 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
291
273
|
delete scriptNode.expression;
|
|
292
274
|
const doctypeNode = scriptNode;
|
|
293
275
|
doctypeNode.type = "AstroDoctype";
|
|
276
|
+
if (targetType === types_1.AST_NODE_TYPES.JSXFragment) {
|
|
277
|
+
context.addRemoveToken((token) => token.value === "<" &&
|
|
278
|
+
token.range[0] === scriptNode.range[0]);
|
|
279
|
+
context.addRemoveToken((token) => token.value === ">" &&
|
|
280
|
+
token.range[1] === scriptNode.range[1]);
|
|
281
|
+
}
|
|
294
282
|
return true;
|
|
295
283
|
}
|
|
296
284
|
return false;
|
|
@@ -299,11 +287,11 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
299
287
|
}
|
|
300
288
|
}, (node, [parent]) => {
|
|
301
289
|
if ((0, astro_1.isTag)(node)) {
|
|
302
|
-
const closing = (0, astro_1.getSelfClosingTag)(node,
|
|
290
|
+
const closing = (0, astro_1.getSelfClosingTag)(node, ctx);
|
|
303
291
|
if (!closing) {
|
|
304
292
|
const end = (0, astro_1.getEndTag)(node, ctx);
|
|
305
293
|
if (!end) {
|
|
306
|
-
const offset = (0, astro_1.
|
|
294
|
+
const offset = (0, astro_1.calcContentEndOffset)(node, ctx);
|
|
307
295
|
script.appendOriginal(offset);
|
|
308
296
|
script.appendScript(`</${node.name}>`);
|
|
309
297
|
script.addRestoreNodeProcess((scriptNode, _result, parent) => {
|
|
@@ -328,9 +316,7 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
328
316
|
const before = parent.children[index - 1];
|
|
329
317
|
if (before &&
|
|
330
318
|
((0, astro_1.isTag)(before) || before.type === "comment")) {
|
|
331
|
-
const end = (0, astro_1.
|
|
332
|
-
? (0, astro_1.getTagEndOffset)(node, ctx)
|
|
333
|
-
: (0, astro_1.getCommentEndOffset)(node, ctx);
|
|
319
|
+
const end = (0, astro_1.getEndOffset)(node, ctx);
|
|
334
320
|
script.appendOriginal(end);
|
|
335
321
|
script.appendScript("</>");
|
|
336
322
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "astro-eslint-parser",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.16",
|
|
4
4
|
"description": "Astro parser for ESLint",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"files": [
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"@types/semver": "^7.3.9",
|
|
61
61
|
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
|
62
62
|
"@typescript-eslint/parser": "^5.4.0",
|
|
63
|
+
"astro-eslint-parser": ">=0.0.15",
|
|
63
64
|
"benchmark": "^2.1.4",
|
|
64
65
|
"chai": "^4.3.4",
|
|
65
66
|
"code-red": "^0.2.3",
|