Skip to content

Commit

Permalink
Merge pull request #215 from wpyoga/wrapped-optional-name
Browse files Browse the repository at this point in the history
Make `name` parameter optional for `wrapped`
  • Loading branch information
keichi authored Sep 5, 2022
2 parents d405fe2 + 1a5daad commit b047862
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 17 deletions.
29 changes: 18 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -442,21 +442,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 @@ -478,9 +484,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

0 comments on commit b047862

Please sign in to comment.