[](https://www.npmjs.com/package/@mono424/cdr-ts) [

 


A robust TypeScript library for parsing data encoded in Custom Data Representation (CDR) format. This parser is schema-driven, allowing for precise and type-safe decoding of binary data, typically received as a base64 encoded string.
- Parses CDR (Common Data Representation) data streams.
- Supports a variety of primitive types:
- Integers: int8, int16, int32, int64 (parsed as number)
- Unsigned Integers: uint8, uint16, uint32 (parsed as number), uint64 (parsed as number or bigint)
- Floating-point numbers: float32, float64 (currently float32 is fully implemented and tested for parsing)
- string (UTF-8, null-terminated)
- string_bytes (sequence of bytes, null-terminated, parsed as Uint8Array)
- Supports composite types:
- sequence: Ordered list of elements of the same type (parsed as an Array).
- dictionary: A collection of key-value pairs, where keys are strings and values can be any CDR type (parsed as an object). Fields are parsed in the order of their index property.
- Type-safe parsing: The structure and types of the parsed payload are determined by the provided schema, leveraging TypeScript's type system (MapSchema utility type).
- Handles byte alignment as per CDR specification.
- Parses the standard CDR header (representation identifier and options).
- Configurable maximum sizes for sequences and strings to prevent excessive memory allocation.
- Accepts base64 encoded strings as input for CDR data.
- Includes utility for creating and managing byte buffers.
This project uses pnpm as its package manager but you can use whatever package manager you like.
``bash`
pnpm install @mono424/cdr-ts # Replace with your actual package name on npm
`bash`
npm install @mono424/cdr-ts # Replace with your actual package name on npm
`bash`
yarn install @mono424/cdr-ts # Replace with your actual package name on npm
Or, if you're working with the source code:
`bash`
git clone https://github.com/mono424/cdr-ts.git
cd your-repo
pnpm install
To parse CDR data, you first need to define a schema that describes the structure of your data. Then, you can use the parseCDRString or parseCDRBytes functions.
The schema defines the fields, their order (via index), and their types.
`typescript
import { CDRSchema, MapSchema } from "@mono424/cdr-ts";
type MyDataType = CDRSchemaDictionaryValue<{
stamp_s: CDRSchemaDictionaryField
stamp_ns: CDRSchemaDictionaryField
frame_id: CDRSchemaDictionaryField
data: CDRSchemaDictionaryField
}>;
// Define the schema for your data structure
const myDataSchema: MyDataType = {
type: "dictionary",
items: {
stamp_s: { index: 0, value: { type: "int", len: 32 } },
stamp_ns: { index: 1, value: { type: "uint", len: 32, format: "number" } },
frame_id: { index: 2, value: { type: "string" } },
data: {
index: 3,
value: {
type: "sequence",
itemSchema: { type: "uint", len: 8, format: "number" },
},
},
},
};
`
Provide the base64 encoded CDR string and your schema to parseCDRString.
`typescript
import { parseCDRString, ParserOptions } from "@mono424/cdr-ts"; // or './src/parser' if local
const base64Data =
"AAEAAAABAAAAAQAAAAZm9vYmFyAAAAAAAAAAAAPkAAABAAAAABAAAADHRlc3RfdGFnXzAxAAAA"; // Example base64 string
const options: ParserOptions = {
maxStringSize: 1024, // Default: 1024
maxSequenceSize: 512, // Default: 1024
};
try {
const { header, payload } = parseCDRString(
base64Data,
cameraPacketSchema,
options,
);
console.log("Parsed CDR Header:", header);
console.log("Parsed Payload:", payload);
// Accessing fields (types are inferred from the schema)
console.log("Timestamp (seconds):", payload.stamp_s); // number
console.log("Timestamp (nanoseconds):", payload.stamp_ns); // number
console.log("Frame ID:", payload.frame_id); // string
console.log("Data Length:", payload.data.length); // number (length of Uint8Array sequence)
// payload.data is Array
// Example specific assertions from tests:
// expect(parsed.payload.stamp_s).toBe(1747238941)
// expect(parsed.payload.stamp_ns).toBe(291125000)
// expect(parsed.payload.frame_id).toBe("62")
// expect(parsed.payload.data).toHaveLength(5456)
} catch (error) {
console.error("Error parsing CDR data:", error);
}
`
Think of a schema as the magical map πΊοΈ that tells our parser how to read your CDR data. It's like giving instructions to a super-smart robot π€: "This part is a number, that part is some text, and over here is a list of things\!"
By defining a schema, you make sure the parser understands your data perfectly and gives you back everything in a neat, typed, and predictable way. Let's dive into how you can create these blueprints\!
First, a few key terms you'll see:
- CDRSchema: This is the big umbrella βοΈ for any type of CDR data structure you can define.CDRType
- : Represents any specific CDR type β whether it's a simple number or a complex structure.CDRPrimitiveTypes
- : These are your basic data types, like numbers π’ and text ζεε.CDRLength
- : For our number-loving types, this specifies how big they are in bits (like 8, 16, 32, or 64 bit).
These are the fundamental data types:
- Integer (CDRSchemaIntValue): For whole numbers! β€
- type: "int"len: CDRLength
- (e.g., 8, 16, 32, 64){ type: "int", len: 32 }
- Example: (a standard 32-bit integer)
- Unsigned Integer (CDRSchemaUintValue): For whole numbers that are always positive! β
- type: "uint"len: CDRLength
- format: "bigint" | "number"
- (Use "bigint" for those really huge uint64 numbers that need extra space!){ type: "uint", len: 32, format: "number" }
- Example (regular number): { type: "uint", len: 64, format: "bigint" }
- Example (big boi number):
- Float (CDRSchemaFloatValue): For numbers with decimal points.
- type: "float"len: CDRLength
- (Usually 32 for single-precision or 64 for double-precision. Our parser is currently best friends with len: 32 for Float32!){ type: "float", len: 32 }
- Example:
- Boolean (CDRSchemaBooleanValue): For true/false values! β
β
- type: "boolean"{ type: "boolean" }
- Example:
- Enum (CDRSchemaEnumValue): For a value that can be one of a fixed set of named constants! π
- type: "enum"enum: { ... }
- (An object mapping names to values)`
- Example:
typescript`
{ type: "enum", enum: { RED: 0, GREEN: 1, BLUE: 2 } }
// Accepts only 0, 1, or 2 (maps to RED, GREEN, BLUE)
- String (CDRSchemaStringValue): For good old text! π
- type: "string" (Reads UTF-8 text that ends with a special 'null' character){ type: "string" }
- Example:
- String Bytes (CDRSchemaStringBytesValue): For when your "string" is more like a sequence of raw bytes.
- type: "string_bytes" (Also ends with a 'null' character, gives you a Uint8Array){ type: "string_bytes" }
- Example:
These types let you group primitive types (or even other composite types!) together:
- Sequence (CDRSchemaSequenceValue)
- type: "sequence"itemSchema: K
- (This is where you define the schema for each item in the list){ type: "sequence", itemSchema: { type: "uint", len: 8, format: "number" } }
- Example (a list of tiny unsigned numbers):
- Fixed Size Array: A sequence with a fixed number of elements! π
- Use the size property on a sequence schema.`
- Example (an array of exactly 4 booleans):
typescript`
{ type: "sequence", itemSchema: { type: "boolean" }, size: 4 }
// Always parses exactly 4 booleans
- Dictionary (CDRSchemaDictionaryValue)
- type: "dictionary"items: K
- (An object where each key is a field name, and its value describes that field)items
- Inside , each field is a CDRSchemaDictionaryField:index: number
- (Super important! Tells the parser the order to read fields, starting from 0 π₯π₯π₯)value: T
- (The schema for this specific field's value)`
- Example (a little dictionary with an ID and a name):
typescript`
{
type: "dictionary",
items: {
id: { index: 0, value: { type: "int", len: 32 } }, // First field!
name: { index: 1, value: { type: "string" } } // Second field!
}
}
Here's a really cool part\! When you give parseCDRString or parseCDRBytes your carefully crafted schema, it doesn't just parse the data; it also knows the _exact TypeScript type_ of the payload you'll get back\! π§ββοΈ
This is thanks to a helper type called MapSchema.
For instance:
- If your schema says { type: "int", len: 32 }, MapSchema knows the output is a number.{ type: "string" }
- If it's , you'll get a string.{ type: "sequence", itemSchema: { type: "int", len: 16 } }
- A will give you a number[] (an array of numbers).
- And a dictionary schema? You guessed it\! An object with perfectly typed properties.
The project uses Jest for testing. Test files are located alongside the source files (e.g., parser.test.ts).
To run tests:
`bash`
pnpm test
To build the project (compile TypeScript to JavaScript):
`bash``
pnpm build
Contributions are welcome! Please feel free to submit issues and pull requests.
For major changes, please open an issue first to discuss what you would like to change.
Make sure to update tests as appropriate.
This project is licensed under the MIT License - see the LICENSE.md file for details (if you have one, otherwise state it here).
---
Happy Parsing! π