prettier/src/common/load-plugins.js

116 lines
3.1 KiB
JavaScript

"use strict";
const uniqBy = require("lodash.uniqby");
const fs = require("fs");
const globby = require("globby");
const path = require("path");
const resolve = require("resolve");
const thirdParty = require("./third-party");
const internalPlugins = require("./internal-plugins");
const partition = require("../utils/partition");
function loadPlugins(plugins, pluginSearchDirs) {
if (!plugins) {
plugins = [];
}
if (!pluginSearchDirs) {
pluginSearchDirs = [];
}
// unless pluginSearchDirs are provided, auto-load plugins from node_modules that are parent to Prettier
if (!pluginSearchDirs.length) {
const autoLoadDir = thirdParty.findParentDir(__dirname, "node_modules");
if (autoLoadDir) {
pluginSearchDirs = [autoLoadDir];
}
}
const [externalPluginNames, externalPluginInstances] = partition(
plugins,
plugin => typeof plugin === "string"
);
const externalManualLoadPluginInfos = externalPluginNames.map(pluginName => {
let requirePath;
try {
// try local files
requirePath = resolve.sync(path.resolve(process.cwd(), pluginName));
} catch (e) {
// try node modules
requirePath = resolve.sync(pluginName, { basedir: process.cwd() });
}
return {
name: pluginName,
requirePath
};
});
const externalAutoLoadPluginInfos = pluginSearchDirs
.map(pluginSearchDir => {
const resolvedPluginSearchDir = path.resolve(
process.cwd(),
pluginSearchDir
);
const nodeModulesDir = path.resolve(
resolvedPluginSearchDir,
"node_modules"
);
// In some fringe cases (ex: files "mounted" as virtual directories), the
// isDirectory(resolvedPluginSearchDir) check might be false even though
// the node_modules actually exists.
if (
!isDirectory(nodeModulesDir) &&
!isDirectory(resolvedPluginSearchDir)
) {
throw new Error(
`${pluginSearchDir} does not exist or is not a directory`
);
}
return findPluginsInNodeModules(nodeModulesDir).map(pluginName => ({
name: pluginName,
requirePath: resolve.sync(pluginName, {
basedir: resolvedPluginSearchDir
})
}));
})
.reduce((a, b) => a.concat(b), []);
const externalPlugins = uniqBy(
externalManualLoadPluginInfos.concat(externalAutoLoadPluginInfos),
"requirePath"
)
.map(externalPluginInfo =>
Object.assign(
{ name: externalPluginInfo.name },
eval("require")(externalPluginInfo.requirePath)
)
)
.concat(externalPluginInstances);
return internalPlugins.concat(externalPlugins);
}
function findPluginsInNodeModules(nodeModulesDir) {
const pluginPackageJsonPaths = globby.sync(
[
"prettier-plugin-*/package.json",
"@*/prettier-plugin-*/package.json",
"@prettier/plugin-*/package.json"
],
{ cwd: nodeModulesDir }
);
return pluginPackageJsonPaths.map(path.dirname);
}
function isDirectory(dir) {
try {
return fs.statSync(dir).isDirectory();
} catch (e) {
return false;
}
}
module.exports = loadPlugins;