Allow plugin override builtin parsers when inferring parser (#17549)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
fisker Cheungandautofix-ci[bot] authored and GitHub committed 2025-06-05 17:23:49 +08:00
1 parent d49444352a
commit 7fb9875413
16 files changed
+197 -42

No files matched your search

+32
View File
@@ -0,0 +1,32 @@
#### Allow plugin to override builtin parsers when inferring parser (#17549 by @fisker)
Previously when inferring parser for file, builtin plugins are checked first, so plugins are not able to override parsers for files like `.js`.
```js
// prettier-plugin-foo
export const languages = [
{
parsers: ["foo"],
extensions: [".js"],
},
];
```
```js
// prettier.config.js
import * as prettierPluginFoo from "prettier-plugin-foo";
export default {
plugins: [prettierPluginFoo],
};
```
```console
prettier --file-info file.js
# Prettier stable
{ "ignored": false, "inferredParser": "babel" }
# Prettier main
{ "ignored": false, "inferredParser": "foo" }
```
+15 -12
View File
@@ -12,16 +12,19 @@ yarn add --dev prettier @prettier/plugin-hermes
Create or modify your [prettier configuration file](https://prettier.io/docs/en/configuration) to use the plugin:
```json
{
"overrides": [
{
"files": ["**/*.{js.flow,js,mjs,cjs}"],
"options": {
"plugins": ["@prettier/plugin-hermes"],
"parser": "hermes"
}
}
]
}
```yaml
plugins:
- "@prettier/plugin-hermes"
```
Or config explicitly
```yaml
overrides:
- files:
- "**/*.{js.flow,js,mjs,cjs}"
options:
plugins:
- "@prettier/plugin-hermes"
parser: hermes
```
+1
View File
@@ -1 +1,2 @@
export * as parsers from "../../src/language-js/parse/hermes.js";
export { default as languages } from "./languages.evaluate.js";
@@ -0,0 +1,15 @@
import builtinJsLanguages from "../../src/language-js/languages.evaluate.js";
const replacements = new Map([["flow", "hermes"]]);
const languages = builtinJsLanguages
.map((language) => {
const parsers = language.parsers
.map((parser) => replacements.get(parser))
.filter(Boolean);
return parsers.length > 0 ? { ...language, parsers } : undefined;
})
.filter(Boolean);
export default languages;
+21 -19
View File
@@ -12,23 +12,25 @@ yarn add --dev prettier @prettier/plugin-oxc
Create or modify your [prettier configuration file](https://prettier.io/docs/en/configuration) to use the plugin:
```json
{
"overrides": [
{
"files": ["**/*.{js,mjs,cjs,jsx}"],
"options": {
"plugins": ["@prettier/plugin-oxc"],
"parser": "oxc"
}
},
{
"files": ["**/*.{ts,mts,cts,tsx}"],
"options": {
"plugins": ["@prettier/plugin-oxc"],
"parser": "oxc-ts"
}
}
]
}
```yaml
plugins:
- "@prettier/plugin-oxc"
```
Or config explicitly
```yaml
overrides:
- files:
- "**/*.{js,mjs,cjs,jsx}"
options:
plugins:
- "@prettier/plugin-oxc"
parser: oxc
- files:
- "**/*.{ts,mts,cts,tsx}"
options:
plugins:
- "@prettier/plugin-oxc"
parser: oxc-ts
```
+1
View File
@@ -1 +1,2 @@
export * as parsers from "../../src/language-js/parse/oxc.js";
export { default as languages } from "./languages.evaluate.js";
+18
View File
@@ -0,0 +1,18 @@
import builtinJsLanguages from "../../src/language-js/languages.evaluate.js";
const replacements = new Map([
["babel", "oxc"],
["typescript", "oxc-ts"],
]);
const languages = builtinJsLanguages
.map((language) => {
const parsers = language.parsers
.map((parser) => replacements.get(parser))
.filter(Boolean);
return parsers.length > 0 ? { ...language, parsers } : undefined;
})
.filter(Boolean);
export default languages;
+13
View File
@@ -0,0 +1,13 @@
const arrayToReversed = (isOptionalObject, array) => {
if (isOptionalObject && (array === undefined || array === null)) {
return;
}
if (array.toReversed || !Array.isArray(array)) {
return array.toReversed();
}
return [...array].reverse();
};
export default arrayToReversed;
@@ -1,5 +1,6 @@
import transformArrayFindLast from "./transform-array-find-last.js";
import transformArrayFindLastIndex from "./transform-array-find-last-index.js";
import transformArrayToReversed from "./transform-array-to-reversed.js";
import transformObjectHasOwnCall from "./transform-object-has-own.js";
import transformRelativeIndexing from "./transform-relative-indexing.js";
import transformStringReplaceAll from "./transform-string-replace-all.js";
@@ -18,4 +19,6 @@ export default [
transformRelativeIndexing,
// Node.js 15.0.0
transformStringReplaceAll,
// Node.js 20
transformArrayToReversed,
];
@@ -0,0 +1,13 @@
import createMethodCallTransform from "./create-method-call-transform.js";
const transformArrayToReversed = createMethodCallTransform({
methodName: "toReversed",
argumentsLength: 0,
functionName: "__arrayToReversed",
functionImplementationUrl: new URL(
"../../shims/array-to-reversed.js",
import.meta.url,
),
});
export default transformArrayToReversed;
+1 -1
View File
@@ -118,7 +118,7 @@ function getLanguageByIsSupported(languages, file) {
* @returns {string | undefined} matched parser name if found
*/
function inferParser(options, fileInfo) {
const languages = options.plugins.flatMap(
const languages = options.plugins.toReversed().flatMap(
(plugin) =>
// @ts-expect-error -- Safe
plugin.languages ?? [],
@@ -166,6 +166,28 @@ describe("--write and --list-different with unknown path and no parser", () => {
});
});
describe("Allow plugin to override builtin plugins", () => {
runCli(
"cli/infer-parser/override-builtin-plugin-languages",
["--stdin-filepath=foo.js"],
{
input: "foo( )",
},
).test({ write: [], status: 0, stderr: "", stdout: "foo();" });
runCli(
"cli/infer-parser/override-builtin-plugin-languages",
["--stdin-filepath=foo.js", "--plugin=./dummy-js-plugin.js"],
{
input: "foo( )",
},
).test({
write: [],
status: 0,
stderr: "",
stdout: "foo( )\nformatted by 'dummy-js-parser' parser",
});
});
describe("API with no path and no parser", () => {
test("prettier.format", async () => {
await expect(prettier.format(" foo ( )")).rejects.toThrow(
@@ -0,0 +1,21 @@
import createPlugin from "../../../../config/utils/create-plugin.cjs";
const PARSER_NAME = 'dummy-js-parser'
const PRINT_MARK = `formatted by '${PARSER_NAME}' parser`
const languages = [
{
parsers: [PARSER_NAME],
extensions: ['.js']
}
]
export default {
...createPlugin({
name: PARSER_NAME,
print: (content) => `${content.replace(PRINT_MARK,"").trim()}\n${PRINT_MARK}`,
finalNewLine: false,
}),
languages,
};
+20 -3
View File
@@ -45,7 +45,7 @@ test(".at", () => {
__at (/* isOptionalObject */false,foo,-1)?.bar"
`);
// Don't support optional call
// Optional call not supported
expect(transform("foo.at?.(-1)")).toMatchInlineSnapshot(`"foo.at?.(-1)"`);
});
@@ -69,7 +69,7 @@ test("Array#findLast", () => {
__arrayFindLast(/* isOptionalObject */true,foo,callback)"
`);
// Don't support
// Not supported
expect(
transform("foo.findLast(callback, thisArgument)"),
).toMatchInlineSnapshot(`"foo.findLast(callback, thisArgument)"`);
@@ -87,8 +87,25 @@ test("Array#findLastIndex", () => {
__arrayFindLastIndex(/* isOptionalObject */true,foo,callback)"
`);
// Don't support
// Not supported
expect(
transform("foo.findLastIndex(callback, thisArgument)"),
).toMatchInlineSnapshot(`"foo.findLastIndex(callback, thisArgument)"`);
});
test("Array#toReversed", () => {
expect(transform("foo.toReversed()")).toMatchInlineSnapshot(`
"import __arrayToReversed from "<SHIMS>/array-to-reversed.js";
__arrayToReversed(/* isOptionalObject */false,foo)"
`);
expect(transform("foo?.toReversed()")).toMatchInlineSnapshot(`
"import __arrayToReversed from "<SHIMS>/array-to-reversed.js";
__arrayToReversed(/* isOptionalObject */true,foo)"
`);
expect(transform("foo.toReversed(extraArgument)")).toMatchInlineSnapshot(
`"foo.toReversed(extraArgument)"`,
);
});
-7
View File
@@ -62,13 +62,6 @@ const plugins = [
createPlugin(plugin),
),
docExplorerPlugin,
prettierPackageManifest.builtinPlugins.some((plugin) =>
plugin.parsers?.includes("hermes"),
)
? {
languages: [{ name: "hermes", parsers: ["hermes"] }],
}
: {},
];
self.onmessage = async function (event) {