crous 1.0.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/LICENSE +21 -0
- package/README.md +413 -0
- package/binding.gyp +50 -0
- package/index.d.ts +358 -0
- package/index.js +290 -0
- package/package.json +57 -0
- package/src/crous_node.c +819 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Pawan Kumar
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
# Crous for Node.js
|
|
2
|
+
|
|
3
|
+
High-performance binary serialization format for Node.js, based on the Crous C library.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Fast**: Native C implementation with N-API bindings
|
|
8
|
+
- **Efficient**: 40-60% smaller than JSON while remaining deterministic
|
|
9
|
+
- **Type-safe**: Full TypeScript support with comprehensive type definitions
|
|
10
|
+
- **Flexible**: Support for custom serializers and decoders
|
|
11
|
+
- **Compatible**: Works with Node.js 14+ on all platforms
|
|
12
|
+
|
|
13
|
+
## Supported Types
|
|
14
|
+
|
|
15
|
+
### Built-in Types
|
|
16
|
+
- **Primitives**: `null`, `boolean`, `number` (int/float), `string`, `Buffer`
|
|
17
|
+
- **Collections**: `Array`, `Object`, `Set`
|
|
18
|
+
- **Custom Types**: Via tagged values with custom serializers/decoders
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install crous
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Or from source:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
git clone https://github.com/axiomchronicles/crous.git
|
|
30
|
+
cd crous/nodejs
|
|
31
|
+
npm install
|
|
32
|
+
npm run build
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
|
|
37
|
+
### Basic Usage
|
|
38
|
+
|
|
39
|
+
```javascript
|
|
40
|
+
const crous = require('crous');
|
|
41
|
+
|
|
42
|
+
// Serialize data
|
|
43
|
+
const data = { name: 'Alice', age: 30, tags: ['developer', 'nodejs'] };
|
|
44
|
+
const binary = crous.dumps(data);
|
|
45
|
+
console.log(binary); // <Buffer ...>
|
|
46
|
+
|
|
47
|
+
// Deserialize data
|
|
48
|
+
const result = crous.loads(binary);
|
|
49
|
+
console.log(result); // { name: 'Alice', age: 30, tags: ['developer', 'nodejs'] }
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### TypeScript Usage
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import * as crous from 'crous';
|
|
56
|
+
|
|
57
|
+
interface User {
|
|
58
|
+
name: string;
|
|
59
|
+
age: number;
|
|
60
|
+
tags: string[];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const user: User = { name: 'Alice', age: 30, tags: ['developer', 'nodejs'] };
|
|
64
|
+
const binary: Buffer = crous.dumps(user);
|
|
65
|
+
const result: User = crous.loads(binary);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### File I/O
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
const crous = require('crous');
|
|
72
|
+
const fs = require('fs');
|
|
73
|
+
|
|
74
|
+
// Write to file
|
|
75
|
+
const data = { users: [{ id: 1, name: 'Alice' }] };
|
|
76
|
+
crous.dump(data, 'output.crous');
|
|
77
|
+
|
|
78
|
+
// Read from file
|
|
79
|
+
const loaded = crous.load('output.crous');
|
|
80
|
+
console.log(loaded); // { users: [{ id: 1, name: 'Alice' }] }
|
|
81
|
+
|
|
82
|
+
// Or use streams
|
|
83
|
+
const writeStream = fs.createWriteStream('output.crous');
|
|
84
|
+
crous.dump(data, writeStream);
|
|
85
|
+
|
|
86
|
+
const readStream = fs.createReadStream('output.crous');
|
|
87
|
+
const result = crous.load(readStream);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Advanced Features
|
|
91
|
+
|
|
92
|
+
### Custom Serializers
|
|
93
|
+
|
|
94
|
+
Register custom serializers for your own classes:
|
|
95
|
+
|
|
96
|
+
```javascript
|
|
97
|
+
const crous = require('crous');
|
|
98
|
+
|
|
99
|
+
class Point {
|
|
100
|
+
constructor(x, y) {
|
|
101
|
+
this.x = x;
|
|
102
|
+
this.y = y;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Register serializer
|
|
107
|
+
crous.registerSerializer(Point, (point) => {
|
|
108
|
+
return { x: point.x, y: point.y };
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Now you can serialize Point instances
|
|
112
|
+
const point = new Point(10, 20);
|
|
113
|
+
const binary = crous.dumps(point);
|
|
114
|
+
|
|
115
|
+
// To deserialize back to Point, register a decoder
|
|
116
|
+
crous.registerDecoder(100, (value) => {
|
|
117
|
+
return new Point(value.x, value.y);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const result = crous.loads(binary);
|
|
121
|
+
console.log(result instanceof Point); // true
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Custom Decoders
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
const crous = require('crous');
|
|
128
|
+
|
|
129
|
+
class DateTime {
|
|
130
|
+
constructor(timestamp) {
|
|
131
|
+
this.date = new Date(timestamp);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Register decoder for tag 101
|
|
136
|
+
crous.registerDecoder(101, (value) => {
|
|
137
|
+
return new DateTime(value);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Now when loading data with tag 101, it will be decoded to DateTime
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Object Hooks
|
|
144
|
+
|
|
145
|
+
Transform dictionaries during deserialization:
|
|
146
|
+
|
|
147
|
+
```javascript
|
|
148
|
+
const crous = require('crous');
|
|
149
|
+
|
|
150
|
+
const data = { user: { name: 'Alice', role: 'admin' } };
|
|
151
|
+
const binary = crous.dumps(data);
|
|
152
|
+
|
|
153
|
+
// Transform all objects during deserialization
|
|
154
|
+
const result = crous.loads(binary, {
|
|
155
|
+
objectHook: (obj) => {
|
|
156
|
+
// Add metadata to all objects
|
|
157
|
+
obj.__loaded = true;
|
|
158
|
+
return obj;
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
console.log(result.user.__loaded); // true
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Default Function
|
|
166
|
+
|
|
167
|
+
Handle unsupported types during serialization:
|
|
168
|
+
|
|
169
|
+
```javascript
|
|
170
|
+
const crous = require('crous');
|
|
171
|
+
|
|
172
|
+
const data = {
|
|
173
|
+
date: new Date(),
|
|
174
|
+
special: new CustomType()
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const binary = crous.dumps(data, {
|
|
178
|
+
default: (obj) => {
|
|
179
|
+
if (obj instanceof Date) {
|
|
180
|
+
return obj.toISOString();
|
|
181
|
+
}
|
|
182
|
+
if (obj instanceof CustomType) {
|
|
183
|
+
return obj.toString();
|
|
184
|
+
}
|
|
185
|
+
throw new Error(`Cannot serialize ${obj}`);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## API Reference
|
|
191
|
+
|
|
192
|
+
### Core Functions
|
|
193
|
+
|
|
194
|
+
#### `dumps(obj, options?)`
|
|
195
|
+
Serialize a JavaScript value to binary format.
|
|
196
|
+
|
|
197
|
+
**Parameters:**
|
|
198
|
+
- `obj` (any): The object to serialize
|
|
199
|
+
- `options` (object, optional):
|
|
200
|
+
- `default` (function): Handler for unsupported types
|
|
201
|
+
- `allowCustom` (boolean): Whether to allow custom serializers (default: true)
|
|
202
|
+
|
|
203
|
+
**Returns:** `Buffer` - Binary encoded data
|
|
204
|
+
|
|
205
|
+
**Throws:** `CrousEncodeError` if encoding fails
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
#### `loads(data, options?)`
|
|
210
|
+
Deserialize binary data to a JavaScript value.
|
|
211
|
+
|
|
212
|
+
**Parameters:**
|
|
213
|
+
- `data` (Buffer): Binary data to deserialize
|
|
214
|
+
- `options` (object, optional):
|
|
215
|
+
- `objectHook` (function): Post-process dictionaries during deserialization
|
|
216
|
+
|
|
217
|
+
**Returns:** Deserialized JavaScript value
|
|
218
|
+
|
|
219
|
+
**Throws:** `CrousDecodeError` if decoding fails
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
#### `dump(obj, filepath, options?)`
|
|
224
|
+
Serialize a JavaScript value and write to a file.
|
|
225
|
+
|
|
226
|
+
**Parameters:**
|
|
227
|
+
- `obj` (any): The object to serialize
|
|
228
|
+
- `filepath` (string | WritableStream): Path to output file or writable stream
|
|
229
|
+
- `options` (object, optional): Same as `dumps()`
|
|
230
|
+
|
|
231
|
+
**Throws:** `CrousEncodeError` if encoding fails
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
#### `load(filepath, options?)`
|
|
236
|
+
Deserialize a JavaScript value from a file.
|
|
237
|
+
|
|
238
|
+
**Parameters:**
|
|
239
|
+
- `filepath` (string | ReadableStream): Path to input file or readable stream
|
|
240
|
+
- `options` (object, optional): Same as `loads()`
|
|
241
|
+
|
|
242
|
+
**Returns:** Deserialized JavaScript value
|
|
243
|
+
|
|
244
|
+
**Throws:** `CrousDecodeError` if decoding fails
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
### Custom Serializers/Decoders
|
|
249
|
+
|
|
250
|
+
#### `registerSerializer(type, serializer)`
|
|
251
|
+
Register a custom serializer for a specific type.
|
|
252
|
+
|
|
253
|
+
**Parameters:**
|
|
254
|
+
- `type` (Function): The constructor/class to register a serializer for
|
|
255
|
+
- `serializer` (Function): Function to convert instances to serializable values
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
#### `unregisterSerializer(type)`
|
|
260
|
+
Unregister a custom serializer for a specific type.
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
#### `registerDecoder(tag, decoder)`
|
|
265
|
+
Register a custom decoder for a specific tag.
|
|
266
|
+
|
|
267
|
+
**Parameters:**
|
|
268
|
+
- `tag` (number): The tag identifier (integer)
|
|
269
|
+
- `decoder` (Function): Function to convert tagged values to objects
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
#### `unregisterDecoder(tag)`
|
|
274
|
+
Unregister a custom decoder for a specific tag.
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
### Classes
|
|
279
|
+
|
|
280
|
+
#### `CrousEncoder`
|
|
281
|
+
Encoder class for custom serialization control.
|
|
282
|
+
|
|
283
|
+
```javascript
|
|
284
|
+
const encoder = new crous.CrousEncoder({
|
|
285
|
+
default: (obj) => obj.toString(),
|
|
286
|
+
allowCustom: true
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
const binary = encoder.encode(data);
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
#### `CrousDecoder`
|
|
295
|
+
Decoder class for custom deserialization control.
|
|
296
|
+
|
|
297
|
+
```javascript
|
|
298
|
+
const decoder = new crous.CrousDecoder({
|
|
299
|
+
objectHook: (obj) => {
|
|
300
|
+
obj.__decoded = true;
|
|
301
|
+
return obj;
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
const data = decoder.decode(binary);
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
### Error Classes
|
|
311
|
+
|
|
312
|
+
- `CrousError`: Base error class for all Crous errors
|
|
313
|
+
- `CrousEncodeError`: Thrown during encoding/serialization
|
|
314
|
+
- `CrousDecodeError`: Thrown during decoding/deserialization
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
### Version Info
|
|
319
|
+
|
|
320
|
+
#### `versionInfo()`
|
|
321
|
+
Get version information about the Crous library.
|
|
322
|
+
|
|
323
|
+
**Returns:** Object with version information:
|
|
324
|
+
```javascript
|
|
325
|
+
{
|
|
326
|
+
major: 2,
|
|
327
|
+
minor: 0,
|
|
328
|
+
patch: 0,
|
|
329
|
+
string: '2.0.0',
|
|
330
|
+
tuple: [2, 0, 0],
|
|
331
|
+
hex: 0x020000
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
## Performance
|
|
336
|
+
|
|
337
|
+
Crous is designed for high performance with native C implementation:
|
|
338
|
+
|
|
339
|
+
- **Encoding**: ~2-5x faster than JSON.stringify()
|
|
340
|
+
- **Decoding**: ~2-4x faster than JSON.parse()
|
|
341
|
+
- **Size**: 40-60% smaller than JSON for typical data
|
|
342
|
+
|
|
343
|
+
## Testing
|
|
344
|
+
|
|
345
|
+
Run the test suite:
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
npm test
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
Or run individual tests:
|
|
352
|
+
|
|
353
|
+
```bash
|
|
354
|
+
node test/test_basic.js
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
## Building from Source
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
# Install dependencies
|
|
361
|
+
npm install
|
|
362
|
+
|
|
363
|
+
# Build native addon
|
|
364
|
+
npm run build
|
|
365
|
+
|
|
366
|
+
# Run tests
|
|
367
|
+
npm test
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
## Platform Support
|
|
371
|
+
|
|
372
|
+
- **Linux**: x64, ARM64
|
|
373
|
+
- **macOS**: x64, ARM64 (Apple Silicon)
|
|
374
|
+
- **Windows**: x64
|
|
375
|
+
|
|
376
|
+
## License
|
|
377
|
+
|
|
378
|
+
MIT License - see [LICENSE](../LICENSE) file for details.
|
|
379
|
+
|
|
380
|
+
## Author
|
|
381
|
+
|
|
382
|
+
Pawan Kumar <aegis.invincible@gmail.com>
|
|
383
|
+
|
|
384
|
+
## Links
|
|
385
|
+
|
|
386
|
+
- GitHub: https://github.com/axiomchronicles/crous
|
|
387
|
+
- Issues: https://github.com/axiomchronicles/crous/issues
|
|
388
|
+
|
|
389
|
+
## Related Projects
|
|
390
|
+
|
|
391
|
+
- **Python Crous**: High-performance binary serialization for Python
|
|
392
|
+
- **FLUX**: Human-readable serialization format (part of Crous ecosystem)
|
|
393
|
+
|
|
394
|
+
## Contributing
|
|
395
|
+
|
|
396
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
397
|
+
|
|
398
|
+
1. Fork the repository
|
|
399
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
400
|
+
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
401
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
402
|
+
5. Open a Pull Request
|
|
403
|
+
|
|
404
|
+
## Changelog
|
|
405
|
+
|
|
406
|
+
### Version 2.0.0
|
|
407
|
+
- Initial Node.js release
|
|
408
|
+
- Full N-API implementation
|
|
409
|
+
- TypeScript definitions
|
|
410
|
+
- Custom serializers/decoders
|
|
411
|
+
- Set support
|
|
412
|
+
- File I/O support
|
|
413
|
+
- Comprehensive test suite
|
package/binding.gyp
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"targets": [
|
|
3
|
+
{
|
|
4
|
+
"target_name": "crous",
|
|
5
|
+
"sources": [
|
|
6
|
+
"src/crous_node.c",
|
|
7
|
+
"../crous/src/c/core/errors.c",
|
|
8
|
+
"../crous/src/c/core/arena.c",
|
|
9
|
+
"../crous/src/c/core/value.c",
|
|
10
|
+
"../crous/src/c/core/version.c",
|
|
11
|
+
"../crous/src/c/utils/token.c",
|
|
12
|
+
"../crous/src/c/lexer/lexer.c",
|
|
13
|
+
"../crous/src/c/parser/parser.c",
|
|
14
|
+
"../crous/src/c/binary/binary.c",
|
|
15
|
+
"../crous/src/c/flux/flux_lexer.c",
|
|
16
|
+
"../crous/src/c/flux/flux_parser.c",
|
|
17
|
+
"../crous/src/c/flux/flux_serializer.c"
|
|
18
|
+
],
|
|
19
|
+
"include_dirs": [
|
|
20
|
+
"../crous/include"
|
|
21
|
+
],
|
|
22
|
+
"cflags": [
|
|
23
|
+
"-O3",
|
|
24
|
+
"-Wall",
|
|
25
|
+
"-Wextra",
|
|
26
|
+
"-std=c99"
|
|
27
|
+
],
|
|
28
|
+
"cflags_cc": [
|
|
29
|
+
"-O3",
|
|
30
|
+
"-Wall",
|
|
31
|
+
"-Wextra"
|
|
32
|
+
],
|
|
33
|
+
"xcode_settings": {
|
|
34
|
+
"GCC_OPTIMIZATION_LEVEL": "3",
|
|
35
|
+
"WARNING_CFLAGS": [
|
|
36
|
+
"-Wall",
|
|
37
|
+
"-Wextra"
|
|
38
|
+
],
|
|
39
|
+
"OTHER_CFLAGS": [
|
|
40
|
+
"-std=c99"
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"msvs_settings": {
|
|
44
|
+
"VCCLCompilerTool": {
|
|
45
|
+
"Optimization": 3
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|