Skip to content

Commit e46cad0

Browse files
committed
feat(@angular/cli): Update generate & new to use schematics
This feature is related to angular#6593
1 parent ea592a1 commit e46cad0

File tree

7 files changed

+384
-61
lines changed

7 files changed

+384
-61
lines changed

package.json

+3
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
},
4141
"homepage": "https://github.com/angular/angular-cli",
4242
"dependencies": {
43+
"@angular-devkit/schematics": "0.0.1",
44+
"@angular-devkit/schematics-tools": "0.0.1",
45+
"@schematics/angular": "^0.0.2",
4346
"autoprefixer": "^6.5.3",
4447
"chalk": "^1.1.3",
4548
"circular-dependency-plugin": "^3.0.0",
+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import { cyan, yellow } from 'chalk';
2+
const stringUtils = require('ember-cli-string-utils');
3+
import { oneLine } from 'common-tags';
4+
import { CliConfig } from '../models/config';
5+
6+
import 'rxjs/add/observable/of';
7+
import 'rxjs/add/operator/ignoreElements';
8+
import { getCollection, getEngineHost, getSchematic, runSchematic } from '../utilities/schematics';
9+
import { DynamicPathOptions, dynamicPathParser } from '../utilities/dynamic-path-parser';
10+
import { getAppFromConfig } from '../utilities/app-utils';
11+
import * as path from 'path';
12+
13+
const Command = require('../ember-cli/lib/models/command');
14+
const SilentError = require('silent-error');
15+
16+
function mapSchematicOptions(schematic: any): any[] {
17+
const properties = schematic.description.schemaJson.properties;
18+
const keys = Object.keys(properties);
19+
const options = keys
20+
.map(key => ({...properties[key], ...{name: stringUtils.dasherize(key)}}))
21+
.map(opt => {
22+
let type;
23+
switch(opt.type) {
24+
case 'string':
25+
type = String;
26+
break;
27+
case 'boolean':
28+
type = Boolean;
29+
break;
30+
}
31+
let aliases: string[] = [];
32+
if (opt.alias) {
33+
aliases = [...aliases, opt.alias];
34+
}
35+
if (opt.aliases) {
36+
aliases = [...aliases, ...opt.aliases];
37+
}
38+
39+
return {
40+
...opt,
41+
aliases,
42+
type
43+
};
44+
});
45+
46+
return options;
47+
}
48+
49+
export default Command.extend({
50+
name: 'brocco',
51+
description: 'Generates and/or modifies files based on a schematic.',
52+
aliases: ['b'],
53+
54+
availableOptions: [
55+
{
56+
name: 'dry-run',
57+
type: Boolean,
58+
default: false,
59+
aliases: ['d'],
60+
description: 'Run through without making any changes.'
61+
},
62+
{
63+
name: 'force',
64+
type: Boolean,
65+
default: false,
66+
aliases: ['f'],
67+
description: 'Forces overwriting of files.'
68+
},
69+
{
70+
name: 'app',
71+
type: String,
72+
aliases: ['a'],
73+
description: 'Specifies app name to use.'
74+
},
75+
{
76+
name: 'collection',
77+
type: String,
78+
aliases: ['c'],
79+
description: 'Schematics collection to use.'
80+
}
81+
],
82+
83+
anonymousOptions: [
84+
'<schemtatic>'
85+
],
86+
87+
getCollectionName(rawArgs: string[]) {
88+
let collectionName = CliConfig.getValue('defaults.schematics.collection');
89+
if (rawArgs) {
90+
const parsedArgs = this.parseArgs(rawArgs, false);
91+
if (parsedArgs.options.collection) {
92+
collectionName = parsedArgs.options.collection;
93+
}
94+
}
95+
return collectionName;
96+
},
97+
98+
beforeRun: function(rawArgs: string[]) {
99+
const collection = getCollection(this.getCollectionName(rawArgs));
100+
101+
const isHelp = ['--help', '-h'].includes(rawArgs[0]);
102+
if (isHelp) {
103+
return;
104+
}
105+
106+
const schematicName = rawArgs[0];
107+
if (!schematicName) {
108+
return Promise.reject(new SilentError(oneLine`
109+
The "ng brocco" command requires a
110+
schematic name to be specified.
111+
For more details, use "ng help".
112+
`));
113+
}
114+
115+
this.schematic = getSchematic(collection, schematicName);
116+
117+
const schematicOptions = mapSchematicOptions(this.schematic);
118+
119+
this.registerOptions({availableOptions: schematicOptions});
120+
},
121+
122+
run: function (commandOptions: any, rawArgs: string[]) {
123+
const entityName = rawArgs[1];
124+
commandOptions.name = stringUtils.dasherize(entityName.split(path.sep).pop());
125+
126+
const appConfig = getAppFromConfig(commandOptions.app);
127+
const dynamicPathOptions: DynamicPathOptions = {
128+
project: this.project,
129+
entityName: entityName,
130+
appConfig: appConfig,
131+
dryRun: commandOptions.dryRun
132+
};
133+
const parsedPath = dynamicPathParser(dynamicPathOptions);
134+
commandOptions.path = parsedPath.dir.replace(parsedPath.appRoot + path.sep, '');
135+
const cwd = process.cwd();
136+
const collectionName = this.getCollectionName(rawArgs);
137+
const collection = getCollection(collectionName);
138+
const schematicName = rawArgs[0];
139+
const schematic = getSchematic(collection, schematicName);
140+
return runSchematic(schematic, cwd, commandOptions, this.project.root);
141+
142+
},
143+
144+
printDetailedHelp: function () {
145+
const engineHost = getEngineHost();
146+
const collectionName = this.getCollectionName();
147+
const collection = getCollection(collectionName);
148+
const schematicNames: string[] = engineHost.listSchematics(collection)
149+
this.ui.writeLine(cyan('Available schematics:'));
150+
schematicNames.forEach(schematicName => {
151+
this.ui.writeLine(yellow(` ${schematicName}`));
152+
})
153+
this.ui.writeLine('');
154+
}
155+
});

packages/@angular/cli/commands/new.ts

+7-28
Original file line numberDiff line numberDiff line change
@@ -156,42 +156,21 @@ const NewCommand = Command.extend({
156156
commandOptions.skipGit = true;
157157
}
158158

159-
const directoryName = path.join(process.cwd(),
160-
commandOptions.directory ? commandOptions.directory : packageName);
161-
159+
commandOptions.directory = commandOptions.directory || packageName;
160+
const directoryName = path.join(process.cwd(), commandOptions.directory);
162161
const initCommand = new InitCommand({
163162
ui: this.ui,
164163
tasks: this.tasks,
165164
project: Project.nullProject(this.ui, this.cli)
166165
});
167166

168-
let createDirectory;
169-
if (commandOptions.dryRun) {
170-
createDirectory = Promise.resolve()
171-
.then(() => {
172-
if (fs.existsSync(directoryName) && this.isProject(directoryName)) {
173-
throw new SilentError(oneLine`
174-
Directory ${directoryName} exists and is already an Angular CLI project.
175-
`);
176-
}
177-
});
178-
} else {
179-
createDirectory = mkdir(directoryName)
180-
.catch(err => {
181-
if (err.code === 'EEXIST') {
182-
if (this.isProject(directoryName)) {
183-
throw new SilentError(oneLine`
184-
Directory ${directoryName} exists and is already an Angular CLI project.
185-
`);
186-
}
187-
} else {
188-
throw err;
189-
}
190-
})
191-
.then(() => process.chdir(directoryName));
167+
if (fs.existsSync(directoryName) && this.isProject(directoryName)) {
168+
throw new SilentError(oneLine`
169+
Directory ${directoryName} exists and is already an Angular CLI project.
170+
`);
192171
}
193172

194-
return createDirectory
173+
return Promise.resolve()
195174
.then(initCommand.run.bind(initCommand, commandOptions, rawArgs));
196175
}
197176
});

