diff --git a/packages/schematics/angular/component/index.ts b/packages/schematics/angular/component/index.ts index 00b9e75cc6..efa53995ab 100644 --- a/packages/schematics/angular/component/index.ts +++ b/packages/schematics/angular/component/index.ts @@ -22,7 +22,11 @@ import { url, } from '@angular-devkit/schematics'; import * as ts from 'typescript'; -import { addDeclarationToModule, addExportToModule } from '../utility/ast-utils'; +import { + addDeclarationToModule, + addEntryComponentToModule, + addExportToModule, +} from '../utility/ast-utils'; import { InsertChange } from '../utility/change'; import { getWorkspace } from '../utility/config'; import { buildRelativePath, findModuleFromOptions } from '../utility/find-module'; @@ -30,6 +34,15 @@ import { parseName } from '../utility/parse-name'; import { validateHtmlSelector, validateName } from '../utility/validation'; import { Schema as ComponentOptions } from './schema'; +function readIntoSourceFile(host: Tree, modulePath: string): ts.SourceFile { + const text = host.read(modulePath); + if (text === null) { + throw new SchematicsException(`File ${modulePath} does not exist.`); + } + const sourceText = text.toString('utf-8'); + + return ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true); +} function addDeclarationToNgModule(options: ComponentOptions): Rule { return (host: Tree) => { @@ -38,12 +51,7 @@ function addDeclarationToNgModule(options: ComponentOptions): Rule { } const modulePath = options.module; - const text = host.read(modulePath); - if (text === null) { - throw new SchematicsException(`File ${modulePath} does not exist.`); - } - const sourceText = text.toString('utf-8'); - const source = ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true); + const source = readIntoSourceFile(host, modulePath); const componentPath = `/${options.path}/` + (options.flat ? '' : strings.dasherize(options.name) + '/') @@ -66,12 +74,7 @@ function addDeclarationToNgModule(options: ComponentOptions): Rule { if (options.export) { // Need to refresh the AST because we overwrote the file in the host. - const text = host.read(modulePath); - if (text === null) { - throw new SchematicsException(`File ${modulePath} does not exist.`); - } - const sourceText = text.toString('utf-8'); - const source = ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true); + const source = readIntoSourceFile(host, modulePath); const exportRecorder = host.beginUpdate(modulePath); const exportChanges = addExportToModule(source, modulePath, @@ -86,6 +89,24 @@ function addDeclarationToNgModule(options: ComponentOptions): Rule { host.commitUpdate(exportRecorder); } + if (options.entryComponent) { + // Need to refresh the AST because we overwrote the file in the host. + const source = readIntoSourceFile(host, modulePath); + + const entryComponentRecorder = host.beginUpdate(modulePath); + const entryComponentChanges = addEntryComponentToModule( + source, modulePath, + strings.classify(`${options.name}Component`), + relativePath); + + for (const change of entryComponentChanges) { + if (change instanceof InsertChange) { + entryComponentRecorder.insertLeft(change.pos, change.toAdd); + } + } + host.commitUpdate(entryComponentRecorder); + } + return host; }; diff --git a/packages/schematics/angular/component/index_spec.ts b/packages/schematics/angular/component/index_spec.ts index eb7ce900a7..90fd99db8b 100644 --- a/packages/schematics/angular/component/index_spec.ts +++ b/packages/schematics/angular/component/index_spec.ts @@ -135,6 +135,14 @@ describe('Component Schematic', () => { expect(appModuleContent).toMatch(/exports: \[FooComponent\]/); }); + it('should set the entry component', () => { + const options = { ...defaultOptions, entryComponent: true }; + + const tree = schematicRunner.runSchematic('component', options, appTree); + const appModuleContent = tree.readContent('/projects/bar/src/app/app.module.ts'); + expect(appModuleContent).toMatch(/entryComponents: \[FooComponent\]/); + }); + it('should import into a specified module', () => { const options = { ...defaultOptions, module: 'app.module.ts' }; diff --git a/packages/schematics/angular/component/schema.d.ts b/packages/schematics/angular/component/schema.d.ts index 81c02e4ab5..cc7b8cd518 100644 --- a/packages/schematics/angular/component/schema.d.ts +++ b/packages/schematics/angular/component/schema.d.ts @@ -67,4 +67,8 @@ export interface Schema { * Specifies if declaring module exports the component. */ export?: boolean; + /** + * Specifies if the component is an entry component of declaring module. + */ + entryComponent?: boolean; } diff --git a/packages/schematics/angular/component/schema.json b/packages/schematics/angular/component/schema.json index 72c180782f..b626626941 100644 --- a/packages/schematics/angular/component/schema.json +++ b/packages/schematics/angular/component/schema.json @@ -98,6 +98,11 @@ "type": "boolean", "default": false, "description": "Specifies if declaring module exports the component." + }, + "entryComponent": { + "type": "boolean", + "default": false, + "description": "Specifies if the component is an entry component of declaring module." } }, "required": [] diff --git a/packages/schematics/angular/utility/ast-utils.ts b/packages/schematics/angular/utility/ast-utils.ts index 99640ce86a..d584ae9801 100644 --- a/packages/schematics/angular/utility/ast-utils.ts +++ b/packages/schematics/angular/utility/ast-utils.ts @@ -531,6 +531,18 @@ export function addBootstrapToModule(source: ts.SourceFile, return addSymbolToNgModuleMetadata(source, modulePath, 'bootstrap', classifiedName, importPath); } +/** + * Custom function to insert an entryComponent into NgModule. It also imports it. + */ +export function addEntryComponentToModule(source: ts.SourceFile, + modulePath: string, classifiedName: string, + importPath: string): Change[] { + return addSymbolToNgModuleMetadata( + source, modulePath, + 'entryComponents', classifiedName, importPath, + ); +} + /** * Determine if an import already exists. */