Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove plugin search feature #14759

Merged
merged 12 commits into from May 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions changelog_unreleased/api/14759.md
@@ -0,0 +1,7 @@
#### [Breaking] plugin search feature has been removed (#14759 by @fisker)

The plugin auto search feature didn't work well when using pnpm, and cause slowness.

`--plugin-search-dir`, `--no-plugin-search` flags for CLI and `pluginSearchDirs` in API options has been removed in Prettier main.

`--plugin` flag and `plugins` option should be used instead, see [documentation](https://prettier.io/docs/en/plugins.html#using-plugins).
4 changes: 0 additions & 4 deletions docs/cli.md
Expand Up @@ -204,10 +204,6 @@ prettier "**/*" --write --ignore-unknown

Prevent errors when pattern is unmatched.

## `--no-plugin-search`

Disable plugin autoloading.

## `--cache`

If this option is enabled, the following values are used as cache keys and the file is formatted only if one of them is changed.
Expand Down
24 changes: 6 additions & 18 deletions docs/plugins.md
Expand Up @@ -7,26 +7,21 @@ Plugins are ways of adding new languages or formatting rules to Prettier. Pretti

## Using Plugins

Plugins are automatically loaded if you have them installed in the same `node_modules` directory where `prettier` is located. Plugin package names must start with `@prettier/plugin-` or `prettier-plugin-` or `@<scope>/prettier-plugin-` to be registered.
You can load plugins with:

> `<scope>` should be replaced by a name, read more about [NPM scope](https://docs.npmjs.com/misc/scope.html).

When plugins cannot be found automatically, you can load them with:

- The [CLI](cli.md), via `--plugin-search-dir` and `--plugin`:
- The [CLI](cli.md), via `--plugin`:

```bash
prettier --write main.foo --plugin-search-dir=./dir-with-plugins --plugin=prettier-plugin-foo
prettier --write main.foo --plugin=prettier-plugin-foo
```

> Tip: You can set `--plugin-search-dir` or `--plugin` options multiple times.
> Tip: You can set `--plugin` options multiple times.

- The [API](api.md), via the `pluginSearchDirs` and `plugins` options:
- The [API](api.md), via the `plugins` options:

```js
await prettier.format("code", {
parser: "foo",
pluginSearchDirs: ["./dir-with-plugins"],
plugins: ["prettier-plugin-foo"],
});
```
Expand All @@ -35,18 +30,11 @@ When plugins cannot be found automatically, you can load them with:

```json
{
"pluginSearchDirs": ["./dir-with-plugins"],
"plugins": ["prettier-plugin-foo"]
}
```

`pluginSearchDirs` and `plugins` are independent and one does not require the other.

The paths that are provided to `pluginSearchDirs` will be searched for `@prettier/plugin-*`, `prettier-plugin-*`, and `@*/prettier-plugin-*`. For instance, these can be your project directory, a `node_modules` directory, the location of global npm modules, or any arbitrary directory that contains plugins.

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()`.)

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.
Strings provided to `plugins` are ultimately passed to [`import()` expression](https://nodejs.org/api/esm.html#import-expressions), so you can provide a module/package name, a path, or anything else `import()` takes.

## Official Plugins

Expand Down
13 changes: 0 additions & 13 deletions scripts/utils/generate-schema.js
Expand Up @@ -80,19 +80,6 @@ function optionToSchema(option) {
}
if (option.array) {
schema = wrapWithArraySchema(schema);

// #10274
if (option.name === "pluginSearchDirs") {
schema = {
oneOf: [
schema,
{
enum: [false],
description: "Disable plugin autoloading.",
},
],
};
}
}
return {
description: option.description,
Expand Down
4 changes: 0 additions & 4 deletions src/cli/cli-options.evaluate.js
Expand Up @@ -220,10 +220,6 @@ const options = {
description: "What level of logs to report.",
type: "choice",
},
pluginSearch: {
oppositeDescription: "Disable plugin autoloading.",
type: "boolean",
},
supportInfo: {
description: "Print support information as JSON.",
type: "boolean",
Expand Down
15 changes: 6 additions & 9 deletions src/cli/context.js
Expand Up @@ -29,13 +29,11 @@ class Context {
async init() {
const { rawArguments, logger } = this;

const { plugins, pluginSearchDirs } = parseArgvWithoutPlugins(
rawArguments,
logger,
["plugin", "plugin-search-dir"]
);
const { plugins } = parseArgvWithoutPlugins(rawArguments, logger, [
"plugin",
]);

await this.pushContextPlugins(plugins, pluginSearchDirs);
await this.pushContextPlugins(plugins);

const argv = parseArgv(rawArguments, this.detailedOptions, logger);
this.argv = argv;
Expand All @@ -44,10 +42,9 @@ class Context {

/**
* @param {string[]} plugins
* @param {string[]=} pluginSearchDirs
*/
async pushContextPlugins(plugins, pluginSearchDirs) {
const options = await getContextOptions(plugins, pluginSearchDirs);
async pushContextPlugins(plugins) {
const options = await getContextOptions(plugins);
this.#stack.push(options);
Object.assign(this, options);
}
Expand Down
2 changes: 0 additions & 2 deletions src/cli/file-info.js
Expand Up @@ -8,15 +8,13 @@ async function logFileInfoOrDie(context) {
ignorePath,
withNodeModules,
plugins,
pluginSearchDirs,
config,
} = context.argv;

const fileInfo = await getFileInfo(file, {
ignorePath,
withNodeModules,
plugins,
pluginSearchDirs,
resolveConfig: config !== false,
});

Expand Down
14 changes: 1 addition & 13 deletions src/cli/index.js
Expand Up @@ -6,7 +6,7 @@ import { createDetailedUsage, createUsage } from "./usage.js";
import { formatStdin, formatFiles } from "./format.js";
import logFileInfoOrDie from "./file-info.js";
import logResolvedConfigPathOrDie from "./find-config-path.js";
import { printToScreen, isNonEmptyArray } from "./utils.js";
import { printToScreen } from "./utils.js";
import printSupportInfo from "./print-support-info.js";

async function run(rawArguments) {
Expand Down Expand Up @@ -38,18 +38,6 @@ async function run(rawArguments) {
async function main(context) {
context.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.");
}
Expand Down
4 changes: 1 addition & 3 deletions src/cli/options/create-minimist-options.js
Expand Up @@ -13,9 +13,7 @@ export default function createMinimistOptions(detailedOptions) {

if (
!option.deprecated &&
(!option.forwardToApi ||
name === "plugin" ||
name === "plugin-search-dir") &&
(!option.forwardToApi || name === "plugin") &&
option.default !== undefined
) {
defaultValues[option.name] = option.default;
Expand Down
3 changes: 1 addition & 2 deletions src/cli/options/get-context-options.js
Expand Up @@ -64,11 +64,10 @@ function supportInfoToContextOptions({ options: supportOptions, languages }) {
};
}

async function getContextOptions(plugins, pluginSearchDirs) {
async function getContextOptions(plugins) {
const supportInfo = await getSupportInfo({
showDeprecated: true,
plugins,
pluginSearchDirs,
});

return supportInfoToContextOptions(supportInfo);
Expand Down
7 changes: 1 addition & 6 deletions src/cli/options/parse-cli-arguments.js
Expand Up @@ -10,10 +10,6 @@ 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)
);
Expand All @@ -26,8 +22,7 @@ function parseArgv(rawArguments, detailedOptions, logger, keys) {
...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`
// If the flag is a prettier api option, use the option name
// Otherwise use camel case for readability
// `--ignore-unknown` -> `ignoreUnknown`
return [option.forwardToApi || camelCase(key), value];
Expand Down
14 changes: 6 additions & 8 deletions src/config/resolve-config.js
Expand Up @@ -49,14 +49,12 @@ async function resolveConfig(filePath, options) {
...mergeOverrides(result, filePath),
};

for (const optionName of ["plugins", "pluginSearchDirs"]) {
if (Array.isArray(merged[optionName])) {
merged[optionName] = merged[optionName].map((value) =>
typeof value === "string" && value.startsWith(".") // relative path
? path.resolve(path.dirname(result.filepath), value)
: value
);
}
if (Array.isArray(merged.plugins)) {
merged.plugins = merged.plugins.map((value) =>
typeof value === "string" && value.startsWith(".") // relative path
? path.resolve(path.dirname(result.filepath), value)
: value
);
}

return merged;
Expand Down
4 changes: 0 additions & 4 deletions src/index.d.ts
Expand Up @@ -405,10 +405,6 @@ export interface RequiredOptions extends doc.printer.Options {
* Provide ability to support new languages to prettier.
*/
plugins: Array<string | Plugin>;
/**
* Specify plugin directory paths to search for plugins if not installed in the same `node_modules` where prettier is located.
*/
pluginSearchDirs: string[] | false;
/**
* How to handle whitespaces in HTML.
* @default "css"
Expand Down
7 changes: 2 additions & 5 deletions src/index.js
@@ -1,4 +1,5 @@
import vnopts from "vnopts";
// "fast-glob" is bundled here since the API uses `micromatch` too
import fastGlob from "fast-glob";
import * as core from "./main/core.js";
import {
Expand All @@ -9,7 +10,6 @@ import getFileInfoWithoutPlugins from "./common/get-file-info.js";
import {
loadBuiltinPlugins,
loadPlugins,
searchPlugins,
clearCache as clearPluginCache,
} from "./main/plugins/index.js";
import {
Expand Down Expand Up @@ -37,7 +37,7 @@ function withPlugins(
) {
return async (...args) => {
const options = args[optionsArgumentIndex] ?? {};
const { plugins = [], pluginSearchDirs } = options;
const { plugins = [] } = options;

args[optionsArgumentIndex] = {
...options,
Expand All @@ -46,9 +46,6 @@ function withPlugins(
loadBuiltinPlugins(),
// TODO: standalone version allow `plugins` to be `prettierPlugins` which is an object, should allow that too
loadPlugins(plugins),
options.pluginSearchDirs === false
? []
: searchPlugins(pluginSearchDirs),
])
).flat(),
};
Expand Down
15 changes: 0 additions & 15 deletions src/main/core-options.evaluate.js
Expand Up @@ -145,21 +145,6 @@ const options = {
cliName: "plugin",
cliCategory: CATEGORY_CONFIG,
},
pluginSearchDirs: {
type: "path",
array: true,
default: [{ value: [] }],
category: CATEGORY_GLOBAL,
description: outdent`
Custom directory that contains prettier plugins in node_modules subdirectory.
Overrides default behavior when plugins are searched relatively to the location of Prettier.
Multiple values are accepted.
`,
exception: (value) =>
typeof value === "string" || typeof value === "object",
cliName: "plugin-search-dir",
cliCategory: CATEGORY_CONFIG,
},
printWidth: {
category: CATEGORY_GLOBAL,
type: "int",
Expand Down
30 changes: 0 additions & 30 deletions src/main/normalize-options.js
Expand Up @@ -72,10 +72,6 @@ function normalizeOptions(
hasDeprecationWarned = normalizer._hasDeprecationWarned;
}

if (isCLI && normalized["plugin-search"] === false) {
normalized["plugin-search-dir"] = false;
}

return normalized;
}

Expand Down Expand Up @@ -117,32 +113,6 @@ function optionInfosToSchemas(optionInfos, { isCLI, FlagSchema }) {
function optionInfoToSchema(optionInfo, { isCLI, optionInfos, FlagSchema }) {
const { name } = optionInfo;

if (name === "plugin-search-dir" || name === "pluginSearchDirs") {
return vnopts.AnySchema.create({
// @ts-expect-error
name,
preprocess(value) {
if (value === false) {
return value;
}
value = Array.isArray(value) ? value : [value];
return value;
},
/**
* @param {Array<unknown> | false} 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 handlers = {};
Expand Down
9 changes: 1 addition & 8 deletions src/main/plugins/index.js
@@ -1,10 +1,3 @@
import { clearCache as clearPluginLoadCache } from "./load-plugin.js";
import { clearCache as clearPluginSearchCache } from "./search-plugins.js";

export function clearCache() {
clearPluginLoadCache();
clearPluginSearchCache();
}
export { clearCache } from "./load-plugin.js";
export { default as loadBuiltinPlugins } from "./load-builtin-plugins.js";
export { default as loadPlugins } from "./load-plugins.js";
export { searchPlugins } from "./search-plugins.js";