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
101 lines (83 loc) · 2.14 KB
/
ast.js
File metadata and controls
101 lines (83 loc) · 2.14 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
/* 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 traverse from "babel-traverse";
import isEmpty from "lodash/isEmpty";
import type { Source } from "debugger-html";
let ASTs = new Map();
function _parse(code, opts) {
return babylon.parse(code, opts);
}
const sourceOptions = {
generated: {},
original: {
sourceType: "module",
plugins: [
"jsx",
"flow",
"doExpressions",
"objectRestSpread",
"classProperties",
"exportExtensions",
"asyncGenerators",
"functionBind",
"functionSent",
"dynamicImport",
"templateInvalidEscapes"
]
}
};
function parse(text: ?string, opts?: Object) {
let ast;
if (!text) {
return;
}
try {
ast = _parse(text, opts);
} catch (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(source: Source) {
if (!source || !source.text) {
return {};
}
if (ASTs.has(source.id)) {
return ASTs.get(source.id);
}
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);
}
ASTs.set(source.id, ast);
return ast;
}
export function clearASTs() {
ASTs = new Map();
}
type Visitor = { enter: Function };
export function traverseAst(source: Source, visitor: Visitor) {
const ast = getAst(source);
if (isEmpty(ast)) {
return null;
}
traverse(ast, visitor);
return ast;
}