From 4473539c2cfc26eed14a103e68e286478b96d2f0 Mon Sep 17 00:00:00 2001 From: Hsuan Lee Date: Sat, 29 Jun 2019 11:50:32 +0800 Subject: [PATCH] feat(schematics): add template option in `ng-add` (#3674) --- docs/schematics.en-US.md | 57 ++----------- docs/schematics.zh-CN.md | 80 +------------------ schematics/collection.json | 16 +++- schematics/ng-add/index.ts | 5 +- schematics/ng-add/schema.json | 18 +++-- schematics/ng-add/schema.ts | 9 ++- .../ng-generate/{boot-page => blank}/index.ts | 0 .../{boot-page => blank}/schema.json | 0 .../{boot-page => blank}/schema.ts | 0 .../src/app/app-routing.module.ts.template | 13 +++ .../src/app/app.component.__style__.template | 80 +++++++++++++++++++ .../files/src/app/app.component.html.template | 54 +++++++++++++ .../files/src/app/app.component.ts.template | 10 +++ .../src/app/icons-provider.module.ts.template | 19 +++++ .../welcome.component.__style__.template | 0 .../welcome/welcome.component.html.template | 0 .../welcome/welcome.component.ts.template | 15 ++++ .../pages/welcome/welcome.module.ts.template | 8 ++ schematics/ng-generate/side-menu/index.ts | 53 ++++++++++++ schematics/ng-generate/side-menu/schema.json | 33 ++++++++ schematics/ng-generate/side-menu/schema.ts | 7 ++ .../src/app/app-routing.module.ts.template | 13 +++ .../src/app/app.component.__style__.template | 46 +++++++++++ .../files/src/app/app.component.html.template | 20 +++++ .../files/src/app/app.component.ts.template | 10 +++ .../welcome.component.__style__.template | 0 .../welcome/welcome.component.html.template | 1 + .../welcome/welcome.component.ts.template | 15 ++++ .../pages/welcome/welcome.module.ts.template | 8 ++ schematics/ng-generate/topnav/index.ts | 52 ++++++++++++ schematics/ng-generate/topnav/schema.json | 34 ++++++++ schematics/ng-generate/topnav/schema.ts | 7 ++ schematics/tsconfig.json | 3 +- schematics/utils/root-module.ts | 48 +++++++++++ scripts/schematics/copy-resources.js | 2 +- 35 files changed, 596 insertions(+), 140 deletions(-) rename schematics/ng-generate/{boot-page => blank}/index.ts (100%) rename schematics/ng-generate/{boot-page => blank}/schema.json (100%) rename schematics/ng-generate/{boot-page => blank}/schema.ts (100%) create mode 100644 schematics/ng-generate/side-menu/files/src/app/app-routing.module.ts.template create mode 100644 schematics/ng-generate/side-menu/files/src/app/app.component.__style__.template create mode 100644 schematics/ng-generate/side-menu/files/src/app/app.component.html.template create mode 100644 schematics/ng-generate/side-menu/files/src/app/app.component.ts.template create mode 100644 schematics/ng-generate/side-menu/files/src/app/icons-provider.module.ts.template create mode 100644 schematics/ng-generate/side-menu/files/src/app/pages/welcome/welcome.component.__style__.template create mode 100644 schematics/ng-generate/side-menu/files/src/app/pages/welcome/welcome.component.html.template create mode 100644 schematics/ng-generate/side-menu/files/src/app/pages/welcome/welcome.component.ts.template create mode 100644 schematics/ng-generate/side-menu/files/src/app/pages/welcome/welcome.module.ts.template create mode 100644 schematics/ng-generate/side-menu/index.ts create mode 100644 schematics/ng-generate/side-menu/schema.json create mode 100644 schematics/ng-generate/side-menu/schema.ts create mode 100644 schematics/ng-generate/topnav/files/src/app/app-routing.module.ts.template create mode 100644 schematics/ng-generate/topnav/files/src/app/app.component.__style__.template create mode 100644 schematics/ng-generate/topnav/files/src/app/app.component.html.template create mode 100644 schematics/ng-generate/topnav/files/src/app/app.component.ts.template create mode 100644 schematics/ng-generate/topnav/files/src/app/pages/welcome/welcome.component.__style__.template create mode 100644 schematics/ng-generate/topnav/files/src/app/pages/welcome/welcome.component.html.template create mode 100644 schematics/ng-generate/topnav/files/src/app/pages/welcome/welcome.component.ts.template create mode 100644 schematics/ng-generate/topnav/files/src/app/pages/welcome/welcome.module.ts.template create mode 100644 schematics/ng-generate/topnav/index.ts create mode 100644 schematics/ng-generate/topnav/schema.json create mode 100644 schematics/ng-generate/topnav/schema.ts create mode 100644 schematics/utils/root-module.ts diff --git a/docs/schematics.en-US.md b/docs/schematics.en-US.md index 30557180c5..473801eaf5 100644 --- a/docs/schematics.en-US.md +++ b/docs/schematics.en-US.md @@ -8,6 +8,12 @@ title: Schematics Init project with `ng-zorro-antd`. +Run `ng add ng-zorro-antd` in your project directory, and follow the options to configure. + + + +You can choose a preset template to create your project, then develop on this basis code. + ### Command ```bash @@ -51,54 +57,3 @@ For example, you can generate an login form with the follow command. ```bash ng g ng-zorro-antd:form-normal-login login ``` - -### Options - -***--entry-component*** - -Specifies if the component is an entry component of declaring module. - -***--export*** - -Specifies if declaring module exports the component. - -***--flat*** - -Flag to indicate if a dir is created. - -***--inline-style (-s)*** - -Specifies if the style will be in the ts file. - -***--inline-template (-t)*** - -Specifies if the template will be in the ts file. - -***--module (-m)*** - -Allows specification of the declaring module. - -***--prefix (-p)*** - -The prefix to apply to generated selectors. - -***--project*** - -The name of the project. - -***--selector*** - -The selector to use for the component. - -***--skip-import*** - -Flag to skip the module import. - -***--spec*** - -Specifies if a spec file is generated. - -***--styleext*** - -The file extension to be used for style files. - diff --git a/docs/schematics.zh-CN.md b/docs/schematics.zh-CN.md index 465b9290a3..a16f8fbe34 100644 --- a/docs/schematics.zh-CN.md +++ b/docs/schematics.zh-CN.md @@ -7,35 +7,13 @@ title: 脚手架 ## 项目初始化 -自动完成 `ng-zorro-antd` 的初始化配置,包括引入国际化文件,导入模块,引入样式文件等工作。 +在项目下运行命令 `ng add ng-zorro-antd` 跟随选项便可完成初始化配置,包括引入国际化文件,导入模块,引入样式文件等工作。 -### 命令 - -```bash -ng add ng-zorro-antd [options] -``` - -### 参数 - -***--theme*** - -`ng-zorro-antd` 会在 `src` 目录下生成 `theme.less` 的主题配置文件 - -详细的配置可以在[自定义主题](/docs/customize-theme/zh)中查看。 - -***--locale*** - -初始化配置时增加 `--locale=[语言]` 参数,`ng-zorro-antd` 会自动引入支持的语言包以及 Angular 对应的 [i18n 文件](https://angular.io/guide/i18n) + -默认的国际化配置为中文(zh_CN),详细的可配置选项可以在[国际化](/docs/i18n/zh)中查看。 +同时你可以通过选择预设的模板创建一个 Angular 项目,并在此基础上进行开发。 -***--animations*** - -启用 `BrowserAnimationsModule` - -***--gestures*** - -安装 `hammerjs` 并引入为项目添加手势支持 + ## 生成组件 @@ -52,53 +30,3 @@ ng g ng-zorro-antd:[schematic] [options] ```bash ng g ng-zorro-antd:form-normal-login login ``` - -### 参数 - -***--entry-component*** - -组件是否在模块的 `entryComponents` 声明 - -***--export*** - -组件是否在模块的 `exports` 声明 - -***--flat*** - -指定是否创建目录 - -***--inline-style (-s)*** - -指定是否使用行内样式 - -***--inline-template (-t)*** - -指定是否使用行内模版 - -***--module (-m)*** - -指定声明的模块 - -***--prefix (-p)*** - -组件选择器前缀 - -***--project*** - -指定声明到的项目名 - -***--selector*** - -组件的选择器名称 - -***--skip-import*** - -指定是否跳过模块引入 - -***--spec*** - -指定是否生成 `.spec` 测试文件 - -***--styleext*** - -指定样式文件扩展名 diff --git a/schematics/collection.json b/schematics/collection.json index 647f0d59d9..90fdcfd914 100644 --- a/schematics/collection.json +++ b/schematics/collection.json @@ -12,11 +12,21 @@ "factory": "./ng-add/setup-project/index", "schema": "./ng-add/schema.json" }, - "boot-page": { + "blank": { "description": "Set up boot page", "private": true, - "factory": "./ng-generate/boot-page/index", - "schema": "./ng-generate/boot-page/schema.json" + "factory": "./ng-generate/blank/index", + "schema": "./ng-generate/blank/schema.json" + }, + "sidemenu": { + "description": "Add Sidebar Navigation Layout in your project.", + "factory": "./ng-generate/side-menu/index", + "schema": "./ng-generate/side-menu/schema.json" + }, + "topnav": { + "description": "Add Top Navigation Layout in your project.", + "factory": "./ng-generate/topnav/index", + "schema": "./ng-generate/topnav/schema.json" }, "add-icon-assets": { "description": "Add icon assets into CLI config", diff --git a/schematics/ng-add/index.ts b/schematics/ng-add/index.ts index 38220ba8b8..5f5871ca52 100644 --- a/schematics/ng-add/index.ts +++ b/schematics/ng-add/index.ts @@ -17,8 +17,9 @@ export default function(options: Schema): Rule { context.addTask(new RunSchematicTask('ng-add-setup-project', options), [installTaskId]); - if (options.bootPage) { - context.addTask(new RunSchematicTask('boot-page', options)); + if (options.template) { + context.addTask(new RunSchematicTask(options.template, options)); } + }; } diff --git a/schematics/ng-add/schema.json b/schematics/ng-add/schema.json index e50b80035d..249ab1cbcb 100644 --- a/schematics/ng-add/schema.json +++ b/schematics/ng-add/schema.json @@ -16,11 +16,6 @@ "default": false, "description": "Do not add ng-zorro-antd dependencies to package.json (e.g., --skipPackageJson)" }, - "bootPage": { - "type": "boolean", - "default": true, - "description": "Set up boot page." - }, "dynamicIcon": { "type": "boolean", "default": false, @@ -120,6 +115,19 @@ ] } }, + "template": { + "type": "string", + "default": "blank", + "description": "Create an Angular project with using preset template.", + "x-prompt": { + "message": "Choose template to create project:", + "type": "list", + "items": [ + "blank", + "sidemenu" + ] + } + }, "gestures": { "type": "boolean", "default": false, diff --git a/schematics/ng-add/schema.ts b/schematics/ng-add/schema.ts index 60866a76b5..e4afe720e8 100644 --- a/schematics/ng-add/schema.ts +++ b/schematics/ng-add/schema.ts @@ -35,8 +35,14 @@ export type Locale = | 'zh_CN' | 'zh_TW'; +export enum ProjectTemplate { + Blank = 'blank', + Sidemenu = 'sidemenu', + Topnav = 'topnav', + None = 'none' +} + export interface Schema { - bootPage?: boolean; /** Name of the project to target. */ project?: string; /** Whether to skip package.json install. */ @@ -47,4 +53,5 @@ export interface Schema { animations?: boolean; locale?: Locale; i18n?: Locale; + template?: ProjectTemplate; } diff --git a/schematics/ng-generate/boot-page/index.ts b/schematics/ng-generate/blank/index.ts similarity index 100% rename from schematics/ng-generate/boot-page/index.ts rename to schematics/ng-generate/blank/index.ts diff --git a/schematics/ng-generate/boot-page/schema.json b/schematics/ng-generate/blank/schema.json similarity index 100% rename from schematics/ng-generate/boot-page/schema.json rename to schematics/ng-generate/blank/schema.json diff --git a/schematics/ng-generate/boot-page/schema.ts b/schematics/ng-generate/blank/schema.ts similarity index 100% rename from schematics/ng-generate/boot-page/schema.ts rename to schematics/ng-generate/blank/schema.ts diff --git a/schematics/ng-generate/side-menu/files/src/app/app-routing.module.ts.template b/schematics/ng-generate/side-menu/files/src/app/app-routing.module.ts.template new file mode 100644 index 0000000000..29be260602 --- /dev/null +++ b/schematics/ng-generate/side-menu/files/src/app/app-routing.module.ts.template @@ -0,0 +1,13 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; + +const routes: Routes = [ + { path: '', pathMatch: 'full', redirectTo: '/welcome' }, + { path: 'welcome', loadChildren: () => import('./pages/welcome/welcome.module').then(m => m.WelcomeModule) } +]; + +@NgModule({ + imports: [RouterModule.forRoot(routes)], + exports: [RouterModule] +}) +export class AppRoutingModule { } diff --git a/schematics/ng-generate/side-menu/files/src/app/app.component.__style__.template b/schematics/ng-generate/side-menu/files/src/app/app.component.__style__.template new file mode 100644 index 0000000000..163c43a236 --- /dev/null +++ b/schematics/ng-generate/side-menu/files/src/app/app.component.__style__.template @@ -0,0 +1,80 @@ +:host { + display: flex; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.app-layout { + height: 100vh; +} + +.menu-sidebar { + position: relative; + z-index: 10; + min-height: 100vh; + box-shadow: 2px 0 6px rgba(0,21,41,.35); +} + +.header-trigger { + height: 64px; + padding: 20px 24px; + font-size: 20px; + cursor: pointer; + transition: all .3s,padding 0s; +} + +.trigger:hover { + color: #1890ff; +} + +.sidebar-logo { + position: relative; + height: 64px; + padding-left: 24px; + overflow: hidden; + line-height: 64px; + background: #001529; + transition: all .3s; +} + +.sidebar-logo img { + display: inline-block; + height: 32px; + width: 32px; + vertical-align: middle; +} + +.sidebar-logo h1 { + display: inline-block; + margin: 0 0 0 20px; + color: #fff; + font-weight: 600; + font-size: 14px; + font-family: Avenir,Helvetica Neue,Arial,Helvetica,sans-serif; + vertical-align: middle; +} + +nz-header { + padding: 0; + width: 100%; + z-index: 2; +} + +.app-header { + position: relative; + height: 64px; + padding: 0; + background: #fff; + box-shadow: 0 1px 4px rgba(0,21,41,.08); +} + +nz-content { + margin: 24px; +} + +.inner-content { + padding: 24px; + background: #fff; + height: 100%; +} diff --git a/schematics/ng-generate/side-menu/files/src/app/app.component.html.template b/schematics/ng-generate/side-menu/files/src/app/app.component.html.template new file mode 100644 index 0000000000..014c586efe --- /dev/null +++ b/schematics/ng-generate/side-menu/files/src/app/app.component.html.template @@ -0,0 +1,54 @@ + + + + + + + +
+ + + +
+
+ +
+ +
+
+
+
diff --git a/schematics/ng-generate/side-menu/files/src/app/app.component.ts.template b/schematics/ng-generate/side-menu/files/src/app/app.component.ts.template new file mode 100644 index 0000000000..98a4eedeee --- /dev/null +++ b/schematics/ng-generate/side-menu/files/src/app/app.component.ts.template @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: '<%= prefix %>-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.<%= style %>'] +}) +export class AppComponent { + isCollapsed = false; +} diff --git a/schematics/ng-generate/side-menu/files/src/app/icons-provider.module.ts.template b/schematics/ng-generate/side-menu/files/src/app/icons-provider.module.ts.template new file mode 100644 index 0000000000..d48bbb024c --- /dev/null +++ b/schematics/ng-generate/side-menu/files/src/app/icons-provider.module.ts.template @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { NZ_ICONS } from 'ng-zorro-antd'; + +import { + MenuFoldOutline, + MenuUnfoldOutline, + FormOutline, + DashboardOutline +} from '@ant-design/icons-angular/icons'; + +const icons = [MenuFoldOutline, MenuUnfoldOutline, DashboardOutline, FormOutline]; + +@NgModule({ + providers: [ + { provide: NZ_ICONS, useValue: icons } + ] +}) +export class IconsProviderModule { +} diff --git a/schematics/ng-generate/side-menu/files/src/app/pages/welcome/welcome.component.__style__.template b/schematics/ng-generate/side-menu/files/src/app/pages/welcome/welcome.component.__style__.template new file mode 100644 index 0000000000..e69de29bb2 diff --git a/schematics/ng-generate/side-menu/files/src/app/pages/welcome/welcome.component.html.template b/schematics/ng-generate/side-menu/files/src/app/pages/welcome/welcome.component.html.template new file mode 100644 index 0000000000..e69de29bb2 diff --git a/schematics/ng-generate/side-menu/files/src/app/pages/welcome/welcome.component.ts.template b/schematics/ng-generate/side-menu/files/src/app/pages/welcome/welcome.component.ts.template new file mode 100644 index 0000000000..d33f473ee9 --- /dev/null +++ b/schematics/ng-generate/side-menu/files/src/app/pages/welcome/welcome.component.ts.template @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: '<%= prefix %>-welcome', + templateUrl: './welcome.component.html', + styleUrls: ['./welcome.component.<%= style %>'] +}) +export class WelcomeComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/schematics/ng-generate/side-menu/files/src/app/pages/welcome/welcome.module.ts.template b/schematics/ng-generate/side-menu/files/src/app/pages/welcome/welcome.module.ts.template new file mode 100644 index 0000000000..95381f5bba --- /dev/null +++ b/schematics/ng-generate/side-menu/files/src/app/pages/welcome/welcome.module.ts.template @@ -0,0 +1,8 @@ +import { NgModule } from '@angular/core'; +import { WelcomeComponent } from './welcome.component'; + +@NgModule({ + declarations: [ WelcomeComponent ], + exports: [ WelcomeComponent ] +}) +export class WelcomeModule { } diff --git a/schematics/ng-generate/side-menu/index.ts b/schematics/ng-generate/side-menu/index.ts new file mode 100644 index 0000000000..5898c529c0 --- /dev/null +++ b/schematics/ng-generate/side-menu/index.ts @@ -0,0 +1,53 @@ +import { strings } from '@angular-devkit/core'; +import { + apply, + applyTemplates, + chain, + forEach, + mergeWith, + move, + url, + FileEntry, + MergeStrategy, + Rule, + Tree +} from '@angular-devkit/schematics'; +import { getProjectFromWorkspace } from '@angular/cdk/schematics'; +import { Style } from '@schematics/angular/application/schema'; +import { getWorkspace } from '@schematics/angular/utility/config'; +import { addModule } from '../../utils/root-module'; + +import { Schema } from './schema'; + +export default function(options: Schema): Rule { + return (host: Tree) => { + const workspace = getWorkspace(host); + const project = getProjectFromWorkspace(workspace, options.project); + const prefix = options.prefix || project.prefix; + const style = options.style || Style.Css; + return chain([ + mergeWith( + apply( + url('./files/src'), [ + applyTemplates({ + prefix, + style, + ...strings, + ...options + }), + move(project.sourceRoot as string), + forEach((fileEntry: FileEntry) => { + if (host.exists(fileEntry.path)) { + host.overwrite(fileEntry.path, fileEntry.content); + } + return fileEntry; + }) + ] + ), + MergeStrategy.Overwrite + ), + addModule('AppRoutingModule', './app-routing.module'), + addModule('IconsProviderModule', './icons-provider.module') + ]); + } +} diff --git a/schematics/ng-generate/side-menu/schema.json b/schematics/ng-generate/side-menu/schema.json new file mode 100644 index 0000000000..7d43d2c24a --- /dev/null +++ b/schematics/ng-generate/side-menu/schema.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/schema", + "id": "sidebar-nav", + "title": "Sidebar Navigation Layout", + "type": "object", + "properties": { + "project": { + "type": "string", + "description": "The name of the project.", + "$default": { + "$source": "projectName" + } + }, + "style": { + "description": "The file extension or preprocessor to use for style files.", + "type": "string", + "default": "css", + "enum": [ + "css", + "scss", + "sass", + "less" + ] + }, + "prefix": { + "type": "string", + "format": "html-selector", + "description": "A prefix to apply to generated selectors.", + "default": "app", + "alias": "p" + } + } +} diff --git a/schematics/ng-generate/side-menu/schema.ts b/schematics/ng-generate/side-menu/schema.ts new file mode 100644 index 0000000000..acb95d53a6 --- /dev/null +++ b/schematics/ng-generate/side-menu/schema.ts @@ -0,0 +1,7 @@ +import { Style } from '@schematics/angular/application/schema'; + +export interface Schema { + project: string; + style: Style; + prefix: string; +} diff --git a/schematics/ng-generate/topnav/files/src/app/app-routing.module.ts.template b/schematics/ng-generate/topnav/files/src/app/app-routing.module.ts.template new file mode 100644 index 0000000000..29be260602 --- /dev/null +++ b/schematics/ng-generate/topnav/files/src/app/app-routing.module.ts.template @@ -0,0 +1,13 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; + +const routes: Routes = [ + { path: '', pathMatch: 'full', redirectTo: '/welcome' }, + { path: 'welcome', loadChildren: () => import('./pages/welcome/welcome.module').then(m => m.WelcomeModule) } +]; + +@NgModule({ + imports: [RouterModule.forRoot(routes)], + exports: [RouterModule] +}) +export class AppRoutingModule { } diff --git a/schematics/ng-generate/topnav/files/src/app/app.component.__style__.template b/schematics/ng-generate/topnav/files/src/app/app.component.__style__.template new file mode 100644 index 0000000000..73a1c7eaf7 --- /dev/null +++ b/schematics/ng-generate/topnav/files/src/app/app.component.__style__.template @@ -0,0 +1,46 @@ +:host { + display: flex; +} + +.app-layout { + height: 100vh; +} + +.top-nav { + line-height: 64px; +} + +.logo { + float: left; + height: 64px; + padding-right: 24px; + line-height: 64px; + background: #001529; +} + +.logo img { + display: inline-block; + height: 32px; + width: 32px; + vertical-align: middle; +} + +.logo h1 { + display: inline-block; + margin: 0 0 0 15px; + color: #fff; + font-weight: 600; + font-size: 20px; + font-family: Avenir,Helvetica Neue,Arial,Helvetica,sans-serif; + vertical-align: middle; +} + +nz-content { + padding: 24px 50px; +} + +.inner-content { + padding: 24px; + background: #fff; + height: 100%; +} diff --git a/schematics/ng-generate/topnav/files/src/app/app.component.html.template b/schematics/ng-generate/topnav/files/src/app/app.component.html.template new file mode 100644 index 0000000000..47d5824ad4 --- /dev/null +++ b/schematics/ng-generate/topnav/files/src/app/app.component.html.template @@ -0,0 +1,20 @@ + + + +
    +
  • Home
  • +
  • Account
  • +
  • Profile
  • +
