Add --no-plugin-search (#10274)

Co-authored-by: Alexander Kachkaev <alexander@kachkaev.ru>
This commit is contained in:
fisker CheungandAlexander Kachkaev authored and GitHub committed 2022-02-18 16:36:53 +08:00
1 parent 162097e2d2
commit 3ba48bb266
14 files changed
+190 -20

No files matched your search

+12
View File
@@ -0,0 +1,12 @@
#### Add `--no-plugin-search` to turn off plugin autoloading (#10274 by @fisker)
To turn off plugin autoloading, use `--no-plugin-search` when using Prettier CLI or add `{ pluginSearchDirs: false }` to options in `prettier.format()` or to the config file.
<!-- prettier-ignore -->
```cli
// Prettier stable
$ prettier . --plugin-search-dir=a-dir-without-plugins
// Prettier main
$ prettier . --no-plugin-search
```
+4
View File
@@ -200,3 +200,7 @@ $ prettier "**/*" --write --ignore-unknown
## `--no-error-on-unmatched-pattern`
Prevent errors when pattern is unmatched.
## `--no-plugin-search`
Disable plugin autoloading.
+1 -1
View File
@@ -46,7 +46,7 @@ The paths that are provided to `pluginSearchDirs` will be searched for `@prettie
Strings provided to `plugins` are ultimately passed to `require()`, so you can provide a module/package name, a path, or anything else `require()` takes. (`pluginSearchDirs` works the same way. That is, valid plugin paths that it finds are passed to `require()`.)
Providing at least one path to `--plugin-search-dir`/`pluginSearchDirs` turns off plugin autoloading in the default directory (i.e. `node_modules` above `prettier` binary).
To turn off plugin autoloading, use `--no-plugin-search` when using Prettier CLI or add `{ pluginSearchDirs: false }` to options in `prettier.format()` or to the config file.
## Official Plugins
+4
View File
@@ -202,6 +202,10 @@ const options = {
default: "log",
choices: ["silent", "error", "warn", "log", "debug"],
},
"plugin-search": {
type: "boolean",
oppositeDescription: "Disable plugin autoloading.",
},
"support-info": {
type: "boolean",
description: "Print support information as JSON.",
+15
View File
@@ -15,6 +15,9 @@ const { createDetailedUsage, createUsage } = require("./usage.js");
const { formatStdin, formatFiles } = require("./format.js");
const logFileInfoOrDie = require("./file-info.js");
const logResolvedConfigPathOrDie = require("./find-config-path.js");
const {
utils: { isNonEmptyArray },
} = require("./prettier-internal.js");
async function run(rawArguments) {
// Create a default level logger, so we can log errors during `logLevel` parsing
@@ -42,6 +45,18 @@ async function main(rawArguments, logger) {
logger.debug(`normalized argv: ${JSON.stringify(context.argv)}`);
if (context.argv.pluginSearch === false) {
const rawPluginSearchDirs = context.argv.__raw["plugin-search-dir"];
if (
typeof rawPluginSearchDirs === "string" ||
isNonEmptyArray(rawPluginSearchDirs)
) {
throw new Error(
"Cannot use --no-plugin-search and --plugin-search-dir together."
);
}
}
if (context.argv.check && context.argv.listDifferent) {
throw new Error("Cannot use --check and --list-different together.");
}
+23 -11
View File
@@ -14,6 +14,10 @@ function parseArgv(rawArguments, detailedOptions, logger, keys) {
let argv = minimist(rawArguments, minimistOptions);
if (keys) {
if (keys.includes("plugin-search-dir") && !keys.includes("plugin-search")) {
keys.push("plugin-search");
}
detailedOptions = detailedOptions.filter((option) =>
keys.includes(option.name)
);
@@ -25,19 +29,27 @@ function parseArgv(rawArguments, detailedOptions, logger, keys) {
colorsModule: chalk,
});
return Object.fromEntries(
Object.entries(normalized).map(([key, value]) => {
const option = detailedOptions.find(({ name }) => name === key) || {};
// If the flag is a prettier option, use the option name
// `--plugin-search-dir` -> `pluginSearchDirs`
// Otherwise use camel case for readability
// `--ignore-unknown` -> `ignoreUnknown`
return [option.forwardToApi || camelCase(key), value];
})
);
return {
...Object.fromEntries(
Object.entries(normalized).map(([key, value]) => {
const option = detailedOptions.find(({ name }) => name === key) || {};
// If the flag is a prettier option, use the option name
// `--plugin-search-dir` -> `pluginSearchDirs`
// Otherwise use camel case for readability
// `--ignore-unknown` -> `ignoreUnknown`
return [option.forwardToApi || camelCase(key), value];
})
),
get __raw() {
return argv;
},
};
}
const detailedOptionsWithoutPlugins = getContextOptions().detailedOptions;
const detailedOptionsWithoutPlugins = getContextOptions(
[],
false
).detailedOptions;
function parseArgvWithoutPlugins(rawArguments, logger, keys) {
return parseArgv(
rawArguments,
+10 -7
View File
@@ -22,14 +22,17 @@ function load(plugins, pluginSearchDirs) {
plugins = [];
}
if (!pluginSearchDirs) {
if (pluginSearchDirs === false) {
pluginSearchDirs = [];
}
// unless pluginSearchDirs are provided, auto-load plugins from node_modules that are parent to Prettier
if (pluginSearchDirs.length === 0) {
const autoLoadDir = thirdParty.findParentDir(__dirname, "node_modules");
if (autoLoadDir) {
pluginSearchDirs = [autoLoadDir];
} else {
pluginSearchDirs = pluginSearchDirs || [];
// unless pluginSearchDirs are provided, auto-load plugins from node_modules that are parent to Prettier
if (pluginSearchDirs.length === 0) {
const autoLoadDir = thirdParty.findParentDir(__dirname, "node_modules");
if (autoLoadDir) {
pluginSearchDirs = [autoLoadDir];
}
}
}
+1
View File
@@ -75,6 +75,7 @@ module.exports = {
utils: {
arrayify: require("./utils/arrayify.js"),
getLast: require("./utils/get-last.js"),
isNonEmptyArray: require("./common/util.js").isNonEmptyArray,
},
},
+29 -1
View File
@@ -94,6 +94,10 @@ function normalizeOptions(
hasDeprecationWarned = normalizer._hasDeprecationWarned;
}
if (isCLI && normalized["plugin-search"] === false) {
normalized["plugin-search-dir"] = false;
}
return normalized;
}
@@ -123,8 +127,32 @@ function optionInfosToSchemas(optionInfos, { isCLI, colorsModule }) {
}
function optionInfoToSchema(optionInfo, { isCLI, optionInfos, colorsModule }) {
const { name } = optionInfo;
if (name === "plugin-search-dir" || name === "pluginSearchDirs") {
return vnopts.AnySchema.create({
name,
preprocess(value) {
if (value === false) {
return value;
}
value = Array.isArray(value) ? value : [value];
return value;
},
validate(value) {
if (value === false) {
return true;
}
return value.every((dir) => typeof dir === "string");
},
expected() {
return "false or paths to plugin search dir";
},
});
}
const parameters = { name };
let SchemaConstructor;
const parameters = { name: optionInfo.name };
const handlers = {};
switch (optionInfo.type) {
@@ -153,6 +153,7 @@ Other options:
--loglevel <silent|error|warn|log|debug>
What level of logs to report.
Defaults to log.
--no-plugin-search Disable plugin autoloading.
--require-pragma Require either '@prettier' or '@format' to be present in the file's first docblock comment
in order for it to be formatted.
Defaults to false.
@@ -322,6 +323,7 @@ Other options:
--loglevel <silent|error|warn|log|debug>
What level of logs to report.
Defaults to log.
--no-plugin-search Disable plugin autoloading.
--require-pragma Require either '@prettier' or '@format' to be present in the file's first docblock comment
in order for it to be formatted.
Defaults to false.
@@ -358,6 +358,17 @@ exports[`show detailed usage with --help no-error-on-unmatched-pattern (stdout)
exports[`show detailed usage with --help no-error-on-unmatched-pattern (write) 1`] = `Array []`;
exports[`show detailed usage with --help no-plugin-search (stderr) 1`] = `""`;
exports[`show detailed usage with --help no-plugin-search (stdout) 1`] = `
"--no-plugin-search
Disable plugin autoloading.
"
`;
exports[`show detailed usage with --help no-plugin-search (write) 1`] = `Array []`;
exports[`show detailed usage with --help no-semi (stderr) 1`] = `""`;
exports[`show detailed usage with --help no-semi (stdout) 1`] = `
@@ -304,6 +304,14 @@ test("API resolveConfig resolves relative path values based on config filepath",
plugins: [path.join(parentDir, "path-to-plugin")],
pluginSearchDirs: [path.join(parentDir, "path-to-plugin-search-dir")],
});
expect(
prettier.resolveConfig.sync(
path.join(__dirname, "../cli/config/plugin-search-dirs/index.js")
)
).toMatchObject({
pluginSearchDirs: false,
});
});
test("API resolveConfig de-references to an external module", () => {
@@ -205,3 +205,70 @@ describe("loads --plugin by bespoke plugin name (assuming it is installed in cwd
write: [],
});
});
test("--no-plugin-search", async () => {
async function getParser(args = []) {
const { stdout } = await runPrettier("plugins/automatic", [
"--file-info=file.foo",
...args,
]);
return JSON.parse(stdout).inferredParser;
}
expect(await getParser()).toBe("foo");
expect(await getParser(["--plugin-search-dir=."])).toBe("foo");
expect(await getParser(["--no-plugin-search"])).toBeNull();
});
test("--no-plugin-search still allow use --plugin", async () => {
const args = ["file.txt", "--parser=bar"];
const { stdout: stdoutWithoutPlugin } = await runPrettier(
"plugins/automatic",
args
);
const argsWithPlugin = [...args, "--plugin=./prettier-plugin-bar.js"];
const { stdout: stdoutWithPlugin } = await runPrettier(
"plugins/automatic",
argsWithPlugin
);
const { stdout: stdoutWithoutPluginAndNoPluginSearch } = await runPrettier(
"plugins/automatic",
[...args, "--no-plugin-search"]
);
const { stdout: stdoutWithPluginButNoPluginSearch } = await runPrettier(
"plugins/automatic",
[...argsWithPlugin, "--no-plugin-search"]
);
expect(stdoutWithoutPlugin).not.toBe(stdoutWithPlugin);
expect(stdoutWithoutPluginAndNoPluginSearch).toBe("");
expect(stdoutWithPlugin).toBe(stdoutWithPluginButNoPluginSearch);
});
test("--no-plugin-search together with --plugin-search-dir", async () => {
const result1 = await runPrettier("plugins/automatic", [
"--no-plugin-search",
"--plugin-search-dir",
]);
const result2 = await runPrettier("plugins/automatic", [
"--no-plugin-search",
"--plugin-search-dir=foo",
]);
const result3 = await runPrettier("plugins/automatic", [
"--no-plugin-search",
"--plugin-search-dir=foo",
"--plugin-search-dir=bar",
]);
expect(result1).toMatchInlineSnapshot(`
Object {
"status": 1,
"stderr": "[error] Cannot use --no-plugin-search and --plugin-search-dir together.
",
"stdout": "",
"write": Array [],
}
`);
expect(result2).toEqual(result1);
expect(result3).toEqual(result1);
});
@@ -0,0 +1,3 @@
{
"pluginSearchDirs": false
}