@atproto/lex-json 0.0.14 β 0.0.16
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/CHANGELOG.md +15 -0
- package/dist/blob.d.ts +4 -4
- package/dist/blob.d.ts.map +1 -1
- package/dist/blob.js +6 -6
- package/dist/blob.js.map +1 -1
- package/dist/json-bytes-decoder.d.ts +24 -0
- package/dist/json-bytes-decoder.d.ts.map +1 -0
- package/dist/json-bytes-decoder.js +600 -0
- package/dist/json-bytes-decoder.js.map +1 -0
- package/dist/lex-json.d.ts +9 -1
- package/dist/lex-json.d.ts.map +1 -1
- package/dist/lex-json.js +25 -24
- package/dist/lex-json.js.map +1 -1
- package/package.json +2 -2
- package/src/blob.ts +8 -8
- package/src/json-bytes-decoder.bench.ts +252 -0
- package/src/json-bytes-decoder.test.ts +889 -0
- package/src/json-bytes-decoder.ts +672 -0
- package/src/lex-json.bench.ts +125 -0
- package/src/lex-json.test.ts +535 -69
- package/src/lex-json.ts +29 -23
- package/tsconfig.build.json +1 -1
- package/tsconfig.tests.json +1 -1
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { bench, describe } from 'vitest'
|
|
2
|
+
import { JsonValue } from './json.js'
|
|
3
|
+
import {
|
|
4
|
+
LexParseOptions,
|
|
5
|
+
jsonToLex,
|
|
6
|
+
lexParse,
|
|
7
|
+
parseSpecialJsonObject,
|
|
8
|
+
} from './lex-json.js'
|
|
9
|
+
|
|
10
|
+
// This benchmark compares the performance of two implementations of
|
|
11
|
+
// lexParse:
|
|
12
|
+
// - One that uses a reviver function with JSON.parse to directly parse special
|
|
13
|
+
// objects and handle numbers (lexParse with reviver)
|
|
14
|
+
// - One that first parses JSON to a plain JS object and then converts it to
|
|
15
|
+
// LexValue using jsonToLex (lexParse with jsonToLex)
|
|
16
|
+
|
|
17
|
+
describe('small object', () => {
|
|
18
|
+
benchData({
|
|
19
|
+
$type: 'app.bsky.feed.post',
|
|
20
|
+
text: 'Hello world! π',
|
|
21
|
+
createdAt: '2024-01-01T00:00:00Z',
|
|
22
|
+
})
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
describe('simple mixed structure', () => {
|
|
26
|
+
benchData({
|
|
27
|
+
cid: {
|
|
28
|
+
$link: 'bafyreidfayvfuwqa7qlnopdjiqrxzs6blmoeu4rujcjtnci5beludirz2a',
|
|
29
|
+
},
|
|
30
|
+
bytes: {
|
|
31
|
+
$bytes: 'nFERjvLLiw9qm45JrqH9QTzyC2Lu1Xb4ne6+sBrCzI0',
|
|
32
|
+
},
|
|
33
|
+
blob: {
|
|
34
|
+
$type: 'blob',
|
|
35
|
+
ref: {
|
|
36
|
+
$link: 'bafkreig77vqcdozl2wyk6z3cscaj5q5fggi53aoh64fewkdiri3cdauyn4',
|
|
37
|
+
},
|
|
38
|
+
mimeType: 'image/jpeg',
|
|
39
|
+
size: 10000,
|
|
40
|
+
},
|
|
41
|
+
nested: {
|
|
42
|
+
array: [
|
|
43
|
+
{
|
|
44
|
+
number: 42,
|
|
45
|
+
string: 'hello world',
|
|
46
|
+
bool: true,
|
|
47
|
+
null: null,
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
string: 'Hello δΈη! πππ ΓoΓ±o',
|
|
51
|
+
createdAt: '2024-01-01T00:00:00Z',
|
|
52
|
+
},
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
describe('large payload', () => {
|
|
57
|
+
benchData({
|
|
58
|
+
items: Array.from({ length: 25 }, (_, i) => ({
|
|
59
|
+
id: i,
|
|
60
|
+
name: `Item ${i}`,
|
|
61
|
+
longUnicode:
|
|
62
|
+
'Lorem ipsum dolor sit amet, consectetur adipiscing elit π€©.\n'.repeat(
|
|
63
|
+
2,
|
|
64
|
+
),
|
|
65
|
+
tags: ['tag1', 'tag2', 'tag3'],
|
|
66
|
+
bytes: {
|
|
67
|
+
$bytes: Buffer.from(`This is some byte data for item ${i}`).toString(
|
|
68
|
+
'base64',
|
|
69
|
+
),
|
|
70
|
+
},
|
|
71
|
+
cid: {
|
|
72
|
+
$link: 'bafyreidfayvfuwqa7qlnopdjiqrxzs6blmoeu4rujcjtnci5beludirz2a',
|
|
73
|
+
},
|
|
74
|
+
metadata: {
|
|
75
|
+
created: '2024-01-01T00:00:00Z',
|
|
76
|
+
count: i * 10,
|
|
77
|
+
nested: {
|
|
78
|
+
flag: i % 2 === 0,
|
|
79
|
+
values: [i, i * 2, i * 3],
|
|
80
|
+
},
|
|
81
|
+
items: Array.from({ length: 5 }, (_, j) => ({
|
|
82
|
+
id: `${i}-${j}`,
|
|
83
|
+
value: `Value ${i}-${j}`,
|
|
84
|
+
})),
|
|
85
|
+
},
|
|
86
|
+
})),
|
|
87
|
+
})
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
function benchData(data: unknown, options?: LexParseOptions) {
|
|
91
|
+
const jsonString = JSON.stringify(data)
|
|
92
|
+
|
|
93
|
+
const withReviver: typeof lexParse = (input, options = { strict: true }) => {
|
|
94
|
+
return JSON.parse(input, (key: string, value: JsonValue) => {
|
|
95
|
+
switch (typeof value) {
|
|
96
|
+
case 'object':
|
|
97
|
+
if (value === null) return null
|
|
98
|
+
if (Array.isArray(value)) return value
|
|
99
|
+
return parseSpecialJsonObject(value, options) ?? value
|
|
100
|
+
case 'number':
|
|
101
|
+
if (Number.isSafeInteger(value)) return value
|
|
102
|
+
if (options && options.strict === false) return value
|
|
103
|
+
throw new TypeError(`Invalid non-integer number: ${value}`)
|
|
104
|
+
default:
|
|
105
|
+
return value
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const naiveParse: typeof lexParse = (input, options) => {
|
|
111
|
+
return jsonToLex(JSON.parse(input), options) as any
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
bench('current', () => {
|
|
115
|
+
lexParse(jsonString, options)
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
bench('with-reviver', () => {
|
|
119
|
+
withReviver(jsonString, options)
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
bench('naive', () => {
|
|
123
|
+
naiveParse(jsonString, options)
|
|
124
|
+
})
|
|
125
|
+
}
|