Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make name parameter optional for wrapped #215

Merged
merged 4 commits into from
Sep 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 18 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -438,21 +438,27 @@ const buffer = Buffer.from([2, /* left */ 1, 1, 0, /* right */ 0]);
parser.parse(buffer);
```

### wrapped(name[, options])
Read data then wrap it by transforming it by a function for further parsing.
It works similarly to a buffer where it reads a block of data. But instead of returning the buffer it
will pass it on to a parser for further processing.
- `wrapper` - (Required) A function taking a buffer and returning a buffer (`(x: Buffer | Uint8Array ) => Buffer | Uint8Array`)
transforming the buffer into a buffer expected by `type`.
- `type` - (Required) A `Parser` object to parse the result of wrapper.
### wrapped([name,] options)
Read data, then wrap it by transforming it by a function for further parsing.
It works similarly to a buffer where it reads a block of data. But instead of
returning the buffer it will pass the buffer on to a parser for further processing.

The result will be stored in the key `name`. If `name` is an empty string or
`null`, or if it is omitted, the parsed result is directly embedded into the
current object.

- `wrapper` - (Required) A function taking a buffer and returning a buffer
(`(x: Buffer | Uint8Array ) => Buffer | Uint8Array`) transforming the buffer
into a buffer expected by `type`.
- `type` - (Required) A `Parser` object to parse the buffer returned by `wrapper`.
- `length ` - (either `length` or `readUntil` is required) Length of the
buffer. Can be a number, string or a function. Use number for statically
sized buffers, string to reference another variable and function to do some
buffer. Can be a number, string or a function. Use a number for statically
sized buffers, a string to reference another variable and a function to do some
calculation.
- `readUntil` - (either `length` or `readUntil` is required) If `"eof"`, then
this parser will read till it reaches the end of the `Buffer`/`Uint8Array`
object. If it is a function, this parser will read the buffer until the
function returns true.
function returns `true`.

```javascript
const zlib = require("zlib");
Expand All @@ -474,9 +480,10 @@ const mainParser = Parser.start()
// E.g. decompress data and return it for further parsing
return zlib.inflateRawSync(buffer);
},
// The parser to run the dec
// The parser to run on the decompressed data
type: textParser,
});

mainParser.parse(buffer);
```

Expand Down
17 changes: 11 additions & 6 deletions lib/binary_parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -605,16 +605,21 @@ export class Parser {
return this.setNextParser("buffer", varName, options);
}

wrapped(varName: string, options: ParserOptions): this {
if (!options.length && !options.readUntil) {
throw new Error("length or readUntil must be defined for wrapped.");
wrapped(varName: string | ParserOptions, options?: ParserOptions): this {
if (typeof options !== "object" && typeof varName === "object") {
options = varName;
varName = "";
}

if (!options.wrapper || !options.type) {
if (!options || !options.wrapper || !options.type) {
throw new Error("Both wrapper and type must be defined for wrapped.");
}

return this.setNextParser("wrapper", varName, options);
if (!options.length && !options.readUntil) {
throw new Error("length or readUntil must be defined for wrapped.");
}

return this.setNextParser("wrapper", varName as string, options);
}

array(varName: string, options: ParserOptions): this {
Expand Down Expand Up @@ -697,7 +702,7 @@ export class Parser {
);
}

return this.setNextParser("nest", varName as string, options || {});
return this.setNextParser("nest", varName as string, options);
}

pointer(varName: string, options: ParserOptions): this {
Expand Down
130 changes: 130 additions & 0 deletions test/composite_parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1273,6 +1273,136 @@ function compositeParserTests(
answer: 42,
});
});
it("should embed parsed object in current object", () => {
const parserEmptyName = Parser.start()
.uint8("messageId")
.uint8("reportCount")
.array("reports", {
length: "reportCount",
type: Parser.start()
.uint8("reportId")
.uint8("reportLength")
.wrapped("", {
length: "reportLength",
wrapper: (buffer) => buffer,
type: Parser.start()
.nest("basicReport", {
type: Parser.start()
.uint8("dataPoint1")
.uint8("dataPoint2")
.uint8("dataPoint3")
.uint8("dataPoint4"),
})
.array("extendedReport", {
readUntil: "eof",
type: Parser.start()
.uint8("dataType")
.uint8("dataLength")
.buffer("data", { length: "dataLength" }),
}),
}),
});

const parserWithoutName = Parser.start()
.uint8("messageId")
.uint8("reportCount")
.array("reports", {
length: "reportCount",
type: Parser.start()
.uint8("reportId")
.uint8("reportLength")
.wrapped({
length: "reportLength",
wrapper: (buffer) => buffer,
type: Parser.start()
.nest("basicReport", {
type: Parser.start()
.uint8("dataPoint1")
.uint8("dataPoint2")
.uint8("dataPoint3")
.uint8("dataPoint4"),
})
.array("extendedReport", {
readUntil: "eof",
type: Parser.start()
.uint8("dataType")
.uint8("dataLength")
.buffer("data", { length: "dataLength" }),
}),
}),
});

const buffer = Buffer.from(
"1002f11012345678a003303132a101dfa20255aaf21201020304a003343536a202aa55a101eb",
"hex"
);

deepStrictEqual(parserEmptyName.parse(buffer), {
messageId: 16,
reportCount: 2,
reports: [
{
reportId: 241,
reportLength: 16,
basicReport: {
dataPoint1: 18,
dataPoint2: 52,
dataPoint3: 86,
dataPoint4: 120,
},
extendedReport: [
{
dataType: 160,
dataLength: 3,
data: Buffer.from([48, 49, 50]),
},
{
dataType: 161,
dataLength: 1,
data: Buffer.from([223]),
},
{
dataType: 162,
dataLength: 2,
data: Buffer.from([85, 170]),
},
],
},
{
reportId: 242,
reportLength: 18,
basicReport: {
dataPoint1: 1,
dataPoint2: 2,
dataPoint3: 3,
dataPoint4: 4,
},
extendedReport: [
{
dataType: 160,
dataLength: 3,
data: Buffer.from([52, 53, 54]),
},
{
dataType: 162,
dataLength: 2,
data: Buffer.from([170, 85]),
},
{
dataType: 161,
dataLength: 1,
data: Buffer.from([235]),
},
],
},
],
});

deepStrictEqual(
parserEmptyName.parse(buffer),
parserWithoutName.parse(buffer)
);
});
});
});
}
Expand Down