packages/@angular/cli/lib/cli/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ function loadCommands() {
1717
'eject': require('../../commands/eject').default,
1818
'new': require('../../commands/new').default,
1919
'generate': require('../../commands/generate').default,
20+
'brocco': require('../../commands/brocco').default,
2021
'destroy': require('../../commands/destroy').default,
2122
'test': require('../../commands/test').default,
2223
'e2e': require('../../commands/e2e').default,

packages/@angular/cli/lib/config/schema.json

+17
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,23 @@
521521
"type": "string"
522522
}
523523
}
524+
},
525+
"schematics": {
526+
"description": "Properties about schematics.",
527+
"type": "object",
528+
"properties": {
529+
"collection": {
530+
"description": "The schematics collection to use.",
531+
"type": "string",
532+
"default": "@schematics/angular"
533+
},
534+
"newApp": {
535+
"description": "The new app schematic.",
536+
"type": "string",
537+
"default": "angular-app"
538+
}
539+
},
540+
"additionalProperties": false
524541
}
525542
},
526543
"additionalProperties": false

packages/@angular/cli/tasks/init.ts

+24-33
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import * as chalk from 'chalk';
2+
import * as path from 'path';
23
import LinkCli from '../tasks/link-cli';
34
import NpmInstall from '../tasks/npm-install';
45
import { validateProjectName } from '../utilities/validate-project-name';
56
import {checkYarnOrCNPM} from '../utilities/check-package-manager';
67
import {CliConfig} from '../models/config';
8+
import { runSchematic, getSchematic, getCollection } from "../utilities/schematics";
79

