Skip to content

Commit b047862

Browse files
authored
Merge pull request #215 from wpyoga/wrapped-optional-name
Make `name` parameter optional for `wrapped`
2 parents d405fe2 + 1a5daad commit b047862

File tree

3 files changed

+159
-17
lines changed

3 files changed

+159
-17
lines changed

README.md

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -442,21 +442,27 @@ const buffer = Buffer.from([2, /* left */ 1, 1, 0, /* right */ 0]);
442442
parser.parse(buffer);
443443
```
444444

445-
### wrapped(name[, options])
446-
Read data then wrap it by transforming it by a function for further parsing.
447-
It works similarly to a buffer where it reads a block of data. But instead of returning the buffer it
448-
will pass it on to a parser for further processing.
449-
- `wrapper` - (Required) A function taking a buffer and returning a buffer (`(x: Buffer | Uint8Array ) => Buffer | Uint8Array`)
450-
transforming the buffer into a buffer expected by `type`.
451-
- `type` - (Required) A `Parser` object to parse the result of wrapper.
445+
### wrapped([name,] options)
446+
Read data, then wrap it by transforming it by a function for further parsing.
447+
It works similarly to a buffer where it reads a block of data. But instead of
448+
returning the buffer it will pass the buffer on to a parser for further processing.
449+
450+
The result will be stored in the key `name`. If `name` is an empty string or
451+
`null`, or if it is omitted, the parsed result is directly embedded into the
452+
current object.
453+
454+
- `wrapper` - (Required) A function taking a buffer and returning a buffer
455+
(`(x: Buffer | Uint8Array ) => Buffer | Uint8Array`) transforming the buffer
456+
into a buffer expected by `type`.
457+
- `type` - (Required) A `Parser` object to parse the buffer returned by `wrapper`.
452458
- `length ` - (either `length` or `readUntil` is required) Length of the
453-
buffer. Can be a number, string or a function. Use number for statically
454-
sized buffers, string to reference another variable and function to do some
459+
buffer. Can be a number, string or a function. Use a number for statically
460+
sized buffers, a string to reference another variable and a function to do some
455461
calculation.
456462
- `readUntil` - (either `length` or `readUntil` is required) If `"eof"`, then
457463
this parser will read till it reaches the end of the `Buffer`/`Uint8Array`
458464
object. If it is a function, this parser will read the buffer until the
459-
function returns true.
465+
function returns `true`.
460466

461467
```javascript
462468
const zlib = require("zlib");
@@ -478,9 +484,10 @@ const mainParser = Parser.start()
478484
// E.g. decompress data and return it for further parsing
479485
return zlib.inflateRawSync(buffer);
480486
},
481-
// The parser to run the dec
487+
// The parser to run on the decompressed data
482488
type: textParser,
483489
});
490+
484491
mainParser.parse(buffer);
485492
```
486493

lib/binary_parser.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -605,16 +605,21 @@ export class Parser {
605605
return this.setNextParser("buffer", varName, options);
606606
}
607607

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

613-
if (!options.wrapper || !options.type) {
614+
if (!options || !options.wrapper || !options.type) {
614615
throw new Error("Both wrapper and type must be defined for wrapped.");
615616
}
616617

617-
return this.setNextParser("wrapper", varName, options);
618+
if (!options.length && !options.readUntil) {
619+
throw new Error("length or readUntil must be defined for wrapped.");
620+
}
621+
622+
return this.setNextParser("wrapper", varName as string, options);
618623
}
619624

620625
array(varName: string, options: ParserOptions): this {
@@ -697,7 +702,7 @@ export class Parser {
697702
);
698703
}
699704

700-
return this.setNextParser("nest", varName as string, options || {});
705+
return this.setNextParser("nest", varName as string, options);
701706
}
702707

703708
pointer(varName: string, options: ParserOptions): this {

test/composite_parser.ts

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1273,6 +1273,136 @@ function compositeParserTests(
12731273
answer: 42,
12741274
});
12751275
});
1276+
it("should embed parsed object in current object", () => {
1277+
const parserEmptyName = Parser.start()
1278+
.uint8("messageId")
1279+
.uint8("reportCount")
1280+
.array("reports", {
1281+
length: "reportCount",
1282+
type: Parser.start()
1283+
.uint8("reportId")
1284+
.uint8("reportLength")
1285+
.wrapped("", {
1286+
length: "reportLength",
1287+
wrapper: (buffer) => buffer,
1288+
type: Parser.start()
1289+
.nest("basicReport", {
1290+
type: Parser.start()
1291+
.uint8("dataPoint1")
1292+
.uint8("dataPoint2")
1293+
.uint8("dataPoint3")
1294+
.uint8("dataPoint4"),
1295+
})
1296+
.array("extendedReport", {
1297+
readUntil: "eof",
1298+
type: Parser.start()
1299+
.uint8("dataType")
1300+
.uint8("dataLength")
1301+
.buffer("data", { length: "dataLength" }),
1302+
}),
1303+
}),
1304+
});
1305+
1306+
const parserWithoutName = Parser.start()
1307+
.uint8("messageId")
1308+
.uint8("reportCount")
1309+
.array("reports", {
1310+
length: "reportCount",
1311+
type: Parser.start()
1312+
.uint8("reportId")
1313+
.uint8("reportLength")
1314+
.wrapped({
1315+
length: "reportLength",
1316+
wrapper: (buffer) => buffer,
1317+
type: Parser.start()
1318+
.nest("basicReport", {
1319+
type: Parser.start()
1320+
.uint8("dataPoint1")
1321+
.uint8("dataPoint2")
1322+
.uint8("dataPoint3")
1323+
.uint8("dataPoint4"),
1324+
})
1325+
.array("extendedReport", {
1326+
readUntil: "eof",
1327+
type: Parser.start()
1328+
.uint8("dataType")
1329+
.uint8("dataLength")
1330+
.buffer("data", { length: "dataLength" }),
1331+
}),
1332+
}),
1333+
});
1334+
1335+
const buffer = Buffer.from(
1336+
"1002f11012345678a003303132a101dfa20255aaf21201020304a003343536a202aa55a101eb",
1337+
"hex"
1338+
);
1339+
1340+
deepStrictEqual(parserEmptyName.parse(buffer), {
1341+
messageId: 16,
1342+
reportCount: 2,
1343+
reports: [
1344+
{
1345+
reportId: 241,
1346+
reportLength: 16,
1347+
basicReport: {
1348+
dataPoint1: 18,
1349+
dataPoint2: 52,
1350+
dataPoint3: 86,
1351+
dataPoint4: 120,
1352+
},
1353+
extendedReport: [
1354+
{
1355+
dataType: 160,
1356+
dataLength: 3,
1357+
data: Buffer.from([48, 49, 50]),
1358+
},
1359+
{
1360+
dataType: 161,
1361+
dataLength: 1,
1362+
data: Buffer.from([223]),
1363+
},
1364+
{
1365+
dataType: 162,
1366+
dataLength: 2,
1367+
data: Buffer.from([85, 170]),
1368+
},
1369+
],
1370+
},
1371+
{
1372+
reportId: 242,
1373+
reportLength: 18,
1374+
basicReport: {
1375+
dataPoint1: 1,
1376+
dataPoint2: 2,
1377+
dataPoint3: 3,
1378+
dataPoint4: 4,
1379+
},
1380+
extendedReport: [
1381+
{
1382+
dataType: 160,
1383+
dataLength: 3,
1384+
data: Buffer.from([52, 53, 54]),
1385+
},
1386+
{
1387+
dataType: 162,
1388+
dataLength: 2,
1389+
data: Buffer.from([170, 85]),
1390+
},
1391+
{
1392+
dataType: 161,
1393+
dataLength: 1,
1394+
data: Buffer.from([235]),
1395+
},
1396+
],
1397+
},
1398+
],
1399+
});
1400+
1401+
deepStrictEqual(
1402+
parserEmptyName.parse(buffer),
1403+
parserWithoutName.parse(buffer)
1404+
);
1405+
});
12761406
});
12771407
});
12781408
}

0 commit comments

Comments
 (0)