fast-json-stringify 5.8.0 → 5.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.gitattributes ADDED
@@ -0,0 +1,2 @@
1
+ # Set default behavior to automatically convert line endings
2
+ * text=auto eol=lf
@@ -14,13 +14,13 @@ jobs:
14
14
  PR-BENCH: ${{ steps.benchmark-pr.outputs.BENCH_RESULT }}
15
15
  MASTER-BENCH: ${{ steps.benchmark-master.outputs.BENCH_RESULT }}
16
16
  steps:
17
- - uses: actions/checkout@v3
17
+ - uses: actions/checkout@v4
18
18
  with:
19
19
  persist-credentials: false
20
20
  ref: ${{github.event.pull_request.head.sha}}
21
21
  repository: ${{github.event.pull_request.head.repo.full_name}}
22
22
 
23
- - uses: actions/setup-node@v3
23
+ - uses: actions/setup-node@v4
24
24
  with:
25
25
  node-version: 18
26
26
 
@@ -39,7 +39,7 @@ jobs:
39
39
  echo "::set-output name=BENCH_RESULT::$content"
40
40
 
41
41
  # master benchmark
42
- - uses: actions/checkout@v3
42
+ - uses: actions/checkout@v4
43
43
  with:
44
44
  ref: 'master'
45
45
 
package/README.md CHANGED
@@ -692,7 +692,7 @@ The standalone mode is used to compile the code that can be directly run by `nod
692
692
  itself. You need to have `fast-json-stringify` installed for the standalone code to work.
693
693
 
694
694
  ```js
