From 935ad9d26168b821e79a5e68fb9a4d77221591e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Dewitte?= Date: Tue, 21 May 2024 11:45:33 +0200 Subject: [PATCH] feat: Strip external schemas from standalone compiled code --- lib/standalone.js | 6 +- test/standalone-mode.test.js | 111 ++++++++++++++++++++++++++++++++--- 2 files changed, 108 insertions(+), 9 deletions(-) diff --git a/lib/standalone.js b/lib/standalone.js index a3f705ea..0ba3ac3f 100644 --- a/lib/standalone.js +++ b/lib/standalone.js @@ -10,11 +10,15 @@ function buildStandaloneCode (contextFunc, context, serializer, validator) { ajvDependencyCode += 'const validator = null\n' } + // Don't need to keep external schemas once compiled + // validatorState will hold external schemas if it needs them + const { schema, ...serializerState } = serializer.getState() + return ` 'use strict' const Serializer = require('fast-json-stringify/lib/serializer') - const serializerState = ${JSON.stringify(serializer.getState())} + const serializerState = ${JSON.stringify(serializerState)} const serializer = Serializer.restoreFromState(serializerState) ${ajvDependencyCode} diff --git a/test/standalone-mode.test.js b/test/standalone-mode.test.js index 1e1570f2..73b25fa0 100644 --- a/test/standalone-mode.test.js +++ b/test/standalone-mode.test.js @@ -26,14 +26,14 @@ test('activate standalone mode', async (t) => { t.type(code, 'string') t.equal(code.indexOf('ajv'), -1) - const destionation = path.resolve(tmpDir, 'standalone.js') + const destination = path.resolve(tmpDir, 'standalone.js') t.teardown(async () => { - await fs.promises.rm(destionation, { force: true }) + await fs.promises.rm(destination, { force: true }) }) - await fs.promises.writeFile(destionation, code) - const standalone = require(destionation) + await fs.promises.writeFile(destination, code) + const standalone = require(destination) t.same(standalone({ firstName: 'Foo', surname: 'bar' }), JSON.stringify({ firstName: 'Foo' }), 'surname evicted') }) @@ -89,14 +89,14 @@ test('test ajv schema', async (t) => { t.type(code, 'string') t.equal(code.indexOf('ajv') > 0, true) - const destionation = path.resolve(tmpDir, 'standalone2.js') + const destination = path.resolve(tmpDir, 'standalone2.js') t.teardown(async () => { - await fs.promises.rm(destionation, { force: true }) + await fs.promises.rm(destination, { force: true }) }) - await fs.promises.writeFile(destionation, code) - const standalone = require(destionation) + await fs.promises.writeFile(destination, code) + const standalone = require(destination) t.same(standalone({ kind: 'foobar', foo: 'FOO', @@ -119,3 +119,98 @@ test('test ajv schema', async (t) => { }] })) }) + +test('no need to keep external schemas once compiled', async (t) => { + t.plan(1) + const externalSchema = { + first: { + definitions: { + id1: { + type: 'object', + properties: { + id1: { + type: 'integer' + } + } + } + } + } + } + const code = fjs({ + $ref: 'first#/definitions/id1' + }, { + mode: 'standalone', + schema: externalSchema + }) + + const destination = path.resolve(tmpDir, 'standalone3.js') + + t.teardown(async () => { + await fs.promises.rm(destination, { force: true }) + }) + + await fs.promises.writeFile(destination, code) + const standalone = require(destination) + + t.same(standalone({ id1: 5 }), JSON.stringify({ id1: 5 }), 'serialization works with external schemas') +}) + +test('no need to keep external schemas once compiled - with oneOf validator', async (t) => { + t.plan(2) + + const externalSchema = { + ext: { + definitions: { + oBaz: { + type: 'object', + properties: { + baz: { type: 'number' } + }, + required: ['baz'] + }, + oBar: { + type: 'object', + properties: { + bar: { type: 'string' } + }, + required: ['bar'] + }, + other: { + type: 'string', + const: 'other' + } + } + } + } + + const schema = { + title: 'object with oneOf property value containing refs to external schema', + type: 'object', + properties: { + oneOfSchema: { + oneOf: [ + { $ref: 'ext#/definitions/oBaz' }, + { $ref: 'ext#/definitions/oBar' } + ] + } + }, + required: ['oneOfSchema'] + } + + const code = fjs(schema, { + mode: 'standalone', + schema: externalSchema + }) + + const destination = path.resolve(tmpDir, 'standalone-oneOf-ref.js') + + t.teardown(async () => { + await fs.promises.rm(destination, { force: true }) + }) + + await fs.promises.writeFile(destination, code) + const stringify = require(destination) + + t.equal(stringify({ oneOfSchema: { baz: 5 } }), '{"oneOfSchema":{"baz":5}}') + t.equal(stringify({ oneOfSchema: { bar: 'foo' } }), '{"oneOfSchema":{"bar":"foo"}}') +})