UNPKG

@storm-stack/core

Version:

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

1 lines 11.3 kB
{"version":3,"sources":["../../src/base/plugin.ts"],"names":["Plugin","dependencies","options","packageDeps","overrideName","undefined","name","kebabCase","startsWith","replace","trim","endsWith","primaryKeys","primaryKeyFields","map","primaryKeyField","isSingleton","length","identifier","camelCase","join","log","extendLog","titleCase","createLog","isSame","plugin","addHooks","hooks","bind","context","LogLevelLabel","TRACE","defu","plugins","Object","keys","forEach","dependency","projectType","lastIndexOf","substring"],"mappings":"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","file":"chunk-IVUZGPD7.cjs","sourcesContent":["/* -------------------------------------------------------------------\n\n ⚡ Storm Software - Storm Stack\n\n This code was released as part of the Storm Stack project. Storm Stack\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/storm-stack.\n\n Website: https://stormsoftware.com\n Repository: https://github.com/storm-software/storm-stack\n Documentation: https://docs.stormsoftware.com/projects/storm-stack\n Contact: https://stormsoftware.com/contact\n\n SPDX-License-Identifier: Apache-2.0\n\n ------------------------------------------------------------------- */\n\nimport { LogLevelLabel } from \"@storm-software/config-tools/types\";\nimport { camelCase } from \"@stryke/string-format/camel-case\";\nimport { kebabCase } from \"@stryke/string-format/kebab-case\";\nimport { titleCase } from \"@stryke/string-format/title-case\";\nimport defu from \"defu\";\nimport { createLog, extendLog } from \"../lib/logger\";\nimport type { EngineHooks } from \"../types/build\";\nimport type { LogFn, PluginConfig } from \"../types/config\";\nimport { Context } from \"../types/context\";\nimport type {\n PluginBaseOptions,\n PluginInterface,\n PluginOptions\n} from \"../types/plugin\";\n\n/**\n * The base class for all plugins\n */\nexport abstract class Plugin<\n TOptions extends PluginBaseOptions = PluginBaseOptions,\n TContext extends Context = Context\n> implements PluginInterface<TOptions>\n{\n #log?: LogFn;\n\n #primaryKeyFields: string[] = [];\n\n /**\n * A list of plugin modules required as dependencies by the current Plugin.\n *\n * @remarks\n * These plugins will be called prior to the current Plugin.\n */\n public dependencies = [] as Array<string | PluginConfig>;\n\n /**\n * The configuration options for the plugin\n *\n * @remarks\n * This is used to store the configuration options for the plugin, which can be accessed by the plugin's methods.\n */\n public options: PluginOptions<TOptions>;\n\n /**\n * A list of dependencies that are required for the plugin to work. These dependencies will be installed when Storm Stack CLI is run.\n */\n protected packageDeps: Record<string, \"dependency\" | \"devDependency\"> = {};\n\n /**\n * A property to override the plugin's {@link name} field.\n *\n * @remarks\n * This is useful for plugins that need to have a different name than the default one derived from the class name.\n */\n protected get overrideName(): string | undefined {\n return undefined;\n }\n\n /**\n * The name of the plugin\n *\n * @remarks\n * This is used to identify the plugin's name used in {@link Context.options}, logs, and other output.\n */\n public get name(): string {\n let name = kebabCase(this.overrideName || this.constructor.name);\n if (name.startsWith(\"plugin-\")) {\n name = name.replace(/^plugin-/g, \"\").trim();\n }\n if (name.endsWith(\"-plugin\")) {\n name = name.replace(/-plugin$/g, \"\").trim();\n }\n\n return name;\n }\n\n /**\n * The primary keys for the plugin's options.\n *\n * @remarks\n * This is used to identify when a two instances of the plugin are the same and can be de-duplicated.\n */\n public get primaryKeys(): any[] {\n return this.primaryKeyFields.map(\n primaryKeyField => (this.options as any)[primaryKeyField]\n );\n }\n\n /**\n * Returns true if the plugin is a singleton. Singleton plugins can only be instantiated once (so whenever other plugins specify them as dependencies, they will be de-duplicated).\n *\n * @remarks\n * A plugin is considered a singleton if it has zero primary key option fields defined.\n */\n public get isSingleton(): boolean {\n return this.primaryKeyFields.length === 0;\n }\n\n /**\n * A list of primary keys for the plugin's options.\n *\n * @remarks\n * This is used to identify when a two instances of the plugin are the same and can be de-duplicated.\n */\n protected get primaryKeyFields(): string[] {\n return this.#primaryKeyFields ?? [];\n }\n\n /**\n * The identifier for the plugin used in the {@link isSame} method\n *\n * @remarks\n * Child plugins can override this to provide a more or less specific identifier. This is used to identify the plugin's options in {@link Context.options}.\n */\n public get identifier(): string {\n return camelCase(\n `${this.name}${this.isSingleton ? \"\" : `-${this.primaryKeys.join(\"-\")}`}`\n );\n }\n\n /**\n * The logger function to use\n */\n protected get log(): LogFn {\n if (!this.#log) {\n this.#log = this.options.log\n ? extendLog(this.options.log, `${titleCase(this.name)} Plugin`)\n : createLog(`${titleCase(this.name)} Plugin`);\n }\n\n return this.#log;\n }\n\n /**\n * The constructor for the plugin\n *\n * @param options - The configuration options for the plugin\n */\n public constructor(options: PluginOptions<TOptions>) {\n this.options = options;\n\n // try {\n // this.#primaryKeyFields = ReflectionClass.from<TOptions>()\n // .getPrimaries()\n // .map(property => property.name)\n // .toSorted();\n // } catch (error) {\n // this.log(\n // LogLevelLabel.ERROR,\n // `Failed to get primary key of plugin options: ${error.message}`\n // );\n\n // this.#primaryKeyFields = [];\n // }\n }\n\n /**\n * Checks if the current plugin is the same as another plugin based on primary key fields.\n *\n * @param plugin - The plugin to compare with.\n * @returns `true` if the plugins are the same, `false` otherwise.\n */\n public isSame(plugin: PluginInterface): boolean {\n return (\n this.identifier === plugin.identifier ||\n (this.name === plugin.name && this.isSingleton && plugin.isSingleton)\n );\n }\n\n /**\n * Adds hooks to the engine's hook system.\n *\n * @param hooks - The hooks to add to the engine.\n */\n public addHooks(hooks: EngineHooks<TContext>) {\n hooks.addHooks({\n \"init:begin\": this.#initBegin.bind(this)\n });\n }\n\n /**\n * Initializes the plugin's context with required installations.\n *\n * @param context - The context to initialize.\n */\n async #initBegin(context: TContext) {\n this.log(\n LogLevelLabel.TRACE,\n `Adding required installations for the project.`\n );\n\n this.options = defu(\n this.options,\n context.options.plugins[this.identifier] ?? {}\n ) as PluginOptions<TOptions>;\n\n if (Object.keys(this.packageDeps).length > 0) {\n Object.keys(this.packageDeps).forEach(dependency => {\n if (\n this.packageDeps[dependency] &&\n (this.packageDeps[dependency] === \"devDependency\" ||\n context.options.projectType === \"application\")\n ) {\n if (\n dependency.lastIndexOf(\"@\") > 0 &&\n dependency.substring(0, dependency.lastIndexOf(\"@\")) in\n context.packageDeps\n ) {\n // Remove the existing dependency if it does not include the version\n // This is a workaround for the fact that we cannot install the same package with different versions\n delete context.packageDeps[\n dependency.substring(0, dependency.lastIndexOf(\"@\"))\n ];\n }\n\n context.packageDeps[dependency] = this.packageDeps[dependency];\n }\n });\n }\n }\n}\n"]}