@comake/skl-js-engine
Version:
Standard Knowledge Language Javascript Engine
164 lines • 6.58 kB
JavaScript
;
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