@storm-stack/plugin-system
Advanced tools
Comparing version 1.4.1 to 1.4.2
@@ -0,51 +1,77 @@ | ||
## 1.4.2 (2024-01-29) | ||
### 🩹 Fixes | ||
- **plugin-system:** Resolved various linting issues with workspace ([71d1541](https://github.com/storm-software/storm-stack/commit/71d1541)) | ||
### ❤️ Thank You | ||
- Patrick Sullivan | ||
## 1.4.1 (2024-01-29) | ||
### 🩹 Fixes | ||
- **plugin-system:** Resolved issue with instanciating the `PluginLoader` from the provided module ([778bb6d](https://github.com/storm-software/storm-stack/commit/778bb6d)) | ||
- **plugin-system:** Resolved issue with instanciating the `PluginLoader` from the provided module ([778bb6d](https://github.com/storm-software/storm-stack/commit/778bb6d)) | ||
### ❤️ Thank You | ||
- Patrick Sullivan | ||
### ❤️ Thank You | ||
- Patrick Sullivan | ||
## 1.4.0 (2024-01-24) | ||
### 🚀 Features | ||
- **plugin-system:** Added the `autoInstall` option to resolvers ([18c1841](https://github.com/storm-software/storm-stack/commit/18c1841)) | ||
- **plugin-system:** Added the `autoInstall` option to resolvers ([18c1841](https://github.com/storm-software/storm-stack/commit/18c1841)) | ||
### ❤️ Thank You | ||
- Patrick Sullivan | ||
### ❤️ Thank You | ||
- Patrick Sullivan | ||
## 1.3.8 (2024-01-24) | ||
### 🩹 Fixes | ||
- **plugin-system:** Added tsconfig file paths to resolver handler ([56ff717](https://github.com/storm-software/storm-stack/commit/56ff717)) | ||
- **plugin-system:** Added tsconfig file paths to resolver handler ([56ff717](https://github.com/storm-software/storm-stack/commit/56ff717)) | ||
### ❤️ Thank You | ||
- Patrick Sullivan | ||
### ❤️ Thank You | ||
- Patrick Sullivan | ||
## 1.3.7 (2024-01-23) | ||
### 🩹 Fixes | ||
- **plugin-system:** Updated the resolver implementation to use `enhanced-resolve` package ([bda2c10](https://github.com/storm-software/storm-stack/commit/bda2c10)) | ||
- **plugin-system:** Updated the resolver implementation to use `enhanced-resolve` package ([bda2c10](https://github.com/storm-software/storm-stack/commit/bda2c10)) | ||
### ❤️ Thank You | ||
- Patrick Sullivan | ||
### ❤️ Thank You | ||
- Patrick Sullivan | ||
## 1.3.4 (2024-01-21) | ||
### 🩹 Fixes | ||
- **monorepo:** Update the storm-ops workspace dependencies ([faadeb6](https://github.com/storm-software/storm-stack/commit/faadeb6)) | ||
- **monorepo:** Update the storm-ops workspace dependencies ([faadeb6](https://github.com/storm-software/storm-stack/commit/faadeb6)) | ||
### ❤️ Thank You | ||
- Patrick Sullivan | ||
### ❤️ Thank You | ||
- Patrick Sullivan | ||
## [1.3.3](https://github.com/storm-software/storm-stack/compare/plugin-system-v1.3.2...plugin-system-v1.3.3) (2024-01-21) | ||
@@ -52,0 +78,0 @@ |
{ | ||
"name": "@storm-stack/plugin-system", | ||
"version": "1.4.1", | ||
"version": "1.4.2", | ||
"private": false, | ||
@@ -5,0 +5,0 @@ "description": "A library used to create and manage a plugin-styled architecture in a TypeScript application.", |
import { readFile } from "node:fs/promises"; | ||
import { StormDateTime } from "@storm-stack/date-time"; | ||
import { StormError } from "@storm-stack/errors"; | ||
import { | ||
exists, | ||
findContainingFolder, | ||
findFilePath, | ||
joinPaths, | ||
} from "@storm-stack/file-system"; | ||
import { exists, findContainingFolder, findFilePath, joinPaths } from "@storm-stack/file-system"; | ||
import type { IStormLog } from "@storm-stack/logging"; | ||
@@ -21,3 +16,3 @@ import { StormParser } from "@storm-stack/serialization"; | ||
kebabCase, | ||
titleCase, | ||
titleCase | ||
} from "@storm-stack/utilities"; | ||
@@ -35,3 +30,3 @@ import { glob } from "glob"; | ||
type PluginInstance, | ||
type PluginManagerOptions, | ||
type PluginManagerOptions | ||
} from "../types"; | ||
@@ -45,6 +40,3 @@ import { createResolver } from "../utilities/create-resolver"; | ||
*/ | ||
export class PluginManager< | ||
TContext = any, | ||
TPluginModule extends IPluginModule = any, | ||
> { | ||
export class PluginManager<TContext = any, TPluginModule extends IPluginModule = any> { | ||
private _options: PluginManagerOptions; | ||
@@ -63,12 +55,9 @@ private _hasDiscovered = false; | ||
TContext = any, | ||
TPluginModule extends IPluginModule<TContext> = any, | ||
TPluginModule extends IPluginModule<TContext> = any | ||
>( | ||
logger: IStormLog, | ||
options: Omit<Partial<PluginManagerOptions>, "defaultLoader"> & | ||
Pick<PluginManagerOptions, "defaultLoader">, | ||
Pick<PluginManagerOptions, "defaultLoader"> | ||
): Promise<PluginManager<TContext, TPluginModule>> => { | ||
const pluginManager = new PluginManager<TContext, TPluginModule>( | ||
logger, | ||
options, | ||
); | ||
const pluginManager = new PluginManager<TContext, TPluginModule>(logger, options); | ||
@@ -92,3 +81,3 @@ await pluginManager._getLoader(pluginManager._options.defaultLoader); | ||
options: Omit<Partial<PluginManagerOptions>, "defaultLoader"> & | ||
Pick<PluginManagerOptions, "defaultLoader">, | ||
Pick<PluginManagerOptions, "defaultLoader"> | ||
) { | ||
@@ -99,3 +88,3 @@ const defaults: Partial<PluginManagerOptions> = { | ||
autoInstall: true, | ||
discoveryMode: PluginDiscoveryMode.FALLBACK, | ||
discoveryMode: PluginDiscoveryMode.FALLBACK | ||
}; | ||
@@ -105,11 +94,5 @@ this._options = deepMerge(defaults, options); | ||
if (!this._options.tsconfig || !exists(this._options.tsconfig)) { | ||
this._options.tsconfig = joinPaths( | ||
this._options.rootPath, | ||
"tsconfig.json", | ||
); | ||
this._options.tsconfig = joinPaths(this._options.rootPath, "tsconfig.json"); | ||
if (!exists(this._options.tsconfig)) { | ||
this._options.tsconfig = joinPaths( | ||
this._options.rootPath, | ||
"tsconfig.base.json", | ||
); | ||
this._options.tsconfig = joinPaths(this._options.rootPath, "tsconfig.base.json"); | ||
} | ||
@@ -126,3 +109,3 @@ } | ||
this._options.tsconfig, | ||
this._options.autoInstall, | ||
this._options.autoInstall | ||
); | ||
@@ -148,3 +131,3 @@ } | ||
provider: string, | ||
options: Record<string, any> = {}, | ||
options: Record<string, any> = {} | ||
): PluginInstance<TContext, TPluginModule> | undefined => { | ||
@@ -156,3 +139,3 @@ return this._store.get(this._getCacheId(provider, options)); | ||
provider: string, | ||
options: Record<string, any> = {}, | ||
options: Record<string, any> = {} | ||
): Promise<PluginInstance<TContext, TPluginModule>> => { | ||
@@ -165,5 +148,3 @@ let instance = this.getInstance(provider, options); | ||
const definition: PluginDefinition = await this.register(provider); | ||
const loader = await this._getLoader( | ||
definition.loader ?? this._options.defaultLoader, | ||
); | ||
const loader = await this._getLoader(definition.loader ?? this._options.defaultLoader); | ||
@@ -173,15 +154,10 @@ instance = await loader.load(definition, options); | ||
throw new StormError(PluginSystemErrorCode.plugin_loading_failure, { | ||
message: `The plugin "${provider}" did not return an object after loading.`, | ||
message: `The plugin "${provider}" did not return an object after loading.` | ||
}); | ||
} | ||
this._store.set( | ||
this._getCacheId(instance.definition.provider, options), | ||
instance, | ||
); | ||
this._store.set(this._getCacheId(instance.definition.provider, options), instance); | ||
await Promise.all( | ||
instance.definition.dependencies.map((dependency) => | ||
this.instantiate(dependency, options), | ||
), | ||
instance.definition.dependencies.map((dependency) => this.instantiate(dependency, options)) | ||
); | ||
@@ -196,3 +172,3 @@ | ||
options: Record<string, any> = {}, | ||
executionDateTime: StormDateTime = StormDateTime.current(), | ||
executionDateTime: StormDateTime = StormDateTime.current() | ||
): Promise<Record<string, Error | null>> => { | ||
@@ -202,8 +178,5 @@ const instance = await this.instantiate(provider, options); | ||
return { | ||
[provider]: new StormError( | ||
PluginSystemErrorCode.plugin_loading_failure, | ||
{ | ||
message: `The plugin "${provider}" could not be loaded prior to execution.`, | ||
}, | ||
), | ||
[provider]: new StormError(PluginSystemErrorCode.plugin_loading_failure, { | ||
message: `The plugin "${provider}" could not be loaded prior to execution.` | ||
}) | ||
}; | ||
@@ -217,11 +190,8 @@ } | ||
instance.definition.dependencies.map((dependency) => | ||
this.execute(dependency, context, options, executionDateTime), | ||
), | ||
this.execute(dependency, context, options, executionDateTime) | ||
) | ||
); | ||
const result = dependenciesResults.reduce( | ||
( | ||
ret: Record<string, Error | null>, | ||
dependenciesResult: Record<string, Error | null>, | ||
) => { | ||
(ret: Record<string, Error | null>, dependenciesResult: Record<string, Error | null>) => { | ||
for (const key of Object.keys(dependenciesResult)) { | ||
@@ -236,3 +206,3 @@ if (!ret[key]) { | ||
}, | ||
{}, | ||
{} | ||
); | ||
@@ -252,3 +222,3 @@ | ||
context: TContext, | ||
handler?: (context: TContext) => Promise<TContext> | TContext, | ||
handler?: (context: TContext) => Promise<TContext> | TContext | ||
): Promise<TContext> => { | ||
@@ -273,3 +243,3 @@ let listeners = [] as PluginHookFn<TContext>[]; | ||
listener: value.module.hooks?.[name]!, | ||
dependencies: plugin?.definition?.dependencies ?? [], | ||
dependencies: plugin?.definition?.dependencies ?? [] | ||
}); | ||
@@ -286,8 +256,6 @@ } | ||
dependencies: string[]; | ||
}, | ||
} | ||
) => { | ||
hook.dependencies | ||
.filter((dependency) => | ||
hooks.some((depHook) => depHook.provider === dependency), | ||
) | ||
.filter((dependency) => hooks.some((depHook) => depHook.provider === dependency)) | ||
.map((dependency) => ret.push([hook.provider, dependency])); | ||
@@ -297,3 +265,3 @@ | ||
}, | ||
[], | ||
[] | ||
); | ||
@@ -304,8 +272,6 @@ | ||
hooks.map((hook) => hook.provider), | ||
edges, | ||
edges | ||
) | ||
// biome-ignore lint/style/noNonNullAssertion: <explanation> | ||
.map( | ||
(hook: string) => hooks.find((h) => h.provider === hook)?.listener!, | ||
); | ||
.map((hook: string) => hooks.find((h) => h.provider === hook)?.listener!); | ||
} | ||
@@ -357,3 +323,3 @@ | ||
message: `Could not find plugin provider ${provider}. \nDiscovered plugins: ${Object.keys( | ||
this._registry, | ||
this._registry | ||
) | ||
@@ -365,3 +331,3 @@ .map((key) => { | ||
}) | ||
.join("\n")}`, | ||
.join("\n")}` | ||
}); | ||
@@ -424,5 +390,5 @@ } | ||
_tsconfig?: string, | ||
_autoInstall?: boolean, | ||
_autoInstall?: boolean | ||
) => IPluginLoader<any, any>; | ||
}, | ||
} | ||
): Promise<IPluginLoader<TContext, TPluginModule>> => { | ||
@@ -433,3 +399,3 @@ if (!isString(loader)) { | ||
this._options.tsconfig, | ||
this._options.autoInstall, | ||
this._options.autoInstall | ||
); | ||
@@ -450,3 +416,3 @@ this._loaders.set(loader.provider, instance); | ||
_tsconfig?: string, | ||
_autoInstall?: boolean, | ||
_autoInstall?: boolean | ||
) => IPluginLoader<any, any>; | ||
@@ -458,3 +424,3 @@ }; | ||
throw new StormError(PluginSystemErrorCode.module_not_found, { | ||
message: `Cannot find plugin loader ${loader}`, | ||
message: `Cannot find plugin loader ${loader}` | ||
}); | ||
@@ -465,10 +431,6 @@ } | ||
} catch (origError) { | ||
this._logger.error( | ||
`Unable to initialize loader module ${loader}: ${origError}`, | ||
); | ||
this._logger.error(`Unable to initialize loader module ${loader}: ${origError}`); | ||
throw new StormError(PluginSystemErrorCode.module_not_found, { | ||
message: isSet(origError) | ||
? `Error: ${StormParser.stringify(origError)}` | ||
: undefined, | ||
message: isSet(origError) ? `Error: ${StormParser.stringify(origError)}` : undefined | ||
}); | ||
@@ -481,3 +443,3 @@ } | ||
throw new StormError(PluginSystemErrorCode.module_not_found, { | ||
message: `Plugin provider ${loader} cannot be found`, | ||
message: `Plugin provider ${loader} cannot be found` | ||
}); | ||
@@ -489,3 +451,3 @@ } | ||
this._options.tsconfig, | ||
this._options.autoInstall, | ||
this._options.autoInstall | ||
); | ||
@@ -503,5 +465,3 @@ this._loaders.set(loader, instance); | ||
*/ | ||
private _getDefinition = async ( | ||
_configPath: string, | ||
): Promise<PluginDefinition | undefined> => { | ||
private _getDefinition = async (_configPath: string): Promise<PluginDefinition | undefined> => { | ||
let configPath = _configPath; | ||
@@ -534,5 +494,3 @@ let packagePath!: string; | ||
if (exists(joinPaths(configPath, "package.json"))) { | ||
const packageContent = await readFile( | ||
joinPaths(configPath, "package.json"), | ||
); | ||
const packageContent = await readFile(joinPaths(configPath, "package.json")); | ||
const packageJson = JSON.parse(packageContent.toString()); | ||
@@ -548,3 +506,3 @@ if (packageJson.peerDependencies) { | ||
}, | ||
dependencies, | ||
dependencies | ||
); | ||
@@ -576,3 +534,3 @@ } | ||
.replaceAll("\\", "-") | ||
.replaceAll(" ", "-"), | ||
.replaceAll(" ", "-") | ||
), | ||
@@ -589,5 +547,5 @@ provider: provider ?? packagePath ?? configPath, | ||
tags, | ||
loader: configJson.loader ?? this._options.defaultLoader, | ||
loader: configJson.loader ?? this._options.defaultLoader | ||
}; | ||
}; | ||
} |
@@ -11,2 +11,5 @@ import type { StormDateTime } from "@storm-stack/date-time"; | ||
/** | ||
* The options to configure the plugin manager. | ||
*/ | ||
export interface PluginManagerOptions { | ||
@@ -68,2 +71,5 @@ /** | ||
/** | ||
* The definition of a plugin. | ||
*/ | ||
export interface PluginDefinition { | ||
@@ -70,0 +76,0 @@ /** |
@@ -6,3 +6,3 @@ import fs from "node:fs"; | ||
import { CachedInputFileSystem, ResolverFactory } from "enhanced-resolve"; | ||
import { PluginSystemErrorCode } from ".."; | ||
import { PluginSystemErrorCode } from "../errors"; | ||
import { install } from "./run"; | ||
@@ -19,6 +19,6 @@ | ||
tsconfig = "tsconfig.json", | ||
autoInstall = true | ||
autoInstall = true, | ||
): ((request: string) => Promise<string>) => { | ||
const tsconfigJson = loadTsConfigFile( | ||
tsconfig.includes(rootPath) ? tsconfig : joinPaths(rootPath, tsconfig) | ||
tsconfig.includes(rootPath) ? tsconfig : joinPaths(rootPath, tsconfig), | ||
); | ||
@@ -29,6 +29,15 @@ | ||
fileSystem: new CachedInputFileSystem(fs, 4000), | ||
extensions: [".js", ".cjs", ".mjs", ".jsx", ".json", ".node", ".ts", ".tsx"], | ||
extensions: [ | ||
".js", | ||
".cjs", | ||
".mjs", | ||
".jsx", | ||
".json", | ||
".node", | ||
".ts", | ||
".tsx", | ||
], | ||
mainFields: ["main", "module"], | ||
mainFiles: ["index"], | ||
descriptionFiles: ["package.json"] | ||
descriptionFiles: ["package.json"], | ||
}); | ||
@@ -38,50 +47,56 @@ | ||
const resolveContext = { | ||
issuer: rootPath | ||
issuer: rootPath, | ||
}; | ||
return new Promise((resolve, reject) => { | ||
resolverFactory.resolve(resolveContext, rootPath, request, {}, (error, result) => { | ||
if (error || !result || !isString(result)) { | ||
if (autoInstall) { | ||
install(request, rootPath).then(() => { | ||
resolverFactory.resolve( | ||
resolveContext, | ||
rootPath, | ||
request, | ||
{}, | ||
(innerError, innerResult) => { | ||
if (innerError) { | ||
reject(innerError); | ||
} else if (!innerResult || !isString(innerResult)) { | ||
reject( | ||
StormError.create({ | ||
code: PluginSystemErrorCode.module_not_found, | ||
message: `Cannot find plugin ${request}` | ||
}) | ||
); | ||
} else { | ||
resolve(innerResult as string); | ||
} | ||
} | ||
resolverFactory.resolve( | ||
resolveContext, | ||
rootPath, | ||
request, | ||
{}, | ||
(error, result) => { | ||
if (error || !result || !isString(result)) { | ||
if (autoInstall) { | ||
install(request, rootPath).then(() => { | ||
resolverFactory.resolve( | ||
resolveContext, | ||
rootPath, | ||
request, | ||
{}, | ||
(innerError, innerResult) => { | ||
if (innerError) { | ||
reject(innerError); | ||
} else if (!innerResult || !isString(innerResult)) { | ||
reject( | ||
StormError.create({ | ||
code: PluginSystemErrorCode.module_not_found, | ||
message: `Cannot find plugin ${request}`, | ||
}), | ||
); | ||
} else { | ||
resolve(innerResult as string); | ||
} | ||
}, | ||
); | ||
resolve(result as string); | ||
}); | ||
} | ||
if (error) { | ||
reject(error); | ||
} else { | ||
reject( | ||
StormError.create({ | ||
code: PluginSystemErrorCode.module_not_found, | ||
message: `Cannot find plugin ${request}`, | ||
}), | ||
); | ||
resolve(result as string); | ||
}); | ||
} | ||
if (error) { | ||
reject(error); | ||
} | ||
} else { | ||
reject( | ||
StormError.create({ | ||
code: PluginSystemErrorCode.module_not_found, | ||
message: `Cannot find plugin ${request}` | ||
}) | ||
); | ||
resolve(result as string); | ||
} | ||
} else { | ||
resolve(result as string); | ||
} | ||
}); | ||
}, | ||
); | ||
}); | ||
}; | ||
}; |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
56181
0
922