Skip to content

Commit 875b326

Browse files
robwormaldMikeRyanDev
authored andcommitted
fix(effects): allow downleveled annotations (#98)
Applications using Google Closure Compiler with Angular's ngc can opt into downleveling specifically marked decorators into static properties. This change enables that usage. Closes #93
1 parent 9f4664e commit 875b326

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

modules/effects/spec/effects_metadata.spec.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,24 @@ describe('Effect Metadata', () => {
2323
]);
2424
});
2525

26+
it('should get the effects metadata for a downleveled class instance', () => {
27+
class Fixture {
28+
static get propDecorators() {
29+
return {
30+
a: [{ type: Effect, args: [{ dispatch: false }] }],
31+
b: [{ type: Effect, args: [] }],
32+
};
33+
}
34+
}
35+
36+
const mock = new Fixture();
37+
38+
expect(getSourceMetadata(mock)).toEqual([
39+
{ propertyName: 'a', dispatch: false },
40+
{ propertyName: 'b', dispatch: true },
41+
]);
42+
});
43+
2644
it('should return an empty array if the class has not been decorated', () => {
2745
class Fixture {
2846
a: any;

modules/effects/src/effects_metadata.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,35 @@ export interface EffectMetadata {
1111
dispatch: boolean;
1212
}
1313

14+
function hasStaticMetadata(sourceType: any): boolean {
15+
return !!(sourceType as any).propDecorators;
16+
}
17+
18+
function getStaticMetadata(sourceType: any): EffectMetadata[] {
19+
const propDecorators = sourceType.propDecorators;
20+
return Object.keys(propDecorators).reduce(
21+
(all, key) => all.concat(getStaticMetadataEntry(propDecorators[key], key)),
22+
[]
23+
);
24+
}
25+
26+
function getStaticMetadataEntry(metadataEntry: any, propertyName: string) {
27+
return metadataEntry
28+
.filter((entry: any) => entry.type === Effect)
29+
.map((entry: any) => {
30+
let dispatch = true;
31+
if (entry.args.length) {
32+
dispatch = !!entry.args[0].dispatch;
33+
}
34+
return { propertyName, dispatch };
35+
});
36+
}
37+
1438
function getEffectMetadataEntries(sourceProto: any): EffectMetadata[] {
39+
if (hasStaticMetadata(sourceProto.constructor)) {
40+
return getStaticMetadata(sourceProto.constructor);
41+
}
42+
1543
if (r.hasOwnMetadata(METADATA_KEY, sourceProto)) {
1644
return r.getOwnMetadata(METADATA_KEY, sourceProto);
1745
}
@@ -23,6 +51,9 @@ function setEffectMetadataEntries(sourceProto: any, entries: EffectMetadata[]) {
2351
r.defineMetadata(METADATA_KEY, entries, sourceProto);
2452
}
2553

54+
/**
55+
* @Annotation
56+
*/
2657
export function Effect({ dispatch } = { dispatch: true }): PropertyDecorator {
2758
return function(target: any, propertyName: string) {
2859
const effects: EffectMetadata[] = getEffectMetadataEntries(target);

0 commit comments

Comments
 (0)