Skip to content

Commit 8a0a049

Browse files
feat(schematics): add support for reducer creators (#1785)
Closes #1764, 1766
1 parent c79362d commit 8a0a049

29 files changed

Lines changed: 272 additions & 168 deletions

File tree

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
import { createAction, union } from '@ngrx/store';
1+
import { createAction, props } from '@ngrx/store';
22

3-
export const load<%= classify(name) %>s = createAction('[<%= classify(name) %>] Load <%= classify(name) %>s');
4-
<% if (api) { %>export const load<%= classify(name) %>sSuccess = createAction('[<%= classify(name) %>] Load <%= classify(name) %>s Success');<% } %>
5-
<% if (api) { %>export const load<%= classify(name) %>sFailure = createAction('[<%= classify(name) %>] Load <%= classify(name) %>s Failure');<% } %>
3+
export const load<%= classify(name) %>s = createAction(
4+
'[<%= classify(name) %>] Load <%= classify(name) %>s'
5+
);
66

7-
const all = union({
8-
load<%= classify(name) %>s,
9-
<% if (api) { %>
10-
load<%= classify(name) %>sSuccess,
11-
load<%= classify(name) %>sFailure
12-
<% } %>
13-
});
14-
export Union = typeof all;
7+
<% if (api) { %>export const load<%= classify(name) %>sSuccess = createAction(
8+
'[<%= classify(name) %>] Load <%= classify(name) %>s Success',
9+
props<{ data: any }>()
10+
);<% } %>
11+
12+
<% if (api) { %>export const load<%= classify(name) %>sFailure = createAction(
13+
'[<%= classify(name) %>] Load <%= classify(name) %>s Failure',
14+
props<{ error: any }>()
15+
);<% } %>

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

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ describe('Action Schematic', () => {
117117
});
118118

119119
describe('action creators', () => {
120-
const creatorOptions = { ...defaultOptions, actionCreators: true };
120+
const creatorOptions = { ...defaultOptions, creators: true };
121121

122122
it('should create a const for the action creator', () => {
123123
const tree = schematicRunner.runSchematic(
@@ -129,9 +129,25 @@ describe('Action Schematic', () => {
129129
`${projectPath}/src/app/foo.actions.ts`
130130
);
131131

132-
expect(fileContent).toMatch(
133-
/export const loadFoos = createAction\('\[Foo\] Load Foos'\);/
132+
expect(fileContent).toMatch(/export const loadFoos = createAction\(/);
133+
expect(fileContent).toMatch(/\[Foo\] Load Foos'/);
134+
});
135+
136+
it('should create success/error actions when the api flag is set', () => {
137+
const tree = schematicRunner.runSchematic(
138+
'action',
139+
{ ...creatorOptions, api: true },
140+
appTree
134141
);
142+
const fileContent = tree.readContent(
143+
`${projectPath}/src/app/foo.actions.ts`
144+
);
145+
146+
expect(fileContent).toMatch(/export const loadFoos = createAction\(/);
147+
expect(fileContent).toMatch(/\[Foo\] Load Foos Success/);
148+
expect(fileContent).toMatch(/props<{ data: any }>\(\)/);
149+
expect(fileContent).toMatch(/\[Foo\] Load Foos Failure/);
150+
expect(fileContent).toMatch(/props<{ error: any }>\(\)/);
135151
});
136152
});
137153

modules/schematics/src/action/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export default function(options: ActionOptions): Rule {
3030
options.path = parsedPath.path;
3131

3232
const templateSource = apply(
33-
url(options.actionCreators ? './creator-files' : './files'),
33+
url(options.creators ? './creator-files' : './files'),
3434
[
3535
options.spec
3636
? noop()

modules/schematics/src/action/schema.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,12 @@
4646
"Specifies if api success and failure actions should be generated.",
4747
"aliases": ["a"]
4848
},
49-
"actionCreators": {
49+
"creators": {
5050
"type": "boolean",
5151
"default": false,
5252
"description":
53-
"Specifies whether to generate action creators instead of action classes.",
54-
"aliases": ["ac"]
53+
"Specifies whether to use creator functions for handling actions and reducers.",
54+
"aliases": ["c"]
5555
}
5656
},
5757
"required": []

modules/schematics/src/action/schema.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ export interface Schema {
3737
api?: boolean;
3838

3939
/**
40-
* Specifies whether to generate action creators
41-
* instead of action classes.
40+
* Specifies whether to use creator functions for
41+
* handling actions and reducers.
4242
*/
43-
actionCreators?: boolean;
43+
creators?: boolean;
4444
}

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@ import { Injectable } from '@angular/core';
22
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';
5-
<% if (!effectCreators) {%>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';<% } %>
6-
<% if (effectCreators) {%>import * as <%= classify(name) %>Actions from '<%= featurePath(group, flat, "actions", dasherize(name)) %><%= dasherize(name) %>.actions';<% } %>
5+
<% if (!creators) {%>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';<% } %>
6+
<% if (creators) {%>import * as <%= classify(name) %>Actions from '<%= featurePath(group, flat, "actions", dasherize(name)) %><%= dasherize(name) %>.actions';<% } %>
77
<% } %>
88
<% if (feature && !api) { %>import { concatMap } from 'rxjs/operators';
99
import { EMPTY } from 'rxjs';
10-
<% if (!effectCreators) {%>import { <%= classify(name) %>ActionTypes, <%= classify(name) %>Actions } from '<%= featurePath(group, flat, "actions", dasherize(name)) %><%= dasherize(name) %>.actions';<% } %>
11-
<% if (effectCreators) {%>import * as <%= classify(name) %>Actions from '<%= featurePath(group, flat, "actions", dasherize(name)) %><%= dasherize(name) %>.actions';<% } %>
10+
<% if (!creators) {%>import { <%= classify(name) %>ActionTypes, <%= classify(name) %>Actions } from '<%= featurePath(group, flat, "actions", dasherize(name)) %><%= dasherize(name) %>.actions';<% } %>
11+
<% if (creators) {%>import * as <%= classify(name) %>Actions from '<%= featurePath(group, flat, "actions", dasherize(name)) %><%= dasherize(name) %>.actions';<% } %>
1212
<% } %>
1313

1414
@Injectable()
1515
export class <%= classify(name) %>Effects {
16-
<% if (feature && api && !effectCreators) { %>
16+
<% if (feature && api && !creators) { %>
1717
<%= effectStart %>
1818
ofType(<%= classify(name) %>ActionTypes.Load<%= classify(name) %>s),
1919
concatMap(() =>
@@ -23,7 +23,7 @@ export class <%= classify(name) %>Effects {
2323
catchError(error => of(new Load<%= classify(name) %>sFailure({ error }))))
2424
)
2525
<%= effectEnd %>
26-
<% } else if (feature && api && effectCreators) { %>
26+
<% } else if (feature && api && creators) { %>
2727
<%= effectStart %>
2828
ofType(<%= classify(name) %>Actions.load<%= classify(name) %>s),
2929
concatMap(() =>
@@ -34,22 +34,22 @@ export class <%= classify(name) %>Effects {
3434
)
3535
<%= effectEnd %>
3636
<% } %>
37-
<% if (feature && !api && !effectCreators) { %>
37+
<% if (feature && !api && !creators) { %>
3838
<%= effectStart %>
3939
ofType(<%= classify(name) %>ActionTypes.Load<%= classify(name) %>s),
4040
/** An EMPTY observable only emits completion. Replace with your own observable API request */
4141
concatMap(() => EMPTY)
4242
<%= effectEnd %>
43-
<% } else if (feature && !api && effectCreators) { %>
43+
<% } else if (feature && !api && creators) { %>
4444
<%= effectStart %>
4545
ofType(<%= classify(name) %>Actions.load<%= classify(name) %>s),
4646
/** An EMPTY observable only emits completion. Replace with your own observable API request */
4747
concatMap(() => EMPTY)
4848
<%= effectEnd %>
4949
<% } %>
50-
<% if (feature && !effectCreators) { %>
50+
<% if (feature && !creators) { %>
5151
constructor(private actions$: Actions<<%= classify(name) %>Actions>) {}
52-
<% } else if (feature && effectCreators) { %>
52+
<% } else if (feature && creators) { %>
5353
constructor(private actions$: Actions) {}
5454
<% } else { %>
5555
constructor(private actions$: Actions) {}

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

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

3333
const projectPath = getTestProjectPath();
@@ -319,7 +319,7 @@ describe('Effect Schematic', () => {
319319
});
320320

321321
it('should create an effect using creator function', () => {
322-
const options = { ...defaultOptions, effectCreators: true, feature: true };
322+
const options = { ...defaultOptions, creators: true, feature: true };
323323

324324
const tree = schematicRunner.runSchematic('effect', options, appTree);
325325
const content = tree.readContent(
@@ -334,8 +334,8 @@ describe('Effect Schematic', () => {
334334
);
335335
});
336336

337-
it('should use action creators when effectCreators is enabled in a feature', () => {
338-
const options = { ...defaultOptions, effectCreators: true, feature: true };
337+
it('should use action creators when creators is enabled in a feature', () => {
338+
const options = { ...defaultOptions, creators: true, feature: true };
339339

340340
const tree = schematicRunner.runSchematic('effect', options, appTree);
341341
const content = tree.readContent(
@@ -352,7 +352,7 @@ describe('Effect Schematic', () => {
352352
it('should create an api effect using creator function', () => {
353353
const options = {
354354
...defaultOptions,
355-
effectCreators: true,
355+
creators: true,
356356
api: true,
357357
feature: true,
358358
};

modules/schematics/src/effect/index.ts

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

96-
function getEffectMethod(effectCreators?: boolean) {
97-
return effectCreators ? 'createEffect' : 'Effect';
96+
function getEffectMethod(creators?: boolean) {
97+
return creators ? 'createEffect' : 'Effect';
9898
}
9999

100-
function getEffectStart(name: string, effectCreators?: boolean): string {
100+
function getEffectStart(name: string, creators?: boolean): string {
101101
const effectName = stringUtils.classify(name);
102-
return effectCreators
102+
return creators
103103
? `load${effectName}s$ = createEffect(() => this.actions$.pipe(`
104104
: '@Effect()\n' + ` load${effectName}s$ = this.actions$.pipe(`;
105105
}
106106

107-
function getEffectEnd(effectCreators?: boolean) {
108-
return effectCreators ? '));' : ');';
107+
function getEffectEnd(creators?: boolean) {
108+
return creators ? '));' : ');';
109109
}
110110

111111
export default function(options: EffectOptions): Rule {
@@ -131,9 +131,9 @@ export default function(options: EffectOptions): Rule {
131131
options.flat ? '' : s,
132132
options.group ? 'effects' : ''
133133
),
134-
effectMethod: getEffectMethod(options.effectCreators),
135-
effectStart: getEffectStart(options.name, options.effectCreators),
136-
effectEnd: getEffectEnd(options.effectCreators),
134+
effectMethod: getEffectMethod(options.creators),
135+
effectStart: getEffectStart(options.name, options.creators),
136+
effectEnd: getEffectEnd(options.creators),
137137
...(options as object),
138138
} as any),
139139
move(parsedPath.path),

modules/schematics/src/effect/schema.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,12 @@
6464
"Specifies if effect has api success and failure actions wired up",
6565
"aliases": ["a"]
6666
},
67-
"effectCreators": {
67+
"creators": {
6868
"type": "boolean",
6969
"default": false,
70-
"description": "Specifies whether to use the effect creators function",
71-
"aliases": ["ec"]
70+
"description":
71+
"Specifies whether to use creator functions for handling actions, reducers, and effects.",
72+
"aliases": ["c"]
7273
}
7374
},
7475
"required": []

modules/schematics/src/effect/schema.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ export interface Schema {
5050
api?: boolean;
5151

5252
/**
53-
* Specifies if the effect creation uses 'createEffect'
53+
* Specifies whether to use creator functions for
54+
* handling actions, reducers, and effects.
5455
*/
55-
effectCreators?: boolean;
56+
creators?: boolean;
5657
}

0 commit comments

Comments
 (0)