diff --git a/e2e/schematics/application.test.ts b/e2e/schematics/application.test.ts index 52332ddf92..86ca80a3c1 100644 --- a/e2e/schematics/application.test.ts +++ b/e2e/schematics/application.test.ts @@ -43,4 +43,30 @@ describe('Nrwl Workspace', () => { }, 100000 ); + + it( + 'should support router config generation (lazy)', + () => { + ngNew('--collection=@nrwl/schematics --npmScope=nrwl'); + copyMissingPackages(); + newApp('myapp --routing'); + newLib('mylib --ngmodule --routing --lazy --parentModule=apps/myapp/src/app/app.module.ts'); + + runCLI('build --aot'); + }, + 100000 + ); + + it( + 'should support router config generation (eager)', + () => { + ngNew('--collection=@nrwl/schematics --npmScope=nrwl'); + copyMissingPackages(); + newApp('myapp --routing'); + newLib('mylib --ngmodule --routing --parentModule=apps/myapp/src/app/app.module.ts'); + + runCLI('build --aot'); + }, + 100000 + ); }); diff --git a/packages/schematics/src/app/index.ts b/packages/schematics/src/app/index.ts index 6ed262e0c5..99c5701a3f 100644 --- a/packages/schematics/src/app/index.ts +++ b/packages/schematics/src/app/index.ts @@ -82,6 +82,20 @@ function addAppToAngularCliJson(options: Schema): Rule { }; } +function addRouterRootConfiguration(path: string): Rule { + return (host: Tree) => { + const modulePath = `${path}/app/app.module.ts`; + const moduleSource = host.read(modulePath)!.toString('utf-8'); + const sourceFile = ts.createSourceFile(modulePath, moduleSource, ts.ScriptTarget.Latest, true); + insert(host, modulePath, [ + insertImport(sourceFile, modulePath, 'RouterModule', '@angular/router'), + ...addImportToModule(sourceFile, modulePath, `RouterModule.forRoot([], {initialNavigation: 'enabled'})`) + ]); + return host; + // add onSameUrlNavigation: 'reload' + }; +} + export default function(schema: Schema): Rule { const options = { ...schema, name: toFileName(schema.name) }; const templateSource = apply(url('./files'), [ @@ -95,7 +109,7 @@ export default function(schema: Schema): Rule { name: 'app', commonModule: false, flat: true, - routing: options.routing, + routing: false, sourceDir: fullPath(options), spec: false }), @@ -122,7 +136,8 @@ export default function(schema: Schema): Rule { ), addBootstrap(fullPath(options)), addNxModule(fullPath(options)), - addAppToAngularCliJson(options) + addAppToAngularCliJson(options), + options.routing ? addRouterRootConfiguration(fullPath(options)) : noop() ]); } diff --git a/packages/schematics/src/application/application.spec.ts b/packages/schematics/src/application/application.spec.ts index 08867ca7c9..7e5e5be3ad 100644 --- a/packages/schematics/src/application/application.spec.ts +++ b/packages/schematics/src/application/application.spec.ts @@ -49,6 +49,9 @@ describe('application', () => { it('should set right npmScope', () => { const tree = schematicRunner.runSchematic('application', { name: 'myApp', directory: 'my-app' }, appTree); + const angularCliJson = JSON.parse(getFileContent(tree, '/my-app/.angular-cli.json')); + expect(angularCliJson.project.npmScope).toEqual('myApp'); + const tsconfigJson = JSON.parse(getFileContent(tree, '/my-app/tsconfig.json')); expect(tsconfigJson.compilerOptions.paths).toEqual({ '@myApp/*': ['libs/*'] }); diff --git a/packages/schematics/src/application/files/__directory__/__dot__angular-cli.json b/packages/schematics/src/application/files/__directory__/__dot__angular-cli.json index b2d4b26631..c46dd64c50 100644 --- a/packages/schematics/src/application/files/__directory__/__dot__angular-cli.json +++ b/packages/schematics/src/application/files/__directory__/__dot__angular-cli.json @@ -1,7 +1,8 @@ { "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "project": { - "name": "<%= utils.dasherize(name) %>" + "name": "<%= utils.dasherize(name) %>", + "npmScope": "<%= npmScope %>" }, "apps": [], "e2e": { diff --git a/packages/schematics/src/lib/index.ts b/packages/schematics/src/lib/index.ts index ed75e57038..d1f618c91e 100644 --- a/packages/schematics/src/lib/index.ts +++ b/packages/schematics/src/lib/index.ts @@ -5,24 +5,23 @@ import { externalSchematic, mergeWith, move, + noop, Rule, template, Tree, url } from '@angular-devkit/schematics'; import { Schema } from './schema'; -import { names, toFileName } from '@nrwl/schematics'; +import { addImportToModule, insert, names, toClassName, toFileName, toPropertyName } from '@nrwl/schematics'; import * as path from 'path'; -import { serializeJson, addApp } from '../utility/fileutils'; +import { serializeJson, addApp, cliConfig } from '../utility/fileutils'; +import { insertImport } from '@schematics/angular/utility/route-utils'; +import * as ts from 'typescript'; +import { addGlobal, addReexport, addRoute } from '../utility/ast-utils'; function addLibToAngularCliJson(options: Schema): Rule { return (host: Tree) => { - if (!host.exists('.angular-cli.json')) { - throw new Error('Missing .angular-cli.json'); - } - - const sourceText = host.read('.angular-cli.json')!.toString('utf-8'); - const json = JSON.parse(sourceText); + const json = cliConfig(host); json.apps = addApp(json.apps, { name: options.name, root: fullPath(options), @@ -35,11 +34,116 @@ function addLibToAngularCliJson(options: Schema): Rule { }; } +function addLazyLoadedRouterConfiguration(modulePath: string): Rule { + return (host: Tree) => { + const moduleSource = host.read(modulePath)!.toString('utf-8'); + const sourceFile = ts.createSourceFile(modulePath, moduleSource, ts.ScriptTarget.Latest, true); + insert(host, modulePath, [ + insertImport(sourceFile, modulePath, 'RouterModule', '@angular/router'), + ...addImportToModule( + sourceFile, + modulePath, + ` + RouterModule.forChild([ + /* {path: '', pathMatch: 'full', component: InsertYourComponentHere} */ + ]) ` + ) + ]); + return host; + }; +} + +function addRouterConfiguration( + schema: Schema, + indexFilePath: string, + moduleFileName: string, + modulePath: string +): Rule { + return (host: Tree) => { + const indexSource = host.read(indexFilePath)!.toString('utf-8'); + const indexSourceFile = ts.createSourceFile(indexFilePath, indexSource, ts.ScriptTarget.Latest, true); + const moduleSource = host.read(modulePath)!.toString('utf-8'); + const moduleSourceFile = ts.createSourceFile(modulePath, moduleSource, ts.ScriptTarget.Latest, true); + const constName = `${toPropertyName(schema.name)}Routes`; + + insert(host, modulePath, [ + insertImport(moduleSourceFile, modulePath, 'RouterModule, Route', '@angular/router'), + ...addImportToModule(moduleSourceFile, modulePath, `RouterModule`), + ...addGlobal(moduleSourceFile, modulePath, `export const ${constName}: Route[] = [];`) + ]); + insert(host, indexFilePath, [...addReexport(indexSourceFile, indexFilePath, moduleFileName, constName)]); + return host; + }; +} + +function addLoadChildren(schema: Schema): Rule { + return (host: Tree) => { + const json = cliConfig(host); + + const moduleSource = host.read(schema.parentModule)!.toString('utf-8'); + const sourceFile = ts.createSourceFile(schema.parentModule, moduleSource, ts.ScriptTarget.Latest, true); + + const loadChildren = `@${json.project.npmScope}/${toFileName(schema.name)}#${toClassName(schema.name)}Module`; + insert(host, schema.parentModule, [ + ...addRoute( + schema.parentModule, + sourceFile, + `{path: '${toFileName(schema.name)}', loadChildren: '${loadChildren}'}` + ) + ]); + return host; + }; +} + +function addChildren(schema: Schema): Rule { + return (host: Tree) => { + const json = cliConfig(host); + + const moduleSource = host.read(schema.parentModule)!.toString('utf-8'); + const sourceFile = ts.createSourceFile(schema.parentModule, moduleSource, ts.ScriptTarget.Latest, true); + const constName = `${toPropertyName(schema.name)}Routes`; + const importPath = `@${json.project.npmScope}/${toFileName(schema.name)}`; + + insert(host, schema.parentModule, [ + insertImport(sourceFile, schema.parentModule, constName, importPath), + ...addRoute(schema.parentModule, sourceFile, `{path: '${toFileName(schema.name)}', children: ${constName}}`) + ]); + return host; + }; +} + +function updateTsLint(schema: Schema): Rule { + return (host: Tree) => { + const tsLint = JSON.parse(host.read('tslint.json')!.toString('utf-8')); + if ( + tsLint['rules'] && + tsLint['rules']['nx-enforce-module-boundaries'] && + tsLint['rules']['nx-enforce-module-boundaries'][1] && + tsLint['rules']['nx-enforce-module-boundaries'][1]['lazyLoad'] + ) { + tsLint['rules']['nx-enforce-module-boundaries'][1]['lazyLoad'].push(toFileName(schema.name)); + host.overwrite('tslint.json', serializeJson(tsLint)); + } + return host; + }; +} + export default function(schema: Schema): Rule { const options = { ...schema, name: toFileName(schema.name) }; const fullPath = path.join('libs', toFileName(options.name), options.sourceDir); + const moduleFileName = `${toFileName(schema.name)}.module`; + const modulePath = path.join(fullPath, `${moduleFileName}.ts`); + const indexFile = path.join('libs', toFileName(options.name), 'index.ts'); - const templateSource = apply(url(options.ngmodule ? './ngfiles' : './files'), [ + if (schema.routing && schema.nomodule) { + throw new Error(`nomodule and routing cannot be used together`); + } + + if (!schema.routing && schema.lazy) { + throw new Error(`routing must be set`); + } + + const templateSource = apply(url(options.nomodule ? './files' : './ngfiles'), [ template({ ...names(options.name), dot: '.', @@ -48,7 +152,16 @@ export default function(schema: Schema): Rule { }) ]); - return chain([branchAndMerge(chain([mergeWith(templateSource)])), addLibToAngularCliJson(options)]); + return chain([ + branchAndMerge(chain([mergeWith(templateSource)])), + addLibToAngularCliJson(options), + schema.routing && schema.lazy ? addLazyLoadedRouterConfiguration(modulePath) : noop(), + schema.routing && schema.lazy ? updateTsLint(schema) : noop(), + schema.routing && schema.lazy && schema.parentModule ? addLoadChildren(schema) : noop(), + + schema.routing && !schema.lazy ? addRouterConfiguration(schema, indexFile, moduleFileName, modulePath) : noop(), + schema.routing && !schema.lazy && schema.parentModule ? addChildren(schema) : noop() + ]); } function fullPath(options: Schema) { diff --git a/packages/schematics/src/lib/lib.spec.ts b/packages/schematics/src/lib/lib.spec.ts index 2619e6c6b8..cbc68b7698 100644 --- a/packages/schematics/src/lib/lib.spec.ts +++ b/packages/schematics/src/lib/lib.spec.ts @@ -1,7 +1,7 @@ import { SchematicTestRunner } from '@angular-devkit/schematics/testing'; import * as path from 'path'; import { Tree, VirtualTree } from '@angular-devkit/schematics'; -import { createEmptyWorkspace } from '../testing-utils'; +import { createApp, createEmptyWorkspace } from '../testing-utils'; import { getFileContent } from '@schematics/angular/utility/test'; describe('lib', () => { @@ -12,6 +12,8 @@ describe('lib', () => { beforeEach(() => { appTree = new VirtualTree(); appTree = createEmptyWorkspace(appTree); + + schematicRunner.logger.subscribe(s => console.log(s)); }); it('should update angular-cli.json', () => { @@ -28,18 +30,100 @@ describe('lib', () => { }); it('should generate files', () => { - const tree = schematicRunner.runSchematic('lib', { name: 'myLib' }, appTree); + const tree = schematicRunner.runSchematic('lib', { name: 'myLib', nomodule: true }, appTree); expect(tree.exists('libs/my-lib/src/my-lib.ts')).toBeTruthy(); expect(tree.exists('libs/my-lib/src/my-lib.spec.ts')).toBeTruthy(); expect(tree.exists('libs/my-lib/index.ts')).toBeTruthy(); expect(getFileContent(tree, 'libs/my-lib/src/my-lib.ts')).toContain('class MyLib'); }); - it('should generate files (--ngmodule)', () => { - const tree = schematicRunner.runSchematic('lib', { name: 'myLib', ngmodule: true }, appTree); + it('should generate files', () => { + const tree = schematicRunner.runSchematic('lib', { name: 'myLib' }, appTree); expect(tree.exists('libs/my-lib/src/my-lib.module.ts')).toBeTruthy(); expect(tree.exists('libs/my-lib/src/my-lib.module.spec.ts')).toBeTruthy(); expect(tree.exists('libs/my-lib/index.ts')).toBeTruthy(); expect(getFileContent(tree, 'libs/my-lib/src/my-lib.module.ts')).toContain('class MyLibModule'); }); + + describe('router', () => { + it('should error when routing is set with nomodule = true', () => { + expect(() => + schematicRunner.runSchematic('lib', { name: 'myLib', nomodule: true, routing: true }, appTree) + ).toThrow('nomodule and routing cannot be used together'); + }); + + it('should error when lazy is set without routing', () => { + expect(() => schematicRunner.runSchematic('lib', { name: 'myLib', lazy: true }, appTree)).toThrow( + 'routing must be set' + ); + }); + + describe('lazy', () => { + it('should add RouterModule.forChild', () => { + const tree = schematicRunner.runSchematic('lib', { name: 'myLib', routing: true, lazy: true }, appTree); + expect(tree.exists('libs/my-lib/src/my-lib.module.ts')).toBeTruthy(); + expect(getFileContent(tree, 'libs/my-lib/src/my-lib.module.ts')).toContain('RouterModule.forChild'); + }); + + it('should update the parent module', () => { + appTree = createApp(appTree, 'myapp'); + const tree = schematicRunner.runSchematic( + 'lib', + { name: 'myLib', routing: true, lazy: true, parentModule: 'apps/myapp/src/app/app.module.ts' }, + appTree + ); + expect(getFileContent(tree, 'apps/myapp/src/app/app.module.ts')).toContain( + `RouterModule.forRoot([{path: 'my-lib', loadChildren: '@proj/my-lib#MyLibModule'}])` + ); + + const tree2 = schematicRunner.runSchematic( + 'lib', + { name: 'myLib2', routing: true, lazy: true, parentModule: 'apps/myapp/src/app/app.module.ts' }, + tree + ); + expect(getFileContent(tree2, 'apps/myapp/src/app/app.module.ts')).toContain( + `RouterModule.forRoot([{path: 'my-lib', loadChildren: '@proj/my-lib#MyLibModule'}, {path: 'my-lib2', loadChildren: '@proj/my-lib2#MyLib2Module'}])` + ); + }); + + it('should register the module as lazy loaded in tslint.json', () => { + const tree = schematicRunner.runSchematic('lib', { name: 'myLib', routing: true, lazy: true }, appTree); + const tslint = JSON.parse(getFileContent(tree, 'tslint.json')); + expect(tslint['rules']['nx-enforce-module-boundaries'][1]['lazyLoad']).toEqual(['my-lib']); + }); + }); + + describe('eager', () => { + it('should add RouterModule and define an array of routes', () => { + const tree = schematicRunner.runSchematic('lib', { name: 'myLib', routing: true }, appTree); + expect(tree.exists('libs/my-lib/src/my-lib.module.ts')).toBeTruthy(); + expect(getFileContent(tree, 'libs/my-lib/src/my-lib.module.ts')).toContain('RouterModule]'); + expect(getFileContent(tree, 'libs/my-lib/src/my-lib.module.ts')).toContain('const myLibRoutes: Route[] = '); + expect(getFileContent(tree, 'libs/my-lib/index.ts')).toContain('myLibRoutes'); + }); + + it('should update the parent module', () => { + appTree = createApp(appTree, 'myapp'); + const tree = schematicRunner.runSchematic( + 'lib', + { name: 'myLib', routing: true, parentModule: 'apps/myapp/src/app/app.module.ts' }, + appTree + ); + expect(getFileContent(tree, 'apps/myapp/src/app/app.module.ts')).toContain( + `RouterModule.forRoot([{path: 'my-lib', children: myLibRoutes}])` + ); + + const tree2 = schematicRunner.runSchematic( + 'lib', + { name: 'myLib2', routing: true, parentModule: 'apps/myapp/src/app/app.module.ts' }, + tree + ); + expect(getFileContent(tree2, 'apps/myapp/src/app/app.module.ts')).toContain( + `RouterModule.forRoot([{path: 'my-lib', children: myLibRoutes}, {path: 'my-lib2', children: myLib2Routes}])` + ); + }); + }); + }); + + // should throw when no --ngmodule }); diff --git a/packages/schematics/src/lib/schema.d.ts b/packages/schematics/src/lib/schema.d.ts index 365132b53c..11cf317c67 100644 --- a/packages/schematics/src/lib/schema.d.ts +++ b/packages/schematics/src/lib/schema.d.ts @@ -1,10 +1,13 @@ export interface Schema { name: string; sourceDir?: string; - ngmodule: boolean; + nomodule: boolean; - routing?: boolean; spec?: boolean; flat?: boolean; commonModule?: boolean; + + routing?: boolean; + lazy?: boolean; + parentModule?: string; } diff --git a/packages/schematics/src/lib/schema.json b/packages/schematics/src/lib/schema.json index a21877aa56..75cef36f2e 100644 --- a/packages/schematics/src/lib/schema.json +++ b/packages/schematics/src/lib/schema.json @@ -13,9 +13,24 @@ "default": "src", "alias": "sd" }, - "ngmodule": { + "nomodule": { "type": "boolean", - "default": false + "default": false, + "description": "Generate a simple TS library when set to true." + }, + "routing": { + "type": "boolean", + "default": false, + "description": "Add router configuration. See lazy for more information." + }, + "lazy": { + "type": "boolean", + "default": false, + "description": "Add RouterModule.forChild when set to true, and a simple array of routes when set to false." + }, + "parentModule": { + "type": "string", + "description": "Update the router configuration of the parent module using loadChildren or children, depending on what `lazy` is set to." } }, "required": [ diff --git a/packages/schematics/src/testing-utils.ts b/packages/schematics/src/testing-utils.ts index f4228946b3..9b555b6d2e 100644 --- a/packages/schematics/src/testing-utils.ts +++ b/packages/schematics/src/testing-utils.ts @@ -3,6 +3,20 @@ import { Tree } from '@angular-devkit/schematics'; export function createEmptyWorkspace(tree: Tree): Tree { tree.create('/.angular-cli.json', JSON.stringify({})); tree.create('/package.json', JSON.stringify({})); + tree.create( + '/tslint.json', + JSON.stringify({ + rules: { + 'nx-enforce-module-boundaries': [ + true, + { + npmScope: '<%= npmScope %>', + lazyLoad: [] + } + ] + } + }) + ); return tree; } @@ -12,9 +26,10 @@ export function createApp(tree: Tree, appName: string): Tree { ` import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; + import { RouterModule } from '@angular/router'; import { AppComponent } from './app.component'; @NgModule({ - imports: [BrowserModule], + imports: [BrowserModule, RouterModule.forRoot([])], declarations: [AppComponent], bootstrap: [AppComponent] }) @@ -42,6 +57,10 @@ export function createApp(tree: Tree, appName: string): Tree { tree.overwrite( '/.angular-cli.json', JSON.stringify({ + project: { + name: 'proj', + npmScope: 'proj' + }, apps: [ { name: appName, diff --git a/packages/schematics/src/utility/ast-utils.ts b/packages/schematics/src/utility/ast-utils.ts index 0aed653ef0..93d78dd053 100644 --- a/packages/schematics/src/utility/ast-utils.ts +++ b/packages/schematics/src/utility/ast-utils.ts @@ -234,6 +234,25 @@ export function addImportToModule(source: ts.SourceFile, modulePath: string, sym return _addSymbolToNgModuleMetadata(source, modulePath, 'imports', symbolName); } +export function addReexport( + source: ts.SourceFile, + modulePath: string, + reexportedFileName: string, + token: string +): Change[] { + const allExports = findNodes(source, ts.SyntaxKind.ExportDeclaration); + if (allExports.length > 0) { + const m = allExports.filter( + (e: ts.ExportDeclaration) => e.moduleSpecifier.getText(source).indexOf(reexportedFileName) > -1 + ); + if (m.length > 0) { + const mm: ts.ExportDeclaration = m[0]; + return [new InsertChange(modulePath, mm.exportClause.end - 1, `, ${token} `)]; + } + } + return []; +} + export function getBootstrapComponent(source: ts.SourceFile, moduleClassName: string): string { const bootstrap = getMatchingProperty(source, 'bootstrap'); if (!bootstrap) { @@ -275,6 +294,39 @@ function getMatchingProperty(source: ts.SourceFile, property: string): ts.Object ); } +export function addRoute(ngModulePath: string, source: ts.SourceFile, route: string): Change[] { + const routes = getListOfRoutes(source); + if (!routes) return []; + + if (routes.hasTrailingComma || routes.length === 0) { + return [new InsertChange(ngModulePath, routes.end, route)]; + } else { + return [new InsertChange(ngModulePath, routes.end, `, ${route}`)]; + } +} + +function getListOfRoutes(source: ts.SourceFile): ts.NodeArray { + const imports: any = getMatchingProperty(source, 'imports'); + + if (imports.initializer.kind === ts.SyntaxKind.ArrayLiteralExpression) { + const a = imports.initializer as ts.ArrayLiteralExpression; + + for (let e of a.elements) { + if (e.kind === 181) { + const ee = e as ts.CallExpression; + const text = ee.expression.getText(source); + if ((text === 'RouterModule.forRoot' || text === 'RouterModule.forChild') && ee.arguments.length > 0) { + const routes = ee.arguments[0]; + if (routes.kind === ts.SyntaxKind.ArrayLiteralExpression) { + return (routes as ts.ArrayLiteralExpression).elements; + } + } + } + } + } + return null; +} + export function getImport( source: ts.SourceFile, predicate: (a: any) => boolean @@ -306,6 +358,16 @@ export function addEntryComponents(source: ts.SourceFile, modulePath: string, sy return _addSymbolToNgModuleMetadata(source, modulePath, 'entryComponents', symbolName); } +export function addGlobal(source: ts.SourceFile, modulePath: string, statement: string): Change[] { + const allImports = findNodes(source, ts.SyntaxKind.ImportDeclaration); + if (allImports.length > 0) { + const lastImport = allImports[allImports.length - 1]; + return [new InsertChange(modulePath, lastImport.end + 1, `\n${statement}\n`)]; + } else { + return [new InsertChange(modulePath, 0, `${statement}\n`)]; + } +} + export function insert(host: Tree, modulePath: string, changes: Change[]) { const recorder = host.beginUpdate(modulePath); for (const change of changes) { diff --git a/packages/schematics/src/utility/fileutils.ts b/packages/schematics/src/utility/fileutils.ts index 7225298d3e..0c795e92ca 100644 --- a/packages/schematics/src/utility/fileutils.ts +++ b/packages/schematics/src/utility/fileutils.ts @@ -1,4 +1,5 @@ import * as fs from 'fs'; +import { Tree } from '@angular-devkit/schematics'; export function updateJsonFile(path: string, callback: (a: any) => any) { const json = JSON.parse(fs.readFileSync(path, 'utf-8')); @@ -25,3 +26,12 @@ export function addApp(apps: any[] | undefined, newApp: any): any[] { export function serializeJson(json: any): string { return `${JSON.stringify(json, null, 2)}\n`; } + +export function cliConfig(host: Tree): any { + if (!host.exists('.angular-cli.json')) { + throw new Error('Missing .angular-cli.json'); + } + + const sourceText = host.read('.angular-cli.json')!.toString('utf-8'); + return JSON.parse(sourceText); +} diff --git a/packages/schematics/src/workspace/index.ts b/packages/schematics/src/workspace/index.ts index 5fd2f4fb51..2fff592a85 100644 --- a/packages/schematics/src/workspace/index.ts +++ b/packages/schematics/src/workspace/index.ts @@ -70,6 +70,8 @@ function updateAngularCLIJson(options: Schema) { throw new Error('Cannot find .angular-cli.json'); } const angularCliJson = JSON.parse(host.read('.angular-cli.json')!.toString('utf-8')); + angularCliJson.project.npmScope = npmScope(options); + if (angularCliJson.apps.length !== 1) { throw new Error('Can only convert projects with one app'); } @@ -105,15 +107,13 @@ function updateAngularCLIJson(options: Schema) { function updateTsConfigsJson(options: Schema) { return (host: Tree) => { - const npmScope = options && options.npmScope ? options.npmScope : options.name; - - updateJsonFile('tsconfig.json', json => setUpCompilerOptions(json, npmScope)); + updateJsonFile('tsconfig.json', json => setUpCompilerOptions(json, npmScope(options))); updateJsonFile('tsconfig.app.json', json => { json['extends'] = './tsconfig.json'; if (!json.exclude) json.exclude = []; json.exclude = dedup(json.exclude.concat(['**/*.spec.ts', '**/*.e2e-spec.ts', 'node_modules', 'tmp'])); - setUpCompilerOptions(json, npmScope); + setUpCompilerOptions(json, npmScope(options)); }); updateJsonFile('tsconfig.spec.json', json => { @@ -121,14 +121,14 @@ function updateTsConfigsJson(options: Schema) { if (!json.exclude) json.exclude = []; json.files = ['test.js']; json.exclude = dedup(json.exclude.concat(['node_modules', 'tmp'])); - setUpCompilerOptions(json, npmScope); + setUpCompilerOptions(json, npmScope(options)); }); updateJsonFile('tsconfig.e2e.json', json => { json['extends'] = './tsconfig.json'; if (!json.exclude) json.exclude = []; json.exclude = dedup(json.exclude.concat(['**/*.spec.ts', 'node_modules', 'tmp'])); - setUpCompilerOptions(json, npmScope); + setUpCompilerOptions(json, npmScope(options)); }); return host; @@ -137,18 +137,20 @@ function updateTsConfigsJson(options: Schema) { function updateTsLintJson(options: Schema) { return (host: Tree) => { - const npmScope = options && options.npmScope ? options.npmScope : options.name; - updateJsonFile('tslint.json', json => { ['no-trailing-whitespace', 'one-line', 'quotemark', 'typedef-whitespace', 'whitespace'].forEach(key => { json[key] = undefined; }); - json['nx-enforce-module-boundaries'] = [true, { npmScope: npmScope, lazyLoad: [] }]; + json['nx-enforce-module-boundaries'] = [true, { npmScope: npmScope(options), lazyLoad: [] }]; }); return host; }; } +function npmScope(options: Schema): string { + return options && options.npmScope ? options.npmScope : options.name; +} + function updateProtractorConf() { return (host: Tree) => { if (!host.exists('protractor.conf.js')) {