810
const Task = require('../ember-cli/lib/models/task');
911
const SilentError = require('silent-error');
10-
const normalizeBlueprint = require('../ember-cli/lib/utilities/normalize-blueprint-option');
1112
const GitInit = require('../tasks/git-init');
12-
const InstallBlueprint = require('../ember-cli/lib/tasks/install-blueprint');
1313

1414

1515
export default Task.extend({
@@ -18,11 +18,6 @@ export default Task.extend({
1818
commandOptions.skipInstall = true;
1919
}
2020

21-
const installBlueprint = new InstallBlueprint({
22-
ui: this.ui,
23-
project: this.project
24-
});
25-
2621
// needs an explicit check in case it's just 'undefined'
2722
// due to passing of options from 'new' and 'addon'
2823
let gitInit: any;
@@ -64,51 +59,47 @@ export default Task.extend({
6459
return Promise.reject(new SilentError(message));
6560
}
6661

67-
const blueprintOpts = {
68-
dryRun: commandOptions.dryRun,
69-
blueprint: 'ng',
70-
rawName: packageName,
71-
targetFiles: rawArgs || '',
72-
rawArgs: rawArgs.toString(),
73-
sourceDir: commandOptions.sourceDir,
74-
style: commandOptions.style,
75-
prefix: commandOptions.prefix.trim() || 'app',
76-
routing: commandOptions.routing,
77-
inlineStyle: commandOptions.inlineStyle,
78-
inlineTemplate: commandOptions.inlineTemplate,
79-
minimal: commandOptions.minimal,
80-
ignoredUpdateFiles: ['favicon.ico'],
81-
skipGit: commandOptions.skipGit,
82-
skipTests: commandOptions.skipTests
83-
};
84-
8562
validateProjectName(packageName);
8663

87-
blueprintOpts.blueprint = normalizeBlueprint(blueprintOpts.blueprint);
64+
let collectionName = CliConfig.getValue('defaults.schematics.collection');
65+
const collection = getCollection(collectionName);
66+
const schematicName = 'angular-app';
67+
const schematic = getSchematic(collection, schematicName);
68+
const dir = process.cwd();
69+
70+
commandOptions.version = require(path.resolve(__dirname, '../../package.json')).version;
8871

89-
return installBlueprint.run(blueprintOpts)
72+
return runSchematic(schematic, dir, commandOptions)
9073
.then(function () {
91-
if (!commandOptions.skipInstall) {
92-
return npmInstall.run();
74+
if (!commandOptions.dryRun) {
75+
process.chdir(commandOptions.directory);
9376
}
9477
})
9578
.then(function () {
96-
if (commandOptions.skipGit === false) {
79+
if (!commandOptions.dryRun && commandOptions.skipGit === false) {
9780
return gitInit.run(commandOptions, rawArgs);
9881
}
9982
})
10083
.then(function () {
101-
if (commandOptions.linkCli) {
84+
if (!commandOptions.dryRun && !commandOptions.skipInstall) {
85+
return npmInstall.run();
86+
}
87+
})
88+
.then(function () {
89+
if (!commandOptions.dryRun && commandOptions.linkCli) {
10290
return linkCli.run();
10391
}
10492
})
10593
.then(() => {
106-
if (!commandOptions.skipInstall || commandOptions.linkCli) {
94+
if (!commandOptions.dryRun &&
95+
(!commandOptions.skipInstall || commandOptions.linkCli)) {
10796
return checkYarnOrCNPM();
10897
}
10998
})
11099
.then(() => {
111-
this.ui.writeLine(chalk.green(`Project '${packageName}' successfully created.`));
100+
if (!commandOptions.dryRun) {
101+
this.ui.writeLine(chalk.green(`Project '${packageName}' successfully created.`));
102+
}
112103
});
113104
}
114105
});

0 commit comments

Comments
 (0)