From d49444352a85d60e5c8ff50446803ef3df3466e0 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Thu, 5 Jun 2025 17:10:39 +0800 Subject: [PATCH] Fix plugin loading in `prettier.getFileInfo()` (#17548) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- changelog_unreleased/api/17548.md | 29 +++++++++++ src/cli/file-info.js | 3 +- src/common/get-file-info.js | 20 ++++--- src/index.js | 6 +-- .../__tests__/__snapshots__/file-info.js.snap | 2 +- tests/integration/__tests__/file-info.js | 52 +++++++++++++++++++ .../file-info/config-with-parser/.prettierrc | 1 + .../file-info/config-with-plugin/.prettierrc | 2 + .../cli/file-info/empty-config/.prettierrc | 1 + tests/integration/cli/file-info/plugin.js | 10 ++++ 10 files changed, 113 insertions(+), 13 deletions(-) create mode 100644 changelog_unreleased/api/17548.md create mode 100644 tests/integration/cli/file-info/config-with-parser/.prettierrc create mode 100644 tests/integration/cli/file-info/config-with-plugin/.prettierrc create mode 100644 tests/integration/cli/file-info/empty-config/.prettierrc create mode 100644 tests/integration/cli/file-info/plugin.js diff --git a/changelog_unreleased/api/17548.md b/changelog_unreleased/api/17548.md new file mode 100644 index 000000000..d3c6bf6fe --- /dev/null +++ b/changelog_unreleased/api/17548.md @@ -0,0 +1,29 @@ +#### Fix plugin loading in `prettier.getFileInfo()` (#17548 by @fisker) + +In previous version, `prettier.getFileInfo()` only read `parser` config from `.prettierrc`, but doesn't load plugin to infer parser from plugin `languages`, Prettier main fixed it. + +```js +// prettier-plugin-foo +export const languages = [ + { + parsers: ["foo"], + extensions: [".foo"], + }, +]; +``` + +```yaml +# .prettierrc +plugins: + - prettier-plugin-foo +``` + +```console +prettier --file-info file.foo + +# Prettier stable +{ "ignored": false, "inferredParser": null } + +# Prettier main +{ "ignored": false, "inferredParser": "foo" } +``` diff --git a/src/cli/file-info.js b/src/cli/file-info.js index 377445757..1b21bdfbc 100644 --- a/src/cli/file-info.js +++ b/src/cli/file-info.js @@ -3,6 +3,7 @@ import stringify from "fast-json-stable-stringify"; import { format, getFileInfo } from "../index.js"; import { printToScreen } from "./utils.js"; +// Note: This does not work with `--config-precedence` async function logFileInfoOrDie(context) { const { fileInfo: file, @@ -15,7 +16,7 @@ async function logFileInfoOrDie(context) { const fileInfo = await getFileInfo(path.resolve(file), { ignorePath, withNodeModules, - plugins, + plugins: plugins.length > 0 ? plugins : undefined, resolveConfig: config !== false, }); diff --git a/src/common/get-file-info.js b/src/common/get-file-info.js index d29b8ae51..6a967db6f 100644 --- a/src/common/get-file-info.js +++ b/src/common/get-file-info.js @@ -1,4 +1,5 @@ import { resolveConfig } from "../config/resolve-config.js"; +import { loadBuiltinPlugins, loadPlugins } from "../main/plugins/index.js"; import { isIgnored } from "../utils/ignore.js"; import inferParser from "../utils/infer-parser.js"; @@ -13,10 +14,9 @@ import inferParser from "../utils/infer-parser.js"; * @returns {Promise} * * Please note that prettier.getFileInfo() expects options.plugins to be an array of paths, - * not an object. A transformation from this array to an object is automatically done - * internally by the method wrapper. See withPlugins() in index.js. + * not an object. */ -async function getFileInfo(file, options) { +async function getFileInfo(file, options = {}) { if (typeof file !== "string" && !(file instanceof URL)) { throw new TypeError( `expect \`file\` to be a string or URL, got \`${typeof file}\``, @@ -30,10 +30,9 @@ async function getFileInfo(file, options) { } const ignored = await isIgnored(file, { ignorePath, withNodeModules }); - let inferredParser; if (!ignored) { - inferredParser = await getParser(file, options); + inferredParser = options.parser ?? (await getParser(file, options)); } return { @@ -51,7 +50,16 @@ async function getParser(file, options) { }); } - return config?.parser ?? inferParser(options, { physicalFile: file }); + if (config?.parser) { + return config.parser; + } + + let plugins = options.plugins ?? config?.plugins ?? []; + plugins = ( + await Promise.all([loadBuiltinPlugins(), loadPlugins(plugins)]) + ).flat(); + + return inferParser({ plugins }, { physicalFile: file }); } export default getFileInfo; diff --git a/src/index.js b/src/index.js index cf06e88c9..1ac5a26ad 100644 --- a/src/index.js +++ b/src/index.js @@ -11,7 +11,6 @@ import leven from "leven"; import picocolors from "picocolors"; import * as vnopts from "vnopts"; import * as errors from "./common/errors.js"; -import getFileInfoWithoutPlugins from "./common/get-file-info.js"; import { mockable } from "./common/mockable.js"; import { clearCache as clearConfigCache, @@ -84,9 +83,6 @@ async function clearCache() { clearPluginCache(); } -/** @type {typeof getFileInfoWithoutPlugins} */ -const getFileInfo = withPlugins(getFileInfoWithoutPlugins); - /** @type {typeof getSupportInfoWithoutPlugins} */ const getSupportInfo = withPlugins(getSupportInfoWithoutPlugins, 0); @@ -136,11 +132,11 @@ export { clearCache as clearConfigCache, format, formatWithCursor, - getFileInfo, getSupportInfo, resolveConfig, resolveConfigFile, }; +export { default as getFileInfo } from "./common/get-file-info.js"; export * as doc from "./document/public.js"; export { default as version } from "./main/version.evaluate.js"; export * as util from "./utils/public.js"; diff --git a/tests/integration/__tests__/__snapshots__/file-info.js.snap b/tests/integration/__tests__/__snapshots__/file-info.js.snap index ac7edf07c..0f67b3885 100644 --- a/tests/integration/__tests__/__snapshots__/file-info.js.snap +++ b/tests/integration/__tests__/__snapshots__/file-info.js.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`extracts file-info for a file in not_node_modules 1`] = ` { diff --git a/tests/integration/__tests__/file-info.js b/tests/integration/__tests__/file-info.js index 2fe76dbe1..a9d209645 100644 --- a/tests/integration/__tests__/file-info.js +++ b/tests/integration/__tests__/file-info.js @@ -397,6 +397,58 @@ test("API getFileInfo accepts path or URL", async () => { expect(resultByRelativePath).toEqual(expectedResult); }); +test("getFileInfo should support `parser` and `plugins` in options", async () => { + { + const { inferredParser: parser } = await prettier.getFileInfo( + new URL("../cli/file-info/empty-config/foo.js", import.meta.url), + { + parser: "parser-from-options", + }, + ); + expect(parser).toBe("parser-from-options"); + } + + { + const { inferredParser: parser } = await prettier.getFileInfo( + new URL("../cli/file-info/empty-config/foo.js", import.meta.url), + ); + expect(parser).toBe("babel"); + } + + { + const { inferredParser: parser } = await prettier.getFileInfo( + new URL("../cli/file-info/config-with-parser/foo.js", import.meta.url), + ); + expect(parser).toBe("parser-from-prettierrc"); + } + + { + const { inferredParser: parser } = await prettier.getFileInfo( + new URL("../cli/file-info/config-with-plugin/file.foo", import.meta.url), + ); + expect(parser).toBe("parser-for-foo-file-from-plugin"); + } + + { + const { stdout } = await runCli("cli/file-info/config-with-plugin", [ + "--file-info", + "file.foo", + ]); + const { inferredParser: parser } = JSON.parse(stdout); + expect(parser).toBe("parser-for-foo-file-from-plugin"); + } + + { + const { inferredParser: parser } = await prettier.getFileInfo( + new URL("../cli/file-info/empty-config/file.bar", import.meta.url), + { + plugins: [new URL("../cli/file-info/plugin.js", import.meta.url)], + }, + ); + expect(parser).toBe("parser-for-bar-file-from-plugin"); + } +}); + test("API getFileInfo accepts path or URL as ignorePath", async () => { const file = new URL( "../cli/ignore-path/file-info-test/ignored-by-customignore.js", diff --git a/tests/integration/cli/file-info/config-with-parser/.prettierrc b/tests/integration/cli/file-info/config-with-parser/.prettierrc new file mode 100644 index 000000000..945a5f3af --- /dev/null +++ b/tests/integration/cli/file-info/config-with-parser/.prettierrc @@ -0,0 +1 @@ +parser: parser-from-prettierrc diff --git a/tests/integration/cli/file-info/config-with-plugin/.prettierrc b/tests/integration/cli/file-info/config-with-plugin/.prettierrc new file mode 100644 index 000000000..64bbc899a --- /dev/null +++ b/tests/integration/cli/file-info/config-with-plugin/.prettierrc @@ -0,0 +1,2 @@ +plugins: + - ../plugin.js diff --git a/tests/integration/cli/file-info/empty-config/.prettierrc b/tests/integration/cli/file-info/empty-config/.prettierrc new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/tests/integration/cli/file-info/empty-config/.prettierrc @@ -0,0 +1 @@ +{} diff --git a/tests/integration/cli/file-info/plugin.js b/tests/integration/cli/file-info/plugin.js new file mode 100644 index 000000000..60027eb1b --- /dev/null +++ b/tests/integration/cli/file-info/plugin.js @@ -0,0 +1,10 @@ +export const languages = [ + { + parsers: ['parser-for-foo-file-from-plugin'], + extensions: ['.foo'] + }, + { + parsers: ['parser-for-bar-file-from-plugin'], + extensions: ['.bar'] + } +]