Skip to content

Commit 387472a

Browse files
committed
fix(@angular/cli): register schematic aliases when providing collection name in ng generate
Previously, schematic aliases were not registered when a collection name was provided to `ng generate`. Example: `ng generate c` where `c` is an alias for `component` would work, but `ng generate @schematics/angular:c` would fail. This commits fixes the schematic registration to handle the latter case. Closes #24518 (cherry picked from commit 3ebb195)
1 parent b000481 commit 387472a

File tree

2 files changed

+65
-16
lines changed

2 files changed

+65
-16
lines changed

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

+51-16
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ export class GenerateCommandModule
7979
// When 'describe' is set to false, it results in a hidden command.
8080
describe: hidden === true ? false : typeof description === 'string' ? description : '',
8181
deprecated: xDeprecated === true || typeof xDeprecated === 'string' ? xDeprecated : false,
82-
aliases: Array.isArray(aliases) ? (aliases as string[]) : undefined,
82+
aliases: Array.isArray(aliases)
83+
? await this.generateCommandAliasesStrings(collectionName, aliases as string[])
84+
: undefined,
8385
builder: (localYargs) => this.addSchemaOptionsToCommand(localYargs, options).strict(),
8486
handler: (options) =>
8587
this.handler({ ...options, schematic: `${collectionName}:${schematicName}` }),
@@ -120,6 +122,41 @@ export class GenerateCommandModule
120122
return collectionName ? [collectionName] : [...(await this.getSchematicCollections())];
121123
}
122124

125+
private async shouldAddCollectionNameAsPartOfCommand(): Promise<boolean> {
126+
const [collectionNameFromArgs] = this.parseSchematicInfo(
127+
// positional = [generate, component] or [generate]
128+
this.context.args.positional[1],
129+
);
130+
131+
const schematicCollectionsFromConfig = await this.getSchematicCollections();
132+
const collectionNames = await this.getCollectionNames();
133+
134+
// Only add the collection name as part of the command when it's not a known
135+
// schematics collection or when it has been provided via the CLI.
136+
// Ex:`ng generate @schematics/angular:c`
137+
return (
138+
!!collectionNameFromArgs ||
139+
!collectionNames.some((c) => schematicCollectionsFromConfig.has(c))
140+
);
141+
}
142+
143+
/**
144+
* Generate an aliases string array to be passed to the command builder.
145+
*
146+
* @example `[component]` or `[@schematics/angular:component]`.
147+
*/
148+
private async generateCommandAliasesStrings(
149+
collectionName: string,
150+
schematicAliases: string[],
151+
): Promise<string[]> {
152+
// Only add the collection name as part of the command when it's not a known
153+
// schematics collection or when it has been provided via the CLI.
154+
// Ex:`ng generate @schematics/angular:c`
155+
return (await this.shouldAddCollectionNameAsPartOfCommand())
156+
? schematicAliases.map((alias) => `${collectionName}:${alias}`)
157+
: schematicAliases;
158+
}
159+
123160
/**
124161
* Generate a command string to be passed to the command builder.
125162
*
@@ -130,23 +167,14 @@ export class GenerateCommandModule
130167
schematicName: string,
131168
options: Option[],
132169
): Promise<string> {
133-
const [collectionNameFromArgs] = this.parseSchematicInfo(
134-
// positional = [generate, component] or [generate]
135-
this.context.args.positional[1],
136-
);
137-
138170
const dasherizedSchematicName = strings.dasherize(schematicName);
139-
const schematicCollectionsFromConfig = await this.getSchematicCollections();
140-
const collectionNames = await this.getCollectionNames();
141171

142172
// Only add the collection name as part of the command when it's not a known
143173
// schematics collection or when it has been provided via the CLI.
144174
// Ex:`ng generate @schematics/angular:component`
145-
const commandName =
146-
!!collectionNameFromArgs ||
147-
!collectionNames.some((c) => schematicCollectionsFromConfig.has(c))
148-
? collectionName + ':' + dasherizedSchematicName
149-
: dasherizedSchematicName;
175+
const commandName = (await this.shouldAddCollectionNameAsPartOfCommand())
176+
? collectionName + ':' + dasherizedSchematicName
177+
: dasherizedSchematicName;
150178

151179
const positionalArgs = options
152180
.filter((o) => o.positional !== undefined)
@@ -165,6 +193,7 @@ export class GenerateCommandModule
165193
*/
166194
private async *getSchematics(): AsyncGenerator<{
167195
schematicName: string;
196+
schematicAliases?: Set<string>;
168197
collectionName: string;
169198
}> {
170199
const seenNames = new Set<string>();
@@ -176,7 +205,10 @@ export class GenerateCommandModule
176205
// If a schematic with this same name is already registered skip.
177206
if (!seenNames.has(schematicName)) {
178207
seenNames.add(schematicName);
179-
yield { schematicName, collectionName };
208+
const { aliases } = collection.description.schematics[schematicName];
209+
const schematicAliases = aliases && new Set(aliases);
210+
211+
yield { schematicName, schematicAliases, collectionName };
180212
}
181213
}
182214
}
@@ -196,8 +228,11 @@ export class GenerateCommandModule
196228
this.context.args.positional[1],
197229
);
198230

199-
for await (const { schematicName, collectionName } of this.getSchematics()) {
200-
if (schematicName === schematicNameFromArgs) {
231+
for await (const { schematicName, collectionName, schematicAliases } of this.getSchematics()) {
232+
if (
233+
schematicNameFromArgs &&
234+
(schematicName === schematicNameFromArgs || schematicAliases?.has(schematicNameFromArgs))
235+
) {
201236
return [[schematicName, collectionName]];
202237
}
203238

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { ng } from '../../utils/process';
2+
3+
export default async function () {
4+
const schematicNameVariation = [
5+
'component',
6+
'c',
7+
'@schematics/angular:component',
8+
'@schematics/angular:c',
9+
];
10+
11+
for (const schematic of schematicNameVariation) {
12+
await ng('generate', schematic, 'comp-name', '--display-block', '--dry-run');
13+
}
14+
}

0 commit comments

Comments
 (0)