From 0a2657d27bb4a016232767fd1fa766d89df4c146 Mon Sep 17 00:00:00 2001 From: Manuel Spigolon Date: Sun, 21 Aug 2022 10:20:27 +0200 Subject: [PATCH 01/11] feat: standalone mode --- README.md | 88 +++++++++++++++++++ package.json | 1 + standalone.js | 43 +++++++++ test/plugin.test.js | 4 +- test/standalone.test.js | 188 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 321 insertions(+), 3 deletions(-) create mode 100644 standalone.js create mode 100644 test/standalone.test.js diff --git a/README.md b/README.md index 6047f98..08afbaa 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,94 @@ You can also override the default configuration by passing the [`serializerOpts` This module is already used as default by Fastify. If you need to provide to your server instance a different version, refer to [the official doc](https://www.fastify.io/docs/latest/Reference/Server/#schemacontroller). +### fast-json-stringify Standalone + +`fast-json-stringify@v4.1.0` introduces the [standalone feature](https://github.com/fastify/fast-json-stringify#standalone) that let you to pre-compile your schemas and use them in your application for a faster startup. + +To use this feature, you must be aware of the following: + +1. You must generate and save the application's compiled schemas. +2. Read the compiled schemas from the file and provide them back to your Fastify application. + + +#### Generate and save the compiled schemas + +Fastify helps you to generate the serialization schemas functions and it is your choice to save them where you want. +To accomplish this, you must use a new compiler: `@fastify/fast-json-stringify-compiler/standalone`. + +You must provide 2 parameters to this compiler: + +- `readMode: false`: a boolean to indicate that you want generate the schemas functions string. +- `storeFunction`" a sync function that must store the source code of the schemas functions. You may provide an async function too, but you must manage errors. + +When `readMode: false`, **the compiler is meant to be used in development ONLY**. + + +```js +const factory = require('@fastify/fast-json-stringify-compiler/standalone')({ + readMode: false, + storeFunction (routeOpts, schemaSerializationCode) { + // routeOpts is like: { schema, method, url, httpStatus } + // schemaSerializationCode is a string source code that is the compiled schema function + const fileName = generateFileName(routeOpts) + fs.writeFileSync(path.join(__dirname, fileName), schemaSerializationCode) + } +}) + +const app = fastify({ + jsonShorthand: false, + schemaController: { + compilersFactory: { + buildSerializer: factory + } + } +}) + +// ... add all your routes with schemas ... + +app.ready().then(() => { + // at this stage all your schemas are compiled and stored in the file system + // now it is important to turn off the readMode +}) +``` + +#### Read the compiled schemas functions + +At this stage, you should have a file for every route's schema. +To use them, you must use the `@fastify/fast-json-stringify-compiler/standalone` with the parameters: + +- `readMode: true`: a boolean to indicate that you want read and use the schemas functions string. +- `restoreFunction`" a sync function that must return a function to serialize the route's payload. + +Important keep away before you continue reading the documentation: + +- when you use the `readMode: true`, the application schemas are not compiled (they are ignored). So, if you change your schemas, you must recompile them! +- as you can see, you must relate the route's schema to the file name using the `routeOpts` object. You may use the `routeOpts.schema.$id` field to do so, it is up to you to define a unique schema identifier. + +```js +const factory = require('@fastify/fast-json-stringify-compiler/standalone')({ + readMode: true, + restoreFunction (routeOpts) { + // routeOpts is like: { schema, method, url, httpStatus } + const fileName = generateFileName(routeOpts) + return require(path.join(__dirname, fileName)) + } +}) + +const app = fastify({ + jsonShorthand: false, + schemaController: { + compilersFactory: { + buildSerializer: factory + } + } +}) + +// ... add all your routes with schemas as before... + +app.listen({ port: 3000 }) +``` + ### How it works This module provide a factory function to produce [Serializer Compilers](https://www.fastify.io/docs/latest/Reference/Server/#serializercompiler) functions. diff --git a/package.json b/package.json index 0e3dc69..d6f4444 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "homepage": "https://github.com/fastify/fast-json-stringify-compiler#readme", "devDependencies": { "fastify": "^4.0.0", + "sanitize-filename": "^1.6.3", "standard": "^17.0.0", "tap": "^16.0.0", "tsd": "^0.22.0" diff --git a/standalone.js b/standalone.js new file mode 100644 index 0000000..488e92f --- /dev/null +++ b/standalone.js @@ -0,0 +1,43 @@ +'use strict' + +const SerializerSelector = require('./index') + +function StandaloneValidator (options = { readMode: true }) { + if (options.readMode === true && !options.restoreFunction) { + throw new Error('You must provide a restoreFunction options when readMode ON') + } + + if (options.readMode !== true && !options.storeFunction) { + throw new Error('You must provide a storeFunction options when readMode OFF') + } + + if (options.readMode === true) { + // READ MODE: it behalf only in the restore function provided by the user + return function wrapper () { + return function (opts) { + return options.restoreFunction(opts) + } + } + } + + // WRITE MODE: it behalf on the default SerializerSelector, wrapping the API to run the Ajv Standalone code generation + const factory = SerializerSelector() + return function wrapper (externalSchemas, serializerOpts = {}) { + if (!serializerOpts.mode || !serializerOpts.mode !== 'standalone') { + // to generate the serialization source code, these options are mandatory + serializerOpts.mode = 'standalone' + } + + const compiler = factory(externalSchemas, serializerOpts) + return function (opts) { // { schema/*, method, url, httpPart */ } + const serializeFuncCode = compiler(opts) + + options.storeFunction(opts, serializeFuncCode) + + // eslint-disable-next-line no-new-func + return new Function(serializeFuncCode) + } + } +} + +module.exports = StandaloneValidator diff --git a/test/plugin.test.js b/test/plugin.test.js index d467720..df2582b 100644 --- a/test/plugin.test.js +++ b/test/plugin.test.js @@ -25,9 +25,7 @@ const externalSchemas2 = Object.freeze({ } }) -const fastifyFjsOptionsDefault = Object.freeze({ - customOptions: {} -}) +const fastifyFjsOptionsDefault = Object.freeze({}) t.test('basic usage', t => { t.plan(1) diff --git a/test/standalone.test.js b/test/standalone.test.js new file mode 100644 index 0000000..bdf2609 --- /dev/null +++ b/test/standalone.test.js @@ -0,0 +1,188 @@ +'use strict' + +const fs = require('fs') +const path = require('path') +const t = require('tap') +const fastify = require('fastify') +const sanitize = require('sanitize-filename') + +const FjsStandaloneCompiler = require('../standalone') + +function generateFileName (routeOpts) { + return `/fjs-generated-${sanitize(routeOpts.schema.$id)}-${routeOpts.method}-${routeOpts.httpPart}-${sanitize(routeOpts.url)}.js` +} + +t.test('errors', t => { + t.plan(2) + t.throws(() => { + FjsStandaloneCompiler() + }, 'missing restoreFunction') + t.throws(() => { + FjsStandaloneCompiler({ readMode: false }) + }, 'missing storeFunction') +}) + +t.test('generate standalone code', t => { + t.plan(5) + + const base = { + $id: 'urn:schema:base', + definitions: { + hello: { type: 'string' } + }, + type: 'object', + properties: { + hello: { $ref: '#/definitions/hello' } + } + } + + const refSchema = { + $id: 'urn:schema:ref', + type: 'object', + properties: { + hello: { $ref: 'urn:schema:base#/definitions/hello' } + } + } + + const endpointSchema = { + schema: { + $id: 'urn:schema:endpoint', + $ref: 'urn:schema:ref' + } + } + + const schemaMap = { + [base.$id]: base, + [refSchema.$id]: refSchema + } + + const factory = FjsStandaloneCompiler({ + readMode: false, + storeFunction (routeOpts, schemaValidationCode) { + t.same(routeOpts, endpointSchema) + t.type(schemaValidationCode, 'string') + fs.writeFileSync(path.join(__dirname, '/fjs-generated.js'), schemaValidationCode) + t.pass('stored the validation function') + } + }) + + const compiler = factory(schemaMap) + compiler(endpointSchema) + t.pass('compiled the endpoint schema') + + t.test('usage standalone code', t => { + t.plan(3) + const standaloneSerializer = require('./fjs-generated') + t.ok(standaloneSerializer) + + const valid = standaloneSerializer({ hello: 'world' }) + t.same(valid, JSON.stringify({ hello: 'world' })) + + const invalid = standaloneSerializer({ hello: [] }) + t.same(invalid, '{"hello":""}') + }) +}) + +t.test('fastify integration - writeMode', async t => { + t.plan(4) + + const factory = FjsStandaloneCompiler({ + readMode: false, + storeFunction (routeOpts, schemaSerializationCode) { + const fileName = generateFileName(routeOpts) + t.ok(routeOpts) + fs.writeFileSync(path.join(__dirname, fileName), schemaSerializationCode) + t.pass(`stored the validation function ${fileName}`) + }, + restoreFunction () { + t.fail('write mode ON') + } + }) + + const app = buildApp(factory) + await app.ready() +}) + +t.test('fastify integration - readMode', async t => { + t.plan(6) + + const factory = FjsStandaloneCompiler({ + readMode: true, + storeFunction () { + t.fail('read mode ON') + }, + restoreFunction (routeOpts) { + const fileName = generateFileName(routeOpts) + t.pass(`restore the validation function ${fileName}}`) + return require(path.join(__dirname, fileName)) + } + }) + + const app = buildApp(factory) + await app.ready() + + let res = await app.inject({ + url: '/foo', + method: 'POST' + }) + t.equal(res.statusCode, 200) + t.equal(res.payload, JSON.stringify({ hello: 'world' })) + + res = await app.inject({ + url: '/bar?lang=it', + method: 'GET' + }) + t.equal(res.statusCode, 200) + t.equal(res.payload, JSON.stringify({ lang: 'en' })) +}) + +function buildApp (factory) { + const app = fastify({ + exposeHeadRoutes: false, + jsonShorthand: false, + schemaController: { + compilersFactory: { + buildSerializer: factory + } + } + }) + + app.addSchema({ + $id: 'urn:schema:foo', + type: 'object', + properties: { + name: { type: 'string' }, + id: { type: 'integer' } + } + }) + + app.post('/foo', { + schema: { + response: { + 200: { + $id: 'urn:schema:response', + type: 'object', + properties: { + hello: { $ref: 'urn:schema:foo#/properties/name' } + } + } + } + } + }, () => { return { hello: 'world' } }) + + app.get('/bar', { + schema: { + response: { + 200: { + $id: 'urn:schema:response:bar', + type: 'object', + properties: { + lang: { type: 'string', enum: ['it', 'en'] } + } + } + } + } + }, () => { return { lang: 'en' } }) + + return app +} From 74f5e9ac7d36fa793b64539e838609da67de462d Mon Sep 17 00:00:00 2001 From: Manuel Spigolon Date: Sun, 21 Aug 2022 10:29:38 +0200 Subject: [PATCH 02/11] fix: coverage --- .github/workflows/ci.yml | 1 + package.json | 6 ++++-- standalone.js | 2 +- test/standalone.test.js | 29 +++++++++++++++++++++++++++-- 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 325921f..079a8f0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,3 +15,4 @@ jobs: uses: fastify/workflows/.github/workflows/plugins-ci.yml@v3 with: license-check: true + lint: true diff --git a/package.json b/package.json index d6f4444..d125c52 100644 --- a/package.json +++ b/package.json @@ -5,9 +5,11 @@ "main": "index.js", "types": "index.d.ts", "scripts": { + "lint": "standard", "lint:fix": "standard --fix", - "unit": "tap --100 test/**/*.test.js", - "test": "standard && npm run unit && npm run test:typescript", + "unit": "tap test/**/*.test.js", + "test": "npm run unit && npm run test:typescript", + "posttest": "rm test/fjs-generated*.js", "test:typescript": "tsd" }, "repository": { diff --git a/standalone.js b/standalone.js index 488e92f..d54e514 100644 --- a/standalone.js +++ b/standalone.js @@ -23,7 +23,7 @@ function StandaloneValidator (options = { readMode: true }) { // WRITE MODE: it behalf on the default SerializerSelector, wrapping the API to run the Ajv Standalone code generation const factory = SerializerSelector() return function wrapper (externalSchemas, serializerOpts = {}) { - if (!serializerOpts.mode || !serializerOpts.mode !== 'standalone') { + if (!serializerOpts.mode || serializerOpts.mode !== 'standalone') { // to generate the serialization source code, these options are mandatory serializerOpts.mode = 'standalone' } diff --git a/test/standalone.test.js b/test/standalone.test.js index bdf2609..5fc149b 100644 --- a/test/standalone.test.js +++ b/test/standalone.test.js @@ -103,6 +103,30 @@ t.test('fastify integration - writeMode', async t => { await app.ready() }) +t.test('fastify integration - writeMode forces standalone', async t => { + t.plan(4) + + const factory = FjsStandaloneCompiler({ + readMode: false, + storeFunction (routeOpts, schemaSerializationCode) { + const fileName = generateFileName(routeOpts) + t.ok(routeOpts) + fs.writeFileSync(path.join(__dirname, fileName), schemaSerializationCode) + t.pass(`stored the validation function ${fileName}`) + }, + restoreFunction () { + t.fail('write mode ON') + } + }) + + const app = buildApp(factory, { + mode: 'not-standalone', + rounding: 'ceil' + }) + + await app.ready() +}) + t.test('fastify integration - readMode', async t => { t.plan(6) @@ -136,7 +160,7 @@ t.test('fastify integration - readMode', async t => { t.equal(res.payload, JSON.stringify({ lang: 'en' })) }) -function buildApp (factory) { +function buildApp (factory, serializerOpts) { const app = fastify({ exposeHeadRoutes: false, jsonShorthand: false, @@ -144,7 +168,8 @@ function buildApp (factory) { compilersFactory: { buildSerializer: factory } - } + }, + serializerOpts }) app.addSchema({ From ebbb3fb564fa937329bb6735d5073b893d1ab1bc Mon Sep 17 00:00:00 2001 From: Manuel Spigolon Date: Sun, 21 Aug 2022 10:33:49 +0200 Subject: [PATCH 03/11] chore: fix wording --- standalone.js | 4 ++-- test/standalone.test.js | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/standalone.js b/standalone.js index d54e514..82a0308 100644 --- a/standalone.js +++ b/standalone.js @@ -2,7 +2,7 @@ const SerializerSelector = require('./index') -function StandaloneValidator (options = { readMode: true }) { +function StandaloneSerializer (options = { readMode: true }) { if (options.readMode === true && !options.restoreFunction) { throw new Error('You must provide a restoreFunction options when readMode ON') } @@ -40,4 +40,4 @@ function StandaloneValidator (options = { readMode: true }) { } } -module.exports = StandaloneValidator +module.exports = StandaloneSerializer diff --git a/test/standalone.test.js b/test/standalone.test.js index 5fc149b..e71428b 100644 --- a/test/standalone.test.js +++ b/test/standalone.test.js @@ -58,11 +58,11 @@ t.test('generate standalone code', t => { const factory = FjsStandaloneCompiler({ readMode: false, - storeFunction (routeOpts, schemaValidationCode) { + storeFunction (routeOpts, schemaSerializerCode) { t.same(routeOpts, endpointSchema) - t.type(schemaValidationCode, 'string') - fs.writeFileSync(path.join(__dirname, '/fjs-generated.js'), schemaValidationCode) - t.pass('stored the validation function') + t.type(schemaSerializerCode, 'string') + fs.writeFileSync(path.join(__dirname, '/fjs-generated.js'), schemaSerializerCode) + t.pass('stored the serializer function') } }) @@ -92,7 +92,7 @@ t.test('fastify integration - writeMode', async t => { const fileName = generateFileName(routeOpts) t.ok(routeOpts) fs.writeFileSync(path.join(__dirname, fileName), schemaSerializationCode) - t.pass(`stored the validation function ${fileName}`) + t.pass(`stored the serializer function ${fileName}`) }, restoreFunction () { t.fail('write mode ON') @@ -112,7 +112,7 @@ t.test('fastify integration - writeMode forces standalone', async t => { const fileName = generateFileName(routeOpts) t.ok(routeOpts) fs.writeFileSync(path.join(__dirname, fileName), schemaSerializationCode) - t.pass(`stored the validation function ${fileName}`) + t.pass(`stored the serializer function ${fileName}`) }, restoreFunction () { t.fail('write mode ON') @@ -137,7 +137,7 @@ t.test('fastify integration - readMode', async t => { }, restoreFunction (routeOpts) { const fileName = generateFileName(routeOpts) - t.pass(`restore the validation function ${fileName}}`) + t.pass(`restore the serializer function ${fileName}}`) return require(path.join(__dirname, fileName)) } }) From c56931fbde03ebbb1e7b2938c0188831be7e95ef Mon Sep 17 00:00:00 2001 From: Manuel Spigolon Date: Mon, 22 Aug 2022 09:06:04 +0200 Subject: [PATCH 04/11] chore: use rimraf --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index d125c52..f5f8b3b 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "lint:fix": "standard --fix", "unit": "tap test/**/*.test.js", "test": "npm run unit && npm run test:typescript", - "posttest": "rm test/fjs-generated*.js", + "posttest": "rimraf test/fjs-generated*.js", "test:typescript": "tsd" }, "repository": { @@ -25,6 +25,7 @@ "homepage": "https://github.com/fastify/fast-json-stringify-compiler#readme", "devDependencies": { "fastify": "^4.0.0", + "rimraf": "^3.0.2", "sanitize-filename": "^1.6.3", "standard": "^17.0.0", "tap": "^16.0.0", From eb4085208422461f0e353ee56d107b8a7be36fe9 Mon Sep 17 00:00:00 2001 From: Manuel Spigolon Date: Mon, 22 Aug 2022 09:29:46 +0200 Subject: [PATCH 05/11] chore: unuseful if --- standalone.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/standalone.js b/standalone.js index 82a0308..4472f62 100644 --- a/standalone.js +++ b/standalone.js @@ -23,10 +23,8 @@ function StandaloneSerializer (options = { readMode: true }) { // WRITE MODE: it behalf on the default SerializerSelector, wrapping the API to run the Ajv Standalone code generation const factory = SerializerSelector() return function wrapper (externalSchemas, serializerOpts = {}) { - if (!serializerOpts.mode || serializerOpts.mode !== 'standalone') { - // to generate the serialization source code, these options are mandatory - serializerOpts.mode = 'standalone' - } + // to generate the serialization source code, this option is mandatory + serializerOpts.mode = 'standalone' const compiler = factory(externalSchemas, serializerOpts) return function (opts) { // { schema/*, method, url, httpPart */ } From 0bf60611e92ad6872de4d27d65cc8427c5147449 Mon Sep 17 00:00:00 2001 From: Manuel Spigolon Date: Mon, 22 Aug 2022 19:38:12 +0200 Subject: [PATCH 06/11] Apply suggestions from code review Co-authored-by: Uzlopak --- standalone.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/standalone.js b/standalone.js index 4472f62..0a82e88 100644 --- a/standalone.js +++ b/standalone.js @@ -3,12 +3,12 @@ const SerializerSelector = require('./index') function StandaloneSerializer (options = { readMode: true }) { - if (options.readMode === true && !options.restoreFunction) { - throw new Error('You must provide a restoreFunction options when readMode ON') + if (options.readMode === true && typeof options.restoreFunction !== 'function') { + throw new Error('You must provide a function for the restoreFunction-option when readMode ON') } if (options.readMode !== true && !options.storeFunction) { - throw new Error('You must provide a storeFunction options when readMode OFF') + throw new Error('You must provide a function for the restoreFunction-option when readMode OFF') } if (options.readMode === true) { From aceca81e897437ceb5646405b4d40eae824c64da Mon Sep 17 00:00:00 2001 From: Manuel Spigolon Date: Mon, 22 Aug 2022 20:28:06 +0200 Subject: [PATCH 07/11] wip: add typescript --- standalone.d.ts | 16 ++++++++++++++++ test/types/standalone.test.ts | 21 +++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 standalone.d.ts create mode 100644 test/types/standalone.test.ts diff --git a/standalone.d.ts b/standalone.d.ts new file mode 100644 index 0000000..dcd7ee5 --- /dev/null +++ b/standalone.d.ts @@ -0,0 +1,16 @@ +import { SerializerCompiler } from './index' + +export type RouteDefinition = { + method: string, + url: string, + httpStatus: string, + schema?: unknown, +} + +interface Option { + readMode: Boolean, + storeFunction?(opts: RouteDefinition, schemaSerializationCode: string): void, + restoreFunction?(opts: RouteDefinition): void, +} + +export declare function StandaloneSerializer(Options): SerializerCompiler; diff --git a/test/types/standalone.test.ts b/test/types/standalone.test.ts new file mode 100644 index 0000000..54e4272 --- /dev/null +++ b/test/types/standalone.test.ts @@ -0,0 +1,21 @@ +import { expectAssignable, expectType } from "tsd"; + +import StandaloneSerializer, { RouteDefinition } from "../../standalone"; +import { SerializerCompiler } from "../.."; + +const reader = StandaloneSerializer({ + readMode: true, + restoreFunction: (route: RouteDefinition) => { + expectAssignable(route) + }, +}); +expectType(reader); + +const writer = StandaloneSerializer({ + readMode: false, + storeFunction: (route: RouteDefinition, code: string) => { + expectAssignable(route) + expectAssignable(code) + }, +}); +expectType(writer); \ No newline at end of file From 3ac0e8e4467099f258cea273566e23d6effa567c Mon Sep 17 00:00:00 2001 From: Manuel Spigolon Date: Tue, 23 Aug 2022 00:34:40 +0200 Subject: [PATCH 08/11] fix: typescript suggestions --- index.js | 2 ++ standalone.d.ts | 7 ++++--- standalone.js | 2 ++ test/types/{index.test.ts => index.test-d.ts} | 0 test/types/{standalone.test.ts => standalone.test-d.ts} | 0 5 files changed, 8 insertions(+), 3 deletions(-) rename test/types/{index.test.ts => index.test-d.ts} (100%) rename test/types/{standalone.test.ts => standalone.test-d.ts} (100%) diff --git a/index.js b/index.js index 836b4c7..6820c03 100644 --- a/index.js +++ b/index.js @@ -18,3 +18,5 @@ function responseSchemaCompiler (fjsOpts, { schema /* method, url, httpStatus */ } module.exports = SerializerSelector +module.exports.default = SerializerSelector +module.exports.SerializerSelector = SerializerSelector diff --git a/standalone.d.ts b/standalone.d.ts index dcd7ee5..790e7cc 100644 --- a/standalone.d.ts +++ b/standalone.d.ts @@ -1,4 +1,4 @@ -import { SerializerCompiler } from './index' +import { SerializerCompiler } from '.' export type RouteDefinition = { method: string, @@ -7,10 +7,11 @@ export type RouteDefinition = { schema?: unknown, } -interface Option { +export interface Options { readMode: Boolean, storeFunction?(opts: RouteDefinition, schemaSerializationCode: string): void, restoreFunction?(opts: RouteDefinition): void, } -export declare function StandaloneSerializer(Options): SerializerCompiler; +export function StandaloneSerializer(options: Options): SerializerCompiler; +export default StandaloneSerializer diff --git a/standalone.js b/standalone.js index 0a82e88..ab9ff10 100644 --- a/standalone.js +++ b/standalone.js @@ -39,3 +39,5 @@ function StandaloneSerializer (options = { readMode: true }) { } module.exports = StandaloneSerializer +module.exports.default = StandaloneSerializer +module.exports.StandaloneSerializer = StandaloneSerializer diff --git a/test/types/index.test.ts b/test/types/index.test-d.ts similarity index 100% rename from test/types/index.test.ts rename to test/types/index.test-d.ts diff --git a/test/types/standalone.test.ts b/test/types/standalone.test-d.ts similarity index 100% rename from test/types/standalone.test.ts rename to test/types/standalone.test-d.ts From 01d71c3f89999cb2f21047a49403ed889011b95d Mon Sep 17 00:00:00 2001 From: Manuel Spigolon Date: Tue, 23 Aug 2022 00:36:56 +0200 Subject: [PATCH 09/11] Apply suggestions from code review Co-authored-by: Ivan Tymoshenko --- standalone.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/standalone.js b/standalone.js index ab9ff10..78268eb 100644 --- a/standalone.js +++ b/standalone.js @@ -7,8 +7,8 @@ function StandaloneSerializer (options = { readMode: true }) { throw new Error('You must provide a function for the restoreFunction-option when readMode ON') } - if (options.readMode !== true && !options.storeFunction) { - throw new Error('You must provide a function for the restoreFunction-option when readMode OFF') + if (options.readMode !== true && typeof options.storeFunction !== 'function') { + throw new Error('You must provide a function for the storeFunction-option when readMode OFF') } if (options.readMode === true) { From 60429587816e4ce899a29c6cbdc750e4b7e4afe7 Mon Sep 17 00:00:00 2001 From: Manuel Spigolon Date: Tue, 23 Aug 2022 13:23:48 +0200 Subject: [PATCH 10/11] fix: exported interface --- index.js | 1 - standalone.js | 1 - 2 files changed, 2 deletions(-) diff --git a/index.js b/index.js index 6820c03..7bafff1 100644 --- a/index.js +++ b/index.js @@ -19,4 +19,3 @@ function responseSchemaCompiler (fjsOpts, { schema /* method, url, httpStatus */ module.exports = SerializerSelector module.exports.default = SerializerSelector -module.exports.SerializerSelector = SerializerSelector diff --git a/standalone.js b/standalone.js index 78268eb..39b4937 100644 --- a/standalone.js +++ b/standalone.js @@ -40,4 +40,3 @@ function StandaloneSerializer (options = { readMode: true }) { module.exports = StandaloneSerializer module.exports.default = StandaloneSerializer -module.exports.StandaloneSerializer = StandaloneSerializer From 46a2b0f48c59b574c343fc6aab2d0cf1418bf1ad Mon Sep 17 00:00:00 2001 From: Manuel Spigolon Date: Tue, 23 Aug 2022 17:55:39 +0200 Subject: [PATCH 11/11] fix: exported interface --- README.md | 8 ++++++-- index.d.ts | 24 +++++++++++++++++++++--- index.js | 2 ++ standalone.d.ts | 17 ----------------- test/standalone.test.js | 2 +- test/types/index.test-d.ts | 16 +++++++++++++--- test/types/standalone.test-d.ts | 2 +- 7 files changed, 44 insertions(+), 27 deletions(-) delete mode 100644 standalone.d.ts diff --git a/README.md b/README.md index 08afbaa..9f74dbd 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,9 @@ When `readMode: false`, **the compiler is meant to be used in development ONLY** ```js -const factory = require('@fastify/fast-json-stringify-compiler/standalone')({ +const { StandaloneSerializer } = require('@fastify/fast-json-stringify-compiler') + +const factory = StandaloneSerializer({ readMode: false, storeFunction (routeOpts, schemaSerializationCode) { // routeOpts is like: { schema, method, url, httpStatus } @@ -91,7 +93,9 @@ Important keep away before you continue reading the documentation: - as you can see, you must relate the route's schema to the file name using the `routeOpts` object. You may use the `routeOpts.schema.$id` field to do so, it is up to you to define a unique schema identifier. ```js -const factory = require('@fastify/fast-json-stringify-compiler/standalone')({ +const { StandaloneSerializer } = require('@fastify/fast-json-stringify-compiler') + +const factory = StandaloneSerializer({ readMode: true, restoreFunction (routeOpts) { // routeOpts is like: { schema, method, url, httpStatus } diff --git a/index.d.ts b/index.d.ts index 31506ad..0d7ec24 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,12 +1,30 @@ import { Options as FJSOptions } from 'fast-json-stringify' +export type { Options } from 'fast-json-stringify' + export type SerializerCompiler = ( externalSchemas: unknown, options: FJSOptions ) => (doc: any) => string; -export declare function SerializerSelector(): SerializerCompiler; +export type RouteDefinition = { + method: string, + url: string, + httpStatus: string, + schema?: unknown, +} -export type { Options } from 'fast-json-stringify' +export interface StandaloneOptions { + readMode: Boolean, + storeFunction?(opts: RouteDefinition, schemaSerializationCode: string): void, + restoreFunction?(opts: RouteDefinition): void, +} + +declare function SerializerSelector(): SerializerCompiler; +declare function StandaloneSerializer(options: StandaloneOptions): SerializerCompiler; -export default SerializerSelector; \ No newline at end of file +export default SerializerSelector; +export { + SerializerSelector, + StandaloneSerializer, +}; diff --git a/index.js b/index.js index 7bafff1..a021ea1 100644 --- a/index.js +++ b/index.js @@ -19,3 +19,5 @@ function responseSchemaCompiler (fjsOpts, { schema /* method, url, httpStatus */ module.exports = SerializerSelector module.exports.default = SerializerSelector +module.exports.SerializerSelector = SerializerSelector +module.exports.StandaloneSerializer = require('./standalone') diff --git a/standalone.d.ts b/standalone.d.ts deleted file mode 100644 index 790e7cc..0000000 --- a/standalone.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { SerializerCompiler } from '.' - -export type RouteDefinition = { - method: string, - url: string, - httpStatus: string, - schema?: unknown, -} - -export interface Options { - readMode: Boolean, - storeFunction?(opts: RouteDefinition, schemaSerializationCode: string): void, - restoreFunction?(opts: RouteDefinition): void, -} - -export function StandaloneSerializer(options: Options): SerializerCompiler; -export default StandaloneSerializer diff --git a/test/standalone.test.js b/test/standalone.test.js index e71428b..fa26e61 100644 --- a/test/standalone.test.js +++ b/test/standalone.test.js @@ -6,7 +6,7 @@ const t = require('tap') const fastify = require('fastify') const sanitize = require('sanitize-filename') -const FjsStandaloneCompiler = require('../standalone') +const { StandaloneSerializer: FjsStandaloneCompiler } = require('../') function generateFileName (routeOpts) { return `/fjs-generated-${sanitize(routeOpts.schema.$id)}-${routeOpts.method}-${routeOpts.httpPart}-${sanitize(routeOpts.url)}.js` diff --git a/test/types/index.test-d.ts b/test/types/index.test-d.ts index 67caf0d..9980fc9 100644 --- a/test/types/index.test-d.ts +++ b/test/types/index.test-d.ts @@ -1,6 +1,16 @@ import { expectType } from "tsd"; -import SerializerSelector, { SerializerCompiler } from "../.."; +import SerializerSelector, { + SerializerCompiler, + SerializerSelector as SerializerSelectorNamed, + StandaloneSerializer, +} from "../.."; -const compiler = SerializerSelector(); +{ + const compiler = SerializerSelector(); + expectType(compiler); +} -expectType(compiler); \ No newline at end of file +{ + const compiler = SerializerSelectorNamed(); + expectType(compiler); +} \ No newline at end of file diff --git a/test/types/standalone.test-d.ts b/test/types/standalone.test-d.ts index 54e4272..789b40e 100644 --- a/test/types/standalone.test-d.ts +++ b/test/types/standalone.test-d.ts @@ -1,6 +1,6 @@ import { expectAssignable, expectType } from "tsd"; -import StandaloneSerializer, { RouteDefinition } from "../../standalone"; +import { StandaloneSerializer, RouteDefinition } from "../../"; import { SerializerCompiler } from "../.."; const reader = StandaloneSerializer({