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 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
- "extends": "eslint:recommended",
45
- "overrides": [
46
- {
47
- "files": ["*.astro"],
48
- "parser": "astro-eslint-parser"
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
- ```console
55
- $ eslint "src/**/*.{js,astro}"
56
- # or
57
- $ eslint src --ext .astro
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
 
@@ -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
@@ -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, cb: (n: Node, parents: ParentNode[]) => void, parents?: ParentNode[]): void;
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?: (n: Node | AttributeNode, parents: ParentNode[]) => void, parents?: ParentNode[]): void;
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 getStartTagEndOffset(node: TagLikeNode, ctx: Context): number;
18
+ export declare function calcStartTagEndOffset(node: TagLikeNode, ctx: Context): number;
19
19
  /**
20
- * Get end offset of tag
20
+ * Get end offset of attribute
21
21
  */
22
- export declare function getTagEndOffset(node: TagLikeNode, parents: ParentNode[], ctx: Context): number;
22
+ export declare function calcAttributeEndOffset(node: AttributeNode, ctx: Context): number;
23
23
  /**
24
- * Get end offset of Expression
24
+ * Get start offset of attribute value
25
25
  */
26
- export declare function getExpressionEndOffset(node: ExpressionNode, parents: ParentNode[], ctx: Context): number;
26
+ export declare function calcAttributeValueStartOffset(node: AttributeNode, ctx: Context): number;
27
27
  /**
28
- * Get end offset of attribute
28
+ * Get end offset of tag
29
29
  */
30
- export declare function getAttributeEndOffset(node: AttributeNode, ctx: Context): number;
30
+ export declare function getEndOffset(node: Node, ctx: Context): number;
31
31
  /**
32
- * Get start offset of attribute value
32
+ * Get content end offset
33
33
  */
34
- export declare function getAttributeValueStartOffset(node: AttributeNode, ctx: Context): number;
34
+ export declare function calcContentEndOffset(parent: ParentNode, ctx: Context): number;
35
35
  /**
36
- * Get end offset of comment
36
+ * If the given tag is a self-close tag, get the self-closing tag.
37
37
  */
38
- export declare function getCommentEndOffset(node: CommentNode, ctx: Context): number;
38
+ export declare function getSelfClosingTag(node: TagLikeNode, ctx: Context): null | {
39
+ offset: number;
40
+ end: "/>" | ">";
41
+ };
39
42
  /**
40
- * If the given tag is a void tag, get the self-closing tag.
43
+ * If the given tag has a end tag, get the end tag.
41
44
  */
42
- export declare function getSelfClosingTag(node: TagLikeNode, parents: ParentNode[], ctx: Context): null | {
45
+ export declare function getEndTag(node: TagLikeNode, ctx: Context): null | {
43
46
  offset: number;
44
- end: "/>" | ">";
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
  */
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.skipSpaces = exports.getSelfClosingTag = 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
@@ -20,45 +20,40 @@ function isParent(node) {
20
20
  }
21
21
  exports.isParent = isParent;
22
22
  /** walk element nodes */
23
- function walkElements(parent, code, cb, parents = []) {
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
- cb(node, currParents);
27
+ enter(node, currParents);
28
28
  if (isParent(node)) {
29
- walkElements(node, code, cb, currParents);
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, parents = []) {
36
- const children = getSortedChildren(parent, code);
37
- const currParents = [parent, ...parents];
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, ...currParents];
40
+ const attrParents = [node, ...parents];
42
41
  for (const attr of node.attributes) {
43
42
  enter(attr, attrParents);
44
- leave === null || leave === void 0 ? void 0 : leave(attr, attrParents);
43
+ leave(attr, attrParents);
45
44
  }
46
45
  }
47
- if (isParent(node)) {
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 getStartTagEndOffset(node, ctx) {
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 = getAttributeEndOffset(lastAttr, ctx);
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.getStartTagEndOffset = getStartTagEndOffset;
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 getAttributeEndOffset(node, ctx) {
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]], getAttributeValueStartOffset(node, ctx));
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, "}"], getAttributeValueStartOffset(node, ctx));
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}\``], getAttributeValueStartOffset(node, ctx));
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.getAttributeEndOffset = getAttributeEndOffset;
94
+ exports.calcAttributeEndOffset = calcAttributeEndOffset;
174
95
  /**
175
96
  * Get start offset of attribute value
176
97
  */
