Skip to content

Commit e751464

Browse files
alan-agius4dgp1130
authored andcommitted
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 cd2250f commit e751464

File tree

15 files changed

+78
-19
lines changed

15 files changed

+78
-19
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: 41 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, isJsonObject, 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,10 +133,16 @@ 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+
139+
const workingDir = devkitNormalize(relative(this.context.root, process.cwd()));
140+
workflow.registry.addSmartDefaultProvider('workingDirectory', () =>
141+
workingDir === '' ? undefined : workingDir,
142+
);
138143

139144
let shouldReportAnalytics = true;
145+
140146
workflow.engineHost.registerOptionsTransform(async (schematic, options) => {
141147
if (shouldReportAnalytics) {
142148
shouldReportAnalytics = false;
@@ -150,6 +156,35 @@ export abstract class SchematicsCommandModule
150156
]);
151157
}
152158

159+
// TODO: The below should be removed in version 15 when we change 1P schematics to use the `workingDirectory smart default`.
160+
// Handle `"format": "path"` options.
161+
const schema = schematic?.schemaJson;
162+
if (!options || !schema || !isJsonObject(schema)) {
163+
return options;
164+
}
165+
166+
if (!('path' in options && (options as Record<string, unknown>)['path'] === undefined)) {
167+
return options;
168+
}
169+
170+
const properties = schema?.['properties'];
171+
if (!properties || !isJsonObject(properties)) {
172+
return options;
173+
}
174+
175+
const property = properties['path'];
176+
if (!property || !isJsonObject(property)) {
177+
return options;
178+
}
179+
180+
if (property['format'] === 'path' && !property['$default']) {
181+
(options as Record<string, unknown>)['path'] = workingDir || undefined;
182+
this.context.logger.warn(
183+
`The 'path' option in '${schematic?.schema}' is using deprecated behaviour.` +
184+
`'workingDirectory' smart default provider should be used instead.`,
185+
);
186+
}
187+
153188
return options;
154189
});
155190

@@ -356,9 +391,9 @@ export abstract class SchematicsCommandModule
356391
if (typeof defaultProjectName === 'string' && defaultProjectName) {
357392
if (!this.defaultProjectDeprecationWarningShown) {
358393
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-
`);
394+
DEPRECATED: The 'defaultProject' workspace option has been deprecated.
395+
The project to use will be determined from the current working directory.
396+
`);
362397

363398
this.defaultProjectDeprecationWarningShown = true;
364399
}

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 & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
"path": {
1919
"type": "string",
2020
"format": "path",
21+
"$default": {
22+
"$source": "workingDirectory"
23+
},
2124
"description": "The path at which to create the class, relative to the workspace root.",
2225
"visible": false
2326
},

packages/schematics/angular/component/schema.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
"path": {
1010
"type": "string",
1111
"format": "path",
12+
"$default": {
13+
"$source": "workingDirectory"
14+
},
1215
"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.",
1316
"visible": false
1417
},

packages/schematics/angular/directive/schema.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
"path": {
1919
"type": "string",
2020
"format": "path",
21+
"$default": {
22+
"$source": "workingDirectory"
23+
},
2124
"description": "The path at which to create the interface that defines the directive, relative to the workspace root.",
2225
"visible": false
2326
},

packages/schematics/angular/enum/schema.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
"path": {
1919
"type": "string",
2020
"format": "path",
21+
"$default": {
22+
"$source": "workingDirectory"
23+
},
2124
"description": "The path at which to create the enum definition, relative to the current workspace.",
2225
"visible": false
2326
},

packages/schematics/angular/guard/schema.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
"path": {
3030
"type": "string",
3131
"format": "path",
32+
"$default": {
33+
"$source": "workingDirectory"
34+
},
3235
"description": "The path at which to create the interface that defines the guard, relative to the current workspace.",
3336
"visible": false
3437
},

packages/schematics/angular/interceptor/schema.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
"path": {
1919
"type": "string",
2020
"format": "path",
21+
"$default": {
22+
"$source": "workingDirectory"
23+
},
2124
"description": "The path at which to create the interceptor, relative to the workspace root.",
2225
"visible": false
2326
},

packages/schematics/angular/interface/schema.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
"path": {
1919
"type": "string",
2020
"format": "path",
21+
"$default": {
22+
"$source": "workingDirectory"
23+
},
2124
"description": "The path at which to create the interface, relative to the workspace root.",
2225
"visible": false
2326
},

packages/schematics/angular/module/schema.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
"path": {
1919
"type": "string",
2020
"format": "path",
21+
"$default": {
22+
"$source": "workingDirectory"
23+
},
2124
"description": "The path at which to create the NgModule, relative to the workspace root.",
2225
"visible": false
2326
},

packages/schematics/angular/pipe/schema.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
"path": {
1919
"type": "string",
2020
"format": "path",
21+
"$default": {
22+
"$source": "workingDirectory"
23+
},
2124
"description": "The path at which to create the pipe, relative to the workspace root.",
2225
"visible": false
2326
},

packages/schematics/angular/resolver/schema.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
"path": {
3030
"type": "string",
3131
"format": "path",
32+
"$default": {
33+
"$source": "workingDirectory"
34+
},
3235
"description": "The path at which to create the interface that defines the resolver, relative to the current workspace.",
3336
"visible": false
3437
},

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/web-worker/schema.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
"path": {
1010
"type": "string",
1111
"format": "path",
12+
"$default": {
13+
"$source": "workingDirectory"
14+
},
1215
"description": "The path at which to create the worker file, relative to the current workspace.",
1316
"visible": false
1417
},

0 commit comments

Comments
 (0)