+
+ +
+ +
+
+
diff --git a/schematics/ng-generate/topnav/files/src/app/app.component.ts.template b/schematics/ng-generate/topnav/files/src/app/app.component.ts.template new file mode 100644 index 0000000000..2a4d2c9159 --- /dev/null +++ b/schematics/ng-generate/topnav/files/src/app/app.component.ts.template @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: '<%= prefix %>-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.<%= style %>'] +}) +export class AppComponent { + +} diff --git a/schematics/ng-generate/topnav/files/src/app/pages/welcome/welcome.component.__style__.template b/schematics/ng-generate/topnav/files/src/app/pages/welcome/welcome.component.__style__.template new file mode 100644 index 0000000000..e69de29bb2 diff --git a/schematics/ng-generate/topnav/files/src/app/pages/welcome/welcome.component.html.template b/schematics/ng-generate/topnav/files/src/app/pages/welcome/welcome.component.html.template new file mode 100644 index 0000000000..6b4f37e319 --- /dev/null +++ b/schematics/ng-generate/topnav/files/src/app/pages/welcome/welcome.component.html.template @@ -0,0 +1 @@ +

welcome works!

diff --git a/schematics/ng-generate/topnav/files/src/app/pages/welcome/welcome.component.ts.template b/schematics/ng-generate/topnav/files/src/app/pages/welcome/welcome.component.ts.template new file mode 100644 index 0000000000..d33f473ee9 --- /dev/null +++ b/schematics/ng-generate/topnav/files/src/app/pages/welcome/welcome.component.ts.template @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: '<%= prefix %>-welcome', + templateUrl: './welcome.component.html', + styleUrls: ['./welcome.component.<%= style %>'] +}) +export class WelcomeComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/schematics/ng-generate/topnav/files/src/app/pages/welcome/welcome.module.ts.template b/schematics/ng-generate/topnav/files/src/app/pages/welcome/welcome.module.ts.template new file mode 100644 index 0000000000..95381f5bba --- /dev/null +++ b/schematics/ng-generate/topnav/files/src/app/pages/welcome/welcome.module.ts.template @@ -0,0 +1,8 @@ +import { NgModule } from '@angular/core'; +import { WelcomeComponent } from './welcome.component'; + +@NgModule({ + declarations: [ WelcomeComponent ], + exports: [ WelcomeComponent ] +}) +export class WelcomeModule { } diff --git a/schematics/ng-generate/topnav/index.ts b/schematics/ng-generate/topnav/index.ts new file mode 100644 index 0000000000..7d4f5593c9 --- /dev/null +++ b/schematics/ng-generate/topnav/index.ts @@ -0,0 +1,52 @@ +import { strings } from '@angular-devkit/core'; +import { + apply, + applyTemplates, + chain, + forEach, + mergeWith, + move, + url, + FileEntry, + MergeStrategy, + Rule, + Tree +} from '@angular-devkit/schematics'; +import { getProjectFromWorkspace } from '@angular/cdk/schematics'; +import { Style } from '@schematics/angular/application/schema'; +import { getWorkspace } from '@schematics/angular/utility/config'; +import { addModule } from '../../utils/root-module'; + +import { Schema } from './schema'; + +export default function(options: Schema): Rule { + return (host: Tree) => { + const workspace = getWorkspace(host); + const project = getProjectFromWorkspace(workspace, options.project); + const prefix = options.prefix || project.prefix; + const style = options.style || Style.Css; + return chain([ + mergeWith( + apply( + url('./files/src'), [ + applyTemplates({ + prefix, + style, + ...strings, + ...options + }), + move(project.sourceRoot), + forEach((fileEntry: FileEntry) => { + if (host.exists(fileEntry.path)) { + host.overwrite(fileEntry.path, fileEntry.content); + } + return fileEntry; + }) + ] + ), + MergeStrategy.Overwrite + ), + addModule('AppRoutingModule', './app-routing.module') + ]); + } +} diff --git a/schematics/ng-generate/topnav/schema.json b/schematics/ng-generate/topnav/schema.json new file mode 100644 index 0000000000..caaa1d0eb8 --- /dev/null +++ b/schematics/ng-generate/topnav/schema.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json-schema.org/schema", + "id": "top-nav", + "title": "Top Navigation Layout", + "type": "object", + "properties": { + "project": { + "type": "string", + "description": "The name of the project.", + "$default": { + "$source": "projectName" + } + }, + "style": { + "description": "The file extension or preprocessor to use for style files.", + "type": "string", + "default": "css", + "enum": [ + "css", + "scss", + "sass", + "less", + "styl" + ] + }, + "prefix": { + "type": "string", + "format": "html-selector", + "description": "A prefix to apply to generated selectors.", + "default": "app", + "alias": "p" + } + } +} diff --git a/schematics/ng-generate/topnav/schema.ts b/schematics/ng-generate/topnav/schema.ts new file mode 100644 index 0000000000..acb95d53a6 --- /dev/null +++ b/schematics/ng-generate/topnav/schema.ts @@ -0,0 +1,7 @@ +import { Style } from '@schematics/angular/application/schema'; + +export interface Schema { + project: string; + style: Style; + prefix: string; +} diff --git a/schematics/tsconfig.json b/schematics/tsconfig.json index 9c0ac514c7..741929b999 100644 --- a/schematics/tsconfig.json +++ b/schematics/tsconfig.json @@ -20,6 +20,7 @@ "exclude": [ "**/*.component.ts", "**/*spec*", - "template/**/*" + "template/**/*", + "**/files/**/*" ] } \ No newline at end of file diff --git a/schematics/utils/root-module.ts b/schematics/utils/root-module.ts new file mode 100644 index 0000000000..d8deefc7f4 --- /dev/null +++ b/schematics/utils/root-module.ts @@ -0,0 +1,48 @@ +import { Rule, SchematicsException, Tree } from '@angular-devkit/schematics'; +import { addModuleImportToRootModule, getProjectFromWorkspace, getProjectMainFile } from '@angular/cdk/schematics'; +import { addDeclarationToModule } from '@schematics/angular/utility/ast-utils'; +import { InsertChange } from '@schematics/angular/utility/change'; +import { getWorkspace } from '@schematics/angular/utility/config'; +import { buildRelativePath } from '@schematics/angular/utility/find-module'; +import { getAppModulePath } from '@schematics/angular/utility/ng-ast-utils'; +import { ProjectType, WorkspaceProject } from '@schematics/angular/utility/workspace-models'; +import * as ts from 'typescript'; + +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); +} + +export function addModule(moduleName: string, modulePath: string): Rule { + return (host: Tree) => { + const workspace = getWorkspace(host); + const project = getProjectFromWorkspace(workspace) as WorkspaceProject; + addModuleImportToRootModule(host, moduleName, modulePath, project); + return host; + } +} + +export function addDeclaration(componentName: string, componentPath: string): Rule { + return (host: Tree) => { + const workspace = getWorkspace(host); + const project = getProjectFromWorkspace(workspace) as WorkspaceProject; + const appModulePath = getAppModulePath(host, getProjectMainFile(project)); + const source = readIntoSourceFile(host, appModulePath); + const relativePath = buildRelativePath(appModulePath, componentPath); + const declarationChanges = addDeclarationToModule(source, appModulePath, componentName, relativePath); + const declarationRecorder = host.beginUpdate(appModulePath); + for (const change of declarationChanges) { + if (change instanceof InsertChange) { + declarationRecorder.insertLeft(change.pos, change.toAdd); + } + } + host.commitUpdate(declarationRecorder); + + return host; + } +} diff --git a/scripts/schematics/copy-resources.js b/scripts/schematics/copy-resources.js index 0e78cf419b..2b493da742 100644 --- a/scripts/schematics/copy-resources.js +++ b/scripts/schematics/copy-resources.js @@ -3,7 +3,7 @@ const path = require('path'); const srcPath = path.resolve(__dirname, `../../schematics`); const targetPath = path.resolve(__dirname, `../../publish/schematics`); -const copyFilter = (path) => (/files\/__path__/.test(path) || (!/.+\.ts/.test(path))); +const copyFilter = (path) => (/files\/__path__/.test(path) || !/.+\.ts/.test(path) || /.template$/.test(path)); function mergeDemoCollection() {