Skip to content

Commit ba3f671

Browse files
alan-agius4dgp1130
authored andcommitted
fix(@angular/cli): temporarily handle boolean options in schema prefixed with no
With this commit we introduce an interim solution for options prefixed with `no` in `schema.json` Previously, such options were handled as normal boolean option, but yargs handles options prefixed with `no` as negatations of the original option. Example with yargs, an option `noWatch` is will registered as `watch`. Closes #23397
1 parent 507a7e2 commit ba3f671

File tree

6 files changed

+81
-2
lines changed

6 files changed

+81
-2
lines changed

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

+32-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { analytics, logging, schema, strings } from '@angular-devkit/core';
1010
import { readFileSync } from 'fs';
1111
import * as path from 'path';
1212
import {
13+
Arguments,
1314
ArgumentsCamelCase,
1415
Argv,
1516
CamelCaseKey,
@@ -199,6 +200,8 @@ export abstract class CommandModule<T extends {} = {}> implements CommandModuleI
199200
* **Note:** This method should be called from the command bundler method.
200201
*/
201202
protected addSchemaOptionsToCommand<T>(localYargs: Argv<T>, options: Option[]): Argv<T> {
203+
const booleanOptionsWithNoPrefix = new Set<string>();
204+
202205
for (const option of options) {
203206
const {
204207
default: defaultVal,
@@ -223,13 +226,27 @@ export abstract class CommandModule<T extends {} = {}> implements CommandModuleI
223226
...(this.context.args.options.help ? { default: defaultVal } : {}),
224227
};
225228

229+
// TODO(alanagius4): remove in a major version.
230+
// the below is an interim workaround to handle options which have been defined in the schema with `no` prefix.
231+
let dashedName = strings.dasherize(name);
232+
if (type === 'boolean' && dashedName.startsWith('no-')) {
233+
dashedName = dashedName.slice(3);
234+
booleanOptionsWithNoPrefix.add(dashedName);
235+
236+
// eslint-disable-next-line no-console
237+
console.warn(
238+
`Warning: '${name}' option has been declared with a 'no' prefix in the schema.` +
239+
'Please file an issue with the author of this package.',
240+
);
241+
}
242+
226243
if (positional === undefined) {
227-
localYargs = localYargs.option(strings.dasherize(name), {
244+
localYargs = localYargs.option(dashedName, {
228245
type,
229246
...sharedOptions,
230247
});
231248
} else {
232-
localYargs = localYargs.positional(strings.dasherize(name), {
249+
localYargs = localYargs.positional(dashedName, {
233250
type: type === 'array' || type === 'count' ? 'string' : type,
234251
...sharedOptions,
235252
});
@@ -241,6 +258,19 @@ export abstract class CommandModule<T extends {} = {}> implements CommandModuleI
241258
}
242259
}
243260

261+
// TODO(alanagius4): remove in a major version.
262+
// the below is an interim workaround to handle options which have been defined in the schema with `no` prefix.
263+
if (booleanOptionsWithNoPrefix.size) {
264+
localYargs.middleware((options: Arguments) => {
265+
for (const key of booleanOptionsWithNoPrefix) {
266+
if (key in options) {
267+
options[`no-${key}`] = !options[key];
268+
delete options[key];
269+
}
270+
}
271+
}, false);
272+
}
273+
244274
return localYargs;
245275
}
246276

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"schematics": {
3+
"test": {
4+
"factory": "./index.js",
5+
"schema": "./schema.json",
6+
"description": "test schematic that logs the options in the console."
7+
}
8+
}
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
exports.default = (options) => console.log(options);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"name": "schematic-boolean-option",
3+
"version": "0.0.1",
4+
"schematics": "./collection.json"
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema",
3+
"type": "object",
4+
"description": "test schematic that logs the options in the console.",
5+
"properties": {
6+
"noWatch": {
7+
"type": "boolean"
8+
}
9+
}
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { copyAssets } from '../../utils/assets';
2+
import { execAndWaitForOutputToMatch } from '../../utils/process';
3+
4+
export default async function () {
5+
await copyAssets('schematic-boolean-option-negated', 'schematic-boolean-option-negated');
6+
7+
await execAndWaitForOutputToMatch(
8+
'ng',
9+
['generate', './schematic-boolean-option-negated:test', '--no-watch'],
10+
/noWatch: true/,
11+
);
12+
13+
await execAndWaitForOutputToMatch(
14+
'ng',
15+
['generate', './schematic-boolean-option-negated:test', '--watch'],
16+
/noWatch: false/,
17+
);
18+
19+
await execAndWaitForOutputToMatch(
20+
'ng',
21+
['generate', './schematic-boolean-option-negated:test'],
22+
/'noWatch' option has been declared with a 'no' prefix in the schema/,
23+
);
24+
}

0 commit comments

Comments
 (0)