Skip to content

Commit

Permalink
fix(decorators): don't apply instance decorators when accessing from a
Browse files Browse the repository at this point in the history
prototype
  • Loading branch information
steelsojka committed Jun 9, 2018
1 parent c866405 commit 17caeb6
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 2 deletions.
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
{
"typescript.tsdk": "node_modules/typescript/lib"
"typescript.tsdk": "node_modules/typescript/lib",
"cSpell.words": [
"applicate"
]
}
19 changes: 19 additions & 0 deletions src/bind.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,23 @@ describe('bind', () => {
myClass2.fn.call(null);
expect(context).to.equal(myClass2);
});

it('should not bind when accessed on the prototype', () => {
let context;

class MyClass {
@Bind
fn() {
context = this;
}
}

MyClass.prototype.fn();

const myClass = new MyClass();

myClass.fn.call(null);

expect(context).to.equal(myClass);
});
});
14 changes: 13 additions & 1 deletion src/factory/DecoratorFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import {
InstanceChainContext
} from './common';
import { DecoratorConfig } from './DecoratorConfig';
import { copyMetadata, bind, isMethodOrPropertyDecoratorArgs } from '../utils';
import {
copyMetadata,
bind,
isMethodOrPropertyDecoratorArgs,
isPrototypeAccess
} from '../utils';

export type GenericDecorator = (...args: any[]) => LodashDecorator;

Expand Down Expand Up @@ -60,6 +65,7 @@ export class InternalDecoratorFactory {
const isSetter = isFirstInstance && isFunction(set);
const isMethod = isFirstInstance && isFunction(value);
const isProperty = isFirstInstance && !isGetter && !isSetter && !isMethod;
const baseValue = isGetter ? get : isMethod ? value : undefined;

chainData.properties.push(name);
chainData.fns.push((fn: Function, instance: any, context: InstanceChainContext) => {
Expand Down Expand Up @@ -132,6 +138,12 @@ export class InternalDecoratorFactory {
}

descriptor.get = function() {
// Check for direct access on the prototype.
// MyClass.prototype.fn <-- This should not apply the decorator.
if (isPrototypeAccess(this, target)) {
return baseValue;
}

applyDecorator(this);

const descriptor = Object.getOwnPropertyDescriptor(this, name)!;
Expand Down
1 change: 1 addition & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export * from './utils/bind';
export * from './utils/wrapConstructor';
export * from './utils/assignAll';
export * from './utils/isDecoratorArgs';
export * from './utils/isPrototypeAccess';
5 changes: 5 additions & 0 deletions src/utils/isPrototypeAccess.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export function isPrototypeAccess(context: object, target: object): boolean {
return context === target
|| (context.constructor !== target.constructor
&& Object.getPrototypeOf(this).constructor === target.constructor);
}

0 comments on commit 17caeb6

Please sign in to comment.