Avoid JSON.stringify calls
Yes, it is so right now.
I would open an issue for it and leave it as-is right now
The solutions I see:
- track the ajv options to write a fast-json-stringify function that serialize them instead of
JSON.stringify - apply a new logic like:
- check the number of keys
- check iteratively the values (I see only primitive types as values)
Originally posted by @Eomm in https://github.com/fastify/ajv-compiler/pull/1#discussion_r588874508
Benchmark Script
const { Benchmark } = require("benchmark");
const FJS = require("fast-json-stringify");
const stringify = FJS({
type: "object",
properties: {
coerceTypes: {
type: "boolean",
},
useDefaults: {
type: "boolean",
},
removeAdditional: {
type: "boolean",
},
allErrors: {
type: "boolean",
},
nullable: {
type: "boolean",
},
},
});
const ajvConfig = {
coerceTypes: true,
useDefaults: true,
removeAdditional: true,
allErrors: false,
nullable: true,
};
const externalSchema = {};
const suite = new Benchmark.Suite();
suite.add("JSON.stringify", function () {
const a = JSON.stringify(ajvConfig);
const b = JSON.stringify(externalSchema);
const key = `${a}${b}`;
});
suite.add("FJS", function () {
const a = stringify(ajvConfig);
const b = JSON.stringify(externalSchema);
const key = `${a}${b}`;
});
suite.on("cycle", function (event) {
console.log(String(event.target));
});
suite.on("complete", function () {
console.log("Fastest is " + this.filter("fastest").map("name"));
});
suite.run();
Result
JSON.stringify x 1,130,049 ops/sec ±3.60% (79 runs sampled)
FJS x 6,217,771 ops/sec ±2.15% (82 runs sampled)
Fastest is FJS
Environment Node: v14.16.0 CPU: [email protected]
The ajv options are quite a lot: https://ajv.js.org/options.html
We should keep track of all new addition if we write a schema of those settings
The type below is created by referencing the type from https://github.com/ajv-validator/ajv/blob/master/lib/core.ts
Note: RemovedOptions is not added in below which contain nullable.
If we go for the schema approach, should we include all the options including RemovedOptions ?
Schema for AJV options with primitive value only
{
type: "object",
properties: {
// strict mode options (NEW)
strict: {
$ref: "#/definitions/strictOption",
},
strictSchema: {
$ref: "#/definitions/strictOption",
},
strictNumbers: {
$ref: "#/definitions/strictOption",
},
strictTypes: {
$ref: "#/definitions/strictOption",
},
strictTuples: {
$ref: "#/definitions/strictOption",
},
strictRequired: {
$ref: "#/definitions/strictOption",
},
allowMatchingProperties: {
type: "boolean",
},
allowUnionTypes: {
type: "boolean",
},
validateFormats: {
type: "boolean",
},
// validation and reporting options:
$data: {
type: "boolean",
},
allErrors: {
type: "boolean",
},
verbose: {
type: "boolean",
},
discriminator: {
type: "boolean",
},
unicodeRegExp: {
type: "boolean",
},
// options to modify validated data:
removeAdditional: {
oneOf: [
{ type: "boolean" },
{ type: "string", enum: ["all", "failing"] },
],
},
useDefaults: {
oneOf: [{ type: "boolean" }, { type: "string", enum: ["empty"] }],
},
useDefaults: {
oneOf: [{ type: "boolean" }, { type: "string", enum: ["array"] }],
},
// advanced options:
next: {
type: "boolean",
},
unevaluated: {
type: "boolean",
},
dynamicRef: {
type: "boolean",
},
jtd: {
type: "boolean",
},
validateSchema: {
$ref: "#/definitions/strictOption",
},
addUsedSchema: {
type: "boolean",
},
inlineRefs: {
oneOf: [{ type: "boolean" }, { type: "number" }],
},
passContext: {
type: "boolean",
},
loopRequired: {
type: "number",
},
loopEnum: {
type: "number",
},
ownProperties: {
type: "boolean",
},
multipleOfPrecision: {
type: "number",
},
messages: {
type: "boolean",
},
code: {
$ref: "#/definitions/codeOption",
},
},
definitions: {
strictOption: {
oneOf: [{ type: "boolean" }, { type: "string", enum: ["log"] }],
},
codeOption: {
type: "object",
properties: {
es5: {
type: "boolean",
},
lines: {
type: "boolean",
},
optimize: {
oneOf: [{ type: "boolean" }, { type: "number" }],
},
source: {
type: "boolean",
},
},
},
},
}