Package Exports
- @openai-hce/decode
Readme
@openai-hce/decode
Decoder for Hierarchical Columnar Encoding (HCE). Converts HCE strings generated by @openai-hce/encode back into JSON objects with full fidelity.
Installation
npm install @openai-hce/decodepnpm add @openai-hce/decode
yarn add @openai-hce/decodeQuick start
import { HCEDecoder } from '@openai-hce/decode';
const hce = `users(user)[2]:
user(id,name,role)[2]:
1,Alice,admin|2,Bob,user`;
const decoder = new HCEDecoder();
const data = decoder.decode(hce);
console.log(data.users[0].name); // "Alice"Highlights
- Lossless round-trip with the encoder package.
- Automatic type inference (numbers, booleans, null, arrays).
- Supports nested objects via dotted paths.
- Matches any delimiter configuration used during encoding.
- Lightweight TypeScript implementation with zero dependencies.
API overview
new HCEDecoder(options?: HCEDecodeOptions)
interface HCEDecodeOptions {
fieldDelimiter?: string; // default: ','
recordDelimiter?: string; // default: '|'
nestedDelimiter?: string; // default: ';'
missingValue?: string; // default: ' '
typeField?: string; // default: 'type'
}decoder.decode(hce: string)
- Accepts an HCE string.
- Returns an object where each key is a root group and each value is an array of reconstructed JSON objects.
const result = decoder.decode(hce);
const users = result.users; // arrayExamples
Default decoding
const hce = `entities(user,org)[3]:
user(id,name,email)[2]:
1,Alice,alice@example.com|2,Bob,bob@example.com
org(id,name,industry)[1]:
10,Acme,Tech`;
const { entities } = new HCEDecoder().decode(hce);Result:
[
{ "type": "user", "id": 1, "name": "Alice", "email": "alice@example.com" },
{ "type": "user", "id": 2, "name": "Bob", "email": "bob@example.com" },
{ "type": "org", "id": 10, "name": "Acme", "industry": "Tech" }
]Restoring secondary grouping
const grouped = `users(user by role)[3]:
admin(id,name)[2]:
1,Alice|2,Bob
guest(id,name)[1]:
3,Carol`;
const { users } = new HCEDecoder().decode(grouped);Result:
[
{ "type": "user", "role": "admin", "id": 1, "name": "Alice" },
{ "type": "user", "role": "admin", "id": 2, "name": "Bob" },
{ "type": "user", "role": "guest", "id": 3, "name": "Carol" }
]Nested objects and arrays
const nested = `posts(post)[2]:
post(id,title,.author,.tags)[2]:
1,'Hello World'|2,'Encoder Tips'
.author(name,team)[2]:
Alice,Platform|Bob,SDK
.tags: intro;hce|guide`;
const { posts } = new HCEDecoder().decode(nested);Result:
[
{
"type": "post",
"id": 1,
"title": "Hello World",
"author": { "name": "Alice", "team": "Platform" },
"tags": ["intro", "hce"]
},
{
"type": "post",
"id": 2,
"title": "Encoder Tips",
"author": { "name": "Bob", "team": "SDK" },
"tags": ["guide"]
}
]Type-only grouping is implicit
const hce = `products(product)[2]:
product(name,price)[2]:
Laptop,999|Phone,599`;
const { products } = new HCEDecoder().decode(hce);Result:
[
{ "type": "product", "name": "Laptop", "price": 999 },
{ "type": "product", "name": "Phone", "price": 599 }
]Secondary grouping reconstruction
const grouped = `products(product by category)[4]:
Electronics(name,price)[2]:
Laptop,999|Phone,599
Books(name,price)[2]:
JS Guide,39|TS Handbook,45`;
const { products } = new HCEDecoder().decode(grouped);Result:
[
{ "type": "product", "category": "Electronics", "name": "Laptop", "price": 999 },
{ "type": "product", "category": "Electronics", "name": "Phone", "price": 599 },
{ "type": "product", "category": "Books", "name": "JS Guide", "price": 39 },
{ "type": "product", "category": "Books", "name": "TS Handbook", "price": 45 }
]Uniform schema stays merged
const hce = `users(user)[3]:
user(age,name,role)[3]:
30,Alice,admin|25,Bob,admin|35,Charlie,user`;
const { users } = new HCEDecoder().decode(hce);Result:
[
{ "type": "user", "age": 30, "name": "Alice", "role": "admin" },
{ "type": "user", "age": 25, "name": "Bob", "role": "admin" },
{ "type": "user", "age": 35, "name": "Charlie", "role": "user" }
]Multi-type collections
const hce = `items(book,product,service)[3]:
book(pages,title)[1]:
200,HCE Guide
product(name,price)[1]:
Laptop,999
service(name,rate)[1]:
Consulting,150`;
const { items } = new HCEDecoder().decode(hce);The type-only header lists every type value, which the decoder maps back to type fields.
Result:
[
{ "type": "book", "pages": 200, "title": "HCE Guide" },
{ "type": "product", "name": "Laptop", "price": 999 },
{ "type": "service", "name": "Consulting", "rate": 150 }
]Edge case: single secondary value
const hce = `users(user)[2]:
user(name,role)[2]:
Alice,admin|Bob,admin`;
const { users } = new HCEDecoder().decode(hce);Result:
[
{ "type": "user", "name": "Alice", "role": "admin" },
{ "type": "user", "name": "Bob", "role": "admin" }
]Edge case: no type column provided
const hce = `products(name,price)[2]:
Laptop,999|Phone,599`;
const { products } = new HCEDecoder().decode(hce);Result:
[
{ "name": "Laptop", "price": 999 },
{ "name": "Phone", "price": 599 }
]Custom delimiters
const hce = `rows(row)[1]:
row(id value)[1]:
1 A`;
const decoder = new HCEDecoder({
fieldDelimiter: '\t',
recordDelimiter: '\n',
nestedDelimiter: ',',
});
const { rows } = decoder.decode(hce);Result:
[
{ "type": "row", "id": 1, "value": "A" }
]Type inference reference
| HCE token | Parsed JSON value |
|---|---|
123 |
123 (number) |
45.67 |
45.67 (number) |
true / false |
boolean |
null |
null |
'quoted text' |
"quoted text" |
unquoted |
"unquoted" (string) |
1;2;3 |
[1, 2, 3] (array) |
| (space) | omitted / undefined |
License
MIT © OpenAI HCE Team