# Conflicts: # .eslintrc.cjs # package.json # scripts/build/bundler.mjs # scripts/build/config.mjs # scripts/build/esbuild-plugins/replace-module.mjs # src/cli/file-info.js # src/cli/find-config-path.js # src/cli/index.js
118 lines
2.9 KiB
JavaScript
118 lines
2.9 KiB
JavaScript
import { createRequire } from "node:module";
|
|
import path from "node:path";
|
|
import { ConfigError } from "../common/errors.js";
|
|
import { locStart, locEnd } from "../language-js/loc.js";
|
|
|
|
const require = createRequire(import.meta.url);
|
|
|
|
// 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) {
|
|
// TODO: test this with plugins
|
|
/* istanbul ignore next */
|
|
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 = 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 (Object.prototype.hasOwnProperty.call(parsers, 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.`
|
|
);
|
|
}
|
|
|
|
// This line of code will be removed when bundling `standalone.js`
|
|
return requireParser(opts.parser);
|
|
}
|
|
}
|
|
|
|
function requireParser(parser) {
|
|
try {
|
|
return {
|
|
parse: require(path.resolve(process.cwd(), parser)),
|
|
astFormat: "estree",
|
|
locStart,
|
|
locEnd,
|
|
};
|
|
} catch {
|
|
/* istanbul ignore next */
|
|
throw new ConfigError(`Couldn't resolve parser "${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.defineProperties(
|
|
{},
|
|
Object.fromEntries(
|
|
Object.keys(parsers).map((parserName) => [
|
|
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;
|
|
|
|
if (loc) {
|
|
const { codeFrameColumns } = require("@babel/code-frame");
|
|
error.codeFrame = codeFrameColumns(text, loc, { highlightCode: true });
|
|
error.message += "\n" + error.codeFrame;
|
|
throw error;
|
|
}
|
|
|
|
/* istanbul ignore next */
|
|
throw error.stack;
|
|
}
|
|
}
|
|
|
|
export { parse, resolveParser };
|