Skip to content

Commit 24bcc19

Browse files
Broccohansl
authored andcommitted
fix(@angular/cli): Organize the help output
1 parent 9d84529 commit 24bcc19

File tree

7 files changed

+144
-78
lines changed

7 files changed

+144
-78
lines changed

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@ export default class AddCommand extends SchematicCommand {
1616
options: Option[] = [];
1717

1818
private async _parseSchematicOptions(collectionName: string): Promise<any> {
19-
const availableOptions: Option[] = await this.getOptions({
19+
const schematicOptions = await this.getOptions({
2020
schematicName: 'ng-add',
2121
collectionName,
2222
});
2323

24-
const options = this.options.concat(availableOptions || []);
24+
const options = this.options.concat(schematicOptions.options);
25+
const args = schematicOptions.arguments.map(arg => arg.name);
2526

26-
return parseOptions(this._rawArgs, options, [], this.argStrategy);
27+
return parseOptions(this._rawArgs, options, args, this.argStrategy);
2728
}
2829

2930
validate(options: any) {

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,12 @@ export default class GenerateCommand extends SchematicCommand {
3131
const [collectionName, schematicName] = this.parseSchematicInfo(options);
3232

3333
if (!!schematicName) {
34-
const availableOptions: Option[] = await this.getOptions({
34+
const schematicOptions = await this.getOptions({
3535
schematicName,
3636
collectionName,
3737
});
38-
this.options = this.options.concat( availableOptions || []);
38+
this.options = this.options.concat(schematicOptions.options);
39+
this.arguments = this.arguments.concat(schematicOptions.arguments.map(a => a.name));
3940
}
4041
}
4142

@@ -83,8 +84,16 @@ export default class GenerateCommand extends SchematicCommand {
8384
}
8485

8586
public printHelp(options: any) {
86-
if (options.schematic) {
87-
super.printHelp(options);
87+
const schematicName = options._[0];
88+
if (schematicName) {
89+
const argDisplay = this.arguments && this.arguments.length > 0
90+
? ' ' + this.arguments.filter(a => a !== 'schematic').map(a => `<${a}>`).join(' ')
91+
: '';
92+
const optionsDisplay = this.options && this.options.length > 0
93+
? ' [options]'
94+
: '';
95+
this.logger.info(`usage: ng generate ${schematicName}${argDisplay}${optionsDisplay}`);
96+
this.printHelpOptions(options);
8897
} else {
8998
this.printHelpUsage(this.name, this.arguments, this.options);
9099
const engineHost = getEngineHost();

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

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export default class NewCommand extends SchematicCommand {
99
'Creates a new directory and a new Angular app.';
1010
public static aliases = ['n'];
1111
public scope = CommandScope.outsideProject;
12+
public arguments: string[] = [];
1213
public options: Option[] = [
1314
...this.coreOptions,
1415
{
@@ -41,12 +42,10 @@ export default class NewCommand extends SchematicCommand {
4142
schematicName,
4243
collectionName
4344
})
44-
.then((availableOptions: Option[]) => {
45-
// if (availableOptions) {
46-
// availableOptions = availableOptions.filter(opt => opt.name !== 'name');
47-
// }
48-
49-
this.options = this.options.concat( availableOptions || []);
45+
.then((schematicOptions) => {
46+
this.options = this.options.concat(schematicOptions.options);
47+
const args = schematicOptions.arguments.map(arg => arg.name);
48+
this.arguments = this.arguments.concat(args);
5049
});
5150
}
5251

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export default class UpdateCommand extends SchematicCommand {
1212
public readonly description = 'Updates your application and its dependencies.';
1313
public static aliases: string[] = [];
1414
public readonly scope = CommandScope.inProject;
15-
public readonly arguments: string[] = [ 'packages' ];
15+
public arguments: string[] = [ 'packages' ];
1616
public options: Option[] = [
1717
...this.coreOptions,
1818
];
@@ -29,11 +29,12 @@ export default class UpdateCommand extends SchematicCommand {
2929
super.initialize(options);
3030
this.initialized = true;
3131

32-
const availableOptions: Option[] = await this.getOptions({
32+
const schematicOptions = await this.getOptions({
3333
schematicName: this.schematicName,
3434
collectionName: this.collectionName,
3535
});
36-
this.options = this.options.concat( availableOptions || []);
36+
this.options = this.options.concat(schematicOptions.options);
37+
this.arguments = this.arguments.concat(schematicOptions.arguments.map(a => a.name));
3738
}
3839

3940
public async run(options: UpdateOptions) {

packages/@angular/cli/models/command.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,12 @@ export abstract class Command {
6262
this.logger.info(`options:`);
6363
this.options
6464
.filter(o => !o.hidden)
65+
.sort((a, b) => a.name >= b.name ? 1 : -1)
6566
.forEach(o => {
6667
const aliases = o.aliases && o.aliases.length > 0
6768
? '(' + o.aliases.map(a => `-${a}`).join(' ') + ')'
6869
: '';
69-
this.logger.info(` ${cyan(o.name)} ${aliases}`);
70+
this.logger.info(` ${cyan('--' + o.name)} ${aliases}`);
7071
this.logger.info(` ${o.description}`);
7172
});
7273
}

packages/@angular/cli/models/schematic-command.ts

Lines changed: 30 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { DryRunEvent, UnsuccessfulWorkflowExecution } from '@angular-devkit/sche
77
import { getCollection, getSchematic } from '../utilities/schematics';
88
import { take } from 'rxjs/operators';
99
import { WorkspaceLoader } from '../models/workspace-loader';
10-
import chalk from 'chalk';
1110

1211
export interface CoreSchematicOptions {
1312
dryRun: boolean;
@@ -28,20 +27,11 @@ export interface GetOptionsOptions {
2827
schematicName: string;
2928
}
3029

31-
export interface GetHelpOutputOptions {
32-
collectionName: string;
33-
schematicName: string;
34-
nonSchematicOptions: any[];
30+
export interface GetOptionsResult {
31+
options: Option[];
32+
arguments: Option[];
3533
}
3634

37-
const hiddenOptions = [
38-
'name',
39-
'path',
40-
'source-dir',
41-
'app-root',
42-
'link-cli',
43-
];
44-
4535
export abstract class SchematicCommand extends Command {
4636
readonly options: Option[] = [];
4737
private _host = new NodeJsSyncHost();
@@ -185,7 +175,7 @@ export abstract class SchematicCommand extends Command {
185175
return opts;
186176
}
187177

188-
protected getOptions(options: GetOptionsOptions): Promise<Option[] | null> {
178+
protected getOptions(options: GetOptionsOptions): Promise<GetOptionsResult> {
189179
// TODO: get default collectionName
190180
const collectionName = options.collectionName || '@schematics/angular';
191181

@@ -195,7 +185,10 @@ export abstract class SchematicCommand extends Command {
195185
this._deAliasedName = schematic.description.name;
196186

197187
if (!schematic.description.schemaJson) {
198-
return Promise.resolve(null);
188+
return Promise.resolve({
189+
options: [],
190+
arguments: []
191+
});
199192
}
200193

201194
const properties = schematic.description.schemaJson.properties;
@@ -228,7 +221,6 @@ export abstract class SchematicCommand extends Command {
228221
if (opt.aliases) {
229222
aliases = [...aliases, ...opt.aliases];
230223
}
231-
232224
const schematicDefault = opt.default;
233225

234226
return {
@@ -243,54 +235,31 @@ export abstract class SchematicCommand extends Command {
243235
})
244236
.filter(x => x);
245237

246-
return Promise.resolve(availableOptions);
247-
}
248-
249-
protected getHelpOutput(
250-
{ schematicName, collectionName, nonSchematicOptions }: GetHelpOutputOptions):
251-
Promise<string[]> {
238+
const schematicOptions = availableOptions
239+
.filter(opt => opt.$default === undefined || opt.$default.$source !== 'argv');
252240

253-
const SchematicGetOptionsTask = require('./schematic-get-options').default;
254-
const getOptionsTask = new SchematicGetOptionsTask({
255-
ui: this.ui,
256-
project: this.project
257-
});
258-
return Promise.all([getOptionsTask.run({
259-
schematicName: schematicName,
260-
collectionName: collectionName,
261-
}), nonSchematicOptions])
262-
.then(([availableOptions, nonSchematicOptions]: [Option[], any[]]) => {
263-
const output: string[] = [];
264-
[...(nonSchematicOptions || []), ...availableOptions || []]
265-
.filter(opt => hiddenOptions.indexOf(opt.name) === -1)
266-
.forEach(opt => {
267-
let text = chalk.cyan(` --${opt.name}`);
268-
if (opt.schematicType) {
269-
text += chalk.cyan(` (${opt.schematicType})`);
270-
}
271-
if (opt.schematicDefault) {
272-
text += chalk.cyan(` (Default: ${opt.schematicDefault})`);
273-
}
274-
if (opt.description) {
275-
text += ` ${opt.description}`;
276-
}
277-
output.push(text);
278-
if (opt.aliases && opt.aliases.length > 0) {
279-
const aliasText = opt.aliases.reduce(
280-
(acc: string, curr: string) => {
281-
return acc + ` -${curr}`;
282-
},
283-
'');
284-
output.push(chalk.grey(` aliases: ${aliasText}`));
285-
}
286-
});
287-
if (availableOptions === null) {
288-
output.push(chalk.green('This schematic accept additional options, but did not provide '
289-
+ 'documentation.'));
241+
const schematicArguments = availableOptions
242+
.filter(opt => opt.$default !== undefined && opt.$default.$source === 'argv')
243+
.sort((a, b) => {
244+
if (a.$default.index === undefined) {
245+
return 1;
246+
}
247+
if (b.$default.index === undefined) {
248+
return -1;
249+
}
250+
if (a.$default.index == b.$default.index) {
251+
return 0;
252+
} else if (a.$default.index > b.$default.index) {
253+
return 1;
254+
} else {
255+
return -1;
290256
}
291-
292-
return output;
293257
});
258+
259+
return Promise.resolve({
260+
options: schematicOptions,
261+
arguments: schematicArguments
262+
});
294263
}
295264

296265
private _loadWorkspace() {
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import {join} from 'path';
2+
import {ng} from '../../utils/process';
3+
import {writeMultipleFiles, createDir} from '../../utils/fs';
4+
5+
6+
export default function() {
7+
// setup temp collection
8+
const genRoot = join('node_modules/fake-schematics/');
9+
10+
return Promise.resolve()
11+
.then(() => createDir(genRoot))
12+
.then(() => writeMultipleFiles({
13+
[join(genRoot, 'package.json')]: `
14+
{
15+
"schematics": "./collection.json"
16+
}`,
17+
[join(genRoot, 'collection.json')]: `
18+
{
19+
"schematics": {
20+
"fake": {
21+
"factory": "./fake",
22+
"description": "Fake schematic",
23+
"schema": "./fake-schema.json"
24+
}
25+
}
26+
}`,
27+
[join(genRoot, 'fake-schema.json')]: `
28+
{
29+
"id": "FakeSchema",
30+
"title": "Fake Schema",
31+
"type": "object",
32+
"properties": {
33+
"b": {
34+
"type": "string",
35+
"description": "b.",
36+
"$default": {
37+
"$source": "argv",
38+
"index": 1
39+
}
40+
},
41+
"a": {
42+
"type": "string",
43+
"description": "a.",
44+
"$default": {
45+
"$source": "argv",
46+
"index": 0
47+
}
48+
},
49+
"optC": {
50+
"type": "string",
51+
"description": "optC"
52+
},
53+
"optA": {
54+
"type": "string",
55+
"description": "optA"
56+
},
57+
"optB": {
58+
"type": "string",
59+
"description": "optB"
60+
}
61+
},
62+
"required": []
63+
}`,
64+
[join(genRoot, 'fake.js')]: `
65+
function def(options) {
66+
return (host, context) => {
67+
return host;
68+
};
69+
}
70+
exports.default = def;
71+
`},
72+
))
73+
.then(() => ng('generate', 'fake-schematics:fake', '--help'))
74+
.then(({stdout}) => {
75+
console.warn('stdout start');
76+
console.error(stdout);
77+
console.warn('stdout end');
78+
if (!/ng generate fake-schematics:fake <a> <b> \[options\]/.test(stdout)) {
79+
throw new Error('Help signature is wrong.');
80+
}
81+
if (!/opt-a[\s\S]*opt-b[\s\S]*opt-c/.test(stdout)) {
82+
throw new Error('Help signature options are incorrect.');
83+
}
84+
});
85+
86+
}

0 commit comments

Comments
 (0)