A monadic LL(infinity) parser combinator library
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Specialized parsers for binary data formats, buffers, and bit-level operations. These parsers work with Node.js Buffer objects and provide precise control over binary data interpretation.
Fundamental parsers for binary data structures.
/**
* Parse a specific byte value
* @param {number} b - Byte value to match (0-255)
* @returns {Parser} Parser that matches the specific byte
*/
Parsimmon.Binary.byte(b);
/**
* Parse a buffer of specified length
* @param {number} length - Number of bytes to read
* @returns {Parser} Parser that returns Buffer of specified length
*/
Parsimmon.Binary.buffer(length);
/**
* Parse an encoded string of specified length
* @param {string} encoding - Character encoding (utf8, ascii, etc.)
* @param {number} length - Number of bytes to read
* @returns {Parser} Parser that returns decoded string
*/
Parsimmon.Binary.encodedString(encoding, length);Usage Examples:
// Parse specific bytes
const magicNumber = Parsimmon.Binary.byte(0x89)
.then(Parsimmon.Binary.byte(0x50))
.then(Parsimmon.Binary.byte(0x4E))
.then(Parsimmon.Binary.byte(0x47));
// Parse PNG signature
const pngSig = Parsimmon.seq(
Parsimmon.Binary.byte(0x89),
Parsimmon.Binary.byte(0x50),
Parsimmon.Binary.byte(0x4E),
Parsimmon.Binary.byte(0x47),
Parsimmon.Binary.byte(0x0D),
Parsimmon.Binary.byte(0x0A),
Parsimmon.Binary.byte(0x1A),
Parsimmon.Binary.byte(0x0A)
);
// Parse raw buffer data
const header = Parsimmon.Binary.buffer(16);
const data = header.parse(someBuffer);
// Parse encoded strings
const utf8String = Parsimmon.Binary.encodedString("utf8", 10);
const asciiString = Parsimmon.Binary.encodedString("ascii", 20);Parsers for various integer formats with different endianness.
/**
* Parse unsigned big-endian integer
* @param {number} length - Byte length (1-6)
* @returns {Parser} Parser that returns unsigned integer
*/
Parsimmon.Binary.uintBE(length);
/**
* Parse unsigned little-endian integer
* @param {number} length - Byte length (1-6)
* @returns {Parser} Parser that returns unsigned integer
*/
Parsimmon.Binary.uintLE(length);
/**
* Parse signed big-endian integer
* @param {number} length - Byte length (1-6)
* @returns {Parser} Parser that returns signed integer
*/
Parsimmon.Binary.intBE(length);
/**
* Parse signed little-endian integer
* @param {number} length - Byte length (1-6)
* @returns {Parser} Parser that returns signed integer
*/
Parsimmon.Binary.intLE(length);Pre-defined Integer Parsers:
// Unsigned big-endian
Parsimmon.Binary.uint8BE; // 1-byte unsigned
Parsimmon.Binary.uint16BE; // 2-byte unsigned
Parsimmon.Binary.uint32BE; // 4-byte unsigned
// Unsigned little-endian
Parsimmon.Binary.uint8LE; // 1-byte unsigned
Parsimmon.Binary.uint16LE; // 2-byte unsigned
Parsimmon.Binary.uint32LE; // 4-byte unsigned
// Signed big-endian
Parsimmon.Binary.int8BE; // 1-byte signed
Parsimmon.Binary.int16BE; // 2-byte signed
Parsimmon.Binary.int32BE; // 4-byte signed
// Signed little-endian
Parsimmon.Binary.int8LE; // 1-byte signed
Parsimmon.Binary.int16LE; // 2-byte signed
Parsimmon.Binary.int32LE; // 4-byte signedUsage Examples:
// Parse various integer sizes
const header = Parsimmon.seqObj(
["magic", Parsimmon.Binary.uint32BE],
["version", Parsimmon.Binary.uint16BE],
["flags", Parsimmon.Binary.uint8BE],
["count", Parsimmon.Binary.uint32LE]
);
// Parse file header with mixed endianness
const fileHeader = Parsimmon.seqMap(
Parsimmon.Binary.uint32BE, // File size (big-endian)
Parsimmon.Binary.uint16LE, // Format version (little-endian)
Parsimmon.Binary.uint16BE, // Flags (big-endian)
(size, version, flags) => ({ size, version, flags })
);
// Parse signed values
const coordinate = Parsimmon.seqMap(
Parsimmon.Binary.int16BE,
Parsimmon.Binary.int16BE,
(x, y) => ({ x, y })
);Parsers for IEEE 754 floating point numbers.
/**
* Parse 32-bit big-endian float
* @returns {Parser} Parser that returns 32-bit float
*/
Parsimmon.Binary.floatBE();
/**
* Parse 32-bit little-endian float
* @returns {Parser} Parser that returns 32-bit float
*/
Parsimmon.Binary.floatLE();
/**
* Parse 64-bit big-endian double
* @returns {Parser} Parser that returns 64-bit double
*/
Parsimmon.Binary.doubleBE();
/**
* Parse 64-bit little-endian double
* @returns {Parser} Parser that returns 64-bit double
*/
Parsimmon.Binary.doubleLE();Usage Examples:
// Parse 3D coordinates as floats
const vertex = Parsimmon.seqMap(
Parsimmon.Binary.floatLE(),
Parsimmon.Binary.floatLE(),
Parsimmon.Binary.floatLE(),
(x, y, z) => ({ x, y, z })
);
// Parse scientific data with doubles
const measurement = Parsimmon.seqObj(
["timestamp", Parsimmon.Binary.doubleBE()],
["value", Parsimmon.Binary.doubleBE()],
["error", Parsimmon.Binary.floatBE()]
);
// Parse mixed numeric data
const record = Parsimmon.seqMap(
Parsimmon.Binary.uint32BE, // ID
Parsimmon.Binary.floatLE(), // Temperature
Parsimmon.Binary.floatLE(), // Humidity
Parsimmon.Binary.doubleBE(), // Timestamp
(id, temp, humidity, time) => ({
id, temperature: temp, humidity, timestamp: time
})
);Advanced parsers for bit-level data manipulation.
/**
* Parse sequence of bit fields
* @param {number[]} alignments - Array of bit counts for each field
* @returns {Parser} Parser that returns array of bit field values
*/
Parsimmon.Binary.bitSeq(alignments);
/**
* Parse bit fields into named object
* @param {Array} namedAlignments - Array of [name, bits] pairs or bit counts
* @returns {Parser} Parser that returns object with named bit fields
*/
Parsimmon.Binary.bitSeqObj(namedAlignments);Usage Examples:
// Parse IP header flags (3 bits total)
const ipFlags = Parsimmon.Binary.bitSeq([1, 1, 1]); // Reserved, DF, MF
ipFlags.parse(Buffer.from([0x40])); // [0, 1, 0] - Don't Fragment set
// Parse bit fields with names
const tcpFlags = Parsimmon.Binary.bitSeqObj([
["fin", 1],
["syn", 1],
["rst", 1],
["psh", 1],
["ack", 1],
["urg", 1],
["ece", 1],
["cwr", 1]
]);
// Parse complex bit structures
const bitmapHeader = Parsimmon.Binary.bitSeqObj([
["signature", 16],
["fileSize", 32],
4, // reserved
4, // reserved
["dataOffset", 32]
]);
// Parse packed data structures
const packedCoord = Parsimmon.Binary.bitSeqObj([
["x", 10], // X coordinate (10 bits)
["y", 10], // Y coordinate (10 bits)
["z", 10], // Z coordinate (10 bits)
["flags", 2] // Status flags (2 bits)
]);Examples of validating binary data during parsing.
Usage Examples:
// Validate magic numbers
const validateMagic = (expected) => (value) => {
if (value === expected) return Parsimmon.succeed(value);
return Parsimmon.fail(`expected magic ${expected.toString(16)}, got ${value.toString(16)}`);
};
const jpegHeader = Parsimmon.Binary.uint16BE
.chain(validateMagic(0xFFD8))
.desc("JPEG magic number");
// Validate ranges
const validateRange = (min, max) => (value) => {
if (value >= min && value <= max) return Parsimmon.succeed(value);
return Parsimmon.fail(`value ${value} out of range [${min}, ${max}]`);
};
const rgbColor = Parsimmon.seqMap(
Parsimmon.Binary.uint8BE.chain(validateRange(0, 255)),
Parsimmon.Binary.uint8BE.chain(validateRange(0, 255)),
Parsimmon.Binary.uint8BE.chain(validateRange(0, 255)),
(r, g, b) => ({ r, g, b })
);
// Parse with length validation
const lengthPrefixedString = Parsimmon.Binary.uint16BE.chain(length => {
if (length > 1024) return Parsimmon.fail("string too long");
return Parsimmon.Binary.encodedString("utf8", length);
});
// Parse arrays with count
const parseArray = (elementParser) => {
return Parsimmon.Binary.uint32BE.chain(count => {
if (count > 10000) return Parsimmon.fail("array too large");
return elementParser.times(count);
});
};
const intArray = parseArray(Parsimmon.Binary.int32BE);Examples of parsing complex binary file formats.
Usage Examples:
// Parse TGA image header
const tgaHeader = Parsimmon.seqObj(
["idLength", Parsimmon.Binary.uint8BE],
["colorMapType", Parsimmon.Binary.uint8BE],
["imageType", Parsimmon.Binary.uint8BE],
["colorMapSpec", Parsimmon.seqObj(
["firstEntryIndex", Parsimmon.Binary.uint16LE],
["colorMapLength", Parsimmon.Binary.uint16LE],
["colorMapEntrySize", Parsimmon.Binary.uint8BE]
)],
["imageSpec", Parsimmon.seqObj(
["xOrigin", Parsimmon.Binary.uint16LE],
["yOrigin", Parsimmon.Binary.uint16LE],
["width", Parsimmon.Binary.uint16LE],
["height", Parsimmon.Binary.uint16LE],
["pixelDepth", Parsimmon.Binary.uint8BE],
["imageDescriptor", Parsimmon.Binary.uint8BE]
)]
);
// Parse WAV file header
const wavHeader = Parsimmon.seqObj(
["riff", Parsimmon.Binary.buffer(4)], // "RIFF"
["fileSize", Parsimmon.Binary.uint32LE],
["wave", Parsimmon.Binary.buffer(4)], // "WAVE"
["fmt", Parsimmon.Binary.buffer(4)], // "fmt "
["fmtSize", Parsimmon.Binary.uint32LE],
["audioFormat", Parsimmon.Binary.uint16LE],
["numChannels", Parsimmon.Binary.uint16LE],
["sampleRate", Parsimmon.Binary.uint32LE],
["byteRate", Parsimmon.Binary.uint32LE],
["blockAlign", Parsimmon.Binary.uint16LE],
["bitsPerSample", Parsimmon.Binary.uint16LE]
);
// Parse network packet
const ethernetFrame = Parsimmon.seqObj(
["destination", Parsimmon.Binary.buffer(6)],
["source", Parsimmon.Binary.buffer(6)],
["etherType", Parsimmon.Binary.uint16BE],
["payload", Parsimmon.Binary.buffer(46)] // Minimum payload
);Install with Tessl CLI
npx tessl i tessl/npm-parsimmon