astro-eslint-parser 0.0.14 → 0.0.17

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 CHANGED
@@ -1,8 +1,10 @@
1
1
  # astro-eslint-parser
2
2
 
3
- [Astro] parser for [ESLint].
3
+ [Astro] component parser for [ESLint].
4
4
  You can check it on [Online DEMO](https://ota-meshi.github.io/astro-eslint-parser/playground).
5
5
 
6
+ [![sponsors](https://img.shields.io/badge/-Sponsor-fafbfc?logo=GitHub%20Sponsors)](https://github.com/sponsors/ota-meshi)
7
+
6
8
  [![NPM license](https://img.shields.io/npm/l/astro-eslint-parser.svg)](https://www.npmjs.com/package/astro-eslint-parser)
7
9
  [![NPM version](https://img.shields.io/npm/v/astro-eslint-parser.svg)](https://www.npmjs.com/package/astro-eslint-parser)
8
10
  [![NPM downloads](https://img.shields.io/badge/dynamic/json.svg?label=downloads&colorB=green&suffix=/day&query=$.downloads&uri=https://api.npmjs.org//downloads/point/last-day/astro-eslint-parser&maxAge=3600)](http://www.npmtrends.com/astro-eslint-parser)
@@ -15,6 +17,8 @@ You can check it on [Online DEMO](https://ota-meshi.github.io/astro-eslint-parse
15
17
 
16
18
  This parser is in the ***experimental stages*** of development.
17
19
 
20
+ At least it works fine with a [fork of the `astro.build` repository](https://github.com/ota-meshi/astro.build/tree/eslint).
21
+
18
22
  ⚠ Currently this parser relies heavily on the internal API of [@astrojs/compiler]. It may stop working in a future update of [@astrojs/compiler]. ⚠
19
23
 
20
24
  [@astrojs/compiler]: https://github.com/withastro/compiler
@@ -37,25 +41,28 @@ npm install --save-dev eslint astro-eslint-parser
37
41
  ## 📖 Usage
38
42
 
39
43
  1. Write `overrides.parser` option into your `.eslintrc.*` file.
40
- 2. Use glob patterns or `--ext .astro` CLI option.
41
44
 
42
- ```json
43
- {
44
- "extends": "eslint:recommended",
45
- "overrides": [
46
- {
47
- "files": ["*.astro"],
48
- "parser": "astro-eslint-parser"
49
- }
50
- ]
51
- }
52
- ```
45
+ ```json
46
+ {
47
+ "extends": "eslint:recommended",
48
+ "overrides": [
49
+ {
50
+ "files": ["*.astro"],
51
+ "parser": "astro-eslint-parser"
52
+ }
53
+ ]
54
+ }
55
+ ```
53
56
 
54
- ```console
55
- $ eslint "src/**/*.{js,astro}"
56
- # or
57
- $ eslint src --ext .astro
58
- ```
57
+ 2. If you have specified the extension in the CLI, add `.astro` as well.
58
+
59
+ ```console
60
+ $ eslint "src/**/*.{js,astro}"
61
+ # or
62
+ $ eslint src --ext .js,.astro
63
+ ```
64
+
65
+ 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
66
 
60
67
  ## 🔧 Options
61
68
 
@@ -138,17 +145,16 @@ Example **.vscode/settings.json**:
138
145
  }
139
146
  ```
140
147
 
141
- ## Compatibility With Existing ESLint Rules
148
+ ## :two_hearts: Compatibility With Existing ESLint Rules
142
149
 
143
150
  Most of the rules in the ESLint core work for the script part, but some rules are incompatible.
144
151
  This parser will generate a JSX compatible AST for most of the HTML part of the Astro component. Therefore, some rules of [eslint-plugin-react] may work.
145
152
  For example, the [react/jsx-no-target-blank] rule works fine.
146
153
 
147
- [semi]: https://eslint.org/docs/rules/semi
148
154
  [eslint-plugin-react]: https://github.com/jsx-eslint/eslint-plugin-react/
149
155
  [react/jsx-no-target-blank]: https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-target-blank.md
150
156
 
151
- ## Usage for Custom Rules / Plugins
157
+ ## :hammer: Usage for Custom Rules / Plugins
152
158
 
153
159
  - TBA
154
160
  - You can check the AST in the [Online DEMO](https://ota-meshi.github.io/astro-eslint-parser/). However, AST is subject to major changes in the future.
@@ -162,6 +168,12 @@ Welcome contributing!
162
168
 
163
169
  Please use GitHub's Issues/PRs.
164
170
 
171
+ ## :heart: Supporting
172
+
173
+ If you are willing to see that this package continues to be maintained, please consider sponsoring me.
174
+
175
+ [![sponsors](https://img.shields.io/badge/-Sponsor-fafbfc?logo=GitHub%20Sponsors)](https://github.com/sponsors/ota-meshi)
176
+
165
177
  ## :lock: License
166
178
 
167
179
  See the [LICENSE](LICENSE) file for license rights and limitations (MIT).
package/lib/ast.d.ts CHANGED
@@ -1,30 +1,31 @@
1
1
  import type { TSESTree } from "@typescript-eslint/types";
2
- export declare type AstroNode = AstroProgram | AstroRootFragment | AstroHTMLComment | AstroDoctype | AstroShorthandAttribute | AstroTemplateLiteralAttribute | AstroRawText | AstroFragment;
2
+ export declare type AstroNode = AstroProgram | AstroFragment | AstroHTMLComment | AstroDoctype | AstroShorthandAttribute | AstroTemplateLiteralAttribute | AstroRawText;
3
+ export declare type AstroChild = TSESTree.JSXFragment["children"][number] | AstroHTMLComment;
3
4
  /** Node of Astro program root */
4
5
  export interface AstroProgram extends Omit<TSESTree.Program, "type" | "body"> {
5
6
  type: "Program";
6
- body: (TSESTree.Program["body"][number] | AstroRootFragment | AstroHTMLComment)[];
7
+ body: (TSESTree.Program["body"][number] | AstroFragment)[];
7
8
  sourceType: "script" | "module";
8
9
  comments: TSESTree.Comment[];
9
10
  tokens: TSESTree.Token[];
10
11
  parent: undefined;
11
12
  }
12
- /** Node of Astro fragment root */
13
- export interface AstroRootFragment extends Omit<TSESTree.BaseNode, "type" | "parent"> {
14
- type: "AstroRootFragment";
15
- children: TSESTree.JSXFragment["children"];
16
- parent: AstroProgram;
13
+ /** Node of Astro fragment */
14
+ export interface AstroFragment extends Omit<TSESTree.BaseNode, "type" | "parent"> {
15
+ type: "AstroFragment";
16
+ children: AstroChild[];
17
+ parent: TSESTree.JSXFragment["parent"];
17
18
  }
18
19
  /** Node of Astro html comment */
19
20
  export interface AstroHTMLComment extends Omit<TSESTree.BaseNode, "type" | "parent"> {
20
21
  type: "AstroHTMLComment";
21
22
  value: string;
22
- parent: AstroRootFragment | TSESTree.JSXElement | TSESTree.JSXFragment;
23
+ parent: AstroFragment | AstroFragment | TSESTree.JSXElement | TSESTree.JSXFragment;
23
24
  }
24
25
  /** Node of Astro doctype */
25
26
  export interface AstroDoctype extends Omit<TSESTree.BaseNode, "type" | "parent"> {
26
27
  type: "AstroDoctype";
27
- parent: AstroRootFragment;
28
+ parent: AstroFragment | AstroFragment;
28
29
  }
29
30
  /** Node of Astro shorthand attribute */
30
31
  export interface AstroShorthandAttribute extends Omit<TSESTree.JSXAttribute, "type" | "parent"> {
@@ -43,11 +44,5 @@ export interface AstroTemplateLiteralAttribute extends Omit<TSESTree.JSXAttribut
43
44
  /** Node of Astro raw text */
44
45
  export interface AstroRawText extends Omit<TSESTree.JSXText, "type" | "parent"> {
45
46
  type: "AstroRawText";
46
- parent: AstroRootFragment | TSESTree.JSXElement | TSESTree.JSXFragment;
47
- }
48
- /** Node of Astro fragment expression */
49
- export interface AstroFragment extends Omit<TSESTree.BaseNode, "type" | "parent"> {
50
- type: "AstroFragment";
51
- children: TSESTree.JSXFragment["children"];
52
- parent: TSESTree.JSXFragment["parent"];
47
+ parent: AstroFragment | TSESTree.JSXElement | TSESTree.JSXFragment;
53
48
  }
@@ -1,4 +1,4 @@
1
- import type { AttributeNode, CommentNode, ExpressionNode, Node, ParentNode, TagLikeNode } from "@astrojs/compiler/types";
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,45 +15,41 @@ 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 getStartTagEndOffset(node: TagLikeNode, ctx: Context): number;
19
- /**
20
- * Get end offset of tag
21
- */
22
- export declare function getTagEndOffset(node: TagLikeNode, parents: ParentNode[], ctx: Context): number;
23
- /**
24
- * Get end offset of Expression
25
- */
26
- export declare function getExpressionEndOffset(node: ExpressionNode, parents: ParentNode[], 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 getAttributeEndOffset(node: AttributeNode, ctx: Context): number;
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 getAttributeValueStartOffset(node: AttributeNode, ctx: Context): number;
26
+ export declare function calcAttributeValueStartOffset(node: AttributeNode, ctx: Context): number;
35
27
  /**
36
- * Get end offset of comment
28
+ * Get end offset of tag
37
29
  */
38
- export declare function getCommentEndOffset(node: CommentNode, ctx: Context): number;
30
+ export declare function getEndOffset(node: Node, ctx: Context): number;
39
31
  /**
40
32
  * Get content end offset
41
33
  */
42
- export declare function getContentEndOffset(parent: ParentNode, parents: ParentNode[], ctx: Context): number;
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, parents: ParentNode[], ctx: Context): null | {
38
+ export declare function getSelfClosingTag(node: TagLikeNode, ctx: Context): null | {
47
39
  offset: number;
48
40
  end: "/>" | ">";
49
41
  };
50
42
  /**
51
43
  * If the given tag has a end tag, get the end tag.
52
44
  */
53
- export declare function getEndTag(node: TagLikeNode, parents: ParentNode[], ctx: Context): null | {
45
+ 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
  */
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.skipSpaces = exports.getEndTag = exports.getSelfClosingTag = exports.getContentEndOffset = exports.getCommentEndOffset = exports.getAttributeValueStartOffset = exports.getAttributeEndOffset = exports.getExpressionEndOffset = exports.getTagEndOffset = exports.getStartTagEndOffset = exports.walk = exports.walkElements = exports.isParent = exports.isTag = void 0;
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 getStartTagEndOffset(node, ctx) {
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 = getAttributeEndOffset(lastAttr, ctx);
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.getStartTagEndOffset = getStartTagEndOffset;
66
- /**
67
- * Get end offset of tag
68
- */
69
- function getTagEndOffset(node, parents, 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, [node, ...parents], 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, parents, 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, [node, ...parents], 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 getAttributeEndOffset(node, ctx) {
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]], getAttributeValueStartOffset(node, ctx));
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, "}"], getAttributeValueStartOffset(node, ctx));
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}\``], getAttributeValueStartOffset(node, ctx));
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.getAttributeEndOffset = getAttributeEndOffset;
94
+ exports.calcAttributeEndOffset = calcAttributeEndOffset;
138
95
  /**
139
96
  * Get start offset of attribute value
140
97
  */
141
- function getAttributeValueStartOffset(node, ctx) {
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,33 +111,58 @@ function getAttributeValueStartOffset(node, ctx) {
154
111
  }
155
112
  return info.index;
156
113
  }
157
- exports.getAttributeValueStartOffset = getAttributeValueStartOffset;
114
+ exports.calcAttributeValueStartOffset = calcAttributeValueStartOffset;
158
115
  /**
159
- * Get end offset of comment
116
+ * Get end offset of tag
160
117
  */
161
- function getCommentEndOffset(node, ctx) {
162
- const info = getTokenInfo(ctx, ["<!--", node.value, "-->"], node.position.start.offset);
163
- return info.index + info.match.length;
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.getCommentEndOffset = getCommentEndOffset;
146
+ exports.getEndOffset = getEndOffset;
166
147
  /**
167
148
  * Get content end offset
168
149
  */
169
- function getContentEndOffset(parent, parents, ctx) {
150
+ function calcContentEndOffset(parent, ctx) {
170
151
  const code = ctx.code;
171
152
  if (isTag(parent)) {
172
- const end = getTagEndOffset(parent, parents, ctx);
153
+ const end = getEndOffset(parent, ctx);
173
154
  if (code[end - 1] !== ">") {
174
155
  return end;
175
156
  }
176
- const index = code.lastIndexOf("</", end);
177
- if (index >= 0 && code.slice(index, end).trim() === parent.name) {
157
+ const index = code.lastIndexOf("</", end - 1);
158
+ if (index >= 0 &&
159
+ code.slice(index + 2, end - 1).trim() === parent.name) {
178
160
  return index;
179
161
  }
180
162
  return end;
181
163
  }
182
164
  else if (parent.type === "expression") {
183
- const end = getExpressionEndOffset(parent, parents, ctx);
165
+ const end = getEndOffset(parent, ctx);
184
166
  return code.lastIndexOf("}", end);
185
167
  }
186
168
  else if (parent.type === "root") {
@@ -188,49 +170,42 @@ function getContentEndOffset(parent, parents, ctx) {
188
170
  }
189
171
  throw new Error(`unknown type: ${parent.type}`);
190
172
  }
191
- exports.getContentEndOffset = getContentEndOffset;
173
+ exports.calcContentEndOffset = calcContentEndOffset;
192
174
  /**
193
175
  * If the given tag is a self-close tag, get the self-closing tag.
194
176
  */
195
- function getSelfClosingTag(node, parents, ctx) {
196
- const children = node.children.filter((c) => c.type !== "text" || c.value.trim());
197
- if (children.length > 0) {
177
+ function getSelfClosingTag(node, ctx) {
178
+ if (node.children.length > 0) {
198
179
  return null;
199
180
  }
200
- const parent = parents[0];
201
181
  const code = ctx.code;
202
- let nextElementIndex = code.length;
203
- const childIndex = parent.children.indexOf(node);
204
- if (childIndex === parent.children.length - 1) {
205
- // last
206
- nextElementIndex = getContentEndOffset(parent, parents.slice(1), ctx);
207
- }
208
- else {
209
- const next = parent.children[childIndex + 1];
210
- 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
+ };
211
188
  }
212
- const endOffset = getStartTagEndOffset(node, ctx);
213
- if (code.slice(endOffset, nextElementIndex).trim()) {
214
- // has end tag
189
+ if (code.startsWith(`</${node.name}`, startTagEndOffset)) {
215
190
  return null;
216
191
  }
217
192
  return {
218
- offset: endOffset,
219
- end: code.slice(endOffset - 2, endOffset) === "/>" ? "/>" : ">",
193
+ offset: startTagEndOffset,
194
+ end: ">",
220
195
  };
221
196
  }
222
197
  exports.getSelfClosingTag = getSelfClosingTag;
223
198
  /**
224
199
  * If the given tag has a end tag, get the end tag.
225
200
  */
226
- function getEndTag(node, parents, ctx) {
201
+ function getEndTag(node, ctx) {
227
202
  let beforeIndex;
228
203
  if (node.children.length) {
229
204
  const lastChild = node.children[node.children.length - 1];
230
- beforeIndex = getEndOffset(lastChild, [node, ...parents], ctx);
205
+ beforeIndex = getEndOffset(lastChild, ctx);
231
206
  }
232
207
  else {
233
- beforeIndex = getStartTagEndOffset(node, ctx);
208
+ beforeIndex = calcStartTagEndOffset(node, ctx);
234
209
  }
235
210
  beforeIndex = skipSpaces(ctx.code, beforeIndex);
236
211
  if (ctx.code.startsWith(`</${node.name}`, beforeIndex)) {
@@ -246,36 +221,46 @@ function getEndTag(node, parents, ctx) {
246
221
  return null;
247
222
  }
248
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;
249
232
  /**
250
233
  * Get end offset of tag
251
234
  */
252
- function getEndOffset(node, parents, ctx) {
253
- var _a;
254
- if (((_a = node.position.end) === null || _a === void 0 ? void 0 : _a.offset) != null) {
255
- return node.position.end.offset;
256
- }
257
- if (isTag(node))
258
- return getTagEndOffset(node, parents, ctx);
259
- if (node.type === "expression")
260
- return getExpressionEndOffset(node, parents, ctx);
261
- if (node.type === "comment")
262
- return getCommentEndOffset(node, ctx);
263
- if (node.type === "frontmatter") {
264
- const start = node.position.start.offset;
265
- 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);
266
240
  }
267
- if (node.type === "doctype") {
268
- const start = node.position.start.offset;
269
- return ctx.code.indexOf(">", start) + 1;
241
+ else {
242
+ beforeIndex = calcStartTagEndOffset(node, ctx);
270
243
  }
271
- if (node.type === "text") {
272
- const start = node.position.start.offset;
273
- return start + node.value.length;
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;
274
249
  }
275
- if (node.type === "root") {
276
- return ctx.code.length;
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;
277
261
  }
278
- throw new Error(`unknown type: ${node.type}`);
262
+ const info = getTokenInfo(ctx, ["{", "}"], node.position.start.offset);
263
+ return info.index + info.match.length;
279
264
  }
280
265
  /**
281
266
  * Get token info
@@ -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, result: ESLintExtendedProgram, parent: TSESTree.Node) => boolean): void;
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 {};
@@ -2,7 +2,15 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ScriptContext = void 0;
4
4
  const traverse_1 = require("../traverse");
5
- const errors_1 = require("../errors");
5
+ class RestoreNodeProcessContext {
6
+ constructor(result) {
7
+ this.removeTokens = new Set();
8
+ this.result = result;
9
+ }
10
+ addRemoveToken(test) {
11
+ this.removeTokens.add(test);
12
+ }
13
+ }
6
14
  class ScriptContext {
7
15
  constructor(ctx) {
8
16
  this.script = "";
@@ -17,6 +25,9 @@ class ScriptContext {
17
25
  this.consumedIndex += offset;
18
26
  }
19
27
  appendOriginal(index) {
28
+ if (this.consumedIndex >= index) {
29
+ return;
30
+ }
20
31
  this.offsets.push({
21
32
  original: this.consumedIndex,
22
33
  script: this.script.length,
@@ -39,18 +50,7 @@ class ScriptContext {
39
50
  * Restore AST nodes
40
51
  */
41
52
  restore(result) {
42
- const last = result.ast.body[result.ast.body.length - 1];
43
- if (last.type !== "ExpressionStatement") {
44
- throw new errors_1.ParseError("Unknown state error: Expected ExpressionStatement", last.range[0], this.ctx);
45
- }
46
- if (last.expression.type !== "JSXFragment") {
47
- throw new errors_1.ParseError("Unknown state error: Expected JSXFragment", last.expression.range[0], this.ctx);
48
- }
49
- // Process for Astro
50
- const rootFragment = (result.ast.body[result.ast.body.length - 1] = last.expression);
51
- delete rootFragment.closingFragment;
52
- delete rootFragment.openingFragment;
53
- rootFragment.type = "AstroRootFragment";
53
+ var _a, _b;
54
54
  // remap locations
55
55
  const traversed = new Map();
56
56
  (0, traverse_1.traverseNodes)(result.ast, {
@@ -77,17 +77,39 @@ class ScriptContext {
77
77
  for (const token of result.ast.comments || []) {
78
78
  this.remapLocation(token);
79
79
  }
80
+ const context = new RestoreNodeProcessContext(result);
80
81
  let restoreNodeProcesses = this.restoreNodeProcesses;
81
82
  for (const [node, parent] of traversed) {
82
83
  if (!parent)
83
84
  continue;
84
- restoreNodeProcesses = restoreNodeProcesses.filter((proc) => !proc(node, result, parent));
85
+ restoreNodeProcesses = restoreNodeProcesses.filter((proc) => !proc(node, context, parent));
86
+ }
87
+ if (context.removeTokens.size) {
88
+ const tokens = result.ast.tokens || [];
89
+ for (let index = tokens.length - 1; index >= 0; index--) {
90
+ const token = tokens[index];
91
+ for (const rt of context.removeTokens) {
92
+ if (rt(token)) {
93
+ tokens.splice(index, 1);
94
+ context.removeTokens.delete(rt);
95
+ if (!context.removeTokens.size) {
96
+ break;
97
+ }
98
+ }
99
+ }
100
+ }
85
101
  }
86
102
  // Adjust program node location
87
- const first = result.ast.body[0];
88
- if (first.range[0] < result.ast.range[0]) {
89
- result.ast.range[0] = first.range[0];
90
- result.ast.loc.start = this.ctx.getLocFromIndex(result.ast.range[0]);
103
+ const firstOffset = Math.min(...[
104
+ result.ast.body[0],
105
+ (_a = result.ast.tokens) === null || _a === void 0 ? void 0 : _a[0],
106
+ (_b = result.ast.comments) === null || _b === void 0 ? void 0 : _b[0],
107
+ ]
108
+ .filter(Boolean)
109
+ .map((t) => t.range[0]));
110
+ if (firstOffset < result.ast.range[0]) {
111
+ result.ast.range[0] = firstOffset;
112
+ result.ast.loc.start = this.ctx.getLocFromIndex(firstOffset);
91
113
  }
92
114
  }
93
115
  remapLocation(node) {
@@ -116,6 +138,9 @@ class ScriptContext {
116
138
  }
117
139
  }
118
140
  getRemapRange(start, end) {
141
+ if (!this.offsets.length) {
142
+ return [start, end];
143
+ }
119
144
  let lastStart = this.offsets[0];
120
145
  let lastEnd = this.offsets[0];
121
146
  for (const offset of this.offsets) {
@@ -32,6 +32,10 @@ const errors_1 = require("../../errors");
32
32
  */
33
33
  function parse(code, ctx) {
34
34
  const ast = parseByService(code, ctx).ast;
35
+ if (!ast.children) {
36
+ // If the source code is empty, the children property may not be available.
37
+ ast.children = [];
38
+ }
35
39
  const htmlElement = ast.children.find((n) => n.type === "element" && n.name === "html");
36
40
  if (htmlElement) {
37
41
  adjustHTML(ast, htmlElement, ctx);
@@ -140,16 +144,22 @@ function fixLocations(node, ctx) {
140
144
  start += 1;
141
145
  start += node.name.length;
142
146
  if (!node.attributes.length) {
143
- start = (0, astro_1.getStartTagEndOffset)(node, ctx);
147
+ start = (0, astro_1.calcStartTagEndOffset)(node, ctx);
144
148
  }
145
149
  }
146
150
  else if (node.type === "attribute") {
147
151
  fixLocationForAttr(node, ctx, start);
148
- start = (0, astro_1.getAttributeEndOffset)(node, ctx);
152
+ start = (0, astro_1.calcAttributeEndOffset)(node, ctx);
153
+ if (node.position.end) {
154
+ node.position.end.offset = start;
155
+ }
149
156
  }
150
157
  else if (node.type === "comment") {
151
158
  node.position.start.offset = tokenIndex(ctx, "<!--", start);
152
- start = (0, astro_1.getCommentEndOffset)(node, ctx);
159
+ start = (0, astro_1.calcCommentEndOffset)(node, ctx);
160
+ if (node.position.end) {
161
+ node.position.end.offset = start;
162
+ }
153
163
  }
154
164
  else if (node.type === "text") {
155
165
  if (parent.type === "element" &&
@@ -193,6 +203,9 @@ function fixLocations(node, ctx) {
193
203
  node.value = ctx.code.slice(node.position.start.offset, start);
194
204
  }
195
205
  }
206
+ if (node.position.end) {
207
+ node.position.end.offset = start;
208
+ }
196
209
  }
197
210
  else if (node.type === "expression") {
198
211
  start = node.position.start.offset = tokenIndex(ctx, "{", start);
@@ -217,21 +230,22 @@ function fixLocations(node, ctx) {
217
230
  if (node.type === "attribute") {
218
231
  const attributes = parent.attributes;
219
232
  if (attributes[attributes.length - 1] === node) {
220
- start = (0, astro_1.getStartTagEndOffset)(parent, ctx);
233
+ start = (0, astro_1.calcStartTagEndOffset)(parent, ctx);
221
234
  }
222
- return;
223
235
  }
224
- if (node.type === "expression") {
236
+ else if (node.type === "expression") {
225
237
  start = tokenIndex(ctx, "}", start) + 1;
226
238
  }
227
239
  else if (node.type === "fragment" ||
228
240
  node.type === "element" ||
229
241
  node.type === "component" ||
230
242
  node.type === "custom-element") {
231
- const closeTagStart = tokenIndexSafe(ctx.code, `</${node.name}`, start);
232
- if (closeTagStart != null) {
233
- start = closeTagStart + 2 + node.name.length;
234
- start = tokenIndex(ctx, ">", start) + 1;
243
+ if (!(0, astro_1.getSelfClosingTag)(node, ctx)) {
244
+ const closeTagStart = tokenIndexSafe(ctx.code, `</${node.name}`, start);
245
+ if (closeTagStart != null) {
246
+ start = closeTagStart + 2 + node.name.length;
247
+ start = tokenIndex(ctx, ">", start) + 1;
248
+ }
235
249
  }
236
250
  }
237
251
  else {
@@ -11,30 +11,47 @@ function processTemplate(ctx, resultTemplate) {
11
11
  let uniqueIdSeq = 0;
12
12
  const usedUniqueIds = new Set();
13
13
  const script = new script_1.ScriptContext(ctx);
14
- const frontmatter = resultTemplate.ast.children.find((n) => n.type === "frontmatter");
15
14
  let fragmentOpened = false;
16
- if (!frontmatter) {
15
+ /** Open astro root fragment */
16
+ function openRootFragment(startOffset) {
17
17
  script.appendScript("<>");
18
18
  fragmentOpened = true;
19
+ script.addRestoreNodeProcess((scriptNode, { result }) => {
20
+ if (scriptNode.type === types_1.AST_NODE_TYPES.ExpressionStatement &&
21
+ scriptNode.expression.type === types_1.AST_NODE_TYPES.JSXFragment &&
22
+ scriptNode.range[0] === startOffset &&
23
+ result.ast.body.includes(scriptNode)) {
24
+ const index = result.ast.body.indexOf(scriptNode);
25
+ const rootFragment = (result.ast.body[index] =
26
+ scriptNode.expression);
27
+ delete rootFragment.closingFragment;
28
+ delete rootFragment.openingFragment;
29
+ rootFragment.type = "AstroFragment";
30
+ return true;
31
+ }
32
+ return false;
33
+ });
19
34
  }
20
35
  (0, astro_1.walkElements)(resultTemplate.ast, ctx.code,
21
36
  // eslint-disable-next-line complexity -- X(
22
- (node, parents) => {
37
+ (node, [parent]) => {
23
38
  if (node.type === "frontmatter") {
24
39
  const start = node.position.start.offset;
40
+ if (fragmentOpened) {
41
+ script.appendScript("</>;");
42
+ fragmentOpened = false;
43
+ }
25
44
  script.appendOriginal(start);
26
45
  script.skipOriginalOffset(3);
27
- const end = node.position.end.offset;
46
+ const end = (0, astro_1.getEndOffset)(node, ctx);
28
47
  script.appendOriginal(end - 3);
29
- script.appendScript(";<>");
30
- fragmentOpened = true;
48
+ script.appendScript(";");
31
49
  script.skipOriginalOffset(3);
32
- script.addRestoreNodeProcess((_scriptNode, result) => {
50
+ script.addRestoreNodeProcess((_scriptNode, { result }) => {
33
51
  for (let index = 0; index < result.ast.body.length; index++) {
34
52
  const st = result.ast.body[index];
35
53
  if (st.type === types_1.AST_NODE_TYPES.EmptyStatement) {
36
- if (st.range[0] === end - 3 &&
37
- st.range[1] === end) {
54
+ if (st.range[0] === end - 3 && st.range[1] <= end) {
38
55
  result.ast.body.splice(index, 1);
39
56
  break;
40
57
  }
@@ -50,7 +67,6 @@ function processTemplate(ctx, resultTemplate) {
50
67
  }
51
68
  else if ((0, astro_1.isTag)(node)) {
52
69
  // Process for multiple tag
53
- const parent = parents[0];
54
70
  if (parent.type === "expression") {
55
71
  const index = parent.children.indexOf(node);
56
72
  const before = parent.children[index - 1];
@@ -82,6 +98,11 @@ function processTemplate(ctx, resultTemplate) {
82
98
  }
83
99
  }
84
100
  }
101
+ const start = node.position.start.offset;
102
+ script.appendOriginal(start);
103
+ if (!fragmentOpened) {
104
+ openRootFragment(start);
105
+ }
85
106
  // Process for attributes
86
107
  for (const attr of node.attributes) {
87
108
  if ((node.type === "component" ||
@@ -108,7 +129,7 @@ function processTemplate(ctx, resultTemplate) {
108
129
  start + colonIndex + 1,
109
130
  start + attr.name.length,
110
131
  ]);
111
- script.addRestoreNodeProcess((scriptNode, result) => {
132
+ script.addRestoreNodeProcess((scriptNode, context) => {
112
133
  if (scriptNode.type ===
113
134
  types_1.AST_NODE_TYPES.JSXAttribute &&
114
135
  scriptNode.range[0] === start) {
@@ -120,17 +141,10 @@ function processTemplate(ctx, resultTemplate) {
120
141
  scriptNode.name = nsn;
121
142
  nsn.namespace.parent = nsn;
122
143
  nsn.name.parent = nsn;
123
- const tokens = result.ast.tokens || [];
124
- for (let index = 0; index < tokens.length; index++) {
125
- const token = tokens[index];
126
- if (token.range[0] ===
127
- baseNameNode.range[0] &&
128
- token.range[1] ===
129
- baseNameNode.range[1]) {
130
- tokens.splice(index, 1);
131
- break;
132
- }
133
- }
144
+ context.addRemoveToken((token) => token.range[0] ===
145
+ baseNameNode.range[0] &&
146
+ token.range[1] ===
147
+ baseNameNode.range[1]);
134
148
  return true;
135
149
  }
136
150
  return false;
@@ -163,8 +177,8 @@ function processTemplate(ctx, resultTemplate) {
163
177
  }
164
178
  else if (attr.kind === "template-literal") {
165
179
  const attrStart = attr.position.start.offset;
166
- const start = (0, astro_1.getAttributeValueStartOffset)(attr, ctx);
167
- const end = (0, astro_1.getAttributeEndOffset)(attr, ctx);
180
+ const start = (0, astro_1.calcAttributeValueStartOffset)(attr, ctx);
181
+ const end = (0, astro_1.calcAttributeEndOffset)(attr, ctx);
168
182
  script.appendOriginal(start);
169
183
  script.appendScript("{");
170
184
  script.appendOriginal(end);
@@ -182,7 +196,7 @@ function processTemplate(ctx, resultTemplate) {
182
196
  }
183
197
  }
184
198
  // Process for start tag close
185
- const closing = (0, astro_1.getSelfClosingTag)(node, parents, ctx);
199
+ const closing = (0, astro_1.getSelfClosingTag)(node, ctx);
186
200
  if (closing && closing.end === ">") {
187
201
  script.appendOriginal(closing.offset - 1);
188
202
  script.appendScript("/");
@@ -215,23 +229,19 @@ function processTemplate(ctx, resultTemplate) {
215
229
  }
216
230
  else if (node.type === "comment") {
217
231
  const start = node.position.start.offset;
218
- const length = 4 + node.value.length + 3;
232
+ const end = (0, astro_1.getEndOffset)(node, ctx);
233
+ const length = end - start;
219
234
  script.appendOriginal(start);
220
- let targetType;
221
- if (fragmentOpened) {
222
- script.appendOriginal(start + 1);
223
- script.appendScript(`></`);
224
- script.skipOriginalOffset(length - 2);
225
- targetType = types_1.AST_NODE_TYPES.JSXFragment;
235
+ if (!fragmentOpened) {
236
+ openRootFragment(start);
226
237
  }
227
- else {
228
- script.appendScript(`0;`);
229
- targetType = types_1.AST_NODE_TYPES.ExpressionStatement;
230
- script.skipOriginalOffset(length);
231
- }
232
- script.addRestoreNodeProcess((scriptNode, result) => {
238
+ script.appendOriginal(start + 1);
239
+ script.appendScript(`></`);
240
+ script.skipOriginalOffset(length - 2);
241
+ script.appendOriginal(end);
242
+ script.addRestoreNodeProcess((scriptNode, context) => {
233
243
  if (scriptNode.range[0] === start &&
234
- scriptNode.type === targetType) {
244
+ scriptNode.type === types_1.AST_NODE_TYPES.JSXFragment) {
235
245
  delete scriptNode.children;
236
246
  delete scriptNode.openingFragment;
237
247
  delete scriptNode.closingFragment;
@@ -239,27 +249,10 @@ function processTemplate(ctx, resultTemplate) {
239
249
  const commentNode = scriptNode;
240
250
  commentNode.type = "AstroHTMLComment";
241
251
  commentNode.value = node.value;
242
- if (fragmentOpened) {
243
- const removeTokenSet = new Set([
244
- (token) => token.value === "<" &&
245
- token.range[0] === scriptNode.range[0],
246
- (token) => token.value === ">" &&
247
- token.range[1] === scriptNode.range[1],
248
- ]);
249
- const tokens = result.ast.tokens || [];
250
- for (let index = tokens.length - 1; index >= 0; index--) {
251
- const token = tokens[index];
252
- for (const rt of removeTokenSet) {
253
- if (rt(token)) {
254
- tokens.splice(index, 1);
255
- removeTokenSet.delete(rt);
256
- if (!removeTokenSet.size) {
257
- break;
258
- }
259
- }
260
- }
261
- }
262
- }
252
+ context.addRemoveToken((token) => token.value === "<" &&
253
+ token.range[0] === scriptNode.range[0]);
254
+ context.addRemoveToken((token) => token.value === ">" &&
255
+ token.range[1] === scriptNode.range[1]);
263
256
  return true;
264
257
  }
265
258
  return false;
@@ -271,40 +264,49 @@ function processTemplate(ctx, resultTemplate) {
271
264
  }
272
265
  else if (node.type === "doctype") {
273
266
  const start = node.position.start.offset;
274
- const end = node.position.end.offset;
267
+ const end = (0, astro_1.getEndOffset)(node, ctx);
268
+ const length = end - start;
275
269
  script.appendOriginal(start);
276
- let targetType;
277
- if (fragmentOpened) {
278
- script.appendScript(`<></>`);
279
- targetType = types_1.AST_NODE_TYPES.JSXFragment;
280
- }
281
- else {
282
- script.appendScript(`0;`);
283
- targetType = types_1.AST_NODE_TYPES.ExpressionStatement;
270
+ if (!fragmentOpened) {
271
+ openRootFragment(start);
284
272
  }
285
- script.skipOriginalOffset(end - start);
286
- script.addRestoreNodeProcess((scriptNode) => {
273
+ script.appendOriginal(start + 1);
274
+ script.appendScript(`></`);
275
+ script.skipOriginalOffset(length - 2);
276
+ script.appendOriginal(end);
277
+ script.addRestoreNodeProcess((scriptNode, context) => {
287
278
  if (scriptNode.range[0] === start &&
288
- scriptNode.type === targetType) {
279
+ scriptNode.type === types_1.AST_NODE_TYPES.JSXFragment) {
289
280
  delete scriptNode.children;
290
281
  delete scriptNode.openingFragment;
291
282
  delete scriptNode.closingFragment;
292
283
  delete scriptNode.expression;
293
284
  const doctypeNode = scriptNode;
294
285
  doctypeNode.type = "AstroDoctype";
286
+ context.addRemoveToken((token) => token.value === "<" &&
287
+ token.range[0] === scriptNode.range[0]);
288
+ context.addRemoveToken((token) => token.value === ">" &&
289
+ token.range[1] === scriptNode.range[1]);
295
290
  return true;
296
291
  }
297
292
  return false;
298
293
  });
299
294
  script.addToken("HTMLDocType", [start, end]);
300
295
  }
301
- }, (node, parents) => {
296
+ else {
297
+ const start = node.position.start.offset;
298
+ script.appendOriginal(start);
299
+ if (!fragmentOpened) {
300
+ openRootFragment(start);
301
+ }
302
+ }
303
+ }, (node, [parent]) => {
302
304
  if ((0, astro_1.isTag)(node)) {
303
- const closing = (0, astro_1.getSelfClosingTag)(node, parents, ctx);
305
+ const closing = (0, astro_1.getSelfClosingTag)(node, ctx);
304
306
  if (!closing) {
305
- const end = (0, astro_1.getEndTag)(node, parents, ctx);
307
+ const end = (0, astro_1.getEndTag)(node, ctx);
306
308
  if (!end) {
307
- const offset = (0, astro_1.getContentEndOffset)(node, parents, ctx);
309
+ const offset = (0, astro_1.calcContentEndOffset)(node, ctx);
308
310
  script.appendOriginal(offset);
309
311
  script.appendScript(`</${node.name}>`);
310
312
  script.addRestoreNodeProcess((scriptNode, _result, parent) => {
@@ -321,7 +323,6 @@ function processTemplate(ctx, resultTemplate) {
321
323
  }
322
324
  }
323
325
  // Process for multiple tag
324
- const parent = parents[0];
325
326
  if (((0, astro_1.isTag)(node) || node.type === "comment") &&
326
327
  parent.type === "expression") {
327
328
  const index = parent.children.indexOf(node);
@@ -330,17 +331,20 @@ function processTemplate(ctx, resultTemplate) {
330
331
  const before = parent.children[index - 1];
331
332
  if (before &&
332
333
  ((0, astro_1.isTag)(before) || before.type === "comment")) {
333
- const end = (0, astro_1.isTag)(node)
334
- ? (0, astro_1.getTagEndOffset)(node, parents, ctx)
335
- : (0, astro_1.getCommentEndOffset)(node, ctx);
334
+ const end = (0, astro_1.getEndOffset)(node, ctx);
336
335
  script.appendOriginal(end);
337
336
  script.appendScript("</>");
338
337
  }
339
338
  }
340
339
  }
341
340
  });
341
+ if (fragmentOpened) {
342
+ const last = resultTemplate.ast.children[resultTemplate.ast.children.length - 1];
343
+ const end = (0, astro_1.getEndOffset)(last, ctx);
344
+ script.appendOriginal(end);
345
+ script.appendScript("</>");
346
+ }
342
347
  script.appendOriginal(ctx.code.length);
343
- script.appendScript("</>");
344
348
  return script;
345
349
  /**
346
350
  * Generate unique id
@@ -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 {
@@ -4,12 +4,11 @@ exports.KEYS = void 0;
4
4
  const eslint_visitor_keys_1 = require("eslint-visitor-keys");
5
5
  const astroKeys = {
6
6
  Program: ["body"],
7
- AstroRootFragment: ["children"],
7
+ AstroFragment: ["children"],
8
8
  AstroHTMLComment: [],
9
9
  AstroDoctype: [],
10
10
  AstroShorthandAttribute: ["name", "value"],
11
11
  AstroTemplateLiteralAttribute: ["name", "value"],
12
12
  AstroRawText: [],
13
- AstroFragment: ["children"],
14
13
  };
15
14
  exports.KEYS = (0, eslint_visitor_keys_1.unionWith)(astroKeys);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "astro-eslint-parser",
3
- "version": "0.0.14",
4
- "description": "Astro parser for ESLint",
3
+ "version": "0.0.17",
4
+ "description": "Astro component parser for ESLint",
5
5
  "main": "lib/index.js",
6
6
  "files": [
7
7
  "lib"
@@ -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",
@@ -87,6 +88,6 @@
87
88
  "string-replace-loader": "^3.0.3",
88
89
  "ts-node": "^10.4.0",
89
90
  "typescript": "~4.6.0",
90
- "vue-eslint-parser": "^8.0.1"
91
+ "vue-eslint-parser": "^9.0.0"
91
92
  }
92
93
  }