From 4dc71caae20ee5abbaf4605380387683756d2f4d Mon Sep 17 00:00:00 2001 From: sprootshift <35349469+sprootshift@users.noreply.github.com> Date: Mon, 11 May 2020 12:18:40 -0400 Subject: [PATCH] Update enjoi and @hapi/joi to Joi 17 (#176) * Fixed failing `unknown` call for array schema After commit 429bfbfa53c8b8f1f5574f0e9447a3acdc669474 Joi object unknown method was called for all input schemas. This results in a runtime error for array input schema. This commit only invokes unknown method for object schema type. For convenience VS Code launch file to debug tape tests is also included. * Update enjoi and @hapi/joi to Joi 17 * Changed validator to return unwraped value * Updated enjoi dependency to 7.0.0 --- lib/index.js | 2 +- lib/validators.js | 41 +++++++++++++++-------------- package.json | 14 +++++----- test/fixtures/handlers/pets.js | 2 +- test/fixtures/handlers/pets/{id}.js | 2 +- test/test-validators.js | 2 +- 6 files changed, 32 insertions(+), 31 deletions(-) diff --git a/lib/index.js b/lib/index.js index 0a753f5..2f67b06 100644 --- a/lib/index.js +++ b/lib/index.js @@ -67,7 +67,7 @@ const requireApi = function (path) { const register = async function (server, options, next) { - const validation = Joi.validate(options, optionsSchema); + const validation = optionsSchema.validate(options); Hoek.assert(!validation.error, validation.error); diff --git a/lib/validators.js b/lib/validators.js index 2ad1958..09d6925 100644 --- a/lib/validators.js +++ b/lib/validators.js @@ -3,20 +3,21 @@ const Enjoi = require('enjoi'); const Joi = require('@hapi/joi'); -const types = { - int64: Joi.string().regex(/^\d+$/), - byte: Joi.string().base64(), - binary: Joi.binary(), - date: Joi.date(), - 'date-time': Joi.date().iso(), - file: Joi.object({ - value: Joi.binary().required(true), - consumes: Joi.array().items([ - Joi.string().regex(/multipart\/form-data|application\/x-www-form-urlencoded/) - ]).required(true), - in: Joi.string().regex(/formData/).required(true) - }) -}; +const extensions = [ + { type: 'int64', base: Joi.string().regex(/^\d+$/) }, + { type: 'byte', base: Joi.string().base64() }, + { type: 'date-time', base: Joi.date().iso() }, + { + type: 'file', + base: Joi.object({ + value: Joi.binary().required(true), + consumes: Joi.array().items( + Joi.string().regex(/multipart\/form-data|application\/x-www-form-urlencoded/) + ).required(true), + in: Joi.string().regex(/formData/).required(true) + }) + } +]; const refineType = function (type, format) { if (type === 'integer') { @@ -35,7 +36,7 @@ const refineType = function (type, format) { } }; -const enjoi = Enjoi.defaults({ types, refineType }); +const enjoi = Enjoi.defaults({ extensions, refineType }); const create = function (options = {}) { @@ -46,7 +47,7 @@ const create = function (options = {}) { if ((parameter.in === 'body' || parameter.in === 'formData') && parameter.schema) { schema = enjoi.schema(parameter.schema); - if (schema.schemaType === 'object') { + if (schema.type === 'object') { schema = schema.unknown(allowUnknownProperties); } } @@ -84,7 +85,7 @@ const create = function (options = {}) { schema = schema.required(); } - if (parameter.in !== 'body' && parameter.allowEmptyValue){ + if (parameter.in !== 'body' && parameter.allowEmptyValue) { schema = schema.allow('').optional(); } @@ -112,7 +113,7 @@ const create = function (options = {}) { throw result.error; } - return result; + return result.value; } }; }; @@ -196,7 +197,7 @@ const create = function (options = {}) { } for (const [key, value] of Object.entries(validate)) { - if (typeof value === 'object' && !value.isJoi) { + if (typeof value === 'object' && !Joi.isSchema(value)) { validate[key] = Joi.object(value); } } @@ -233,7 +234,7 @@ const coercion = function (parameter, consumes) { let fn; switch (parameter.type) { - case 'array' : + case 'array': fn = function (data) { if (Array.isArray(data)) { return data; diff --git a/package.json b/package.json index 3e38b98..f637b88 100644 --- a/package.json +++ b/package.json @@ -16,21 +16,21 @@ }, "dependencies": { "@hapi/hoek": "^9.0.4", - "@hapi/joi": "^14.5.0", - "dot-prop": "^4.2.0", - "enjoi": "^6.0.1", + "@hapi/joi": "^17.1.0", + "dot-prop": "^5.2.0", + "enjoi": "^7.0.0", "js-yaml": "^3.11.0", "merge-object-files": "^2.0.0", "swagger-parser": "^9.0.1" }, "devDependencies": { "@hapi/boom": "^9.1.0", + "@hapi/eslint-config-hapi": "^13.0.2", + "@hapi/eslint-plugin-hapi": "^4.3.5", "@hapi/hapi": "^19.1.1", - "eslint": "^4.19.1", - "eslint-config-hapi": "^11.1.0", - "eslint-plugin-hapi": "^4.1.0", + "eslint": "^6.8.0", "nyc": "^15.0.0", - "tape": "^4.9.0" + "tape": "^5.0.0" }, "scripts": { "test": "tape test/*.js", diff --git a/test/fixtures/handlers/pets.js b/test/fixtures/handlers/pets.js index 387caae..346e1b9 100644 --- a/test/fixtures/handlers/pets.js +++ b/test/fixtures/handlers/pets.js @@ -1,6 +1,6 @@ 'use strict'; -var Store = require('../lib/store'); +const Store = require('../lib/store'); module.exports = { get: function (req, h) { diff --git a/test/fixtures/handlers/pets/{id}.js b/test/fixtures/handlers/pets/{id}.js index 42e84b5..6739946 100644 --- a/test/fixtures/handlers/pets/{id}.js +++ b/test/fixtures/handlers/pets/{id}.js @@ -1,6 +1,6 @@ 'use strict'; -var Store = require('../../lib/store'); +const Store = require('../../lib/store'); module.exports = { get: [ diff --git a/test/test-validators.js b/test/test-validators.js index 7e493aa..581b5d8 100644 --- a/test/test-validators.js +++ b/test/test-validators.js @@ -107,7 +107,7 @@ Test('validator special types', function(t) { const v = validator.makeAll(api.paths['/test/{foo*}'].get.parameters); - const keys = Object.keys(v.validate.params.describe().children); + const keys = Object.keys(v.validate.params.describe().keys); if (keys.length === 1 && keys[0] === 'foo') { return t.pass(`${keys.join(', ')} are valid.`);