fast-json-stringify 1.15.0 → 1.15.4

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/bench.js CHANGED
@@ -4,19 +4,36 @@ const benchmark = require('benchmark')
4
4
  const suite = new benchmark.Suite()
5
5
 
6
6
  const schema = {
7
- 'title': 'Example Schema',
8
- 'type': 'object',
9
- 'properties': {
10
- 'firstName': {
11
- 'type': 'string'
7
+ title: 'Example Schema',
8
+ type: 'object',
9
+ properties: {
10
+ firstName: {
11
+ type: 'string'
12
12
  },
13
- 'lastName': {
14
- 'type': ['string', 'null']
13
+ lastName: {
14
+ type: ['string', 'null']
15
15
  },
16
- 'age': {
17
- 'description': 'Age in years',
18
- 'type': 'integer',
19
- 'minimum': 0
16
+ age: {
17
+ description: 'Age in years',
18
+ type: 'integer',
19
+ minimum: 0
20
+ }
21
+ }
22
+ }
23
+ const schemaCJS = {
24
+ title: 'Example Schema',
25
+ type: 'object',
26
+ properties: {
27
+ firstName: {
28
+ type: 'string'
29
+ },
30
+ lastName: {
31
+ type: ['string', 'null']
32
+ },
33
+ age: {
34
+ description: 'Age in years',
35
+ type: 'number',
36
+ minimum: 0
20
37
  }
21
38
  }
22
39
  }
@@ -27,6 +44,12 @@ const arraySchema = {
27
44
  items: schema
28
45
  }
29
46
 
47
+ const arraySchemaCJS = {
48
+ title: 'array schema',
49
+ type: 'array',
50
+ items: schemaCJS
51
+ }
52
+
30
53
  const obj = {
31
54
  firstName: 'Matteo',
32
55
  lastName: 'Collina',
@@ -35,6 +58,16 @@ const obj = {
35
58
 
36
59
  const multiArray = []
37
60
 
61
+ const JSTR = require('json-strify')
62
+ const JSTRStringify = JSTR(schemaCJS)
63
+ const JSTRArray = JSTR(arraySchemaCJS)
64
+ const JSTRInstance = JSTR()
65
+
66
+ const CJS = require('compile-json-stringify')
67
+ const CJSStringify = CJS(schemaCJS)
68
+ const CJSStringifyArray = CJS(arraySchemaCJS)
69
+ const CJSStringifyString = CJS({ type: 'string' })
70
+
38
71
  const FJS = require('.')
39
72
  const stringify = FJS(schema)
40
73
  const stringifyUgly = FJS(schema, { uglify: true })
@@ -60,6 +93,12 @@ for (i = 0; i < 1000; i++) {
60
93
  suite.add('FJS creation', function () {
61
94
  FJS(schema)
62
95
  })
96
+ suite.add('JSTR creation', function () {
97
+ JSTR(schemaCJS)
98
+ })
99
+ suite.add('CJS creation', function () {
100
+ CJS(schemaCJS)
101
+ })
63
102
 
64
103
  suite.add('JSON.stringify array', function () {
65
104
  JSON.stringify(multiArray)
@@ -73,6 +112,14 @@ suite.add('fast-json-stringify-uglified array', function () {
73
112
  stringifyArrayUgly(multiArray)
74
113
  })
75
114
 
115
+ suite.add('json-strify array', function () {
116
+ JSTRArray(multiArray)
117
+ })
118
+
119
+ suite.add('compile-json-stringify array', function () {
120
+ CJSStringifyArray(multiArray)
121
+ })
122
+
76
123
  suite.add('JSON.stringify long string', function () {
77
124
  JSON.stringify(str)
78
125
  })
@@ -85,6 +132,14 @@ suite.add('fast-json-stringify-uglified long string', function () {
85
132
  stringifyStringUgly(str)
86
133
  })
87
134
 
135
+ suite.add('json-strify long string', function () {
136
+ JSTRInstance(str)
137
+ })
138
+
139
+ suite.add('compile-json-stringify long string', function () {
140
+ CJSStringifyString(str)
141
+ })
142
+
88
143
  suite.add('JSON.stringify short string', function () {
89
144
  JSON.stringify('hello world')
90
145
  })
@@ -97,6 +152,14 @@ suite.add('fast-json-stringify-uglified short string', function () {
97
152
  stringifyStringUgly('hello world')
98
153
  })
99
154
 
155
+ suite.add('json-strify short string', function () {
156
+ JSTRInstance('hello world')
157
+ })
158
+
159
+ suite.add('compile-json-stringify short string', function () {
160
+ CJSStringifyString('hello world')
161
+ })
162
+
100
163
  suite.add('JSON.stringify obj', function () {
101
164
  JSON.stringify(obj)
102
165
  })
@@ -109,6 +172,14 @@ suite.add('fast-json-stringify-uglified obj', function () {
109
172
  stringifyUgly(obj)
110
173
  })
111
174
 
175
+ suite.add('json-strify obj', function () {
176
+ JSTRStringify(obj)
177
+ })
178
+
179
+ suite.add('compile-json-stringify obj', function () {
180
+ CJSStringify(obj)
181
+ })
182
+
112
183
  suite.on('cycle', cycle)
113
184
 
114
185
  suite.run()
@@ -11,7 +11,7 @@ const ajv = new Ajv({
11
11
 
12
12
  const validate = ajv.compile(require('ajv/lib/refs/json-schema-draft-07.json'))
13
13
 
14
- let moduleCode = `// This file is autogenerated by ${path.basename(__filename)}, do not edit
14
+ const moduleCode = `// This file is autogenerated by ${path.basename(__filename)}, do not edit
15
15
 
16
16
  function nop () { return true }
17
17
 
package/example.js CHANGED
@@ -46,7 +46,7 @@ const stringify = fastJson({
46
46
  '.*foo$': {
47
47
  type: 'string'
48
48
  },
49
- 'test': {
49
+ test: {
50
50
  type: 'number'
51
51
  }
52
52
  },
package/index.js CHANGED
@@ -1,7 +1,10 @@
1
1
  'use strict'
2
2
 
3
+ /* eslint no-prototype-builtins: 0 */
4
+
3
5
  var Ajv = require('ajv')
4
6
  var merge = require('deepmerge')
7
+ var util = require('util')
5
8
  var validate = require('./schema-validator')
6
9
 
7
10
  var uglify = null
@@ -37,7 +40,7 @@ function build (schema, options) {
37
40
  options = options || {}
38
41
  isValidSchema(schema)
39
42
  if (options.schema) {
40
- for (let key of Object.keys(options.schema)) {
43
+ for (const key of Object.keys(options.schema)) {
41
44
  isValidSchema(options.schema[key], key)
42
45
  }
43
46
  }
@@ -71,6 +74,10 @@ function build (schema, options) {
71
74
  `
72
75
  }
73
76
 
77
+ if (schema['$ref']) {
78
+ schema = refFinder(schema['$ref'], schema, options.schema)
79
+ }
80
+
74
81
  if (schema.type === undefined) {
75
82
  schema.type = inferTypeByKeyword(schema)
76
83
  }
@@ -181,6 +188,7 @@ function inferTypeByKeyword (schema) {
181
188
  }
182
189
 
183
190
  function hasAnyOf (schema) {
191
+ if (!schema) { return false }
184
192
  if ('anyOf' in schema) { return true }
185
193
 
186
194
  var objectKeys = Object.keys(schema)
@@ -306,7 +314,7 @@ function addPatternProperties (schema, externalSchema, fullSchema) {
306
314
  }
307
315
  var type = pp[regex].type
308
316
  code += `
309
- if (/${regex}/.test(keys[i])) {
317
+ if (/${regex.replace(/\\*\//g, '\\/')}/.test(keys[i])) {
310
318
  `
311
319
  if (type === 'object') {
312
320
  code += buildObject(pp[regex], '', 'buildObjectPP' + index, externalSchema, fullSchema)
@@ -477,25 +485,51 @@ function refFinder (ref, schema, externalSchema) {
477
485
  // If external file
478
486
  if (ref[0]) {
479
487
  schema = externalSchema[ref[0]]
488
+
489
+ if (schema['$ref']) {
490
+ return refFinder(schema['$ref'], schema, externalSchema)
491
+ }
480
492
  }
481
493
 
482
494
  var code = 'return schema'
483
495
  // If it has a path
484
496
  if (ref[1]) {
485
497
  // ref[1] could contain a JSON pointer - ex: /definitions/num
486
- // or plan name fragment id without suffix # - ex: customId
498
+ // or plain name fragment id without suffix # - ex: customId
487
499
  var walk = ref[1].split('/')
488
500
  if (walk.length === 1) {
489
- return idFinder(schema, `#${ref[1]}`)
501
+ var targetId = `#${ref[1]}`
502
+ var dereferenced = idFinder(schema, targetId)
503
+ if (dereferenced === undefined && !ref[0]) {
504
+ for (var key of Object.keys(externalSchema)) {
505
+ dereferenced = idFinder(externalSchema[key], targetId)
506
+ if (dereferenced !== undefined) break
507
+ }
508
+ }
509
+ return dereferenced
490
510
  } else {
491
511
  for (var i = 1; i < walk.length; i++) {
492
- code += `['${walk[i]}']`
512
+ code += `['${sanitizeKey(walk[i])}']`
493
513
  }
494
514
  }
495
515
  }
496
516
  return (new Function('schema', code))(schema)
497
517
  }
498
518
 
519
+ function sanitizeKey (key) {
520
+ const rep = key.replace(/(\\*)'/g, function (match, p1) {
521
+ var base = ''
522
+ if (p1.length % 2 === 1) {
523
+ base = p1.slice(2)
524
+ } else {
525
+ base = p1
526
+ }
527
+ var rep = base + '\\\''
528
+ return rep
529
+ })
530
+ return rep
531
+ }
532
+
499
533
  function buildCode (schema, code, laterCode, name, externalSchema, fullSchema) {
500
534
  Object.keys(schema.properties || {}).forEach((key, i, a) => {
501
535
  if (schema.properties[key]['$ref']) {
@@ -507,12 +541,14 @@ function buildCode (schema, code, laterCode, name, externalSchema, fullSchema) {
507
541
 
508
542
  var type = schema.properties[key].type
509
543
  var nullable = schema.properties[key].nullable
544
+ var sanitized = sanitizeKey(key)
545
+ var asString = sanitizeKey($asString(key).replace(/\\/g, '\\\\'))
510
546
 
511
547
  if (nullable) {
512
548
  code += `
513
- if (obj['${key}'] === null) {
549
+ if (obj['${sanitized}'] === null) {
514
550
  ${addComma}
515
- json += '${$asString(key)}:null'
551
+ json += '${asString}:null'
516
552
  var rendered = true
517
553
  } else {
518
554
  `
@@ -520,10 +556,10 @@ function buildCode (schema, code, laterCode, name, externalSchema, fullSchema) {
520
556
 
521
557
  if (type === 'number') {
522
558
  code += `
523
- var t = Number(obj['${key}'])
559
+ var t = Number(obj['${sanitized}'])
524
560
  if (!isNaN(t)) {
525
561
  ${addComma}
526
- json += '${$asString(key)}:' + t
562
+ json += '${asString}:' + t
527
563
  `
528
564
  } else if (type === 'integer') {
529
565
  code += `
@@ -531,25 +567,25 @@ function buildCode (schema, code, laterCode, name, externalSchema, fullSchema) {
531
567
  `
532
568
  if (isLong) {
533
569
  code += `
534
- if (isLong(obj['${key}'])) {
570
+ if (isLong(obj['${sanitized}'])) {
535
571
  ${addComma}
536
- json += '${$asString(key)}:' + obj['${key}'].toString()
572
+ json += '${asString}:' + obj['${sanitized}'].toString()
537
573
  rendered = true
538
574
  } else {
539
- var t = Number(obj['${key}'])
575
+ var t = Number(obj['${sanitized}'])
540
576
  if (!isNaN(t)) {
541
577
  ${addComma}
542
- json += '${$asString(key)}:' + t
578
+ json += '${asString}:' + t
543
579
  rendered = true
544
580
  }
545
581
  }
546
582
  `
547
583
  } else {
548
584
  code += `
549
- var t = Number(obj['${key}'])
585
+ var t = Number(obj['${sanitized}'])
550
586
  if (!isNaN(t)) {
551
587
  ${addComma}
552
- json += '${$asString(key)}:' + t
588
+ json += '${asString}:' + t
553
589
  rendered = true
554
590
  }
555
591
  `
@@ -559,9 +595,9 @@ function buildCode (schema, code, laterCode, name, externalSchema, fullSchema) {
559
595
  `
560
596
  } else {
561
597
  code += `
562
- if (obj['${key}'] !== undefined) {
598
+ if (obj['${sanitized}'] !== undefined) {
563
599
  ${addComma}
564
- json += '${$asString(key)}:'
600
+ json += '${asString}:'
565
601
  `
566
602
 
567
603
  var result = nested(laterCode, name, key, schema.properties[key], externalSchema, fullSchema)
@@ -574,12 +610,12 @@ function buildCode (schema, code, laterCode, name, externalSchema, fullSchema) {
574
610
  code += `
575
611
  } else {
576
612
  ${addComma}
577
- json += '${$asString(key)}:${JSON.stringify(defaultValue).replace(/'/g, '\'')}'
613
+ json += '${asString}:${sanitizeKey(JSON.stringify(defaultValue).replace(/\\/g, '\\\\'))}'
578
614
  `
579
615
  } else if (schema.required && schema.required.indexOf(key) !== -1) {
580
616
  code += `
581
617
  } else {
582
- throw new Error('${key} is required!')
618
+ throw new Error('${sanitized} is required!')
583
619
  `
584
620
  }
585
621
 
@@ -642,7 +678,7 @@ function addIfThenElse (schema, name, externalSchema, fullSchema) {
642
678
  var merged = merge(copy, then)
643
679
 
644
680
  code += `
645
- valid = ajv.validate(${require('util').inspect(i, { depth: null })}, obj)
681
+ valid = ajv.validate(${util.inspect(i, { depth: null })}, obj)
646
682
  if (valid) {
647
683
  `
648
684
  if (merged.if && merged.then) {
@@ -840,6 +876,8 @@ function nested (laterCode, name, key, schema, externalSchema, fullSchema, subKe
840
876
  var code = ''
841
877
  var funcName
842
878
 
879
+ subKey = subKey || ''
880
+
843
881
  if (schema.type === undefined) {
844
882
  var inferedType = inferTypeByKeyword(schema)
845
883
  if (inferedType) {
@@ -850,7 +888,7 @@ function nested (laterCode, name, key, schema, externalSchema, fullSchema, subKe
850
888
  var type = schema.type
851
889
  var nullable = schema.nullable === true
852
890
 
853
- var accessor = key.indexOf('[') === 0 ? key : `['${key}']`
891
+ var accessor = key.indexOf('[') === 0 ? sanitizeKey(key) : `['${sanitizeKey(key)}']`
854
892
  switch (type) {
855
893
  case 'null':
856
894
  code += `
@@ -886,7 +924,7 @@ function nested (laterCode, name, key, schema, externalSchema, fullSchema, subKe
886
924
  case undefined:
887
925
  if ('anyOf' in schema) {
888
926
  schema.anyOf.forEach((s, index) => {
889
- var nestedResult = nested(laterCode, name, key, s, externalSchema, fullSchema, subKey !== undefined ? subKey : 'i' + index)
927
+ var nestedResult = nested(laterCode, name, key, s, externalSchema, fullSchema, subKey !== '' ? subKey : 'i' + index)
890
928
  code += `
891
929
  ${index === 0 ? 'if' : 'else if'}(ajv.validate(${require('util').inspect(s, { depth: null })}, obj${accessor}))
892
930
  ${nestedResult.code}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fast-json-stringify",
3
- "version": "1.15.0",
3
+ "version": "1.15.4",
4
4
  "description": "Stringify your JSON at max speed",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -37,19 +37,26 @@
37
37
  "long": "^4.0.0",
38
38
  "pre-commit": "^1.2.2",
39
39
  "proxyquire": "^2.1.0",
40
- "standard": "^12.0.1",
41
- "tap": "^12.5.1",
40
+ "standard": "^13.0.1",
41
+ "tap": "^12.6.5",
42
42
  "tap-mocha-reporter": "^3.0.9",
43
43
  "typescript": "^3.0.0",
44
- "uglify-es": "^3.3.9"
44
+ "uglify-es": "^3.3.9",
45
+ "compile-json-stringify": "^0.1.2",
46
+ "json-strify": "^0.1.7"
45
47
  },
46
48
  "dependencies": {
47
49
  "ajv": "^6.8.1",
48
- "deepmerge": "^3.0.0"
50
+ "deepmerge": "^4.0.0"
49
51
  },
50
52
  "standard": {
51
53
  "ignore": [
52
54
  "schema-validator.js"
53
55
  ]
56
+ },
57
+ "greenkeeper": {
58
+ "ignore": [
59
+ "tap"
60
+ ]
54
61
  }
55
62
  }
@@ -18,7 +18,7 @@ test('additionalProperties', (t) => {
18
18
  }
19
19
  })
20
20
 
21
- let obj = { str: 'test', foo: 42, ofoo: true, foof: 'string', objfoo: { a: true } }
21
+ const obj = { str: 'test', foo: 42, ofoo: true, foof: 'string', objfoo: { a: true } }
22
22
  t.equal('{"foo":"42","ofoo":"true","foof":"string","objfoo":"[object Object]","str":"test"}', stringify(obj))
23
23
  })
24
24
 
@@ -177,7 +177,7 @@ test('nested additionalProperties', (t) => {
177
177
  }
178
178
  })
179
179
 
180
- let obj = [{ ap: { value: 'string' } }]
180
+ const obj = [{ ap: { value: 'string' } }]
181
181
  t.equal('[{"ap":{"value":"string"}}]', stringify(obj))
182
182
  })
183
183
 
@@ -214,7 +214,7 @@ test('very nested additionalProperties', (t) => {
214
214
  }
215
215
  })
216
216
 
217
- let obj = [{ ap: { nested: { moarNested: { finally: { value: 'str' } } } } }]
217
+ const obj = [{ ap: { nested: { moarNested: { finally: { value: 'str' } } } } }]
218
218
  t.equal('[{"ap":{"nested":{"moarNested":{"finally":{"value":"str"}}}}}]', stringify(obj))
219
219
  })
220
220
 
@@ -231,7 +231,7 @@ test('nested additionalProperties set to true', (t) => {
231
231
  }
232
232
  })
233
233
 
234
- let obj = { ap: { value: 'string', someNumber: 42 } }
234
+ const obj = { ap: { value: 'string', someNumber: 42 } }
235
235
  t.equal('{"ap":{"value":"string","someNumber":42}}', stringify(obj))
236
236
  })
237
237
 
@@ -248,6 +248,6 @@ test('field passed to fastSafeStringify as undefined should be removed', (t) =>
248
248
  }
249
249
  })
250
250
 
251
- let obj = { ap: { value: 'string', someNumber: undefined } }
251
+ const obj = { ap: { value: 'string', someNumber: undefined } }
252
252
  t.equal('{"ap":{"value":"string"}}', stringify(obj))
253
253
  })
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const test = require('tap').test
3
+ const { test } = require('tap')
4
4
  const build = require('..')
5
5
 
6
6
  test('object with multiple types field', (t) => {
@@ -231,3 +231,20 @@ test('object with field with type union of multiple objects', (t) => {
231
231
  t.fail()
232
232
  }
233
233
  })
234
+
235
+ test('null value in schema', (t) => {
236
+ t.plan(0)
237
+
238
+ const schema = {
239
+ title: 'schema with null child',
240
+ type: 'string',
241
+ nullable: true,
242
+ enum: [null]
243
+ }
244
+
245
+ try {
246
+ build(schema)
247
+ } catch (e) {
248
+ t.fail()
249
+ }
250
+ })
@@ -23,13 +23,13 @@ function buildTest (schema, toStringify) {
23
23
  }
24
24
 
25
25
  buildTest({
26
- 'title': 'string array',
27
- 'type': 'object',
28
- 'properties': {
29
- 'ids': {
30
- 'type': 'array',
31
- 'items': {
32
- 'type': 'string'
26
+ title: 'string array',
27
+ type: 'object',
28
+ properties: {
29
+ ids: {
30
+ type: 'array',
31
+ items: {
32
+ type: 'string'
33
33
  }
34
34
  }
35
35
  }
@@ -38,13 +38,13 @@ buildTest({
38
38
  })
39
39
 
40
40
  buildTest({
41
- 'title': 'number array',
42
- 'type': 'object',
43
- 'properties': {
44
- 'ids': {
45
- 'type': 'array',
46
- 'items': {
47
- 'type': 'number'
41
+ title: 'number array',
42
+ type: 'object',
43
+ properties: {
44
+ ids: {
45
+ type: 'array',
46
+ items: {
47
+ type: 'number'
48
48
  }
49
49
  }
50
50
  }
@@ -53,39 +53,39 @@ buildTest({
53
53
  })
54
54
 
55
55
  buildTest({
56
- 'title': 'mixed array',
57
- 'type': 'object',
58
- 'properties': {
59
- 'ids': {
60
- 'type': 'array',
61
- 'items': [
56
+ title: 'mixed array',
57
+ type: 'object',
58
+ properties: {
59
+ ids: {
60
+ type: 'array',
61
+ items: [
62
62
  {
63
- 'type': 'null'
63
+ type: 'null'
64
64
  },
65
65
  {
66
- 'type': 'string'
66
+ type: 'string'
67
67
  },
68
68
  {
69
- 'type': 'integer'
69
+ type: 'integer'
70
70
  },
71
71
  {
72
- 'type': 'number'
72
+ type: 'number'
73
73
  },
74
74
  {
75
- 'type': 'boolean'
75
+ type: 'boolean'
76
76
  },
77
77
  {
78
- 'type': 'object',
79
- 'properties': {
80
- 'a': {
81
- 'type': 'string'
78
+ type: 'object',
79
+ properties: {
80
+ a: {
81
+ type: 'string'
82
82
  }
83
83
  }
84
84
  },
85
85
  {
86
- 'type': 'array',
87
- 'items': {
88
- 'type': 'string'
86
+ type: 'array',
87
+ items: {
88
+ type: 'string'
89
89
  }
90
90
  }
91
91
  ]
@@ -96,12 +96,12 @@ buildTest({
96
96
  })
97
97
 
98
98
  buildTest({
99
- 'title': 'repeated types',
100
- 'type': 'object',
101
- 'properties': {
102
- 'ids': {
103
- 'type': 'array',
104
- 'items': [
99
+ title: 'repeated types',
100
+ type: 'object',
101
+ properties: {
102
+ ids: {
103
+ type: 'array',
104
+ items: [
105
105
  {
106
106
  type: 'number'
107
107
  },
@@ -114,25 +114,25 @@ buildTest({
114
114
  }, { ids: [1, 2] })
115
115
 
116
116
  buildTest({
117
- 'title': 'pattern properties array',
118
- 'type': 'object',
119
- 'properties': {
120
- 'args': {
121
- 'type': 'array',
122
- 'items': [
117
+ title: 'pattern properties array',
118
+ type: 'object',
119
+ properties: {
120
+ args: {
121
+ type: 'array',
122
+ items: [
123
123
  {
124
- 'type': 'object',
125
- 'patternProperties': {
124
+ type: 'object',
125
+ patternProperties: {
126
126
  '.*': {
127
- 'type': 'string'
127
+ type: 'string'
128
128
  }
129
129
  }
130
130
  },
131
131
  {
132
- 'type': 'object',
133
- 'patternProperties': {
132
+ type: 'object',
133
+ patternProperties: {
134
134
  '.*': {
135
- 'type': 'number'
135
+ type: 'number'
136
136
  }
137
137
  }
138
138
  }
@@ -144,16 +144,16 @@ buildTest({
144
144
  test('invalid items throw', (t) => {
145
145
  t.plan(1)
146
146
  const schema = {
147
- 'type': 'object',
148
- 'properties': {
149
- 'args': {
150
- 'type': 'array',
151
- 'items': [
147
+ type: 'object',
148
+ properties: {
149
+ args: {
150
+ type: 'array',
151
+ items: [
152
152
  {
153
- 'type': 'object',
154
- 'patternProperties': {
153
+ type: 'object',
154
+ patternProperties: {
155
155
  '.*': {
156
- 'type': 'string'
156
+ type: 'string'
157
157
  }
158
158
  }
159
159
  }