Skip to content

bepalo/rjson

Repository files navigation

πŸ† @bepalo/rjson

hero

npm version CI tests license

Vitest

A compact, URL-friendly serialization format that is smaller than JSON while remaining human-readable and fast to parse.

RJSON (Remote JavaScript Object Notation) is a specification and implementation inspired by RISON and it was originally designed for better frontend-to-backend communication via search parameters.

🎯 Why RJSON?

JSON is an excellent interchange format, but:

  • It is not as compressed as it can be
  • It is not url friendly
  • It cannot represent several JavaScript runtime values: undefined NaN Infinity -Infinity -0

RJSON preserves these values while remaining compact, human-readable, and URL-friendly.

const value = {
  active: true,
  deletedAt: undefined,
  score: NaN,
  "limit.upper": Infinity,
  "limit.lower": -Infinity,
};

const text = RJSON.stringify(value);

Output:

(active:T,deletedAt:U,score:X,limit.upper:I,limit.lower:-I)

✨ Features

  • ⚑ Fast parser with direct character scanning (recursive descent parsing).
  • πŸ“¦ Smaller than JSON for many real-world payloads
  • 🌐 URL-friendly syntax
  • 🧩 Supports objects, arrays, strings, numbers, booleans
  • πŸ” Supports null, undefined, -0, NaN, Infinity, -Infinity
  • πŸ—œοΈ Built-in mapped-array compression ~T(id,title,body)~ -> { id:true, title:true, body:true }
  • πŸ”„ Value-preserving roundtrip. RJSON.parse(RJSON.stringify(value)) preserves JavaScript value semantics.
  • πŸ“ Tagged template support
  • β˜‘οΈ Whitespace support (starting from v2.1.11)
  • πŸš€ Runtime agnostic (Node.js, Bun, Deno, Browser)
  • 🟦 TypeScript ready
  • πŸ”§ Zero dependencies

πŸ“‘ Table of Contents

πŸš€ Get Started

πŸ“₯ Installation

bun

bun add @bepalo/rjson

npm

npm install @bepalo/rjson

pnpm

pnpm add @bepalo/rjson

deno

import { RJSON } from "jsr:@bepalo/rjson";

πŸ“¦ Quick Start

Parse RJSON

import { RJSON } from "@bepalo/rjson";

const user = RJSON.parse(
  "(name:'Natnael',age:28,active:T,tasks:_('push','deploy','sleep')_)",
);

console.log(user);

Output:

{
  name: "Natnael",
  age: 28,
  active: true,
  tasks: [ "push", "deploy", "sleep" ],
}

Stringify Objects

import { RJSON } from "@bepalo/rjson";

const text = RJSON.stringify({
  name: "Natnael",
  age: 28,
  active: true,
});

console.log(text);

Output:

(name:'Natnael',age:28,active:T)

Stringify arrays

import { RJSON } from "@bepalo/rjson";

const text = RJSON.stringify([1, 3.1415, null, undefined, true, "hello"]);

console.log(text);

Output:

_(1,3.1415,N,,T,'hello')_

Stringify mapped-arrays

import { RJSON } from "@bepalo/rjson";

const text = RJSON.stringifyMappedArray(true, ["id", "title", "body"]);

console.log(text);

Output:

~T(id,title,body)~

Tagged Template Helper

import { rjson } from "@bepalo/rjson";

const name = "Natnael";
const age = 28;

const user = rjson`(name:'${name}',age:${age},active:T)`;

console.log(user);

Output:

{
  name: "Natnael",
  age: 28,
  active: true,
}

πŸ“š Syntax Overview

Type RJSON JSON
Object (name:'John') {"name":"John"}
Array _(1,2,3)_ [1,2,3]
Mapped Array ~T(admin,user)~ {"admin":true,"user":true}
String 'hello' "hello" `hello` "hello"
Number 123 123
Boolean T / F true / false
Null N null
Undefined U Not supported
NaN X Not Supported
Infinity I Not Supported
-Infinity -I Not Supported
-0 -0 Not Supported

πŸ“š Core Types

Objects

