kist
Version:
Lightweight Package Pipeline Processor with Plugin Architecture
197 lines • 8.57 kB
JavaScript
import { __awaiter } from "tslib";
import { existsSync, readdirSync, readFileSync, statSync } from "fs";
import { join } from "path";
import { AbstractProcess } from "../abstract/AbstractProcess.js";
export class PluginManager extends AbstractProcess {
constructor() {
super();
this.loadedPlugins = new Map();
this.pluginActions = new Map();
this.logInfo("PluginManager initialized.");
}
static getInstance() {
if (!PluginManager.instance) {
PluginManager.instance = new PluginManager();
}
return PluginManager.instance;
}
static resetInstance() {
PluginManager.instance = null;
}
discoverPlugins(options) {
return __awaiter(this, void 0, void 0, function* () {
this.logInfo("Starting plugin discovery...");
const prefixes = (options === null || options === void 0 ? void 0 : options.pluginPrefixes) || [
"@getkist/action-",
"kist-plugin-",
];
yield this.discoverNpmPlugins(prefixes);
if (options === null || options === void 0 ? void 0 : options.localPluginsPath) {
yield this.discoverLocalPlugins(options.localPluginsPath);
}
this.logInfo(`Plugin discovery complete. Loaded ${this.loadedPlugins.size} plugins.`);
});
}
discoverNpmPlugins(prefixes) {
return __awaiter(this, void 0, void 0, function* () {
const nodeModulesPath = join(process.cwd(), "node_modules");
try {
const directories = readdirSync(nodeModulesPath, {
withFileTypes: true,
});
for (const dir of directories) {
if (dir.isDirectory() && dir.name.startsWith("@")) {
yield this.discoverScopedPlugins(join(nodeModulesPath, dir.name), prefixes);
}
for (const prefix of prefixes) {
if (dir.isDirectory() &&
!prefix.startsWith("@") &&
dir.name.startsWith(prefix)) {
yield this.loadPlugin(join(nodeModulesPath, dir.name), dir.name);
}
}
}
}
catch (error) {
this.logError("Failed to discover npm plugins.", error);
}
});
}
discoverScopedPlugins(scopePath, prefixes) {
return __awaiter(this, void 0, void 0, function* () {
try {
const packages = readdirSync(scopePath, { withFileTypes: true });
for (const pkg of packages) {
for (const prefix of prefixes) {
const scopePrefix = prefix.split("/")[1];
const pkgPath = join(scopePath, pkg.name);
const isDir = pkg.isDirectory() ||
(pkg.isSymbolicLink() &&
statSync(pkgPath).isDirectory());
if (isDir &&
scopePrefix &&
pkg.name.startsWith(scopePrefix)) {
const fullName = `${scopePath.split("/").pop()}/${pkg.name}`;
yield this.loadPlugin(join(scopePath, pkg.name), fullName);
}
}
}
}
catch (_error) {
this.logDebug(`No scoped plugins found in ${scopePath}`);
}
});
}
discoverLocalPlugins(localPath) {
return __awaiter(this, void 0, void 0, function* () {
try {
const pluginPath = join(process.cwd(), localPath);
const directories = readdirSync(pluginPath, {
withFileTypes: true,
});
for (const dir of directories) {
if (dir.isDirectory()) {
yield this.loadPlugin(join(pluginPath, dir.name), `local:${dir.name}`);
}
}
}
catch (_error) {
this.logDebug(`No local plugins found at ${localPath}`);
}
});
}
loadPlugin(pluginPath, pluginName) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e;
try {
this.logDebug(`Loading plugin: ${pluginName}`);
let entryPoint = pluginPath;
const packageJsonPath = join(pluginPath, "package.json");
if (existsSync(packageJsonPath)) {
try {
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
const mainEntry = packageJson.module ||
packageJson.main ||
((_b = (_a = packageJson.exports) === null || _a === void 0 ? void 0 : _a["."]) === null || _b === void 0 ? void 0 : _b.import) ||
((_d = (_c = packageJson.exports) === null || _c === void 0 ? void 0 : _c["."]) === null || _d === void 0 ? void 0 : _d.require) ||
((_e = packageJson.exports) === null || _e === void 0 ? void 0 : _e["."]) ||
"dist/index.js";
entryPoint = join(pluginPath, mainEntry);
}
catch (jsonError) {
this.logDebug(`Failed to parse package.json for ${pluginName}`);
}
}
const pluginModule = yield import(entryPoint);
const plugin = pluginModule.default || pluginModule;
if (!plugin || typeof plugin.registerActions !== "function") {
this.logWarn(`Plugin ${pluginName} does not implement ActionPlugin interface.`);
return;
}
const metadata = {
name: pluginName,
version: typeof plugin.version === "string"
? plugin.version
: "unknown",
description: typeof plugin.description === "string"
? plugin.description
: undefined,
actions: [],
};
const actions = plugin.registerActions();
for (const [actionName, actionClass] of Object.entries(actions)) {
this.pluginActions.set(actionName, actionClass);
metadata.actions.push(actionName);
this.logDebug(` - Registered action: ${actionName}`);
}
this.loadedPlugins.set(pluginName, metadata);
this.logInfo(`Plugin "${pluginName}" loaded successfully with ${metadata.actions.length} actions.`);
}
catch (error) {
this.logError(`Failed to load plugin ${pluginName}:`, error);
}
});
}
registerPlugin(plugin, name) {
this.logInfo(`Manually registering plugin: ${name}`);
const metadata = {
name,
version: typeof plugin.version === "string"
? plugin.version
: "unknown",
description: typeof plugin.description === "string"
? plugin.description
: undefined,
actions: [],
};
const actions = plugin.registerActions();
for (const [actionName, actionClass] of Object.entries(actions)) {
this.pluginActions.set(actionName, actionClass);
metadata.actions.push(actionName);
}
this.loadedPlugins.set(name, metadata);
this.logInfo(`Plugin "${name}" registered with ${metadata.actions.length} actions.`);
}
getPluginActions() {
return new Map(this.pluginActions);
}
getLoadedPlugins() {
return Array.from(this.loadedPlugins.values());
}
getPluginMetadata(name) {
return this.loadedPlugins.get(name);
}
isPluginLoaded(name) {
return this.loadedPlugins.has(name);
}
listPluginActions() {
return Array.from(this.pluginActions.keys());
}
clearPlugins() {
this.loadedPlugins.clear();
this.pluginActions.clear();
this.logInfo("All plugins cleared.");
}
}
PluginManager.instance = null;
//# sourceMappingURL=PluginManager.js.map