Skip to content

Commit 30b0cbd

Browse files
hanslKeen Yee Liau
authored and
Keen Yee Liau
committed
refactor(@angular/cli): automated JSON schema interface generation
1 parent 0b3d996 commit 30b0cbd

30 files changed

+348
-166
lines changed

packages/angular/cli/BUILD

+171
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
licenses(["notice"]) # MIT
77

88
load("@build_bazel_rules_typescript//:defs.bzl", "ts_library")
9+
load("//tools:ts_json_schema.bzl", "ts_json_schema")
910

1011
package(default_visibility = ["//visibility:public"])
1112

@@ -21,6 +22,7 @@ ts_library(
2122
data = glob(["**/*.json"]),
2223
module_name = "@angular/cli",
2324
deps = [
25+
":command_schemas",
2426
"//packages/angular_devkit/architect",
2527
"//packages/angular_devkit/core",
2628
"//packages/angular_devkit/core:node",
@@ -34,3 +36,172 @@ ts_library(
3436
# @typings: semver
3537
],
3638
)
39+
40+
ts_library(
41+
name = "command_schemas",
42+
srcs = [],
43+
deps = [
44+
":add_schema",
45+
":build_schema",
46+
":config_schema",
47+
":deprecated_schema",
48+
":doc_schema",
49+
":e2e_schema",
50+
":easter_egg_schema",
51+
":eject_schema",
52+
":generate_schema",
53+
":help_schema",
54+
":lint_schema",
55+
":new_schema",
56+
":run_schema",
57+
":serve_schema",
58+
":test_schema",
59+
":update_schema",
60+
":version_schema",
61+
":xi18n_schema",
62+
],
63+
)
64+
65+
ts_json_schema(
66+
name = "add_schema",
67+
src = "commands/add.json",
68+
data = [
69+
"commands/definitions.json",
70+
],
71+
)
72+
73+
ts_json_schema(
74+
name = "build_schema",
75+
src = "commands/build.json",
76+
data = [
77+
"commands/definitions.json",
78+
],
79+
)
80+
81+
ts_json_schema(
82+
name = "config_schema",
83+
src = "commands/config.json",
84+
data = [
85+
"commands/definitions.json",
86+
],
87+
)
88+
89+
ts_json_schema(
90+
name = "deprecated_schema",
91+
src = "commands/deprecated.json",
92+
data = [
93+
"commands/definitions.json",
94+
],
95+
)
96+
97+
ts_json_schema(
98+
name = "doc_schema",
99+
src = "commands/doc.json",
100+
data = [
101+
"commands/definitions.json",
102+
],
103+
)
104+
105+
ts_json_schema(
106+
name = "e2e_schema",
107+
src = "commands/e2e.json",
108+
data = [
109+
"commands/definitions.json",
110+
],
111+
)
112+
113+
ts_json_schema(
114+
name = "easter_egg_schema",
115+
src = "commands/easter-egg.json",
116+
data = [
117+
"commands/definitions.json",
118+
],
119+
)
120+
121+
ts_json_schema(
122+
name = "eject_schema",
123+
src = "commands/eject.json",
124+
data = [
125+
"commands/definitions.json",
126+
],
127+
)
128+
129+
ts_json_schema(
130+
name = "generate_schema",
131+
src = "commands/generate.json",
132+
data = [
133+
"commands/definitions.json",
134+
],
135+
)
136+
137+
ts_json_schema(
138+
name = "help_schema",
139+
src = "commands/help.json",
140+
data = [
141+
"commands/definitions.json",
142+
],
143+
)
144+
145+
ts_json_schema(
146+
name = "lint_schema",
147+
src = "commands/lint.json",
148+
data = [
149+
"commands/definitions.json",
150+
],
151+
)
152+
153+
ts_json_schema(
154+
name = "new_schema",
155+
src = "commands/new.json",
156+
data = [
157+
"commands/definitions.json",
158+
],
159+
)
160+
161+
ts_json_schema(
162+
name = "run_schema",
163+
src = "commands/run.json",
164+
data = [
165+
"commands/definitions.json",
166+
],
167+
)
168+
169+
ts_json_schema(
170+
name = "serve_schema",
171+
src = "commands/serve.json",
172+
data = [
173+
"commands/definitions.json",
174+
],
175+
)
176+
177+
ts_json_schema(
178+
name = "test_schema",
179+
src = "commands/test.json",
180+
data = [
181+
"commands/definitions.json",
182+
],
183+
)
184+
185+
ts_json_schema(
186+
name = "update_schema",
187+
src = "commands/update.json",
188+
data = [
189+
"commands/definitions.json",
190+
],
191+
)
192+
193+
ts_json_schema(
194+
name = "version_schema",
195+
src = "commands/version.json",
196+
data = [
197+
"commands/definitions.json",
198+
],
199+
)
200+
201+
ts_json_schema(
202+
name = "xi18n_schema",
203+
src = "commands/xi18n.json",
204+
data = [
205+
"commands/definitions.json",
206+
],
207+
)

packages/angular/cli/commands/add-impl.ts

+4-9
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,15 @@
1010
import { tags, terminal } from '@angular-devkit/core';
1111
import { NodePackageDoesNotSupportSchematics } from '@angular-devkit/schematics/tools';
1212
import { Arguments } from '../models/interface';
13-
import { BaseSchematicOptions, SchematicCommand } from '../models/schematic-command';
13+
import { SchematicCommand } from '../models/schematic-command';
1414
import { NpmInstall } from '../tasks/npm-install';
1515
import { getPackageManager } from '../utilities/config';
16+
import { Schema as AddCommandSchema } from './add';
1617

17-
export interface AddCommandOptions extends BaseSchematicOptions {
18-
collection: string;
19-
}
20-
21-
export class AddCommand<
22-
T extends AddCommandOptions = AddCommandOptions,
23-
> extends SchematicCommand<T> {
18+
export class AddCommand extends SchematicCommand<AddCommandSchema> {
2419
readonly allowPrivateSchematics = true;
2520

26-
async run(options: AddCommandOptions & Arguments) {
21+
async run(options: AddCommandSchema & Arguments) {
2722
if (!options.collection) {
2823
this.logger.fatal(
2924
`The "ng add" command requires a name argument to be specified eg. `

packages/angular/cli/commands/add.json

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
"required": [
2424
]
2525
},
26+
{
27+
"$ref": "./definitions.json#/definitions/schematic"
28+
},
2629
{
2730
"$ref": "./definitions.json#/definitions/base"
2831
}

packages/angular/cli/commands/build-impl.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@
77
*/
88

99
import { ArchitectCommand, ArchitectCommandOptions } from '../models/architect-command';
10+
import { Arguments } from '../models/interface';
1011
import { Version } from '../upgrade/version';
12+
import { Schema as BuildCommandSchema } from './build';
1113

12-
export class BuildCommand extends ArchitectCommand {
14+
export class BuildCommand extends ArchitectCommand<BuildCommandSchema> {
1315
public readonly target = 'build';
1416

15-
public async run(options: ArchitectCommandOptions) {
17+
public async run(options: ArchitectCommandOptions & Arguments) {
1618
// Check Angular and TypeScript versions.
1719
Version.assertCompatibleAngularVersion(this.workspace.root);
1820
Version.assertTypescriptVersion(this.workspace.root);

packages/angular/cli/commands/config-impl.ts

+11-15
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,17 @@ import {
1717
tags,
1818
} from '@angular-devkit/core';
1919
import { writeFileSync } from 'fs';
20-
import { BaseCommandOptions, Command } from '../models/command';
20+
import { Command } from '../models/command';
21+
import { Arguments } from '../models/interface';
2122
import {
2223
getWorkspace,
2324
getWorkspaceRaw,
2425
migrateLegacyGlobalConfig,
2526
validateWorkspace,
2627
} from '../utilities/config';
28+
import { Schema as ConfigCommandSchema, Value as ConfigCommandSchemaValue } from './config';
2729

2830

29-
export interface ConfigOptions extends BaseCommandOptions {
30-
jsonPath: string;
31-
value?: string;
32-
global?: boolean;
33-
}
34-
3531
const validCliPaths = new Map([
3632
['cli.warnings.versionMismatch', 'boolean'],
3733
['cli.warnings.typescriptMismatch', 'boolean'],
@@ -139,20 +135,20 @@ function setValueFromPath<T extends JsonArray | JsonObject>(
139135
}
140136
}
141137

142-
function normalizeValue(value: string, path: string): JsonValue {
138+
function normalizeValue(value: ConfigCommandSchemaValue, path: string): JsonValue {
143139
const cliOptionType = validCliPaths.get(path);
144140
if (cliOptionType) {
145141
switch (cliOptionType) {
146142
case 'boolean':
147-
if (value.trim() === 'true') {
143+
if (('' + value).trim() === 'true') {
148144
return true;
149-
} else if (value.trim() === 'false') {
145+
} else if (('' + value).trim() === 'false') {
150146
return false;
151147
}
152148
break;
153149
case 'number':
154150
const numberValue = Number(value);
155-
if (!Number.isNaN(numberValue)) {
151+
if (!Number.isFinite(numberValue)) {
156152
return numberValue;
157153
}
158154
break;
@@ -178,8 +174,8 @@ function normalizeValue(value: string, path: string): JsonValue {
178174
return value;
179175
}
180176

181-
export class ConfigCommand<T extends ConfigOptions = ConfigOptions> extends Command<T> {
182-
public async run(options: T) {
177+
export class ConfigCommand extends Command<ConfigCommandSchema> {
178+
public async run(options: ConfigCommandSchema & Arguments) {
183179
const level = options.global ? 'global' : 'local';
184180

185181
let config =
@@ -210,7 +206,7 @@ export class ConfigCommand<T extends ConfigOptions = ConfigOptions> extends Comm
210206
}
211207
}
212208

213-
private get(config: experimental.workspace.WorkspaceSchema, options: T) {
209+
private get(config: experimental.workspace.WorkspaceSchema, options: ConfigCommandSchema) {
214210
let value;
215211
if (options.jsonPath) {
216212
value = getValueFromPath(config as {} as JsonObject, options.jsonPath);
@@ -229,7 +225,7 @@ export class ConfigCommand<T extends ConfigOptions = ConfigOptions> extends Comm
229225
}
230226
}
231227

232-
private set(options: ConfigOptions) {
228+
private set(options: ConfigCommandSchema) {
233229
if (!options.jsonPath || !options.jsonPath.trim()) {
234230
throw new Error('Invalid Path.');
235231
}

packages/angular/cli/commands/config.json

+29-24
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,35 @@
1010
"$impl": "./config-impl#ConfigCommand",
1111

1212
"type": "object",
13-
"properties": {
14-
"jsonPath": {
15-
"type": "string",
16-
"description": "The path to the value to get/set.",
17-
"$default": {
18-
"$source": "argv",
19-
"index": 0
20-
}
13+
"allOf": [
14+
{
15+
"properties": {
16+
"jsonPath": {
17+
"type": "string",
18+
"description": "The path to the value to get/set.",
19+
"$default": {
20+
"$source": "argv",
21+
"index": 0
22+
}
23+
},
24+
"value": {
25+
"type": ["string", "number", "boolean"],
26+
"description": "The new value to be set.",
27+
"$default": {
28+
"$source": "argv",
29+
"index": 1
30+
}
31+
},
32+
"global": {
33+
"type": "boolean",
34+
"description": "Get/set the value in the global configuration (in your home directory).",
35+
"default": false,
36+
"aliases": ["g"]
37+
}
38+
},
39+
"required": [
40+
]
2141
},
22-
"value": {
23-
"type": ["string", "number", "boolean"],
24-
"description": "The new value to be set.",
25-
"$default": {
26-
"$source": "argv",
27-
"index": 1
28-
}
29-
},
30-
"global": {
31-
"type": "boolean",
32-
"description": "Get/set the value in the global configuration (in your home directory).",
33-
"default": false,
34-
"aliases": ["g"]
35-
}
36-
},
37-
"required": [
42+
{ "$ref": "./definitions.json#/definitions/base" }
3843
]
3944
}

packages/angular/cli/commands/deprecated-impl.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88
import { Command } from '../models/command';
9+
import { Schema as DeprecatedCommandSchema } from './deprecated';
910

10-
export class DeprecatedCommand extends Command {
11+
export class DeprecatedCommand extends Command<DeprecatedCommandSchema> {
1112
public async run() {
1213
let message = 'The "${this.description.name}" command has been deprecated.';
1314
if (this.description.name == 'get' || this.description.name == 'set') {

0 commit comments

Comments
 (0)