{"_id":"@actualwave/tree-walker","_rev":"4-6317bc20be610c7ef0ee8e0966eef020","name":"@actualwave/tree-walker","dist-tags":{"latest":"1.0.7"},"versions":{"0.0.4":{"name":"@actualwave/tree-walker","description":"Wireframe based on ES6 Proxies for making tree traversing APIs.","version":"0.0.4","main":"dist/tree-walker.js","keywords":["js","javascript","proxy","tree","E4X"],"homepage":"https://github.com/burdiuz/js-tree-walker","bugs":{"url":"https://github.com/burdiuz/js-tree-walker/issues","email":"burdiuz@gmail.com"},"license":"MIT","author":{"name":"Oleg Galaburda","email":"burdiuz@gmail.com","url":"http://actualwave.com/"},"repository":{"type":"git","url":"git+https://github.com/burdiuz/js-tree-walker.git"},"dependencies":{},"devDependencies":{"babel-core":"^6.26.0","babel-eslint":"^8.2.2","babel-loader":"^7.1.4","babel-plugin-external-helpers":"^6.22.0","babel-plugin-istanbul":"^4.1.6","babel-plugin-transform-class-properties":"^6.24.1","babel-plugin-transform-es2015-modules-commonjs":"^6.26.0","babel-plugin-transform-flow-strip-types":"^6.22.0","babel-plugin-transform-object-rest-spread":"^6.26.0","babel-preset-jest":"^22.4.3","chai":"^4.1.2","eslint":"^4.19.1","eslint-config-airbnb":"^16.1.0","eslint-plugin-import":"^2.10.0","eslint-plugin-jsx-a11y":"^6.0.2","eslint-plugin-react":"^7.7.0","flow-bin":"^0.57.3","husky":"^0.14.3","jest":"^22.4.3","lint-staged":"^6.1.1","prettier":"^1.11.1","rollup-plugin-babel":"^3.0.3","rollup-plugin-commonjs":"^8.4.1","rollup-plugin-json":"^2.3.0","rollup-plugin-node-resolve":"^3.3.0","rollup-plugin-serve":"^0.4.2","rollup-plugin-uglify":"^2.0.1","uglify-es":"^3.3.10"},"lint-staged":{"source/**/!(__tests__/).js":"eslint --fix","{source/**/__tests__/*.js,source/**/__mocks__/*.js}":"eslint -c eslintrc.spec.json --fix","source/**/*.js":["prettier --write","git add"]},"prettier":{"singleQuote":true,"trailing-comma":"es5","arrowParens":"always","parser":"flow"},"babel":{"env":{"test":{"plugins":["babel-plugin-transform-es2015-modules-commonjs","babel-plugin-transform-flow-strip-types","babel-plugin-transform-class-properties",["babel-plugin-transform-object-rest-spread",{"useBuiltIns":true}]],"presets":["jest"]}}},"jest":{"collectCoverage":true,"coverageReporters":["json","lcov"],"coverageDirectory":"coverage","collectCoverageFrom":["source/**/*.js","!**/node_modules/**","!**/vendor/**"]},"scripts":{"start":"build","build":"rollup --config","build:watch":"rollup --config --watch \"./source\"","lint":"eslint \"source/**/!(__tests__/)*.js\"","lint:spec":"eslint -c eslintrc.spec.json \"source/**/__tests__/*.js\"","flow":"flow","server":"rollup --config rollup.serve.js","test":"jest --colors","test:watch":"jest --colors --watch","lint-staged":"lint-staged","precommit":"npm run lint-staged && npm run build && npm run test"},"gitHead":"a3ad981a102e26f559ae013347f723d2a7232779","_id":"@actualwave/tree-walker@0.0.4","_npmVersion":"5.6.0","_nodeVersion":"8.11.1","_npmUser":{"name":"actualwave","email":"burdiuz@gmail.com"},"dist":{"integrity":"sha512-FDUA9TDuUDmsvmlCacyNzjS5G6nxhtCt9e1p3/jByTxcIayDInVdDSw3sv7ZkxsmRR19OavRTL6g+ZK9NEqRcA==","shasum":"c897cefd61efdf110ef7ef13669207cdf0155009","tarball":"https://registry.npmjs.org/@actualwave/tree-walker/-/tree-walker-0.0.4.tgz","fileCount":28,"unpackedSize":62885,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDpbcZlR3fhrWOGjtwDiGywJbgMKsdZL3E06WRlUrZJQQIgJT0hwDZnKGnuzWuhLKRal+lldUn/jvM7Nx0n6w84omA="}]},"maintainers":[{"name":"actualwave","email":"burdiuz@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tree-walker_0.0.4_1523181907718_0.5343545709778876"},"_hasShrinkwrap":false},"1.0.6":{"name":"@actualwave/tree-walker","description":"Wireframe based on ES6 Proxies for making tree traversing APIs.","version":"1.0.6","main":"dist/tree-walker.js","keywords":["js","javascript","proxy","tree","E4X"],"homepage":"https://github.com/burdiuz/js-tree-walker","bugs":{"url":"https://github.com/burdiuz/js-tree-walker/issues","email":"burdiuz@gmail.com"},"license":"MIT","author":{"name":"Oleg Galaburda","email":"burdiuz@gmail.com","url":"http://actualwave.com/"},"repository":{"type":"git","url":"git+https://github.com/burdiuz/js-tree-walker.git"},"dependencies":{"@actualwave/has-own":"0.0.1"},"devDependencies":{"babel-core":"^6.26.3","babel-eslint":"^8.2.6","babel-loader":"^7.1.5","babel-plugin-external-helpers":"^6.22.0","babel-plugin-istanbul":"^4.1.6","babel-plugin-syntax-trailing-function-commas":"^6.22.0","babel-plugin-transform-class-properties":"^6.24.1","babel-plugin-transform-es2015-modules-commonjs":"^6.26.2","babel-plugin-transform-flow-strip-types":"^6.22.0","babel-plugin-transform-object-rest-spread":"^6.26.0","babel-preset-jest":"^23.2.0","dotenv":"^6.0.0","eslint":"^5.4.0","eslint-config-airbnb":"^17.1.0","eslint-plugin-import":"^2.14.0","eslint-plugin-jsx-a11y":"^6.1.1","eslint-plugin-react":"^7.11.1","flow-bin":"^0.79.1","husky":"^0.14.3","jest":"^23.5.0","lint-staged":"^7.2.2","prettier":"^1.14.2","rollup-plugin-babel":"^3.0.7","rollup-plugin-commonjs":"^9.1.5","rollup-plugin-json":"^3.0.0","rollup-plugin-node-resolve":"^3.3.0","rollup-plugin-serve":"^0.4.2","rollup-plugin-uglify":"^4.0.0","uglify-es":"^3.3.9"},"lint-staged":{"source/**/*.js":["eslint --fix","git add"]},"babel":{"env":{"test":{"plugins":["babel-plugin-transform-es2015-modules-commonjs","babel-plugin-transform-flow-strip-types","babel-plugin-transform-class-properties",["babel-plugin-transform-object-rest-spread",{"useBuiltIns":true}]],"presets":["jest"]}}},"jest":{"collectCoverage":true,"coverageReporters":["json","lcov"],"coverageDirectory":"coverage","collectCoverageFrom":["source/**/*.js","!**/node_modules/**","!**/vendor/**"],"modulePathIgnorePatterns":["\\/\\."]},"scripts":{"start":"build","build":"rollup --config","build:watch":"rollup --config --watch \"./source\"","lint":"eslint \"source/**/*.js\"","test":"jest --colors","test:watch":"jest --colors --watch","lint-staged":"lint-staged","precommit":"npm run lint-staged && npm run build && npm run test"},"gitHead":"9e234defd10f256c1db326e0d0d7275f4b54054f","_id":"@actualwave/tree-walker@1.0.6","_npmVersion":"5.6.0","_nodeVersion":"8.11.3","_npmUser":{"name":"actualwave","email":"burdiuz@gmail.com"},"dist":{"integrity":"sha512-NpkVp7Il3ObnSGdy8Hut/ZqmNv96RnqGAJC+HiehRHf0f+/DKAWY/swtHJbDiownLrhTAIdl2ruCTyuUfvLOug==","shasum":"90f2abc5b9e4742fa8be5d40acc0bdc6bcd73558","tarball":"https://registry.npmjs.org/@actualwave/tree-walker/-/tree-walker-1.0.6.tgz","fileCount":8,"unpackedSize":92514,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJblt6dCRA9TVsSAnZWagAA7wgQAIgH4kJQku61wobS9UD1\nVTBEkWnI8xKloh8enhI7S5ga179LmgZxQdXwkZirdLLQqy7tE8eChZQMBDBq\n5wq1iouyagdSn9A/1toUlkG3ctGEJf39dBuj8DfUfuEk6Yt5bNBn97X+Zfyj\ncySnP5whBVbsdzlIBe52TjjjXK4DzE/OZEc0wtd5hNvpiG57Kg5RiZlQ9I/i\nON8PIeaQ8n1P32WtdZLqeMQ0L+IMtqfYteW6Q8d3X4TANSEPLvfIlGnOAR6j\nHOy3WNuAdXeQaQJWmQ5w9HoHPEKTciuTqE0bX6+ydDD/PcbRijQD5yqmg1CI\nutS8iKxHGAq8fjAKvOq8kL/G4XQ7KSSC31EVW1L/203MrWoBTkDCwocw9AdN\nXuhsw+3Wl1IUjtDYl136MFUXKy8HcoReHa5bQkVpIICeGT5FDKZND+1jIkH/\n51D35FtQy758lZpxY6udtYYJc4LejCcIdzpXxEx3xtFL5hCDKTDk4ck/Rzb/\nPfJ/cmTx4lIrxOvJTfTjVH9n/uLjbN+S2DcXcKE7lbERNv5rkXoVjnsRC9ii\nYznbcDQtJpHmpsWf+u64pt6mGRZB40yooqWgghGux/2dcpFOH/96MyXunOFo\nbRUqPWcrmqB7Ey8c16OHw9x53CrPfSqco+/20Be7tvLxzFOSeQukD3ud8iKt\nbNKY\r\n=KO31\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQD1DD2wXWbtmmmOla0dOroBO0QFqDgNnPEA9pETpE33AAIgSTiyk0BWV/kAeX0ppqmoVKdRxmyq20cCRGKSDXoWVlU="}]},"maintainers":[{"name":"actualwave","email":"burdiuz@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tree-walker_1.0.6_1536614044718_0.6821882580316871"},"_hasShrinkwrap":false},"1.0.7":{"name":"@actualwave/tree-walker","description":"Wireframe based on ES6 Proxies for making tree traversing APIs.","version":"1.0.7","main":"dist/tree-walker.js","keywords":["js","javascript","proxy","tree","E4X"],"homepage":"https://github.com/burdiuz/js-tree-walker","bugs":{"url":"https://github.com/burdiuz/js-tree-walker/issues","email":"burdiuz@gmail.com"},"license":"MIT","author":{"name":"Oleg Galaburda","email":"burdiuz@gmail.com","url":"http://actualwave.com/"},"repository":{"type":"git","url":"git+https://github.com/burdiuz/js-tree-walker.git"},"dependencies":{"@actualwave/has-own":"0.0.1"},"devDependencies":{"babel-core":"^6.26.3","babel-eslint":"^8.2.6","babel-loader":"^7.1.5","babel-plugin-external-helpers":"^6.22.0","babel-plugin-istanbul":"^4.1.6","babel-plugin-syntax-trailing-function-commas":"^6.22.0","babel-plugin-transform-class-properties":"^6.24.1","babel-plugin-transform-es2015-modules-commonjs":"^6.26.2","babel-plugin-transform-flow-strip-types":"^6.22.0","babel-plugin-transform-object-rest-spread":"^6.26.0","babel-preset-jest":"^23.2.0","dotenv":"^6.0.0","eslint":"^5.4.0","eslint-config-airbnb":"^17.1.0","eslint-plugin-import":"^2.14.0","eslint-plugin-jsx-a11y":"^6.1.1","eslint-plugin-react":"^7.11.1","flow-bin":"^0.79.1","husky":"^0.14.3","jest":"^23.5.0","lint-staged":"^7.2.2","prettier":"^1.14.2","rollup-plugin-babel":"^3.0.7","rollup-plugin-commonjs":"^9.1.5","rollup-plugin-json":"^3.0.0","rollup-plugin-node-resolve":"^3.3.0","rollup-plugin-serve":"^0.4.2","rollup-plugin-uglify":"^4.0.0","uglify-es":"^3.3.9"},"lint-staged":{"source/**/*.js":["eslint --fix","git add"]},"babel":{"env":{"test":{"plugins":["babel-plugin-transform-es2015-modules-commonjs","babel-plugin-transform-flow-strip-types","babel-plugin-transform-class-properties",["babel-plugin-transform-object-rest-spread",{"useBuiltIns":true}]],"presets":["jest"]}}},"jest":{"collectCoverage":true,"coverageReporters":["json","lcov"],"coverageDirectory":"coverage","collectCoverageFrom":["source/**/*.js","!**/node_modules/**","!**/vendor/**"],"modulePathIgnorePatterns":["\\/\\."]},"scripts":{"start":"build","build":"rollup --config","build:watch":"rollup --config --watch \"./source\"","lint":"eslint \"source/**/*.js\"","test":"jest --colors","test:watch":"jest --colors --watch","lint-staged":"lint-staged","precommit":"npm run lint-staged && npm run build && npm run test"},"gitHead":"aa38a8dba2eb055ce21aaf6c0bc90e81f06c15d6","_id":"@actualwave/tree-walker@1.0.7","_npmVersion":"5.6.0","_nodeVersion":"8.11.2","_npmUser":{"name":"actualwave","email":"burdiuz@gmail.com"},"dist":{"integrity":"sha512-CPb6LMrmYXOrr0f4yd37HYQcoWK/dehr0/VqIsfUhLB3H3A/lPnSjgACpG54tpus98OKDy7YWlhfQeMDsW35Dw==","shasum":"4a4d371d08cd36c4a3354d301ab4f1cb1f2c9de0","tarball":"https://registry.npmjs.org/@actualwave/tree-walker/-/tree-walker-1.0.7.tgz","fileCount":8,"unpackedSize":93497,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbsMLiCRA9TVsSAnZWagAAsB4P/1b2tqTRSL1EDxl5tVdm\n14dtLIpofNLpvO+eBDZBcm9JuxvXoyjEALE8UXAdhiBx3NkdtMS1ka0rdQCl\nPCzjXUp0JF6mSFPIFQlDhLh9EVUUh5rUzhcdmkRpBIrw2y3817Pdh230219p\nRTE7wCXrj0u2oRggHZTEtoleyuOH/a2fx6yFX1MOVix0Po8hjlPtM98khXzK\nqhHX/mFuKiYNt+ljtHnQImnozHp6/TB8iMsQnc0bqzNxhFtKPxY/u66y2Gyp\nxnzrptW7tJerllsUXPLYwAFB30ievK7kKSXSFvvDFYgZmp/r/a81bc8Vj220\nh+bvf8ADjqwsnw2ZStXXj1cM79+6bNWWi8tIKj34Thoz7jI30gPR2XSd0S10\nn4JXgpK4nZcPPSEJlMNs9TYyeFK87jF/HiNLGouwhZ91reWLoA9PkAbLyb04\nrKXsQLIY0/Y6Igc6Sst595DdqDNlvmslTNYcV/jdcI9eTLHuB7tYfp2fMNk7\nZXAtlTwwfQMsKo60liIVT4PP1kxJWkMjDAXnkaciYyrW7PxC7d0QrHyYrJyO\n2780FPBcWIuUT5uUX3wyztgdZKNav3UZhq6P1OWspqubgQUicqTKTq4pwemY\nLXGKDn6Q5lQatWjYiIDWMPPcZ3d/kb1947JP3ur6mRItq3XOowwGrOZU66DE\n5yfO\r\n=XSE6\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDm1MrdBjFvlYjPMhuvnNdHc3jABGFuCP6/t9Hl8GujsgIhAPpZo2YXHqsx1oqSB+H4ApbhasLPFVygNF1XdmhnyAW0"}]},"maintainers":[{"name":"actualwave","email":"burdiuz@gmail.com"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/tree-walker_1.0.7_1538310880886_0.5911476795359594"},"_hasShrinkwrap":false}},"time":{"created":"2018-04-08T10:05:07.659Z","0.0.4":"2018-04-08T10:05:07.814Z","modified":"2022-04-04T11:20:16.126Z","1.0.6":"2018-09-10T21:14:04.878Z","1.0.7":"2018-09-30T12:34:41.105Z"},"maintainers":[{"name":"actualwave","email":"burdiuz@gmail.com"}],"description":"Wireframe based on ES6 Proxies for making tree traversing APIs.","homepage":"https://github.com/burdiuz/js-tree-walker","keywords":["js","javascript","proxy","tree","E4X"],"repository":{"type":"git","url":"git+https://github.com/burdiuz/js-tree-walker.git"},"author":{"name":"Oleg Galaburda","email":"burdiuz@gmail.com","url":"http://actualwave.com/"},"bugs":{"url":"https://github.com/burdiuz/js-tree-walker/issues","email":"burdiuz@gmail.com"},"license":"MIT","readme":"\n# TreeWalker\n\n[![Build Status](https://travis-ci.org/burdiuz/js-tree-walker.svg?branch=master)](https://travis-ci.org/burdiuz/js-tree-walker) [![Coverage Status](https://coveralls.io/repos/github/burdiuz/js-tree-walker/badge.svg?branch=master)](https://coveralls.io/github/burdiuz/js-tree-walker?branch=master)\nThis is wireframe based on ES6 Proxies for making tree traversing APIs.\nYou may check ready to use implementation DOMWalker for better understanding.\nInspired by [E4X(ECMAScript for XML)](https://en.wikipedia.org/wiki/ECMAScript_for_XML) and its ActionScript 3 implementation(R.I.P.).\n\n### Demo\n* Using with [Object Children Adapter](https://github.com/burdiuz/js-walker-children-adapter): [TreeWalker Object Tree Demo](https://jsfiddle.net/actualwave/6kw7z4xj/).\n* Using with [Denormalize Adapter](https://github.com/burdiuz/js-walker-denormalize-adapter): [TreeWalker Normalized Tree Demo](https://jsfiddle.net/actualwave/5euz47hq/)\n* Using with [Browser DOM Adapter](https://github.com/burdiuz/js-walker-browserdom-adapter): [TreeWalker BrowserDOM Tree Demo](https://jsfiddle.net/actualwave/p1k4wjy2/)\n\n### Table of Contents\n* [Installation](#installation)\n* [How it works](#how_it_works)\n* [Usage](#usage)\n* [API](#api)\n* [Adapter](#adapter)\n* [Augmentations](#augmentations)\n* [Prefixes](#prefixes)\n\n<a name=\"installation\"></a>\n## Installation\n\nVia NPM\n```bash\nnpm install @actualwave/tree-walker --save\n```\nOr Yarn\n```bash\nyarn add @actualwave/tree-walker\n```\n\nAfter importing TreeWalker, it needs to be configured to specify default adapter and augmentations, prefixes.\n\nWithout any configurations you will be able to access child nodes\n```javascript\nconst root = create(souceData);\nconst myDescendants = root.child.otherChild.descendant;\n```\n\nbut no methods can be called on them except\n* valueOf() -- to return raw data(source node)\n* toString() -- to call `toString()` method on source node\n\n\n<a name=\"how_it_works\"></a>\n## How it works\n\nTo start working with source data tree, it should be wrapped into a [Proxy wrapper object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) using`create()` function. But wrapper does not work with source data directly, all communication with source data is done via `adapter` object which should implement specific API.\n\nSo we pass source data and adapter object which knows how to work with this data to `create()` function.\n```javascript\nconst root = create(souceData, myAdapter);\n```\n\nWhen requesting any field/property/index from Proxy wrapper, it does not return values of corresponding properties of the source node, but tries to get children nodes of same name or index.\n```javascript\n/*\n  this does not request property \"child\" of \"souceData\"\n  it will look for all chidren nodes with name \"child\"\n*/\nconst child = root.child;\n\n/*\n  this will look for fifth child node with name \"child\"\n*/\nconst fifth = root.child[5];\n```\nWrapper will access children nodes with `getChildren()` and `getChildrenByName()` methods of adapter object.\n\n```javascript\nconst root = create(mySourceTreeData, myAdapter);\nconst myDescendants = root.child.otherChild.descendant;\nconst myThirdChild = root.child[2];\nconst jerries = myDescendants.jerry;\n```\nWith this code, on line 1, Proxy object for root node of the source tree is created. On line 2 additional Proxies are created for `child`, `otherChild` and proxy for `descendant` nodes is stored in `myDescendants`.\n\nWhen requesting a child node by name, it returns not one node but a list of all child nodes with same name, but when children requested from the list(like `otherChild` from `child` or `descendant` from `otherChild` or `jerry` from `myDescendants`), Proxy will take first node from this list and return its children.\n\nSo, if you have a list of 2 nodes where first does not have children\n\n```javascript\nconst root = <source data>;\n/**\nnode structure\n     root\n     / \\\none[0] one[1]\n        /  \\\n    two[0] two[1]\n*/\n\nconst rootProxy = create(root, myAdapter);\nconst twoProxy = rootProxy.one.two;\n```\n`twoProxy` will contain empty list, because only first `one` node is checked for children.\nHere are equivalent code\n```javascript\nconst rootProxy = create(root, myAdapter);\nconst twoProxy = rootProxy.one[0].two;\n```\n\nTo retrieve children from second `one` node you should specify it, like this\n```javascript\nconst rootProxy = create(root, myAdapter);\nconst twoProxy = rootProxy.one[1].two;\n```\nNow we will have two `two` nodes in `twoProxy`.\n\nAdapter should always return empty list if no nodes found\n```javascript\nconst rootProxy = create(root, myAdapter);\nconst veryDeepNode = rootProxy.one.five.seven.anyOther.dont.know.if.it.exists;\n```\nin this way you can request any descendants from any depth without worrying about their existence.\n\n<a name=\"usage\"></a>\n## Usage\n\nTo use TreeWalker, it should be supplied with two required components:\n\n1. Source data - Tree data structure, that you want to work with\n\n2. Adapter - Provides standardized API to work with source data\n\nAdditionally augmentations and prefixes could be used to enrich final API.\n\nBefore using, TreeWalker must be created via factory function `create()`, it returns source data wrapped into a Proxy wrapper(just \"wrapper\" in text below) which will use adapter to get children nodes, call augmentations and apply prefixes. TreeWrapper is read-only tree traverser, so it has only `get`, `has` and `apply` traps, `set` or `deleteProperty` are not implemented. But you may create an augmentation for source data mutations(explained below).\n\n```javascript\nimport { create } from '@actualwave/tree-walker';\n\n// root is a wrapped \"source\" node\nconst root = create(source, myAdapter);\n```\n\nAfter instantiating, you can access child nodes as properties and augmentations as methods. Its possible to have methods and nodes of same name, because, when wrapper is created for child object, it stores parent node and name of child node.\n\nIf property is requested from wrapper, it will return new wrapper with that node and name of the property:\n```javascript\n// stores { target: node, name: \"parent\" }\nconst parent = node.parent;\n\n// stores { target: parent, name: \"otherChild\" }\nconst child = parent.otherChild;\n\n// stores { target: child, name: \"sibblings\" }\nconst sibblings = child.sibblings;\n```\nor\n```javascript\n// stores { target: otherChild, name: \"sibblings\" }\nconst sibblings = node.parent.otherChild.sibblings;\n```\nIf `sibblings` node from example above will be replaced in a source tree or removed, your wrapper object will reflect changes.\n\nWhen requesting a child, wrapper uses `getChildren()` and `getChildrenByName()` methods of adapter, so its always a list of nodes, even if single child available -- it will be a list with one child.\n```javascript\nconst firstSibbling = sibblings[0];\n```\n\nWhen requesting a child from wrapped list of nodes, wrapper will request children of first node from the list.\n\n> Adapter methods `toList()`, `getChildren()` and `getChildrenByName()` must always return list of nodes. In case of 0 nodes it should be empty list. Single node must have length 1 and, if requested, index 0 must return same node.\n\nIf you wish to have specific node in a wrapper, you can request it by specifying index:\n```javascript\n// stores { target: otherChild }\nconst sibblings = node.parent.otherChild[0];\n```\nIn this case wrapper will contain one node resolved by name.\n\nIf wrapper is being called as function, it will look for augmentation registered for that name:\n```javascript\n// stores { target: node, name: \"parent\" }\nconst parent = node.parent;\n\n// will call augmentation\nconsole.log(parent());\n```\nor\n```javascript\n// will call augmentation \"descendants\" on \"otherChild\" node\nconsole.log(node.child.otherChild.descendants());\n```\nImportant to say, that wrapper has set of restricted names for child nodes\n**constructor**\n**prototype**\nValues of these properties will be requested directly from source node or list and returned as is.\n\n<a name=\"api\"></a>\n## API\n\n*  **create(rootNode, adapter)** -- create wrapper for node and use supplied adapter to work with it\n\n*  **setDefaultAdapter(adapter)** -- specifying default adapter makes optional defining adapter in `create()` factory function\n\n*  **getDefaultAdapter(adapter)** -- get default adapter\n\n*  **addAugmentations({...})** -- add augmentations to the pool, accepts an object with functions, name of the property will be used as name of augmentation.\n\n```javascript\naddAugmentations({\n\tchildren: (node, adapter, utils) => {...},\n\tparent: (node, adapter, utils) => {...},\n\tname: (node, adapter, utils) => {...},\n});\n```\n\n*  **hasAugmentation(name)** -- check if augmentation was added\n\n*  **resetAugmentations({...})** -- remove all currently registered augmentations(including core augmentations) and, replace them with augmentations if passed\n\n*  **setNamePrefix(char, handlerFunc)** -- set prefix handler\n\n*  **isValidPrefix(char)** -- check if prefix is valid and has handler registered\n\n<a name=\"adapter\"></a>\n## Adapter\n\nAdapter is an object with set of methods required by wrapper and augmentations to work with source data. Each instance of wrapper and augmentation calls receive instance of adapter as well as target node or list of nodes to pass into adapter. All calls to source data should be done via adapter API.\n\nAdapter API(required methods marked with bold)\n\n*  **validateRoot(item)** -- is called before crating wrapper for root node, could accept anything and must return root node.\n\n*  **isList(item)** -- check if item is a list\n\n*  **toList(item)** -- convert anything to list, node to list with one item or nothing to empty list\n\n* getLength(item) -- returns length of the item, in case of node it should be 1\n\n*  **getNodeAt(item, index = 0)** -- return node from a list by its index\n\n*  **isNode(item)** -- check if item is single node\n\n*  **toNode(item)** -- convert anything to node, if possible. If list, get first node from it\n\n* getName(item) -- return name of the node\n\n* hasChild(item, name) -- check if node has children with specified name\n\n*  **getChildren(item)** -- get list of all children from node\n\n*  **getChildrenByName(item, name)** -- get list of children with specified name\n\n* getChildAt: (item, index = 0) -- get child of the node by index\n\n* getNodeParent(item) -- get node parent\n\n* getNodeRoot(item) -- get root node of the tree\n\n* value(item) -- get source value behind the wrapper\n\n* string(item) -- get string representation of source value .\n\nAll methods should work equally with lists and nodes, if it requires node but was supplied with list, it should get first node from the list and continue and vice versa -- if list is required but node supplied, convert it to list with one node and proceed.\n\n> You are free to add any methods or properties to adapter for your custom augmentations, but its not recommended to change signature of described here methods.\n\n<a name=\"augmentations\"></a>\n## Augmentations\n\nAugmentations are simple functions which receive set of arguments and result with any kind of data(not limited to nodes). Augmentations work only when called as function, otherwise it's treated as wrapped node:\n\n```javascript\n// add \"children\" augmentation\naddAugmentations({\n\tchildren: (node, adapter, [childName], utils) => {\n\t\tlet list;\n\t\tif (childName) {\n\t\t\tlist = adapter.getChildrenByName(node, childName);\n\t\t} else {\n\t\t\tlist = adapter.getChildren(node);\n\t\t}\n\n\t\treturn utils.wrap(list, adapter);\n\t},\n}};\n\n// now augmentation may be called from any wrapped node\nconst root = create(source, myAdapter);\n\n// list of \"children\" nodes\nconst children1 = root.children;\n\n// result of \"children\" augmentation call\nconst children2 = root.children();\n```\nWhen wrapper received a function call, it checks for available augmentations and if its available, its being called. In other cases it will act as node list retrieved by name, so this will work too.\n\n```javascript\n// result of \"children\" augmentation call\nconst children2 = children1();\n```\nBecause wrapper in `children1` have stored its parent `root` node and `children` name.\n\nTreeWalker supplied with set of basic augmentations:\n\n#### coreAugmentations\nThere are only two augmentations `toString()` and `valueOf()`, they are pre-applied.\n\n*  **valueOf():any** -- If adapter has `value()` method, it will be called, otherwise unwrap source node or list of nodes and return it\n\n*  **toString():String** -- If adapter has `string()` method, it will be called, otherwise call `toString()` method on source node\n\n#### nodeAugmentations\nSet of augmentations to work with nodes and their children.\n\n*  **children(name:String?):WrappedNode[]** - List of all children nodes, if name is supplied, list will be filtered by name.\n\n*  **descendants(name:String?):WrappedNode[]** - List of all descendant nodes, if name is supplied, list will be filtered by name.\n\n*  **childAt (index:Number=0):WrappedNode** - Child node at index\n\n*  **root():WrappedNode** - Root node of the tree\n\n*  **parent():WrappedNode** - Parent node\n\n#### listAugmentations\nSet of augmentations to work with lists.\n\n*  **length():Number** - Length of the list, will return 1 for single wrapped node\n\n*  **at(index:Number=0):WrappedNode** - Get item from list by index, can be called on single node as on list with one item\n\n*  **first():WrappedNode** - Get first item from the list, can be called in single node, will return itself\n\n*  **filter(handler:Function):WrappedNode[]** - Filter list of nodes, will return filtered list\n\n*  **map(handler:Function):any[]** - Map list of nodes, will return list with map results for each node\n\n*  **reduce(handler:Function, initialValue:any?):any** - Reduce list of nodes will return final value\n\n<a name=\"prefixes\"></a>\n## Prefixes\n\nPrefix is always a one symbol string, any character. It maps a function which will be called when property is requested([`get` Proxy trap](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/get)).\n\nTo access properties of this object we can use prefixes, so we register a special handler function which wil be called when we request a property from `data` object:\n\n```javascript\nconst dataPrefixGetHandler = (target, adapter, [name]) => {\n\tconst node = adapter.toNode(target);\n\treturn node.data ? node.data[name] : undefined;\n};\n\nsetNamePrefix(\"$\", dataPrefixGetHandler);\n```\n\nHandler receives source node, adapter, list of arguments in case of function call and utils object which contains method to wrap with Proxy.\n\nAfter registering this prefix, we may access node properties stored in `data` like this\n```javascript\nconst root = create(source, myAdapter);\n\nconsole.log(root.$prop1); // will request \"prop1\" from \"data\" object\nconsole.log(root.child.$prop1); // will request \"prop1\" from \"data\" object of \"child\" node\n```\n\nFor example, let's imagine that every node in our tree has some `data` object which holds additional properties of the node. But data object may have properties with same name as children nodes:\n```javascript\n// node object structure\nconst source = {\n  name: 'node',\n  data: {\n    prop1: true,\n    prop2: 'my value',\n  },\n  children: [\n    { name: 'prop1', data: {} },\n    { name: 'prop2', data: {} },\n  ],\n};\n```\n\nThe solution to access `data` properties is to prefix every data property with special symbol -- you don't need to rename every `data` property, just add prefix when requesting it through wrapper.\n```javascript\n// register prefix\nsetNamePrefix(\"$\", dataPrefixGetHandler);\n\n// access data\nconsole.log(wrappedNode.$prop1); // true\nconsole.log(wrappedNode.$prop2); // \"my value\"\n```\n\nBy using one handler you receive read-only access to prefixed properties, to extend control, additionally to `get` handler you may also register handlers to [`has`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/has), [`set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/set) and [`depeteProperty`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/deleteProperty) Proxy traps.\n```javascript\nconst dataPrefixGetHandler = (target, adapter, [name]) => {\n  const node = adapter.toNode(target);\n  return node.data ? node.data[name] : undefined;\n};\n\nconst dataPrefixHasHandler = (target, adapter, [name]) => {\n  const node = adapter.toNode(target);\n  return node.data ? node.data.hasOwnProperty(name) : false;\n};\n\nconst dataPrefixSetHandler = (target, adapter, [name, value]) => {\n  const node = adapter.toNode(target);\n  if (!node.data) {\n    node.data = {};\n  }\n\n  node.data[name] = value;\n  return true;\n};\n\nconst dataPrefixDeleteHandler = (target, adapter, [name]) => {\n  const node = adapter.toNode(target);\n  return node.data ? delete node.data[name] : false;\n};\n\nsetNamePrefix('$', {\n  get: dataPrefixGetHandler,\n  has: dataPrefixHasHandler,\n  set: dataPrefixSetHandler,\n  deleteProperty: dataPrefixDeleteHandler,\n});\n```\n\nFor additional example of prefix utilization, check [`js-dom-walker`](https://github.com/burdiuz/js-dom-walker) project, it uses `$` as prefix for DOM node attributes.\n","readmeFilename":"README.md"}