{"id":41692670,"url":"https://github.com/wshager/triply","last_synced_at":"2026-01-24T20:23:48.605Z","repository":{"id":57380001,"uuid":"140862843","full_name":"wshager/triply","owner":"wshager","description":"Triply linked list for creating trees","archived":false,"fork":false,"pushed_at":"2018-09-28T06:30:26.000Z","size":73,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-02T06:15:31.334Z","etag":null,"topics":["construction","linked-list","modification","traversal","tree"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wshager.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2018-07-13T15:18:50.000Z","updated_at":"2018-09-28T06:30:28.000Z","dependencies_parsed_at":"2022-09-05T13:50:47.608Z","dependency_job_id":null,"html_url":"https://github.com/wshager/triply","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/wshager/triply","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wshager%2Ftriply","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wshager%2Ftriply/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wshager%2Ftriply/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wshager%2Ftriply/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wshager","download_url":"https://codeload.github.com/wshager/triply/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wshager%2Ftriply/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28736509,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-24T19:23:36.361Z","status":"ssl_error","status_checked_at":"2026-01-24T19:23:28.966Z","response_time":89,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["construction","linked-list","modification","traversal","tree"],"created_at":"2026-01-24T20:23:48.539Z","updated_at":"2026-01-24T20:23:48.589Z","avatar_url":"https://github.com/wshager.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Triply, a triply-linked list lib\n\nYet another data structure for creating trees.\n\n\n## Install\n\n`npm i triply`\n\n\n## Usage\n\n```javascript\nconst Triply = require(\"../lib/triply\").Triply;\n\n// NOTE only objects are valid entries\n// which will be formatted using reserved keys.\n// Here we use `data` to insert a number\nconst node = new Triply({data:1})\n    .push({data:2}) // just append a sibling, the insertion point is moved to the new node\n    .open({data:3}) // make the insertion point a branch and append a new child\n    .close() // try to move the insertion point to the parent\n    .push({data:4}) // append another sibling\n    .previous() // try to move the insertion point back along the traversal path (the branch containing `data:2`)\n    .open({data:5}) // append another child\n    .push({data:6}); // append another sibling to that child\n\n// traverse the tree (lazy iterator)\n// we have to keep track of branch 'closers' (compare for example with XML closing tags)\nfor(let x of node.traverse()) console.log(\"x\",Triply.isClose(x) ? \"closes: \" + Triply.link(x).data : x.data);\n```\n\n\n## License\n\n[License](./LICENSE)\n\n\n## API documentation\n\n* [Triply Class](./docs/triply.md)\n* [Functional implementation](./docs/chimp.md)\n\n## About\n\nTriply is a way to create in-memory trees with some very interesting performance characteristics:\n\n* Fast traversal in 2 directions\n* Fast appendChild, insertBefore, insertAfter, removeChild\n* Fast access to siblings\n* Fast access to the parent at the first or last child\n\nUpdates require writes to at most 4 pointers (5 when expanding or collapsing branches).\n\nUse Triply to create trees that can be modified with some ease.\n\n\n### Triply Pointer Rules\n\n* 1 = depth-first traversal\n* 2 = reversed traversal\n* 3 = open/close link\n\nTraversal directions (invert directions and arrows for reversed traversal):\n* UP = BRANCH -\u003e LEAF or BRANCH\n* DOWN = BRANCH or LEAF -\u003e CLOSE\n* SAME = LEAF -\u003e LEAF\n\n\n### Tree Diagrams\n\n```\n           L\n     1 // 2 1 \\\\ 2\n      B 3-\u003e\u003c-3 /B\n  1 // 2      1 \\\\ 2\n   B 3---\u003e \u003c---3 /B 1 --\u003e \u003c-- 2 B ~\n```\n\nAppend a child at tier 1 (or a sibling at tier 2):\n\n```\n         L 1 --\u003e \u003c-- 2 L\n     1 // 2          1 \\\\ 2\n      B 3---\u003e     \u003c---3 /B\n  1 // 2               1 \\\\ 2\n   B 3---\u003e          \u003c---3 /B 1 --\u003e \u003c-- 2 B ~\n```\n\nAppend a child at tier 0 (or a sibling at tier 1):\n\n```\n         L 1 --\u003e \u003c-- 2 L                   L\n     1 // 2          1 \\\\ 2          1 // 2 1 \\\\ 2\n      B 3---\u003e     \u003c---3 /B 1--\u003e \u003c-- 2 B 3-\u003e\u003c-3 /B\n  1 // 2                                      1 \\\\ 2\n   B 3---\u003e                                 \u003c---3 /B 1 --\u003e \u003c-- 2 B ~\n```\n\n\n### Access logic\n\n* firstChild: follow 1 from BRANCH\n* lastChild: follow 3 to find CLOSE and then 2\n* nextSibling: follow 1 from LEAF or 3 + 1 from BRANCH\n* previousSibling: follow 2, if found CLOSE follow 3\n* parent (O[no of siblings]): follow 2 from firstSibling or 1 + 3 from lastSibling\n* firstChildTest: child -\u003e 2 === BRANCH\n* lastChildTest: child -\u003e 1 === CLOSE\n\nNOTE: Accessing the parent is only relevant for insertBefore when it's the first child.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwshager%2Ftriply","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwshager%2Ftriply","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwshager%2Ftriply/lists"}