{"id":13464904,"url":"https://github.com/goto-bus-stop/awestruct","last_synced_at":"2025-04-16T00:05:45.373Z","repository":{"id":19889686,"uuid":"23154276","full_name":"goto-bus-stop/awestruct","owner":"goto-bus-stop","description":"🤩 Library for reading binary Buffer structures into objects in Node.js","archived":false,"fork":false,"pushed_at":"2021-07-26T04:49:41.000Z","size":129,"stargazers_count":40,"open_issues_count":5,"forks_count":1,"subscribers_count":3,"default_branch":"default","last_synced_at":"2025-04-16T00:05:25.492Z","etag":null,"topics":["buffer","struct"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/goto-bus-stop.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-08-20T15:45:18.000Z","updated_at":"2024-07-27T08:34:22.000Z","dependencies_parsed_at":"2022-07-23T14:09:13.902Z","dependency_job_id":null,"html_url":"https://github.com/goto-bus-stop/awestruct","commit_stats":null,"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goto-bus-stop%2Fawestruct","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goto-bus-stop%2Fawestruct/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goto-bus-stop%2Fawestruct/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goto-bus-stop%2Fawestruct/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/goto-bus-stop","download_url":"https://codeload.github.com/goto-bus-stop/awestruct/tar.gz/refs/heads/default","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249173084,"owners_count":21224483,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["buffer","struct"],"created_at":"2024-07-31T14:00:52.535Z","updated_at":"2025-04-16T00:05:45.355Z","avatar_url":"https://github.com/goto-bus-stop.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# awestruct\n\nLibrary for reading complex binary Buffer structures into objects in Node.js\n\n[![NPM](https://nodei.co/npm/awestruct.png?compact=true)](https://nodei.co/npm/awestruct)\n\n## Usage Example\n\n```js\nconst Struct = require('awestruct')\nconst t = Struct.types\n\n// https://github.com/goto-bus-stop/genie-slp/\nconst slpHeader = Struct([\n  ['version', t.string(4)],\n  ['numFrames', t.int32],\n  ['comment', t.string(24)],\n\n  ['frames', t.array('numFrames', Struct([\n    ['cmdTableOffset', t.uint32],\n    ['outlineTableOffset', t.uint32],\n    ['paletteOffset', t.uint32],\n    ['properties', t.uint32],\n\n    ['width', t.int32],\n    ['height', t.int32],\n    ['hotspot', Struct([\n      ['x', t.int32],\n      ['y', t.int32]\n    ])]\n  ]))]\n])\n\nconst headerContents = slpHeader(slpBuffer) // → { version: '1.00', ... }\n```\n\n## API\n\n### Struct(descriptor)\n\nCreates a new `Struct` function that reads from `Buffer`s according to the described format.\n\n`descriptor` is a Struct Descriptor. For example:\n\n```js\nvar buffer = Buffer.from([ 0x10, 0x20, 0x30 ])\nvar t = Struct.types\nvar struct = Struct([\n  ['a', t.uint16],\n  ['b', t.uint8]\n])\n\nstruct(buffer) //→ { a: 8208, b: 48 }\n```\n\nA struct descriptor is an array of fields. A field can either be an array with two elements, `[name, type]`, or an unnamed raw `type`.\nUnnamed types are useful if there is some padding you need to skip.\n\nIf an unnamed type reads another struct, it is merged into the current one. For example:\n\n```js\nvar struct = Struct([\n  ['needToReadThing', t.int8],\n  t.skip(3), // padding\n  t.if('needToReadThing', Struct([\n    ['value1', t.int8],\n    ['value2', t.int8],\n  ]))\n])\n```\n\nNow, if the `buffer`'s first byte is zero, `struct(buffer)` will return an object like:\n\n```js\n{ needToReadThing: 0 }\n```\n\nBut if it is nonzero, `struct(buffer)` will return an object of this shape:\n\n```js\n{\n  needToReadThing: 1,\n  value1: 43,\n  value2: 76\n}\n```\n\n#### struct(buffer, ?parent)\n\nInstances of `Struct()` can be called directly to read data from buffers. The first parameter is the\nBuffer you want to use. The second (optional) parameter is a parent object for the struct, as shown in [Value Paths](#valuepaths).\n\n#### struct.decode(buffer)\n\n`abstract-encoding` compatible.\n\n#### struct.encode(value[, buffer]\\[, start = 0])\n\nEncode `value` into a `buffer`. Start writing at offset `start`. If no `buffer` is given, awestruct allocates one.\n`abstract-encoding` compatible.\n\n#### struct.encodingLength(value)\n\nReturn the size in bytes that would be necessary to encode `value`.\n`abstract-encoding` compatible.\n\n### Custom types: Struct.Type(type)\n\nCreates a Struct type object. `type` is an object:\n\n```js\nvar myType = Struct.Type({\n  read: function (opts, parent) {\n    // `opts.buf` is the Buffer to read from.\n    // `opts.offset` is the current offset within the Buffer that's being read. Make sure to increment this appropriately when you're done reading.\n    // `opts.struct` is the result Object of the entire Struct so far. You'll only want to use this with the Struct.get* methods, usually.\n    // `parent` is the parent result Object if there is a parent Struct.\n    var val = opts.buf.readInt8(opts.offset)\n    opts.offset++\n    return val * 1000\n  },\n  size: function (val, struct) {\n    return 1 // always 1 byte, could also write as { size: 1 }\n  }\n})\n```\n\nCustom types can be used like so:\n\n```js\nvar myStruct = Struct([\n  ['builtinType', Struct.types.uint8],\n  ['customType', myType]\n])\nmyStruct(Buffer.from([ 5, 5 ])) //→ { builtinType: 5, customType: 5000 }\n```\n\n#### Struct.Type#mapRead(function)\n\nCreates a new type that applies the given transform function when reading values.\n\n```js\nvar int32 = Struct.types.int32\nvar myStruct = Struct([\n  ['a', int32],\n  ['b', int32.mapRead(num =\u003e num * 2)]\n])\nmyStruct(Buffer.from([ 5, 5 ])) //→ { a: 5, b: 10 }\n```\n\n### Builtin Types\n\n#### Number types\n\nThese just map straight to the relevant `Buffer().read*()` methods. Number types read Little-Endian by default, append -`be` if you're dealing with Big-Endian data.\n\n* int8, uint8\n* int16, uint16, int16be, uint16be\n* int32, uint32, int32be, uint32be\n* float, floatbe\n* double, doublebe\n\n#### Other common types\n\n* `string(n, encoding = 'utf8')` → Creates a type that decodes `n` bytes into a string with the given encoding (defaults to 'utf8')\n* `array(n, type)` → Creates a type that reads `n` items of Struct.Type `type` into an `n`-length array.\n* `dynstring(ntype, encoding = 'utf8')` → Creates a type that first reads the length `n` using the type in the first parameter, then decodes `n` bytes into a string with the given encoding.\n* `dynarray(ntype, type)` → Creates a type that first reads the length `n` using the type in the first parameter, then reads `n` items of type `type` into an `n`-length array.\n* `skip(n)` → Creates a type that skips `n` bytes and returns `undefined`.\n\nThe `n` parameter in each of those is a Value Path.\n\n#### Conditional types\n\n* `if(condition, type)` → Creates a type that decodes `type` if the `condition` Value Path is truthy.\n  `if()` types also have an `.else(type)` method, to specify a `type` to decode if the `condition` is falsy.\n\n  ```js\n  t.if('is32bit', t.int32).else(t.int16)\n  ```\n\n### Value Paths\n\nValue paths are used to pass values to some type readers, particularly lengths. Value paths can be raw numbers, or depend on other values in the struct.\n\nValue paths take three forms:\n\n* Numbers: produces the given number.\n* Strings: looks up the value at the given path.\n* Functions: takes the return value of the function.\n\n```js\nStruct([\n  ['len', int8],\n  ['string', string('len')]\n])(Buffer.from([ 3, 104, 105, 33 ])) → { len: 3, string: 'hi!' }\n```\n\nA string path can be a plain property name, or a bunch of property names separated by dots ('child.struct.key') to descend into child structs, and can also start with '../' to look back into a \"parent\" struct.\n\n```js\nStruct([\n  ['otherArrayLength', t.int8],\n  ['subStruct', Struct([\n    ['irrelevantDataLength', t.int32],\n    ['array', t.array('../otherArrayLength', t.int8)]\n  ])]\n  t.skip('subStruct.irrelevantDataLength')\n])\n```\n\nFunctions will be called with the current (possibly incomplete) struct in the first parameter:\n\n```js\nStruct([\n  ['child', Struct([\n    ['data', t.array(100, t.uint8)],\n    ['whatever', t.if((struct) =\u003e {\n      struct.data //→ array of 100 uint8s\n      struct.$parent //→ the \"parent\" struct, like '../' in a path\n      return true\n    }, uint8)]\n  ])]\n])\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoto-bus-stop%2Fawestruct","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgoto-bus-stop%2Fawestruct","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoto-bus-stop%2Fawestruct/lists"}