From 9f01816f4c1427e8b04b46b0a350d66201a56d7f Mon Sep 17 00:00:00 2001 From: Sergey Date: Sat, 28 Oct 2017 23:01:04 +0200 Subject: [PATCH] feat: add support for `typeof`, `instanceof` (`{Function\|RegExp}`) (#10) --- package.json | 3 +- src/validateOptions.js | 15 ++++--- test/__snapshots__/index.test.js.snap | 60 +++++++++++++++++++++++++++ test/fixtures/schema.json | 6 +++ test/index.test.js | 30 +++++++++++--- yarn.lock | 4 ++ 6 files changed, 106 insertions(+), 12 deletions(-) create mode 100644 test/__snapshots__/index.test.js.snap diff --git a/package.json b/package.json index 6b4c4e5..dad5122 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,8 @@ "release": "yarn run standard-version" }, "dependencies": { - "ajv": "^5.0.0" + "ajv": "^5.0.0", + "ajv-keywords": "^2.1.0" }, "devDependencies": { "babel-cli": "^6.24.1", diff --git a/src/validateOptions.js b/src/validateOptions.js index 3120183..2673daa 100644 --- a/src/validateOptions.js +++ b/src/validateOptions.js @@ -2,15 +2,18 @@ import fs from 'fs'; import path from 'path'; // eslint-disable-line import Ajv from 'ajv'; +import ajvKeywords from 'ajv-keywords'; import ValidationError from './ValidationError'; -const validateOptions = (schema, options, name) => { - const ajv = new Ajv({ - useDefaults: true, - allErrors: true, - errorDataPath: 'property', - }); +const ajv = new Ajv({ + useDefaults: true, + allErrors: true, + errorDataPath: 'property', +}); + +ajvKeywords(ajv, ['instanceof', 'typeof']); +const validateOptions = (schema, options, name) => { if (typeof schema === 'string') { schema = fs.readFileSync(path.resolve(schema), 'utf8'); // eslint-disable-line schema = JSON.parse(schema); // eslint-disable-line diff --git a/test/__snapshots__/index.test.js.snap b/test/__snapshots__/index.test.js.snap new file mode 100644 index 0000000..6d5e56a --- /dev/null +++ b/test/__snapshots__/index.test.js.snap @@ -0,0 +1,60 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Error should have errors for every key in options 1`] = ` +Array [ + Object { + "dataPath": ".string", + "keyword": "type", + "message": "should be string", + "params": Object { + "type": "string", + }, + "schemaPath": "#/properties/string/type", + }, + Object { + "dataPath": ".array", + "keyword": "type", + "message": "should be array", + "params": Object { + "type": "array", + }, + "schemaPath": "#/properties/array/type", + }, + Object { + "dataPath": ".object.prop", + "keyword": "type", + "message": "should be boolean", + "params": Object { + "type": "boolean", + }, + "schemaPath": "#/properties/object/properties/prop/type", + }, + Object { + "dataPath": ".boolean", + "keyword": "type", + "message": "should be boolean", + "params": Object { + "type": "boolean", + }, + "schemaPath": "#/properties/boolean/type", + }, + Object { + "dataPath": ".type", + "keyword": "typeof", + "message": "should pass \\"typeof\\" keyword validation", + "params": Object { + "keyword": "typeof", + }, + "schemaPath": "#/properties/type/typeof", + }, + Object { + "dataPath": ".instance", + "keyword": "instanceof", + "message": "should pass \\"instanceof\\" keyword validation", + "params": Object { + "keyword": "instanceof", + }, + "schemaPath": "#/properties/instance/instanceof", + }, +] +`; diff --git a/test/fixtures/schema.json b/test/fixtures/schema.json index 692ff53..b7668a4 100644 --- a/test/fixtures/schema.json +++ b/test/fixtures/schema.json @@ -20,6 +20,12 @@ }, "boolean": { "type": "boolean" + }, + "type": { + "typeof": "function" + }, + "instance": { + "instanceof": "RegExp" } }, "additionalProperties": false diff --git a/test/index.test.js b/test/index.test.js index cb7695a..c608b45 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -6,21 +6,41 @@ test('Valid', () => { string: 'hello', array: [ 'a' ], object: { prop: false }, - boolean: true + boolean: true, + type: function() {}, + instance: new RegExp(''), + }; expect(validateOptions('test/fixtures/schema.json', options, 'Loader')) .toBe(true); }); -test('Error', () => { +describe('Error', () => { const options = { string: false, array: {}, object: { prop: 1 }, - boolean: 'hello' + boolean: 'hello', + type: null, + instance: function() {}, }; - expect(() => validateOptions('test/fixtures/schema.json', options, '{Name}')) - .toThrowError(/Validation Error\n\n{Name} Invalid Options\n\n/); + const validate = () => validateOptions('test/fixtures/schema.json', options, '{Name}') + + test('should throw error', () => { + expect(validate).toThrowError(/Validation Error\n\n{Name} Invalid Options\n\n/); + }) + + test('should have errors for every key in options', () => { + try { + validate() + } catch(error) { + const expected = ['.string', '.array', '.object.prop', '.boolean', '.type', '.instance']; + const errors = error.err.map(e => e.dataPath) + + expect(errors).toMatchObject(expected); + expect(error.err).toMatchSnapshot(); + } + }) }); diff --git a/yarn.lock b/yarn.lock index f3c4da0..0512bc2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -52,6 +52,10 @@ ajv-keywords@^1.0.0: version "1.5.1" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" +ajv-keywords@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.0.tgz#a296e17f7bfae7c1ce4f7e0de53d29cb32162df0" + ajv@^4.7.0, ajv@^4.9.1: version "4.11.7" resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.7.tgz#8655a5d86d0824985cc471a1d913fb6729a0ec48"