astro-eslint-parser 0.0.13 → 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 +24 -17
- package/lib/astro/index.js +155 -130
- package/lib/context/index.d.ts +3 -1
- package/lib/context/index.js +6 -0
- package/lib/context/script.d.ts +8 -1
- package/lib/context/script.js +33 -5
- package/lib/errors.d.ts +1 -0
- package/lib/errors.js +1 -0
- package/lib/parser/astro-parser/parse.js +25 -12
- package/lib/parser/process-template.js +106 -83
- package/lib/parser/script.js +3 -1
- package/package.json +3 -2
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
|
|
@@ -9,40 +9,47 @@ export declare function isTag(node: Node): node is Node & TagLikeNode;
|
|
|
9
9
|
*/
|
|
10
10
|
export declare function isParent(node: Node): node is ParentNode;
|
|
11
11
|
/** walk element nodes */
|
|
12
|
-
export declare function walkElements(parent: ParentNode, code: string,
|
|
12
|
+
export declare function walkElements(parent: ParentNode, code: string, enter: (n: Node, parents: ParentNode[]) => void, leave: (n: Node, parents: ParentNode[]) => void, parents?: ParentNode[]): void;
|
|
13
13
|
/** walk nodes */
|
|
14
|
-
export declare function walk(parent: ParentNode, code: string, enter: (n: Node | AttributeNode, parents: ParentNode[]) => void, leave
|
|
14
|
+
export declare function walk(parent: ParentNode, code: string, enter: (n: Node | AttributeNode, parents: ParentNode[]) => void, leave: (n: Node | AttributeNode, parents: ParentNode[]) => void): void;
|
|
15
15
|
/**
|
|
16
16
|
* Get end offset of start tag
|
|
17
17
|
*/
|
|
18
|
-
export declare function
|
|
18
|
+
export declare function calcStartTagEndOffset(node: TagLikeNode, ctx: Context): number;
|
|
19
19
|
/**
|
|
20
|
-
* Get end offset of
|
|
20
|
+
* Get end offset of attribute
|
|
21
21
|
*/
|
|
22
|
-
export declare function
|
|
22
|
+
export declare function calcAttributeEndOffset(node: AttributeNode, ctx: Context): number;
|
|
23
23
|
/**
|
|
24
|
-
* Get
|
|
24
|
+
* Get start offset of attribute value
|
|
25
25
|
*/
|
|
26
|
-
export declare function
|
|
26
|
+
export declare function calcAttributeValueStartOffset(node: AttributeNode, ctx: Context): number;
|
|
27
27
|
/**
|
|
28
|
-
* Get end offset of
|
|
28
|
+
* Get end offset of tag
|
|
29
29
|
*/
|
|
30
|
-
export declare function
|
|
30
|
+
export declare function getEndOffset(node: Node, ctx: Context): number;
|
|
31
31
|
/**
|
|
32
|
-
* Get
|
|
32
|
+
* Get content end offset
|
|
33
33
|
*/
|
|
34
|
-
export declare function
|
|
34
|
+
export declare function calcContentEndOffset(parent: ParentNode, ctx: Context): number;
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
36
|
+
* If the given tag is a self-close tag, get the self-closing tag.
|
|
37
37
|
*/
|
|
38
|
-
export declare function
|
|
38
|
+
export declare function getSelfClosingTag(node: TagLikeNode, ctx: Context): null | {
|
|
39
|
+
offset: number;
|
|
40
|
+
end: "/>" | ">";
|
|
41
|
+
};
|
|
39
42
|
/**
|
|
40
|
-
* If the given tag
|
|
43
|
+
* If the given tag has a end tag, get the end tag.
|
|
41
44
|
*/
|
|
42
|
-
export declare function
|
|
45
|
+
export declare function getEndTag(node: TagLikeNode, ctx: Context): null | {
|
|
43
46
|
offset: number;
|
|
44
|
-
|
|
47
|
+
tag: string;
|
|
45
48
|
};
|
|
49
|
+
/**
|
|
50
|
+
* Get end offset of comment
|
|
51
|
+
*/
|
|
52
|
+
export declare function calcCommentEndOffset(node: CommentNode, ctx: Context): number;
|
|
46
53
|
/**
|
|
47
54
|
* Skip spaces
|
|
48
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
|
|
@@ -20,45 +20,40 @@ function isParent(node) {
|
|
|
20
20
|
}
|
|
21
21
|
exports.isParent = isParent;
|
|
22
22
|
/** walk element nodes */
|
|
23
|
-
function walkElements(parent, code,
|
|
23
|
+
function walkElements(parent, code, enter, leave, parents = []) {
|
|
24
24
|
const children = getSortedChildren(parent, code);
|
|
25
25
|
const currParents = [parent, ...parents];
|
|
26
26
|
for (const node of children) {
|
|
27
|
-
|
|
27
|
+
enter(node, currParents);
|
|
28
28
|
if (isParent(node)) {
|
|
29
|
-
walkElements(node, code,
|
|
29
|
+
walkElements(node, code, enter, leave, currParents);
|
|
30
30
|
}
|
|
31
|
+
leave(node, currParents);
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
exports.walkElements = walkElements;
|
|
34
35
|
/** walk nodes */
|
|
35
|
-
function walk(parent, code, enter, leave
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
for (const node of children) {
|
|
39
|
-
enter(node, currParents);
|
|
36
|
+
function walk(parent, code, enter, leave) {
|
|
37
|
+
walkElements(parent, code, (node, parents) => {
|
|
38
|
+
enter(node, parents);
|
|
40
39
|
if (isTag(node)) {
|
|
41
|
-
const attrParents = [node, ...
|
|
40
|
+
const attrParents = [node, ...parents];
|
|
42
41
|
for (const attr of node.attributes) {
|
|
43
42
|
enter(attr, attrParents);
|
|
44
|
-
leave
|
|
43
|
+
leave(attr, attrParents);
|
|
45
44
|
}
|
|
46
45
|
}
|
|
47
|
-
|
|
48
|
-
walk(node, code, enter, leave, currParents);
|
|
49
|
-
}
|
|
50
|
-
leave === null || leave === void 0 ? void 0 : leave(node, currParents);
|
|
51
|
-
}
|
|
46
|
+
}, leave);
|
|
52
47
|
}
|
|
53
48
|
exports.walk = walk;
|
|
54
49
|
/**
|
|
55
50
|
* Get end offset of start tag
|
|
56
51
|
*/
|
|
57
|
-
function
|
|
52
|
+
function calcStartTagEndOffset(node, ctx) {
|
|
58
53
|
const lastAttr = node.attributes[node.attributes.length - 1];
|
|
59
54
|
let beforeCloseIndex;
|
|
60
55
|
if (lastAttr) {
|
|
61
|
-
beforeCloseIndex =
|
|
56
|
+
beforeCloseIndex = calcAttributeEndOffset(lastAttr, ctx);
|
|
62
57
|
}
|
|
63
58
|
else {
|
|
64
59
|
const info = getTokenInfo(ctx, [`<${node.name}`], node.position.start.offset);
|
|
@@ -67,94 +62,20 @@ function getStartTagEndOffset(node, ctx) {
|
|
|
67
62
|
const info = getTokenInfo(ctx, [[">", "/>"]], beforeCloseIndex);
|
|
68
63
|
return info.index + info.match.length;
|
|
69
64
|
}
|
|
70
|
-
exports.
|
|
71
|
-
/**
|
|
72
|
-
* Get end offset of tag
|
|
73
|
-
*/
|
|
74
|
-
function getTagEndOffset(node, parents, ctx) {
|
|
75
|
-
var _a;
|
|
76
|
-
if (((_a = node.position.end) === null || _a === void 0 ? void 0 : _a.offset) != null) {
|
|
77
|
-
return node.position.end.offset;
|
|
78
|
-
}
|
|
79
|
-
if (node.children.length) {
|
|
80
|
-
const code = ctx.code;
|
|
81
|
-
let nextElementIndex = code.length;
|
|
82
|
-
const parent = parents[0];
|
|
83
|
-
const childIndex = parent.children.indexOf(node);
|
|
84
|
-
if (childIndex === parent.children.length - 1) {
|
|
85
|
-
// last
|
|
86
|
-
if (isTag(parent)) {
|
|
87
|
-
nextElementIndex = getTagEndOffset(parent, parents.slice(1), ctx);
|
|
88
|
-
nextElementIndex = code.lastIndexOf("</", nextElementIndex);
|
|
89
|
-
}
|
|
90
|
-
else if (parent.type === "expression") {
|
|
91
|
-
nextElementIndex = getExpressionEndOffset(parent, parents.slice(1), ctx);
|
|
92
|
-
nextElementIndex = code.lastIndexOf("}", nextElementIndex);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
96
|
-
const next = parent.children[childIndex + 1];
|
|
97
|
-
nextElementIndex = next.position.start.offset;
|
|
98
|
-
}
|
|
99
|
-
return code.lastIndexOf(">", nextElementIndex);
|
|
100
|
-
}
|
|
101
|
-
let beforeIndex = getStartTagEndOffset(node, ctx);
|
|
102
|
-
beforeIndex = skipSpaces(ctx.code, beforeIndex);
|
|
103
|
-
if (ctx.code.startsWith(`</${node.name}`, beforeIndex)) {
|
|
104
|
-
beforeIndex = beforeIndex + 2 + node.name.length;
|
|
105
|
-
const info = getTokenInfo(ctx, [">"], beforeIndex);
|
|
106
|
-
return info.index + info.match.length;
|
|
107
|
-
}
|
|
108
|
-
return ctx.code.length;
|
|
109
|
-
}
|
|
110
|
-
exports.getTagEndOffset = getTagEndOffset;
|
|
111
|
-
/**
|
|
112
|
-
* Get end offset of Expression
|
|
113
|
-
*/
|
|
114
|
-
function getExpressionEndOffset(node, parents, ctx) {
|
|
115
|
-
var _a;
|
|
116
|
-
if (((_a = node.position.end) === null || _a === void 0 ? void 0 : _a.offset) != null) {
|
|
117
|
-
return node.position.end.offset;
|
|
118
|
-
}
|
|
119
|
-
if (node.children.length) {
|
|
120
|
-
const code = ctx.code;
|
|
121
|
-
let nextElementIndex = code.length;
|
|
122
|
-
const parent = parents[0];
|
|
123
|
-
const childIndex = parent.children.indexOf(node);
|
|
124
|
-
if (childIndex === parent.children.length - 1) {
|
|
125
|
-
// last
|
|
126
|
-
if (isTag(parent)) {
|
|
127
|
-
nextElementIndex = getTagEndOffset(parent, parents.slice(1), ctx);
|
|
128
|
-
nextElementIndex = code.lastIndexOf("</", nextElementIndex);
|
|
129
|
-
}
|
|
130
|
-
else if (parent.type === "expression") {
|
|
131
|
-
nextElementIndex = getExpressionEndOffset(parent, parents.slice(1), ctx);
|
|
132
|
-
nextElementIndex = code.lastIndexOf("}", nextElementIndex);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
else {
|
|
136
|
-
const next = parent.children[childIndex + 1];
|
|
137
|
-
nextElementIndex = next.position.start.offset;
|
|
138
|
-
}
|
|
139
|
-
return code.lastIndexOf("}", nextElementIndex);
|
|
140
|
-
}
|
|
141
|
-
const info = getTokenInfo(ctx, ["{", "}"], node.position.start.offset);
|
|
142
|
-
return info.index + info.match.length;
|
|
143
|
-
}
|
|
144
|
-
exports.getExpressionEndOffset = getExpressionEndOffset;
|
|
65
|
+
exports.calcStartTagEndOffset = calcStartTagEndOffset;
|
|
145
66
|
/**
|
|
146
67
|
* Get end offset of attribute
|
|
147
68
|
*/
|
|
148
|
-
function
|
|
69
|
+
function calcAttributeEndOffset(node, ctx) {
|
|
149
70
|
let info;
|
|
150
71
|
if (node.kind === "empty") {
|
|
151
72
|
info = getTokenInfo(ctx, [node.name], node.position.start.offset);
|
|
152
73
|
}
|
|
153
74
|
else if (node.kind === "quoted") {
|
|
154
|
-
info = getTokenInfo(ctx, [[`"${node.value}"`, `'${node.value}'`, node.value]],
|
|
75
|
+
info = getTokenInfo(ctx, [[`"${node.value}"`, `'${node.value}'`, node.value]], calcAttributeValueStartOffset(node, ctx));
|
|
155
76
|
}
|
|
156
77
|
else if (node.kind === "expression") {
|
|
157
|
-
info = getTokenInfo(ctx, ["{", node.value, "}"],
|
|
78
|
+
info = getTokenInfo(ctx, ["{", node.value, "}"], calcAttributeValueStartOffset(node, ctx));
|
|
158
79
|
}
|
|
159
80
|
else if (node.kind === "shorthand") {
|
|
160
81
|
info = getTokenInfo(ctx, ["{", node.name, "}"], node.position.start.offset);
|
|
@@ -163,18 +84,18 @@ function getAttributeEndOffset(node, ctx) {
|
|
|
163
84
|
info = getTokenInfo(ctx, ["{", "...", node.name, "}"], node.position.start.offset);
|
|
164
85
|
}
|
|
165
86
|
else if (node.kind === "template-literal") {
|
|
166
|
-
info = getTokenInfo(ctx, [`\`${node.value}\``],
|
|
87
|
+
info = getTokenInfo(ctx, [`\`${node.value}\``], calcAttributeValueStartOffset(node, ctx));
|
|
167
88
|
}
|
|
168
89
|
else {
|
|
169
90
|
throw new errors_1.ParseError(`Unknown attr kind: ${node.kind}`, node.position.start.offset, ctx);
|
|
170
91
|
}
|
|
171
92
|
return info.index + info.match.length;
|
|
172
93
|
}
|
|
173
|
-
exports.
|
|
94
|
+
exports.calcAttributeEndOffset = calcAttributeEndOffset;
|
|
174
95
|
/**
|
|
175
96
|
* Get start offset of attribute value
|
|
176
97
|
*/
|
|
177
|
-
function
|
|
98
|
+
function calcAttributeValueStartOffset(node, ctx) {
|
|
178
99
|
let info;
|
|
179
100
|
if (node.kind === "quoted") {
|
|
180
101
|
info = getTokenInfo(ctx, [node.name, "=", [`"`, `'`, node.value]], node.position.start.offset);
|
|
@@ -190,53 +111,157 @@ function getAttributeValueStartOffset(node, ctx) {
|
|
|
190
111
|
}
|
|
191
112
|
return info.index;
|
|
192
113
|
}
|
|
193
|
-
exports.
|
|
114
|
+
exports.calcAttributeValueStartOffset = calcAttributeValueStartOffset;
|
|
194
115
|
/**
|
|
195
|
-
* Get end offset of
|
|
116
|
+
* Get end offset of tag
|
|
196
117
|
*/
|
|
197
|
-
function
|
|
198
|
-
|
|
199
|
-
|
|
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}`);
|
|
200
145
|
}
|
|
201
|
-
exports.
|
|
146
|
+
exports.getEndOffset = getEndOffset;
|
|
202
147
|
/**
|
|
203
|
-
*
|
|
148
|
+
* Get content end offset
|
|
204
149
|
*/
|
|
205
|
-
function
|
|
206
|
-
const children = node.children.filter((c) => c.type !== "text" || c.value.trim());
|
|
207
|
-
if (children.length > 0) {
|
|
208
|
-
return null;
|
|
209
|
-
}
|
|
210
|
-
const parent = parents[0];
|
|
150
|
+
function calcContentEndOffset(parent, ctx) {
|
|
211
151
|
const code = ctx.code;
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
if (isTag(parent)) {
|
|
217
|
-
nextElementIndex = getTagEndOffset(parent, parents.slice(1), ctx);
|
|
218
|
-
nextElementIndex = code.lastIndexOf("</", nextElementIndex);
|
|
152
|
+
if (isTag(parent)) {
|
|
153
|
+
const end = getEndOffset(parent, ctx);
|
|
154
|
+
if (code[end - 1] !== ">") {
|
|
155
|
+
return end;
|
|
219
156
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
157
|
+
const index = code.lastIndexOf("</", end - 1);
|
|
158
|
+
if (index >= 0 &&
|
|
159
|
+
code.slice(index + 2, end - 1).trim() === parent.name) {
|
|
160
|
+
return index;
|
|
223
161
|
}
|
|
162
|
+
return end;
|
|
224
163
|
}
|
|
225
|
-
else {
|
|
226
|
-
const
|
|
227
|
-
|
|
164
|
+
else if (parent.type === "expression") {
|
|
165
|
+
const end = getEndOffset(parent, ctx);
|
|
166
|
+
return code.lastIndexOf("}", end);
|
|
167
|
+
}
|
|
168
|
+
else if (parent.type === "root") {
|
|
169
|
+
return code.length;
|
|
170
|
+
}
|
|
171
|
+
throw new Error(`unknown type: ${parent.type}`);
|
|
172
|
+
}
|
|
173
|
+
exports.calcContentEndOffset = calcContentEndOffset;
|
|
174
|
+
/**
|
|
175
|
+
* If the given tag is a self-close tag, get the self-closing tag.
|
|
176
|
+
*/
|
|
177
|
+
function getSelfClosingTag(node, ctx) {
|
|
178
|
+
if (node.children.length > 0) {
|
|
179
|
+
return null;
|
|
228
180
|
}
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
181
|
+
const code = ctx.code;
|
|
182
|
+
const startTagEndOffset = calcStartTagEndOffset(node, ctx);
|
|
183
|
+
if (code.startsWith("/>", startTagEndOffset - 2)) {
|
|
184
|
+
return {
|
|
185
|
+
offset: startTagEndOffset,
|
|
186
|
+
end: "/>",
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
if (code.startsWith(`</${node.name}`, startTagEndOffset)) {
|
|
232
190
|
return null;
|
|
233
191
|
}
|
|
234
192
|
return {
|
|
235
|
-
offset:
|
|
236
|
-
end:
|
|
193
|
+
offset: startTagEndOffset,
|
|
194
|
+
end: ">",
|
|
237
195
|
};
|
|
238
196
|
}
|
|
239
197
|
exports.getSelfClosingTag = getSelfClosingTag;
|
|
198
|
+
/**
|
|
199
|
+
* If the given tag has a end tag, get the end tag.
|
|
200
|
+
*/
|
|
201
|
+
function getEndTag(node, ctx) {
|
|
202
|
+
let beforeIndex;
|
|
203
|
+
if (node.children.length) {
|
|
204
|
+
const lastChild = node.children[node.children.length - 1];
|
|
205
|
+
beforeIndex = getEndOffset(lastChild, ctx);
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
beforeIndex = calcStartTagEndOffset(node, ctx);
|
|
209
|
+
}
|
|
210
|
+
beforeIndex = skipSpaces(ctx.code, beforeIndex);
|
|
211
|
+
if (ctx.code.startsWith(`</${node.name}`, beforeIndex)) {
|
|
212
|
+
const offset = beforeIndex;
|
|
213
|
+
beforeIndex = beforeIndex + 2 + node.name.length;
|
|
214
|
+
const info = getTokenInfo(ctx, [">"], beforeIndex);
|
|
215
|
+
const end = info.index + info.match.length;
|
|
216
|
+
return {
|
|
217
|
+
offset,
|
|
218
|
+
tag: ctx.code.slice(offset, end),
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
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;
|
|
232
|
+
/**
|
|
233
|
+
* Get end offset of tag
|
|
234
|
+
*/
|
|
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);
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
beforeIndex = calcStartTagEndOffset(node, ctx);
|
|
243
|
+
}
|
|
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;
|
|
249
|
+
}
|
|
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;
|
|
261
|
+
}
|
|
262
|
+
const info = getTokenInfo(ctx, ["{", "}"], node.position.start.offset);
|
|
263
|
+
return info.index + info.match.length;
|
|
264
|
+
}
|
|
240
265
|
/**
|
|
241
266
|
* Get token info
|
|
242
267
|
*/
|
package/lib/context/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export declare class Context {
|
|
|
9
9
|
readonly parserOptions: any;
|
|
10
10
|
readonly locs: LinesAndColumns;
|
|
11
11
|
private readonly locsMap;
|
|
12
|
-
private state;
|
|
12
|
+
private readonly state;
|
|
13
13
|
constructor(code: string, parserOptions: any);
|
|
14
14
|
getLocFromIndex(index: number): {
|
|
15
15
|
line: number;
|
|
@@ -29,6 +29,8 @@ export declare class Context {
|
|
|
29
29
|
getText(range: TSESTree.Range): string;
|
|
30
30
|
isTypeScript(): boolean;
|
|
31
31
|
remapCR({ ast, visitorKeys }: ESLintExtendedProgram): void;
|
|
32
|
+
get originalAST(): any;
|
|
33
|
+
set originalAST(originalAST: any);
|
|
32
34
|
}
|
|
33
35
|
export declare class LinesAndColumns {
|
|
34
36
|
readonly code: string;
|
package/lib/context/index.js
CHANGED
|
@@ -129,6 +129,12 @@ class Context {
|
|
|
129
129
|
comment.range = remapRange(comment.range);
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
|
+
get originalAST() {
|
|
133
|
+
return this.state.originalAST;
|
|
134
|
+
}
|
|
135
|
+
set originalAST(originalAST) {
|
|
136
|
+
this.state.originalAST = originalAST;
|
|
137
|
+
}
|
|
132
138
|
}
|
|
133
139
|
exports.Context = Context;
|
|
134
140
|
class LinesAndColumns {
|
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") {
|
|
@@ -52,12 +62,12 @@ class ScriptContext {
|
|
|
52
62
|
delete rootFragment.openingFragment;
|
|
53
63
|
rootFragment.type = "AstroRootFragment";
|
|
54
64
|
// remap locations
|
|
55
|
-
const traversed = new
|
|
65
|
+
const traversed = new Map();
|
|
56
66
|
(0, traverse_1.traverseNodes)(result.ast, {
|
|
57
67
|
visitorKeys: result.visitorKeys,
|
|
58
|
-
enterNode: (node) => {
|
|
68
|
+
enterNode: (node, p) => {
|
|
59
69
|
if (!traversed.has(node)) {
|
|
60
|
-
traversed.
|
|
70
|
+
traversed.set(node, p);
|
|
61
71
|
this.remapLocation(node);
|
|
62
72
|
}
|
|
63
73
|
},
|
|
@@ -77,9 +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
|
-
for (const node of traversed) {
|
|
82
|
-
|
|
92
|
+
for (const [node, parent] of traversed) {
|
|
93
|
+
if (!parent)
|
|
94
|
+
continue;
|
|
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
|
+
}
|
|
83
111
|
}
|
|
84
112
|
// Adjust program node location
|
|
85
113
|
const first = result.ast.body[0];
|
package/lib/errors.d.ts
CHANGED
package/lib/errors.js
CHANGED
|
@@ -31,7 +31,7 @@ const errors_1 = require("../../errors");
|
|
|
31
31
|
* Parse code by `@astrojs/compiler`
|
|
32
32
|
*/
|
|
33
33
|
function parse(code, ctx) {
|
|
34
|
-
const ast = parseByService(code).ast;
|
|
34
|
+
const ast = parseByService(code, ctx).ast;
|
|
35
35
|
const htmlElement = ast.children.find((n) => n.type === "element" && n.name === "html");
|
|
36
36
|
if (htmlElement) {
|
|
37
37
|
adjustHTML(ast, htmlElement, ctx);
|
|
@@ -43,10 +43,12 @@ exports.parse = parse;
|
|
|
43
43
|
/**
|
|
44
44
|
* Parse code by `@astrojs/compiler`
|
|
45
45
|
*/
|
|
46
|
-
function parseByService(code) {
|
|
46
|
+
function parseByService(code, ctx) {
|
|
47
47
|
const jsonAst = service.parse(code, { position: true }).ast;
|
|
48
|
+
ctx.originalAST = jsonAst;
|
|
48
49
|
try {
|
|
49
50
|
const ast = JSON.parse(jsonAst);
|
|
51
|
+
ctx.originalAST = ast;
|
|
50
52
|
return { ast };
|
|
51
53
|
}
|
|
52
54
|
catch (_a) {
|
|
@@ -61,6 +63,7 @@ function parseByService(code) {
|
|
|
61
63
|
return `\\${m}`;
|
|
62
64
|
}
|
|
63
65
|
}));
|
|
66
|
+
ctx.originalAST = ast;
|
|
64
67
|
return { ast };
|
|
65
68
|
}
|
|
66
69
|
}
|
|
@@ -137,16 +140,22 @@ function fixLocations(node, ctx) {
|
|
|
137
140
|
start += 1;
|
|
138
141
|
start += node.name.length;
|
|
139
142
|
if (!node.attributes.length) {
|
|
140
|
-
start = (0, astro_1.
|
|
143
|
+
start = (0, astro_1.calcStartTagEndOffset)(node, ctx);
|
|
141
144
|
}
|
|
142
145
|
}
|
|
143
146
|
else if (node.type === "attribute") {
|
|
144
147
|
fixLocationForAttr(node, ctx, start);
|
|
145
|
-
start = (0, astro_1.
|
|
148
|
+
start = (0, astro_1.calcAttributeEndOffset)(node, ctx);
|
|
149
|
+
if (node.position.end) {
|
|
150
|
+
node.position.end.offset = start;
|
|
151
|
+
}
|
|
146
152
|
}
|
|
147
153
|
else if (node.type === "comment") {
|
|
148
154
|
node.position.start.offset = tokenIndex(ctx, "<!--", start);
|
|
149
|
-
start = (0, astro_1.
|
|
155
|
+
start = (0, astro_1.calcCommentEndOffset)(node, ctx);
|
|
156
|
+
if (node.position.end) {
|
|
157
|
+
node.position.end.offset = start;
|
|
158
|
+
}
|
|
150
159
|
}
|
|
151
160
|
else if (node.type === "text") {
|
|
152
161
|
if (parent.type === "element" &&
|
|
@@ -190,6 +199,9 @@ function fixLocations(node, ctx) {
|
|
|
190
199
|
node.value = ctx.code.slice(node.position.start.offset, start);
|
|
191
200
|
}
|
|
192
201
|
}
|
|
202
|
+
if (node.position.end) {
|
|
203
|
+
node.position.end.offset = start;
|
|
204
|
+
}
|
|
193
205
|
}
|
|
194
206
|
else if (node.type === "expression") {
|
|
195
207
|
start = node.position.start.offset = tokenIndex(ctx, "{", start);
|
|
@@ -214,21 +226,22 @@ function fixLocations(node, ctx) {
|
|
|
214
226
|
if (node.type === "attribute") {
|
|
215
227
|
const attributes = parent.attributes;
|
|
216
228
|
if (attributes[attributes.length - 1] === node) {
|
|
217
|
-
start = (0, astro_1.
|
|
229
|
+
start = (0, astro_1.calcStartTagEndOffset)(parent, ctx);
|
|
218
230
|
}
|
|
219
|
-
return;
|
|
220
231
|
}
|
|
221
|
-
if (node.type === "expression") {
|
|
232
|
+
else if (node.type === "expression") {
|
|
222
233
|
start = tokenIndex(ctx, "}", start) + 1;
|
|
223
234
|
}
|
|
224
235
|
else if (node.type === "fragment" ||
|
|
225
236
|
node.type === "element" ||
|
|
226
237
|
node.type === "component" ||
|
|
227
238
|
node.type === "custom-element") {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
239
|
+
if (!(0, astro_1.getSelfClosingTag)(node, ctx)) {
|
|
240
|
+
const closeTagStart = tokenIndexSafe(ctx.code, `</${node.name}`, start);
|
|
241
|
+
if (closeTagStart != null) {
|
|
242
|
+
start = closeTagStart + 2 + node.name.length;
|
|
243
|
+
start = tokenIndex(ctx, ">", start) + 1;
|
|
244
|
+
}
|
|
232
245
|
}
|
|
233
246
|
}
|
|
234
247
|
else {
|
|
@@ -17,51 +17,24 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
17
17
|
script.appendScript("<>");
|
|
18
18
|
fragmentOpened = true;
|
|
19
19
|
}
|
|
20
|
+
(0, astro_1.walkElements)(resultTemplate.ast, ctx.code,
|
|
20
21
|
// eslint-disable-next-line complexity -- X(
|
|
21
|
-
(
|
|
22
|
-
const parent = parents[0];
|
|
23
|
-
if ((0, astro_1.isTag)(node) && parent.type === "expression") {
|
|
24
|
-
const index = parent.children.indexOf(node);
|
|
25
|
-
const before = parent.children[index - 1];
|
|
26
|
-
if (!before || !(0, astro_1.isTag)(before)) {
|
|
27
|
-
const after = parent.children[index + 1];
|
|
28
|
-
if (after && ((0, astro_1.isTag)(after) || after.type === "comment")) {
|
|
29
|
-
const start = node.position.start.offset;
|
|
30
|
-
script.appendOriginal(start);
|
|
31
|
-
script.appendScript("<>");
|
|
32
|
-
script.addRestoreNodeProcess((scriptNode) => {
|
|
33
|
-
if (scriptNode.range[0] === start &&
|
|
34
|
-
scriptNode.type === types_1.AST_NODE_TYPES.JSXFragment) {
|
|
35
|
-
delete scriptNode.openingFragment;
|
|
36
|
-
delete scriptNode.closingFragment;
|
|
37
|
-
const fragmentNode = scriptNode;
|
|
38
|
-
fragmentNode.type = "AstroFragment";
|
|
39
|
-
const last = fragmentNode.children[fragmentNode.children.length - 1];
|
|
40
|
-
if (fragmentNode.range[1] < last.range[1]) {
|
|
41
|
-
fragmentNode.range[1] = last.range[1];
|
|
42
|
-
fragmentNode.loc.end = ctx.getLocFromIndex(fragmentNode.range[1]);
|
|
43
|
-
}
|
|
44
|
-
return true;
|
|
45
|
-
}
|
|
46
|
-
return false;
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
22
|
+
(node, [parent]) => {
|
|
51
23
|
if (node.type === "frontmatter") {
|
|
52
24
|
const start = node.position.start.offset;
|
|
53
25
|
script.appendOriginal(start);
|
|
54
26
|
script.skipOriginalOffset(3);
|
|
55
|
-
const end = node
|
|
27
|
+
const end = (0, astro_1.getEndOffset)(node, ctx);
|
|
56
28
|
script.appendOriginal(end - 3);
|
|
57
29
|
script.appendScript(";<>");
|
|
58
30
|
fragmentOpened = true;
|
|
59
31
|
script.skipOriginalOffset(3);
|
|
60
|
-
script.addRestoreNodeProcess((_scriptNode, result) => {
|
|
32
|
+
script.addRestoreNodeProcess((_scriptNode, { result }) => {
|
|
61
33
|
for (let index = 0; index < result.ast.body.length; index++) {
|
|
62
34
|
const st = result.ast.body[index];
|
|
63
35
|
if (st.type === types_1.AST_NODE_TYPES.EmptyStatement) {
|
|
64
|
-
if (st.range[0] === end - 3 &&
|
|
36
|
+
if (st.range[0] === end - 3 &&
|
|
37
|
+
st.range[1] === end) {
|
|
65
38
|
result.ast.body.splice(index, 1);
|
|
66
39
|
break;
|
|
67
40
|
}
|
|
@@ -76,8 +49,42 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
76
49
|
script.addToken(types_1.AST_TOKEN_TYPES.Punctuator, [end - 3, end]);
|
|
77
50
|
}
|
|
78
51
|
else if ((0, astro_1.isTag)(node)) {
|
|
52
|
+
// Process for multiple tag
|
|
53
|
+
if (parent.type === "expression") {
|
|
54
|
+
const index = parent.children.indexOf(node);
|
|
55
|
+
const before = parent.children[index - 1];
|
|
56
|
+
if (!before || !(0, astro_1.isTag)(before)) {
|
|
57
|
+
const after = parent.children[index + 1];
|
|
58
|
+
if (after &&
|
|
59
|
+
((0, astro_1.isTag)(after) || after.type === "comment")) {
|
|
60
|
+
const start = node.position.start.offset;
|
|
61
|
+
script.appendOriginal(start);
|
|
62
|
+
script.appendScript("<>");
|
|
63
|
+
script.addRestoreNodeProcess((scriptNode) => {
|
|
64
|
+
if (scriptNode.range[0] === start &&
|
|
65
|
+
scriptNode.type ===
|
|
66
|
+
types_1.AST_NODE_TYPES.JSXFragment) {
|
|
67
|
+
delete scriptNode.openingFragment;
|
|
68
|
+
delete scriptNode.closingFragment;
|
|
69
|
+
const fragmentNode = scriptNode;
|
|
70
|
+
fragmentNode.type = "AstroFragment";
|
|
71
|
+
const last = fragmentNode.children[fragmentNode.children.length - 1];
|
|
72
|
+
if (fragmentNode.range[1] < last.range[1]) {
|
|
73
|
+
fragmentNode.range[1] = last.range[1];
|
|
74
|
+
fragmentNode.loc.end =
|
|
75
|
+
ctx.getLocFromIndex(fragmentNode.range[1]);
|
|
76
|
+
}
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
return false;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Process for attributes
|
|
79
85
|
for (const attr of node.attributes) {
|
|
80
|
-
if ((node.type === "component" ||
|
|
86
|
+
if ((node.type === "component" ||
|
|
87
|
+
node.type === "fragment") &&
|
|
81
88
|
(attr.kind === "quoted" ||
|
|
82
89
|
attr.kind === "empty" ||
|
|
83
90
|
attr.kind === "expression" ||
|
|
@@ -100,27 +107,22 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
100
107
|
start + colonIndex + 1,
|
|
101
108
|
start + attr.name.length,
|
|
102
109
|
]);
|
|
103
|
-
script.addRestoreNodeProcess((scriptNode,
|
|
110
|
+
script.addRestoreNodeProcess((scriptNode, context) => {
|
|
104
111
|
if (scriptNode.type ===
|
|
105
112
|
types_1.AST_NODE_TYPES.JSXAttribute &&
|
|
106
113
|
scriptNode.range[0] === start) {
|
|
107
114
|
const baseNameNode = scriptNode.name;
|
|
108
|
-
const nsn = Object.assign(Object.assign({}, baseNameNode), { type: types_1.AST_NODE_TYPES.JSXNamespacedName, namespace: Object.assign({ type: types_1.AST_NODE_TYPES.JSXIdentifier, name: attr.name.slice(0, colonIndex) }, ctx.getLocations(baseNameNode.range[0], baseNameNode.range[0] +
|
|
115
|
+
const nsn = Object.assign(Object.assign({}, baseNameNode), { type: types_1.AST_NODE_TYPES.JSXNamespacedName, namespace: Object.assign({ type: types_1.AST_NODE_TYPES.JSXIdentifier, name: attr.name.slice(0, colonIndex) }, ctx.getLocations(baseNameNode.range[0], baseNameNode.range[0] +
|
|
116
|
+
colonIndex)), name: Object.assign({ type: types_1.AST_NODE_TYPES.JSXIdentifier, name: attr.name.slice(colonIndex + 1) }, ctx.getLocations(baseNameNode.range[0] +
|
|
109
117
|
colonIndex +
|
|
110
118
|
1, baseNameNode.range[1])) });
|
|
111
119
|
scriptNode.name = nsn;
|
|
112
120
|
nsn.namespace.parent = nsn;
|
|
113
121
|
nsn.name.parent = nsn;
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
baseNameNode.range[0] &&
|
|
119
|
-
token.range[1] === baseNameNode.range[1]) {
|
|
120
|
-
tokens.splice(index, 1);
|
|
121
|
-
break;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
122
|
+
context.addRemoveToken((token) => token.range[0] ===
|
|
123
|
+
baseNameNode.range[0] &&
|
|
124
|
+
token.range[1] ===
|
|
125
|
+
baseNameNode.range[1]);
|
|
124
126
|
return true;
|
|
125
127
|
}
|
|
126
128
|
return false;
|
|
@@ -135,7 +137,8 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
135
137
|
: attr.name;
|
|
136
138
|
script.appendScript(`${jsxName}=`);
|
|
137
139
|
script.addRestoreNodeProcess((scriptNode) => {
|
|
138
|
-
if (scriptNode.type ===
|
|
140
|
+
if (scriptNode.type ===
|
|
141
|
+
types_1.AST_NODE_TYPES.JSXAttribute &&
|
|
139
142
|
scriptNode.range[0] === start) {
|
|
140
143
|
const attrNode = scriptNode;
|
|
141
144
|
attrNode.type = "AstroShorthandAttribute";
|
|
@@ -152,14 +155,15 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
152
155
|
}
|
|
153
156
|
else if (attr.kind === "template-literal") {
|
|
154
157
|
const attrStart = attr.position.start.offset;
|
|
155
|
-
const start = (0, astro_1.
|
|
156
|
-
const end = (0, astro_1.
|
|
158
|
+
const start = (0, astro_1.calcAttributeValueStartOffset)(attr, ctx);
|
|
159
|
+
const end = (0, astro_1.calcAttributeEndOffset)(attr, ctx);
|
|
157
160
|
script.appendOriginal(start);
|
|
158
161
|
script.appendScript("{");
|
|
159
162
|
script.appendOriginal(end);
|
|
160
163
|
script.appendScript("}");
|
|
161
164
|
script.addRestoreNodeProcess((scriptNode) => {
|
|
162
|
-
if (scriptNode.type ===
|
|
165
|
+
if (scriptNode.type ===
|
|
166
|
+
types_1.AST_NODE_TYPES.JSXAttribute &&
|
|
163
167
|
scriptNode.range[0] === attrStart) {
|
|
164
168
|
const attrNode = scriptNode;
|
|
165
169
|
attrNode.type = "AstroTemplateLiteralAttribute";
|
|
@@ -169,11 +173,13 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
169
173
|
});
|
|
170
174
|
}
|
|
171
175
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
176
|
+
// Process for start tag close
|
|
177
|
+
const closing = (0, astro_1.getSelfClosingTag)(node, ctx);
|
|
178
|
+
if (closing && closing.end === ">") {
|
|
179
|
+
script.appendOriginal(closing.offset - 1);
|
|
175
180
|
script.appendScript("/");
|
|
176
181
|
}
|
|
182
|
+
// Process for raw text
|
|
177
183
|
if (node.name === "script" || node.name === "style") {
|
|
178
184
|
const text = node.children[0];
|
|
179
185
|
if (text && text.type === "text") {
|
|
@@ -201,7 +207,8 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
201
207
|
}
|
|
202
208
|
else if (node.type === "comment") {
|
|
203
209
|
const start = node.position.start.offset;
|
|
204
|
-
const
|
|
210
|
+
const end = (0, astro_1.getEndOffset)(node, ctx);
|
|
211
|
+
const length = end - start;
|
|
205
212
|
script.appendOriginal(start);
|
|
206
213
|
let targetType;
|
|
207
214
|
if (fragmentOpened) {
|
|
@@ -215,7 +222,7 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
215
222
|
targetType = types_1.AST_NODE_TYPES.ExpressionStatement;
|
|
216
223
|
script.skipOriginalOffset(length);
|
|
217
224
|
}
|
|
218
|
-
script.addRestoreNodeProcess((scriptNode,
|
|
225
|
+
script.addRestoreNodeProcess((scriptNode, context) => {
|
|
219
226
|
if (scriptNode.range[0] === start &&
|
|
220
227
|
scriptNode.type === targetType) {
|
|
221
228
|
delete scriptNode.children;
|
|
@@ -225,26 +232,11 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
225
232
|
const commentNode = scriptNode;
|
|
226
233
|
commentNode.type = "AstroHTMLComment";
|
|
227
234
|
commentNode.value = node.value;
|
|
228
|
-
if (
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
token.range[1] === scriptNode.range[1],
|
|
234
|
-
]);
|
|
235
|
-
const tokens = result.ast.tokens || [];
|
|
236
|
-
for (let index = tokens.length - 1; index >= 0; index--) {
|
|
237
|
-
const token = tokens[index];
|
|
238
|
-
for (const rt of removeTokenSet) {
|
|
239
|
-
if (rt(token)) {
|
|
240
|
-
tokens.splice(index, 1);
|
|
241
|
-
removeTokenSet.delete(rt);
|
|
242
|
-
if (!removeTokenSet.size) {
|
|
243
|
-
break;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
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]);
|
|
248
240
|
}
|
|
249
241
|
return true;
|
|
250
242
|
}
|
|
@@ -257,19 +249,22 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
257
249
|
}
|
|
258
250
|
else if (node.type === "doctype") {
|
|
259
251
|
const start = node.position.start.offset;
|
|
260
|
-
const end = node
|
|
252
|
+
const end = (0, astro_1.getEndOffset)(node, ctx);
|
|
253
|
+
const length = end - start;
|
|
261
254
|
script.appendOriginal(start);
|
|
262
255
|
let targetType;
|
|
263
256
|
if (fragmentOpened) {
|
|
264
|
-
script.
|
|
257
|
+
script.appendOriginal(start + 1);
|
|
258
|
+
script.appendScript(`></`);
|
|
259
|
+
script.skipOriginalOffset(length - 2);
|
|
265
260
|
targetType = types_1.AST_NODE_TYPES.JSXFragment;
|
|
266
261
|
}
|
|
267
262
|
else {
|
|
268
263
|
script.appendScript(`0;`);
|
|
269
264
|
targetType = types_1.AST_NODE_TYPES.ExpressionStatement;
|
|
265
|
+
script.skipOriginalOffset(length);
|
|
270
266
|
}
|
|
271
|
-
script.
|
|
272
|
-
script.addRestoreNodeProcess((scriptNode) => {
|
|
267
|
+
script.addRestoreNodeProcess((scriptNode, context) => {
|
|
273
268
|
if (scriptNode.range[0] === start &&
|
|
274
269
|
scriptNode.type === targetType) {
|
|
275
270
|
delete scriptNode.children;
|
|
@@ -278,22 +273,50 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
278
273
|
delete scriptNode.expression;
|
|
279
274
|
const doctypeNode = scriptNode;
|
|
280
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
|
+
}
|
|
281
282
|
return true;
|
|
282
283
|
}
|
|
283
284
|
return false;
|
|
284
285
|
});
|
|
285
286
|
script.addToken("HTMLDocType", [start, end]);
|
|
286
287
|
}
|
|
288
|
+
}, (node, [parent]) => {
|
|
289
|
+
if ((0, astro_1.isTag)(node)) {
|
|
290
|
+
const closing = (0, astro_1.getSelfClosingTag)(node, ctx);
|
|
291
|
+
if (!closing) {
|
|
292
|
+
const end = (0, astro_1.getEndTag)(node, ctx);
|
|
293
|
+
if (!end) {
|
|
294
|
+
const offset = (0, astro_1.calcContentEndOffset)(node, ctx);
|
|
295
|
+
script.appendOriginal(offset);
|
|
296
|
+
script.appendScript(`</${node.name}>`);
|
|
297
|
+
script.addRestoreNodeProcess((scriptNode, _result, parent) => {
|
|
298
|
+
if (scriptNode.range[0] === offset &&
|
|
299
|
+
scriptNode.type ===
|
|
300
|
+
types_1.AST_NODE_TYPES.JSXClosingElement &&
|
|
301
|
+
parent.type === types_1.AST_NODE_TYPES.JSXElement) {
|
|
302
|
+
parent.closingElement = null;
|
|
303
|
+
return true;
|
|
304
|
+
}
|
|
305
|
+
return false;
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
// Process for multiple tag
|
|
287
311
|
if (((0, astro_1.isTag)(node) || node.type === "comment") &&
|
|
288
312
|
parent.type === "expression") {
|
|
289
313
|
const index = parent.children.indexOf(node);
|
|
290
314
|
const after = parent.children[index + 1];
|
|
291
315
|
if (!after || (!(0, astro_1.isTag)(after) && after.type !== "comment")) {
|
|
292
316
|
const before = parent.children[index - 1];
|
|
293
|
-
if (before &&
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
: (0, astro_1.getCommentEndOffset)(node, ctx);
|
|
317
|
+
if (before &&
|
|
318
|
+
((0, astro_1.isTag)(before) || before.type === "comment")) {
|
|
319
|
+
const end = (0, astro_1.getEndOffset)(node, ctx);
|
|
297
320
|
script.appendOriginal(end);
|
|
298
321
|
script.appendScript("</>");
|
|
299
322
|
}
|
package/lib/parser/script.js
CHANGED
|
@@ -30,7 +30,9 @@ function parseScript(code, ctx) {
|
|
|
30
30
|
return { ast: result };
|
|
31
31
|
}
|
|
32
32
|
catch (e) {
|
|
33
|
-
(0, debug_1.debug)("[script] parsing error:", e.message, `@ ${JSON.stringify(code)}
|
|
33
|
+
(0, debug_1.debug)("[script] parsing error:", e.message, `@ ${JSON.stringify(code)}
|
|
34
|
+
|
|
35
|
+
${code}`);
|
|
34
36
|
throw e;
|
|
35
37
|
}
|
|
36
38
|
finally {
|
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": [
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"cover": "nyc --reporter=lcov npm run test",
|
|
20
20
|
"debug": "mocha --require ts-node/register/transpile-only \"tests/src/**/*.ts\" --reporter dot --timeout 60000",
|
|
21
21
|
"preversion": "npm run lint && npm test",
|
|
22
|
-
"update-fixtures": "ts-node --transpile-only ./tools/update-fixtures.ts",
|
|
22
|
+
"update-fixtures": "DEBUG='astro-eslint-parser' ts-node --transpile-only ./tools/update-fixtures.ts",
|
|
23
23
|
"debug-parser": "ts-node --transpile-only ./tools/parser-test.ts",
|
|
24
24
|
"eslint-playground": "eslint tests/fixtures --ext .astro --config .eslintrc-for-playground.js --format codeframe",
|
|
25
25
|
"benchmark": "ts-node --transpile-only benchmark/index.ts"
|
|
@@ -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",
|