Validate on top-level settings and use pre-compiled ajv

jh-changes
Shin'ya Ueoka 4 years ago
parent 2318e3a555
commit 776977e0dc
  1. 33
      src/shared/settings/Blacklist.ts
  2. 31
      src/shared/settings/Keymaps.ts
  3. 21
      src/shared/settings/Properties.ts
  4. 34
      src/shared/settings/Search.ts
  5. 52
      src/shared/settings/Settings.ts
  6. 20
      src/shared/settings/Validator.ts
  7. 3
      src/shared/settings/schema.json
  8. 618
      src/shared/settings/validate.js
  9. 18
      test/shared/settings/Blacklist.test.ts
  10. 1
      test/shared/settings/Keymaps.test.ts
  11. 13
      test/shared/settings/Search.test.ts

@ -1,23 +1,4 @@
import Key from './Key'; import Key from './Key';
import Validator from './Validator';
const ItemSchema = {
anyOf: [
{ type: 'string' },
{
type: 'object',
properties: {
url: { type: 'string' },
keys: {
type: 'array',
items: { type: 'string', minLength: 1 },
minItems: 1,
}
},
required: ['url', 'keys'],
}
],
};
export type BlacklistItemJSON = string | { export type BlacklistItemJSON = string | {
url: string, url: string,
@ -54,11 +35,10 @@ export class BlacklistItem {
this.keyEntities = this.keys.map(Key.fromMapKey); this.keyEntities = this.keys.map(Key.fromMapKey);
} }
static fromJSON(json: unknown): BlacklistItem { static fromJSON(json: BlacklistItemJSON): BlacklistItem {
let obj = new Validator<BlacklistItemJSON>(ItemSchema).validate(json); return typeof json === 'string'
return typeof obj === 'string' ? new BlacklistItem(json, false, [])
? new BlacklistItem(obj, false, []) : new BlacklistItem(json.url, true, json.keys);
: new BlacklistItem(obj.url, true, obj.keys);
} }
toJSON(): BlacklistItemJSON { toJSON(): BlacklistItemJSON {
@ -91,10 +71,7 @@ export default class Blacklist {
) { ) {
} }
static fromJSON(json: unknown): Blacklist { static fromJSON(json: BlacklistJSON): Blacklist {
if (!Array.isArray(json)) {
throw new TypeError('blacklist is not an array');
}
let items = json.map(o => BlacklistItem.fromJSON(o)); let items = json.map(o => BlacklistItem.fromJSON(o));
return new Blacklist(items); return new Blacklist(items);
} }

@ -1,32 +1,23 @@
import * as operations from '../operations'; import * as operations from '../operations';
import Validator from './Validator';
const Schema = { type OperationJson = {
type: 'object', type: string
patternProperties: { } | {
'.*': { type: string;
type: 'object', [prop: string]: string | number | boolean;
properties: {
type: { type: 'string' },
},
required: ['type'],
},
}
}; };
export type KeymapsJSON = { [key: string]: OperationJson };
export type KeymapsJSON = { [key: string]: operations.Operation };
export default class Keymaps { export default class Keymaps {
constructor( constructor(
private readonly data: KeymapsJSON, private readonly data: { [key: string]: operations.Operation },
) { ) {
} }
static fromJSON(json: unknown): Keymaps { static fromJSON(json: KeymapsJSON): Keymaps {
let obj = new Validator<KeymapsJSON>(Schema).validate(json); let entries: { [key: string]: operations.Operation } = {};
let entries: KeymapsJSON = {}; for (let key of Object.keys(json)) {
for (let key of Object.keys(obj)) { entries[key] = operations.valueOf(json[key]);
entries[key] = operations.valueOf(obj[key]);
} }
return new Keymaps(entries); return new Keymaps(entries);
} }

@ -1,19 +1,3 @@
import Validator from './Validator';
const Schema = {
type: 'object',
properties: {
hintchars: {
type: 'string',
},
smoothscroll: {
type: 'boolean',
},
complete: {
type: 'string',
},
},
};
export type PropertiesJSON = { export type PropertiesJSON = {
hintchars?: string; hintchars?: string;
@ -82,9 +66,8 @@ export default class Properties {
this.complete = complete || defaultValues.complete; this.complete = complete || defaultValues.complete;
} }
static fromJSON(json: unknown): Properties { static fromJSON(json: PropertiesJSON): Properties {
let obj = new Validator<PropertiesJSON>(Schema).validate(json); return new Properties(json);
return new Properties(obj);
} }
static types(): PropertyTypes { static types(): PropertyTypes {

@ -1,22 +1,3 @@
import Validator from './Validator';
const Schema = {
type: 'object',
properties: {
default: { type: 'string' },
engines: {
type: 'object',
propertyNames: {
pattern: '^[A-Za-z_][A-Za-z0-9_]+$',
},
patternProperties: {
'.*': { type: 'string' },
},
},
},
required: ['default'],
};
type Entries = { [name: string]: string }; type Entries = { [name: string]: string };
export type SearchJSON = { export type SearchJSON = {
@ -31,10 +12,11 @@ export default class Search {
) { ) {
} }
static fromJSON(json: unknown): Search { static fromJSON(json: SearchJSON): Search {
let obj = new Validator<SearchJSON>(Schema).validate(json); for (let [name, url] of Object.entries(json.engines)) {
if (!(/^[a-zA-Z0-9]+$/).test(name)) {
for (let [name, url] of Object.entries(obj.engines)) { throw new TypeError('Search engine\'s name must be [a-zA-Z0-9]+');
}
let matches = url.match(/{}/g); let matches = url.match(/{}/g);
if (matches === null) { if (matches === null) {
throw new TypeError(`No {}-placeholders in URL of "${name}"`); throw new TypeError(`No {}-placeholders in URL of "${name}"`);
@ -42,11 +24,11 @@ export default class Search {
throw new TypeError(`Multiple {}-placeholders in URL of "${name}"`); throw new TypeError(`Multiple {}-placeholders in URL of "${name}"`);
} }
} }
if (!Object.keys(obj.engines).includes(obj.default)) { if (!Object.keys(json.engines).includes(json.default)) {
throw new TypeError(`Default engine "${obj.default}" not found`); throw new TypeError(`Default engine "${json.default}" not found`);
} }
return new Search(obj.default, obj.engines); return new Search(json.default, json.engines);
} }
toJSON(): SearchJSON { toJSON(): SearchJSON {

@ -1,13 +1,16 @@
import Ajv from 'ajv';
import Keymaps, { KeymapsJSON } from './Keymaps'; import Keymaps, { KeymapsJSON } from './Keymaps';
import Search, { SearchJSON } from './Search'; import Search, { SearchJSON } from './Search';
import Properties, { PropertiesJSON } from './Properties'; import Properties, { PropertiesJSON } from './Properties';
import Blacklist, { BlacklistJSON } from './Blacklist'; import Blacklist, { BlacklistJSON } from './Blacklist';
import validate from './validate';
export type SettingsJSON = { export type SettingsJSON = {
keymaps: KeymapsJSON, keymaps?: KeymapsJSON,
search: SearchJSON, search?: SearchJSON,
properties: PropertiesJSON, properties?: PropertiesJSON,
blacklist: BlacklistJSON, blacklist?: BlacklistJSON,
}; };
export default class Settings { export default class Settings {
@ -36,25 +39,30 @@ export default class Settings {
this.blacklist = blacklist; this.blacklist = blacklist;
} }
static fromJSON(json: any): Settings { static fromJSON(json: unknown): Settings {
let valid = validate(json);
if (!valid) {
let message = (validate as any).errors!!
.map((err: Ajv.ErrorObject) => {
return `'${err.dataPath}' of ${err.keyword} ${err.message}`;
})
.join('; ');
throw new TypeError(message);
}
let obj = json as SettingsJSON;
let settings = { ...DefaultSetting }; let settings = { ...DefaultSetting };
for (let key of Object.keys(json)) { if (obj.keymaps) {
switch (key) { settings.keymaps = Keymaps.fromJSON(obj.keymaps);
case 'keymaps': }
settings.keymaps = Keymaps.fromJSON(json.keymaps); if (obj.search) {
break; settings.search = Search.fromJSON(obj.search);
case 'search': }
settings.search = Search.fromJSON(json.search); if (obj.properties) {
break; settings.properties = Properties.fromJSON(obj.properties);
case 'properties': }
settings.properties = Properties.fromJSON(json.properties); if (obj.blacklist) {
break; settings.blacklist = Blacklist.fromJSON(obj.blacklist);
case 'blacklist':
settings.blacklist = Blacklist.fromJSON(json.blacklist);
break;
default:
throw new TypeError('unknown setting: ' + key);
}
} }
return new Settings(settings); return new Settings(settings);
} }

@ -1,20 +0,0 @@
import Ajv from 'ajv';
export default class Validator<T> {
constructor(
private schema: object | boolean,
) {
}
validate(data: any): T {
let ajv = new Ajv();
let valid = ajv.validate(this.schema, data);
if (!valid) {
let message = ajv.errors!!
.map(err => `'${err.dataPath}' of ${err.keyword} ${err.message}`)
.join('; ');
throw new TypeError(message);
}
return data as T;
}
}

@ -78,5 +78,6 @@
] ]
} }
} }
} },
"additionalProperties": false
} }

@ -9,168 +9,90 @@ var validate = (function() {
if ((data && typeof data === "object" && !Array.isArray(data))) { if ((data && typeof data === "object" && !Array.isArray(data))) {
var errs__0 = errors; var errs__0 = errors;
var valid1 = true; var valid1 = true;
var data1 = data.keymaps; for (var key0 in data) {
if (data1 === undefined) { var isAdditional0 = !(false || key0 == 'keymaps' || key0 == 'search' || key0 == 'properties' || key0 == 'blacklist');
valid1 = true; if (isAdditional0) {
} else { valid1 = false;
var errs_1 = errors;
if ((data1 && typeof data1 === "object" && !Array.isArray(data1))) {
var errs__1 = errors;
var valid2 = true;
for (var key1 in data1) {
if (pattern0.test(key1)) {
var data2 = data1[key1];
var errs_2 = errors;
if ((data2 && typeof data2 === "object" && !Array.isArray(data2))) {
if (true) {
var errs__2 = errors;
var valid3 = true;
if (data2.type === undefined) {
valid3 = false;
validate.errors = [{
keyword: 'required',
dataPath: (dataPath || '') + '.keymaps[\'' + key1 + '\']',
schemaPath: '#/properties/keymaps/patternProperties/.*/required',
params: {
missingProperty: 'type'
},
message: 'should have required property \'type\''
}];
return false;
} else {
var errs_3 = errors;
if (typeof data2.type !== "string") {
validate.errors = [{
keyword: 'type',
dataPath: (dataPath || '') + '.keymaps[\'' + key1 + '\'].type',
schemaPath: '#/properties/keymaps/patternProperties/.*/properties/type/type',
params: {
type: 'string'
},
message: 'should be string'
}];
return false;
}
var valid3 = errors === errs_3;
}
}
} else {
validate.errors = [{
keyword: 'type',
dataPath: (dataPath || '') + '.keymaps[\'' + key1 + '\']',
schemaPath: '#/properties/keymaps/patternProperties/.*/type',
params: {
type: 'object'
},
message: 'should be object'
}];
return false;
}
var valid2 = errors === errs_2;
if (!valid2) break;
} else valid2 = true;
}
} else {
validate.errors = [{ validate.errors = [{
keyword: 'type', keyword: 'additionalProperties',
dataPath: (dataPath || '') + '.keymaps', dataPath: (dataPath || '') + "",
schemaPath: '#/properties/keymaps/type', schemaPath: '#/additionalProperties',
params: { params: {
type: 'object' additionalProperty: '' + key0 + ''
}, },
message: 'should be object' message: 'should NOT have additional properties'
}]; }];
return false; return false;
break;
} }
var valid1 = errors === errs_1;
} }
if (valid1) { if (valid1) {
var data1 = data.search; var data1 = data.keymaps;
if (data1 === undefined) { if (data1 === undefined) {
valid1 = true; valid1 = true;
} else { } else {
var errs_1 = errors; var errs_1 = errors;
if ((data1 && typeof data1 === "object" && !Array.isArray(data1))) { if ((data1 && typeof data1 === "object" && !Array.isArray(data1))) {
if (true) { var errs__1 = errors;
var errs__1 = errors; var valid2 = true;
var valid2 = true; for (var key1 in data1) {
if (data1.default === undefined) { if (pattern0.test(key1)) {
valid2 = false; var data2 = data1[key1];
validate.errors = [{
keyword: 'required',
dataPath: (dataPath || '') + '.search',
schemaPath: '#/properties/search/required',
params: {
missingProperty: 'default'
},
message: 'should have required property \'default\''
}];
return false;
} else {
var errs_2 = errors; var errs_2 = errors;
if (typeof data1.default !== "string") { if ((data2 && typeof data2 === "object" && !Array.isArray(data2))) {
if (true) {
var errs__2 = errors;
var valid3 = true;
if (data2.type === undefined) {
valid3 = false;
validate.errors = [{
keyword: 'required',
dataPath: (dataPath || '') + '.keymaps[\'' + key1 + '\']',
schemaPath: '#/properties/keymaps/patternProperties/.*/required',
params: {
missingProperty: 'type'
},
message: 'should have required property \'type\''
}];
return false;
} else {
var errs_3 = errors;
if (typeof data2.type !== "string") {
validate.errors = [{
keyword: 'type',
dataPath: (dataPath || '') + '.keymaps[\'' + key1 + '\'].type',
schemaPath: '#/properties/keymaps/patternProperties/.*/properties/type/type',
params: {
type: 'string'
},
message: 'should be string'
}];
return false;
}
var valid3 = errors === errs_3;
}
}
} else {
validate.errors = [{ validate.errors = [{
keyword: 'type', keyword: 'type',
dataPath: (dataPath || '') + '.search.default', dataPath: (dataPath || '') + '.keymaps[\'' + key1 + '\']',
schemaPath: '#/properties/search/properties/default/type', schemaPath: '#/properties/keymaps/patternProperties/.*/type',
params: { params: {
type: 'string' type: 'object'
}, },
message: 'should be string' message: 'should be object'
}]; }];
return false; return false;
} }
var valid2 = errors === errs_2; var valid2 = errors === errs_2;
} if (!valid2) break;
if (valid2) { } else valid2 = true;
var data2 = data1.engines;
if (data2 === undefined) {
valid2 = true;
} else {
var errs_2 = errors;
if ((data2 && typeof data2 === "object" && !Array.isArray(data2))) {
var errs__2 = errors;
var valid3 = true;
for (var key2 in data2) {
if (pattern0.test(key2)) {
var errs_3 = errors;
if (typeof data2[key2] !== "string") {
validate.errors = [{
keyword: 'type',
dataPath: (dataPath || '') + '.search.engines[\'' + key2 + '\']',
schemaPath: '#/properties/search/properties/engines/patternProperties/.*/type',
params: {
type: 'string'
},
message: 'should be string'
}];
return false;
}
var valid3 = errors === errs_3;
if (!valid3) break;
} else valid3 = true;
}
} else {
validate.errors = [{
keyword: 'type',
dataPath: (dataPath || '') + '.search.engines',
schemaPath: '#/properties/search/properties/engines/type',
params: {
type: 'object'
},
message: 'should be object'
}];
return false;
}
var valid2 = errors === errs_2;
}
}
} }
} else { } else {
validate.errors = [{ validate.errors = [{
keyword: 'type', keyword: 'type',
dataPath: (dataPath || '') + '.search', dataPath: (dataPath || '') + '.keymaps',
schemaPath: '#/properties/search/type', schemaPath: '#/properties/keymaps/type',
params: { params: {
type: 'object' type: 'object'
}, },
@ -181,65 +103,80 @@ var validate = (function() {
var valid1 = errors === errs_1; var valid1 = errors === errs_1;
} }
if (valid1) { if (valid1) {
var data1 = data.properties; var data1 = data.search;
if (data1 === undefined) { if (data1 === undefined) {
valid1 = true; valid1 = true;
} else { } else {
var errs_1 = errors; var errs_1 = errors;
if ((data1 && typeof data1 === "object" && !Array.isArray(data1))) { if ((data1 && typeof data1 === "object" && !Array.isArray(data1))) {
var errs__1 = errors; if (true) {
var valid2 = true; var errs__1 = errors;
if (data1.hintchars === undefined) { var valid2 = true;
valid2 = true; if (data1.default === undefined) {
} else { valid2 = false;
var errs_2 = errors;
if (typeof data1.hintchars !== "string") {
validate.errors = [{ validate.errors = [{
keyword: 'type', keyword: 'required',
dataPath: (dataPath || '') + '.properties.hintchars', dataPath: (dataPath || '') + '.search',
schemaPath: '#/properties/properties/properties/hintchars/type', schemaPath: '#/properties/search/required',
params: { params: {
type: 'string' missingProperty: 'default'
}, },
message: 'should be string' message: 'should have required property \'default\''
}]; }];
return false; return false;
}
var valid2 = errors === errs_2;
}
if (valid2) {
if (data1.smoothscroll === undefined) {
valid2 = true;
} else { } else {
var errs_2 = errors; var errs_2 = errors;
if (typeof data1.smoothscroll !== "boolean") { if (typeof data1.default !== "string") {
validate.errors = [{ validate.errors = [{
keyword: 'type', keyword: 'type',
dataPath: (dataPath || '') + '.properties.smoothscroll', dataPath: (dataPath || '') + '.search.default',
schemaPath: '#/properties/properties/properties/smoothscroll/type', schemaPath: '#/properties/search/properties/default/type',
params: { params: {
type: 'boolean' type: 'string'
}, },
message: 'should be boolean' message: 'should be string'
}]; }];
return false; return false;
} }
var valid2 = errors === errs_2; var valid2 = errors === errs_2;
} }
if (valid2) { if (valid2) {
if (data1.complete === undefined) { var data2 = data1.engines;
if (data2 === undefined) {
valid2 = true; valid2 = true;
} else { } else {
var errs_2 = errors; var errs_2 = errors;
if (typeof data1.complete !== "string") { if ((data2 && typeof data2 === "object" && !Array.isArray(data2))) {
var errs__2 = errors;
var valid3 = true;
for (var key2 in data2) {
if (pattern0.test(key2)) {
var errs_3 = errors;
if (typeof data2[key2] !== "string") {
validate.errors = [{
keyword: 'type',
dataPath: (dataPath || '') + '.search.engines[\'' + key2 + '\']',
schemaPath: '#/properties/search/properties/engines/patternProperties/.*/type',
params: {
type: 'string'
},
message: 'should be string'
}];
return false;
}
var valid3 = errors === errs_3;
if (!valid3) break;
} else valid3 = true;
}
} else {
validate.errors = [{ validate.errors = [{
keyword: 'type', keyword: 'type',
dataPath: (dataPath || '') + '.properties.complete', dataPath: (dataPath || '') + '.search.engines',
schemaPath: '#/properties/properties/properties/complete/type', schemaPath: '#/properties/search/properties/engines/type',
params: { params: {
type: 'string' type: 'object'
}, },
message: 'should be string' message: 'should be object'
}]; }];
return false; return false;
} }
@ -250,8 +187,8 @@ var validate = (function() {
} else { } else {
validate.errors = [{ validate.errors = [{
keyword: 'type', keyword: 'type',
dataPath: (dataPath || '') + '.properties', dataPath: (dataPath || '') + '.search',
schemaPath: '#/properties/properties/type', schemaPath: '#/properties/search/type',
params: { params: {
type: 'object' type: 'object'
}, },
@ -262,123 +199,148 @@ var validate = (function() {
var valid1 = errors === errs_1; var valid1 = errors === errs_1;
} }
if (valid1) { if (valid1) {
var data1 = data.blacklist; var data1 = data.properties;
if (data1 === undefined) { if (data1 === undefined) {
valid1 = true; valid1 = true;
} else { } else {
var errs_1 = errors; var errs_1 = errors;
if (Array.isArray(data1)) { if ((data1 && typeof data1 === "object" && !Array.isArray(data1))) {
var errs__1 = errors; var errs__1 = errors;
var valid1; var valid2 = true;
for (var i1 = 0; i1 < data1.length; i1++) { if (data1.hintchars === undefined) {
var data2 = data1[i1]; valid2 = true;
} else {
var errs_2 = errors; var errs_2 = errors;
var errs__2 = errors; if (typeof data1.hintchars !== "string") {
var valid2 = false; validate.errors = [{
var errs_3 = errors;
if (typeof data2 !== "string") {
var err = {
keyword: 'type', keyword: 'type',
dataPath: (dataPath || '') + '.blacklist[' + i1 + ']', dataPath: (dataPath || '') + '.properties.hintchars',
schemaPath: '#/properties/blacklist/items/anyOf/0/type', schemaPath: '#/properties/properties/properties/hintchars/type',
params: { params: {
type: 'string' type: 'string'
}, },
message: 'should be string' message: 'should be string'
}; }];
if (vErrors === null) vErrors = [err]; return false;
else vErrors.push(err); }
errors++; var valid2 = errors === errs_2;
}
if (valid2) {
if (data1.smoothscroll === undefined) {
valid2 = true;
} else {
var errs_2 = errors;
if (typeof data1.smoothscroll !== "boolean") {
validate.errors = [{
keyword: 'type',
dataPath: (dataPath || '') + '.properties.smoothscroll',
schemaPath: '#/properties/properties/properties/smoothscroll/type',
params: {
type: 'boolean'
},
message: 'should be boolean'
}];
return false;
}
var valid2 = errors === errs_2;
}
if (valid2) {
if (data1.complete === undefined) {
valid2 = true;
} else {
var errs_2 = errors;
if (typeof data1.complete !== "string") {
validate.errors = [{
keyword: 'type',
dataPath: (dataPath || '') + '.properties.complete',
schemaPath: '#/properties/properties/properties/complete/type',
params: {
type: 'string'
},
message: 'should be string'
}];
return false;
}
var valid2 = errors === errs_2;
}
} }
var valid3 = errors === errs_3; }
valid2 = valid2 || valid3; } else {
if (!valid2) { validate.errors = [{
keyword: 'type',
dataPath: (dataPath || '') + '.properties',
schemaPath: '#/properties/properties/type',
params: {
type: 'object'
},
message: 'should be object'
}];
return false;
}
var valid1 = errors === errs_1;
}
if (valid1) {
var data1 = data.blacklist;
if (data1 === undefined) {
valid1 = true;
} else {
var errs_1 = errors;
if (Array.isArray(data1)) {
var errs__1 = errors;
var valid1;
for (var i1 = 0; i1 < data1.length; i1++) {
var data2 = data1[i1];
var errs_2 = errors;
var errs__2 = errors;
var valid2 = false;
var errs_3 = errors; var errs_3 = errors;
if ((data2 && typeof data2 === "object" && !Array.isArray(data2))) { if (typeof data2 !== "string") {
if (true) { var err = {
var errs__3 = errors; keyword: 'type',
var valid4 = true; dataPath: (dataPath || '') + '.blacklist[' + i1 + ']',
if (data2.url === undefined) { schemaPath: '#/properties/blacklist/items/anyOf/0/type',
valid4 = false; params: {
var err = { type: 'string'
keyword: 'required', },
dataPath: (dataPath || '') + '.blacklist[' + i1 + ']', message: 'should be string'
schemaPath: '#/properties/blacklist/items/anyOf/1/required', };
params: { if (vErrors === null) vErrors = [err];
missingProperty: 'url' else vErrors.push(err);
}, errors++;
message: 'should have required property \'url\'' }
}; var valid3 = errors === errs_3;
if (vErrors === null) vErrors = [err]; valid2 = valid2 || valid3;
else vErrors.push(err); if (!valid2) {
errors++; var errs_3 = errors;
} else { if ((data2 && typeof data2 === "object" && !Array.isArray(data2))) {
var errs_4 = errors; if (true) {
if (typeof data2.url !== "string") { var errs__3 = errors;
var err = { var valid4 = true;
keyword: 'type', if (data2.url === undefined) {
dataPath: (dataPath || '') + '.blacklist[' + i1 + '].url',
schemaPath: '#/properties/blacklist/items/anyOf/1/properties/url/type',
params: {
type: 'string'
},
message: 'should be string'
};
if (vErrors === null) vErrors = [err];
else vErrors.push(err);
errors++;
}
var valid4 = errors === errs_4;
}
if (valid4) {
var data3 = data2.keys;
if (data3 === undefined) {
valid4 = false; valid4 = false;
var err = { var err = {
keyword: 'required', keyword: 'required',
dataPath: (dataPath || '') + '.blacklist[' + i1 + ']', dataPath: (dataPath || '') + '.blacklist[' + i1 + ']',
schemaPath: '#/properties/blacklist/items/anyOf/1/required', schemaPath: '#/properties/blacklist/items/anyOf/1/required',
params: { params: {
missingProperty: 'keys' missingProperty: 'url'
}, },
message: 'should have required property \'keys\'' message: 'should have required property \'url\''
}; };
if (vErrors === null) vErrors = [err]; if (vErrors === null) vErrors = [err];
else vErrors.push(err); else vErrors.push(err);
errors++; errors++;
} else { } else {
var errs_4 = errors; var errs_4 = errors;
if (Array.isArray(data3)) { if (typeof data2.url !== "string") {
var errs__4 = errors;
var valid4;
for (var i4 = 0; i4 < data3.length; i4++) {
var errs_5 = errors;
if (typeof data3[i4] !== "string") {
var err = {
keyword: 'type',
dataPath: (dataPath || '') + '.blacklist[' + i1 + '].keys[' + i4 + ']',
schemaPath: '#/properties/blacklist/items/anyOf/1/properties/keys/items/type',
params: {
type: 'string'
},
message: 'should be string'
};
if (vErrors === null) vErrors = [err];
else vErrors.push(err);
errors++;
}
var valid5 = errors === errs_5;
if (!valid5) break;
}
} else {
var err = { var err = {
keyword: 'type', keyword: 'type',
dataPath: (dataPath || '') + '.blacklist[' + i1 + '].keys', dataPath: (dataPath || '') + '.blacklist[' + i1 + '].url',
schemaPath: '#/properties/blacklist/items/anyOf/1/properties/keys/type', schemaPath: '#/properties/blacklist/items/anyOf/1/properties/url/type',
params: { params: {
type: 'array' type: 'string'
}, },
message: 'should be array' message: 'should be string'
}; };
if (vErrors === null) vErrors = [err]; if (vErrors === null) vErrors = [err];
else vErrors.push(err); else vErrors.push(err);
@ -386,61 +348,118 @@ var validate = (function() {
} }
var valid4 = errors === errs_4; var valid4 = errors === errs_4;
} }
if (valid4) {
var data3 = data2.keys;
if (data3 === undefined) {
valid4 = false;
var err = {
keyword: 'required',
dataPath: (dataPath || '') + '.blacklist[' + i1 + ']',
schemaPath: '#/properties/blacklist/items/anyOf/1/required',
params: {
missingProperty: 'keys'
},
message: 'should have required property \'keys\''
};
if (vErrors === null) vErrors = [err];
else vErrors.push(err);
errors++;
} else {
var errs_4 = errors;
if (Array.isArray(data3)) {
var errs__4 = errors;
var valid4;
for (var i4 = 0; i4 < data3.length; i4++) {
var errs_5 = errors;
if (typeof data3[i4] !== "string") {
var err = {
keyword: 'type',
dataPath: (dataPath || '') + '.blacklist[' + i1 + '].keys[' + i4 + ']',
schemaPath: '#/properties/blacklist/items/anyOf/1/properties/keys/items/type',
params: {
type: 'string'
},
message: 'should be string'
};
if (vErrors === null) vErrors = [err];
else vErrors.push(err);
errors++;
}
var valid5 = errors === errs_5;
if (!valid5) break;
}
} else {
var err = {
keyword: 'type',
dataPath: (dataPath || '') + '.blacklist[' + i1 + '].keys',
schemaPath: '#/properties/blacklist/items/anyOf/1/properties/keys/type',
params: {
type: 'array'
},
message: 'should be array'
};
if (vErrors === null) vErrors = [err];
else vErrors.push(err);
errors++;
}
var valid4 = errors === errs_4;
}
}
} }
} else {
var err = {
keyword: 'type',
dataPath: (dataPath || '') + '.blacklist[' + i1 + ']',
schemaPath: '#/properties/blacklist/items/anyOf/1/type',
params: {
type: 'object'
},
message: 'should be object'
};
if (vErrors === null) vErrors = [err];
else vErrors.push(err);
errors++;
} }
} else { var valid3 = errors === errs_3;
valid2 = valid2 || valid3;
}
if (!valid2) {
var err = { var err = {
keyword: 'type', keyword: 'anyOf',
dataPath: (dataPath || '') + '.blacklist[' + i1 + ']', dataPath: (dataPath || '') + '.blacklist[' + i1 + ']',
schemaPath: '#/properties/blacklist/items/anyOf/1/type', schemaPath: '#/properties/blacklist/items/anyOf',
params: { params: {},
type: 'object' message: 'should match some schema in anyOf'
},
message: 'should be object'
}; };
if (vErrors === null) vErrors = [err]; if (vErrors === null) vErrors = [err];
else vErrors.push(err); else vErrors.push(err);
errors++; errors++;
validate.errors = vErrors;
return false;
} else {
errors = errs__2;
if (vErrors !== null) {
if (errs__2) vErrors.length = errs__2;
else vErrors = null;
}
} }
var valid3 = errors === errs_3; var valid2 = errors === errs_2;
valid2 = valid2 || valid3; if (!valid2) break;
}
if (!valid2) {
var err = {
keyword: 'anyOf',
dataPath: (dataPath || '') + '.blacklist[' + i1 + ']',
schemaPath: '#/properties/blacklist/items/anyOf',
params: {},
message: 'should match some schema in anyOf'
};
if (vErrors === null) vErrors = [err];
else vErrors.push(err);
errors++;
validate.errors = vErrors;
return false;
} else {
errors = errs__2;
if (vErrors !== null) {
if (errs__2) vErrors.length = errs__2;
else vErrors = null;
}
} }
var valid2 = errors === errs_2; } else {
if (!valid2) break; validate.errors = [{
keyword: 'type',
dataPath: (dataPath || '') + '.blacklist',
schemaPath: '#/properties/blacklist/type',
params: {
type: 'array'
},
message: 'should be array'
}];
return false;
} }
} else { var valid1 = errors === errs_1;
validate.errors = [{
keyword: 'type',
dataPath: (dataPath || '') + '.blacklist',
schemaPath: '#/properties/blacklist/type',
params: {
type: 'array'
},
message: 'should be array'
}];
return false;
} }
var valid1 = errors === errs_1;
} }
} }
} }
@ -531,7 +550,8 @@ validate.schema = {
}] }]
} }
} }
} },
"additionalProperties": false
}; };
validate.errors = null; validate.errors = null;
module.exports = validate; module.exports = validate;

@ -16,16 +16,6 @@ describe('BlacklistItem', () => {
expect(item.partial).to.be.true; expect(item.partial).to.be.true;
expect(item.keys).to.deep.equal(['j', 'k']); expect(item.keys).to.deep.equal(['j', 'k']);
}); });
it('throws a TypeError', () => {
expect(() => BlacklistItem.fromJSON(null)).to.throw(TypeError);
expect(() => BlacklistItem.fromJSON(100)).to.throw(TypeError);
expect(() => BlacklistItem.fromJSON({})).to.throw(TypeError);
expect(() => BlacklistItem.fromJSON({url: 'google.com'})).to.throw(TypeError);
expect(() => BlacklistItem.fromJSON({keys: ['a']})).to.throw(TypeError);
expect(() => BlacklistItem.fromJSON({url: 'google.com', keys: 10})).to.throw(TypeError);
expect(() => BlacklistItem.fromJSON({url: 'google.com', keys: ['a', 'b', 3]})).to.throw(TypeError);
});
}); });
describe('#matches', () => { describe('#matches', () => {
@ -118,14 +108,6 @@ describe('Blacklist', () => {
let blacklist = Blacklist.fromJSON([]); let blacklist = Blacklist.fromJSON([]);
expect(blacklist.toJSON()).to.deep.equals([]); expect(blacklist.toJSON()).to.deep.equals([]);
}); });
it('throws a TypeError', () => {
expect(() => Blacklist.fromJSON(null)).to.throw(TypeError);
expect(() => Blacklist.fromJSON(100)).to.throw(TypeError);
expect(() => Blacklist.fromJSON({})).to.throw(TypeError);
expect(() => Blacklist.fromJSON([100])).to.throw(TypeError);
expect(() => Blacklist.fromJSON([{}])).to.throw(TypeError);
})
}); });
describe('#includesEntireBlacklist', () => { describe('#includesEntireBlacklist', () => {

@ -19,7 +19,6 @@ describe('Keymaps', () => {
}); });
it('throws a TypeError by invalid settings', () => { it('throws a TypeError by invalid settings', () => {
expect(() => Keymaps.fromJSON(null)).to.throw(TypeError);
expect(() => Keymaps.fromJSON({ expect(() => Keymaps.fromJSON({
k: { type: "invalid.operation" }, k: { type: "invalid.operation" },
})).to.throw(TypeError); })).to.throw(TypeError);

@ -26,19 +26,6 @@ describe('Search', () => {
}); });
it('throws a TypeError by invalid settings', () => { it('throws a TypeError by invalid settings', () => {
expect(() => Search.fromJSON(null)).to.throw(TypeError);
expect(() => Search.fromJSON({})).to.throw(TypeError);
expect(() => Search.fromJSON([])).to.throw(TypeError);
expect(() => Search.fromJSON({
default: 123,
engines: {}
})).to.throw(TypeError);
expect(() => Search.fromJSON({
default: 'google',
engines: {
'google': 123456,
}
})).to.throw(TypeError);
expect(() => Search.fromJSON({ expect(() => Search.fromJSON({
default: 'wikipedia', default: 'wikipedia',
engines: { engines: {