@covenant-rpc/ion 1.0.3
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 +13 -0
- package/README.md +101 -0
- package/benchmark-types.ts +184 -0
- package/benchmark.ts +183 -0
- package/index.test.ts +386 -0
- package/index.ts +698 -0
- package/package.json +18 -0
- package/tsconfig.json +29 -0
package/CHANGELOG.md
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
# `ION`
|
|
4
|
+
|
|
5
|
+
`ION` - Isomorphic Object Notation
|
|
6
|
+
|
|
7
|
+
## Purpose
|
|
8
|
+
|
|
9
|
+
`ION` is a `JSON` like object serialization format. If given the following code:
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
function isomorphicSerialize(obj: any) {
|
|
13
|
+
const serialized = ION.stringify(obj);
|
|
14
|
+
const deserialized = ION.parse(obj);
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
It guarantees that either:
|
|
19
|
+
- `ION.stringify` throws an error
|
|
20
|
+
- `deserialized` and `obj` are identical objects
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
`JSON` fails in various circumstances at this:
|
|
24
|
+
- `Date`s become strings
|
|
25
|
+
- `undefined` becomes null
|
|
26
|
+
- `Symbol`s are omitted
|
|
27
|
+
- `NaN`, `Infinity`, and `-Infinity` become null
|
|
28
|
+
- Sets and maps become `{}`
|
|
29
|
+
|
|
30
|
+
In cases where something can't be perfectly recreated from parsing, ION will throw an error.
|
|
31
|
+
|
|
32
|
+
## Performance
|
|
33
|
+
|
|
34
|
+
ION is optimized for performance while maintaining type safety guarantees:
|
|
35
|
+
|
|
36
|
+
**Stringify Performance:**
|
|
37
|
+
- Small objects: ~3.2x slower than JSON
|
|
38
|
+
- Medium objects: ~3.5x slower than JSON
|
|
39
|
+
- Large arrays (100 items): ~1.8x slower than JSON
|
|
40
|
+
- String-heavy data: ~2.1x slower than JSON
|
|
41
|
+
|
|
42
|
+
**Parse Performance:**
|
|
43
|
+
- Small objects: ~8.6x slower than JSON
|
|
44
|
+
- Medium objects: ~5.6x slower than JSON
|
|
45
|
+
- Large arrays (100 items): ~5.5x slower than JSON
|
|
46
|
+
- String-heavy data: ~2.4x slower than JSON
|
|
47
|
+
|
|
48
|
+
**Average:** ION stringify is ~2.2x slower and parse is ~5.7x slower than JSON, while providing complete type preservation and safety guarantees that JSON cannot offer.
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
## Syntax
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
`ION` is a superset of `JSON`. Any valid `JSON` is valid `ION`, although not all objects are translated exactly the same.
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
```ion
|
|
58
|
+
{
|
|
59
|
+
"string": "hello",
|
|
60
|
+
"number": 123,
|
|
61
|
+
"array": [
|
|
62
|
+
{
|
|
63
|
+
"name": null,
|
|
64
|
+
"boolean": true,
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`JSON` has support for several types: `boolean`, `number`, `string`, `object`, and `array`. `ION` adds a couple more:
|
|
71
|
+
- `Infinity`
|
|
72
|
+
- `-Infinity`
|
|
73
|
+
- `NaN`
|
|
74
|
+
- `Date`
|
|
75
|
+
- `Map`
|
|
76
|
+
- `Set`
|
|
77
|
+
|
|
78
|
+
Note: `WeakMap` and `WeakSet` cannot be serialized and will throw an error if encountered.
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
If an object has any `undefined` properties, they are simply omitted. These advanced properties look like:
|
|
82
|
+
|
|
83
|
+
```ion
|
|
84
|
+
{
|
|
85
|
+
"date": date:2026-01-27T15:30:00Z,
|
|
86
|
+
"not-a-number": NaN,
|
|
87
|
+
"infinity": Infinity,
|
|
88
|
+
"negativeInf": -Infinity,
|
|
89
|
+
"someMap": map {
|
|
90
|
+
"property": 1,
|
|
91
|
+
"another": 2
|
|
92
|
+
},
|
|
93
|
+
"someSet": set {
|
|
94
|
+
"a",
|
|
95
|
+
"b"
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import ION from './index.ts';
|
|
2
|
+
|
|
3
|
+
console.log('='.repeat(100));
|
|
4
|
+
console.log('ION vs JSON: Type Preservation Comparison');
|
|
5
|
+
console.log('='.repeat(100));
|
|
6
|
+
|
|
7
|
+
// Test 1: Dates
|
|
8
|
+
console.log('\n1. Date Handling');
|
|
9
|
+
console.log('-'.repeat(100));
|
|
10
|
+
const dateObj = { timestamp: new Date('2026-01-27T15:30:00Z'), name: 'Event' };
|
|
11
|
+
|
|
12
|
+
const jsonDate = JSON.parse(JSON.stringify(dateObj));
|
|
13
|
+
const ionDate = ION.parse(ION.stringify(dateObj)) as typeof dateObj;
|
|
14
|
+
|
|
15
|
+
console.log('Original:', dateObj);
|
|
16
|
+
console.log('JSON: ', jsonDate);
|
|
17
|
+
console.log(' - timestamp type:', typeof jsonDate.timestamp);
|
|
18
|
+
console.log(' - timestamp value:', jsonDate.timestamp);
|
|
19
|
+
console.log('ION: ', ionDate);
|
|
20
|
+
console.log(' - timestamp type:', typeof ionDate.timestamp);
|
|
21
|
+
console.log(' - timestamp instanceof Date:', ionDate.timestamp instanceof Date);
|
|
22
|
+
|
|
23
|
+
// Test 2: NaN and Infinity
|
|
24
|
+
console.log('\n2. Special Numbers (NaN, Infinity)');
|
|
25
|
+
console.log('-'.repeat(100));
|
|
26
|
+
const specialNumbers = {
|
|
27
|
+
nan: NaN,
|
|
28
|
+
infinity: Infinity,
|
|
29
|
+
negInfinity: -Infinity,
|
|
30
|
+
normal: 42,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const jsonSpecial = JSON.parse(JSON.stringify(specialNumbers));
|
|
34
|
+
const ionSpecial = ION.parse(ION.stringify(specialNumbers)) as typeof specialNumbers;
|
|
35
|
+
|
|
36
|
+
console.log('Original:', specialNumbers);
|
|
37
|
+
console.log('JSON: ', jsonSpecial);
|
|
38
|
+
console.log(' - nan is NaN:', Number.isNaN(jsonSpecial.nan));
|
|
39
|
+
console.log(' - infinity is Infinity:', jsonSpecial.infinity === Infinity);
|
|
40
|
+
console.log('ION: ', ionSpecial);
|
|
41
|
+
console.log(' - nan is NaN:', Number.isNaN(ionSpecial.nan));
|
|
42
|
+
console.log(' - infinity is Infinity:', ionSpecial.infinity === Infinity);
|
|
43
|
+
console.log(' - negInfinity is -Infinity:', ionSpecial.negInfinity === -Infinity);
|
|
44
|
+
|
|
45
|
+
// Test 3: Maps
|
|
46
|
+
console.log('\n3. Map Handling');
|
|
47
|
+
console.log('-'.repeat(100));
|
|
48
|
+
const mapObj = {
|
|
49
|
+
config: new Map<string | number, string | number>([
|
|
50
|
+
['theme', 'dark'],
|
|
51
|
+
['fontSize', 14],
|
|
52
|
+
[123, 'numeric key'],
|
|
53
|
+
]),
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const jsonMap = JSON.parse(JSON.stringify(mapObj));
|
|
57
|
+
const ionMap = ION.parse(ION.stringify(mapObj)) as typeof mapObj;
|
|
58
|
+
|
|
59
|
+
console.log('Original:', mapObj);
|
|
60
|
+
console.log(' - config instanceof Map:', mapObj.config instanceof Map);
|
|
61
|
+
console.log(' - config.get("theme"):', mapObj.config.get('theme'));
|
|
62
|
+
console.log('JSON: ', jsonMap);
|
|
63
|
+
console.log(' - config instanceof Map:', jsonMap.config instanceof Map);
|
|
64
|
+
console.log(' - config type:', typeof jsonMap.config);
|
|
65
|
+
console.log('ION: ', ionMap);
|
|
66
|
+
console.log(' - config instanceof Map:', ionMap.config instanceof Map);
|
|
67
|
+
console.log(' - config.get("theme"):', ionMap.config.get('theme'));
|
|
68
|
+
console.log(' - config.get(123):', ionMap.config.get(123));
|
|
69
|
+
|
|
70
|
+
// Test 4: Sets
|
|
71
|
+
console.log('\n4. Set Handling');
|
|
72
|
+
console.log('-'.repeat(100));
|
|
73
|
+
const setObj = {
|
|
74
|
+
tags: new Set(['javascript', 'typescript', 'bun']),
|
|
75
|
+
count: 3,
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const jsonSet = JSON.parse(JSON.stringify(setObj));
|
|
79
|
+
const ionSet = ION.parse(ION.stringify(setObj)) as typeof setObj;
|
|
80
|
+
|
|
81
|
+
console.log('Original:', setObj);
|
|
82
|
+
console.log(' - tags instanceof Set:', setObj.tags instanceof Set);
|
|
83
|
+
console.log(' - tags.has("typescript"):', setObj.tags.has('typescript'));
|
|
84
|
+
console.log('JSON: ', jsonSet);
|
|
85
|
+
console.log(' - tags instanceof Set:', jsonSet.tags instanceof Set);
|
|
86
|
+
console.log(' - tags type:', typeof jsonSet.tags);
|
|
87
|
+
console.log('ION: ', ionSet);
|
|
88
|
+
console.log(' - tags instanceof Set:', ionSet.tags instanceof Set);
|
|
89
|
+
console.log(' - tags.has("typescript"):', ionSet.tags.has('typescript'));
|
|
90
|
+
|
|
91
|
+
// Test 5: undefined properties
|
|
92
|
+
console.log('\n5. undefined Handling');
|
|
93
|
+
console.log('-'.repeat(100));
|
|
94
|
+
const undefinedObj = {
|
|
95
|
+
name: 'Alice',
|
|
96
|
+
age: undefined,
|
|
97
|
+
email: 'alice@example.com',
|
|
98
|
+
phone: undefined,
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const jsonUndefined = JSON.parse(JSON.stringify(undefinedObj));
|
|
102
|
+
const ionUndefined = ION.parse(ION.stringify(undefinedObj)) as Record<string, unknown>;
|
|
103
|
+
|
|
104
|
+
console.log('Original:', undefinedObj);
|
|
105
|
+
console.log(' - has "age" property:', 'age' in undefinedObj);
|
|
106
|
+
console.log(' - has "phone" property:', 'phone' in undefinedObj);
|
|
107
|
+
console.log('JSON: ', jsonUndefined);
|
|
108
|
+
console.log(' - has "age" property:', 'age' in jsonUndefined);
|
|
109
|
+
console.log(' - has "phone" property:', 'phone' in jsonUndefined);
|
|
110
|
+
console.log('ION: ', ionUndefined);
|
|
111
|
+
console.log(' - has "age" property:', 'age' in ionUndefined);
|
|
112
|
+
console.log(' - has "phone" property:', 'phone' in ionUndefined);
|
|
113
|
+
|
|
114
|
+
// Test 6: Complex real-world scenario
|
|
115
|
+
console.log('\n6. Real-World Scenario: API Response with Mixed Types');
|
|
116
|
+
console.log('-'.repeat(100));
|
|
117
|
+
const apiResponse = {
|
|
118
|
+
user: {
|
|
119
|
+
id: 123,
|
|
120
|
+
name: 'Alice',
|
|
121
|
+
lastLogin: new Date('2026-01-27T15:30:00Z'),
|
|
122
|
+
score: NaN, // not yet calculated
|
|
123
|
+
preferences: new Map<string, string | boolean>([
|
|
124
|
+
['theme', 'dark'],
|
|
125
|
+
['notifications', true],
|
|
126
|
+
]),
|
|
127
|
+
roles: new Set(['admin', 'user']),
|
|
128
|
+
optionalField: undefined,
|
|
129
|
+
},
|
|
130
|
+
metadata: {
|
|
131
|
+
requestTime: new Date('2026-01-27T15:35:00Z'),
|
|
132
|
+
version: '1.0.0',
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
console.log('\nOriginal object:');
|
|
137
|
+
console.log(' - user.lastLogin instanceof Date:', apiResponse.user.lastLogin instanceof Date);
|
|
138
|
+
console.log(' - user.score is NaN:', Number.isNaN(apiResponse.user.score));
|
|
139
|
+
console.log(' - user.preferences instanceof Map:', apiResponse.user.preferences instanceof Map);
|
|
140
|
+
console.log(' - user.roles instanceof Set:', apiResponse.user.roles instanceof Set);
|
|
141
|
+
console.log(' - user has "optionalField":', 'optionalField' in apiResponse.user);
|
|
142
|
+
|
|
143
|
+
const jsonApi = JSON.parse(JSON.stringify(apiResponse));
|
|
144
|
+
console.log('\nJSON round-trip:');
|
|
145
|
+
console.log(' - user.lastLogin instanceof Date:', jsonApi.user.lastLogin instanceof Date);
|
|
146
|
+
console.log(' - user.lastLogin type:', typeof jsonApi.user.lastLogin);
|
|
147
|
+
console.log(' - user.score is NaN:', Number.isNaN(jsonApi.user.score));
|
|
148
|
+
console.log(' - user.score value:', jsonApi.user.score);
|
|
149
|
+
console.log(' - user.preferences instanceof Map:', jsonApi.user.preferences instanceof Map);
|
|
150
|
+
console.log(' - user.roles instanceof Set:', jsonApi.user.roles instanceof Set);
|
|
151
|
+
console.log(' - user has "optionalField":', 'optionalField' in jsonApi.user);
|
|
152
|
+
|
|
153
|
+
const ionApi = ION.parse(ION.stringify(apiResponse)) as typeof apiResponse;
|
|
154
|
+
console.log('\nION round-trip:');
|
|
155
|
+
console.log(' - user.lastLogin instanceof Date:', ionApi.user.lastLogin instanceof Date);
|
|
156
|
+
console.log(' - user.score is NaN:', Number.isNaN(ionApi.user.score));
|
|
157
|
+
console.log(' - user.preferences instanceof Map:', ionApi.user.preferences instanceof Map);
|
|
158
|
+
console.log(' - user.preferences.get("theme"):', ionApi.user.preferences.get('theme'));
|
|
159
|
+
console.log(' - user.roles instanceof Set:', ionApi.user.roles instanceof Set);
|
|
160
|
+
console.log(' - user.roles.has("admin"):', ionApi.user.roles.has('admin'));
|
|
161
|
+
console.log(' - user has "optionalField":', 'optionalField' in ionApi.user);
|
|
162
|
+
|
|
163
|
+
// Summary
|
|
164
|
+
console.log('\n' + '='.repeat(100));
|
|
165
|
+
console.log('Summary');
|
|
166
|
+
console.log('='.repeat(100));
|
|
167
|
+
console.log('\nJSON Issues:');
|
|
168
|
+
console.log(' ✗ Dates become strings (need manual conversion)');
|
|
169
|
+
console.log(' ✗ NaN becomes null (information loss)');
|
|
170
|
+
console.log(' ✗ Infinity becomes null (information loss)');
|
|
171
|
+
console.log(' ✗ Maps become empty objects (data loss)');
|
|
172
|
+
console.log(' ✗ Sets become empty objects (data loss)');
|
|
173
|
+
console.log(' ✓ undefined properties are removed');
|
|
174
|
+
|
|
175
|
+
console.log('\nION Guarantees:');
|
|
176
|
+
console.log(' ✓ Dates preserved as Date objects');
|
|
177
|
+
console.log(' ✓ NaN preserved as NaN');
|
|
178
|
+
console.log(' ✓ Infinity preserved as Infinity');
|
|
179
|
+
console.log(' ✓ Maps preserved with all entries and types');
|
|
180
|
+
console.log(' ✓ Sets preserved with all values');
|
|
181
|
+
console.log(' ✓ undefined properties are removed');
|
|
182
|
+
console.log(' ✓ Throws errors for unsupported types (WeakMap, functions, etc.)');
|
|
183
|
+
|
|
184
|
+
console.log('\n' + '='.repeat(100) + '\n');
|
package/benchmark.ts
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import ION from './index.ts';
|
|
2
|
+
|
|
3
|
+
interface BenchmarkResult {
|
|
4
|
+
name: string;
|
|
5
|
+
jsonStringify: number;
|
|
6
|
+
ionStringify: number;
|
|
7
|
+
jsonParse: number;
|
|
8
|
+
ionParse: number;
|
|
9
|
+
jsonSize: number;
|
|
10
|
+
ionSize: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function benchmark(name: string, data: unknown, iterations = 10000): BenchmarkResult {
|
|
14
|
+
// Warmup
|
|
15
|
+
for (let i = 0; i < 100; i++) {
|
|
16
|
+
JSON.stringify(data);
|
|
17
|
+
ION.stringify(data);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Benchmark JSON.stringify
|
|
21
|
+
const jsonStringifyStart = performance.now();
|
|
22
|
+
let jsonStr = '';
|
|
23
|
+
for (let i = 0; i < iterations; i++) {
|
|
24
|
+
jsonStr = JSON.stringify(data);
|
|
25
|
+
}
|
|
26
|
+
const jsonStringifyTime = performance.now() - jsonStringifyStart;
|
|
27
|
+
|
|
28
|
+
// Benchmark ION.stringify
|
|
29
|
+
const ionStringifyStart = performance.now();
|
|
30
|
+
let ionStr = '';
|
|
31
|
+
for (let i = 0; i < iterations; i++) {
|
|
32
|
+
ionStr = ION.stringify(data);
|
|
33
|
+
}
|
|
34
|
+
const ionStringifyTime = performance.now() - ionStringifyStart;
|
|
35
|
+
|
|
36
|
+
// Benchmark JSON.parse
|
|
37
|
+
const jsonParseStart = performance.now();
|
|
38
|
+
for (let i = 0; i < iterations; i++) {
|
|
39
|
+
JSON.parse(jsonStr);
|
|
40
|
+
}
|
|
41
|
+
const jsonParseTime = performance.now() - jsonParseStart;
|
|
42
|
+
|
|
43
|
+
// Benchmark ION.parse
|
|
44
|
+
const ionParseStart = performance.now();
|
|
45
|
+
for (let i = 0; i < iterations; i++) {
|
|
46
|
+
ION.parse(ionStr);
|
|
47
|
+
}
|
|
48
|
+
const ionParseTime = performance.now() - ionParseStart;
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
name,
|
|
52
|
+
jsonStringify: jsonStringifyTime,
|
|
53
|
+
ionStringify: ionStringifyTime,
|
|
54
|
+
jsonParse: jsonParseTime,
|
|
55
|
+
ionParse: ionParseTime,
|
|
56
|
+
jsonSize: jsonStr.length,
|
|
57
|
+
ionSize: ionStr.length,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function formatTime(ms: number): string {
|
|
62
|
+
if (ms < 1) {
|
|
63
|
+
return `${(ms * 1000).toFixed(2)}μs`;
|
|
64
|
+
}
|
|
65
|
+
return `${ms.toFixed(2)}ms`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function formatRatio(ion: number, json: number): string {
|
|
69
|
+
const ratio = ion / json;
|
|
70
|
+
if (ratio < 1) {
|
|
71
|
+
return `${(1 / ratio).toFixed(2)}x faster`;
|
|
72
|
+
} else {
|
|
73
|
+
return `${ratio.toFixed(2)}x slower`;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function printResults(results: BenchmarkResult[]): void {
|
|
78
|
+
console.log('\n' + '='.repeat(100));
|
|
79
|
+
console.log('ION vs JSON Benchmark Results');
|
|
80
|
+
console.log('='.repeat(100));
|
|
81
|
+
|
|
82
|
+
for (const result of results) {
|
|
83
|
+
console.log(`\n${result.name}`);
|
|
84
|
+
console.log('-'.repeat(100));
|
|
85
|
+
|
|
86
|
+
console.log('\nStringify:');
|
|
87
|
+
console.log(` JSON: ${formatTime(result.jsonStringify)}`);
|
|
88
|
+
console.log(` ION: ${formatTime(result.ionStringify)} (${formatRatio(result.ionStringify, result.jsonStringify)})`);
|
|
89
|
+
|
|
90
|
+
console.log('\nParse:');
|
|
91
|
+
console.log(` JSON: ${formatTime(result.jsonParse)}`);
|
|
92
|
+
console.log(` ION: ${formatTime(result.ionParse)} (${formatRatio(result.ionParse, result.jsonParse)})`);
|
|
93
|
+
|
|
94
|
+
console.log('\nSize:');
|
|
95
|
+
console.log(` JSON: ${result.jsonSize} bytes`);
|
|
96
|
+
console.log(` ION: ${result.ionSize} bytes (${result.ionSize > result.jsonSize ? '+' : ''}${result.ionSize - result.jsonSize} bytes)`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
console.log('\n' + '='.repeat(100));
|
|
100
|
+
console.log('Summary');
|
|
101
|
+
console.log('='.repeat(100));
|
|
102
|
+
|
|
103
|
+
const avgJsonStringify = results.reduce((sum, r) => sum + r.jsonStringify, 0) / results.length;
|
|
104
|
+
const avgIonStringify = results.reduce((sum, r) => sum + r.ionStringify, 0) / results.length;
|
|
105
|
+
const avgJsonParse = results.reduce((sum, r) => sum + r.jsonParse, 0) / results.length;
|
|
106
|
+
const avgIonParse = results.reduce((sum, r) => sum + r.ionParse, 0) / results.length;
|
|
107
|
+
|
|
108
|
+
console.log(`\nAverage Stringify: JSON ${formatTime(avgJsonStringify)}, ION ${formatTime(avgIonStringify)}`);
|
|
109
|
+
console.log(`Average Parse: JSON ${formatTime(avgJsonParse)}, ION ${formatTime(avgIonParse)}`);
|
|
110
|
+
console.log(`\nION is ${formatRatio(avgIonStringify, avgJsonStringify)} for stringify`);
|
|
111
|
+
console.log(`ION is ${formatRatio(avgIonParse, avgJsonParse)} for parse`);
|
|
112
|
+
console.log('='.repeat(100) + '\n');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Test data
|
|
116
|
+
const smallObject = {
|
|
117
|
+
name: 'Alice',
|
|
118
|
+
age: 30,
|
|
119
|
+
active: true,
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const mediumObject = {
|
|
123
|
+
users: [
|
|
124
|
+
{ id: 1, name: 'Alice', email: 'alice@example.com', active: true },
|
|
125
|
+
{ id: 2, name: 'Bob', email: 'bob@example.com', active: false },
|
|
126
|
+
{ id: 3, name: 'Charlie', email: 'charlie@example.com', active: true },
|
|
127
|
+
],
|
|
128
|
+
metadata: {
|
|
129
|
+
version: '1.0.0',
|
|
130
|
+
created: '2026-01-27',
|
|
131
|
+
count: 3,
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const largeArray = Array.from({ length: 100 }, (_, i) => ({
|
|
136
|
+
id: i,
|
|
137
|
+
name: `User ${i}`,
|
|
138
|
+
email: `user${i}@example.com`,
|
|
139
|
+
score: Math.random() * 100,
|
|
140
|
+
active: i % 2 === 0,
|
|
141
|
+
}));
|
|
142
|
+
|
|
143
|
+
const deepNesting = {
|
|
144
|
+
level1: {
|
|
145
|
+
level2: {
|
|
146
|
+
level3: {
|
|
147
|
+
level4: {
|
|
148
|
+
level5: {
|
|
149
|
+
data: 'deep value',
|
|
150
|
+
numbers: [1, 2, 3, 4, 5],
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const stringHeavy = {
|
|
159
|
+
description: 'This is a longer description with multiple sentences. '.repeat(10),
|
|
160
|
+
comments: Array.from({ length: 20 }, (_, i) => `Comment number ${i} with some text content`),
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// Run benchmarks
|
|
164
|
+
console.log('Running benchmarks...\n');
|
|
165
|
+
|
|
166
|
+
const results: BenchmarkResult[] = [];
|
|
167
|
+
|
|
168
|
+
console.log('[1/5] Small object...');
|
|
169
|
+
results.push(benchmark('Small Object (3 properties)', smallObject, 50000));
|
|
170
|
+
|
|
171
|
+
console.log('[2/5] Medium object...');
|
|
172
|
+
results.push(benchmark('Medium Object (users array + metadata)', mediumObject, 20000));
|
|
173
|
+
|
|
174
|
+
console.log('[3/5] Large array...');
|
|
175
|
+
results.push(benchmark('Large Array (100 objects)', largeArray, 5000));
|
|
176
|
+
|
|
177
|
+
console.log('[4/5] Deep nesting...');
|
|
178
|
+
results.push(benchmark('Deep Nesting (5 levels)', deepNesting, 50000));
|
|
179
|
+
|
|
180
|
+
console.log('[5/5] String heavy...');
|
|
181
|
+
results.push(benchmark('String Heavy (long strings + array)', stringHeavy, 10000));
|
|
182
|
+
|
|
183
|
+
printResults(results);
|