Skip to content

Commit

Permalink
feat(schematics): add support for effect creators to schematics (#1725)
Browse files Browse the repository at this point in the history
Closes #1682
  • Loading branch information
itayod authored and brandonroberts committed Apr 12, 2019
1 parent 634a082 commit 8901abd
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import { Actions, Effect<% if (feature) { %>, ofType<% } %> } from '@ngrx/effects';
import { Actions, <%= effectMethod %><% if (feature) { %>, ofType<% } %> } from '@ngrx/effects';
<% if (feature && api) { %>import { catchError, map, concatMap } from 'rxjs/operators';
import { EMPTY, of } from 'rxjs';
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';
Expand All @@ -12,24 +12,25 @@ import { <%= classify(name) %>ActionTypes, <%= classify(name) %>Actions } from '
@Injectable()
export class <%= classify(name) %>Effects {
<% if (feature && api) { %>
@Effect()
load<%= classify(name) %>s$ = this.actions$.pipe(
<%= effectStart %>
ofType(<%= classify(name) %>ActionTypes.Load<%= classify(name) %>s),
concatMap(() =>
/** An EMPTY observable only emits completion. Replace with your own observable API request */
EMPTY.pipe(
map(data => new Load<%= classify(name) %>sSuccess({ data })),
catchError(error => of(new Load<%= classify(name) %>sFailure({ error }))))
)
);<% } %>
<%= effectEnd %>
<% } %>

<% if (feature && !api) { %>
@Effect()
load<%= classify(name) %>s$ = this.actions$.pipe(
<%= effectStart %>
ofType(<%= classify(name) %>ActionTypes.Load<%= classify(name) %>s),
/** An EMPTY observable only emits completion. Replace with your own observable API request */
concatMap(() => EMPTY)
);
<%= effectEnd %>
<% } %>

<% if (feature) { %>
constructor(private actions$: Actions<<%= classify(name) %>Actions>) {}
<% } else { %>
Expand Down
39 changes: 39 additions & 0 deletions modules/schematics/src/effect/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ describe('Effect Schematic', () => {
feature: false,
root: false,
group: false,
effectCreators: false,
};

const projectPath = getTestProjectPath();
Expand Down Expand Up @@ -316,4 +317,42 @@ describe('Effect Schematic', () => {
/constructor\(private actions\$: Actions<FooActions>\) {}/
);
});

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

const tree = schematicRunner.runSchematic('effect', options, appTree);
const content = tree.readContent(
`${projectPath}/src/app/foo/foo.effects.ts`
);
expect(content).toMatch(
/import { Actions, createEffect, ofType } from '@ngrx\/effects';/
);
expect(content).not.toMatch(/@Effect\(\)/);
expect(content).toMatch(
/loadFoos\$ = createEffect\(\(\) => this.actions\$.pipe\(/
);
});

it('should create an api effect using creator function', () => {
const options = {
...defaultOptions,
effectCreators: true,
api: true,
feature: true,
};

const tree = schematicRunner.runSchematic('effect', options, appTree);
const content = tree.readContent(
`${projectPath}/src/app/foo/foo.effects.ts`
);

expect(content).toMatch(
/import { Actions, createEffect, ofType } from '@ngrx\/effects';/
);
expect(content).not.toMatch(/@Effect\(\)/);
expect(content).toMatch(
/loadFoos\$ = createEffect\(\(\) => this.actions\$.pipe\(/
);
});
});
18 changes: 18 additions & 0 deletions modules/schematics/src/effect/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,21 @@ function addImportToNgModule(options: EffectOptions): Rule {
};
}

function getEffectMethod(effectCreators?: boolean) {
return effectCreators ? 'createEffect' : 'Effect';
}

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

function getEffectEnd(effectCreators?: boolean) {
return effectCreators ? '));' : ');';
}

export default function(options: EffectOptions): Rule {
return (host: Tree, context: SchematicContext) => {
options.path = getProjectPath(host, options);
Expand All @@ -116,6 +131,9 @@ export default function(options: EffectOptions): Rule {
options.flat ? '' : s,
options.group ? 'effects' : ''
),
effectMethod: getEffectMethod(options.effectCreators),
effectStart: getEffectStart(options.name, options.effectCreators),
effectEnd: getEffectEnd(options.effectCreators),
...(options as object),
} as any),
move(parsedPath.path),
Expand Down
6 changes: 6 additions & 0 deletions modules/schematics/src/effect/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@
"description":
"Specifies if effect has api success and failure actions wired up",
"aliases": ["a"]
},
"effectCreators": {
"type": "boolean",
"default": false,
"description": "Specifies whether to use the effect creators function",
"aliases": ["ec"]
}
},
"required": []
Expand Down
5 changes: 5 additions & 0 deletions modules/schematics/src/effect/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,9 @@ export interface Schema {
* Specifies if effect has api success and failure actions wired up
*/
api?: boolean;

/**
* Specifies if the effect creation uses 'createEffect'
*/
effectCreators?: boolean;
}
7 changes: 7 additions & 0 deletions modules/schematics/src/feature/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@
"description":
"Specifies if api success and failure actions, reducer, and effects should be generated as part of this feature.",
"aliases": ["a"]
},
"creators": {
"type": "boolean",
"default": false,
"description":
"Specifies if the effects and actions be created using creator functions",
"aliases": ["c"]
}
},
"required": []
Expand Down
5 changes: 5 additions & 0 deletions modules/schematics/src/feature/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,9 @@ export interface Schema {
* should be generated as part of this feature.
*/
api?: boolean;

/**
* Specifies if the effect creation uses 'createEffect'
*/
effectCreators?: boolean;
}

0 comments on commit 8901abd

Please sign in to comment.