Accept URL in getFileInfo (#15360)

This commit is contained in:
fisker Cheung authored and GitHub committed 2023-09-06 15:49:22 +08:00
1 parent 7e45a92707
commit b2c33a4cec
5 files changed
+70 -56

No files matched your search

+4 -2
View File
@@ -1,13 +1,15 @@
#### Accept `URL` in `prettier.{resolveConfig,resolveConfigFile}()` (#15332, #15354 by @fisker)
#### Accept `URL` in `prettier.{resolveConfig,resolveConfigFile,getFileInfo}()` (#15332, #15354, #15360 by @fisker)
[`prettier.resolveConfig()`](https://prettier.io/docs/en/api#prettierresolveconfigfileurlorpath--options) and [`prettier.resolveConfigFile()`](https://prettier.io/docs/en/api#prettierresolveconfigfilefileurlorpath) now accepts an [URL](https://developer.mozilla.org/en-US/docs/Web/API/URL) with `file:` protocol or a url string starts with `file://`.
[`prettier.resolveConfig()`](https://prettier.io/docs/en/api#prettierresolveconfigfileurlorpath--options), [`prettier.resolveConfigFile()`](https://prettier.io/docs/en/api#prettierresolveconfigfilefileurlorpath), and [`prettier.getFileInfo()`](https://prettier.io/docs/en/api#prettiergetfileinfofileurlorpath--options) now accepts an [URL](https://developer.mozilla.org/en-US/docs/Web/API/URL) with `file:` protocol or a url string starts with `file://`.
```js
// `URL`
await prettier.resolveConfig(new URL("./path/to/file", import.meta.url));
await prettier.resolveConfigFile(new URL("./path/to/file", import.meta.url));
await prettier.getFileInfo(new URL("./path/to/file", import.meta.url));
// URL string
await prettier.resolveConfig("file:///path/to/file");
await prettier.resolveConfigFile("file:///path/to/file");
await prettier.getFileInfo("file:///path/to/file");
```
+3 -3
View File
@@ -77,7 +77,7 @@ const configFile = await prettier.resolveConfigFile(filePath);
When Prettier loads configuration files and plugins, the file system structure is cached for performance. This function will clear the cache. Generally this is only needed for editor integrations that know that the file system has changed since the last format took place.
## `prettier.getFileInfo(filePath [, options])`
## `prettier.getFileInfo(fileUrlOrPath [, options])`
`getFileInfo` can be used by editor extensions to decide if a particular file needs to be formatted. This method returns a promise, which resolves to an object with the following properties:
@@ -88,11 +88,11 @@ When Prettier loads configuration files and plugins, the file system structure i
}
```
The promise will be rejected if the type of `filePath` is not `string`.
The promise will be rejected if the type of `fileUrlOrPath` is not `string` or `URL`.
Setting `options.ignorePath` (`string | string[]`) and `options.withNodeModules` (`boolean`) influence the value of `ignored` (`false` by default).
If the given `filePath` is ignored, the `inferredParser` is always `null`.
If the given `fileUrlOrPath` 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.
+6 -4
View File
@@ -1,3 +1,4 @@
import { toPath } from "url-or-path";
import inferParser from "../utils/infer-parser.js";
import { resolveConfig } from "../config/resolve-config.js";
import { isIgnored } from "../utils/ignore.js";
@@ -8,7 +9,7 @@ import { isIgnored } from "../utils/ignore.js";
*/
/**
* @param {string} filePath
* @param {string | URL} fileUrlOrPath
* @param {FileInfoOptions} options
* @returns {Promise<FileInfoResult>}
*
@@ -16,10 +17,10 @@ import { isIgnored } from "../utils/ignore.js";
* not an object. A transformation from this array to an object is automatically done
* internally by the method wrapper. See withPlugins() in index.js.
*/
async function getFileInfo(filePath, options) {
if (typeof filePath !== "string") {
async function getFileInfo(fileUrlOrPath, options) {
if (typeof fileUrlOrPath !== "string" && !(fileUrlOrPath instanceof URL)) {
throw new TypeError(
`expect \`filePath\` to be a string, got \`${typeof filePath}\``,
`expect \`fileUrlOrPath\` to be a string or URL, got \`${typeof fileUrlOrPath}\``,
);
}
@@ -29,6 +30,7 @@ async function getFileInfo(filePath, options) {
ignorePath = [ignorePath];
}
const filePath = toPath(fileUrlOrPath);
const ignored = await isIgnored(filePath, { ignorePath, withNodeModules });
let inferredParser;
+1 -1
View File
@@ -799,7 +799,7 @@ export interface FileInfoResult {
}
export function getFileInfo(
filePath: string,
fileUrlOrPath: string,
options?: FileInfoOptions,
): Promise<FileInfoResult>;
+56 -46
View File
@@ -1,5 +1,6 @@
import path from "node:path";
import fs from "node:fs";
import url from "node:url";
import { temporaryDirectory as getTemporaryDirectory } from "tempy";
import createEsmUtils from "esm-utils";
import prettier from "../../config/prettier-entry.js";
@@ -118,12 +119,14 @@ describe("extracts file-info with inferredParser=foo when a plugin is hand-picke
test("API getFileInfo with no args", async () => {
await expect(prettier.getFileInfo()).rejects.toThrow(
new TypeError("expect `filePath` to be a string, got `undefined`"),
new TypeError(
"expect `fileUrlOrPath` to be a string or URL, got `undefined`",
),
);
});
test("API getFileInfo with filepath only", async () => {
await expect(prettier.getFileInfo("README")).resolves.toMatchObject({
await expect(prettier.getFileInfo("README")).resolves.toEqual({
ignored: false,
inferredParser: "markdown",
});
@@ -133,25 +136,23 @@ describe("API getFileInfo resolveConfig", () => {
const files = Object.fromEntries(
["foo", "js", "bar", "css"].map((ext) => [
ext,
path.resolve(
path.join(__dirname, `../cli/with-resolve-config/file.${ext}`),
),
new URL(`../cli/with-resolve-config/file.${ext}`, import.meta.url),
]),
);
test("{resolveConfig: undefined}", async () => {
await expect(prettier.getFileInfo(files.foo)).resolves.toMatchObject({
await expect(prettier.getFileInfo(files.foo)).resolves.toEqual({
ignored: false,
inferredParser: "foo-parser",
});
await expect(prettier.getFileInfo(files.js)).resolves.toMatchObject({
await expect(prettier.getFileInfo(files.js)).resolves.toEqual({
ignored: false,
inferredParser: "override-js-parser",
});
await expect(prettier.getFileInfo(files.bar)).resolves.toMatchObject({
await expect(prettier.getFileInfo(files.bar)).resolves.toEqual({
ignored: false,
inferredParser: null,
});
await expect(prettier.getFileInfo(files.css)).resolves.toMatchObject({
await expect(prettier.getFileInfo(files.css)).resolves.toEqual({
ignored: false,
inferredParser: "css",
});
@@ -159,25 +160,25 @@ describe("API getFileInfo resolveConfig", () => {
test("{resolveConfig: true}", async () => {
await expect(
prettier.getFileInfo(files.foo, { resolveConfig: true }),
).resolves.toMatchObject({
).resolves.toEqual({
ignored: false,
inferredParser: "foo-parser",
});
await expect(
prettier.getFileInfo(files.js, { resolveConfig: true }),
).resolves.toMatchObject({
).resolves.toEqual({
ignored: false,
inferredParser: "override-js-parser",
});
await expect(
prettier.getFileInfo(files.bar, { resolveConfig: true }),
).resolves.toMatchObject({
).resolves.toEqual({
ignored: false,
inferredParser: null,
});
await expect(
prettier.getFileInfo(files.css, { resolveConfig: true }),
).resolves.toMatchObject({
).resolves.toEqual({
ignored: false,
inferredParser: "css",
});
@@ -188,15 +189,15 @@ describe("API getFileInfo resolveConfig when no config is present", () => {
const files = Object.fromEntries(
["foo", "js"].map((ext) => [
ext,
path.resolve(path.join(__dirname, `../cli/non-exists-dir/file.${ext}`)),
new URL(`../cli/non-exists-dir/file.${ext}`, import.meta.url),
]),
);
test("{resolveConfig: undefined}", async () => {
await expect(prettier.getFileInfo(files.foo)).resolves.toMatchObject({
await expect(prettier.getFileInfo(files.foo)).resolves.toEqual({
ignored: false,
inferredParser: null,
});
await expect(prettier.getFileInfo(files.js)).resolves.toMatchObject({
await expect(prettier.getFileInfo(files.js)).resolves.toEqual({
ignored: false,
inferredParser: "babel",
});
@@ -204,13 +205,13 @@ describe("API getFileInfo resolveConfig when no config is present", () => {
test("{resolveConfig: true}", async () => {
await expect(
prettier.getFileInfo(files.foo, { resolveConfig: true }),
).resolves.toMatchObject({
).resolves.toEqual({
ignored: false,
inferredParser: null,
});
await expect(
prettier.getFileInfo(files.js, { resolveConfig: true }),
).resolves.toMatchObject({
).resolves.toEqual({
ignored: false,
inferredParser: "babel",
});
@@ -218,48 +219,40 @@ describe("API getFileInfo resolveConfig when no config is present", () => {
});
test("API getFileInfo with ignorePath", async () => {
const file = path.resolve(
path.join(
__dirname,
"../cli/ignore-path/file-info-test/ignored-by-customignore.js",
),
const file = new URL(
"../cli/ignore-path/file-info-test/ignored-by-customignore.js",
import.meta.url,
);
const ignorePath = path.resolve(
path.join(__dirname, "../cli/ignore-path/file-info-test/.customignore"),
);
await expect(prettier.getFileInfo(file)).resolves.toMatchObject({
await expect(prettier.getFileInfo(file)).resolves.toEqual({
ignored: false,
inferredParser: "babel",
});
await expect(
prettier.getFileInfo(file, { ignorePath }),
).resolves.toMatchObject({
await expect(prettier.getFileInfo(file, { ignorePath })).resolves.toEqual({
ignored: true,
inferredParser: null,
});
});
test("API getFileInfo with ignorePath containing relative paths", async () => {
const file = path.resolve(
path.join(
__dirname,
"../cli/ignore-relative-path/level1-glob/level2-glob/level3-glob/shouldNotBeFormat.js",
),
const file = new URL(
"../cli/ignore-relative-path/level1-glob/level2-glob/level3-glob/shouldNotBeFormat.js",
import.meta.url,
);
const ignorePath = path.resolve(
path.join(__dirname, "../cli/ignore-relative-path/.prettierignore"),
);
await expect(prettier.getFileInfo(file)).resolves.toMatchObject({
await expect(prettier.getFileInfo(file)).resolves.toEqual({
ignored: false,
inferredParser: "babel",
});
await expect(
prettier.getFileInfo(file, { ignorePath }),
).resolves.toMatchObject({
await expect(prettier.getFileInfo(file, { ignorePath })).resolves.toEqual({
ignored: true,
inferredParser: null,
});
@@ -300,10 +293,11 @@ describe("API getFileInfo with ignorePath", () => {
});
test("API getFileInfo with withNodeModules", async () => {
const file = path.resolve(
path.join(__dirname, "../cli/with-node-modules/node_modules/file.js"),
const file = new URL(
"../cli/with-node-modules/node_modules/file.js",
import.meta.url,
);
await expect(prettier.getFileInfo(file)).resolves.toMatchObject({
await expect(prettier.getFileInfo(file)).resolves.toEqual({
ignored: true,
inferredParser: null,
});
@@ -311,7 +305,7 @@ test("API getFileInfo with withNodeModules", async () => {
prettier.getFileInfo(file, {
withNodeModules: true,
}),
).resolves.toMatchObject({
).resolves.toEqual({
ignored: false,
inferredParser: "babel",
});
@@ -320,7 +314,7 @@ test("API getFileInfo with withNodeModules", async () => {
test("extracts file-info for a JS file with no extension but a standard shebang", async () => {
await expect(
prettier.getFileInfo("tests/integration/cli/shebang/node-shebang"),
).resolves.toMatchObject({
).resolves.toEqual({
ignored: false,
inferredParser: "babel",
});
@@ -329,7 +323,7 @@ test("extracts file-info for a JS file with no extension but a standard shebang"
test("extracts file-info for a JS file with no extension but an env-based shebang", async () => {
await expect(
prettier.getFileInfo("tests/integration/cli/shebang/env-node-shebang"),
).resolves.toMatchObject({
).resolves.toEqual({
ignored: false,
inferredParser: "babel",
});
@@ -338,7 +332,7 @@ test("extracts file-info for a JS file with no extension but an env-based sheban
test("returns null parser for unknown shebang", async () => {
await expect(
prettier.getFileInfo("tests/integration/cli/shebang/nonsense-shebang"),
).resolves.toMatchObject({
).resolves.toEqual({
ignored: false,
inferredParser: null,
});
@@ -352,7 +346,7 @@ test("API getFileInfo with hand-picked plugins", async () => {
"../plugins/automatic/node_modules/@prettier/plugin-foo/index.js",
),
);
await expect(prettier.getFileInfo(file)).resolves.toMatchObject({
await expect(prettier.getFileInfo(file)).resolves.toEqual({
ignored: false,
inferredParser: null,
});
@@ -360,7 +354,7 @@ test("API getFileInfo with hand-picked plugins", async () => {
prettier.getFileInfo(file, {
plugins: [pluginPath],
}),
).resolves.toMatchObject({
).resolves.toEqual({
ignored: false,
inferredParser: "foo",
});
@@ -375,8 +369,24 @@ test("API getFileInfo with ignorePath and resolveConfig should infer parser with
ignorePath,
};
await expect(prettier.getFileInfo(filePath, options)).resolves.toMatchObject({
await expect(prettier.getFileInfo(filePath, options)).resolves.toEqual({
ignored: false,
inferredParser: "parser-for-config-dir",
});
});
test("API getFileInfo accepts path or URL", async () => {
const fileUrl = new URL("../../../README.md", import.meta.url);
const expectedResult = { ignored: false, inferredParser: "markdown" };
const resultByUrl = await prettier.getFileInfo(fileUrl);
const resultByUrlHref = await prettier.getFileInfo(fileUrl.href);
const resultByPath = await prettier.getFileInfo(url.fileURLToPath(fileUrl));
const resultByRelativePath = await prettier.getFileInfo(
path.relative(process.cwd(), url.fileURLToPath(fileUrl)),
);
expect(resultByUrl).toEqual(expectedResult);
expect(resultByUrlHref).toEqual(expectedResult);
expect(resultByPath).toEqual(expectedResult);
expect(resultByRelativePath).toEqual(expectedResult);
});