Skip to content

Commit 1773c5d

Browse files
committed
Added command for out of project module generation
1 parent 58fea8f commit 1773c5d

File tree

8 files changed

+379
-0
lines changed

8 files changed

+379
-0
lines changed

packages/angular-cli/addon/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ module.exports = {
2121
'build': require('../commands/build').default,
2222
'serve': require('../commands/serve').default,
2323
'new': require('../commands/new').default,
24+
'new-module': require('../commands/new-module').default,
2425
'generate': require('../commands/generate').default,
26+
'generate-lib-module': require('../commands/generate-lib-module').default,
2527
'destroy': require('../commands/destroy').default,
2628
'init': require('../commands/init').default,
2729
'test': require('../commands/test').default,
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { NgModule } from '@angular/core';
2+
import { Routes, RouterModule } from '@angular/router';
3+
4+
const routes: Routes = [];
5+
6+
@NgModule({
7+
imports: [RouterModule.forChild(routes)],
8+
exports: [RouterModule],
9+
providers: []
10+
})
11+
export class <%= classifiedModuleName %>RoutingModule { }
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/* tslint:disable:no-unused-variable */
2+
3+
import { TestBed, async } from '@angular/core/testing';
4+
import <%= classifiedModuleName %>Module from './<%= dasherizedModuleName %>.module';
5+
6+
describe('<%= classifiedModuleName %>Module', () => {
7+
let <%= camelizedModuleName %>Module;
8+
9+
beforeEach(() => {
10+
<%= camelizedModuleName %>Module = new <%= classifiedModuleName %>Module();
11+
});
12+
13+
it('should create an instance', () => {
14+
expect(<%= camelizedModuleName %>Module).toBeTruthy();
15+
})
16+
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { NgModule } from '@angular/core';
2+
import { CommonModule } from '@angular/common';<% if (routing) { %>
3+
import { <%= classifiedModuleName %>RoutingModule } from './<%= dasherizedModuleName %>-routing.module';<% } %>
4+
5+
@NgModule({
6+
imports: [
7+
CommonModule<% if (routing) { %>,
8+
<%= classifiedModuleName %>RoutingModule<% } %>
9+
],
10+
declarations: []
11+
})
12+
export class <%= classifiedModuleName %>Module { }
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "<%= htmlComponentName %>",
3+
"version": "0.0.0",
4+
"license": "MIT",
5+
"scripts": {
6+
"test": "echo \"Error: no test specified\" && exit 1"
7+
},
8+
"dependencies": {},
9+
"devDependencies": {}
10+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
const Blueprint = require('../../ember-cli/lib/models/blueprint');
2+
const path = require('path');
3+
const stringUtils = require('ember-cli-string-utils');
4+
const getFiles = Blueprint.prototype.files;
5+
6+
module.exports = {
7+
description: '',
8+
9+
availableOptions: [
10+
{ name: 'source-dir', type: String, default: 'src', aliases: ['sd'] },
11+
{ name: 'prefix', type: String, default: 'app', aliases: ['p'] },
12+
{ name: 'style', type: String, default: 'css' },
13+
{ name: 'mobile', type: Boolean, default: false },
14+
{ name: 'routing', type: Boolean, default: false },
15+
{ name: 'inline-style', type: Boolean, default: false, aliases: ['is'] },
16+
{ name: 'inline-template', type: Boolean, default: false, aliases: ['it'] }
17+
],
18+
19+
beforeInstall: function(options) {
20+
if (options.ignoredUpdateFiles && options.ignoredUpdateFiles.length > 0) {
21+
return Blueprint.ignoredUpdateFiles = Blueprint.ignoredUpdateFiles.concat(options.ignoredUpdateFiles);
22+
}
23+
},
24+
25+
afterInstall: function (options) {
26+
if (options.mobile) {
27+
return Blueprint.load(path.join(__dirname, '../mobile')).install(options);
28+
}
29+
},
30+
31+
locals: function(options) {
32+
this.styleExt = options.style;
33+
this.version = require(path.resolve(__dirname, '../../package.json')).version;
34+
35+
// Split/join with / not path.sep as reference to typings require forward slashes.
36+
const relativeRootPath = options.sourceDir.split('/').map(() => '..').join('/');
37+
const fullAppName = stringUtils.dasherize(options.entity.name)
38+
.replace(/-(.)/g, (_, l) => ' ' + l.toUpperCase())
39+
.replace(/^./, (l) => l.toUpperCase());
40+
41+
// For mobile projects, force inline styles and templates.
42+
if (options.mobile) {
43+
options.inlineStyle = true;
44+
options.inlineTemplate = true;
45+
}
46+
47+
return {
48+
htmlComponentName: stringUtils.dasherize(options.entity.name),
49+
jsComponentName: stringUtils.classify(options.entity.name),
50+
fullAppName: fullAppName,
51+
version: this.version,
52+
sourceDir: options.sourceDir,
53+
prefix: options.prefix,
54+
styleExt: this.styleExt,
55+
relativeRootPath: relativeRootPath,
56+
isMobile: options.mobile,
57+
routing: options.routing,
58+
inlineStyle: options.inlineStyle,
59+
inlineTemplate: options.inlineTemplate
60+
};
61+
},
62+
63+
files: function() {
64+
var fileList = getFiles.call(this);
65+
66+
if (this.options && !this.options.routing) {
67+
fileList = fileList.filter(p => p.indexOf('app-routing.module.ts') < 0);
68+
}
69+
if (this.options && this.options.inlineTemplate) {
70+
fileList = fileList.filter(p => p.indexOf('app.component.html') < 0);
71+
}
72+
if (this.options && this.options.inlineStyle) {
73+
fileList = fileList.filter(p => p.indexOf('app.component.__styleext__') < 0);
74+
}
75+
76+
return fileList;
77+
},
78+
79+
fileMapTokens: function (options) {
80+
// Return custom template variables here.
81+
return {
82+
__path__: () => {
83+
return options.locals.sourceDir;
84+
},
85+
__styleext__: () => {
86+
return this.styleExt;
87+
}
88+
};
89+
}
90+
};
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
2+
import LinkCli from '../tasks/link-cli';
3+
import NpmInstall from '../tasks/npm-install';
4+
5+
const Command = require('../ember-cli/lib/models/command');
6+
const Promise = require('../ember-cli/lib/ext/promise');
7+
const SilentError = require('silent-error');
8+
const validProjectName = require('../ember-cli/lib/utilities/valid-project-name');
9+
const normalizeBlueprint = require('../ember-cli/lib/utilities/normalize-blueprint-option');
10+
const GitInit = require('../tasks/git-init');
11+
12+
13+
const LibModuleCommand: any = Command.extend({
14+
name: 'generate-lib-module',
15+
description: 'Creates a new angular 2 module in the current folder.',
16+
works: 'everywhere',
17+
18+
availableOptions: [
19+
{ name: 'dry-run', type: Boolean, default: false, aliases: ['d'] },
20+
{ name: 'verbose', type: Boolean, default: false, aliases: ['v'] },
21+
{ name: 'link-cli', type: Boolean, default: false, aliases: ['lc'] },
22+
{ name: 'skip-npm', type: Boolean, default: false, aliases: ['sn'] },
23+
{ name: 'skip-bower', type: Boolean, default: true, aliases: ['sb'] },
24+
{ name: 'name', type: String, default: '', aliases: ['n'] },
25+
{ name: 'source-dir', type: String, default: 'src', aliases: ['sd'] },
26+
{ name: 'style', type: String, default: 'css' },
27+
{ name: 'prefix', type: String, default: 'app', aliases: ['p'] },
28+
{ name: 'mobile', type: Boolean, default: false },
29+
{ name: 'routing', type: Boolean, default: false },
30+
{ name: 'inline-style', type: Boolean, default: false, aliases: ['is'] },
31+
{ name: 'inline-template', type: Boolean, default: false, aliases: ['it'] }
32+
],
33+
34+
anonymousOptions: ['<glob-pattern>'],
35+
36+
run: function (commandOptions: any, rawArgs: string[]) {
37+
const packageName = rawArgs.shift();
38+
39+
if (!packageName) {
40+
return Promise.reject(new SilentError(
41+
`The "ng ${this.name}" command requires a name argument to be specified. ` +
42+
`For more details, use "ng help".`));
43+
}
44+
45+
commandOptions.name = packageName;
46+
commandOptions.directory = packageName;
47+
48+
if (commandOptions.dryRun) {
49+
commandOptions.skipGit = true;
50+
}
51+
52+
if (commandOptions.dryRun) {
53+
commandOptions.skipNpm = true;
54+
commandOptions.skipBower = true;
55+
}
56+
57+
const installBlueprint = new this.tasks.InstallBlueprint({
58+
ui: this.ui,
59+
analytics: this.analytics,
60+
project: this.project
61+
});
62+
63+
// needs an explicit check in case it's just 'undefined'
64+
// due to passing of options from 'new' and 'addon'
65+
let gitInit: any;
66+
if (commandOptions.skipGit === false) {
67+
gitInit = new GitInit({
68+
ui: this.ui,
69+
project: this.project
70+
});
71+
}
72+
73+
let npmInstall: any;
74+
if (!commandOptions.skipNpm) {
75+
npmInstall = new NpmInstall({
76+
ui: this.ui,
77+
analytics: this.analytics,
78+
project: this.project
79+
});
80+
}
81+
82+
let linkCli: any;
83+
if (commandOptions.linkCli) {
84+
linkCli = new LinkCli({
85+
ui: this.ui,
86+
analytics: this.analytics,
87+
project: this.project
88+
});
89+
}
90+
91+
let bowerInstall: any;
92+
if (!commandOptions.skipBower) {
93+
bowerInstall = new this.tasks.BowerInstall({
94+
ui: this.ui,
95+
analytics: this.analytics,
96+
project: this.project
97+
});
98+
}
99+
100+
const project = this.project;
101+
102+
if (!packageName) {
103+
const message = 'The `ng ' + this.name + '` command requires a ' +
104+
'package.json in current folder with name attribute or a specified name via arguments. ' +
105+
'For more details, use `ng help`.';
106+
107+
return Promise.reject(new SilentError(message));
108+
}
109+
110+
const blueprintOpts = {
111+
dryRun: commandOptions.dryRun,
112+
blueprint: 'libmodule',
113+
rawName: packageName,
114+
targetFiles: rawArgs || '',
115+
rawArgs: rawArgs.toString(),
116+
sourceDir: commandOptions.sourceDir,
117+
style: commandOptions.style,
118+
prefix: commandOptions.prefix,
119+
mobile: commandOptions.mobile,
120+
routing: commandOptions.routing,
121+
inlineStyle: commandOptions.inlineStyle,
122+
inlineTemplate: commandOptions.inlineTemplate,
123+
ignoredUpdateFiles: ['favicon.ico']
124+
};
125+
126+
if (!validProjectName(packageName)) {
127+
return Promise.reject(
128+
new SilentError('We currently do not support a name of `' + packageName + '`.'));
129+
}
130+
131+
if (commandOptions.mobile) {
132+
return Promise.reject(new SilentError(
133+
'The --mobile flag has been disabled temporarily while we await an update of ' +
134+
'angular-universal for supporting NgModule. Sorry for the inconvenience.'
135+
));
136+
}
137+
138+
blueprintOpts.blueprint = normalizeBlueprint(blueprintOpts.blueprint);
139+
140+
return installBlueprint.run(blueprintOpts)
141+
.then(function () {
142+
if (commandOptions.skipGit === false) {
143+
return gitInit.run(commandOptions, rawArgs);
144+
}
145+
}.bind(this))
146+
.then(function () {
147+
if (!commandOptions.skipNpm) {
148+
return npmInstall.run();
149+
}
150+
})
151+
.then(function () {
152+
if (commandOptions.linkCli) {
153+
return linkCli.run();
154+
}
155+
})
156+
.then(function () {
157+
if (!commandOptions.skipBower) {
158+
return bowerInstall.run({
159+
verbose: commandOptions.verbose
160+
});
161+
}
162+
});
163+
}
164+
});
165+
166+
LibModuleCommand.overrideCore = true;
167+
export default LibModuleCommand;
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import * as chalk from 'chalk';
2+
import InitCommand from './init';
3+
4+
const Command = require('../ember-cli/lib/models/command');
5+
const Project = require('../ember-cli/lib/models/project');
6+
const SilentError = require('silent-error');
7+
const validProjectName = require('../ember-cli/lib/utilities/valid-project-name');
8+
9+
10+
const NewModuleCommand = Command.extend({
11+
name: 'new-module',
12+
description: `Creates a new directory and runs ${chalk.green('ng generate-lib-module')} in it.`,
13+
works: 'everywhere',
14+
15+
availableOptions: [
16+
{ name: 'dry-run', type: Boolean, default: false, aliases: ['d'] },
17+
{ name: 'verbose', type: Boolean, default: false, aliases: ['v'] },
18+
{ name: 'link-cli', type: Boolean, default: false, aliases: ['lc'] },
19+
{ name: 'skip-npm', type: Boolean, default: false, aliases: ['sn'] },
20+
{ name: 'skip-bower', type: Boolean, default: true, aliases: ['sb'] },
21+
{ name: 'skip-git', type: Boolean, default: false, aliases: ['sg'] },
22+
{ name: 'directory', type: String, aliases: ['dir'] },
23+
{ name: 'source-dir', type: String, default: 'src', aliases: ['sd'] },
24+
{ name: 'style', type: String, default: 'css' },
25+
{ name: 'prefix', type: String, default: 'app', aliases: ['p'] },
26+
{ name: 'mobile', type: Boolean, default: false },
27+
{ name: 'routing', type: Boolean, default: false },
28+
{ name: 'inline-style', type: Boolean, default: false, aliases: ['is'] },
29+
{ name: 'inline-template', type: Boolean, default: false, aliases: ['it'] }
30+
],
31+
32+
run: function (commandOptions: any, rawArgs: string[]) {
33+
const packageName = rawArgs.shift();
34+
35+
if (!packageName) {
36+
return Promise.reject(new SilentError(
37+
`The "ng ${this.name}" command requires a name argument to be specified. ` +
38+
`For more details, use "ng help".`));
39+
}
40+
41+
commandOptions.name = packageName;
42+
if (commandOptions.dryRun) {
43+
commandOptions.skipGit = true;
44+
}
45+
46+
if (!commandOptions.directory) {
47+
commandOptions.directory = packageName;
48+
}
49+
50+
const createAndStepIntoDirectory =
51+
new this.tasks.CreateAndStepIntoDirectory({ ui: this.ui, analytics: this.analytics });
52+
53+
const generateLibModuleCommand = new InitCommand({
54+
ui: this.ui,
55+
analytics: this.analytics,
56+
tasks: this.tasks,
57+
project: Project.nullProject(this.ui, this.cli)
58+
});
59+
60+
return createAndStepIntoDirectory
61+
.run({
62+
directoryName: commandOptions.directory,
63+
dryRun: commandOptions.dryRun
64+
})
65+
.then(generateLibModuleCommand.run.bind(generateLibModuleCommand, commandOptions, rawArgs));
66+
}
67+
});
68+
69+
70+
NewModuleCommand.overrideCore = true;
71+
export default NewModuleCommand;

0 commit comments

Comments
 (0)