Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

upgrade fast-json-stringify with ajv8 #3280

Merged
merged 3 commits into from
Jan 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
27 changes: 27 additions & 0 deletions build/build-error-serializer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use strict'

const FJS = require('fast-json-stringify')
const path = require('path')
const fs = require('fs')

const debugCompiled = FJS({
type: 'object',
properties: {
statusCode: { type: 'number' },
code: { type: 'string' },
error: { type: 'string' },
message: { type: 'string' }
}
}, { debugMode: true })

const file = path.join(__dirname, '..', 'lib', 'error-serializer.js')
const rawString = debugCompiled.toString()

const moduleCode = `// This file is autogenerated by build/build-error-serializer.js, do not edit
/* istanbul ignore file */
module.exports = $main
${rawString.slice(5)}
`

fs.writeFileSync(file, moduleCode)
console.log(`Saved ${file} file successfully`)
6 changes: 3 additions & 3 deletions fastify.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import { FastifyBaseLogger, FastifyLoggerInstance, FastifyLoggerOptions, PinoLog
import { FastifyInstance } from './types/instance'
import { FastifyServerFactory } from './types/serverFactory'
import { Options as AjvOptions } from '@fastify/ajv-compiler'
import { Options as FJSOptions } from '@fastify/fast-json-stringify-compiler'
import { FastifyError } from 'fastify-error'
import { FastifyReply } from './types/reply'
import { FastifySchemaValidationError } from './types/schema'
import { ConstructorAction, ProtoAction } from "./types/content-type-parser";
import { Socket } from 'net'
import { Options as FJSOptions } from 'fast-json-stringify'
import { ValidatorCompiler } from '@fastify/ajv-compiler'
import { FastifySerializerCompiler } from './types/schema';
import { SerializerCompiler } from '@fastify/fast-json-stringify-compiler'
import { FastifySchema } from './types/schema'
import { FastifyContextConfig } from './types/context'
import { FastifyTypeProvider, FastifyTypeProviderDefault } from './types/type-provider'
Expand Down Expand Up @@ -149,7 +149,7 @@ export type FastifyServerOptions<
};
compilersFactory?: {
buildValidator?: ValidatorCompiler;
buildSerializer?: (externalSchemas: unknown, serializerOptsServerOption: FastifyServerOptions["serializerOpts"]) => FastifySerializerCompiler<unknown>;
buildSerializer?: SerializerCompiler;
};
};
return503OnClosing?: boolean,
Expand Down
11 changes: 1 addition & 10 deletions lib/error-handler.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use strict'

