Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Schematics): Add effect to registered effects array #717

Merged
merged 1 commit into from
Jan 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}