@rushstack/heft
Version:
Build all your JavaScript projects the same way: A way that works.
147 lines • 8.45 kB
JavaScript
;
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
Object.defineProperty(exports, "__esModule", { value: true });
exports.HeftLifecycle = void 0;
const tapable_1 = require("tapable");
const node_core_library_1 = require("@rushstack/node-core-library");
const HeftPluginConfiguration_1 = require("../configuration/HeftPluginConfiguration");
const HeftPluginHost_1 = require("./HeftPluginHost");
const HeftLifecycleSession_1 = require("./HeftLifecycleSession");
class HeftLifecycle extends HeftPluginHost_1.HeftPluginHost {
get hooks() {
return this._lifecycleHooks;
}
get pluginDefinitions() {
if (!this._isInitialized) {
throw new node_core_library_1.InternalError('HeftLifecycle.ensureInitializedAsync() must be called before accessing HeftLifecycle.pluginDefinitions.');
}
return this._lifecycleContextByDefinition.keys();
}
constructor(internalHeftSession, lifecyclePluginSpecifiers) {
super();
this._lifecycleContextByDefinition = new Map();
this._lifecyclePluginsByDefinition = new Map();
this._isInitialized = false;
this._internalHeftSession = internalHeftSession;
this._lifecyclePluginSpecifiers = lifecyclePluginSpecifiers;
this._lifecycleHooks = {
clean: new tapable_1.AsyncParallelHook(),
toolStart: new tapable_1.AsyncParallelHook(),
toolFinish: new tapable_1.AsyncParallelHook(),
recordMetrics: internalHeftSession.metricsCollector.recordMetricsHook,
taskStart: new tapable_1.AsyncParallelHook(['task']),
taskFinish: new tapable_1.AsyncParallelHook(['task']),
phaseStart: new tapable_1.AsyncParallelHook(['phase']),
phaseFinish: new tapable_1.AsyncParallelHook(['phase'])
};
}
async applyPluginsInternalAsync() {
await this.ensureInitializedAsync();
// Load up all plugins concurrently
const loadPluginPromises = [];
for (const [pluginDefinition, lifecycleContext] of this._lifecycleContextByDefinition) {
if (!lifecycleContext.lifecycleSession) {
// Generate the plugin-specific session
lifecycleContext.lifecycleSession = new HeftLifecycleSession_1.HeftLifecycleSession({
debug: this._internalHeftSession.debug,
heftConfiguration: this._internalHeftSession.heftConfiguration,
loggingManager: this._internalHeftSession.loggingManager,
metricsCollector: this._internalHeftSession.metricsCollector,
logger: this._internalHeftSession.loggingManager.requestScopedLogger(`lifecycle:${pluginDefinition.pluginName}`),
lifecycleHooks: this.hooks,
lifecycleParameters: this._internalHeftSession.parameterManager.getParametersForPlugin(pluginDefinition),
pluginDefinition: pluginDefinition,
pluginHost: this
});
}
loadPluginPromises.push(this._getLifecyclePluginForPluginDefinitionAsync(pluginDefinition, lifecycleContext.lifecycleSession));
}
// Promise.all maintains the order of the input array
const plugins = await Promise.all(loadPluginPromises);
// Iterate through and apply the plugins
let pluginIndex = 0;
for (const [pluginDefinition, lifecycleContext] of this._lifecycleContextByDefinition) {
const lifecyclePlugin = plugins[pluginIndex++];
try {
// Apply the plugin. We know the session should exist because we generated it above.
lifecyclePlugin.apply(lifecycleContext.lifecycleSession, this._internalHeftSession.heftConfiguration, lifecycleContext.pluginOptions);
}
catch (error) {
throw new Error(`Error applying plugin ${JSON.stringify(pluginDefinition.pluginName)} from package ` +
`${JSON.stringify(pluginDefinition.pluginPackageName)}: ${error}`);
}
}
// Do a second pass to apply the plugin access requests for each plugin
pluginIndex = 0;
for (const [pluginDefinition] of this._lifecycleContextByDefinition) {
const lifecyclePlugin = plugins[pluginIndex++];
this.resolvePluginAccessRequests(lifecyclePlugin, pluginDefinition);
}
}
async ensureInitializedAsync() {
if (!this._isInitialized) {
this._isInitialized = true;
// Load up all plugin configurations concurrently
const pluginConfigurationPromises = [];
for (const pluginSpecifier of this._lifecyclePluginSpecifiers) {
const { pluginPackageRoot, pluginPackage } = pluginSpecifier;
pluginConfigurationPromises.push(HeftPluginConfiguration_1.HeftPluginConfiguration.loadFromPackageAsync(pluginPackageRoot, pluginPackage));
}
// Promise.all maintains the order of the input array
const pluginConfigurations = await Promise.all(pluginConfigurationPromises);
// Iterate through and generate the lifecycle context for each plugin
let pluginConfigurationIndex = 0;
for (const pluginSpecifier of this._lifecyclePluginSpecifiers) {
const pluginConfiguration = pluginConfigurations[pluginConfigurationIndex++];
const pluginDefinition = pluginConfiguration.getPluginDefinitionBySpecifier(pluginSpecifier);
// Ensure the plugin is a lifecycle plugin
const isLifecyclePlugin = pluginConfiguration.isLifecyclePluginDefinition(pluginDefinition);
if (!isLifecyclePlugin) {
throw new Error(`Plugin ${JSON.stringify(pluginDefinition.pluginName)} from package ` +
`${JSON.stringify(pluginSpecifier.pluginPackage)} is not a lifecycle plugin.`);
}
// Ensure there are no duplicate plugin names within the same package
if (this._lifecycleContextByDefinition.has(pluginDefinition)) {
throw new Error(`Lifecycle plugin ${JSON.stringify(pluginDefinition.pluginName)} from package ` +
`${JSON.stringify(pluginSpecifier.pluginPackage)} cannot be specified more than once.`);
}
// Validate the plugin options
const pluginOptions = pluginSpecifier.options;
pluginDefinition.validateOptions(pluginOptions);
// Partially populate the context. The session will be populated while applying the plugins.
const lifecycleContext = { pluginOptions };
this._lifecycleContextByDefinition.set(pluginDefinition, lifecycleContext);
}
}
}
get lifecycleLogger() {
let logger = this._lifecycleLogger;
if (!logger) {
logger = this._internalHeftSession.loggingManager.requestScopedLogger(`lifecycle`);
this._lifecycleLogger = logger;
}
return logger;
}
async getSessionForPluginDefinitionAsync(pluginDefinition) {
await this.ensureInitializedAsync();
const lifecycleContext = this._lifecycleContextByDefinition.get(pluginDefinition);
if (!lifecycleContext) {
throw new node_core_library_1.InternalError(`Could not find lifecycle context for plugin ${JSON.stringify(pluginDefinition.pluginName)}.`);
}
if (!lifecycleContext.lifecycleSession) {
throw new node_core_library_1.InternalError(`Lifecycle session for plugin ${JSON.stringify(pluginDefinition.pluginName)} has not been created yet.`);
}
return lifecycleContext.lifecycleSession;
}
async _getLifecyclePluginForPluginDefinitionAsync(pluginDefinition, lifecycleSession) {
let lifecyclePlugin = this._lifecyclePluginsByDefinition.get(pluginDefinition);
if (!lifecyclePlugin) {
lifecyclePlugin = await pluginDefinition.loadPluginAsync(lifecycleSession.logger);
this._lifecyclePluginsByDefinition.set(pluginDefinition, lifecyclePlugin);
}
return lifecyclePlugin;
}
}
exports.HeftLifecycle = HeftLifecycle;
//# sourceMappingURL=HeftLifecycle.js.map