Skip to content

Commit a063f43

Browse files
clydinhansl
authored andcommitted
refactor(@angular/cli): correct strict compilation errors
1 parent f90489d commit a063f43

File tree

13 files changed

+129
-63
lines changed

13 files changed

+129
-63
lines changed

packages/angular/cli/BUILD

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Copyright Google Inc. All Rights Reserved.
2+
#
3+
# Use of this source code is governed by an MIT-style license that can be
4+
# found in the LICENSE file at https://angular.io/license
5+
6+
licenses(["notice"]) # MIT
7+
8+
load("//tools:defaults.bzl", "ts_library")
9+
10+
package(default_visibility = ["//visibility:public"])
11+
12+
ts_library(
13+
name = "angular-cli",
14+
srcs = glob(
15+
["**/*.ts"],
16+
exclude = [
17+
"**/*_spec.ts",
18+
"**/*_spec_large.ts",
19+
],
20+
),
21+
deps = [
22+
"//packages/angular_devkit/architect",
23+
"//packages/angular_devkit/core",
24+
"//packages/angular_devkit/core:node",
25+
"//packages/angular_devkit/schematics",
26+
"//packages/angular_devkit/schematics:tools",
27+
"@rxjs",
28+
"@rxjs//operators",
29+
],
30+
tsconfig = "//:tsconfig.json"
31+
)

