diff --git a/index.js b/index.js index 946abf12..417f7c87 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,7 @@ 'use strict' var fastSafeStringify = require('fast-safe-stringify') +var Ajv = require('ajv') var uglify = null var isLong @@ -87,10 +88,19 @@ function build (schema, options) { code = uglifyCode(code) } + var dependencies = [] + var dependenciesName = [] if (hasAdditionalPropertiesTrue(schema)) { - return (new Function('fastSafeStringify', code))(fastSafeStringify) + dependencies.push(fastSafeStringify) + dependenciesName.push('fastSafeStringify') } - return (new Function(code))() + if (hasAnyOf(schema)) { + dependencies.push(new Ajv()) + dependenciesName.push('ajv') + } + + dependenciesName.push(code) + return (Function.apply(null, dependenciesName).apply(null, dependencies)) } function hasAdditionalPropertiesTrue (schema) { @@ -107,6 +117,20 @@ function hasAdditionalPropertiesTrue (schema) { return false } +function hasAnyOf (schema) { + if ('anyOf' in schema) { return true } + + var objectKeys = Object.keys(schema) + for (var i = 0; i < objectKeys.length; i++) { + var value = schema[objectKeys[i]] + if (typeof value === 'object') { + if (hasAnyOf(value)) { return true } + } + } + + return false +} + function $asNull () { return 'null' } @@ -517,8 +541,22 @@ function nested (laterCode, name, key, schema, externalSchema, fullSchema, subKe funcName = (name + key + subKey).replace(/[-.\[\]]/g, '') // eslint-disable-line laterCode = buildArray(schema, laterCode, funcName, externalSchema, fullSchema) code += ` - json += ${funcName}(obj${accessor}) - ` +json += ${funcName}(obj${accessor}) + ` + break + + case undefined: + if ('anyOf' in schema) { + schema.anyOf.forEach((s, index) => { + code += ` + ${index === 0 ? 'if' : 'else if'}(ajv.validate(${require('util').inspect(s, {depth: null})}, obj${accessor})) + ${nested(laterCode, name, key, s, externalSchema, fullSchema, subKey).code} + ` + }) + code += ` + else json+= null + ` + } else throw new Error(`${schema} unsupported`) break default: throw new Error(`${type} unsupported`) diff --git a/package.json b/package.json index 188ade19..69bd2e26 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "Stringify your JSON at max speed", "main": "index.js", "scripts": { + "benchmark": "node bench.js", "test": "standard && tap test/*.test.js" }, "precommit": "test", @@ -33,6 +34,7 @@ "uglify-es": "^3.1.1" }, "dependencies": { + "ajv": "^5.2.3", "fast-safe-stringify": "^1.2.0" } } diff --git a/test/anyof.test.js b/test/anyof.test.js new file mode 100644 index 00000000..af008c1a --- /dev/null +++ b/test/anyof.test.js @@ -0,0 +1,41 @@ +'use strict' + +const test = require('tap').test +const build = require('..') + +test('object with multiple types field', (t) => { + t.plan(2) + + const schema = { + title: 'object with multiple types field', + type: 'object', + properties: { + str: { + 'anyOf': [{ + type: 'string' + }, { + type: 'boolean' + }] + } + } + } + const stringify = build(schema) + + try { + const value = stringify({ + str: 'string' + }) + t.is(value, '{"str":"string"}') + } catch (e) { + t.fail() + } + + try { + const value = stringify({ + str: true + }) + t.is(value, '{"str":true}') + } catch (e) { + t.fail() + } +})