UNPKG

xpm

Version:

The xPack project manager command line tool

250 lines 10.1 kB
import assert from 'node:assert'; import * as os from 'node:os'; import { isJsonObject, isString, isJsonArray, } from '../functions/is-something.js'; import { performSubstitutions } from '../functions/perform-substitutions.js'; import { getErrorMessage, hasLiquidSyntax } from '../functions/utils.js'; import { ConfigurationError } from './errors.js'; import { TemplateExpander } from './template-expander.js'; export class Actions { log; engine; substitutionsVariables; jsonActions; buildConfiguration; _actionsMap = new Map(); _namesSet = new Set(); _jsonActionsNamesMap = new Map(); _isInitialised = false; _names = []; constructor({ engine, substitutionsVariables, jsonActions, inheritedActionsMap, buildConfiguration, log, }) { assert(log, 'log is required'); assert(engine, 'engine is required'); assert(substitutionsVariables, 'substitutionsVariables is required'); if (buildConfiguration !== undefined) { log.trace(`${Actions.name}()` + ` @${buildConfiguration.name}`); } else { log.trace(`${Actions.name}()`); } this.log = log; this.engine = engine; this.substitutionsVariables = substitutionsVariables; this.jsonActions = jsonActions ?? {}; if (buildConfiguration !== undefined) { this.buildConfiguration = buildConfiguration; } if (inheritedActionsMap !== undefined) { for (const [inheritedActionName, inheritedAction,] of inheritedActionsMap) { const action = new Action({ actionName: inheritedActionName, jsonAction: inheritedAction.jsonAction, parentActions: this, }); this._actionsMap.set(inheritedActionName, action); } } } async initialise() { const log = this.log; if (this._isInitialised) { if (this.buildConfiguration !== undefined) { log.trace(`${Actions.name}.initialise()` + ` @${this.buildConfiguration.name} again`); } else { log.trace(`${Actions.name}.initialise() again`); } return false; } if (this.buildConfiguration !== undefined) { log.trace(`${Actions.name}.initialise()` + ` @${this.buildConfiguration.name}`); } else { log.trace(`${Actions.name}.initialise()`); } for (const [actionName, jsonAction] of Object.entries(this.jsonActions)) { if (hasLiquidSyntax(actionName)) { await this._processTemplate({ actionName, jsonActionTemplate: jsonAction, }); } else { if (this._namesSet.has(actionName)) { throw new ConfigurationError(`action name "${actionName}" already defined`); } else { this._actionsMap.set(actionName, undefined); this._jsonActionsNamesMap.set(actionName, actionName); this._namesSet.add(actionName); } } } const names = Array.from(this._actionsMap.keys()); this._names = names; this.log.trace(`${Actions.name}.initialise() =>`, names); this._isInitialised = true; return true; } get size() { assert(this._isInitialised, 'Actions collection must be initialised before accessing size'); return this._actionsMap.size; } get isEmpty() { assert(this._isInitialised, 'Actions collection must be initialised before accessing isEmpty'); return this._actionsMap.size === 0; } get names() { assert(this._isInitialised, 'Actions collection must be initialised before accessing names'); return this._names; } has(actionName) { assert(this._isInitialised, 'Actions collection must be initialised before accessing has()'); return this._actionsMap.has(actionName); } get(actionName) { assert(this._isInitialised, 'Actions collection must be initialised before accessing get()'); const log = this.log; log.trace(`${Actions.name}.get(${actionName})`); let action = this._actionsMap.get(actionName); if (action === undefined) { const jsonActionName = this._jsonActionsNamesMap.get(actionName); if (jsonActionName === undefined) { throw new ConfigurationError(`action "${actionName}" does not exist`); } const jsonAction = (this.jsonActions[jsonActionName] ?? ''); action = new Action({ actionName, jsonAction, parentActions: this, }); this._actionsMap.set(actionName, action); } return action; } async _processTemplate({ actionName, jsonActionTemplate, }) { try { const expandedActionsMap = await this._expandTemplateActions({ actionName, jsonActionTemplate, }); for (const [expandedActionName, expandedAction] of expandedActionsMap) { if (this._namesSet.has(expandedActionName)) { throw new ConfigurationError(`duplicate action name "${expandedActionName}" ` + `could not be generated from template.`); } else { this._actionsMap.set(expandedActionName, expandedAction); this._jsonActionsNamesMap.set(expandedActionName, actionName); this._namesSet.add(expandedActionName); } } } catch (error) { const message = getErrorMessage(error) + ` in action "${actionName}"`; throw new ConfigurationError(message); } } async _expandTemplateActions({ actionName, jsonActionTemplate, }) { const log = this.log; log.trace(`${Actions.name}.#expandTemplateActions(${actionName})`); if (jsonActionTemplate.matrix == undefined) { throw new ConfigurationError(`action "${actionName}" has no matrix`); } if (!isJsonObject(jsonActionTemplate.matrix)) { throw new ConfigurationError(`action "${actionName}" matrix is not an object`); } if (jsonActionTemplate.template == undefined) { throw new ConfigurationError(`action "${actionName}" has no template`); } if (!isString(jsonActionTemplate.template) && !isJsonArray(jsonActionTemplate.template)) { throw new ConfigurationError(`action "${actionName}" template is not a string or array`); } const expander = new TemplateExpander({ engine: this.engine, substitutionsVariables: this.substitutionsVariables, log: this.log, }); return await expander.expandTemplate({ templateName: actionName, matrix: jsonActionTemplate.matrix, templateContent: jsonActionTemplate.template, templateType: 'action', instanceFactory: (expandedName, combination, templateContent) => new Action({ actionName: expandedName, jsonAction: templateContent, parentActions: this, matrixParameters: { ...combination }, }), }); } } export class Action { name; jsonAction; parentActions; _matrixParameters; _commands; _isInitialised = false; constructor({ actionName, jsonAction, parentActions, matrixParameters, }) { assert(actionName, 'actionName is required'); assert(parentActions, 'parentActions is required'); const log = parentActions.log; log.trace(`${Action.name}(${actionName})`); this.name = actionName; this.jsonAction = jsonAction; this.parentActions = parentActions; if (matrixParameters !== undefined) { this._matrixParameters = matrixParameters; } } async initialise() { const log = this.parentActions.log; if (this._isInitialised) { log.trace(`${Action.name}.initialise(${this.name}) again`); return false; } log.trace(`${Action.name}.initialise(${this.name})`); const jsonAction = this.jsonAction; const inputCommands = Array.isArray(jsonAction) ? jsonAction.join(os.EOL) : jsonAction; let substitutedCommands; if (hasLiquidSyntax(inputCommands)) { try { substitutedCommands = await performSubstitutions({ input: inputCommands, engine: this.parentActions.engine, substitutionsVariables: { ...this.parentActions.substitutionsVariables, matrix: this._matrixParameters ?? {}, }, log, }); } catch (error) { const message = getErrorMessage(error) + ` in action "${this.name}" commands substitution`; throw new ConfigurationError(message); } } else { substitutedCommands = inputCommands; } this._commands = substitutedCommands .replace(new RegExp(os.EOL + '$'), '') .split(os.EOL); log.trace(`${Action.name}.initialise() =>`, this.name); log.trace(this.name, 'commands =>', this._commands); this._isInitialised = true; return true; } get commands() { assert(this._isInitialised, 'Action must be initialised before accessing commands'); assert(this._commands, 'Action _commands not initialised'); return this._commands; } } //# sourceMappingURL=actions.js.map