diff --git a/.eslint/.eslintrc.module-boundaries.client.js b/.eslint/.eslintrc.module-boundaries.client.js index 47cb1cef..c5bb6f5a 100644 --- a/.eslint/.eslintrc.module-boundaries.client.js +++ b/.eslint/.eslintrc.module-boundaries.client.js @@ -10,8 +10,9 @@ exports.constraints = [ 'scope:client-testing-unit', 'scope:client-service-worker', 'scope:client-util', + 'scope:client-util-decorators', 'scope:client-util-ngrx', - 'scope:client-util-security' + 'scope:client-util-security', ], sourceTag: 'scope:documentation', }, diff --git a/apps/documentation/src/app/componenets/md-reference-tree/md-reference-tree.component.ts b/apps/documentation/src/app/componenets/md-reference-tree/md-reference-tree.component.ts index a6774845..73c8a8a0 100644 --- a/apps/documentation/src/app/componenets/md-reference-tree/md-reference-tree.component.ts +++ b/apps/documentation/src/app/componenets/md-reference-tree/md-reference-tree.component.ts @@ -1,6 +1,7 @@ import { NestedTreeControl } from '@angular/cdk/tree'; import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'; import { MatTreeNestedDataSource } from '@angular/material/tree'; +import { logMethod } from '@app/client-util-decorators'; import { Store } from '@ngrx/store'; import { DOCUMENTATION_ENVIRONMENT, IDocumentationEnvironment } from '../../interfaces/environment.interface'; @@ -28,7 +29,8 @@ export class AppDocMarkdownReferenceTreeComponent { public readonly dataSource = new MatTreeNestedDataSource(); - private readonly treeData = () => { + @logMethod() + private treeData() { const mdFilePaths = [ '/README.md', // the root readme in not present in the autogenerated array and should be added here ...this.env.mdFilePaths, @@ -42,7 +44,7 @@ export class AppDocMarkdownReferenceTreeComponent { }); this.showReadme(`md${mdFilePaths[0]}`); return treeNodes; - }; + } constructor( private readonly store: Store, @@ -51,8 +53,10 @@ export class AppDocMarkdownReferenceTreeComponent { this.dataSource.data = this.treeData(); } - public readonly hasChild = (index: number, node: IMarkdownReferenceNode) => - typeof node.children !== 'undefined' && node.children.length > 0; + @logMethod() + public hasChild(index: number, node: IMarkdownReferenceNode) { + return typeof node.children !== 'undefined' && node.children.length > 0; + } public showReadme(filePath: string): void { this.store.dispatch(mdFilesAction.showReadme({ filePath })); diff --git a/libs/client-util-decorators/.eslintrc.json b/libs/client-util-decorators/.eslintrc.json index 3a51d69a..2813bad4 100644 --- a/libs/client-util-decorators/.eslintrc.json +++ b/libs/client-util-decorators/.eslintrc.json @@ -1,4 +1,12 @@ { "extends": ["../../.eslintrc.js", "../../.eslintrc.angular.js"], - "ignorePatterns": ["!**/*"] + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["log-method.decorator.ts"], + "rules": { + "no-console": "off" + } + } + ] } diff --git a/libs/client-util-decorators/src/index.ts b/libs/client-util-decorators/src/index.ts index 5dbd0ea7..f41a696f 100644 --- a/libs/client-util-decorators/src/index.ts +++ b/libs/client-util-decorators/src/index.ts @@ -1 +1 @@ -export * from './lib/decorators'; +export * from './lib'; diff --git a/libs/client-util-decorators/src/lib/decorators/index.ts b/libs/client-util-decorators/src/lib/decorators/index.ts index 3309da4f..0232401a 100644 --- a/libs/client-util-decorators/src/lib/decorators/index.ts +++ b/libs/client-util-decorators/src/lib/decorators/index.ts @@ -1 +1,2 @@ +export * from './log-method/log-method.decorator'; export * from './track-changes/track-changes.decorator'; diff --git a/libs/client-util-decorators/src/lib/decorators/log-method/log-method.decorator.spec.ts b/libs/client-util-decorators/src/lib/decorators/log-method/log-method.decorator.spec.ts new file mode 100644 index 00000000..f3b46d59 --- /dev/null +++ b/libs/client-util-decorators/src/lib/decorators/log-method/log-method.decorator.spec.ts @@ -0,0 +1,63 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { ComponentFixture, TestBed, TestModuleMetadata } from '@angular/core/testing'; + +import { logMethod } from './log-method.decorator'; + +@Component({ + selector: 'app-log-method-testing-component', + template: `
`, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +class AppLogMethodTestingComponent { + @logMethod(true) + public logEnabled(options: { test: string }) { + return options; + } + + @logMethod() + public logEnabledImplicitly(options: { test: string }) { + return options; + } + + @logMethod(false) + public logDisabled(options: { test: string }) { + return options; + } +} + +describe('trackChanges', () => { + const testBedConfig: TestModuleMetadata = { + declarations: [AppLogMethodTestingComponent], + }; + + let fixture: ComponentFixture; + let component: AppLogMethodTestingComponent; + + let spy: jest.SpyInstance; + + beforeEach(async () => { + await TestBed.configureTestingModule(testBedConfig).compileComponents(); + fixture = TestBed.createComponent(AppLogMethodTestingComponent); + component = fixture.componentInstance; + spy = jest.spyOn(console, 'log'); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + it('should log changes if attached and enabled explicitly', () => { + component.logEnabled({ test: 'test' }); + expect(spy).toHaveBeenCalledTimes(1); + }); + + it('should log changes if attached and enabled implicitly', () => { + component.logEnabledImplicitly({ test: 'test' }); + expect(spy).toHaveBeenCalledTimes(1); + }); + + it('should not log changes if attached and disabled', () => { + component.logDisabled({ test: 'test' }); + expect(spy).not.toHaveBeenCalled(); + }); +}); diff --git a/libs/client-util-decorators/src/lib/decorators/log-method/log-method.decorator.ts b/libs/client-util-decorators/src/lib/decorators/log-method/log-method.decorator.ts new file mode 100644 index 00000000..990861f2 --- /dev/null +++ b/libs/client-util-decorators/src/lib/decorators/log-method/log-method.decorator.ts @@ -0,0 +1,20 @@ +/** + * @title The log method decorator. + * @description This log is mainly useful for development and should not be used in production. + * @param enable Indicates whether to enable the logger or not. + * @param propertyKey The class property key. + */ +export function logMethod>(enable = true) { + return function (targetClass: TargetClass, propertyKey: string, descriptor: PropertyDescriptor) { + const originalMethod: (...args: any[]) => unknown = descriptor.value; + descriptor.value = function (...args: any[]) { + const className = targetClass.constructor.name; + const result = originalMethod.apply(this, args); + if (enable) { + console.log(`Executing: ${className}.${propertyKey}`, `\nArguments: ${JSON.stringify(args)}`, `\nResult: ${result}`); + } + return result; + }; + return descriptor; + }; +} diff --git a/libs/client-util-decorators/src/lib/decorators/track-changes/track-changes.decorator.spec.ts b/libs/client-util-decorators/src/lib/decorators/track-changes/track-changes.decorator.spec.ts index 91a2ebd4..a025f2bb 100644 --- a/libs/client-util-decorators/src/lib/decorators/track-changes/track-changes.decorator.spec.ts +++ b/libs/client-util-decorators/src/lib/decorators/track-changes/track-changes.decorator.spec.ts @@ -1,12 +1,8 @@ -import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChange, SimpleChanges } from '@angular/core'; +import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core'; import { ComponentFixture, TestBed, TestModuleMetadata } from '@angular/core/testing'; import { trackChanges } from './track-changes.decorator'; -interface IInputChanges extends SimpleChanges { - input: SimpleChange; -} - const controlSuffix = 'Changes'; @Component({ @@ -21,7 +17,7 @@ class AppTrackChangesTestingComponent implements OnChanges { @trackChanges('noinput', 'inputChangeHandler') @trackChanges('input', 'inputChangeHandler') - public ngOnChanges(changes: IInputChanges) { + public ngOnChanges(changes: SimpleChanges) { return changes; } diff --git a/libs/client-util-decorators/src/lib/index.ts b/libs/client-util-decorators/src/lib/index.ts new file mode 100644 index 00000000..b7a1cf14 --- /dev/null +++ b/libs/client-util-decorators/src/lib/index.ts @@ -0,0 +1 @@ +export * from './decorators'; diff --git a/tools/.eslintrc.json b/tools/.eslintrc.json index 57d056c5..cbbf5c3e 100644 --- a/tools/.eslintrc.json +++ b/tools/.eslintrc.json @@ -1,4 +1,12 @@ { "extends": ["../.eslintrc.js"], - "ignorePatterns": ["!**/*"] + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*logger*.ts"], + "rules": { + "no-console": "off" + } + } + ] }