diff --git a/packages/schematics/angular/utility/ast-utils.ts b/packages/schematics/angular/utility/ast-utils.ts index 96479d02e964..2442f0661793 100644 --- a/packages/schematics/angular/utility/ast-utils.ts +++ b/packages/schematics/angular/utility/ast-utils.ts @@ -395,7 +395,7 @@ export function addSymbolToNgModuleMetadata( // Get the indentation of the last element, if any. const text = node.getFullText(source); const matches = text.match(/^\r?\n\s*/); - if (matches.length > 0) { + if (matches && matches.length > 0) { toInsert = `,${matches[0]}${metadataField}: [${symbolName}]`; } else { toInsert = `, ${metadataField}: [${symbolName}]`; diff --git a/packages/schematics/angular/utility/ast-utils_spec.ts b/packages/schematics/angular/utility/ast-utils_spec.ts index 1ea30a5126a5..bd694b6499a3 100644 --- a/packages/schematics/angular/utility/ast-utils_spec.ts +++ b/packages/schematics/angular/utility/ast-utils_spec.ts @@ -151,4 +151,19 @@ describe('ast utils', () => { const output = applyChanges(modulePath, moduleContent, changes || []); expect(output).toMatch(/imports: \[HelloWorld],\r?\n/m); }); + + it('should handle NgModule with no newlines', () => { + const moduleContent = ` + import { BrowserModule } from '@angular/platform-browser'; + import { NgModule } from '@angular/core'; + + @NgModule({imports: [BrowserModule], declarations: []}) + export class AppModule { } + `; + const source = getTsSource(modulePath, moduleContent); + const changes = addExportToModule(source, modulePath, 'FooComponent', './foo.component'); + const output = applyChanges(modulePath, moduleContent, changes); + expect(output).toMatch(/import { FooComponent } from '.\/foo.component';/); + expect(output).toMatch(/exports: \[FooComponent\]/); + }); }); diff --git a/packages/schematics/angular/utility/find-module.ts b/packages/schematics/angular/utility/find-module.ts index f1485c2aefb2..32eb6645d86a 100644 --- a/packages/schematics/angular/utility/find-module.ts +++ b/packages/schematics/angular/utility/find-module.ts @@ -25,6 +25,7 @@ export interface ModuleOptions { skipImport?: boolean; moduleExt?: string; routingModuleExt?: string; + nameFormatter?: (str: string) => string; } const MODULE_EXT = '.module.ts'; @@ -42,8 +43,9 @@ export function findModuleFromOptions(host: Tree, options: ModuleOptions): Path const routingModuleExt = options.routingModuleExt || ROUTING_MODULE_EXT; if (!options.module) { + options.nameFormatter = options.nameFormatter || strings.dasherize; const pathToCheck = (options.path || '') - + (options.flat ? '' : '/' + strings.dasherize(options.name)); + + (options.flat ? '' : '/' + options.nameFormatter(options.name)); return normalize(findModule(host, pathToCheck, moduleExt, routingModuleExt)); } else { diff --git a/packages/schematics/angular/utility/find-module_spec.ts b/packages/schematics/angular/utility/find-module_spec.ts index babbdcbdb6a3..70e1034445d4 100644 --- a/packages/schematics/angular/utility/find-module_spec.ts +++ b/packages/schematics/angular/utility/find-module_spec.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import { Path } from '@angular-devkit/core'; +import { Path, strings } from '@angular-devkit/core'; import { EmptyTree, Tree } from '@angular-devkit/schematics'; import { ModuleOptions, findModule, findModuleFromOptions } from './find-module'; @@ -111,6 +111,14 @@ describe('find-module', () => { expect(modPath).toEqual('/projects/my-proj/src/app.module.ts' as Path); }); + it('should find a module if nameFormatter is provided', () => { + tree.create('/projects/my-proj/src/app_test.module.ts', ''); + options.path = '/projects/my-proj/src'; + options.nameFormatter = strings.underscore; + const modPath = findModuleFromOptions(tree, options); + expect(modPath).toEqual('/projects/my-proj/src/app_test.module.ts' as Path); + }); + it('should find a module in a sub dir', () => { tree.create('/projects/my-proj/src/admin/foo.module.ts', ''); options.name = 'other/test';