Skip to content

Commit d274add

Browse files
authored
fix(@angular/cli): use correct schematic defaults considering workspace (#15041)
Fix #14986 This PR includes some refactoring to simplify the interaction of the `NodeWorkflow` and the `BaseWorkflow` with the registry. We were registering redundant `addPostTransform`s. Some of them in the constructor of the `BaseWorkflow`, which did not allow us to intercept `addUndefinedDefaults`. Additionally, we were setting the `validateOptionsWithSchema` transform multiple times unnecessarily. An issue left to fix is support for the `--project` option in schematic commands. Currently, `getProjectName` does not know about this option, since `createWorkflow` does not know how to parse the command line arguments. The parsing logic is implemented partially by the concrete implementation of the `SchematicCommand` template method.
1 parent dbea7d5 commit d274add

File tree

6 files changed

+46
-18
lines changed

6 files changed

+46
-18
lines changed

etc/api/angular_devkit/schematics/tools/index.d.ts

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export declare type FileSystemCollection = Collection<FileSystemCollectionDescri
2828
export declare type FileSystemCollectionDesc = CollectionDescription<FileSystemCollectionDescription>;
2929

3030
export interface FileSystemCollectionDescription {
31+
readonly name: string;
3132
readonly path: string;
3233
readonly schematics: {
3334
[name: string]: FileSystemSchematicDesc;
@@ -92,9 +93,11 @@ export interface FileSystemSchematicDescription extends FileSystemSchematicJsonD
9293

9394
export interface FileSystemSchematicJsonDescription {
9495
readonly aliases?: string[];
96+
readonly collection: FileSystemCollectionDescription;
9597
readonly description: string;
9698
readonly extends?: string;
9799
readonly factory: string;
100+
readonly name: string;
98101
readonly schema?: string;
99102
}
100103

@@ -135,6 +138,7 @@ export declare class NodeWorkflow extends workflow.BaseWorkflow {
135138
dryRun?: boolean;
136139
root?: Path;
137140
packageManager?: string;
141+
registry?: schema.CoreSchemaRegistry;
138142
});
139143
}
140144

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

+27-11
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,17 @@ import {
1616
workspaces,
1717
} from '@angular-devkit/core';
1818
import { NodeJsSyncHost } from '@angular-devkit/core/node';
19-
import { DryRunEvent, UnsuccessfulWorkflowExecution, workflow } from '@angular-devkit/schematics';
19+
import {
20+
DryRunEvent,
21+
UnsuccessfulWorkflowExecution,
22+
formats,
23+
workflow,
24+
} from '@angular-devkit/schematics';
2025
import {
2126
FileSystemCollection,
2227
FileSystemEngine,
2328
FileSystemSchematic,
29+
FileSystemSchematicDescription,
2430
NodeWorkflow,
2531
validateOptionsWithSchema,
2632
} from '@angular-devkit/schematics/tools';
@@ -246,6 +252,7 @@ export abstract class SchematicCommand<
246252
dryRun,
247253
packageManager: getPackageManager(this.workspace.root),
248254
root: normalize(this.workspace.root),
255+
registry: new schema.CoreSchemaRegistry(formats.standardFormats),
249256
});
250257
workflow.engineHost.registerContextTransform(context => {
251258
// This is run by ALL schematics, so if someone uses `externalSchematics(...)` which
@@ -261,15 +268,7 @@ export abstract class SchematicCommand<
261268
}
262269
});
263270

264-
workflow.engineHost.registerOptionsTransform(validateOptionsWithSchema(workflow.registry));
265-
266-
if (options.defaults) {
267-
workflow.registry.addPreTransform(schema.transforms.addUndefinedDefaults);
268-
} else {
269-
workflow.registry.addPostTransform(schema.transforms.addUndefinedDefaults);
270-
}
271-
272-
workflow.registry.addSmartDefaultProvider('projectName', () => {
271+
const getProjectName = () => {
273272
if (this._workspace) {
274273
const projectNames = getProjectsByPath(this._workspace, process.cwd(), this.workspace.root);
275274

@@ -292,7 +291,24 @@ export abstract class SchematicCommand<
292291
}
293292

294293
return undefined;
295-
});
294+
};
295+
296+
workflow.engineHost.registerOptionsTransform(
297+
<T extends {}>(schematic: FileSystemSchematicDescription, current: T) => ({
298+
...getSchematicDefaults(schematic.collection.name, schematic.name, getProjectName()),
299+
...current,
300+
}),
301+
);
302+
303+
if (options.defaults) {
304+
workflow.registry.addPreTransform(schema.transforms.addUndefinedDefaults);
305+
} else {
306+
workflow.registry.addPostTransform(schema.transforms.addUndefinedDefaults);
307+
}
308+
309+
workflow.engineHost.registerOptionsTransform(validateOptionsWithSchema(workflow.registry));
310+
311+
workflow.registry.addSmartDefaultProvider('projectName', getProjectName);
296312