177
- function getAttributeValueStartOffset(node, ctx) {
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.getAttributeValueStartOffset = getAttributeValueStartOffset;
114
+ exports.calcAttributeValueStartOffset = calcAttributeValueStartOffset;
194
115
  /**
195
- * Get end offset of comment
116
+ * Get end offset of tag
196
117
  */
197
- function getCommentEndOffset(node, ctx) {
198
- const info = getTokenInfo(ctx, ["<!--", node.value, "-->"], node.position.start.offset);
199
- 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}`);
200
145
  }
201
- exports.getCommentEndOffset = getCommentEndOffset;
146
+ exports.getEndOffset = getEndOffset;
202
147
  /**
203
- * If the given tag is a void tag, get the self-closing tag.
148
+ * Get content end offset
204
149
  */
205
- function getSelfClosingTag(node, parents, ctx) {
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
- let nextElementIndex = code.length;
213
- const childIndex = parent.children.indexOf(node);
214
- if (childIndex === parent.children.length - 1) {
215
- // last
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
- else if (parent.type === "expression") {
221
- nextElementIndex = getExpressionEndOffset(parent, parents.slice(1), ctx);
222
- nextElementIndex = code.lastIndexOf("}", nextElementIndex);
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 next = parent.children[childIndex + 1];
227
- nextElementIndex = next.position.start.offset;
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 endOffset = getStartTagEndOffset(node, ctx);
230
- if (code.slice(endOffset, nextElementIndex).trim()) {
231
- // has end tag
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: endOffset,
236
- end: code.slice(endOffset - 2, endOffset) === "/>" ? "/>" : ">",
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
  */
@@ -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;
@@ -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 {
@@ -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) => 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 {};
@@ -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 Set();
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.add(node);
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
- restoreNodeProcesses = restoreNodeProcesses.filter((proc) => !proc(node, result));
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
@@ -6,6 +6,7 @@ export declare class ParseError extends SyntaxError {
6
6
  index: number;
7
7
  lineNumber: number;
8
8
  column: number;
9
+ originalAST: any;
9
10
  /**
10
11
  * Initialize this ParseError instance.
11
12
  */
package/lib/errors.js CHANGED
@@ -14,6 +14,7 @@ class ParseError extends SyntaxError {
14
14
  const loc = ctx.getLocFromIndex(offset);
15
15
  this.lineNumber = loc.line;
16
16
  this.column = loc.column;
17
+ this.originalAST = ctx.originalAST;
17
18
  }
18
19
  }
19
20
  exports.ParseError = ParseError;
@@ -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.getStartTagEndOffset)(node, ctx);
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.getAttributeEndOffset)(node, ctx);
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.getCommentEndOffset)(node, ctx);
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.getStartTagEndOffset)(parent, ctx);
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
- const closeTagStart = tokenIndexSafe(ctx.code, `</${node.name}`, start);
229
- if (closeTagStart != null) {
230
- start = closeTagStart + 2 + node.name.length;
231
- start = tokenIndex(ctx, ">", start) + 1;
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
- (0, astro_1.walkElements)(resultTemplate.ast, ctx.code, (node, parents) => {
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.position.end.offset;
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 && st.range[1] === end) {
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" || node.type === "fragment") &&
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, result) => {
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] + colonIndex)), name: Object.assign({ type: types_1.AST_NODE_TYPES.JSXIdentifier, name: attr.name.slice(colonIndex + 1) }, ctx.getLocations(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
- const tokens = result.ast.tokens || [];
115
- for (let index = 0; index < tokens.length; index++) {
116
- const token = tokens[index];
117
- if (token.range[0] ===
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 === types_1.AST_NODE_TYPES.JSXAttribute &&
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.getAttributeValueStartOffset)(attr, ctx);
156
- const end = (0, astro_1.getAttributeEndOffset)(attr, ctx);
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 === types_1.AST_NODE_TYPES.JSXAttribute &&
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
- const end = (0, astro_1.getSelfClosingTag)(node, parents, ctx);
173
- if (end && end.end === ">") {
174
- script.appendOriginal(end.offset - 1);
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 length = 4 + node.value.length + 3;
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, result) => {
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 (fragmentOpened) {
229
- const removeTokenSet = new Set([
230
- (token) => token.value === "<" &&
231
- token.range[0] === scriptNode.range[0],
232
- (token) => token.value === ">" &&
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.position.end.offset;
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.appendScript(`<></>`);
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.skipOriginalOffset(end - start);
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 && ((0, astro_1.isTag)(before) || before.type === "comment")) {
294
- const end = (0, astro_1.isTag)(node)
295
- ? (0, astro_1.getTagEndOffset)(node, parents, ctx)
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
  }
@@ -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.13",
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",