diff --git a/changelog_unreleased/api/pr-8551.md b/changelog_unreleased/api/pr-8551.md new file mode 100644 index 000000000..bf60b5a1a --- /dev/null +++ b/changelog_unreleased/api/pr-8551.md @@ -0,0 +1,29 @@ +#### Fix `prettier.getFileInfo()` ([#8548](https://github.com/prettier/prettier/pull/8548), [#8551](https://github.com/prettier/prettier/pull/8551) by [@fisker](https://github.com/fisker)) + +When passing `{resolveConfig: true}`, the parsers in config file is preferred. + + +```console +$ echo {"parser":"flow"}>.prettierrc +$ node -p "require('prettier').getFileInfo.sync('./foo.js', {resolveConfig: true})" + +# Prettier stable +# { ignored: false, inferredParser: 'babel' } + +# Prettier master +# { ignored: false, inferredParser: 'flow' } +``` + +If given `filePath` is ignored, the `inferredParser` is always `null`. + + +```console +$ echo ignored.js>>.prettierignore +$ node -p "require('prettier').getFileInfo.sync('./ignored.js')" + +# Prettier stable +# { ignored: true, inferredParser: 'babel' } + +# Prettier master +# { ignored: true, inferredParser: null } +``` diff --git a/docs/api.md b/docs/api.md index a0f11070d..7aca4b126 100644 --- a/docs/api.md +++ b/docs/api.md @@ -98,6 +98,8 @@ The promise will be rejected if the type of `filePath` is not `string`. Setting `options.ignorePath` (`string`) and `options.withNodeModules` (`boolean`) influence the value of `ignored` (`false` by default). +If the given `filePath` is ignored, the `inferredParser` is always `null`. + Providing [plugin](plugins.md) paths in `options.plugins` (`string[]`) helps extract `inferredParser` for files that are not supported by Prettier core. When setting `options.resolveConfig` (`boolean`, default `false`), Prettier will resolve the configuration for the given `filePath`. This is useful, for example, when the `inferredParser` might be overridden for a subset of files. diff --git a/src/common/get-file-info.js b/src/common/get-file-info.js index 794c85899..e1b99784e 100644 --- a/src/common/get-file-info.js +++ b/src/common/get-file-info.js @@ -58,6 +58,20 @@ getFileInfo.sync = function (filePath, opts) { }); }; +function getFileParser(resolvedConfig, filePath, plugins) { + if (resolvedConfig && resolvedConfig.parser) { + return resolvedConfig.parser; + } + + const inferredParser = options.inferParser(filePath, plugins); + + if (inferredParser) { + return inferredParser; + } + + return null; +} + function _getFileInfo({ ignorer, filePath, @@ -74,31 +88,25 @@ function _getFileInfo({ return fileInfo; } - const inferredParser = options.inferParser(filePath, plugins); + let resolvedConfig; - if (inferredParser) { - fileInfo.inferredParser = inferredParser; - return fileInfo; - } - - if (!resolveConfig) { - return fileInfo; - } - - if (sync) { - const resolvedConfig = config.resolveConfig.sync(filePath); - if (resolvedConfig && resolvedConfig.parser) { - fileInfo.inferredParser = resolvedConfig.parser; + if (resolveConfig) { + if (sync) { + resolvedConfig = config.resolveConfig.sync(filePath); + } else { + return config.resolveConfig(filePath).then((resolvedConfig) => { + fileInfo.inferredParser = getFileParser( + resolvedConfig, + filePath, + plugins + ); + return fileInfo; + }); } - return fileInfo; } - return config.resolveConfig(filePath).then((resolvedConfig) => { - if (resolvedConfig && resolvedConfig.parser) { - fileInfo.inferredParser = resolvedConfig.parser; - } - return fileInfo; - }); + fileInfo.inferredParser = getFileParser(resolvedConfig, filePath, plugins); + return fileInfo; } function normalizeFilePath(filePath, ignorePath) { diff --git a/tests_integration/__tests__/file-info.js b/tests_integration/__tests__/file-info.js index 8772e684f..3df43c07b 100644 --- a/tests_integration/__tests__/file-info.js +++ b/tests_integration/__tests__/file-info.js @@ -3,6 +3,7 @@ const path = require("path"); const tempy = require("tempy"); const fs = require("fs"); +const fromPairs = require("lodash/fromPairs"); const runPrettier = require("../runPrettier"); const prettier = require("prettier/local"); @@ -131,155 +132,167 @@ test("API getFileInfo.sync with filepath only", () => { }); }); -test("API getFileInfo with resolveConfig", () => { - const file1 = path.resolve( - path.join(__dirname, "../cli/with-resolve-config/file.foo") +describe("API getFileInfo resolveConfig", () => { + const files = fromPairs( + ["foo", "js", "bar", "css"].map((ext) => [ + ext, + path.resolve( + path.join(__dirname, `../cli/with-resolve-config/file.${ext}`) + ), + ]) ); - const file2 = path.resolve( - path.join(__dirname, "../cli/with-resolve-config/file.bar") - ); - const file3 = path.resolve( - path.join(__dirname, "../cli/with-resolve-config/file.js") - ); - - expect(prettier.getFileInfo(file1)).resolves.toMatchObject({ - ignored: false, - inferredParser: null, + test("{resolveConfig: undefined}", () => { + expect(prettier.getFileInfo(files.foo)).resolves.toMatchObject({ + ignored: false, + inferredParser: null, + }); + expect(prettier.getFileInfo(files.js)).resolves.toMatchObject({ + ignored: false, + inferredParser: "babel", + }); + expect(prettier.getFileInfo(files.bar)).resolves.toMatchObject({ + ignored: false, + inferredParser: null, + }); + expect(prettier.getFileInfo(files.css)).resolves.toMatchObject({ + ignored: false, + inferredParser: "css", + }); }); - expect(prettier.getFileInfo(file2)).resolves.toMatchObject({ - ignored: false, - inferredParser: null, + test("{resolveConfig: true}", () => { + expect( + prettier.getFileInfo(files.foo, { resolveConfig: true }) + ).resolves.toMatchObject({ + ignored: false, + inferredParser: "foo-parser", + }); + expect( + prettier.getFileInfo(files.js, { resolveConfig: true }) + ).resolves.toMatchObject({ + ignored: false, + inferredParser: "override-js-parser", + }); + expect( + prettier.getFileInfo(files.bar, { resolveConfig: true }) + ).resolves.toMatchObject({ + ignored: false, + inferredParser: null, + }); + expect( + prettier.getFileInfo(files.css, { resolveConfig: true }) + ).resolves.toMatchObject({ + ignored: false, + inferredParser: "css", + }); }); - expect(prettier.getFileInfo(file3)).resolves.toMatchObject({ - ignored: false, - inferredParser: "babel", + test("sync {resolveConfig: undefined}", () => { + expect(prettier.getFileInfo.sync(files.foo)).toMatchObject({ + ignored: false, + inferredParser: null, + }); + expect(prettier.getFileInfo.sync(files.js)).toMatchObject({ + ignored: false, + inferredParser: "babel", + }); + expect(prettier.getFileInfo.sync(files.bar)).toMatchObject({ + ignored: false, + inferredParser: null, + }); + expect(prettier.getFileInfo.sync(files.css)).toMatchObject({ + ignored: false, + inferredParser: "css", + }); }); - expect( - prettier.getFileInfo(file1, { - resolveConfig: true, - }) - ).resolves.toMatchObject({ - ignored: false, - inferredParser: "json", - }); - expect( - prettier.getFileInfo(file2, { - resolveConfig: true, - }) - ).resolves.toMatchObject({ - ignored: false, - inferredParser: "babel", - }); - expect( - prettier.getFileInfo(file3, { - resolveConfig: true, - }) - ).resolves.toMatchObject({ - ignored: false, - // Bug: should be `not-babel` - inferredParser: "babel", + test("sync {resolveConfig: true}", () => { + expect( + prettier.getFileInfo.sync(files.foo, { + resolveConfig: true, + }) + ).toMatchObject({ + ignored: false, + inferredParser: "foo-parser", + }); + expect( + prettier.getFileInfo.sync(files.js, { + resolveConfig: true, + }) + ).toMatchObject({ + ignored: false, + inferredParser: "override-js-parser", + }); + expect( + prettier.getFileInfo.sync(files.bar, { + resolveConfig: true, + }) + ).toMatchObject({ + ignored: false, + inferredParser: null, + }); + expect( + prettier.getFileInfo.sync(files.css, { + resolveConfig: true, + }) + ).toMatchObject({ + ignored: false, + inferredParser: "css", + }); }); }); -test("API getFileInfo with resolveConfig when no config is present", () => { - const file1 = path.resolve( - path.join(__dirname, "../cli/with-resolve-config-no-config/file.foo") +describe("API getFileInfo resolveConfig when no config is present", () => { + const files = fromPairs( + ["foo", "js"].map((ext) => [ + ext, + path.resolve(path.join(__dirname, `../cli/non-exists-dir/file.${ext}`)), + ]) ); - const file2 = path.resolve( - path.join(__dirname, "../cli/with-resolve-config-no-config/file.bar") - ); - - expect(prettier.getFileInfo(file1)).resolves.toMatchObject({ - ignored: false, - inferredParser: null, + test("{resolveConfig: undefined}", () => { + expect(prettier.getFileInfo(files.foo)).resolves.toMatchObject({ + ignored: false, + inferredParser: null, + }); + expect(prettier.getFileInfo(files.js)).resolves.toMatchObject({ + ignored: false, + inferredParser: "babel", + }); }); - expect(prettier.getFileInfo(file2)).resolves.toMatchObject({ - ignored: false, - inferredParser: null, + test("{resolveConfig: true}", () => { + expect( + prettier.getFileInfo(files.foo, { resolveConfig: true }) + ).resolves.toMatchObject({ + ignored: false, + inferredParser: null, + }); + expect( + prettier.getFileInfo(files.js, { resolveConfig: true }) + ).resolves.toMatchObject({ + ignored: false, + inferredParser: "babel", + }); }); - expect( - prettier.getFileInfo(file1, { - resolveConfig: true, - }) - ).resolves.toMatchObject({ - ignored: false, - inferredParser: null, + test("sync {resolveConfig: undefined}", () => { + expect(prettier.getFileInfo.sync(files.foo)).toMatchObject({ + ignored: false, + inferredParser: null, + }); + expect(prettier.getFileInfo.sync(files.js)).toMatchObject({ + ignored: false, + inferredParser: "babel", + }); }); - expect( - prettier.getFileInfo(file2, { - resolveConfig: true, - }) - ).resolves.toMatchObject({ - ignored: false, - inferredParser: null, - }); -}); - -test("API getFileInfo.sync with resolveConfig", () => { - const file1 = path.resolve( - path.join(__dirname, "../cli/with-resolve-config/file.foo") - ); - const file2 = path.resolve( - path.join(__dirname, "../cli/with-resolve-config/file.bar") - ); - - expect(prettier.getFileInfo.sync(file1)).toMatchObject({ - ignored: false, - inferredParser: null, - }); - expect(prettier.getFileInfo.sync(file2)).toMatchObject({ - ignored: false, - inferredParser: null, - }); - expect( - prettier.getFileInfo.sync(file1, { - resolveConfig: true, - }) - ).toMatchObject({ - ignored: false, - inferredParser: "json", - }); - expect( - prettier.getFileInfo.sync(file2, { - resolveConfig: true, - }) - ).toMatchObject({ - ignored: false, - inferredParser: "babel", - }); -}); - -test("API getFileInfo.sync with resolveConfig when no config is present", () => { - const file1 = path.resolve( - path.join(__dirname, "../cli/with-resolve-config-no-config/file.foo") - ); - const file2 = path.resolve( - path.join(__dirname, "../cli/with-resolve-config-no-config/file.bar") - ); - - expect(prettier.getFileInfo.sync(file1)).toMatchObject({ - ignored: false, - inferredParser: null, - }); - expect(prettier.getFileInfo.sync(file2)).toMatchObject({ - ignored: false, - inferredParser: null, - }); - expect( - prettier.getFileInfo.sync(file1, { - resolveConfig: true, - }) - ).toMatchObject({ - ignored: false, - inferredParser: null, - }); - expect( - prettier.getFileInfo.sync(file2, { - resolveConfig: true, - }) - ).toMatchObject({ - ignored: false, - inferredParser: null, + test("sync {resolveConfig: true}", () => { + expect( + prettier.getFileInfo.sync(files.foo, { resolveConfig: true }) + ).toMatchObject({ + ignored: false, + inferredParser: null, + }); + expect( + prettier.getFileInfo.sync(files.js, { resolveConfig: true }) + ).toMatchObject({ + ignored: false, + inferredParser: "babel", + }); }); }); diff --git a/tests_integration/cli/with-resolve-config-no-config/file.bar b/tests_integration/cli/with-resolve-config-no-config/file.bar deleted file mode 100644 index 4f4b4c843..000000000 --- a/tests_integration/cli/with-resolve-config-no-config/file.bar +++ /dev/null @@ -1 +0,0 @@ -const foo = "bar"; diff --git a/tests_integration/cli/with-resolve-config-no-config/file.foo b/tests_integration/cli/with-resolve-config-no-config/file.foo deleted file mode 100644 index 0967ef424..000000000 --- a/tests_integration/cli/with-resolve-config-no-config/file.foo +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/tests_integration/cli/with-resolve-config/.prettierrc b/tests_integration/cli/with-resolve-config/.prettierrc index 9c434fb72..b30d8cbb0 100644 --- a/tests_integration/cli/with-resolve-config/.prettierrc +++ b/tests_integration/cli/with-resolve-config/.prettierrc @@ -2,15 +2,11 @@ "overrides": [ { "files": "*.foo", - "options": { "parser": "json" } - }, - { - "files": "*.bar", - "options": { "parser": "babel" } + "options": { "parser": "foo-parser" } }, { "files": "*.js", - "options": { "parser": "not-babel" } + "options": { "parser": "override-js-parser" } } ] } diff --git a/tests_integration/cli/with-resolve-config/file.bar b/tests_integration/cli/with-resolve-config/file.bar deleted file mode 100644 index 4f4b4c843..000000000 --- a/tests_integration/cli/with-resolve-config/file.bar +++ /dev/null @@ -1 +0,0 @@ -const foo = "bar"; diff --git a/tests_integration/cli/with-resolve-config/file.foo b/tests_integration/cli/with-resolve-config/file.foo deleted file mode 100644 index 0967ef424..000000000 --- a/tests_integration/cli/with-resolve-config/file.foo +++ /dev/null @@ -1 +0,0 @@ -{}