Repository: keichi/binary-parser
Pull request #215 (2022-09-02 13:16:54)

Make `name` parameter optional for `wrapped`
This is just like `nest`, where if the `name` parameter is omitted, then the parsed object is embedded directly into the current object.

The update for the readme assumes that #213 has been merged.


Patch:
diff --git a/README.md b/README.md
index ec835a9..3644dc6 100644
--- a/README.md
+++ b/README.md
@@ -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");
@@ -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);
 ```
 
diff --git a/lib/binary_parser.ts b/lib/binary_parser.ts
index 93294b1..f8a9229 100644
--- a/lib/binary_parser.ts
+++ b/lib/binary_parser.ts
@@ -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 {
@@ -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 {


Test patch:
diff --git a/test/composite_parser.ts b/test/composite_parser.ts
index 4378ce9..333c768 100644
--- a/test/composite_parser.ts
+++ b/test/composite_parser.ts
@@ -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)
+        );
+      });
     });
   });
 }