Skip to content
This repository was archived by the owner on Apr 4, 2025. It is now read-only.

Support entry component #936

Merged
merged 2 commits into from
May 21, 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
47 changes: 34 additions & 13 deletions packages/schematics/angular/component/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,27 @@ 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';
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) => {
Expand All @@ -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) + '/')
Expand All @@ -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,
Expand All @@ -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;
};
Expand Down
8 changes: 8 additions & 0 deletions packages/schematics/angular/component/index_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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' };

Expand Down
4 changes: 4 additions & 0 deletions packages/schematics/angular/component/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
5 changes: 5 additions & 0 deletions packages/schematics/angular/component/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": []
Expand Down
12 changes: 12 additions & 0 deletions packages/schematics/angular/utility/ast-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down