secret-polar-reworks
Version:
Polar is a development environment to compile, deploy, test, run scrt contracts on different networks.
155 lines (130 loc) • 4.5 kB
text/typescript
import debug from "debug";
import * as path from "path";
import * as semver from "semver";
import { StrMap } from "../../types";
import { PolarContext } from "../context";
import { PolarError } from "../core/errors";
import { ERRORS } from "../core/errors-list";
import { ExecutionMode, getExecutionMode } from "./execution-mode";
const log = debug("polar:core:plugins");
interface PackageJson {
name: string
version: string
peerDependencies: {
[name: string]: string
}
}
/**
* Validates a plugin dependencies and loads it.
* @param pluginName - The plugin name
* @param PolarContext - The PolarContext
* @param from - Where to resolve plugins and dependencies from. Only for
* testing purposes.
*/
export function usePlugin (
PolarContext: PolarContext,
pluginName: string,
from?: string
): void {
log("Loading plugin %s", pluginName);
// We have a special case for `ExecutionMode.EXECUTION_MODE_LINKED`
//
// If polar is linked, a require without `from` would be executed in the
// context of polar, and not find any plugin (linked or not). We workaround
// this by using the CWD here.
//
// This is not ideal, but the only reason to link polar is testing.
if (
from === undefined &&
getExecutionMode() === ExecutionMode.EXECUTION_MODE_LINKED
) {
from = process.cwd();
log("polar is linked, searching for plugin starting from CWD", from);
}
let globalFlag = "";
let globalWarning = "";
if (getExecutionMode() === ExecutionMode.EXECUTION_MODE_GLOBAL_INSTALLATION) {
globalFlag = " --global";
globalWarning =
"You are using a global installation of polar. Plugins and their dependencies must also be global.\n";
}
const pluginPackageJson = readPackageJson(pluginName, from);
if (pluginPackageJson === undefined) {
const installExtraFlags = globalFlag;
throw new PolarError(ERRORS.PLUGINS.NOT_INSTALLED, {
plugin: pluginName,
extraMessage: globalWarning,
extraFlags: installExtraFlags
});
}
// We use the package.json's version of the name, as it is normalized.
pluginName = pluginPackageJson.name;
if (PolarContext.loadedPlugins.includes(pluginName)) {
return;
}
if (pluginPackageJson.peerDependencies !== undefined) {
checkPeerDependencies(pluginPackageJson.peerDependencies,
pluginName, from, globalFlag, globalWarning);
}
const options = from !== undefined ? { paths: [from] } : undefined;
const pluginPath = require.resolve(pluginName, options);
loadPluginFile(pluginPath);
PolarContext.setPluginAsLoaded(pluginName);
}
function checkPeerDependencies (deps: StrMap, pluginName: string,
from: string | undefined, flag: string, warning: string): void {
for (const [dependencyName, versionSpec] of Object.entries(deps)) {
const dependencyPackageJson = readPackageJson(dependencyName, from);
let installExtraFlags = flag;
if (versionSpec.match(/^[0-9]/) !== null) {
installExtraFlags += " --save-exact";
}
if (dependencyPackageJson === undefined) {
throw new PolarError(ERRORS.PLUGINS.MISSING_DEPENDENCIES, {
plugin: pluginName,
dependency: dependencyName,
extraMessage: warning,
extraFlags: installExtraFlags,
versionSpec
});
}
const installedVersion = dependencyPackageJson.version;
if (
!semver.satisfies(installedVersion, versionSpec, {
includePrerelease: true
})
) {
throw new PolarError(ERRORS.PLUGINS.DEPENDENCY_VERSION_MISMATCH, {
plugin: pluginName,
dependency: dependencyName,
extraMessage: warning,
extraFlags: installExtraFlags,
versionSpec,
installedVersion
});
}
}
}
export function loadPluginFile (absolutePluginFilePath: string): void {
log("Loading plugin file %s", absolutePluginFilePath);
const imported = require(absolutePluginFilePath); // eslint-disable-line @typescript-eslint/no-var-requires
const plugin = imported.default !== undefined ? imported.default : imported;
if (typeof plugin === "function") {
plugin();
}
}
export function readPackageJson (
packageName: string,
from?: string
): PackageJson | undefined {
try {
const options = from !== undefined ? { paths: [from] } : undefined;
const packageJsonPath = require.resolve(
path.join(packageName, "package.json"),
options
);
return require(packageJsonPath);
} catch (error) {
return undefined;
}
}