fix(core): add `noSideEffects()` to `make*Decorator()` functions (#35769)
This causes all the `make*Decorator()` functions to be considered pure and to be eligible for associated tree shaking by Closure. PR Close #35769
This commit is contained in:
parent
4052dd8188
commit
dc6a7918e3
|
@ -8,6 +8,10 @@
|
||||||
|
|
||||||
import {Type} from '../interface/type';
|
import {Type} from '../interface/type';
|
||||||
|
|
||||||
|
import {noSideEffects} from './closure';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface implemented by all Angular type decorators, which allows them to be used as
|
* An interface implemented by all Angular type decorators, which allows them to be used as
|
||||||
* decorators as well as Angular syntax.
|
* decorators as well as Angular syntax.
|
||||||
|
@ -44,39 +48,41 @@ export function makeDecorator<T>(
|
||||||
additionalProcessing?: (type: Type<T>) => void,
|
additionalProcessing?: (type: Type<T>) => void,
|
||||||
typeFn?: (type: Type<T>, ...args: any[]) => void):
|
typeFn?: (type: Type<T>, ...args: any[]) => void):
|
||||||
{new (...args: any[]): any; (...args: any[]): any; (...args: any[]): (cls: any) => any;} {
|
{new (...args: any[]): any; (...args: any[]): any; (...args: any[]): (cls: any) => any;} {
|
||||||
const metaCtor = makeMetadataCtor(props);
|
return noSideEffects(() => {
|
||||||
|
const metaCtor = makeMetadataCtor(props);
|
||||||
|
|
||||||
function DecoratorFactory(
|
function DecoratorFactory(
|
||||||
this: unknown | typeof DecoratorFactory, ...args: any[]): (cls: Type<T>) => any {
|
this: unknown | typeof DecoratorFactory, ...args: any[]): (cls: Type<T>) => any {
|
||||||
if (this instanceof DecoratorFactory) {
|
if (this instanceof DecoratorFactory) {
|
||||||
metaCtor.call(this, ...args);
|
metaCtor.call(this, ...args);
|
||||||
return this as typeof DecoratorFactory;
|
return this as typeof DecoratorFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
const annotationInstance = new (DecoratorFactory as any)(...args);
|
||||||
|
return function TypeDecorator(cls: Type<T>) {
|
||||||
|
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);
|
if (parentClass) {
|
||||||
return function TypeDecorator(cls: Type<T>) {
|
DecoratorFactory.prototype = Object.create(parentClass.prototype);
|
||||||
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);
|
|
||||||
|
|
||||||
|
DecoratorFactory.prototype.ngMetadataName = name;
|
||||||
if (additionalProcessing) additionalProcessing(cls);
|
(DecoratorFactory as any).annotationCls = DecoratorFactory;
|
||||||
|
return DecoratorFactory as any;
|
||||||
return cls;
|
});
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parentClass) {
|
|
||||||
DecoratorFactory.prototype = Object.create(parentClass.prototype);
|
|
||||||
}
|
|
||||||
|
|
||||||
DecoratorFactory.prototype.ngMetadataName = name;
|
|
||||||
(DecoratorFactory as any).annotationCls = DecoratorFactory;
|
|
||||||
return DecoratorFactory as any;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeMetadataCtor(props?: (...args: any[]) => any): any {
|
function makeMetadataCtor(props?: (...args: any[]) => any): any {
|
||||||
|
@ -92,77 +98,82 @@ function makeMetadataCtor(props?: (...args: any[]) => any): any {
|
||||||
|
|
||||||
export function makeParamDecorator(
|
export function makeParamDecorator(
|
||||||
name: string, props?: (...args: any[]) => any, parentClass?: any): any {
|
name: string, props?: (...args: any[]) => any, parentClass?: any): any {
|
||||||
const metaCtor = makeMetadataCtor(props);
|
return noSideEffects(() => {
|
||||||
function ParamDecoratorFactory(
|
const metaCtor = makeMetadataCtor(props);
|
||||||
this: unknown | typeof ParamDecoratorFactory, ...args: any[]): any {
|
function ParamDecoratorFactory(
|
||||||
if (this instanceof ParamDecoratorFactory) {
|
this: unknown | typeof ParamDecoratorFactory, ...args: any[]): any {
|
||||||
metaCtor.apply(this, args);
|
if (this instanceof ParamDecoratorFactory) {
|
||||||
return this;
|
metaCtor.apply(this, args);
|
||||||
}
|
return this;
|
||||||
const annotationInstance = new (<any>ParamDecoratorFactory)(...args);
|
|
||||||
|
|
||||||
(<any>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);
|
|
||||||
}
|
}
|
||||||
|
const annotationInstance = new (<any>ParamDecoratorFactory)(...args);
|
||||||
|
|
||||||
(parameters[index] = parameters[index] || []).push(annotationInstance);
|
(<any>ParamDecorator).annotation = annotationInstance;
|
||||||
return cls;
|
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) {
|
||||||
if (parentClass) {
|
ParamDecoratorFactory.prototype = Object.create(parentClass.prototype);
|
||||||
ParamDecoratorFactory.prototype = Object.create(parentClass.prototype);
|
}
|
||||||
}
|
ParamDecoratorFactory.prototype.ngMetadataName = name;
|
||||||
ParamDecoratorFactory.prototype.ngMetadataName = name;
|
(<any>ParamDecoratorFactory).annotationCls = ParamDecoratorFactory;
|
||||||
(<any>ParamDecoratorFactory).annotationCls = ParamDecoratorFactory;
|
return ParamDecoratorFactory;
|
||||||
return ParamDecoratorFactory;
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makePropDecorator(
|
export function makePropDecorator(
|
||||||
name: string, props?: (...args: any[]) => any, parentClass?: any,
|
name: string, props?: (...args: any[]) => any, parentClass?: any,
|
||||||
additionalProcessing?: (target: any, name: string, ...args: any[]) => void): 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 {
|
function PropDecoratorFactory(
|
||||||
if (this instanceof PropDecoratorFactory) {
|
this: unknown | typeof PropDecoratorFactory, ...args: any[]): any {
|
||||||
metaCtor.apply(this, args);
|
if (this instanceof PropDecoratorFactory) {
|
||||||
return this;
|
metaCtor.apply(this, args);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const decoratorInstance = new (<any>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 (<any>PropDecoratorFactory)(...args);
|
if (parentClass) {
|
||||||
|
PropDecoratorFactory.prototype = Object.create(parentClass.prototype);
|
||||||
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;
|
PropDecoratorFactory.prototype.ngMetadataName = name;
|
||||||
}
|
(<any>PropDecoratorFactory).annotationCls = PropDecoratorFactory;
|
||||||
|
return PropDecoratorFactory;
|
||||||
if (parentClass) {
|
});
|
||||||
PropDecoratorFactory.prototype = Object.create(parentClass.prototype);
|
|
||||||
}
|
|
||||||
|
|
||||||
PropDecoratorFactory.prototype.ngMetadataName = name;
|
|
||||||
(<any>PropDecoratorFactory).annotationCls = PropDecoratorFactory;
|
|
||||||
return PropDecoratorFactory;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -220,5 +220,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "ɵɵinject"
|
"name": "ɵɵinject"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "noSideEffects"
|
||||||
}
|
}
|
||||||
]
|
]
|
Loading…
Reference in New Issue