const FJS = require('fast-json-stringify')
const statusCodes = require('http').STATUS_CODES
const wrapThenable = require('./wrapThenable')
const {
Expand All @@ -13,15 +12,7 @@ const {

const { getSchemaSerializer } = require('./schemas')

const serializeError = FJS({
type: 'object',
properties: {
statusCode: { type: 'number' },
code: { type: 'string' },
error: { type: 'string' },
message: { type: 'string' }
}
})
const serializeError = require('./error-serializer')

const rootErrorHandler = {
func: defaultErrorHandler,
Expand Down
257 changes: 257 additions & 0 deletions lib/error-serializer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
// This file is autogenerated by build/build-error-serializer.js, do not edit
/* istanbul ignore file */
module.exports = $main
'use strict'


function $pad2Zeros (num) {
const s = '00' + num
return s[s.length - 2] + s[s.length - 1]
}

function $asAny (i) {
return JSON.stringify(i)
}

function $asNull () {
return 'null'
}

function $asInteger (i) {
if (typeof i === 'bigint') {
return i.toString()
} else if (Number.isInteger(i)) {
return $asNumber(i)
} else {
/* eslint no-undef: "off" */
return $asNumber(parseInteger(i))
}
}

function $asIntegerNullable (i) {
return i === null ? null : $asInteger(i)
}

function $asNumber (i) {
const num = Number(i)
if (isNaN(num)) {
return 'null'
} else {
return '' + num
}
}

function $asNumberNullable (i) {
return i === null ? null : $asNumber(i)
}

function $asBoolean (bool) {
return bool && 'true' || 'false' // eslint-disable-line
}

function $asBooleanNullable (bool) {
return bool === null ? null : $asBoolean(bool)
}

function $asDatetime (date, skipQuotes) {
const quotes = skipQuotes === true ? '' : '"'
if (date instanceof Date) {
return quotes + date.toISOString() + quotes
} else if (date && typeof date.toISOString === 'function') {
return quotes + date.toISOString() + quotes
} else {
return $asString(date, skipQuotes)
}
}

function $asDate (date, skipQuotes) {
const quotes = skipQuotes === true ? '' : '"'
if (date instanceof Date) {
return quotes + new Date(date.getTime() - (date.getTimezoneOffset() * 60000 )).toISOString().slice(0, 10) + quotes
} else if (date && typeof date.format === 'function') {
return quotes + date.format('YYYY-MM-DD') + quotes
} else {
return $asString(date, skipQuotes)
}
}

function $asTime (date, skipQuotes) {
const quotes = skipQuotes === true ? '' : '"'
if (date instanceof Date) {
const hour = new Intl.DateTimeFormat('en', { hour: 'numeric', hour12: false }).format(date)
const minute = new Intl.DateTimeFormat('en', { minute: 'numeric' }).format(date)
const second = new Intl.DateTimeFormat('en', { second: 'numeric' }).format(date)
return quotes + $pad2Zeros(hour) + ':' + $pad2Zeros(minute) + ':' + $pad2Zeros(second) + quotes
} else if (date && typeof date.format === 'function') {
return quotes + date.format('HH:mm:ss') + quotes
} else {
return $asString(date, skipQuotes)
}
}

function $asString (str, skipQuotes) {
const quotes = skipQuotes === true ? '' : '"'
if (str instanceof Date) {
return quotes + str.toISOString() + quotes
} else if (str === null) {
return quotes + quotes
} else if (str instanceof RegExp) {
str = str.source
} else if (typeof str !== 'string') {
str = str.toString()
}
// If we skipQuotes it means that we are using it as test
// no need to test the string length for the render
if (skipQuotes) {
return str
}

if (str.length < 42) {
return $asStringSmall(str)
} else {
return JSON.stringify(str)
}
}

function $asStringNullable (str) {
return str === null ? null : $asString(str)
}

// magically escape strings for json
// relying on their charCodeAt
// everything below 32 needs JSON.stringify()
// every string that contain surrogate needs JSON.stringify()
// 34 and 92 happens all the time, so we
// have a fast case for them
function $asStringSmall (str) {
const l = str.length
let result = ''
let last = 0
let found = false
let surrogateFound = false
let point = 255
// eslint-disable-next-line
for (var i = 0; i < l && point >= 32; i++) {
point = str.charCodeAt(i)
if (point >= 0xD800 && point <= 0xDFFF) {
// The current character is a surrogate.
surrogateFound = true
}
if (point === 34 || point === 92) {
result += str.slice(last, i) + '\\'
last = i
found = true
}
}

if (!found) {
result = str
} else {
result += str.slice(last)
}
return ((point < 32) || (surrogateFound === true)) ? JSON.stringify(str) : '"' + result + '"'
}



/**
* Used by schemas that are dependant on calling 'ajv.validate' during runtime,
* it stores the value of the '$id' property of the schema (if it has it) inside
* a cache which is used to figure out if the schema was compiled into a validator
* by ajv on a previous call, if it was then the '$id' string will be used to
* invoke 'ajv.validate', this allows:
*
* 1. Schemas that depend on ajv.validate calls to leverage ajv caching system.
* 2. To avoid errors, since directly invoking 'ajv.validate' with the same
* schema (that contains an '$id' property) twice will throw an error.
*/
const $validateWithAjv = (function() {
const cache = new Set()

return function (schema, target) {
const id = schema.$id

if (!id) {
return ajv.validate(schema, target)
}

const cached = cache.has(id)

if (cached) {
return ajv.validate(id, target)
} else {
cache.add(id)
return ajv.validate(schema, target)
}
}
})()


function parseInteger(int) { return Math.trunc(int) }

function $main (input) {

var obj = (input && typeof input.toJSON === 'function')
? input.toJSON()
: input

var json = '{'
var addComma = false

var t = Number(obj["statusCode"])
if (!isNaN(t)) {

if (addComma) {
json += ','
} else {
addComma = true
}

json += "\"statusCode\"" + ':' + t

}

if (obj["code"] !== undefined) {

if (addComma) {
json += ','
} else {
addComma = true
}

json += "\"code\"" + ':'
json += $asString(obj["code"])
}

if (obj["error"] !== undefined) {

if (addComma) {
json += ','
} else {
addComma = true
}

json += "\"error\"" + ':'
json += $asString(obj["error"])
}

if (obj["message"] !== undefined) {

if (addComma) {
json += ','
} else {
addComma = true
}

json += "\"message\"" + ':'
json += $asString(obj["message"])
}

json += '}'
return json
}


;
return $main

12 changes: 0 additions & 12 deletions lib/schema-compilers.js

This file was deleted.

4 changes: 2 additions & 2 deletions lib/schema-controller.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict'

const { buildSchemas } = require('./schemas')
const { serializerCompiler } = require('./schema-compilers')
const SerializerSelector = require('@fastify/fast-json-stringify-compiler')
const ValidatorSelector = require('@fastify/ajv-compiler')

/**
Expand All @@ -17,7 +17,7 @@ function buildSchemaController (parentSchemaCtrl, opts) {

let compilersFactory = {
buildValidator: ValidatorSelector(),
buildSerializer: serializerCompiler
buildSerializer: SerializerSelector()
}
if (opts && opts.compilersFactory) {
compilersFactory = Object.assign(compilersFactory, opts.compilersFactory)
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.2.0",
"fast-json-body": "^1.1.0",
"fast-json-stringify": "^3.0.0",
"fastify-plugin": "^3.0.0",
"fluent-json-schema": "^3.0.1",
"form-data": "^4.0.0",
Expand Down Expand Up @@ -176,9 +177,9 @@
},
"dependencies": {
"@fastify/ajv-compiler": "^2.1.0",
"@fastify/fast-json-stringify-compiler": "^1.0.0",
"abstract-logging": "^2.0.1",
"avvio": "^8.1.0",
"fast-json-stringify": "^2.7.12",
"fastify-error": "^0.3.1",
"find-my-way": "^5.1.0",
"light-my-request": "^4.7.0",
Expand All @@ -194,6 +195,7 @@
"standard": {
"ignore": [
"lib/configValidator.js",
"lib/error-serializer.js",
"fastify.d.ts",
"types/*",
"test/types/*",
Expand Down