(name:'John',age:30)

Produces:

{
  name: "John",
  age: 30
}

Arrays

_(1,2,3,4)_

Produces:

[1, 2, 3, 4];

Nested Structures

(user:(name:'John',age:30),active:T)

Produces:

{
  user: {
    name: "John",
    age: 30
  },
  active: true
}

Strings

RJSON supports three string delimiters: ' " `

'hello'
"hello"
`hello`

The serializer automatically chooses the delimiter that requires the least escaping.

RJSON.stringify(`'"hello"'`);

Output:

`'"hello"'`

This keeps serialized output compact and readable.

Numbers

Supported formats:

123
-123
+123
12.5
1e10
1e-10
-0
X -> NaN
I -> Infinity
-I -> -Infinity

Examples:

age:28
price:19.99
distance:1.5e6

Booleans

_( T, F )_

Produces:

[true, false];

Null

N

Produces:

null;

Undefined

(name:U)

Produces:

{
  name: undefined;
}

Empty values are also treated as undefined:

(name:,array:_(,)_,mapped:~(a)~,empty:(),end:)

Produces:

{
  name: undefined,
  array: [ undefined ],
  mapped: {
    a: undefined,
  },
  empty: {},
  end: undefined,
}

πŸ—œοΈ Mapped Arrays

Mapped arrays compress repeated values.

Instead of doing:

{
  admin: true,
  editor: true,
  user: true
}

Use:

~T(admin,editor,user)~

Produces:

{
  admin: true,
  editor: true,
  user: true
}

The value can be any valid RJSON type. However, to have an object as value its start token ( has to be escaped.

NOTE: Allowed whitespace positions. Also whitespaces are not required.

~ \(roles:_('admin','user')_) (create,update,delete)~

~ F (create,update,delete)~

~ ~ F (admin,user)~ (create,update,delete)~

πŸ”§ API Reference

parseRJSON

Parses RJSON from string.

const value = parseRJSON("(name:'John',active:T)");

stringifyRJSON

Serializes JavaScript values to RJSON format.

const text = stringifyRJSON({
  name: "John",
  active: true,
});

Result:

(name:'John',active:T)

stringifyRJSONMappedArray

Creates mapped-array expressions.

stringifyRJSONMappedArray(true, ["read", "write", "delete"]);

Result:

~T(read,write,delete)~

rjson

Tagged-template parser.

const data = rjson`
(name:'John')
`;

πŸ”„ Migration Guide

Upgrading from v1.0.10 to v2.1.11

RJSON v2.x introduces a fully optimized grammar layout that treats explicit null and implicit undefined as independent, native values. If you are migrating an existing application from a v1.x runtime, use the matrix below to audit changes to your network transport footprints and api surface.

Serialization Footprint Matrix

Value / API Reference Target v1.0.10 Target v2.1.11 Notes / Semantic Shifts
null "" "N" Now serialized explicitly to prevent collision with missing properties.
undefined "U" "" | "U" Evaluates to an empty slot inside collection layouts; returns "U" if standalone.
[1, undefined, 3] _(1,U,3)_ _(1,,3)_ Array holes leverage highly efficient conditional trailing comma notation.
[,] [,,] _()_ _(,)_ _(,)_ _(,,)_ Empty array elements are now handled properly and treated as undefined.
NaN null X Native support added for IEEE 754 special values.
Infinity null I Native positive infinity tracking.
-Infinity null -I Native negative infinity tracking.
-0 0 -0 Sign-bit fidelity preserved during serialization loops.
stringifyRJSONString stringifyRJSONString stringifyRJSONText Utility renamed to clear naming collision with global String.
RJSON.stringifyString RJSON.stringifyString RJSON.stringifyText Namespace reference updated to point to the text subsystem encoder.

πŸ“„ License

MIT

πŸ•ŠοΈ Thanks and Enjoy

If you find RJSON useful, please consider starring the repository and sharing it with others.

πŸ’– Be a Sponsor

Support development and future improvements.

About

A compact, URL-friendly serialization format that is smaller than JSON while remaining human-readable and fast to parse.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors