118 lines
2.9 KiB
JavaScript
118 lines
2.9 KiB
JavaScript
import fs from "node:fs";
|
|
import getPrettier from "../get-prettier.js";
|
|
import {
|
|
CURSOR_PLACEHOLDER,
|
|
isProduction,
|
|
TEST_RUNTIME,
|
|
TEST_STANDALONE,
|
|
} from "./constants.js";
|
|
import { ensurePromise } from "./utilities.js";
|
|
import visualizeEndOfLine from "./visualize-end-of-line.js";
|
|
|
|
function unsetFilepath(options) {
|
|
const { filepath, ...restOptions } = options;
|
|
|
|
if (typeof filepath === "string" && filepath.endsWith(".unset-filepath")) {
|
|
return restOptions;
|
|
}
|
|
|
|
return options;
|
|
}
|
|
|
|
async function parse(input, options) {
|
|
options = unsetFilepath(options);
|
|
|
|
const prettier = await getPrettier();
|
|
const { ast } = await ensurePromise(
|
|
prettier.__debug.parse(input, await loadPlugins(options), {
|
|
massage: true,
|
|
}),
|
|
);
|
|
return ast;
|
|
}
|
|
|
|
async function format(input, options) {
|
|
options = unsetFilepath(options);
|
|
|
|
const inputWithCursor = insertCursor(input, options.cursorOffset);
|
|
const prettier = await getPrettier();
|
|
|
|
const { formatted: output, cursorOffset } = await ensurePromise(
|
|
prettier.formatWithCursor(input, await loadPlugins(options)),
|
|
);
|
|
const outputWithCursor = insertCursor(output, cursorOffset);
|
|
const eolVisualizedOutput = visualizeEndOfLine(outputWithCursor);
|
|
|
|
const changed = outputWithCursor !== inputWithCursor;
|
|
|
|
return {
|
|
changed,
|
|
options,
|
|
input,
|
|
inputWithCursor,
|
|
output,
|
|
outputWithCursor,
|
|
eolVisualizedOutput,
|
|
};
|
|
}
|
|
|
|
const insertCursor = (text, cursorOffset) =>
|
|
cursorOffset >= 0
|
|
? text.slice(0, cursorOffset) +
|
|
CURSOR_PLACEHOLDER +
|
|
text.slice(cursorOffset)
|
|
: text;
|
|
|
|
// Move this to prettier installation
|
|
let externalParsers;
|
|
async function loadPlugins(options) {
|
|
if (!isProduction || !options.parser || TEST_RUNTIME === "browser") {
|
|
return options;
|
|
}
|
|
|
|
const { parser } = options;
|
|
|
|
if (!externalParsers) {
|
|
externalParsers = getExternalPlugins();
|
|
}
|
|
externalParsers = await externalParsers;
|
|
if (!externalParsers.has(parser)) {
|
|
return options;
|
|
}
|
|
const plugin = externalParsers.get(parser);
|
|
|
|
const plugins = options.plugins ?? [];
|
|
plugins.push(TEST_STANDALONE ? plugin.implementation : plugin.url);
|
|
|
|
return { ...options, plugins };
|
|
}
|
|
|
|
async function getExternalPlugins() {
|
|
const distDirectory = new URL("../../../dist/", import.meta.url);
|
|
const directories = fs.readdirSync(distDirectory);
|
|
const plugins = await Promise.all(
|
|
directories
|
|
.filter((directory) => directory.startsWith("plugin-"))
|
|
.map(async (directory) => {
|
|
const url = new URL(`./${directory}/index.mjs`, distDirectory);
|
|
const implementation = await import(url);
|
|
return {
|
|
url,
|
|
implementation,
|
|
};
|
|
}),
|
|
);
|
|
const externalParsers = new Map();
|
|
for (const plugin of plugins) {
|
|
const { parsers } = plugin.implementation;
|
|
if (parsers) {
|
|
for (const parser of Object.keys(parsers)) {
|
|
externalParsers.set(parser, plugin);
|
|
}
|
|
}
|
|
}
|
|
return externalParsers;
|
|
}
|
|
|
|
export { format, parse };
|