diff --git a/packages/core/src/util/decorators.ts b/packages/core/src/util/decorators.ts index c6cb35b7f4..7ffb8fe565 100644 --- a/packages/core/src/util/decorators.ts +++ b/packages/core/src/util/decorators.ts @@ -8,6 +8,10 @@ import {Type} from '../interface/type'; +import {noSideEffects} from './closure'; + + + /** * An interface implemented by all Angular type decorators, which allows them to be used as * decorators as well as Angular syntax. @@ -44,39 +48,41 @@ export function makeDecorator( additionalProcessing?: (type: Type) => void, typeFn?: (type: Type, ...args: any[]) => void): {new (...args: any[]): any; (...args: any[]): any; (...args: any[]): (cls: any) => any;} { - const metaCtor = makeMetadataCtor(props); + return noSideEffects(() => { + const metaCtor = makeMetadataCtor(props); - function DecoratorFactory( - this: unknown | typeof DecoratorFactory, ...args: any[]): (cls: Type) => any { - if (this instanceof DecoratorFactory) { - metaCtor.call(this, ...args); - return this as typeof DecoratorFactory; + function DecoratorFactory( + this: unknown | typeof DecoratorFactory, ...args: any[]): (cls: Type) => any { + if (this instanceof DecoratorFactory) { + metaCtor.call(this, ...args); + return this as typeof DecoratorFactory; + } + + const annotationInstance = new (DecoratorFactory as any)(...args); + return function TypeDecorator(cls: Type) { + if (typeFn) typeFn(cls, ...args); + // Use of Object.defineProperty is important since it creates non-enumerable property which + // prevents the property is copied during subclassing. + const annotations = cls.hasOwnProperty(ANNOTATIONS) ? + (cls as any)[ANNOTATIONS] : + Object.defineProperty(cls, ANNOTATIONS, {value: []})[ANNOTATIONS]; + annotations.push(annotationInstance); + + + if (additionalProcessing) additionalProcessing(cls); + + return cls; + }; } - const annotationInstance = new (DecoratorFactory as any)(...args); - return function TypeDecorator(cls: Type) { - if (typeFn) typeFn(cls, ...args); - // Use of Object.defineProperty is important since it creates non-enumerable property which - // prevents the property is copied during subclassing. - const annotations = cls.hasOwnProperty(ANNOTATIONS) ? - (cls as any)[ANNOTATIONS] : - Object.defineProperty(cls, ANNOTATIONS, {value: []})[ANNOTATIONS]; - annotations.push(annotationInstance); + if (parentClass) { + DecoratorFactory.prototype = Object.create(parentClass.prototype); + } - - if (additionalProcessing) additionalProcessing(cls); - - return cls; - }; - } - - if (parentClass) { - DecoratorFactory.prototype = Object.create(parentClass.prototype); - } - - DecoratorFactory.prototype.ngMetadataName = name; - (DecoratorFactory as any).annotationCls = DecoratorFactory; - return DecoratorFactory as any; + DecoratorFactory.prototype.ngMetadataName = name; + (DecoratorFactory as any).annotationCls = DecoratorFactory; + return DecoratorFactory as any; + }); } function makeMetadataCtor(props?: (...args: any[]) => any): any { @@ -92,77 +98,82 @@ function makeMetadataCtor(props?: (...args: any[]) => any): any { export function makeParamDecorator( name: string, props?: (...args: any[]) => any, parentClass?: any): any { - const metaCtor = makeMetadataCtor(props); - function ParamDecoratorFactory( - this: unknown | typeof ParamDecoratorFactory, ...args: any[]): any { - if (this instanceof ParamDecoratorFactory) { - metaCtor.apply(this, args); - return this; - } - const annotationInstance = new (ParamDecoratorFactory)(...args); - - (ParamDecorator).annotation = annotationInstance; - return ParamDecorator; - - function ParamDecorator(cls: any, unusedKey: any, index: number): any { - // Use of Object.defineProperty is important since it creates non-enumerable property which - // prevents the property is copied during subclassing. - const parameters = cls.hasOwnProperty(PARAMETERS) ? - (cls as any)[PARAMETERS] : - Object.defineProperty(cls, PARAMETERS, {value: []})[PARAMETERS]; - - // there might be gaps if some in between parameters do not have annotations. - // we pad with nulls. - while (parameters.length <= index) { - parameters.push(null); + return noSideEffects(() => { + const metaCtor = makeMetadataCtor(props); + function ParamDecoratorFactory( + this: unknown | typeof ParamDecoratorFactory, ...args: any[]): any { + if (this instanceof ParamDecoratorFactory) { + metaCtor.apply(this, args); + return this; } + const annotationInstance = new (ParamDecoratorFactory)(...args); - (parameters[index] = parameters[index] || []).push(annotationInstance); - return cls; + (ParamDecorator).annotation = annotationInstance; + return ParamDecorator; + + function ParamDecorator(cls: any, unusedKey: any, index: number): any { + // Use of Object.defineProperty is important since it creates non-enumerable property which + // prevents the property is copied during subclassing. + const parameters = cls.hasOwnProperty(PARAMETERS) ? + (cls as any)[PARAMETERS] : + Object.defineProperty(cls, PARAMETERS, {value: []})[PARAMETERS]; + + // there might be gaps if some in between parameters do not have annotations. + // we pad with nulls. + while (parameters.length <= index) { + parameters.push(null); + } + + (parameters[index] = parameters[index] || []).push(annotationInstance); + return cls; + } } - } - if (parentClass) { - ParamDecoratorFactory.prototype = Object.create(parentClass.prototype); - } - ParamDecoratorFactory.prototype.ngMetadataName = name; - (ParamDecoratorFactory).annotationCls = ParamDecoratorFactory; - return ParamDecoratorFactory; + if (parentClass) { + ParamDecoratorFactory.prototype = Object.create(parentClass.prototype); + } + ParamDecoratorFactory.prototype.ngMetadataName = name; + (ParamDecoratorFactory).annotationCls = ParamDecoratorFactory; + return ParamDecoratorFactory; + }); } export function makePropDecorator( name: string, props?: (...args: any[]) => any, parentClass?: any, additionalProcessing?: (target: any, name: string, ...args: any[]) => void): any { - const metaCtor = makeMetadataCtor(props); + return noSideEffects(() => { + const metaCtor = makeMetadataCtor(props); - function PropDecoratorFactory(this: unknown | typeof PropDecoratorFactory, ...args: any[]): any { - if (this instanceof PropDecoratorFactory) { - metaCtor.apply(this, args); - return this; + function PropDecoratorFactory( + this: unknown | typeof PropDecoratorFactory, ...args: any[]): any { + if (this instanceof PropDecoratorFactory) { + metaCtor.apply(this, args); + return this; + } + + const decoratorInstance = new (PropDecoratorFactory)(...args); + + function PropDecorator(target: any, name: string) { + const constructor = target.constructor; + // Use of Object.defineProperty is important since it creates non-enumerable property which + // prevents the property is copied during subclassing. + const meta = constructor.hasOwnProperty(PROP_METADATA) ? + (constructor as any)[PROP_METADATA] : + Object.defineProperty(constructor, PROP_METADATA, {value: {}})[PROP_METADATA]; + meta[name] = meta.hasOwnProperty(name) && meta[name] || []; + meta[name].unshift(decoratorInstance); + + if (additionalProcessing) additionalProcessing(target, name, ...args); + } + + return PropDecorator; } - const decoratorInstance = new (PropDecoratorFactory)(...args); - - function PropDecorator(target: any, name: string) { - const constructor = target.constructor; - // Use of Object.defineProperty is important since it creates non-enumerable property which - // prevents the property is copied during subclassing. - const meta = constructor.hasOwnProperty(PROP_METADATA) ? - (constructor as any)[PROP_METADATA] : - Object.defineProperty(constructor, PROP_METADATA, {value: {}})[PROP_METADATA]; - meta[name] = meta.hasOwnProperty(name) && meta[name] || []; - meta[name].unshift(decoratorInstance); - - if (additionalProcessing) additionalProcessing(target, name, ...args); + if (parentClass) { + PropDecoratorFactory.prototype = Object.create(parentClass.prototype); } - return PropDecorator; - } - - if (parentClass) { - PropDecoratorFactory.prototype = Object.create(parentClass.prototype); - } - - PropDecoratorFactory.prototype.ngMetadataName = name; - (PropDecoratorFactory).annotationCls = PropDecoratorFactory; - return PropDecoratorFactory; + PropDecoratorFactory.prototype.ngMetadataName = name; + (PropDecoratorFactory).annotationCls = PropDecoratorFactory; + return PropDecoratorFactory; + }); } diff --git a/packages/core/test/bundling/injection/bundle.golden_symbols.json b/packages/core/test/bundling/injection/bundle.golden_symbols.json index 885d5971d5..58d5050179 100644 --- a/packages/core/test/bundling/injection/bundle.golden_symbols.json +++ b/packages/core/test/bundling/injection/bundle.golden_symbols.json @@ -220,5 +220,8 @@ }, { "name": "ɵɵinject" + }, + { + "name": "noSideEffects" } ] \ No newline at end of file