/
index.js
executable file
路100 lines (85 loc) 路 2.53 KB
/
index.js
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
// @flow
import { type Options } from "./options";
import {
hasPlugin,
validatePlugins,
mixinPluginNames,
mixinPlugins,
type PluginList,
} from "./plugin-utils";
import Parser from "./parser";
import { types as tokTypes } from "./tokenizer/types";
import "./tokenizer/context";
import type { Expression, File } from "./types";
export function parse(input: string, options?: Options): File {
if (options && options.sourceType === "unambiguous") {
options = {
...options,
};
try {
options.sourceType = "module";
const parser = getParser(options, input);
const ast = parser.parse();
if (parser.sawUnambiguousESM) {
return ast;
}
if (parser.ambiguousScriptDifferentAst) {
// Top level await introduces code which can be both a valid script and
// a valid module, but which produces different ASTs:
// await
// 0
// can be parser either as an AwaitExpression, or as two ExpressionStatements.
try {
options.sourceType = "script";
return getParser(options, input).parse();
} catch {}
} else {
// This is both a valid module and a valid script, but
// we parse it as a script by default
ast.program.sourceType = "script";
}
return ast;
} catch (moduleError) {
try {
options.sourceType = "script";
return getParser(options, input).parse();
} catch {}
throw moduleError;
}
} else {
return getParser(options, input).parse();
}
}
export function parseExpression(input: string, options?: Options): Expression {
const parser = getParser(options, input);
if (parser.options.strictMode) {
parser.state.strict = true;
}
return parser.getExpression();
}
export { tokTypes };
function getParser(options: ?Options, input: string): Parser {
let cls = Parser;
if (options && options.plugins) {
validatePlugins(options.plugins);
cls = getParserClass(options.plugins);
}
return new cls(options, input);
}
const parserClassCache: { [key: string]: Class<Parser> } = {};
/** Get a Parser class with plugins applied. */
function getParserClass(pluginsFromOptions: PluginList): Class<Parser> {
const pluginList = mixinPluginNames.filter(name =>
hasPlugin(pluginsFromOptions, name),
);
const key = pluginList.join("/");
let cls = parserClassCache[key];
if (!cls) {
cls = Parser;
for (const plugin of pluginList) {
cls = mixinPlugins[plugin](cls);
}
parserClassCache[key] = cls;
}
return cls;
}