Skip to content

Commit 343ad56

Browse files
committed
fix(@angular/cli): populate path with working directory in nested schematics
With this change we change the how we handle `"format": "path"` schematic property option. We replace the formatter in favour of a `SmartDefaultProvider`, which ensures that nested schematics can access the `workingDirectory`.
1 parent fe3d8ca commit 343ad56

File tree

22 files changed

+58
-40
lines changed

22 files changed

+58
-40
lines changed

packages/angular/cli/src/command-builder/command-module.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import { analytics, logging, normalize, schema, strings } from '@angular-devkit/core';
9+
import { analytics, logging, schema, strings } from '@angular-devkit/core';
1010
import { readFileSync } from 'fs';
1111
import * as path from 'path';
1212
import {
@@ -197,8 +197,6 @@ export abstract class CommandModule<T extends {} = {}> implements CommandModuleI
197197
* **Note:** This method should be called from the command bundler method.
198198
*/
199199
protected addSchemaOptionsToCommand<T>(localYargs: Argv<T>, options: Option[]): Argv<T> {
200-
const workingDir = normalize(path.relative(this.context.root, process.cwd()));
201-
202200
for (const option of options) {
203201
const {
204202
default: defaultVal,
@@ -211,7 +209,6 @@ export abstract class CommandModule<T extends {} = {}> implements CommandModuleI
211209
hidden,
212210
name,
213211
choices,
214-
format,
215212
} = option;
216213

217214
const sharedOptions: YargsOptions & PositionalOptions = {
@@ -224,11 +221,6 @@ export abstract class CommandModule<T extends {} = {}> implements CommandModuleI
224221
...(this.context.args.options.help ? { default: defaultVal } : {}),
225222
};
226223

227-
// Special case for schematics
228-
if (workingDir && format === 'path' && name === 'path' && hidden) {
229-
sharedOptions.default = workingDir;
230-
}
231-
232224
if (positional === undefined) {
233225
localYargs = localYargs.option(strings.dasherize(name), {
234226
type,

packages/angular/cli/src/command-builder/schematics-command-module.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import { schema, tags } from '@angular-devkit/core';
9+
import { normalize as devkitNormalize, schema, tags } from '@angular-devkit/core';
1010
import { Collection, UnsuccessfulWorkflowExecution, formats } from '@angular-devkit/schematics';
1111
import {
1212
FileSystemCollectionDescription,
1313
FileSystemSchematicDescription,
1414
NodeWorkflow,
1515
} from '@angular-devkit/schematics/tools';
1616
import type { CheckboxQuestion, Question } from 'inquirer';
17-
import { resolve } from 'path';
17+
import { relative, resolve } from 'path';
1818
import { Argv } from 'yargs';
1919
import { getProjectByCwd, getSchematicDefaults } from '../utilities/config';
2020
import { memoize } from '../utilities/memoize';
@@ -133,8 +133,11 @@ export abstract class SchematicsCommandModule
133133
});
134134

135135
workflow.registry.addPostTransform(schema.transforms.addUndefinedDefaults);
136-
workflow.registry.addSmartDefaultProvider('projectName', () => this.getProjectName());
137136
workflow.registry.useXDeprecatedProvider((msg) => logger.warn(msg));
137+
workflow.registry.addSmartDefaultProvider('projectName', () => this.getProjectName());
138+
workflow.registry.addSmartDefaultProvider('workingDirectory', () =>
139+
devkitNormalize(relative(this.context.root, process.cwd())),
140+
);
138141

139142
let shouldReportAnalytics = true;
140143
workflow.engineHost.registerOptionsTransform(async (schematic, options) => {
@@ -356,9 +359,9 @@ export abstract class SchematicsCommandModule
356359
if (typeof defaultProjectName === 'string' && defaultProjectName) {
357360
if (!this.defaultProjectDeprecationWarningShown) {
358361
logger.warn(tags.oneLine`
359-
DEPRECATED: The 'defaultProject' workspace option has been deprecated.
360-
The project to use will be determined from the current working directory.
361-
`);
362+
DEPRECATED: The 'defaultProject' workspace option has been deprecated.
363+
The project to use will be determined from the current working directory.
364+
`);
362365

363366
this.defaultProjectDeprecationWarningShown = true;
364367
}

packages/schematics/angular/app-shell/schema.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,16 @@
2727
},
2828
"main": {
2929
"type": "string",
30-
"format": "path",
3130
"description": "The name of the main entry-point file.",
3231
"default": "main.server.ts"
3332
},
3433
"appDir": {
3534
"type": "string",
36-
"format": "path",
3735
"description": "The name of the application directory.",
3836
"default": "app"
3937
},
4038
"rootModuleFileName": {
4139
"type": "string",
42-
"format": "path",
4340
"description": "The name of the root module file",
4441
"default": "app.server.module.ts"
4542
},

packages/schematics/angular/class/schema.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
},
1818
"path": {
1919
"type": "string",
20-
"format": "path",
20+
"$default": {
21+
"$source": "workingDirectory"
22+
},
2123
"description": "The path at which to create the class, relative to the workspace root.",
2224
"visible": false
2325
},

packages/schematics/angular/component/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ export default function (options: ComponentOptions): Rule {
115115
throw new SchematicsException(`Project "${options.project}" does not exist.`);
116116
}
117117

118-
if (options.path === undefined) {
118+
if (!options.path) {
119119
options.path = buildDefaultPath(project);
120120
}
121121

packages/schematics/angular/component/schema.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
"properties": {
99
"path": {
1010
"type": "string",
11-
"format": "path",
11+
"$default": {
12+
"$source": "workingDirectory"
13+
},
1214
"description": "The path at which to create the component file, relative to the current workspace. Default is a folder with the same name as the component in the project root.",
1315
"visible": false
1416
},

packages/schematics/angular/directive/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ export default function (options: DirectiveOptions): Rule {
104104
throw new SchematicsException(`Project "${options.project}" does not exist.`);
105105
}
106106

107-
if (options.path === undefined) {
107+
if (!options.path) {
108108
options.path = buildDefaultPath(project);
109109
}
110110

packages/schematics/angular/directive/schema.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
},
1818
"path": {
1919
"type": "string",
20-
"format": "path",
20+
"$default": {
21+
"$source": "workingDirectory"
22+
},
2123
"description": "The path at which to create the interface that defines the directive, relative to the workspace root.",
2224
"visible": false
2325
},

packages/schematics/angular/enum/schema.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
},
1818
"path": {
1919
"type": "string",
20-
"format": "path",
20+
"$default": {
21+
"$source": "workingDirectory"
22+
},
2123
"description": "The path at which to create the enum definition, relative to the current workspace.",
2224
"visible": false
2325
},

packages/schematics/angular/guard/schema.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
},
2929
"path": {
3030
"type": "string",
31-
"format": "path",
31+
"$default": {
32+
"$source": "workingDirectory"
33+
},
3234
"description": "The path at which to create the interface that defines the guard, relative to the current workspace.",
3335
"visible": false
3436
},

packages/schematics/angular/interceptor/schema.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
},
1818
"path": {
1919
"type": "string",
20-
"format": "path",
20+
"$default": {
21+
"$source": "workingDirectory"
22+
},
2123
"description": "The path at which to create the interceptor, relative to the workspace root.",
2224
"visible": false
2325
},

packages/schematics/angular/interface/schema.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
},
1818
"path": {
1919
"type": "string",
20-
"format": "path",
20+
"$default": {
21+
"$source": "workingDirectory"
22+
},
2123
"description": "The path at which to create the interface, relative to the workspace root.",
2224
"visible": false
2325
},

packages/schematics/angular/library/schema.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
},
2020
"entryFile": {
2121
"type": "string",
22-
"format": "path",
22+
"$default": {
23+
"$source": "workingDirectory"
24+
},
2325
"description": "The path at which to create the library's public API file, relative to the workspace root.",
2426
"default": "public-api"
2527
},

packages/schematics/angular/module/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ function buildRoute(options: ModuleOptions, modulePath: string) {
131131

132132
export default function (options: ModuleOptions): Rule {
133133
return async (host: Tree) => {
134-
if (options.path === undefined) {
134+
if (!options.path) {
135135
options.path = await createDefaultPath(host, options.project as string);
136136
}
137137

packages/schematics/angular/module/schema.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
},
1818
"path": {
1919
"type": "string",
20-
"format": "path",
20+
"$default": {
21+
"$source": "workingDirectory"
22+
},
2123
"description": "The path at which to create the NgModule, relative to the workspace root.",
2224
"visible": false
2325
},

packages/schematics/angular/pipe/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ function addDeclarationToNgModule(options: PipeOptions): Rule {
8484

8585
export default function (options: PipeOptions): Rule {
8686
return async (host: Tree) => {
87-
if (options.path === undefined) {
87+
if (!options.path) {
8888
options.path = await createDefaultPath(host, options.project as string);
8989
}
9090

packages/schematics/angular/pipe/schema.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
},
1818
"path": {
1919
"type": "string",
20-
"format": "path",
20+
"$default": {
21+
"$source": "workingDirectory"
22+
},
2123
"description": "The path at which to create the pipe, relative to the workspace root.",
2224
"visible": false
2325
},

packages/schematics/angular/resolver/schema.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
},
2929
"path": {
3030
"type": "string",
31-
"format": "path",
31+
"$default": {
32+
"$source": "workingDirectory"
33+
},
3234
"description": "The path at which to create the interface that defines the resolver, relative to the current workspace.",
3335
"visible": false
3436
},

packages/schematics/angular/service/schema.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
},
1818
"path": {
1919
"type": "string",
20-
"format": "path",
20+
"$default": {
21+
"$source": "workingDirectory"
22+
},
2123
"description": "The path at which to create the service, relative to the workspace root.",
2224
"visible": false
2325
},

packages/schematics/angular/universal/schema.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,19 @@
2121
},
2222
"main": {
2323
"type": "string",
24-
"format": "path",
2524
"description": "The name of the main entry-point file.",
2625
"default": "main.server.ts"
2726
},
2827
"appDir": {
2928
"type": "string",
30-
"format": "path",
3129
"description": "The name of the application folder.",
3230
"default": "app"
3331
},
3432
"rootModuleFileName": {
3533
"type": "string",
36-
"format": "path",
34+
"$default": {
35+
"$source": "workingDirectory"
36+
},
3737
"description": "The name of the root NgModule file.",
3838
"default": "app.server.module.ts"
3939
},

packages/schematics/angular/web-worker/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ function addSnippet(options: WebWorkerOptions): Rule {
3030
return (host: Tree, context: SchematicContext) => {
3131
context.logger.debug('Updating appmodule');
3232

33-
if (options.path === undefined) {
33+
if (!options.path) {
3434
return;
3535
}
3636

@@ -90,7 +90,7 @@ export default function (options: WebWorkerOptions): Rule {
9090
throw new SchematicsException(`Web Worker requires a project type of "application".`);
9191
}
9292

93-
if (options.path === undefined) {
93+
if (!options.path) {
9494
options.path = buildDefaultPath(project);
9595
}
9696
const parsedPath = parseName(options.path, options.name);

packages/schematics/angular/web-worker/schema.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
"properties": {
99
"path": {
1010
"type": "string",
11-
"format": "path",
11+
"$default": {
12+
"$source": "workingDirectory"
13+
},
1214
"description": "The path at which to create the worker file, relative to the current workspace.",
1315
"visible": false
1416
},

0 commit comments

Comments
 (0)