Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit dc6a791

Browse files
dgp1130atscott
authored andcommitted
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
1 parent 4052dd8 commit dc6a791

File tree

2 files changed

+100
-86
lines changed

2 files changed

+100
-86
lines changed

‎packages/core/src/util/decorators.ts

Lines changed: 97 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88

99
import {Type} from '../interface/type';
1010

11+
import {noSideEffects} from './closure';
12+
13+
14+
1115
/**
1216
* An interface implemented by all Angular type decorators, which allows them to be used as
1317
* decorators as well as Angular syntax.
@@ -44,39 +48,41 @@ export function makeDecorator<T>(
4448
additionalProcessing?: (type: Type<T>) => void,
4549
typeFn?: (type: Type<T>, ...args: any[]) => void):
4650
{new (...args: any[]): any; (...args: any[]): any; (...args: any[]): (cls: any) => any;} {
47-
const metaCtor = makeMetadataCtor(props);
48-
49-
function DecoratorFactory(
50-
this: unknown | typeof DecoratorFactory, ...args: any[]): (cls: Type<T>) => any {
51-
if (this instanceof DecoratorFactory) {
52-
metaCtor.call(this, ...args);
53-
return this as typeof DecoratorFactory;
54-
}
51+
return noSideEffects(() => {
52+
const metaCtor = makeMetadataCtor(props);
53+
54+
function DecoratorFactory(
55+
this: unknown | typeof DecoratorFactory, ...args: any[]): (cls: Type<T>) => any {
56+
if (this instanceof DecoratorFactory) {
57+
metaCtor.call(this, ...args);
58+
return this as typeof DecoratorFactory;
59+
}
5560

56-
const annotationInstance = new (DecoratorFactory as any)(...args);
57-
return function TypeDecorator(cls: Type<T>) {
58-
if (typeFn) typeFn(cls, ...args);
59-
// Use of Object.defineProperty is important since it creates non-enumerable property which
60-
// prevents the property is copied during subclassing.
61-
const annotations = cls.hasOwnProperty(ANNOTATIONS) ?
62-
(cls as any)[ANNOTATIONS] :
63-
Object.defineProperty(cls, ANNOTATIONS, {value: []})[ANNOTATIONS];
64-
annotations.push(annotationInstance);
61+
const annotationInstance = new (DecoratorFactory as any)(...args);
62+
return function TypeDecorator(cls: Type<T>) {
63+
if (typeFn) typeFn(cls, ...args);
64+
// Use of Object.defineProperty is important since it creates non-enumerable property which
65+
// prevents the property is copied during subclassing.
66+
const annotations = cls.hasOwnProperty(ANNOTATIONS) ?
67+
(cls as any)[ANNOTATIONS] :
68+
Object.defineProperty(cls, ANNOTATIONS, {value: []})[ANNOTATIONS];
69+
annotations.push(annotationInstance);
6570

6671

67-
if (additionalProcessing) additionalProcessing(cls);
72+
if (additionalProcessing) additionalProcessing(cls);
6873

69-
return cls;
70-
};
71-
}
74+
return cls;
75+
};
76+
}
7277

73-
if (parentClass) {
74-
DecoratorFactory.prototype = Object.create(parentClass.prototype);
75-
}
78+
if (parentClass) {
79+
DecoratorFactory.prototype = Object.create(parentClass.prototype);
80+
}
7681

77-
DecoratorFactory.prototype.ngMetadataName = name;
78-
(DecoratorFactory as any).annotationCls = DecoratorFactory;
79-
return DecoratorFactory as any;
82+
DecoratorFactory.prototype.ngMetadataName = name;
83+
(DecoratorFactory as any).annotationCls = DecoratorFactory;
84+
return DecoratorFactory as any;
85+
});
8086
}
8187

8288
function makeMetadataCtor(props?: (...args: any[]) => any): any {
@@ -92,77 +98,82 @@ function makeMetadataCtor(props?: (...args: any[]) => any): any {
9298

9399
export function makeParamDecorator(
94100
name: string, props?: (...args: any[]) => any, parentClass?: any): any {
95-
const metaCtor = makeMetadataCtor(props);
96-
function ParamDecoratorFactory(
97-
this: unknown | typeof ParamDecoratorFactory, ...args: any[]): any {
98-
if (this instanceof ParamDecoratorFactory) {
99-
metaCtor.apply(this, args);
100-
return this;
101-
}
102-
const annotationInstance = new (<any>ParamDecoratorFactory)(...args);
103-
104-
(<any>ParamDecorator).annotation = annotationInstance;
105-
return ParamDecorator;
106-
107-
function ParamDecorator(cls: any, unusedKey: any, index: number): any {
108-
// Use of Object.defineProperty is important since it creates non-enumerable property which
109-
// prevents the property is copied during subclassing.
110-
const parameters = cls.hasOwnProperty(PARAMETERS) ?
111-
(cls as any)[PARAMETERS] :
112-
Object.defineProperty(cls, PARAMETERS, {value: []})[PARAMETERS];
113-
114-
// there might be gaps if some in between parameters do not have annotations.
115-
// we pad with nulls.
116-
while (parameters.length <= index) {
117-
parameters.push(null);
101+
return noSideEffects(() => {
102+
const metaCtor = makeMetadataCtor(props);
103+
function ParamDecoratorFactory(
104+
this: unknown | typeof ParamDecoratorFactory, ...args: any[]): any {
105+
if (this instanceof ParamDecoratorFactory) {
106+
metaCtor.apply(this, args);
107+
return this;
108+
}
109+
const annotationInstance = new (<any>ParamDecoratorFactory)(...args);
110+
111+
(<any>ParamDecorator).annotation = annotationInstance;
112+
return ParamDecorator;
113+
114+
function ParamDecorator(cls: any, unusedKey: any, index: number): any {
115+
// Use of Object.defineProperty is important since it creates non-enumerable property which
116+
// prevents the property is copied during subclassing.
117+
const parameters = cls.hasOwnProperty(PARAMETERS) ?
118+
(cls as any)[PARAMETERS] :
119+
Object.defineProperty(cls, PARAMETERS, {value: []})[PARAMETERS];
120+
121+
// there might be gaps if some in between parameters do not have annotations.
122+
// we pad with nulls.
123+
while (parameters.length <= index) {
124+
parameters.push(null);
125+
}
126+
127+
(parameters[index] = parameters[index] || []).push(annotationInstance);
128+
return cls;
118129
}
119-
120-
(parameters[index] = parameters[index] || []).push(annotationInstance);
121-
return cls;
122130
}
123-
}
124-
if (parentClass) {
125-
ParamDecoratorFactory.prototype = Object.create(parentClass.prototype);
126-
}
127-
ParamDecoratorFactory.prototype.ngMetadataName = name;
128-
(<any>ParamDecoratorFactory).annotationCls = ParamDecoratorFactory;
129-
return ParamDecoratorFactory;
131+
if (parentClass) {
132+
ParamDecoratorFactory.prototype = Object.create(parentClass.prototype);
133+
}
134+
ParamDecoratorFactory.prototype.ngMetadataName = name;
135+
(<any>ParamDecoratorFactory).annotationCls = ParamDecoratorFactory;
136+
return ParamDecoratorFactory;
137+
});
130138
}
131139

132140
export function makePropDecorator(
133141
name: string, props?: (...args: any[]) => any, parentClass?: any,
134142
additionalProcessing?: (target: any, name: string, ...args: any[]) => void): any {
135-
const metaCtor = makeMetadataCtor(props);
143+
return noSideEffects(() => {
144+
const metaCtor = makeMetadataCtor(props);
145+
146+
function PropDecoratorFactory(
147+
this: unknown | typeof PropDecoratorFactory, ...args: any[]): any {
148+
if (this instanceof PropDecoratorFactory) {
149+
metaCtor.apply(this, args);
150+
return this;
151+
}
136152

137-
function PropDecoratorFactory(this: unknown | typeof PropDecoratorFactory, ...args: any[]): any {
138-
if (this instanceof PropDecoratorFactory) {
139-
metaCtor.apply(this, args);
140-
return this;
141-
}
153+
const decoratorInstance = new (<any>PropDecoratorFactory)(...args);
142154

143-
const decoratorInstance = new (<any>PropDecoratorFactory)(...args);
155+
function PropDecorator(target: any, name: string) {
156+
const constructor = target.constructor;
157+
// Use of Object.defineProperty is important since it creates non-enumerable property which
158+
// prevents the property is copied during subclassing.
159+
const meta = constructor.hasOwnProperty(PROP_METADATA) ?
160+
(constructor as any)[PROP_METADATA] :
161+
Object.defineProperty(constructor, PROP_METADATA, {value: {}})[PROP_METADATA];
162+
meta[name] = meta.hasOwnProperty(name) && meta[name] || [];
163+
meta[name].unshift(decoratorInstance);
144164

145-
function PropDecorator(target: any, name: string) {
146-
const constructor = target.constructor;
147-
// Use of Object.defineProperty is important since it creates non-enumerable property which
148-
// prevents the property is copied during subclassing.
149-
const meta = constructor.hasOwnProperty(PROP_METADATA) ?
150-
(constructor as any)[PROP_METADATA] :
151-
Object.defineProperty(constructor, PROP_METADATA, {value: {}})[PROP_METADATA];
152-
meta[name] = meta.hasOwnProperty(name) && meta[name] || [];
153-
meta[name].unshift(decoratorInstance);
165+
if (additionalProcessing) additionalProcessing(target, name, ...args);
166+
}
154167

155-
if (additionalProcessing) additionalProcessing(target, name, ...args);
168+
return PropDecorator;
156169
}
157170

158-
return PropDecorator;
159-
}
160-
161-
if (parentClass) {
162-
PropDecoratorFactory.prototype = Object.create(parentClass.prototype);
163-
}
171+
if (parentClass) {
172+
PropDecoratorFactory.prototype = Object.create(parentClass.prototype);
173+
}
164174

165-
PropDecoratorFactory.prototype.ngMetadataName = name;
166-
(<any>PropDecoratorFactory).annotationCls = PropDecoratorFactory;
167-
return PropDecoratorFactory;
175+
PropDecoratorFactory.prototype.ngMetadataName = name;
176+
(<any>PropDecoratorFactory).annotationCls = PropDecoratorFactory;
177+
return PropDecoratorFactory;
178+
});
168179
}

‎packages/core/test/bundling/injection/bundle.golden_symbols.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,5 +220,8 @@
220220
},
221221
{
222222
"name": "ɵɵinject"
223+
},
224+
{
225+
"name": "noSideEffects"
223226
}
224227
]

0 commit comments

Comments
 (0)