diff --git a/README.md b/README.md index d2abfa9..6e536f7 100644 --- a/README.md +++ b/README.md @@ -334,6 +334,16 @@ The class also allows to decorate the Dapi functions with decorators and hooks. #### Methods +##### `getDefinition` + +`DapiDefinition` getter. + +**Syntax**: + +```Typescript +getDefinition(): DapiDefinition +``` + ##### `getDependencies` Dependencies getter. @@ -471,6 +481,27 @@ Removes a decorator from the `DapiWrapper` instance. - `key` - The name of the decorated method. Must be a key of the [`DapiDefinition.fns`](#dapidefinition) fns dictionary. - `decorator` - The decorator function to be removed from the method. +##### `decorateAll` + +Decorates all the `DapiDefinition.fns` with the passed decorator. + +**Syntax**: + +```Typescript + decorateAll(decorator: DecoratorFn): () => void +``` + +**Parameters**: + +- `decorator` - The decorator function to be added to the method. Each decorator must accept the following arguments + - `fn` - The function to be decorated. + - `deps` - The dependencies of the [`DapiDefinition.fns`](#dapidefinition). + - `args` - The arguments passed to the method. + +**Returns**: + +- Function to remove the all the added that accepts no arguments. + ##### `addHook` Adds a hook to a `DapiFn` of the `DapiWrapper` instance. Hooks are functions that are called before (`hookType` = `'pre'`) or after (`hookType` = `'post'`) the `DapiFn` is called. diff --git a/src/DapiMixin.ts b/src/DapiMixin.ts index c9c5156..1a2eec5 100644 --- a/src/DapiMixin.ts +++ b/src/DapiMixin.ts @@ -197,6 +197,15 @@ export function DapiMixin, T ex this.__definition.dependencies = newDeps; } + /** + * DapiDefinition getter. + * + * @returns DapiDefinition + */ + getDefinition() { + return this.__definition; + } + /** * Returns a JSON representation of the `DapiWrapper` instance. * @param replacer An array of strings and numbers that acts as an approved list for selecting the object properties that will be stringified. @@ -241,6 +250,25 @@ export function DapiMixin, T ex }; } + /** + * Decorates all the Dapi functions of the `DapiWrapper`'s Dapi functions dictionary. + * @param decorator The decorator function. The decorator function receives the decorated function as its first argument and the rest of the arguments are the arguments of the decorated function. + * @returns A function to remove all the added decorators. + */ + decorateAll(decorator: DecoratorFn) { + const removeDecorators: (() => void)[] = []; + + for (const key of Object.keys(this.__definition.fns)) { + removeDecorators.push(this.addDecorator(key as keyof DAPI, decorator)); + } + + return () => { + for (const removeDecorator of removeDecorators) { + removeDecorator(); + } + }; + } + /** * Removes a decorator from the DapiWrapper instance. * @param key The key of the function to remove the decorator from. Must be a key of the `DapiDefinition.fns` dictionary. diff --git a/src/__tests__/DapiMixin.test.ts b/src/__tests__/DapiMixin.test.ts index 60b1b00..b8f3e32 100644 --- a/src/__tests__/DapiMixin.test.ts +++ b/src/__tests__/DapiMixin.test.ts @@ -117,6 +117,13 @@ describe('DapiMixin', () => { assert.deepStrictEqual(testClass.getDependencies(), newDependencies); }); + it('should expose a definition getter', () => { + const TestClass = DapiMixin(definition, BaseTestClass); + const instance = new TestClass(); + + assert.deepStrictEqual(instance.getDefinition(), definition); + }); + it('should throw if you try to set the dependencies to a falsy value', () => { const TestClass = DapiMixin(definition, BaseTestClass); const instance = new TestClass(); @@ -308,7 +315,7 @@ describe('DapiMixin', () => { assert.throws(() => instance.command4()); }); - it('should be possible to decorate the commands', () => { + it('should be possible to decorate the dapi fns', () => { const TestClass = DapiMixin(definition, BaseTestClass); const instance = new TestClass(); const decorator = mock.fn(function (method, ...args) { @@ -685,5 +692,38 @@ describe('DapiMixin', () => { assert.strictEqual(TestClass.testProperty, 'test'); assert.strictEqual(TestClass.baseStaticProperty, 'baseStaticProperty'); }); + + it('should be possible to decorate all dapi functions at once', async () => { + const TestClass = DapiMixin(definition, BaseTestClass); + const instance = new TestClass(); + const decorator = mock.fn(function (method, ...args) { + return method(...args); + }); + + const removeAllDecorators = instance.decorateAll(decorator); + + assert.deepStrictEqual(instance.command1('a1', 'a2'), ['a1', 'a2']); + assert.deepStrictEqual(command1.mock.calls[0].arguments, [deps, 'a1', 'a2']); + assert.deepStrictEqual(command1.mock.calls[0].this, instance); + assert.equal(decorator.mock.callCount(), 1); + + assert.deepStrictEqual(instance.command2(), undefined); + assert.deepStrictEqual(command2.mock.calls[0].arguments, [deps]); + assert.deepStrictEqual(command2.mock.calls[0].this, instance); + assert.equal(decorator.mock.callCount(), 2); + + assert.deepStrictEqual(await instance.command3('a1', 'a2'), ['a1', 'a2']); + assert.deepStrictEqual(command3.mock.calls[0].arguments, [deps, 'a1', 'a2']); + assert.deepStrictEqual(command3.mock.calls[0].this, instance); + assert.equal(decorator.mock.callCount(), 3); + + removeAllDecorators(); + + assert.deepStrictEqual(instance.command1('a1', 'a2'), ['a1', 'a2']); + assert.deepStrictEqual(instance.command2(), undefined); + assert.deepStrictEqual(await instance.command3('a1', 'a2'), ['a1', 'a2']); + + assert.equal(decorator.mock.callCount(), 3); + }); }); });