forked from eslint/code-explorer
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuse-ast.ts
More file actions
115 lines (105 loc) · 2.71 KB
/
use-ast.ts
File metadata and controls
115 lines (105 loc) · 2.71 KB
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import * as espree from "espree";
import type { Node as EstreeNode } from "estree";
import css from "@eslint/css";
import json from "@eslint/json";
import markdown from "@eslint/markdown";
import esquery from "esquery";
import { useExplorer } from "@/hooks/use-explorer";
import { assertIsUnreachable } from "@/lib/utils";
export function useAST() {
const {
language,
code,
jsOptions,
cssOptions,
jsonOptions,
markdownOptions,
esquerySelector,
} = useExplorer();
let astParseResult:
| { ok: true; ast: unknown }
| { ok: false; errors: Array<unknown> };
switch (language) {
case "javascript": {
try {
const ast = espree.parse(code.javascript, {
ecmaVersion: jsOptions.esVersion,
sourceType: jsOptions.sourceType,
ecmaFeatures: {
jsx: jsOptions.isJSX,
},
});
astParseResult = { ast, ok: true };
} catch (err) {
// error occured e.g. because the JS code cannot be parsed into an AST, or the esquery selector is no valid selector --> just ignore (no highlighted ranges)
astParseResult = { ok: false, errors: [err] };
}
break;
}
case "json": {
const { jsonMode } = jsonOptions;
const language = json.languages[jsonMode];
astParseResult = language.parse({
body: code.json,
path: "",
physicalPath: "",
bom: false,
});
break;
}
case "markdown": {
const { markdownMode, markdownFrontmatter } = markdownOptions;
const language = markdown.languages[markdownMode];
astParseResult = language.parse(
{ body: code.markdown, path: "", physicalPath: "", bom: false },
{
languageOptions: {
frontmatter:
markdownFrontmatter === "off"
? false
: markdownFrontmatter,
},
},
);
break;
}
case "css": {
const { cssMode, tolerant } = cssOptions;
const language = css.languages[cssMode];
astParseResult = language.parse(
{ body: code.css, path: "", physicalPath: "", bom: false },
{ languageOptions: { tolerant } },
);
break;
}
default: {
assertIsUnreachable(language);
}
}
if (astParseResult.ok) {
const esqueryMatchedNodes = getEsqueryMatchedNodes(
astParseResult.ast,
esquerySelector?.selector ?? "",
);
return {
...astParseResult,
esqueryMatchedNodes,
};
} else {
return astParseResult;
}
}
function getEsqueryMatchedNodes(ast: unknown, esquerySelector: string) {
if (esquerySelector.trim().length > 0) {
try {
const esqueryMatchedNodes = esquery.match(
ast as EstreeNode,
esquery.parse(esquerySelector),
) as unknown[];
return esqueryMatchedNodes;
} catch {
// error occured e.g. because the esquery selector is no valid selector --> just ignore (no nodes matched --> no highlighted ranges)
}
}
return [];
}