fix(@angular/cli): error out when command json is invalid

This commit is contained in:
Filipe Silva 2018-10-11 12:28:58 +01:00 committed by Alex Eagle
parent 7ca3bb5263
commit eef66f0f65
5 changed files with 91 additions and 11 deletions

View File

@ -36,7 +36,6 @@ export class GenerateCommand extends SchematicCommand<GenerateCommandSchema> {
schematic.description.path,
this._workflow.registry,
schematic.description.schemaJson,
this.logger,
);
} else {
continue;

View File

@ -92,7 +92,7 @@ export async function runCommand(
}
commandMap[name] =
await parseJsonSchemaToCommandDescription(name, schemaPath, registry, schema, logger);
await parseJsonSchemaToCommandDescription(name, schemaPath, registry, schema);
}
let commandName: string | undefined = undefined;

View File

@ -5,7 +5,7 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import { json, logging } from '@angular-devkit/core';
import { BaseException, json } from '@angular-devkit/core';
import { ExportStringRef } from '@angular-devkit/schematics/tools';
import { readFileSync } from 'fs';
import { dirname, resolve } from 'path';
@ -19,6 +19,13 @@ import {
Value,
} from '../models/interface';
export class CommandJsonPathException extends BaseException {
constructor(public readonly path: string, public readonly name: string) {
super(`File ${path} was not found while constructing the subcommand ${name}.`);
}
}
function _getEnumFromValue<E, T extends E[keyof E]>(
value: json.JsonValue,
enumeration: E,
@ -40,7 +47,6 @@ export async function parseJsonSchemaToSubCommandDescription(
jsonPath: string,
registry: json.schema.SchemaRegistry,
schema: json.JsonObject,
logger: logging.Logger,
): Promise<SubCommandDescription> {
const options = await parseJsonSchemaToOptions(registry, schema);
@ -69,7 +75,7 @@ export async function parseJsonSchemaToSubCommandDescription(
try {
longDescription = readFileSync(ldPath, 'utf-8');
} catch (e) {
logger.warn(`File ${ldPath} was not found while constructing the subcommand ${name}.`);
throw new CommandJsonPathException(ldPath, name);
}
}
let usageNotes = '';
@ -78,7 +84,7 @@ export async function parseJsonSchemaToSubCommandDescription(
try {
usageNotes = readFileSync(unPath, 'utf-8');
} catch (e) {
logger.warn(`File ${unPath} was not found while constructing the subcommand ${name}.`);
throw new CommandJsonPathException(unPath, name);
}
}
@ -99,10 +105,9 @@ export async function parseJsonSchemaToCommandDescription(
jsonPath: string,
registry: json.schema.SchemaRegistry,
schema: json.JsonObject,
logger: logging.Logger,
): Promise<CommandDescription> {
const subcommand =
await parseJsonSchemaToSubCommandDescription(name, jsonPath, registry, schema, logger);
await parseJsonSchemaToSubCommandDescription(name, jsonPath, registry, schema);
// Before doing any work, let's validate the implementation.
if (typeof schema.$impl != 'string') {

View File

@ -0,0 +1,76 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*
*/
import { schema } from '@angular-devkit/core';
import { readFileSync } from 'fs';
import { join } from 'path';
import { of } from 'rxjs';
import { CommandJsonPathException, parseJsonSchemaToCommandDescription } from './json-schema';
describe('parseJsonSchemaToCommandDescription', () => {
let registry: schema.CoreSchemaRegistry;
const baseSchemaJson = {
'$schema': 'http://json-schema.org/schema',
'$id': 'ng-cli://commands/version.json',
'description': 'Outputs Angular CLI version.',
'$longDescription': 'not a file ref',
'$aliases': ['v'],
'$scope': 'all',
'$impl': './version-impl#VersionCommand',
'type': 'object',
'allOf': [
{ '$ref': './definitions.json#/definitions/base' },
],
};
beforeEach(() => {
registry = new schema.CoreSchemaRegistry([]);
registry.registerUriHandler((uri: string) => {
if (uri.startsWith('ng-cli://')) {
const content = readFileSync(
join(__dirname, '..', uri.substr('ng-cli://'.length)), 'utf-8');
return of(JSON.parse(content));
} else {
return null;
}
});
});
it(`should throw on invalid $longDescription path`, async () => {
const name = 'version';
const schemaPath = join(__dirname, './bad-sample.json');
const schemaJson = { ...baseSchemaJson, $longDescription: 'not a file ref' };
try {
await parseJsonSchemaToCommandDescription(name, schemaPath, registry, schemaJson);
} catch (error) {
const refPath = join(__dirname, schemaJson.$longDescription);
expect(error).toEqual(new CommandJsonPathException(refPath, name));
return;
}
expect(true).toBe(false, 'function should have thrown');
});
it(`should throw on invalid $usageNotes path`, async () => {
const name = 'version';
const schemaPath = join(__dirname, './bad-sample.json');
const schemaJson = { ...baseSchemaJson, $usageNotes: 'not a file ref' };
try {
await parseJsonSchemaToCommandDescription(name, schemaPath, registry, schemaJson);
} catch (error) {
const refPath = join(__dirname, schemaJson.$usageNotes);
expect(error).toEqual(new CommandJsonPathException(refPath, name));
return;
}
expect(true).toBe(false, 'function should have thrown');
});
});

View File

@ -184,9 +184,9 @@ export default async function(opts: SnapshotsOptions, logger: logging.Logger) {
const options = { cwd: newProjectRoot };
const childLogger = logger.createChild(commandName);
const stdout = _exec(ngPath, [commandName, '--help=json'], options, childLogger);
if (stdout.trim()) {
fs.writeFileSync(path.join(helpOutputRoot, commandName + '.json'), stdout);
}
// Make sure the output is JSON before printing it, and format it as well.
const jsonOutput = JSON.stringify(JSON.parse(stdout.trim()), undefined, 2);
fs.writeFileSync(path.join(helpOutputRoot, commandName + '.json'), jsonOutput);
}
if (!githubToken) {