@xobj/core
v1.3.2
Published
Decoding and encoding JavaScript/TypeScript/JSON objects to binary format.
Downloads
42
Maintainers
Readme
@xobj/core
Decoding and encoding JavaScript / TypeScript objects to compact binary format.
Available basic types:
null
examplesundefined
examplesNumber
examplesBigInt
examplesBoolean
examplesString
examplesSymbol
examples via replacerObject
examplesArray
examplesFunction
examples via replacerMap
examplesSet
examplesArrayBuffer
examplesTypedArray
: examplesUint8ClampedArray
Uint8Array
Uint16Array
Uint32Array
Int8Array
Int16Array
Int32Array
Float32Array
Float64Array
DataView
RegExp
examplesDate
examples
For all basic types used optimization for data minification.
Recursive objects links are also supported.
You can see more examples in tests.
Also you can use custom types and replacers.
Install
yarn add @xobj/core
Usage
Basic usage with default types
// import library methods
import { encode, decode } from '@xobj/core';
interface User {
name: string,
age: number,
gender?: 'male' | 'female',
children?: User[],
}
// some kind of object
const source: User = {
name: 'John Doe',
age: 33,
gender: 'male',
children: [
{ name: 'Jane', age: 12, gender: 'male' },
{ name: 'Jack', age: 6 },
],
};
// encode object to binary data
const buffer: ArrayBuffer = encode(source);
// decode binary data to object
const target: User = decode(buffer);
// use object
console.log(target.name);// John Doe
console.log(target!.children![0].age);// 12
Custom types usage
import { encode, decode, EncodeContext, DecodeContext, ValueType } from '@xobj/core';
class Point {
constructor(public x: number, public y: number) {
}
}
enum CustomType { POINT = 0 }
const source = {
color: 0xff00ff,
points: [
new Point(1, 2),
new Point(3, 4),
new Point(5, 6),
],
};
// encode
function customDetect(value: any): ValueType {
if (value instanceof Point) {
return ValueType.CUSTOM;
}
return ValueType.UNKNOWN;
}
function customEncode(value: any, context: EncodeContext) {
const { writer } = context;
if (value instanceof Point) {
writer.writeUint8(CustomType.POINT);
writer.writeUint8(value.x);
writer.writeUint8(value.y);
} else {
throw `Unknown custom type: ${value}`;
}
}
const buffer = encode(source, { customDetect, customEncode });
// decode
function customDecode(context: DecodeContext): any {
const { reader } = context;
const type = reader.readUint8() as CustomType;
switch (type) {
case CustomType.POINT:
return new Point(
reader.readUint8(),
reader.readUint8()
);
default:
throw `Unknown custom type: ${type}`;
}
}
const target = decode(buffer, { customDecode });
// use object
console.log(target.points[0].x) // 1
console.log(target.points[0].y) // 2
See more about BufferWriter and BufferReader
Encode options
encode(value, {
bufferSize, // buffer starter size, by default is 1024 bytes
customDetect, // function for custom type detection
customEncode, // function for custom type encoding
floatQuality, // encoding float quality : 'double' | 'single' | number (default is 'double')
replacer, // replacer method or table: (value: any) => any | Map<any,any> | map entries
});
The floatQuality
parameter allows you to select the encoding type for floating point numbers.
Encoding all float numbers into float64
format (8 bytes)
encode(value); // by default float quality is 'double'
Encoding all float numbers into float32
format (4 bytes)
encode(value, { floatQuality: 'single' });
Encoding all float numbers into intVar
format (1-9+ bytes).
In this case floatQuality
is number (divider / multiplier). For decoding it is used as multiplier, and for decoding it is used as divider. For example:
const buffer = encode({ x: 123.456, y: -3456.789 }, { floatQuality: 100 });
// 'x' and 'y' will be transformed to 'integer' and encoded as 'intVar'
// floor(123.456 * 100) => 12345 => write intVar to 2 bytes
// floor(-3456.789 * 100) => -345678 => write intVar to 3 bytes
const value = decode(buffer);
// 'x' and 'y' will be decoded as 'intVar' and transformed to 'float'
// read intVar from 2 bytes => 12345 / 100 => 123.45
// read intVar from 3 bytes => -345678 / 100 => -3456.78
Decode options
decode(value, {
customDecode, // function for custom type decoding
replacer, // replacer method or table: (value: any) => any | Map<any,any> | map entries
});
You can see more examples in tests.
Check out integration samples.
Replacers
You can use 3 replacer types
Via function:
const id = Symbol('id');
const source = {
x: 1,
update(value: number) {
this.x += value;
},
id,
};
const buffer = encode(source, {
replacer: (value) => {
if (value === id) return 'id-0';
if (value === source.update) return 345678;
return value;
},
});
const target = decode(buffer, {
replacer: (value) => {
if (value === 'id-0') return id;
if (value === 345678) return source.update;
return value;
},
});
Via Map
table:
const id = Symbol('id');
const source = {
x: 1,
update(value: number) {
this.x += value;
},
id,
};
const buffer = encode(source, {
replacer: new Map<any, any>([
[id, 'id-0'],
[source.update, 345678],
]),
});
const target = decode(buffer, {
replacer: new Map<any, any>([
['id-0', id],
[345678, source.update],
]),
});
Via map entries table:
const id = Symbol('id');
const source = {
x: 1,
update(value: number) {
this.x += value;
},
id,
};
const buffer = encode(source, {
replacer: [
[id, 'id-0'],
[source.update, 345678],
],
});
const target = decode(buffer, {
replacer: [
['id-0', id],
[345678, source.update],
],
});
Samples
- Rollup bundle sample project / build
- Rollup with external module project / build
- Simple JS lib sample project / build
- NodeJS sample project
File format (xobj)
Coming soon
Development
Install all dependencies
yarn
Build project
yarn build
Test project
yarn test
Generate coverage report
yarn coverage
Check code quality
yarn lint