UNPKG

@comake/skl-js-engine

Version:

Standard Knowledge Language Javascript Engine

164 lines 6.58 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.globalHooks = exports.HookStages = exports.HookTypes = void 0; // Use symbols for hook types to avoid string collisions exports.HookTypes = { CREATE: Symbol('create'), READ: Symbol('read'), UPDATE: Symbol('update'), DELETE: Symbol('delete'), EXECUTE_CAPABILITY_MAPPING: Symbol('executeCapabilityMapping') }; exports.HookStages = { BEFORE: Symbol('before'), AFTER: Symbol('after'), ERROR: Symbol('error') }; // Registry to store global hooks class GlobalHooksRegistry { constructor() { this.hooks = new Map(); // Initialize hook maps for all CRUD operations and stages Object.values(exports.HookTypes).forEach(type => { this.hooks.set(type, new Map()); Object.values(exports.HookStages).forEach(stage => { this.hooks.get(type).set(stage, []); }); }); } /** * Register a hook with optional priority (higher runs first) */ register(type, stage, hook, priority = 0) { const hookId = Symbol(); const hooksList = this.hooks.get(type)?.get(stage); if (!hooksList) { throw new Error(`Invalid hook type or stage`); } hooksList.push({ id: hookId, fn: hook, priority }); // Sort by priority (descending) hooksList.sort((a, b) => b.priority - a.priority); return hookId; } /** * Unregister a hook by its ID */ unregister(hookId) { let removed = false; this.hooks.forEach(stageMap => { stageMap.forEach(hooksList => { const index = hooksList.findIndex(entry => entry.id === hookId); if (index !== -1) { hooksList.splice(index, 1); removed = true; } }); }); return removed; } /** * Execute hooks for a specific operation and stage */ async execute(type, stage, context, resultOrError) { // Allow bypassing hooks to prevent re-entrancy from within hooks if (context?.bypassHooks) { return resultOrError; } const hooksList = this.hooks.get(type)?.get(stage); if (!hooksList || hooksList.length === 0) { return resultOrError; } if (stage === exports.HookStages.BEFORE) { for (const entry of hooksList) { await entry.fn(context); } return resultOrError; } if (stage === exports.HookStages.AFTER) { let result = resultOrError; for (const entry of hooksList) { const newResult = await entry.fn(context, result); if (newResult !== undefined) { result = newResult; } } return result; } if (stage === exports.HookStages.ERROR) { for (const entry of hooksList) { await entry.fn(context, resultOrError); } return resultOrError; } return resultOrError; } // Convenience methods for common operations registerBeforeCreate(hook, priority) { return this.register(exports.HookTypes.CREATE, exports.HookStages.BEFORE, hook, priority); } registerAfterCreate(hook, priority) { return this.register(exports.HookTypes.CREATE, exports.HookStages.AFTER, hook, priority); } registerErrorCreate(hook, priority) { return this.register(exports.HookTypes.CREATE, exports.HookStages.ERROR, hook, priority); } // Additional convenience methods for other CRUD operations registerBeforeRead(hook, priority) { return this.register(exports.HookTypes.READ, exports.HookStages.BEFORE, hook, priority); } // ... other convenience methods for read, update, delete operations // Convenience methods for execute capability operations registerBeforeExecuteCapabilityMapping(hook, priority) { return this.register(exports.HookTypes.EXECUTE_CAPABILITY_MAPPING, exports.HookStages.BEFORE, hook, priority); } registerAfterExecuteCapabilityMapping(hook, priority) { return this.register(exports.HookTypes.EXECUTE_CAPABILITY_MAPPING, exports.HookStages.AFTER, hook, priority); } registerErrorExecuteCapabilityMapping(hook, priority) { return this.register(exports.HookTypes.EXECUTE_CAPABILITY_MAPPING, exports.HookStages.ERROR, hook, priority); } // Execution convenience methods async executeBeforeCreate(entities, extras) { await this.execute(exports.HookTypes.CREATE, exports.HookStages.BEFORE, { entities, operation: 'save', operationParameters: {}, ...extras }); } async executeAfterCreate(entities, extras) { if (!Array.isArray(entities)) { entities = [entities]; } return this.execute(exports.HookTypes.CREATE, exports.HookStages.AFTER, { entities, operation: 'save', operationParameters: {}, ...extras }, entities); } async executeErrorCreate(entities, error, extras) { await this.execute(exports.HookTypes.CREATE, exports.HookStages.ERROR, { entities, operation: 'save', operationParameters: {}, ...extras }, error); } async executeBeforeExecuteCapabilityMapping(entities, capabilityMapping, extras) { await this.execute(exports.HookTypes.EXECUTE_CAPABILITY_MAPPING, exports.HookStages.BEFORE, { entities, operation: 'executeCapabilityMapping', operationParameters: { capabilityMapping }, ...extras }); } async executeAfterExecuteCapabilityMapping(entities, capabilityMapping, result, extras) { return this.execute(exports.HookTypes.EXECUTE_CAPABILITY_MAPPING, exports.HookStages.AFTER, { entities, operation: 'executeCapabilityMapping', operationParameters: { capabilityMapping }, ...extras }, result); } async executeErrorExecuteCapabilityMapping(entities, capabilityMapping, error, extras) { await this.execute(exports.HookTypes.EXECUTE_CAPABILITY_MAPPING, exports.HookStages.ERROR, { entities, operation: 'executeCapabilityMapping', operationParameters: { capabilityMapping }, ...extras }, error); } } // Export a singleton instance exports.globalHooks = new GlobalHooksRegistry(); //# sourceMappingURL=globalHooks.js.map