{"id":20885725,"url":"https://github.com/sabakihq/sgf","last_synced_at":"2025-05-12T19:31:18.628Z","repository":{"id":94470347,"uuid":"129548800","full_name":"SabakiHQ/sgf","owner":"SabakiHQ","description":"A library for parsing SGF files.","archived":false,"fork":false,"pushed_at":"2023-08-08T01:39:27.000Z","size":295,"stargazers_count":50,"open_issues_count":8,"forks_count":14,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-11T08:16:13.340Z","etag":null,"topics":["baduk","board-game","file","go","parser","sgf","weiqi"],"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/SabakiHQ.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"custom":"https://www.paypal.me/yishn/5"}},"created_at":"2018-04-14T19:39:38.000Z","updated_at":"2025-04-03T20:17:39.000Z","dependencies_parsed_at":"2024-06-18T23:08:15.839Z","dependency_job_id":null,"html_url":"https://github.com/SabakiHQ/sgf","commit_stats":{"total_commits":135,"total_committers":3,"mean_commits":45.0,"dds":"0.16296296296296298","last_synced_commit":"606f0593766407322d1decf8dc86001ef4adbb24"},"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SabakiHQ%2Fsgf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SabakiHQ%2Fsgf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SabakiHQ%2Fsgf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SabakiHQ%2Fsgf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SabakiHQ","download_url":"https://codeload.github.com/SabakiHQ/sgf/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253808182,"owners_count":21967503,"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":["baduk","board-game","file","go","parser","sgf","weiqi"],"created_at":"2024-11-18T08:14:19.272Z","updated_at":"2025-05-12T19:31:18.194Z","avatar_url":"https://github.com/SabakiHQ.png","language":"JavaScript","funding_links":["https://www.paypal.me/yishn/5"],"categories":[],"sub_categories":[],"readme":"# @sabaki/sgf [![Build Status](https://travis-ci.org/SabakiHQ/sgf.svg?branch=master)](https://travis-ci.org/SabakiHQ/sgf)\r\n\r\nA library for parsing SGF files.\r\n\r\n## Installation\r\n\r\nUse npm to install:\r\n\r\n```\r\n$ npm install @sabaki/sgf\r\n```\r\n\r\n## Usage\r\n\r\n```js\r\nconst sgf = require('@sabaki/sgf')\r\n\r\nlet rootNodes = sgf.parseFile('./game.sgf')\r\n```\r\n\r\n`rootNodes` looks like this:\r\n\r\n```js\r\n[\r\n  {\r\n    id: 1,\r\n    data: {B: ['dd'], ...},\r\n    parentId: null,\r\n    children: [\r\n      {\r\n        id: 2,\r\n        data: {W: ['dq']},\r\n        parentId: 1,\r\n        children: []\r\n      },\r\n      ...\r\n    ]\r\n  },\r\n  ...\r\n]\r\n```\r\n\r\n### Use in the browser\r\n\r\nYou can use this library in the browser by using a bundler, such as webpack. If\r\nyou do, you need to add the following lines to your webpack configuration:\r\n\r\n```js\r\n{\r\n  ...\r\n  externals: {\r\n    'fs': 'null',\r\n\r\n    // Add the next lines to disable automatic encoding detection\r\n    // and reduce bundle size:\r\n    'jschardet': 'null',\r\n    'iconv-lite': 'null'\r\n  }\r\n}\r\n```\r\n\r\nNote that [`parseFile`](#sgfparsefilefilename-options) is not available in the\r\nbrowser; you have to use [`parse`](#sgfparsecontents-options) instead.\r\n\r\n### Integration with [@sabaki/immutable-gametree](https://github.com/SabakiHQ/immutable-gametree)\r\n\r\nThis library uses the same node structure as\r\n[@sabaki/immutable-gametree](https://github.com/SabakiHQ/immutable-gametree) and\r\nis fully compatible with it. To wrap parsed SGF into game trees, you can write,\r\nfor example, something like this:\r\n\r\n```js\r\nconst sgf = require('@sabaki/sgf')\r\nconst GameTree = require('@sabaki/immutable-gametree')\r\n\r\nlet getId = (id =\u003e () =\u003e id++)(0)\r\nlet rootNodes = sgf.parse(content, {getId})\r\nlet gameTrees = rootNodes.map(rootNode =\u003e {\r\n  return new GameTree({getId, root: rootNode})\r\n})\r\n```\r\n\r\nMake sure the id generation function is shared between `@sabaki/sgf` and\r\n`@sabaki/immutable-gametree`.\r\n\r\n## Contributors\r\n\r\nA big thanks to [@apetresc](https://github.com/apetresc) and\r\n[@fohristiwhirl](https://github.com/fohristiwhirl) for adding decoding and\r\nautomatic encoding detection functionalities.\r\n\r\n## API\r\n\r\n### Node Object\r\n\r\nA tree _node_ is represented by an object of the following form:\r\n\r\n```js\r\n{\r\n  id: \u003cPrimitive\u003e,\r\n  data: {\r\n    [property]: \u003cArray\u003cString\u003e\u003e\r\n  },\r\n  parentId: \u003cPrimitive\u003e | null,\r\n  children: \u003cArray\u003cNodeObject\u003e\u003e\r\n}\r\n```\r\n\r\n`data` contains node properties which matches their\r\n[SGF property](https://www.red-bean.com/sgf/proplist.html) equivalent.\r\n\r\n---\r\n\r\n### Basic Functions\r\n\r\n#### `*sgf.tokenizeIter(contents)`\r\n\r\n- `contents` `\u003cString\u003e` - SGF input\r\n\r\nA generator function that yields SGF tokens, objects of the following form:\r\n\r\n```js\r\n{\r\n  type: \u003cString\u003e,\r\n  value: \u003cString\u003e,\r\n  row: \u003cInteger\u003e,\r\n  col: \u003cInteger\u003e,\r\n  pos: \u003cInteger\u003e,\r\n  progress: \u003cNumber\u003e\r\n}\r\n```\r\n\r\n`type` is one of `\"parenthesis\"`, `\"semicolon\"`, `\"prop_ident\"`,\r\n`\"c_value_type\"`, `\"invalid\"`. `row` is the zero-based index of the row where\r\nthe token starts, `col` the zero-based index of column where the token starts,\r\nand `pos` denotes the index in `contents` where the token starts. `progress` is\r\na number between `0` and `1` denoting the percental position of the token.\r\n\r\n#### `sgf.tokenize(contents)`\r\n\r\nThe same as [`sgf.tokenizeIter`](#sgftokenizeitercontents), except this function\r\nwill return an array.\r\n\r\n#### `*sgf.tokenizeBufferIter(buffer[, options])`\r\n\r\n- `buffer` [`\u003cBuffer\u003e`](https://nodejs.org/api/buffer.html) - SGF input\r\n- `options` `\u003cObject\u003e` _(optional)_\r\n  - `encoding` `\u003cString\u003e` _(optional)_\r\n\r\nA generator function that yields SGF tokens as in\r\n[`sgf.tokenizeIter()`](#sgftokenizeitercontents). If `encoding` isn't set, we\r\nwill automatically choose an encoding. Automatic encoding detection is only\r\npossible if optional dependencies are installed, otherwise UTF-8 will be used.\r\n\r\n#### `sgf.tokenizeBuffer(buffer[, options])`\r\n\r\nThe same as [`sgf.tokenizeBufferIter`](#sgftokenizebufferiterbuffer-options),\r\nexcept this function will return an array.\r\n\r\n#### `sgf.parseTokens(tokens[, options])`\r\n\r\n- `tokens` - List of tokens as returned by\r\n  [`sgf.tokenize()`](#sgftokenizecontents)\r\n- `options` `\u003cObject\u003e` _(optional)_\r\n  - `getId` `\u003cFunction\u003e` _(optional)_\r\n  - `dictionary` `\u003cObject\u003e` _(optional)_\r\n  - `onProgress` `\u003cFunction\u003e` _(optional)_\r\n  - `onNodeCreated` `\u003cFunction\u003e` _(optional)_\r\n\r\nReturns an array of [node objects](#node-object) which represent the root nodes\r\nof each game tree.\r\n\r\n`getId` can be specified to control the id generation. It will be called without\r\nany arguments. By default, we will use consecutive integers starting at `0` as\r\nids.\r\n\r\nPass an object to `dictionary` and it will get filled with references to all the\r\nnodes with their ids as keys.\r\n\r\n`onProgress` will be called with an object with the following keys:\r\n\r\n- `progress` `\u003cNumber\u003e` - Between `0` and `1`\r\n\r\n`onNodeCreated` will be called when property parsing has been completed for a\r\nnode. It will be called with an object with the following keys:\r\n\r\n- `node` [`\u003cNodeObject\u003e`](#node-object)\r\n\r\n#### `sgf.parse(contents[, options])`\r\n\r\n- `contents` `\u003cString\u003e` - SGF input\r\n- `options` `\u003cObject\u003e` _(optional)_ - See\r\n  [`sgf.parseTokens()`](#sgfparsetokenstokens-options)\r\n\r\nReturns an array of [node objects](#node-object).\r\n\r\n#### `sgf.parseBuffer(buffer[, options])`\r\n\r\n- `buffer` [`\u003cBuffer\u003e`](https://nodejs.org/api/buffer.html) - The buffer\r\n- `options` `\u003cObject\u003e` _(optional)_\r\n  - `encoding` `\u003cString\u003e` _(optional)_ - See\r\n    [`sgf.tokenizeBuffer()`](#sgftokenizebufferbuffer-options)\r\n  - `getId` `\u003cFunction\u003e` _(optional)_ - See\r\n    [`sgf.parseTokens()`](#sgfparsetokenstokens-options)\r\n  - `dictionary` `\u003cObject\u003e` _(optional)_ - See\r\n    [`sgf.parseTokens()`](#sgfparsetokenstokens-options)\r\n  - `onProgress` `\u003cFunction\u003e` _(optional)_ - See\r\n    [`sgf.parseTokens()`](#sgfparsetokenstokens-options)\r\n\r\nReturns an array of [node objects](#node-object).\r\n\r\n#### `sgf.parseFile(filename[, options])`\r\n\r\n- `filename` `\u003cString\u003e` - Path to an SGF file\r\n- `options` `\u003cObject\u003e` _(optional)_ - See\r\n  [`sgf.parseBuffer()`](#sgfparsebufferbuffer-options)\r\n\r\nReturns an array of [node objects](#node-object). Automatically detects\r\nencoding.\r\n\r\n#### `sgf.stringify(nodes[, options])`\r\n\r\n- `nodes` [`\u003cNodeObject[]\u003e`](#node-object)\r\n- `options` `\u003cObject\u003e` _(optional)_\r\n  - `linebreak` `\u003cString\u003e` _(optional)_ - Default: `\"\\n\"`\r\n  - `indent` `\u003cString\u003e` _(optional)_ - Default: `\" \"`\r\n\r\nReturns an SGF string representing the root nodes `nodes`.\r\n\r\n---\r\n\r\n### Helper Functions\r\n\r\n#### `sgf.escapeString(input)`\r\n\r\n- `input` `\u003cString\u003e`\r\n\r\nEscapes `\\` and `]` characters and returns the new string.\r\n\r\n#### `sgf.unescapeString(input)`\r\n\r\n- `input` `\u003cString\u003e`\r\n\r\nResolves escaped characters and returns the new string.\r\n\r\n#### `sgf.parseVertex(input)`\r\n\r\n- `input` `\u003cString\u003e`\r\n\r\nTurns an SGF point string into a vertex, an integer array of the form `[x, y]`.\r\nAn invalid string will yield `[-1, -1]`.\r\n\r\n#### `sgf.stringifyVertex(vertex)`\r\n\r\n- `vertex` `\u003cInteger[]\u003e`\r\n\r\nTurns a vertex into an SGF point string. Returns an empty string if vertex is\r\ninvalid.\r\n\r\n#### `sgf.parseCompressedVertices(input)`\r\n\r\n- `input` `\u003cString\u003e`\r\n\r\nTurns an SGF compressed point list into an array of vertices.\r\n\r\n#### `sgf.parseDates(input)`\r\n\r\n- `input` `\u003cString\u003e`\r\n\r\nParses an SGF date string into an array of date arrays, integer arrays of the\r\nform `[year, month, date]`.\r\n\r\n#### `sgf.stringifyDates(dates)`\r\n\r\n- `dates` `\u003cInteger[][]\u003e`\r\n\r\nTurns an array of date arrays and returns an SGF date string.\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsabakihq%2Fsgf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsabakihq%2Fsgf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsabakihq%2Fsgf/lists"}