-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
/
parser.js
111 lines (94 loc) · 2.75 KB
/
parser.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
101
102
103
104
105
106
107
108
109
110
111
"use strict";
const path = require("path");
const ConfigError = require("../common/errors").ConfigError;
const jsLoc = require("../language-js/loc");
const { locStart, locEnd } = jsLoc;
// Use defineProperties()/getOwnPropertyDescriptor() to prevent
// triggering the parsers getters.
const ownNames = Object.getOwnPropertyNames;
const ownDescriptor = Object.getOwnPropertyDescriptor;
function getParsers(options) {
const parsers = {};
for (const plugin of options.plugins) {
if (!plugin.parsers) {
continue;
}
for (const name of ownNames(plugin.parsers)) {
Object.defineProperty(parsers, name, ownDescriptor(plugin.parsers, name));
}
}
return parsers;
}
function resolveParser(opts, parsers) {
parsers = parsers || getParsers(opts);
if (typeof opts.parser === "function") {
// Custom parser API always works with JavaScript.
return {
parse: opts.parser,
astFormat: "estree",
locStart,
locEnd
};
}
if (typeof opts.parser === "string") {
if (parsers.hasOwnProperty(opts.parser)) {
return parsers[opts.parser];
}
/* istanbul ignore next */
if (process.env.PRETTIER_TARGET === "universal") {
throw new ConfigError(
`Couldn't resolve parser "${opts.parser}". Parsers must be explicitly added to the standalone bundle.`
);
} else {
try {
return {
parse: eval("require")(path.resolve(process.cwd(), opts.parser)),
astFormat: "estree",
locStart,
locEnd
};
} catch (err) {
/* istanbul ignore next */
throw new ConfigError(`Couldn't resolve parser "${opts.parser}"`);
}
}
}
}
function parse(text, opts) {
const parsers = getParsers(opts);
// Create a new object {parserName: parseFn}. Uses defineProperty() to only call
// the parsers getters when actually calling the parser `parse` function.
const parsersForCustomParserApi = Object.keys(parsers).reduce(
(object, parserName) =>
Object.defineProperty(object, parserName, {
enumerable: true,
get() {
return parsers[parserName].parse;
}
}),
{}
);
const parser = resolveParser(opts, parsers);
try {
if (parser.preprocess) {
text = parser.preprocess(text, opts);
}
return {
text,
ast: parser.parse(text, parsersForCustomParserApi, opts)
};
} catch (error) {
const loc = error.loc;
if (loc) {
const codeFrame = require("@babel/code-frame");
error.codeFrame = codeFrame.codeFrameColumns(text, loc, {
highlightCode: true
});
error.message += "\n" + error.codeFrame;
throw error;
}
/* istanbul ignore next */
throw error.stack;
}
}
module.exports = { parse, resolveParser };