astro-eslint-parser 0.2.2 → 0.4.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 +47 -2
- package/lib/context/script.d.ts +5 -2
- package/lib/context/script.js +13 -3
- package/lib/index.d.ts +6 -2
- package/lib/index.js +13 -1
- package/lib/markdown/frontmatter.d.ts +9 -0
- package/lib/markdown/frontmatter.js +53 -0
- package/lib/markdown/index.d.ts +19 -0
- package/lib/markdown/index.js +60 -0
- package/lib/markdown/mdast-util-from-markdown-service.d.ts +5 -0
- package/lib/markdown/mdast-util-from-markdown-service.js +12 -0
- package/lib/markdown/mdast-util-from-markdown-worker.d.ts +2 -0
- package/lib/markdown/mdast-util-from-markdown-worker.js +8 -0
- package/lib/markdown/process-markdown.d.ts +6 -0
- package/lib/markdown/process-markdown.js +82 -0
- package/lib/markdown/yaml.d.ts +9 -0
- package/lib/markdown/yaml.js +86 -0
- package/lib/parser/index.d.ts +4 -0
- package/lib/parser/index.js +2 -1
- package/lib/parser/process-template.js +2 -1
- package/lib/parser/ts-patch.js +9 -2
- package/package.json +98 -95
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ You can check it on [Online DEMO](https://ota-meshi.github.io/astro-eslint-parse
|
|
|
17
17
|
|
|
18
18
|
This parser is in the ***experimental stages*** of development.
|
|
19
19
|
|
|
20
|
-
At least it works fine with a [
|
|
20
|
+
At least it works fine with a [withastro/docs](https://github.com/withastro/docs) repository.
|
|
21
21
|
|
|
22
22
|
[@astrojs/compiler]: https://github.com/withastro/compiler
|
|
23
23
|
|
|
@@ -41,7 +41,10 @@ npm install --save-dev eslint astro-eslint-parser
|
|
|
41
41
|
|
|
42
42
|
## 📖 Usage
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
**First, we recommend using [eslint-plugin-astro] rather than just the parser.**
|
|
45
|
+
The following usage it are for introducing only the parser. This is not useful for most people. It can be useful if you create your own plugin.
|
|
46
|
+
|
|
47
|
+
1. Write `overrides[*].parser` option into your `.eslintrc.*` file.
|
|
45
48
|
|
|
46
49
|
```json
|
|
47
50
|
{
|
|
@@ -126,6 +129,48 @@ module.exports = {
|
|
|
126
129
|
}
|
|
127
130
|
```
|
|
128
131
|
|
|
132
|
+
### parserOptions.astroFeatures
|
|
133
|
+
|
|
134
|
+
You can use `parserOptions.astroFeatures` property to specify how to parse related to Astro component features. For example:
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"parser": "astro-eslint-parser",
|
|
139
|
+
"parserOptions": {
|
|
140
|
+
"astroFeatures": {
|
|
141
|
+
"syntax": "auto",
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### parserOptions.vueFeatures.syntax
|
|
148
|
+
|
|
149
|
+
You can use `parserOptions.vueFeatures.syntax` property to choose whether to parse as Astro Component (`*.astro`) or Astro Markdown Page (`*.md`).
|
|
150
|
+
If `"astro"` is specified, it will be parsed as `*.astro`. If `"markdown"` is specified, it will be parsed as `*.md`. If `"auto"` is specified, it will be automatically selected from the file extensions.
|
|
151
|
+
For example:
|
|
152
|
+
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"parser": "astro-eslint-parser",
|
|
156
|
+
"parserOptions": {
|
|
157
|
+
"astroFeatures": {
|
|
158
|
+
"syntax": "auto", // or "astro", or "markdown"
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
#### Known Limitations on Markdown Pages
|
|
165
|
+
|
|
166
|
+
There are some known limitations when parsing Markdown Pages for ESLint integration.
|
|
167
|
+
|
|
168
|
+
- Incompatible with ESLint's [indent] rule. Turn off the [indent] rule in the markdown file. Otherwise the file syntax will be broken.
|
|
169
|
+
- Incompatible with [eslint-plugin-markdown]. eslint-plugin-markdown separates the contents of markdown by the processor. So using this parser doesn't work because the parser doesn't know the whole markdown.
|
|
170
|
+
|
|
171
|
+
[indent]: https://eslint.org/docs/rules/indent
|
|
172
|
+
[eslint-plugin-markdown]: https://github.com/eslint/eslint-plugin-markdown
|
|
173
|
+
|
|
129
174
|
## :computer: Editor Integrations
|
|
130
175
|
|
|
131
176
|
### Visual Studio Code
|
package/lib/context/script.d.ts
CHANGED
|
@@ -4,8 +4,10 @@ import type { ESLintExtendedProgram } from "../types";
|
|
|
4
4
|
declare class RestoreNodeProcessContext {
|
|
5
5
|
readonly result: ESLintExtendedProgram;
|
|
6
6
|
readonly removeTokens: Set<(token: TSESTree.Token) => boolean>;
|
|
7
|
-
|
|
7
|
+
private readonly parentMap;
|
|
8
|
+
constructor(result: ESLintExtendedProgram, parentMap: Map<TSESTree.Node, TSESTree.Node | null>);
|
|
8
9
|
addRemoveToken(test: (token: TSESTree.Token) => boolean): void;
|
|
10
|
+
getParent(node: TSESTree.Node): TSESTree.Node | null;
|
|
9
11
|
}
|
|
10
12
|
export declare class ScriptContext {
|
|
11
13
|
private readonly ctx;
|
|
@@ -16,11 +18,12 @@ export declare class ScriptContext {
|
|
|
16
18
|
private readonly tokens;
|
|
17
19
|
private readonly restoreNodeProcesses;
|
|
18
20
|
constructor(ctx: Context);
|
|
21
|
+
get originalCode(): string;
|
|
19
22
|
skipOriginalOffset(offset: number): void;
|
|
20
23
|
appendOriginal(index: number): void;
|
|
21
24
|
appendScript(fragment: string): void;
|
|
22
25
|
addToken(type: TSESTree.Token["type"], range: TSESTree.Range): void;
|
|
23
|
-
addRestoreNodeProcess(process: (node: TSESTree.Node, context: RestoreNodeProcessContext
|
|
26
|
+
addRestoreNodeProcess(process: (node: TSESTree.Node, context: RestoreNodeProcessContext) => boolean): void;
|
|
24
27
|
/**
|
|
25
28
|
* Restore AST nodes
|
|
26
29
|
*/
|
package/lib/context/script.js
CHANGED
|
@@ -3,13 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ScriptContext = void 0;
|
|
4
4
|
const traverse_1 = require("../traverse");
|
|
5
5
|
class RestoreNodeProcessContext {
|
|
6
|
-
constructor(result) {
|
|
6
|
+
constructor(result, parentMap) {
|
|
7
7
|
this.removeTokens = new Set();
|
|
8
8
|
this.result = result;
|
|
9
|
+
this.parentMap = parentMap;
|
|
9
10
|
}
|
|
10
11
|
addRemoveToken(test) {
|
|
11
12
|
this.removeTokens.add(test);
|
|
12
13
|
}
|
|
14
|
+
getParent(node) {
|
|
15
|
+
return this.parentMap.get(node) || null;
|
|
16
|
+
}
|
|
13
17
|
}
|
|
14
18
|
class ScriptContext {
|
|
15
19
|
constructor(ctx) {
|
|
@@ -21,6 +25,9 @@ class ScriptContext {
|
|
|
21
25
|
this.restoreNodeProcesses = [];
|
|
22
26
|
this.ctx = ctx;
|
|
23
27
|
}
|
|
28
|
+
get originalCode() {
|
|
29
|
+
return this.ctx.code;
|
|
30
|
+
}
|
|
24
31
|
skipOriginalOffset(offset) {
|
|
25
32
|
this.consumedIndex += offset;
|
|
26
33
|
}
|
|
@@ -41,6 +48,9 @@ class ScriptContext {
|
|
|
41
48
|
this.fragments.push({ start, end: this.script.length });
|
|
42
49
|
}
|
|
43
50
|
addToken(type, range) {
|
|
51
|
+
if (range[0] >= range[1]) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
44
54
|
this.tokens.push(this.ctx.buildToken(type, range));
|
|
45
55
|
}
|
|
46
56
|
addRestoreNodeProcess(process) {
|
|
@@ -76,12 +86,12 @@ class ScriptContext {
|
|
|
76
86
|
for (const token of result.ast.comments || []) {
|
|
77
87
|
this.remapLocation(token);
|
|
78
88
|
}
|
|
79
|
-
const context = new RestoreNodeProcessContext(result);
|
|
89
|
+
const context = new RestoreNodeProcessContext(result, traversed);
|
|
80
90
|
let restoreNodeProcesses = this.restoreNodeProcesses;
|
|
81
91
|
for (const [node, parent] of traversed) {
|
|
82
92
|
if (!parent)
|
|
83
93
|
continue;
|
|
84
|
-
restoreNodeProcesses = restoreNodeProcesses.filter((proc) => !proc(node, context
|
|
94
|
+
restoreNodeProcesses = restoreNodeProcesses.filter((proc) => !proc(node, context));
|
|
85
95
|
}
|
|
86
96
|
if (context.removeTokens.size) {
|
|
87
97
|
const tokens = result.ast.tokens || [];
|
package/lib/index.d.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import { parseForESLint } from "./parser";
|
|
1
|
+
import { parseForESLint as parseAstro } from "./parser";
|
|
2
|
+
import { parseForESLint as parseMarkdown } from "./markdown";
|
|
2
3
|
import { parseTemplate, ParseTemplateResult } from "./astro-tools";
|
|
3
4
|
import * as AST from "./ast";
|
|
4
5
|
import { traverseNodes } from "./traverse";
|
|
5
6
|
import { ParseError } from "./errors";
|
|
6
7
|
export { AST, ParseError };
|
|
7
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Parse source code
|
|
10
|
+
*/
|
|
11
|
+
export declare function parseForESLint(code: string, options?: any): ReturnType<typeof parseAstro | typeof parseMarkdown>;
|
|
8
12
|
export declare const VisitorKeys: import("eslint").SourceCode.VisitorKeys;
|
|
9
13
|
export { traverseNodes, parseTemplate, ParseTemplateResult };
|
package/lib/index.js
CHANGED
|
@@ -25,7 +25,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.parseTemplate = exports.traverseNodes = exports.VisitorKeys = exports.parseForESLint = exports.ParseError = exports.AST = void 0;
|
|
27
27
|
const parser_1 = require("./parser");
|
|
28
|
-
|
|
28
|
+
const markdown_1 = require("./markdown");
|
|
29
29
|
const astro_tools_1 = require("./astro-tools");
|
|
30
30
|
Object.defineProperty(exports, "parseTemplate", { enumerable: true, get: function () { return astro_tools_1.parseTemplate; } });
|
|
31
31
|
const AST = __importStar(require("./ast"));
|
|
@@ -35,6 +35,18 @@ Object.defineProperty(exports, "traverseNodes", { enumerable: true, get: functio
|
|
|
35
35
|
const visitor_keys_1 = require("./visitor-keys");
|
|
36
36
|
const errors_1 = require("./errors");
|
|
37
37
|
Object.defineProperty(exports, "ParseError", { enumerable: true, get: function () { return errors_1.ParseError; } });
|
|
38
|
+
/**
|
|
39
|
+
* Parse source code
|
|
40
|
+
*/
|
|
41
|
+
function parseForESLint(code, options) {
|
|
42
|
+
const syntax = options?.astroFeatures?.syntax ?? "auto";
|
|
43
|
+
if (syntax === "markdown" ||
|
|
44
|
+
(syntax === "auto" && options?.filePath?.endsWith(".md"))) {
|
|
45
|
+
return (0, markdown_1.parseForESLint)(code, options);
|
|
46
|
+
}
|
|
47
|
+
return (0, parser_1.parseForESLint)(code, options);
|
|
48
|
+
}
|
|
49
|
+
exports.parseForESLint = parseForESLint;
|
|
38
50
|
// Keys
|
|
39
51
|
// eslint-disable-next-line @typescript-eslint/naming-convention -- ignore
|
|
40
52
|
exports.VisitorKeys = visitor_keys_1.KEYS;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseFrontmatter = void 0;
|
|
4
|
+
/** Parse frontmatter */
|
|
5
|
+
function parseFrontmatter(code) {
|
|
6
|
+
if (!code.startsWith("---") || code[3] === "-") {
|
|
7
|
+
return {
|
|
8
|
+
frontmatter: null,
|
|
9
|
+
content: {
|
|
10
|
+
range: [0, code.length],
|
|
11
|
+
value: code,
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
let closeIndex = code.indexOf("\n---", 3);
|
|
16
|
+
let contentOpenIndex = closeIndex + 4;
|
|
17
|
+
if (closeIndex === -1) {
|
|
18
|
+
closeIndex = code.length;
|
|
19
|
+
contentOpenIndex = code.length;
|
|
20
|
+
}
|
|
21
|
+
let openIndex = 3;
|
|
22
|
+
if (code[openIndex] === "\r") {
|
|
23
|
+
openIndex++;
|
|
24
|
+
}
|
|
25
|
+
if (code[openIndex] === "\n") {
|
|
26
|
+
openIndex++;
|
|
27
|
+
}
|
|
28
|
+
if (openIndex < closeIndex && code[closeIndex] === "\n") {
|
|
29
|
+
closeIndex--;
|
|
30
|
+
}
|
|
31
|
+
if (openIndex < closeIndex && code[closeIndex] === "\r") {
|
|
32
|
+
closeIndex++;
|
|
33
|
+
}
|
|
34
|
+
if (code[contentOpenIndex] === "\r") {
|
|
35
|
+
contentOpenIndex++;
|
|
36
|
+
}
|
|
37
|
+
if (code[contentOpenIndex] === "\n") {
|
|
38
|
+
contentOpenIndex++;
|
|
39
|
+
}
|
|
40
|
+
const frontmatter = code.slice(openIndex, closeIndex + 1);
|
|
41
|
+
const content = code.slice(contentOpenIndex);
|
|
42
|
+
return {
|
|
43
|
+
frontmatter: {
|
|
44
|
+
range: [openIndex, closeIndex + 1],
|
|
45
|
+
value: frontmatter,
|
|
46
|
+
},
|
|
47
|
+
content: {
|
|
48
|
+
range: [contentOpenIndex, code.length],
|
|
49
|
+
value: content,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
exports.parseFrontmatter = parseFrontmatter;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ScopeManager } from "eslint-scope";
|
|
2
|
+
import type { AstroProgram } from "../ast";
|
|
3
|
+
import type { ParseResult } from "@astrojs/compiler/node";
|
|
4
|
+
/**
|
|
5
|
+
* Parse source code
|
|
6
|
+
*/
|
|
7
|
+
export declare function parseForESLint(code: string, options?: any): {
|
|
8
|
+
ast: AstroProgram;
|
|
9
|
+
services: Record<string, any> & {
|
|
10
|
+
isAstro: true;
|
|
11
|
+
getAstroAst: () => ParseResult;
|
|
12
|
+
isAstroMarkdown: true;
|
|
13
|
+
getAstroMarkdownFrontmatter: () => any;
|
|
14
|
+
};
|
|
15
|
+
visitorKeys: {
|
|
16
|
+
[type: string]: string[];
|
|
17
|
+
};
|
|
18
|
+
scopeManager: ScopeManager;
|
|
19
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseForESLint = void 0;
|
|
4
|
+
const context_1 = require("../context");
|
|
5
|
+
const mdast_util_from_markdown_service_1 = require("./mdast-util-from-markdown-service");
|
|
6
|
+
const frontmatter_1 = require("./frontmatter");
|
|
7
|
+
const process_markdown_1 = require("./process-markdown");
|
|
8
|
+
const parser_1 = require("../parser");
|
|
9
|
+
const sort_1 = require("../parser/sort");
|
|
10
|
+
const script_1 = require("../context/script");
|
|
11
|
+
const yaml_1 = require("./yaml");
|
|
12
|
+
/**
|
|
13
|
+
* Parse source code
|
|
14
|
+
*/
|
|
15
|
+
function parseForESLint(code, options) {
|
|
16
|
+
const { frontmatter, content } = (0, frontmatter_1.parseFrontmatter)(code);
|
|
17
|
+
const ctx = new context_1.Context(code);
|
|
18
|
+
const root = (0, mdast_util_from_markdown_service_1.parseMarkdown)(content.value);
|
|
19
|
+
const scriptContext = new script_1.ScriptContext(ctx);
|
|
20
|
+
let yamlResult;
|
|
21
|
+
if (frontmatter) {
|
|
22
|
+
scriptContext.appendOriginal(frontmatter.range[0]);
|
|
23
|
+
yamlResult = (0, yaml_1.parseYaml)(frontmatter);
|
|
24
|
+
if (yamlResult) {
|
|
25
|
+
scriptContext.skipOriginalOffset(yamlResult.setupValueRange[0] - frontmatter.range[0]);
|
|
26
|
+
scriptContext.appendOriginal(yamlResult.setupValueRange[1]);
|
|
27
|
+
scriptContext.skipOriginalOffset(frontmatter.range[1] - yamlResult.setupValueRange[1]);
|
|
28
|
+
scriptContext.addToken("YAMLToken", [
|
|
29
|
+
frontmatter.range[0],
|
|
30
|
+
yamlResult.before,
|
|
31
|
+
]);
|
|
32
|
+
scriptContext.addToken("YAMLToken", [
|
|
33
|
+
yamlResult.after,
|
|
34
|
+
frontmatter.range[1],
|
|
35
|
+
]);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
scriptContext.skipOriginalOffset(frontmatter.range[1] - frontmatter.range[0]);
|
|
39
|
+
scriptContext.addToken("YAMLToken", [
|
|
40
|
+
frontmatter.range[0],
|
|
41
|
+
frontmatter.range[1],
|
|
42
|
+
]);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
(0, process_markdown_1.processMarkdown)(scriptContext, root, content.range[0]);
|
|
46
|
+
scriptContext.appendOriginal(code.length);
|
|
47
|
+
const resultAstro = (0, parser_1.parseForESLint)(scriptContext.script, options);
|
|
48
|
+
scriptContext.restore(resultAstro);
|
|
49
|
+
(0, sort_1.sort)(resultAstro.ast.comments);
|
|
50
|
+
(0, sort_1.sort)(resultAstro.ast.tokens);
|
|
51
|
+
(0, parser_1.extractTokens)(resultAstro, ctx);
|
|
52
|
+
resultAstro.services = Object.assign(resultAstro.services || {}, {
|
|
53
|
+
isAstroMarkdown: true,
|
|
54
|
+
getAstroMarkdownFrontmatter() {
|
|
55
|
+
return yamlResult?.getYamlValue();
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
return resultAstro;
|
|
59
|
+
}
|
|
60
|
+
exports.parseForESLint = parseForESLint;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseMarkdown = void 0;
|
|
4
|
+
const synckit_1 = require("synckit");
|
|
5
|
+
const parseSync = (0, synckit_1.createSyncFn)(require.resolve("./mdast-util-from-markdown-worker"));
|
|
6
|
+
/**
|
|
7
|
+
* Parse code by `mdast-util-from-markdown`
|
|
8
|
+
*/
|
|
9
|
+
function parseMarkdown(code) {
|
|
10
|
+
return parseSync(code);
|
|
11
|
+
}
|
|
12
|
+
exports.parseMarkdown = parseMarkdown;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const synckit_1 = require("synckit");
|
|
4
|
+
const dynamicImport = new Function("m", "return import(m)");
|
|
5
|
+
(0, synckit_1.runAsWorker)(async (source) => {
|
|
6
|
+
const { fromMarkdown } = await dynamicImport("mdast-util-from-markdown");
|
|
7
|
+
return fromMarkdown(source);
|
|
8
|
+
});
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.processMarkdown = void 0;
|
|
4
|
+
const types_1 = require("@typescript-eslint/types");
|
|
5
|
+
/**
|
|
6
|
+
* Process the markdown ast to generate a ScriptContext.
|
|
7
|
+
*/
|
|
8
|
+
function processMarkdown(script, root, offset) {
|
|
9
|
+
walk(root, (node) => {
|
|
10
|
+
const start = node.position.start.offset + offset;
|
|
11
|
+
const end = node.position.end.offset + offset;
|
|
12
|
+
script.appendOriginal(start);
|
|
13
|
+
if (node.type === "code" || node.type === "inlineCode") {
|
|
14
|
+
script.appendScript(`<></>`);
|
|
15
|
+
script.skipOriginalOffset(end - start);
|
|
16
|
+
script.addRestoreNodeProcess((scriptNode, context) => {
|
|
17
|
+
if (scriptNode.range[0] === start &&
|
|
18
|
+
scriptNode.type === types_1.AST_NODE_TYPES.JSXFragment) {
|
|
19
|
+
delete scriptNode.openingFragment;
|
|
20
|
+
delete scriptNode.closingFragment;
|
|
21
|
+
delete scriptNode.expression;
|
|
22
|
+
delete scriptNode.children;
|
|
23
|
+
const text = script.originalCode.slice(start, end);
|
|
24
|
+
const mdNode = scriptNode;
|
|
25
|
+
mdNode.type = "AstroRawText";
|
|
26
|
+
mdNode.value = text;
|
|
27
|
+
mdNode.raw = text;
|
|
28
|
+
let parent = context.getParent(scriptNode);
|
|
29
|
+
while (parent) {
|
|
30
|
+
let update = false;
|
|
31
|
+
if (parent.range[0] > scriptNode.range[0]) {
|
|
32
|
+
parent.range[0] = scriptNode.range[0];
|
|
33
|
+
parent.loc.start = {
|
|
34
|
+
line: scriptNode.loc.start.line,
|
|
35
|
+
column: scriptNode.loc.start.column,
|
|
36
|
+
};
|
|
37
|
+
update = true;
|
|
38
|
+
}
|
|
39
|
+
if (parent.range[1] < scriptNode.range[1]) {
|
|
40
|
+
parent.range[1] = scriptNode.range[1];
|
|
41
|
+
parent.loc.end = {
|
|
42
|
+
line: scriptNode.loc.end.line,
|
|
43
|
+
column: scriptNode.loc.end.column,
|
|
44
|
+
};
|
|
45
|
+
update = true;
|
|
46
|
+
}
|
|
47
|
+
if (!update) {
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
parent = context.getParent(parent);
|
|
51
|
+
}
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
});
|
|
56
|
+
script.addToken(types_1.AST_TOKEN_TYPES.JSXText, [start, end]);
|
|
57
|
+
}
|
|
58
|
+
}, (node) => {
|
|
59
|
+
// const start = node.position!.start.offset! + offset
|
|
60
|
+
const end = node.position.end.offset + offset;
|
|
61
|
+
script.appendOriginal(end);
|
|
62
|
+
});
|
|
63
|
+
script.addRestoreNodeProcess((scriptNode) => {
|
|
64
|
+
if (scriptNode.type === "JSXText") {
|
|
65
|
+
const rawNode = scriptNode;
|
|
66
|
+
rawNode.type = "AstroRawText";
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
exports.processMarkdown = processMarkdown;
|
|
72
|
+
/** walk nodes */
|
|
73
|
+
function walk(parent, enter, leave, parents = []) {
|
|
74
|
+
const currParents = [parent, ...parents];
|
|
75
|
+
if ("children" in parent) {
|
|
76
|
+
for (const node of parent.children) {
|
|
77
|
+
enter(node, currParents);
|
|
78
|
+
walk(node, enter, leave, currParents);
|
|
79
|
+
leave(node, currParents);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { MarkdownContent } from "./frontmatter";
|
|
2
|
+
export declare type FrontmatterYAMLResult = {
|
|
3
|
+
before: number;
|
|
4
|
+
setupValueRange: [number, number];
|
|
5
|
+
after: number;
|
|
6
|
+
getYamlValue: () => any;
|
|
7
|
+
};
|
|
8
|
+
/** Parse for yaml */
|
|
9
|
+
export declare function parseYaml(frontmatter: MarkdownContent): FrontmatterYAMLResult | null;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseYaml = void 0;
|
|
4
|
+
const yaml_1 = require("yaml");
|
|
5
|
+
/** Parse for yaml */
|
|
6
|
+
function parseYaml(frontmatter) {
|
|
7
|
+
const doc = (0, yaml_1.parseDocument)(frontmatter.value, { keepSourceTokens: true });
|
|
8
|
+
const range = getSetupRange(doc);
|
|
9
|
+
if (!range) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
let before = range[0];
|
|
13
|
+
let after = range[1];
|
|
14
|
+
while (isSpace(frontmatter.value[before - 1])) {
|
|
15
|
+
before--;
|
|
16
|
+
}
|
|
17
|
+
while (isSpace(frontmatter.value[after])) {
|
|
18
|
+
after++;
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
before: before + frontmatter.range[0],
|
|
22
|
+
setupValueRange: [
|
|
23
|
+
range[0] + frontmatter.range[0],
|
|
24
|
+
range[1] + frontmatter.range[0],
|
|
25
|
+
],
|
|
26
|
+
after: after + frontmatter.range[0],
|
|
27
|
+
getYamlValue: () => doc.toJS(),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
exports.parseYaml = parseYaml;
|
|
31
|
+
/** Checks whether the given char is spaces, or not */
|
|
32
|
+
function isSpace(c) {
|
|
33
|
+
return c && !c.trim();
|
|
34
|
+
}
|
|
35
|
+
/** Get setup range */
|
|
36
|
+
function getSetupRange(ast) {
|
|
37
|
+
if (!ast.contents) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
if (!(0, yaml_1.isMap)(ast.contents)) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
for (const item of ast.contents.items) {
|
|
44
|
+
if (!(0, yaml_1.isScalar)(item.key) || !(0, yaml_1.isScalar)(item.value)) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (item.key.value !== "setup") {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (item.value.type === "PLAIN") {
|
|
51
|
+
return [item.value.range[0], item.value.range[1]];
|
|
52
|
+
}
|
|
53
|
+
if (item.value.type === "QUOTE_DOUBLE" ||
|
|
54
|
+
item.value.type === "QUOTE_SINGLE") {
|
|
55
|
+
return [item.value.range[0] + 1, item.value.range[1] - 1];
|
|
56
|
+
}
|
|
57
|
+
if (item.value.type === "BLOCK_FOLDED" ||
|
|
58
|
+
item.value.type === "BLOCK_LITERAL") {
|
|
59
|
+
const cst = item.value.srcToken;
|
|
60
|
+
let blockStart = cst.offset;
|
|
61
|
+
for (const token of cst.props) {
|
|
62
|
+
if (isCommentOrSpace(token) ||
|
|
63
|
+
token.type === "block-scalar-header") {
|
|
64
|
+
blockStart = token.offset + token.source.length;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
/* istanbul ignore next */
|
|
68
|
+
throw new Error(`Unknown token:${token.type}`);
|
|
69
|
+
}
|
|
70
|
+
return [blockStart, item.value.range[1]];
|
|
71
|
+
}
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Checks whether the given cst is comments, spaces, or not
|
|
78
|
+
*/
|
|
79
|
+
function isCommentOrSpace(node) {
|
|
80
|
+
if (node.type === "space" ||
|
|
81
|
+
node.type === "newline" ||
|
|
82
|
+
node.type === "comment") {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
return false;
|
|
86
|
+
}
|
package/lib/parser/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import type { Context } from "../context";
|
|
1
2
|
import type { AstroProgram } from "../ast";
|
|
2
3
|
import type { ScopeManager } from "eslint-scope";
|
|
3
4
|
import type { ParseResult } from "@astrojs/compiler";
|
|
5
|
+
import type { ESLintExtendedProgram } from "../types";
|
|
4
6
|
/**
|
|
5
7
|
* Parse source code
|
|
6
8
|
*/
|
|
@@ -15,3 +17,5 @@ export declare function parseForESLint(code: string, options?: any): {
|
|
|
15
17
|
};
|
|
16
18
|
scopeManager: ScopeManager;
|
|
17
19
|
};
|
|
20
|
+
/** Extract tokens */
|
|
21
|
+
export declare function extractTokens(ast: ESLintExtendedProgram, ctx: Context): void;
|
package/lib/parser/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseForESLint = void 0;
|
|
3
|
+
exports.extractTokens = exports.parseForESLint = void 0;
|
|
4
4
|
const visitor_keys_1 = require("../visitor-keys");
|
|
5
5
|
const types_1 = require("@typescript-eslint/types");
|
|
6
6
|
const script_1 = require("./script");
|
|
@@ -69,3 +69,4 @@ function extractTokens(ast, ctx) {
|
|
|
69
69
|
return /^[^\w$]$/iu.test(c);
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
|
+
exports.extractTokens = extractTokens;
|
|
@@ -328,7 +328,8 @@ function processTemplate(ctx, resultTemplate) {
|
|
|
328
328
|
const offset = (0, astro_1.calcContentEndOffset)(node, ctx);
|
|
329
329
|
script.appendOriginal(offset);
|
|
330
330
|
script.appendScript(`</${node.name}>`);
|
|
331
|
-
script.addRestoreNodeProcess((scriptNode,
|
|
331
|
+
script.addRestoreNodeProcess((scriptNode, context) => {
|
|
332
|
+
const parent = context.getParent(scriptNode);
|
|
332
333
|
if (scriptNode.range[0] === offset &&
|
|
333
334
|
scriptNode.type ===
|
|
334
335
|
types_1.AST_NODE_TYPES.JSXClosingElement &&
|
package/lib/parser/ts-patch.js
CHANGED
|
@@ -11,6 +11,13 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
11
11
|
* Apply a patch to parse .astro files as TSX.
|
|
12
12
|
*/
|
|
13
13
|
function tsPatch(scriptParserOptions) {
|
|
14
|
+
let targetExt = ".astro";
|
|
15
|
+
if (scriptParserOptions.filePath) {
|
|
16
|
+
const ext = path_1.default.extname(scriptParserOptions.filePath);
|
|
17
|
+
if (ext) {
|
|
18
|
+
targetExt = ext;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
14
21
|
try {
|
|
15
22
|
// Apply a patch to parse .astro files as TSX.
|
|
16
23
|
const cwd = process.cwd();
|
|
@@ -20,13 +27,13 @@ function tsPatch(scriptParserOptions) {
|
|
|
20
27
|
if (typeof ensureScriptKind === "function" &&
|
|
21
28
|
typeof getScriptKindFromFileName === "function") {
|
|
22
29
|
ts.ensureScriptKind = function (fileName, ...args) {
|
|
23
|
-
if (fileName.endsWith(
|
|
30
|
+
if (fileName.endsWith(targetExt)) {
|
|
24
31
|
return ts.ScriptKind.TSX;
|
|
25
32
|
}
|
|
26
33
|
return ensureScriptKind.call(this, fileName, ...args);
|
|
27
34
|
};
|
|
28
35
|
ts.getScriptKindFromFileName = function (fileName, ...args) {
|
|
29
|
-
if (fileName.endsWith(
|
|
36
|
+
if (fileName.endsWith(targetExt)) {
|
|
30
37
|
return ts.ScriptKind.TSX;
|
|
31
38
|
}
|
|
32
39
|
return getScriptKindFromFileName.call(this, fileName, ...args);
|
package/package.json
CHANGED
|
@@ -1,97 +1,100 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
2
|
+
"name": "astro-eslint-parser",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Astro component parser for ESLint",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"lib"
|
|
8
|
+
],
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": "^14.17.0 || >=16.0.0"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"prebuild": "npm run -s clean",
|
|
14
|
+
"build": "tsc --project ./tsconfig.build.json",
|
|
15
|
+
"clean": "rimraf .nyc_output lib coverage",
|
|
16
|
+
"lint": "eslint . --ext .js,.ts,.json,.astro,.svelte",
|
|
17
|
+
"eslint-fix": "npm run lint -- --fix",
|
|
18
|
+
"test": "mocha --require ts-node/register \"tests/src/**/*.ts\" --reporter dot --timeout 60000",
|
|
19
|
+
"cover": "nyc --reporter=lcov npm run test",
|
|
20
|
+
"debug": "mocha --require ts-node/register/transpile-only \"tests/src/**/*.ts\" --reporter dot --timeout 60000",
|
|
21
|
+
"preversion": "npm run lint && npm test",
|
|
22
|
+
"update-fixtures": "DEBUG='astro-eslint-parser' ts-node --transpile-only ./tools/update-fixtures.ts",
|
|
23
|
+
"debug-parser": "ts-node --transpile-only ./tools/parser-test.ts",
|
|
24
|
+
"eslint-playground": "eslint tests/fixtures --ext .astro --config .eslintrc-for-playground.js --format codeframe",
|
|
25
|
+
"benchmark": "ts-node --transpile-only benchmark/index.ts"
|
|
26
|
+
},
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/ota-meshi/astro-eslint-parser.git"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"astro",
|
|
33
|
+
"astrojs",
|
|
34
|
+
"eslint",
|
|
35
|
+
"parser"
|
|
36
|
+
],
|
|
37
|
+
"author": "Yosuke Ota",
|
|
38
|
+
"funding": "https://github.com/sponsors/ota-meshi",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/ota-meshi/astro-eslint-parser/issues"
|
|
42
|
+
},
|
|
43
|
+
"homepage": "https://github.com/ota-meshi/astro-eslint-parser#readme",
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@astrojs/compiler": "^0.18.0",
|
|
46
|
+
"@typescript-eslint/types": "^5.25.0",
|
|
47
|
+
"debug": "^4.3.4",
|
|
48
|
+
"eslint-visitor-keys": "^3.0.0",
|
|
49
|
+
"espree": "^9.0.0",
|
|
50
|
+
"mdast-util-from-markdown": "^1.2.0",
|
|
51
|
+
"synckit": "^0.7.1",
|
|
52
|
+
"yaml": "^2.1.1"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@ota-meshi/eslint-plugin": "^0.11.0",
|
|
56
|
+
"@types/benchmark": "^2.1.1",
|
|
57
|
+
"@types/chai": "^4.3.0",
|
|
58
|
+
"@types/debug": "^4.1.7",
|
|
59
|
+
"@types/eslint": "^8.0.0",
|
|
60
|
+
"@types/eslint-scope": "^3.7.0",
|
|
61
|
+
"@types/eslint-visitor-keys": "^1.0.0",
|
|
62
|
+
"@types/mocha": "^9.0.0",
|
|
63
|
+
"@types/node": "^16.0.0",
|
|
64
|
+
"@types/semver": "^7.3.9",
|
|
65
|
+
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
|
66
|
+
"@typescript-eslint/parser": "^5.4.0",
|
|
67
|
+
"astro-eslint-parser": ">=0.1.0",
|
|
68
|
+
"benchmark": "^2.1.4",
|
|
69
|
+
"chai": "^4.3.4",
|
|
70
|
+
"code-red": "^0.2.3",
|
|
71
|
+
"eslint": "^8.15.0",
|
|
72
|
+
"eslint-config-prettier": "^8.3.0",
|
|
73
|
+
"eslint-formatter-codeframe": "^7.32.1",
|
|
74
|
+
"eslint-plugin-astro": "^0.14.0",
|
|
75
|
+
"eslint-plugin-eslint-comments": "^3.2.0",
|
|
76
|
+
"eslint-plugin-json-schema-validator": "^3.0.0",
|
|
77
|
+
"eslint-plugin-jsonc": "^2.0.0",
|
|
78
|
+
"eslint-plugin-jsx-a11y": "^6.5.1",
|
|
79
|
+
"eslint-plugin-node": "^11.1.0",
|
|
80
|
+
"eslint-plugin-node-dependencies": "^0.9.0",
|
|
81
|
+
"eslint-plugin-prettier": "^4.0.0",
|
|
82
|
+
"eslint-plugin-react": "^7.29.4",
|
|
83
|
+
"eslint-plugin-regexp": "^1.5.0",
|
|
84
|
+
"eslint-plugin-svelte": "^2.0.0",
|
|
85
|
+
"estree-walker": "^3.0.0",
|
|
86
|
+
"locate-character": "^2.0.5",
|
|
87
|
+
"magic-string": "^0.26.0",
|
|
88
|
+
"mocha": "^10.0.0",
|
|
89
|
+
"mocha-chai-jest-snapshot": "^1.1.3",
|
|
90
|
+
"nyc": "^15.1.0",
|
|
91
|
+
"prettier": "^2.0.5",
|
|
92
|
+
"prettier-plugin-astro": "^0.1.0-0",
|
|
93
|
+
"prettier-plugin-svelte": "^2.7.0",
|
|
94
|
+
"semver": "^7.3.5",
|
|
95
|
+
"string-replace-loader": "^3.0.3",
|
|
96
|
+
"svelte": "^3.48.0",
|
|
97
|
+
"ts-node": "^10.4.0",
|
|
98
|
+
"typescript": "~4.7.0"
|
|
99
|
+
}
|
|
97
100
|
}
|