Skip to content

Commit

Permalink
upgrade fast-json-stringify with ajv8 (#3280)
Browse files Browse the repository at this point in the history
  • Loading branch information
Eomm committed Jan 4, 2022
1 parent 7dbfbe1 commit 20e1731
Show file tree
Hide file tree
Showing 7 changed files with 293 additions and 28 deletions.
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

0 comments on commit 20e1731

Please sign in to comment.