695
- const fs = require('fs')
695
+ const fs = require('node:fs')
696
696
  const code = fastJson({
697
697
  title: 'default string',
698
698
  type: 'object',
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { spawn } = require('child_process')
3
+ const { spawn } = require('node:child_process')
4
4
 
5
5
  const cliSelect = require('cli-select')
6
6
  const simpleGit = require('simple-git')
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { workerData: benchmark, parentPort } = require('worker_threads')
3
+ const { workerData: benchmark, parentPort } = require('node:worker_threads')
4
4
 
5
5
  const Benchmark = require('benchmark')
6
6
  Benchmark.options.minSamples = 100
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
- const path = require('path')
4
- const { Worker } = require('worker_threads')
3
+ const path = require('node:path')
4
+ const { Worker } = require('node:worker_threads')
5
5
 
6
6
  const BENCH_THREAD_PATH = path.join(__dirname, 'bench-thread.js')
7
7
 
@@ -3,8 +3,8 @@
3
3
  const Ajv = require('ajv')
4
4
  const standaloneCode = require('ajv/dist/standalone').default
5
5
  const ajvFormats = require('ajv-formats')
6
- const fs = require('fs')
7
- const path = require('path')
6
+ const fs = require('node:fs')
7
+ const path = require('node:path')
8
8
 
9
9
  const ajv = new Ajv({
10
10
  addUsedSchema: false,
@@ -1,3 +1,5 @@
1
+ 'use strict'
2
+
1
3
  const fastJson = require('..')
2
4
  const stringify = fastJson({
3
5
  title: 'Example Schema',
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const http = require('http')
3
+ const http = require('node:http')
4
4
 
5
5
  const stringify = require('fast-json-stringify')({
6
6
  type: 'object',
package/index.js CHANGED
@@ -4,14 +4,16 @@
4
4
 
5
5
  const merge = require('@fastify/deepmerge')()
6
6
  const clone = require('rfdc')({ proto: true })
7
- const { randomUUID } = require('crypto')
7
+ const { randomUUID } = require('node:crypto')
8
+ const { RefResolver } = require('json-schema-ref-resolver')
8
9
 
9
10
  const validate = require('./lib/schema-validator')
10
11
  const Serializer = require('./lib/serializer')
11
12
  const Validator = require('./lib/validator')
12
- const RefResolver = require('./lib/ref-resolver')
13
13
  const Location = require('./lib/location')
14
14
 
15
+ const SINGLE_TICK = /'/g
16
+
15
17
  let largeArraySize = 2e4
16
18
  let largeArrayMechanism = 'default'
17
19
 
@@ -53,8 +55,7 @@ function resolveRef (context, location, ref) {
53
55
  const jsonPointer = ref.slice(hashIndex) || '#'
54
56
 
55
57
  const schema = context.refResolver.getSchema(schemaId, jsonPointer)
56
-
57
- if (schema === undefined) {
58
+ if (schema === null) {
58
59
  throw new Error(`Cannot find reference "${ref}"`)
59
60
  }
60
61
 
@@ -66,6 +67,13 @@ function resolveRef (context, location, ref) {
66
67
  return newLocation
67
68
  }
68
69
 
70
+ function getSchemaId (schema, rootSchemaId) {
71
+ if (schema.$id && schema.$id.charAt(0) !== '#') {
72
+ return schema.$id
73
+ }
74
+ return rootSchemaId
75
+ }
76
+
69
77
  function build (schema, options) {
70
78
  isValidSchema(schema)
71
79
 
@@ -82,12 +90,19 @@ function build (schema, options) {
82
90
  validatorSchemasIds: new Set()
83
91
  }
84
92
 
85
- context.refResolver.addSchema(schema, context.rootSchemaId)
93
+ const schemaId = getSchemaId(schema, context.rootSchemaId)
94
+ if (!context.refResolver.hasSchema(schemaId)) {
95
+ context.refResolver.addSchema(schema, context.rootSchemaId)
96
+ }
86
97
 
87
98
  if (options.schema) {
88
- for (const key of Object.keys(options.schema)) {
89
- isValidSchema(options.schema[key], key)
90
- context.refResolver.addSchema(options.schema[key], key)
99
+ for (const key in options.schema) {
100
+ const schema = options.schema[key]
101
+ const schemaId = getSchemaId(schema, key)
102
+ if (!context.refResolver.hasSchema(schemaId)) {
103
+ isValidSchema(schema, key)
104
+ context.refResolver.addSchema(schema, key)
105
+ }
91
106
  }
92
107
  }
93
108
 
@@ -821,7 +836,7 @@ function buildConstSerializer (location, input) {
821
836
  `
822
837
  }
823
838
 
824
- code += `json += '${JSON.stringify(schema.const)}'`
839
+ code += `json += '${JSON.stringify(schema.const).replace(SINGLE_TICK, "\\'")}'`
825
840
 
826
841
  if (hasNullType) {
827
842
  code += `
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "fast-json-stringify",
3
- "version": "5.8.0",
3
+ "version": "5.9.0",
4
4
  "description": "Stringify your JSON at max speed",
5
5
  "main": "index.js",
6
+ "type": "commonjs",
6
7
  "types": "types/index.d.ts",
7
8
  "scripts": {
8
9
  "bench": "node ./benchmark/bench.js",
@@ -34,7 +35,7 @@
34
35
  "homepage": "https://github.com/fastify/fast-json-stringify#readme",
35
36
  "devDependencies": {
36
37
  "@fastify/pre-commit": "^2.0.2",
37
- "@sinclair/typebox": "^0.29.1",
38
+ "@sinclair/typebox": "^0.31.1",
38
39
  "benchmark": "^2.1.4",
39
40
  "cli-select": "^1.1.2",
40
41
  "compile-json-stringify": "^0.1.2",
@@ -42,7 +43,7 @@
42
43
  "simple-git": "^3.7.1",
43
44
  "standard": "^17.0.0",
44
45
  "tap": "^16.0.1",
45
- "tsd": "^0.28.0",
46
+ "tsd": "^0.29.0",
46
47
  "webpack": "^5.40.0",
47
48
  "fast-json-stringify": "."
48
49
  },
@@ -52,7 +53,8 @@
52
53
  "ajv-formats": "^2.1.1",
53
54
  "fast-deep-equal": "^3.1.3",
54
55
  "fast-uri": "^2.1.0",
55
- "rfdc": "^1.2.0"
56
+ "rfdc": "^1.2.0",
57
+ "json-schema-ref-resolver": "^1.0.1"
56
58
  },
57
59
  "standard": {
58
60
  "ignore": [
@@ -82,6 +82,26 @@ test('schema with const string and no input', (t) => {
82
82
  t.ok(validate(JSON.parse(output)), 'valid schema')
83
83
  })
84
84
 
85
+ test('schema with const string that contains \'', (t) => {
86
+ t.plan(2)
87
+
88
+ const schema = {
89
+ type: 'object',
90
+ properties: {
91
+ foo: { const: "'bar'" }
92
+ }
93
+ }
94
+
95
+ const validate = validator(schema)
96
+ const stringify = build(schema)
97
+ const output = stringify({
98
+ foo: "'bar'"
99
+ })
100
+
101
+ t.equal(output, '{"foo":"\'bar\'"}')
102
+ t.ok(validate(JSON.parse(output)), 'valid schema')
103
+ })
104
+
85
105
  test('schema with const number', (t) => {
86
106
  t.plan(2)
87
107
 
package/test/ref.test.js CHANGED
@@ -1377,7 +1377,10 @@ test('Bad key', t => {
1377
1377
  })
1378
1378
  t.fail('Should throw')
1379
1379
  } catch (err) {
1380
- t.equal(err.message, 'Cannot find reference "extrenal#/definitions/projectId"')
1380
+ t.equal(
1381
+ err.message,
1382
+ 'Cannot resolve ref "extrenal#/definitions/projectId". Schema with id "extrenal" is not found.'
1383
+ )
1381
1384
  }
1382
1385
  })
1383
1386
 
@@ -2076,7 +2079,11 @@ test('should throw an Error if two non-identical schemas with same id are provid
2076
2079
  ]
2077
2080
  }
2078
2081
 
2079
- t.throws(() => build(schema), new Error('There is already another schema with id inner_schema'))
2082
+ try {
2083
+ build(schema)
2084
+ } catch (err) {
2085
+ t.equal(err.message, 'There is already another schema with id "inner_schema".')
2086
+ }
2080
2087
  })
2081
2088
 
2082
2089
  test('ref internal - throw if schema has definition twice with different shape', (t) => {
@@ -2115,5 +2122,9 @@ test('ref internal - throw if schema has definition twice with different shape',
2115
2122
  }
2116
2123
  }
2117
2124
 
2118
- t.throws(() => build(schema), Error('There is already another schema with id test##uri'))
2125
+ try {
2126
+ build(schema)
2127
+ } catch (err) {
2128
+ t.equal(err.message, 'There is already another anchor "#uri" in a schema "test".')
2129
+ }
2119
2130
  })
@@ -2,8 +2,8 @@
2
2
 
3
3
  const test = require('tap').test
4
4
  const fjs = require('..')
5
- const fs = require('fs')
6
- const path = require('path')
5
+ const fs = require('node:fs')
6
+ const path = require('node:path')
7
7
 
8
8
  function build (opts, schema) {
9
9
  return fjs(schema || {
@@ -2,7 +2,7 @@
2
2
 
3
3
  const test = require('tap').test
4
4
  const webpack = require('webpack')
5
- const path = require('path')
5
+ const path = require('node:path')
6
6
 
7
7
  test('the library should work with webpack', async (t) => {
8
8
  t.plan(1)
@@ -1,104 +0,0 @@
1
- 'use strict'
2
-
3
- const deepEqual = require('fast-deep-equal')
4
-
5
- class RefResolver {
6
- constructor () {
7
- this.schemas = {}
8
- }
9
-
10
- addSchema (schema, schemaId) {
11
- if (schema.$id !== undefined && schema.$id.charAt(0) !== '#') {
12
- schemaId = schema.$id
13
- }
14
- if (this.getSchema(schemaId) === undefined) {
15
- this.insertSchemaBySchemaId(schema, schemaId)
16
- this.insertSchemaSubschemas(schema, schemaId)
17
- }
18
- }
19
-
20
- getSchema (schemaId, jsonPointer = '#') {
21
- const schema = this.schemas[schemaId]
22
- if (schema === undefined) {
23
- return undefined
24
- }
25
- if (schema.anchors[jsonPointer] !== undefined) {
26
- return schema.anchors[jsonPointer]
27
- }
28
- return getDataByJSONPointer(schema.schema, jsonPointer)
29
- }
30
-
31
- getSchemaDependencies (schemaId, dependencies = {}) {
32
- const schema = this.schemas[schemaId]
33
-
34
- for (const dependencySchemaId of schema.dependencies) {
35
- if (dependencies[dependencySchemaId] !== undefined) continue
36
- dependencies[dependencySchemaId] = this.getSchema(dependencySchemaId)
37
- this.getSchemaDependencies(dependencySchemaId, dependencies)
38
- }
39
-
40
- return dependencies
41
- }
42
-
43
- insertSchemaBySchemaId (schema, schemaId) {
44
- if (
45
- this.schemas[schemaId] !== undefined &&
46
- !deepEqual(schema, this.schemas[schemaId].schema)
47
- ) {
48
- throw new Error(`There is already another schema with id ${schemaId}`)
49
- }
50
- this.schemas[schemaId] = { schema, anchors: {}, dependencies: [] }
51
- }
52
-
53
- insertSchemaByAnchor (schema, schemaId, anchor) {
54
- const { anchors } = this.schemas[schemaId]
55
- if (
56
- anchors[anchor] !== undefined &&
57
- !deepEqual(schema, anchors[anchor])
58
- ) {
59
- throw new Error(`There is already another schema with id ${schemaId}#${anchor}`)
60
- }
61
- anchors[anchor] = schema
62
- }
63
-
64
- insertSchemaSubschemas (schema, rootSchemaId) {
65
- const schemaId = schema.$id
66
- if (schemaId !== undefined && typeof schemaId === 'string') {
67
- if (schemaId.charAt(0) === '#') {
68
- this.insertSchemaByAnchor(schema, rootSchemaId, schemaId)
69
- } else {
70
- this.insertSchemaBySchemaId(schema, schemaId)
71
- rootSchemaId = schemaId
72
- }
73
- }
74
-
75
- const ref = schema.$ref
76
- if (ref !== undefined && typeof ref === 'string') {
77
- if (ref.charAt(0) !== '#') {
78
- const dependencySchemaId = ref.split('#')[0]
79
- this.schemas[rootSchemaId].dependencies.push(dependencySchemaId)
80
- }
81
- }
82
-
83
- for (const key in schema) {
84
- if (typeof schema[key] === 'object' && schema[key] !== null) {
85
- this.insertSchemaSubschemas(schema[key], rootSchemaId)
86
- }
87
- }
88
- }
89
- }
90
-
91
- function getDataByJSONPointer (data, jsonPointer) {
92
- const parts = jsonPointer.split('/')
93
- let current = data
94
- for (const part of parts) {
95
- if (part === '' || part === '#') continue
96
- if (typeof current !== 'object' || current === null) {
97
- return undefined
98
- }
99
- current = current[part]
100
- }
101
- return current
102
- }
103
-
104
- module.exports = RefResolver