Validate on top-level settings and use pre-compiled ajv
This commit is contained in:
		
							parent
							
								
									2318e3a555
								
							
						
					
					
						commit
						776977e0dc
					
				
					 11 changed files with 397 additions and 487 deletions
				
			
		| 
						 | 
					@ -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 settings = { ...DefaultSetting };
 | 
					    let valid = validate(json);
 | 
				
			||||||
    for (let key of Object.keys(json)) {
 | 
					    if (!valid) {
 | 
				
			||||||
      switch (key) {
 | 
					      let message = (validate as any).errors!!
 | 
				
			||||||
      case 'keymaps':
 | 
					        .map((err: Ajv.ErrorObject) => {
 | 
				
			||||||
        settings.keymaps = Keymaps.fromJSON(json.keymaps);
 | 
					          return `'${err.dataPath}' of ${err.keyword} ${err.message}`;
 | 
				
			||||||
        break;
 | 
					        })
 | 
				
			||||||
      case 'search':
 | 
					        .join('; ');
 | 
				
			||||||
        settings.search = Search.fromJSON(json.search);
 | 
					      throw new TypeError(message);
 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      case 'properties':
 | 
					 | 
				
			||||||
        settings.properties = Properties.fromJSON(json.properties);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      case 'blacklist':
 | 
					 | 
				
			||||||
        settings.blacklist = Blacklist.fromJSON(json.blacklist);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      default:
 | 
					 | 
				
			||||||
        throw new TypeError('unknown setting: ' + key);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let obj = json as SettingsJSON;
 | 
				
			||||||
 | 
					    let settings = { ...DefaultSetting };
 | 
				
			||||||
 | 
					    if (obj.keymaps) {
 | 
				
			||||||
 | 
					      settings.keymaps = Keymaps.fromJSON(obj.keymaps);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (obj.search) {
 | 
				
			||||||
 | 
					      settings.search = Search.fromJSON(obj.search);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (obj.properties) {
 | 
				
			||||||
 | 
					      settings.properties = Properties.fromJSON(obj.properties);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (obj.blacklist) {
 | 
				
			||||||
 | 
					      settings.blacklist = Blacklist.fromJSON(obj.blacklist);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    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,6 +9,24 @@ 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;
 | 
				
			||||||
 | 
					      for (var key0 in data) {
 | 
				
			||||||
 | 
					        var isAdditional0 = !(false || key0 == 'keymaps' || key0 == 'search' || key0 == 'properties' || key0 == 'blacklist');
 | 
				
			||||||
 | 
					        if (isAdditional0) {
 | 
				
			||||||
 | 
					          valid1 = false;
 | 
				
			||||||
 | 
					          validate.errors = [{
 | 
				
			||||||
 | 
					            keyword: 'additionalProperties',
 | 
				
			||||||
 | 
					            dataPath: (dataPath || '') + "",
 | 
				
			||||||
 | 
					            schemaPath: '#/additionalProperties',
 | 
				
			||||||
 | 
					            params: {
 | 
				
			||||||
 | 
					              additionalProperty: '' + key0 + ''
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            message: 'should NOT have additional properties'
 | 
				
			||||||
 | 
					          }];
 | 
				
			||||||
 | 
					          return false;
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (valid1) {
 | 
				
			||||||
        var data1 = data.keymaps;
 | 
					        var data1 = data.keymaps;
 | 
				
			||||||
        if (data1 === undefined) {
 | 
					        if (data1 === undefined) {
 | 
				
			||||||
          valid1 = true;
 | 
					          valid1 = true;
 | 
				
			||||||
| 
						 | 
					@ -445,6 +463,7 @@ var validate = (function() {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      validate.errors = [{
 | 
					      validate.errors = [{
 | 
				
			||||||
        keyword: 'type',
 | 
					        keyword: 'type',
 | 
				
			||||||
| 
						 | 
					@ -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: {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Reference in a new issue