Browse Source
Former-commit-id: 9e4c5f831818db1529398a257fc097efe03afbb0 Former-commit-id: 6e70da743d218717f285a06c196cea01d09cc261beta
Jack Lukic
11 years ago
815 changed files with 59853 additions and 292 deletions
@ -1 +1 @@ |
|||
.ui.nag{display:none;opacity:.95;position:absolute;top:0;left:10%;z-index:100;width:80%;min-height:20px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;margin:0;padding:.75em 1em;background-color:#555;-webkit-box-shadow:0 1px 2px 0 rgba(0,0,0,.2);-moz-box-shadow:0 1px 2px 0 rgba(0,0,0,.2);box-shadow:0 1px 2px 0 rgba(0,0,0,.2);font-size:1em;text-align:center;color:rgba(255,255,255,.8);-webkit-border-radius:0 0 5px 5px;-moz-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px;-webkit-transition:.2s background;-moz-transition:.2s background;-o-transition:.2s background;-ms-transition:.2s background;transition:.2s background}a.ui.nag{cursor:pointer}.ui.nag>.title{display:inline-block;margin:0 .5em;color:#FFF}.ui.nag>.icon.close{cursor:pointer;opacity:.4;position:absolute;top:50%;right:1em;margin-top:-.5em;color:#FFF;-webkit-transition:.1s opacity;-moz-transition:.1s opacity;-o-transition:.1s opacity;-ms-transition:.1s opacity;transition:.1s opacity}.ui.nag:hover{opacity:1}.ui.nag .close:hover{opacity:1}.ui.static.nag{position:static;display:block}.ui.fixed.nag{position:fixed}.ui.nag.bottom{-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.ui.nag.bottom.fixed{top:auto;bottom:0}.ui.nag.white{background-color:#F1F1F1;text-shadow:0 1px 0 rgba(255,255,255,.8);color:#ACACAC}.ui.nag.white .close,.ui.nag.white .title{color:#333} |
|||
.ui.nag{display:none;opacity:.95;position:absolute;top:0;left:10%;z-index:101;width:80%;min-height:20px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;margin:0;padding:.75em 1em;background-color:#555;-webkit-box-shadow:0 1px 2px 0 rgba(0,0,0,.2);-moz-box-shadow:0 1px 2px 0 rgba(0,0,0,.2);box-shadow:0 1px 2px 0 rgba(0,0,0,.2);font-size:1em;text-align:center;color:rgba(255,255,255,.8);-webkit-border-radius:0 0 5px 5px;-moz-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px;-webkit-transition:.2s background;-moz-transition:.2s background;-o-transition:.2s background;-ms-transition:.2s background;transition:.2s background}a.ui.nag{cursor:pointer}.ui.nag>.title{display:inline-block;margin:0 .5em;color:#FFF}.ui.nag>.icon.close{cursor:pointer;opacity:.4;position:absolute;top:50%;right:1em;margin-top:-.5em;color:#FFF;-webkit-transition:.1s opacity;-moz-transition:.1s opacity;-o-transition:.1s opacity;-ms-transition:.1s opacity;transition:.1s opacity}.ui.nag:hover{opacity:1}.ui.nag .close:hover{opacity:1}.ui.static.nag{position:static;display:block}.ui.fixed.nag{position:fixed}.ui.nag.bottom{-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.ui.nag.bottom.fixed{top:auto;bottom:0}.ui.nag.white{background-color:#F1F1F1;text-shadow:0 1px 0 rgba(255,255,255,.8);color:#ACACAC}.ui.nag.white .close,.ui.nag.white .title{color:#333} |
File diff suppressed because one or more lines are too long
@ -1 +1 @@ |
|||
b064b9beab68a8b3be641d50e6fd1b43f9c22364 |
|||
a37ad87f843c5e10d77e889ccaddeb43f4d0b221 |
@ -0,0 +1 @@ |
|||
../docpad/bin/docpad-trace |
@ -0,0 +1,43 @@ |
|||
# Contributing |
|||
|
|||
## Support |
|||
|
|||
[Post your question on StackOverflow with the `docpad` tag](http://stackoverflow.com/questions/tagged/docpad) |
|||
|
|||
|
|||
## Bug reports |
|||
|
|||
[Post your bug report on the GitHub Issue Tracker for this project](https://github.com/docpad/docpad-plugin-coffeescript/issues) |
|||
|
|||
|
|||
## Development |
|||
|
|||
### Install dependencies |
|||
|
|||
``` bash |
|||
npm install; npm install -g coffee-script |
|||
``` |
|||
|
|||
### Setup for development |
|||
|
|||
``` bash |
|||
cake setup |
|||
``` |
|||
|
|||
### Watch and compile |
|||
|
|||
``` bash |
|||
cake watch |
|||
``` |
|||
|
|||
### Setup for testing |
|||
|
|||
``` bash |
|||
cake test-setup |
|||
``` |
|||
|
|||
### Run the tests |
|||
|
|||
``` bash |
|||
cake test |
|||
``` |
@ -0,0 +1,10 @@ |
|||
# The MIT License |
|||
|
|||
Copyright © 2012+ [Bevry Pty Ltd](http://bevry.me) |
|||
<br/>Copyright © 2011 [Benjamin Lupton](http://balupton.com) |
|||
|
|||
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,8 @@ |
|||
.travis* |
|||
Cakefile |
|||
Makefile |
|||
History.md |
|||
|
|||
src/ |
|||
out/test/ |
|||
test/ |
@ -0,0 +1,10 @@ |
|||
(The MIT License) |
|||
|
|||
Copyright © 2013+ [Bevry Pty Ltd](http://bevry.me) <us@bevry.me> |
|||
Copyright © 2011-2012 [Benjamin Lupton](http://balupton.com) <b@lupton.cc> |
|||
|
|||
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,51 @@ |
|||
# Extract Opts |
|||
|
|||
[![Build Status](https://secure.travis-ci.org/bevry/extract-opts.png?branch=master)](http://travis-ci.org/bevry/extract-opts) |
|||
[![NPM version](https://badge.fury.io/js/extract-opts.png)](https://npmjs.org/package/extract-opts) |
|||
[![Flattr this project](https://raw.github.com/balupton/flattr-buttons/master/badge-89x18.gif)](http://flattr.com/thing/344188/balupton-on-Flattr) |
|||
|
|||
Extract the options and callback from a function's arguments easily |
|||
|
|||
|
|||
|
|||
## Install |
|||
|
|||
1. [Install Node.js](http://bevry.me/node/install) |
|||
2. `npm install --save extract-opts` |
|||
|
|||
|
|||
|
|||
## Usage |
|||
|
|||
``` javascript |
|||
var extractOpts = require('extract-opts').extractOpts; |
|||
|
|||
// fs.readFile(filename, [options], callback) |
|||
var readFile = function(filename, opts, callback){ |
|||
// Extract options and callback |
|||
var args = extractOpts(opts, callback); |
|||
opts = args[0]; |
|||
callback = args[1]; |
|||
|
|||
// Forward for simplicities sake |
|||
require('fs').readFile(filename, opts, callback); |
|||
}; |
|||
|
|||
// Test it |
|||
var next = console.log.bind(console); |
|||
readFile('package.json', next); // works with no options |
|||
readFile('package.json', null, next); // works with null options |
|||
readFile('package.json', {next:next}); // works with just options |
|||
``` |
|||
|
|||
|
|||
|
|||
## History |
|||
[You can discover the history inside the `History.md` file](https://github.com/bevry/extract-opts/blob/master/History.md#files) |
|||
|
|||
|
|||
|
|||
## License |
|||
Licensed under the incredibly [permissive](http://en.wikipedia.org/wiki/Permissive_free_software_licence) [MIT License](http://creativecommons.org/licenses/MIT/) |
|||
<br/>Copyright © 2013+ [Bevry Pty Ltd](http://bevry.me) |
|||
<br/>Copyright © 2011-2012 [Benjamin Arthur Lupton](http://balupton.com) |
@ -0,0 +1,18 @@ |
|||
var extractOpts = require('./').extractOpts; |
|||
|
|||
// fs.readFile(filename, [options], callback)
|
|||
var readFile = function(filename, opts, callback){ |
|||
// Extract options and callback
|
|||
var args = extractOpts(opts, callback); |
|||
opts = args[0]; |
|||
callback = args[1]; |
|||
|
|||
// Forward for simplicities sake
|
|||
require('fs').readFile(filename, opts, callback); |
|||
}; |
|||
|
|||
// Test it
|
|||
var next = console.log.bind(console); |
|||
readFile('package.json', next); // works with no options
|
|||
readFile('package.json', null, next); // works with null options
|
|||
readFile('package.json', {next:next}); // works with just options
|
@ -0,0 +1,42 @@ |
|||
// Generated by CoffeeScript 1.6.3
|
|||
var extractOpts, typeChecker; |
|||
|
|||
typeChecker = require('typechecker'); |
|||
|
|||
extractOpts = { |
|||
extractOpts: function(opts, next, config) { |
|||
return extractOpts.extractOptsAndCallback(opts, next, config); |
|||
}, |
|||
extractOptsAndCallback: function(opts, next, config) { |
|||
var completionCallbackName, _i, _len, _ref; |
|||
if (config == null) { |
|||
config = {}; |
|||
} |
|||
if ((config.completionCallbackNames != null) === false) { |
|||
config.completionCallbackNames = ['next']; |
|||
} else if (typeChecker.isArray(config.completionCallbackNames) === false) { |
|||
config.completionCallbackNames = [config.completionCallbackNames]; |
|||
} |
|||
if (typeChecker.isFunction(opts) && (next != null) === false) { |
|||
next = opts; |
|||
opts = {}; |
|||
} else { |
|||
opts || (opts = {}); |
|||
} |
|||
if (!next) { |
|||
_ref = config.completionCallbackNames; |
|||
for (_i = 0, _len = _ref.length; _i < _len; _i++) { |
|||
completionCallbackName = _ref[_i]; |
|||
next = opts[completionCallbackName]; |
|||
delete opts[completionCallbackName]; |
|||
if (next) { |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
next || (next = null); |
|||
return [opts, next]; |
|||
} |
|||
}; |
|||
|
|||
module.exports = extractOpts; |
@ -0,0 +1,68 @@ |
|||
{ |
|||
"name": "extract-opts", |
|||
"version": "2.2.0", |
|||
"description": "Extract the options and callback from a function's arguments easily", |
|||
"homepage": "https://github.com/bevry/extract-opts", |
|||
"keywords": [ |
|||
"opts", |
|||
"options", |
|||
"cb", |
|||
"callback", |
|||
"next", |
|||
"flow", |
|||
"args", |
|||
"optional", |
|||
"arguments", |
|||
"extract" |
|||
], |
|||
"author": { |
|||
"name": "Bevry Pty Ltd", |
|||
"email": "us@bevry.me", |
|||
"url": "http://bevry.me" |
|||
}, |
|||
"maintainers": [ |
|||
{ |
|||
"name": "Benjamin Lupton", |
|||
"email": "b@lupton.cc", |
|||
"url": "https://github.com/balupton" |
|||
} |
|||
], |
|||
"contributors": [ |
|||
{ |
|||
"name": "Benjamin Lupton", |
|||
"email": "b@lupton.cc", |
|||
"url": "https://github.com/balupton" |
|||
} |
|||
], |
|||
"bugs": { |
|||
"url": "https://github.com/bevry/extract-opts/issues" |
|||
}, |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "http://github.com/bevry/extract-opts.git" |
|||
}, |
|||
"engines": { |
|||
"node": ">=0.4" |
|||
}, |
|||
"dependencies": { |
|||
"typechecker": "~2.0.1" |
|||
}, |
|||
"devDependencies": { |
|||
"coffee-script": "~1.6.2", |
|||
"joe": "~1.2.0", |
|||
"joe-reporter-console": "~1.2.1", |
|||
"chai": "~1.5.0", |
|||
"eachr": "~2.0.2" |
|||
}, |
|||
"directories": { |
|||
"lib": "./out/lib" |
|||
}, |
|||
"scripts": { |
|||
"test": "node ./out/test/extract-opts-test.js" |
|||
}, |
|||
"main": "./out/lib/extract-opts.js", |
|||
"readme": "# Extract Opts\n\n[![Build Status](https://secure.travis-ci.org/bevry/extract-opts.png?branch=master)](http://travis-ci.org/bevry/extract-opts)\n[![NPM version](https://badge.fury.io/js/extract-opts.png)](https://npmjs.org/package/extract-opts)\n[![Flattr this project](https://raw.github.com/balupton/flattr-buttons/master/badge-89x18.gif)](http://flattr.com/thing/344188/balupton-on-Flattr)\n\nExtract the options and callback from a function's arguments easily\n\n\n\n## Install\n\n1. [Install Node.js](http://bevry.me/node/install)\n2. `npm install --save extract-opts`\n\n\n\n## Usage\n\n``` javascript\nvar extractOpts = require('extract-opts').extractOpts;\n\n// fs.readFile(filename, [options], callback)\nvar readFile = function(filename, opts, callback){\n\t// Extract options and callback\n\tvar args = extractOpts(opts, callback);\n\topts = args[0];\n\tcallback = args[1];\n\n\t// Forward for simplicities sake\n\trequire('fs').readFile(filename, opts, callback);\n};\n\n// Test it\nvar next = console.log.bind(console);\nreadFile('package.json', next); // works with no options\nreadFile('package.json', null, next); // works with null options\nreadFile('package.json', {next:next}); // works with just options\n```\n\n\n\n## History\n[You can discover the history inside the `History.md` file](https://github.com/bevry/extract-opts/blob/master/History.md#files)\n\n\n\n## License\nLicensed under the incredibly [permissive](http://en.wikipedia.org/wiki/Permissive_free_software_licence) [MIT License](http://creativecommons.org/licenses/MIT/)\n<br/>Copyright © 2013+ [Bevry Pty Ltd](http://bevry.me)\n<br/>Copyright © 2011-2012 [Benjamin Arthur Lupton](http://balupton.com)\n", |
|||
"readmeFilename": "README.md", |
|||
"_id": "extract-opts@2.2.0", |
|||
"_from": "extract-opts@~2.2.0" |
|||
} |
@ -0,0 +1,8 @@ |
|||
.travis* |
|||
Cakefile |
|||
Makefile |
|||
History.md |
|||
|
|||
src/ |
|||
out/test/ |
|||
test/ |
@ -0,0 +1,10 @@ |
|||
(The MIT License) |
|||
|
|||
Copyright © 2013+ [Bevry Pty Ltd](http://bevry.me) <us@bevry.me> |
|||
Copyright © 2011-2012 [Benjamin Lupton](http://balupton.com) <b@lupton.cc> |
|||
|
|||
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,122 @@ |
|||
# Safe PS |
|||
|
|||
[![Build Status](https://secure.travis-ci.org/bevry/safeps.png?branch=master)](http://travis-ci.org/bevry/safeps) |
|||
[![NPM version](https://badge.fury.io/js/safeps.png)](https://npmjs.org/package/safeps) |
|||
[![Flattr this project](https://raw.github.com/balupton/flattr-buttons/master/badge-89x18.gif)](http://flattr.com/thing/344188/balupton-on-Flattr) |
|||
|
|||
Work with processes safely and easily in Node.js |
|||
|
|||
|
|||
|
|||
## Install |
|||
|
|||
1. [Install Node.js](http://bevry.me/node/install) |
|||
2. `npm install --save safeps` |
|||
|
|||
|
|||
|
|||
## Usage |
|||
|
|||
``` javascript |
|||
var safeps = require('safeps'); |
|||
``` |
|||
|
|||
### Processes |
|||
|
|||
- `openProcess(task)` fire a process task, and keep it open until the task's completion callback fires |
|||
- `task(complete)` |
|||
- `spawn(command, opts?, next?)` spawn a process, with respect to the maximum amount of processes we can open at once |
|||
- `command` an array of arguments to execute |
|||
- `opts={safe:true, read:true, output:false, stdin:null}` options are also sent on to `require('child_process').spawn` |
|||
- `safe` whether or not we should attempt to get the absolute executable path of the command to execute via `require('safeps').getExecPath` |
|||
- `read` whether or not we should listen to the child process's stdout and stderr streams for use in the completion callback |
|||
- `output` if set to `true` will output the child process's stdout to our process's stdout |
|||
- `stdin` if set will be written to the child process's stdin |
|||
- `next(err, stdout, stderr, code, signal)` |
|||
- `spawnMultiple(commands, opts?, next?)` spawn multiple processes, forwards on to `require('safeps').spawn` |
|||
- `commands` an array of commands to execute |
|||
- `opts={concurrency:1}` options are also sent on to `require('safeps').spawn` |
|||
- `concurrency` how many processes should we execute at once? |
|||
- `next(err, results)` |
|||
- `results = [result...]` |
|||
- `result = [err, stdout, stderr, code, signal]` |
|||
- `spawnCommand(command, args, opts?, next?)` alias of `require('safeps').spawn` but with the `command` prefixed to the `args`, e.g. `spawnCommand('git', 'status')` |
|||
- `spawnCommands(command, multiArgs, opts?, next?` alias of `require('safeps').spawnMultiple` but with the `command` prefixed to the `multiArgs`, e.g. `spawnCommands('git', [['status'],['pull']])` |
|||
- `exec(command, opts?, next?)` execute a process, with respect to the maximum amount of processes we can open at once |
|||
- `command` a string to execute |
|||
- `opts={output:false}` options are also sent on to `require('child_process').exec` |
|||
- `output` if set to `true` will set the `stdio` option to `inherit` which will output the child process's stdout and stderr to our own |
|||
- `next(err, stdout, stderr)` |
|||
- `execMultiple(commands, opts, next)` execute multiple processes, forwards on to `require('safeps').exec` |
|||
- `commands` is an array of commands to execute |
|||
- `opts={concurrency:1}` options are also sent to `require('safeps').exec` |
|||
- `concurrency` how many processes should we execute at once? |
|||
- `next(err, results)` |
|||
- `results = [result...]` |
|||
- `result = [err, stdout, stderr]` |
|||
|
|||
|
|||
### Paths |
|||
|
|||
- `determineExecPath(possibleExecPaths, next)` determine an executable path from a list |
|||
- `possibleExecPaths` an array of possible executable paths that we shall evaluate |
|||
- `next(err, execPath)` |
|||
- `getEnvironmentPaths()` returns an array of the environment paths for executables |
|||
- `getStandardExecPaths(execName?)` return an array of the the environment paths for executables with the cwd prepended |
|||
- `execName` if provided, is added onto each of the paths |
|||
- `getExecPath(execName, next)` get the absolute executable path, forwards to `get#{execName}Path` when appropriate |
|||
- `next(err, execPath)` |
|||
- `getHomePath(next)` get the user's home path |
|||
- `next(err, homePath)` |
|||
- `getTmpPath(next)` get the temporary path |
|||
- `next(err, tmpPath)` |
|||
- `getGitPath(next)` get the git path |
|||
- `next(err, gitPath)` |
|||
- `getNodePath(next)` get the node path |
|||
- `next(err, nodePath)` |
|||
- `getNpmPath(next)` get the npm path |
|||
- `next(err, npmPath)` |
|||
|
|||
|
|||
### Modules |
|||
|
|||
- `initGitRepo(opts, next?)` get the git path, forwards on to `require('safeps').spawnCommand` |
|||
- `opts={cwd:process.cwd(), url:null, remote:'origin', branch:'master'}` options are also sent on to `require('safeps').spawnCommand` |
|||
- `cwd` the path to initialize the repo to |
|||
- `url` the url to initialize |
|||
- `remote` the remote name to associate the `url` to |
|||
- `branch` the branch name to initialize the repo to |
|||
- `next(err, results)`, `results = [result...]`, `result = [err, stdout, stderr, code, signal]` |
|||
- `initOrPullGitRepo(opts, next?)` if the path exists, update it, otherwise initialize it, forwards on to `require('safeps').spawnCommand` |
|||
- `opts={cwd:process.cwd(), url:null, remote:'origin', branch:'master'}` options are also sent on to `require('safeps').spawnCommand` |
|||
- `next(err, method, results)` |
|||
- `method` is either `pull` or `init` depending on the method used |
|||
- `results = [result...]` |
|||
- `result = [err, stdout, stderr, code, signal]` |
|||
- `initNodeModules(opts, next?)` initialize node modules, forwards on to `require('safeps').spawn` |
|||
- `opts={cwd:process.cwd(), args:[], force:false}` options are also sent on to `require('safeps').spawnCommand` |
|||
- `cwd` the path to initialize the repo to |
|||
- `args` an array of arguments to add onto the initialize command |
|||
- `force` whether or not to still initialize modules if `node_modules` already exists |
|||
- `next(err, results)`, `results = [result...]`, `result = [err, stdout, stderr, code, signal]` |
|||
|
|||
|
|||
### Environment |
|||
|
|||
- `requireFresh(path)` require the file without adding it to the cache |
|||
- `isWindows()` are we running on windows? |
|||
- `getLocaleCode(lang?=process.env.LANG)` get the locale code from a language, e.g. `en_au` |
|||
- `getLanguageCode(localeCode?=getLocaleCode())` get the language code from a locale code, e.g. `en` |
|||
- `getCountryCode(localeCode?=getLocaleCode())` get the country code from a locale code, e.g. `au` |
|||
|
|||
|
|||
|
|||
## History |
|||
[You can discover the history inside the `History.md` file](https://github.com/bevry/safeps/blob/master/History.md#files) |
|||
|
|||
|
|||
|
|||
## License |
|||
Licensed under the incredibly [permissive](http://en.wikipedia.org/wiki/Permissive_free_software_licence) [MIT License](http://creativecommons.org/licenses/MIT/) |
|||
<br/>Copyright © 2013+ [Bevry Pty Ltd](http://bevry.me) |
|||
<br/>Copyright © 2011-2012 [Benjamin Arthur Lupton](http://balupton.com) |
@ -0,0 +1,8 @@ |
|||
.travis* |
|||
Cakefile |
|||
Makefile |
|||
History.md |
|||
|
|||
src/ |
|||
out/test/ |
|||
test/ |
@ -0,0 +1,10 @@ |
|||
(The MIT License) |
|||
|
|||
Copyright © 2013+ [Bevry Pty Ltd](http://bevry.me) <us@bevry.me> |
|||
Copyright © 2011-2012 [Benjamin Lupton](http://balupton.com) <b@lupton.cc> |
|||
|
|||
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,51 @@ |
|||
# Extract Opts |
|||
|
|||
[![Build Status](https://secure.travis-ci.org/bevry/extract-opts.png?branch=master)](http://travis-ci.org/bevry/extract-opts) |
|||
[![NPM version](https://badge.fury.io/js/extract-opts.png)](https://npmjs.org/package/extract-opts) |
|||
[![Flattr this project](https://raw.github.com/balupton/flattr-buttons/master/badge-89x18.gif)](http://flattr.com/thing/344188/balupton-on-Flattr) |
|||
|
|||
Extract the options and callback from a function's arguments easily |
|||
|
|||
|
|||
|
|||
## Install |
|||
|
|||
1. [Install Node.js](http://bevry.me/node/install) |
|||
2. `npm install --save extract-opts` |
|||
|
|||
|
|||
|
|||
## Usage |
|||
|
|||
``` javascript |
|||
var extractOpts = require('extract-opts').extractOpts; |
|||
|
|||
// fs.readFile(filename, [options], callback) |
|||
var readFile = function(filename, opts, callback){ |
|||
// Extract options and callback |
|||
var args = extractOpts(opts, callback); |
|||
opts = args[0]; |
|||
callback = args[1]; |
|||
|
|||
// Forward for simplicities sake |
|||
require('fs').readFile(filename, opts, callback); |
|||
}; |
|||
|
|||
// Test it |
|||
var next = console.log.bind(console); |
|||
readFile('package.json', next); // works with no options |
|||
readFile('package.json', null, next); // works with null options |
|||
readFile('package.json', {next:next}); // works with just options |
|||
``` |
|||
|
|||
|
|||
|
|||
## History |
|||
[You can discover the history inside the `History.md` file](https://github.com/bevry/extract-opts/blob/master/History.md#files) |
|||
|
|||
|
|||
|
|||
## License |
|||
Licensed under the incredibly [permissive](http://en.wikipedia.org/wiki/Permissive_free_software_licence) [MIT License](http://creativecommons.org/licenses/MIT/) |
|||
<br/>Copyright © 2013+ [Bevry Pty Ltd](http://bevry.me) |
|||
<br/>Copyright © 2011-2012 [Benjamin Arthur Lupton](http://balupton.com) |
@ -0,0 +1,18 @@ |
|||
var extractOpts = require('./').extractOpts; |
|||
|
|||
// fs.readFile(filename, [options], callback)
|
|||
var readFile = function(filename, opts, callback){ |
|||
// Extract options and callback
|
|||
var args = extractOpts(opts, callback); |
|||
opts = args[0]; |
|||
callback = args[1]; |
|||
|
|||
// Forward for simplicities sake
|
|||
require('fs').readFile(filename, opts, callback); |
|||
}; |
|||
|
|||
// Test it
|
|||
var next = console.log.bind(console); |
|||
readFile('package.json', next); // works with no options
|
|||
readFile('package.json', null, next); // works with null options
|
|||
readFile('package.json', {next:next}); // works with just options
|
@ -0,0 +1,42 @@ |
|||
// Generated by CoffeeScript 1.6.3
|
|||
var extractOpts, typeChecker; |
|||
|
|||
typeChecker = require('typechecker'); |
|||
|
|||
extractOpts = { |
|||
extractOpts: function(opts, next, config) { |
|||
return extractOpts.extractOptsAndCallback(opts, next, config); |
|||
}, |
|||
extractOptsAndCallback: function(opts, next, config) { |
|||
var completionCallbackName, _i, _len, _ref; |
|||
if (config == null) { |
|||
config = {}; |
|||
} |
|||
if ((config.completionCallbackNames != null) === false) { |
|||
config.completionCallbackNames = ['next']; |
|||
} else if (typeChecker.isArray(config.completionCallbackNames) === false) { |
|||
config.completionCallbackNames = [config.completionCallbackNames]; |
|||
} |
|||
if (typeChecker.isFunction(opts) && (next != null) === false) { |
|||
next = opts; |
|||
opts = {}; |
|||
} else { |
|||
opts || (opts = {}); |
|||
} |
|||
if (!next) { |
|||
_ref = config.completionCallbackNames; |
|||
for (_i = 0, _len = _ref.length; _i < _len; _i++) { |
|||
completionCallbackName = _ref[_i]; |
|||
next = opts[completionCallbackName]; |
|||
delete opts[completionCallbackName]; |
|||
if (next) { |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
next || (next = null); |
|||
return [opts, next]; |
|||
} |
|||
}; |
|||
|
|||
module.exports = extractOpts; |
@ -0,0 +1,68 @@ |
|||
{ |
|||
"name": "extract-opts", |
|||
"version": "2.2.0", |
|||
"description": "Extract the options and callback from a function's arguments easily", |
|||
"homepage": "https://github.com/bevry/extract-opts", |
|||
"keywords": [ |
|||
"opts", |
|||
"options", |
|||
"cb", |
|||
"callback", |
|||
"next", |
|||
"flow", |
|||
"args", |
|||
"optional", |
|||
"arguments", |
|||
"extract" |
|||
], |
|||
"author": { |
|||
"name": "Bevry Pty Ltd", |
|||
"email": "us@bevry.me", |
|||
"url": "http://bevry.me" |
|||
}, |
|||
"maintainers": [ |
|||
{ |
|||
"name": "Benjamin Lupton", |
|||
"email": "b@lupton.cc", |
|||
"url": "https://github.com/balupton" |
|||
} |
|||
], |
|||
"contributors": [ |
|||
{ |
|||
"name": "Benjamin Lupton", |
|||
"email": "b@lupton.cc", |
|||
"url": "https://github.com/balupton" |
|||
} |
|||
], |
|||
"bugs": { |
|||
"url": "https://github.com/bevry/extract-opts/issues" |
|||
}, |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "http://github.com/bevry/extract-opts.git" |
|||
}, |
|||
"engines": { |
|||
"node": ">=0.4" |
|||
}, |
|||
"dependencies": { |
|||
"typechecker": "~2.0.1" |
|||
}, |
|||
"devDependencies": { |
|||
"coffee-script": "~1.6.2", |
|||
"joe": "~1.2.0", |
|||
"joe-reporter-console": "~1.2.1", |
|||
"chai": "~1.5.0", |
|||
"eachr": "~2.0.2" |
|||
}, |
|||
"directories": { |
|||
"lib": "./out/lib" |
|||
}, |
|||
"scripts": { |
|||
"test": "node ./out/test/extract-opts-test.js" |
|||
}, |
|||
"main": "./out/lib/extract-opts.js", |
|||
"readme": "# Extract Opts\n\n[![Build Status](https://secure.travis-ci.org/bevry/extract-opts.png?branch=master)](http://travis-ci.org/bevry/extract-opts)\n[![NPM version](https://badge.fury.io/js/extract-opts.png)](https://npmjs.org/package/extract-opts)\n[![Flattr this project](https://raw.github.com/balupton/flattr-buttons/master/badge-89x18.gif)](http://flattr.com/thing/344188/balupton-on-Flattr)\n\nExtract the options and callback from a function's arguments easily\n\n\n\n## Install\n\n1. [Install Node.js](http://bevry.me/node/install)\n2. `npm install --save extract-opts`\n\n\n\n## Usage\n\n``` javascript\nvar extractOpts = require('extract-opts').extractOpts;\n\n// fs.readFile(filename, [options], callback)\nvar readFile = function(filename, opts, callback){\n\t// Extract options and callback\n\tvar args = extractOpts(opts, callback);\n\topts = args[0];\n\tcallback = args[1];\n\n\t// Forward for simplicities sake\n\trequire('fs').readFile(filename, opts, callback);\n};\n\n// Test it\nvar next = console.log.bind(console);\nreadFile('package.json', next); // works with no options\nreadFile('package.json', null, next); // works with null options\nreadFile('package.json', {next:next}); // works with just options\n```\n\n\n\n## History\n[You can discover the history inside the `History.md` file](https://github.com/bevry/extract-opts/blob/master/History.md#files)\n\n\n\n## License\nLicensed under the incredibly [permissive](http://en.wikipedia.org/wiki/Permissive_free_software_licence) [MIT License](http://creativecommons.org/licenses/MIT/)\n<br/>Copyright © 2013+ [Bevry Pty Ltd](http://bevry.me)\n<br/>Copyright © 2011-2012 [Benjamin Arthur Lupton](http://balupton.com)\n", |
|||
"readmeFilename": "README.md", |
|||
"_id": "extract-opts@2.2.0", |
|||
"_from": "extract-opts@~2.2.0" |
|||
} |
@ -0,0 +1,8 @@ |
|||
.travis* |
|||
Cakefile |
|||
Makefile |
|||
History.md |
|||
|
|||
src/ |
|||
out/test/ |
|||
test/ |
@ -0,0 +1,10 @@ |
|||
(The MIT License) |
|||
|
|||
Copyright © 2013+ [Bevry Pty Ltd](http://bevry.me) <us@bevry.me> |
|||
Copyright © 2011-2012 [Benjamin Lupton](http://balupton.com) <b@lupton.cc> |
|||
|
|||
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,60 @@ |
|||
# Safe FS |
|||
|
|||
[![Build Status](https://secure.travis-ci.org/bevry/safefs.png?branch=master)](http://travis-ci.org/bevry/safefs) |
|||
[![NPM version](https://badge.fury.io/js/safefs.png)](https://npmjs.org/package/safefs) |
|||
|
|||
Stop getting EMFILE errors! Open only as many files as the operating system supports. |
|||
|
|||
|
|||
|
|||
## Install |
|||
|
|||
1. [Install Node.js](http://bevry.me/node/install) |
|||
2. `npm install --save safefs` |
|||
|
|||
|
|||
|
|||
## Usage |
|||
|
|||
``` javascript |
|||
var safefs = require('safefs'); |
|||
``` |
|||
|
|||
The following [file system](http://nodejs.org/docs/latest/api/all.html#all_file_system) methods are available (but wrapped in safe way to prevent EMFILE errors): |
|||
|
|||
- `readFile(path, options?, next)` |
|||
- `writeFile(path, data, options?, next)` - will also attempt to ensure the path exists |
|||
- `appendFile(path, data, options?, next)` - will also attempt to ensure the path exists |
|||
- `mkdir(path, mode?, next)` - mode defaults to `0o777 & (~process.umask())` |
|||
- `stat(path, next)` |
|||
- `readdir(path, next)` |
|||
- `unlink(path, next)` |
|||
- `rmdir(path, next)` |
|||
- `exists(path, next)` |
|||
|
|||
For other file system interaction, you can do the following: |
|||
|
|||
``` javascript |
|||
// get a slot in the file system queue |
|||
require('safefs').openFile(function(closeFile){ |
|||
// do our file system interaction |
|||
require('fs').someOtherMethod(a,b,c,function(err,a,b,c){ |
|||
// close the slot we are using in the file system queue |
|||
closeFile(); |
|||
}); |
|||
}); |
|||
``` |
|||
|
|||
To make this possible we define a global variable called `safefsGlobal` that manages the available slots for interacting with the file system. |
|||
|
|||
|
|||
|
|||
## History |
|||
You can discover the history inside the [History.md](https://github.com/bevry/safefs/blob/master/History.md#files) file |
|||
|
|||
|
|||
|
|||
## License |
|||
Licensed under the incredibly [permissive](http://en.wikipedia.org/wiki/Permissive_free_software_licence) [MIT License](http://creativecommons.org/licenses/MIT/) |
|||
<br/>Copyright © 2013+ [Bevry Pty Ltd](http://bevry.me) |
|||
<br/>Copyright © 2011-2012 [Benjamin Arthur Lupton](http://balupton.com) |
@ -0,0 +1,195 @@ |
|||
// Generated by CoffeeScript 1.6.2
|
|||
var TaskGroup, fsUtil, pathUtil, safefs, _base, _ref, _ref1, _ref2; |
|||
|
|||
fsUtil = require('fs'); |
|||
|
|||
pathUtil = require('path'); |
|||
|
|||
TaskGroup = require('taskgroup').TaskGroup; |
|||
|
|||
if ((_ref = global.safefsGlobal) == null) { |
|||
global.safefsGlobal = {}; |
|||
} |
|||
|
|||
if ((_ref1 = (_base = global.safefsGlobal).pool) == null) { |
|||
_base.pool = new TaskGroup().setConfig({ |
|||
concurrency: (_ref2 = process.env.NODE_MAX_OPEN_FILES) != null ? _ref2 : 100, |
|||
pauseOnError: false |
|||
}).run(); |
|||
} |
|||
|
|||
safefs = { |
|||
openFile: function(fn) { |
|||
global.safefsGlobal.pool.addTask(fn); |
|||
return safefs; |
|||
}, |
|||
closeFile: function() { |
|||
console.log('safefs.closeFile has been deprecated, please use the safefs.openFile completion callback to close files'); |
|||
return safefs; |
|||
}, |
|||
getParentPathSync: function(p) { |
|||
var parentPath; |
|||
|
|||
parentPath = p.replace(/[\/\\]$/, '').replace(/[\/\\][^\/\\]+$/, ''); |
|||
return parentPath; |
|||
}, |
|||
ensurePath: function(path, options, next) { |
|||
var _ref3; |
|||
|
|||
if (next == null) { |
|||
next = options; |
|||
options = null; |
|||
} |
|||
if (options == null) { |
|||
options = {}; |
|||
} |
|||
if ((_ref3 = options.mode) == null) { |
|||
options.mode = null; |
|||
} |
|||
safefs.exists(path, function(exists) { |
|||
var parentPath; |
|||
|
|||
if (exists) { |
|||
return next(null, true); |
|||
} |
|||
parentPath = safefs.getParentPathSync(path); |
|||
return safefs.ensurePath(parentPath, options, function(err) { |
|||
if (err) { |
|||
return next(err, false); |
|||
} |
|||
return safefs.mkdir(path, options.mode, function(err) { |
|||
return safefs.exists(path, function(exists) { |
|||
if (!exists) { |
|||
err = new Error("Failed to create the directory: " + path); |
|||
return next(err, false); |
|||
} |
|||
return next(null, false); |
|||
}); |
|||
}); |
|||
}); |
|||
}); |
|||
return safefs; |
|||
}, |
|||
readFile: function(path, options, next) { |
|||
if (next == null) { |
|||
next = options; |
|||
options = null; |
|||
} |
|||
safefs.openFile(function(closeFile) { |
|||
return fsUtil.readFile(path, options, function(err, data) { |
|||
closeFile(); |
|||
return next(err, data); |
|||
}); |
|||
}); |
|||
return safefs; |
|||
}, |
|||
writeFile: function(path, data, options, next) { |
|||
if (next == null) { |
|||
next = options; |
|||
options = null; |
|||
} |
|||
safefs.ensurePath(pathUtil.dirname(path), options, function(err) { |
|||
if (err) { |
|||
return next(err); |
|||
} |
|||
return safefs.openFile(function(closeFile) { |
|||
return fsUtil.writeFile(path, data, options, function(err) { |
|||
closeFile(); |
|||
return next(err); |
|||
}); |
|||
}); |
|||
}); |
|||
return safefs; |
|||
}, |
|||
appendFile: function(path, data, options, next) { |
|||
if (next == null) { |
|||
next = options; |
|||
options = null; |
|||
} |
|||
safefs.ensurePath(pathUtil.dirname(path), options, function(err) { |
|||
if (err) { |
|||
return next(err); |
|||
} |
|||
return safefs.openFile(function(closeFile) { |
|||
return fsUtil.appendFile(path, data, options, function(err) { |
|||
closeFile(); |
|||
return next(err); |
|||
}); |
|||
}); |
|||
}); |
|||
return safefs; |
|||
}, |
|||
mkdir: function(path, mode, next) { |
|||
if (next == null) { |
|||
next = mode; |
|||
mode = null; |
|||
} |
|||
if (mode == null) { |
|||
mode = 0x1ff & (~process.umask()); |
|||
} |
|||
safefs.openFile(function(closeFile) { |
|||
return fsUtil.mkdir(path, mode, function(err) { |
|||
closeFile(); |
|||
return next(err); |
|||
}); |
|||
}); |
|||
return safefs; |
|||
}, |
|||
stat: function(path, next) { |
|||
safefs.openFile(function(closeFile) { |
|||
return fsUtil.stat(path, function(err, stat) { |
|||
closeFile(); |
|||
return next(err, stat); |
|||
}); |
|||
}); |
|||
return safefs; |
|||
}, |
|||
readdir: function(path, next) { |
|||
safefs.openFile(function(closeFile) { |
|||
return fsUtil.readdir(path, function(err, files) { |
|||
closeFile(); |
|||
return next(err, files); |
|||
}); |
|||
}); |
|||
return safefs; |
|||
}, |
|||
unlink: function(path, next) { |
|||
safefs.openFile(function(closeFile) { |
|||
return fsUtil.unlink(path, function(err) { |
|||
closeFile(); |
|||
return next(err); |
|||
}); |
|||
}); |
|||
return safefs; |
|||
}, |
|||
rmdir: function(path, next) { |
|||
safefs.openFile(function(closeFile) { |
|||
return fsUtil.rmdir(path, function(err) { |
|||
closeFile(); |
|||
return next(err); |
|||
}); |
|||
}); |
|||
return safefs; |
|||
}, |
|||
exists: function(path, next) { |
|||
var exists; |
|||
|
|||
exists = fsUtil.exists || pathUtil.exists; |
|||
safefs.openFile(function(closeFile) { |
|||
return exists(path, function(exists) { |
|||
closeFile(); |
|||
return next(exists); |
|||
}); |
|||
}); |
|||
return safefs; |
|||
}, |
|||
existsSync: function(path) { |
|||
var existsSync, result; |
|||
|
|||
existsSync = fsUtil.existsSync || pathUtil.existsSync; |
|||
result = existsSync(path); |
|||
return result; |
|||
} |
|||
}; |
|||
|
|||
module.exports = safefs; |
@ -0,0 +1,62 @@ |
|||
{ |
|||
"name": "safefs", |
|||
"version": "3.0.1", |
|||
"description": "Stop getting EMFILE errors! Open only as many files as the operating system supports.", |
|||
"homepage": "https://github.com/bevry/safefs", |
|||
"keywords": [ |
|||
"fs", |
|||
"path", |
|||
"openFile", |
|||
"closeFile", |
|||
"emfile" |
|||
], |
|||
"author": { |
|||
"name": "Bevry Pty Ltd", |
|||
"email": "us@bevry.me", |
|||
"url": "http://bevry.me" |
|||
}, |
|||
"maintainers": [ |
|||
{ |
|||
"name": "Benjamin Lupton", |
|||
"email": "b@lupton.cc", |
|||
"url": "https://github.com/balupton" |
|||
} |
|||
], |
|||
"contributors": [ |
|||
{ |
|||
"name": "Benjamin Lupton", |
|||
"email": "b@lupton.cc", |
|||
"url": "https://github.com/balupton" |
|||
} |
|||
], |
|||
"bugs": { |
|||
"url": "https://github.com/bevry/safefs/issues" |
|||
}, |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "http://github.com/bevry/safefs.git" |
|||
}, |
|||
"engines": { |
|||
"node": ">=0.4" |
|||
}, |
|||
"dependencies": { |
|||
"taskgroup": ">=3 <3.2" |
|||
}, |
|||
"devDependencies": { |
|||
"coffee-script": "~1.6.2", |
|||
"joe": "~1.2.0", |
|||
"joe-reporter-console": "~1.2.1", |
|||
"chai": "~1.5.0" |
|||
}, |
|||
"directories": { |
|||
"lib": "./out/lib" |
|||
}, |
|||
"scripts": { |
|||
"test": "node ./out/test/safefs-test.js" |
|||
}, |
|||
"main": "./out/lib/safefs.js", |
|||
"readme": "# Safe FS\n\n[![Build Status](https://secure.travis-ci.org/bevry/safefs.png?branch=master)](http://travis-ci.org/bevry/safefs)\n[![NPM version](https://badge.fury.io/js/safefs.png)](https://npmjs.org/package/safefs)\n\nStop getting EMFILE errors! Open only as many files as the operating system supports.\n\n\n\n## Install\n\n1. [Install Node.js](http://bevry.me/node/install)\n2. `npm install --save safefs`\n\n\n\n## Usage\n\n``` javascript\nvar safefs = require('safefs');\n```\n\nThe following [file system](http://nodejs.org/docs/latest/api/all.html#all_file_system) methods are available (but wrapped in safe way to prevent EMFILE errors):\n\n- `readFile(path, options?, next)`\n- `writeFile(path, data, options?, next)` - will also attempt to ensure the path exists\n- `appendFile(path, data, options?, next)` - will also attempt to ensure the path exists\n- `mkdir(path, mode?, next)` - mode defaults to `0o777 & (~process.umask())`\n- `stat(path, next)`\n- `readdir(path, next)`\n- `unlink(path, next)`\n- `rmdir(path, next)`\n- `exists(path, next)`\n\nFor other file system interaction, you can do the following:\n\n``` javascript\n// get a slot in the file system queue\nrequire('safefs').openFile(function(closeFile){\n\t// do our file system interaction\n\trequire('fs').someOtherMethod(a,b,c,function(err,a,b,c){\n\t\t// close the slot we are using in the file system queue\n\t\tcloseFile();\n\t});\n});\n```\n\nTo make this possible we define a global variable called `safefsGlobal` that manages the available slots for interacting with the file system.\n\n\n\n## History\nYou can discover the history inside the [History.md](https://github.com/bevry/safefs/blob/master/History.md#files) file\n\n\n\n## License\nLicensed under the incredibly [permissive](http://en.wikipedia.org/wiki/Permissive_free_software_licence) [MIT License](http://creativecommons.org/licenses/MIT/)\n<br/>Copyright © 2013+ [Bevry Pty Ltd](http://bevry.me)\n<br/>Copyright © 2011-2012 [Benjamin Arthur Lupton](http://balupton.com)\n", |
|||
"readmeFilename": "README.md", |
|||
"_id": "safefs@3.0.1", |
|||
"_from": "safefs@~3.0.1" |
|||
} |
@ -0,0 +1,8 @@ |
|||
.travis* |
|||
Cakefile |
|||
Makefile |
|||
History.md |
|||
|
|||
src/ |
|||
out/test/ |
|||
test/ |
@ -0,0 +1,10 @@ |
|||
(The MIT License) |
|||
|
|||
Copyright © 2013+ [Bevry Pty Ltd](http://bevry.me) <us@bevry.me> |
|||
Copyright © 2011-2012 [Benjamin Lupton](http://balupton.com) <b@lupton.cc> |
|||
|
|||
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,156 @@ |
|||
# Task Group |
|||
|
|||
[![Build Status](https://secure.travis-ci.org/bevry/taskgroup.png?branch=master)](http://travis-ci.org/bevry/taskgroup) |
|||
[![NPM version](https://badge.fury.io/js/taskgroup.png)](https://npmjs.org/package/taskgroup) |
|||
|
|||
Group together synchronous and asynchronous tasks and execute them with support for concurrency, naming, and nesting. |
|||
|
|||
|
|||
|
|||
## Install |
|||
|
|||
### Backend |
|||
|
|||
1. [Install Node.js](http://bevry.me/node/install) |
|||
2. `npm install --save taskgroup` |
|||
|
|||
### Frontend |
|||
|
|||
1. [See Browserify](http://browserify.org/) |
|||
|
|||
|
|||
|
|||
## Usage |
|||
|
|||
### Example |
|||
|
|||
``` javascript |
|||
// Import |
|||
var TaskGroup = require('taskgroup').TaskGroup; |
|||
|
|||
// Create our new group |
|||
var group = new TaskGroup(); |
|||
|
|||
// Define what should happen once the group has completed |
|||
group.once('complete', function(err,results){ |
|||
// Log the error that has occured |
|||
console.log(err); |
|||
// => null |
|||
|
|||
// Log the results that our group received from the executing items |
|||
console.log(JSON.stringify(results)); |
|||
/* => |
|||
[ |
|||
[null, 'first', 'task'], |
|||
[null, 'second task'], |
|||
[null, [ |
|||
[null, 'sub second task'], |
|||
[null, 'sub first', 'task'] |
|||
]] |
|||
] |
|||
*/ |
|||
}); |
|||
|
|||
// Add an asynchronous task that gives the result to the completion callback |
|||
group.addTask(function(complete){ |
|||
setTimeout(function(){ |
|||
complete(null, 'first', 'task'); |
|||
},500); |
|||
}); |
|||
|
|||
// Add a synchronous task that returns the result |
|||
// Errors should be returned, though if an error is thrown we will catch it |
|||
group.addTask(function(){ |
|||
return 'second task'; |
|||
}); |
|||
|
|||
// Add a sub-group to our exiting group |
|||
group.addGroup(function(addGroup,addTask){ |
|||
// Tell this sub-group to execute in parallel (all at once) by setting its concurrency to unlimited |
|||
// by default the concurrency for all groups is set to 1 |
|||
// which means that they execute in serial fashion (one after the other, instead of all at once) |
|||
this.setConfig({concurrency:0}); |
|||
|
|||
// Add an asynchronous task that gives its result to the completion callback |
|||
addTask(function(complete){ |
|||
setTimeout(function(){ |
|||
complete(null, 'sub first', 'task'); |
|||
},500); |
|||
}); |
|||
|
|||
// Add a synchronous task that returns its result |
|||
addTask(function(){ |
|||
return 'sub second task'; |
|||
}); |
|||
}); |
|||
|
|||
// Execute our group |
|||
group.run(); |
|||
``` |
|||
|
|||
### TaskGroup API |
|||
|
|||
``` javascript |
|||
new require('taskgroup').TaskGroup() |
|||
``` |
|||
|
|||
- Available methods: |
|||
- `constructor(name?,fn?)` - create our new group, the arguments `name` and `fn` are optional, refer to their entries in configuration |
|||
- `setConfig(config)` - set the configuration for the group, returns chain |
|||
- `addTask(args...)` - create a new task item with the arguments and adds it to the group, returns the new task item |
|||
- `addGroup(args...)` - create a new group item with the arguments and adds it to the group, returns the new group item |
|||
- `getTotals()` - returns counts for the following `{running,remaining,completed,total}` |
|||
- `clear()` - remove the remaining items to be executed |
|||
- `pause()` - pause the execution of the items |
|||
- `stop()` - clear and pause |
|||
- `exit(err)` - stop and complete, `err` if specified is sent to the completion event when fired |
|||
- `complete()` - will fire the completion event if we are already complete, useful if you're binding your listeners after run |
|||
- `run()` - start/resume executing the items, returns chain |
|||
- All those of [EventEmitter2](https://github.com/hij1nx/EventEmitter2) |
|||
- Available configuration: |
|||
- `name`, no default - allows us to assign a name to the group, useful for debugging |
|||
- `fn(addGroup,addTask,complete?)`, no default - allows us to use an inline and self-executing style for defining groups, useful for nesting |
|||
- `concurrency`, defaults to `1` - how many items shall we allow to be run at the same time, set to `0` to allow unlimited |
|||
- `pauseOnError`, defaults to `true` - if an error occurs in one of our items, should we stop executing any remaining items? |
|||
- setting to `false` will continue with execution with the other items even if an item experiences an error |
|||
- Available events: |
|||
- `run()` - fired just before we execute the items |
|||
- `complete(err, results)` - fired when all our items have completed |
|||
- `task.run(task)` - fired just before a task item executes |
|||
- `task.complete(task, err, args...)` - fired when a task item has completed |
|||
- `group.run(group)` - fired just before a group item executes |
|||
- `group.complete(group, err, results)` - fired when a group item has completed |
|||
- `item.run(item)` - fired just before an item executes (fired for both sub-tasks and sub-groups) |
|||
- `item.complete(item, err, args...)` - fired when an item has completed (fired for both sub-task and sub-groups) |
|||
|
|||
|
|||
### Task API |
|||
|
|||
``` javascript |
|||
new require('taskgroup').Task() |
|||
``` |
|||
|
|||
- Available methods: |
|||
- `constructor(name?,fn?)` - create our new task, the arguments `name` and `fn` are optional though `fn` must be set at some point, refer to their entries in configuration |
|||
- `setConfig(config)` - set the configuration for the group, returns chain |
|||
- `complete()` - will fire the completion event if we are already complete, useful if you're binding your listeners after run |
|||
- `run()` - execute the task |
|||
- Available configuration: |
|||
- `name`, no default - allows us to assign a name to the group, useful for debugging |
|||
- `fn(complete?)`, no default - must be set at some point, it is the function to execute for the task, if it is asynchronous it should use the completion callback provided |
|||
- `args`, no default - an array of arguments that you would like to precede the completion callback when executing `fn` |
|||
- Available events: |
|||
- `run()` - fired just before we execute the task |
|||
- `complete(err, args...)` - fired when the task has completed |
|||
|
|||
|
|||
|
|||
## History |
|||
You can discover the history inside the [History.md](https://github.com/bevry/taskgroup/blob/master/History.md#files) file |
|||
|
|||
|
|||
|
|||
## License |
|||
Licensed under the incredibly [permissive](http://en.wikipedia.org/wiki/Permissive_free_software_licence) [MIT License](http://creativecommons.org/licenses/MIT/) |
|||
<br/>Copyright © 2013+ [Bevry Pty Ltd](http://bevry.me) |
|||
<br/>Copyright © 2011-2012 [Benjamin Arthur Lupton](http://balupton.com) |
@ -0,0 +1,61 @@ |
|||
// Import
|
|||
var TaskGroup = require('./').TaskGroup; |
|||
|
|||
// Create our new group
|
|||
var group = new TaskGroup(); |
|||
|
|||
// Define what should happen once the group has completed
|
|||
group.once('complete', function(err,results){ |
|||
// Log the error that has occured
|
|||
console.log(err); |
|||
// => null
|
|||
|
|||
// Log the results that our group received from the executing items
|
|||
console.log(JSON.stringify(results)); |
|||
/* => |
|||
[ |
|||
[null, 'first', 'task'], |
|||
[null, 'second task'], |
|||
[null, [ |
|||
[null, 'sub second task'], |
|||
[null, 'sub first', 'task'] |
|||
]] |
|||
] |
|||
*/ |
|||
}); |
|||
|
|||
// Add an asynchronous task that gives the result to the completion callback
|
|||
group.addTask(function(complete){ |
|||
setTimeout(function(){ |
|||
complete(null, 'first', 'task'); |
|||
},500); |
|||
}); |
|||
|
|||
// Add a synchronous task that returns the result
|
|||
// Errors should be returned, though if an error is thrown we will catch it
|
|||
group.addTask(function(){ |
|||
return 'second task'; |
|||
}); |
|||
|
|||
// Add a sub-group to our exiting group
|
|||
group.addGroup(function(addGroup,addTask){ |
|||
// Tell this sub-group to execute in parallel (all at once) by setting its concurrency to unlimited
|
|||
// by default the concurrency for all groups is set to 1
|
|||
// which means that they execute in serial fashion (one after the other, instead of all at once)
|
|||
this.setConfig({concurrency:0}); |
|||
|
|||
// Add an asynchronous task that gives its result to the completion callback
|
|||
addTask(function(complete){ |
|||
setTimeout(function(){ |
|||
complete(null, 'sub first', 'task'); |
|||
},500); |
|||
}); |
|||
|
|||
// Add a synchronous task that returns its result
|
|||
addTask(function(){ |
|||
return 'sub second task'; |
|||
}); |
|||
}); |
|||
|
|||
// Execute our group
|
|||
group.run(); |
@ -0,0 +1,8 @@ |
|||
.travis* |
|||
Cakefile |
|||
Makefile |
|||
History.md |
|||
|
|||
src/ |
|||
out/test/ |
|||
test/ |
@ -0,0 +1,10 @@ |
|||
(The MIT License) |
|||
|
|||
Copyright © 2013+ [Bevry Pty Ltd](http://bevry.me) <us@bevry.me> |
|||
Copyright © 2011-2012 [Benjamin Lupton](http://balupton.com) <b@lupton.cc> |
|||
|
|||
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,75 @@ |
|||
# Ambi [![Build Status](https://secure.travis-ci.org/bevry/ambi.png?branch=master)](http://travis-ci.org/bevry/ambi) |
|||
Execute a function ambidextrously (normalizes the differences between synchronous and asynchronous functions). |
|||
Useful for treating synchronous functions as asynchronous functions (like supporting both synchronous and asynchronous event definitions automatically). |
|||
|
|||
|
|||
|
|||
## Install |
|||
|
|||
### Backend |
|||
|
|||
1. [Install Node.js](http://bevry.me/node/install) |
|||
2. `npm install --save ambi` |
|||
|
|||
### Frontend |
|||
|
|||
1. [See Browserify](http://browserify.org) |
|||
|
|||
|
|||
|
|||
## Usage |
|||
|
|||
``` javascript |
|||
// Import |
|||
var ambi = require('ambi') |
|||
var result |
|||
|
|||
// Sample methods |
|||
var syncMethod = function(x,y){ |
|||
return x*y |
|||
} |
|||
var asyncMethod = function(x,y,next){ |
|||
return setTimeout(function(){ |
|||
next(null,x*y) |
|||
},0) |
|||
} |
|||
|
|||
// Call the synchronous function asynchronously |
|||
result = ambi(syncMethod, 5, 2, function(err,result){ // ambi adds support for this asynchronous callback automatically |
|||
console.log(err, result) // null, 10 |
|||
}) |
|||
console.log(result) // 10 - just like normal |
|||
|
|||
// Call the asynchronous function asynchronously |
|||
result = ambi(asyncMethod, 5, 2, function(err,result){ // ambi doesn't do anything special here |
|||
console.log(err, result) // null, 10 |
|||
}) |
|||
console.log(result) // setTimeout - just like normal |
|||
``` |
|||
|
|||
|
|||
|
|||
## Process |
|||
|
|||
- Ambi accepts the arguments `(method, args...)` |
|||
- `method` is the function to execute |
|||
- `args...` is the arguments to send to the method |
|||
- the last argument is expected to be the completion callback |
|||
- the completion callback is optional, but if defined, is expected to have the signature of `(err, results...)` |
|||
- If the method has the same amount of arguments as those ambi received, then we assume it is an asynchronous method and let it handle calling of the completion callback itself |
|||
- If the method does not have the same amount of arguments as those ambi received, then we assume it is a synchronous method and we'll call the completion callback ourselves |
|||
- If the synchronous method throws an error or returns an error, we'll try to call the completion callback with a single `err` argument |
|||
- If the synchronous method executes without error, we'll try to call the completion callback with a `err` argument equal to null, and a `result` argument equal to the returned result of the synchronous method |
|||
- Ambi can also introspect a different method than the one it fires, by passing `[methodToFire, methodToIntrospect]` as the `method` argument |
|||
|
|||
|
|||
|
|||
## History |
|||
You can discover the history inside the [History.md](https://github.com/bevry/ambi/blob/master/History.md#files) file |
|||
|
|||
|
|||
|
|||
## License |
|||
Licensed under the incredibly [permissive](http://en.wikipedia.org/wiki/Permissive_free_software_licence) [MIT License](http://creativecommons.org/licenses/MIT/) |
|||
<br/>Copyright © 2013+ [Bevry Pty Ltd](http://bevry.me) |
|||
<br/>Copyright © 2011-2012 [Benjamin Arthur Lupton](http://balupton.com) |
@ -0,0 +1,57 @@ |
|||
// Generated by CoffeeScript 1.6.2
|
|||
var ambi, typeChecker, |
|||
__slice = [].slice; |
|||
|
|||
typeChecker = require('typechecker'); |
|||
|
|||
ambi = function() { |
|||
var args, callback, caughtError, err, fireMethod, introspectMethod, method, result; |
|||
|
|||
method = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; |
|||
callback = args[args.length - 1]; |
|||
result = null; |
|||
err = null; |
|||
if (typeChecker.isArray(method)) { |
|||
fireMethod = method[0], introspectMethod = method[1]; |
|||
} else { |
|||
fireMethod = introspectMethod = method; |
|||
} |
|||
if (introspectMethod.length === args.length) { |
|||
try { |
|||
result = fireMethod.apply(null, args); |
|||
if (typeChecker.isError(result)) { |
|||
err = result; |
|||
} |
|||
} catch (_error) { |
|||
caughtError = _error; |
|||
err = caughtError; |
|||
} |
|||
if (err) { |
|||
if (typeof callback === "function") { |
|||
callback(err); |
|||
} |
|||
} |
|||
} else { |
|||
try { |
|||
result = fireMethod.apply(null, args); |
|||
if (typeChecker.isError(result)) { |
|||
err = result; |
|||
} |
|||
} catch (_error) { |
|||
caughtError = _error; |
|||
err = caughtError; |
|||
} |
|||
if (err) { |
|||
if (typeof callback === "function") { |
|||
callback(err); |
|||
} |
|||
} else { |
|||
if (typeof callback === "function") { |
|||
callback(null, result); |
|||
} |
|||
} |
|||
} |
|||
return err || result; |
|||
}; |
|||
|
|||
module.exports = ambi; |
@ -0,0 +1,66 @@ |
|||
{ |
|||
"name": "ambi", |
|||
"version": "2.0.0", |
|||
"description": "Execute a function ambidextrously (normalizes the differences between synchronous and asynchronous functions). Useful for treating synchronous functions as asynchronous functions (like supporting both synchronous and asynchronous event definitions automatically).", |
|||
"homepage": "https://github.com/bevry/ambi", |
|||
"keywords": [ |
|||
"sync", |
|||
"async", |
|||
"fire", |
|||
"exec", |
|||
"execute", |
|||
"ambidextrous" |
|||
], |
|||
"author": { |
|||
"name": "Bevry Pty Ltd", |
|||
"email": "us@bevry.me", |
|||
"url": "http://bevry.me" |
|||
}, |
|||
"maintainers": [ |
|||
{ |
|||
"name": "Benjamin Lupton", |
|||
"email": "b@lupton.cc", |
|||
"url": "https://github.com/balupton" |
|||
} |
|||
], |
|||
"contributors": [ |
|||
{ |
|||
"name": "Benjamin Lupton", |
|||
"email": "b@lupton.cc", |
|||
"url": "https://github.com/balupton" |
|||
} |
|||
], |
|||
"bugs": { |
|||
"url": "https://github.com/bevry/ambi/issues" |
|||
}, |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "http://github.com/bevry/ambi.git" |
|||
}, |
|||
"engines": { |
|||
"node": ">=0.4" |
|||
}, |
|||
"dependencies": { |
|||
"typechecker": "~2.0.1" |
|||
}, |
|||
"devDependencies": { |
|||
"coffee-script": "~1.6.2", |
|||
"joe": "~1.1.2", |
|||
"chai": "~1.5.0" |
|||
}, |
|||
"directories": { |
|||
"lib": "./out/lib" |
|||
}, |
|||
"scripts": { |
|||
"test": "node ./out/test/ambi-test.js" |
|||
}, |
|||
"main": "./out/lib/ambi.js", |
|||
"readme": "# Ambi [![Build Status](https://secure.travis-ci.org/bevry/ambi.png?branch=master)](http://travis-ci.org/bevry/ambi)\nExecute a function ambidextrously (normalizes the differences between synchronous and asynchronous functions).\nUseful for treating synchronous functions as asynchronous functions (like supporting both synchronous and asynchronous event definitions automatically).\n\n\n\n## Install\n\n### Backend\n\n1. [Install Node.js](http://bevry.me/node/install)\n2. `npm install --save ambi`\n\n### Frontend\n\n1. [See Browserify](http://browserify.org)\n\n\n\n## Usage\n\n``` javascript\n// Import\nvar ambi = require('ambi')\nvar result\n\n// Sample methods\nvar syncMethod = function(x,y){\n\treturn x*y\n}\nvar asyncMethod = function(x,y,next){\n\treturn setTimeout(function(){\n\t\tnext(null,x*y)\n\t},0)\n}\n\n// Call the synchronous function asynchronously\nresult = ambi(syncMethod, 5, 2, function(err,result){ // ambi adds support for this asynchronous callback automatically\n\tconsole.log(err, result) // null, 10\n})\nconsole.log(result) // 10 - just like normal\n\n// Call the asynchronous function asynchronously\nresult = ambi(asyncMethod, 5, 2, function(err,result){ // ambi doesn't do anything special here\n\tconsole.log(err, result) // null, 10\n})\nconsole.log(result) // setTimeout - just like normal\n```\n\n\n\n## Process\n\n- Ambi accepts the arguments `(method, args...)`\n\t- `method` is the function to execute\n\t- `args...` is the arguments to send to the method\n\t\t- the last argument is expected to be the completion callback\n\t\t- the completion callback is optional, but if defined, is expected to have the signature of `(err, results...)`\n- If the method has the same amount of arguments as those ambi received, then we assume it is an asynchronous method and let it handle calling of the completion callback itself\n- If the method does not have the same amount of arguments as those ambi received, then we assume it is a synchronous method and we'll call the completion callback ourselves\n\t- If the synchronous method throws an error or returns an error, we'll try to call the completion callback with a single `err` argument\n\t- If the synchronous method executes without error, we'll try to call the completion callback with a `err` argument equal to null, and a `result` argument equal to the returned result of the synchronous method\n- Ambi can also introspect a different method than the one it fires, by passing `[methodToFire, methodToIntrospect]` as the `method` argument\n\n\n\n## History\nYou can discover the history inside the [History.md](https://github.com/bevry/ambi/blob/master/History.md#files) file\n\n\n\n## License\nLicensed under the incredibly [permissive](http://en.wikipedia.org/wiki/Permissive_free_software_licence) [MIT License](http://creativecommons.org/licenses/MIT/)\n<br/>Copyright © 2013+ [Bevry Pty Ltd](http://bevry.me)\n<br/>Copyright © 2011-2012 [Benjamin Arthur Lupton](http://balupton.com)\n", |
|||
"readmeFilename": "README.md", |
|||
"_id": "ambi@2.0.0", |
|||
"_from": "ambi@~2.0.0", |
|||
"dist": { |
|||
"shasum": "ffa645cfb3787233268519cadc8054538e53d228" |
|||
}, |
|||
"_resolved": "https://registry.npmjs.org/ambi/-/ambi-2.0.0.tgz" |
|||
} |
@ -0,0 +1,13 @@ |
|||
#ignore these files |
|||
*.swp |
|||
*~ |
|||
*.lock |
|||
*.DS_Store |
|||
node_modules |
|||
npm-debug.log |
|||
*.out |
|||
*.o |
|||
*.tmp |
|||
|
|||
|
|||
|
@ -0,0 +1,212 @@ |
|||
# EventEmitter2 |
|||
|
|||
EventEmitter2 is a an implementation of the EventEmitter found in Node.js |
|||
|
|||
## Features |
|||
|
|||
- Namespaces/Wildcards. |
|||
- Times To Listen (TTL), extends the `once` concept with `many`. |
|||
- Browser environment compatibility. |
|||
- Demonstrates good performance in benchmarks |
|||
|
|||
``` |
|||
EventEmitterHeatUp x 3,728,965 ops/sec \302\2610.68% (60 runs sampled) |
|||
EventEmitter x 2,822,904 ops/sec \302\2610.74% (63 runs sampled) |
|||
EventEmitter2 x 7,251,227 ops/sec \302\2610.55% (58 runs sampled) |
|||
EventEmitter2 (wild) x 3,220,268 ops/sec \302\2610.44% (65 runs sampled) |
|||
Fastest is EventEmitter2 |
|||
``` |
|||
|
|||
## Differences (Non breaking, compatible with existing EventEmitter) |
|||
|
|||
- The constructor takes a configuration object. |
|||
|
|||
```javascript |
|||
var EventEmitter2 = require('eventemitter2').EventEmitter2; |
|||
var server = new EventEmitter2({ |
|||
wildcard: true, // should the event emitter use wildcards. |
|||
delimiter: '::', // the delimiter used to segment namespaces, defaults to `.`. |
|||
newListener: false, // if you want to emit the newListener event set to true. |
|||
maxListeners: 20, // the max number of listeners that can be assigned to an event, defaults to 10. |
|||
}); |
|||
``` |
|||
|
|||
- Getting the actual event that fired. |
|||
|
|||
```javascript |
|||
server.on('foo.*', function(value1, value2) { |
|||
console.log(this.event, value1, value2); |
|||
}); |
|||
``` |
|||
|
|||
- Fire an event N times and then remove it, an extension of the `once` concept. |
|||
|
|||
```javascript |
|||
server.many('foo', 4, function() { |
|||
console.log('hello'); |
|||
}); |
|||
``` |
|||
|
|||
- Pass in a namespaced event as an array rather than a delimited string. |
|||
|
|||
```javascript |
|||
server.many(['foo', 'bar', 'bazz'], function() { |
|||
console.log('hello'); |
|||
}); |
|||
``` |
|||
|
|||
|
|||
## API |
|||
|
|||
When an `EventEmitter` instance experiences an error, the typical action is |
|||
to emit an `error` event. Error events are treated as a special case. |
|||
If there is no listener for it, then the default action is to print a stack |
|||
trace and exit the program. |
|||
|
|||
All EventEmitters emit the event `newListener` when new listeners are |
|||
added. |
|||
|
|||
|
|||
**Namespaces** with **Wildcards** |
|||
To use namespaces/wildcards, pass the `wildcard` option into the EventEmitter constructor. |
|||
When namespaces/wildcards are enabled, events can either be strings (`foo.bar`) separated |
|||
by a delimiter or arrays (`['foo', 'bar']`). The delimiter is also configurable as a |
|||
constructor option. |
|||
|
|||
An event name passed to any event emitter method can contain a wild card (the `*` character). |
|||
If the event name is a string, a wildcard may appear as `foo.*`. If the event name is an array, |
|||
the wildcard may appear as `['foo', '*']`. |
|||
|
|||
If either of the above described events were passed to the `on` method, subsequent emits such |
|||
as the following would be observed... |
|||
|
|||
```javascript |
|||
emitter.emit('foo.bazz'); |
|||
emitter.emit(['foo', 'bar']); |
|||
``` |
|||
|
|||
|
|||
#### emitter.addListener(event, listener) |
|||
#### emitter.on(event, listener) |
|||
|
|||
Adds a listener to the end of the listeners array for the specified event. |
|||
|
|||
```javascript |
|||
server.on('data', function(value1, value2, value3 /* accepts any number of expected values... */) { |
|||
console.log('The event was raised!'); |
|||
}); |
|||
``` |
|||
|
|||
```javascript |
|||
server.on('data', function(value) { |
|||
console.log('The event was raised!'); |
|||
}); |
|||
``` |
|||
|
|||
#### emitter.onAny(listener) |
|||
|
|||
Adds a listener that will be fired when any event is emitted. |
|||
|
|||
```javascript |
|||
server.onAny(function(value) { |
|||
console.log('All events trigger this.'); |
|||
}); |
|||
``` |
|||
|
|||
#### emitter.offAny(listener) |
|||
|
|||
Removes the listener that will be fired when any event is emitted. |
|||
|
|||
```javascript |
|||
server.offAny(function(value) { |
|||
console.log('The event was raised!'); |
|||
}); |
|||
``` |
|||
|
|||
#### emitter.once(event, listener) |
|||
|
|||
Adds a **one time** listener for the event. The listener is invoked only the first time the event is fired, after which it is removed. |
|||
|
|||
```javascript |
|||
server.once('get', function (value) { |
|||
console.log('Ah, we have our first value!'); |
|||
}); |
|||
``` |
|||
|
|||
#### emitter.many(event, timesToListen, listener) |
|||
|
|||
Adds a listener that will execute **n times** for the event before being removed. The listener is invoked only the first time the event is fired, after which it is removed. |
|||
|
|||
```javascript |
|||
server.many('get', 4, function (value) { |
|||
console.log('This event will be listened to exactly four times.'); |
|||
}); |
|||
``` |
|||
|
|||
|
|||
#### emitter.removeListener(event, listener) |
|||
#### emitter.off(event, listener) |
|||
|
|||
Remove a listener from the listener array for the specified event. **Caution**: changes array indices in the listener array behind the listener. |
|||
|
|||
```javascript |
|||
var callback = function(value) { |
|||
console.log('someone connected!'); |
|||
}; |
|||
server.on('get', callback); |
|||
// ... |
|||
server.removeListener('get', callback); |
|||
``` |
|||
|
|||
|
|||
#### emitter.removeAllListeners([event]) |
|||
|
|||
Removes all listeners, or those of the specified event. |
|||
|
|||
|
|||
#### emitter.setMaxListeners(n) |
|||
|
|||
By default EventEmitters will print a warning if more than 10 listeners are added to it. This is a useful default which helps finding memory leaks. Obviously not all Emitters should be limited to 10. This function allows that to be increased. Set to zero for unlimited. |
|||
|
|||
|
|||
#### emitter.listeners(event) |
|||
|
|||
Returns an array of listeners for the specified event. This array can be manipulated, e.g. to remove listeners. |
|||
|
|||
```javascript |
|||
server.on('get', function(value) { |
|||
console.log('someone connected!'); |
|||
}); |
|||
console.log(console.log(server.listeners('get')); // [ [Function] ] |
|||
``` |
|||
|
|||
#### emitter.listenersAny() |
|||
|
|||
Returns an array of listeners that are listening for any event that is specified. This array can be manipulated, e.g. to remove listeners. |
|||
|
|||
```javascript |
|||
server.onAny(function(value) { |
|||
console.log('someone connected!'); |
|||
}); |
|||
console.log(console.log(server.listenersAny()[0]); // [ [Function] ] // someone connected! |
|||
``` |
|||
|
|||
#### emitter.emit(event, [arg1], [arg2], [...]) |
|||
|
|||
Execute each of the listeners that may be listening for the specified event name in order with the list of arguments. |
|||
|
|||
## Test coverage |
|||
|
|||
There is a test suite that tries to cover each use case, it can be found <a href="https://github.com/hij1nx/EventEmitter2/tree/master/test">here</a>. |
|||
|
|||
## Licence |
|||
|
|||
(The MIT License) |
|||
|
|||
Copyright (c) 2011 hij1nx <http://www.twitter.com/hij1nx> |
|||
|
|||
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 @@ |
|||
module.exports = require('./lib/eventemitter2'); |
@ -0,0 +1,560 @@ |
|||
;!function(exports, undefined) { |
|||
|
|||
var isArray = Array.isArray ? Array.isArray : function _isArray(obj) { |
|||
return Object.prototype.toString.call(obj) === "[object Array]"; |
|||
}; |
|||
var defaultMaxListeners = 10; |
|||
|
|||
function init() { |
|||
this._events = {}; |
|||
if (this._conf) { |
|||
configure.call(this, this._conf); |
|||
} |
|||
} |
|||
|
|||
function configure(conf) { |
|||
if (conf) { |
|||
|
|||
this._conf = conf; |
|||
|
|||
conf.delimiter && (this.delimiter = conf.delimiter); |
|||
conf.maxListeners && (this._events.maxListeners = conf.maxListeners); |
|||
conf.wildcard && (this.wildcard = conf.wildcard); |
|||
conf.newListener && (this.newListener = conf.newListener); |
|||
|
|||
if (this.wildcard) { |
|||
this.listenerTree = {}; |
|||
} |
|||
} |
|||
} |
|||
|
|||
function EventEmitter(conf) { |
|||
this._events = {}; |
|||
this.newListener = false; |
|||
configure.call(this, conf); |
|||
} |
|||
|
|||
//
|
|||
// Attention, function return type now is array, always !
|
|||
// It has zero elements if no any matches found and one or more
|
|||
// elements (leafs) if there are matches
|
|||
//
|
|||
function searchListenerTree(handlers, type, tree, i) { |
|||
if (!tree) { |
|||
return []; |
|||
} |
|||
var listeners=[], leaf, len, branch, xTree, xxTree, isolatedBranch, endReached, |
|||
typeLength = type.length, currentType = type[i], nextType = type[i+1]; |
|||
if (i === typeLength && tree._listeners) { |
|||
//
|
|||
// If at the end of the event(s) list and the tree has listeners
|
|||
// invoke those listeners.
|
|||
//
|
|||
if (typeof tree._listeners === 'function') { |
|||
handlers && handlers.push(tree._listeners); |
|||
return [tree]; |
|||
} else { |
|||
for (leaf = 0, len = tree._listeners.length; leaf < len; leaf++) { |
|||
handlers && handlers.push(tree._listeners[leaf]); |
|||
} |
|||
return [tree]; |
|||
} |
|||
} |
|||
|
|||
if ((currentType === '*' || currentType === '**') || tree[currentType]) { |
|||
//
|
|||
// If the event emitted is '*' at this part
|
|||
// or there is a concrete match at this patch
|
|||
//
|
|||
if (currentType === '*') { |
|||
for (branch in tree) { |
|||
if (branch !== '_listeners' && tree.hasOwnProperty(branch)) { |
|||
listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+1)); |
|||
} |
|||
} |
|||
return listeners; |
|||
} else if(currentType === '**') { |
|||
endReached = (i+1 === typeLength || (i+2 === typeLength && nextType === '*')); |
|||
if(endReached && tree._listeners) { |
|||
// The next element has a _listeners, add it to the handlers.
|
|||
listeners = listeners.concat(searchListenerTree(handlers, type, tree, typeLength)); |
|||
} |
|||
|
|||
for (branch in tree) { |
|||
if (branch !== '_listeners' && tree.hasOwnProperty(branch)) { |
|||
if(branch === '*' || branch === '**') { |
|||
if(tree[branch]._listeners && !endReached) { |
|||
listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], typeLength)); |
|||
} |
|||
listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i)); |
|||
} else if(branch === nextType) { |
|||
listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+2)); |
|||
} else { |
|||
// No match on this one, shift into the tree but not in the type array.
|
|||
listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i)); |
|||
} |
|||
} |
|||
} |
|||
return listeners; |
|||
} |
|||
|
|||
listeners = listeners.concat(searchListenerTree(handlers, type, tree[currentType], i+1)); |
|||
} |
|||
|
|||
xTree = tree['*']; |
|||
if (xTree) { |
|||
//
|
|||
// If the listener tree will allow any match for this part,
|
|||
// then recursively explore all branches of the tree
|
|||
//
|
|||
searchListenerTree(handlers, type, xTree, i+1); |
|||
} |
|||
|
|||
xxTree = tree['**']; |
|||
if(xxTree) { |
|||
if(i < typeLength) { |
|||
if(xxTree._listeners) { |
|||
// If we have a listener on a '**', it will catch all, so add its handler.
|
|||
searchListenerTree(handlers, type, xxTree, typeLength); |
|||
} |
|||
|
|||
// Build arrays of matching next branches and others.
|
|||
for(branch in xxTree) { |
|||
if(branch !== '_listeners' && xxTree.hasOwnProperty(branch)) { |
|||
if(branch === nextType) { |
|||
// We know the next element will match, so jump twice.
|
|||
searchListenerTree(handlers, type, xxTree[branch], i+2); |
|||
} else if(branch === currentType) { |
|||
// Current node matches, move into the tree.
|
|||
searchListenerTree(handlers, type, xxTree[branch], i+1); |
|||
} else { |
|||
isolatedBranch = {}; |
|||
isolatedBranch[branch] = xxTree[branch]; |
|||
searchListenerTree(handlers, type, { '**': isolatedBranch }, i+1); |
|||
} |
|||
} |
|||
} |
|||
} else if(xxTree._listeners) { |
|||
// We have reached the end and still on a '**'
|
|||
searchListenerTree(handlers, type, xxTree, typeLength); |
|||
} else if(xxTree['*'] && xxTree['*']._listeners) { |
|||
searchListenerTree(handlers, type, xxTree['*'], typeLength); |
|||
} |
|||
} |
|||
|
|||
return listeners; |
|||
} |
|||
|
|||
function growListenerTree(type, listener) { |
|||
|
|||
type = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); |
|||
|
|||
//
|
|||
// Looks for two consecutive '**', if so, don't add the event at all.
|
|||
//
|
|||
for(var i = 0, len = type.length; i+1 < len; i++) { |
|||
if(type[i] === '**' && type[i+1] === '**') { |
|||
return; |
|||
} |
|||
} |
|||
|
|||
var tree = this.listenerTree; |
|||
var name = type.shift(); |
|||
|
|||
while (name) { |
|||
|
|||
if (!tree[name]) { |
|||
tree[name] = {}; |
|||
} |
|||
|
|||
tree = tree[name]; |
|||
|
|||
if (type.length === 0) { |
|||
|
|||
if (!tree._listeners) { |
|||
tree._listeners = listener; |
|||
} |
|||
else if(typeof tree._listeners === 'function') { |
|||
tree._listeners = [tree._listeners, listener]; |
|||
} |
|||
else if (isArray(tree._listeners)) { |
|||
|
|||
tree._listeners.push(listener); |
|||
|
|||
if (!tree._listeners.warned) { |
|||
|
|||
var m = defaultMaxListeners; |
|||
|
|||
if (typeof this._events.maxListeners !== 'undefined') { |
|||
m = this._events.maxListeners; |
|||
} |
|||
|
|||
if (m > 0 && tree._listeners.length > m) { |
|||
|
|||
tree._listeners.warned = true; |
|||
console.error('(node) warning: possible EventEmitter memory ' + |
|||
'leak detected. %d listeners added. ' + |
|||
'Use emitter.setMaxListeners() to increase limit.', |
|||
tree._listeners.length); |
|||
console.trace(); |
|||
} |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
name = type.shift(); |
|||
} |
|||
return true; |
|||
}; |
|||
|
|||
// By default EventEmitters will print a warning if more than
|
|||
// 10 listeners are added to it. This is a useful default which
|
|||
// helps finding memory leaks.
|
|||
//
|
|||
// Obviously not all Emitters should be limited to 10. This function allows
|
|||
// that to be increased. Set to zero for unlimited.
|
|||
|
|||
EventEmitter.prototype.delimiter = '.'; |
|||
|
|||
EventEmitter.prototype.setMaxListeners = function(n) { |
|||
this._events || init.call(this); |
|||
this._events.maxListeners = n; |
|||
if (!this._conf) this._conf = {}; |
|||
this._conf.maxListeners = n; |
|||
}; |
|||
|
|||
EventEmitter.prototype.event = ''; |
|||
|
|||
EventEmitter.prototype.once = function(event, fn) { |
|||
this.many(event, 1, fn); |
|||
return this; |
|||
}; |
|||
|
|||
EventEmitter.prototype.many = function(event, ttl, fn) { |
|||
var self = this; |
|||
|
|||
if (typeof fn !== 'function') { |
|||
throw new Error('many only accepts instances of Function'); |
|||
} |
|||
|
|||
function listener() { |
|||
if (--ttl === 0) { |
|||
self.off(event, listener); |
|||
} |
|||
fn.apply(this, arguments); |
|||
}; |
|||
|
|||
listener._origin = fn; |
|||
|
|||
this.on(event, listener); |
|||
|
|||
return self; |
|||
}; |
|||
|
|||
EventEmitter.prototype.emit = function() { |
|||
|
|||
this._events || init.call(this); |
|||
|
|||
var type = arguments[0]; |
|||
|
|||
if (type === 'newListener' && !this.newListener) { |
|||
if (!this._events.newListener) { return false; } |
|||
} |
|||
|
|||
// Loop through the *_all* functions and invoke them.
|
|||
if (this._all) { |
|||
var l = arguments.length; |
|||
var args = new Array(l - 1); |
|||
for (var i = 1; i < l; i++) args[i - 1] = arguments[i]; |
|||
for (i = 0, l = this._all.length; i < l; i++) { |
|||
this.event = type; |
|||
this._all[i].apply(this, args); |
|||
} |
|||
} |
|||
|
|||
// If there is no 'error' event listener then throw.
|
|||
if (type === 'error') { |
|||
|
|||
if (!this._all && |
|||
!this._events.error && |
|||
!(this.wildcard && this.listenerTree.error)) { |
|||
|
|||
if (arguments[1] instanceof Error) { |
|||
throw arguments[1]; // Unhandled 'error' event
|
|||
} else { |
|||
throw new Error("Uncaught, unspecified 'error' event."); |
|||
} |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
var handler; |
|||
|
|||
if(this.wildcard) { |
|||
handler = []; |
|||
var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); |
|||
searchListenerTree.call(this, handler, ns, this.listenerTree, 0); |
|||
} |
|||
else { |
|||
handler = this._events[type]; |
|||
} |
|||
|
|||
if (typeof handler === 'function') { |
|||
this.event = type; |
|||
if (arguments.length === 1) { |
|||
handler.call(this); |
|||
} |
|||
else if (arguments.length > 1) |
|||
switch (arguments.length) { |
|||
case 2: |
|||
handler.call(this, arguments[1]); |
|||
break; |
|||
case 3: |
|||
handler.call(this, arguments[1], arguments[2]); |
|||
break; |
|||
// slower
|
|||
default: |
|||
var l = arguments.length; |
|||
var args = new Array(l - 1); |
|||
for (var i = 1; i < l; i++) args[i - 1] = arguments[i]; |
|||
handler.apply(this, args); |
|||
} |
|||
return true; |
|||
} |
|||
else if (handler) { |
|||
var l = arguments.length; |
|||
var args = new Array(l - 1); |
|||
for (var i = 1; i < l; i++) args[i - 1] = arguments[i]; |
|||
|
|||
var listeners = handler.slice(); |
|||
for (var i = 0, l = listeners.length; i < l; i++) { |
|||
this.event = type; |
|||
listeners[i].apply(this, args); |
|||
} |
|||
return (listeners.length > 0) || this._all; |
|||
} |
|||
else { |
|||
return this._all; |
|||
} |
|||
|
|||
}; |
|||
|
|||
EventEmitter.prototype.on = function(type, listener) { |
|||
|
|||
if (typeof type === 'function') { |
|||
this.onAny(type); |
|||
return this; |
|||
} |
|||
|
|||
if (typeof listener !== 'function') { |
|||
throw new Error('on only accepts instances of Function'); |
|||
} |
|||
this._events || init.call(this); |
|||
|
|||
// To avoid recursion in the case that type == "newListeners"! Before
|
|||
// adding it to the listeners, first emit "newListeners".
|
|||
this.emit('newListener', type, listener); |
|||
|
|||
if(this.wildcard) { |
|||
growListenerTree.call(this, type, listener); |
|||
return this; |
|||
} |
|||
|
|||
if (!this._events[type]) { |
|||
// Optimize the case of one listener. Don't need the extra array object.
|
|||
this._events[type] = listener; |
|||
} |
|||
else if(typeof this._events[type] === 'function') { |
|||
// Adding the second element, need to change to array.
|
|||
this._events[type] = [this._events[type], listener]; |
|||
} |
|||
else if (isArray(this._events[type])) { |
|||
// If we've already got an array, just append.
|
|||
this._events[type].push(listener); |
|||
|
|||
// Check for listener leak
|
|||
if (!this._events[type].warned) { |
|||
|
|||
var m = defaultMaxListeners; |
|||
|
|||
if (typeof this._events.maxListeners !== 'undefined') { |
|||
m = this._events.maxListeners; |
|||
} |
|||
|
|||
if (m > 0 && this._events[type].length > m) { |
|||
|
|||
this._events[type].warned = true; |
|||
console.error('(node) warning: possible EventEmitter memory ' + |
|||
'leak detected. %d listeners added. ' + |
|||
'Use emitter.setMaxListeners() to increase limit.', |
|||
this._events[type].length); |
|||
console.trace(); |
|||
} |
|||
} |
|||
} |
|||
return this; |
|||
}; |
|||
|
|||
EventEmitter.prototype.onAny = function(fn) { |
|||
|
|||
if(!this._all) { |
|||
this._all = []; |
|||
} |
|||
|
|||
if (typeof fn !== 'function') { |
|||
throw new Error('onAny only accepts instances of Function'); |
|||
} |
|||
|
|||
// Add the function to the event listener collection.
|
|||
this._all.push(fn); |
|||
return this; |
|||
}; |
|||
|
|||
EventEmitter.prototype.addListener = EventEmitter.prototype.on; |
|||
|
|||
EventEmitter.prototype.off = function(type, listener) { |
|||
if (typeof listener !== 'function') { |
|||
throw new Error('removeListener only takes instances of Function'); |
|||
} |
|||
|
|||
var handlers,leafs=[]; |
|||
|
|||
if(this.wildcard) { |
|||
var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); |
|||
leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0); |
|||
} |
|||
else { |
|||
// does not use listeners(), so no side effect of creating _events[type]
|
|||
if (!this._events[type]) return this; |
|||
handlers = this._events[type]; |
|||
leafs.push({_listeners:handlers}); |
|||
} |
|||
|
|||
for (var iLeaf=0; iLeaf<leafs.length; iLeaf++) { |
|||
var leaf = leafs[iLeaf]; |
|||
handlers = leaf._listeners; |
|||
if (isArray(handlers)) { |
|||
|
|||
var position = -1; |
|||
|
|||
for (var i = 0, length = handlers.length; i < length; i++) { |
|||
if (handlers[i] === listener || |
|||
(handlers[i].listener && handlers[i].listener === listener) || |
|||
(handlers[i]._origin && handlers[i]._origin === listener)) { |
|||
position = i; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (position < 0) { |
|||
return this; |
|||
} |
|||
|
|||
if(this.wildcard) { |
|||
leaf._listeners.splice(position, 1) |
|||
} |
|||
else { |
|||
this._events[type].splice(position, 1); |
|||
} |
|||
|
|||
if (handlers.length === 0) { |
|||
if(this.wildcard) { |
|||
delete leaf._listeners; |
|||
} |
|||
else { |
|||
delete this._events[type]; |
|||
} |
|||
} |
|||
} |
|||
else if (handlers === listener || |
|||
(handlers.listener && handlers.listener === listener) || |
|||
(handlers._origin && handlers._origin === listener)) { |
|||
if(this.wildcard) { |
|||
delete leaf._listeners; |
|||
} |
|||
else { |
|||
delete this._events[type]; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return this; |
|||
}; |
|||
|
|||
EventEmitter.prototype.offAny = function(fn) { |
|||
var i = 0, l = 0, fns; |
|||
if (fn && this._all && this._all.length > 0) { |
|||
fns = this._all; |
|||
for(i = 0, l = fns.length; i < l; i++) { |
|||
if(fn === fns[i]) { |
|||
fns.splice(i, 1); |
|||
return this; |
|||
} |
|||
} |
|||
} else { |
|||
this._all = []; |
|||
} |
|||
return this; |
|||
}; |
|||
|
|||
EventEmitter.prototype.removeListener = EventEmitter.prototype.off; |
|||
|
|||
EventEmitter.prototype.removeAllListeners = function(type) { |
|||
if (arguments.length === 0) { |
|||
!this._events || init.call(this); |
|||
return this; |
|||
} |
|||
|
|||
if(this.wildcard) { |
|||
var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); |
|||
var leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0); |
|||
|
|||
for (var iLeaf=0; iLeaf<leafs.length; iLeaf++) { |
|||
var leaf = leafs[iLeaf]; |
|||
leaf._listeners = null; |
|||
} |
|||
} |
|||
else { |
|||
if (!this._events[type]) return this; |
|||
this._events[type] = null; |
|||
} |
|||
return this; |
|||
}; |
|||
|
|||
EventEmitter.prototype.listeners = function(type) { |
|||
if(this.wildcard) { |
|||
var handlers = []; |
|||
var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); |
|||
searchListenerTree.call(this, handlers, ns, this.listenerTree, 0); |
|||
return handlers; |
|||
} |
|||
|
|||
this._events || init.call(this); |
|||
|
|||
if (!this._events[type]) this._events[type] = []; |
|||
if (!isArray(this._events[type])) { |
|||
this._events[type] = [this._events[type]]; |
|||
} |
|||
return this._events[type]; |
|||
}; |
|||
|
|||
EventEmitter.prototype.listenersAny = function() { |
|||
|
|||
if(this._all) { |
|||
return this._all; |
|||
} |
|||
else { |
|||
return []; |
|||
} |
|||
|
|||
}; |
|||
|
|||
if (typeof define === 'function' && define.amd) { |
|||
define(function() { |
|||
return EventEmitter; |
|||
}); |
|||
} else { |
|||
exports.EventEmitter2 = EventEmitter; |
|||
} |
|||
|
|||
}(typeof process !== 'undefined' && typeof process.title !== 'undefined' && typeof exports !== 'undefined' ? exports : window); |
File diff suppressed because one or more lines are too long
@ -0,0 +1,122 @@ |
|||
// Copyright Joyent, Inc. and other Node contributors.
|
|||
//
|
|||
// 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.
|
|||
|
|||
var path = require('path'); |
|||
var assert = require('assert'); |
|||
|
|||
exports.testDir = path.dirname(__filename); |
|||
exports.fixturesDir = path.join(exports.testDir, 'fixtures'); |
|||
exports.libDir = path.join(exports.testDir, '../lib'); |
|||
exports.tmpDir = path.join(exports.testDir, 'tmp'); |
|||
exports.PORT = 12346; |
|||
|
|||
if (process.platform == 'win32') { |
|||
exports.PIPE = '\\\\.\\pipe\\libuv-test'; |
|||
} else { |
|||
exports.PIPE = exports.tmpDir + '/test.sock'; |
|||
} |
|||
|
|||
var util = require('util'); |
|||
for (var i in util) exports[i] = util[i]; |
|||
//for (var i in exports) global[i] = exports[i];
|
|||
|
|||
function protoCtrChain(o) { |
|||
var result = []; |
|||
for (; o; o = o.__proto__) { result.push(o.constructor); } |
|||
return result.join(); |
|||
} |
|||
|
|||
exports.indirectInstanceOf = function(obj, cls) { |
|||
if (obj instanceof cls) { return true; } |
|||
var clsChain = protoCtrChain(cls.prototype); |
|||
var objChain = protoCtrChain(obj); |
|||
return objChain.slice(-clsChain.length) === clsChain; |
|||
}; |
|||
|
|||
|
|||
// Turn this off if the test should not check for global leaks.
|
|||
exports.globalCheck = true; |
|||
|
|||
process.on('exit', function() { |
|||
if (!exports.globalCheck) return; |
|||
var knownGlobals = [setTimeout, |
|||
setInterval, |
|||
clearTimeout, |
|||
clearInterval, |
|||
console, |
|||
Buffer, |
|||
process, |
|||
global.ArrayBuffer!==undefined?ArrayBuffer:null, |
|||
global.Int8Array!==undefined?Int8Array:null, |
|||
global.Uint8Array!==undefined?Uint8Array:null, |
|||
global.Int16Array!==undefined?Int16Array:null, |
|||
global.Uint16Array!==undefined?Uint16Array:null, |
|||
global.Int32Array!==undefined?Int32Array:null, |
|||
global.Uint32Array!==undefined?Uint32Array:null, |
|||
global.Float32Array!==undefined?Float32Array:null, |
|||
global.Float64Array!==undefined?Float64Array:null, |
|||
global.DataView!==undefined?DataView:null, |
|||
global.Uint8ClampedArray!==undefined?Uint8ClampedArray:null, |
|||
AssertionError, |
|||
global |
|||
]; |
|||
|
|||
if (global.errno) { |
|||
knownGlobals.push(errno); |
|||
} |
|||
|
|||
if (global.gc) { |
|||
knownGlobals.push(gc); |
|||
} |
|||
|
|||
if (global.DTRACE_HTTP_SERVER_RESPONSE) { |
|||
knownGlobals.push(DTRACE_HTTP_SERVER_RESPONSE); |
|||
knownGlobals.push(DTRACE_HTTP_SERVER_REQUEST); |
|||
knownGlobals.push(DTRACE_HTTP_CLIENT_RESPONSE); |
|||
knownGlobals.push(DTRACE_HTTP_CLIENT_REQUEST); |
|||
knownGlobals.push(DTRACE_NET_STREAM_END); |
|||
knownGlobals.push(DTRACE_NET_SERVER_CONNECTION); |
|||
knownGlobals.push(DTRACE_NET_SOCKET_READ); |
|||
knownGlobals.push(DTRACE_NET_SOCKET_WRITE); |
|||
} |
|||
|
|||
for (var x in global) { |
|||
var found = false; |
|||
|
|||
for (var y in knownGlobals) { |
|||
if (global[x] === knownGlobals[y]) { |
|||
found = true; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (!found) { |
|||
console.error('Unknown global: %s', x); |
|||
assert.ok(false, 'Unknown global founded'); |
|||
} |
|||
} |
|||
}); |
|||
|
|||
|
|||
// This function allows one two run an HTTP test agaist both HTTPS and
|
|||
// normal HTTP modules. This ensures they fit the same API.
|
|||
exports.httpTest = function httpTest(cb) { |
|||
}; |
@ -0,0 +1,53 @@ |
|||
|
|||
var Benchmark = require('benchmark'); |
|||
var suite = new Benchmark.Suite(); |
|||
|
|||
var EventEmitter = require('events').EventEmitter; |
|||
var emitter = new EventEmitter; |
|||
|
|||
var EventEmitter2 = require('../../lib/eventemitter2').EventEmitter2; |
|||
var emitter2 = new EventEmitter2; |
|||
|
|||
var EventEmitter3 = require('events').EventEmitter; |
|||
var emitter3 = new EventEmitter3; |
|||
|
|||
suite |
|||
|
|||
.add('EventEmitterHeatUp', function() { |
|||
|
|||
emitter3.on('test3', function () { 1==1; }); |
|||
emitter3.emit('test3'); |
|||
emitter3.removeAllListeners('test3'); |
|||
|
|||
}) |
|||
.add('EventEmitter', function() { |
|||
|
|||
emitter.on('test1', function () { 1==1; }); |
|||
emitter.emit('test1'); |
|||
emitter.removeAllListeners('test1'); |
|||
|
|||
}) |
|||
.add('EventEmitter2', function() { |
|||
|
|||
emitter2.on('test2', function () { 1==1; }); |
|||
emitter2.emit('test2'); |
|||
emitter2.removeAllListeners('test2'); |
|||
|
|||
}) |
|||
|
|||
.add('EventEmitter2 (wild)', function() { |
|||
|
|||
emitter2.on('test2.foo', function () { 1==1; }); |
|||
emitter2.emit('test2.foo'); |
|||
emitter2.removeAllListeners('test2.foo'); |
|||
|
|||
}) |
|||
|
|||
.on('cycle', function(event, bench) { |
|||
console.log(String(bench)); |
|||
}) |
|||
.on('complete', function() { |
|||
console.log('Fastest is ' + this.filter('fastest').pluck('name')); |
|||
}) |
|||
|
|||
.run(true); |
@ -0,0 +1,179 @@ |
|||
|
|||
var simpleEvents = require('nodeunit').testCase; |
|||
var file = '../../lib/eventemitter2'; |
|||
|
|||
if(typeof require !== 'undefined') { |
|||
EventEmitter2 = require(file).EventEmitter2; |
|||
} |
|||
else { |
|||
EventEmitter2 = window.EventEmitter2; |
|||
} |
|||
|
|||
module.exports = simpleEvents({ |
|||
|
|||
'1. Add a single listener on a single event.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ verbose: true }); |
|||
|
|||
emitter.on('test1', function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
test.equal(emitter.listeners('test1').length, 1, 'There are three emitters'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
|
|||
}, |
|||
'2. Add two listeners on a single event.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ verbose: true }); |
|||
|
|||
emitter.on('test1', function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.on('test1', function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
test.equal(emitter.listeners('test1').length, 2, 'There are three emitters'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
|
|||
}, |
|||
'3. Add three listeners on a single event.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ verbose: true }); |
|||
|
|||
emitter.on('test1', function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.on('test1', function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.on('test1', function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
test.equal(emitter.listeners('test1').length, 3, 'There are three emitters'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
|
|||
}, |
|||
'4. Add two listeners to two different events.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ verbose: true }); |
|||
|
|||
emitter.on('test1', function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.on('test1', function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.on('test2', function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.on('test2', function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
test.equal(emitter.listeners('test1').length, 2, 'There are two emitters'); |
|||
test.equal(emitter.listeners('test2').length, 2, 'There are two emitters'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
|
|||
}, |
|||
'5. Never adding any listeners should yield a listeners array with the length of 0.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ verbose: true }); |
|||
|
|||
emitter.on('test1', function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
test.equal(emitter.listeners('test2').length, 0, 'There are no emitters'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
}, |
|||
|
|||
'6. the listener added should be the right listener.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ verbose: true }); |
|||
|
|||
var type = 'somelistenerbar'; |
|||
var f = function () {}; |
|||
|
|||
emitter.on(type, f); |
|||
test.equal(emitter.listeners(type).length, 1, 'There are is one emitters'); |
|||
test.equal(emitter.listeners(type)[0], f, 'The function should be f'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
|
|||
}, |
|||
|
|||
'7. should be able to listen on any event' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ verbose: true }); |
|||
|
|||
var f = function () { |
|||
test.ok(true, 'the event was fired'); |
|||
}; |
|||
|
|||
emitter.onAny(f); |
|||
emitter.emit('test23.ns5.ns5', 'someData'); //1
|
|||
emitter.offAny(f); |
|||
emitter.emit('test21'); //0
|
|||
emitter.onAny(f); |
|||
emitter.onAny(f); |
|||
emitter.emit('test23.ns5.ns5', 'someData'); //3
|
|||
|
|||
test.expect(3); |
|||
test.done(); |
|||
|
|||
}, |
|||
|
|||
'8. should be able to listen on any event (should cause an error)' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ verbose: true }); |
|||
|
|||
var f = function () { |
|||
test.ok(true, 'the event was fired'); |
|||
}; |
|||
emitter.onAny(f); |
|||
|
|||
emitter.emit('error'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
|
|||
}, |
|||
|
|||
'9. onAny alias' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ verbose: true }); |
|||
|
|||
var f = function () { |
|||
test.ok(true, 'the event was fired'); |
|||
}; |
|||
|
|||
emitter.on(f); |
|||
|
|||
emitter.emit('foo'); |
|||
emitter.emit('bar'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
|
|||
} |
|||
}); |
@ -0,0 +1,142 @@ |
|||
|
|||
var simpleEvents = require('nodeunit').testCase; |
|||
var file = '../../lib/eventemitter2'; |
|||
var EventEmitter2; |
|||
|
|||
if(typeof require !== 'undefined') { |
|||
EventEmitter2 = require(file).EventEmitter2; |
|||
} |
|||
else { |
|||
EventEmitter2 = window.EventEmitter2; |
|||
} |
|||
|
|||
module.exports = simpleEvents({ |
|||
|
|||
'1. Add two listeners on a single event and emit the event.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ verbose: true }); |
|||
|
|||
function functionA() { test.ok(true, 'The event was raised'); } |
|||
function functionB() { test.ok(true, 'The event was raised'); } |
|||
|
|||
emitter.on('test2', functionA); |
|||
emitter.on('test2', functionB); |
|||
|
|||
emitter.emit('test2'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
|
|||
}, |
|||
'2. Add two listeners on a single event and emit the event twice.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ verbose: true }); |
|||
|
|||
function functionA() { test.ok(true, 'The event was raised'); } |
|||
function functionB() { test.ok(true, 'The event was raised'); } |
|||
|
|||
emitter.on('test2', functionA); |
|||
emitter.on('test2', functionB); |
|||
|
|||
emitter.emit('test2'); |
|||
emitter.emit('test2'); |
|||
|
|||
test.expect(4); |
|||
test.done(); |
|||
|
|||
}, |
|||
'3. Add two listeners on a single event and emit the event with a parameter.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ verbose: true }); |
|||
|
|||
function functionA(value1) { |
|||
test.ok(true, 'The event was raised'); |
|||
test.equal(typeof value1, 'string', 'The event was raised'); |
|||
} |
|||
|
|||
function functionB(value1) { |
|||
test.ok(true, 'The event was raised'); |
|||
test.equal(typeof value1, 'string', 'The event was raised'); |
|||
} |
|||
|
|||
emitter.on('test2', functionA); |
|||
emitter.on('test2', functionB); |
|||
|
|||
emitter.emit('test2', 'Hello, Node'); |
|||
|
|||
test.expect(4); |
|||
test.done(); |
|||
|
|||
}, |
|||
'4. Add two listeners on an single event and emit the event twice with a parameter.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ verbose: true }); |
|||
|
|||
function functionA(value1) { |
|||
test.ok(true, 'The event was raised'); |
|||
test.equal(typeof value1, 'string', 'The event was raised'); |
|||
} |
|||
|
|||
function functionB(value1) { |
|||
test.ok(true, 'The event was raised'); |
|||
test.equal(typeof value1, 'string', 'The event was raised'); |
|||
} |
|||
|
|||
emitter.on('test2', functionA); |
|||
emitter.on('test2', functionB); |
|||
|
|||
emitter.emit('test2', 'Hello, Node1'); |
|||
emitter.emit('test2', 'Hello, Node2'); |
|||
|
|||
test.expect(8); |
|||
test.done(); |
|||
|
|||
}, |
|||
'5. Add two listeners on an single event and emit the event twice with multiple parameters.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ verbose: true }); |
|||
|
|||
function functionA(value1, value2, value3) { |
|||
test.ok(true, 'The event was raised'); |
|||
test.equal(typeof value1, 'string', 'The value named "value1" is OK'); |
|||
test.equal(typeof value2, 'string', 'The value named "value2" is OK'); |
|||
test.equal(typeof value3, 'string', 'The value named "value3" is OK'); |
|||
} |
|||
|
|||
function functionB(value1, value2, value3) { |
|||
test.ok(true, 'The event was raised'); |
|||
test.equal(typeof value1, 'string', 'The value named "value1" is OK'); |
|||
test.equal(typeof value2, 'string', 'The value named "value2" is OK'); |
|||
test.equal(typeof value3, 'string', 'The value named "value3" is OK'); |
|||
} |
|||
|
|||
emitter.on('test2', functionA); |
|||
emitter.on('test2', functionB); |
|||
|
|||
emitter.emit('test2', 'Hello, Node1', 'Hello, Node2', 'Hello, Node3'); |
|||
emitter.emit('test2', 'Hello, Node1', 'Hello, Node2', 'Hello, Node3'); |
|||
|
|||
test.expect(16); |
|||
test.done(); |
|||
|
|||
}, |
|||
'6. Check return values of emit.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ verbose: true }); |
|||
|
|||
function functionA() { test.ok(true, 'The event was raised'); } |
|||
|
|||
emitter.on('test6', functionA); |
|||
|
|||
test.ok(emitter.emit('test6'), 'emit should return true after calling a listener'); |
|||
test.ok(!emitter.emit('other'), 'emit should return false when no listener was called'); |
|||
|
|||
emitter.onAny(functionA); |
|||
test.ok(emitter.emit('other'), 'emit should return true after calling an onAny() listener'); |
|||
|
|||
test.expect(5); |
|||
test.done(); |
|||
}, |
|||
|
|||
}); |
|||
|
@ -0,0 +1,55 @@ |
|||
var simpleEvents = require('nodeunit').testCase; |
|||
var file = '../../lib/eventemitter2'; |
|||
var EventEmitter2; |
|||
|
|||
if(typeof require !== 'undefined') { |
|||
EventEmitter2 = require(file).EventEmitter2; |
|||
} |
|||
else { |
|||
EventEmitter2 = window.EventEmitter2; |
|||
} |
|||
|
|||
module.exports = simpleEvents({ |
|||
|
|||
'reconfigure1. initialize, removeAllListeners' : function (test) { |
|||
|
|||
var emitter, |
|||
config = { |
|||
wildcard: true, // should the event emitter use wildcards.
|
|||
delimiter: '::::', // the delimiter used to segment namespaces, defaults to `.`.
|
|||
maxListeners: 20 // the max number of listeners that can be assigned to an event, defaults to 10.
|
|||
}; |
|||
|
|||
emitter = new EventEmitter2(config); |
|||
|
|||
emitter.removeAllListeners(); |
|||
|
|||
test.equal(emitter._events.maxListeners, config.maxListeners, 'should be ' + config.maxListeners); |
|||
|
|||
test.equal(emitter._conf.maxListeners, config.maxListeners, 'should be ' + config.maxListeners); |
|||
test.equal(emitter._conf.delimiter, config.delimiter, 'should be ' + config.delimiter); |
|||
test.equal(emitter._conf.wildcard, config.wildcard, 'should be ' + config.wildcard); |
|||
|
|||
test.expect(4); |
|||
test.done(); |
|||
}, |
|||
|
|||
'reconfigure1. setMaxListeners, removeAllListeners' : function (test) { |
|||
var emitter, |
|||
amount = 99; |
|||
|
|||
emitter = new EventEmitter2(); |
|||
|
|||
emitter.setMaxListeners(amount); |
|||
|
|||
emitter.removeAllListeners(); |
|||
|
|||
test.equal(emitter._events.maxListeners, amount, 'should be ' + amount); |
|||
|
|||
test.equal(emitter._conf.maxListeners, amount, 'should be ' + amount); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
} |
|||
|
|||
}); |
@ -0,0 +1,196 @@ |
|||
|
|||
var simpleEvents= require('nodeunit').testCase; |
|||
var file = '../../lib/eventemitter2'; |
|||
var EventEmitter2; |
|||
|
|||
if(typeof require !== 'undefined') { |
|||
EventEmitter2 = require(file).EventEmitter2; |
|||
} |
|||
else { |
|||
EventEmitter2 = window.EventEmitter2; |
|||
} |
|||
|
|||
module.exports = simpleEvents({ |
|||
|
|||
'removeListener1. adding 1, removing 1' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2; |
|||
|
|||
var type = 'remove', |
|||
listeners; |
|||
|
|||
var f = function f() { |
|||
test.ok(true, 'event was raised'); |
|||
}; |
|||
|
|||
emitter.on(type, f); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 1, 'should only have 1'); |
|||
|
|||
//remove
|
|||
emitter.removeListener(type, f); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 0, 'should be 0'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
}, |
|||
|
|||
'removeListener2. adding 2, removing 1' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2; |
|||
|
|||
var type = 'remove', |
|||
listeners; |
|||
|
|||
var f = function f() { |
|||
test.ok(true, 'event was raised'); |
|||
}; |
|||
|
|||
emitter.on(type, f); |
|||
emitter.on(type, f); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 2, 'should only have 2'); |
|||
|
|||
//remove
|
|||
emitter.removeListener(type, f); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 1, 'should be 1'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
}, |
|||
|
|||
'removeListener3. adding 3, removing 1' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2; |
|||
|
|||
var type = 'remove', |
|||
listeners; |
|||
|
|||
var f = function f() { |
|||
test.ok(true, 'event was raised'); |
|||
}; |
|||
|
|||
emitter.on(type, f); |
|||
emitter.on(type, f); |
|||
emitter.on(type, f); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 3, 'should only have 3'); |
|||
|
|||
//remove
|
|||
emitter.removeListener(type, f); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 2, 'should be 2'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
}, |
|||
|
|||
'removeListener4. should error if we don\'t pass in a function' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2; |
|||
var type = 'remove', |
|||
listeners; |
|||
|
|||
var f = function f() { |
|||
test.ok(true, 'event was raised'); |
|||
}; |
|||
|
|||
emitter.on(type, f); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 1, 'should only have 1'); |
|||
|
|||
//remove
|
|||
test.throws(function () {emitter.removeListener(type, type)}, Error, 'should throw an Error'); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 1, 'should be 1'); |
|||
|
|||
test.expect(3); |
|||
test.done(); |
|||
}, |
|||
|
|||
'removeListener5. removing a different function, should not remove' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2; |
|||
var type = 'remove', |
|||
listeners; |
|||
|
|||
var f = function f() { |
|||
test.ok(true, 'event was raised'); |
|||
}; |
|||
var g = function g() { |
|||
test.ok(true, 'event was raised'); |
|||
}; |
|||
|
|||
emitter.on(type, f); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 1, 'should only have 1'); |
|||
|
|||
//remove
|
|||
emitter.removeListener(type, g); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 1, 'should be 1'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
}, |
|||
|
|||
'removeListener6. removing all functions' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2; |
|||
var type = 'remove', |
|||
listeners; |
|||
|
|||
var f = function f() { |
|||
test.ok(true, 'event was raised'); |
|||
}; |
|||
for (var i = 0; i < 10; i++) { |
|||
emitter.on(type, f); |
|||
} |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 10, 'should only have 10'); |
|||
|
|||
emitter.removeListener(type, f); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 9, 'should be 9'); |
|||
emitter.removeAllListeners(type); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 0, 'should be 0'); |
|||
|
|||
test.expect(3); |
|||
test.done(); |
|||
}, |
|||
|
|||
'removeListener7. removing different event, should not remove' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2; |
|||
var type = 'remove', |
|||
listeners; |
|||
|
|||
var f = function f() { |
|||
test.ok(true, 'event was raised'); |
|||
}; |
|||
|
|||
for (var i = 0; i < 10; i++) { |
|||
emitter.on(type, f); |
|||
} |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 10, 'should only have 10'); |
|||
|
|||
emitter.removeListener(type+type, f); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 10, 'should be 10'); |
|||
|
|||
emitter.removeAllListeners(type+type); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 10, 'should be 10'); |
|||
|
|||
emitter.removeAllListeners(type); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 0, 'should be 0'); |
|||
|
|||
test.expect(4); |
|||
test.done(); |
|||
} |
|||
}); |
@ -0,0 +1,135 @@ |
|||
|
|||
var simpleEvents= require('nodeunit').testCase; |
|||
var file = '../../lib/eventemitter2'; |
|||
var EventEmitter2; |
|||
|
|||
if(typeof require !== 'undefined') { |
|||
EventEmitter2 = require(file).EventEmitter2; |
|||
} |
|||
else { |
|||
EventEmitter2 = window.EventEmitter2; |
|||
} |
|||
|
|||
module.exports = simpleEvents({ |
|||
|
|||
'setMaxListener1. default behavior of 10 listeners.' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2; |
|||
|
|||
for (var i = 0; i < 10; i++) { |
|||
emitter.on('foobar', function () { |
|||
test.ok(true, 'event was raised'); |
|||
}); |
|||
} |
|||
|
|||
var listeners = emitter.listeners('foobar'); |
|||
test.equal(listeners.length, 10, 'should only have 10'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
}, |
|||
|
|||
'setMaxListener2. If we added more than 10, should not see them' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2; |
|||
|
|||
for (var i = 0; i < 10 ; i++) { |
|||
emitter.on('foobar2', function () { |
|||
test.ok(true, 'event was raised'); |
|||
}); |
|||
} |
|||
console.log('should see EE2 complaining:'); |
|||
emitter.on('foobar2', function () { |
|||
test.ok(true, 'event was raised'); |
|||
}); |
|||
|
|||
var listeners = emitter.listeners('foobar2'); |
|||
test.equal(listeners.length, 11, 'should have 11'); |
|||
test.ok(emitter._events['foobar2'].warned, 'should have been warned'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
}, |
|||
|
|||
'setMaxListener3. if we set maxListener to be greater before adding' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2; |
|||
var type = 'foobar3'; |
|||
|
|||
// set to 20
|
|||
emitter.setMaxListeners(20); |
|||
|
|||
for (var i = 0; i < 15 ; i++) { |
|||
emitter.on(type, function () { |
|||
test.ok(true, 'event was raised'); |
|||
}); |
|||
} |
|||
|
|||
var listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 15, 'should have 15'); |
|||
test.ok(!(emitter._events[type].warned), 'should not have been set'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
}, |
|||
|
|||
'setMaxListener4. should be able to change it right at 10' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2; |
|||
var type = 'foobar4'; |
|||
|
|||
for (var i = 0; i < 10 ; i++) { |
|||
emitter.on(type, function () { |
|||
test.ok(true, 'event was raised'); |
|||
}); |
|||
} |
|||
|
|||
emitter.setMaxListeners(9001); |
|||
emitter.on(type, function () { |
|||
test.ok(true, 'event was raised'); |
|||
}); |
|||
|
|||
var listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 11, 'should have 11'); |
|||
test.ok(!(emitter._events[type].warned), 'should not have been set'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
}, |
|||
|
|||
'setMaxListener5. if we set maxListener to be 0 should add endlessly' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2; |
|||
var type = 'foobar'; |
|||
|
|||
// set to 0
|
|||
emitter.setMaxListeners(0); |
|||
|
|||
for (var i = 0; i < 25 ; i++) { |
|||
emitter.on(type, function () { |
|||
test.ok(true, 'event was raised'); |
|||
}); |
|||
} |
|||
|
|||
var listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 25, 'should have 25'); |
|||
test.ok(!(emitter._events[type].warned), 'should not have been set'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
}, |
|||
'maxListeners parameter. Passing maxListeners as a parameter should override default.' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
maxListeners: 2 |
|||
}); |
|||
|
|||
console.log(emitter, test.equal, test.ok); |
|||
emitter.on('a', function () {}); |
|||
emitter.on('a', function () {}); |
|||
emitter.on('a', function () {}); |
|||
test.ok(emitter._events.a.warned, |
|||
'.on() should warn when maxListeners is exceeded.'); |
|||
test.done(); |
|||
} |
|||
}); |
@ -0,0 +1,115 @@ |
|||
|
|||
var simpleEvents = require('nodeunit').testCase; |
|||
var file = '../../lib/eventemitter2'; |
|||
var EventEmitter2; |
|||
|
|||
if(typeof require !== 'undefined') { |
|||
EventEmitter2 = require(file).EventEmitter2; |
|||
} |
|||
else { |
|||
EventEmitter2 = window.EventEmitter2; |
|||
} |
|||
|
|||
module.exports = simpleEvents({ |
|||
|
|||
'1. A listener added with `once` should only listen once and then be removed.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2(); |
|||
|
|||
emitter.once('test1', function () { |
|||
test.ok(true, 'The event was raised once'); |
|||
}); |
|||
|
|||
emitter.emit('test1'); |
|||
emitter.emit('test1'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
|
|||
}, |
|||
'2. A listener with a TTL of 4 should only listen 4 times.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2(); |
|||
|
|||
emitter.many('test1', 4, function (value1) { |
|||
test.ok(true, 'The event was raised 4 times.'); |
|||
}); |
|||
|
|||
emitter.emit('test1', 1); |
|||
emitter.emit('test1', 2); |
|||
emitter.emit('test1', 3); |
|||
emitter.emit('test1', 4); |
|||
emitter.emit('test1', 5); |
|||
|
|||
test.expect(4); |
|||
test.done(); |
|||
|
|||
}, |
|||
'3. A listener with a TTL of 4 should only listen 4 times and pass parameters.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2(); |
|||
|
|||
emitter.many('test1', 4, function (value1, value2, value3) { |
|||
test.ok(typeof value1 !== 'undefined', 'got value 1'); |
|||
test.ok(typeof value2 !== 'undefined', 'got value 2'); |
|||
test.ok(typeof value3 !== 'undefined', 'got value 3'); |
|||
}); |
|||
|
|||
emitter.emit('test1', 1, 'A', false); |
|||
emitter.emit('test1', 2, 'A', false); |
|||
emitter.emit('test1', 3, 'A', false); |
|||
emitter.emit('test1', 4, 'A', false); |
|||
emitter.emit('test1', 5, 'A', false); |
|||
|
|||
test.done(); |
|||
|
|||
}, |
|||
'4. Remove an event listener by signature.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2(); |
|||
var count = 0; |
|||
|
|||
function f1(event) { |
|||
"event A"; |
|||
test.ok(true, 'The event was raised less than 3 times.'); |
|||
} |
|||
|
|||
emitter.on('test1', f1); |
|||
|
|||
function f2(event) { |
|||
"event B"; |
|||
test.ok(true, 'The event was raised less than 3 times.'); |
|||
} |
|||
|
|||
emitter.on('test1', f2); |
|||
|
|||
function f3(event) { |
|||
"event C"; |
|||
test.ok(true, 'The event was raised less than 3 times.'); |
|||
} |
|||
|
|||
emitter.on('test1', f3); |
|||
|
|||
emitter.removeListener('test1', f2); |
|||
|
|||
emitter.emit('test1'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
|
|||
}, |
|||
'5. `removeListener` and `once`': function(test) { |
|||
|
|||
var emitter = new EventEmitter2(); |
|||
var functionA = function() { test.ok(true, 'Event was fired'); }; |
|||
|
|||
emitter.once('testA', functionA); |
|||
emitter.removeListener('testA', functionA); |
|||
|
|||
emitter.emit('testA'); |
|||
|
|||
test.expect(0); |
|||
test.done(); |
|||
} |
|||
|
|||
}); |
@ -0,0 +1,338 @@ |
|||
|
|||
var simpleEvents = require('nodeunit').testCase; |
|||
var file = '../../lib/eventemitter2'; |
|||
|
|||
var EventEmitter2; |
|||
|
|||
if(typeof require !== 'undefined') { |
|||
EventEmitter2 = require(file).EventEmitter2; |
|||
} |
|||
else { |
|||
EventEmitter2 = window.EventEmitter2; |
|||
} |
|||
|
|||
module.exports = simpleEvents({ |
|||
|
|||
'1. Add a single listener on a single event.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true |
|||
}); |
|||
|
|||
var type = 'some.listener.bar'; |
|||
|
|||
emitter.on(type, function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
test.equal(emitter.listeners(type).length, 1, 'There are three emitters'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
|
|||
}, |
|||
|
|||
'1a. Add a single listener on a single event (using an array).': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true |
|||
}); |
|||
|
|||
var type = ['some', 'listener', 'bar']; |
|||
|
|||
emitter.on(type, function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
test.equal(emitter.listeners(type).length, 1, 'There are three emitters'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
|
|||
}, |
|||
|
|||
'2. Add two listeners on a single event.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true |
|||
}); |
|||
|
|||
var type = 'some.listener.bar'; |
|||
|
|||
emitter.on(type, function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.on(type, function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
test.equal(emitter.listeners(type).length, 2, 'There are three emitters'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
|
|||
}, |
|||
|
|||
'2a. Add two listeners on a single event (using an array).': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true |
|||
}); |
|||
|
|||
var type = ['some', 'listener', 'bar']; |
|||
|
|||
emitter.on(type, function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.on(type, function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
test.equal(emitter.listeners(type).length, 2, 'There are three emitters'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
|
|||
}, |
|||
|
|||
'3. Add three listeners on a single event.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true |
|||
}); |
|||
|
|||
var type = 'some.listener.bar'; |
|||
|
|||
emitter.on(type, function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.on(type, function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.on(type, function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
test.equal(emitter.listeners(type).length, 3, 'There are three emitters'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
|
|||
}, |
|||
|
|||
'4. Add two listeners to two different events.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true |
|||
}); |
|||
|
|||
var type = 'some.listener.bar'; |
|||
|
|||
emitter.on(type, function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.on(type, function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.on('test2', function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.on('test2', function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
test.equal(emitter.listeners(type).length, 2, 'There are two emitters'); |
|||
test.equal(emitter.listeners('test2').length, 2, 'There are two emitters'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
}, |
|||
|
|||
'5. Never adding any listeners should yield a listeners array with the length of 0.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true |
|||
}); |
|||
|
|||
var type = 'some.listener.bar'; |
|||
|
|||
emitter.on(type, function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
test.equal(emitter.listeners('test2').length, 0, 'There are no emitters'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
}, |
|||
|
|||
'6. the listener added should be the right listener.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true |
|||
}); |
|||
|
|||
var type = 'some.listener.bar'; |
|||
var f = function () {}; |
|||
|
|||
emitter.on(type, f); |
|||
test.equal(emitter.listeners(type).length, 1, 'There are is one emitters'); |
|||
test.equal(emitter.listeners(type)[0], f, 'The function should be f'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
|
|||
}, |
|||
|
|||
'7. Listeners on `*`, `*.*`, `*.test` with emissions from `foo.test` and `other.emit`': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true |
|||
}); |
|||
|
|||
var f = function () { |
|||
test.ok(true, 'the event was fired') |
|||
}; |
|||
|
|||
emitter.on('*.test', f); |
|||
emitter.on('*.*', f); |
|||
emitter.on('*', f); |
|||
|
|||
emitter.emit('other.emit'); |
|||
emitter.emit('foo.test'); |
|||
|
|||
test.expect(3); |
|||
test.done(); |
|||
}, |
|||
|
|||
'8. Listeners on `*`, `*.*`, foo.test with emissions from `*`, `*.*` and `foo.test`': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true |
|||
}); |
|||
|
|||
var f = function () { |
|||
test.ok(true, 'the event was fired') |
|||
}; |
|||
|
|||
emitter.on('foo.test', f); |
|||
emitter.on('*.*', f); |
|||
emitter.on('*', f); |
|||
|
|||
emitter.emit('*.*'); |
|||
emitter.emit('foo.test'); |
|||
emitter.emit('*') |
|||
|
|||
test.expect(5); |
|||
test.done(); |
|||
}, |
|||
|
|||
'9. Listeners on `*`. (using an array)': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true |
|||
}); |
|||
|
|||
var f = function () { |
|||
test.ok(true, 'the event was fired') |
|||
}; |
|||
|
|||
emitter.on(['*'], f); |
|||
emitter.emit('*') |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
}, |
|||
|
|||
'10. actual event name': function(test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true |
|||
}); |
|||
|
|||
emitter.on('foo', function() { |
|||
emitter.emit('bar'); // changes the current event, passes the old one in as a parameter.
|
|||
}); |
|||
|
|||
emitter.on('*', function() { |
|||
console.log(this.event); |
|||
}); |
|||
|
|||
emitter.emit('foo'); |
|||
|
|||
test.done(); |
|||
}, |
|||
|
|||
'11. Listeners with multi-level wildcards': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true |
|||
}); |
|||
|
|||
var i = 0; |
|||
var f = function (n) { |
|||
return function() { |
|||
//console.log('Event', n, 'fired by', this.event);
|
|||
test.ok(true, 'the event was fired'); |
|||
}; |
|||
}; |
|||
|
|||
emitter.on('**.test', f(i++)); // 0: 0 + 1 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 1
|
|||
emitter.on('**.bar.**', f(i++)); // 1: 0 + 1 + 1 + 1 + 1 + 0 + 0 + 1 + 1 + 1
|
|||
emitter.on('**.*', f(i++)); // 2: 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1
|
|||
emitter.on('*.**', f(i++)); // 3: 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1
|
|||
emitter.on('**', f(i++)); // 4: 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1
|
|||
emitter.on('other.**', f(i++)); // 5: 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 1
|
|||
emitter.on('foo.**.test', f(i++)); // 6: 0 + 1 + 0 + 0 + 1 + 0 + 1 + 1 + 1 + 1
|
|||
emitter.on('test.**', f(i++)); // 7: 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 1 + 1
|
|||
// Add forbidden patterns for safety purpose.
|
|||
emitter.on('**.**', f(i++)); |
|||
emitter.on('a.b.**.**', f(i++)); |
|||
emitter.on('**.**.a.b', f(i++)); |
|||
emitter.on('a.b.**.**.a.b', f(i++)); |
|||
|
|||
emitter.emit('other.emit'); // 4
|
|||
emitter.emit('foo.bar.test'); // 6
|
|||
emitter.emit('foo.bar.test.bar.foo.test.foo'); // 4
|
|||
emitter.emit('bar.bar.bar.bar.bar.bar'); // 4
|
|||
emitter.emit('**.*'); // 8
|
|||
emitter.emit('test'); // 5
|
|||
emitter.emit('foo.test'); // 5
|
|||
emitter.emit('foo.**.*'); // 6
|
|||
emitter.emit('**.test'); // 8
|
|||
emitter.emit('**.test.**'); // 8
|
|||
//emitter.emit('*.**.test.**.a'); // 0
|
|||
|
|||
test.expect(58); |
|||
test.done(); |
|||
}, |
|||
|
|||
'12. Check return values of emit for wildcard emitter.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true |
|||
}); |
|||
|
|||
emitter.on('foo.*', function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.onAny(function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
test.ok(emitter.emit('foo.blah'), 'emit should return true after calling a listener'); |
|||
test.ok(emitter.emit('bar'), 'emit should return true after calling a listener'); |
|||
|
|||
test.expect(5); |
|||
test.done(); |
|||
} |
|||
|
|||
}); |
@ -0,0 +1,248 @@ |
|||
var basicEvents = require('nodeunit').testCase; |
|||
|
|||
var EventEmitter2; |
|||
|
|||
if(typeof require !== 'undefined') { |
|||
EventEmitter2 = require('../../lib/eventemitter2').EventEmitter2; |
|||
} |
|||
else { |
|||
EventEmitter2 = window.EventEmitter2; |
|||
} |
|||
|
|||
function setHelper (emitter, test, testName){ |
|||
var eventNames = [ |
|||
testName, |
|||
testName + '.*', |
|||
testName + '.ns1', |
|||
testName + '.ns1.ns2', |
|||
testName + '.ns2.*' |
|||
]; |
|||
|
|||
for (var i = 0; i < eventNames.length; i++) { |
|||
emitter.on(eventNames[i], function () { |
|||
test.ok(true, eventNames[i] + 'has fired'); |
|||
}); |
|||
} |
|||
|
|||
return eventNames; |
|||
}; |
|||
|
|||
module.exports = basicEvents({ |
|||
|
|||
'1. An event can be namespaced.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true, |
|||
verbose: true |
|||
}); |
|||
|
|||
emitter.on('test1.ns1', function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.emit('test1.ns1'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
|
|||
}, |
|||
'2. An event can be namespaced and accept values.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true, |
|||
verbose: true |
|||
}); |
|||
|
|||
emitter.on('test2.ns1', function(value1) { |
|||
test.ok(true, 'The event was raised'); |
|||
test.ok(typeof value1 !== 'undefined', 'The event was raised with the value `' + value1 + '`.'); |
|||
}); |
|||
|
|||
emitter.emit('test2.ns1', 1); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
|
|||
}, |
|||
'3. A namespaced event can be raised multiple times and accept values.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true, |
|||
verbose: true |
|||
}); |
|||
|
|||
emitter.on('test3.ns1', function (value1, value2, value3) { |
|||
test.ok(true, 'The event was raised'); |
|||
test.ok(arguments.length === 3, 'The event was raised with the correct number of arguments'); |
|||
test.ok(value1 === 1 || value1 === 4, 'The event was raised with the value `' + value1 + '`.'); |
|||
test.ok(value2 === 2 || value2 === 5, 'The event was raised with the value `' + value2 + '`.'); |
|||
test.ok(value3 === 3 || value3 === 6, 'The event was raised with the value `' + value3 + '`.'); |
|||
}); |
|||
|
|||
emitter.emit('test3.ns1', 1, 2, 3); |
|||
emitter.emit('test3.ns1', 4, 5, 6); |
|||
|
|||
test.expect(10); |
|||
test.done(); |
|||
}, |
|||
'4. A listener should support wild cards.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true, |
|||
verbose: true |
|||
}); |
|||
|
|||
emitter.on('test4.*', function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.emit('test4.ns1'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
|
|||
}, |
|||
'5. Emitting an event should support wildcards.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true, |
|||
verbose: true |
|||
}); |
|||
|
|||
emitter.on('test5A.test5B', function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.emit('test5A.*'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
|
|||
}, |
|||
'6. A listener should support complex wild cards.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true, |
|||
verbose: true |
|||
}); |
|||
|
|||
emitter.on('test10.*.foo', function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.emit('test10.ns1.foo'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
|
|||
}, |
|||
'7. Emitting an event should support complex wildcards.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true, |
|||
verbose: true |
|||
}); |
|||
|
|||
emitter.on('test11.ns1.foo', function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.emit('test11.*.foo'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
|
|||
}, |
|||
'8. Emitting an event should support complex wildcards multiple times, a valid listener should accept values.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true, |
|||
verbose: true |
|||
}); |
|||
|
|||
emitter.on('test12.ns1.ns2', function (value1, value2, value3) { |
|||
test.ok(true, 'The event was raised'); |
|||
test.ok(arguments.length === 3, 'The event was raised with the correct number of arguments'); |
|||
test.ok(value1 === 1 || value1 === 4, 'The event was raised with the value `' + value1 + '`.'); |
|||
test.ok(value2 === 2 || value2 === 5, 'The event was raised with the value `' + value1 + '`.'); |
|||
test.ok(value3 === 3 || value3 === 6, 'The event was raised with the value `' + value1 + '`.'); |
|||
}); |
|||
|
|||
emitter.emit('test12.*.ns2', 1, 2, 3); |
|||
emitter.emit('test12.*.ns2', 4, 5, 6); |
|||
|
|||
test.expect(10); |
|||
test.done(); |
|||
|
|||
}, |
|||
'9. List all the listeners for a particular event.': function(test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true, |
|||
verbose: true |
|||
}); |
|||
|
|||
emitter.on('test13', function (event) { |
|||
test.ok(true,'raised one'); |
|||
}); |
|||
|
|||
emitter.on('test13', function (event) { |
|||
test.ok(true,'raised two'); |
|||
}); |
|||
|
|||
var listeners = emitter.listeners('test13'); |
|||
|
|||
test.ok(listeners.length === 2, 'The event `test13` should have 2 listeners'); |
|||
test.expect(1); |
|||
test.done(); |
|||
|
|||
}, |
|||
'10. should be able to listen on any event' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true, |
|||
verbose: true |
|||
}); |
|||
|
|||
var fn = function (foo, bar) { |
|||
test.equal(this.event, 'test23.ns5.ns5') |
|||
test.equal(foo, 'foo'); |
|||
test.equal(bar, 1); |
|||
test.ok(true, 'raised test23.ns5.ns5'); |
|||
} |
|||
|
|||
emitter.onAny(fn); |
|||
emitter.emit('test23.ns5.ns5', 'foo', 1); |
|||
test.expect(4); |
|||
test.done(); |
|||
|
|||
}, |
|||
|
|||
'11. No warning should be raised if we set maxListener to be greater before adding' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true, |
|||
verbose: true |
|||
}); |
|||
|
|||
var type = 'test29.*'; |
|||
|
|||
// set to 20
|
|||
emitter.setMaxListeners(20); |
|||
|
|||
for (var i = 0; i < 15 ; i++) { |
|||
emitter.on(type, function () { |
|||
test.ok(true, 'event was raised'); |
|||
}); |
|||
} |
|||
|
|||
var listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 15, 'should have 15'); |
|||
test.ok(!(emitter.listenerTree[ 'test29' ]['*']._listeners.warned), 'should not have been set'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
} |
|||
|
|||
|
|||
}); |
@ -0,0 +1,250 @@ |
|||
|
|||
var simpleEvents = require('nodeunit').testCase; |
|||
var file = '../../lib/eventemitter2'; |
|||
|
|||
var EventEmitter2; |
|||
|
|||
if(typeof require !== 'undefined') { |
|||
EventEmitter2 = require(file).EventEmitter2; |
|||
} |
|||
else { |
|||
EventEmitter2 = window.EventEmitter2; |
|||
} |
|||
|
|||
module.exports = simpleEvents({ |
|||
|
|||
'1. Add a single listener on a single event.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true, |
|||
delimiter: '::' |
|||
}); |
|||
|
|||
var type = 'some::listener::bar'; |
|||
|
|||
emitter.on(type, function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
test.equal(emitter.listeners(type).length, 1, 'There are three emitters'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
|
|||
}, |
|||
|
|||
'2. Add two listeners on a single event.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true, |
|||
delimiter: '::' |
|||
}); |
|||
|
|||
var type = 'some::listener::bar'; |
|||
|
|||
emitter.on(type, function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.on(type, function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
test.equal(emitter.listeners(type).length, 2, 'There are three emitters'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
|
|||
}, |
|||
'3. Add three listeners on a single event.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true, |
|||
delimiter: '::' |
|||
}); |
|||
|
|||
var type = 'some::listener::bar'; |
|||
|
|||
emitter.on(type, function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.on(type, function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.on(type, function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
test.equal(emitter.listeners(type).length, 3, 'There are three emitters'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
|
|||
}, |
|||
'4. Add two listeners to two different events.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true, |
|||
delimiter: '::' |
|||
}); |
|||
|
|||
var type = 'some::listener::bar'; |
|||
|
|||
emitter.on(type, function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.on(type, function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.on('test2', function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
emitter.on('test2', function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
test.equal(emitter.listeners(type).length, 2, 'There are two emitters'); |
|||
test.equal(emitter.listeners('test2').length, 2, 'There are two emitters'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
}, |
|||
|
|||
'5. Never adding any listeners should yield a listeners array with the length of 0.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true, |
|||
delimiter: '::' |
|||
}); |
|||
|
|||
var type = 'some::listener::bar'; |
|||
|
|||
emitter.on(type, function () { |
|||
test.ok(true, 'The event was raised'); |
|||
}); |
|||
|
|||
test.equal(emitter.listeners('test2').length, 0, 'There are no emitters'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
}, |
|||
|
|||
'6. the listener added should be the right listener.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true, |
|||
delimiter: '::' |
|||
}); |
|||
|
|||
var type = 'some::listener::bar'; |
|||
var f = function () {}; |
|||
|
|||
emitter.on(type, f); |
|||
test.equal(emitter.listeners(type).length, 1, 'There are is one emitters'); |
|||
test.equal(emitter.listeners(type)[0], f, 'The function should be f'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
|
|||
}, |
|||
|
|||
'7. Listeners on *, *::*, *::test with emissions from foo::test and other::emit': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true, |
|||
delimiter: '::' |
|||
}); |
|||
|
|||
var f = function () { |
|||
test.ok(true, 'the event was fired') |
|||
}; |
|||
|
|||
emitter.on('*::test', f); |
|||
emitter.on('*::*', f); |
|||
emitter.on('*', f); |
|||
|
|||
emitter.emit('other::emit'); |
|||
emitter.emit('foo::test'); |
|||
|
|||
test.expect(3); |
|||
test.done(); |
|||
}, |
|||
|
|||
'8. Listeners on *, *::*, foo.test with emissions from *, *::* and foo.test': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true, |
|||
delimiter: '::' |
|||
}); |
|||
|
|||
var f = function () { |
|||
test.ok(true, 'the event was fired') |
|||
}; |
|||
|
|||
emitter.on('foo::test', f); |
|||
emitter.on('*::*', f); |
|||
emitter.on('*', f); |
|||
|
|||
emitter.emit('*::*'); |
|||
emitter.emit('foo::test'); |
|||
emitter.emit('*') |
|||
|
|||
test.expect(5); |
|||
test.done(); |
|||
}, |
|||
|
|||
'9. Listeners on **, **::*, **::test with emissions from foo::test and other::emit': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true, |
|||
delimiter: '::' |
|||
}); |
|||
|
|||
var f = function () { |
|||
test.ok(true, 'the event was fired'); |
|||
}; |
|||
|
|||
emitter.on('**::test', f); |
|||
emitter.on('**::*', f); |
|||
emitter.on('**', f); |
|||
|
|||
emitter.emit('other::emit'); // 2
|
|||
emitter.emit('foo::test'); // 3
|
|||
|
|||
test.expect(5); |
|||
test.done(); |
|||
}, |
|||
|
|||
'10. Listeners on **, **::*, foo.test with emissions from **, **::* and foo.test': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true, |
|||
delimiter: '::' |
|||
}); |
|||
|
|||
var i = 0; |
|||
var f = function (n) { |
|||
return function() { |
|||
//console.log(n, this.event);
|
|||
test.ok(true, 'the event was fired'); |
|||
}; |
|||
}; |
|||
|
|||
emitter.on('foo::test', f(i++)); |
|||
emitter.on('**::*', f(i++)); |
|||
emitter.on('**', f(i++)); |
|||
|
|||
emitter.emit('**::*'); // 3
|
|||
emitter.emit('foo::test'); // 3
|
|||
emitter.emit('**'); // 3
|
|||
|
|||
test.expect(9); |
|||
test.done(); |
|||
} |
|||
|
|||
}); |
@ -0,0 +1,56 @@ |
|||
|
|||
// Copyright Joyent, Inc. and other Node contributors.
|
|||
//
|
|||
// 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.
|
|||
|
|||
var common = require('../common'); |
|||
var assert = require('assert'); |
|||
var EventEmitter = require('../../lib/eventemitter2').EventEmitter2; |
|||
|
|||
var e = new EventEmitter({wildcard: true}); |
|||
var countWildcard = 0; |
|||
var counMultiLevelWildcard = 0; |
|||
var countAny = 0; |
|||
|
|||
e.on('foo', function() { |
|||
e.emit('bar', 'bar'); |
|||
}); |
|||
e.on('*', function(name) { |
|||
++countWildcard; |
|||
console.log(this.event, name); |
|||
assert.equal(this.event, name); |
|||
}); |
|||
e.on('**', function(name) { |
|||
++counMultiLevelWildcard; |
|||
console.log(this.event, name); |
|||
assert.equal(this.event, name); |
|||
}); |
|||
e.onAny(function(name) { |
|||
++countAny; |
|||
assert.equal(this.event, name); |
|||
}); |
|||
|
|||
e.emit('foo', 'foo'); |
|||
|
|||
process.on('exit', function() { |
|||
assert.equal(countWildcard, 2); |
|||
assert.equal(counMultiLevelWildcard, 2); |
|||
assert.equal(countAny, 2); |
|||
}); |
@ -0,0 +1,72 @@ |
|||
var basicEvents = require('nodeunit').testCase; |
|||
var lib = '../../lib/eventemitter2'; |
|||
|
|||
var EventEmitter2; |
|||
|
|||
if(typeof require !== 'undefined') { |
|||
EventEmitter2 = require(lib).EventEmitter2; |
|||
} |
|||
else { |
|||
EventEmitter2 = window.EventEmitter2; |
|||
} |
|||
|
|||
function setHelper (emitter, test, testName){ |
|||
var eventNames = [ |
|||
testName, |
|||
testName + '.*', |
|||
testName + '.ns1', |
|||
testName + '.ns1.ns2', |
|||
testName + '.ns2.*', |
|||
testName + '.**', |
|||
testName = '.ns2.**' |
|||
]; |
|||
|
|||
for (var i = 0; i < eventNames.length; i++) { |
|||
emitter.on(eventNames[i], function () { |
|||
test.ok(true, eventNames[i] + 'has fired'); |
|||
}); |
|||
} |
|||
|
|||
return eventNames; |
|||
} |
|||
|
|||
module.exports = basicEvents({ |
|||
|
|||
'intialize 1. Configuration Flags Test.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true, |
|||
verbose: true |
|||
}); |
|||
|
|||
var emitterDefault = new EventEmitter2({ |
|||
}); |
|||
|
|||
test.ok(!emitterDefault.wildcard, 'default .wildcard should be false'); |
|||
test.ok(emitter.wildcard, '.wildcard should be true when set'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
|
|||
}, |
|||
'initialize 2. creating a wildcard EE should have listenerTree.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard: true, |
|||
verbose: true |
|||
}); |
|||
|
|||
var emitterDefault = new EventEmitter2({ |
|||
}); |
|||
|
|||
test.ok(emitter.listenerTree, 'listenerTree should exist'); |
|||
test.equal(typeof emitter.listenerTree, 'object', 'listenerTree should be an Object'); |
|||
|
|||
test.ok(!emitterDefault.listenerTree, 'listenerTree should not exist'); |
|||
// check the tree to be empty?
|
|||
|
|||
test.expect(3); |
|||
test.done(); |
|||
|
|||
}, |
|||
}); |
@ -0,0 +1,317 @@ |
|||
var simpleEvents= require('nodeunit').testCase; |
|||
var file = '../../lib/eventemitter2'; |
|||
|
|||
var EventEmitter2; |
|||
|
|||
if(typeof require !== 'undefined') { |
|||
EventEmitter2 = require(file).EventEmitter2; |
|||
} |
|||
else { |
|||
EventEmitter2 = window.EventEmitter2; |
|||
} |
|||
|
|||
module.exports = simpleEvents({ |
|||
|
|||
'1. add a single event and then remove the event.' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard : true, |
|||
verbose : true |
|||
}); |
|||
|
|||
var type = 'remove.foo.bar', |
|||
listeners; |
|||
|
|||
var f = function () { |
|||
test.ok(true, 'event was raised'); |
|||
}; |
|||
|
|||
emitter.on(type, f); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 1, 'should only have 1'); |
|||
|
|||
//remove
|
|||
emitter.removeListener(type, f); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 0, 'should be 0'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
}, |
|||
|
|||
'2. Add two events and then remove only one of those events.' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard : true, |
|||
verbose : true |
|||
}); |
|||
|
|||
var type = 'remove.foo.bar', |
|||
listeners; |
|||
|
|||
var f = function f() { |
|||
test.ok(true, 'event was raised'); |
|||
}; |
|||
|
|||
emitter.on(type, f); |
|||
emitter.on(type, f); |
|||
|
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 2, 'should only have 2'); |
|||
|
|||
emitter.removeListener(type, f); |
|||
|
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 1, 'should be 1'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
}, |
|||
|
|||
'3. Add three events and remove only one of the events that was added.' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard : true, |
|||
verbose : true |
|||
}); |
|||
|
|||
var type = 'remove.foo.bar', |
|||
listeners; |
|||
|
|||
var f = function () { |
|||
test.ok(true, 'event was raised'); |
|||
}; |
|||
|
|||
emitter.on(type, f); |
|||
emitter.on(type, f); |
|||
emitter.on(type, f); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 3, 'should only have 3'); |
|||
|
|||
//remove
|
|||
emitter.removeListener(type, f); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 2, 'should be 2'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
}, |
|||
|
|||
'4. Should error if we don\'t pass a function to the emit method.' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard : true, |
|||
verbose : true |
|||
}); |
|||
|
|||
var type = 'remove.foo.bar', |
|||
listeners; |
|||
|
|||
var f = function () { |
|||
test.ok(true, 'event was raised'); |
|||
}; |
|||
|
|||
emitter.on(type, f); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 1, 'should only have 1'); |
|||
|
|||
//remove
|
|||
test.throws(function () {emitter.removeListener(type, type)}, Error, 'should throw an Error'); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 1, 'should be 1'); |
|||
|
|||
test.expect(3); |
|||
test.done(); |
|||
}, |
|||
|
|||
'5. Removing one listener should not affect another listener.' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard : true, |
|||
verbose : true |
|||
}); |
|||
|
|||
var type = 'remove.foo.bar', |
|||
listeners; |
|||
|
|||
var f = function () { |
|||
test.ok(true, 'event was raised'); |
|||
}; |
|||
var g = function () { |
|||
test.ok(true, 'event was raised'); |
|||
}; |
|||
|
|||
emitter.on(type, f); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 1, 'should only have 1'); |
|||
|
|||
//remove
|
|||
emitter.removeListener(type, g); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 1, 'should be 1'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
}, |
|||
|
|||
'6. Remove all listener functions.' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard : true, |
|||
verbose : true |
|||
}); |
|||
|
|||
var type = 'remove.foo.bar', |
|||
listeners; |
|||
|
|||
var f = function () { |
|||
test.ok(true, 'event was raised'); |
|||
}; |
|||
for (var i = 0; i < 10; i++) { |
|||
emitter.on(type, f); |
|||
} |
|||
|
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 10, 'should only have 10'); |
|||
|
|||
emitter.removeListener(type, f); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 9, 'should be 9'); |
|||
emitter.removeAllListeners(type); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 0, 'should be 0'); |
|||
|
|||
test.expect(3); |
|||
test.done(); |
|||
}, |
|||
|
|||
'7. Removing listeners for one event should not affect another event\'s listeners.' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard : true, |
|||
verbose : true |
|||
}); |
|||
|
|||
var type = 'remove.foo.bar'; |
|||
|
|||
var listeners; |
|||
|
|||
var f = function () { |
|||
test.ok(true, 'event was raised'); |
|||
}; |
|||
|
|||
for (var i = 0; i < 10; i++) { |
|||
emitter.on(type, f); |
|||
} |
|||
|
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 10, 'should only have 10'); |
|||
|
|||
emitter.removeListener(type+type, f); |
|||
|
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 10, 'should be 10'); |
|||
|
|||
emitter.removeAllListeners(type+type); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 10, 'should be 10'); |
|||
|
|||
emitter.removeAllListeners(type+'.'+type); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 10, 'should be 10'); |
|||
|
|||
emitter.removeAllListeners(type); |
|||
listeners = emitter.listeners(type); |
|||
test.equal(listeners.length, 0, 'should be 0'); |
|||
|
|||
test.expect(5); |
|||
test.done(); |
|||
}, |
|||
|
|||
'8. Its ok to listen on wildcard, so it is ok to remove it.' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard : true, |
|||
verbose : true |
|||
}); |
|||
|
|||
var type1 = '*.wild.card', |
|||
type2 = 'just.another.event', |
|||
listeners; |
|||
|
|||
var f = function () { |
|||
test.ok(true, 'event was raised'); |
|||
}; |
|||
|
|||
emitter.on(type2, f); |
|||
emitter.on(type1, f); |
|||
|
|||
//remove
|
|||
emitter.removeListener(type1, f); |
|||
listeners = emitter.listeners(type1); |
|||
test.equal(listeners.length, 0, 'should be 0'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
}, |
|||
|
|||
'9. And (8) should not depend on order of listening.' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard : true, |
|||
verbose : true |
|||
}); |
|||
|
|||
var type1 = '*.wild.card', |
|||
type2 = 'just.another.event', |
|||
listeners; |
|||
|
|||
var f = function () { |
|||
test.ok(true, 'event was raised'); |
|||
}; |
|||
|
|||
emitter.on(type1, f); |
|||
emitter.on(type2, f); |
|||
|
|||
//remove
|
|||
emitter.removeListener(type1, f); |
|||
listeners = emitter.listeners(type1); |
|||
test.equal(listeners.length, 0, 'should be 0'); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
}, |
|||
|
|||
'10. Reporting many listeners on wildcard all should removed.' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard : true, |
|||
verbose : true |
|||
}); |
|||
|
|||
var type1 = '*.wild.card', |
|||
type2 = 'exact.wild.card', |
|||
listeners; |
|||
|
|||
var f = function () { |
|||
test.ok(true, 'event was raised'); |
|||
}; |
|||
|
|||
emitter.on(type1, f); |
|||
emitter.on(type2, f); |
|||
|
|||
// check number of listeners by wild card
|
|||
listeners = emitter.listeners(type1); |
|||
test.equal(listeners.length, 2, 'should only have 2'); |
|||
|
|||
// remove by wild card should remove both
|
|||
emitter.removeListener(type1, f); |
|||
listeners = emitter.listeners(type1); |
|||
test.equal(listeners.length, 0, 'should be 0'); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
} |
|||
|
|||
|
|||
}); |
@ -0,0 +1,223 @@ |
|||
var simpleEvents = require('nodeunit').testCase; |
|||
var file = '../../lib/eventemitter2'; |
|||
|
|||
var EventEmitter2; |
|||
|
|||
if(typeof require !== 'undefined') { |
|||
EventEmitter2 = require(file).EventEmitter2; |
|||
} |
|||
else { |
|||
EventEmitter2 = window.EventEmitter2; |
|||
} |
|||
|
|||
module.exports = simpleEvents({ |
|||
|
|||
'1. A listener added with `once` should only listen once and then be removed.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard : true, |
|||
verbose : true |
|||
}); |
|||
|
|||
var type = 'test1.foo.bar'; |
|||
|
|||
emitter.once(type, function () { |
|||
test.ok(true, 'The event was raised once'); |
|||
}); |
|||
|
|||
emitter.emit(type); |
|||
emitter.emit(type); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
|
|||
}, |
|||
'2. A listener with a TTL of 4 should only listen 4 times.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard : true, |
|||
verbose : true |
|||
}); |
|||
|
|||
var type = 'test1.foo.bar'; |
|||
|
|||
emitter.many(type, 4, function (value1) { |
|||
test.ok(true, 'The event was raised 4 times.'); |
|||
}); |
|||
|
|||
emitter.emit(type, 1); |
|||
emitter.emit(type, 2); |
|||
emitter.emit(type, 3); |
|||
emitter.emit(type, 4); |
|||
emitter.emit(type, 5); |
|||
|
|||
test.expect(4); |
|||
test.done(); |
|||
|
|||
}, |
|||
'3. A listener with a TTL of 4 should only listen 4 times and pass parameters.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard : true, |
|||
verbose : true |
|||
}); |
|||
|
|||
var type = 'test1.foo.bar'; |
|||
|
|||
emitter.many(type, 4, function (value1, value2, value3) { |
|||
test.ok(typeof value1 !== 'undefined', 'got value 1'); |
|||
test.ok(typeof value2 !== 'undefined', 'got value 2'); |
|||
test.ok(typeof value3 !== 'undefined', 'got value 3'); |
|||
}); |
|||
|
|||
emitter.emit(type, 1, 'A', false); |
|||
emitter.emit(type, 2, 'A', false); |
|||
emitter.emit(type, 3, 'A', false); |
|||
emitter.emit(type, 4, 'A', false); |
|||
emitter.emit(type, 5, 'A', false); |
|||
|
|||
test.done(); |
|||
|
|||
}, |
|||
'4. Remove an event listener by signature.': function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard : true, |
|||
verbose : true |
|||
}); |
|||
|
|||
var type = 'test1.foo.bar'; |
|||
var count = 0; |
|||
|
|||
function f1(event) { |
|||
"event A"; |
|||
test.ok(true, 'The event was raised less than 3 times.'); |
|||
} |
|||
|
|||
emitter.on(type, f1); |
|||
|
|||
function f2(event) { |
|||
"event B"; |
|||
test.ok(true, 'The event was raised less than 3 times.'); |
|||
} |
|||
|
|||
emitter.on(type, f2); |
|||
|
|||
function f3(event) { |
|||
"event C"; |
|||
test.ok(true, 'The event was raised less than 3 times.'); |
|||
} |
|||
|
|||
emitter.on(type, f3); |
|||
|
|||
emitter.removeListener(type, f2); |
|||
|
|||
emitter.emit(type); |
|||
|
|||
test.expect(2); |
|||
test.done(); |
|||
|
|||
}, |
|||
'5. `removeListener` and `once`': function(test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard : true, |
|||
verbose : true |
|||
}); |
|||
|
|||
var type = 'test1.foo.bar'; |
|||
var functionA = function() { test.ok(true, 'Event was fired'); }; |
|||
|
|||
emitter.once(type, functionA); |
|||
emitter.removeListener(type, functionA); |
|||
|
|||
emitter.emit(type); |
|||
|
|||
test.expect(0); |
|||
test.done(); |
|||
}, |
|||
|
|||
'6. Listening with a wildcard on once' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard : true, |
|||
verbose : true |
|||
}); |
|||
|
|||
var type = 'test1.foo.*'; |
|||
var functionA = function() { test.ok(true, 'Event was fired'); }; |
|||
|
|||
emitter.once(type, functionA); |
|||
emitter.on(type,functionA); |
|||
|
|||
emitter.emit(type); //2
|
|||
emitter.emit(type); //1
|
|||
|
|||
test.expect(3); |
|||
test.done(); |
|||
}, |
|||
|
|||
'7. Emitting with a wildcard targeted at once' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard : true, |
|||
verbose : true |
|||
}); |
|||
|
|||
var type = 'test1.foo.bar'; |
|||
var type2 = 'test1.foo.*'; |
|||
var functionA = function() { test.ok(true, 'Event was fired'); }; |
|||
|
|||
emitter.once(type, functionA); |
|||
emitter.emit(type2); |
|||
emitter.emit(type2); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
}, |
|||
|
|||
'8. Emitting with a multi-level wildcard on once': function(test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard : true, |
|||
verbose : true |
|||
}); |
|||
|
|||
var i = 0; |
|||
var type = 'test1.**'; |
|||
var functionA = function(n) { |
|||
return function() { |
|||
console.log(n, this.event); |
|||
test.ok(true, 'Event was fired'); |
|||
}; |
|||
} |
|||
|
|||
emitter.once(type, functionA(i++)); |
|||
emitter.on(type, functionA(i++)); |
|||
emitter.emit(type); //2
|
|||
emitter.emit(type); //1
|
|||
|
|||
test.expect(3); |
|||
test.done(); |
|||
}, |
|||
|
|||
'9. Emitting with a multi-level wildcard targeted at once' : function (test) { |
|||
|
|||
var emitter = new EventEmitter2({ |
|||
wildcard : true, |
|||
verbose : true |
|||
}); |
|||
|
|||
var type = 'test1.foo.bar'; |
|||
var type2 = 'test1.**'; |
|||
var functionA = function() { test.ok(true, 'Event was fired'); }; |
|||
|
|||
emitter.once(type, functionA); |
|||
emitter.emit(type2); |
|||
emitter.emit(type2); |
|||
|
|||
test.expect(1); |
|||
test.done(); |
|||
} |
|||
|
|||
}); |
@ -0,0 +1,410 @@ |
|||
// Generated by CoffeeScript 1.6.2
|
|||
var EventEmitter, Task, TaskGroup, ambi, |
|||
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, |
|||
__hasProp = {}.hasOwnProperty, |
|||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, |
|||
__slice = [].slice; |
|||
|
|||
ambi = require('ambi'); |
|||
|
|||
EventEmitter = require('eventemitter2').EventEmitter2; |
|||
|
|||
Task = (function(_super) { |
|||
__extends(Task, _super); |
|||
|
|||
Task.prototype.type = 'task'; |
|||
|
|||
Task.prototype.result = null; |
|||
|
|||
Task.prototype.running = false; |
|||
|
|||
Task.prototype.parent = null; |
|||
|
|||
Task.prototype.name = null; |
|||
|
|||
Task.prototype.fn = null; |
|||
|
|||
Task.prototype.args = null; |
|||
|
|||
function Task() { |
|||
var args, fn, name; |
|||
|
|||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; |
|||
this.setConfig = __bind(this.setConfig, this); |
|||
Task.__super__.constructor.apply(this, arguments); |
|||
name = fn = null; |
|||
if (args.length) { |
|||
if (args.length === 2) { |
|||
name = args[0], fn = args[1]; |
|||
} else if (args.length === 1) { |
|||
fn = args[0]; |
|||
} |
|||
} |
|||
this.setConfig({ |
|||
name: name, |
|||
fn: fn |
|||
}); |
|||
this; |
|||
} |
|||
|
|||
Task.prototype.setConfig = function(opts) { |
|||
var key, value; |
|||
|
|||
if (opts == null) { |
|||
opts = {}; |
|||
} |
|||
for (key in opts) { |
|||
if (!__hasProp.call(opts, key)) continue; |
|||
value = opts[key]; |
|||
this[key] = value; |
|||
} |
|||
return this; |
|||
}; |
|||
|
|||
Task.prototype.run = function() { |
|||
var complete, |
|||
_this = this; |
|||
|
|||
complete = function() { |
|||
var args; |
|||
|
|||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; |
|||
_this.running = false; |
|||
_this.result = args; |
|||
return _this.complete(); |
|||
}; |
|||
this.running = true; |
|||
this.emit('run'); |
|||
process.nextTick(function() { |
|||
var args; |
|||
|
|||
args = (_this.args || []).concat([complete]); |
|||
return ambi.apply(null, [_this.fn.bind(_this)].concat(__slice.call(args))); |
|||
}); |
|||
return this; |
|||
}; |
|||
|
|||
Task.prototype.complete = function() { |
|||
var completed; |
|||
|
|||
completed = (this.result != null) && this.running === false; |
|||
if (completed) { |
|||
this.emit.apply(this, ['complete'].concat(__slice.call(this.result))); |
|||
} |
|||
return completed; |
|||
}; |
|||
|
|||
return Task; |
|||
|
|||
})(EventEmitter); |
|||
|
|||
TaskGroup = (function(_super) { |
|||
__extends(TaskGroup, _super); |
|||
|
|||
TaskGroup.prototype.type = 'taskgroup'; |
|||
|
|||
TaskGroup.prototype.running = 0; |
|||
|
|||
TaskGroup.prototype.remaining = null; |
|||
|
|||
TaskGroup.prototype.err = null; |
|||
|
|||
TaskGroup.prototype.results = null; |
|||
|
|||
TaskGroup.prototype.parent = null; |
|||
|
|||
TaskGroup.prototype.paused = true; |
|||
|
|||
TaskGroup.prototype.name = null; |
|||
|
|||
TaskGroup.prototype.fn = null; |
|||
|
|||
TaskGroup.prototype.concurrency = 1; |
|||
|
|||
TaskGroup.prototype.pauseOnError = true; |
|||
|
|||
function TaskGroup() { |
|||
var args, fn, name, |
|||
_this = this; |
|||
|
|||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; |
|||
this.run = __bind(this.run, this); |
|||
this.pause = __bind(this.pause, this); |
|||
this.exit = __bind(this.exit, this); |
|||
this.stop = __bind(this.stop, this); |
|||
this.clear = __bind(this.clear, this); |
|||
this.complete = __bind(this.complete, this); |
|||
this.nextItem = __bind(this.nextItem, this); |
|||
this.nextItems = __bind(this.nextItems, this); |
|||
this.isReady = __bind(this.isReady, this); |
|||
this.hasItems = __bind(this.hasItems, this); |
|||
this.addGroup = __bind(this.addGroup, this); |
|||
this.createGroup = __bind(this.createGroup, this); |
|||
this.addTask = __bind(this.addTask, this); |
|||
this.createTask = __bind(this.createTask, this); |
|||
this.addItem = __bind(this.addItem, this); |
|||
this.setConfig = __bind(this.setConfig, this); |
|||
TaskGroup.__super__.constructor.apply(this, arguments); |
|||
this.err = null; |
|||
this.results = []; |
|||
this.remaining = []; |
|||
name = fn = null; |
|||
if (args.length) { |
|||
if (args.length === 2) { |
|||
name = args[0], fn = args[1]; |
|||
} else if (args.length === 1) { |
|||
fn = args[0]; |
|||
} |
|||
} |
|||
this.setConfig({ |
|||
name: name, |
|||
fn: fn |
|||
}); |
|||
process.nextTick(function() { |
|||
if (_this.fn) { |
|||
args = [_this.addGroup, _this.addTask]; |
|||
_this.addTask(_this.fn.bind(_this)).setConfig({ |
|||
args: args, |
|||
includeInResults: false |
|||
}); |
|||
if (!_this.parent) { |
|||
return _this.run(); |
|||
} |
|||
} |
|||
}); |
|||
this.on('item.complete', function() { |
|||
var args, item; |
|||
|
|||
item = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; |
|||
if (item.includeInResults !== false) { |
|||
_this.results.push(args); |
|||
} |
|||
if (args[0]) { |
|||
_this.err = args[0]; |
|||
} |
|||
if (_this.running > 0) { |
|||
--_this.running; |
|||
} |
|||
if (_this.paused) { |
|||
return; |
|||
} |
|||
if (!_this.complete()) { |
|||
return _this.nextItems(); |
|||
} |
|||
}); |
|||
this; |
|||
} |
|||
|
|||
TaskGroup.prototype.setConfig = function(opts) { |
|||
var key, value; |
|||
|
|||
if (opts == null) { |
|||
opts = {}; |
|||
} |
|||
for (key in opts) { |
|||
if (!__hasProp.call(opts, key)) continue; |
|||
value = opts[key]; |
|||
this[key] = value; |
|||
} |
|||
return this; |
|||
}; |
|||
|
|||
TaskGroup.prototype.getTotals = function() { |
|||
var completed, remaining, running, total; |
|||
|
|||
running = this.running; |
|||
remaining = this.remaining.length; |
|||
completed = this.results.length; |
|||
total = running + remaining + completed; |
|||
return { |
|||
running: running, |
|||
remaining: remaining, |
|||
completed: completed, |
|||
total: total |
|||
}; |
|||
}; |
|||
|
|||
TaskGroup.prototype.addItem = function(item) { |
|||
var me; |
|||
|
|||
me = this; |
|||
item.onAny(function() { |
|||
var args; |
|||
|
|||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; |
|||
return me.emit.apply(me, ["item." + this.event, item].concat(__slice.call(args))); |
|||
}); |
|||
this.emit('add', item); |
|||
this.remaining.push(item); |
|||
if (!this.paused) { |
|||
this.nextItems(); |
|||
} |
|||
return item; |
|||
}; |
|||
|
|||
TaskGroup.prototype.createTask = function() { |
|||
var args, task; |
|||
|
|||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; |
|||
task = (function(func, args, ctor) { |
|||
ctor.prototype = func.prototype; |
|||
var child = new ctor, result = func.apply(child, args); |
|||
return Object(result) === result ? result : child; |
|||
})(Task, args, function(){}); |
|||
return task; |
|||
}; |
|||
|
|||
TaskGroup.prototype.addTask = function() { |
|||
var args, me, task; |
|||
|
|||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; |
|||
me = this; |
|||
task = this.createTask.apply(this, args).setConfig({ |
|||
parent: this |
|||
}); |
|||
task.onAny(function() { |
|||
var args; |
|||
|
|||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; |
|||
return me.emit.apply(me, ["task." + this.event, task].concat(__slice.call(args))); |
|||
}); |
|||
return this.addItem(task); |
|||
}; |
|||
|
|||
TaskGroup.prototype.createGroup = function() { |
|||
var args, group; |
|||
|
|||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; |
|||
group = (function(func, args, ctor) { |
|||
ctor.prototype = func.prototype; |
|||
var child = new ctor, result = func.apply(child, args); |
|||
return Object(result) === result ? result : child; |
|||
})(TaskGroup, args, function(){}); |
|||
return group; |
|||
}; |
|||
|
|||
TaskGroup.prototype.addGroup = function() { |
|||
var args, group, me; |
|||
|
|||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; |
|||
me = this; |
|||
group = this.createGroup.apply(this, args).setConfig({ |
|||
concurrency: this.concurrency, |
|||
parent: this |
|||
}); |
|||
group.onAny(function() { |
|||
var args; |
|||
|
|||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; |
|||
return me.emit.apply(me, ["group." + this.event, group].concat(__slice.call(args))); |
|||
}); |
|||
return this.addItem(group); |
|||
}; |
|||
|
|||
TaskGroup.prototype.hasItems = function() { |
|||
return this.remaining.length !== 0; |
|||
}; |
|||
|
|||
TaskGroup.prototype.isReady = function() { |
|||
return !this.concurrency || this.running < this.concurrency; |
|||
}; |
|||
|
|||
TaskGroup.prototype.nextItems = function() { |
|||
var item, items; |
|||
|
|||
items = []; |
|||
while (true) { |
|||
item = this.nextItem(); |
|||
if (item) { |
|||
items.push(item); |
|||
} else { |
|||
break; |
|||
} |
|||
} |
|||
if (items.length) { |
|||
return items; |
|||
} else { |
|||
return false; |
|||
} |
|||
}; |
|||
|
|||
TaskGroup.prototype.nextItem = function() { |
|||
var nextItem; |
|||
|
|||
if (this.hasItems()) { |
|||
if (this.isReady()) { |
|||
nextItem = this.remaining.shift(); |
|||
++this.running; |
|||
nextItem.run(); |
|||
return nextItem; |
|||
} |
|||
} |
|||
return false; |
|||
}; |
|||
|
|||
TaskGroup.prototype.complete = function() { |
|||
var completed, empty, pause; |
|||
|
|||
pause = this.pauseOnError && this.err; |
|||
empty = this.hasItems() === false && this.running === 0; |
|||
completed = pause || empty; |
|||
if (completed) { |
|||
if (pause) { |
|||
this.pause(); |
|||
} |
|||
this.emit('complete', this.err, this.results); |
|||
this.err = null; |
|||
this.results = []; |
|||
} |
|||
return completed; |
|||
}; |
|||
|
|||
TaskGroup.prototype.clear = function() { |
|||
this.remaining.splice(0); |
|||
return this; |
|||
}; |
|||
|
|||
TaskGroup.prototype.stop = function() { |
|||
this.pause(); |
|||
this.clear(); |
|||
return this; |
|||
}; |
|||
|
|||
TaskGroup.prototype.exit = function(err) { |
|||
if (err) { |
|||
this.err = err; |
|||
} |
|||
this.stop(); |
|||
this.running = 0; |
|||
this.complete(); |
|||
return this; |
|||
}; |
|||
|
|||
TaskGroup.prototype.pause = function() { |
|||
this.paused = true; |
|||
return this; |
|||
}; |
|||
|
|||
TaskGroup.prototype.run = function() { |
|||
var args, |
|||
_this = this; |
|||
|
|||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; |
|||
this.paused = false; |
|||
this.emit('run'); |
|||
process.nextTick(function() { |
|||
if (!_this.complete()) { |
|||
return _this.nextItems(); |
|||
} |
|||
}); |
|||
return this; |
|||
}; |
|||
|
|||
return TaskGroup; |
|||
|
|||
})(EventEmitter); |
|||
|
|||
module.exports = { |
|||
Task: Task, |
|||
TaskGroup: TaskGroup |
|||
}; |
File diff suppressed because one or more lines are too long
@ -0,0 +1,8 @@ |
|||
.travis* |
|||
Cakefile |
|||
Makefile |
|||
History.md |
|||
|
|||
src/ |
|||
out/test/ |
|||
test/ |
@ -0,0 +1,10 @@ |
|||
(The MIT License) |
|||
|
|||
Copyright © 2013+ [Bevry Pty Ltd](http://bevry.me) <us@bevry.me> |
|||
Copyright © 2011-2012 Benjamin Lupton <b@lupton.cc> |
|||
|
|||
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,56 @@ |
|||
# TypeChecker [![Build Status](https://secure.travis-ci.org/bevry/typechecker.png?branch=master)](http://travis-ci.org/bevry/typechecker) |
|||
Utilities to get and check variable types (isString, isPlainObject, isRegExp, etc) |
|||
|
|||
|
|||
|
|||
## Install |
|||
|
|||
### Backend |
|||
|
|||
1. [Install Node.js](http://bevry.me/node/install) |
|||
2. `npm install --save typechecker` |
|||
|
|||
### Frontend |
|||
|
|||
1. [See Browserify](http://browserify.org/) |
|||
|
|||
|
|||
|
|||
## Usage |
|||
|
|||
### Example |
|||
|
|||
``` javascript |
|||
require('typechecker').isRegExp(/^a/) |
|||
``` |
|||
|
|||
### Available Methods |
|||
|
|||
- `getObjectType` (e.g. `[object RegExp]`) |
|||
- `getType` (e.g. `regexp`) |
|||
- `isPlainObject` (checks for no custom prototype) |
|||
- `isError` |
|||
- `isDate` |
|||
- `isArguments` |
|||
- `isFunction` |
|||
- `isRegExp` |
|||
- `isArray` |
|||
- `isNumber` |
|||
- `isString` |
|||
- `isBoolean` |
|||
- `isNull` |
|||
- `isUndefined` |
|||
- `isEmpty` (checks for `null` or `undefined`) |
|||
- `isEmptyObject` (checks for no keys that are its own) |
|||
|
|||
|
|||
|
|||
## History |
|||
You can discover the history inside the [History.md](https://github.com/bevry/typechecker/blob/master/History.md#files) file |
|||
|
|||
|
|||
|
|||
## License |
|||
Licensed under the incredibly [permissive](http://en.wikipedia.org/wiki/Permissive_free_software_licence) [MIT License](http://creativecommons.org/licenses/MIT/) |
|||
<br/>Copyright © 2013+ [Bevry Pty Ltd](http://bevry.me) |
|||
<br/>Copyright © 2011-2012 [Benjamin Arthur Lupton](http://balupton.com) |
@ -0,0 +1,83 @@ |
|||
// Generated by CoffeeScript 1.6.2
|
|||
var typeChecker, |
|||
__hasProp = {}.hasOwnProperty; |
|||
|
|||
typeChecker = { |
|||
getObjectType: function(value) { |
|||
return Object.prototype.toString.call(value); |
|||
}, |
|||
getType: function(value) { |
|||
var result, type, _i, _len, _ref; |
|||
|
|||
result = 'object'; |
|||
_ref = ['Array', 'RegExp', 'Date', 'Function', 'Boolean', 'Number', 'Error', 'String', 'Null', 'Undefined']; |
|||
for (_i = 0, _len = _ref.length; _i < _len; _i++) { |
|||
type = _ref[_i]; |
|||
if (typeChecker['is' + type](value)) { |
|||
result = type.toLowerCase(); |
|||
break; |
|||
} |
|||
} |
|||
return result; |
|||
}, |
|||
isPlainObject: function(value) { |
|||
return typeChecker.isObject(value) && value.__proto__ === Object.prototype; |
|||
}, |
|||
isObject: function(value) { |
|||
return value && typeof value === 'object'; |
|||
}, |
|||
isError: function(value) { |
|||
return value instanceof Error; |
|||
}, |
|||
isDate: function(value) { |
|||
return typeChecker.getObjectType(value) === '[object Date]'; |
|||
}, |
|||
isArguments: function(value) { |
|||
return typeChecker.getObjectType(value) === '[object Arguments]'; |
|||
}, |
|||
isFunction: function(value) { |
|||
return typeChecker.getObjectType(value) === '[object Function]'; |
|||
}, |
|||
isRegExp: function(value) { |
|||
return typeChecker.getObjectType(value) === '[object RegExp]'; |
|||
}, |
|||
isArray: function(value) { |
|||
var _ref; |
|||
|
|||
return (_ref = typeof Array.isArray === "function" ? Array.isArray(value) : void 0) != null ? _ref : typeChecker.getObjectType(value) === '[object Array]'; |
|||
}, |
|||
isNumber: function(value) { |
|||
return typeof value === 'number' || typeChecker.getObjectType(value) === '[object Number]'; |
|||
}, |
|||
isString: function(value) { |
|||
return typeof value === 'string' || typeChecker.getObjectType(value) === '[object String]'; |
|||
}, |
|||
isBoolean: function(value) { |
|||
return value === true || value === false || typeChecker.getObjectType(value) === '[object Boolean]'; |
|||
}, |
|||
isNull: function(value) { |
|||
return value === null; |
|||
}, |
|||
isUndefined: function(value) { |
|||
return typeof value === 'undefined'; |
|||
}, |
|||
isEmpty: function(value) { |
|||
return value != null; |
|||
}, |
|||
isEmptyObject: function(value) { |
|||
var empty, key; |
|||
|
|||
empty = true; |
|||
if (value != null) { |
|||
for (key in value) { |
|||
if (!__hasProp.call(value, key)) continue; |
|||
value = value[key]; |
|||
empty = false; |
|||
break; |
|||
} |
|||
} |
|||
return empty; |
|||
} |
|||
}; |
|||
|
|||
module.exports = typeChecker; |
@ -0,0 +1,56 @@ |
|||
{ |
|||
"name": "typechecker", |
|||
"version": "2.0.1", |
|||
"description": "Utilities to get and check variable types (isString, isPlainObject, isRegExp, etc)", |
|||
"homepage": "https://github.com/bevry/typechecker", |
|||
"keywords": [ |
|||
"types", |
|||
"type" |
|||
], |
|||
"author": { |
|||
"name": "Bevry Pty Ltd", |
|||
"email": "us@bevry.me", |
|||
"url": "http://bevry.me" |
|||
}, |
|||
"maintainers": [ |
|||
{ |
|||
"name": "Benjamin Lupton", |
|||
"email": "b@lupton.cc", |
|||
"url": "https://github.com/balupton" |
|||
} |
|||
], |
|||
"contributors": [ |
|||
{ |
|||
"name": "Benjamin Lupton", |
|||
"email": "b@lupton.cc", |
|||
"url": "https://github.com/balupton" |
|||
} |
|||
], |
|||
"bugs": { |
|||
"url": "https://github.com/bevry/typechecker/issues" |
|||
}, |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "http://github.com/bevry/typechecker.git" |
|||
}, |
|||
"engines": { |
|||
"node": ">=0.4" |
|||
}, |
|||
"dependencies": {}, |
|||
"devDependencies": { |
|||
"coffee-script": "~1.6.2", |
|||
"joe": "~1.1.2", |
|||
"chai": "~1.5.0" |
|||
}, |
|||
"directories": { |
|||
"lib": "./out/lib" |
|||
}, |
|||
"scripts": { |
|||
"test": "node ./out/test/typechecker-test.js --joe-reporter=list" |
|||
}, |
|||
"main": "./out/lib/typechecker.js", |
|||
"readme": "# TypeChecker [![Build Status](https://secure.travis-ci.org/bevry/typechecker.png?branch=master)](http://travis-ci.org/bevry/typechecker)\nUtilities to get and check variable types (isString, isPlainObject, isRegExp, etc)\n\n\n\n## Install\n\n### Backend\n\n1. [Install Node.js](http://bevry.me/node/install)\n2. `npm install --save typechecker`\n\n### Frontend\n\n1. [See Browserify](http://browserify.org/)\n\n\n\n## Usage\n\n### Example\n\n``` javascript\nrequire('typechecker').isRegExp(/^a/)\n```\n\n### Available Methods\n\n- `getObjectType` (e.g. `[object RegExp]`)\n- `getType` (e.g. `regexp`)\n- `isPlainObject` (checks for no custom prototype)\n- `isError`\n- `isDate`\n- `isArguments`\n- `isFunction`\n- `isRegExp`\n- `isArray`\n- `isNumber`\n- `isString`\n- `isBoolean`\n- `isNull`\n- `isUndefined`\n- `isEmpty` (checks for `null` or `undefined`)\n- `isEmptyObject` (checks for no keys that are its own)\n\n\n\n## History\nYou can discover the history inside the [History.md](https://github.com/bevry/typechecker/blob/master/History.md#files) file\n\n\n\n## License\nLicensed under the incredibly [permissive](http://en.wikipedia.org/wiki/Permissive_free_software_licence) [MIT License](http://creativecommons.org/licenses/MIT/)\n<br/>Copyright © 2013+ [Bevry Pty Ltd](http://bevry.me)\n<br/>Copyright © 2011-2012 [Benjamin Arthur Lupton](http://balupton.com)\n", |
|||
"readmeFilename": "README.md", |
|||
"_id": "typechecker@2.0.1", |
|||
"_from": "typechecker@~2.0.1" |
|||
} |
@ -0,0 +1,583 @@ |
|||
// Generated by CoffeeScript 1.6.3
|
|||
var TaskGroup, extractOptsAndCallback, isWindows, safefs, safeps, typeChecker, _base, _ref, _ref1, |
|||
__slice = [].slice; |
|||
|
|||
safeps = null; |
|||
|
|||
TaskGroup = require('taskgroup').TaskGroup; |
|||
|
|||
typeChecker = require('typechecker'); |
|||
|
|||
safefs = require('safefs'); |
|||
|
|||
extractOptsAndCallback = require('extract-opts').extractOptsAndCallback; |
|||
|
|||
isWindows = (typeof process !== "undefined" && process !== null ? (_ref = process.platform) != null ? _ref.indexOf('win') : void 0 : void 0) === 0; |
|||
|
|||
if (global.safepsGlobal == null) { |
|||
global.safepsGlobal = {}; |
|||
} |
|||
|
|||
if ((_base = global.safepsGlobal).pool == null) { |
|||
_base.pool = new TaskGroup().setConfig({ |
|||
concurrency: (_ref1 = process.env.NODE_MAX_OPEN_PROCESSES) != null ? _ref1 : 100, |
|||
pauseOnError: false |
|||
}).run(); |
|||
} |
|||
|
|||
safeps = { |
|||
openProcess: function(fn) { |
|||
global.safepsGlobal.pool.addTask(fn); |
|||
return safeps; |
|||
}, |
|||
requireFresh: function(path) { |
|||
var result; |
|||
path = require('path').resolve(path); |
|||
delete require.cache[path]; |
|||
result = require(path); |
|||
delete require.cache[path]; |
|||
return result; |
|||
}, |
|||
isWindows: function() { |
|||
return isWindows; |
|||
}, |
|||
getLocaleCode: function(lang) { |
|||
var localeCode; |
|||
if (lang == null) { |
|||
lang = null; |
|||
} |
|||
if (lang == null) { |
|||
lang = process.env.LANG || ''; |
|||
} |
|||
localeCode = lang.replace(/\..+/, '').replace('-', '_').toLowerCase() || null; |
|||
return localeCode; |
|||
}, |
|||
getLanguageCode: function(localeCode) { |
|||
var languageCode; |
|||
if (localeCode == null) { |
|||
localeCode = null; |
|||
} |
|||
localeCode = safeps.getLocaleCode(localeCode) || ''; |
|||
languageCode = localeCode.replace(/^([a-z]+)[_-]([a-z]+)$/i, '$1').toLowerCase() || null; |
|||
return languageCode; |
|||
}, |
|||
getCountryCode: function(localeCode) { |
|||
var countryCode; |
|||
if (localeCode == null) { |
|||
localeCode = null; |
|||
} |
|||
localeCode = safeps.getLocaleCode(localeCode) || ''; |
|||
countryCode = localeCode.replace(/^([a-z]+)[_-]([a-z]+)$/i, '$2').toLowerCase() || null; |
|||
return countryCode; |
|||
}, |
|||
spawn: function(command, opts, next) { |
|||
safeps.openProcess(function(closeProcess) { |
|||
var code, pid, signal, spawn, stderr, stdout, tasks, _ref2; |
|||
spawn = require('child_process').spawn; |
|||
_ref2 = extractOptsAndCallback(opts, next), opts = _ref2[0], next = _ref2[1]; |
|||
if (opts.safe == null) { |
|||
opts.safe = true; |
|||
} |
|||
if (opts.env == null) { |
|||
opts.env = process.env; |
|||
} |
|||
if (opts.read == null) { |
|||
opts.read = true; |
|||
} |
|||
if (opts.output == null) { |
|||
opts.output = false; |
|||
} |
|||
if (opts.stdin == null) { |
|||
opts.stdin = null; |
|||
} |
|||
if (opts.env === false) { |
|||
delete opts.env; |
|||
} |
|||
if (typeChecker.isString(command)) { |
|||
command = command.split(' '); |
|||
} |
|||
pid = null; |
|||
stdout = null; |
|||
stderr = null; |
|||
code = null; |
|||
signal = null; |
|||
tasks = new TaskGroup().once('complete', function(err) { |
|||
closeProcess(); |
|||
return typeof next === "function" ? next(err, stdout, stderr, code, signal) : void 0; |
|||
}); |
|||
if (opts.safe) { |
|||
tasks.addTask(function(complete) { |
|||
return safeps.getExecPath(command[0], function(err, execPath) { |
|||
if (err) { |
|||
return complete(err); |
|||
} |
|||
command[0] = execPath; |
|||
return complete(); |
|||
}); |
|||
}); |
|||
} |
|||
tasks.addTask(function(complete) { |
|||
var d; |
|||
d = require('domain').create(); |
|||
d.on('error', function(err) { |
|||
return complete(err); |
|||
}); |
|||
return d.run(function() { |
|||
var _ref3, _ref4, _ref5, _ref6; |
|||
pid = spawn(command[0], command.slice(1), opts); |
|||
if (opts.read) { |
|||
stdout = ''; |
|||
stderr = ''; |
|||
if ((_ref3 = pid.stdout) != null) { |
|||
_ref3.on('data', function(data) { |
|||
if (opts.output) { |
|||
process.stdout.write(data); |
|||
} |
|||
return stdout += data.toString(); |
|||
}); |
|||
} |
|||
if ((_ref4 = pid.stderr) != null) { |
|||
_ref4.on('data', function(data) { |
|||
if (opts.output) { |
|||
process.stderr.write(data); |
|||
} |
|||
return stderr += data.toString(); |
|||
}); |
|||
} |
|||
} |
|||
pid.on('close', function(_code, _signal) { |
|||
var err; |
|||
code = _code; |
|||
signal = _signal; |
|||
err = null; |
|||
if (code !== 0) { |
|||
err = new Error(stderr || 'exited with a non-zero status code'); |
|||
} |
|||
return complete(err); |
|||
}); |
|||
if (opts.stdin) { |
|||
if ((_ref5 = pid.stdin) != null) { |
|||
_ref5.write(opts.stdin); |
|||
} |
|||
return (_ref6 = pid.stdin) != null ? _ref6.end() : void 0; |
|||
} |
|||
}); |
|||
}); |
|||
return tasks.run(); |
|||
}); |
|||
return this; |
|||
}, |
|||
spawnMultiple: function(commands, opts, next) { |
|||
var results, tasks, _ref2; |
|||
_ref2 = extractOptsAndCallback(opts, next), opts = _ref2[0], next = _ref2[1]; |
|||
if (opts.concurrency == null) { |
|||
opts.concurrency = 1; |
|||
} |
|||
results = []; |
|||
tasks = new TaskGroup().setConfig({ |
|||
concurrency: opts.concurrency |
|||
}).once('complete', function(err) { |
|||
return next(err, results); |
|||
}); |
|||
if (!typeChecker.isArray(commands)) { |
|||
commands = [commands]; |
|||
} |
|||
commands.forEach(function(command) { |
|||
return tasks.addTask(function(complete) { |
|||
return safeps.spawn(command, opts, function() { |
|||
var args, err; |
|||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; |
|||
err = args[0] || null; |
|||
results.push(args); |
|||
return complete(err); |
|||
}); |
|||
}); |
|||
}); |
|||
tasks.run(); |
|||
return this; |
|||
}, |
|||
spawnCommand: function(command, args, opts, next) { |
|||
var pieces, _ref2; |
|||
if (args == null) { |
|||
args = []; |
|||
} |
|||
_ref2 = extractOptsAndCallback(opts, next), opts = _ref2[0], next = _ref2[1]; |
|||
pieces = [command].concat(args); |
|||
safeps.spawn(pieces, opts, next); |
|||
return this; |
|||
}, |
|||
spawnCommands: function(command, multiArgs, opts, next) { |
|||
var args, pieces, _i, _len, _ref2; |
|||
if (multiArgs == null) { |
|||
multiArgs = []; |
|||
} |
|||
_ref2 = extractOptsAndCallback(opts, next), opts = _ref2[0], next = _ref2[1]; |
|||
pieces = []; |
|||
for (_i = 0, _len = multiArgs.length; _i < _len; _i++) { |
|||
args = multiArgs[_i]; |
|||
pieces.push([command].concat(args)); |
|||
} |
|||
safeps.spawnMultiple(pieces, opts, next); |
|||
return this; |
|||
}, |
|||
exec: function(command, opts, next) { |
|||
safeps.openProcess(function(closeProcess) { |
|||
var exec, _ref2; |
|||
exec = require('child_process').exec; |
|||
_ref2 = extractOptsAndCallback(opts, next), opts = _ref2[0], next = _ref2[1]; |
|||
if (opts.output == null) { |
|||
opts.output = false; |
|||
} |
|||
if (opts.output) { |
|||
opts.stdio = 'inherit'; |
|||
delete opts.output; |
|||
} |
|||
return exec(command, opts, function(err, stdout, stderr) { |
|||
closeProcess(); |
|||
return typeof next === "function" ? next(err, stdout, stderr) : void 0; |
|||
}); |
|||
}); |
|||
return this; |
|||
}, |
|||
execMultiple: function(commands, opts, next) { |
|||
var results, tasks, _ref2; |
|||
_ref2 = extractOptsAndCallback(opts, next), opts = _ref2[0], next = _ref2[1]; |
|||
if (opts.concurrency == null) { |
|||
opts.concurrency = 1; |
|||
} |
|||
results = []; |
|||
tasks = new TaskGroup().setConfig({ |
|||
concurrency: opts.concurrency |
|||
}).once('complete', function(err) { |
|||
return next(err, results); |
|||
}); |
|||
if (!typeChecker.isArray(commands)) { |
|||
commands = [commands]; |
|||
} |
|||
commands.forEach(function(command) { |
|||
return tasks.addTask(function(complete) { |
|||
return safeps.exec(this.command, opts, function() { |
|||
var args, err; |
|||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; |
|||
err = args[0] || null; |
|||
results.push(args); |
|||
return complete(err); |
|||
}); |
|||
}); |
|||
}); |
|||
tasks.run(); |
|||
return this; |
|||
}, |
|||
determineExecPath: function(possibleExecPaths, next) { |
|||
var execPath, pathUtil, tasks; |
|||
pathUtil = require('path'); |
|||
execPath = null; |
|||
tasks = new TaskGroup().once('complete', function(err) { |
|||
return next(err, execPath); |
|||
}); |
|||
possibleExecPaths.forEach(function(possibleExecPath) { |
|||
if (!possibleExecPath) { |
|||
return; |
|||
} |
|||
return tasks.addTask(function(complete) { |
|||
if (execPath) { |
|||
return complete(); |
|||
} |
|||
possibleExecPath = pathUtil.resolve(possibleExecPath); |
|||
return safefs.exists(possibleExecPath, function(exists) { |
|||
if (!exists) { |
|||
return complete(); |
|||
} |
|||
return safeps.spawn([possibleExecPath, '--version'], function(err, stdout, stderr, code, signal) { |
|||
if (((err != null ? err.message : void 0) || '').indexOf('spawn') !== -1) { |
|||
return complete(); |
|||
} |
|||
execPath = possibleExecPath; |
|||
return tasks.exit(); |
|||
}); |
|||
}); |
|||
}); |
|||
}); |
|||
tasks.run(); |
|||
return this; |
|||
}, |
|||
getEnvironmentPaths: function() { |
|||
var environmentPaths, pathUtil; |
|||
pathUtil = require('path'); |
|||
environmentPaths = process.env.PATH.split(pathUtil.delimiter); |
|||
return environmentPaths; |
|||
}, |
|||
getStandardExecPaths: function(execName) { |
|||
var pathUtil, standardExecPaths; |
|||
pathUtil = require('path'); |
|||
standardExecPaths = [process.cwd()].concat(safeps.getEnvironmentPaths()); |
|||
if (execName) { |
|||
standardExecPaths = standardExecPaths.map(function(path) { |
|||
return pathUtil.join(path, execName); |
|||
}); |
|||
} |
|||
return standardExecPaths; |
|||
}, |
|||
getPossibleExecPaths: function(execName) { |
|||
var possibleExecPaths, standardExecPath, standardExecPaths, _i, _len; |
|||
if (isWindows && execName.indexOf('.') === -1) { |
|||
standardExecPaths = safeps.getStandardExecPaths(execName); |
|||
possibleExecPaths = []; |
|||
for (_i = 0, _len = standardExecPaths.length; _i < _len; _i++) { |
|||
standardExecPath = standardExecPaths[_i]; |
|||
possibleExecPaths.push(standardExecPath, standardExecPath + '.exe', standardExecPath + '.cmd', standardExecPath + '.bat'); |
|||
} |
|||
} else { |
|||
possibleExecPaths = safeps.getStandardExecPaths(execName); |
|||
} |
|||
return possibleExecPaths; |
|||
}, |
|||
execPathCache: {}, |
|||
getExecPath: function(execName, next) { |
|||
var execNameCapitalized, getExecMethodName, possibleExecPaths; |
|||
if (execName.substr(0, 1) === '/' || execName.substr(1, 1) === ':') { |
|||
return next(null, execName); |
|||
} |
|||
if (safeps.execPathCache[execName] != null) { |
|||
return next(null, safeps.execPathCache[execName]); |
|||
} |
|||
execNameCapitalized = execName[0].toUpperCase() + execName.substr(1); |
|||
getExecMethodName = 'get' + execNameCapitalized + 'Path'; |
|||
if (safeps[getExecMethodName] != null) { |
|||
safeps[getExecMethodName](next); |
|||
} else { |
|||
possibleExecPaths = safeps.getPossibleExecPaths(execName); |
|||
safeps.determineExecPath(possibleExecPaths, function(err, execPath) { |
|||
if (err) { |
|||
return next(err); |
|||
} |
|||
if (!execPath) { |
|||
err = new Error('Could not locate the ' + execName + ' executable path'); |
|||
return next(err); |
|||
} |
|||
safeps.execPathCache[execName] = execPath; |
|||
return next(null, execPath); |
|||
}); |
|||
} |
|||
return this; |
|||
}, |
|||
getHomePath: function(next) { |
|||
var homePath; |
|||
if (safeps.cachedHomePath != null) { |
|||
next(null, safeps.cachedHomePath); |
|||
return this; |
|||
} |
|||
homePath = process.env.USERPROFILE || process.env.HOME; |
|||
homePath || (homePath = null); |
|||
safeps.cachedHomePath = homePath; |
|||
next(null, homePath); |
|||
return this; |
|||
}, |
|||
getTmpPath: function(next) { |
|||
var pathUtil, tmpDirName, tmpPath; |
|||
if (safeps.cachedTmpPath != null) { |
|||
next(null, safeps.cachedTmpPath); |
|||
return this; |
|||
} |
|||
pathUtil = require('path'); |
|||
tmpDirName = isWindows ? 'temp' : 'tmp'; |
|||
tmpPath = process.env.TMPDIR || process.env.TMP || process.env.TEMP; |
|||
if (!tmpPath) { |
|||
safeps.getHomePath(function(err, homePath) { |
|||
if (err) { |
|||
return next(err); |
|||
} |
|||
tmpPath = pathUtil.resolve(homePath, tmpDirName); |
|||
if (!tmpPath) { |
|||
return tmpPath = isWindows ? pathUtil.resolve(process.env.windir || 'C:\\Windows', tmpDirName) : '/tmp'; |
|||
} |
|||
}); |
|||
} |
|||
tmpPath || (tmpPath = null); |
|||
safeps.cachedTmpPath = tmpPath; |
|||
next(null, tmpPath); |
|||
return this; |
|||
}, |
|||
getGitPath: function(next) { |
|||
var execName, possibleExecPaths; |
|||
if (safeps.cachedGitPath != null) { |
|||
next(null, safeps.cachedGitPath); |
|||
return this; |
|||
} |
|||
execName = isWindows ? 'git.exe' : 'git'; |
|||
possibleExecPaths = []; |
|||
if (process.env.GIT_PATH) { |
|||
possibleExecPaths.push(process.env.GIT_PATH); |
|||
} |
|||
if (process.env.GITPATH) { |
|||
possibleExecPaths.push(process.env.GITPATH); |
|||
} |
|||
possibleExecPaths = possibleExecPaths.concat(safeps.getStandardExecPaths(execName)).concat(isWindows ? ["/Program Files (x64)/Git/bin/" + execName, "/Program Files (x86)/Git/bin/" + execName, "/Program Files/Git/bin/" + execName] : ["/usr/local/bin/" + execName, "/usr/bin/" + execName, "~/bin/" + execName]); |
|||
safeps.determineExecPath(possibleExecPaths, function(err, execPath) { |
|||
safeps.cachedGitPath = execPath; |
|||
if (err) { |
|||
return next(err); |
|||
} |
|||
if (!execPath) { |
|||
err = new Error('Could not locate git binary'); |
|||
return next(err); |
|||
} |
|||
return next(null, execPath); |
|||
}); |
|||
return this; |
|||
}, |
|||
getNodePath: function(next) { |
|||
var execName, possibleExecPaths; |
|||
if (safeps.cachedNodePath != null) { |
|||
next(null, safeps.cachedNodePath); |
|||
return this; |
|||
} |
|||
execName = isWindows ? 'node.exe' : 'node'; |
|||
possibleExecPaths = []; |
|||
if (process.env.NODE_PATH) { |
|||
possibleExecPaths.push(process.env.NODE_PATH); |
|||
} |
|||
if (process.env.NODEPATH) { |
|||
possibleExecPaths.push(process.env.NODEPATH); |
|||
} |
|||
if (/node(.exe)?$/.test(process.execPath)) { |
|||
possibleExecPaths.push(process.execPath); |
|||
} |
|||
possibleExecPaths = possibleExecPaths.concat(safeps.getStandardExecPaths(execName)).concat(isWindows ? ["/Program Files (x64)/nodejs/" + execName, "/Program Files (x86)/nodejs/" + execName, "/Program Files/nodejs/" + execName] : ["/usr/local/bin/" + execName, "/usr/bin/" + execName, "~/bin/" + execName]); |
|||
safeps.determineExecPath(possibleExecPaths, function(err, execPath) { |
|||
safeps.cachedNodePath = execPath; |
|||
if (err) { |
|||
return next(err); |
|||
} |
|||
if (!execPath) { |
|||
err = new Error('Could not locate node binary'); |
|||
return next(err); |
|||
} |
|||
return next(null, execPath); |
|||
}); |
|||
return this; |
|||
}, |
|||
getNpmPath: function(next) { |
|||
var execName, possibleExecPaths; |
|||
if (safeps.cachedNpmPath != null) { |
|||
next(null, safeps.cachedNpmPath); |
|||
return this; |
|||
} |
|||
execName = isWindows ? 'npm.cmd' : 'npm'; |
|||
possibleExecPaths = []; |
|||
if (process.env.NPM_PATH) { |
|||
possibleExecPaths.push(process.env.NPM_PATH); |
|||
} |
|||
if (process.env.NPMPATH) { |
|||
possibleExecPaths.push(process.env.NPMPATH); |
|||
} |
|||
if (/node(.exe)?$/.test(process.execPath)) { |
|||
possibleExecPaths.push(process.execPath.replace(/node(.exe)?$/, execName)); |
|||
} |
|||
possibleExecPaths = possibleExecPaths.concat(safeps.getStandardExecPaths(execName)).concat(isWindows ? ["/Program Files (x64)/nodejs/" + execName, "/Program Files (x86)/nodejs/" + execName, "/Program Files/nodejs/" + execName] : ["/usr/local/bin/" + execName, "/usr/bin/" + execName, "~/node_modules/.bin/" + execName]); |
|||
safeps.determineExecPath(possibleExecPaths, function(err, execPath) { |
|||
safeps.cachedNpmPath = execPath; |
|||
if (err) { |
|||
return next(err); |
|||
} |
|||
if (!execPath) { |
|||
err = new Error('Could not locate npm binary'); |
|||
return next(err); |
|||
} |
|||
return next(null, execPath); |
|||
}); |
|||
return this; |
|||
}, |
|||
initGitRepo: function(opts, next) { |
|||
var commands, _ref2; |
|||
_ref2 = extractOptsAndCallback(opts, next), opts = _ref2[0], next = _ref2[1]; |
|||
if (opts.path) { |
|||
opts.cwd = opts.path; |
|||
delete opts.path; |
|||
} |
|||
opts.cwd || (opts.cwd = process.cwd()); |
|||
opts.remote || (opts.remote = 'origin'); |
|||
opts.branch || (opts.branch = 'master'); |
|||
commands = []; |
|||
commands.push(['init']); |
|||
if (opts.url) { |
|||
commands.push(['remote', 'add', opts.remote, opts.url]); |
|||
} |
|||
commands.push(['fetch', opts.remote]); |
|||
commands.push(['pull', opts.remote, opts.branch]); |
|||
commands.push(['submodule', 'init']); |
|||
commands.push(['submodule', 'update', '--recursive']); |
|||
safeps.spawnCommands('git', commands, opts, next); |
|||
return this; |
|||
}, |
|||
initOrPullGitRepo: function(opts, next) { |
|||
var _ref2, |
|||
_this = this; |
|||
_ref2 = extractOptsAndCallback(opts, next), opts = _ref2[0], next = _ref2[1]; |
|||
if (opts.path) { |
|||
opts.cwd = opts.path; |
|||
delete opts.path; |
|||
} |
|||
opts.cwd || (opts.cwd = process.cwd()); |
|||
opts.remote || (opts.remote = 'origin'); |
|||
opts.branch || (opts.branch = 'master'); |
|||
safefs.ensurePath(opts.cwd, function(err, exists) { |
|||
if (err) { |
|||
return complete(err); |
|||
} |
|||
if (exists) { |
|||
return safeps.spawnCommand('git', ['pull', opts.remote, opts.branch], opts, function() { |
|||
var err, result; |
|||
err = arguments[0], result = 2 <= arguments.length ? __slice.call(arguments, 1) : []; |
|||
return next(err, 'pull', result); |
|||
}); |
|||
} else { |
|||
return safeps.initGitRepo(opts, function(err, result) { |
|||
return next(err, 'init', result); |
|||
}); |
|||
} |
|||
}); |
|||
return this; |
|||
}, |
|||
initNodeModules: function(opts, next) { |
|||
var nodeModulesPath, packageJsonPath, partTwo, pathUtil, _ref2; |
|||
pathUtil = require('path'); |
|||
_ref2 = extractOptsAndCallback(opts, next), opts = _ref2[0], next = _ref2[1]; |
|||
if (opts.path) { |
|||
opts.cwd = opts.path; |
|||
delete opts.path; |
|||
} |
|||
opts.cwd || (opts.cwd = process.cwd()); |
|||
if (opts.args == null) { |
|||
opts.args = []; |
|||
} |
|||
if (opts.force == null) { |
|||
opts.force = false; |
|||
} |
|||
packageJsonPath = pathUtil.join(opts.cwd, 'package.json'); |
|||
nodeModulesPath = pathUtil.join(opts.cwd, 'node_modules'); |
|||
partTwo = function() { |
|||
return safefs.exists(packageJsonPath, function(exists) { |
|||
var command; |
|||
if (!exists) { |
|||
return next(); |
|||
} |
|||
command = ['install'].concat(opts.args); |
|||
return safeps.spawnCommand('npm', command, opts, next); |
|||
}); |
|||
}; |
|||
if (opts.force === false) { |
|||
safefs.exists(nodeModulesPath, function(exists) { |
|||
if (exists) { |
|||
return next(); |
|||
} |
|||
return partTwo(); |
|||
}); |
|||
} else { |
|||
partTwo(); |
|||
} |
|||
return this; |
|||
} |
|||
}; |
|||
|
|||
module.exports = safeps; |
File diff suppressed because one or more lines are too long
@ -0,0 +1,36 @@ |
|||
# Contributing |
|||
|
|||
## Support |
|||
|
|||
[Post your question on StackOverflow with the `docpad` tag](http://stackoverflow.com/questions/tagged/docpad) |
|||
|
|||
|
|||
## Bug reports |
|||
|
|||
[Post your bug report on the GitHub Issue Tracker for this project](https://github.com/docpad/docpad-plugin-handlebars/issues) |
|||
|
|||
|
|||
## Development |
|||
|
|||
### Install dependencies |
|||
|
|||
``` bash |
|||
npm install; npm install -g coffee-script |
|||
``` |
|||
|
|||
### Setup for development |
|||
|
|||
``` bash |
|||
cake setup |
|||
``` |
|||
|
|||
### Watch and compile |
|||
|
|||
``` bash |
|||
cake watch |
|||
``` |
|||
|
|||
|
|||
## Testing |
|||
|
|||
No tests yet! |
@ -0,0 +1,9 @@ |
|||
# The MIT License |
|||
|
|||
Copyright © 2012+ [Mike Moulton](http://meltmedia.com) <mike@meltmedia.com> |
|||
|
|||
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,52 @@ |
|||
{ |
|||
"predef": [ |
|||
"console", |
|||
"Ember", |
|||
"DS", |
|||
"Handlebars", |
|||
"Metamorph", |
|||
"ember_assert", |
|||
"ember_warn", |
|||
"ember_deprecate", |
|||
"ember_deprecateFunc", |
|||
"require", |
|||
"suite", |
|||
"equal", |
|||
"equals", |
|||
"test", |
|||
"testBoth", |
|||
"raises", |
|||
"deepEqual", |
|||
"start", |
|||
"stop", |
|||
"ok", |
|||
"strictEqual", |
|||
"module" |
|||
], |
|||
|
|||
"node" : true, |
|||
"es5" : true, |
|||
"browser" : true, |
|||
|
|||
"boss" : true, |
|||
"curly": false, |
|||
"debug": false, |
|||
"devel": false, |
|||
"eqeqeq": true, |
|||
"evil": true, |
|||
"forin": false, |
|||
"immed": false, |
|||
"laxbreak": false, |
|||
"newcap": true, |
|||
"noarg": true, |
|||
"noempty": false, |
|||
"nonew": false, |
|||
"nomen": false, |
|||
"onevar": false, |
|||
"plusplus": false, |
|||
"regexp": false, |
|||
"undef": true, |
|||
"sub": true, |
|||
"strict": false, |
|||
"white": false |
|||
} |
@ -0,0 +1,36 @@ |
|||
# Contributing |
|||
|
|||
## Support |
|||
|
|||
[Post your question on StackOverflow with the `docpad` tag](http://stackoverflow.com/questions/tagged/docpad) |
|||
|
|||
|
|||
## Bug reports |
|||
|
|||
[Post your bug report on the GitHub Issue Tracker for this project](https://github.com/docpad/docpad-plugin-jade/issues) |
|||
|
|||
|
|||
## Development |
|||
|
|||
### Install dependencies |
|||
|
|||
``` bash |
|||
npm install; npm install -g coffee-script |
|||
``` |
|||
|
|||
### Setup for development |
|||
|
|||
``` bash |
|||
cake setup |
|||
``` |
|||
|
|||
### Watch and compile |
|||
|
|||
``` bash |
|||
cake watch |
|||
``` |
|||
|
|||
|
|||
## Testing |
|||
|
|||
No tests yet! |
@ -0,0 +1,10 @@ |
|||
# The MIT License |
|||
|
|||
Copyright © 2012+ [Bevry Pty Ltd](http://bevry.me) <us@bevry.me> |
|||
<br/>Copyright © 2011 [Benjamin Lupton](http://balupton.com) <b@lupton.cc> |
|||
|
|||
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,16 @@ |
|||
{ |
|||
"name": "jade", |
|||
"repo": "visionmedia/jade", |
|||
"description": "Jade template runtime", |
|||
"version": "0.31.2", |
|||
"keywords": [ |
|||
"template" |
|||
], |
|||
"dependencies": {}, |
|||
"development": {}, |
|||
"license": "MIT", |
|||
"scripts": [ |
|||
"lib/runtime.js" |
|||
], |
|||
"main": "lib/runtime.js" |
|||
} |
@ -0,0 +1,18 @@ |
|||
/*! |
|||
* Jade - filters |
|||
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca> |
|||
* MIT Licensed |
|||
*/ |
|||
|
|||
module.exports = filter; |
|||
function filter(name, str, options) { |
|||
if (typeof filter[name] === 'function') { |
|||
var res = filter[name](str, options); |
|||
} else { |
|||
throw new Error('unknown filter ":' + name + '"'); |
|||
} |
|||
return res; |
|||
} |
|||
filter.exists = function (name, str, options) { |
|||
return typeof filter[name] === 'function'; |
|||
}; |
@ -0,0 +1 @@ |
|||
jade.js |
@ -0,0 +1,16 @@ |
|||
lib-cov |
|||
*.seed |
|||
*.log |
|||
*.csv |
|||
*.dat |
|||
*.out |
|||
*.pid |
|||
*.gz |
|||
|
|||
pids |
|||
logs |
|||
results |
|||
|
|||
npm-debug.log |
|||
|
|||
node_modules |
@ -0,0 +1,4 @@ |
|||
language: node_js |
|||
node_js: |
|||
- "0.10" |
|||
- "0.8" |
@ -0,0 +1,123 @@ |
|||
# character-parser |
|||
|
|||
Parse JavaScript one character at a time to look for snippets in Templates. This is not a validator, it's just designed to allow you to have sections of JavaScript delimited by brackets robustly. |
|||
|
|||
[![Build Status](https://travis-ci.org/ForbesLindesay/character-parser.png?branch=master)](https://travis-ci.org/ForbesLindesay/character-parser) |
|||
|
|||
## Installation |
|||
|
|||
npm install character-parser |
|||
|
|||
## Usage |
|||
|
|||
Work out how much depth changes: |
|||
|
|||
```js |
|||
var state = parse('foo(arg1, arg2, {\n foo: [a, b\n'); |
|||
assert(state.roundDepth === 1); |
|||
assert(state.curlyDepth === 1); |
|||
assert(state.squareDepth === 1); |
|||
parse(' c, d]\n })', state); |
|||
assert(state.squareDepth === 0); |
|||
assert(state.curlyDepth === 0); |
|||
assert(state.roundDepth === 0); |
|||
``` |
|||
|
|||
### Bracketed Expressions |
|||
|
|||
Find all the contents of a bracketed expression: |
|||
|
|||
```js |
|||
var section = parser.parseMax('foo="(", bar="}") bing bong'); |
|||
assert(section.start === 0); |
|||
assert(section.end === 16);//exclusive end of string |
|||
assert(section.src = 'foo="(", bar="}"'); |
|||
|
|||
|
|||
var section = parser.parseMax('{foo="(", bar="}"} bing bong', {start: 1}); |
|||
assert(section.start === 1); |
|||
assert(section.end === 17);//exclusive end of string |
|||
assert(section.src = 'foo="(", bar="}"'); |
|||
``` |
|||
|
|||
The bracketed expression parsing simply parses up to but excluding the first unmatched closed bracket (`)`, `}`, `]`). It is clever enough to ignore brackets in comments or strings. |
|||
|
|||
|
|||
### Custom Delimited Expressions |
|||
|
|||
Find code up to a custom delimiter: |
|||
|
|||
```js |
|||
var section = parser.parseUntil('foo.bar("%>").baz%> bing bong', '%>'); |
|||
assert(section.start === 0); |
|||
assert(section.end === 17);//exclusive end of string |
|||
assert(section.src = 'foo.bar("%>").baz'); |
|||
|
|||
var section = parser.parseUntil('<%foo.bar("%>").baz%> bing bong', '%>', {start: 2}); |
|||
assert(section.start === 2); |
|||
assert(section.end === 19);//exclusive end of string |
|||
assert(section.src = 'foo.bar("%>").baz'); |
|||
``` |
|||
|
|||
Delimiters are ignored if they are inside strings or comments. |
|||
|
|||
## API |
|||
|
|||
### parse(str, state = defaultState(), options = {start: 0, end: src.length}) |
|||
|
|||
Parse a string starting at the index start, and return the state after parsing that string. |
|||
|
|||
If you want to parse one string in multiple sections you should keep passing the resulting state to the next parse operation. |
|||
|
|||
The resulting object has the structure: |
|||
|
|||
```js |
|||
{ |
|||
lineComment: false, //true if inside a line comment |
|||
blockComment: false, //true if inside a block comment |
|||
|
|||
singleQuote: false, //true if inside a single quoted string |
|||
doubleQuote: false, //true if inside a double quoted string |
|||
escaped: false, //true if in a string and the last character was an escape character |
|||
|
|||
roundDepth: 0, //number of un-closed open `(` brackets |
|||
curlyDepth: 0, //number of un-closed open `{` brackets |
|||
squareDepth: 0 //number of un-closed open `[` brackets |
|||
} |
|||
``` |
|||
|
|||
### parseMax(src, options = {start: 0}) |
|||
|
|||
Parses the source until the first unmatched close bracket (any of `)`, `}`, `]`). It returns an object with the structure: |
|||
|
|||
```js |
|||
{ |
|||
start: 0,//index of first character of string |
|||
end: 13,//index of first character after the end of string |
|||
src: 'source string' |
|||
} |
|||
``` |
|||
|
|||
### parseUntil(src, delimiter, options = {start: 0, includeLineComment: false}) |
|||
|
|||
Parses the source until the first occurence of `delimiter` which is not in a string or a comment. If `includeLineComment` is `true`, it will still count if the delimiter occurs in a line comment, but not in a block comment. It returns an object with the structure: |
|||
|
|||
```js |
|||
{ |
|||
start: 0,//index of first character of string |
|||
end: 13,//index of first character after the end of string |
|||
src: 'source string' |
|||
} |
|||
``` |
|||
|
|||
### parseChar(character, state = defaultState()) |
|||
|
|||
Parses the single character and returns the state. See `parse` for the structure of the returned state object. N.B. character must be a single character not a multi character string. |
|||
|
|||
### defaultState() |
|||
|
|||
Get a default starting state. See `parse` for the structure of the returned state object. |
|||
|
|||
## License |
|||
|
|||
MIT |
@ -0,0 +1,205 @@ |
|||
exports = (module.exports = parse); |
|||
exports.parse = parse; |
|||
function parse(src, state, options) { |
|||
options = options || {}; |
|||
state = state || exports.defaultState(); |
|||
var start = options.start || 0; |
|||
var end = options.end || src.length; |
|||
var index = start; |
|||
while (index < end) { |
|||
if (state.roundDepth < 0 || state.curlyDepth < 0 || state.squareDepth < 0) { |
|||
throw new SyntaxError('Mismatched Bracket: ' + src[index - 1]); |
|||
} |
|||
exports.parseChar(src[index++], state); |
|||
} |
|||
return state; |
|||
} |
|||
|
|||
exports.parseMax = parseMax; |
|||
function parseMax(src, options) { |
|||
options = options || {}; |
|||
var start = options.start || 0; |
|||
var index = start; |
|||
var state = exports.defaultState(); |
|||
while (state.roundDepth >= 0 && state.curlyDepth >= 0 && state.squareDepth >= 0) { |
|||
if (index >= src.length) { |
|||
throw new Error('The end of the string was reached with no closing bracket found.'); |
|||
} |
|||
exports.parseChar(src[index++], state); |
|||
} |
|||
var end = index - 1; |
|||
return { |
|||
start: start, |
|||
end: end, |
|||
src: src.substring(start, end) |
|||
}; |
|||
} |
|||
|
|||
exports.parseUntil = parseUntil; |
|||
function parseUntil(src, delimiter, options) { |
|||
options = options || {}; |
|||
var includeLineComment = options.includeLineComment || false; |
|||
var start = options.start || 0; |
|||
var index = start; |
|||
var state = exports.defaultState(); |
|||
while (state.singleQuote || state.doubleQuote || state.regexp || state.blockComment || |
|||
(!includeLineComment && state.lineComment) || !startsWith(src, delimiter, index)) { |
|||
exports.parseChar(src[index++], state); |
|||
} |
|||
var end = index; |
|||
return { |
|||
start: start, |
|||
end: end, |
|||
src: src.substring(start, end) |
|||
}; |
|||
} |
|||
|
|||
|
|||
exports.parseChar = parseChar; |
|||
function parseChar(character, state) { |
|||
if (character.length !== 1) throw new Error('Character must be a string of length 1'); |
|||
state = state || defaultState(); |
|||
var wasComment = state.blockComment || state.lineComment; |
|||
var lastChar = state.history ? state.history[0] : ''; |
|||
if (state.lineComment) { |
|||
if (character === '\n') { |
|||
state.lineComment = false; |
|||
} |
|||
} else if (state.blockComment) { |
|||
if (state.lastChar === '*' && character === '/') { |
|||
state.blockComment = false; |
|||
} |
|||
} else if (state.singleQuote) { |
|||
if (character === '\'' && !state.escaped) { |
|||
state.singleQuote = false; |
|||
} else if (character === '\\' && !state.escaped) { |
|||
state.escaped = true; |
|||
} else { |
|||
state.escaped = false; |
|||
} |
|||
} else if (state.doubleQuote) { |
|||
if (character === '"' && !state.escaped) { |
|||
state.doubleQuote = false; |
|||
} else if (character === '\\' && !state.escaped) { |
|||
state.escaped = true; |
|||
} else { |
|||
state.escaped = false; |
|||
} |
|||
} else if (state.regexp) { |
|||
if (character === '/' && !state.escaped) { |
|||
state.regexp = false; |
|||
} else if (character === '\\' && !state.escaped) { |
|||
state.escaped = true; |
|||
} else { |
|||
state.escaped = false; |
|||
} |
|||
} else if (lastChar === '/' && character === '/') { |
|||
history = history.substr(1); |
|||
state.lineComment = true; |
|||
} else if (lastChar === '/' && character === '*') { |
|||
history = history.substr(1); |
|||
state.blockComment = true; |
|||
} else if (character === '/') { |
|||
//could be start of regexp or divide sign
|
|||
var history = state.history.replace(/^\s*/, ''); |
|||
if (history[0] === ')') { |
|||
//unless its an `if`, `while`, `for` or `with` it's a divide
|
|||
//this is probably best left though
|
|||
} else if (history[0] === '}') { |
|||
//unless it's a function expression, it's a regexp
|
|||
//this is probably best left though
|
|||
} else if (isPunctuator(history[0])) { |
|||
state.regexp = true; |
|||
} else if (/^\w+\b/.test(history) && isKeyword(/^\w+\b/.exec(history)[0])) { |
|||
state.regexp = true; |
|||
} else { |
|||
// assume it's divide
|
|||
} |
|||
} else if (character === '\'') { |
|||
state.singleQuote = true; |
|||
} else if (character === '"') { |
|||
state.doubleQuote = true; |
|||
} else if (character === '(') { |
|||
state.roundDepth++; |
|||
} else if (character === ')') { |
|||
state.roundDepth--; |
|||
} else if (character === '{') { |
|||
state.curlyDepth++; |
|||
} else if (character === '}') { |
|||
state.curlyDepth--; |
|||
} else if (character === '[') { |
|||
state.squareDepth++; |
|||
} else if (character === ']') { |
|||
state.squareDepth--; |
|||
} |
|||
if (!state.blockComment && !state.lineComment && !wasComment) state.history = character + state.history; |
|||
return state; |
|||
} |
|||
|
|||
exports.defaultState = defaultState; |
|||
function defaultState() { |
|||
return { |
|||
lineComment: false, |
|||
blockComment: false, |
|||
|
|||
singleQuote: false, |
|||
doubleQuote: false, |
|||
regexp: false, |
|||
escaped: false, |
|||
|
|||
roundDepth: 0, |
|||
curlyDepth: 0, |
|||
squareDepth: 0, |
|||
|
|||
history: '' |
|||
}; |
|||
} |
|||
|
|||
function startsWith(str, start, i) { |
|||
return str.substr(i || 0, start.length) === start; |
|||
} |
|||
|
|||
function isPunctuator(c) { |
|||
var code = c.charCodeAt(0) |
|||
|
|||
switch (code) { |
|||
case 46: // . dot
|
|||
case 40: // ( open bracket
|
|||
case 41: // ) close bracket
|
|||
case 59: // ; semicolon
|
|||
case 44: // , comma
|
|||
case 123: // { open curly brace
|
|||
case 125: // } close curly brace
|
|||
case 91: // [
|
|||
case 93: // ]
|
|||
case 58: // :
|
|||
case 63: // ?
|
|||
case 126: // ~
|
|||
case 37: // %
|
|||
case 38: // &
|
|||
case 42: // *:
|
|||
case 43: // +
|
|||
case 45: // -
|
|||
case 47: // /
|
|||
case 60: // <
|
|||
case 62: // >
|
|||
case 94: // ^
|
|||
case 124: // |
|
|||
case 33: // !
|
|||
case 61: // =
|
|||
return true; |
|||
default: |
|||
return false; |
|||
} |
|||
} |
|||
function isKeyword(id) { |
|||
return (id === 'if') || (id === 'in') || (id === 'do') || (id === 'var') || (id === 'for') || (id === 'new') || |
|||
(id === 'try') || (id === 'let') || (id === 'this') || (id === 'else') || (id === 'case') || |
|||
(id === 'void') || (id === 'with') || (id === 'enum') || (id === 'while') || (id === 'break') || (id === 'catch') || |
|||
(id === 'throw') || (id === 'const') || (id === 'yield') || (id === 'class') || (id === 'super') || |
|||
(id === 'return') || (id === 'typeof') || (id === 'delete') || (id === 'switch') || (id === 'export') || |
|||
(id === 'import') || (id === 'default') || (id === 'finally') || (id === 'extends') || (id === 'function') || |
|||
(id === 'continue') || (id === 'debugger') || (id === 'package') || (id === 'private') || (id === 'interface') || |
|||
(id === 'instanceof') || (id === 'implements') || (id === 'protected') || (id === 'public') || (id === 'static') || |
|||
(id === 'yield') || (id === 'let'); |
|||
} |
@ -0,0 +1,42 @@ |
|||
{ |
|||
"name": "character-parser", |
|||
"version": "1.0.2", |
|||
"description": "Parse JavaScript one character at a time to look for snippets in Templates. This is not a validator, it's just designed to allow you to have sections of JavaScript delimited by brackets robustly.", |
|||
"main": "index.js", |
|||
"scripts": { |
|||
"test": "mocha -R spec" |
|||
}, |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "https://github.com/ForbesLindesay/character-parser.git" |
|||
}, |
|||
"keywords": [ |
|||
"parser", |
|||
"JavaScript", |
|||
"bracket", |
|||
"nesting", |
|||
"comment", |
|||
"string", |
|||
"escape", |
|||
"escaping" |
|||
], |
|||
"author": { |
|||
"name": "ForbesLindesay" |
|||
}, |
|||
"license": "MIT", |
|||
"devDependencies": { |
|||
"better-assert": "~1.0.0", |
|||
"mocha": "~1.9.0" |
|||
}, |
|||
"readme": "# character-parser\r\n\r\nParse JavaScript one character at a time to look for snippets in Templates. This is not a validator, it's just designed to allow you to have sections of JavaScript delimited by brackets robustly.\r\n\r\n[![Build Status](https://travis-ci.org/ForbesLindesay/character-parser.png?branch=master)](https://travis-ci.org/ForbesLindesay/character-parser)\r\n\r\n## Installation\r\n\r\n npm install character-parser\r\n\r\n## Usage\r\n\r\nWork out how much depth changes:\r\n\r\n```js\r\nvar state = parse('foo(arg1, arg2, {\\n foo: [a, b\\n');\r\nassert(state.roundDepth === 1);\r\nassert(state.curlyDepth === 1);\r\nassert(state.squareDepth === 1);\r\nparse(' c, d]\\n })', state);\r\nassert(state.squareDepth === 0);\r\nassert(state.curlyDepth === 0);\r\nassert(state.roundDepth === 0);\r\n```\r\n\r\n### Bracketed Expressions\r\n\r\nFind all the contents of a bracketed expression:\r\n\r\n```js\r\nvar section = parser.parseMax('foo=\"(\", bar=\"}\") bing bong');\r\nassert(section.start === 0);\r\nassert(section.end === 16);//exclusive end of string\r\nassert(section.src = 'foo=\"(\", bar=\"}\"');\r\n\r\n\r\nvar section = parser.parseMax('{foo=\"(\", bar=\"}\"} bing bong', {start: 1});\r\nassert(section.start === 1);\r\nassert(section.end === 17);//exclusive end of string\r\nassert(section.src = 'foo=\"(\", bar=\"}\"');\r\n```\r\n\r\nThe bracketed expression parsing simply parses up to but excluding the first unmatched closed bracket (`)`, `}`, `]`). It is clever enough to ignore brackets in comments or strings.\r\n\r\n\r\n### Custom Delimited Expressions\r\n\r\nFind code up to a custom delimiter:\r\n\r\n```js\r\nvar section = parser.parseUntil('foo.bar(\"%>\").baz%> bing bong', '%>');\r\nassert(section.start === 0);\r\nassert(section.end === 17);//exclusive end of string\r\nassert(section.src = 'foo.bar(\"%>\").baz');\r\n\r\nvar section = parser.parseUntil('<%foo.bar(\"%>\").baz%> bing bong', '%>', {start: 2});\r\nassert(section.start === 2);\r\nassert(section.end === 19);//exclusive end of string\r\nassert(section.src = 'foo.bar(\"%>\").baz');\r\n```\r\n\r\nDelimiters are ignored if they are inside strings or comments.\r\n\r\n## API\r\n\r\n### parse(str, state = defaultState(), options = {start: 0, end: src.length})\r\n\r\nParse a string starting at the index start, and return the state after parsing that string.\r\n\r\nIf you want to parse one string in multiple sections you should keep passing the resulting state to the next parse operation.\r\n\r\nThe resulting object has the structure:\r\n\r\n```js\r\n{\r\n lineComment: false, //true if inside a line comment\r\n blockComment: false, //true if inside a block comment\r\n\r\n singleQuote: false, //true if inside a single quoted string\r\n doubleQuote: false, //true if inside a double quoted string\r\n escaped: false, //true if in a string and the last character was an escape character\r\n\r\n roundDepth: 0, //number of un-closed open `(` brackets\r\n curlyDepth: 0, //number of un-closed open `{` brackets\r\n squareDepth: 0 //number of un-closed open `[` brackets\r\n}\r\n```\r\n\r\n### parseMax(src, options = {start: 0})\r\n\r\nParses the source until the first unmatched close bracket (any of `)`, `}`, `]`). It returns an object with the structure:\r\n\r\n```js\r\n{\r\n start: 0,//index of first character of string\r\n end: 13,//index of first character after the end of string\r\n src: 'source string'\r\n}\r\n```\r\n\r\n### parseUntil(src, delimiter, options = {start: 0, includeLineComment: false})\r\n\r\nParses the source until the first occurence of `delimiter` which is not in a string or a comment. If `includeLineComment` is `true`, it will still count if the delimiter occurs in a line comment, but not in a block comment. It returns an object with the structure:\r\n\r\n```js\r\n{\r\n start: 0,//index of first character of string\r\n end: 13,//index of first character after the end of string\r\n src: 'source string'\r\n}\r\n```\r\n\r\n### parseChar(character, state = defaultState())\r\n\r\nParses the single character and returns the state. See `parse` for the structure of the returned state object. N.B. character must be a single character not a multi character string.\r\n\r\n### defaultState()\r\n\r\nGet a default starting state. See `parse` for the structure of the returned state object.\r\n\r\n## License\r\n\r\nMIT", |
|||
"readmeFilename": "README.md", |
|||
"bugs": { |
|||
"url": "https://github.com/ForbesLindesay/character-parser/issues" |
|||
}, |
|||
"_id": "character-parser@1.0.2", |
|||
"dist": { |
|||
"shasum": "841ea54a26ede2d4663f2420a50ae0edda8708d1" |
|||
}, |
|||
"_from": "character-parser@1.0.2", |
|||
"_resolved": "https://registry.npmjs.org/character-parser/-/character-parser-1.0.2.tgz" |
|||
} |
@ -0,0 +1,50 @@ |
|||
var assert = require('better-assert'); |
|||
var parser = require('../'); |
|||
var parse = parser; |
|||
|
|||
it('works out how much depth changes', function () { |
|||
var state = parse('foo(arg1, arg2, {\n foo: [a, b\n'); |
|||
assert(state.roundDepth === 1); |
|||
assert(state.curlyDepth === 1); |
|||
assert(state.squareDepth === 1); |
|||
|
|||
parse(' c, d]\n })', state); |
|||
assert(state.squareDepth === 0); |
|||
assert(state.curlyDepth === 0); |
|||
assert(state.roundDepth === 0); |
|||
}); |
|||
|
|||
it('finds contents of bracketed expressions', function () { |
|||
var section = parser.parseMax('foo="(", bar="}") bing bong'); |
|||
assert(section.start === 0); |
|||
assert(section.end === 16);//exclusive end of string
|
|||
assert(section.src = 'foo="(", bar="}"'); |
|||
|
|||
var section = parser.parseMax('{foo="(", bar="}"} bing bong', {start: 1}); |
|||
assert(section.start === 1); |
|||
assert(section.end === 17);//exclusive end of string
|
|||
assert(section.src = 'foo="(", bar="}"'); |
|||
}); |
|||
|
|||
it('finds code up to a custom delimiter', function () { |
|||
var section = parser.parseUntil('foo.bar("%>").baz%> bing bong', '%>'); |
|||
assert(section.start === 0); |
|||
assert(section.end === 17);//exclusive end of string
|
|||
assert(section.src = 'foo.bar("%>").baz'); |
|||
|
|||
var section = parser.parseUntil('<%foo.bar("%>").baz%> bing bong', '%>', {start: 2}); |
|||
assert(section.start === 2); |
|||
assert(section.end === 19);//exclusive end of string
|
|||
assert(section.src = 'foo.bar("%>").baz'); |
|||
}); |
|||
|
|||
describe('regressions', function () { |
|||
describe('#1', function () { |
|||
it('parses regular expressions', function () { |
|||
var section = parser.parseMax('foo=/\\//g, bar="}") bing bong'); |
|||
assert(section.start === 0); |
|||
assert(section.end === 18);//exclusive end of string
|
|||
assert(section.src = 'foo=/\\//g, bar="}"'); |
|||
}) |
|||
}) |
|||
}) |
@ -0,0 +1,101 @@ |
|||
keypress |
|||
======== |
|||
### Make any Node ReadableStream emit "keypress" events |
|||
|
|||
|
|||
Previous to Node `v0.8.x`, there was an undocumented `"keypress"` event that |
|||
`process.stdin` would emit when it was a TTY. Some people discovered this hidden |
|||
gem, and started using it in their own code. |
|||
|
|||
Now in Node `v0.8.x`, this `"keypress"` event does not get emitted by default, |
|||
but rather only when it is being used in conjuction with the `readline` (or by |
|||
extension, the `repl`) module. |
|||
|
|||
This module is the exact logic from the node `v0.8.x` releases ripped out into its |
|||
own module. |
|||
|
|||
__Bonus:__ Now with mouse support! |
|||
|
|||
Installation |
|||
------------ |
|||
|
|||
Install with `npm`: |
|||
|
|||
``` bash |
|||
$ npm install keypress |
|||
``` |
|||
|
|||
Or add it to the `"dependencies"` section of your _package.json_ file. |
|||
|
|||
|
|||
Example |
|||
------- |
|||
|
|||
#### Listening for "keypress" events |
|||
|
|||
``` js |
|||
var keypress = require('keypress'); |
|||
|
|||
// make `process.stdin` begin emitting "keypress" events |
|||
keypress(process.stdin); |
|||
|
|||
// listen for the "keypress" event |
|||
process.stdin.on('keypress', function (ch, key) { |
|||
console.log('got "keypress"', key); |
|||
if (key && key.ctrl && key.name == 'c') { |
|||
process.stdin.pause(); |
|||
} |
|||
}); |
|||
|
|||
process.stdin.setRawMode(true); |
|||
process.stdin.resume(); |
|||
``` |
|||
|
|||
#### Listening for "mousepress" events |
|||
|
|||
``` js |
|||
var keypress = require('keypress'); |
|||
|
|||
// make `process.stdin` begin emitting "mousepress" (and "keypress") events |
|||
keypress(process.stdin); |
|||
|
|||
// you must enable the mouse events before they will begin firing |
|||
keypress.enableMouse(process.stdout); |
|||
|
|||
process.stdin.on('mousepress', function (info) { |
|||
console.log('got "mousepress" event at %d x %d', info.x, info.y); |
|||
}); |
|||
|
|||
process.on('exit', function () { |
|||
// disable mouse on exit, so that the state |
|||
// is back to normal for the terminal |
|||
keypress.disableMouse(process.stdout); |
|||
}); |
|||
``` |
|||
|
|||
|
|||
License |
|||
------- |
|||
|
|||
(The MIT License) |
|||
|
|||
Copyright (c) 2012 Nathan Rajlich <nathan@tootallnate.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,346 @@ |
|||
|
|||
/** |
|||
* This module offers the internal "keypress" functionality from node-core's |
|||
* `readline` module, for your own programs and modules to use. |
|||
* |
|||
* Usage: |
|||
* |
|||
* require('keypress')(process.stdin); |
|||
* |
|||
* process.stdin.on('keypress', function (ch, key) { |
|||
* console.log(ch, key); |
|||
* if (key.ctrl && key.name == 'c') { |
|||
* process.stdin.pause(); |
|||
* } |
|||
* }); |
|||
* proces.stdin.resume(); |
|||
*/ |
|||
var exports = module.exports = keypress; |
|||
|
|||
exports.enableMouse = function (stream) { |
|||
stream.write('\x1b' +'[?1000h') |
|||
} |
|||
|
|||
exports.disableMouse = function (stream) { |
|||
stream.write('\x1b' +'[?1000l') |
|||
} |
|||
|
|||
|
|||
/** |
|||
* accepts a readable Stream instance and makes it emit "keypress" events |
|||
*/ |
|||
|
|||
function keypress(stream) { |
|||
if (isEmittingKeypress(stream)) return; |
|||
stream._emitKeypress = true; |
|||
|
|||
function onData(b) { |
|||
if (stream.listeners('keypress').length > 0) { |
|||
emitKey(stream, b); |
|||
} else { |
|||
// Nobody's watching anyway
|
|||
stream.removeListener('data', onData); |
|||
stream.on('newListener', onNewListener); |
|||
} |
|||
} |
|||
|
|||
function onNewListener(event) { |
|||
if (event == 'keypress') { |
|||
stream.on('data', onData); |
|||
stream.removeListener('newListener', onNewListener); |
|||
} |
|||
} |
|||
|
|||
if (stream.listeners('keypress').length > 0) { |
|||
stream.on('data', onData); |
|||
} else { |
|||
stream.on('newListener', onNewListener); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Returns `true` if the stream is already emitting "keypress" events. |
|||
* `false` otherwise. |
|||
*/ |
|||
|
|||
function isEmittingKeypress(stream) { |
|||
var rtn = stream._emitKeypress; |
|||
if (!rtn) { |
|||
// hack: check for the v0.6.x "data" event
|
|||
stream.listeners('data').forEach(function (l) { |
|||
if (l.name == 'onData' && /emitKey/.test(l.toString())) { |
|||
rtn = true; |
|||
stream._emitKeypress = true; |
|||
} |
|||
}); |
|||
} |
|||
if (!rtn) { |
|||
// hack: check for the v0.6.x "newListener" event
|
|||
stream.listeners('newListener').forEach(function (l) { |
|||
if (l.name == 'onNewListener' && /keypress/.test(l.toString())) { |
|||
rtn = true; |
|||
stream._emitKeypress = true; |
|||
} |
|||
}); |
|||
} |
|||
return rtn; |
|||
} |
|||
|
|||
|
|||
/* |
|||
Some patterns seen in terminal key escape codes, derived from combos seen |
|||
at http://www.midnight-commander.org/browser/lib/tty/key.c
|
|||
|
|||
ESC letter |
|||
ESC [ letter |
|||
ESC [ modifier letter |
|||
ESC [ 1 ; modifier letter |
|||
ESC [ num char |
|||
ESC [ num ; modifier char |
|||
ESC O letter |
|||
ESC O modifier letter |
|||
ESC O 1 ; modifier letter |
|||
ESC N letter |
|||
ESC [ [ num ; modifier char |
|||
ESC [ [ 1 ; modifier letter |
|||
ESC ESC [ num char |
|||
ESC ESC O letter |
|||
|
|||
- char is usually ~ but $ and ^ also happen with rxvt |
|||
- modifier is 1 + |
|||
(shift * 1) + |
|||
(left_alt * 2) + |
|||
(ctrl * 4) + |
|||
(right_alt * 8) |
|||
- two leading ESCs apparently mean the same as one leading ESC |
|||
*/ |
|||
|
|||
// Regexes used for ansi escape code splitting
|
|||
var metaKeyCodeRe = /^(?:\x1b)([a-zA-Z0-9])$/; |
|||
var functionKeyCodeRe = |
|||
/^(?:\x1b+)(O|N|\[|\[\[)(?:(\d+)(?:;(\d+))?([~^$])|(?:1;)?(\d+)?([a-zA-Z]))/; |
|||
|
|||
function emitKey(stream, s) { |
|||
var ch, |
|||
key = { |
|||
name: undefined, |
|||
ctrl: false, |
|||
meta: false, |
|||
shift: false |
|||
}, |
|||
parts; |
|||
|
|||
if (Buffer.isBuffer(s)) { |
|||
if (s[0] > 127 && s[1] === undefined) { |
|||
s[0] -= 128; |
|||
s = '\x1b' + s.toString(stream.encoding || 'utf-8'); |
|||
} else { |
|||
s = s.toString(stream.encoding || 'utf-8'); |
|||
} |
|||
} |
|||
|
|||
key.sequence = s; |
|||
|
|||
if (s === '\r' || s === '\n') { |
|||
// enter
|
|||
key.name = 'enter'; |
|||
|
|||
} else if (s === '\t') { |
|||
// tab
|
|||
key.name = 'tab'; |
|||
|
|||
} else if (s === '\b' || s === '\x7f' || |
|||
s === '\x1b\x7f' || s === '\x1b\b') { |
|||
// backspace or ctrl+h
|
|||
key.name = 'backspace'; |
|||
key.meta = (s.charAt(0) === '\x1b'); |
|||
|
|||
} else if (s === '\x1b' || s === '\x1b\x1b') { |
|||
// escape key
|
|||
key.name = 'escape'; |
|||
key.meta = (s.length === 2); |
|||
|
|||
} else if (s === ' ' || s === '\x1b ') { |
|||
key.name = 'space'; |
|||
key.meta = (s.length === 2); |
|||
|
|||
} else if (s <= '\x1a') { |
|||
// ctrl+letter
|
|||
key.name = String.fromCharCode(s.charCodeAt(0) + 'a'.charCodeAt(0) - 1); |
|||
key.ctrl = true; |
|||
|
|||
} else if (s.length === 1 && s >= 'a' && s <= 'z') { |
|||
// lowercase letter
|
|||
key.name = s; |
|||
|
|||
} else if (s.length === 1 && s >= 'A' && s <= 'Z') { |
|||
// shift+letter
|
|||
key.name = s.toLowerCase(); |
|||
key.shift = true; |
|||
|
|||
} else if (parts = metaKeyCodeRe.exec(s)) { |
|||
// meta+character key
|
|||
key.name = parts[1].toLowerCase(); |
|||
key.meta = true; |
|||
key.shift = /^[A-Z]$/.test(parts[1]); |
|||
|
|||
} else if (parts = functionKeyCodeRe.exec(s)) { |
|||
// ansi escape sequence
|
|||
|
|||
// reassemble the key code leaving out leading \x1b's,
|
|||
// the modifier key bitflag and any meaningless "1;" sequence
|
|||
var code = (parts[1] || '') + (parts[2] || '') + |
|||
(parts[4] || '') + (parts[6] || ''), |
|||
modifier = (parts[3] || parts[5] || 1) - 1; |
|||
|
|||
// Parse the key modifier
|
|||
key.ctrl = !!(modifier & 4); |
|||
key.meta = !!(modifier & 10); |
|||
key.shift = !!(modifier & 1); |
|||
key.code = code; |
|||
|
|||
// Parse the key itself
|
|||
switch (code) { |
|||
/* xterm/gnome ESC O letter */ |
|||
case 'OP': key.name = 'f1'; break; |
|||
case 'OQ': key.name = 'f2'; break; |
|||
case 'OR': key.name = 'f3'; break; |
|||
case 'OS': key.name = 'f4'; break; |
|||
|
|||
/* xterm/rxvt ESC [ number ~ */ |
|||
case '[11~': key.name = 'f1'; break; |
|||
case '[12~': key.name = 'f2'; break; |
|||
case '[13~': key.name = 'f3'; break; |
|||
case '[14~': key.name = 'f4'; break; |
|||
|
|||
/* from Cygwin and used in libuv */ |
|||
case '[[A': key.name = 'f1'; break; |
|||
case '[[B': key.name = 'f2'; break; |
|||
case '[[C': key.name = 'f3'; break; |
|||
case '[[D': key.name = 'f4'; break; |
|||
case '[[E': key.name = 'f5'; break; |
|||
|
|||
/* common */ |
|||
case '[15~': key.name = 'f5'; break; |
|||
case '[17~': key.name = 'f6'; break; |
|||
case '[18~': key.name = 'f7'; break; |
|||
case '[19~': key.name = 'f8'; break; |
|||
case '[20~': key.name = 'f9'; break; |
|||
case '[21~': key.name = 'f10'; break; |
|||
case '[23~': key.name = 'f11'; break; |
|||
case '[24~': key.name = 'f12'; break; |
|||
|
|||
/* xterm ESC [ letter */ |
|||
case '[A': key.name = 'up'; break; |
|||
case '[B': key.name = 'down'; break; |
|||
case '[C': key.name = 'right'; break; |
|||
case '[D': key.name = 'left'; break; |
|||
case '[E': key.name = 'clear'; break; |
|||
case '[F': key.name = 'end'; break; |
|||
case '[H': key.name = 'home'; break; |
|||
|
|||
/* xterm/gnome ESC O letter */ |
|||
case 'OA': key.name = 'up'; break; |
|||
case 'OB': key.name = 'down'; break; |
|||
case 'OC': key.name = 'right'; break; |
|||
case 'OD': key.name = 'left'; break; |
|||
case 'OE': key.name = 'clear'; break; |
|||
case 'OF': key.name = 'end'; break; |
|||
case 'OH': key.name = 'home'; break; |
|||
|
|||
/* xterm/rxvt ESC [ number ~ */ |
|||
case '[1~': key.name = 'home'; break; |
|||
case '[2~': key.name = 'insert'; break; |
|||
case '[3~': key.name = 'delete'; break; |
|||
case '[4~': key.name = 'end'; break; |
|||
case '[5~': key.name = 'pageup'; break; |
|||
case '[6~': key.name = 'pagedown'; break; |
|||
|
|||
/* putty */ |
|||
case '[[5~': key.name = 'pageup'; break; |
|||
case '[[6~': key.name = 'pagedown'; break; |
|||
|
|||
/* rxvt */ |
|||
case '[7~': key.name = 'home'; break; |
|||
case '[8~': key.name = 'end'; break; |
|||
|
|||
/* rxvt keys with modifiers */ |
|||
case '[a': key.name = 'up'; key.shift = true; break; |
|||
case '[b': key.name = 'down'; key.shift = true; break; |
|||
case '[c': key.name = 'right'; key.shift = true; break; |
|||
case '[d': key.name = 'left'; key.shift = true; break; |
|||
case '[e': key.name = 'clear'; key.shift = true; break; |
|||
|
|||
case '[2$': key.name = 'insert'; key.shift = true; break; |
|||
case '[3$': key.name = 'delete'; key.shift = true; break; |
|||
case '[5$': key.name = 'pageup'; key.shift = true; break; |
|||
case '[6$': key.name = 'pagedown'; key.shift = true; break; |
|||
case '[7$': key.name = 'home'; key.shift = true; break; |
|||
case '[8$': key.name = 'end'; key.shift = true; break; |
|||
|
|||
case 'Oa': key.name = 'up'; key.ctrl = true; break; |
|||
case 'Ob': key.name = 'down'; key.ctrl = true; break; |
|||
case 'Oc': key.name = 'right'; key.ctrl = true; break; |
|||
case 'Od': key.name = 'left'; key.ctrl = true; break; |
|||
case 'Oe': key.name = 'clear'; key.ctrl = true; break; |
|||
|
|||
case '[2^': key.name = 'insert'; key.ctrl = true; break; |
|||
case '[3^': key.name = 'delete'; key.ctrl = true; break; |
|||
case '[5^': key.name = 'pageup'; key.ctrl = true; break; |
|||
case '[6^': key.name = 'pagedown'; key.ctrl = true; break; |
|||
case '[7^': key.name = 'home'; key.ctrl = true; break; |
|||
case '[8^': key.name = 'end'; key.ctrl = true; break; |
|||
|
|||
/* misc. */ |
|||
case '[Z': key.name = 'tab'; key.shift = true; break; |
|||
default: key.name = 'undefined'; break; |
|||
|
|||
} |
|||
} else if (s.length > 1 && s[0] !== '\x1b') { |
|||
// Got a longer-than-one string of characters.
|
|||
// Probably a paste, since it wasn't a control sequence.
|
|||
Array.prototype.forEach.call(s, function(c) { |
|||
emitKey(stream, c); |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
if (key.code == '[M') { |
|||
key.name = 'mouse'; |
|||
var s = key.sequence; |
|||
var b = s.charCodeAt(3); |
|||
key.x = s.charCodeAt(4) - 040; |
|||
key.y = s.charCodeAt(5) - 040; |
|||
|
|||
key.scroll = 0; |
|||
|
|||
key.ctrl = !!(1<<4 & b); |
|||
key.meta = !!(1<<3 & b); |
|||
key.shift = !!(1<<2 & b); |
|||
|
|||
key.release = (3 & b) === 3; |
|||
|
|||
if (1<<6 & b) { //scroll
|
|||
key.scroll = 1 & b ? 1 : -1; |
|||
} |
|||
|
|||
if (!key.release && !key.scroll) { |
|||
key.button = b & 3; |
|||
} |
|||
} |
|||
|
|||
// Don't emit a key if no name was found
|
|||
if (key.name === undefined) { |
|||
key = undefined; |
|||
} |
|||
|
|||
if (s.length === 1) { |
|||
ch = s; |
|||
} |
|||
|
|||
if (key && key.name == 'mouse') { |
|||
stream.emit('mousepress', key) |
|||
} else if (key || ch) { |
|||
stream.emit('keypress', ch, key); |
|||
} |
|||
} |
@ -0,0 +1,31 @@ |
|||
{ |
|||
"name": "keypress", |
|||
"version": "0.1.0", |
|||
"description": "Make any Node ReadableStream emit \"keypress\" events", |
|||
"author": { |
|||
"name": "Nathan Rajlich", |
|||
"email": "nathan@tootallnate.net", |
|||
"url": "http://tootallnate.net" |
|||
}, |
|||
"main": "index.js", |
|||
"scripts": { |
|||
"test": "echo \"Error: no test specified\" && exit 1" |
|||
}, |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "git://github.com/TooTallNate/keypress.git" |
|||
}, |
|||
"keywords": [ |
|||
"keypress", |
|||
"readline", |
|||
"core" |
|||
], |
|||
"license": "MIT", |
|||
"readme": "keypress\n========\n### Make any Node ReadableStream emit \"keypress\" events\n\n\nPrevious to Node `v0.8.x`, there was an undocumented `\"keypress\"` event that\n`process.stdin` would emit when it was a TTY. Some people discovered this hidden\ngem, and started using it in their own code.\n\nNow in Node `v0.8.x`, this `\"keypress\"` event does not get emitted by default,\nbut rather only when it is being used in conjuction with the `readline` (or by\nextension, the `repl`) module.\n\nThis module is the exact logic from the node `v0.8.x` releases ripped out into its\nown module.\n\n__Bonus:__ Now with mouse support!\n\nInstallation\n------------\n\nInstall with `npm`:\n\n``` bash\n$ npm install keypress\n```\n\nOr add it to the `\"dependencies\"` section of your _package.json_ file.\n\n\nExample\n-------\n\n#### Listening for \"keypress\" events\n\n``` js\nvar keypress = require('keypress');\n\n// make `process.stdin` begin emitting \"keypress\" events\nkeypress(process.stdin);\n\n// listen for the \"keypress\" event\nprocess.stdin.on('keypress', function (ch, key) {\n console.log('got \"keypress\"', key);\n if (key && key.ctrl && key.name == 'c') {\n process.stdin.pause();\n }\n});\n\nprocess.stdin.setRawMode(true);\nprocess.stdin.resume();\n```\n\n#### Listening for \"mousepress\" events\n\n``` js\nvar keypress = require('keypress');\n\n// make `process.stdin` begin emitting \"mousepress\" (and \"keypress\") events\nkeypress(process.stdin);\n\n// you must enable the mouse events before they will begin firing\nkeypress.enableMouse(process.stdout);\n\nprocess.stdin.on('mousepress', function (info) {\n console.log('got \"mousepress\" event at %d x %d', info.x, info.y);\n});\n\nprocess.on('exit', function () {\n // disable mouse on exit, so that the state\n // is back to normal for the terminal\n keypress.disableMouse(process.stdout);\n});\n```\n\n\nLicense\n-------\n\n(The MIT License)\n\nCopyright (c) 2012 Nathan Rajlich <nathan@tootallnate.net>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", |
|||
"readmeFilename": "README.md", |
|||
"bugs": { |
|||
"url": "https://github.com/TooTallNate/keypress/issues" |
|||
}, |
|||
"_id": "keypress@0.1.0", |
|||
"_from": "keypress@0.1.x" |
|||
} |
@ -0,0 +1,28 @@ |
|||
|
|||
var keypress = require('./') |
|||
keypress(process.stdin) |
|||
|
|||
if (process.stdin.setRawMode) |
|||
process.stdin.setRawMode(true) |
|||
else |
|||
require('tty').setRawMode(true) |
|||
|
|||
process.stdin.on('keypress', function (c, key) { |
|||
console.log(0, c, key) |
|||
if (key && key.ctrl && key.name == 'c') { |
|||
process.stdin.pause() |
|||
} |
|||
}) |
|||
process.stdin.on('mousepress', function (mouse) { |
|||
console.log(mouse) |
|||
}) |
|||
|
|||
keypress.enableMouse(process.stdout) |
|||
process.on('exit', function () { |
|||
//disable mouse on exit, so that the state is back to normal
|
|||
//for the terminal.
|
|||
keypress.disableMouse(process.stdout) |
|||
}) |
|||
|
|||
process.stdin.resume() |
|||
|
@ -0,0 +1,2 @@ |
|||
node_modules |
|||
.DS_Store |
@ -0,0 +1,5 @@ |
|||
language: node_js |
|||
node_js: |
|||
- "0.11" |
|||
- "0.10" |
|||
- "0.8" |
@ -0,0 +1,23 @@ |
|||
Copyright (c) 2013, Sam Saccone |
|||
All rights reserved. |
|||
|
|||
Redistribution and use in source and binary forms, with or without |
|||
modification, are permitted provided that the following conditions are met: |
|||
|
|||
* Redistributions of source code must retain the above copyright notice, |
|||
this list of conditions and the following disclaimer. |
|||
* Redistributions in binary form must reproduce the above copyright |
|||
notice, this list of conditions and the following disclaimer in the |
|||
documentation and/or other materials provided with the distribution. |
|||
|
|||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY |
|||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|||
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY |
|||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
|||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
|||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
|||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
|||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
|||
DAMAGE. |
@ -0,0 +1,67 @@ |
|||
[![Build Status](https://travis-ci.org/samccone/monocle.png?branch=master)](https://travis-ci.org/samccone/monocle) |
|||
|
|||
# Monocle -- a tool for watching things |
|||
|
|||
[![logo](https://raw.github.com/samccone/monocle/master/logo.png)](https://raw.github.com/samccone/monocle/master/logo.png) |
|||
|
|||
Have you ever wanted to watch a folder and all of its files/nested folders for changes. well now you can! |
|||
|
|||
## Installation |
|||
|
|||
``` |
|||
npm install monocle |
|||
``` |
|||
|
|||
## Usage |
|||
|
|||
### Watch a directory: |
|||
|
|||
```js |
|||
var monocle = require('monocle')() |
|||
monocle.watchDirectory({ |
|||
root: <root directory>, |
|||
fileFilter: <optional>, |
|||
directoryFilter: <optional>, |
|||
listener: fn(fs.stat+ object), //triggered on file change / addition |
|||
complete: <fn> //file watching all set up |
|||
}); |
|||
``` |
|||
|
|||
The listener will recive an object with the following |
|||
|
|||
```js |
|||
name: <filename>, |
|||
path: <filepath-relative>, |
|||
fullPath: <filepath-absolute>, |
|||
parentDir: <parentDir-relative>, |
|||
fullParentDir: <parentDir-absolute>, |
|||
stat: <see fs.stats> |
|||
``` |
|||
|
|||
[fs.stats](http://nodejs.org/api/fs.html#fs_class_fs_stats) |
|||
|
|||
When a new file is added to the directoy it triggers a file change and thus will be passed to your specified listener. |
|||
|
|||
The two filters are passed through to `readdirp`. More documentation can be found [here](https://github.com/thlorenz/readdirp#filters) |
|||
|
|||
### Watch a list of files: |
|||
|
|||
```js |
|||
Monocle.watchFiles({ |
|||
files: [], //path of file(s) |
|||
listener: <fn(fs.stat+ object)>, //triggered on file / addition |
|||
complete: <fn> //file watching all set up |
|||
}); |
|||
``` |
|||
|
|||
## Why not just use fs.watch ? |
|||
|
|||
- file watching is really bad cross platforms in node |
|||
- you need to be smart when using fs.watch as compared to fs.watchFile |
|||
- Monocle takes care of this logic for you! |
|||
- windows systems use fs.watch |
|||
- osx and linux uses fs.watchFile |
|||
|
|||
## License |
|||
|
|||
BSD |
After Width: | Height: | Size: 25 KiB |
@ -0,0 +1,142 @@ |
|||
var path = require('path'); |
|||
var fs = require('fs'); |
|||
var readdirp = require('readdirp'); |
|||
var is_windows = process.platform === 'win32'; |
|||
|
|||
module.exports = function() { |
|||
var watched_files = {}; |
|||
var watched_directories = {}; |
|||
var check_dir_pause = 1000; |
|||
var checkInterval = undefined; |
|||
|
|||
// @api public
|
|||
// Watches the directory passed and its contained files
|
|||
// accepts args as an object.
|
|||
|
|||
// @param root(string): the root directory to watch
|
|||
// @param fileFilter(array): ignore these files
|
|||
// @param directoryFilter(array): ignore these files
|
|||
// @param listener(fn(file)): on file change event this will be called
|
|||
// @param complete(fn): on complete of file watching setup
|
|||
function watchDirectory(args) { |
|||
readdirp({ root: args.root, fileFilter: args.fileFilter, directoryFilter: args.directoryFilter }, function(err, res) { |
|||
res.files.forEach(function(file) { |
|||
watchFile(file, args.listener, args.partial); |
|||
}); |
|||
typeof args.complete == "function" && args.complete(); |
|||
}); |
|||
|
|||
!args.partial && (checkInterval = setInterval(function() {checkDirectory(args)}, check_dir_pause)); |
|||
} |
|||
|
|||
// @api public
|
|||
// Watches the files passed
|
|||
// accepts args as an object.
|
|||
// @param files(array): a list of files to watch
|
|||
// @param listener(fn(file)): on file change event this will be called
|
|||
// @param complete(fn): on complete of file watching setup
|
|||
function watchFiles(args) { |
|||
args.files.forEach(function(file) { |
|||
var o = { |
|||
fullPath: fs.realpathSync(file), |
|||
name: fs.realpathSync(file).split('/').pop() |
|||
}; |
|||
o.fullParentDir = o.fullPath.split('/').slice(0, o.fullPath.split('/').length - 1).join('/') |
|||
|
|||
watchFile(o, args.listener); |
|||
}); |
|||
|
|||
typeof args.complete == "function" && args.complete(); |
|||
} |
|||
|
|||
function unwatchAll() { |
|||
if (is_windows) { |
|||
Object.keys(watched_files).forEach(function(key) { |
|||
watched_files[key].close(); |
|||
}); |
|||
} else { |
|||
Object.keys(watched_files).forEach(function(key) { |
|||
fs.unwatchFile(key); |
|||
}); |
|||
} |
|||
|
|||
clearInterval(checkInterval); |
|||
watched_files = {}; |
|||
watched_directories = {}; |
|||
} |
|||
|
|||
// Checks to see if something in the directory has changed
|
|||
function checkDirectory(args) { |
|||
Object.keys(watched_directories).forEach(function(path) { |
|||
var lastModified = watched_directories[path]; |
|||
fs.stat(path, function(err, stats) { |
|||
var stats_stamp = lastModified; |
|||
if (!err) { |
|||
stats_stamp = (new Date(stats.mtime)).getTime(); |
|||
} |
|||
if (stats_stamp != lastModified) { |
|||
watched_directories[path] = stats_stamp; |
|||
watchDirectory({ |
|||
root: path, |
|||
listener: args.listener, |
|||
fileFilter: args.fileFilter, |
|||
directoryFilter: args.directoryFilter, |
|||
partial: true |
|||
}); |
|||
} |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
// sets the absolute path to the file from the current working dir
|
|||
function setAbsolutePath(file) { |
|||
file.absolutePath = path.resolve(process.cwd(), file.fullPath); |
|||
return file.absolutePath; |
|||
} |
|||
|
|||
// Watches the file passed and its containing directory
|
|||
// on change calls given listener with file object
|
|||
function watchFile(file, cb, partial) { |
|||
setAbsolutePath(file); |
|||
storeDirectory(file); |
|||
if (!watched_files[file.fullPath]) { |
|||
if (is_windows) { |
|||
(function() { |
|||
watched_files[file.fullPath] = fs.watch(file.fullPath, function() { |
|||
typeof cb === "function" && cb(file); |
|||
}); |
|||
partial && cb(file); |
|||
})(file, cb); |
|||
} else { |
|||
(function(file, cb) { |
|||
watched_files[file.fullPath] = true; |
|||
fs.watchFile(file.fullPath, {interval: 150}, function() { |
|||
typeof cb === "function" && cb(file); |
|||
}); |
|||
partial && cb(file); |
|||
})(file, cb); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Sets up a store of the folders being watched
|
|||
// and saves the last modification timestamp for it
|
|||
function storeDirectory(file) { |
|||
var directory = file.fullParentDir; |
|||
if (!watched_directories[directory]) { |
|||
fs.stat(directory, function(err, stats) { |
|||
if (err) { |
|||
watched_directories[directory] = (new Date).getTime(); |
|||
} else { |
|||
watched_directories[directory] = (new Date(stats.mtime)).getTime(); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
|
|||
return { |
|||
watchDirectory: watchDirectory, |
|||
watchFiles: watchFiles, |
|||
unwatchAll: unwatchAll |
|||
}; |
|||
} |
@ -0,0 +1,15 @@ |
|||
lib-cov |
|||
*.seed |
|||
*.log |
|||
*.csv |
|||
*.dat |
|||
*.out |
|||
*.pid |
|||
*.gz |
|||
|
|||
pids |
|||
logs |
|||
results |
|||
|
|||
node_modules |
|||
npm-debug.log |
@ -0,0 +1,5 @@ |
|||
language: node_js |
|||
node_js: |
|||
- 0.6 |
|||
- 0.8 |
|||
- 0.9 |
@ -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,227 @@ |
|||
# readdirp [![Build Status](https://secure.travis-ci.org/thlorenz/readdirp.png)](http://travis-ci.org/thlorenz/readdirp) |
|||
|
|||
Recursive version of [fs.readdir](http://nodejs.org/docs/latest/api/fs.html#fs_fs_readdir_path_callback). Exposes a **stream api**. |
|||
|
|||
```javascript |
|||
var readdirp = require('readdirp'); |
|||
, path = require('path') |
|||
, es = require('event-stream'); |
|||
|
|||
// print out all JavaScript files along with their size |
|||
|
|||
var stream = readdirp({ root: path.join(__dirname), fileFilter: '*.js' }); |
|||
stream |
|||
.on('warn', function (err) { |
|||
console.error('non-fatal error', err); |
|||
// optionally call stream.destroy() here in order to abort and cause 'close' to be emitted |
|||
}) |
|||
.on('error', function (err) { console.error('fatal error', err); }) |
|||
.pipe(es.mapSync(function (entry) { |
|||
return { path: entry.path, size: entry.stat.size }; |
|||
})) |
|||
.pipe(es.stringify()) |
|||
.pipe(process.stdout); |
|||
``` |
|||
|
|||
Meant to be one of the recursive versions of [fs](http://nodejs.org/docs/latest/api/fs.html) functions, e.g., like [mkdirp](https://github.com/substack/node-mkdirp). |
|||
|
|||
**Table of Contents** *generated with [DocToc](http://doctoc.herokuapp.com/)* |
|||
|
|||
- [Installation](#installation) |
|||
- [API](#api) |
|||
- [entry stream](#entry-stream) |
|||
- [options](#options) |
|||
- [entry info](#entry-info) |
|||
- [Filters](#filters) |
|||
- [Callback API](#callback-api) |
|||
- [allProcessed ](#allprocessed) |
|||
- [fileProcessed](#fileprocessed) |
|||
- [More Examples](#more-examples) |
|||
- [stream api](#stream-api) |
|||
- [stream api pipe](#stream-api-pipe) |
|||
- [grep](#grep) |
|||
- [using callback api](#using-callback-api) |
|||
- [tests](#tests) |
|||
|
|||
|
|||
# Installation |
|||
|
|||
npm install readdirp |
|||
|
|||
# API |
|||
|
|||
***var entryStream = readdirp (options)*** |
|||
|
|||
Reads given root recursively and returns a `stream` of [entry info](#entry-info)s. |
|||
|
|||
## entry stream |
|||
|
|||
Behaves as follows: |
|||
|
|||
- `emit('data')` passes an [entry info](#entry-info) whenever one is found |
|||
- `emit('warn')` passes a non-fatal `Error` that prevents a file/directory from being processed (i.e., if it is |
|||
inaccessible to the user) |
|||
- `emit('error')` passes a fatal `Error` which also ends the stream (i.e., when illegal options where passed) |
|||
- `emit('end')` called when all entries were found and no more will be emitted (i.e., we are done) |
|||
- `emit('close')` called when the stream is destroyed via `stream.destroy()` (which could be useful if you want to |
|||
manually abort even on a non fatal error) - at that point the stream is no longer `readable` and no more entries, |
|||
warning or errors are emitted |
|||
- the stream is `paused` initially in order to allow `pipe` and `on` handlers be connected before data or errors are |
|||
emitted |
|||
- the stream is `resumed` automatically during the next event loop |
|||
- to learn more about streams, consult the [stream-handbook](https://github.com/substack/stream-handbook) |
|||
|
|||
## options |
|||
|
|||
- **root**: path in which to start reading and recursing into subdirectories |
|||
|
|||
- **fileFilter**: filter to include/exclude files found (see [Filters](#filters) for more) |
|||
|
|||
- **directoryFilter**: filter to include/exclude directories found and to recurse into (see [Filters](#filters) for more) |
|||
|
|||
- **depth**: depth at which to stop recursing even if more subdirectories are found |
|||
|
|||
## entry info |
|||
|
|||
Has the following properties: |
|||
|
|||
- **parentDir** : directory in which entry was found (relative to given root) |
|||
- **fullParentDir** : full path to parent directory |
|||
- **name** : name of the file/directory |
|||
- **path** : path to the file/directory (relative to given root) |
|||
- **fullPath** : full path to the file/directory found |
|||
- **stat** : built in [stat object](http://nodejs.org/docs/v0.4.9/api/fs.html#fs.Stats) |
|||
- **Example**: (assuming root was `/User/dev/readdirp`) |
|||
|
|||
parentDir : 'test/bed/root_dir1', |
|||
fullParentDir : '/User/dev/readdirp/test/bed/root_dir1', |
|||
name : 'root_dir1_subdir1', |
|||
path : 'test/bed/root_dir1/root_dir1_subdir1', |
|||
fullPath : '/User/dev/readdirp/test/bed/root_dir1/root_dir1_subdir1', |
|||
stat : [ ... ] |
|||
|
|||
## Filters |
|||
|
|||
There are three different ways to specify filters for files and directories respectively. |
|||
|
|||
- **function**: a function that takes an entry info as a parameter and returns true to include or false to exclude the entry |
|||
|
|||
- **glob string**: a string (e.g., `*.js`) which is matched using [minimatch](https://github.com/isaacs/minimatch), so go there for more |
|||
information. |
|||
|
|||
Globstars (`**`) are not supported since specifiying a recursive pattern for an already recursive function doesn't make sense. |
|||
|
|||
Negated globs (as explained in the minimatch documentation) are allowed, e.g., `!*.txt` matches everything but text files. |
|||
|
|||
- **array of glob strings**: either need to be all inclusive or all exclusive (negated) patterns otherwise an error is thrown. |
|||
|
|||
`[ '*.json', '*.js' ]` includes all JavaScript and Json files. |
|||
|
|||
|
|||
`[ '!.git', '!node_modules' ]` includes all directories except the '.git' and 'node_modules'. |
|||
|
|||
Directories that do not pass a filter will not be recursed into. |
|||
|
|||
## Callback API |
|||
|
|||
Although the stream api is recommended, readdirp also exposes a callback based api. |
|||
|
|||
***readdirp (options, callback1 [, callback2])*** |
|||
|
|||
If callback2 is given, callback1 functions as the **fileProcessed** callback, and callback2 as the **allProcessed** callback. |
|||
|
|||
If only callback1 is given, it functions as the **allProcessed** callback. |
|||
|
|||
### allProcessed |
|||
|
|||
- function with err and res parameters, e.g., `function (err, res) { ... }` |
|||
- **err**: array of errors that occurred during the operation, **res may still be present, even if errors occurred** |
|||
- **res**: collection of file/directory [entry infos](#entry-info) |
|||
|
|||
### fileProcessed |
|||
|
|||
- function with [entry info](#entry-info) parameter e.g., `function (entryInfo) { ... }` |
|||
|
|||
|
|||
# More Examples |
|||
|
|||
`on('error', ..)`, `on('warn', ..)` and `on('end', ..)` handling omitted for brevity |
|||
|
|||
```javascript |
|||
var readdirp = require('readdirp'); |
|||
|
|||
// Glob file filter |
|||
readdirp({ root: './test/bed', fileFilter: '*.js' }) |
|||
.on('data', function (entry) { |
|||
// do something with each JavaScript file entry |
|||
}); |
|||
|
|||
// Combined glob file filters |
|||
readdirp({ root: './test/bed', fileFilter: [ '*.js', '*.json' ] }) |
|||
.on('data', function (entry) { |
|||
// do something with each JavaScript and Json file entry |
|||
}); |
|||
|
|||
// Combined negated directory filters |
|||
readdirp({ root: './test/bed', directoryFilter: [ '!.git', '!*modules' ] }) |
|||
.on('data', function (entry) { |
|||
// do something with each file entry found outside '.git' or any modules directory |
|||
}); |
|||
|
|||
// Function directory filter |
|||
readdirp({ root: './test/bed', directoryFilter: function (di) { return di.name.length === 9; } }) |
|||
.on('data', function (entry) { |
|||
// do something with each file entry found inside directories whose name has length 9 |
|||
}); |
|||
|
|||
// Limiting depth |
|||
readdirp({ root: './test/bed', depth: 1 }) |
|||
.on('data', function (entry) { |
|||
// do something with each file entry found up to 1 subdirectory deep |
|||
}); |
|||
|
|||
// callback api |
|||
readdirp( |
|||
{ root: '.' } |
|||
, function(fileInfo) { |
|||
// do something with file entry here |
|||
} |
|||
, function (err, res) { |
|||
// all done, move on or do final step for all file entries here |
|||
} |
|||
); |
|||
``` |
|||
|
|||
Try more examples by following [instructions](https://github.com/thlorenz/readdirp/blob/master/examples/Readme.md) |
|||
on how to get going. |
|||
|
|||
## stream api |
|||
|
|||
[stream-api.js](https://github.com/thlorenz/readdirp/blob/master/examples/stream-api.js) |
|||
|
|||
Demonstrates error and data handling by listening to events emitted from the readdirp stream. |
|||
|
|||
## stream api pipe |
|||
|
|||
[stream-api-pipe.js](https://github.com/thlorenz/readdirp/blob/master/examples/stream-api-pipe.js) |
|||
|
|||
Demonstrates error handling by listening to events emitted from the readdirp stream and how to pipe the data stream into |
|||
another destination stream. |
|||
|
|||
## grep |
|||
|
|||
[grep.js](https://github.com/thlorenz/readdirp/blob/master/examples/grep.js) |
|||
|
|||
Very naive implementation of grep, for demonstration purposes only. |
|||
|
|||
## using callback api |
|||
|
|||
[callback-api.js](https://github.com/thlorenz/readdirp/blob/master/examples/callback-api.js) |
|||
|
|||
Shows how to pass callbacks in order to handle errors and/or data. |
|||
|
|||
## tests |
|||
|
|||
The [readdirp tests](https://github.com/thlorenz/readdirp/blob/master/test/readdirp.js) also will give you a good idea on |
|||
how things work. |
|||
|
@ -0,0 +1,37 @@ |
|||
# readdirp examples |
|||
|
|||
## How to run the examples |
|||
|
|||
Assuming you installed readdirp (`npm install readdirp`), you can do the following: |
|||
|
|||
1. `npm explore readdirp` |
|||
2. `cd examples` |
|||
3. `npm install` |
|||
|
|||
At that point you can run the examples with node, i.e., `node grep`. |
|||
|
|||
## stream api |
|||
|
|||
[stream-api.js](https://github.com/thlorenz/readdirp/blob/master/examples/stream-api.js) |
|||
|
|||
Demonstrates error and data handling by listening to events emitted from the readdirp stream. |
|||
|
|||
## stream api pipe |
|||
|
|||
[stream-api-pipe.js](https://github.com/thlorenz/readdirp/blob/master/examples/stream-api-pipe.js) |
|||
|
|||
Demonstrates error handling by listening to events emitted from the readdirp stream and how to pipe the data stream into |
|||
another destination stream. |
|||
|
|||
## grep |
|||
|
|||
[grep.js](https://github.com/thlorenz/readdirp/blob/master/examples/grep.js) |
|||
|
|||
Very naive implementation of grep, for demonstration purposes only. |
|||
|
|||
## using callback api |
|||
|
|||
[callback-api.js](https://github.com/thlorenz/readdirp/blob/master/examples/callback-api.js) |
|||
|
|||
Shows how to pass callbacks in order to handle errors and/or data. |
|||
|
@ -0,0 +1,10 @@ |
|||
var readdirp = require('..'); |
|||
|
|||
readdirp({ root: '.', fileFilter: '*.js' }, function (errors, res) { |
|||
if (errors) { |
|||
errors.forEach(function (err) { |
|||
console.error('Error: ', err); |
|||
}); |
|||
} |
|||
console.log('all javascript files', res); |
|||
}); |
@ -0,0 +1,73 @@ |
|||
'use strict'; |
|||
var readdirp = require('..') |
|||
, util = require('util') |
|||
, fs = require('fs') |
|||
, path = require('path') |
|||
, Stream = require('stream') |
|||
, tap = require('tap-stream') |
|||
, es = require('event-stream') |
|||
; |
|||
|
|||
function findLinesMatching (searchTerm) { |
|||
|
|||
return es.through(function (entry) { |
|||
var lineno = 0 |
|||
, matchingLines = [] |
|||
, fileStream = this; |
|||
|
|||
function filter () { |
|||
return es.mapSync(function (line) { |
|||
lineno++; |
|||
return ~line.indexOf(searchTerm) ? lineno + ': ' + line : undefined; |
|||
}); |
|||
} |
|||
|
|||
function aggregate () { |
|||
return es.through( |
|||
function write (data) { |
|||
matchingLines.push(data); |
|||
} |
|||
, function end () { |
|||
|
|||
// drop files that had no matches
|
|||
if (matchingLines.length) { |
|||
var result = { file: entry, lines: matchingLines }; |
|||
|
|||
// pass result on to file stream
|
|||
fileStream.emit('data', result); |
|||
} |
|||
this.emit('end'); |
|||
} |
|||
); |
|||
} |
|||
|
|||
fs.createReadStream(entry.fullPath, { encoding: 'utf-8' }) |
|||
|
|||
// handle file contents line by line
|
|||
.pipe(es.split('\n')) |
|||
|
|||
// keep only the lines that matched the term
|
|||
.pipe(filter()) |
|||
|
|||
// aggregate all matching lines and delegate control back to the file stream
|
|||
.pipe(aggregate()) |
|||
; |
|||
}); |
|||
} |
|||
|
|||
console.log('grepping for "arguments"'); |
|||
|
|||
// create a stream of all javascript files found in this and all sub directories
|
|||
readdirp({ root: path.join(__dirname), fileFilter: '*.js' }) |
|||
|
|||
// find all lines matching the term for each file (if none found, that file is ignored)
|
|||
.pipe(findLinesMatching('arguments')) |
|||
|
|||
// format the results and output
|
|||
.pipe( |
|||
es.mapSync(function (res) { |
|||
return '\n\n' + res.file.path + '\n\t' + res.lines.join('\n\t'); |
|||
}) |
|||
) |
|||
.pipe(process.stdout) |
|||
; |
@ -0,0 +1,3 @@ |
|||
node_modules |
|||
node_modules/* |
|||
npm_debug.log |
@ -0,0 +1,4 @@ |
|||
language: node_js |
|||
node_js: |
|||
- 0.6 |
|||
- 0.8 |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue