From 8b220a4012d518debe65f6b7322c5539d36a80d7 Mon Sep 17 00:00:00 2001 From: Stephen Cavaliere Date: Fri, 17 Mar 2017 15:24:04 -0400 Subject: [PATCH] feat(@angular/cli): add import flag to modules closes #5377 --- docs/documentation/generate/module.md | 12 ++++ .../@angular/cli/blueprints/module/index.ts | 62 +++++++++++++++++-- packages/@angular/cli/utilities/ast-utils.ts | 1 + .../tests/generate/module/module-import.ts | 43 +++++++++++++ 4 files changed, 112 insertions(+), 6 deletions(-) create mode 100644 tests/e2e/tests/generate/module/module-import.ts diff --git a/docs/documentation/generate/module.md b/docs/documentation/generate/module.md index 24a4fe95a3af..55559f122406 100644 --- a/docs/documentation/generate/module.md +++ b/docs/documentation/generate/module.md @@ -26,6 +26,16 @@

+
+ module +

+ --module (aliases: -m) +

+

+ Specifies where the module should be imported. +

+
+
spec

@@ -45,3 +55,5 @@ Specifies if a routing module file should be generated.

+ + diff --git a/packages/@angular/cli/blueprints/module/index.ts b/packages/@angular/cli/blueprints/module/index.ts index 91fcd7a5c608..e954f6b34073 100644 --- a/packages/@angular/cli/blueprints/module/index.ts +++ b/packages/@angular/cli/blueprints/module/index.ts @@ -1,9 +1,15 @@ -import {CliConfig} from '../../models/config'; -import {getAppFromConfig} from '../../utilities/app-utils'; -import {dynamicPathParser} from '../../utilities/dynamic-path-parser'; +import * as chalk from 'chalk'; +import * as path from 'path'; +import { oneLine } from 'common-tags'; +import { NodeHost } from '../../lib/ast-tools'; +import { CliConfig } from '../../models/config'; +import { getAppFromConfig } from '../../utilities/app-utils'; +import { resolveModulePath } from '../../utilities/resolve-module-file'; +import { dynamicPathParser } from '../../utilities/dynamic-path-parser'; -const path = require('path'); -const Blueprint = require('../../ember-cli/lib/models/blueprint'); +const stringUtils = require('ember-cli-string-utils'); +const Blueprint = require('../../ember-cli/lib/models/blueprint'); +const astUtils = require('../../utilities/ast-utils'); const getFiles = Blueprint.prototype.files; export default Blueprint.extend({ @@ -32,9 +38,22 @@ export default Blueprint.extend({ type: String, aliases: ['a'], description: 'Specifies app name to use.' + }, + { + name: 'module', + type: String, aliases: ['m'], + description: 'Specifies where the module should be imported.' } ], + beforeInstall: function(options: any) { + if (options.module) { + const appConfig = getAppFromConfig(this.options.app); + this.pathToModule = + resolveModulePath(options.module, this.project, this.project.root, appConfig); + } + }, + normalizeEntityName: function (entityName: string) { this.entityName = entityName; const appConfig = getAppFromConfig(this.options.app); @@ -59,7 +78,7 @@ export default Blueprint.extend({ }; }, - files: function() { + files: function () { let fileList = getFiles.call(this) as Array; if (!this.options || !this.options.spec) { @@ -84,5 +103,36 @@ export default Blueprint.extend({ return this.generatePath; } }; + }, + + afterInstall(options: any) { + const returns: Array = []; + + if (!this.pathToModule) { + const warningMessage = oneLine` + Module is generated but not provided, + it must be provided to be used + `; + this._writeStatusToUI(chalk.yellow, 'WARNING', warningMessage); + } else { + let className = stringUtils.classify(`${options.entity.name}Module`); + let fileName = stringUtils.dasherize(`${options.entity.name}.module`); + if (options.routing) { + className = stringUtils.classify(`${options.entity.name}RoutingModule`); + fileName = stringUtils.dasherize(`${options.entity.name}-routing.module`); + } + const fullGeneratePath = path.join(this.project.root, this.generatePath); + const moduleDir = path.parse(this.pathToModule).dir; + const relativeDir = path.relative(moduleDir, fullGeneratePath); + const importPath = relativeDir ? `./${relativeDir}/${fileName}` : `./${fileName}`; + returns.push( + astUtils.addImportToModule(this.pathToModule, className, importPath) + .then((change: any) => change.apply(NodeHost))); + this._writeStatusToUI(chalk.yellow, + 'update', + path.relative(this.project.root, this.pathToModule)); + } + + return Promise.all(returns); } }); diff --git a/packages/@angular/cli/utilities/ast-utils.ts b/packages/@angular/cli/utilities/ast-utils.ts index 0369f46df36e..0d0a07fca32f 100644 --- a/packages/@angular/cli/utilities/ast-utils.ts +++ b/packages/@angular/cli/utilities/ast-utils.ts @@ -9,5 +9,6 @@ export { getDecoratorMetadata, addDeclarationToModule, addProviderToModule, + addImportToModule, addExportToModule } from '../lib/ast-tools'; diff --git a/tests/e2e/tests/generate/module/module-import.ts b/tests/e2e/tests/generate/module/module-import.ts new file mode 100644 index 000000000000..2f2f2104fe9c --- /dev/null +++ b/tests/e2e/tests/generate/module/module-import.ts @@ -0,0 +1,43 @@ +import { join } from 'path'; +import { ng } from '../../../utils/process'; +import { expectFileToMatch } from '../../../utils/fs'; + +export default function () { + const modulePath = join('src', 'app', 'app.module.ts'); + const subModulePath = join('src', 'app', 'sub', 'sub.module.ts'); + const deepSubModulePath = join('src', 'app', 'sub', 'deep', 'deep.module.ts'); + + return Promise.resolve() + .then(() => ng('generate', 'module', 'sub')) + .then(() => ng('generate', 'module', 'sub/deep')) + + .then(() => ng('generate', 'module', 'test1', '--module', 'app.module.ts')) + .then(() => expectFileToMatch(modulePath, + /import { Test1Module } from '.\/test1\/test1.module'/)) + .then(() => expectFileToMatch(modulePath, /imports: \[(.|\s)*Test1Module(.|\s)*\]/m)) + + .then(() => ng('generate', 'module', 'test2', '--module', 'app.module')) + .then(() => expectFileToMatch(modulePath, + /import { Test2Module } from '.\/test2\/test2.module'/)) + .then(() => expectFileToMatch(modulePath, /imports: \[(.|\s)*Test2Module(.|\s)*\]/m)) + + .then(() => ng('generate', 'module', 'test3', '--module', 'app')) + .then(() => expectFileToMatch(modulePath, + /import { Test3Module } from '.\/test3\/test3.module'/)) + .then(() => expectFileToMatch(modulePath, /imports: \[(.|\s)*Test3Module(.|\s)*\]/m)) + + .then(() => ng('generate', 'module', 'test4', '--routing', '--module', 'app')) + .then(() => expectFileToMatch(modulePath, + /import { Test4RoutingModule } from '.\/test4\/test4-routing.module'/)) + .then(() => expectFileToMatch(modulePath, /imports: \[(.|\s)*Test4RoutingModule(.|\s)*\]/m)) + + .then(() => ng('generate', 'module', 'test5', '--module', 'sub')) + .then(() => expectFileToMatch(subModulePath, + /import { Test5Module } from '.\/..\/test5\/test5.module'/)) + .then(() => expectFileToMatch(subModulePath, /imports: \[(.|\s)*Test5Module(.|\s)*\]/m)) + + .then(() => ng('generate', 'module', 'test6', '--module', join('sub', 'deep')) + .then(() => expectFileToMatch(deepSubModulePath, + /import { Test6Module } from '.\/..\/..\/test6\/test6.module'/)) + .then(() => expectFileToMatch(deepSubModulePath, /imports: \[(.|\s)*Test6Module(.|\s)*\]/m))); +}