dot.dot.dot.exampol
This commit is contained in:
commit
a0bc2d79de
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -0,0 +1,17 @@
|
||||||
|
const LNSocket = require('../')
|
||||||
|
|
||||||
|
async function go() {
|
||||||
|
const ln = await LNSocket()
|
||||||
|
|
||||||
|
ln.genkey()
|
||||||
|
await ln.connect_and_init("03f3c108ccd536b8526841f0a5c58212bb9e6584a1eb493080e7c1cc34f82dad71", "24.84.152.187")
|
||||||
|
|
||||||
|
const rune = "uQux-hID66AX5rFUpkt1p9CU_7DsTMyUC4G5yq7-dcw9MTMmbWV0aG9kPWdldGluZm8="
|
||||||
|
const res = await ln.rpc({ method: "getinfo", rune })
|
||||||
|
|
||||||
|
ln.destroy()
|
||||||
|
console.log(res)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
go()
|
|
@ -0,0 +1 @@
|
||||||
|
../nopt/bin/nopt.js
|
|
@ -0,0 +1 @@
|
||||||
|
../tap/bin/tap.js
|
|
@ -0,0 +1 @@
|
||||||
|
../uglify-js/bin/uglifyjs
|
|
@ -0,0 +1,195 @@
|
||||||
|
{
|
||||||
|
"name": "examples",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"node_modules/abbrev": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/buffer-equal": {
|
||||||
|
"version": "0.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.2.tgz",
|
||||||
|
"integrity": "sha512-4hr0gS7+NK47X6WbA/okVFrN5qGh3WLT7N3hMRv7+hlkXnbUIdU2u05n6r0RQv6cq6xke06nVl70r0NW0WM2OQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/bunker": {
|
||||||
|
"version": "0.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/bunker/-/bunker-0.1.2.tgz",
|
||||||
|
"integrity": "sha512-YnahkcXBNT522S46k5LUA9P18lzvgkunbMl0qIJQ8oeRMQ+dAg3YI3k32q5TnO+AAUErFHO6R768To6jslgYmQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"burrito": ">=0.2.5 <0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/burrito": {
|
||||||
|
"version": "0.2.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/burrito/-/burrito-0.2.12.tgz",
|
||||||
|
"integrity": "sha512-ZhhT5iVTAgzQ+s8rily7m45Swxe/cU3dVCHTzqmHVWD/cc0Ds3W4Q4MExbkevY+fm0Me3lEwpehIy6TH7p+ehw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"traverse": "~0.5.1",
|
||||||
|
"uglify-js": "~1.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/burrito/node_modules/traverse": {
|
||||||
|
"version": "0.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/traverse/-/traverse-0.5.2.tgz",
|
||||||
|
"integrity": "sha512-PUBVcfB3RqgLpzgTRGNiqK4duqrDbgGa1bobbUtzUwLiBNAjZ7vd5eCOdBxqZ/Fgezagr9o69IxP2fZp41RGFA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/charm": {
|
||||||
|
"version": "0.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/charm/-/charm-0.1.2.tgz",
|
||||||
|
"integrity": "sha512-syedaZ9cPe7r3hoQA9twWYKu5AIyCswN5+szkmPBe9ccdLrj4bYaCnLVPTLd2kgVRc7+zoX4tyPgRnFKCj5YjQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/deep-equal": {
|
||||||
|
"version": "0.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.0.0.tgz",
|
||||||
|
"integrity": "sha512-p1bI/kkDPT6auUI0U+WLuIIrzmDIDo80I406J8tT4y6I4ZGtBuMeTudrKDtBdMJFAcxqrQdx27gosqPVyY3IvQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/deep-is": {
|
||||||
|
"version": "0.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
|
||||||
|
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/difflet": {
|
||||||
|
"version": "0.2.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/difflet/-/difflet-0.2.6.tgz",
|
||||||
|
"integrity": "sha512-ruldDDRmY1t678UOAJBng6sL77f62SqjHj0498YC0EJhxIe2yKkqJn2qEchwG3eU/dqJ/RxPZkAnYjePS4pDCw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"charm": "0.1.x",
|
||||||
|
"deep-is": "0.1.x",
|
||||||
|
"traverse": "0.6.x"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/lnsocket": {
|
||||||
|
"version": "0.2.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/lnsocket/-/lnsocket-0.2.5.tgz",
|
||||||
|
"integrity": "sha512-gGmxaG9+w1IV3D5qRc/HX0WOBs8H5Osg00OBAOEdbP3UXjyU1/3JQgGOqrCoplbUu4BXUWKbX1IrROrhq2VQYw=="
|
||||||
|
},
|
||||||
|
"node_modules/mkdirp": {
|
||||||
|
"version": "0.3.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz",
|
||||||
|
"integrity": "sha512-8OCq0De/h9ZxseqzCH8Kw/Filf5pF/vMI6+BH7Lu0jXz2pqYCjTAQRolSxRIi+Ax+oCCjlxoJMP0YQ4XlrQNHg==",
|
||||||
|
"deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"node_modules/nopt": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/nopt/-/nopt-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-gIOTA/uJuhPwFqp+spY7VQ1satbnGlD+iQVZxI18K6hs8Evq4sX81Ml7BB5byP/LsbR2yBVtmvdEmhi7evJ6Aw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"abbrev": "1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"nopt": "bin/nopt.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/runforcover": {
|
||||||
|
"version": "0.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/runforcover/-/runforcover-0.0.2.tgz",
|
||||||
|
"integrity": "sha512-yarCIK2HcAOadqnKW419+FA38qpWDCKcOr5RZU+jnyLL/hn3No9BHZY+YJDEzvQ0k8Oyl7ffLjZv9ZUxvyKoLQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"bunker": "0.1.X"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/slide": {
|
||||||
|
"version": "1.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz",
|
||||||
|
"integrity": "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tap": {
|
||||||
|
"version": "0.2.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/tap/-/tap-0.2.6.tgz",
|
||||||
|
"integrity": "sha512-uLvaKbh3+A4nh+P3SrfX52kWGkVvP37UYI7LxKjRkd6Bjdqbyc7MARaPFGl7SdwyNwWtZHlUxQX3w9pVNf3FKQ==",
|
||||||
|
"bundleDependencies": [
|
||||||
|
"inherits",
|
||||||
|
"tap-consumer",
|
||||||
|
"yamlish"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"buffer-equal": "~0.0.0",
|
||||||
|
"deep-equal": "~0.0.0",
|
||||||
|
"difflet": "~0.2.0",
|
||||||
|
"inherits": "*",
|
||||||
|
"mkdirp": "~0.3",
|
||||||
|
"nopt": "~2",
|
||||||
|
"runforcover": "~0.0.2",
|
||||||
|
"slide": "*",
|
||||||
|
"yamlish": "*"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"tap": "bin/tap.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tap/node_modules/inherits": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"dev": true,
|
||||||
|
"inBundle": true,
|
||||||
|
"license": "WTFPL2"
|
||||||
|
},
|
||||||
|
"node_modules/tap/node_modules/yamlish": {
|
||||||
|
"version": "0.0.5",
|
||||||
|
"dev": true,
|
||||||
|
"inBundle": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/traverse": {
|
||||||
|
"version": "0.6.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.7.tgz",
|
||||||
|
"integrity": "sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/uglify-js": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-YYY9Dle1leC+btgrHnAR05eq0aRdcPJsXlYYD+SYw2lqc5HFuFNHg3wWEW4SNE0iXXEUl0fz43gTQ3r1YK76rg==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"uglifyjs": "bin/uglifyjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
This software is dual-licensed under the ISC and MIT licenses.
|
||||||
|
You may use this software under EITHER of the following licenses.
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
The ISC License
|
||||||
|
|
||||||
|
Copyright (c) Isaac Z. Schlueter and Contributors
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||||
|
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
----------
|
||||||
|
|
||||||
|
Copyright Isaac Z. Schlueter and Contributors
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person
|
||||||
|
obtaining a copy of this software and associated documentation
|
||||||
|
files (the "Software"), to deal in the Software without
|
||||||
|
restriction, including without limitation the rights to use,
|
||||||
|
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following
|
||||||
|
conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||||
|
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,23 @@
|
||||||
|
# abbrev-js
|
||||||
|
|
||||||
|
Just like [ruby's Abbrev](http://apidock.com/ruby/Abbrev).
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
var abbrev = require("abbrev");
|
||||||
|
abbrev("foo", "fool", "folding", "flop");
|
||||||
|
|
||||||
|
// returns:
|
||||||
|
{ fl: 'flop'
|
||||||
|
, flo: 'flop'
|
||||||
|
, flop: 'flop'
|
||||||
|
, fol: 'folding'
|
||||||
|
, fold: 'folding'
|
||||||
|
, foldi: 'folding'
|
||||||
|
, foldin: 'folding'
|
||||||
|
, folding: 'folding'
|
||||||
|
, foo: 'foo'
|
||||||
|
, fool: 'fool'
|
||||||
|
}
|
||||||
|
|
||||||
|
This is handy for command-line scripts, or other cases where you want to be able to accept shorthands.
|
|
@ -0,0 +1,61 @@
|
||||||
|
module.exports = exports = abbrev.abbrev = abbrev
|
||||||
|
|
||||||
|
abbrev.monkeyPatch = monkeyPatch
|
||||||
|
|
||||||
|
function monkeyPatch () {
|
||||||
|
Object.defineProperty(Array.prototype, 'abbrev', {
|
||||||
|
value: function () { return abbrev(this) },
|
||||||
|
enumerable: false, configurable: true, writable: true
|
||||||
|
})
|
||||||
|
|
||||||
|
Object.defineProperty(Object.prototype, 'abbrev', {
|
||||||
|
value: function () { return abbrev(Object.keys(this)) },
|
||||||
|
enumerable: false, configurable: true, writable: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function abbrev (list) {
|
||||||
|
if (arguments.length !== 1 || !Array.isArray(list)) {
|
||||||
|
list = Array.prototype.slice.call(arguments, 0)
|
||||||
|
}
|
||||||
|
for (var i = 0, l = list.length, args = [] ; i < l ; i ++) {
|
||||||
|
args[i] = typeof list[i] === "string" ? list[i] : String(list[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort them lexicographically, so that they're next to their nearest kin
|
||||||
|
args = args.sort(lexSort)
|
||||||
|
|
||||||
|
// walk through each, seeing how much it has in common with the next and previous
|
||||||
|
var abbrevs = {}
|
||||||
|
, prev = ""
|
||||||
|
for (var i = 0, l = args.length ; i < l ; i ++) {
|
||||||
|
var current = args[i]
|
||||||
|
, next = args[i + 1] || ""
|
||||||
|
, nextMatches = true
|
||||||
|
, prevMatches = true
|
||||||
|
if (current === next) continue
|
||||||
|
for (var j = 0, cl = current.length ; j < cl ; j ++) {
|
||||||
|
var curChar = current.charAt(j)
|
||||||
|
nextMatches = nextMatches && curChar === next.charAt(j)
|
||||||
|
prevMatches = prevMatches && curChar === prev.charAt(j)
|
||||||
|
if (!nextMatches && !prevMatches) {
|
||||||
|
j ++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev = current
|
||||||
|
if (j === cl) {
|
||||||
|
abbrevs[current] = current
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for (var a = current.substr(0, j) ; j <= cl ; j ++) {
|
||||||
|
abbrevs[a] = current
|
||||||
|
a += current.charAt(j)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return abbrevs
|
||||||
|
}
|
||||||
|
|
||||||
|
function lexSort (a, b) {
|
||||||
|
return a === b ? 0 : a > b ? 1 : -1
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"name": "abbrev",
|
||||||
|
"version": "1.1.1",
|
||||||
|
"description": "Like ruby's abbrev module, but in js",
|
||||||
|
"author": "Isaac Z. Schlueter <i@izs.me>",
|
||||||
|
"main": "abbrev.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "tap test.js --100",
|
||||||
|
"preversion": "npm test",
|
||||||
|
"postversion": "npm publish",
|
||||||
|
"postpublish": "git push origin --all; git push origin --tags"
|
||||||
|
},
|
||||||
|
"repository": "http://github.com/isaacs/abbrev-js",
|
||||||
|
"license": "ISC",
|
||||||
|
"devDependencies": {
|
||||||
|
"tap": "^10.1"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"abbrev.js"
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- 0.8
|
||||||
|
- "0.10"
|
|
@ -0,0 +1,18 @@
|
||||||
|
This software is released under the MIT license:
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,62 @@
|
||||||
|
buffer-equal
|
||||||
|
============
|
||||||
|
|
||||||
|
Return whether two buffers are equal.
|
||||||
|
|
||||||
|
[![build status](https://secure.travis-ci.org/substack/node-buffer-equal.png)](http://travis-ci.org/substack/node-buffer-equal)
|
||||||
|
|
||||||
|
example
|
||||||
|
=======
|
||||||
|
|
||||||
|
``` js
|
||||||
|
var bufferEqual = require('buffer-equal');
|
||||||
|
|
||||||
|
console.dir(bufferEqual(
|
||||||
|
new Buffer([253,254,255]),
|
||||||
|
new Buffer([253,254,255])
|
||||||
|
));
|
||||||
|
console.dir(bufferEqual(
|
||||||
|
new Buffer('abc'),
|
||||||
|
new Buffer('abcd')
|
||||||
|
));
|
||||||
|
console.dir(bufferEqual(
|
||||||
|
new Buffer('abc'),
|
||||||
|
'abc'
|
||||||
|
));
|
||||||
|
```
|
||||||
|
|
||||||
|
output:
|
||||||
|
|
||||||
|
```
|
||||||
|
true
|
||||||
|
false
|
||||||
|
undefined
|
||||||
|
```
|
||||||
|
|
||||||
|
methods
|
||||||
|
=======
|
||||||
|
|
||||||
|
``` js
|
||||||
|
var bufferEqual = require('buffer-equal')
|
||||||
|
```
|
||||||
|
|
||||||
|
bufferEqual(a, b)
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Return whether the two buffers `a` and `b` are equal.
|
||||||
|
|
||||||
|
If `a` or `b` is not a buffer, return `undefined`.
|
||||||
|
|
||||||
|
install
|
||||||
|
=======
|
||||||
|
|
||||||
|
With [npm](http://npmjs.org) do:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install buffer-equal
|
||||||
|
```
|
||||||
|
|
||||||
|
license
|
||||||
|
=======
|
||||||
|
|
||||||
|
MIT
|
|
@ -0,0 +1,14 @@
|
||||||
|
var bufferEqual = require('../');
|
||||||
|
|
||||||
|
console.dir(bufferEqual(
|
||||||
|
new Buffer([253,254,255]),
|
||||||
|
new Buffer([253,254,255])
|
||||||
|
));
|
||||||
|
console.dir(bufferEqual(
|
||||||
|
new Buffer('abc'),
|
||||||
|
new Buffer('abcd')
|
||||||
|
));
|
||||||
|
console.dir(bufferEqual(
|
||||||
|
new Buffer('abc'),
|
||||||
|
'abc'
|
||||||
|
));
|
|
@ -0,0 +1,14 @@
|
||||||
|
var Buffer = require('buffer').Buffer; // for use with browserify
|
||||||
|
|
||||||
|
module.exports = function (a, b) {
|
||||||
|
if (!Buffer.isBuffer(a)) return undefined;
|
||||||
|
if (!Buffer.isBuffer(b)) return undefined;
|
||||||
|
if (typeof a.equals === 'function') return a.equals(b);
|
||||||
|
if (a.length !== b.length) return false;
|
||||||
|
|
||||||
|
for (var i = 0; i < a.length; i++) {
|
||||||
|
if (a[i] !== b[i]) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"name" : "buffer-equal",
|
||||||
|
"description" : "return whether two buffers are equal",
|
||||||
|
"version" : "0.0.2",
|
||||||
|
"repository" : {
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "git://github.com/substack/node-buffer-equal.git"
|
||||||
|
},
|
||||||
|
"main" : "index.js",
|
||||||
|
"keywords" : [
|
||||||
|
"buffer",
|
||||||
|
"equal"
|
||||||
|
],
|
||||||
|
"directories" : {
|
||||||
|
"example" : "example",
|
||||||
|
"test" : "test"
|
||||||
|
},
|
||||||
|
"scripts" : {
|
||||||
|
"test" : "tap test/*.js"
|
||||||
|
},
|
||||||
|
"devDependencies" : {
|
||||||
|
"tap" : "0.2.4"
|
||||||
|
},
|
||||||
|
"engines" : {
|
||||||
|
"node" : ">=0.4.0"
|
||||||
|
},
|
||||||
|
"license" : "MIT",
|
||||||
|
"author" : {
|
||||||
|
"name" : "James Halliday",
|
||||||
|
"email" : "mail@substack.net",
|
||||||
|
"url" : "http://substack.net"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
var bufferEqual = require('../');
|
||||||
|
var test = require('tap').test;
|
||||||
|
|
||||||
|
test('equal', function (t) {
|
||||||
|
var eq = bufferEqual(
|
||||||
|
new Buffer([253,254,255]),
|
||||||
|
new Buffer([253,254,255])
|
||||||
|
);
|
||||||
|
t.strictEqual(eq, true);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('not equal', function (t) {
|
||||||
|
var eq = bufferEqual(
|
||||||
|
new Buffer('abc'),
|
||||||
|
new Buffer('abcd')
|
||||||
|
);
|
||||||
|
t.strictEqual(eq, false);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('not equal not buffer', function (t) {
|
||||||
|
var eq = bufferEqual(
|
||||||
|
new Buffer('abc'),
|
||||||
|
'abc'
|
||||||
|
);
|
||||||
|
t.strictEqual(eq, undefined);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('equal not buffer', function (t) {
|
||||||
|
var eq = bufferEqual('abc', 'abc');
|
||||||
|
t.strictEqual(eq, undefined);
|
||||||
|
t.end();
|
||||||
|
});
|
|
@ -0,0 +1 @@
|
||||||
|
node_modules
|
|
@ -0,0 +1,4 @@
|
||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- 0.4
|
||||||
|
- 0.6
|
|
@ -0,0 +1,82 @@
|
||||||
|
bunker
|
||||||
|
======
|
||||||
|
|
||||||
|
Bunker is a module to calculate code coverage using native javascript
|
||||||
|
[burrito](https://github.com/substack/node-burrito) AST trickery.
|
||||||
|
|
||||||
|
[![build status](https://secure.travis-ci.org/substack/node-bunker.png)](http://travis-ci.org/substack/node-bunker)
|
||||||
|
|
||||||
|
![code coverage](http://substack.net/images/code_coverage.png)
|
||||||
|
|
||||||
|
examples
|
||||||
|
========
|
||||||
|
|
||||||
|
tiny
|
||||||
|
----
|
||||||
|
|
||||||
|
````javascript
|
||||||
|
var bunker = require('bunker');
|
||||||
|
var b = bunker('var x = 0; for (var i = 0; i < 30; i++) { x++ }');
|
||||||
|
|
||||||
|
var counts = {};
|
||||||
|
|
||||||
|
b.on('node', function (node) {
|
||||||
|
if (!counts[node.id]) {
|
||||||
|
counts[node.id] = { times : 0, node : node };
|
||||||
|
}
|
||||||
|
counts[node.id].times ++;
|
||||||
|
});
|
||||||
|
|
||||||
|
b.run();
|
||||||
|
|
||||||
|
Object.keys(counts).forEach(function (key) {
|
||||||
|
var count = counts[key];
|
||||||
|
console.log(count.times + ' : ' + count.node.source());
|
||||||
|
});
|
||||||
|
````
|
||||||
|
|
||||||
|
output:
|
||||||
|
|
||||||
|
$ node example/tiny.js
|
||||||
|
1 : var x=0;
|
||||||
|
31 : i<30
|
||||||
|
30 : i++
|
||||||
|
30 : x++;
|
||||||
|
30 : x++
|
||||||
|
|
||||||
|
methods
|
||||||
|
=======
|
||||||
|
|
||||||
|
var bunker = require('bunker');
|
||||||
|
|
||||||
|
var b = bunker(src)
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Create a new bunker code coverageifier with some source `src`.
|
||||||
|
|
||||||
|
The bunker object `b` is an `EventEmitter` that emits `'node'` events with two
|
||||||
|
parameters:
|
||||||
|
|
||||||
|
* `node` - the [burrito](https://github.com/substack/node-burrito) node object
|
||||||
|
* `stack` - the stack, [stackedy](https://github.com/substack/node-stackedy) style
|
||||||
|
|
||||||
|
b.include(src)
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Include some source into the bunker.
|
||||||
|
|
||||||
|
b.compile()
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Return the source wrapped with burrito.
|
||||||
|
|
||||||
|
b.assign(context={})
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Assign the statement-tracking functions into `context`.
|
||||||
|
|
||||||
|
b.run(context={})
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Run the source using `vm.runInNewContext()` with some `context`.
|
||||||
|
The statement-tracking functions will be added to `context` by `assign()`.
|
|
@ -0,0 +1,51 @@
|
||||||
|
var bunker = require('bunker');
|
||||||
|
var b = bunker('(' + function () {
|
||||||
|
function beep () {
|
||||||
|
var x = 0;
|
||||||
|
for (var i = 0; i < 1000; i++) {
|
||||||
|
for (var j = 0; j < 100; j++) {
|
||||||
|
x += j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
beep();
|
||||||
|
|
||||||
|
} + ')()');
|
||||||
|
|
||||||
|
var counts = {};
|
||||||
|
|
||||||
|
b.on('node', function (node) {
|
||||||
|
if (!counts[node.id]) {
|
||||||
|
counts[node.id] = { times : 0, node : node, elapsed : 0 };
|
||||||
|
}
|
||||||
|
counts[node.id].times ++;
|
||||||
|
|
||||||
|
var now = Date.now();
|
||||||
|
|
||||||
|
if (last.id !== undefined) {
|
||||||
|
counts[last.id].elapsed += last.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.name === 'call') {
|
||||||
|
var start = now;
|
||||||
|
|
||||||
|
last.id = node.id;
|
||||||
|
counts[node.id].elapsed += Date.now() - start;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
counts[node.id].elapsed += now - last;
|
||||||
|
last = now;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
b.run();
|
||||||
|
|
||||||
|
Object.keys(counts).forEach(function (key) {
|
||||||
|
var count = counts[key];
|
||||||
|
console.log(
|
||||||
|
[ count.times, count.node.source(), count.elapsed ]
|
||||||
|
.join(' : ')
|
||||||
|
);
|
||||||
|
});
|
|
@ -0,0 +1,18 @@
|
||||||
|
var bunker = require('bunker');
|
||||||
|
var b = bunker('var x = 0; for (var i = 0; i < 30; i++) { x++ }');
|
||||||
|
|
||||||
|
var counts = {};
|
||||||
|
|
||||||
|
b.on('node', function (node) {
|
||||||
|
if (!counts[node.id]) {
|
||||||
|
counts[node.id] = { times : 0, node : node };
|
||||||
|
}
|
||||||
|
counts[node.id].times ++;
|
||||||
|
});
|
||||||
|
|
||||||
|
b.run();
|
||||||
|
|
||||||
|
Object.keys(counts).forEach(function (key) {
|
||||||
|
var count = counts[key];
|
||||||
|
console.log(count.times + ' : ' + count.node.source());
|
||||||
|
});
|
|
@ -0,0 +1,31 @@
|
||||||
|
var bunker = require('bunker');
|
||||||
|
var fs = require('fs');
|
||||||
|
var src = fs.readFileSync(__dirname + '/src.js', 'utf8');
|
||||||
|
|
||||||
|
var counts = {};
|
||||||
|
|
||||||
|
var b = bunker(src);
|
||||||
|
b.on('node', function (node) {
|
||||||
|
if (!counts[node.id]) {
|
||||||
|
counts[node.id] = { times : 0, node : node };
|
||||||
|
}
|
||||||
|
counts[node.id].times ++;
|
||||||
|
});
|
||||||
|
|
||||||
|
b.run({
|
||||||
|
setInterval : setInterval,
|
||||||
|
clearInterval : clearInterval,
|
||||||
|
end : function () {
|
||||||
|
Object.keys(counts)
|
||||||
|
.sort(function (a, b) {
|
||||||
|
return counts[b].times - counts[a].times
|
||||||
|
})
|
||||||
|
.forEach(function (key) {
|
||||||
|
var count = counts[key];
|
||||||
|
console.log(
|
||||||
|
count.times + ' : ' + count.node.source()
|
||||||
|
);
|
||||||
|
})
|
||||||
|
;
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,18 @@
|
||||||
|
function boop () {
|
||||||
|
for (var i = 0; i < 30; i++) {
|
||||||
|
nop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function nop () {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
var times = 0;
|
||||||
|
var iv = setInterval(function () {
|
||||||
|
if (++times === 10) {
|
||||||
|
clearInterval(iv);
|
||||||
|
end();
|
||||||
|
}
|
||||||
|
else boop()
|
||||||
|
}, 100);
|
|
@ -0,0 +1,116 @@
|
||||||
|
var burrito = require('burrito');
|
||||||
|
var vm = require('vm');
|
||||||
|
var EventEmitter = require('events').EventEmitter;
|
||||||
|
|
||||||
|
module.exports = function (src) {
|
||||||
|
var b = new Bunker();
|
||||||
|
if (src) b.include(src);
|
||||||
|
return b;
|
||||||
|
};
|
||||||
|
|
||||||
|
function Bunker () {
|
||||||
|
this.sources = [];
|
||||||
|
this.nodes = [];
|
||||||
|
|
||||||
|
this.names = {
|
||||||
|
call : burrito.generateName(6),
|
||||||
|
expr : burrito.generateName(6),
|
||||||
|
stat : burrito.generateName(6),
|
||||||
|
return : burrito.generateName(6)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Bunker.prototype = new EventEmitter;
|
||||||
|
|
||||||
|
Bunker.prototype.include = function (src) {
|
||||||
|
this.sources.push(src);
|
||||||
|
this.source = null;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Bunker.prototype.compile = function () {
|
||||||
|
var src = this.sources.join('\n');
|
||||||
|
var nodes = this.nodes;
|
||||||
|
var names = this.names;
|
||||||
|
|
||||||
|
return burrito(src, function (node) {
|
||||||
|
var i = nodes.length;
|
||||||
|
|
||||||
|
if (node.name === 'call') {
|
||||||
|
nodes.push(node);
|
||||||
|
node.wrap(names.call + '(' + i + ')(%s)');
|
||||||
|
}
|
||||||
|
else if (node.name === 'stat' || node.name === 'throw'
|
||||||
|
|| node.name === 'var') {
|
||||||
|
nodes.push(node);
|
||||||
|
node.wrap('{' + names.stat + '(' + i + ');%s}');
|
||||||
|
}
|
||||||
|
else if (node.name === 'return') {
|
||||||
|
nodes.push(node);
|
||||||
|
// We need to wrap the new source in a function definition
|
||||||
|
// so that UglifyJS will allow the presence of return
|
||||||
|
var stat = names.stat + '(' + i + ');';
|
||||||
|
var wrapped = 'function ' + names.return + '() {'
|
||||||
|
+ stat + node.source()
|
||||||
|
+'}'
|
||||||
|
;
|
||||||
|
var parsed = burrito.parse(wrapped);
|
||||||
|
// Remove the function definition from the AST
|
||||||
|
parsed[1] = parsed[1][0][3];
|
||||||
|
node.state.update(parsed, true);
|
||||||
|
}
|
||||||
|
else if (node.name === 'binary') {
|
||||||
|
nodes.push(node);
|
||||||
|
node.wrap(names.expr + '(' + i + ')(%s)');
|
||||||
|
}
|
||||||
|
else if (node.name === 'unary-postfix' || node.name === 'unary-prefix') {
|
||||||
|
nodes.push(node);
|
||||||
|
node.wrap(names.expr + '(' + i + ')(%s)');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i !== nodes.length) {
|
||||||
|
node.id = i;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Bunker.prototype.assign = function (context) {
|
||||||
|
if (!context) context = {};
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
var stack = [];
|
||||||
|
|
||||||
|
context[self.names.call] = function (i) {
|
||||||
|
var node = self.nodes[i];
|
||||||
|
stack.unshift(node);
|
||||||
|
self.emit('node', node, stack);
|
||||||
|
|
||||||
|
return function (expr) {
|
||||||
|
stack.shift();
|
||||||
|
return expr;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
context[self.names.expr] = function (i) {
|
||||||
|
var node = self.nodes[i];
|
||||||
|
self.emit('node', node, stack);
|
||||||
|
|
||||||
|
return function (expr) {
|
||||||
|
return expr;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
context[self.names.stat] = function (i) {
|
||||||
|
var node = self.nodes[i];
|
||||||
|
self.emit('node', node, stack);
|
||||||
|
};
|
||||||
|
|
||||||
|
return context;
|
||||||
|
};
|
||||||
|
|
||||||
|
Bunker.prototype.run = function (context) {
|
||||||
|
var src = this.compile();
|
||||||
|
vm.runInNewContext(src, this.assign(context));
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
|
@ -0,0 +1,35 @@
|
||||||
|
{
|
||||||
|
"name" : "bunker",
|
||||||
|
"version" : "0.1.2",
|
||||||
|
"description" : "code coverage in native javascript",
|
||||||
|
"main" : "index.js",
|
||||||
|
"directories" : {
|
||||||
|
"lib" : ".",
|
||||||
|
"example" : "example",
|
||||||
|
"test" : "test"
|
||||||
|
},
|
||||||
|
"dependencies" : {
|
||||||
|
"burrito" : ">=0.2.5 <0.3"
|
||||||
|
},
|
||||||
|
"devDependencies" : {
|
||||||
|
"tap" : "~0.2.4"
|
||||||
|
},
|
||||||
|
"scripts" : {
|
||||||
|
"test" : "tap test/*.js"
|
||||||
|
},
|
||||||
|
"repository" : {
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "http://github.com/substack/node-bunker.git"
|
||||||
|
},
|
||||||
|
"keywords" : [
|
||||||
|
"code",
|
||||||
|
"coverage"
|
||||||
|
],
|
||||||
|
"author" : {
|
||||||
|
"name" : "James Halliday",
|
||||||
|
"email" : "mail@substack.net",
|
||||||
|
"url" : "http://substack.net"
|
||||||
|
},
|
||||||
|
"license" : "MIT/X11",
|
||||||
|
"engine" : { "node" : ">=0.4" }
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
var test = require('tap').test;
|
||||||
|
var bunker = require('../');
|
||||||
|
var fs = require('fs');
|
||||||
|
|
||||||
|
var src = fs.readdirSync(__dirname + '/src').reduce(function (acc, file) {
|
||||||
|
acc[file] = fs.readFileSync(__dirname + '/src/' + file, 'utf8');
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
test('cover', function (t) {
|
||||||
|
t.plan(1);
|
||||||
|
|
||||||
|
var b = bunker(src['cover.js']);
|
||||||
|
var counts = {};
|
||||||
|
|
||||||
|
b.on('node', function (node) {
|
||||||
|
counts[node.name] = (counts[node.name] || 0) + 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
b.run({
|
||||||
|
setInterval : setInterval,
|
||||||
|
clearInterval : function () {
|
||||||
|
process.nextTick(function () {
|
||||||
|
t.same(counts, {
|
||||||
|
binary : 11,
|
||||||
|
'unary-postfix' : 11,
|
||||||
|
'var' : 2,
|
||||||
|
call : 2, // setInterval and clearInterval
|
||||||
|
stat : 1, // clearInterval
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return clearInterval.apply(this, arguments);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,29 @@
|
||||||
|
var test = require('tap').test;
|
||||||
|
var bunker = require('../');
|
||||||
|
|
||||||
|
test('cover', function (t) {
|
||||||
|
t.plan(1);
|
||||||
|
|
||||||
|
var b = bunker('(' + function () {
|
||||||
|
function foo () {}
|
||||||
|
function bar () {}
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
return foo();
|
||||||
|
})();
|
||||||
|
} + ')()');
|
||||||
|
var counts = {};
|
||||||
|
|
||||||
|
b.on('node', function (node) {
|
||||||
|
counts[node.name] = (counts[node.name] || 0) + 1;
|
||||||
|
});
|
||||||
|
b.run();
|
||||||
|
|
||||||
|
process.nextTick(function () {
|
||||||
|
t.same(counts, {
|
||||||
|
stat : 2,
|
||||||
|
call : 2,
|
||||||
|
return : 1,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,6 @@
|
||||||
|
var i = 0;
|
||||||
|
var iv = setInterval(function () {
|
||||||
|
if (i++ === 10) {
|
||||||
|
clearInterval(iv);
|
||||||
|
}
|
||||||
|
}, 10);
|
|
@ -0,0 +1 @@
|
||||||
|
node_modules
|
|
@ -0,0 +1,4 @@
|
||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- 0.4
|
||||||
|
- 0.6
|
|
@ -0,0 +1,187 @@
|
||||||
|
burrito
|
||||||
|
=======
|
||||||
|
|
||||||
|
Burrito makes it easy to do crazy stuff with the javascript AST.
|
||||||
|
|
||||||
|
This is super useful if you want to roll your own stack traces or build a code
|
||||||
|
coverage tool.
|
||||||
|
|
||||||
|
[![build status](https://secure.travis-ci.org/substack/node-burrito.png)](http://travis-ci.org/substack/node-burrito)
|
||||||
|
|
||||||
|
![node.wrap("burrito")](http://substack.net/images/burrito.png)
|
||||||
|
|
||||||
|
examples
|
||||||
|
========
|
||||||
|
|
||||||
|
microwave
|
||||||
|
---------
|
||||||
|
|
||||||
|
examples/microwave.js
|
||||||
|
|
||||||
|
````javascript
|
||||||
|
var burrito = require('burrito');
|
||||||
|
|
||||||
|
var res = burrito.microwave('Math.sin(2)', function (node) {
|
||||||
|
if (node.name === 'num') node.wrap('Math.PI / %s');
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(res); // sin(pi / 2) == 1
|
||||||
|
````
|
||||||
|
|
||||||
|
output:
|
||||||
|
|
||||||
|
1
|
||||||
|
|
||||||
|
wrap
|
||||||
|
----
|
||||||
|
|
||||||
|
examples/wrap.js
|
||||||
|
|
||||||
|
````javascript
|
||||||
|
var burrito = require('burrito');
|
||||||
|
|
||||||
|
var src = burrito('f() && g(h())\nfoo()', function (node) {
|
||||||
|
if (node.name === 'call') node.wrap('qqq(%s)');
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(src);
|
||||||
|
````
|
||||||
|
|
||||||
|
output:
|
||||||
|
|
||||||
|
qqq(f()) && qqq(g(qqq(h())));
|
||||||
|
|
||||||
|
qqq(foo());
|
||||||
|
|
||||||
|
methods
|
||||||
|
=======
|
||||||
|
|
||||||
|
var burrito = require('burrito');
|
||||||
|
|
||||||
|
burrito(code, cb)
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Given some source `code` and a function `trace`, walk the ast by expression.
|
||||||
|
|
||||||
|
The `cb` gets called with a node object described below.
|
||||||
|
|
||||||
|
If `code` is an Array then it is assumbed to be an AST which you can generate
|
||||||
|
yourself with `burrito.parse()`. The AST must be annotated, so make sure to
|
||||||
|
`burrito.parse(src, false, true)`.
|
||||||
|
|
||||||
|
burrito.microwave(code, context={}, cb)
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
Like `burrito()` except the result is run using
|
||||||
|
`vm.runInNewContext(res, context)`.
|
||||||
|
|
||||||
|
node object
|
||||||
|
===========
|
||||||
|
|
||||||
|
node.name
|
||||||
|
---------
|
||||||
|
|
||||||
|
Name is a string that contains the type of the expression as named by uglify.
|
||||||
|
|
||||||
|
node.wrap(s)
|
||||||
|
------------
|
||||||
|
|
||||||
|
Wrap the current expression in `s`.
|
||||||
|
|
||||||
|
If `s` is a string, `"%s"` will be replaced with the stringified current
|
||||||
|
expression.
|
||||||
|
|
||||||
|
If `s` is a function, it is called with the stringified current expression and
|
||||||
|
should return a new stringified expression.
|
||||||
|
|
||||||
|
If the `node.name === "binary"`, you get the subterms "%a" and "%b" to play with
|
||||||
|
too. These subterms are applied if `s` is a function too: `s(expr, a, b)`.
|
||||||
|
|
||||||
|
Protip: to insert multiple statements you can use javascript's lesser-known block
|
||||||
|
syntax that it gets from C:
|
||||||
|
|
||||||
|
````javascript
|
||||||
|
if (node.name === 'stat') node.wrap('{ foo(); %s }')
|
||||||
|
````
|
||||||
|
|
||||||
|
node.node
|
||||||
|
---------
|
||||||
|
|
||||||
|
raw ast data generated by uglify
|
||||||
|
|
||||||
|
node.value
|
||||||
|
----------
|
||||||
|
|
||||||
|
`node.node.slice(1)` to skip the annotations
|
||||||
|
|
||||||
|
node.start
|
||||||
|
----------
|
||||||
|
|
||||||
|
The start location of the expression, like this:
|
||||||
|
|
||||||
|
````javascript
|
||||||
|
{ type: 'name',
|
||||||
|
value: 'b',
|
||||||
|
line: 0,
|
||||||
|
col: 3,
|
||||||
|
pos: 3,
|
||||||
|
nlb: false,
|
||||||
|
comments_before: [] }
|
||||||
|
````
|
||||||
|
|
||||||
|
node.end
|
||||||
|
--------
|
||||||
|
|
||||||
|
The end location of the expression, formatted the same as `node.start`.
|
||||||
|
|
||||||
|
node.state
|
||||||
|
----------
|
||||||
|
|
||||||
|
The state of the traversal using traverse.
|
||||||
|
|
||||||
|
node.source()
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Returns a stringified version of the expression.
|
||||||
|
|
||||||
|
node.parent()
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Returns the parent `node` or `null` if the node is the root element.
|
||||||
|
|
||||||
|
node.label()
|
||||||
|
------------
|
||||||
|
|
||||||
|
Return the label of the present node or `null` if there is no label.
|
||||||
|
|
||||||
|
Labels are returned for "call", "var", "defun", and "function" nodes.
|
||||||
|
|
||||||
|
Returns an array for "var" nodes since `var` statements can
|
||||||
|
contain multiple labels in assignment.
|
||||||
|
|
||||||
|
install
|
||||||
|
=======
|
||||||
|
|
||||||
|
With [npm](http://npmjs.org) you can just:
|
||||||
|
|
||||||
|
npm install burrito
|
||||||
|
|
||||||
|
in the browser
|
||||||
|
==============
|
||||||
|
|
||||||
|
Burrito works in browser with
|
||||||
|
[browserify](https://github.com/substack/node-browserify).
|
||||||
|
|
||||||
|
It has been tested against:
|
||||||
|
|
||||||
|
* Internet Explorer 5.5, 6.0, 7.0, 8.0, 9.0
|
||||||
|
* Firefox 3.5
|
||||||
|
* Chrome 6.0
|
||||||
|
* Opera 10.6
|
||||||
|
* Safari 5.0
|
||||||
|
|
||||||
|
kudos
|
||||||
|
=====
|
||||||
|
|
||||||
|
Heavily inspired by (and previously mostly lifted outright from) isaacs's nifty
|
||||||
|
tmp/instrument.js thingy from uglify-js.
|
|
@ -0,0 +1,8 @@
|
||||||
|
var burrito = require('burrito');
|
||||||
|
|
||||||
|
var res = burrito.microwave('Math.sin(2)', function (node) {
|
||||||
|
console.dir(node);
|
||||||
|
if (node.name === 'num') node.wrap('Math.PI / %s');
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(res); // sin(pi / 2) == 1
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,14 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script type="text/javascript" src="/browserify.js"></script>
|
||||||
|
<style type="text/css">
|
||||||
|
pre {
|
||||||
|
white-space: pre;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<pre id="output"></pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,17 @@
|
||||||
|
var burrito = require('burrito');
|
||||||
|
var json = require('jsonify');
|
||||||
|
|
||||||
|
var src = [
|
||||||
|
'function f () { g() }',
|
||||||
|
'function g () { h() }',
|
||||||
|
'function h () { throw "moo" + Array(x).join("!") }',
|
||||||
|
'var x = 4',
|
||||||
|
'f()'
|
||||||
|
].join('\r\n');
|
||||||
|
|
||||||
|
window.onload = function () {
|
||||||
|
burrito(src, function (node) {
|
||||||
|
document.body.innerHTML += node.name + '<br>\n';
|
||||||
|
});
|
||||||
|
};
|
||||||
|
if (document.readyState === 'complete') window.onload();
|
|
@ -0,0 +1,12 @@
|
||||||
|
var express = require('express');
|
||||||
|
var browserify = require('browserify');
|
||||||
|
|
||||||
|
var app = express.createServer();
|
||||||
|
app.use(express.static(__dirname));
|
||||||
|
app.use(browserify({
|
||||||
|
entry : __dirname + '/main.js',
|
||||||
|
watch : true,
|
||||||
|
}));
|
||||||
|
|
||||||
|
app.listen(8081);
|
||||||
|
console.log('Listening on :8081');
|
|
@ -0,0 +1,7 @@
|
||||||
|
var burrito = require('burrito');
|
||||||
|
|
||||||
|
var src = burrito('f() && g(h())\nfoo()', function (node) {
|
||||||
|
if (node.name === 'call') node.wrap('qqq(%s)');
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(src);
|
|
@ -0,0 +1,208 @@
|
||||||
|
var uglify = require('uglify-js');
|
||||||
|
var parser = uglify.parser;
|
||||||
|
var parse = function (expr) {
|
||||||
|
if (typeof expr !== 'string') throw 'expression should be a string';
|
||||||
|
|
||||||
|
try {
|
||||||
|
var ast = parser.parse.apply(null, arguments);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
if (err.message === undefined
|
||||||
|
|| err.line === undefined
|
||||||
|
|| err.col === undefined
|
||||||
|
|| err.pos === undefined
|
||||||
|
) { throw err }
|
||||||
|
|
||||||
|
var e = new SyntaxError(
|
||||||
|
err.message
|
||||||
|
+ '\n at line ' + err.line + ':' + err.col + ' in expression:\n\n'
|
||||||
|
+ ' ' + expr.split(/\r?\n/)[err.line]
|
||||||
|
);
|
||||||
|
|
||||||
|
e.original = err;
|
||||||
|
e.line = err.line;
|
||||||
|
e.col = err.col;
|
||||||
|
e.pos = err.pos;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
return ast;
|
||||||
|
};
|
||||||
|
|
||||||
|
var deparse = function (ast, b) {
|
||||||
|
return uglify.uglify.gen_code(ast, { beautify : b });
|
||||||
|
};
|
||||||
|
|
||||||
|
var traverse = require('traverse');
|
||||||
|
var vm = require('vm');
|
||||||
|
|
||||||
|
var burrito = module.exports = function (code, cb) {
|
||||||
|
var ast = Array_isArray(code)
|
||||||
|
? code // already an ast
|
||||||
|
: parse(code.toString(), false, true)
|
||||||
|
;
|
||||||
|
|
||||||
|
var ast_ = traverse(ast).map(function mapper () {
|
||||||
|
wrapNode(this, cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
return deparse(parse(deparse(ast_)), true);
|
||||||
|
};
|
||||||
|
|
||||||
|
var wrapNode = burrito.wrapNode = function (state, cb) {
|
||||||
|
var node = state.node;
|
||||||
|
|
||||||
|
var ann = Array_isArray(node) && node[0]
|
||||||
|
&& typeof node[0] === 'object' && node[0].name
|
||||||
|
? node[0]
|
||||||
|
: null
|
||||||
|
;
|
||||||
|
|
||||||
|
if (!ann) return undefined;
|
||||||
|
|
||||||
|
var self = {
|
||||||
|
name : ann.name,
|
||||||
|
node : node,
|
||||||
|
start : node[0].start,
|
||||||
|
end : node[0].end,
|
||||||
|
value : node.slice(1),
|
||||||
|
state : state
|
||||||
|
};
|
||||||
|
|
||||||
|
self.wrap = function (s) {
|
||||||
|
var subsrc = deparse(
|
||||||
|
traverse(node).map(function (x) {
|
||||||
|
if (!this.isRoot) wrapNode(this, cb)
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
if (self.name === 'binary') {
|
||||||
|
var a = deparse(traverse(node[2]).map(function (x) {
|
||||||
|
if (!this.isRoot) wrapNode(this, cb)
|
||||||
|
}));
|
||||||
|
var b = deparse(traverse(node[3]).map(function (x) {
|
||||||
|
if (!this.isRoot) wrapNode(this, cb)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
var src = '';
|
||||||
|
|
||||||
|
if (typeof s === 'function') {
|
||||||
|
if (self.name === 'binary') {
|
||||||
|
src = s(subsrc, a, b);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
src = s(subsrc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
src = s.toString()
|
||||||
|
.replace(/%s/g, function () {
|
||||||
|
return subsrc
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
|
if (self.name === 'binary') {
|
||||||
|
src = src
|
||||||
|
.replace(/%a/g, function () { return a })
|
||||||
|
.replace(/%b/g, function () { return b })
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var expr = parse(src);
|
||||||
|
state.update(expr, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
var cache = {};
|
||||||
|
|
||||||
|
self.parent = state.isRoot ? null : function () {
|
||||||
|
if (!cache.parent) {
|
||||||
|
var s = state;
|
||||||
|
var x;
|
||||||
|
do {
|
||||||
|
s = s.parent;
|
||||||
|
if (s) x = wrapNode(s);
|
||||||
|
} while (s && !x);
|
||||||
|
|
||||||
|
cache.parent = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cache.parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.source = function () {
|
||||||
|
if (!cache.source) cache.source = deparse(node);
|
||||||
|
return cache.source;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.label = function () {
|
||||||
|
return burrito.label(self);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (cb) cb.call(state, self);
|
||||||
|
|
||||||
|
if (self.node[0].name === 'conditional') {
|
||||||
|
self.wrap('[%s][0]');
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
burrito.microwave = function (code, context, cb) {
|
||||||
|
if (!cb) { cb = context; context = {} };
|
||||||
|
if (!context) context = {};
|
||||||
|
|
||||||
|
var src = burrito(code, cb);
|
||||||
|
return vm.runInNewContext(src, context);
|
||||||
|
};
|
||||||
|
|
||||||
|
burrito.generateName = function (len) {
|
||||||
|
var name = '';
|
||||||
|
var lower = '$'.charCodeAt(0);
|
||||||
|
var upper = 'z'.charCodeAt(0);
|
||||||
|
|
||||||
|
while (name.length < len) {
|
||||||
|
var c = String.fromCharCode(Math.floor(
|
||||||
|
Math.random() * (upper - lower + 1) + lower
|
||||||
|
));
|
||||||
|
if ((name + c).match(/^[A-Za-z_$][A-Za-z0-9_$]*$/)) name += c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
};
|
||||||
|
|
||||||
|
burrito.parse = parse;
|
||||||
|
burrito.deparse = deparse;
|
||||||
|
|
||||||
|
burrito.label = function (node) {
|
||||||
|
if (node.name === 'call') {
|
||||||
|
if (typeof node.value[0] === 'string') {
|
||||||
|
return node.value[0];
|
||||||
|
}
|
||||||
|
else if (node.value[0] && typeof node.value[0][1] === 'string') {
|
||||||
|
return node.value[0][1];
|
||||||
|
}
|
||||||
|
else if (node.value[0][0] === 'dot') {
|
||||||
|
return node.value[0][node.value[0].length - 1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (node.name === 'var') {
|
||||||
|
return node.value[0].map(function (x) { return x[0] });
|
||||||
|
}
|
||||||
|
else if (node.name === 'defun') {
|
||||||
|
return node.value[0];
|
||||||
|
}
|
||||||
|
else if (node.name === 'function') {
|
||||||
|
return node.value[0];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var Array_isArray = Array.isArray || function isArray (xs) {
|
||||||
|
return Object.prototype.toString.call(xs) === '[object Array]';
|
||||||
|
};
|
|
@ -0,0 +1 @@
|
||||||
|
node_modules
|
|
@ -0,0 +1,24 @@
|
||||||
|
Copyright 2010 James Halliday (mail@substack.net)
|
||||||
|
|
||||||
|
This project is free software released under the MIT/X11 license:
|
||||||
|
http://www.opensource.org/licenses/mit-license.php
|
||||||
|
|
||||||
|
Copyright 2010 James Halliday (mail@substack.net)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
|
@ -0,0 +1,237 @@
|
||||||
|
traverse
|
||||||
|
========
|
||||||
|
|
||||||
|
Traverse and transform objects by visiting every node on a recursive walk.
|
||||||
|
|
||||||
|
examples
|
||||||
|
========
|
||||||
|
|
||||||
|
transform negative numbers in-place
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
negative.js
|
||||||
|
|
||||||
|
````javascript
|
||||||
|
var traverse = require('traverse');
|
||||||
|
var obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ];
|
||||||
|
|
||||||
|
traverse(obj).forEach(function (x) {
|
||||||
|
if (x < 0) this.update(x + 128);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.dir(obj);
|
||||||
|
````
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
[ 5, 6, 125, [ 7, 8, 126, 1 ], { f: 10, g: 115 } ]
|
||||||
|
|
||||||
|
collect leaf nodes
|
||||||
|
------------------
|
||||||
|
|
||||||
|
leaves.js
|
||||||
|
|
||||||
|
````javascript
|
||||||
|
var traverse = require('traverse');
|
||||||
|
|
||||||
|
var obj = {
|
||||||
|
a : [1,2,3],
|
||||||
|
b : 4,
|
||||||
|
c : [5,6],
|
||||||
|
d : { e : [7,8], f : 9 },
|
||||||
|
};
|
||||||
|
|
||||||
|
var leaves = traverse(obj).reduce(function (acc, x) {
|
||||||
|
if (this.isLeaf) acc.push(x);
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
console.dir(leaves);
|
||||||
|
````
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
[ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
|
||||||
|
|
||||||
|
scrub circular references
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
scrub.js:
|
||||||
|
|
||||||
|
````javascript
|
||||||
|
var traverse = require('traverse');
|
||||||
|
|
||||||
|
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
|
||||||
|
obj.c.push(obj);
|
||||||
|
|
||||||
|
var scrubbed = traverse(obj).map(function (x) {
|
||||||
|
if (this.circular) this.remove()
|
||||||
|
});
|
||||||
|
console.dir(scrubbed);
|
||||||
|
````
|
||||||
|
|
||||||
|
output:
|
||||||
|
|
||||||
|
{ a: 1, b: 2, c: [ 3, 4 ] }
|
||||||
|
|
||||||
|
context
|
||||||
|
=======
|
||||||
|
|
||||||
|
Each method that takes a callback has a context (its `this` object) with these
|
||||||
|
attributes:
|
||||||
|
|
||||||
|
this.node
|
||||||
|
---------
|
||||||
|
|
||||||
|
The present node on the recursive walk
|
||||||
|
|
||||||
|
this.path
|
||||||
|
---------
|
||||||
|
|
||||||
|
An array of string keys from the root to the present node
|
||||||
|
|
||||||
|
this.parent
|
||||||
|
-----------
|
||||||
|
|
||||||
|
The context of the node's parent.
|
||||||
|
This is `undefined` for the root node.
|
||||||
|
|
||||||
|
this.key
|
||||||
|
--------
|
||||||
|
|
||||||
|
The name of the key of the present node in its parent.
|
||||||
|
This is `undefined` for the root node.
|
||||||
|
|
||||||
|
this.isRoot, this.notRoot
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
Whether the present node is the root node
|
||||||
|
|
||||||
|
this.isLeaf, this.notLeaf
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
Whether or not the present node is a leaf node (has no children)
|
||||||
|
|
||||||
|
this.level
|
||||||
|
----------
|
||||||
|
|
||||||
|
Depth of the node within the traversal
|
||||||
|
|
||||||
|
this.circular
|
||||||
|
-------------
|
||||||
|
|
||||||
|
If the node equals one of its parents, the `circular` attribute is set to the
|
||||||
|
context of that parent and the traversal progresses no deeper.
|
||||||
|
|
||||||
|
this.update(value, stopHere=false)
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
Set a new value for the present node.
|
||||||
|
|
||||||
|
All the elements in `value` will be recursively traversed unless `stopHere` is
|
||||||
|
true.
|
||||||
|
|
||||||
|
this.remove(stopHere=false)
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Remove the current element from the output. If the node is in an Array it will
|
||||||
|
be spliced off. Otherwise it will be deleted from its parent.
|
||||||
|
|
||||||
|
this.delete(stopHere=false)
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Delete the current element from its parent in the output. Calls `delete` even on
|
||||||
|
Arrays.
|
||||||
|
|
||||||
|
this.before(fn)
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Call this function before any of the children are traversed.
|
||||||
|
|
||||||
|
You can assign into `this.keys` here to traverse in a custom order.
|
||||||
|
|
||||||
|
this.after(fn)
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Call this function after any of the children are traversed.
|
||||||
|
|
||||||
|
this.pre(fn)
|
||||||
|
------------
|
||||||
|
|
||||||
|
Call this function before each of the children are traversed.
|
||||||
|
|
||||||
|
this.post(fn)
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Call this function after each of the children are traversed.
|
||||||
|
|
||||||
|
methods
|
||||||
|
=======
|
||||||
|
|
||||||
|
.map(fn)
|
||||||
|
--------
|
||||||
|
|
||||||
|
Execute `fn` for each node in the object and return a new object with the
|
||||||
|
results of the walk. To update nodes in the result use `this.update(value)`.
|
||||||
|
|
||||||
|
.forEach(fn)
|
||||||
|
------------
|
||||||
|
|
||||||
|
Execute `fn` for each node in the object but unlike `.map()`, when
|
||||||
|
`this.update()` is called it updates the object in-place.
|
||||||
|
|
||||||
|
.reduce(fn, acc)
|
||||||
|
----------------
|
||||||
|
|
||||||
|
For each node in the object, perform a
|
||||||
|
[left-fold](http://en.wikipedia.org/wiki/Fold_(higher-order_function))
|
||||||
|
with the return value of `fn(acc, node)`.
|
||||||
|
|
||||||
|
If `acc` isn't specified, `acc` is set to the root object for the first step
|
||||||
|
and the root element is skipped.
|
||||||
|
|
||||||
|
.paths()
|
||||||
|
--------
|
||||||
|
|
||||||
|
Return an `Array` of every possible non-cyclic path in the object.
|
||||||
|
Paths are `Array`s of string keys.
|
||||||
|
|
||||||
|
.nodes()
|
||||||
|
--------
|
||||||
|
|
||||||
|
Return an `Array` of every node in the object.
|
||||||
|
|
||||||
|
.clone()
|
||||||
|
--------
|
||||||
|
|
||||||
|
Create a deep clone of the object.
|
||||||
|
|
||||||
|
install
|
||||||
|
=======
|
||||||
|
|
||||||
|
Using [npm](http://npmjs.org) do:
|
||||||
|
|
||||||
|
$ npm install traverse
|
||||||
|
|
||||||
|
test
|
||||||
|
====
|
||||||
|
|
||||||
|
Using [expresso](http://github.com/visionmedia/expresso) do:
|
||||||
|
|
||||||
|
$ expresso
|
||||||
|
|
||||||
|
100% wahoo, your stuff is not broken!
|
||||||
|
|
||||||
|
in the browser
|
||||||
|
==============
|
||||||
|
|
||||||
|
Use [browserify](https://github.com/substack/node-browserify) to run traverse in
|
||||||
|
the browser.
|
||||||
|
|
||||||
|
traverse has been tested and works with:
|
||||||
|
|
||||||
|
* Internet Explorer 5.5, 6.0, 7.0, 8.0, 9.0
|
||||||
|
* Firefox 3.5
|
||||||
|
* Chrome 6.0
|
||||||
|
* Opera 10.6
|
||||||
|
* Safari 5.0
|
|
@ -0,0 +1,16 @@
|
||||||
|
var traverse = require('traverse');
|
||||||
|
|
||||||
|
var id = 54;
|
||||||
|
var callbacks = {};
|
||||||
|
var obj = { moo : function () {}, foo : [2,3,4, function () {}] };
|
||||||
|
|
||||||
|
var scrubbed = traverse(obj).map(function (x) {
|
||||||
|
if (typeof x === 'function') {
|
||||||
|
callbacks[id] = { id : id, f : x, path : this.path };
|
||||||
|
this.update('[Function]');
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.dir(scrubbed);
|
||||||
|
console.dir(callbacks);
|
|
@ -0,0 +1,15 @@
|
||||||
|
var traverse = require('traverse');
|
||||||
|
|
||||||
|
var obj = {
|
||||||
|
a : [1,2,3],
|
||||||
|
b : 4,
|
||||||
|
c : [5,6],
|
||||||
|
d : { e : [7,8], f : 9 },
|
||||||
|
};
|
||||||
|
|
||||||
|
var leaves = traverse(obj).reduce(function (acc, x) {
|
||||||
|
if (this.isLeaf) acc.push(x);
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
console.dir(leaves);
|
8
node_modules/burrito/node_modules/traverse/examples/negative.js
generated
vendored
Executable file
8
node_modules/burrito/node_modules/traverse/examples/negative.js
generated
vendored
Executable file
|
@ -0,0 +1,8 @@
|
||||||
|
var traverse = require('traverse');
|
||||||
|
var obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ];
|
||||||
|
|
||||||
|
traverse(obj).forEach(function (x) {
|
||||||
|
if (x < 0) this.update(x + 128);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.dir(obj);
|
|
@ -0,0 +1,10 @@
|
||||||
|
// scrub out circular references
|
||||||
|
var traverse = require('traverse');
|
||||||
|
|
||||||
|
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
|
||||||
|
obj.c.push(obj);
|
||||||
|
|
||||||
|
var scrubbed = traverse(obj).map(function (x) {
|
||||||
|
if (this.circular) this.remove()
|
||||||
|
});
|
||||||
|
console.dir(scrubbed);
|
38
node_modules/burrito/node_modules/traverse/examples/stringify.js
generated
vendored
Executable file
38
node_modules/burrito/node_modules/traverse/examples/stringify.js
generated
vendored
Executable file
|
@ -0,0 +1,38 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
var traverse = require('traverse');
|
||||||
|
|
||||||
|
var obj = [ 'five', 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ];
|
||||||
|
|
||||||
|
var s = '';
|
||||||
|
traverse(obj).forEach(function to_s (node) {
|
||||||
|
if (Array.isArray(node)) {
|
||||||
|
this.before(function () { s += '[' });
|
||||||
|
this.post(function (child) {
|
||||||
|
if (!child.isLast) s += ',';
|
||||||
|
});
|
||||||
|
this.after(function () { s += ']' });
|
||||||
|
}
|
||||||
|
else if (typeof node == 'object') {
|
||||||
|
this.before(function () { s += '{' });
|
||||||
|
this.pre(function (x, key) {
|
||||||
|
to_s(key);
|
||||||
|
s += ':';
|
||||||
|
});
|
||||||
|
this.post(function (child) {
|
||||||
|
if (!child.isLast) s += ',';
|
||||||
|
});
|
||||||
|
this.after(function () { s += '}' });
|
||||||
|
}
|
||||||
|
else if (typeof node == 'string') {
|
||||||
|
s += '"' + node.toString().replace(/"/g, '\\"') + '"';
|
||||||
|
}
|
||||||
|
else if (typeof node == 'function') {
|
||||||
|
s += 'null';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s += node.toString();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('JSON.stringify: ' + JSON.stringify(obj));
|
||||||
|
console.log('this stringify: ' + s);
|
|
@ -0,0 +1,267 @@
|
||||||
|
module.exports = Traverse;
|
||||||
|
function Traverse (obj) {
|
||||||
|
if (!(this instanceof Traverse)) return new Traverse(obj);
|
||||||
|
this.value = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
Traverse.prototype.get = function (ps) {
|
||||||
|
var node = this.value;
|
||||||
|
for (var i = 0; i < ps.length; i ++) {
|
||||||
|
var key = ps[i];
|
||||||
|
if (!Object.hasOwnProperty.call(node, key)) {
|
||||||
|
node = undefined;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
node = node[key];
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
};
|
||||||
|
|
||||||
|
Traverse.prototype.set = function (ps, value) {
|
||||||
|
var node = this.value;
|
||||||
|
for (var i = 0; i < ps.length - 1; i ++) {
|
||||||
|
var key = ps[i];
|
||||||
|
if (!Object.hasOwnProperty.call(node, key)) node[key] = {};
|
||||||
|
node = node[key];
|
||||||
|
}
|
||||||
|
node[ps[i]] = value;
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
Traverse.prototype.map = function (cb) {
|
||||||
|
return walk(this.value, cb, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
Traverse.prototype.forEach = function (cb) {
|
||||||
|
this.value = walk(this.value, cb, false);
|
||||||
|
return this.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
Traverse.prototype.reduce = function (cb, init) {
|
||||||
|
var skip = arguments.length === 1;
|
||||||
|
var acc = skip ? this.value : init;
|
||||||
|
this.forEach(function (x) {
|
||||||
|
if (!this.isRoot || !skip) {
|
||||||
|
acc = cb.call(this, acc, x);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return acc;
|
||||||
|
};
|
||||||
|
|
||||||
|
Traverse.prototype.paths = function () {
|
||||||
|
var acc = [];
|
||||||
|
this.forEach(function (x) {
|
||||||
|
acc.push(this.path);
|
||||||
|
});
|
||||||
|
return acc;
|
||||||
|
};
|
||||||
|
|
||||||
|
Traverse.prototype.nodes = function () {
|
||||||
|
var acc = [];
|
||||||
|
this.forEach(function (x) {
|
||||||
|
acc.push(this.node);
|
||||||
|
});
|
||||||
|
return acc;
|
||||||
|
};
|
||||||
|
|
||||||
|
Traverse.prototype.clone = function () {
|
||||||
|
var parents = [], nodes = [];
|
||||||
|
|
||||||
|
return (function clone (src) {
|
||||||
|
for (var i = 0; i < parents.length; i++) {
|
||||||
|
if (parents[i] === src) {
|
||||||
|
return nodes[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof src === 'object' && src !== null) {
|
||||||
|
var dst = copy(src);
|
||||||
|
|
||||||
|
parents.push(src);
|
||||||
|
nodes.push(dst);
|
||||||
|
|
||||||
|
forEach(Object_keys(src), function (key) {
|
||||||
|
dst[key] = clone(src[key]);
|
||||||
|
});
|
||||||
|
|
||||||
|
parents.pop();
|
||||||
|
nodes.pop();
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return src;
|
||||||
|
}
|
||||||
|
})(this.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
function walk (root, cb, immutable) {
|
||||||
|
var path = [];
|
||||||
|
var parents = [];
|
||||||
|
var alive = true;
|
||||||
|
|
||||||
|
return (function walker (node_) {
|
||||||
|
var node = immutable ? copy(node_) : node_;
|
||||||
|
var modifiers = {};
|
||||||
|
|
||||||
|
var keepGoing = true;
|
||||||
|
|
||||||
|
var state = {
|
||||||
|
node : node,
|
||||||
|
node_ : node_,
|
||||||
|
path : [].concat(path),
|
||||||
|
parent : parents[parents.length - 1],
|
||||||
|
parents : parents,
|
||||||
|
key : path.slice(-1)[0],
|
||||||
|
isRoot : path.length === 0,
|
||||||
|
level : path.length,
|
||||||
|
circular : null,
|
||||||
|
update : function (x, stopHere) {
|
||||||
|
if (!state.isRoot) {
|
||||||
|
state.parent.node[state.key] = x;
|
||||||
|
}
|
||||||
|
state.node = x;
|
||||||
|
if (stopHere) keepGoing = false;
|
||||||
|
},
|
||||||
|
'delete' : function (stopHere) {
|
||||||
|
delete state.parent.node[state.key];
|
||||||
|
if (stopHere) keepGoing = false;
|
||||||
|
},
|
||||||
|
remove : function (stopHere) {
|
||||||
|
if (Array_isArray(state.parent.node)) {
|
||||||
|
state.parent.node.splice(state.key, 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
delete state.parent.node[state.key];
|
||||||
|
}
|
||||||
|
if (stopHere) keepGoing = false;
|
||||||
|
},
|
||||||
|
keys : null,
|
||||||
|
before : function (f) { modifiers.before = f },
|
||||||
|
after : function (f) { modifiers.after = f },
|
||||||
|
pre : function (f) { modifiers.pre = f },
|
||||||
|
post : function (f) { modifiers.post = f },
|
||||||
|
stop : function () { alive = false },
|
||||||
|
block : function () { keepGoing = false }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!alive) return state;
|
||||||
|
|
||||||
|
if (typeof node === 'object' && node !== null) {
|
||||||
|
state.keys = Object_keys(node);
|
||||||
|
|
||||||
|
state.isLeaf = state.keys.length == 0;
|
||||||
|
|
||||||
|
for (var i = 0; i < parents.length; i++) {
|
||||||
|
if (parents[i].node_ === node_) {
|
||||||
|
state.circular = parents[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
state.isLeaf = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.notLeaf = !state.isLeaf;
|
||||||
|
state.notRoot = !state.isRoot;
|
||||||
|
|
||||||
|
// use return values to update if defined
|
||||||
|
var ret = cb.call(state, state.node);
|
||||||
|
if (ret !== undefined && state.update) state.update(ret);
|
||||||
|
|
||||||
|
if (modifiers.before) modifiers.before.call(state, state.node);
|
||||||
|
|
||||||
|
if (!keepGoing) return state;
|
||||||
|
|
||||||
|
if (typeof state.node == 'object'
|
||||||
|
&& state.node !== null && !state.circular) {
|
||||||
|
parents.push(state);
|
||||||
|
|
||||||
|
forEach(state.keys, function (key, i) {
|
||||||
|
path.push(key);
|
||||||
|
|
||||||
|
if (modifiers.pre) modifiers.pre.call(state, state.node[key], key);
|
||||||
|
|
||||||
|
var child = walker(state.node[key]);
|
||||||
|
if (immutable && Object.hasOwnProperty.call(state.node, key)) {
|
||||||
|
state.node[key] = child.node;
|
||||||
|
}
|
||||||
|
|
||||||
|
child.isLast = i == state.keys.length - 1;
|
||||||
|
child.isFirst = i == 0;
|
||||||
|
|
||||||
|
if (modifiers.post) modifiers.post.call(state, child);
|
||||||
|
|
||||||
|
path.pop();
|
||||||
|
});
|
||||||
|
parents.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modifiers.after) modifiers.after.call(state, state.node);
|
||||||
|
|
||||||
|
return state;
|
||||||
|
})(root).node;
|
||||||
|
}
|
||||||
|
|
||||||
|
function copy (src) {
|
||||||
|
if (typeof src === 'object' && src !== null) {
|
||||||
|
var dst;
|
||||||
|
|
||||||
|
if (Array_isArray(src)) {
|
||||||
|
dst = [];
|
||||||
|
}
|
||||||
|
else if (src instanceof Date) {
|
||||||
|
dst = new Date(src);
|
||||||
|
}
|
||||||
|
else if (src instanceof Boolean) {
|
||||||
|
dst = new Boolean(src);
|
||||||
|
}
|
||||||
|
else if (src instanceof Number) {
|
||||||
|
dst = new Number(src);
|
||||||
|
}
|
||||||
|
else if (src instanceof String) {
|
||||||
|
dst = new String(src);
|
||||||
|
}
|
||||||
|
else if (Object.create && Object.getPrototypeOf) {
|
||||||
|
dst = Object.create(Object.getPrototypeOf(src));
|
||||||
|
}
|
||||||
|
else if (src.__proto__ || src.constructor.prototype) {
|
||||||
|
var proto = src.__proto__ || src.constructor.prototype || {};
|
||||||
|
var T = function () {};
|
||||||
|
T.prototype = proto;
|
||||||
|
dst = new T;
|
||||||
|
if (!dst.__proto__) dst.__proto__ = proto;
|
||||||
|
}
|
||||||
|
|
||||||
|
forEach(Object_keys(src), function (key) {
|
||||||
|
dst[key] = src[key];
|
||||||
|
});
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
else return src;
|
||||||
|
}
|
||||||
|
|
||||||
|
var Object_keys = Object.keys || function keys (obj) {
|
||||||
|
var res = [];
|
||||||
|
for (var key in obj) res.push(key)
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
var Array_isArray = Array.isArray || function isArray (xs) {
|
||||||
|
return Object.prototype.toString.call(xs) === '[object Array]';
|
||||||
|
};
|
||||||
|
|
||||||
|
var forEach = function (xs, fn) {
|
||||||
|
if (xs.forEach) return xs.forEach(fn)
|
||||||
|
else for (var i = 0; i < xs.length; i++) {
|
||||||
|
fn(xs[i], i, xs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
forEach(Object_keys(Traverse.prototype), function (key) {
|
||||||
|
Traverse[key] = function (obj) {
|
||||||
|
var args = [].slice.call(arguments, 1);
|
||||||
|
var t = Traverse(obj);
|
||||||
|
return t[key].apply(t, args);
|
||||||
|
};
|
||||||
|
});
|
|
@ -0,0 +1,10 @@
|
||||||
|
// scrub out circular references
|
||||||
|
var traverse = require('./index.js');
|
||||||
|
|
||||||
|
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
|
||||||
|
obj.c.push(obj);
|
||||||
|
|
||||||
|
var scrubbed = traverse(obj).map(function (x) {
|
||||||
|
if (this.circular) this.remove()
|
||||||
|
});
|
||||||
|
console.dir(scrubbed);
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"name" : "traverse",
|
||||||
|
"version" : "0.5.2",
|
||||||
|
"description" : "Traverse and transform objects by visiting every node on a recursive walk",
|
||||||
|
"author" : "James Halliday",
|
||||||
|
"license" : "MIT/X11",
|
||||||
|
"main" : "./index",
|
||||||
|
"repository" : {
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "http://github.com/substack/js-traverse.git"
|
||||||
|
},
|
||||||
|
"devDependencies" : {
|
||||||
|
"expresso" : "0.7.x"
|
||||||
|
},
|
||||||
|
"scripts" : {
|
||||||
|
"test" : "expresso"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
var assert = require('assert');
|
||||||
|
var Traverse = require('../');
|
||||||
|
var deepEqual = require('./lib/deep_equal');
|
||||||
|
var util = require('util');
|
||||||
|
|
||||||
|
exports.circular = function () {
|
||||||
|
var obj = { x : 3 };
|
||||||
|
obj.y = obj;
|
||||||
|
var foundY = false;
|
||||||
|
Traverse(obj).forEach(function (x) {
|
||||||
|
if (this.path.join('') == 'y') {
|
||||||
|
assert.equal(
|
||||||
|
util.inspect(this.circular.node),
|
||||||
|
util.inspect(obj)
|
||||||
|
);
|
||||||
|
foundY = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assert.ok(foundY);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.deepCirc = function () {
|
||||||
|
var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] };
|
||||||
|
obj.y[2] = obj;
|
||||||
|
|
||||||
|
var times = 0;
|
||||||
|
Traverse(obj).forEach(function (x) {
|
||||||
|
if (this.circular) {
|
||||||
|
assert.deepEqual(this.circular.path, []);
|
||||||
|
assert.deepEqual(this.path, [ 'y', 2 ]);
|
||||||
|
times ++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(times, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.doubleCirc = function () {
|
||||||
|
var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] };
|
||||||
|
obj.y[2] = obj;
|
||||||
|
obj.x.push(obj.y);
|
||||||
|
|
||||||
|
var circs = [];
|
||||||
|
Traverse(obj).forEach(function (x) {
|
||||||
|
if (this.circular) {
|
||||||
|
circs.push({ circ : this.circular, self : this, node : x });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(circs[0].self.path, [ 'x', 3, 2 ]);
|
||||||
|
assert.deepEqual(circs[0].circ.path, []);
|
||||||
|
|
||||||
|
assert.deepEqual(circs[1].self.path, [ 'y', 2 ]);
|
||||||
|
assert.deepEqual(circs[1].circ.path, []);
|
||||||
|
|
||||||
|
assert.deepEqual(circs.length, 2);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.circDubForEach = function () {
|
||||||
|
var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] };
|
||||||
|
obj.y[2] = obj;
|
||||||
|
obj.x.push(obj.y);
|
||||||
|
|
||||||
|
Traverse(obj).forEach(function (x) {
|
||||||
|
if (this.circular) this.update('...');
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(obj, { x : [ 1, 2, 3, [ 4, 5, '...' ] ], y : [ 4, 5, '...' ] });
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.circDubMap = function () {
|
||||||
|
var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] };
|
||||||
|
obj.y[2] = obj;
|
||||||
|
obj.x.push(obj.y);
|
||||||
|
|
||||||
|
var c = Traverse(obj).map(function (x) {
|
||||||
|
if (this.circular) {
|
||||||
|
this.update('...');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(c, { x : [ 1, 2, 3, [ 4, 5, '...' ] ], y : [ 4, 5, '...' ] });
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.circClone = function () {
|
||||||
|
var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] };
|
||||||
|
obj.y[2] = obj;
|
||||||
|
obj.x.push(obj.y);
|
||||||
|
|
||||||
|
var clone = Traverse.clone(obj);
|
||||||
|
assert.ok(obj !== clone);
|
||||||
|
|
||||||
|
assert.ok(clone.y[2] === clone);
|
||||||
|
assert.ok(clone.y[2] !== obj);
|
||||||
|
assert.ok(clone.x[3][2] === clone);
|
||||||
|
assert.ok(clone.x[3][2] !== obj);
|
||||||
|
assert.deepEqual(clone.x.slice(0,3), [1,2,3]);
|
||||||
|
assert.deepEqual(clone.y.slice(0,2), [4,5]);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.circMapScrub = function () {
|
||||||
|
var obj = { a : 1, b : 2 };
|
||||||
|
obj.c = obj;
|
||||||
|
|
||||||
|
var scrubbed = Traverse(obj).map(function (node) {
|
||||||
|
if (this.circular) this.remove();
|
||||||
|
});
|
||||||
|
assert.deepEqual(
|
||||||
|
Object.keys(scrubbed).sort(),
|
||||||
|
[ 'a', 'b' ]
|
||||||
|
);
|
||||||
|
assert.ok(deepEqual(scrubbed, { a : 1, b : 2 }));
|
||||||
|
|
||||||
|
assert.equal(obj.c, obj);
|
||||||
|
};
|
|
@ -0,0 +1,35 @@
|
||||||
|
var assert = require('assert');
|
||||||
|
var Traverse = require('../');
|
||||||
|
|
||||||
|
exports.dateEach = function () {
|
||||||
|
var obj = { x : new Date, y : 10, z : 5 };
|
||||||
|
|
||||||
|
var counts = {};
|
||||||
|
|
||||||
|
Traverse(obj).forEach(function (node) {
|
||||||
|
var t = (node instanceof Date && 'Date') || typeof node;
|
||||||
|
counts[t] = (counts[t] || 0) + 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(counts, {
|
||||||
|
object : 1,
|
||||||
|
Date : 1,
|
||||||
|
number : 2,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.dateMap = function () {
|
||||||
|
var obj = { x : new Date, y : 10, z : 5 };
|
||||||
|
|
||||||
|
var res = Traverse(obj).map(function (node) {
|
||||||
|
if (typeof node === 'number') this.update(node + 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.ok(obj.x !== res.x);
|
||||||
|
assert.deepEqual(res, {
|
||||||
|
x : obj.x,
|
||||||
|
y : 110,
|
||||||
|
z : 105,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,220 @@
|
||||||
|
var assert = require('assert');
|
||||||
|
var traverse = require('../');
|
||||||
|
var deepEqual = require('./lib/deep_equal');
|
||||||
|
|
||||||
|
exports.deepDates = function () {
|
||||||
|
assert.ok(
|
||||||
|
deepEqual(
|
||||||
|
{ d : new Date, x : [ 1, 2, 3 ] },
|
||||||
|
{ d : new Date, x : [ 1, 2, 3 ] }
|
||||||
|
),
|
||||||
|
'dates should be equal'
|
||||||
|
);
|
||||||
|
|
||||||
|
var d0 = new Date;
|
||||||
|
setTimeout(function () {
|
||||||
|
assert.ok(
|
||||||
|
!deepEqual(
|
||||||
|
{ d : d0, x : [ 1, 2, 3 ], },
|
||||||
|
{ d : new Date, x : [ 1, 2, 3 ] }
|
||||||
|
),
|
||||||
|
'microseconds should count in date equality'
|
||||||
|
);
|
||||||
|
}, 5);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.deepCircular = function () {
|
||||||
|
var a = [1];
|
||||||
|
a.push(a); // a = [ 1, *a ]
|
||||||
|
|
||||||
|
var b = [1];
|
||||||
|
b.push(a); // b = [ 1, [ 1, *a ] ]
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
!deepEqual(a, b),
|
||||||
|
'circular ref mount points count towards equality'
|
||||||
|
);
|
||||||
|
|
||||||
|
var c = [1];
|
||||||
|
c.push(c); // c = [ 1, *c ]
|
||||||
|
assert.ok(
|
||||||
|
deepEqual(a, c),
|
||||||
|
'circular refs are structurally the same here'
|
||||||
|
);
|
||||||
|
|
||||||
|
var d = [1];
|
||||||
|
d.push(a); // c = [ 1, [ 1, *d ] ]
|
||||||
|
assert.ok(
|
||||||
|
deepEqual(b, d),
|
||||||
|
'non-root circular ref structural comparison'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.deepInstances = function () {
|
||||||
|
assert.ok(
|
||||||
|
!deepEqual([ new Boolean(false) ], [ false ]),
|
||||||
|
'boolean instances are not real booleans'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
!deepEqual([ new String('x') ], [ 'x' ]),
|
||||||
|
'string instances are not real strings'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
!deepEqual([ new Number(4) ], [ 4 ]),
|
||||||
|
'number instances are not real numbers'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
deepEqual([ new RegExp('x') ], [ /x/ ]),
|
||||||
|
'regexp instances are real regexps'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
!deepEqual([ new RegExp(/./) ], [ /../ ]),
|
||||||
|
'these regexps aren\'t the same'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
!deepEqual(
|
||||||
|
[ function (x) { return x * 2 } ],
|
||||||
|
[ function (x) { return x * 2 } ]
|
||||||
|
),
|
||||||
|
'functions with the same .toString() aren\'t necessarily the same'
|
||||||
|
);
|
||||||
|
|
||||||
|
var f = function (x) { return x * 2 };
|
||||||
|
assert.ok(
|
||||||
|
deepEqual([ f ], [ f ]),
|
||||||
|
'these functions are actually equal'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.deepEqual = function () {
|
||||||
|
assert.ok(
|
||||||
|
!deepEqual([ 1, 2, 3 ], { 0 : 1, 1 : 2, 2 : 3 }),
|
||||||
|
'arrays are not objects'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.falsy = function () {
|
||||||
|
assert.ok(
|
||||||
|
!deepEqual([ undefined ], [ null ]),
|
||||||
|
'null is not undefined!'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
!deepEqual([ null ], [ undefined ]),
|
||||||
|
'undefined is not null!'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
!deepEqual(
|
||||||
|
{ a : 1, b : 2, c : [ 3, undefined, 5 ] },
|
||||||
|
{ a : 1, b : 2, c : [ 3, null, 5 ] }
|
||||||
|
),
|
||||||
|
'undefined is not null, however deeply!'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
!deepEqual(
|
||||||
|
{ a : 1, b : 2, c : [ 3, undefined, 5 ] },
|
||||||
|
{ a : 1, b : 2, c : [ 3, null, 5 ] }
|
||||||
|
),
|
||||||
|
'null is not undefined, however deeply!'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
!deepEqual(
|
||||||
|
{ a : 1, b : 2, c : [ 3, undefined, 5 ] },
|
||||||
|
{ a : 1, b : 2, c : [ 3, null, 5 ] }
|
||||||
|
),
|
||||||
|
'null is not undefined, however deeply!'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.deletedArrayEqual = function () {
|
||||||
|
var xs = [ 1, 2, 3, 4 ];
|
||||||
|
delete xs[2];
|
||||||
|
|
||||||
|
var ys = Object.create(Array.prototype);
|
||||||
|
ys[0] = 1;
|
||||||
|
ys[1] = 2;
|
||||||
|
ys[3] = 4;
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
deepEqual(xs, ys),
|
||||||
|
'arrays with deleted elements are only equal to'
|
||||||
|
+ ' arrays with similarly deleted elements'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
!deepEqual(xs, [ 1, 2, undefined, 4 ]),
|
||||||
|
'deleted array elements cannot be undefined'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
!deepEqual(xs, [ 1, 2, null, 4 ]),
|
||||||
|
'deleted array elements cannot be null'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.deletedObjectEqual = function () {
|
||||||
|
var obj = { a : 1, b : 2, c : 3 };
|
||||||
|
delete obj.c;
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
deepEqual(obj, { a : 1, b : 2 }),
|
||||||
|
'deleted object elements should not show up'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
!deepEqual(obj, { a : 1, b : 2, c : undefined }),
|
||||||
|
'deleted object elements are not undefined'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
!deepEqual(obj, { a : 1, b : 2, c : null }),
|
||||||
|
'deleted object elements are not null'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.emptyKeyEqual = function () {
|
||||||
|
assert.ok(!deepEqual(
|
||||||
|
{ a : 1 }, { a : 1, '' : 55 }
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.deepArguments = function () {
|
||||||
|
assert.ok(
|
||||||
|
!deepEqual(
|
||||||
|
[ 4, 5, 6 ],
|
||||||
|
(function () { return arguments })(4, 5, 6)
|
||||||
|
),
|
||||||
|
'arguments are not arrays'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
deepEqual(
|
||||||
|
(function () { return arguments })(4, 5, 6),
|
||||||
|
(function () { return arguments })(4, 5, 6)
|
||||||
|
),
|
||||||
|
'arguments should equal'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.deepUn = function () {
|
||||||
|
assert.ok(!deepEqual({ a : 1, b : 2 }, undefined));
|
||||||
|
assert.ok(!deepEqual({ a : 1, b : 2 }, {}));
|
||||||
|
assert.ok(!deepEqual(undefined, { a : 1, b : 2 }));
|
||||||
|
assert.ok(!deepEqual({}, { a : 1, b : 2 }));
|
||||||
|
assert.ok(deepEqual(undefined, undefined));
|
||||||
|
assert.ok(deepEqual(null, null));
|
||||||
|
assert.ok(!deepEqual(undefined, null));
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.deepLevels = function () {
|
||||||
|
var xs = [ 1, 2, [ 3, 4, [ 5, 6 ] ] ];
|
||||||
|
assert.ok(!deepEqual(xs, []));
|
||||||
|
};
|
|
@ -0,0 +1,17 @@
|
||||||
|
var assert = require('assert');
|
||||||
|
var Traverse = require('../');
|
||||||
|
var EventEmitter = require('events').EventEmitter;
|
||||||
|
|
||||||
|
exports['check instanceof on node elems'] = function () {
|
||||||
|
|
||||||
|
var counts = { emitter : 0 };
|
||||||
|
|
||||||
|
Traverse([ new EventEmitter, 3, 4, { ev : new EventEmitter }])
|
||||||
|
.forEach(function (node) {
|
||||||
|
if (node instanceof EventEmitter) counts.emitter ++;
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
|
assert.equal(counts.emitter, 2);
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
var assert = require('assert');
|
||||||
|
var Traverse = require('../');
|
||||||
|
|
||||||
|
exports['interface map'] = function () {
|
||||||
|
var obj = { a : [ 5,6,7 ], b : { c : [8] } };
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
Traverse.paths(obj)
|
||||||
|
.sort()
|
||||||
|
.map(function (path) { return path.join('/') })
|
||||||
|
.slice(1)
|
||||||
|
.join(' ')
|
||||||
|
,
|
||||||
|
'a a/0 a/1 a/2 b b/c b/c/0'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
Traverse.nodes(obj),
|
||||||
|
[
|
||||||
|
{ a: [ 5, 6, 7 ], b: { c: [ 8 ] } },
|
||||||
|
[ 5, 6, 7 ], 5, 6, 7,
|
||||||
|
{ c: [ 8 ] }, [ 8 ], 8
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
Traverse.map(obj, function (node) {
|
||||||
|
if (typeof node == 'number') {
|
||||||
|
return node + 1000;
|
||||||
|
}
|
||||||
|
else if (Array.isArray(node)) {
|
||||||
|
return node.join(' ');
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
{ a: '5 6 7', b: { c: '8' } }
|
||||||
|
);
|
||||||
|
|
||||||
|
var nodes = 0;
|
||||||
|
Traverse.forEach(obj, function (node) { nodes ++ });
|
||||||
|
assert.deepEqual(nodes, 8);
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
var assert = require('assert');
|
||||||
|
var Traverse = require('../');
|
||||||
|
|
||||||
|
exports['json test'] = function () {
|
||||||
|
var id = 54;
|
||||||
|
var callbacks = {};
|
||||||
|
var obj = { moo : function () {}, foo : [2,3,4, function () {}] };
|
||||||
|
|
||||||
|
var scrubbed = Traverse(obj).map(function (x) {
|
||||||
|
if (typeof x === 'function') {
|
||||||
|
callbacks[id] = { id : id, f : x, path : this.path };
|
||||||
|
this.update('[Function]');
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
scrubbed.moo, '[Function]',
|
||||||
|
'obj.moo replaced with "[Function]"'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
scrubbed.foo[3], '[Function]',
|
||||||
|
'obj.foo[3] replaced with "[Function]"'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.deepEqual(scrubbed, {
|
||||||
|
moo : '[Function]',
|
||||||
|
foo : [ 2, 3, 4, "[Function]" ]
|
||||||
|
}, 'Full JSON string matches');
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
typeof obj.moo, 'function',
|
||||||
|
'Original obj.moo still a function'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
typeof obj.foo[3], 'function',
|
||||||
|
'Original obj.foo[3] still a function'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.deepEqual(callbacks, {
|
||||||
|
54: { id: 54, f : obj.moo, path: [ 'moo' ] },
|
||||||
|
55: { id: 55, f : obj.foo[3], path: [ 'foo', '3' ] },
|
||||||
|
}, 'Check the generated callbacks list');
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
var assert = require('assert');
|
||||||
|
var Traverse = require('../');
|
||||||
|
|
||||||
|
exports['sort test'] = function () {
|
||||||
|
var acc = [];
|
||||||
|
Traverse({
|
||||||
|
a: 30,
|
||||||
|
b: 22,
|
||||||
|
id: 9
|
||||||
|
}).forEach(function (node) {
|
||||||
|
if ((! Array.isArray(node)) && typeof node === 'object') {
|
||||||
|
this.before(function(node) {
|
||||||
|
this.keys = Object.keys(node);
|
||||||
|
this.keys.sort(function(a, b) {
|
||||||
|
a = [a === "id" ? 0 : 1, a];
|
||||||
|
b = [b === "id" ? 0 : 1, b];
|
||||||
|
return a < b ? -1 : a > b ? 1 : 0;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.isLeaf) acc.push(node);
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
acc.join(' '),
|
||||||
|
'9 30 22',
|
||||||
|
'Traversal in a custom order'
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,21 @@
|
||||||
|
var assert = require('assert');
|
||||||
|
var Traverse = require('../');
|
||||||
|
|
||||||
|
exports['leaves test'] = function () {
|
||||||
|
var acc = [];
|
||||||
|
Traverse({
|
||||||
|
a : [1,2,3],
|
||||||
|
b : 4,
|
||||||
|
c : [5,6],
|
||||||
|
d : { e : [7,8], f : 9 }
|
||||||
|
}).forEach(function (x) {
|
||||||
|
if (this.isLeaf) acc.push(x);
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
acc.join(' '),
|
||||||
|
'1 2 3 4 5 6 7 8 9',
|
||||||
|
'Traversal in the right(?) order'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
var traverse = require('../../');
|
||||||
|
|
||||||
|
module.exports = function (a, b) {
|
||||||
|
if (arguments.length !== 2) {
|
||||||
|
throw new Error(
|
||||||
|
'deepEqual requires exactly two objects to compare against'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
var equal = true;
|
||||||
|
var node = b;
|
||||||
|
|
||||||
|
traverse(a).forEach(function (y) {
|
||||||
|
var notEqual = (function () {
|
||||||
|
equal = false;
|
||||||
|
//this.stop();
|
||||||
|
return undefined;
|
||||||
|
}).bind(this);
|
||||||
|
|
||||||
|
//if (node === undefined || node === null) return notEqual();
|
||||||
|
|
||||||
|
if (!this.isRoot) {
|
||||||
|
/*
|
||||||
|
if (!Object.hasOwnProperty.call(node, this.key)) {
|
||||||
|
return notEqual();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if (typeof node !== 'object') return notEqual();
|
||||||
|
node = node[this.key];
|
||||||
|
}
|
||||||
|
|
||||||
|
var x = node;
|
||||||
|
|
||||||
|
this.post(function () {
|
||||||
|
node = x;
|
||||||
|
});
|
||||||
|
|
||||||
|
var toS = function (o) {
|
||||||
|
return Object.prototype.toString.call(o);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.circular) {
|
||||||
|
if (traverse(b).get(this.circular.path) !== x) notEqual();
|
||||||
|
}
|
||||||
|
else if (typeof x !== typeof y) {
|
||||||
|
notEqual();
|
||||||
|
}
|
||||||
|
else if (x === null || y === null || x === undefined || y === undefined) {
|
||||||
|
if (x !== y) notEqual();
|
||||||
|
}
|
||||||
|
else if (x.__proto__ !== y.__proto__) {
|
||||||
|
notEqual();
|
||||||
|
}
|
||||||
|
else if (x === y) {
|
||||||
|
// nop
|
||||||
|
}
|
||||||
|
else if (typeof x === 'function') {
|
||||||
|
if (x instanceof RegExp) {
|
||||||
|
// both regexps on account of the __proto__ check
|
||||||
|
if (x.toString() != y.toString()) notEqual();
|
||||||
|
}
|
||||||
|
else if (x !== y) notEqual();
|
||||||
|
}
|
||||||
|
else if (typeof x === 'object') {
|
||||||
|
if (toS(y) === '[object Arguments]'
|
||||||
|
|| toS(x) === '[object Arguments]') {
|
||||||
|
if (toS(x) !== toS(y)) {
|
||||||
|
notEqual();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (x instanceof Date || y instanceof Date) {
|
||||||
|
if (!(x instanceof Date) || !(y instanceof Date)
|
||||||
|
|| x.getTime() !== y.getTime()) {
|
||||||
|
notEqual();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var kx = Object.keys(x);
|
||||||
|
var ky = Object.keys(y);
|
||||||
|
if (kx.length !== ky.length) return notEqual();
|
||||||
|
for (var i = 0; i < kx.length; i++) {
|
||||||
|
var k = kx[i];
|
||||||
|
if (!Object.hasOwnProperty.call(y, k)) {
|
||||||
|
notEqual();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return equal;
|
||||||
|
};
|
|
@ -0,0 +1,252 @@
|
||||||
|
var assert = require('assert');
|
||||||
|
var Traverse = require('../');
|
||||||
|
var deepEqual = require('./lib/deep_equal');
|
||||||
|
|
||||||
|
exports.mutate = function () {
|
||||||
|
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
|
||||||
|
var res = Traverse(obj).forEach(function (x) {
|
||||||
|
if (typeof x === 'number' && x % 2 === 0) {
|
||||||
|
this.update(x * 10);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assert.deepEqual(obj, res);
|
||||||
|
assert.deepEqual(obj, { a : 1, b : 20, c : [ 3, 40 ] });
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.mutateT = function () {
|
||||||
|
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
|
||||||
|
var res = Traverse.forEach(obj, function (x) {
|
||||||
|
if (typeof x === 'number' && x % 2 === 0) {
|
||||||
|
this.update(x * 10);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assert.deepEqual(obj, res);
|
||||||
|
assert.deepEqual(obj, { a : 1, b : 20, c : [ 3, 40 ] });
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.map = function () {
|
||||||
|
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
|
||||||
|
var res = Traverse(obj).map(function (x) {
|
||||||
|
if (typeof x === 'number' && x % 2 === 0) {
|
||||||
|
this.update(x * 10);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assert.deepEqual(obj, { a : 1, b : 2, c : [ 3, 4 ] });
|
||||||
|
assert.deepEqual(res, { a : 1, b : 20, c : [ 3, 40 ] });
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.mapT = function () {
|
||||||
|
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
|
||||||
|
var res = Traverse.map(obj, function (x) {
|
||||||
|
if (typeof x === 'number' && x % 2 === 0) {
|
||||||
|
this.update(x * 10);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assert.deepEqual(obj, { a : 1, b : 2, c : [ 3, 4 ] });
|
||||||
|
assert.deepEqual(res, { a : 1, b : 20, c : [ 3, 40 ] });
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.clone = function () {
|
||||||
|
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
|
||||||
|
var res = Traverse(obj).clone();
|
||||||
|
assert.deepEqual(obj, res);
|
||||||
|
assert.ok(obj !== res);
|
||||||
|
obj.a ++;
|
||||||
|
assert.deepEqual(res.a, 1);
|
||||||
|
obj.c.push(5);
|
||||||
|
assert.deepEqual(res.c, [ 3, 4 ]);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.cloneT = function () {
|
||||||
|
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
|
||||||
|
var res = Traverse.clone(obj);
|
||||||
|
assert.deepEqual(obj, res);
|
||||||
|
assert.ok(obj !== res);
|
||||||
|
obj.a ++;
|
||||||
|
assert.deepEqual(res.a, 1);
|
||||||
|
obj.c.push(5);
|
||||||
|
assert.deepEqual(res.c, [ 3, 4 ]);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.reduce = function () {
|
||||||
|
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
|
||||||
|
var res = Traverse(obj).reduce(function (acc, x) {
|
||||||
|
if (this.isLeaf) acc.push(x);
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
assert.deepEqual(obj, { a : 1, b : 2, c : [ 3, 4 ] });
|
||||||
|
assert.deepEqual(res, [ 1, 2, 3, 4 ]);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.reduceInit = function () {
|
||||||
|
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
|
||||||
|
var res = Traverse(obj).reduce(function (acc, x) {
|
||||||
|
if (this.isRoot) assert.fail('got root');
|
||||||
|
return acc;
|
||||||
|
});
|
||||||
|
assert.deepEqual(obj, { a : 1, b : 2, c : [ 3, 4 ] });
|
||||||
|
assert.deepEqual(res, obj);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.remove = function () {
|
||||||
|
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
|
||||||
|
Traverse(obj).forEach(function (x) {
|
||||||
|
if (this.isLeaf && x % 2 == 0) this.remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(obj, { a : 1, c : [ 3 ] });
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.removeNoStop = function() {
|
||||||
|
var obj = { a : 1, b : 2, c : { d: 3, e: 4 }, f: 5 };
|
||||||
|
|
||||||
|
var keys = [];
|
||||||
|
Traverse(obj).forEach(function (x) {
|
||||||
|
keys.push(this.key)
|
||||||
|
if (this.key == 'c') this.remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(keys, [undefined, 'a', 'b', 'c', 'd', 'e', 'f'])
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.removeStop = function() {
|
||||||
|
var obj = { a : 1, b : 2, c : { d: 3, e: 4 }, f: 5 };
|
||||||
|
|
||||||
|
var keys = [];
|
||||||
|
Traverse(obj).forEach(function (x) {
|
||||||
|
keys.push(this.key)
|
||||||
|
if (this.key == 'c') this.remove(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(keys, [undefined, 'a', 'b', 'c', 'f'])
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.removeMap = function () {
|
||||||
|
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
|
||||||
|
var res = Traverse(obj).map(function (x) {
|
||||||
|
if (this.isLeaf && x % 2 == 0) this.remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(obj, { a : 1, b : 2, c : [ 3, 4 ] });
|
||||||
|
assert.deepEqual(res, { a : 1, c : [ 3 ] });
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.delete = function () {
|
||||||
|
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
|
||||||
|
Traverse(obj).forEach(function (x) {
|
||||||
|
if (this.isLeaf && x % 2 == 0) this.delete();
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.ok(!deepEqual(
|
||||||
|
obj, { a : 1, c : [ 3, undefined ] }
|
||||||
|
));
|
||||||
|
|
||||||
|
assert.ok(deepEqual(
|
||||||
|
obj, { a : 1, c : [ 3 ] }
|
||||||
|
));
|
||||||
|
|
||||||
|
assert.ok(!deepEqual(
|
||||||
|
obj, { a : 1, c : [ 3, null ] }
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.deleteNoStop = function() {
|
||||||
|
var obj = { a : 1, b : 2, c : { d: 3, e: 4 } };
|
||||||
|
|
||||||
|
var keys = [];
|
||||||
|
Traverse(obj).forEach(function (x) {
|
||||||
|
keys.push(this.key)
|
||||||
|
if (this.key == 'c') this.delete();
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(keys, [undefined, 'a', 'b', 'c', 'd', 'e'])
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.deleteStop = function() {
|
||||||
|
var obj = { a : 1, b : 2, c : { d: 3, e: 4 } };
|
||||||
|
|
||||||
|
var keys = [];
|
||||||
|
Traverse(obj).forEach(function (x) {
|
||||||
|
keys.push(this.key)
|
||||||
|
if (this.key == 'c') this.delete(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(keys, [undefined, 'a', 'b', 'c'])
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.deleteRedux = function () {
|
||||||
|
var obj = { a : 1, b : 2, c : [ 3, 4, 5 ] };
|
||||||
|
Traverse(obj).forEach(function (x) {
|
||||||
|
if (this.isLeaf && x % 2 == 0) this.delete();
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.ok(!deepEqual(
|
||||||
|
obj, { a : 1, c : [ 3, undefined, 5 ] }
|
||||||
|
));
|
||||||
|
|
||||||
|
assert.ok(deepEqual(
|
||||||
|
obj, { a : 1, c : [ 3 ,, 5 ] }
|
||||||
|
));
|
||||||
|
|
||||||
|
assert.ok(!deepEqual(
|
||||||
|
obj, { a : 1, c : [ 3, null, 5 ] }
|
||||||
|
));
|
||||||
|
|
||||||
|
assert.ok(!deepEqual(
|
||||||
|
obj, { a : 1, c : [ 3, 5 ] }
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.deleteMap = function () {
|
||||||
|
var obj = { a : 1, b : 2, c : [ 3, 4 ] };
|
||||||
|
var res = Traverse(obj).map(function (x) {
|
||||||
|
if (this.isLeaf && x % 2 == 0) this.delete();
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.ok(deepEqual(
|
||||||
|
obj,
|
||||||
|
{ a : 1, b : 2, c : [ 3, 4 ] }
|
||||||
|
));
|
||||||
|
|
||||||
|
var xs = [ 3, 4 ];
|
||||||
|
delete xs[1];
|
||||||
|
|
||||||
|
assert.ok(deepEqual(
|
||||||
|
res, { a : 1, c : xs }
|
||||||
|
));
|
||||||
|
|
||||||
|
assert.ok(deepEqual(
|
||||||
|
res, { a : 1, c : [ 3, ] }
|
||||||
|
));
|
||||||
|
|
||||||
|
assert.ok(deepEqual(
|
||||||
|
res, { a : 1, c : [ 3 ] }
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.deleteMapRedux = function () {
|
||||||
|
var obj = { a : 1, b : 2, c : [ 3, 4, 5 ] };
|
||||||
|
var res = Traverse(obj).map(function (x) {
|
||||||
|
if (this.isLeaf && x % 2 == 0) this.delete();
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.ok(deepEqual(
|
||||||
|
obj,
|
||||||
|
{ a : 1, b : 2, c : [ 3, 4, 5 ] }
|
||||||
|
));
|
||||||
|
|
||||||
|
var xs = [ 3, 4, 5 ];
|
||||||
|
delete xs[1];
|
||||||
|
|
||||||
|
assert.ok(deepEqual(
|
||||||
|
res, { a : 1, c : xs }
|
||||||
|
));
|
||||||
|
|
||||||
|
assert.ok(!deepEqual(
|
||||||
|
res, { a : 1, c : [ 3, 5 ] }
|
||||||
|
));
|
||||||
|
|
||||||
|
assert.ok(deepEqual(
|
||||||
|
res, { a : 1, c : [ 3 ,, 5 ] }
|
||||||
|
));
|
||||||
|
};
|
|
@ -0,0 +1,20 @@
|
||||||
|
var Traverse = require('../');
|
||||||
|
var assert = require('assert');
|
||||||
|
|
||||||
|
exports['negative update test'] = function () {
|
||||||
|
var obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ];
|
||||||
|
var fixed = Traverse.map(obj, function (x) {
|
||||||
|
if (x < 0) this.update(x + 128);
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(fixed,
|
||||||
|
[ 5, 6, 125, [ 7, 8, 126, 1 ], { f: 10, g: 115 } ],
|
||||||
|
'Negative values += 128'
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.deepEqual(obj,
|
||||||
|
[ 5, 6, -3, [ 7, 8, -2, 1 ], { f: 10, g: -13 } ],
|
||||||
|
'Original references not modified'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
var assert = require('assert');
|
||||||
|
var Traverse = require('../');
|
||||||
|
|
||||||
|
exports['traverse an object with nested functions'] = function () {
|
||||||
|
var to = setTimeout(function () {
|
||||||
|
assert.fail('never ran');
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
function Cons (x) {
|
||||||
|
clearTimeout(to);
|
||||||
|
assert.equal(x, 10);
|
||||||
|
};
|
||||||
|
Traverse(new Cons(10));
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
var assert = require('assert');
|
||||||
|
var traverse = require('../');
|
||||||
|
|
||||||
|
exports.siblings = function () {
|
||||||
|
var obj = { a : 1, b : 2, c : [ 4, 5, 6 ] };
|
||||||
|
|
||||||
|
var res = traverse(obj).reduce(function (acc, x) {
|
||||||
|
var p = '/' + this.path.join('/');
|
||||||
|
if (this.parent) {
|
||||||
|
acc[p] = {
|
||||||
|
siblings : this.parent.keys,
|
||||||
|
key : this.key,
|
||||||
|
index : this.parent.keys.indexOf(this.key)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
acc[p] = {
|
||||||
|
siblings : [],
|
||||||
|
key : this.key,
|
||||||
|
index : -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
assert.deepEqual(res, {
|
||||||
|
'/' : { siblings : [], key : undefined, index : -1 },
|
||||||
|
'/a' : { siblings : [ 'a', 'b', 'c' ], key : 'a', index : 0 },
|
||||||
|
'/b' : { siblings : [ 'a', 'b', 'c' ], key : 'b', index : 1 },
|
||||||
|
'/c' : { siblings : [ 'a', 'b', 'c' ], key : 'c', index : 2 },
|
||||||
|
'/c/0' : { siblings : [ '0', '1', '2' ], key : '0', index : 0 },
|
||||||
|
'/c/1' : { siblings : [ '0', '1', '2' ], key : '1', index : 1 },
|
||||||
|
'/c/2' : { siblings : [ '0', '1', '2' ], key : '2', index : 2 }
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,41 @@
|
||||||
|
var assert = require('assert');
|
||||||
|
var traverse = require('../');
|
||||||
|
|
||||||
|
exports.stop = function () {
|
||||||
|
var visits = 0;
|
||||||
|
traverse('abcdefghij'.split('')).forEach(function (node) {
|
||||||
|
if (typeof node === 'string') {
|
||||||
|
visits ++;
|
||||||
|
if (node === 'e') this.stop()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(visits, 5);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.stopMap = function () {
|
||||||
|
var s = traverse('abcdefghij'.split('')).map(function (node) {
|
||||||
|
if (typeof node === 'string') {
|
||||||
|
if (node === 'e') this.stop()
|
||||||
|
return node.toUpperCase();
|
||||||
|
}
|
||||||
|
}).join('');
|
||||||
|
|
||||||
|
assert.equal(s, 'ABCDEfghij');
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.stopReduce = function () {
|
||||||
|
var obj = {
|
||||||
|
a : [ 4, 5 ],
|
||||||
|
b : [ 6, [ 7, 8, 9 ] ]
|
||||||
|
};
|
||||||
|
var xs = traverse(obj).reduce(function (acc, node) {
|
||||||
|
if (this.isLeaf) {
|
||||||
|
if (node === 7) this.stop();
|
||||||
|
else acc.push(node)
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
assert.deepEqual(xs, [ 4, 5, 6 ]);
|
||||||
|
};
|
|
@ -0,0 +1,36 @@
|
||||||
|
var assert = require('assert');
|
||||||
|
var Traverse = require('../');
|
||||||
|
|
||||||
|
exports.stringify = function () {
|
||||||
|
var obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ];
|
||||||
|
|
||||||
|
var s = '';
|
||||||
|
Traverse(obj).forEach(function (node) {
|
||||||
|
if (Array.isArray(node)) {
|
||||||
|
this.before(function () { s += '[' });
|
||||||
|
this.post(function (child) {
|
||||||
|
if (!child.isLast) s += ',';
|
||||||
|
});
|
||||||
|
this.after(function () { s += ']' });
|
||||||
|
}
|
||||||
|
else if (typeof node == 'object') {
|
||||||
|
this.before(function () { s += '{' });
|
||||||
|
this.pre(function (x, key) {
|
||||||
|
s += '"' + key + '"' + ':';
|
||||||
|
});
|
||||||
|
this.post(function (child) {
|
||||||
|
if (!child.isLast) s += ',';
|
||||||
|
});
|
||||||
|
this.after(function () { s += '}' });
|
||||||
|
}
|
||||||
|
else if (typeof node == 'function') {
|
||||||
|
s += 'null';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s += node.toString();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(s, JSON.stringify(obj));
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
var traverse = require('../');
|
||||||
|
var assert = require('assert');
|
||||||
|
|
||||||
|
exports.subexpr = function () {
|
||||||
|
var obj = [ 'a', 4, 'b', 5, 'c', 6 ];
|
||||||
|
var r = traverse(obj).map(function (x) {
|
||||||
|
if (typeof x === 'number') {
|
||||||
|
this.update([ x - 0.1, x, x + 0.1 ], true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(obj, [ 'a', 4, 'b', 5, 'c', 6 ]);
|
||||||
|
assert.deepEqual(r, [
|
||||||
|
'a', [ 3.9, 4, 4.1 ],
|
||||||
|
'b', [ 4.9, 5, 5.1 ],
|
||||||
|
'c', [ 5.9, 6, 6.1 ],
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.block = function () {
|
||||||
|
var obj = [ [ 1 ], [ 2 ], [ 3 ] ];
|
||||||
|
var r = traverse(obj).map(function (x) {
|
||||||
|
if (Array.isArray(x) && !this.isRoot) {
|
||||||
|
if (x[0] === 5) this.block()
|
||||||
|
else this.update([ [ x[0] + 1 ] ])
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(r, [
|
||||||
|
[ [ [ [ [ 5 ] ] ] ] ],
|
||||||
|
[ [ [ [ 5 ] ] ] ],
|
||||||
|
[ [ [ 5 ] ] ],
|
||||||
|
]);
|
||||||
|
};
|
|
@ -0,0 +1,55 @@
|
||||||
|
var assert = require('assert');
|
||||||
|
var traverse = require('../');
|
||||||
|
var deepEqual = require('./lib/deep_equal');
|
||||||
|
|
||||||
|
exports.super_deep = function () {
|
||||||
|
var util = require('util');
|
||||||
|
var a0 = make();
|
||||||
|
var a1 = make();
|
||||||
|
assert.ok(deepEqual(a0, a1));
|
||||||
|
|
||||||
|
a0.c.d.moo = true;
|
||||||
|
assert.ok(!deepEqual(a0, a1));
|
||||||
|
|
||||||
|
a1.c.d.moo = true;
|
||||||
|
assert.ok(deepEqual(a0, a1));
|
||||||
|
|
||||||
|
// TODO: this one
|
||||||
|
//a0.c.a = a1;
|
||||||
|
//assert.ok(!deepEqual(a0, a1));
|
||||||
|
};
|
||||||
|
|
||||||
|
function make () {
|
||||||
|
var a = { self : 'a' };
|
||||||
|
var b = { self : 'b' };
|
||||||
|
var c = { self : 'c' };
|
||||||
|
var d = { self : 'd' };
|
||||||
|
var e = { self : 'e' };
|
||||||
|
|
||||||
|
a.a = a;
|
||||||
|
a.b = b;
|
||||||
|
a.c = c;
|
||||||
|
|
||||||
|
b.a = a;
|
||||||
|
b.b = b;
|
||||||
|
b.c = c;
|
||||||
|
|
||||||
|
c.a = a;
|
||||||
|
c.b = b;
|
||||||
|
c.c = c;
|
||||||
|
c.d = d;
|
||||||
|
|
||||||
|
d.a = a;
|
||||||
|
d.b = b;
|
||||||
|
d.c = c;
|
||||||
|
d.d = d;
|
||||||
|
d.e = e;
|
||||||
|
|
||||||
|
e.a = a;
|
||||||
|
e.b = b;
|
||||||
|
e.c = c;
|
||||||
|
e.d = d;
|
||||||
|
e.e = e;
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
{
|
||||||
|
"name" : "burrito",
|
||||||
|
"description" : "Wrap up expressions with a trace function while walking the AST with rice and beans on the side",
|
||||||
|
"version" : "0.2.12",
|
||||||
|
"repository" : {
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "git://github.com/substack/node-burrito.git"
|
||||||
|
},
|
||||||
|
"main" : "./index.js",
|
||||||
|
"keywords" : [
|
||||||
|
"trace",
|
||||||
|
"ast",
|
||||||
|
"walk",
|
||||||
|
"syntax",
|
||||||
|
"source",
|
||||||
|
"tree",
|
||||||
|
"uglify"
|
||||||
|
],
|
||||||
|
"directories" : {
|
||||||
|
"lib" : ".",
|
||||||
|
"example" : "example",
|
||||||
|
"test" : "test"
|
||||||
|
},
|
||||||
|
"scripts" : {
|
||||||
|
"test" : "tap test/*.js"
|
||||||
|
},
|
||||||
|
"dependencies" : {
|
||||||
|
"traverse" : "~0.5.1",
|
||||||
|
"uglify-js" : "~1.1.1"
|
||||||
|
},
|
||||||
|
"devDependencies" : {
|
||||||
|
"tap" : "~0.2.5"
|
||||||
|
},
|
||||||
|
"engines" : {
|
||||||
|
"node" : ">=0.4.0"
|
||||||
|
},
|
||||||
|
"license" : "BSD",
|
||||||
|
"author" : {
|
||||||
|
"name" : "James Halliday",
|
||||||
|
"email" : "mail@substack.net",
|
||||||
|
"url" : "http://substack.net"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
var test = require('tap').test;
|
||||||
|
var burrito = require('../');
|
||||||
|
var vm = require('vm');
|
||||||
|
|
||||||
|
test('ast', function (t) {
|
||||||
|
t.plan(2);
|
||||||
|
|
||||||
|
var ast = burrito.parse('f(g(h(5)))', false, true);
|
||||||
|
var src = burrito(ast, function (node) {
|
||||||
|
if (node.name === 'call') {
|
||||||
|
node.wrap(function (s) {
|
||||||
|
return 'z(' + s + ')';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var times = 0;
|
||||||
|
t.equal(
|
||||||
|
vm.runInNewContext(src, {
|
||||||
|
f : function (x) { return x + 1 },
|
||||||
|
g : function (x) { return x + 2 },
|
||||||
|
h : function (x) { return x + 3 },
|
||||||
|
z : function (x) {
|
||||||
|
times ++;
|
||||||
|
return x * 10;
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
(((((5 + 3) * 10) + 2) * 10) + 1) * 10
|
||||||
|
);
|
||||||
|
t.equal(times, 3);
|
||||||
|
});
|
|
@ -0,0 +1,52 @@
|
||||||
|
var test = require('tap').test;
|
||||||
|
var burrito = require('../');
|
||||||
|
|
||||||
|
test('wrap error', function (t) {
|
||||||
|
t.plan(6);
|
||||||
|
|
||||||
|
try {
|
||||||
|
var src = burrito('f() && g()', function (node) {
|
||||||
|
if (node.name === 'binary') node.wrap('h(%a, %b')
|
||||||
|
});
|
||||||
|
t.fail('should have blown up');
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
t.ok(err.message.match(/unexpected/i));
|
||||||
|
t.ok(err instanceof SyntaxError);
|
||||||
|
t.ok(!err.stack.match(/uglify-js/));
|
||||||
|
t.equal(err.line, 0);
|
||||||
|
t.equal(err.col, 10);
|
||||||
|
t.equal(err.pos, 10);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('non string', function (t) {
|
||||||
|
t.plan(3);
|
||||||
|
|
||||||
|
t.throws(function () {
|
||||||
|
burrito.parse(new Buffer('[]'));
|
||||||
|
});
|
||||||
|
|
||||||
|
t.throws(function () {
|
||||||
|
burrito.parse(new String('[]'));
|
||||||
|
});
|
||||||
|
|
||||||
|
t.throws(function () {
|
||||||
|
burrito.parse();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('syntax error', function (t) {
|
||||||
|
t.plan(3);
|
||||||
|
try {
|
||||||
|
var src = burrito('f() && g())', function (node) {
|
||||||
|
if (node.name === 'binary') node.wrap('h(%a, %b)')
|
||||||
|
});
|
||||||
|
assert.fail('should have blown up');
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
t.ok(err.message.match(/unexpected/i));
|
||||||
|
t.ok(err instanceof SyntaxError);
|
||||||
|
t.ok(!err.stack.match(/uglify-js/));
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,9 @@
|
||||||
|
var burrito = require('../');
|
||||||
|
var test = require('tap').test;
|
||||||
|
var fs = require('fs');
|
||||||
|
var src = fs.readFileSync(__dirname + '/fail/src.js', 'utf8');
|
||||||
|
|
||||||
|
test('fail', function (t) {
|
||||||
|
burrito(src, function (node) {});
|
||||||
|
t.end();
|
||||||
|
});
|
|
@ -0,0 +1,60 @@
|
||||||
|
var path = require('path')
|
||||||
|
|
||||||
|
module.exports = function(fs, ready) {
|
||||||
|
var global_files = {}
|
||||||
|
|
||||||
|
var recurse = function(dir, okay) {
|
||||||
|
fs.readdir(dir, function(err, dir_files) {
|
||||||
|
var countdown = 0
|
||||||
|
, files = []
|
||||||
|
, dirs = []
|
||||||
|
, checked = 0
|
||||||
|
dir_files.forEach(function(file, idx, all) {
|
||||||
|
fs.stat(path.join(dir, file), function(err, stat) {
|
||||||
|
if(stat.isDirectory() && !/node_modules/g.test(dir)) {
|
||||||
|
dirs.push(file)
|
||||||
|
} else if(/\.js$/g.test(file)) {
|
||||||
|
files.push(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(++checked >= dir_files.length)
|
||||||
|
recurse_dirs()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
function recurse_dirs() {
|
||||||
|
var total = 0
|
||||||
|
dirs.forEach(function(this_dir) {
|
||||||
|
recurse(path.join(dir, this_dir), function(err, data) {
|
||||||
|
if(++total >= dirs.length)
|
||||||
|
recurse_files()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
if(!dirs.length)
|
||||||
|
recurse_files()
|
||||||
|
}
|
||||||
|
|
||||||
|
function recurse_files() {
|
||||||
|
var total = 0
|
||||||
|
files.forEach(function(file) {
|
||||||
|
fs.readFile(path.join(dir, file), 'utf8', function(err, src) {
|
||||||
|
global_files[path.join(dir, file)] = src
|
||||||
|
++total >= files.length &&
|
||||||
|
okay(null, global_files)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
if(!files.length)
|
||||||
|
okay(null, global_files)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!dir_files.length)
|
||||||
|
okay(null, global_files)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
recurse('.', ready)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
var test = require('tap').test;
|
||||||
|
var burrito = require('../');
|
||||||
|
|
||||||
|
test('call label', function (t) {
|
||||||
|
t.plan(1);
|
||||||
|
|
||||||
|
burrito('foo(10)', function (node) {
|
||||||
|
if (node.name === 'call') {
|
||||||
|
t.equal(node.label(), 'foo');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('var label', function (t) {
|
||||||
|
t.plan(1);
|
||||||
|
|
||||||
|
burrito('var x = 2', function (node) {
|
||||||
|
if (node.name === 'var') {
|
||||||
|
t.same(node.label(), [ 'x' ]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('vars label', function (t) {
|
||||||
|
t.plan(1);
|
||||||
|
|
||||||
|
burrito('var x = 2, y = 3', function (node) {
|
||||||
|
if (node.name === 'var') {
|
||||||
|
t.same(node.label(), [ 'x', 'y' ]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('defun label', function (t) {
|
||||||
|
t.plan(1);
|
||||||
|
|
||||||
|
burrito('function moo () {}', function (node) {
|
||||||
|
if (node.name === 'defun') {
|
||||||
|
t.same(node.label(), 'moo');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('function label', function (t) {
|
||||||
|
t.plan(1);
|
||||||
|
|
||||||
|
burrito('(function zzz () {})()', function (node) {
|
||||||
|
if (node.name === 'function') {
|
||||||
|
t.same(node.label(), 'zzz');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('anon function label', function (t) {
|
||||||
|
t.plan(1);
|
||||||
|
|
||||||
|
burrito('(function () {})()', function (node) {
|
||||||
|
if (node.name === 'function') {
|
||||||
|
t.equal(node.label(), null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('dot call label', function (t) {
|
||||||
|
t.plan(1);
|
||||||
|
|
||||||
|
burrito('process.nextTick(fn)', function (node) {
|
||||||
|
if (node.name === 'call') {
|
||||||
|
t.equal(node.label(), 'nextTick');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('triple dot label', function (t) {
|
||||||
|
t.plan(1);
|
||||||
|
|
||||||
|
burrito('a.b.c(fn)', function (node) {
|
||||||
|
if (node.name === 'call') {
|
||||||
|
t.equal(node.label(), 'c');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('expr label', function (t) {
|
||||||
|
t.plan(1);
|
||||||
|
|
||||||
|
burrito('a.b[x+1](fn)', function (node) {
|
||||||
|
if (node.name === 'call') {
|
||||||
|
t.ok(node.label() === null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,34 @@
|
||||||
|
var test = require('tap').test;
|
||||||
|
var burrito = require('../');
|
||||||
|
|
||||||
|
test('microwave', function (t) {
|
||||||
|
t.plan(4);
|
||||||
|
|
||||||
|
var context = {
|
||||||
|
f : function (x) { return x + 1 },
|
||||||
|
g : function (x) { return x + 2 },
|
||||||
|
h : function (x) { return x + 3 },
|
||||||
|
z : function (x) {
|
||||||
|
t.ok(true); // 3 times
|
||||||
|
return x * 10;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var res = burrito.microwave('f(g(h(5)))', context, function (node) {
|
||||||
|
if (node.name === 'call') {
|
||||||
|
node.wrap(function (s) {
|
||||||
|
return 'z(' + s + ')';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
t.equal(res, (((((5 + 3) * 10) + 2) * 10) + 1) * 10);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('empty context', function (t) {
|
||||||
|
var res = burrito.microwave('Math.sin(2)', function (node) {
|
||||||
|
if (node.name === 'num') node.wrap('Math.PI / %s');
|
||||||
|
});
|
||||||
|
t.equal(res, 1);
|
||||||
|
t.end();
|
||||||
|
});
|
|
@ -0,0 +1,27 @@
|
||||||
|
var test = require('tap').test;
|
||||||
|
var burrito = require('../');
|
||||||
|
|
||||||
|
test('check parent', function (t) {
|
||||||
|
t.plan(5);
|
||||||
|
var src = 'Math.tan(0) + Math.sin(0)';
|
||||||
|
|
||||||
|
var res = burrito.microwave(src, function (node) {
|
||||||
|
if (node.name === 'binary') {
|
||||||
|
node.wrap('%a - %b');
|
||||||
|
}
|
||||||
|
else if (node.name === 'num') {
|
||||||
|
t.equal(node.parent().value[0][0], 'dot');
|
||||||
|
|
||||||
|
var fn = node.parent().value[0][2];
|
||||||
|
if (fn === 'sin') {
|
||||||
|
node.wrap('Math.PI / 2');
|
||||||
|
}
|
||||||
|
else if (fn === 'tan') {
|
||||||
|
node.wrap('Math.PI / 4');
|
||||||
|
}
|
||||||
|
else t.fail('Unknown fn');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
t.equal(res, Math.tan(Math.PI / 4) - Math.sin(Math.PI / 2)); // ~ 0
|
||||||
|
});
|
|
@ -0,0 +1,159 @@
|
||||||
|
var test = require('tap').test;
|
||||||
|
var burrito = require('../');
|
||||||
|
var vm = require('vm');
|
||||||
|
|
||||||
|
test('preserve ternary parentheses', function (t) {
|
||||||
|
var originalSource = '"anything" + (x ? y : z) + "anything"';
|
||||||
|
var burritoSource = burrito(originalSource, function (node) {
|
||||||
|
// do nothing. we just want to check that ternary parens are persisted
|
||||||
|
});
|
||||||
|
|
||||||
|
var ctxt = {
|
||||||
|
x : false,
|
||||||
|
y : 'y_'+~~(Math.random()*10),
|
||||||
|
z : 'z_'+~~(Math.random()*10)
|
||||||
|
};
|
||||||
|
|
||||||
|
var expectedOutput = vm.runInNewContext(originalSource, ctxt);
|
||||||
|
var burritoOutput = vm.runInNewContext(burritoSource, ctxt);
|
||||||
|
|
||||||
|
t.equal(burritoOutput, expectedOutput);
|
||||||
|
|
||||||
|
ctxt.x = true;
|
||||||
|
|
||||||
|
expectedOutput = vm.runInNewContext(originalSource, ctxt);
|
||||||
|
burritoOutput = vm.runInNewContext(burritoSource, ctxt);
|
||||||
|
|
||||||
|
t.equal(burritoOutput, expectedOutput);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('wrap calls', function (t) {
|
||||||
|
t.plan(20);
|
||||||
|
var src = burrito('f() && g(h())\nfoo()', function (node) {
|
||||||
|
if (node.name === 'call') node.wrap('qqq(%s)');
|
||||||
|
if (node.name === 'binary') node.wrap('bbb(%s)');
|
||||||
|
t.ok(node.state);
|
||||||
|
t.equal(this, node.state);
|
||||||
|
});
|
||||||
|
|
||||||
|
var times = { bbb : 0, qqq : 0 };
|
||||||
|
|
||||||
|
var res = [];
|
||||||
|
vm.runInNewContext(src, {
|
||||||
|
bbb : function (x) {
|
||||||
|
times.bbb ++;
|
||||||
|
res.push(x);
|
||||||
|
return x;
|
||||||
|
},
|
||||||
|
qqq : function (x) {
|
||||||
|
times.qqq ++;
|
||||||
|
res.push(x);
|
||||||
|
return x;
|
||||||
|
},
|
||||||
|
f : function () { return true },
|
||||||
|
g : function (h) {
|
||||||
|
t.equal(h, 7);
|
||||||
|
return h !== 7
|
||||||
|
},
|
||||||
|
h : function () { return 7 },
|
||||||
|
foo : function () { return 'foo!' },
|
||||||
|
});
|
||||||
|
|
||||||
|
t.same(res, [
|
||||||
|
true, // f()
|
||||||
|
7, // h()
|
||||||
|
false, // g(h())
|
||||||
|
false, // f() && g(h())
|
||||||
|
'foo!', // foo()
|
||||||
|
]);
|
||||||
|
t.equal(times.bbb, 1);
|
||||||
|
t.equal(times.qqq, 4);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('wrap fn', function (t) {
|
||||||
|
var src = burrito('f(g(h(5)))', function (node) {
|
||||||
|
if (node.name === 'call') {
|
||||||
|
node.wrap(function (s) {
|
||||||
|
return 'z(' + s + ')';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var times = 0;
|
||||||
|
t.equal(
|
||||||
|
vm.runInNewContext(src, {
|
||||||
|
f : function (x) { return x + 1 },
|
||||||
|
g : function (x) { return x + 2 },
|
||||||
|
h : function (x) { return x + 3 },
|
||||||
|
z : function (x) {
|
||||||
|
times ++;
|
||||||
|
return x * 10;
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
(((((5 + 3) * 10) + 2) * 10) + 1) * 10
|
||||||
|
);
|
||||||
|
t.equal(times, 3);
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('binary string', function (t) {
|
||||||
|
var src = 'z(x + y)';
|
||||||
|
var context = {
|
||||||
|
x : 3,
|
||||||
|
y : 4,
|
||||||
|
z : function (n) { return n * 10 },
|
||||||
|
};
|
||||||
|
|
||||||
|
var res = burrito.microwave(src, context, function (node) {
|
||||||
|
if (node.name === 'binary') {
|
||||||
|
node.wrap('%a*2 - %b*2');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
t.equal(res, 10 * (3*2 - 4*2));
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('binary fn', function (t) {
|
||||||
|
var src = 'z(x + y)';
|
||||||
|
var context = {
|
||||||
|
x : 3,
|
||||||
|
y : 4,
|
||||||
|
z : function (n) { return n * 10 },
|
||||||
|
};
|
||||||
|
|
||||||
|
var res = burrito.microwave(src, context, function (node) {
|
||||||
|
if (node.name === 'binary') {
|
||||||
|
node.wrap(function (expr, a, b) {
|
||||||
|
return '(' + a + ')*2 - ' + '(' + b + ')*2';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
t.equal(res, 10 * (3*2 - 4*2));
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('intersperse', function (t) {
|
||||||
|
var src = '(' + (function () {
|
||||||
|
f();
|
||||||
|
g();
|
||||||
|
}).toString() + ')()';
|
||||||
|
|
||||||
|
var times = { f : 0, g : 0, zzz : 0 };
|
||||||
|
|
||||||
|
var context = {
|
||||||
|
f : function () { times.f ++ },
|
||||||
|
g : function () { times.g ++ },
|
||||||
|
zzz : function () { times.zzz ++ },
|
||||||
|
};
|
||||||
|
|
||||||
|
burrito.microwave(src, context, function (node) {
|
||||||
|
if (node.name === 'stat') node.wrap('{ zzz(); %s }');
|
||||||
|
});
|
||||||
|
|
||||||
|
t.same(times, { f : 1, g : 1, zzz : 3 });
|
||||||
|
t.end();
|
||||||
|
});
|
|
@ -0,0 +1,216 @@
|
||||||
|
charm
|
||||||
|
=====
|
||||||
|
|
||||||
|
Use
|
||||||
|
[ansi terminal characters](http://www.termsys.demon.co.uk/vtansi.htm)
|
||||||
|
to write colors and cursor positions.
|
||||||
|
|
||||||
|
![me lucky charms](http://substack.net/images/charms.png)
|
||||||
|
|
||||||
|
example
|
||||||
|
=======
|
||||||
|
|
||||||
|
lucky
|
||||||
|
-----
|
||||||
|
|
||||||
|
````javascript
|
||||||
|
var charm = require('charm')();
|
||||||
|
charm.pipe(process.stdout);
|
||||||
|
charm.reset();
|
||||||
|
|
||||||
|
var colors = [ 'red', 'cyan', 'yellow', 'green', 'blue' ];
|
||||||
|
var text = 'Always after me lucky charms.';
|
||||||
|
|
||||||
|
var offset = 0;
|
||||||
|
var iv = setInterval(function () {
|
||||||
|
var y = 0, dy = 1;
|
||||||
|
for (var i = 0; i < 40; i++) {
|
||||||
|
var color = colors[(i + offset) % colors.length];
|
||||||
|
var c = text[(i + offset) % text.length];
|
||||||
|
charm
|
||||||
|
.move(1, dy)
|
||||||
|
.foreground(color)
|
||||||
|
.write(c)
|
||||||
|
;
|
||||||
|
y += dy;
|
||||||
|
if (y <= 0 || y >= 5) dy *= -1;
|
||||||
|
}
|
||||||
|
charm.position(0, 1);
|
||||||
|
offset ++;
|
||||||
|
}, 150);
|
||||||
|
````
|
||||||
|
|
||||||
|
events
|
||||||
|
======
|
||||||
|
|
||||||
|
Charm objects pass along the data events from their input stream except for
|
||||||
|
events generated from querying the terminal device.
|
||||||
|
|
||||||
|
Because charm puts stdin into raw mode, charm emits two special events: "^C" and
|
||||||
|
"^D" when the user types those combos. It's super convenient with these events
|
||||||
|
to do:
|
||||||
|
|
||||||
|
````javascript
|
||||||
|
charm.on('^C', process.exit)
|
||||||
|
````
|
||||||
|
|
||||||
|
The above is set on all `charm` streams. If you want to add your own handling for these
|
||||||
|
special events simply:
|
||||||
|
|
||||||
|
````javascript
|
||||||
|
charm.removeAllListeners('^C')
|
||||||
|
charm.on('^C', function () {
|
||||||
|
// Don't exit. Do some mad science instead.
|
||||||
|
})
|
||||||
|
````
|
||||||
|
|
||||||
|
methods
|
||||||
|
=======
|
||||||
|
|
||||||
|
var charm = require('charm')(param or stream, ...)
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
Create a new readable/writable `charm` stream.
|
||||||
|
|
||||||
|
You can pass in readable or writable streams as parameters and they will be
|
||||||
|
piped to or from accordingly. You can also pass `process` in which case
|
||||||
|
`process.stdin` and `process.stdout` will be used.
|
||||||
|
|
||||||
|
You can `pipe()` to and from the `charm` object you get back.
|
||||||
|
|
||||||
|
charm.reset()
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Reset the entire screen, like the /usr/bin/reset command.
|
||||||
|
|
||||||
|
charm.destroy(), charm.end()
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Emit an `"end"` event downstream.
|
||||||
|
|
||||||
|
charm.write(msg)
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Pass along `msg` to the output stream.
|
||||||
|
|
||||||
|
charm.position(x, y)
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Set the cursor position to the absolute coordinates `x, y`.
|
||||||
|
|
||||||
|
charm.position(cb)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Query the absolute cursor position from the input stream through the output
|
||||||
|
stream (the shell does this automatically) and get the response back as
|
||||||
|
`cb(x, y)`.
|
||||||
|
|
||||||
|
charm.move(x, y)
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Move the cursor position by the relative coordinates `x, y`.
|
||||||
|
|
||||||
|
charm.up(y)
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Move the cursor up by `y` rows.
|
||||||
|
|
||||||
|
charm.down(y)
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Move the cursor down by `y` rows.
|
||||||
|
|
||||||
|
charm.left(x)
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Move the cursor left by `x` columns.
|
||||||
|
|
||||||
|
charm.right(x)
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Move the cursor right by `x` columns.
|
||||||
|
|
||||||
|
charm.push(withAttributes=false)
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
Push the cursor state and optionally the attribute state.
|
||||||
|
|
||||||
|
charm.pop(withAttributes=false)
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
Pop the cursor state and optionally the attribute state.
|
||||||
|
|
||||||
|
charm.erase(s)
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Erase a region defined by the string `s`.
|
||||||
|
|
||||||
|
`s` can be:
|
||||||
|
|
||||||
|
* end - erase from the cursor to the end of the line
|
||||||
|
* start - erase from the cursor to the start of the line
|
||||||
|
* line - erase the current line
|
||||||
|
* down - erase everything below the current line
|
||||||
|
* up - erase everything above the current line
|
||||||
|
* screen - erase the entire screen
|
||||||
|
|
||||||
|
charm.display(attr)
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Set the display mode with the string `attr`.
|
||||||
|
|
||||||
|
`attr` can be:
|
||||||
|
|
||||||
|
* reset
|
||||||
|
* bright
|
||||||
|
* dim
|
||||||
|
* underscore
|
||||||
|
* blink
|
||||||
|
* reverse
|
||||||
|
* hidden
|
||||||
|
|
||||||
|
charm.foreground(color)
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Set the foreground color with the string `color`, which can be:
|
||||||
|
|
||||||
|
* red
|
||||||
|
* yellow
|
||||||
|
* green
|
||||||
|
* blue
|
||||||
|
* cyan
|
||||||
|
* magenta
|
||||||
|
* black
|
||||||
|
* white
|
||||||
|
|
||||||
|
or `color` can be an integer from 0 to 255, inclusive.
|
||||||
|
|
||||||
|
charm.background(color)
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Set the background color with the string `color`, which can be:
|
||||||
|
|
||||||
|
* red
|
||||||
|
* yellow
|
||||||
|
* green
|
||||||
|
* blue
|
||||||
|
* cyan
|
||||||
|
* magenta
|
||||||
|
* black
|
||||||
|
* white
|
||||||
|
|
||||||
|
or `color` can be an integer from 0 to 255, inclusive.
|
||||||
|
|
||||||
|
charm.cursor(visible)
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Set the cursor visibility with a boolean `visible`.
|
||||||
|
|
||||||
|
install
|
||||||
|
=======
|
||||||
|
|
||||||
|
With [npm](http://npmjs.org) do:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install charm
|
||||||
|
```
|
|
@ -0,0 +1,17 @@
|
||||||
|
var charm = require('../')(process);
|
||||||
|
|
||||||
|
function exit () {
|
||||||
|
charm.display('reset');
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
charm.on('^C', exit);
|
||||||
|
|
||||||
|
var ix = 0;
|
||||||
|
var iv = setInterval(function () {
|
||||||
|
charm.background(ix++).write(' ');
|
||||||
|
if (ix === 256) {
|
||||||
|
clearInterval(iv);
|
||||||
|
charm.write('\n');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
}, 10);
|
|
@ -0,0 +1,11 @@
|
||||||
|
var charm = require('../')();
|
||||||
|
charm.pipe(process.stdout);
|
||||||
|
|
||||||
|
charm
|
||||||
|
.column(16)
|
||||||
|
.write('beep')
|
||||||
|
.down()
|
||||||
|
.column(32)
|
||||||
|
.write('boop\n')
|
||||||
|
.end()
|
||||||
|
;
|
|
@ -0,0 +1,22 @@
|
||||||
|
var charm = require('../')(process);
|
||||||
|
|
||||||
|
charm.position(5, 10);
|
||||||
|
|
||||||
|
charm.position(function (x, y) {
|
||||||
|
console.dir([ x, y ]);
|
||||||
|
|
||||||
|
charm.move(7,2);
|
||||||
|
charm.push();
|
||||||
|
process.stdout.write('lul');
|
||||||
|
|
||||||
|
charm.left(3).up(1).foreground('magenta');
|
||||||
|
process.stdout.write('v');
|
||||||
|
charm.left(1).up(1).display('reset');
|
||||||
|
process.stdout.write('|');
|
||||||
|
|
||||||
|
charm.down(3);
|
||||||
|
charm.pop().background('blue');
|
||||||
|
process.stdout.write('popped\npow');
|
||||||
|
charm.display('reset').erase('line');
|
||||||
|
charm.destroy();
|
||||||
|
});
|
|
@ -0,0 +1,36 @@
|
||||||
|
var http = require('http');
|
||||||
|
var charmer = require('../');
|
||||||
|
|
||||||
|
http.createServer(function (req, res) {
|
||||||
|
res.setHeader('content-type', 'text/ansi');
|
||||||
|
|
||||||
|
var charm = charmer();
|
||||||
|
charm.pipe(res);
|
||||||
|
charm.reset();
|
||||||
|
|
||||||
|
var radius = 10;
|
||||||
|
var theta = 0;
|
||||||
|
var points = [];
|
||||||
|
|
||||||
|
var iv = setInterval(function () {
|
||||||
|
var x = 2 + (radius + Math.cos(theta) * radius) * 2;
|
||||||
|
var y = 2 + radius + Math.sin(theta) * radius;
|
||||||
|
|
||||||
|
points.unshift([ x, y ]);
|
||||||
|
var colors = [ 'red', 'yellow', 'green', 'cyan', 'blue', 'magenta' ];
|
||||||
|
|
||||||
|
points.forEach(function (p, i) {
|
||||||
|
charm.position(p[0], p[1]);
|
||||||
|
var c = colors[Math.floor(i / 12)];
|
||||||
|
charm.background(c).write(' ')
|
||||||
|
});
|
||||||
|
points = points.slice(0, 12 * colors.length - 1);
|
||||||
|
|
||||||
|
theta += Math.PI / 40;
|
||||||
|
}, 50);
|
||||||
|
|
||||||
|
req.connection.on('end', function () {
|
||||||
|
clearInterval(iv);
|
||||||
|
charm.end();
|
||||||
|
});
|
||||||
|
}).listen(8081);
|
|
@ -0,0 +1,24 @@
|
||||||
|
var charm = require('../')();
|
||||||
|
charm.pipe(process.stdout);
|
||||||
|
charm.reset();
|
||||||
|
|
||||||
|
var colors = [ 'red', 'cyan', 'yellow', 'green', 'blue' ];
|
||||||
|
var text = 'Always after me lucky charms.';
|
||||||
|
|
||||||
|
var offset = 0;
|
||||||
|
var iv = setInterval(function () {
|
||||||
|
var y = 0, dy = 1;
|
||||||
|
for (var i = 0; i < 40; i++) {
|
||||||
|
var color = colors[(i + offset) % colors.length];
|
||||||
|
var c = text[(i + offset) % text.length];
|
||||||
|
charm
|
||||||
|
.move(1, dy)
|
||||||
|
.foreground(color)
|
||||||
|
.write(c)
|
||||||
|
;
|
||||||
|
y += dy;
|
||||||
|
if (y <= 0 || y >= 5) dy *= -1;
|
||||||
|
}
|
||||||
|
charm.position(0, 1);
|
||||||
|
offset ++;
|
||||||
|
}, 150);
|
|
@ -0,0 +1,7 @@
|
||||||
|
var charm = require('charm')(process);
|
||||||
|
|
||||||
|
charm.on('^C', process.exit);
|
||||||
|
|
||||||
|
charm.position(function (x, y) {
|
||||||
|
console.log('(%d, %d)', x, y);
|
||||||
|
});
|
|
@ -0,0 +1,18 @@
|
||||||
|
var charm = require('../')();
|
||||||
|
charm.pipe(process.stdout);
|
||||||
|
|
||||||
|
charm.write('Progress: 0 %');
|
||||||
|
var i = 0;
|
||||||
|
|
||||||
|
var iv = setInterval(function () {
|
||||||
|
charm.left(i.toString().length + 2);
|
||||||
|
i ++;
|
||||||
|
charm.write(i + ' %');
|
||||||
|
if (i === 100) {
|
||||||
|
charm.end('\nDone!\n');
|
||||||
|
clearInterval(iv);
|
||||||
|
}
|
||||||
|
}, 25);
|
||||||
|
|
||||||
|
charm.on('^C',process.exit);
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
var c = require('../')();
|
||||||
|
c.pipe(process.stdout);
|
||||||
|
c.on('^C', process.exit);
|
||||||
|
|
||||||
|
var queue = (function () {
|
||||||
|
var tasks = [];
|
||||||
|
var pending = false;
|
||||||
|
|
||||||
|
return {
|
||||||
|
abort : function () {
|
||||||
|
tasks = [];
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
push : function (t) {
|
||||||
|
tasks.push(t);
|
||||||
|
if (!pending) next();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function next () {
|
||||||
|
pending = true;
|
||||||
|
process.nextTick(function () {
|
||||||
|
if (tasks.length === 0) return;
|
||||||
|
var t = tasks.shift();
|
||||||
|
t();
|
||||||
|
pending = false;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
process.stdout.on('resize', draw);
|
||||||
|
draw();
|
||||||
|
setInterval(function () {}, 1e8);
|
||||||
|
|
||||||
|
function draw () {
|
||||||
|
var cols = process.stdout.columns;
|
||||||
|
var rows = process.stdout.rows;
|
||||||
|
queue.abort();
|
||||||
|
|
||||||
|
queue.push(function () {
|
||||||
|
c.reset();
|
||||||
|
c.background('blue');
|
||||||
|
c.position(1, 1);
|
||||||
|
c.write(Array(cols + 1).join(' '));
|
||||||
|
});
|
||||||
|
|
||||||
|
for (var y = 1; y < rows; y++) {
|
||||||
|
queue.push(function () {
|
||||||
|
c.position(1, y);
|
||||||
|
c.write(' ');
|
||||||
|
c.position(cols, y);
|
||||||
|
c.write(' ');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
queue.push(function () {
|
||||||
|
c.position(1, rows);
|
||||||
|
c.write(Array(cols + 1).join(' '));
|
||||||
|
c.display('reset');
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
var charm = require('../')(process);
|
||||||
|
charm.reset();
|
||||||
|
|
||||||
|
var radius = 10;
|
||||||
|
var theta = 0;
|
||||||
|
var points = [];
|
||||||
|
|
||||||
|
var iv = setInterval(function () {
|
||||||
|
var x = 2 + (radius + Math.cos(theta) * radius) * 2;
|
||||||
|
var y = 2 + radius + Math.sin(theta) * radius;
|
||||||
|
|
||||||
|
points.unshift([ x, y ]);
|
||||||
|
var colors = [ 'red', 'yellow', 'green', 'cyan', 'blue', 'magenta' ];
|
||||||
|
|
||||||
|
points.forEach(function (p, i) {
|
||||||
|
charm.position(p[0], p[1]);
|
||||||
|
var c = colors[Math.floor(i / 12)];
|
||||||
|
charm.background(c).write(' ')
|
||||||
|
});
|
||||||
|
points = points.slice(0, 12 * colors.length - 1);
|
||||||
|
|
||||||
|
theta += Math.PI / 40;
|
||||||
|
}, 50);
|
|
@ -0,0 +1,305 @@
|
||||||
|
var tty = require('tty');
|
||||||
|
var encode = require('./lib/encode');
|
||||||
|
var Stream = require('stream').Stream;
|
||||||
|
|
||||||
|
var exports = module.exports = function () {
|
||||||
|
var input = null;
|
||||||
|
function setInput (s) {
|
||||||
|
if (input) throw new Error('multiple inputs specified')
|
||||||
|
else input = s
|
||||||
|
}
|
||||||
|
|
||||||
|
var output = null;
|
||||||
|
function setOutput (s) {
|
||||||
|
if (output) throw new Error('multiple outputs specified')
|
||||||
|
else output = s
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < arguments.length; i++) {
|
||||||
|
var arg = arguments[i];
|
||||||
|
if (!arg) continue;
|
||||||
|
if (arg.readable) setInput(arg)
|
||||||
|
else if (arg.stdin || arg.input) setInput(arg.stdin || arg.input)
|
||||||
|
|
||||||
|
if (arg.writable) setOutput(arg)
|
||||||
|
else if (arg.stdout || arg.output) setOutput(arg.stdout || arg.output)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input && typeof input.fd === 'number' && tty.isatty(input.fd)) {
|
||||||
|
if (process.stdin.setRawMode) {
|
||||||
|
process.stdin.setRawMode(true);
|
||||||
|
}
|
||||||
|
else tty.setRawMode(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
var charm = new Charm;
|
||||||
|
if (input) {
|
||||||
|
input.pipe(charm);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output) {
|
||||||
|
charm.pipe(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
charm.once('^C', process.exit);
|
||||||
|
charm.once('end', function () {
|
||||||
|
if (input) {
|
||||||
|
if (typeof input.fd === 'number' && tty.isatty(input.fd)) {
|
||||||
|
if (process.stdin.setRawMode) {
|
||||||
|
process.stdin.setRawMode(false);
|
||||||
|
}
|
||||||
|
else tty.setRawMode(false);
|
||||||
|
}
|
||||||
|
input.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return charm;
|
||||||
|
};
|
||||||
|
|
||||||
|
var Charm = exports.Charm = function Charm () {
|
||||||
|
this.writable = true;
|
||||||
|
this.readable = true;
|
||||||
|
this.pending = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
Charm.prototype = new Stream;
|
||||||
|
|
||||||
|
Charm.prototype.write = function (buf) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if (self.pending.length) {
|
||||||
|
var codes = extractCodes(buf);
|
||||||
|
var matched = false;
|
||||||
|
|
||||||
|
for (var i = 0; i < codes.length; i++) {
|
||||||
|
for (var j = 0; j < self.pending.length; j++) {
|
||||||
|
var cb = self.pending[j];
|
||||||
|
if (cb(codes[i])) {
|
||||||
|
matched = true;
|
||||||
|
self.pending.splice(j, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matched) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf.length === 1) {
|
||||||
|
if (buf[0] === 3) self.emit('^C');
|
||||||
|
if (buf[0] === 4) self.emit('^D');
|
||||||
|
}
|
||||||
|
|
||||||
|
self.emit('data', buf);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Charm.prototype.destroy = function () {
|
||||||
|
this.end();
|
||||||
|
};
|
||||||
|
|
||||||
|
Charm.prototype.end = function (buf) {
|
||||||
|
if (buf) this.write(buf);
|
||||||
|
this.emit('end');
|
||||||
|
};
|
||||||
|
|
||||||
|
Charm.prototype.reset = function (cb) {
|
||||||
|
this.write(encode('c'));
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Charm.prototype.position = function (x, y) {
|
||||||
|
// get/set absolute coordinates
|
||||||
|
if (typeof x === 'function') {
|
||||||
|
var cb = x;
|
||||||
|
this.pending.push(function (buf) {
|
||||||
|
if (buf[0] === 27 && buf[1] === encode.ord('[')
|
||||||
|
&& buf[buf.length-1] === encode.ord('R')) {
|
||||||
|
var pos = buf.toString()
|
||||||
|
.slice(2,-1)
|
||||||
|
.split(';')
|
||||||
|
.map(Number)
|
||||||
|
;
|
||||||
|
cb(pos[1], pos[0]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.write(encode('[6n'));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.write(encode(
|
||||||
|
'[' + Math.floor(y) + ';' + Math.floor(x) + 'f'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Charm.prototype.move = function (x, y) {
|
||||||
|
// set relative coordinates
|
||||||
|
var bufs = [];
|
||||||
|
|
||||||
|
if (y < 0) this.up(-y)
|
||||||
|
else if (y > 0) this.down(y)
|
||||||
|
|
||||||
|
if (x > 0) this.right(x)
|
||||||
|
else if (x < 0) this.left(-x)
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Charm.prototype.up = function (y) {
|
||||||
|
if (y === undefined) y = 1;
|
||||||
|
this.write(encode('[' + Math.floor(y) + 'A'));
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Charm.prototype.down = function (y) {
|
||||||
|
if (y === undefined) y = 1;
|
||||||
|
this.write(encode('[' + Math.floor(y) + 'B'));
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Charm.prototype.right = function (x) {
|
||||||
|
if (x === undefined) x = 1;
|
||||||
|
this.write(encode('[' + Math.floor(x) + 'C'));
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Charm.prototype.left = function (x) {
|
||||||
|
if (x === undefined) x = 1;
|
||||||
|
this.write(encode('[' + Math.floor(x) + 'D'));
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Charm.prototype.column = function (x) {
|
||||||
|
this.write(encode('[' + Math.floor(x) + 'G'));
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Charm.prototype.push = function (withAttributes) {
|
||||||
|
this.write(encode(withAttributes ? '7' : '[s'));
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Charm.prototype.pop = function (withAttributes) {
|
||||||
|
this.write(encode(withAttributes ? '8' : '[u'));
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Charm.prototype.erase = function (s) {
|
||||||
|
if (s === 'end' || s === '$') {
|
||||||
|
this.write(encode('[K'));
|
||||||
|
}
|
||||||
|
else if (s === 'start' || s === '^') {
|
||||||
|
this.write(encode('[1K'));
|
||||||
|
}
|
||||||
|
else if (s === 'line') {
|
||||||
|
this.write(encode('[2K'));
|
||||||
|
}
|
||||||
|
else if (s === 'down') {
|
||||||
|
this.write(encode('[J'));
|
||||||
|
}
|
||||||
|
else if (s === 'up') {
|
||||||
|
this.write(encode('[1J'));
|
||||||
|
}
|
||||||
|
else if (s === 'screen') {
|
||||||
|
this.write(encode('[1J'));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.emit('error', new Error('Unknown erase type: ' + s));
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Charm.prototype.display = function (attr) {
|
||||||
|
var c = {
|
||||||
|
reset : 0,
|
||||||
|
bright : 1,
|
||||||
|
dim : 2,
|
||||||
|
underscore : 4,
|
||||||
|
blink : 5,
|
||||||
|
reverse : 7,
|
||||||
|
hidden : 8
|
||||||
|
}[attr];
|
||||||
|
if (c === undefined) {
|
||||||
|
this.emit('error', new Error('Unknown attribute: ' + attr));
|
||||||
|
}
|
||||||
|
this.write(encode('[' + c + 'm'));
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Charm.prototype.foreground = function (color) {
|
||||||
|
if (typeof color === 'number') {
|
||||||
|
if (color < 0 || color >= 256) {
|
||||||
|
this.emit('error', new Error('Color out of range: ' + color));
|
||||||
|
}
|
||||||
|
this.write(encode('[38;5;' + color + 'm'));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var c = {
|
||||||
|
black : 30,
|
||||||
|
red : 31,
|
||||||
|
green : 32,
|
||||||
|
yellow : 33,
|
||||||
|
blue : 34,
|
||||||
|
magenta : 35,
|
||||||
|
cyan : 36,
|
||||||
|
white : 37
|
||||||
|
}[color.toLowerCase()];
|
||||||
|
|
||||||
|
if (!c) this.emit('error', new Error('Unknown color: ' + color));
|
||||||
|
this.write(encode('[' + c + 'm'));
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Charm.prototype.background = function (color) {
|
||||||
|
if (typeof color === 'number') {
|
||||||
|
if (color < 0 || color >= 256) {
|
||||||
|
this.emit('error', new Error('Color out of range: ' + color));
|
||||||
|
}
|
||||||
|
this.write(encode('[48;5;' + color + 'm'));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var c = {
|
||||||
|
black : 40,
|
||||||
|
red : 41,
|
||||||
|
green : 42,
|
||||||
|
yellow : 43,
|
||||||
|
blue : 44,
|
||||||
|
magenta : 45,
|
||||||
|
cyan : 46,
|
||||||
|
white : 47
|
||||||
|
}[color.toLowerCase()];
|
||||||
|
|
||||||
|
if (!c) this.emit('error', new Error('Unknown color: ' + color));
|
||||||
|
this.write(encode('[' + c + 'm'));
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Charm.prototype.cursor = function (visible) {
|
||||||
|
this.write(encode(visible ? '[?25h' : '[?25l'));
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
var extractCodes = exports.extractCodes = function (buf) {
|
||||||
|
var codes = [];
|
||||||
|
var start = -1;
|
||||||
|
|
||||||
|
for (var i = 0; i < buf.length; i++) {
|
||||||
|
if (buf[i] === 27) {
|
||||||
|
if (start >= 0) codes.push(buf.slice(start, i));
|
||||||
|
start = i;
|
||||||
|
}
|
||||||
|
else if (start >= 0 && i === buf.length - 1) {
|
||||||
|
codes.push(buf.slice(start));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return codes;
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
var encode = module.exports = function (xs) {
|
||||||
|
function bytes (s) {
|
||||||
|
if (typeof s === 'string') {
|
||||||
|
return s.split('').map(ord);
|
||||||
|
}
|
||||||
|
else if (Array.isArray(s)) {
|
||||||
|
return s.reduce(function (acc, c) {
|
||||||
|
return acc.concat(bytes(c));
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Buffer([ 0x1b ].concat(bytes(xs)));
|
||||||
|
};
|
||||||
|
|
||||||
|
var ord = encode.ord = function ord (c) {
|
||||||
|
return c.charCodeAt(0)
|
||||||
|
};
|
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"name" : "charm",
|
||||||
|
"version" : "0.1.2",
|
||||||
|
"description" : "ansi control sequences for terminal cursor hopping and colors",
|
||||||
|
"main" : "index.js",
|
||||||
|
"directories" : {
|
||||||
|
"lib" : ".",
|
||||||
|
"example" : "example",
|
||||||
|
"test" : "test"
|
||||||
|
},
|
||||||
|
"repository" : {
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "http://github.com/substack/node-charm.git"
|
||||||
|
},
|
||||||
|
"keywords" : [
|
||||||
|
"terminal",
|
||||||
|
"ansi",
|
||||||
|
"cursor",
|
||||||
|
"color",
|
||||||
|
"console",
|
||||||
|
"control",
|
||||||
|
"escape",
|
||||||
|
"sequence"
|
||||||
|
],
|
||||||
|
"author" : {
|
||||||
|
"name" : "James Halliday",
|
||||||
|
"email" : "mail@substack.net",
|
||||||
|
"url" : "http://substack.net"
|
||||||
|
},
|
||||||
|
"license" : "MIT/X11",
|
||||||
|
"engine" : { "node" : ">=0.4" }
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
deep-equal
|
||||||
|
==========
|
||||||
|
|
||||||
|
Node's `assert.deepEqual() algorithm` as a standalone module.
|
||||||
|
|
||||||
|
example
|
||||||
|
=======
|
||||||
|
|
||||||
|
``` js
|
||||||
|
var equal = require('deep-equal');
|
||||||
|
console.dir([
|
||||||
|
equal(
|
||||||
|
{ a : [ 2, 3 ], b : [ 4 ] },
|
||||||
|
{ a : [ 2, 3 ], b : [ 4 ] }
|
||||||
|
),
|
||||||
|
equal(
|
||||||
|
{ x : 5, y : [6] },
|
||||||
|
{ x : 5, y : 6 }
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
```
|
||||||
|
|
||||||
|
methods
|
||||||
|
=======
|
||||||
|
|
||||||
|
var deepEqual = require('deep-equal')
|
||||||
|
|
||||||
|
deepEqual(a, b)
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Compare objects `a` and `b`, returning whether they are equal according to a
|
||||||
|
recursive equality algorithm.
|
||||||
|
|
||||||
|
install
|
||||||
|
=======
|
||||||
|
|
||||||
|
With [npm](http://npmjs.org) do:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install deep-equal
|
||||||
|
```
|
||||||
|
|
||||||
|
test
|
||||||
|
====
|
||||||
|
|
||||||
|
With [npm](http://npmjs.org) do:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm test
|
||||||
|
```
|
||||||
|
|
||||||
|
license
|
||||||
|
=======
|
||||||
|
|
||||||
|
MIT. Derived largely from node's assert module.
|
|
@ -0,0 +1,11 @@
|
||||||
|
var equal = require('../');
|
||||||
|
console.dir([
|
||||||
|
equal(
|
||||||
|
{ a : [ 2, 3 ], b : [ 4 ] },
|
||||||
|
{ a : [ 2, 3 ], b : [ 4 ] }
|
||||||
|
),
|
||||||
|
equal(
|
||||||
|
{ x : 5, y : [6] },
|
||||||
|
{ x : 5, y : 6 }
|
||||||
|
)
|
||||||
|
]);
|
|
@ -0,0 +1,84 @@
|
||||||
|
var pSlice = Array.prototype.slice;
|
||||||
|
var Object_keys = typeof Object.keys === 'function'
|
||||||
|
? Object.keys
|
||||||
|
: function (obj) {
|
||||||
|
var keys = [];
|
||||||
|
for (var key in obj) keys.push(key);
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
var deepEqual = module.exports = function (actual, expected) {
|
||||||
|
// 7.1. All identical values are equivalent, as determined by ===.
|
||||||
|
if (actual === expected) {
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (actual instanceof Date && expected instanceof Date) {
|
||||||
|
return actual.getTime() === expected.getTime();
|
||||||
|
|
||||||
|
// 7.3. Other pairs that do not both pass typeof value == 'object',
|
||||||
|
// equivalence is determined by ==.
|
||||||
|
} else if (typeof actual != 'object' && typeof expected != 'object') {
|
||||||
|
return actual == expected;
|
||||||
|
|
||||||
|
// 7.4. For all other Object pairs, including Array objects, equivalence is
|
||||||
|
// determined by having the same number of owned properties (as verified
|
||||||
|
// with Object.prototype.hasOwnProperty.call), the same set of keys
|
||||||
|
// (although not necessarily the same order), equivalent values for every
|
||||||
|
// corresponding key, and an identical 'prototype' property. Note: this
|
||||||
|
// accounts for both named and indexed properties on Arrays.
|
||||||
|
} else {
|
||||||
|
return objEquiv(actual, expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isUndefinedOrNull(value) {
|
||||||
|
return value === null || value === undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isArguments(object) {
|
||||||
|
return Object.prototype.toString.call(object) == '[object Arguments]';
|
||||||
|
}
|
||||||
|
|
||||||
|
function objEquiv(a, b) {
|
||||||
|
if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
|
||||||
|
return false;
|
||||||
|
// an identical 'prototype' property.
|
||||||
|
if (a.prototype !== b.prototype) return false;
|
||||||
|
//~~~I've managed to break Object.keys through screwy arguments passing.
|
||||||
|
// Converting to array solves the problem.
|
||||||
|
if (isArguments(a)) {
|
||||||
|
if (!isArguments(b)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
a = pSlice.call(a);
|
||||||
|
b = pSlice.call(b);
|
||||||
|
return deepEqual(a, b);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var ka = Object_keys(a),
|
||||||
|
kb = Object_keys(b),
|
||||||
|
key, i;
|
||||||
|
} catch (e) {//happens when one is a string literal and the other isn't
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// having the same number of owned properties (keys incorporates
|
||||||
|
// hasOwnProperty)
|
||||||
|
if (ka.length != kb.length)
|
||||||
|
return false;
|
||||||
|
//the same set of keys (although not necessarily the same order),
|
||||||
|
ka.sort();
|
||||||
|
kb.sort();
|
||||||
|
//~~~cheap key test
|
||||||
|
for (i = ka.length - 1; i >= 0; i--) {
|
||||||
|
if (ka[i] != kb[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//equivalent values for every corresponding key, and
|
||||||
|
//~~~possibly expensive deep test
|
||||||
|
for (i = ka.length - 1; i >= 0; i--) {
|
||||||
|
key = ka[i];
|
||||||
|
if (!deepEqual(a[key], b[key])) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"name" : "deep-equal",
|
||||||
|
"version" : "0.0.0",
|
||||||
|
"description" : "node's assert.deepEqual algorithm",
|
||||||
|
"main" : "index.js",
|
||||||
|
"directories" : {
|
||||||
|
"lib" : ".",
|
||||||
|
"example" : "example",
|
||||||
|
"test" : "test"
|
||||||
|
},
|
||||||
|
"scripts" : {
|
||||||
|
"test" : "tap test/*.js"
|
||||||
|
},
|
||||||
|
"devDependencies" : {
|
||||||
|
"tap" : "0.0.x"
|
||||||
|
},
|
||||||
|
"repository" : {
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "http://github.com/substack/node-deep-equal.git"
|
||||||
|
},
|
||||||
|
"keywords" : [
|
||||||
|
"equality",
|
||||||
|
"equal",
|
||||||
|
"compare"
|
||||||
|
],
|
||||||
|
"author" : {
|
||||||
|
"name" : "James Halliday",
|
||||||
|
"email" : "mail@substack.net",
|
||||||
|
"url" : "http://substack.net"
|
||||||
|
},
|
||||||
|
"license" : "MIT/X11",
|
||||||
|
"engine" : { "node" : ">=0.4" }
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
var test = require('tap').test;
|
||||||
|
var equal = require('../');
|
||||||
|
|
||||||
|
test('equal', function (t) {
|
||||||
|
t.ok(equal(
|
||||||
|
{ a : [ 2, 3 ], b : [ 4 ] },
|
||||||
|
{ a : [ 2, 3 ], b : [ 4 ] }
|
||||||
|
));
|
||||||
|
t.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('not equal', function (t) {
|
||||||
|
t.notOk(equal(
|
||||||
|
{ x : 5, y : [6] },
|
||||||
|
{ x : 5, y : 6 }
|
||||||
|
));
|
||||||
|
t.end();
|
||||||
|
});
|
|
@ -0,0 +1,5 @@
|
||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- 0.6
|
||||||
|
- 0.8
|
||||||
|
- 0.10
|
|
@ -0,0 +1,22 @@
|
||||||
|
Copyright (c) 2012, 2013 Thorsten Lorenz <thlorenz@gmx.de>
|
||||||
|
Copyright (c) 2012 James Halliday <mail@substack.net>
|
||||||
|
Copyright (c) 2009 Thomas Robinson <280north.com>
|
||||||
|
|
||||||
|
This software is released under the MIT license:
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,70 @@
|
||||||
|
deep-is
|
||||||
|
==========
|
||||||
|
|
||||||
|
Node's `assert.deepEqual() algorithm` as a standalone module. Exactly like
|
||||||
|
[deep-equal](https://github.com/substack/node-deep-equal) except for the fact that `deepEqual(NaN, NaN) === true`.
|
||||||
|
|
||||||
|
This module is around [5 times faster](https://gist.github.com/2790507)
|
||||||
|
than wrapping `assert.deepEqual()` in a `try/catch`.
|
||||||
|
|
||||||
|
[![browser support](http://ci.testling.com/thlorenz/deep-is.png)](http://ci.testling.com/thlorenz/deep-is)
|
||||||
|
|
||||||
|
[![build status](https://secure.travis-ci.org/thlorenz/deep-is.png)](http://travis-ci.org/thlorenz/deep-is)
|
||||||
|
|
||||||
|
example
|
||||||
|
=======
|
||||||
|
|
||||||
|
``` js
|
||||||
|
var equal = require('deep-is');
|
||||||
|
console.dir([
|
||||||
|
equal(
|
||||||
|
{ a : [ 2, 3 ], b : [ 4 ] },
|
||||||
|
{ a : [ 2, 3 ], b : [ 4 ] }
|
||||||
|
),
|
||||||
|
equal(
|
||||||
|
{ x : 5, y : [6] },
|
||||||
|
{ x : 5, y : 6 }
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
```
|
||||||
|
|
||||||
|
methods
|
||||||
|
=======
|
||||||
|
|
||||||
|
var deepIs = require('deep-is')
|
||||||
|
|
||||||
|
deepIs(a, b)
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Compare objects `a` and `b`, returning whether they are equal according to a
|
||||||
|
recursive equality algorithm.
|
||||||
|
|
||||||
|
install
|
||||||
|
=======
|
||||||
|
|
||||||
|
With [npm](http://npmjs.org) do:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install deep-is
|
||||||
|
```
|
||||||
|
|
||||||
|
test
|
||||||
|
====
|
||||||
|
|
||||||
|
With [npm](http://npmjs.org) do:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm test
|
||||||
|
```
|
||||||
|
|
||||||
|
license
|
||||||
|
=======
|
||||||
|
|
||||||
|
Copyright (c) 2012, 2013 Thorsten Lorenz <thlorenz@gmx.de>
|
||||||
|
Copyright (c) 2012 James Halliday <mail@substack.net>
|
||||||
|
|
||||||
|
Derived largely from node's assert module, which has the copyright statement:
|
||||||
|
|
||||||
|
Copyright (c) 2009 Thomas Robinson <280north.com>
|
||||||
|
|
||||||
|
Released under the MIT license, see LICENSE for details.
|
|
@ -0,0 +1,11 @@
|
||||||
|
var equal = require('../');
|
||||||
|
console.dir([
|
||||||
|
equal(
|
||||||
|
{ a : [ 2, 3 ], b : [ 4 ] },
|
||||||
|
{ a : [ 2, 3 ], b : [ 4 ] }
|
||||||
|
),
|
||||||
|
equal(
|
||||||
|
{ x : 5, y : [6] },
|
||||||
|
{ x : 5, y : 6 }
|
||||||
|
)
|
||||||
|
]);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue