diff --git a/.github/FUNDING.yaml b/.github/FUNDING.yaml new file mode 100644 index 0000000..c44624b --- /dev/null +++ b/.github/FUNDING.yaml @@ -0,0 +1 @@ +github: metcoder95 \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index dd84ea7..0000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] - -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] - -**Additional context** -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index bbcbbe7..0000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8e603fc..94caacc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,7 +6,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [14.x, 16.x, 17.x] + node: [14.x, 16.x, 18.x] name: Node ${{ matrix.node }} steps: - uses: actions/checkout@v1 @@ -15,6 +15,4 @@ jobs: with: node-version: ${{ matrix.node }} - run: npm install - - run: npm run lint:ci - run: npm run test:ci - - run: npm run typescript diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml new file mode 100644 index 0000000..2b7b234 --- /dev/null +++ b/.github/workflows/pre-release.yml @@ -0,0 +1,19 @@ +name: Pre-Release +on: + push: + tags: + - 'v*.*.*-beta**' + - 'v*.*.*-rc**' + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: write + name: Pre-Release Creation + steps: + - uses: actions/checkout@v1 + - uses: ncipollo/release-action@v1 + with: + prerelease: true + bodyFile: "CHANGELOG.md" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..9a9451c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,18 @@ +name: Release +on: + push: + tags: + - 'v[0-9]+.[0-9]+.[0-9]+' + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: write + name: Release Creation + steps: + - uses: actions/checkout@v1 + - uses: ncipollo/release-action@v1 + with: + bodyFile: "CHANGELOG.md" + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/README.md b/README.md index 0b04eab..585a8c2 100644 --- a/README.md +++ b/README.md @@ -28,9 +28,16 @@ const Ajv = require('ajv'); const app = fastify(); const validator = new Ajv({}); -app.register(splitValidator, { defaultValidator: validator }); +await app.register(splitValidator, { defaultValidator: validator }); ``` +>**Note**: +> It is important to advice that with the new fastify@v4, all the route registration now happens asynchronously. +> This change translates in a way that if any plugin is meant to set logic into the `onRoute` hook for manipulating +> routes after registration, it is necessary to await until the plugin is fully loaded before proceeding with the next parts +> of your route definition. Otherwise, this can lead to non-deterministic behaviours when the plugin will not the expected +> effect on your fastify application. + **On Route** - `schemaValidators`: an object with the HTTP parts as keys and the validators to be used for that part as values diff --git a/index.js b/index.js index 03e228e..17cc360 100644 --- a/index.js +++ b/index.js @@ -77,6 +77,6 @@ function plugin (fastifyInstance, opts = {}, done) { } module.exports = fp(plugin, { - fastify: '>=3.24.1', + fastify: '>=4', name: 'fastify-split-validator' }) diff --git a/package.json b/package.json index d65db46..c5ad993 100644 --- a/package.json +++ b/package.json @@ -30,9 +30,9 @@ "author": "MetCoder95 ", "license": "MIT", "devDependencies": { - "@types/node": "^14.17.6", - "fastify": "^3.24.1", - "husky": "^7.0.2", + "@types/node": "^16.11.62", + "fastify": "^4.6.0", + "husky": "^7.0.4", "proxyquire": "^2.1.3", "snazzy": "^9.0.0", "standard": "^16.0.3", @@ -41,8 +41,8 @@ "typescript": "^4.4" }, "dependencies": { - "ajv": "^8.6.3", - "fastify-plugin": "^3.0.0" + "ajv": "^8.11.0", + "fastify-plugin": "^4.2.1" }, "tsd": { "directory": "test" diff --git a/test/index.test.js b/test/index.test.js index 2353413..22aa27c 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -102,7 +102,7 @@ test('Should allow custom AJV instance for body', async t => { const body = res.json() - t.equal(body.message, 'body must be array') + t.equal(body.message, 'body/msg must be array') t.equal( res.statusCode, 400, @@ -147,7 +147,7 @@ test('Should allow custom AJV instance for params', async t => { const body = res.json() - t.equal(body.message, 'params must be integer') + t.equal(body.message, 'params/msg must be integer') t.equal( res.statusCode, 400, @@ -198,7 +198,7 @@ test('Should allow custom AJV instance for headers', async t => { // TODO: set into documentation that it's possible the // error formatter doesn't work as expected. // Custom one should be provided - t.equal(body.message, 'headers must be integer') + t.equal(body.message, 'headers/x-type must be integer') t.equal( res.statusCode, 400, @@ -261,7 +261,7 @@ test('Should work with referenced schemas (querystring)', async t => { const body = res.json() - t.equal(body.message, 'querystring must be array') + t.equal(body.message, 'querystring/msg must be array') t.equal( res.statusCode, 400, @@ -313,7 +313,7 @@ test('Should work with referenced schemas (params)', async t => { const body = res.json() - t.equal(body.message, 'params must be integer') + t.equal(body.message, 'params/id must be integer') t.equal(res.statusCode, 400, 'Should not coearce the string into integer') } catch (err) { t.error(err) @@ -364,7 +364,7 @@ test('Should work with referenced schemas (headers)', async t => { const body = res.json() - t.equal(body.message, 'headers must be integer') + t.equal(body.message, 'headers/x-id must be integer') t.equal(res.statusCode, 400, 'Should not coearce the string into integer') } catch (err) { t.error(err) @@ -417,7 +417,7 @@ test('Should work with referenced schemas (body)', async t => { const body = res.json() - t.equal(body.message, 'body must be string') + t.equal(body.message, 'body/msg must be string') t.equal(res.statusCode, 400, 'Should not coearce the string into integer') } catch (err) { t.error(err) @@ -485,7 +485,7 @@ test('Should work with parent and same instance schemas', async t => { const body = res.json() - t.equal(body.message, 'body must be string') + t.equal(body.message, 'body/msg must be string') t.equal(res.statusCode, 400, 'Should not coearce the string into integer') } catch (err) { t.error(err) @@ -543,7 +543,7 @@ test('Should work with parent schemas', async t => { const body = res.json() - t.equal(body.message, 'body must be string') + t.equal(body.message, 'body/msg must be string') t.equal(res.statusCode, 400, 'Should not coearce the string into integer') } catch (err) { t.error(err) @@ -623,9 +623,9 @@ test('Should work with parent nested schemas', async t => { }) ]) - t.equal(res1.json().message, 'querystring must be array') + t.equal(res1.json().message, 'querystring/msg must be array') t.equal(res1.statusCode, 400, 'Should not coearce the string into array') - t.equal(res2.json().message, 'headers must be integer') + t.equal(res2.json().message, 'headers/x-another must be integer') t.equal(res2.statusCode, 400, 'Should not coearce the string into integer') } catch (err) { t.error(err) @@ -705,9 +705,9 @@ test('Should handle parsing to querystring (query)', async t => { }) ]) - t.equal(res1.json().message, 'querystring must be array') + t.equal(res1.json().message, 'querystring/msg must be array') t.equal(res1.statusCode, 400, 'Should not coearce the string into array') - t.equal(res2.json().message, 'headers must be integer') + t.equal(res2.json().message, 'headers/x-another must be integer') t.equal(res2.statusCode, 400, 'Should not coearce the string into integer') } catch (err) { t.error(err) @@ -784,7 +784,7 @@ test('Should use default plugin validator as fallback', async t => { } }) - t.equal(res.json().message, 'querystring must be array') + t.equal(res.json().message, 'querystring/msg must be array') t.equal(res.statusCode, 400, 'Should not coearce the string into array') t.ok(compileCalled, 'Should have called the default Ajv instance') } catch (err) { @@ -807,6 +807,7 @@ test('Should always cache schema to default plugin validator', async t => { } headerAjv.compile = schema => { + console.log('called') customCompileCalled = true return headerDefaultCompile(schema) } @@ -829,13 +830,13 @@ test('Should always cache schema to default plugin validator', async t => { } }) - server.register((instance, opts, done) => { + server.register(async (instance, opts, done) => { instance.addSchema({ $id: 'another', type: 'integer' }) - instance.register(proxiedPlugin, {}) + await instance.register(proxiedPlugin, {}) instance.post( '/', @@ -862,8 +863,6 @@ test('Should always cache schema to default plugin validator', async t => { reply.send({ noop: 'noop' }) } ) - - done() }) try { @@ -872,10 +871,13 @@ test('Should always cache schema to default plugin validator', async t => { url: '/', query: { msg: ['string'] + }, + headers: { + 'x-another': 1 } }) - t.equal(res.json().message, 'querystring must be array') + t.equal(res.json().message, 'querystring/msg must be array') t.equal(res.statusCode, 400, 'Should not coearce the string into array') t.ok(compileCalled, 'Should have called the default Ajv instance') t.ok(customCompileCalled, 'Should have called the custom Ajv instance') @@ -948,7 +950,7 @@ test('Should use default provided validator as fallback', async t => { } }) - t.equal(res.json().message, 'querystring must be array') + t.equal(res.json().message, 'querystring/msg must be array') t.equal(res.statusCode, 400, 'Should not coearce the string into array') t.ok(compileCalled, 'Should have called the default Ajv instance') } catch (err) {