Skip to content

Commit

Permalink
chore(*): Rewrite deprecation decorator for properties and methods (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
Borislav Kulov committed Dec 18, 2018
1 parent a2e731b commit 25b5cfb
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 8 deletions.
24 changes: 24 additions & 0 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,30 @@ If the bug fix or new feature development requires changes to released public AP
2. Add a `BREAKING CHANGE:` section to the commit message body or footer. See https://www.conventionalcommits.org
3. Check if the change can be migrated by `ng update` schematics and add to the project migrations. See [Update Migrations wiki](https://github.com/IgniteUI/igniteui-angular/wiki/Update-Migrations) for available functionality and instructions.

## Deprecating selectors
When deprecating selectors the following code should be placed inside `OnInit` method of the class the selector belongs to:
`
import { isDevMode } from '@angular/core';
...
if (isDevMode()) {
console.log('your deprecation message');
}
`
Write migrations.

## Deprecating methods
When a method is deprecated a few steps have to be done:
1. Add deprecation warning message by decorating the method with `@DeprecateMethod` decorator from `deprecateDecorators.ts` file.
2. Ensure that the deprecated method is no longer used in IgniteUI for Angular codebase, samples and documentation snippets.
3. Write migrations.

## Deprecating class properties
When a class property is deprecated a few steps have to be done:
1. Add deprecation warning message by decorating the property with `@DeprecateProperty` decorator from `deprecateDecorators.ts` file.
2. Ensure that the deprecated property is no longer used in IgniteUI for Angular codebase, samples and documentation snippets.
3. Write migrations.

NOTE: TypeScript disallows decorating both the get and set accessor for a single member. Instead, all decorators for the member must be applied to the first accessor specified in document order. This is because decorators apply to a Property Descriptor, which combines both the get and set accessor, not each declaration separately.

# Testing a PR
In order to test a pull request that is awaiting test, perform the following actions.
Expand Down
60 changes: 54 additions & 6 deletions projects/igniteui-angular/src/lib/core/deprecateDecorators.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,65 @@
import { isDevMode } from '@angular/core';

/**
* @hidden
*/
export function DeprecateMethod(message: string): MethodDecorator {
return (constructor: any) => {
console.warn(constructor.constructor.name + ': ' + message);
};
var isMessageShown = false;

return function (target: any, key: string, descriptor: PropertyDescriptor) {
if (descriptor && descriptor.value) {
const originalMethod = descriptor.value;

descriptor.value = function () {
if (!isMessageShown && isDevMode()) {
const targetName = typeof target === "function" ? target.name : target.constructor.name;
isMessageShown = true;

console.warn(`${targetName}.${key}: ${message}`);
}

return originalMethod.apply(this, arguments);
};

return descriptor;
}
}
}

/**
* @hidden
*/
export function DeprecateProperty(message: string): PropertyDecorator {
return (constructor: any) => {
console.warn(constructor.constructor.name + ': ' + message);
};
return function(target: any, key: string) {
var isMessageShown = false;

// use backing field to set/get the value of the property to ensure there won't be infinite recursive calls
const newKey = generateUniqueKey(target, key);

Object.defineProperty(target, key, {
set(value) {
this[newKey] = value;
},
get() {
if (!isMessageShown && isDevMode()) {
isMessageShown = true;
console.warn(`${target.constructor.name}.${key}: ${message}`);
}

return this[newKey];
}
});
}
}

/**
* @hidden
*/
function generateUniqueKey(target: any, key: string): string {
let newKey = '_' + key;
while (target.hasOwnProperty(newKey)) {
newKey = '_' + newKey;
}

return newKey;
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { filter, takeUntil } from 'rxjs/operators';
import { Subscription, Subject, MonoTypeOperatorFunction } from 'rxjs';
import { OverlayCancelableEventArgs } from '../../services/overlay/utilities';
import { CancelableEventArgs } from '../../core/utils';
import { DeprecateProperty } from '../../core/deprecateDecorators';

@Directive({
exportAs: 'toggle',
Expand Down Expand Up @@ -323,6 +324,8 @@ export class IgxToggleActionDirective implements OnInit {
* let closesOnOutsideClick = this.toggle.closeOnOutsideClick;
* ```
*/
@Input()
@DeprecateProperty(`igxToggleAction 'closeOnOutsideClick' input is deprecated. Use 'overlaySettings' input object instead.`)
public get closeOnOutsideClick(): boolean {
return this._closeOnOutsideClick;
}
Expand All @@ -332,9 +335,7 @@ export class IgxToggleActionDirective implements OnInit {
* <div igxToggleAction [closeOnOutsideClick]="'true'"></div>
* ```
*/
@Input()
public set closeOnOutsideClick(v: boolean) {
console.warn(`igxToggleAction 'closeOnOutsideClick' input is deprecated. Use 'overlaySettings' input object instead.`);
this._closeOnOutsideClick = v;
}

Expand Down

0 comments on commit 25b5cfb

Please sign in to comment.