packages/angular/cli/commands/config.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ function parseJsonPath(path: string): string[] {
4545

4646
while (fragments.length > 0) {
4747
const fragment = fragments.shift();
48+
if (fragment == undefined) {
49+
break;
50+
}
4851

4952
const match = fragment.match(/([^\[]+)((\[.*\])*)/);
5053
if (!match) {
@@ -242,11 +245,15 @@ export default class ConfigCommand extends Command {
242245
}
243246

244247
const [config, configPath] = getWorkspaceRaw(options.global ? 'global' : 'local');
248+
if (!config || !configPath) {
249+
this.logger.error('Confguration file cannot be found.');
250+
return 1;
251+
}
245252

246253
// TODO: Modify & save without destroying comments
247254
const configValue = config.value;
248255

249-
const value = normalizeValue(options.value, options.jsonPath);
256+
const value = normalizeValue(options.value || '', options.jsonPath);
250257
const result = setValueFromPath(configValue, options.jsonPath, value);
251258

252259
if (result === undefined) {

packages/angular/cli/commands/doc.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ export default class DocCommand extends Command {
2727

2828
return false;
2929
}
30+
31+
return true;
3032
}
3133

3234
public async run(options: Options) {

packages/angular/cli/commands/generate.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export default class GenerateCommand extends SchematicCommand {
2424
if (this.initialized) {
2525
return;
2626
}
27-
super.initialize(options);
27+
await super.initialize(options);
2828
this.initialized = true;
2929

3030
const [collectionName, schematicName] = this.parseSchematicInfo(options);

packages/angular/cli/commands/update.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export default class UpdateCommand extends SchematicCommand {
3030
if (this.initialized) {
3131
return;
3232
}
33-
super.initialize(options);
33+
await super.initialize(options);
3434
this.initialized = true;
3535

3636
const schematicOptions = await this.getOptions({

packages/angular/cli/commands/version.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,17 @@ export default class VersionCommand extends Command {
4040
? path.resolve(this.project.root, 'node_modules')
4141
: maybeNodeModules;
4242

43-
const versions = [
43+
const packageNames = [
4444
...Object.keys(pkg && pkg['dependencies'] || {}),
4545
...Object.keys(pkg && pkg['devDependencies'] || {}),
4646
...Object.keys(projPkg && projPkg['dependencies'] || {}),
4747
...Object.keys(projPkg && projPkg['devDependencies'] || {}),
48+
];
4849

50+
if (packageRoot != null) {
4951
// Add all node_modules and node_modules/@*/*
50-
...fs.readdirSync(packageRoot)
51-
.reduce((acc, name) => {
52+
const nodePackageNames = fs.readdirSync(packageRoot)
53+
.reduce<string[]>((acc, name) => {
5254
if (name.startsWith('@')) {
5355
return acc.concat(
5456
fs.readdirSync(path.resolve(packageRoot, name))
@@ -57,8 +59,12 @@ export default class VersionCommand extends Command {
5759
} else {
5860
return acc.concat(name);
5961
}
60-
}, []),
61-
]
62+
}, []);
63+
64+
packageNames.push(...nodePackageNames);
65+
}
66+
67+
const versions = packageNames
6268
.filter(x => patterns.some(p => p.test(x)))
6369
.reduce((acc, name) => {
6470
if (name in acc) {
@@ -114,7 +120,7 @@ export default class VersionCommand extends Command {
114120
Node: ${process.versions.node}
115121
OS: ${process.platform} ${process.arch}
116122
Angular: ${angularCoreVersion}
117-
... ${angularSameAsCore.sort().reduce((acc, name) => {
123+
... ${angularSameAsCore.sort().reduce<string[]>((acc, name) => {
118124
// Perform a simple word wrap around 60.
119125
if (acc.length == 0) {
120126
return [name];
@@ -140,8 +146,8 @@ export default class VersionCommand extends Command {
140146

141147
private getVersion(
142148
moduleName: string,
143-
projectNodeModules: string,
144-
cliNodeModules: string,
149+
projectNodeModules: string | null,
150+
cliNodeModules: string | null,
145151
): string {
146152
try {
147153
if (projectNodeModules) {

packages/angular/cli/lib/cli/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ export default async function(options: { testing?: boolean, cliArgs: string[] })
6868
} catch (err) {
6969
if (err instanceof Error) {
7070
logger.fatal(err.message);
71-
logger.fatal(err.stack);
71+
if (err.stack) {
72+
logger.fatal(err.stack);
73+
}
7274
} else if (typeof err === 'string') {
7375
logger.fatal(err);
7476
} else if (typeof err === 'number') {
@@ -82,7 +84,9 @@ export default async function(options: { testing?: boolean, cliArgs: string[] })
8284
throw err;
8385
}
8486

85-
loggingSubscription.unsubscribe();
87+
if (loggingSubscription) {
88+
loggingSubscription.unsubscribe();
89+
}
8690

8791
return 1;
8892
}

packages/angular/cli/lib/init.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ function _fromPackageJson(cwd?: string) {
4343
if (process.env['NG_CLI_PROFILING']) {
4444
const profiler = require('v8-profiler'); // tslint:disable-line:no-implicit-dependencies
4545
profiler.startProfiling();
46-
function exitHandler(options: { cleanup: boolean, exit: boolean }, _err: Error) {
46+
const exitHandler = (options: { cleanup?: boolean, exit?: boolean }) => {
4747
if (options.cleanup) {
4848
const cpuProfile = profiler.stopProfiling();
4949
fs.writeFileSync(path.resolve(process.cwd(), process.env.NG_CLI_PROFILING) + '.cpuprofile',
@@ -53,11 +53,11 @@ if (process.env['NG_CLI_PROFILING']) {
5353
if (options.exit) {
5454
process.exit();
5555
}
56-
}
56+
};
5757

58-
process.on('exit', exitHandler.bind(null, { cleanup: true }));
59-
process.on('SIGINT', exitHandler.bind(null, { exit: true }));
60-
process.on('uncaughtException', exitHandler.bind(null, { exit: true }));
58+
process.on('exit', () => exitHandler({ cleanup: true }));
59+
process.on('SIGINT', () => exitHandler({ exit: true }));
60+
process.on('uncaughtException', () => exitHandler({ exit: true }));
6161
}
6262

6363
let cli;

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

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ export abstract class ArchitectCommand extends Command<ArchitectCommandOptions>
8282
if (!options.project && this.target) {
8383
const projectNames = this.getProjectNamesByTarget(this.target);
8484
const { overrides } = this._makeTargetSpecifier(options);
85-
if (projectNames.length > 1 && Object.keys(overrides).length > 0) {
85+
if (projectNames.length > 1 && Object.keys(overrides || {}).length > 0) {
8686
throw new Error('Architect commands with multiple targets cannot specify overrides.'
8787
+ `'${this.target}' would be run on the following projects: ${projectNames.join()}`);
8888
}
@@ -166,34 +166,36 @@ export abstract class ArchitectCommand extends Command<ArchitectCommandOptions>
166166
if (!targetSpec.project && this.target) {
167167
// This runs each target sequentially.
168168
// Running them in parallel would jumble the log messages.
169-
return await from(this.getProjectNamesByTarget(this.target)).pipe(
169+
return from(this.getProjectNamesByTarget(this.target)).pipe(
170170
concatMap(project => runSingleTarget({ ...targetSpec, project })),
171171
toArray(),
172172
).toPromise().then(results => results.every(res => res === 0) ? 0 : 1);
173173
} else {
174-
return await runSingleTarget(targetSpec).toPromise();
174+
return runSingleTarget(targetSpec).toPromise();
175175
}
176176
} catch (e) {
177177
if (e instanceof schema.SchemaValidationException) {
178178
const newErrors: schema.SchemaValidatorError[] = [];
179-
e.errors.forEach(schemaError => {
179+
for (const schemaError of e.errors) {
180180
if (schemaError.keyword === 'additionalProperties') {
181181
const unknownProperty = schemaError.params.additionalProperty;
182182
if (unknownProperty in options) {
183183
const dashes = unknownProperty.length === 1 ? '-' : '--';
184184
this.logger.fatal(`Unknown option: '${dashes}${unknownProperty}'`);
185185

186-
return 1;
186+
break;
187187
}
188188
}
189189
newErrors.push(schemaError);
190-
});
190+
};
191191

192192
if (newErrors.length > 0) {
193193
this.logger.error(new schema.SchemaValidationException(newErrors).message);
194194

195195
return 1;
196196
}
197+
198+
return 0;
197199
} else {
198200
throw e;
199201
}
@@ -203,7 +205,7 @@ export abstract class ArchitectCommand extends Command<ArchitectCommandOptions>
203205
private getProjectNamesByTarget(targetName: string): string[] {
204206
const allProjectsForTargetName = this._workspace.listProjectNames().map(projectName =>
205207
this._architect.listProjectTargets(projectName).includes(targetName) ? projectName : null,
206-
).filter(x => !!x);
208+
).filter(x => !!x) as string[];
207209

208210
if (this.multiTarget) {
209211
// For multi target commands, we always list all projects that have the target.
@@ -264,6 +266,13 @@ export abstract class ArchitectCommand extends Command<ArchitectCommandOptions>
264266
delete overrides.project;
265267
}
266268

269+
if (!project) {
270+
throw new Error('No project specified');
271+
}
272+
if (!target) {
273+
throw new Error('No project target specified');
274+
}
275+
267276
return {
268277
project,
269278
configuration,

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

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// tslint:disable:no-any
2-
import { logging, tags } from '@angular-devkit/core';
3-
import { camelize } from '@angular-devkit/core/src/utils/strings';
2+
import { logging, strings as coreStrings, tags } from '@angular-devkit/core';
43
import {
54
ArgumentStrategy,
65
CommandConstructor,
@@ -17,6 +16,28 @@ export interface CommandMap {
1716
[key: string]: CommandConstructor;
1817
}
1918

19+
// Based off https://en.wikipedia.org/wiki/Levenshtein_distance
20+
// No optimization, really.
21+
function levenshtein(a: string, b: string): number {
22+
/* base case: empty strings */
23+
if (a.length == 0) {
24+
return b.length;
25+
}
26+
if (b.length == 0) {
27+
return a.length;
28+
}
29+
30+
// Test if last characters of the strings match.
31+
const cost = a[a.length - 1] == b[b.length - 1] ? 0 : 1;
32+
33+
/* return minimum of delete char from s, delete char from t, and delete char from both */
34+
return Math.min(
35+
levenshtein(a.slice(0, -1), b) + 1,
36+
levenshtein(a, b.slice(0, -1)) + 1,
37+
levenshtein(a.slice(0, -1), b.slice(0, -1)) + cost,
38+
);
39+
}
40+
2041
/**
2142
* Run a command.
2243
* @param commandMap Map of available commands.
@@ -42,7 +63,7 @@ export async function runCommand(commandMap: CommandMap,
4263
? CommandScope.inProject
4364
: CommandScope.outsideProject;
4465

45-
let Cmd: CommandConstructor;
66+
let Cmd: CommandConstructor | null;
4667
Cmd = findCommand(commandMap, commandName);
4768

4869
if (!Cmd && !commandName && (rawOptions.v || rawOptions.version)) {
@@ -56,28 +77,6 @@ export async function runCommand(commandMap: CommandMap,
5677
}
5778

5879
if (!Cmd) {
59-
// Based off https://en.wikipedia.org/wiki/Levenshtein_distance
60-
// No optimization, really.
61-
function levenshtein(a: string, b: string): number {
62-
/* base case: empty strings */
63-
if (a.length == 0) {
64-
return b.length;
65-
}
66-
if (b.length == 0) {
67-
return a.length;
68-
}
69-
70-
// Test if last characters of the strings match.
71-
const cost = a[a.length - 1] == b[b.length - 1] ? 0 : 1;
72-
73-
/* return minimum of delete char from s, delete char from t, and delete char from both */
74-
return Math.min(
75-
levenshtein(a.slice(0, -1), b) + 1,
76-
levenshtein(a, b.slice(0, -1)) + 1,
77-
levenshtein(a.slice(0, -1), b.slice(0, -1)) + cost,
78-
);
79-
}
80-
8180
const commandsDistance = {} as { [name: string]: number };
8281
const allCommands = listAllCommandNames(commandMap).sort((a, b) => {
8382
if (!(a in commandsDistance)) {
@@ -111,7 +110,9 @@ export async function runCommand(commandMap: CommandMap,
111110
}
112111

113112
if (options.help) {
114-
return command.printHelp(options);
113+
command.printHelp(options);
114+
115+
return;
115116
} else {
116117
if (command.scope !== undefined && command.scope !== CommandScope.everywhere) {
117118
if (command.scope !== executionScope) {
@@ -176,7 +177,7 @@ export function parseOptions<T = any>(
176177
const aliases = cmdOpts.concat()
177178
.filter(o => o.aliases && o.aliases.length > 0)
178179
.reduce((aliases: any, opt: Option) => {
179-
aliases[opt.name] = opt.aliases
180+
aliases[opt.name] = (opt.aliases || [])
180181
.filter(a => a.length === 1);
181182

182183
return aliases;
@@ -230,7 +231,7 @@ export function parseOptions<T = any>(
230231
// Remove undefined booleans
231232
booleans
232233
.filter(b => parsedOptions[b] === undefined)
233-
.map(b => camelize(b))
234+
.map(b => coreStrings.camelize(b))
234235
.forEach(b => delete parsedOptions[b]);
235236

236237
// remove options with dashes.

0 commit comments

Comments
 (0)