astro-eslint-parser 0.0.17 → 0.2.0
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 +21 -10
- package/lib/ast/astro.d.ts +49 -0
- package/lib/{ast.js → ast/astro.js} +0 -0
- package/lib/ast/base.d.ts +6 -0
- package/lib/ast/base.js +2 -0
- package/lib/ast/index.d.ts +8 -0
- package/lib/ast/index.js +18 -0
- package/lib/ast/jsx.d.ts +91 -0
- package/lib/ast/jsx.js +2 -0
- package/lib/astro/index.js +2 -4
- package/lib/astro-tools/index.d.ts +21 -0
- package/lib/astro-tools/index.js +26 -0
- package/lib/context/index.d.ts +13 -8
- package/lib/context/index.js +51 -100
- package/lib/context/parser-options.d.ts +8 -0
- package/lib/context/parser-options.js +71 -0
- package/lib/{parser → context/resolve-parser}/espree.d.ts +1 -1
- package/lib/{parser → context/resolve-parser}/espree.js +3 -18
- package/lib/context/resolve-parser/index.d.ts +5 -0
- package/lib/{parser/resolve-parser.js → context/resolve-parser/index.js} +0 -0
- package/lib/context/script.d.ts +1 -1
- package/lib/context/script.js +2 -3
- package/lib/index.d.ts +2 -1
- package/lib/index.js +3 -1
- package/lib/parser/astro-parser/astrojs-compiler-service.d.ts +2 -4
- package/lib/parser/astro-parser/astrojs-compiler-service.js +3 -12
- package/lib/parser/astro-parser/astrojs-compiler-worker.d.ts +1 -0
- package/lib/parser/astro-parser/astrojs-compiler-worker.js +11 -0
- package/lib/parser/astro-parser/parse.js +7 -51
- package/lib/parser/index.d.ts +0 -17
- package/lib/parser/index.js +6 -31
- package/lib/parser/lru-cache.d.ts +7 -0
- package/lib/parser/lru-cache.js +32 -0
- package/lib/parser/process-template.js +24 -5
- package/lib/parser/script.d.ts +3 -2
- package/lib/parser/script.js +18 -19
- package/lib/parser/template.d.ts +10 -0
- package/lib/parser/template.js +102 -0
- package/lib/parser/ts-patch.d.ts +8 -0
- package/lib/parser/ts-patch.js +58 -0
- package/lib/types.d.ts +21 -0
- package/lib/types.js +2 -0
- package/package.json +15 -11
- package/lib/ast.d.ts +0 -48
- package/lib/parser/astro-parser/wasm_exec.d.ts +0 -35
- package/lib/parser/astro-parser/wasm_exec.js +0 -470
- package/lib/parser/resolve-parser.d.ts +0 -16
package/README.md
CHANGED
|
@@ -19,18 +19,21 @@ This parser is in the ***experimental stages*** of development.
|
|
|
19
19
|
|
|
20
20
|
At least it works fine with a [fork of the `astro.build` repository](https://github.com/ota-meshi/astro.build/tree/eslint).
|
|
21
21
|
|
|
22
|
-
⚠ Currently this parser relies heavily on the internal API of [@astrojs/compiler]. It may stop working in a future update of [@astrojs/compiler]. ⚠
|
|
23
|
-
|
|
24
22
|
[@astrojs/compiler]: https://github.com/withastro/compiler
|
|
25
23
|
|
|
26
|
-
|
|
24
|
+
## :checkered_flag: Motivation
|
|
25
|
+
|
|
26
|
+
This parser allows us to lint the script of `.astro` files.
|
|
27
|
+
|
|
28
|
+
> Note that this parser alone will not lint the scripts inside the `<script>` tag. Use [eslint-plugin-astro] to lint the script inside the `<script>` tag as well.
|
|
29
|
+
|
|
27
30
|
### ESLint Plugins Using astro-eslint-parser
|
|
28
31
|
|
|
29
|
-
#### [
|
|
32
|
+
#### [eslint-plugin-astro]
|
|
30
33
|
|
|
31
|
-
ESLint plugin for Astro.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
ESLint plugin for Astro component.
|
|
35
|
+
|
|
36
|
+
[eslint-plugin-astro]: https://ota-meshi.github.io/eslint-plugin-astro/
|
|
34
37
|
|
|
35
38
|
## 💿 Installation
|
|
36
39
|
|
|
@@ -62,7 +65,7 @@ npm install --save-dev eslint astro-eslint-parser
|
|
|
62
65
|
$ eslint src --ext .js,.astro
|
|
63
66
|
```
|
|
64
67
|
|
|
65
|
-
The commit diff [here](https://github.com/
|
|
68
|
+
The commit diff [here](https://github.com/withastro/astro.build/compare/main...ota-meshi:eslint) is an example of introducing this parser to the `astro.build` repository.
|
|
66
69
|
|
|
67
70
|
## 🔧 Options
|
|
68
71
|
|
|
@@ -145,7 +148,7 @@ Example **.vscode/settings.json**:
|
|
|
145
148
|
}
|
|
146
149
|
```
|
|
147
150
|
|
|
148
|
-
## :
|
|
151
|
+
## :handshake: Compatibility With Existing ESLint Rules
|
|
149
152
|
|
|
150
153
|
Most of the rules in the ESLint core work for the script part, but some rules are incompatible.
|
|
151
154
|
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.
|
|
@@ -154,7 +157,15 @@ For example, the [react/jsx-no-target-blank] rule works fine.
|
|
|
154
157
|
[eslint-plugin-react]: https://github.com/jsx-eslint/eslint-plugin-react/
|
|
155
158
|
[react/jsx-no-target-blank]: https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-target-blank.md
|
|
156
159
|
|
|
157
|
-
## :
|
|
160
|
+
## :ghost: Limitations
|
|
161
|
+
|
|
162
|
+
If this parser is used with `@typescript-eslint/parser` and `parserOptions.project` is set, it will temporarily create a `.tsx` file to parse the `.astro` file.
|
|
163
|
+
This parser works by converting the `.astro` file to JSX and letting the JavaScript parser parse it.
|
|
164
|
+
Since `@typescript-eslint/parser` can only parse files with the extension `.tsx` as JSX, it is necessary to temporarily create a `.tsx` file. Temporarily created files will try to be deleted after parses, but if the parsing takes a long time, the files may be visible to you.
|
|
165
|
+
|
|
166
|
+
See also [`@typescript-eslint/parser` readme](https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/parser#parseroptionsecmafeaturesjsx).
|
|
167
|
+
|
|
168
|
+
## :hammer_and_wrench: Usage for Custom Rules / Plugins
|
|
158
169
|
|
|
159
170
|
- TBA
|
|
160
171
|
- 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.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { JSXAttribute, JSXElement, JSXExpression, JSXExpressionContainer, JSXFragment, JSXText } from "./jsx";
|
|
2
|
+
import type { TSESTree as ES } from "@typescript-eslint/types";
|
|
3
|
+
import type { BaseNode } from "./base";
|
|
4
|
+
export declare type AstroNode = AstroProgram | AstroFragment | AstroHTMLComment | AstroDoctype | AstroShorthandAttribute | AstroTemplateLiteralAttribute | AstroRawText;
|
|
5
|
+
export declare type AstroChild = JSXElement | JSXFragment | JSXExpression | JSXText | AstroHTMLComment;
|
|
6
|
+
export declare type AstroParentNode = JSXElement | JSXFragment | AstroFragment;
|
|
7
|
+
/** Node of Astro program root */
|
|
8
|
+
export interface AstroProgram extends Omit<ES.Program, "type" | "body"> {
|
|
9
|
+
type: "Program";
|
|
10
|
+
body: (ES.Program["body"][number] | AstroFragment)[];
|
|
11
|
+
sourceType: "script" | "module";
|
|
12
|
+
comments: ES.Comment[];
|
|
13
|
+
tokens: ES.Token[];
|
|
14
|
+
parent?: undefined;
|
|
15
|
+
}
|
|
16
|
+
/** Node of Astro fragment */
|
|
17
|
+
export interface AstroFragment extends BaseNode {
|
|
18
|
+
type: "AstroFragment";
|
|
19
|
+
children: AstroChild[];
|
|
20
|
+
parent?: AstroParentNode;
|
|
21
|
+
}
|
|
22
|
+
/** Node of Astro html comment */
|
|
23
|
+
export interface AstroHTMLComment extends BaseNode {
|
|
24
|
+
type: "AstroHTMLComment";
|
|
25
|
+
value: string;
|
|
26
|
+
parent?: AstroParentNode;
|
|
27
|
+
}
|
|
28
|
+
/** Node of Astro doctype */
|
|
29
|
+
export interface AstroDoctype extends BaseNode {
|
|
30
|
+
type: "AstroDoctype";
|
|
31
|
+
parent?: AstroFragment;
|
|
32
|
+
}
|
|
33
|
+
/** Node of Astro shorthand attribute */
|
|
34
|
+
export interface AstroShorthandAttribute extends Omit<JSXAttribute, "type"> {
|
|
35
|
+
type: "AstroShorthandAttribute";
|
|
36
|
+
value: JSXExpressionContainer;
|
|
37
|
+
}
|
|
38
|
+
/** Node of Astro template-literal attribute */
|
|
39
|
+
export interface AstroTemplateLiteralAttribute extends Omit<JSXAttribute, "type"> {
|
|
40
|
+
type: "AstroTemplateLiteralAttribute";
|
|
41
|
+
value: JSXExpressionContainer & {
|
|
42
|
+
expression: ES.TemplateLiteral;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/** Node of Astro raw text */
|
|
46
|
+
export interface AstroRawText extends Omit<JSXText, "type"> {
|
|
47
|
+
type: "AstroRawText";
|
|
48
|
+
parent?: JSXElement;
|
|
49
|
+
}
|
|
File without changes
|
package/lib/ast/base.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from "./astro";
|
|
2
|
+
export * from "./jsx";
|
|
3
|
+
import type { TSESTree } from "@typescript-eslint/types";
|
|
4
|
+
export declare type Comment = TSESTree.Comment;
|
|
5
|
+
export declare type Token = TSESTree.Token;
|
|
6
|
+
export declare type SourceLocation = TSESTree.SourceLocation;
|
|
7
|
+
export declare type Range = TSESTree.Range;
|
|
8
|
+
export declare type Position = TSESTree.Position;
|
package/lib/ast/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./astro"), exports);
|
|
18
|
+
__exportStar(require("./jsx"), exports);
|
package/lib/ast/jsx.d.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { TSESTree as ES } from "@typescript-eslint/types";
|
|
2
|
+
import type { AstroFragment, AstroHTMLComment, AstroShorthandAttribute, AstroTemplateLiteralAttribute } from "./astro";
|
|
3
|
+
import type { BaseNode } from "./base";
|
|
4
|
+
export declare type JSXNode = JSXAttribute | JSXClosingElement | JSXClosingFragment | JSXElement | JSXEmptyExpression | JSXExpressionContainer | JSXFragment | JSXIdentifier | JSXMemberExpression | JSXNamespacedName | JSXOpeningElement | JSXOpeningFragment | JSXSpreadAttribute | JSXSpreadChild | JSXText;
|
|
5
|
+
export declare type JSXChild = JSXElement | JSXFragment | JSXExpression | JSXText | AstroHTMLComment;
|
|
6
|
+
export declare type JSXParentNode = JSXElement | JSXFragment | AstroFragment;
|
|
7
|
+
export interface JSXElement extends BaseNode {
|
|
8
|
+
type: "JSXElement";
|
|
9
|
+
openingElement: JSXOpeningElement;
|
|
10
|
+
closingElement: JSXClosingElement | null;
|
|
11
|
+
children: JSXChild[];
|
|
12
|
+
parent?: JSXParentNode;
|
|
13
|
+
}
|
|
14
|
+
export interface JSXFragment extends BaseNode {
|
|
15
|
+
type: "JSXFragment";
|
|
16
|
+
openingFragment: JSXOpeningFragment;
|
|
17
|
+
closingFragment: JSXClosingFragment;
|
|
18
|
+
children: JSXChild[];
|
|
19
|
+
parent?: JSXParentNode;
|
|
20
|
+
}
|
|
21
|
+
export interface JSXOpeningElement extends BaseNode {
|
|
22
|
+
type: "JSXOpeningElement";
|
|
23
|
+
typeParameters?: ES.TSTypeParameterInstantiation;
|
|
24
|
+
selfClosing: boolean;
|
|
25
|
+
name: JSXTagNameExpression;
|
|
26
|
+
attributes: (JSXAttribute | JSXSpreadAttribute | AstroShorthandAttribute | AstroTemplateLiteralAttribute)[];
|
|
27
|
+
parent?: JSXElement;
|
|
28
|
+
}
|
|
29
|
+
export interface JSXClosingElement extends BaseNode {
|
|
30
|
+
type: "JSXClosingElement";
|
|
31
|
+
name: JSXTagNameExpression;
|
|
32
|
+
parent?: JSXElement;
|
|
33
|
+
}
|
|
34
|
+
export interface JSXClosingFragment extends BaseNode {
|
|
35
|
+
type: "JSXClosingFragment";
|
|
36
|
+
parent?: JSXFragment;
|
|
37
|
+
}
|
|
38
|
+
export interface JSXOpeningFragment extends BaseNode {
|
|
39
|
+
type: "JSXOpeningFragment";
|
|
40
|
+
parent?: JSXFragment;
|
|
41
|
+
}
|
|
42
|
+
export interface JSXAttribute extends BaseNode {
|
|
43
|
+
type: "JSXAttribute";
|
|
44
|
+
name: JSXIdentifier | JSXNamespacedName;
|
|
45
|
+
value: JSXExpression | ES.Literal | null;
|
|
46
|
+
parent?: JSXOpeningElement;
|
|
47
|
+
}
|
|
48
|
+
export interface JSXSpreadAttribute extends BaseNode {
|
|
49
|
+
type: "JSXSpreadAttribute";
|
|
50
|
+
argument: ES.Expression;
|
|
51
|
+
parent?: JSXOpeningElement;
|
|
52
|
+
}
|
|
53
|
+
export declare type JSXTagNameExpression = JSXIdentifier | JSXMemberExpression | JSXNamespacedName;
|
|
54
|
+
export interface JSXIdentifier extends BaseNode {
|
|
55
|
+
type: "JSXIdentifier";
|
|
56
|
+
name: string;
|
|
57
|
+
parent?: JSXAttribute | AstroShorthandAttribute | AstroTemplateLiteralAttribute | JSXMemberExpression | JSXNamespacedName | JSXOpeningElement | JSXClosingElement;
|
|
58
|
+
}
|
|
59
|
+
export interface JSXMemberExpression extends BaseNode {
|
|
60
|
+
type: "JSXMemberExpression";
|
|
61
|
+
object: JSXTagNameExpression;
|
|
62
|
+
property: JSXIdentifier;
|
|
63
|
+
parent?: JSXMemberExpression | JSXOpeningElement | JSXClosingElement;
|
|
64
|
+
}
|
|
65
|
+
export interface JSXNamespacedName extends BaseNode {
|
|
66
|
+
type: "JSXNamespacedName";
|
|
67
|
+
namespace: JSXIdentifier;
|
|
68
|
+
name: JSXIdentifier;
|
|
69
|
+
parent?: JSXAttribute | AstroShorthandAttribute | AstroTemplateLiteralAttribute | JSXMemberExpression | JSXOpeningElement | JSXClosingElement;
|
|
70
|
+
}
|
|
71
|
+
export declare type JSXExpression = JSXExpressionContainer | JSXSpreadChild;
|
|
72
|
+
export interface JSXExpressionContainer extends BaseNode {
|
|
73
|
+
type: "JSXExpressionContainer";
|
|
74
|
+
expression: ES.Expression | JSXEmptyExpression;
|
|
75
|
+
parent?: JSXAttribute | AstroShorthandAttribute | AstroTemplateLiteralAttribute | JSXParentNode;
|
|
76
|
+
}
|
|
77
|
+
export interface JSXSpreadChild extends BaseNode {
|
|
78
|
+
type: "JSXSpreadChild";
|
|
79
|
+
expression: ES.Expression;
|
|
80
|
+
parent?: JSXAttribute | JSXParentNode;
|
|
81
|
+
}
|
|
82
|
+
export interface JSXEmptyExpression extends BaseNode {
|
|
83
|
+
type: "JSXEmptyExpression";
|
|
84
|
+
parent?: JSXExpressionContainer;
|
|
85
|
+
}
|
|
86
|
+
export interface JSXText extends BaseNode {
|
|
87
|
+
type: "JSXText";
|
|
88
|
+
value: string;
|
|
89
|
+
raw: string;
|
|
90
|
+
parent?: JSXParentNode;
|
|
91
|
+
}
|
package/lib/ast/jsx.js
ADDED
package/lib/astro/index.js
CHANGED
|
@@ -116,8 +116,7 @@ exports.calcAttributeValueStartOffset = calcAttributeValueStartOffset;
|
|
|
116
116
|
* Get end offset of tag
|
|
117
117
|
*/
|
|
118
118
|
function getEndOffset(node, ctx) {
|
|
119
|
-
|
|
120
|
-
if (((_a = node.position.end) === null || _a === void 0 ? void 0 : _a.offset) != null) {
|
|
119
|
+
if (node.position.end?.offset != null) {
|
|
121
120
|
return node.position.end.offset;
|
|
122
121
|
}
|
|
123
122
|
if (isTag(node))
|
|
@@ -323,8 +322,7 @@ exports.skipSpaces = skipSpaces;
|
|
|
323
322
|
* Get children
|
|
324
323
|
*/
|
|
325
324
|
function getSortedChildren(parent, code) {
|
|
326
|
-
|
|
327
|
-
if (parent.type === "root" && ((_a = parent.children[0]) === null || _a === void 0 ? void 0 : _a.type) === "frontmatter") {
|
|
325
|
+
if (parent.type === "root" && parent.children[0]?.type === "frontmatter") {
|
|
328
326
|
// The order of comments and frontmatter may be changed.
|
|
329
327
|
const children = [...parent.children];
|
|
330
328
|
if (children.every((n) => n.position)) {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ParseResult } from "@astrojs/compiler";
|
|
2
|
+
import type { AttributeNode, Node, ParentNode } from "@astrojs/compiler/types";
|
|
3
|
+
export interface ParseTemplateResult {
|
|
4
|
+
result: ParseResult;
|
|
5
|
+
getEndOffset: (node: Node) => number;
|
|
6
|
+
calcAttributeValueStartOffset: (node: AttributeNode) => number;
|
|
7
|
+
calcAttributeEndOffset: (node: AttributeNode) => number;
|
|
8
|
+
walk: (parent: ParentNode, enter: (n: Node | AttributeNode, parents: ParentNode[]) => void, leave?: (n: Node | AttributeNode, parents: ParentNode[]) => void) => void;
|
|
9
|
+
getLocFromIndex: (index: number) => {
|
|
10
|
+
line: number;
|
|
11
|
+
column: number;
|
|
12
|
+
};
|
|
13
|
+
getIndexFromLoc: (loc: {
|
|
14
|
+
line: number;
|
|
15
|
+
column: number;
|
|
16
|
+
}) => number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Parse the astro component template.
|
|
20
|
+
*/
|
|
21
|
+
export declare function parseTemplate(code: string): ParseTemplateResult;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseTemplate = void 0;
|
|
4
|
+
const template_1 = require("../parser/template");
|
|
5
|
+
const astro_1 = require("../astro");
|
|
6
|
+
/**
|
|
7
|
+
* Parse the astro component template.
|
|
8
|
+
*/
|
|
9
|
+
function parseTemplate(code) {
|
|
10
|
+
const parsed = (0, template_1.parseTemplate)(code);
|
|
11
|
+
return {
|
|
12
|
+
result: parsed.result,
|
|
13
|
+
getEndOffset: (node) => (0, astro_1.getEndOffset)(node, parsed.context),
|
|
14
|
+
calcAttributeValueStartOffset: (node) => (0, astro_1.calcAttributeValueStartOffset)(node, parsed.context),
|
|
15
|
+
calcAttributeEndOffset: (node) => (0, astro_1.calcAttributeEndOffset)(node, parsed.context),
|
|
16
|
+
walk(parent, enter, leave) {
|
|
17
|
+
(0, astro_1.walk)(parent, code, enter, leave ||
|
|
18
|
+
(() => {
|
|
19
|
+
/* noop */
|
|
20
|
+
}));
|
|
21
|
+
},
|
|
22
|
+
getLocFromIndex: (index) => parsed.context.getLocFromIndex(index),
|
|
23
|
+
getIndexFromLoc: (loc) => parsed.context.locs.getIndexFromLoc(loc),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
exports.parseTemplate = parseTemplate;
|
package/lib/context/index.d.ts
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import type { TSESTree } from "@typescript-eslint/types";
|
|
2
|
-
import type { ESLintExtendedProgram } from "../parser";
|
|
3
2
|
declare type RangeAndLoc = {
|
|
4
3
|
range: TSESTree.Range;
|
|
5
4
|
loc: TSESTree.SourceLocation;
|
|
6
5
|
};
|
|
7
6
|
export declare class Context {
|
|
8
7
|
readonly code: string;
|
|
9
|
-
readonly parserOptions: any;
|
|
10
8
|
readonly locs: LinesAndColumns;
|
|
11
9
|
private readonly locsMap;
|
|
12
10
|
private readonly state;
|
|
13
|
-
constructor(code: string
|
|
11
|
+
constructor(code: string);
|
|
14
12
|
getLocFromIndex(index: number): {
|
|
15
13
|
line: number;
|
|
16
14
|
column: number;
|
|
@@ -27,15 +25,12 @@ export declare class Context {
|
|
|
27
25
|
* get text
|
|
28
26
|
*/
|
|
29
27
|
getText(range: TSESTree.Range): string;
|
|
30
|
-
isTypeScript(): boolean;
|
|
31
|
-
remapCR({ ast, visitorKeys }: ESLintExtendedProgram): void;
|
|
32
28
|
get originalAST(): any;
|
|
33
29
|
set originalAST(originalAST: any);
|
|
34
30
|
}
|
|
35
31
|
export declare class LinesAndColumns {
|
|
36
|
-
readonly code: string;
|
|
37
|
-
private readonly crs;
|
|
38
32
|
private readonly lineStartIndices;
|
|
33
|
+
private readonly normalizedLineFeed;
|
|
39
34
|
constructor(origCode: string);
|
|
40
35
|
getLocFromIndex(index: number): {
|
|
41
36
|
line: number;
|
|
@@ -45,6 +40,16 @@ export declare class LinesAndColumns {
|
|
|
45
40
|
line: number;
|
|
46
41
|
column: number;
|
|
47
42
|
}): number;
|
|
48
|
-
|
|
43
|
+
getNormalizedLineFeed(): NormalizedLineFeed;
|
|
44
|
+
}
|
|
45
|
+
export declare class NormalizedLineFeed {
|
|
46
|
+
readonly code: string;
|
|
47
|
+
private readonly offsets;
|
|
48
|
+
get needRemap(): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Remap index
|
|
51
|
+
*/
|
|
52
|
+
readonly remapIndex: (index: number) => number;
|
|
53
|
+
constructor(code: string, offsets: number[]);
|
|
49
54
|
}
|
|
50
55
|
export {};
|
package/lib/context/index.js
CHANGED
|
@@ -1,20 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.LinesAndColumns = exports.Context = void 0;
|
|
7
|
-
const path_1 = __importDefault(require("path"));
|
|
8
|
-
const fs_1 = __importDefault(require("fs"));
|
|
9
|
-
const resolve_parser_1 = require("../parser/resolve-parser");
|
|
10
|
-
const traverse_1 = require("../traverse");
|
|
3
|
+
exports.NormalizedLineFeed = exports.LinesAndColumns = exports.Context = void 0;
|
|
11
4
|
class Context {
|
|
12
|
-
constructor(code
|
|
5
|
+
constructor(code) {
|
|
13
6
|
this.locsMap = new Map();
|
|
14
7
|
this.state = {};
|
|
15
8
|
this.locs = new LinesAndColumns(code);
|
|
16
|
-
this.code =
|
|
17
|
-
this.parserOptions = parserOptions;
|
|
9
|
+
this.code = code;
|
|
18
10
|
}
|
|
19
11
|
getLocFromIndex(index) {
|
|
20
12
|
let loc = this.locsMap.get(index);
|
|
@@ -43,7 +35,11 @@ class Context {
|
|
|
43
35
|
* Build token
|
|
44
36
|
*/
|
|
45
37
|
buildToken(type, range) {
|
|
46
|
-
return
|
|
38
|
+
return {
|
|
39
|
+
type,
|
|
40
|
+
value: this.getText(range),
|
|
41
|
+
...this.getLocations(...range),
|
|
42
|
+
};
|
|
47
43
|
}
|
|
48
44
|
/**
|
|
49
45
|
* get text
|
|
@@ -51,84 +47,6 @@ class Context {
|
|
|
51
47
|
getText(range) {
|
|
52
48
|
return this.code.slice(range[0], range[1]);
|
|
53
49
|
}
|
|
54
|
-
isTypeScript() {
|
|
55
|
-
var _a, _b;
|
|
56
|
-
if (this.state.isTypeScript != null) {
|
|
57
|
-
return this.state.isTypeScript;
|
|
58
|
-
}
|
|
59
|
-
const parserName = (0, resolve_parser_1.getParserName)({}, (_a = this.parserOptions) === null || _a === void 0 ? void 0 : _a.parser);
|
|
60
|
-
if (parserName === "@typescript-eslint/parser") {
|
|
61
|
-
return (this.state.isTypeScript = true);
|
|
62
|
-
}
|
|
63
|
-
if (parserName.includes("@typescript-eslint/parser")) {
|
|
64
|
-
let targetPath = parserName;
|
|
65
|
-
while (targetPath) {
|
|
66
|
-
const pkgPath = path_1.default.join(targetPath, "package.json");
|
|
67
|
-
if (fs_1.default.existsSync(pkgPath)) {
|
|
68
|
-
try {
|
|
69
|
-
return (this.state.isTypeScript =
|
|
70
|
-
((_b = JSON.parse(fs_1.default.readFileSync(pkgPath, "utf-8"))) === null || _b === void 0 ? void 0 : _b.name) === "@typescript-eslint/parser");
|
|
71
|
-
}
|
|
72
|
-
catch (_c) {
|
|
73
|
-
return (this.state.isTypeScript = false);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
const parent = path_1.default.dirname(targetPath);
|
|
77
|
-
if (targetPath === parent) {
|
|
78
|
-
break;
|
|
79
|
-
}
|
|
80
|
-
targetPath = parent;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return (this.state.isTypeScript = false);
|
|
84
|
-
}
|
|
85
|
-
remapCR({ ast, visitorKeys }) {
|
|
86
|
-
const crs = this.locs.getCRs();
|
|
87
|
-
if (!crs.length) {
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
const cache = {};
|
|
91
|
-
/**
|
|
92
|
-
* Remap index
|
|
93
|
-
*/
|
|
94
|
-
function remapIndex(index) {
|
|
95
|
-
let result = cache[index];
|
|
96
|
-
if (result != null) {
|
|
97
|
-
return result;
|
|
98
|
-
}
|
|
99
|
-
result = index;
|
|
100
|
-
for (const cr of crs) {
|
|
101
|
-
if (cr < result) {
|
|
102
|
-
result++;
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
break;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
return (cache[index] = result);
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Remap range
|
|
112
|
-
*/
|
|
113
|
-
function remapRange(range) {
|
|
114
|
-
return [remapIndex(range[0]), remapIndex(range[1])];
|
|
115
|
-
}
|
|
116
|
-
(0, traverse_1.traverseNodes)(ast, {
|
|
117
|
-
visitorKeys,
|
|
118
|
-
enterNode(node) {
|
|
119
|
-
node.range = remapRange(node.range);
|
|
120
|
-
},
|
|
121
|
-
leaveNode() {
|
|
122
|
-
// ignore
|
|
123
|
-
},
|
|
124
|
-
});
|
|
125
|
-
for (const token of ast.tokens || []) {
|
|
126
|
-
token.range = remapRange(token.range);
|
|
127
|
-
}
|
|
128
|
-
for (const comment of ast.comments || []) {
|
|
129
|
-
comment.range = remapRange(comment.range);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
50
|
get originalAST() {
|
|
133
51
|
return this.state.originalAST;
|
|
134
52
|
}
|
|
@@ -142,30 +60,31 @@ class LinesAndColumns {
|
|
|
142
60
|
const len = origCode.length;
|
|
143
61
|
const lineStartIndices = [0];
|
|
144
62
|
const crs = [];
|
|
145
|
-
let
|
|
63
|
+
let normalizedCode = "";
|
|
146
64
|
for (let index = 0; index < len;) {
|
|
147
65
|
const c = origCode[index++];
|
|
148
66
|
if (c === "\r") {
|
|
149
67
|
const next = origCode[index++] || "";
|
|
150
68
|
if (next === "\n") {
|
|
151
|
-
|
|
69
|
+
normalizedCode += next;
|
|
152
70
|
crs.push(index - 2);
|
|
71
|
+
lineStartIndices.push(index);
|
|
153
72
|
}
|
|
154
73
|
else {
|
|
155
|
-
|
|
74
|
+
normalizedCode += `\n${next}`;
|
|
75
|
+
lineStartIndices.push(index - 1);
|
|
156
76
|
}
|
|
157
|
-
lineStartIndices.push(code.length);
|
|
158
77
|
}
|
|
159
78
|
else {
|
|
160
|
-
|
|
79
|
+
normalizedCode += c;
|
|
161
80
|
if (c === "\n") {
|
|
162
|
-
lineStartIndices.push(
|
|
81
|
+
lineStartIndices.push(index);
|
|
163
82
|
}
|
|
164
83
|
}
|
|
165
84
|
}
|
|
166
85
|
this.lineStartIndices = lineStartIndices;
|
|
167
|
-
|
|
168
|
-
this.
|
|
86
|
+
//
|
|
87
|
+
this.normalizedLineFeed = new NormalizedLineFeed(normalizedCode, crs);
|
|
169
88
|
}
|
|
170
89
|
getLocFromIndex(index) {
|
|
171
90
|
const lineNumber = sortedLastIndex(this.lineStartIndices, index);
|
|
@@ -179,11 +98,43 @@ class LinesAndColumns {
|
|
|
179
98
|
const positionIndex = lineStartIndex + loc.column;
|
|
180
99
|
return positionIndex;
|
|
181
100
|
}
|
|
182
|
-
|
|
183
|
-
return this.
|
|
101
|
+
getNormalizedLineFeed() {
|
|
102
|
+
return this.normalizedLineFeed;
|
|
184
103
|
}
|
|
185
104
|
}
|
|
186
105
|
exports.LinesAndColumns = LinesAndColumns;
|
|
106
|
+
class NormalizedLineFeed {
|
|
107
|
+
constructor(code, offsets) {
|
|
108
|
+
this.code = code;
|
|
109
|
+
this.offsets = offsets;
|
|
110
|
+
if (offsets.length) {
|
|
111
|
+
const cache = {};
|
|
112
|
+
this.remapIndex = (index) => {
|
|
113
|
+
let result = cache[index];
|
|
114
|
+
if (result != null) {
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
result = index;
|
|
118
|
+
for (const offset of offsets) {
|
|
119
|
+
if (offset < result) {
|
|
120
|
+
result++;
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return (cache[index] = result);
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
this.remapIndex = (i) => i;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
get needRemap() {
|
|
134
|
+
return this.offsets.length > 0;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
exports.NormalizedLineFeed = NormalizedLineFeed;
|
|
187
138
|
/**
|
|
188
139
|
* Uses a binary search to determine the highest index at which value should be inserted into array in order to maintain its sort order.
|
|
189
140
|
*/
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ParserOptionsContext = void 0;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const resolve_parser_1 = require("./resolve-parser");
|
|
10
|
+
class ParserOptionsContext {
|
|
11
|
+
constructor(options) {
|
|
12
|
+
this.state = {};
|
|
13
|
+
const parserOptions = {
|
|
14
|
+
ecmaVersion: 2020,
|
|
15
|
+
sourceType: "module",
|
|
16
|
+
loc: true,
|
|
17
|
+
range: true,
|
|
18
|
+
raw: true,
|
|
19
|
+
tokens: true,
|
|
20
|
+
comment: true,
|
|
21
|
+
eslintVisitorKeys: true,
|
|
22
|
+
eslintScopeManager: true,
|
|
23
|
+
...(options || {}),
|
|
24
|
+
};
|
|
25
|
+
parserOptions.ecmaFeatures = {
|
|
26
|
+
...(parserOptions.ecmaFeatures || {}),
|
|
27
|
+
jsx: true,
|
|
28
|
+
};
|
|
29
|
+
parserOptions.sourceType = "module";
|
|
30
|
+
if (parserOptions.ecmaVersion <= 5 ||
|
|
31
|
+
parserOptions.ecmaVersion == null) {
|
|
32
|
+
parserOptions.ecmaVersion = 2015;
|
|
33
|
+
}
|
|
34
|
+
this.parserOptions = parserOptions;
|
|
35
|
+
}
|
|
36
|
+
getParser() {
|
|
37
|
+
return (0, resolve_parser_1.getParser)({}, this.parserOptions.parser);
|
|
38
|
+
}
|
|
39
|
+
isTypeScript() {
|
|
40
|
+
if (this.state.isTypeScript != null) {
|
|
41
|
+
return this.state.isTypeScript;
|
|
42
|
+
}
|
|
43
|
+
const parserName = (0, resolve_parser_1.getParserName)({}, this.parserOptions?.parser);
|
|
44
|
+
if (parserName === "@typescript-eslint/parser") {
|
|
45
|
+
return (this.state.isTypeScript = true);
|
|
46
|
+
}
|
|
47
|
+
if (parserName.includes("@typescript-eslint/parser")) {
|
|
48
|
+
let targetPath = parserName;
|
|
49
|
+
while (targetPath) {
|
|
50
|
+
const pkgPath = path_1.default.join(targetPath, "package.json");
|
|
51
|
+
if (fs_1.default.existsSync(pkgPath)) {
|
|
52
|
+
try {
|
|
53
|
+
return (this.state.isTypeScript =
|
|
54
|
+
JSON.parse(fs_1.default.readFileSync(pkgPath, "utf-8"))
|
|
55
|
+
?.name === "@typescript-eslint/parser");
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return (this.state.isTypeScript = false);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const parent = path_1.default.dirname(targetPath);
|
|
62
|
+
if (targetPath === parent) {
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
targetPath = parent;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return (this.state.isTypeScript = false);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.ParserOptionsContext = ParserOptionsContext;
|