Skip to content

Commit

Permalink
feat(Schematics): Add effect to registered effects array (#717)
Browse files Browse the repository at this point in the history
  • Loading branch information
brandonroberts authored and MikeRyanDev committed Jan 13, 2018
1 parent 765b15a commit f1082fe
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 2 deletions.
73 changes: 72 additions & 1 deletion modules/schematics/src/effect/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { Tree, VirtualTree } from '@angular-devkit/schematics';
import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
import * as path from 'path';
import { createAppModule, getFileContent } from '../utility/test';
import {
createAppModule,
getFileContent,
createAppModuleWithEffects,
} from '../utility/test';
import { Schema as EffectOptions } from './schema';

describe('Effect Schematic', () => {
Expand All @@ -16,6 +20,8 @@ describe('Effect Schematic', () => {
spec: true,
module: undefined,
flat: false,
feature: false,
root: false,
};

let appTree: Tree;
Expand Down Expand Up @@ -77,4 +83,69 @@ describe('Effect Schematic', () => {
);
expect(files.indexOf('/src/app/foo/foo.effects.spec.ts')).toEqual(-1);
});

it('should register the root effect in the provided module', () => {
const options = { ...defaultOptions, root: true, module: 'app.module.ts' };

const tree = schematicRunner.runSchematic('effect', options, appTree);
const content = getFileContent(tree, '/src/app/app.module.ts');

expect(content).toMatch(/EffectsModule\.forRoot\(\[FooEffects\]\)/);
});

it('should register the feature effect in the provided module', () => {
const options = { ...defaultOptions, module: 'app.module.ts' };

const tree = schematicRunner.runSchematic('effect', options, appTree);
const content = getFileContent(tree, '/src/app/app.module.ts');

expect(content).toMatch(/EffectsModule\.forFeature\(\[FooEffects\]\)/);
});

it('should add an effect to the empty array of registered effects', () => {
const storeModule = '/src/app/store.module.ts';
const options = { ...defaultOptions, module: 'store.module.ts' };
appTree = createAppModuleWithEffects(
appTree,
storeModule,
'EffectsModule.forRoot([])'
);

const tree = schematicRunner.runSchematic('effect', options, appTree);
const content = getFileContent(tree, storeModule);

expect(content).toMatch(/EffectsModule\.forRoot\(\[FooEffects\]\)/);
});

it('should add an effect to the existing registered effects', () => {
const storeModule = '/src/app/store.module.ts';
const options = { ...defaultOptions, module: 'store.module.ts' };
appTree = createAppModuleWithEffects(
appTree,
storeModule,
'EffectsModule.forRoot([UserEffects])'
);

const tree = schematicRunner.runSchematic('effect', options, appTree);
const content = getFileContent(tree, '/src/app/store.module.ts');

expect(content).toMatch(
/EffectsModule\.forRoot\(\[UserEffects, FooEffects\]\)/
);
});

it('should not add an effect to registered effects defined with a variable', () => {
const storeModule = '/src/app/store.module.ts';
const options = { ...defaultOptions, module: 'store.module.ts' };
appTree = createAppModuleWithEffects(
appTree,
storeModule,
'EffectsModule.forRoot(effects)'
);

const tree = schematicRunner.runSchematic('effect', options, appTree);
const content = getFileContent(tree, '/src/app/store.module.ts');

expect(content).not.toMatch(/EffectsModule\.forRoot\(\[FooEffects\]\)/);
});
});
43 changes: 42 additions & 1 deletion modules/schematics/src/utility/ast-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -352,9 +352,50 @@ function _addSymbolToNgModuleMetadata(
return [];
}

node = node[node.length - 1];
const effectsModule = nodeArray.find(node =>
node.getText().includes('EffectsModule')
);

if (effectsModule && symbolName.includes('EffectsModule')) {
const effectsArgs = (effectsModule as ts.CallExpression).arguments.shift();

if (
effectsArgs &&
effectsArgs.kind === ts.SyntaxKind.ArrayLiteralExpression
) {
const effectsElements = (effectsArgs as ts.ArrayLiteralExpression)
.elements;
const [, effectsSymbol] = (<any>symbolName).match(/\[(.*)\]/);

let epos;
if (effectsElements.length === 0) {
epos = effectsArgs.getStart() + 1;
return [new InsertChange(ngModulePath, epos, effectsSymbol)];
} else {
const lastEffect = effectsElements[
effectsElements.length - 1
] as ts.Expression;
epos = lastEffect.getEnd();
// Get the indentation of the last element, if any.
const text: any = lastEffect.getFullText(source);

let effectInsert: string;
if (text.match('^\r?\r?\n')) {
effectInsert = `,${text.match(/^\r?\n\s+/)[0]}${effectsSymbol}`;
} else {
effectInsert = `, ${effectsSymbol}`;
}

return [new InsertChange(ngModulePath, epos, effectInsert)];
}
} else {
return [];
}
}
}

node = node[node.length - 1];

let toInsert: string;
let position = node.getEnd();
if (node.kind == ts.SyntaxKind.ObjectLiteralExpression) {
Expand Down
31 changes: 31 additions & 0 deletions modules/schematics/src/utility/test/create-app-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,34 @@ export function createAppModule(tree: Tree, path?: string): Tree {

return tree;
}

export function createAppModuleWithEffects(
tree: Tree,
path: string,
effects?: string
): Tree {
tree.create(
path || '/src/app/app.module.ts',
`
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { EffectsModule } from '@ngrx/effects';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
${effects}
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
`
);

return tree;
}

0 comments on commit f1082fe

Please sign in to comment.