npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@xobj/core

v1.3.2

Published

Decoding and encoding JavaScript/TypeScript/JSON objects to binary format.

Downloads

15

Readme

@xobj/core

Build npm Downloads Coverage

Decoding and encoding JavaScript / TypeScript objects to compact binary format.

Available basic types:

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

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