Skip to content

Commit 81bf910

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

File tree

17 files changed

+610
-265
lines changed

17 files changed

+610
-265
lines changed

package-lock.json

+27-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
"homepage": "https://github.com/angular/angular-cli",
4242
"dependencies": {
4343
"@angular-devkit/build-optimizer": "0.0.13",
44+
"@angular-devkit/schematics": "0.0.17",
45+
"@schematics/angular": "0.0.27",
4446
"autoprefixer": "^6.5.3",
4547
"chalk": "^2.0.1",
4648
"circular-dependency-plugin": "^3.0.0",
+110-94
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
1-
import * as chalk from 'chalk';
2-
import * as fs from 'fs';
3-
import * as os from 'os';
4-
import * as path from 'path';
1+
import { cyan, yellow } from 'chalk';
2+
const stringUtils = require('ember-cli-string-utils');
53
import { oneLine } from 'common-tags';
64
import { CliConfig } from '../models/config';
75

6+
import 'rxjs/add/observable/of';
7+
import 'rxjs/add/operator/ignoreElements';
8+
import {
9+
getCollection,
10+
getEngineHost
11+
} from '../utilities/schematics';
12+
import { DynamicPathOptions, dynamicPathParser } from '../utilities/dynamic-path-parser';
13+
import { getAppFromConfig } from '../utilities/app-utils';
14+
import * as path from 'path';
15+
import { SchematicAvailableOptions } from '../tasks/schematic-get-options';
16+
817
const Command = require('../ember-cli/lib/models/command');
9-
const Blueprint = require('../ember-cli/lib/models/blueprint');
10-
const parseOptions = require('../ember-cli/lib/utilities/parse-options');
1118
const SilentError = require('silent-error');
1219

13-
function loadBlueprints(): Array<any> {
14-
const blueprintList = fs.readdirSync(path.join(__dirname, '..', 'blueprints'));
15-
const blueprints = blueprintList
16-
.filter(bp => bp.indexOf('-test') === -1)
17-
.filter(bp => bp !== 'ng')
18-
.map(bp => Blueprint.load(path.join(__dirname, '..', 'blueprints', bp)));
20+
const separatorRegEx = /[\/\\]/g;
1921

20-
return blueprints;
21-
}
2222

2323
export default Command.extend({
2424
name: 'generate',
25-
description: 'Generates and/or modifies files based on a blueprint.',
25+
description: 'Generates and/or modifies files based on a schematic.',
2626
aliases: ['g'],
2727

2828
availableOptions: [
@@ -34,117 +34,133 @@ export default Command.extend({
3434
description: 'Run through without making any changes.'
3535
},
3636
{
37-
name: 'lint-fix',
37+
name: 'force',
3838
type: Boolean,
39-
aliases: ['lf'],
40-
description: 'Use lint to fix files after generation.'
39+
default: false,
40+
aliases: ['f'],
41+
description: 'Forces overwriting of files.'
42+
},
43+
{
44+
name: 'app',
45+
type: String,
46+
aliases: ['a'],
47+
description: 'Specifies app name to use.'
48+
},
49+
{
50+
name: 'collection',
51+
type: String,
52+
aliases: ['c'],
53+
description: 'Schematics collection to use.'
4154
},
4255
{
43-
name: 'verbose',
56+
name: 'lint-fix',
4457
type: Boolean,
45-
default: false,
46-
aliases: ['v'],
47-
description: 'Adds more details to output logging.'
58+
aliases: ['lf'],
59+
description: 'Use lint to fix files after generation.'
4860
}
4961
],
5062

5163
anonymousOptions: [
52-
'<blueprint>'
64+
'<schematic>'
5365
],
5466

55-
beforeRun: function (rawArgs: string[]) {
56-
if (!rawArgs.length) {
57-
return;
67+
getCollectionName(rawArgs: string[]) {
68+
let collectionName = CliConfig.getValue('defaults.schematics.collection');
69+
if (rawArgs) {
70+
const parsedArgs = this.parseArgs(rawArgs, false);
71+
if (parsedArgs.options.collection) {
72+
collectionName = parsedArgs.options.collection;
73+
}
5874
}
75+
return collectionName;
76+
},
77+
78+
beforeRun: function(rawArgs: string[]) {
5979

6080
const isHelp = ['--help', '-h'].includes(rawArgs[0]);
6181
if (isHelp) {
6282
return;
6383
}
6484

65-
this.blueprints = loadBlueprints();
66-
67-
const name = rawArgs[0];
68-
const blueprint = this.blueprints.find((bp: any) => bp.name === name
69-
|| (bp.aliases && bp.aliases.includes(name)));
70-
71-
if (!blueprint) {
72-
SilentError.debugOrThrow('@angular/cli/commands/generate',
73-
`Invalid blueprint: ${name}`);
74-
}
75-
76-
if (!rawArgs[1]) {
77-
SilentError.debugOrThrow('@angular/cli/commands/generate',
78-
`The \`ng generate ${name}\` command requires a name to be specified.`);
85+
const schematicName = rawArgs[0];
86+
if (!schematicName) {
87+
return Promise.reject(new SilentError(oneLine`
88+
The "ng generate" command requires a
89+
schematic name to be specified.
90+
For more details, use "ng help".
91+
`));
7992
}
8093

8194
if (/^\d/.test(rawArgs[1])) {
8295
SilentError.debugOrThrow('@angular/cli/commands/generate',
83-
`The \`ng generate ${name} ${rawArgs[1]}\` file name cannot begin with a digit.`);
96+
`The \`ng generate ${schematicName} ${rawArgs[1]}\` file name cannot begin with a digit.`);
8497
}
8598

86-
rawArgs[0] = blueprint.name;
87-
this.registerOptions(blueprint);
88-
},
99+
const SchematicGetOptionsTask = require('../tasks/schematic-get-options').default;
89100

90-
printDetailedHelp: function () {
91-
if (!this.blueprints) {
92-
this.blueprints = loadBlueprints();
93-
}
94-
this.ui.writeLine(chalk.cyan(' Available blueprints'));
95-
this.ui.writeLine(this.blueprints.map((bp: any) => bp.printBasicHelp(false)).join(os.EOL));
101+
const getOptionsTask = new SchematicGetOptionsTask({
102+
ui: this.ui,
103+
project: this.project
104+
});
105+
106+
return getOptionsTask.run({
107+
schematicName,
108+
collectionName: this.getCollectionName(rawArgs)
109+
})
110+
.then((availableOptions: SchematicAvailableOptions) => {
111+
this.registerOptions({
112+
availableOptions: availableOptions
113+
});
114+
});
96115
},
97116

98117
run: function (commandOptions: any, rawArgs: string[]) {
99-
const name = rawArgs[0];
100-
if (!name) {
101-
return Promise.reject(new SilentError(oneLine`
102-
The "ng generate" command requires a
103-
blueprint name to be specified.
104-
For more details, use "ng help".
105-
`));
118+
if (rawArgs[0] === 'module' && !rawArgs[1]) {
119+
throw 'The `ng generate module` command requires a name to be specified.';
106120
}
107121

108-
const blueprint = this.blueprints.find((bp: any) => bp.name === name
109-
|| (bp.aliases && bp.aliases.includes(name)));
110-
111-
const projectName = CliConfig.getValue('project.name');
112-
const blueprintOptions = {
113-
target: this.project.root,
114-
entity: {
115-
name: rawArgs[1],
116-
options: parseOptions(rawArgs.slice(2))
117-
},
118-
projectName,
119-
ui: this.ui,
122+
const entityName = rawArgs[1];
123+
commandOptions.name = stringUtils.dasherize(entityName.split(separatorRegEx).pop());
124+
125+
const appConfig = getAppFromConfig(commandOptions.app);
126+
const dynamicPathOptions: DynamicPathOptions = {
120127
project: this.project,
121-
settings: this.settings,
122-
testing: this.testing,
123-
args: rawArgs,
124-
...commandOptions
128+
entityName: entityName,
129+
appConfig: appConfig,
130+
dryRun: commandOptions.dryRun
125131
};
132+
const parsedPath = dynamicPathParser(dynamicPathOptions);
133+
commandOptions.sourceDir = appConfig.root;
134+
commandOptions.path = parsedPath.dir
135+
.replace(appConfig.root + path.sep, '')
136+
.replace(separatorRegEx, '/');
126137

127-
return blueprint.install(blueprintOptions)
128-
.then(() => {
129-
const lintFix = commandOptions.lintFix !== undefined ?
130-
commandOptions.lintFix : CliConfig.getValue('defaults.lintFix');
131-
132-
if (lintFix && blueprint.modifiedFiles) {
133-
const LintTask = require('../tasks/lint').default;
134-
const lintTask = new LintTask({
135-
ui: this.ui,
136-
project: this.project
137-
});
138-
139-
return lintTask.run({
140-
fix: true,
141-
force: true,
142-
silent: true,
143-
configs: [{
144-
files: blueprint.modifiedFiles.filter((file: string) => /.ts$/.test(file))
145-
}]
146-
});
147-
}
138+
const cwd = this.project.root;
139+
const schematicName = rawArgs[0];
140+
141+
const SchematicRunTask = require('../tasks/schematic-run').default;
142+
const schematicRunTask = new SchematicRunTask({
143+
ui: this.ui,
144+
project: this.project
145+
});
146+
147+
return schematicRunTask.run({
148+
taskOptions: commandOptions,
149+
workingDir: cwd,
150+
collectionName: this.getCollectionName(rawArgs),
151+
schematicName
148152
});
153+
},
154+
155+
printDetailedHelp: function () {
156+
const engineHost = getEngineHost();
157+
const collectionName = this.getCollectionName();
158+
const collection = getCollection(collectionName);
159+
const schematicNames: string[] = engineHost.listSchematics(collection);
160+
this.ui.writeLine(cyan('Available schematics:'));
161+
schematicNames.forEach(schematicName => {
162+
this.ui.writeLine(yellow(` ${schematicName}`));
163+
});
164+
this.ui.writeLine('');
149165
}
150166
});

0 commit comments

Comments
 (0)