Skip to content

Commit 8901abd

Browse files
itayodbrandonroberts
authored andcommitted
feat(schematics): add support for effect creators to schematics (#1725)
Closes #1682
1 parent 634a082 commit 8901abd

File tree

7 files changed

+88
-7
lines changed

7 files changed

+88
-7
lines changed

modules/schematics/src/effect/files/__name@dasherize@if-flat__/__name@dasherize__.effects.ts.template

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Injectable } from '@angular/core';
2-
import { Actions, Effect<% if (feature) { %>, ofType<% } %> } from '@ngrx/effects';
2+
import { Actions, <%= effectMethod %><% if (feature) { %>, ofType<% } %> } from '@ngrx/effects';
33
<% if (feature && api) { %>import { catchError, map, concatMap } from 'rxjs/operators';
44
import { EMPTY, of } from 'rxjs';
55
import { Load<%= classify(name) %>sFailure, Load<%= classify(name) %>sSuccess, <%= classify(name) %>ActionTypes, <%= classify(name) %>Actions } from '<%= featurePath(group, flat, "actions", dasherize(name)) %><%= dasherize(name) %>.actions';
@@ -12,24 +12,25 @@ import { <%= classify(name) %>ActionTypes, <%= classify(name) %>Actions } from '
1212
@Injectable()
1313
export class <%= classify(name) %>Effects {
1414
<% if (feature && api) { %>
15-
@Effect()
16-
load<%= classify(name) %>s$ = this.actions$.pipe(
15+
<%= effectStart %>
1716
ofType(<%= classify(name) %>ActionTypes.Load<%= classify(name) %>s),
1817
concatMap(() =>
1918
/** An EMPTY observable only emits completion. Replace with your own observable API request */
2019
EMPTY.pipe(
2120
map(data => new Load<%= classify(name) %>sSuccess({ data })),
2221
catchError(error => of(new Load<%= classify(name) %>sFailure({ error }))))
2322
)
24-
);<% } %>
23+
<%= effectEnd %>
24+
<% } %>
25+
2526
<% if (feature && !api) { %>
26-
@Effect()
27-
load<%= classify(name) %>s$ = this.actions$.pipe(
27+
<%= effectStart %>
2828
ofType(<%= classify(name) %>ActionTypes.Load<%= classify(name) %>s),
2929
/** An EMPTY observable only emits completion. Replace with your own observable API request */
3030
concatMap(() => EMPTY)
31-
);
31+
<%= effectEnd %>
3232
<% } %>
33+
3334
<% if (feature) { %>
3435
constructor(private actions$: Actions<<%= classify(name) %>Actions>) {}
3536
<% } else { %>

modules/schematics/src/effect/index.spec.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ describe('Effect Schematic', () => {
2727
feature: false,
2828
root: false,
2929
group: false,
30+
effectCreators: false,
3031
};
3132

3233
const projectPath = getTestProjectPath();
@@ -316,4 +317,42 @@ describe('Effect Schematic', () => {
316317
/constructor\(private actions\$: Actions<FooActions>\) {}/
317318
);
318319
});
320+
321+
it('should create an effect using creator function', () => {
322+
const options = { ...defaultOptions, effectCreators: true, feature: true };
323+
324+
const tree = schematicRunner.runSchematic('effect', options, appTree);
325+
const content = tree.readContent(
326+
`${projectPath}/src/app/foo/foo.effects.ts`
327+
);
328+
expect(content).toMatch(
329+
/import { Actions, createEffect, ofType } from '@ngrx\/effects';/
330+
);
331+
expect(content).not.toMatch(/@Effect\(\)/);
332+
expect(content).toMatch(
333+
/loadFoos\$ = createEffect\(\(\) => this.actions\$.pipe\(/
334+
);
335+
});
336+
337+
it('should create an api effect using creator function', () => {
338+
const options = {
339+
...defaultOptions,
340+
effectCreators: true,
341+
api: true,
342+
feature: true,
343+
};
344+
345+
const tree = schematicRunner.runSchematic('effect', options, appTree);
346+
const content = tree.readContent(
347+
`${projectPath}/src/app/foo/foo.effects.ts`
348+
);
349+
350+
expect(content).toMatch(
351+
/import { Actions, createEffect, ofType } from '@ngrx\/effects';/
352+
);
353+
expect(content).not.toMatch(/@Effect\(\)/);
354+
expect(content).toMatch(
355+
/loadFoos\$ = createEffect\(\(\) => this.actions\$.pipe\(/
356+
);
357+
});
319358
});

modules/schematics/src/effect/index.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,21 @@ function addImportToNgModule(options: EffectOptions): Rule {
9393
};
9494
}
9595

96+
function getEffectMethod(effectCreators?: boolean) {
97+
return effectCreators ? 'createEffect' : 'Effect';
98+
}
99+
100+
function getEffectStart(name: string, effectCreators?: boolean): string {
101+
const effectName = stringUtils.classify(name);
102+
return effectCreators
103+
? `load${effectName}s$ = createEffect(() => this.actions$.pipe(`
104+
: '@Effect()\n' + ` load${effectName}s$ = this.actions$.pipe(`;
105+
}
106+
107+
function getEffectEnd(effectCreators?: boolean) {
108+
return effectCreators ? '));' : ');';
109+
}
110+
96111
export default function(options: EffectOptions): Rule {
97112
return (host: Tree, context: SchematicContext) => {
98113
options.path = getProjectPath(host, options);
@@ -116,6 +131,9 @@ export default function(options: EffectOptions): Rule {
116131
options.flat ? '' : s,
117132
options.group ? 'effects' : ''
118133
),
134+
effectMethod: getEffectMethod(options.effectCreators),
135+
effectStart: getEffectStart(options.name, options.effectCreators),
136+
effectEnd: getEffectEnd(options.effectCreators),
119137
...(options as object),
120138
} as any),
121139
move(parsedPath.path),

modules/schematics/src/effect/schema.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@
6363
"description":
6464
"Specifies if effect has api success and failure actions wired up",
6565
"aliases": ["a"]
66+
},
67+
"effectCreators": {
68+
"type": "boolean",
69+
"default": false,
70+
"description": "Specifies whether to use the effect creators function",
71+
"aliases": ["ec"]
6672
}
6773
},
6874
"required": []

modules/schematics/src/effect/schema.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,9 @@ export interface Schema {
4848
* Specifies if effect has api success and failure actions wired up
4949
*/
5050
api?: boolean;
51+
52+
/**
53+
* Specifies if the effect creation uses 'createEffect'
54+
*/
55+
effectCreators?: boolean;
5156
}

modules/schematics/src/feature/schema.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@
5656
"description":
5757
"Specifies if api success and failure actions, reducer, and effects should be generated as part of this feature.",
5858
"aliases": ["a"]
59+
},
60+
"creators": {
61+
"type": "boolean",
62+
"default": false,
63+
"description":
64+
"Specifies if the effects and actions be created using creator functions",
65+
"aliases": ["c"]
5966
}
6067
},
6168
"required": []

modules/schematics/src/feature/schema.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,9 @@ export interface Schema {
4444
* should be generated as part of this feature.
4545
*/
4646
api?: boolean;
47+
48+
/**
49+
* Specifies if the effect creation uses 'createEffect'
50+
*/
51+
effectCreators?: boolean;
4752
}

0 commit comments

Comments
 (0)