forked from firefox-devtools/debugger
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathast.js
More file actions
120 lines (103 loc) · 2.67 KB
/
ast.js
File metadata and controls
120 lines (103 loc) · 2.67 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
116
117
118
119
120
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
// @flow
import parseScriptTags from "parse-script-tags";
import * as babylon from "babylon";
import * as t from "@babel/types";
import isEmpty from "lodash/isEmpty";
import { getSource } from "../sources";
let ASTs = new Map();
function _parse(code, opts) {
return babylon.parse(code, {
...opts,
tokens: true
});
}
const sourceOptions = {
generated: {
tokens: true,
plugins: ["objectRestSpread"]
},
original: {
sourceType: "unambiguous",
tokens: true,
plugins: [
"jsx",
"flow",
"doExpressions",
"decorators",
"objectRestSpread",
"classProperties",
"exportDefaultFrom",
"exportNamespaceFrom",
"asyncGenerators",
"functionBind",
"functionSent",
"dynamicImport",
"react-jsx"
]
}
};
function parse(text: ?string, opts?: Object) {
let ast;
if (!text) {
return;
}
try {
ast = _parse(text, opts);
} catch (error) {
console.error(error);
ast = {};
}
return ast;
}
// Custom parser for parse-script-tags that adapts its input structure to
// our parser's signature
function htmlParser({ source, line }) {
return parse(source, { startLine: line });
}
export function parseScript(text: string, opts?: Object) {
return _parse(text, opts);
}
export function getAst(sourceId: string) {
if (ASTs.has(sourceId)) {
return ASTs.get(sourceId);
}
const source = getSource(sourceId);
let ast = {};
const { contentType } = source;
if (contentType == "text/html") {
ast = parseScriptTags(source.text, htmlParser) || {};
} else if (contentType && contentType.match(/(javascript|jsx)/)) {
const type = source.id.includes("original") ? "original" : "generated";
const options = sourceOptions[type];
ast = parse(source.text, options);
} else if (contentType && contentType.match(/typescript/)) {
const options = {
...sourceOptions.original,
plugins: [
...sourceOptions.original.plugins.filter(
p => p !== "flow" && p !== "decorators" && p !== "decorators2"
),
"decorators",
"typescript"
]
};
ast = parse(source.text, options);
}
ASTs.set(source.id, ast);
return ast;
}
export function clearASTs() {
ASTs = new Map();
}
type Visitor = { enter: Function };
export function traverseAst<T>(sourceId: string, visitor: Visitor, state?: T) {
const ast = getAst(sourceId);
if (isEmpty(ast)) {
return null;
}
t.traverse(ast, visitor, state);
return ast;
}