297313
if (options.interactive !== false && isTTY()) {
298314
workflow.registry.usePromptProvider((definitions: Array<schema.PromptDefinition>) => {

packages/angular_devkit/schematics/tools/description.ts

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919

2020

2121
export interface FileSystemCollectionDescription {
22+
readonly name: string;
2223
readonly path: string;
2324
readonly version?: string;
2425
readonly schematics: { [name: string]: FileSystemSchematicDesc };
@@ -28,6 +29,8 @@ export interface FileSystemCollectionDescription {
2829
export interface FileSystemSchematicJsonDescription {
2930
readonly aliases?: string[];
3031
readonly factory: string;
32+
readonly name: string;
33+
readonly collection: FileSystemCollectionDescription;
3134
readonly description: string;
3235
readonly schema?: string;
3336
readonly extends?: string;

packages/angular_devkit/schematics/tools/workflow/node-workflow.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
import { Path, getSystemPath, virtualFs } from '@angular-devkit/core';
8+
import { Path, getSystemPath, schema, virtualFs } from '@angular-devkit/core';
99
import {
1010
workflow,
1111
} from '@angular-devkit/schematics'; // tslint:disable-line:no-implicit-dependencies
1212
import { BuiltinTaskExecutor } from '../../tasks/node';
1313
import { FileSystemEngine } from '../description';
1414
import { NodeModulesEngineHost } from '../node-module-engine-host';
15-
import { validateOptionsWithSchema } from '../schema-option-transform';
1615

1716
/**
1817
* A workflow specifically for Node tools.
@@ -23,8 +22,9 @@ export class NodeWorkflow extends workflow.BaseWorkflow {
2322
options: {
2423
force?: boolean;
2524
dryRun?: boolean;
26-
root?: Path,
25+
root?: Path;
2726
packageManager?: string;
27+
registry?: schema.CoreSchemaRegistry;
2828
},
2929
) {
3030
const engineHost = new NodeModulesEngineHost();
@@ -34,9 +34,9 @@ export class NodeWorkflow extends workflow.BaseWorkflow {
3434

3535
force: options.force,
3636
dryRun: options.dryRun,
37+
registry: options.registry
3738
});
3839

39-
engineHost.registerOptionsTransform(validateOptionsWithSchema(this._registry));
4040
engineHost.registerTaskExecutor(
4141
BuiltinTaskExecutor.NodePackage,
4242
{

packages/angular_devkit/schematics/tools/workflow/node-workflow_spec.ts

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88
// tslint:disable:no-implicit-dependencies
9+
import { schema } from '@angular-devkit/core';
910
import { NodeJsSyncHost } from '@angular-devkit/core/node';
1011
import { NodeWorkflow } from '@angular-devkit/schematics/tools';
1112
import * as path from 'path';

packages/angular_devkit/schematics_cli/bin/schematics.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
* found in the LICENSE file at https://angular.io/license
88
*/
99

10-
import 'symbol-observable';
1110
// symbol polyfill must go first
11+
import 'symbol-observable';
1212
// tslint:disable-next-line:ordered-imports import-groups
1313
import {
1414
JsonObject,
@@ -24,8 +24,9 @@ import {
2424
DryRunEvent,
2525
SchematicEngine,
2626
UnsuccessfulWorkflowExecution,
27+
formats
2728
} from '@angular-devkit/schematics';
28-
import { NodeModulesEngineHost, NodeWorkflow } from '@angular-devkit/schematics/tools';
29+
import { NodeModulesEngineHost, NodeWorkflow, validateOptionsWithSchema } from '@angular-devkit/schematics/tools';
2930
import * as inquirer from 'inquirer';
3031
import * as minimist from 'minimist';
3132

@@ -160,9 +161,12 @@ export async function main({
160161

161162
/** Create a Virtual FS Host scoped to where the process is being run. **/
162163
const fsHost = new virtualFs.ScopedHost(new NodeJsSyncHost(), normalize(process.cwd()));
164+
const registry = new schema.CoreSchemaRegistry(formats.standardFormats);
163165

164166
/** Create the workflow that will be executed with this run. */
165-
const workflow = new NodeWorkflow(fsHost, { force, dryRun });
167+
const workflow = new NodeWorkflow(fsHost, { force, dryRun, registry });
168+
registry.addPostTransform(schema.transforms.addUndefinedDefaults);
169+
workflow.engineHost.registerOptionsTransform(validateOptionsWithSchema(registry));
166170

167171
// Indicate to the user when nothing has been done. This is automatically set to off when there's
168172
// a new DryRunEvent.

0 commit comments

Comments
 (0)