@rushstack/heft
Version:
Build all your JavaScript projects the same way: A way that works.
138 lines • 5.65 kB
JavaScript
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
import * as path from 'node:path';
import { InternalError, JsonSchema } from '@rushstack/node-core-library';
export class HeftPluginDefinitionBase {
constructor(options) {
this._heftPluginDefinitionJson = options.heftPluginDefinitionJson;
this._pluginPackageName = options.packageName;
this._resolvedEntryPoint = path.resolve(options.packageRoot, this._heftPluginDefinitionJson.entryPoint);
// Ensure that the plugin parameters are unique
const seenParameters = new Set();
for (const parameter of this.pluginParameters) {
if (seenParameters.has(parameter.longName)) {
throw new Error(`Parameter ${JSON.stringify(parameter.longName)} is defined multiple times by the providing ` +
`plugin ${JSON.stringify(this.pluginName)} in package ` +
`${JSON.stringify(this.pluginPackageName)}.`);
}
seenParameters.add(parameter.longName);
}
// Unfortunately loading the schema is a synchronous process.
if (options.heftPluginDefinitionJson.optionsSchema) {
const resolvedSchemaPath = path.resolve(options.packageRoot, options.heftPluginDefinitionJson.optionsSchema);
this._optionsSchema = JsonSchema.fromFile(resolvedSchemaPath);
}
}
/**
* The package name containing the target plugin.
*/
get pluginPackageName() {
return this._pluginPackageName;
}
/**
* The name of the target plugin.
*/
get pluginName() {
return this._heftPluginDefinitionJson.pluginName;
}
/**
* The resolved entry point to the plugin.
*/
get entryPoint() {
return this._resolvedEntryPoint;
}
/**
* The scope for all parameters defined by this plugin.
*/
get pluginParameterScope() {
// Default to the plugin name for the parameter scope. Plugin names should be unique within any run
// of Heft. Additionally, plugin names have the same naming restrictions as parameter scopes so can
// be used without modification.
return this._heftPluginDefinitionJson.parameterScope || this.pluginName;
}
/**
* The parameters that are defined for this plugin.
*/
get pluginParameters() {
return this._heftPluginDefinitionJson.parameters || [];
}
/**
* Load the plugin associated with the definition.
*/
async loadPluginAsync(logger) {
// Do not memoize the plugin here, since we want a new instance of the plugin each time it is loaded
// from the definition
let heftPlugin;
const entryPointPath = this.entryPoint;
try {
const loadedPluginModule = await import(entryPointPath);
const heftPluginConstructor = loadedPluginModule.default || loadedPluginModule;
heftPlugin = new heftPluginConstructor();
}
catch (e) {
const error = e;
if (error.message === 'heftPluginConstructor is not a constructor') {
// Common error scenario, give a more helpful error message
throw new Error(`Could not load plugin from "${entryPointPath}": The target module does not ` +
'export a plugin class with a parameterless constructor.');
}
else {
throw new InternalError(`Could not load plugin from "${entryPointPath}": ${error}`);
}
}
if (!heftPlugin) {
throw new InternalError(`Plugin ${JSON.stringify(this.pluginName)} loaded from "${entryPointPath}" is null or undefined.`);
}
logger.terminal.writeVerboseLine(`Loaded plugin from "${entryPointPath}"`);
if (typeof heftPlugin.apply !== 'function') {
throw new InternalError(`The plugin ${JSON.stringify(this.pluginName)} loaded from "${entryPointPath}" ` +
'doesn\'t define an "apply" function.');
}
return heftPlugin;
}
/**
* Validate the provided plugin options against the plugin's options schema, if one is provided.
*/
validateOptions(options) {
if (this._optionsSchema) {
try {
this._optionsSchema.validateObject(options || {}, '');
}
catch (error) {
throw new Error(`Provided options for plugin ${JSON.stringify(this.pluginName)} did not match the provided ` +
`plugin schema.\n${error}`);
}
}
}
}
export class HeftLifecyclePluginDefinition extends HeftPluginDefinitionBase {
/**
* Load a lifecycle plugin definition given the provided plugin definition options.
*/
static loadFromObject(options) {
return new HeftLifecyclePluginDefinition(options);
}
/**
* {@inheritDoc HeftPluginDefinitionBase.loadPluginAsync}
* @override
*/
loadPluginAsync(logger) {
return super.loadPluginAsync(logger);
}
}
export class HeftTaskPluginDefinition extends HeftPluginDefinitionBase {
/**
* Load a task plugin definition given the provided plugin definition options.
*/
static loadFromObject(options) {
return new HeftTaskPluginDefinition(options);
}
/**
* {@inheritDoc HeftPluginDefinitionBase.loadPluginAsync}
* @override
*/
loadPluginAsync(logger) {
return super.loadPluginAsync(logger);
}
}
//# sourceMappingURL=HeftPluginDefinition.js.map