Permalink
Browse files

Fix: Improve feedback when config is invalid

Fix #1526
  • Loading branch information...
sarvaje authored and molant committed Jan 14, 2019
1 parent 06c7df2 commit e90f410556c817012e7667c8f4f0e27b14d91bd2
@@ -29,15 +29,14 @@ export default class BabelConfigIsValidHint implements IHint {
};

const invalidSchema = async (fetchEnd: BabelConfigInvalidSchema) => {
const { errors, prettifiedErrors, resource } = fetchEnd;
const { groupedErrors, resource } = fetchEnd;

debug(`parse::error::babel-config::schema received`);

for (let i = 0; i < errors.length; i++) {
const message = prettifiedErrors[i];
const location = errors[i].location;
for (let i = 0; i < groupedErrors.length; i++) {
const groupedError = groupedErrors[i];

await context.report(resource, message, { location });
await context.report(resource, groupedError.message, { location: groupedError.location });
}
};

@@ -14,7 +14,13 @@ const tests: HintLocalTest[] = [
{
name: `Invalid .babelrc configuration should fail`,
path: path.join(__dirname, 'fixtures', 'invalid-schema', '.babelrc'),
reports: [{ message: `'moduleId' should be string.` }]
reports: [{
message: `'moduleId' should be 'string'.`,
position: {
column: 5,
line: 4
}
}]
},
{
name: `Invalid json file should fail`,
@@ -32,17 +38,35 @@ const tests: HintLocalTest[] = [
{
name: `If package.json contains invalid "babel" property, it should fail`,
path: path.join(__dirname, 'fixtures', 'has-invalid-babel-package-json', 'package.json'),
reports: [{ message: `'moduleId' should be string.` }]
reports: [{
message: `'moduleId' should be 'string'.`,
position: {
column: 5,
line: 3
}
}]
},
{
name: `If .babelrc contains an additional property, it should fail`,
path: path.join(__dirname, 'fixtures', 'has-additional-property', '.babelrc'),
reports: [{ message: `Should NOT have additional properties. Additional property found 'additional'.` }]
reports: [{
message: `'root' should NOT have additional properties. Additional property found 'additional'.`,
position: {
column: 5,
line: 10
}
}]
},
{
name: `If .babelrc contains an invalid value, it should fail`,
path: path.join(__dirname, 'fixtures', 'has-invalid-enum-property', '.babelrc'),
reports: [{ message: `'sourceMaps' should be equal to one of the allowed values 'both, inline, true, false'. Value found 'invalidValue'` }]
reports: [{
message: `'sourceMaps' should be equal to one of the allowed values 'both, inline, true, false'. Value found 'invalidValue'`,
position: {
column: 5,
line: 14
}
}]
},
{
name: 'If .babelrc contains a circular reference, it should fail',
@@ -123,9 +123,9 @@ export default class ManifestIsValidHint implements IHint {
};

const handleInvalidSchema = async (manifestInvalidSchemaEvent: ManifestInvalidSchema) => {
for (let i = 0; i < manifestInvalidSchemaEvent.prettifiedErrors.length; i++) {
const error = manifestInvalidSchemaEvent.prettifiedErrors[i];
const location = manifestInvalidSchemaEvent.errors[i].location;
for (let i = 0; i < manifestInvalidSchemaEvent.groupedErrors.length; i++) {
const error = manifestInvalidSchemaEvent.groupedErrors[i].message;
const location = manifestInvalidSchemaEvent.groupedErrors[i].location;

await context.report(manifestInvalidSchemaEvent.resource, error, { location });
}
@@ -36,9 +36,27 @@ const defaultTests: HintTest[] = [
{
name: `Web app manifest is specified and its content does not validate agains the schema`,
reports: [
{ message: `Should NOT have additional properties. Additional property found 'additionalProperty'.` },
{ message: `'icons[0]' should NOT have additional properties. Additional property found 'density'.` },
{ message: `'name' should be string.` }
{
message: `'root' should NOT have additional properties. Additional property found 'additionalProperty'.`,
position: {
column: 2,
line: 0
}
},
{
message: `'icons[0]' should NOT have additional properties. Additional property found 'density'.`,
position: {
column: 63,
line: 0
}
},
{
message: `'name' should be 'string'.`,
position: {
column: 110,
line: 0
}
}
],
serverConfig: {
'/': htmlWithManifestSpecified,
@@ -35,15 +35,14 @@ export default class TypeScriptConfigIsValid implements IHint {
};

const invalidSchema = async (fetchEnd: TypeScriptConfigInvalidSchema) => {
const { errors, prettifiedErrors, resource } = fetchEnd;
const { groupedErrors, resource } = fetchEnd;

debug(`parse::error::typescript-config::schema received`);

for (let i = 0; i < errors.length; i++) {
const message = prettifiedErrors[i];
const location = errors[i].location;
for (let i = 0; i < groupedErrors.length; i++) {
const groupedError = groupedErrors[i];

await context.report(resource, message, { location });
await context.report(resource, groupedError.message, { location: groupedError.location});
}
};

@@ -25,16 +25,23 @@ const tests: HintLocalTest[] = [
path: path.join(__dirname, 'fixtures', 'invalidschemaenum'),
reports: [{
message: `'compilerOptions.lib[3]' should be equal to one of the allowed values 'es5, es6, es2015, es7, es2016, es2017, es2018, esnext, dom, dom.iterable, webworker, scripthost, es2015.core, es2015.collection, es2015.generator, es2015.iterable, es2015.promise, es2015.proxy, es2015.reflect, es2015.symbol, es2015.symbol.wellknown, es2016.array.include, es2017.object, es2017.intl, es2017.sharedmemory, es2017.string, es2017.typedarrays, es2018.intl, es2018.promise, es2018.regexp, esnext.asynciterable, esnext.array, esnext.intl, esnext.symbol'. Value found 'invalidlib'`,
position: { column: 12, line: 9 }
position: {
column: 12,
line: 9
}
}]
},
{
name: 'If schema has an invalid pattern, it should fail',
path: path.join(__dirname, 'fixtures', 'invalidschemapattern'),
reports: [
{ message: `'compilerOptions.target' should be equal to one of the allowed values 'es3, es5, es6, es2015, es2016, es2017, es2018, esnext'. Value found 'invalid'` },
{ message: `'compilerOptions.target' should match pattern '^([eE][sS]([356]|(201[5678])|[nN][eE][xX][tT]))$'. Value found 'invalid'` },
{ message: `'compilerOptions.target' should be equal to one of the allowed values 'es3, es5, es6, es2015, es2016, es2017, es2018, esnext'. Value found 'invalid' or 'compilerOptions.target' should match pattern '^([eE][sS]([356]|(201[5678])|[nN][eE][xX][tT]))$'. Value found 'invalid'` }
{
message: `'compilerOptions.target' should be equal to one of the allowed values 'es3, es5, es6, es2015, es2016, es2017, es2018, esnext'. Value found '"invalid"'. Or 'compilerOptions.target' should match pattern '^([eE][sS]([356]|(201[5678])|[nN][eE][xX][tT]))$'. Value found 'invalid'`,
position: {
column: 9,
line: 14
}
}
]
},
{
@@ -13,6 +13,7 @@ import { validate } from '../utils/schema-validator';
import { debug as d } from '../utils/debug';
import { UserConfig } from '../types';
import * as logger from '../utils/logging';
import { SchemaValidationResult, GroupedError } from '../types/schema-validation-result';

const debug = d(__filename);
const schema = require('./config-schema.json');
@@ -25,10 +26,16 @@ const schema = require('./config-schema.json');

/** Validates that a given config object is valid */
export const validateConfig = (config: UserConfig): boolean => {

debug('Validating configuration');
if (!validate(schema, config).valid) {
logger.error('Configuration schema is not valid');

const validateInfo: SchemaValidationResult = validate(schema, config);

if (!validateInfo.valid) {
logger.error('Configuration schema is not valid:');

validateInfo.groupedErrors.forEach((error: GroupedError) => {
logger.error(` - ${error.message}`);
});

return false;
}
@@ -9,9 +9,9 @@ export enum Severity {

/** The location of a Problem in the code */
export type ProblemLocation = {
/** The column number where a Problem is */
/** The zero-based column number where a Problem is */
column: number;
/** The line number where a Problem is */
/** The zero-based line number where a Problem is */
line: number;
/** The column number relative to the element where a Problem is */
elementColumn?: number;
@@ -5,9 +5,16 @@ export interface ISchemaValidationError extends ajv.ErrorObject {
location?: ProblemLocation;
}

export type GroupedError = {
message: string;
errors: ISchemaValidationError[];
location?: ProblemLocation;
};

export type SchemaValidationResult = {
data: any;
errors: ISchemaValidationError[];
prettifiedErrors: string[];
groupedErrors: GroupedError[];
valid: boolean;
};
@@ -114,7 +114,7 @@ class JSONResult implements IJSONResult {
.replace(/^\./, '')

// Ignore trailing `]` from `foo[1]`
.replace(']', '')
.replace(/]/g, '')

// Break items on `.` or `[`
.split(/[[.]/)
Oops, something went wrong.

0 comments on commit e90f410

Please sign in to comment.