UNPKG

@storm-stack/core

Version:

A build toolkit and runtime used by Storm Software in TypeScript applications

336 lines (327 loc) 14.3 kB
'use strict'; var chunkPZPWGOLX_cjs = require('./chunk-PZPWGOLX.cjs'); var chunkN723EYI4_cjs = require('./chunk-N723EYI4.cjs'); var chunk2Q5IBGHL_cjs = require('./chunk-2Q5IBGHL.cjs'); var chunkS4IWMPTA_cjs = require('./chunk-S4IWMPTA.cjs'); var chunkT5I2IU3S_cjs = require('./chunk-T5I2IU3S.cjs'); var chunkGNGFXTRS_cjs = require('./chunk-GNGFXTRS.cjs'); var chunkXADBBZOU_cjs = require('./chunk-XADBBZOU.cjs'); var chunk35Q7CSEH_cjs = require('./chunk-35Q7CSEH.cjs'); var chunkXXCGGFPH_cjs = require('./chunk-XXCGGFPH.cjs'); var chunkA43FUIC2_cjs = require('./chunk-A43FUIC2.cjs'); var types = require('@storm-software/config-tools/types'); var install = require('@stryke/fs/install'); var packageFns = require('@stryke/fs/package-fns'); var joinPaths = require('@stryke/path/join-paths'); var camelCase = require('@stryke/string-format/camel-case'); var isError = require('@stryke/type-checks/is-error'); var isNumber = require('@stryke/type-checks/is-number'); var isSetObject = require('@stryke/type-checks/is-set-object'); var isSetString = require('@stryke/type-checks/is-set-string'); var chalk = require('chalk'); var defu = require('defu'); var hookable = require('hookable'); function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } var chalk__default = /*#__PURE__*/_interopDefault(chalk); var defu__default = /*#__PURE__*/_interopDefault(defu); // src/base/engine.ts chunkA43FUIC2_cjs.init_cjs_shims(); // src/lib/utilities/plugin-helpers.ts chunkA43FUIC2_cjs.init_cjs_shims(); function isPluginInstance(plugin) { return isSetObject.isSetObject(plugin) && chunkXXCGGFPH_cjs.__STORM_STACK_IS_PLUGIN__ in plugin && plugin[chunkXXCGGFPH_cjs.__STORM_STACK_IS_PLUGIN__] === true; } chunkA43FUIC2_cjs.__name(isPluginInstance, "isPluginInstance"); function isPluginConfigObject(plugin) { return isSetObject.isSetObject(plugin) && "plugin" in plugin && isSetString.isSetString(plugin.plugin); } chunkA43FUIC2_cjs.__name(isPluginConfigObject, "isPluginConfigObject"); // src/base/engine.ts var Engine = class _Engine { static { chunkA43FUIC2_cjs.__name(this, "Engine"); } inlineConfig; /** * The Storm Stack context */ #context; /** * The engine hooks - these allow the plugins to hook into the engines processing */ #hooks; /** * The plugins provided in the options */ #plugins = []; /** * The Storm Stack context */ get context() { return this.#context; } /** * The Storm Stack engine hooks */ get hooks() { return this.#hooks; } /** * Create a new Storm Stack Engine instance * * @param inlineConfig - The inline configuration for the Storm Stack engine */ constructor(inlineConfig) { this.inlineConfig = inlineConfig; } /** * Initialize the engine */ static async create(inlineConfig) { const engine = new _Engine(inlineConfig); await engine.init(); return engine; } /** * Create a new Storm Stack project * * @remarks * This method will create a new Storm Stack project in the current directory. * * @param inlineConfig - The inline configuration for the new command * @returns A promise that resolves when the project has been created */ async new(_inlineConfig = { command: "new" }) { this.#context.log(types.LogLevelLabel.INFO, "\u{1F195} Creating a new Storm Stack project"); await chunkS4IWMPTA_cjs._new(this.#context, this.#hooks); this.#context.log(types.LogLevelLabel.TRACE, "Storm Stack - New command completed"); } /** * Clean any previously prepared artifacts * * @remarks * This method will remove the previous Storm Stack artifacts from the project. * * @param inlineConfig - The inline configuration for the clean command * @returns A promise that resolves when the clean command has completed */ async clean(_inlineConfig = { command: "clean" }) { this.#context.log(types.LogLevelLabel.INFO, "\u{1F9F9} Cleaning the previous Storm Stack artifacts"); await chunkXADBBZOU_cjs.clean(this.#context, this.#hooks); this.#context.log(types.LogLevelLabel.TRACE, "Storm Stack - Clean command completed"); } /** * Prepare the Storm Stack project prior to building * * @remarks * This method will create the necessary directories, and write the artifacts files to the project. * * @param inlineConfig - The inline configuration for the prepare command * @returns A promise that resolves when the prepare command has completed */ async prepare(_inlineConfig = { command: "prepare" }) { this.#context.log(types.LogLevelLabel.INFO, "\u{1F3D7}\uFE0F Preparing the Storm Stack project"); await chunkT5I2IU3S_cjs.prepare(this.#context, this.#hooks); this.#context.log(types.LogLevelLabel.TRACE, "Storm Stack preparation completed"); } /** * Lint the project * * @param inlineConfig - The inline configuration for the lint command * @returns A promise that resolves when the lint command has completed */ async lint(inlineConfig = { command: "lint" }) { if (this.#context.persistedMeta?.checksum !== this.#context.meta.checksum) { this.#context.log(types.LogLevelLabel.INFO, "The Storm Stack project has been modified since the last time `prepare` was ran. Re-preparing the project."); await this.prepare(inlineConfig); } this.#context.log(types.LogLevelLabel.INFO, "\u{1F4CB} Linting the Storm Stack project"); await chunk2Q5IBGHL_cjs.lint(this.#context, this.#hooks); this.#context.log(types.LogLevelLabel.TRACE, "Storm Stack linting completed"); } /** * Build the project * * @remarks * This method will build the Storm Stack project, generating the necessary artifacts. * * @param inlineConfig - The inline configuration for the build command * @returns A promise that resolves when the build command has completed */ async build(inlineConfig = { command: "build" }) { const persistedMeta = await chunkT5I2IU3S_cjs.getPersistedMeta(this.#context); const checksum = await chunkT5I2IU3S_cjs.getChecksum(this.#context.options.projectRoot); if (persistedMeta?.checksum !== checksum) { this.#context.log(types.LogLevelLabel.INFO, "The Storm Stack project has been modified since the last time `prepare` was ran. Re-preparing the project."); await this.prepare(inlineConfig); } this.#context.log(types.LogLevelLabel.INFO, "\u{1F4E6} Building the Storm Stack project"); await chunkGNGFXTRS_cjs.build(this.#context, this.#hooks); this.#context.log(types.LogLevelLabel.TRACE, "Storm Stack build completed"); } /** * Generate the documentation for the project * * @param inlineConfig - The inline configuration for the docs command * @returns A promise that resolves when the documentation generation has completed */ async docs(inlineConfig = { command: "docs" }) { if (this.#context.persistedMeta?.checksum !== this.#context.meta.checksum) { this.#context.log(types.LogLevelLabel.INFO, "The Storm Stack project has been modified since the last time `prepare` was ran. Re-preparing the project."); await this.prepare(inlineConfig); } this.#context.log(types.LogLevelLabel.INFO, "Generating documentation for the Storm Stack project"); await chunk35Q7CSEH_cjs.docs(this.#context, this.#hooks); this.#context.log(types.LogLevelLabel.TRACE, "Storm Stack documentation generation completed"); } /** * Finalization process * * @remarks * This step includes any final processes or clean up required by Storm Stack. It will be run after each Storm Stack command. * * @returns A promise that resolves when the finalization process has completed */ async finalize() { this.#context.log(types.LogLevelLabel.TRACE, "Storm Stack finalize execution started"); await chunkPZPWGOLX_cjs.finalize(this.#context, this.#hooks); this.#context.log(types.LogLevelLabel.TRACE, "Storm Stack finalize execution completed"); } /** * Initialize the engine */ async init() { this.#hooks = hookable.createHooks(); this.#context = await chunkT5I2IU3S_cjs.createContext(this.inlineConfig); this.#context.log(types.LogLevelLabel.TRACE, "\u2699\uFE0F Initializing Storm Stack engine"); for (const plugin of this.#context.options.userConfig.plugins ?? []) { await this.addPlugin(plugin); } if (this.#plugins.length === 0) { this.#context.log(types.LogLevelLabel.WARN, "No Storm Stack plugins or presets were specified in the options. Please ensure this is correct, as it is generally not recommended."); } else { for (const plugin of this.#plugins) { plugin.addHooks(this.#hooks); } } await chunkN723EYI4_cjs.init(this.#context, this.#hooks); this.#context.log(types.LogLevelLabel.INFO, "Storm Stack engine has been initialized"); } /** * Add a Storm Stack plugin used in the build process * * @param config - The import path of the plugin to add */ async addPlugin(config) { if (config) { const instance = await this.initPlugin(config); if (!instance) { return; } if (instance.dependencies) { for (const dependency of instance.dependencies) { await this.addPlugin(dependency); } } this.#context.log(types.LogLevelLabel.DEBUG, `Successfully initialized the ${chalk__default.default.bold.cyanBright(instance.name)} plugin`); this.#plugins.push(instance); } } /** * Initialize a Storm Stack plugin * * @param plugin - The import path of the plugin to add */ async initPlugin(plugin) { if (!plugin || !isSetString.isSetString(plugin) && !Array.isArray(plugin) && !isPluginConfigObject(plugin) && !isPluginInstance(plugin)) { throw new Error(`Invalid plugin specified in the configuration - ${JSON.stringify(plugin)}. Please ensure the value is a plugin name, an object with the \`plugin\` and \`props\` properties, or an instance of \`Plugin\`.`); } let pluginInstance; if (isPluginInstance(plugin)) { pluginInstance = plugin; pluginInstance.options ??= {}; pluginInstance.options.log ??= this.#context.log; } else { const pluginConfig = isSetString.isSetString(plugin) ? [ plugin, {} ] : Array.isArray(plugin) ? plugin : [ plugin.plugin, plugin.props ]; let installPath = pluginConfig[0]; if (installPath.startsWith("@") && installPath.split("/").filter(Boolean).length > 2) { const splits = installPath.split("/").filter(Boolean); installPath = `${splits[0]}/${splits[1]}`; } const isInstalled = packageFns.isPackageExists(installPath, { paths: [ this.#context.options.workspaceConfig.workspaceRoot, this.#context.options.projectRoot ] }); if (!isInstalled && this.#context.options.skipInstalls !== true) { this.#context.log(types.LogLevelLabel.WARN, `The plugin package "${installPath}" is not installed. It will be installed automatically.`); const result = await install.install(installPath, { cwd: this.#context.options.projectRoot }); if (isNumber.isNumber(result.exitCode) && result.exitCode > 0) { this.#context.log(types.LogLevelLabel.ERROR, result.stderr); throw new Error(`An error occurred while installing the build plugin package "${installPath}" `); } } try { const module = await this.#context.resolver.import(this.#context.resolver.esmResolve(joinPaths.joinPaths(pluginConfig[0], "plugin"))); const PluginConstructor = module.plugin ?? module.default; pluginInstance = new PluginConstructor({ ...pluginConfig[1] ?? {}, log: this.#context.log }); } catch (error) { try { const module = await this.#context.resolver.import(this.#context.resolver.esmResolve(pluginConfig[0])); const PluginConstructor = module.plugin ?? module.default; pluginInstance = new PluginConstructor({ ...pluginConfig[1] ?? {}, log: this.#context.log }); } catch { if (!isInstalled) { throw new Error(`The plugin package "${pluginConfig[0]}" is not installed. Please install the package using the command: "npm install ${pluginConfig[0]} --save-dev"`); } else { throw new Error(`An error occurred while importing the build plugin package "${pluginConfig[0]}": ${isError.isError(error) ? error.message : String(error)} Note: Please ensure the plugin package's default export is a class that extends \`Plugin\` with a constructor that excepts a single arguments of type \`PluginOptions\`.`); } } } } if (!isPluginInstance(pluginInstance)) { throw new Error(`The plugin option ${JSON.stringify(plugin)} does not export a valid module.`); } this.#context.options.plugins[pluginInstance.identifier] = defu__default.default(pluginInstance.options ?? {}, isSetObject.isSetObject(this.#context.options.plugins[pluginInstance.identifier]) ? this.#context.options.plugins[pluginInstance.identifier] : {}, camelCase.camelCase(pluginInstance.name) !== camelCase.camelCase(pluginInstance.identifier) && isSetObject.isSetObject(this.#context.options.plugins[pluginInstance.name]) ? this.#context.options.plugins[pluginInstance.name] : {}); pluginInstance.options = this.#context.options.plugins[pluginInstance.identifier]; const duplicatePlugin = this.#plugins.find((plugin2) => plugin2.isSame(pluginInstance)); if (duplicatePlugin) { this.#context.log(types.LogLevelLabel.TRACE, `Duplicate ${chalk__default.default.bold.cyanBright(duplicatePlugin.identifier)} plugin dependency detected - Skipping initialization.`); duplicatePlugin.options = defu__default.default(duplicatePlugin.options ?? {}, this.#context.options.plugins[pluginInstance.identifier]); this.#context.options.plugins[duplicatePlugin.identifier] = duplicatePlugin.options; return null; } this.#context.log(types.LogLevelLabel.TRACE, `Initializing the ${chalk__default.default.bold.cyanBright(pluginInstance.name)} plugin...`); return pluginInstance; } }; exports.Engine = Engine;