├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE.txt ├── README.md ├── coverage ├── coverage.json ├── lcov-report │ ├── base.css │ ├── index.html │ ├── introspected │ │ ├── index.html │ │ └── introspected.js.html │ ├── prettify.css │ ├── prettify.js │ ├── sort-arrow-sprite.png │ └── sorter.js └── lcov.info ├── index.html ├── introspected.js ├── min.js ├── package.json └── test ├── class-state.js ├── how-to-diff.js └── introspected.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | coverage/* 2 | node_modules/* 3 | test 4 | test/* 5 | test/introspected.js 6 | .gitignore 7 | .travis.yml 8 | index.html 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 6 4 | - 8 5 | git: 6 | depth: 1 7 | branches: 8 | only: 9 | - master 10 | after_success: 11 | - "npm run coveralls" 12 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2017, Andrea Giammarchi, @WebReflection 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 10 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 12 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 | OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 | PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introspected 2 | 3 | [![Build Status](https://travis-ci.org/WebReflection/introspected.svg?branch=master)](https://travis-ci.org/WebReflection/introspected) [![Coverage Status](https://coveralls.io/repos/github/WebReflection/introspected/badge.svg?branch=master)](https://coveralls.io/github/WebReflection/introspected?branch=master) [![donate](https://img.shields.io/badge/$-donate-ff69b4.svg?maxAge=2592000&style=flat)](https://github.com/WebReflection/donate) 4 | 5 | [Medium presentation post](https://medium.com/@WebReflection/introspected-js-objects-without-secrets-55cf0bd3dccc) 6 | - - - 7 | 8 | If you'd like to be notified about any possible change that could happen to a JSON compatible model / data / object / array / structure, 9 | including the possibility to retrieve the exact full path of the object that changed and eventually walk through it, 10 | you've reached your destination. 11 | 12 | ```js 13 | const data = Introspected( 14 | // any object or JSON compatible structure 15 | // even with nested properties, objects, arrays 16 | JSON.parse('{}'), 17 | (root, path) => { 18 | // the root object that changed 19 | console.log(root); 20 | // the path that just changed 21 | console.log(path); 22 | } 23 | ); 24 | 25 | // now try the following in console 26 | data.a.b.c.d.e.f.g = 'whatever'; 27 | data.array.value = [1, 2, 3]; 28 | data.array.value.push(4); 29 | // see all notifications about all changes 🎉 30 | 31 | JSON.stringify(data); 32 | // {"a":{"b":{"c":{"d":{"e":{"f":{"g":"whatever"}}}}}},"array":{"value":[1,2,3,4]}} 33 | ``` 34 | 35 | 36 | # API 37 | 38 | * `Introspected(objectOrArray[, callback])` create a new `Introspected` object capable of having infinite depth without ever throwing errors 39 | * `Introspected.observe(objectOrArray, callback)` crate a `Introspected` with a notifier per each change, or set a notifier per each change to an existent `Introspected` object 40 | * `Introspected.pathValue(objectOrArray, path)` walk through an object via a provided path. A `path` is an `Array` of properties, it is usually the one received through the notifier whenever a `Introspected` object is **observed**. 41 | 42 | 43 | # Compatibility 44 | 45 | Any spec compliant ES2015 JavaScript engine. 46 | 47 | (that means native `WeakMap`, `Proxy` and `Symbol.toPrimitive` too) 48 | 49 | [Live test page](https://webreflection.github.io/introspected/) 50 | 51 | **Working:** NodeJS 6+, Chrome, Safari, GNOME Web, Edge, Firefox, Samsung Internet (Chrome 51) 52 | 53 | **Not there yet:** UC Browser (WebKit 534) 54 | 55 | 56 | ## ISC License 57 | 58 | -------------------------------------------------------------------------------- /coverage/coverage.json: -------------------------------------------------------------------------------- 1 | {"/home/webreflection/code/introspected/introspected.js":{"path":"/home/webreflection/code/introspected/introspected.js","s":{"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":4,"10":1,"11":1,"12":1,"13":1,"14":1,"15":1,"16":9,"17":9,"18":8,"19":6,"20":6,"21":6,"22":6,"23":21,"24":21,"25":6,"26":6,"27":6,"28":9,"29":1,"30":2,"31":1,"32":2,"33":16,"34":3,"35":96,"36":30,"37":4,"38":41,"39":41,"40":21,"41":21,"42":16,"43":15,"44":15,"45":15,"46":16,"47":1,"48":9,"49":9,"50":9,"51":22,"52":9,"53":1,"54":15,"55":15,"56":15,"57":15,"58":12,"59":12,"60":15,"61":1,"62":61,"63":61,"64":61,"65":1,"66":63,"67":10,"68":53,"69":21,"70":21,"71":32,"72":1,"73":61,"74":1,"75":18,"76":18,"77":16,"78":16,"79":22,"80":22,"81":11,"82":16,"83":16,"84":14,"85":8,"86":16,"87":5,"88":5,"89":16,"90":2,"91":1,"92":1,"93":2,"94":1,"95":1,"96":2,"97":7,"98":1,"99":1,"100":1},"b":{"1":[8,1],"2":[6,15],"3":[21,6],"4":[1,1],"5":[2,1,1],"6":[30,2,4,41,21],"7":[15,1],"8":[2,14],"9":[10,53],"10":[10,9],"11":[21,32],"12":[53,21],"13":[5,16],"14":[1,20],"15":[20,15],"16":[13,48],"17":[16,2],"18":[18,16,14],"19":[12,4],"20":[16,14],"21":[14,2],"22":[5,11],"23":[1,1],"24":[3,4],"25":[7,4]},"f":{"1":6,"2":2,"3":16,"4":3,"5":96,"6":16,"7":9,"8":15,"9":61,"10":63,"11":61,"12":18,"13":22},"fnMap":{"1":{"name":"(anonymous_1)","line":34,"loc":{"start":{"line":34,"column":11},"end":{"line":34,"column":14}}},"2":{"name":"(anonymous_2)","line":54,"loc":{"start":{"line":54,"column":18},"end":{"line":54,"column":33}}},"3":{"name":"(anonymous_3)","line":61,"loc":{"start":{"line":61,"column":18},"end":{"line":61,"column":21}}},"4":{"name":"(anonymous_4)","line":65,"loc":{"start":{"line":65,"column":7},"end":{"line":65,"column":22}}},"5":{"name":"(anonymous_5)","line":69,"loc":{"start":{"line":69,"column":7},"end":{"line":69,"column":22}}},"6":{"name":"(anonymous_6)","line":88,"loc":{"start":{"line":88,"column":7},"end":{"line":88,"column":29}}},"7":{"name":"importArray","line":98,"loc":{"start":{"line":98,"column":2},"end":{"line":98,"column":46}}},"8":{"name":"importObject","line":107,"loc":{"start":{"line":107,"column":2},"end":{"line":107,"column":47}}},"9":{"name":"register","line":118,"loc":{"start":{"line":118,"column":2},"end":{"line":118,"column":45}}},"10":{"name":"setValue","line":128,"loc":{"start":{"line":128,"column":2},"end":{"line":128,"column":57}}},"11":{"name":"wrap","line":147,"loc":{"start":{"line":147,"column":2},"end":{"line":147,"column":24}}},"12":{"name":"Introspected","line":153,"loc":{"start":{"line":153,"column":2},"end":{"line":153,"column":42}}},"13":{"name":"(anonymous_13)","line":161,"loc":{"start":{"line":161,"column":8},"end":{"line":161,"column":24}}}},"statementMap":{"1":{"start":{"line":2,"column":0},"end":{"line":194,"column":11}},"2":{"start":{"line":2,"column":28},"end":{"line":2,"column":41}},"3":{"start":{"line":5,"column":2},"end":{"line":5,"column":40}},"4":{"start":{"line":6,"column":2},"end":{"line":6,"column":40}},"5":{"start":{"line":7,"column":2},"end":{"line":7,"column":26}},"6":{"start":{"line":8,"column":2},"end":{"line":8,"column":46}},"7":{"start":{"line":9,"column":2},"end":{"line":9,"column":24}},"8":{"start":{"line":10,"column":2},"end":{"line":10,"column":31}},"9":{"start":{"line":10,"column":28},"end":{"line":10,"column":30}},"10":{"start":{"line":11,"column":2},"end":{"line":11,"column":42}},"11":{"start":{"line":12,"column":2},"end":{"line":12,"column":32}},"12":{"start":{"line":13,"column":2},"end":{"line":13,"column":22}},"13":{"start":{"line":14,"column":2},"end":{"line":14,"column":41}},"14":{"start":{"line":18,"column":2},"end":{"line":18,"column":30}},"15":{"start":{"line":21,"column":2},"end":{"line":49,"column":9}},"16":{"start":{"line":32,"column":4},"end":{"line":32,"column":34}},"17":{"start":{"line":33,"column":4},"end":{"line":47,"column":6}},"18":{"start":{"line":33,"column":12},"end":{"line":47,"column":6}},"19":{"start":{"line":35,"column":8},"end":{"line":35,"column":49}},"20":{"start":{"line":36,"column":8},"end":{"line":36,"column":35}},"21":{"start":{"line":37,"column":8},"end":{"line":37,"column":37}},"22":{"start":{"line":38,"column":8},"end":{"line":43,"column":9}},"23":{"start":{"line":39,"column":10},"end":{"line":39,"column":32}},"24":{"start":{"line":40,"column":10},"end":{"line":42,"column":11}},"25":{"start":{"line":41,"column":12},"end":{"line":41,"column":53}},"26":{"start":{"line":44,"column":8},"end":{"line":44,"column":27}},"27":{"start":{"line":45,"column":8},"end":{"line":45,"column":22}},"28":{"start":{"line":48,"column":4},"end":{"line":48,"column":22}},"29":{"start":{"line":52,"column":2},"end":{"line":96,"column":4}},"30":{"start":{"line":55,"column":6},"end":{"line":57,"column":7}},"31":{"start":{"line":56,"column":8},"end":{"line":56,"column":34}},"32":{"start":{"line":58,"column":6},"end":{"line":58,"column":18}},"33":{"start":{"line":62,"column":8},"end":{"line":62,"column":22}},"34":{"start":{"line":66,"column":8},"end":{"line":66,"column":30}},"35":{"start":{"line":70,"column":6},"end":{"line":85,"column":7}},"36":{"start":{"line":72,"column":10},"end":{"line":72,"column":30}},"37":{"start":{"line":75,"column":10},"end":{"line":75,"column":29}},"38":{"start":{"line":77,"column":10},"end":{"line":77,"column":30}},"39":{"start":{"line":77,"column":23},"end":{"line":77,"column":29}},"40":{"start":{"line":79,"column":10},"end":{"line":79,"column":41}},"41":{"start":{"line":80,"column":10},"end":{"line":84,"column":15}},"42":{"start":{"line":89,"column":6},"end":{"line":93,"column":7}},"43":{"start":{"line":90,"column":8},"end":{"line":90,"column":39}},"44":{"start":{"line":91,"column":8},"end":{"line":91,"column":54}},"45":{"start":{"line":92,"column":8},"end":{"line":92,"column":21}},"46":{"start":{"line":94,"column":6},"end":{"line":94,"column":18}},"47":{"start":{"line":98,"column":2},"end":{"line":105,"column":3}},"48":{"start":{"line":99,"column":4},"end":{"line":99,"column":32}},"49":{"start":{"line":100,"column":4},"end":{"line":100,"column":33}},"50":{"start":{"line":101,"column":4},"end":{"line":103,"column":5}},"51":{"start":{"line":102,"column":6},"end":{"line":102,"column":52}},"52":{"start":{"line":104,"column":4},"end":{"line":104,"column":44}},"53":{"start":{"line":107,"column":2},"end":{"line":116,"column":3}},"54":{"start":{"line":108,"column":4},"end":{"line":108,"column":35}},"55":{"start":{"line":109,"column":4},"end":{"line":109,"column":37}},"56":{"start":{"line":110,"column":4},"end":{"line":110,"column":32}},"57":{"start":{"line":111,"column":4},"end":{"line":114,"column":5}},"58":{"start":{"line":112,"column":6},"end":{"line":112,"column":27}},"59":{"start":{"line":113,"column":6},"end":{"line":113,"column":58}},"60":{"start":{"line":115,"column":4},"end":{"line":115,"column":44}},"61":{"start":{"line":118,"column":2},"end":{"line":126,"column":3}},"62":{"start":{"line":119,"column":4},"end":{"line":123,"column":6}},"63":{"start":{"line":124,"column":4},"end":{"line":124,"column":28}},"64":{"start":{"line":125,"column":4},"end":{"line":125,"column":16}},"65":{"start":{"line":128,"column":2},"end":{"line":145,"column":3}},"66":{"start":{"line":129,"column":4},"end":{"line":144,"column":5}},"67":{"start":{"line":130,"column":6},"end":{"line":133,"column":10}},"68":{"start":{"line":134,"column":11},"end":{"line":144,"column":5}},"69":{"start":{"line":135,"column":6},"end":{"line":136,"column":45}},"70":{"start":{"line":137,"column":6},"end":{"line":141,"column":12}},"71":{"start":{"line":143,"column":6},"end":{"line":143,"column":27}},"72":{"start":{"line":147,"column":2},"end":{"line":151,"column":3}},"73":{"start":{"line":148,"column":4},"end":{"line":150,"column":45}},"74":{"start":{"line":153,"column":2},"end":{"line":185,"column":3}},"75":{"start":{"line":154,"column":4},"end":{"line":154,"column":34}},"76":{"start":{"line":155,"column":4},"end":{"line":184,"column":5}},"77":{"start":{"line":159,"column":6},"end":{"line":159,"column":66}},"78":{"start":{"line":160,"column":6},"end":{"line":167,"column":8}},"79":{"start":{"line":162,"column":10},"end":{"line":162,"column":44}},"80":{"start":{"line":163,"column":10},"end":{"line":163,"column":52}},"81":{"start":{"line":163,"column":33},"end":{"line":163,"column":50}},"82":{"start":{"line":168,"column":6},"end":{"line":168,"column":27}},"83":{"start":{"line":169,"column":6},"end":{"line":171,"column":8}},"84":{"start":{"line":169,"column":19},"end":{"line":171,"column":8}},"85":{"start":{"line":170,"column":16},"end":{"line":170,"column":70}},"86":{"start":{"line":172,"column":6},"end":{"line":175,"column":7}},"87":{"start":{"line":173,"column":8},"end":{"line":173,"column":31}},"88":{"start":{"line":174,"column":8},"end":{"line":174,"column":29}},"89":{"start":{"line":176,"column":6},"end":{"line":176,"column":20}},"90":{"start":{"line":178,"column":6},"end":{"line":182,"column":7}},"91":{"start":{"line":179,"column":8},"end":{"line":179,"column":53}},"92":{"start":{"line":181,"column":8},"end":{"line":181,"column":29}},"93":{"start":{"line":183,"column":6},"end":{"line":183,"column":20}},"94":{"start":{"line":187,"column":2},"end":{"line":187,"column":38}},"95":{"start":{"line":189,"column":2},"end":{"line":190,"column":64}},"96":{"start":{"line":190,"column":4},"end":{"line":190,"column":63}},"97":{"start":{"line":190,"column":26},"end":{"line":190,"column":55}},"98":{"start":{"line":192,"column":2},"end":{"line":192,"column":22}},"99":{"start":{"line":196,"column":0},"end":{"line":196,"column":52}},"100":{"start":{"line":196,"column":6},"end":{"line":196,"column":36}}},"branchMap":{"1":{"line":33,"type":"if","locations":[{"start":{"line":33,"column":4},"end":{"line":33,"column":4}},{"start":{"line":33,"column":4},"end":{"line":33,"column":4}}]},"2":{"line":40,"type":"if","locations":[{"start":{"line":40,"column":10},"end":{"line":40,"column":10}},{"start":{"line":40,"column":10},"end":{"line":40,"column":10}}]},"3":{"line":40,"type":"binary-expr","locations":[{"start":{"line":40,"column":14},"end":{"line":40,"column":39}},{"start":{"line":40,"column":43},"end":{"line":40,"column":56}}]},"4":{"line":55,"type":"if","locations":[{"start":{"line":55,"column":6},"end":{"line":55,"column":6}},{"start":{"line":55,"column":6},"end":{"line":55,"column":6}}]},"5":{"line":55,"type":"binary-expr","locations":[{"start":{"line":55,"column":10},"end":{"line":55,"column":24}},{"start":{"line":55,"column":28},"end":{"line":55,"column":47}},{"start":{"line":55,"column":51},"end":{"line":55,"column":68}}]},"6":{"line":70,"type":"switch","locations":[{"start":{"line":71,"column":8},"end":{"line":72,"column":30}},{"start":{"line":73,"column":8},"end":{"line":73,"column":34}},{"start":{"line":74,"column":8},"end":{"line":75,"column":29}},{"start":{"line":76,"column":8},"end":{"line":77,"column":30}},{"start":{"line":78,"column":8},"end":{"line":84,"column":15}}]},"7":{"line":89,"type":"if","locations":[{"start":{"line":89,"column":6},"end":{"line":89,"column":6}},{"start":{"line":89,"column":6},"end":{"line":89,"column":6}}]},"8":{"line":89,"type":"cond-expr","locations":[{"start":{"line":89,"column":28},"end":{"line":89,"column":40}},{"start":{"line":89,"column":43},"end":{"line":89,"column":49}}]},"9":{"line":129,"type":"if","locations":[{"start":{"line":129,"column":4},"end":{"line":129,"column":4}},{"start":{"line":129,"column":4},"end":{"line":129,"column":4}}]},"10":{"line":131,"type":"binary-expr","locations":[{"start":{"line":131,"column":8},"end":{"line":131,"column":24}},{"start":{"line":132,"column":8},"end":{"line":132,"column":55}}]},"11":{"line":134,"type":"if","locations":[{"start":{"line":134,"column":11},"end":{"line":134,"column":11}},{"start":{"line":134,"column":11},"end":{"line":134,"column":11}}]},"12":{"line":134,"type":"binary-expr","locations":[{"start":{"line":134,"column":14},"end":{"line":134,"column":39}},{"start":{"line":134,"column":43},"end":{"line":134,"column":56}}]},"13":{"line":135,"type":"cond-expr","locations":[{"start":{"line":136,"column":22},"end":{"line":136,"column":36}},{"start":{"line":136,"column":39},"end":{"line":136,"column":44}}]},"14":{"line":137,"type":"cond-expr","locations":[{"start":{"line":138,"column":8},"end":{"line":138,"column":14}},{"start":{"line":138,"column":17},"end":{"line":141,"column":11}}]},"15":{"line":139,"type":"binary-expr","locations":[{"start":{"line":139,"column":10},"end":{"line":139,"column":27}},{"start":{"line":140,"column":10},"end":{"line":140,"column":59}}]},"16":{"line":148,"type":"cond-expr","locations":[{"start":{"line":149,"column":6},"end":{"line":149,"column":44}},{"start":{"line":150,"column":6},"end":{"line":150,"column":44}}]},"17":{"line":155,"type":"if","locations":[{"start":{"line":155,"column":4},"end":{"line":155,"column":4}},{"start":{"line":155,"column":4},"end":{"line":155,"column":4}}]},"18":{"line":155,"type":"binary-expr","locations":[{"start":{"line":155,"column":8},"end":{"line":155,"column":14}},{"start":{"line":156,"column":6},"end":{"line":156,"column":39}},{"start":{"line":157,"column":6},"end":{"line":157,"column":24}}]},"19":{"line":159,"type":"cond-expr","locations":[{"start":{"line":159,"column":48},"end":{"line":159,"column":60}},{"start":{"line":159,"column":63},"end":{"line":159,"column":65}}]},"20":{"line":159,"type":"binary-expr","locations":[{"start":{"line":159,"column":19},"end":{"line":159,"column":25}},{"start":{"line":159,"column":29},"end":{"line":159,"column":45}}]},"21":{"line":169,"type":"if","locations":[{"start":{"line":169,"column":6},"end":{"line":169,"column":6}},{"start":{"line":169,"column":6},"end":{"line":169,"column":6}}]},"22":{"line":172,"type":"if","locations":[{"start":{"line":172,"column":6},"end":{"line":172,"column":6}},{"start":{"line":172,"column":6},"end":{"line":172,"column":6}}]},"23":{"line":178,"type":"if","locations":[{"start":{"line":178,"column":6},"end":{"line":178,"column":6}},{"start":{"line":178,"column":6},"end":{"line":178,"column":6}}]},"24":{"line":190,"type":"cond-expr","locations":[{"start":{"line":190,"column":42},"end":{"line":190,"column":46}},{"start":{"line":190,"column":49},"end":{"line":190,"column":55}}]},"25":{"line":190,"type":"binary-expr","locations":[{"start":{"line":190,"column":27},"end":{"line":190,"column":28}},{"start":{"line":190,"column":32},"end":{"line":190,"column":38}}]}}}} -------------------------------------------------------------------------------- /coverage/lcov-report/base.css: -------------------------------------------------------------------------------- 1 | body, html { 2 | margin:0; padding: 0; 3 | height: 100%; 4 | } 5 | body { 6 | font-family: Helvetica Neue, Helvetica, Arial; 7 | font-size: 14px; 8 | color:#333; 9 | } 10 | .small { font-size: 12px; } 11 | *, *:after, *:before { 12 | -webkit-box-sizing:border-box; 13 | -moz-box-sizing:border-box; 14 | box-sizing:border-box; 15 | } 16 | h1 { font-size: 20px; margin: 0;} 17 | h2 { font-size: 14px; } 18 | pre { 19 | font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; 20 | margin: 0; 21 | padding: 0; 22 | -moz-tab-size: 2; 23 | -o-tab-size: 2; 24 | tab-size: 2; 25 | } 26 | a { color:#0074D9; text-decoration:none; } 27 | a:hover { text-decoration:underline; } 28 | .strong { font-weight: bold; } 29 | .space-top1 { padding: 10px 0 0 0; } 30 | .pad2y { padding: 20px 0; } 31 | .pad1y { padding: 10px 0; } 32 | .pad2x { padding: 0 20px; } 33 | .pad2 { padding: 20px; } 34 | .pad1 { padding: 10px; } 35 | .space-left2 { padding-left:55px; } 36 | .space-right2 { padding-right:20px; } 37 | .center { text-align:center; } 38 | .clearfix { display:block; } 39 | .clearfix:after { 40 | content:''; 41 | display:block; 42 | height:0; 43 | clear:both; 44 | visibility:hidden; 45 | } 46 | .fl { float: left; } 47 | @media only screen and (max-width:640px) { 48 | .col3 { width:100%; max-width:100%; } 49 | .hide-mobile { display:none!important; } 50 | } 51 | 52 | .quiet { 53 | color: #7f7f7f; 54 | color: rgba(0,0,0,0.5); 55 | } 56 | .quiet a { opacity: 0.7; } 57 | 58 | .fraction { 59 | font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; 60 | font-size: 10px; 61 | color: #555; 62 | background: #E8E8E8; 63 | padding: 4px 5px; 64 | border-radius: 3px; 65 | vertical-align: middle; 66 | } 67 | 68 | div.path a:link, div.path a:visited { color: #333; } 69 | table.coverage { 70 | border-collapse: collapse; 71 | margin: 10px 0 0 0; 72 | padding: 0; 73 | } 74 | 75 | table.coverage td { 76 | margin: 0; 77 | padding: 0; 78 | vertical-align: top; 79 | } 80 | table.coverage td.line-count { 81 | text-align: right; 82 | padding: 0 5px 0 20px; 83 | } 84 | table.coverage td.line-coverage { 85 | text-align: right; 86 | padding-right: 10px; 87 | min-width:20px; 88 | } 89 | 90 | table.coverage td span.cline-any { 91 | display: inline-block; 92 | padding: 0 5px; 93 | width: 100%; 94 | } 95 | .missing-if-branch { 96 | display: inline-block; 97 | margin-right: 5px; 98 | border-radius: 3px; 99 | position: relative; 100 | padding: 0 4px; 101 | background: #333; 102 | color: yellow; 103 | } 104 | 105 | .skip-if-branch { 106 | display: none; 107 | margin-right: 10px; 108 | position: relative; 109 | padding: 0 4px; 110 | background: #ccc; 111 | color: white; 112 | } 113 | .missing-if-branch .typ, .skip-if-branch .typ { 114 | color: inherit !important; 115 | } 116 | .coverage-summary { 117 | border-collapse: collapse; 118 | width: 100%; 119 | } 120 | .coverage-summary tr { border-bottom: 1px solid #bbb; } 121 | .keyline-all { border: 1px solid #ddd; } 122 | .coverage-summary td, .coverage-summary th { padding: 10px; } 123 | .coverage-summary tbody { border: 1px solid #bbb; } 124 | .coverage-summary td { border-right: 1px solid #bbb; } 125 | .coverage-summary td:last-child { border-right: none; } 126 | .coverage-summary th { 127 | text-align: left; 128 | font-weight: normal; 129 | white-space: nowrap; 130 | } 131 | .coverage-summary th.file { border-right: none !important; } 132 | .coverage-summary th.pct { } 133 | .coverage-summary th.pic, 134 | .coverage-summary th.abs, 135 | .coverage-summary td.pct, 136 | .coverage-summary td.abs { text-align: right; } 137 | .coverage-summary td.file { white-space: nowrap; } 138 | .coverage-summary td.pic { min-width: 120px !important; } 139 | .coverage-summary tfoot td { } 140 | 141 | .coverage-summary .sorter { 142 | height: 10px; 143 | width: 7px; 144 | display: inline-block; 145 | margin-left: 0.5em; 146 | background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; 147 | } 148 | .coverage-summary .sorted .sorter { 149 | background-position: 0 -20px; 150 | } 151 | .coverage-summary .sorted-desc .sorter { 152 | background-position: 0 -10px; 153 | } 154 | .status-line { height: 10px; } 155 | /* dark red */ 156 | .red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } 157 | .low .chart { border:1px solid #C21F39 } 158 | /* medium red */ 159 | .cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } 160 | /* light red */ 161 | .low, .cline-no { background:#FCE1E5 } 162 | /* light green */ 163 | .high, .cline-yes { background:rgb(230,245,208) } 164 | /* medium green */ 165 | .cstat-yes { background:rgb(161,215,106) } 166 | /* dark green */ 167 | .status-line.high, .high .cover-fill { background:rgb(77,146,33) } 168 | .high .chart { border:1px solid rgb(77,146,33) } 169 | /* dark yellow (gold) */ 170 | .medium .chart { border:1px solid #f9cd0b; } 171 | .status-line.medium, .medium .cover-fill { background: #f9cd0b; } 172 | /* light yellow */ 173 | .medium { background: #fff4c2; } 174 | /* light gray */ 175 | span.cline-neutral { background: #eaeaea; } 176 | 177 | .cbranch-no { background: yellow !important; color: #111; } 178 | 179 | .cstat-skip { background: #ddd; color: #111; } 180 | .fstat-skip { background: #ddd; color: #111 !important; } 181 | .cbranch-skip { background: #ddd !important; color: #111; } 182 | 183 | 184 | .cover-fill, .cover-empty { 185 | display:inline-block; 186 | height: 12px; 187 | } 188 | .chart { 189 | line-height: 0; 190 | } 191 | .cover-empty { 192 | background: white; 193 | } 194 | .cover-full { 195 | border-right: none !important; 196 | } 197 | pre.prettyprint { 198 | border: none !important; 199 | padding: 0 !important; 200 | margin: 0 !important; 201 | } 202 | .com { color: #999 !important; } 203 | .ignore-none { color: #999; font-weight: normal; } 204 | 205 | .wrapper { 206 | min-height: 100%; 207 | height: auto !important; 208 | height: 100%; 209 | margin: 0 auto -48px; 210 | } 211 | .footer, .push { 212 | height: 48px; 213 | } 214 | -------------------------------------------------------------------------------- /coverage/lcov-report/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for All files 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | / 20 |

21 |
22 |
23 | 100% 24 | Statements 25 | 100/100 26 |
27 |
28 | 100% 29 | Branches 30 | 55/55 31 |
32 |
33 | 100% 34 | Functions 35 | 13/13 36 |
37 |
38 | 100% 39 | Lines 40 | 92/92 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 |
FileStatementsBranchesFunctionsLines
introspected/
100%100/100100%55/55100%13/13100%92/92
76 |
77 |
78 | 82 | 83 | 84 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /coverage/lcov-report/introspected/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for introspected/ 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files introspected/ 20 |

21 |
22 |
23 | 100% 24 | Statements 25 | 100/100 26 |
27 |
28 | 100% 29 | Branches 30 | 55/55 31 |
32 |
33 | 100% 34 | Functions 35 | 13/13 36 |
37 |
38 | 100% 39 | Lines 40 | 92/92 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 |
FileStatementsBranchesFunctionsLines
introspected.js
100%100/100100%55/55100%13/13100%92/92
76 |
77 |
78 | 82 | 83 | 84 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /coverage/lcov-report/introspected/introspected.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for introspected/introspected.js 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files / introspected/ introspected.js 20 |

21 |
22 |
23 | 100% 24 | Statements 25 | 100/100 26 |
27 |
28 | 100% 29 | Branches 30 | 55/55 31 |
32 |
33 | 100% 34 | Functions 35 | 13/13 36 |
37 |
38 | 100% 39 | Lines 40 | 92/92 41 |
42 |
43 |
44 |
45 |

 46 | 
635 | 
1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 64 | 19 65 | 20 66 | 21 67 | 22 68 | 23 69 | 24 70 | 25 71 | 26 72 | 27 73 | 28 74 | 29 75 | 30 76 | 31 77 | 32 78 | 33 79 | 34 80 | 35 81 | 36 82 | 37 83 | 38 84 | 39 85 | 40 86 | 41 87 | 42 88 | 43 89 | 44 90 | 45 91 | 46 92 | 47 93 | 48 94 | 49 95 | 50 96 | 51 97 | 52 98 | 53 99 | 54 100 | 55 101 | 56 102 | 57 103 | 58 104 | 59 105 | 60 106 | 61 107 | 62 108 | 63 109 | 64 110 | 65 111 | 66 112 | 67 113 | 68 114 | 69 115 | 70 116 | 71 117 | 72 118 | 73 119 | 74 120 | 75 121 | 76 122 | 77 123 | 78 124 | 79 125 | 80 126 | 81 127 | 82 128 | 83 129 | 84 130 | 85 131 | 86 132 | 87 133 | 88 134 | 89 135 | 90 136 | 91 137 | 92 138 | 93 139 | 94 140 | 95 141 | 96 142 | 97 143 | 98 144 | 99 145 | 100 146 | 101 147 | 102 148 | 103 149 | 104 150 | 105 151 | 106 152 | 107 153 | 108 154 | 109 155 | 110 156 | 111 157 | 112 158 | 113 159 | 114 160 | 115 161 | 116 162 | 117 163 | 118 164 | 119 165 | 120 166 | 121 167 | 122 168 | 123 169 | 124 170 | 125 171 | 126 172 | 127 173 | 128 174 | 129 175 | 130 176 | 131 177 | 132 178 | 133 179 | 134 180 | 135 181 | 136 182 | 137 183 | 138 184 | 139 185 | 140 186 | 141 187 | 142 188 | 143 189 | 144 190 | 145 191 | 146 192 | 147 193 | 148 194 | 149 195 | 150 196 | 151 197 | 152 198 | 153 199 | 154 200 | 155 201 | 156 202 | 157 203 | 158 204 | 159 205 | 160 206 | 161 207 | 162 208 | 163 209 | 164 210 | 165 211 | 166 212 | 167 213 | 168 214 | 169 215 | 170 216 | 171 217 | 172 218 | 173 219 | 174 220 | 175 221 | 176 222 | 177 223 | 178 224 | 179 225 | 180 226 | 181 227 | 182 228 | 183 229 | 184 230 | 185 231 | 186 232 | 187 233 | 188 234 | 189 235 | 190 236 | 191 237 | 192 238 | 193 239 | 194 240 | 195 241 | 196 242 | 197  243 | 244 |   245 |   246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 |   257 |   258 |   259 | 260 |   261 |   262 | 263 |   264 |   265 |   266 |   267 |   268 |   269 |   270 |   271 |   272 |   273 | 274 | 275 |   276 | 277 | 278 | 279 | 280 | 21× 281 | 21× 282 | 283 |   284 |   285 | 286 | 287 |   288 |   289 | 290 |   291 |   292 |   293 | 294 |   295 |   296 | 297 | 298 |   299 | 300 |   301 |   302 |   303 | 16× 304 |   305 |   306 |   307 | 308 |   309 |   310 |   311 | 96× 312 |   313 | 30× 314 |   315 |   316 | 317 |   318 | 41× 319 |   320 | 21× 321 | 21× 322 |   323 |   324 |   325 |   326 |   327 |   328 |   329 |   330 | 16× 331 | 15× 332 | 15× 333 | 15× 334 |   335 | 16× 336 |   337 |   338 |   339 | 340 | 341 | 342 | 343 | 22× 344 |   345 | 346 |   347 |   348 | 349 | 15× 350 | 15× 351 | 15× 352 | 15× 353 | 12× 354 | 12× 355 |   356 | 15× 357 |   358 |   359 | 360 | 61× 361 |   362 |   363 |   364 |   365 | 61× 366 | 61× 367 |   368 |   369 | 370 | 63× 371 | 10× 372 |   373 |   374 |   375 | 53× 376 | 21× 377 |   378 | 21× 379 |   380 |   381 |   382 |   383 |   384 | 32× 385 |   386 |   387 |   388 | 389 | 61× 390 |   391 |   392 |   393 |   394 | 395 | 18× 396 | 18× 397 |   398 |   399 |   400 | 16× 401 | 16× 402 |   403 | 22× 404 | 22× 405 |   406 |   407 |   408 |   409 | 16× 410 | 16× 411 | 412 |   413 | 16× 414 | 415 | 416 |   417 | 16× 418 |   419 | 420 | 421 |   422 | 423 |   424 | 425 |   426 |   427 |   428 | 429 |   430 | 431 | 432 |   433 | 434 |   435 |   436 |   437 | 438 |  
/*! (c) Andrea Giammarchi - @WebReflection - ISC License */
439 | var Introspected = ((O) => {'use strict';
440 |  
441 |   // commonly needed shortcuts
442 |   const SProto = Introspected.prototype;
443 |   const toString = O.prototype.toString;
444 |   const create = O.create;
445 |   const defineProperties = O.defineProperties;
446 |   const emptyArray = [];
447 |   const emptyString = () => '';
448 |   const getPrototypeOf = O.getPrototypeOf;
449 |   const isArray = Array.isArray;
450 |   const keys = O.keys;
451 |   const toPrimitive = Symbol.toPrimitive;
452 |  
453 |   // weakly holds all known references
454 |   // avoid useless Proxies when already known
455 |   const known = new WeakMap();
456 |  
457 |   // triggered on Array changes
458 |   const ArrayHandler = [
459 |     'copyWithin',
460 |     'fill',
461 |     'pop',
462 |     'push',
463 |     'reverse',
464 |     'shift',
465 |     'sort',
466 |     'splice',
467 |     'unshift'
468 |   ].reduce((properties, method) => {
469 |     const fn = emptyArray[method];
470 |     if (fn) properties[method] = {
471 |       value() {
472 |         const result = fn.apply(this, arguments);
473 |         const length = this.length;
474 |         const info = known.get(this);
475 |         for (let i = 0; i < length; i++) {
476 |           const value = this[i];
477 |           if (typeof value === 'object' && value != null) {
478 |             setValue(info.O, this, info.$, i, value);
479 |           }
480 |         }
481 |         info.O(emptyArray);
482 |         return result;
483 |       }
484 |     };
485 |     return properties;
486 |   }, {});
487 |  
488 |   // each Introspected is proxied through this handler
489 |   const IntrospectedHandler = {
490 |     // notify if necessary
491 |     deleteProperty(target, prop) {
492 |       if (prop in target && delete target[prop] && known.has(target)) {
493 |         known.get(target).O(prop);
494 |       }
495 |       return true;
496 |     },
497 |     // return the correct prototype
498 |     getPrototypeOf() {
499 |         return SProto;
500 |     },
501 |     // the check to do to know if a path exists
502 |     has(target, prop) {
503 |         return prop in target;
504 |     },
505 |     // returns proxied model or create an empty one
506 |     get(target, prop) {
507 |       switch (true) {
508 |         case prop in target:
509 |           return target[prop];
510 |         case prop === toPrimitive:
511 |         case prop === 'toString':
512 |           return emptyString;
513 |         case prop === 'toJSON':
514 |           return () => target;
515 |         default:
516 |           const info = known.get(target);
517 |           return (target[prop] = register(
518 |             info.O,
519 |             create(null),
520 |             info.$.concat(prop)
521 |           )._);
522 |       }
523 |     },
524 |     // triggers only on actual changes
525 |     set(target, prop, value) {
526 |       if ((prop in target ? target[prop] : void 0) !== value) {
527 |         const info = known.get(target);
528 |         setValue(info.O, target, info.$, prop, value);
529 |         info.O(prop);
530 |       }
531 |       return true;
532 |     }
533 |   };
534 |  
535 |   function importArray(observer, value, path) {
536 |     const length = value.length;
537 |     const target = Array(length);
538 |     for (let i = 0; i < length; i++) {
539 |       setValue(observer, target, path, i, value[i]);
540 |     }
541 |     return register(observer, target, path);
542 |   }
543 |  
544 |   function importObject(observer, value, path) {
545 |     const properties = keys(value);
546 |     const length = properties.length;
547 |     const target = create(null);
548 |     for (let prop, i = 0; i < length; i++) {
549 |       prop = properties[i];
550 |       setValue(observer, target, path, prop, value[prop]);
551 |     }
552 |     return register(observer, target, path);
553 |   }
554 |  
555 |   function register(observer, target, paths) {
556 |     const info = {
557 |       _: wrap(target),
558 |       $: paths,
559 |       O: observer
560 |     };
561 |     known.set(target, info);
562 |     return info;
563 |   }
564 |  
565 |   function setValue(observer, target, path, prop, value) {
566 |     if (isArray(value)) {
567 |       target[prop] = (
568 |         known.get(value) ||
569 |         importArray(observer, value, path.concat(prop))
570 |       )._;
571 |     } else if(typeof value === 'object' && value != null) {
572 |       const object = getPrototypeOf(value) === SProto ?
573 |                       value.toJSON() : value;
574 |       target[prop] = toString.call(object) === '[object Date]' ?
575 |         object : (
576 |           known.get(object) ||
577 |           importObject(observer, object, path.concat(prop))
578 |         )._;
579 |     } else {
580 |       target[prop] = value;
581 |     }
582 |   }
583 |  
584 |   function wrap(target) {
585 |     return isArray(target) ?
586 |       defineProperties(target, ArrayHandler) :
587 |       new Proxy(target, IntrospectedHandler);
588 |   }
589 |  
590 |   function Introspected(target, callback) {
591 |     const isNull = target == null;
592 |     if (isNull || (
593 |       getPrototypeOf(target) !== SProto &&
594 |       !known.has(target)
595 |     )) {
596 |       const root = isNull || !isArray(target) ? create(null) : [];
597 |       const info = register(
598 |         function (path) {
599 |           const paths = this.$.concat(path);
600 |           info.O.$.forEach(fn => fn(info._, paths));
601 |         },
602 |         root,
603 |         emptyArray
604 |       );
605 |       info.O.$ = new Set();
606 |       if (!isNull) keys(target).forEach(
607 |         prop => setValue(info.O, root, emptyArray, prop, target[prop])
608 |       );
609 |       if (callback) {
610 |         info.O.$.add(callback);
611 |         callback(info._, []);
612 |       }
613 |       return info._;
614 |     } else {
615 |       if (callback) {
616 |         known.get(target.toJSON()).O.$.add(callback);
617 |         // don't notify other callbacks since no change was made
618 |         callback(target, []);
619 |       }
620 |       return target;
621 |     }
622 |   }
623 |  
624 |   Introspected.observe = Introspected;
625 |  
626 |   Introspected.pathValue = (model, path) =>
627 |     path.reduce((m, p) => (m && p in m) ? m[p] : void 0, model);
628 |  
629 |   return Introspected;
630 |  
631 | })(Object);
632 |  
633 | try { module.exports = Introspected; } catch(o_O) {}
634 |  
636 |
637 |
638 | 642 | 643 | 644 | 651 | 652 | 653 | 654 | -------------------------------------------------------------------------------- /coverage/lcov-report/prettify.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} 2 | -------------------------------------------------------------------------------- /coverage/lcov-report/prettify.js: -------------------------------------------------------------------------------- 1 | window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); 2 | -------------------------------------------------------------------------------- /coverage/lcov-report/sort-arrow-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebReflection/introspected/7ded3ce371534f55f2a09736d94666c7e04937b3/coverage/lcov-report/sort-arrow-sprite.png -------------------------------------------------------------------------------- /coverage/lcov-report/sorter.js: -------------------------------------------------------------------------------- 1 | var addSorting = (function () { 2 | "use strict"; 3 | var cols, 4 | currentSort = { 5 | index: 0, 6 | desc: false 7 | }; 8 | 9 | // returns the summary table element 10 | function getTable() { return document.querySelector('.coverage-summary'); } 11 | // returns the thead element of the summary table 12 | function getTableHeader() { return getTable().querySelector('thead tr'); } 13 | // returns the tbody element of the summary table 14 | function getTableBody() { return getTable().querySelector('tbody'); } 15 | // returns the th element for nth column 16 | function getNthColumn(n) { return getTableHeader().querySelectorAll('th')[n]; } 17 | 18 | // loads all columns 19 | function loadColumns() { 20 | var colNodes = getTableHeader().querySelectorAll('th'), 21 | colNode, 22 | cols = [], 23 | col, 24 | i; 25 | 26 | for (i = 0; i < colNodes.length; i += 1) { 27 | colNode = colNodes[i]; 28 | col = { 29 | key: colNode.getAttribute('data-col'), 30 | sortable: !colNode.getAttribute('data-nosort'), 31 | type: colNode.getAttribute('data-type') || 'string' 32 | }; 33 | cols.push(col); 34 | if (col.sortable) { 35 | col.defaultDescSort = col.type === 'number'; 36 | colNode.innerHTML = colNode.innerHTML + ''; 37 | } 38 | } 39 | return cols; 40 | } 41 | // attaches a data attribute to every tr element with an object 42 | // of data values keyed by column name 43 | function loadRowData(tableRow) { 44 | var tableCols = tableRow.querySelectorAll('td'), 45 | colNode, 46 | col, 47 | data = {}, 48 | i, 49 | val; 50 | for (i = 0; i < tableCols.length; i += 1) { 51 | colNode = tableCols[i]; 52 | col = cols[i]; 53 | val = colNode.getAttribute('data-value'); 54 | if (col.type === 'number') { 55 | val = Number(val); 56 | } 57 | data[col.key] = val; 58 | } 59 | return data; 60 | } 61 | // loads all row data 62 | function loadData() { 63 | var rows = getTableBody().querySelectorAll('tr'), 64 | i; 65 | 66 | for (i = 0; i < rows.length; i += 1) { 67 | rows[i].data = loadRowData(rows[i]); 68 | } 69 | } 70 | // sorts the table using the data for the ith column 71 | function sortByIndex(index, desc) { 72 | var key = cols[index].key, 73 | sorter = function (a, b) { 74 | a = a.data[key]; 75 | b = b.data[key]; 76 | return a < b ? -1 : a > b ? 1 : 0; 77 | }, 78 | finalSorter = sorter, 79 | tableBody = document.querySelector('.coverage-summary tbody'), 80 | rowNodes = tableBody.querySelectorAll('tr'), 81 | rows = [], 82 | i; 83 | 84 | if (desc) { 85 | finalSorter = function (a, b) { 86 | return -1 * sorter(a, b); 87 | }; 88 | } 89 | 90 | for (i = 0; i < rowNodes.length; i += 1) { 91 | rows.push(rowNodes[i]); 92 | tableBody.removeChild(rowNodes[i]); 93 | } 94 | 95 | rows.sort(finalSorter); 96 | 97 | for (i = 0; i < rows.length; i += 1) { 98 | tableBody.appendChild(rows[i]); 99 | } 100 | } 101 | // removes sort indicators for current column being sorted 102 | function removeSortIndicators() { 103 | var col = getNthColumn(currentSort.index), 104 | cls = col.className; 105 | 106 | cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); 107 | col.className = cls; 108 | } 109 | // adds sort indicators for current column being sorted 110 | function addSortIndicators() { 111 | getNthColumn(currentSort.index).className += currentSort.desc ? ' sorted-desc' : ' sorted'; 112 | } 113 | // adds event listeners for all sorter widgets 114 | function enableUI() { 115 | var i, 116 | el, 117 | ithSorter = function ithSorter(i) { 118 | var col = cols[i]; 119 | 120 | return function () { 121 | var desc = col.defaultDescSort; 122 | 123 | if (currentSort.index === i) { 124 | desc = !currentSort.desc; 125 | } 126 | sortByIndex(i, desc); 127 | removeSortIndicators(); 128 | currentSort.index = i; 129 | currentSort.desc = desc; 130 | addSortIndicators(); 131 | }; 132 | }; 133 | for (i =0 ; i < cols.length; i += 1) { 134 | if (cols[i].sortable) { 135 | // add the click event handler on the th so users 136 | // dont have to click on those tiny arrows 137 | el = getNthColumn(i).querySelector('.sorter').parentElement; 138 | if (el.addEventListener) { 139 | el.addEventListener('click', ithSorter(i)); 140 | } else { 141 | el.attachEvent('onclick', ithSorter(i)); 142 | } 143 | } 144 | } 145 | } 146 | // adds sorting functionality to the UI 147 | return function () { 148 | if (!getTable()) { 149 | return; 150 | } 151 | cols = loadColumns(); 152 | loadData(cols); 153 | addSortIndicators(); 154 | enableUI(); 155 | }; 156 | })(); 157 | 158 | window.addEventListener('load', addSorting); 159 | -------------------------------------------------------------------------------- /coverage/lcov.info: -------------------------------------------------------------------------------- 1 | TN: 2 | SF:/home/webreflection/code/introspected/introspected.js 3 | FN:34,(anonymous_1) 4 | FN:54,(anonymous_2) 5 | FN:61,(anonymous_3) 6 | FN:65,(anonymous_4) 7 | FN:69,(anonymous_5) 8 | FN:88,(anonymous_6) 9 | FN:98,importArray 10 | FN:107,importObject 11 | FN:118,register 12 | FN:128,setValue 13 | FN:147,wrap 14 | FN:153,Introspected 15 | FN:161,(anonymous_13) 16 | FNF:13 17 | FNH:13 18 | FNDA:6,(anonymous_1) 19 | FNDA:2,(anonymous_2) 20 | FNDA:16,(anonymous_3) 21 | FNDA:3,(anonymous_4) 22 | FNDA:96,(anonymous_5) 23 | FNDA:16,(anonymous_6) 24 | FNDA:9,importArray 25 | FNDA:15,importObject 26 | FNDA:61,register 27 | FNDA:63,setValue 28 | FNDA:61,wrap 29 | FNDA:18,Introspected 30 | FNDA:22,(anonymous_13) 31 | DA:2,1 32 | DA:5,1 33 | DA:6,1 34 | DA:7,1 35 | DA:8,1 36 | DA:9,1 37 | DA:10,4 38 | DA:11,1 39 | DA:12,1 40 | DA:13,1 41 | DA:14,1 42 | DA:18,1 43 | DA:21,1 44 | DA:32,9 45 | DA:33,9 46 | DA:35,6 47 | DA:36,6 48 | DA:37,6 49 | DA:38,6 50 | DA:39,21 51 | DA:40,21 52 | DA:41,6 53 | DA:44,6 54 | DA:45,6 55 | DA:48,9 56 | DA:52,1 57 | DA:55,2 58 | DA:56,1 59 | DA:58,2 60 | DA:62,16 61 | DA:66,3 62 | DA:70,96 63 | DA:72,30 64 | DA:75,4 65 | DA:77,41 66 | DA:79,21 67 | DA:80,21 68 | DA:89,16 69 | DA:90,15 70 | DA:91,15 71 | DA:92,15 72 | DA:94,16 73 | DA:98,1 74 | DA:99,9 75 | DA:100,9 76 | DA:101,9 77 | DA:102,22 78 | DA:104,9 79 | DA:107,1 80 | DA:108,15 81 | DA:109,15 82 | DA:110,15 83 | DA:111,15 84 | DA:112,12 85 | DA:113,12 86 | DA:115,15 87 | DA:118,1 88 | DA:119,61 89 | DA:124,61 90 | DA:125,61 91 | DA:128,1 92 | DA:129,63 93 | DA:130,10 94 | DA:134,53 95 | DA:135,21 96 | DA:137,21 97 | DA:143,32 98 | DA:147,1 99 | DA:148,61 100 | DA:153,1 101 | DA:154,18 102 | DA:155,18 103 | DA:159,16 104 | DA:160,16 105 | DA:162,22 106 | DA:163,22 107 | DA:168,16 108 | DA:169,16 109 | DA:170,8 110 | DA:172,16 111 | DA:173,5 112 | DA:174,5 113 | DA:176,16 114 | DA:178,2 115 | DA:179,1 116 | DA:181,1 117 | DA:183,2 118 | DA:187,1 119 | DA:189,1 120 | DA:190,7 121 | DA:192,1 122 | DA:196,1 123 | LF:92 124 | LH:92 125 | BRDA:33,1,0,8 126 | BRDA:33,1,1,1 127 | BRDA:40,2,0,6 128 | BRDA:40,2,1,15 129 | BRDA:40,3,0,21 130 | BRDA:40,3,1,6 131 | BRDA:55,4,0,1 132 | BRDA:55,4,1,1 133 | BRDA:55,5,0,2 134 | BRDA:55,5,1,1 135 | BRDA:55,5,2,1 136 | BRDA:70,6,0,30 137 | BRDA:70,6,1,2 138 | BRDA:70,6,2,4 139 | BRDA:70,6,3,41 140 | BRDA:70,6,4,21 141 | BRDA:89,7,0,15 142 | BRDA:89,7,1,1 143 | BRDA:89,8,0,2 144 | BRDA:89,8,1,14 145 | BRDA:129,9,0,10 146 | BRDA:129,9,1,53 147 | BRDA:131,10,0,10 148 | BRDA:131,10,1,9 149 | BRDA:134,11,0,21 150 | BRDA:134,11,1,32 151 | BRDA:134,12,0,53 152 | BRDA:134,12,1,21 153 | BRDA:135,13,0,5 154 | BRDA:135,13,1,16 155 | BRDA:137,14,0,1 156 | BRDA:137,14,1,20 157 | BRDA:139,15,0,20 158 | BRDA:139,15,1,15 159 | BRDA:148,16,0,13 160 | BRDA:148,16,1,48 161 | BRDA:155,17,0,16 162 | BRDA:155,17,1,2 163 | BRDA:155,18,0,18 164 | BRDA:155,18,1,16 165 | BRDA:155,18,2,14 166 | BRDA:159,19,0,12 167 | BRDA:159,19,1,4 168 | BRDA:159,20,0,16 169 | BRDA:159,20,1,14 170 | BRDA:169,21,0,14 171 | BRDA:169,21,1,2 172 | BRDA:172,22,0,5 173 | BRDA:172,22,1,11 174 | BRDA:178,23,0,1 175 | BRDA:178,23,1,1 176 | BRDA:190,24,0,3 177 | BRDA:190,24,1,4 178 | BRDA:190,25,0,7 179 | BRDA:190,25,1,4 180 | BRF:55 181 | BRH:55 182 | end_of_record 183 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 12 | 13 |

results in console

14 |
green background: all good
15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /introspected.js: -------------------------------------------------------------------------------- 1 | /*! (c) Andrea Giammarchi - @WebReflection - ISC License */ 2 | var Introspected = ((O) => {'use strict'; 3 | 4 | // commonly needed shortcuts 5 | const SProto = Introspected.prototype; 6 | const toString = O.prototype.toString; 7 | const create = O.create; 8 | const defineProperties = O.defineProperties; 9 | const emptyArray = []; 10 | const emptyString = () => ''; 11 | const getPrototypeOf = O.getPrototypeOf; 12 | const isArray = Array.isArray; 13 | const keys = O.keys; 14 | const toPrimitive = Symbol.toPrimitive; 15 | 16 | // weakly holds all known references 17 | // avoid useless Proxies when already known 18 | const known = new WeakMap(); 19 | 20 | // triggered on Array changes 21 | const ArrayHandler = [ 22 | 'copyWithin', 23 | 'fill', 24 | 'pop', 25 | 'push', 26 | 'reverse', 27 | 'shift', 28 | 'sort', 29 | 'splice', 30 | 'unshift' 31 | ].reduce((properties, method) => { 32 | const fn = emptyArray[method]; 33 | if (fn) properties[method] = { 34 | value() { 35 | const result = fn.apply(this, arguments); 36 | const length = this.length; 37 | const info = known.get(this); 38 | for (let i = 0; i < length; i++) { 39 | const value = this[i]; 40 | if (typeof value === 'object' && value != null) { 41 | setValue(info.O, this, info.$, i, value); 42 | } 43 | } 44 | info.O(emptyArray); 45 | return result; 46 | } 47 | }; 48 | return properties; 49 | }, {}); 50 | 51 | // each Introspected is proxied through this handler 52 | const IntrospectedHandler = { 53 | // notify if necessary 54 | deleteProperty(target, prop) { 55 | if (prop in target && delete target[prop] && known.has(target)) { 56 | known.get(target).O(prop); 57 | } 58 | return true; 59 | }, 60 | // return the correct prototype 61 | getPrototypeOf() { 62 | return SProto; 63 | }, 64 | // the check to do to know if a path exists 65 | has(target, prop) { 66 | return prop in target; 67 | }, 68 | // returns proxied model or create an empty one 69 | get(target, prop) { 70 | switch (true) { 71 | case prop in target: 72 | return target[prop]; 73 | case prop === toPrimitive: 74 | case prop === 'toString': 75 | return emptyString; 76 | case prop === 'toJSON': 77 | return () => target; 78 | default: 79 | const info = known.get(target); 80 | return (target[prop] = register( 81 | info.O, 82 | create(null), 83 | info.$.concat(prop) 84 | )._); 85 | } 86 | }, 87 | // triggers only on actual changes 88 | set(target, prop, value) { 89 | if ((prop in target ? target[prop] : void 0) !== value) { 90 | const info = known.get(target); 91 | setValue(info.O, target, info.$, prop, value); 92 | info.O(prop); 93 | } 94 | return true; 95 | } 96 | }; 97 | 98 | function importArray(observer, value, path) { 99 | const length = value.length; 100 | const target = Array(length); 101 | for (let i = 0; i < length; i++) { 102 | setValue(observer, target, path, i, value[i]); 103 | } 104 | return register(observer, target, path); 105 | } 106 | 107 | function importObject(observer, value, path) { 108 | const properties = keys(value); 109 | const length = properties.length; 110 | const target = create(null); 111 | for (let prop, i = 0; i < length; i++) { 112 | prop = properties[i]; 113 | setValue(observer, target, path, prop, value[prop]); 114 | } 115 | return register(observer, target, path); 116 | } 117 | 118 | function register(observer, target, paths) { 119 | const info = { 120 | _: wrap(target), 121 | $: paths, 122 | O: observer 123 | }; 124 | known.set(target, info); 125 | return info; 126 | } 127 | 128 | function setValue(observer, target, path, prop, value) { 129 | if (isArray(value)) { 130 | target[prop] = ( 131 | known.get(value) || 132 | importArray(observer, value, path.concat(prop)) 133 | )._; 134 | } else if(typeof value === 'object' && value != null) { 135 | const object = getPrototypeOf(value) === SProto ? 136 | value.toJSON() : value; 137 | target[prop] = toString.call(object) === '[object Date]' ? 138 | object : ( 139 | known.get(object) || 140 | importObject(observer, object, path.concat(prop)) 141 | )._; 142 | } else { 143 | target[prop] = value; 144 | } 145 | } 146 | 147 | function wrap(target) { 148 | return isArray(target) ? 149 | defineProperties(target, ArrayHandler) : 150 | new Proxy(target, IntrospectedHandler); 151 | } 152 | 153 | function Introspected(target, callback) { 154 | const isNull = target == null; 155 | if (isNull || ( 156 | getPrototypeOf(target) !== SProto && 157 | !known.has(target) 158 | )) { 159 | const root = isNull || !isArray(target) ? create(null) : []; 160 | const info = register( 161 | function (path) { 162 | const paths = this.$.concat(path); 163 | info.O.$.forEach(fn => fn(info._, paths)); 164 | }, 165 | root, 166 | emptyArray 167 | ); 168 | info.O.$ = new Set(); 169 | if (!isNull) keys(target).forEach( 170 | prop => setValue(info.O, root, emptyArray, prop, target[prop]) 171 | ); 172 | if (callback) { 173 | info.O.$.add(callback); 174 | callback(info._, []); 175 | } 176 | return info._; 177 | } else { 178 | if (callback) { 179 | known.get(target.toJSON()).O.$.add(callback); 180 | // don't notify other callbacks since no change was made 181 | callback(target, []); 182 | } 183 | return target; 184 | } 185 | } 186 | 187 | Introspected.observe = Introspected; 188 | 189 | Introspected.pathValue = (model, path) => 190 | path.reduce((m, p) => (m && p in m) ? m[p] : void 0, model); 191 | 192 | return Introspected; 193 | 194 | })(Object); 195 | 196 | try { module.exports = Introspected; } catch(o_O) {} 197 | -------------------------------------------------------------------------------- /min.js: -------------------------------------------------------------------------------- 1 | /*! (c) Andrea Giammarchi - @WebReflection - ISC License */ 2 | var Introspected=(t=>{"use strict";function n(t,n,o){const r=n.length,s=Array(r);for(let e=0;et(s._,n))},r,l);return s.O.$=new Set,o||d(t).forEach(n=>c(s.O,r,l,n,t[n])),n&&(s.O.$.add(n),n(s._,[])),s._}return n&&(g.get(t.toJSON()).O.$.add(n),n(t,[])),t}const i=s.prototype;const u=t.prototype.toString;const f=t.create;const a=t.defineProperties;const l=[];const h=()=>"";const p=t.getPrototypeOf;const O=Array.isArray;const d=t.keys;const y=Symbol.toPrimitive;const g=new WeakMap;const $=["copyWithin","fill","pop","push","reverse","shift","sort","splice","unshift"].reduce((t,n)=>{const o=l[n];o&&(t[n]={value(){const t=o.apply(this,arguments),n=this.length,e=g.get(this);for(let t=0;tt;default:const o=g.get(t);return t[n]=e(o.O,f(null),o.$.concat(n))._}},set(t,n,o){if((n in t?t[n]:void 0)!==o){const e=g.get(t);c(e.O,t,e.$,n,o),e.O(n)}return!0}};s.observe=s;s.pathValue=((t,n)=>n.reduce((t,n)=>t&&n in t?t[n]:void 0,t));return s})(Object);try{module.exports=Introspected}catch(t){} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "introspected", 3 | "version": "0.2.6", 4 | "description": "Introspection for serializable arrays and JSON like objects.", 5 | "main": "./introspected.js", 6 | "unpkg": "min.js", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/WebReflection/introspected.git" 10 | }, 11 | "keywords": [ 12 | "observe", 13 | "JSON", 14 | "object", 15 | "array", 16 | "change", 17 | "subscribe", 18 | "notify" 19 | ], 20 | "author": "Andrea Giammarchi", 21 | "license": "ISC", 22 | "bugs": { 23 | "url": "https://github.com/WebReflection/introspected/issues" 24 | }, 25 | "homepage": "https://github.com/WebReflection/introspected#readme", 26 | "scripts": { 27 | "build": "npm run minify && npm test && npm run size", 28 | "coveralls": "cat ./coverage/lcov.info | coveralls", 29 | "minify": "uglifyjs introspected.js --comments=/^!/ --compress --mangle -o min.js", 30 | "size": "cat introspected.js | wc -c;cat min.js | wc -c;gzip -c min.js | wc -c", 31 | "test": "istanbul cover test/introspected.js", 32 | "web": "$(sleep 2 && open http://0.0.0.0:7151/) & tiny-cdn run ./" 33 | }, 34 | "devDependencies": { 35 | "coveralls": "^2.13.0", 36 | "istanbul": "^0.4.5", 37 | "tiny-cdn": "^0.7.0", 38 | "tressa": "^0.3.1", 39 | "uglify-es": "^3.0.4" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /test/class-state.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // grab from the live test page or require in node 4 | var Introspected = Introspected || require('../introspected.js'); 5 | 6 | class Foo { 7 | constructor() { 8 | this.state = Introspected({}, console.log); 9 | this.state.items = [ 10 | {id: 1, text: "foo"}, 11 | {id: 2, text: "bar"}, 12 | {id: 3, text: "baz"} 13 | ]; 14 | } 15 | add(newItem) { 16 | this.state.items.push(newItem); 17 | } 18 | } 19 | 20 | const foo = new Foo(); 21 | foo.add({ id: 4, text: "minions" }); 22 | 23 | console.log(foo.state); 24 | 25 | -------------------------------------------------------------------------------- /test/how-to-diff.js: -------------------------------------------------------------------------------- 1 | // grab from the live test page or require in node 2 | var Introspected = Introspected || require('../introspected.js'); 3 | 4 | // any JSON compliant data structure 5 | const source = { 6 | name: 'anonymous', 7 | age: 0, 8 | address: { 9 | street: '', 10 | city: '', 11 | country: '' 12 | } 13 | }; 14 | 15 | // an Introspected version of the same data 16 | // any operation will be known, no way to hide changes! 17 | const intr = Introspected(source, (intr, path) => { 18 | 19 | // walk through the source 20 | let src = source; 21 | 22 | // ensure objects/dictionaries won't throw 23 | let hOP = {}.hasOwnProperty; 24 | 25 | // loop over the whole path 26 | for (let sub = [], i = 0; i < path.length; i++) { 27 | 28 | // grab current property, add it to sub-path 29 | let prop = (sub[i] = path[i]); 30 | 31 | // if the property is unknown 32 | if (!hOP.call(src, prop)) { 33 | 34 | // this means it was added 35 | console.log('added ' + sub.join('.')); 36 | 37 | // assign it from the intr 38 | src[prop] = intr[prop]; 39 | } 40 | // if the prop is in the current intr object 41 | else if (prop in intr) { 42 | // this means it was changed 43 | console.log('changed ' + sub.join('.')); 44 | // There is no need to check src[prop] === intr[prop] 45 | // because Introspected notifies changes *only* when 46 | // the new value is different from the previous one. 47 | } 48 | // if property is not in the intr object 49 | else { 50 | // it means it was removed 51 | delete src[prop]; 52 | console.log('removed ' + sub.join('.')); 53 | // no need to keep walking through 54 | // or accessing intr[prop] will set it again 55 | break; // or return; 56 | } 57 | src = src[prop]; 58 | intr = intr[prop]; 59 | } 60 | }); 61 | 62 | // change few fields 63 | intr.name = 'Andrea'; 64 | intr.age = 39; 65 | 66 | // change a nested group 67 | intr.address = { 68 | street: 'Wenlock', 69 | city: 'London', 70 | country: 'UK' 71 | }; 72 | 73 | // add new field 74 | intr.nationality = 'italian'; 75 | 76 | // add nested property 77 | intr.address.postcode = 'N1'; 78 | 79 | // remove a property 80 | delete intr.address.street; 81 | 82 | // no notification will happen 83 | // because it's the same value 84 | intr.age = 39; 85 | 86 | // re set removed field 87 | intr.address.street = 'Archway'; 88 | -------------------------------------------------------------------------------- /test/introspected.js: -------------------------------------------------------------------------------- 1 | var tressa = tressa || require('tressa'); 2 | 3 | const fill = Array.prototype.fill; 4 | delete Array.prototype.fill; 5 | var Introspected = Introspected || require('../introspected.js'); 6 | Array.prototype.fill = fill; 7 | 8 | tressa.title('Introspected'); 9 | 10 | tressa.assert(Object.getPrototypeOf(Introspected({})) === Introspected.prototype, 'is an Introspected object'); 11 | tressa.assert(typeof Introspected({}), 'is an object'); 12 | tressa.assert(Array.isArray(Introspected([])), 'is an array'); 13 | tressa.assert('' == Introspected({}).any, 'is an empty string'); 14 | tressa.assert(typeof Introspected({}, console.log), 'is an observable object'); 15 | tressa.assert(typeof Introspected([], console.log), 'is an observable array'); 16 | 17 | const abusedObject = (o) => { 18 | o.a.b.c = {}; 19 | o.a.b.c.d = 'd'; 20 | o.b = 123; 21 | o.c = [1, 2, 3]; 22 | o.d = [{a: 'a'}, [1, 2]]; 23 | o.d[0].b = 'b'; 24 | o.d[1].push(3); 25 | return o; 26 | }; 27 | 28 | let o = abusedObject(Introspected({})); 29 | let oStringified = '{"a":{"b":{"c":{"d":"d"}}},"b":123,"c":[1,2,3],"d":[{"a":"a","b":"b"},[1,2,3]]}'; 30 | tressa.assert(JSON.stringify(o) === oStringified, 'JSON.stringify(object)'); 31 | tressa.assert(JSON.stringify(o.toJSON()) === oStringified, 'JSON.stringify(object.toJSON())'); 32 | 33 | o = abusedObject(Introspected({gotcha: {}}, () => {})); 34 | oStringified = '{"gotcha":{},"a":{"b":{"c":{"d":"d"}}},"b":123,"c":[1,2,3],"d":[{"a":"a","b":"b"},[1,2,3]]}'; 35 | tressa.assert(JSON.stringify(o) === oStringified, 'JSON.stringify(object)'); 36 | tressa.assert(JSON.stringify(o.toJSON()) === oStringified, 'JSON.stringify(object.toJSON())'); 37 | tressa.assert(o.gotcha.a.b.c.toString() === '', 'initial objects promoted'); 38 | 39 | tressa.assert(Introspected.pathValue(o, ['d', 1, 1]) === 2, 'path can be retrieved'); 40 | tressa.assert(Introspected.pathValue(o, ['n', 'o', 'p', 'e']) === void 0, 'path can be undefined'); 41 | tressa.assert(o.d[1].push(4) === 4, 'nested arrays notify'); 42 | const d = o.d; 43 | o.d = o.d; 44 | tressa.assert(o.d === d, 'same value no effect'); 45 | tressa.assert(o.a.b.c.z + '' === '', 'non set values are empty strings'); 46 | tressa.assert(o.a.b.c.z.toString() === '', 'toString() is always usable'); 47 | tressa.assert('nope' in o === false, 'if not there, it is a false'); 48 | 49 | const empty = Introspected(); 50 | tressa.assert(JSON.stringify(empty) === '{}', 'empty Introspecteds are allowed'); 51 | tressa.assert(Introspected.observe(empty) === empty, 'if observed was a Introspected no wrap'); 52 | 53 | const abusedArray = (a) => { 54 | a.push({a: {b: {c: 'c'}}}, 1, 2, [1, 2, 3]); 55 | a[0].d = 'd'; 56 | a[3].push({a: 'a'}); 57 | return a; 58 | }; 59 | 60 | let a = abusedArray(Introspected([])); 61 | tressa.assert(JSON.stringify(a) === '[{"a":{"b":{"c":"c"}},"d":"d"},1,2,[1,2,3,{"a":"a"}]]'); 62 | 63 | o = Introspected({a: a, empty: empty}); 64 | tressa.assert(o.a === a, 'a was not wrapped'); 65 | tressa.assert(o.empty === empty, 'neither was empty'); 66 | 67 | o = Introspected({any: 123}, (root, path) => { 68 | // only on deleted paths 69 | if (path.length) { 70 | tressa.assert(path.join('') === 'any', 'deleted path'); 71 | } 72 | }); 73 | delete o.any; 74 | delete o.nope; 75 | 76 | let calls = 0; 77 | let double = Introspected(null, () => calls++); 78 | tressa.assert( 79 | double === Introspected(double, () => calls++), 80 | 'same introspected passed twice is same' 81 | ); 82 | tressa.assert(calls === 2, 'callbacks are invoked once ready'); 83 | double.any = 'value'; 84 | tressa.assert(calls === 4, 'callbacks are re-invoked on changes'); 85 | 86 | let withSameChildren = Introspected([{a: 1}, {b: 2}]); 87 | let wscA = withSameChildren[0]; 88 | let wscB = withSameChildren[1]; 89 | withSameChildren.push({c: 3}); 90 | tressa.assert( 91 | wscA === withSameChildren[0] && 92 | wscB === withSameChildren[1], 93 | 'previously mapped objects are not changed' 94 | ); 95 | tressa.assert( 96 | JSON.stringify(withSameChildren) === '[{"a":1},{"b":2},{"c":3}]', 97 | 'expected JSON with known objects' 98 | ); 99 | 100 | withSameChildren = Introspected({items: [{a: 1}, {b: 2}]}); 101 | wscA = withSameChildren.items[0]; 102 | wscB = withSameChildren.items[1]; 103 | withSameChildren.items = withSameChildren.items.concat({c: 3}); 104 | tressa.assert( 105 | wscA === withSameChildren.items[0] && 106 | wscB === withSameChildren.items[1], 107 | 'not changed even if reassigned' 108 | ); 109 | tressa.assert( 110 | JSON.stringify(withSameChildren) === '{"items":[{"a":1},{"b":2},{"c":3}]}', 111 | 'expected JSON with reassigned objects' 112 | ); 113 | 114 | tressa.assert( 115 | JSON.stringify(Introspected({d: new Date(1352505600000)})) === '{"d":"2012-11-10T00:00:00.000Z"}', 116 | 'expected JSON with a stringified date' 117 | ); 118 | 119 | tressa.end(); 120 | 121 | if (!tressa.exitCode && typeof document !== 'undefined') { 122 | document.body.style.backgroundColor = '#0FA'; 123 | } --------------------------------------------------------------------------------