diff --git a/integration-tests/structured-logging/__tests__/to-do.js b/integration-tests/structured-logging/__tests__/to-do.js index 3ac5f2599975c..103b1d74d8841 100644 --- a/integration-tests/structured-logging/__tests__/to-do.js +++ b/integration-tests/structured-logging/__tests__/to-do.js @@ -105,12 +105,12 @@ const commonAssertions = events => { const actionSchema = joi.alternatives().try( joi .object({ - type: joi.string().required().valid([`SET_STATUS`]), + type: joi.string().required().valid(`SET_STATUS`), // TODO: We should change this to always be an Object I think pieh payload: joi .string() .required() - .valid([`SUCCESS`, `IN_PROGRESS`, `FAILED`, `INTERRUPTED`]), + .valid(`SUCCESS`, `IN_PROGRESS`, `FAILED`, `INTERRUPTED`), // Should this be here or one level up? timestamp: joi.string().required(), }) @@ -121,12 +121,7 @@ const commonAssertions = events => { type: joi .string() .required() - .valid([ - `ACTIVITY_START`, - `ACTIVITY_UPDATE`, - `ACTIVITY_END`, - `LOG`, - ]), + .valid(`ACTIVITY_START`, `ACTIVITY_UPDATE`, `ACTIVITY_END`, `LOG`), payload: joi.object(), // Should this be here or one level up? timestamp: joi.string().required(), @@ -135,7 +130,7 @@ const commonAssertions = events => { ) const eventSchema = joi.object({ - type: joi.string().required().valid([`LOG_ACTION`]), + type: joi.string().required().valid(`LOG_ACTION`), action: actionSchema, }) events.forEach(event => { diff --git a/integration-tests/structured-logging/package.json b/integration-tests/structured-logging/package.json index ba9d25953f7a8..ca651d62c9c17 100644 --- a/integration-tests/structured-logging/package.json +++ b/integration-tests/structured-logging/package.json @@ -20,7 +20,7 @@ "fs-extra": "^9.0.1", "jest": "^24.0.0", "jest-cli": "^24.0.0", - "joi": "^14.3.1", + "joi": "^17.4.0", "lodash": "^4.17.20", "node-fetch": "^2.6.1" } diff --git a/packages/gatsby-cli/package.json b/packages/gatsby-cli/package.json index 38d0a346e5bb9..ee88099cf109f 100644 --- a/packages/gatsby-cli/package.json +++ b/packages/gatsby-cli/package.json @@ -11,7 +11,6 @@ }, "dependencies": { "@babel/code-frame": "^7.10.4", - "@hapi/joi": "^15.1.1", "@types/common-tags": "^1.8.0", "better-opn": "^2.0.0", "chalk": "^4.1.0", @@ -29,6 +28,7 @@ "gatsby-telemetry": "^2.1.0-next.1", "hosted-git-info": "^3.0.6", "is-valid-path": "^0.1.1", + "joi": "^17.4.0", "lodash": "^4.17.20", "meant": "^1.0.2", "node-fetch": "^2.6.1", @@ -101,4 +101,4 @@ "engines": { "node": ">=12.13.0" } -} +} \ No newline at end of file diff --git a/packages/gatsby-cli/src/structured-errors/__tests__/error-schema.ts b/packages/gatsby-cli/src/structured-errors/__tests__/error-schema.ts index a01e785f294b5..807dd289597ff 100644 --- a/packages/gatsby-cli/src/structured-errors/__tests__/error-schema.ts +++ b/packages/gatsby-cli/src/structured-errors/__tests__/error-schema.ts @@ -1,13 +1,26 @@ import { errorSchema } from "../error-schema" -test(`throws invalid on an invalid error`, () => { - expect(errorSchema.validate({ lol: `true` })).rejects.toBeDefined() +test(`returns invalid on an invalid error`, () => { + expect(errorSchema.validate({ lol: `true` })).toMatchInlineSnapshot(` + Object { + "error": [ValidationError: "lol" is not allowed], + "value": Object { + "lol": "true", + }, + } + `) }) -test(`does not throw on a valid schema`, () => { +test(`returns a valid value`, () => { expect( errorSchema.validate({ context: {}, }) - ).resolves.toEqual(expect.any(Object)) + ).toMatchInlineSnapshot(` + Object { + "value": Object { + "context": Object {}, + }, + } + `) }) diff --git a/packages/gatsby-cli/src/structured-errors/construct-error.ts b/packages/gatsby-cli/src/structured-errors/construct-error.ts index aa0fd80592a6f..bd8b988fc4dbc 100644 --- a/packages/gatsby-cli/src/structured-errors/construct-error.ts +++ b/packages/gatsby-cli/src/structured-errors/construct-error.ts @@ -38,7 +38,7 @@ const constructError = ( // validate const { error } = errorSchema.validate(structuredError) - if (error !== null) { + if (error) { console.log(`Failed to validate error`, error) process.exit(1) } diff --git a/packages/gatsby-cli/src/structured-errors/error-schema.ts b/packages/gatsby-cli/src/structured-errors/error-schema.ts index 873ba4496f8ee..af4b233a9c87e 100644 --- a/packages/gatsby-cli/src/structured-errors/error-schema.ts +++ b/packages/gatsby-cli/src/structured-errors/error-schema.ts @@ -1,4 +1,4 @@ -import Joi from "@hapi/joi" +import Joi from "joi" import { ILocationPosition, IStructuredError } from "./types" export const Position: Joi.ObjectSchema = Joi.object().keys({ @@ -20,9 +20,9 @@ export const errorSchema: Joi.ObjectSchema = Joi.object().keys }) ) .allow(null), - category: Joi.string().valid([`USER`, `SYSTEM`, `THIRD_PARTY`]), - level: Joi.string().valid([`ERROR`, `WARNING`, `INFO`, `DEBUG`]), - type: Joi.string().valid([`GRAPHQL`, `CONFIG`, `WEBPACK`, `PLUGIN`]), + category: Joi.string().valid(`USER`, `SYSTEM`, `THIRD_PARTY`), + level: Joi.string().valid(`ERROR`, `WARNING`, `INFO`, `DEBUG`), + type: Joi.string().valid(`GRAPHQL`, `CONFIG`, `WEBPACK`, `PLUGIN`), filePath: Joi.string(), location: Joi.object({ start: Position.required(), diff --git a/packages/gatsby/package.json b/packages/gatsby/package.json index c2f4b5be34ce9..506c8ea281228 100644 --- a/packages/gatsby/package.json +++ b/packages/gatsby/package.json @@ -19,7 +19,6 @@ "@babel/types": "^7.12.6", "@gatsbyjs/reach-router": "^1.3.5", "@gatsbyjs/webpack-hot-middleware": "^2.25.2", - "@hapi/joi": "^15.1.1", "@mikaelkristiansson/domready": "^1.0.10", "@nodelib/fs.walk": "^1.2.4", "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3", @@ -170,7 +169,6 @@ "@babel/cli": "^7.12.1", "@babel/runtime": "^7.12.5", "@types/eslint": "^7.2.6", - "@types/hapi__joi": "^16.0.12", "@types/micromatch": "^4.0.1", "@types/normalize-path": "^3.0.0", "@types/reach__router": "^1.3.5", diff --git a/packages/gatsby/src/joi-schemas/__tests__/__snapshots__/joi.ts.snap b/packages/gatsby/src/joi-schemas/__tests__/__snapshots__/joi.ts.snap deleted file mode 100644 index d92eb6dfcf7e7..0000000000000 --- a/packages/gatsby/src/joi-schemas/__tests__/__snapshots__/joi.ts.snap +++ /dev/null @@ -1,9 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`gatsby config does not allow pathPrefix to be full URL 1`] = `"child \\"pathPrefix\\" fails because [\\"pathPrefix\\" must be a valid relative uri]"`; - -exports[`gatsby config throws when relative path used for both assetPrefix and pathPrefix 1`] = `"assetPrefix must be an absolute URI when used with pathPrefix"`; - -exports[`node schema doesn't allow unknown internal fields 1`] = `"child \\"internal\\" fails because [\\"customField\\" is not allowed]"`; - -exports[`node schema force id type 1`] = `"child \\"id\\" fails because [\\"id\\" must be a string]"`; diff --git a/packages/gatsby/src/joi-schemas/__tests__/joi.ts b/packages/gatsby/src/joi-schemas/__tests__/joi.ts index a2480b7c1e009..0cf825d2da485 100644 --- a/packages/gatsby/src/joi-schemas/__tests__/joi.ts +++ b/packages/gatsby/src/joi-schemas/__tests__/joi.ts @@ -1,25 +1,36 @@ import { gatsbyConfigSchema, nodeSchema } from "../joi" describe(`gatsby config`, () => { - it(`returns empty pathPrefix when not set`, async () => { + it(`returns empty pathPrefix when not set`, () => { const config = {} - const result = await gatsbyConfigSchema.validate(config) - expect(result).toEqual( + const result = gatsbyConfigSchema.validate(config) + expect(result.value).toEqual( expect.objectContaining({ pathPrefix: ``, }) ) }) - it(`strips trailing slashes from url fields`, async () => { + it(`throws when linkPrefix is set`, () => { + const config = { + linkPrefix: `/blog/`, + } + + const result = gatsbyConfigSchema.validate(config) + expect(result.error).toMatchInlineSnapshot( + `[Error: "linkPrefix" should be changed to "pathPrefix"]` + ) + }) + + it(`strips trailing slashes from url fields`, () => { const config = { pathPrefix: `/blog///`, assetPrefix: `https://cdn.example.com/`, } - const result = await gatsbyConfigSchema.validate(config) - expect(result).toEqual( + const result = gatsbyConfigSchema.validate(config) + expect(result.value).toEqual( expect.objectContaining({ pathPrefix: `/blog`, assetPrefix: `https://cdn.example.com`, @@ -27,46 +38,46 @@ describe(`gatsby config`, () => { ) }) - it(`allows assetPrefix to be full URL`, async () => { + it(`allows assetPrefix to be full URL`, () => { const config = { assetPrefix: `https://cdn.example.com/`, } - const result = await gatsbyConfigSchema.validate(config) - expect(result).toEqual( + const result = gatsbyConfigSchema.validate(config) + expect(result.value).toEqual( expect.objectContaining({ assetPrefix: `https://cdn.example.com`, }) ) }) - it(`allows assetPrefix to be a URL with nested paths`, async () => { + it(`allows assetPrefix to be a URL with nested paths`, () => { const config = { assetPrefix: `https://cdn.example.com/some/nested/path`, } - const result = await gatsbyConfigSchema.validate(config) - expect(result).toEqual(expect.objectContaining(config)) + const result = gatsbyConfigSchema.validate(config) + expect(result.value).toEqual(expect.objectContaining(config)) }) - it(`allows relative paths for url fields`, async () => { + it(`allows relative paths for url fields`, () => { const config = { pathPrefix: `/blog`, assetPrefix: `https://cdn.example.com`, } - const result = await gatsbyConfigSchema.validate(config) - expect(result).toEqual(expect.objectContaining(config)) + const result = gatsbyConfigSchema.validate(config) + expect(result.value).toEqual(expect.objectContaining(config)) }) - it(`strips trailing slash and add leading slash to pathPrefix`, async () => { + it(`strips trailing slash and add leading slash to pathPrefix`, () => { const config = { pathPrefix: `blog/`, assetPrefix: `https://cdn.example.com/`, } - const result = await gatsbyConfigSchema.validate(config) - expect(result).toEqual( + const result = gatsbyConfigSchema.validate(config) + expect(result.value).toEqual( expect.objectContaining({ pathPrefix: `/blog`, assetPrefix: `https://cdn.example.com`, @@ -74,36 +85,32 @@ describe(`gatsby config`, () => { ) }) - it(`does not allow pathPrefix to be full URL`, async () => { - expect.assertions(1) + it(`does not allow pathPrefix to be full URL`, () => { const config = { pathPrefix: `https://google.com`, } - try { - await gatsbyConfigSchema.validate(config) - } catch (err) { - expect(err.message).toMatchSnapshot() - } + const result = gatsbyConfigSchema.validate(config) + expect(result.error).toMatchInlineSnapshot( + `[ValidationError: "pathPrefix" must be a valid relative uri]` + ) }) - it(`throws when relative path used for both assetPrefix and pathPrefix`, async () => { - expect.assertions(1) + it(`throws when relative path used for both assetPrefix and pathPrefix`, () => { const config = { assetPrefix: `/assets`, pathPrefix: `/blog`, } - try { - await gatsbyConfigSchema.validate(config) - } catch (err) { - expect(err.message).toMatchSnapshot() - } + const result = gatsbyConfigSchema.validate(config) + expect(result.error).toMatchInlineSnapshot( + `[Error: assetPrefix must be an absolute URI when used with pathPrefix]` + ) }) }) describe(`node schema`, () => { - it(`allows correct nodes`, async () => { + it(`allows correct nodes`, () => { const node = { id: `foo`, internal: { @@ -119,7 +126,7 @@ describe(`node schema`, () => { expect(error).toBeFalsy() }) - it(`force id type`, async () => { + it(`force id type`, () => { const node = { id: 5, internal: { @@ -134,10 +141,10 @@ describe(`node schema`, () => { const { error } = nodeSchema.validate(node) expect(error).toBeTruthy() // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - expect(error!.message).toMatchSnapshot() + expect(error!.message).toMatchInlineSnapshot(`"\\"id\\" must be a string"`) }) - it(`doesn't allow unknown internal fields`, async () => { + it(`doesn't allow unknown internal fields`, () => { const node = { id: `foo`, internal: { @@ -154,6 +161,8 @@ describe(`node schema`, () => { const { error } = nodeSchema.validate(node) expect(error).toBeTruthy() // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - expect(error!.message).toMatchSnapshot() + expect(error!.message).toMatchInlineSnapshot( + `"\\"internal.customField\\" is not allowed"` + ) }) }) diff --git a/packages/gatsby/src/joi-schemas/joi.ts b/packages/gatsby/src/joi-schemas/joi.ts index e8a34df017e28..8596b69bb6b71 100644 --- a/packages/gatsby/src/joi-schemas/joi.ts +++ b/packages/gatsby/src/joi-schemas/joi.ts @@ -1,4 +1,4 @@ -import Joi from "@hapi/joi" +import Joi from "joi" import { IGatsbyConfig, IGatsbyPage, IGatsbyNode } from "../redux/types" const stripTrailingSlash = (chain: Joi.StringSchema): Joi.StringSchema => diff --git a/packages/gatsby/src/redux/actions/internal.ts b/packages/gatsby/src/redux/actions/internal.ts index 0fdf234dc61cb..7e512c220cbc0 100644 --- a/packages/gatsby/src/redux/actions/internal.ts +++ b/packages/gatsby/src/redux/actions/internal.ts @@ -291,7 +291,7 @@ export const setSiteConfig = (config?: unknown): ISetSiteConfig => { if (result.error) { const hasUnknownKeys = result.error.details.filter( - details => details.type === `object.allowUnknown` + details => details.type === `object.unknown` ) if (Array.isArray(hasUnknownKeys) && hasUnknownKeys.length) { diff --git a/packages/gatsby/src/redux/actions/public.js b/packages/gatsby/src/redux/actions/public.js index 6edb3e1188f49..113ffd05879a4 100644 --- a/packages/gatsby/src/redux/actions/public.js +++ b/packages/gatsby/src/redux/actions/public.js @@ -1,5 +1,4 @@ // @flow -const Joi = require(`@hapi/joi`) const chalk = require(`chalk`) const _ = require(`lodash`) const { stripIndent } = require(`common-tags`) @@ -647,7 +646,7 @@ const createNode = ( trackCli(`CREATE_NODE`, trackParams, { debounce: true }) - const result = Joi.validate(node, nodeSchema) + const result = nodeSchema.validate(node) if (result.error) { if (!hasErroredBecauseOfNodeValidation.has(result.error.message)) { const errorObj = { diff --git a/yarn.lock b/yarn.lock index b1f0277d77927..302fb250dbac1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4606,6 +4606,23 @@ version "0.3.2" resolved "https://registry.yarnpkg.com/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.2.tgz#8013f2af54a2b7d735f71560ff360d3a8176a87b" +"@sideway/address@^4.1.0": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.1.tgz#9e321e74310963fdf8eebfbee09c7bd69972de4d" + integrity sha512-+I5aaQr3m0OAmMr7RQ3fR9zx55sejEYR2BFJaxL+zT3VM2611X0SHvPWIbAUBZVTn/YzYKbV8gJ2oT/QELknfQ== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@sideway/formula@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.0.tgz#fe158aee32e6bd5de85044be615bc08478a0a13c" + integrity sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg== + +"@sideway/pinpoint@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" + integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== + "@sindresorhus/is@^0.14.0": version "0.14.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" @@ -5138,11 +5155,6 @@ "@types/tough-cookie" "*" form-data "^2.5.0" -"@types/hapi__joi@^16.0.12": - version "16.0.12" - resolved "https://registry.yarnpkg.com/@types/hapi__joi/-/hapi__joi-16.0.12.tgz#fb9113f17cf5764d6b3586ae9817d1606cc7c90c" - integrity sha512-xJYifuz59jXdWY5JMS15uvA3ycS3nQYOGqoIIE0+fwQ0qI3/4CxBc6RHsOTp6wk9M0NWEdpcTl02lOQOKMifbQ== - "@types/hast@^2.0.0": version "2.3.1" resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.1.tgz#b16872f2a6144c7025f296fb9636a667ebb79cd9" @@ -16622,6 +16634,17 @@ joi@^17.2.1: "@hapi/pinpoint" "^2.0.0" "@hapi/topo" "^5.0.0" +joi@^17.4.0: + version "17.4.0" + resolved "https://registry.yarnpkg.com/joi/-/joi-17.4.0.tgz#b5c2277c8519e016316e49ababd41a1908d9ef20" + integrity sha512-F4WiW2xaV6wc1jxete70Rw4V/VuMd6IN+a5ilZsxG4uYtUXWu2kq9W5P2dz30e7Gmw8RCbY/u/uk+dMPma9tAg== + dependencies: + "@hapi/hoek" "^9.0.0" + "@hapi/topo" "^5.0.0" + "@sideway/address" "^4.1.0" + "@sideway/formula" "^3.0.0" + "@sideway/pinpoint" "^2.0.0" + jpeg-js@^0.4.0: version "0.4.1" resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.1.tgz#937a3ae911eb6427f151760f8123f04c8bfe6ef7"