Suppression node_modules exercices
This commit is contained in:
parent
bbcccf4586
commit
e4811d8040
|
@ -1 +0,0 @@
|
|||
../grunt-cli/bin/grunt
|
|
@ -1,3 +0,0 @@
|
|||
node_modules
|
||||
npm-debug.log
|
||||
tmp
|
|
@ -1,4 +0,0 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- "0.8"
|
||||
- "0.10"
|
|
@ -1,4 +0,0 @@
|
|||
Tyler Kellen (http://goingslowly.com)
|
||||
Ben Alman (http://gruntjs.com)
|
||||
Scott González (http://nemikor.com)
|
||||
Forbes Lindesay (https://github.com/)
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* grunt-cli
|
||||
* http://gruntjs.com/
|
||||
*
|
||||
* Copyright (c) 2012 Tyler Kellen, contributors
|
||||
* Licensed under the MIT license.
|
||||
* https://github.com/gruntjs/grunt-init/blob/master/LICENSE-MIT
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = function(grunt) {
|
||||
|
||||
// Project configuration.
|
||||
grunt.initConfig({
|
||||
jshint: {
|
||||
all: [
|
||||
'Gruntfile.js',
|
||||
'lib/**/*.js',
|
||||
'bin/*',
|
||||
],
|
||||
options: {
|
||||
curly: true,
|
||||
eqeqeq: true,
|
||||
immed: true,
|
||||
latedef: true,
|
||||
newcap: true,
|
||||
noarg: true,
|
||||
sub: true,
|
||||
undef: true,
|
||||
unused: true,
|
||||
boss: true,
|
||||
eqnull: true,
|
||||
node: true,
|
||||
es5: true
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// These plugins provide necessary tasks.
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
|
||||
// "npm test" runs these tasks
|
||||
grunt.registerTask('test', ['jshint']);
|
||||
|
||||
// Default task.
|
||||
grunt.registerTask('default', ['test']);
|
||||
|
||||
};
|
|
@ -1,22 +0,0 @@
|
|||
Copyright (c) 2012 Tyler Kellen, 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.
|
|
@ -1,30 +0,0 @@
|
|||
# grunt-cli [![Build Status](https://secure.travis-ci.org/gruntjs/grunt-cli.png?branch=master)](http://travis-ci.org/gruntjs/grunt-cli)
|
||||
> The Grunt command line interface.
|
||||
|
||||
Install this globally and you'll have access to the `grunt` command anywhere on your system.
|
||||
|
||||
```shell
|
||||
npm install -g grunt-cli
|
||||
```
|
||||
|
||||
**Note:** The job of the `grunt` command is to load and run the version of Grunt you have installed locally to your project, irrespective of its version. Starting with Grunt v0.4, you should never install Grunt itself globally. For more information about why, [please read this](http://blog.nodejs.org/2011/03/23/npm-1-0-global-vs-local-installation).
|
||||
|
||||
See the [Getting Started](http://gruntjs.com/getting-started) guide for more information.
|
||||
|
||||
## Shell tab auto-completion
|
||||
To enable tab auto-completion for Grunt, add one of the following lines to your `~/.bashrc` or `~/.zshrc` file.
|
||||
|
||||
```bash
|
||||
# Bash, ~/.bashrc
|
||||
eval "$(grunt --completion=bash)"
|
||||
```
|
||||
|
||||
```bash
|
||||
# Zsh, ~/.zshrc
|
||||
eval "$(grunt --completion=zsh)"
|
||||
```
|
||||
|
||||
## Installing grunt-cli locally
|
||||
If you prefer the idiomatic Node.js method to get started with a project (`npm install && npm test`) then install grunt-cli locally with `npm install grunt-cli --save-dev`. Then add a script to your `package.json` to run the associated grunt command: `"scripts": { "test": "grunt test" } `. Now `npm test` will use the locally installed `./node_modules/.bin/grunt` executable to run your Grunt commands.
|
||||
|
||||
To read more about npm scripts, please visit the npm docs: [https://npmjs.org/doc/misc/npm-scripts.html](https://npmjs.org/doc/misc/npm-scripts.html).
|
|
@ -1,45 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
process.title = 'grunt';
|
||||
|
||||
// Especially badass external libs.
|
||||
var findup = require('findup-sync');
|
||||
var resolve = require('resolve').sync;
|
||||
|
||||
// Internal libs.
|
||||
var options = require('../lib/cli').options;
|
||||
var completion = require('../lib/completion');
|
||||
var info = require('../lib/info');
|
||||
var path = require('path');
|
||||
|
||||
|
||||
var basedir = process.cwd();
|
||||
var gruntpath;
|
||||
|
||||
// Do stuff based on CLI options.
|
||||
if ('completion' in options) {
|
||||
completion.print(options.completion);
|
||||
} else if (options.version) {
|
||||
info.version();
|
||||
} else if (options.base && !options.gruntfile) {
|
||||
basedir = path.resolve(options.base);
|
||||
} else if (options.gruntfile) {
|
||||
basedir = path.resolve(path.dirname(options.gruntfile));
|
||||
}
|
||||
|
||||
try {
|
||||
gruntpath = resolve('grunt', {basedir: basedir});
|
||||
} catch (ex) {
|
||||
gruntpath = findup('lib/grunt.js');
|
||||
// No grunt install found!
|
||||
if (!gruntpath) {
|
||||
if (options.version) { process.exit(); }
|
||||
if (options.help) { info.help(); }
|
||||
info.fatal('Unable to find local grunt.', 99);
|
||||
}
|
||||
}
|
||||
|
||||
// Everything looks good. Require local grunt and run it.
|
||||
require(gruntpath).cli();
|
49
javascript/base/exercices/pipeline/grunt/node_modules/grunt-cli/completion/bash
generated
vendored
49
javascript/base/exercices/pipeline/grunt/node_modules/grunt-cli/completion/bash
generated
vendored
|
@ -1,49 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# grunt-cli
|
||||
# http://gruntjs.com/
|
||||
#
|
||||
# Copyright (c) 2012 Tyler Kellen, contributors
|
||||
# Licensed under the MIT license.
|
||||
# https://github.com/gruntjs/grunt/blob/master/LICENSE-MIT
|
||||
|
||||
# Usage:
|
||||
#
|
||||
# To enable bash <tab> completion for grunt, add the following line (minus the
|
||||
# leading #, which is the bash comment character) to your ~/.bashrc file:
|
||||
#
|
||||
# eval "$(grunt --completion=bash)"
|
||||
|
||||
# Search the current directory and all parent directories for a gruntfile.
|
||||
function _grunt_gruntfile() {
|
||||
local curpath="$PWD"
|
||||
while [[ "$curpath" ]]; do
|
||||
for gruntfile in "$curpath/"{G,g}runtfile.{js,coffee}; do
|
||||
if [[ -e "$gruntfile" ]]; then
|
||||
echo "$gruntfile"
|
||||
return
|
||||
fi
|
||||
done
|
||||
curpath="${curpath%/*}"
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# Enable bash autocompletion.
|
||||
function _grunt_completions() {
|
||||
# The currently-being-completed word.
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
# The current gruntfile, if it exists.
|
||||
local gruntfile="$(_grunt_gruntfile)"
|
||||
# The current grunt version, available tasks, options, etc.
|
||||
local gruntinfo="$(grunt --version --verbose 2>/dev/null)"
|
||||
# Options and tasks.
|
||||
local opts="$(echo "$gruntinfo" | awk '/Available options: / {$1=$2=""; print $0}')"
|
||||
local compls="$(echo "$gruntinfo" | awk '/Available tasks: / {$1=$2=""; print $0}')"
|
||||
# Only add -- or - options if the user has started typing -
|
||||
[[ "$cur" == -* ]] && compls="$compls $opts"
|
||||
# Tell complete what stuff to show.
|
||||
COMPREPLY=($(compgen -W "$compls" -- "$cur"))
|
||||
}
|
||||
|
||||
complete -o default -F _grunt_completions grunt
|
37
javascript/base/exercices/pipeline/grunt/node_modules/grunt-cli/completion/zsh
generated
vendored
37
javascript/base/exercices/pipeline/grunt/node_modules/grunt-cli/completion/zsh
generated
vendored
|
@ -1,37 +0,0 @@
|
|||
#!/bin/zsh
|
||||
|
||||
# grunt-cli
|
||||
# http://gruntjs.com/
|
||||
#
|
||||
# Copyright (c) 2012 Tyler Kellen, contributors
|
||||
# Licensed under the MIT license.
|
||||
# https://github.com/gruntjs/grunt/blob/master/LICENSE-MIT
|
||||
|
||||
# Usage:
|
||||
#
|
||||
# To enable zsh <tab> completion for grunt, add the following line (minus the
|
||||
# leading #, which is the zsh comment character) to your ~/.zshrc file:
|
||||
#
|
||||
# eval "$(grunt --completion=zsh)"
|
||||
|
||||
# Enable zsh autocompletion.
|
||||
function _grunt_completion() {
|
||||
local completions
|
||||
# The currently-being-completed word.
|
||||
local cur="${words[@]}"
|
||||
# The current grunt version, available tasks, options, etc.
|
||||
local gruntinfo="$(grunt --version --verbose 2>/dev/null)"
|
||||
# Options and tasks.
|
||||
local opts="$(echo "$gruntinfo" | awk '/Available options: / {$1=$2=""; print $0}')"
|
||||
local compls="$(echo "$gruntinfo" | awk '/Available tasks: / {$1=$2=""; print $0}')"
|
||||
# Only add -- or - options if the user has started typing -
|
||||
[[ "$cur" == -* ]] && compls="$compls $opts"
|
||||
# Trim whitespace.
|
||||
compls=$(echo "$compls" | sed -e 's/^ *//g' -e 's/ *$//g')
|
||||
# Turn compls into an array to of completions.
|
||||
completions=(${=compls})
|
||||
# Tell complete what stuff to show.
|
||||
compadd -- $completions
|
||||
}
|
||||
|
||||
compdef _grunt_completion grunt
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* grunt-cli
|
||||
* http://gruntjs.com/
|
||||
*
|
||||
* Copyright (c) 2012 Tyler Kellen, contributors
|
||||
* Licensed under the MIT license.
|
||||
* https://github.com/gruntjs/grunt-init/blob/master/LICENSE-MIT
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// External lib.
|
||||
var nopt = require('nopt');
|
||||
|
||||
// CLI options we care about.
|
||||
exports.known = {help: Boolean, version: Boolean, completion: String};
|
||||
exports.aliases = {h: '--help', V: '--version', v: '--verbose'};
|
||||
|
||||
// Parse them and return an options object.
|
||||
Object.defineProperty(exports, 'options', {
|
||||
get: function() {
|
||||
return nopt(exports.known, exports.aliases, process.argv, 2);
|
||||
}
|
||||
});
|
34
javascript/base/exercices/pipeline/grunt/node_modules/grunt-cli/lib/completion.js
generated
vendored
34
javascript/base/exercices/pipeline/grunt/node_modules/grunt-cli/lib/completion.js
generated
vendored
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* grunt-cli
|
||||
* http://gruntjs.com/
|
||||
*
|
||||
* Copyright (c) 2012 Tyler Kellen, contributors
|
||||
* Licensed under the MIT license.
|
||||
* https://github.com/gruntjs/grunt-init/blob/master/LICENSE-MIT
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// Nodejs libs.
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
exports.print = function(name) {
|
||||
var code = 0;
|
||||
var filepath = path.join(__dirname, '../completion', name);
|
||||
var output;
|
||||
try {
|
||||
// Attempt to read shell completion file.
|
||||
output = String(fs.readFileSync(filepath));
|
||||
} catch (err) {
|
||||
code = 5;
|
||||
output = 'echo "Specified grunt shell auto-completion rules ';
|
||||
if (name && name !== 'true') {
|
||||
output += 'for \'' + name + '\' ';
|
||||
}
|
||||
output += 'not found."';
|
||||
}
|
||||
|
||||
console.log(output);
|
||||
process.exit(code);
|
||||
};
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* grunt-cli
|
||||
* http://gruntjs.com/
|
||||
*
|
||||
* Copyright (c) 2012 Tyler Kellen, contributors
|
||||
* Licensed under the MIT license.
|
||||
* https://github.com/gruntjs/grunt-init/blob/master/LICENSE-MIT
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// Project metadata.
|
||||
var pkg = require('../package.json');
|
||||
|
||||
// Display grunt-cli version.
|
||||
exports.version = function() {
|
||||
console.log('grunt-cli v' + pkg.version);
|
||||
};
|
||||
|
||||
// Show help, then exit with a message and error code.
|
||||
exports.fatal = function(msg, code) {
|
||||
exports.helpHeader();
|
||||
console.log('Fatal error: ' + msg);
|
||||
console.log('');
|
||||
exports.helpFooter();
|
||||
process.exit(code);
|
||||
};
|
||||
|
||||
// Show help and exit.
|
||||
exports.help = function() {
|
||||
exports.helpHeader();
|
||||
exports.helpFooter();
|
||||
process.exit();
|
||||
};
|
||||
|
||||
// Help header.
|
||||
exports.helpHeader = function() {
|
||||
console.log('grunt-cli: ' + pkg.description + ' (v' + pkg.version + ')');
|
||||
console.log('');
|
||||
};
|
||||
|
||||
// Help footer.
|
||||
exports.helpFooter = function() {
|
||||
[
|
||||
'If you\'re seeing this message, either a Gruntfile wasn\'t found or grunt',
|
||||
'hasn\'t been installed locally to your project. For more information about',
|
||||
'installing and configuring grunt, please see the Getting Started guide:',
|
||||
'',
|
||||
'http://gruntjs.com/getting-started',
|
||||
].forEach(function(str) { console.log(str); });
|
||||
};
|
|
@ -1 +0,0 @@
|
|||
../nopt/bin/nopt.js
|
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"loopfunc": true,
|
||||
"curly": true,
|
||||
"eqeqeq": true,
|
||||
"immed": true,
|
||||
"latedef": true,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"sub": true,
|
||||
"undef": true,
|
||||
"unused": true,
|
||||
"boss": true,
|
||||
"eqnull": true,
|
||||
"node": true
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- 0.8
|
||||
before_script:
|
||||
- npm install -g grunt-cli
|
|
@ -1,25 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = function(grunt) {
|
||||
|
||||
// Project configuration.
|
||||
grunt.initConfig({
|
||||
nodeunit: {
|
||||
files: ['test/**/*_test.js'],
|
||||
},
|
||||
jshint: {
|
||||
options: {
|
||||
jshintrc: '.jshintrc'
|
||||
},
|
||||
all: ['Gruntfile.js', 'lib/**/*.js', 'test/**/*.js']
|
||||
}
|
||||
});
|
||||
|
||||
// Load plugins.
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
grunt.loadNpmTasks('grunt-contrib-nodeunit');
|
||||
|
||||
// Default task.
|
||||
grunt.registerTask('default', ['jshint', 'nodeunit']);
|
||||
|
||||
};
|
|
@ -1,22 +0,0 @@
|
|||
Copyright (c) 2013 "Cowboy" Ben Alman
|
||||
|
||||
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.
|
|
@ -1,45 +0,0 @@
|
|||
# findup-sync [![Build Status](https://secure.travis-ci.org/cowboy/node-findup-sync.png?branch=master)](http://travis-ci.org/cowboy/node-findup-sync)
|
||||
|
||||
Find the first file matching a given pattern in the current directory or the nearest ancestor directory.
|
||||
|
||||
## Getting Started
|
||||
Install the module with: `npm install findup-sync`
|
||||
|
||||
```js
|
||||
var findup = require('findup-sync');
|
||||
|
||||
// Start looking in the CWD.
|
||||
var filepath1 = findup('{a,b}*.txt');
|
||||
|
||||
// Start looking somewhere else, and ignore case (probably a good idea).
|
||||
var filepath2 = findup('{a,b}*.txt', {cwd: '/some/path', nocase: true});
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
findup(patternOrPatterns [, minimatchOptions])
|
||||
```
|
||||
|
||||
### patternOrPatterns
|
||||
Type: `String` or `Array`
|
||||
Default: none
|
||||
|
||||
One or more wildcard glob patterns. Or just filenames.
|
||||
|
||||
### minimatchOptions
|
||||
Type: `Object`
|
||||
Default: `{}`
|
||||
|
||||
Options to be passed to [minimatch](https://github.com/isaacs/minimatch).
|
||||
|
||||
Note that if you want to start in a different directory than the current working directory, specify a `cwd` property here.
|
||||
|
||||
## Contributing
|
||||
In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com/).
|
||||
|
||||
## Release History
|
||||
2014-03-14 - v0.1.3 - Updated dependencies.
|
||||
2013-03-08 - v0.1.2 - Updated dependencies. Fixed a Node 0.9.x bug. Updated unit tests to work cross-platform.
|
||||
2012-11-15 - v0.1.1 - Now works without an options object.
|
||||
2012-11-01 - v0.1.0 - Initial release.
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* findup-sync
|
||||
* https://github.com/cowboy/node-findup-sync
|
||||
*
|
||||
* Copyright (c) 2013 "Cowboy" Ben Alman
|
||||
* Licensed under the MIT license.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// Nodejs libs.
|
||||
var path = require('path');
|
||||
|
||||
// External libs.
|
||||
var glob = require('glob');
|
||||
var _ = require('lodash');
|
||||
|
||||
// Search for a filename in the given directory or all parent directories.
|
||||
module.exports = function(patterns, options) {
|
||||
// Normalize patterns to an array.
|
||||
if (!Array.isArray(patterns)) { patterns = [patterns]; }
|
||||
// Create globOptions so that it can be modified without mutating the
|
||||
// original object.
|
||||
var globOptions = Object.create(options || {});
|
||||
globOptions.maxDepth = 1;
|
||||
globOptions.cwd = path.resolve(globOptions.cwd || '.');
|
||||
|
||||
var files, lastpath;
|
||||
do {
|
||||
// Search for files matching patterns.
|
||||
files = _(patterns).map(function(pattern) {
|
||||
return glob.sync(pattern, globOptions);
|
||||
}).flatten().uniq().value();
|
||||
// Return file if found.
|
||||
if (files.length > 0) {
|
||||
return path.resolve(path.join(globOptions.cwd, files[0]));
|
||||
}
|
||||
// Go up a directory.
|
||||
lastpath = globOptions.cwd;
|
||||
globOptions.cwd = path.resolve(globOptions.cwd, '..');
|
||||
// If parentpath is the same as basedir, we can't go any higher.
|
||||
} while (globOptions.cwd !== lastpath);
|
||||
|
||||
// No files were found!
|
||||
return null;
|
||||
};
|
|
@ -1,2 +0,0 @@
|
|||
.*.swp
|
||||
test/a/
|
|
@ -1,3 +0,0 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- 0.8
|
|
@ -1,27 +0,0 @@
|
|||
Copyright (c) Isaac Z. Schlueter ("Author")
|
||||
All rights reserved.
|
||||
|
||||
The BSD License
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. 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.
|
|
@ -1,250 +0,0 @@
|
|||
# Glob
|
||||
|
||||
Match files using the patterns the shell uses, like stars and stuff.
|
||||
|
||||
This is a glob implementation in JavaScript. It uses the `minimatch`
|
||||
library to do its matching.
|
||||
|
||||
## Attention: node-glob users!
|
||||
|
||||
The API has changed dramatically between 2.x and 3.x. This library is
|
||||
now 100% JavaScript, and the integer flags have been replaced with an
|
||||
options object.
|
||||
|
||||
Also, there's an event emitter class, proper tests, and all the other
|
||||
things you've come to expect from node modules.
|
||||
|
||||
And best of all, no compilation!
|
||||
|
||||
## Usage
|
||||
|
||||
```javascript
|
||||
var glob = require("glob")
|
||||
|
||||
// options is optional
|
||||
glob("**/*.js", options, function (er, files) {
|
||||
// files is an array of filenames.
|
||||
// If the `nonull` option is set, and nothing
|
||||
// was found, then files is ["**/*.js"]
|
||||
// er is an error object or null.
|
||||
})
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
Please see the [minimatch
|
||||
documentation](https://github.com/isaacs/minimatch) for more details.
|
||||
|
||||
Supports these glob features:
|
||||
|
||||
* Brace Expansion
|
||||
* Extended glob matching
|
||||
* "Globstar" `**` matching
|
||||
|
||||
See:
|
||||
|
||||
* `man sh`
|
||||
* `man bash`
|
||||
* `man 3 fnmatch`
|
||||
* `man 5 gitignore`
|
||||
* [minimatch documentation](https://github.com/isaacs/minimatch)
|
||||
|
||||
## glob(pattern, [options], cb)
|
||||
|
||||
* `pattern` {String} Pattern to be matched
|
||||
* `options` {Object}
|
||||
* `cb` {Function}
|
||||
* `err` {Error | null}
|
||||
* `matches` {Array<String>} filenames found matching the pattern
|
||||
|
||||
Perform an asynchronous glob search.
|
||||
|
||||
## glob.sync(pattern, [options])
|
||||
|
||||
* `pattern` {String} Pattern to be matched
|
||||
* `options` {Object}
|
||||
* return: {Array<String>} filenames found matching the pattern
|
||||
|
||||
Perform a synchronous glob search.
|
||||
|
||||
## Class: glob.Glob
|
||||
|
||||
Create a Glob object by instanting the `glob.Glob` class.
|
||||
|
||||
```javascript
|
||||
var Glob = require("glob").Glob
|
||||
var mg = new Glob(pattern, options, cb)
|
||||
```
|
||||
|
||||
It's an EventEmitter, and starts walking the filesystem to find matches
|
||||
immediately.
|
||||
|
||||
### new glob.Glob(pattern, [options], [cb])
|
||||
|
||||
* `pattern` {String} pattern to search for
|
||||
* `options` {Object}
|
||||
* `cb` {Function} Called when an error occurs, or matches are found
|
||||
* `err` {Error | null}
|
||||
* `matches` {Array<String>} filenames found matching the pattern
|
||||
|
||||
Note that if the `sync` flag is set in the options, then matches will
|
||||
be immediately available on the `g.found` member.
|
||||
|
||||
### Properties
|
||||
|
||||
* `minimatch` The minimatch object that the glob uses.
|
||||
* `options` The options object passed in.
|
||||
* `error` The error encountered. When an error is encountered, the
|
||||
glob object is in an undefined state, and should be discarded.
|
||||
* `aborted` Boolean which is set to true when calling `abort()`. There
|
||||
is no way at this time to continue a glob search after aborting, but
|
||||
you can re-use the statCache to avoid having to duplicate syscalls.
|
||||
* `statCache` Collection of all the stat results the glob search
|
||||
performed.
|
||||
* `cache` Convenience object. Each field has the following possible
|
||||
values:
|
||||
* `false` - Path does not exist
|
||||
* `true` - Path exists
|
||||
* `1` - Path exists, and is not a directory
|
||||
* `2` - Path exists, and is a directory
|
||||
* `[file, entries, ...]` - Path exists, is a directory, and the
|
||||
array value is the results of `fs.readdir`
|
||||
|
||||
### Events
|
||||
|
||||
* `end` When the matching is finished, this is emitted with all the
|
||||
matches found. If the `nonull` option is set, and no match was found,
|
||||
then the `matches` list contains the original pattern. The matches
|
||||
are sorted, unless the `nosort` flag is set.
|
||||
* `match` Every time a match is found, this is emitted with the matched.
|
||||
* `error` Emitted when an unexpected error is encountered, or whenever
|
||||
any fs error occurs if `options.strict` is set.
|
||||
* `abort` When `abort()` is called, this event is raised.
|
||||
|
||||
### Methods
|
||||
|
||||
* `abort` Stop the search.
|
||||
|
||||
### Options
|
||||
|
||||
All the options that can be passed to Minimatch can also be passed to
|
||||
Glob to change pattern matching behavior. Also, some have been added,
|
||||
or have glob-specific ramifications.
|
||||
|
||||
All options are false by default, unless otherwise noted.
|
||||
|
||||
All options are added to the glob object, as well.
|
||||
|
||||
* `cwd` The current working directory in which to search. Defaults
|
||||
to `process.cwd()`.
|
||||
* `root` The place where patterns starting with `/` will be mounted
|
||||
onto. Defaults to `path.resolve(options.cwd, "/")` (`/` on Unix
|
||||
systems, and `C:\` or some such on Windows.)
|
||||
* `dot` Include `.dot` files in normal matches and `globstar` matches.
|
||||
Note that an explicit dot in a portion of the pattern will always
|
||||
match dot files.
|
||||
* `nomount` By default, a pattern starting with a forward-slash will be
|
||||
"mounted" onto the root setting, so that a valid filesystem path is
|
||||
returned. Set this flag to disable that behavior.
|
||||
* `mark` Add a `/` character to directory matches. Note that this
|
||||
requires additional stat calls.
|
||||
* `nosort` Don't sort the results.
|
||||
* `stat` Set to true to stat *all* results. This reduces performance
|
||||
somewhat, and is completely unnecessary, unless `readdir` is presumed
|
||||
to be an untrustworthy indicator of file existence. It will cause
|
||||
ELOOP to be triggered one level sooner in the case of cyclical
|
||||
symbolic links.
|
||||
* `silent` When an unusual error is encountered
|
||||
when attempting to read a directory, a warning will be printed to
|
||||
stderr. Set the `silent` option to true to suppress these warnings.
|
||||
* `strict` When an unusual error is encountered
|
||||
when attempting to read a directory, the process will just continue on
|
||||
in search of other matches. Set the `strict` option to raise an error
|
||||
in these cases.
|
||||
* `cache` See `cache` property above. Pass in a previously generated
|
||||
cache object to save some fs calls.
|
||||
* `statCache` A cache of results of filesystem information, to prevent
|
||||
unnecessary stat calls. While it should not normally be necessary to
|
||||
set this, you may pass the statCache from one glob() call to the
|
||||
options object of another, if you know that the filesystem will not
|
||||
change between calls. (See "Race Conditions" below.)
|
||||
* `sync` Perform a synchronous glob search.
|
||||
* `nounique` In some cases, brace-expanded patterns can result in the
|
||||
same file showing up multiple times in the result set. By default,
|
||||
this implementation prevents duplicates in the result set.
|
||||
Set this flag to disable that behavior.
|
||||
* `nonull` Set to never return an empty set, instead returning a set
|
||||
containing the pattern itself. This is the default in glob(3).
|
||||
* `nocase` Perform a case-insensitive match. Note that case-insensitive
|
||||
filesystems will sometimes result in glob returning results that are
|
||||
case-insensitively matched anyway, since readdir and stat will not
|
||||
raise an error.
|
||||
* `debug` Set to enable debug logging in minimatch and glob.
|
||||
* `globDebug` Set to enable debug logging in glob, but not minimatch.
|
||||
|
||||
## Comparisons to other fnmatch/glob implementations
|
||||
|
||||
While strict compliance with the existing standards is a worthwhile
|
||||
goal, some discrepancies exist between node-glob and other
|
||||
implementations, and are intentional.
|
||||
|
||||
If the pattern starts with a `!` character, then it is negated. Set the
|
||||
`nonegate` flag to suppress this behavior, and treat leading `!`
|
||||
characters normally. This is perhaps relevant if you wish to start the
|
||||
pattern with a negative extglob pattern like `!(a|B)`. Multiple `!`
|
||||
characters at the start of a pattern will negate the pattern multiple
|
||||
times.
|
||||
|
||||
If a pattern starts with `#`, then it is treated as a comment, and
|
||||
will not match anything. Use `\#` to match a literal `#` at the
|
||||
start of a line, or set the `nocomment` flag to suppress this behavior.
|
||||
|
||||
The double-star character `**` is supported by default, unless the
|
||||
`noglobstar` flag is set. This is supported in the manner of bsdglob
|
||||
and bash 4.1, where `**` only has special significance if it is the only
|
||||
thing in a path part. That is, `a/**/b` will match `a/x/y/b`, but
|
||||
`a/**b` will not.
|
||||
|
||||
If an escaped pattern has no matches, and the `nonull` flag is set,
|
||||
then glob returns the pattern as-provided, rather than
|
||||
interpreting the character escapes. For example,
|
||||
`glob.match([], "\\*a\\?")` will return `"\\*a\\?"` rather than
|
||||
`"*a?"`. This is akin to setting the `nullglob` option in bash, except
|
||||
that it does not resolve escaped pattern characters.
|
||||
|
||||
If brace expansion is not disabled, then it is performed before any
|
||||
other interpretation of the glob pattern. Thus, a pattern like
|
||||
`+(a|{b),c)}`, which would not be valid in bash or zsh, is expanded
|
||||
**first** into the set of `+(a|b)` and `+(a|c)`, and those patterns are
|
||||
checked for validity. Since those two are valid, matching proceeds.
|
||||
|
||||
## Windows
|
||||
|
||||
**Please only use forward-slashes in glob expressions.**
|
||||
|
||||
Though windows uses either `/` or `\` as its path separator, only `/`
|
||||
characters are used by this glob implementation. You must use
|
||||
forward-slashes **only** in glob expressions. Back-slashes will always
|
||||
be interpreted as escape characters, not path separators.
|
||||
|
||||
Results from absolute patterns such as `/foo/*` are mounted onto the
|
||||
root setting using `path.join`. On windows, this will by default result
|
||||
in `/foo/*` matching `C:\foo\bar.txt`.
|
||||
|
||||
## Race Conditions
|
||||
|
||||
Glob searching, by its very nature, is susceptible to race conditions,
|
||||
since it relies on directory walking and such.
|
||||
|
||||
As a result, it is possible that a file that exists when glob looks for
|
||||
it may have been deleted or modified by the time it returns the result.
|
||||
|
||||
As part of its internal implementation, this program caches all stat
|
||||
and readdir calls that it makes, in order to cut down on system
|
||||
overhead. However, this also makes it even more susceptible to races,
|
||||
especially if the cache or statCache objects are reused between glob
|
||||
calls.
|
||||
|
||||
Users are thus advised not to use a glob result as a guarantee of
|
||||
filesystem state in the face of rapid changes. For the vast majority
|
||||
of operations, this is never a problem.
|
|
@ -1,9 +0,0 @@
|
|||
var Glob = require("../").Glob
|
||||
|
||||
var pattern = "test/a/**/[cg]/../[cg]"
|
||||
console.log(pattern)
|
||||
|
||||
var mg = new Glob(pattern, {mark: true, sync:true}, function (er, matches) {
|
||||
console.log("matches", matches)
|
||||
})
|
||||
console.log("after")
|
|
@ -1,9 +0,0 @@
|
|||
var Glob = require("../").Glob
|
||||
|
||||
var pattern = "{./*/*,/*,/usr/local/*}"
|
||||
console.log(pattern)
|
||||
|
||||
var mg = new Glob(pattern, {mark: true}, function (er, matches) {
|
||||
console.log("matches", matches)
|
||||
})
|
||||
console.log("after")
|
|
@ -1,728 +0,0 @@
|
|||
// Approach:
|
||||
//
|
||||
// 1. Get the minimatch set
|
||||
// 2. For each pattern in the set, PROCESS(pattern)
|
||||
// 3. Store matches per-set, then uniq them
|
||||
//
|
||||
// PROCESS(pattern)
|
||||
// Get the first [n] items from pattern that are all strings
|
||||
// Join these together. This is PREFIX.
|
||||
// If there is no more remaining, then stat(PREFIX) and
|
||||
// add to matches if it succeeds. END.
|
||||
// readdir(PREFIX) as ENTRIES
|
||||
// If fails, END
|
||||
// If pattern[n] is GLOBSTAR
|
||||
// // handle the case where the globstar match is empty
|
||||
// // by pruning it out, and testing the resulting pattern
|
||||
// PROCESS(pattern[0..n] + pattern[n+1 .. $])
|
||||
// // handle other cases.
|
||||
// for ENTRY in ENTRIES (not dotfiles)
|
||||
// // attach globstar + tail onto the entry
|
||||
// PROCESS(pattern[0..n] + ENTRY + pattern[n .. $])
|
||||
//
|
||||
// else // not globstar
|
||||
// for ENTRY in ENTRIES (not dotfiles, unless pattern[n] is dot)
|
||||
// Test ENTRY against pattern[n]
|
||||
// If fails, continue
|
||||
// If passes, PROCESS(pattern[0..n] + item + pattern[n+1 .. $])
|
||||
//
|
||||
// Caveat:
|
||||
// Cache all stats and readdirs results to minimize syscall. Since all
|
||||
// we ever care about is existence and directory-ness, we can just keep
|
||||
// `true` for files, and [children,...] for directories, or `false` for
|
||||
// things that don't exist.
|
||||
|
||||
|
||||
|
||||
module.exports = glob
|
||||
|
||||
var fs = require("fs")
|
||||
, minimatch = require("minimatch")
|
||||
, Minimatch = minimatch.Minimatch
|
||||
, inherits = require("inherits")
|
||||
, EE = require("events").EventEmitter
|
||||
, path = require("path")
|
||||
, isDir = {}
|
||||
, assert = require("assert").ok
|
||||
|
||||
function glob (pattern, options, cb) {
|
||||
if (typeof options === "function") cb = options, options = {}
|
||||
if (!options) options = {}
|
||||
|
||||
if (typeof options === "number") {
|
||||
deprecated()
|
||||
return
|
||||
}
|
||||
|
||||
var g = new Glob(pattern, options, cb)
|
||||
return g.sync ? g.found : g
|
||||
}
|
||||
|
||||
glob.fnmatch = deprecated
|
||||
|
||||
function deprecated () {
|
||||
throw new Error("glob's interface has changed. Please see the docs.")
|
||||
}
|
||||
|
||||
glob.sync = globSync
|
||||
function globSync (pattern, options) {
|
||||
if (typeof options === "number") {
|
||||
deprecated()
|
||||
return
|
||||
}
|
||||
|
||||
options = options || {}
|
||||
options.sync = true
|
||||
return glob(pattern, options)
|
||||
}
|
||||
|
||||
this._processingEmitQueue = false
|
||||
|
||||
glob.Glob = Glob
|
||||
inherits(Glob, EE)
|
||||
function Glob (pattern, options, cb) {
|
||||
if (!(this instanceof Glob)) {
|
||||
return new Glob(pattern, options, cb)
|
||||
}
|
||||
|
||||
if (typeof options === "function") {
|
||||
cb = options
|
||||
options = null
|
||||
}
|
||||
|
||||
if (typeof cb === "function") {
|
||||
this.on("error", cb)
|
||||
this.on("end", function (matches) {
|
||||
cb(null, matches)
|
||||
})
|
||||
}
|
||||
|
||||
options = options || {}
|
||||
|
||||
this._endEmitted = false
|
||||
this.EOF = {}
|
||||
this._emitQueue = []
|
||||
|
||||
this.paused = false
|
||||
this._processingEmitQueue = false
|
||||
|
||||
this.maxDepth = options.maxDepth || 1000
|
||||
this.maxLength = options.maxLength || Infinity
|
||||
this.cache = options.cache || {}
|
||||
this.statCache = options.statCache || {}
|
||||
|
||||
this.changedCwd = false
|
||||
var cwd = process.cwd()
|
||||
if (!options.hasOwnProperty("cwd")) this.cwd = cwd
|
||||
else {
|
||||
this.cwd = options.cwd
|
||||
this.changedCwd = path.resolve(options.cwd) !== cwd
|
||||
}
|
||||
|
||||
this.root = options.root || path.resolve(this.cwd, "/")
|
||||
this.root = path.resolve(this.root)
|
||||
if (process.platform === "win32")
|
||||
this.root = this.root.replace(/\\/g, "/")
|
||||
|
||||
this.nomount = !!options.nomount
|
||||
|
||||
if (!pattern) {
|
||||
throw new Error("must provide pattern")
|
||||
}
|
||||
|
||||
// base-matching: just use globstar for that.
|
||||
if (options.matchBase && -1 === pattern.indexOf("/")) {
|
||||
if (options.noglobstar) {
|
||||
throw new Error("base matching requires globstar")
|
||||
}
|
||||
pattern = "**/" + pattern
|
||||
}
|
||||
|
||||
this.strict = options.strict !== false
|
||||
this.dot = !!options.dot
|
||||
this.mark = !!options.mark
|
||||
this.sync = !!options.sync
|
||||
this.nounique = !!options.nounique
|
||||
this.nonull = !!options.nonull
|
||||
this.nosort = !!options.nosort
|
||||
this.nocase = !!options.nocase
|
||||
this.stat = !!options.stat
|
||||
|
||||
this.debug = !!options.debug || !!options.globDebug
|
||||
if (this.debug)
|
||||
this.log = console.error
|
||||
|
||||
this.silent = !!options.silent
|
||||
|
||||
var mm = this.minimatch = new Minimatch(pattern, options)
|
||||
this.options = mm.options
|
||||
pattern = this.pattern = mm.pattern
|
||||
|
||||
this.error = null
|
||||
this.aborted = false
|
||||
|
||||
// list of all the patterns that ** has resolved do, so
|
||||
// we can avoid visiting multiple times.
|
||||
this._globstars = {}
|
||||
|
||||
EE.call(this)
|
||||
|
||||
// process each pattern in the minimatch set
|
||||
var n = this.minimatch.set.length
|
||||
|
||||
// The matches are stored as {<filename>: true,...} so that
|
||||
// duplicates are automagically pruned.
|
||||
// Later, we do an Object.keys() on these.
|
||||
// Keep them as a list so we can fill in when nonull is set.
|
||||
this.matches = new Array(n)
|
||||
|
||||
this.minimatch.set.forEach(iterator.bind(this))
|
||||
function iterator (pattern, i, set) {
|
||||
this._process(pattern, 0, i, function (er) {
|
||||
if (er) this.emit("error", er)
|
||||
if (-- n <= 0) this._finish()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Glob.prototype.log = function () {}
|
||||
|
||||
Glob.prototype._finish = function () {
|
||||
assert(this instanceof Glob)
|
||||
|
||||
var nou = this.nounique
|
||||
, all = nou ? [] : {}
|
||||
|
||||
for (var i = 0, l = this.matches.length; i < l; i ++) {
|
||||
var matches = this.matches[i]
|
||||
this.log("matches[%d] =", i, matches)
|
||||
// do like the shell, and spit out the literal glob
|
||||
if (!matches) {
|
||||
if (this.nonull) {
|
||||
var literal = this.minimatch.globSet[i]
|
||||
if (nou) all.push(literal)
|
||||
else all[literal] = true
|
||||
}
|
||||
} else {
|
||||
// had matches
|
||||
var m = Object.keys(matches)
|
||||
if (nou) all.push.apply(all, m)
|
||||
else m.forEach(function (m) {
|
||||
all[m] = true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (!nou) all = Object.keys(all)
|
||||
|
||||
if (!this.nosort) {
|
||||
all = all.sort(this.nocase ? alphasorti : alphasort)
|
||||
}
|
||||
|
||||
if (this.mark) {
|
||||
// at *some* point we statted all of these
|
||||
all = all.map(this._mark, this)
|
||||
}
|
||||
|
||||
this.log("emitting end", all)
|
||||
|
||||
this.EOF = this.found = all
|
||||
this.emitMatch(this.EOF)
|
||||
}
|
||||
|
||||
function alphasorti (a, b) {
|
||||
a = a.toLowerCase()
|
||||
b = b.toLowerCase()
|
||||
return alphasort(a, b)
|
||||
}
|
||||
|
||||
function alphasort (a, b) {
|
||||
return a > b ? 1 : a < b ? -1 : 0
|
||||
}
|
||||
|
||||
Glob.prototype._mark = function (p) {
|
||||
var c = this.cache[p]
|
||||
var m = p
|
||||
if (c) {
|
||||
var isDir = c === 2 || Array.isArray(c)
|
||||
var slash = p.slice(-1) === '/'
|
||||
|
||||
if (isDir && !slash)
|
||||
m += '/'
|
||||
else if (!isDir && slash)
|
||||
m = m.slice(0, -1)
|
||||
|
||||
if (m !== p) {
|
||||
this.statCache[m] = this.statCache[p]
|
||||
this.cache[m] = this.cache[p]
|
||||
}
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
Glob.prototype.abort = function () {
|
||||
this.aborted = true
|
||||
this.emit("abort")
|
||||
}
|
||||
|
||||
Glob.prototype.pause = function () {
|
||||
if (this.paused) return
|
||||
if (this.sync)
|
||||
this.emit("error", new Error("Can't pause/resume sync glob"))
|
||||
this.paused = true
|
||||
this.emit("pause")
|
||||
}
|
||||
|
||||
Glob.prototype.resume = function () {
|
||||
if (!this.paused) return
|
||||
if (this.sync)
|
||||
this.emit("error", new Error("Can't pause/resume sync glob"))
|
||||
this.paused = false
|
||||
this.emit("resume")
|
||||
this._processEmitQueue()
|
||||
//process.nextTick(this.emit.bind(this, "resume"))
|
||||
}
|
||||
|
||||
Glob.prototype.emitMatch = function (m) {
|
||||
this.log('emitMatch', m)
|
||||
this._emitQueue.push(m)
|
||||
this._processEmitQueue()
|
||||
}
|
||||
|
||||
Glob.prototype._processEmitQueue = function (m) {
|
||||
this.log("pEQ paused=%j processing=%j m=%j", this.paused,
|
||||
this._processingEmitQueue, m)
|
||||
var done = false
|
||||
while (!this._processingEmitQueue &&
|
||||
!this.paused) {
|
||||
this._processingEmitQueue = true
|
||||
var m = this._emitQueue.shift()
|
||||
this.log(">processEmitQueue", m === this.EOF ? ":EOF:" : m)
|
||||
if (!m) {
|
||||
this.log(">processEmitQueue, falsey m")
|
||||
this._processingEmitQueue = false
|
||||
break
|
||||
}
|
||||
|
||||
if (m === this.EOF || !(this.mark && !this.stat)) {
|
||||
this.log("peq: unmarked, or eof")
|
||||
next.call(this, 0, false)
|
||||
} else if (this.statCache[m]) {
|
||||
var sc = this.statCache[m]
|
||||
var exists
|
||||
if (sc)
|
||||
exists = sc.isDirectory() ? 2 : 1
|
||||
this.log("peq: stat cached")
|
||||
next.call(this, exists, exists === 2)
|
||||
} else {
|
||||
this.log("peq: _stat, then next")
|
||||
this._stat(m, next)
|
||||
}
|
||||
|
||||
function next(exists, isDir) {
|
||||
this.log("next", m, exists, isDir)
|
||||
var ev = m === this.EOF ? "end" : "match"
|
||||
|
||||
// "end" can only happen once.
|
||||
assert(!this._endEmitted)
|
||||
if (ev === "end")
|
||||
this._endEmitted = true
|
||||
|
||||
if (exists) {
|
||||
// Doesn't mean it necessarily doesn't exist, it's possible
|
||||
// we just didn't check because we don't care that much, or
|
||||
// this is EOF anyway.
|
||||
if (isDir && !m.match(/\/$/)) {
|
||||
m = m + "/"
|
||||
} else if (!isDir && m.match(/\/$/)) {
|
||||
m = m.replace(/\/+$/, "")
|
||||
}
|
||||
}
|
||||
this.log("emit", ev, m)
|
||||
this.emit(ev, m)
|
||||
this._processingEmitQueue = false
|
||||
if (done && m !== this.EOF && !this.paused)
|
||||
this._processEmitQueue()
|
||||
}
|
||||
}
|
||||
done = true
|
||||
}
|
||||
|
||||
Glob.prototype._process = function (pattern, depth, index, cb_) {
|
||||
assert(this instanceof Glob)
|
||||
|
||||
var cb = function cb (er, res) {
|
||||
assert(this instanceof Glob)
|
||||
if (this.paused) {
|
||||
if (!this._processQueue) {
|
||||
this._processQueue = []
|
||||
this.once("resume", function () {
|
||||
var q = this._processQueue
|
||||
this._processQueue = null
|
||||
q.forEach(function (cb) { cb() })
|
||||
})
|
||||
}
|
||||
this._processQueue.push(cb_.bind(this, er, res))
|
||||
} else {
|
||||
cb_.call(this, er, res)
|
||||
}
|
||||
}.bind(this)
|
||||
|
||||
if (this.aborted) return cb()
|
||||
|
||||
if (depth > this.maxDepth) return cb()
|
||||
|
||||
// Get the first [n] parts of pattern that are all strings.
|
||||
var n = 0
|
||||
while (typeof pattern[n] === "string") {
|
||||
n ++
|
||||
}
|
||||
// now n is the index of the first one that is *not* a string.
|
||||
|
||||
// see if there's anything else
|
||||
var prefix
|
||||
switch (n) {
|
||||
// if not, then this is rather simple
|
||||
case pattern.length:
|
||||
prefix = pattern.join("/")
|
||||
this._stat(prefix, function (exists, isDir) {
|
||||
// either it's there, or it isn't.
|
||||
// nothing more to do, either way.
|
||||
if (exists) {
|
||||
if (prefix && isAbsolute(prefix) && !this.nomount) {
|
||||
if (prefix.charAt(0) === "/") {
|
||||
prefix = path.join(this.root, prefix)
|
||||
} else {
|
||||
prefix = path.resolve(this.root, prefix)
|
||||
}
|
||||
}
|
||||
|
||||
if (process.platform === "win32")
|
||||
prefix = prefix.replace(/\\/g, "/")
|
||||
|
||||
this.matches[index] = this.matches[index] || {}
|
||||
this.matches[index][prefix] = true
|
||||
this.emitMatch(prefix)
|
||||
}
|
||||
return cb()
|
||||
})
|
||||
return
|
||||
|
||||
case 0:
|
||||
// pattern *starts* with some non-trivial item.
|
||||
// going to readdir(cwd), but not include the prefix in matches.
|
||||
prefix = null
|
||||
break
|
||||
|
||||
default:
|
||||
// pattern has some string bits in the front.
|
||||
// whatever it starts with, whether that's "absolute" like /foo/bar,
|
||||
// or "relative" like "../baz"
|
||||
prefix = pattern.slice(0, n)
|
||||
prefix = prefix.join("/")
|
||||
break
|
||||
}
|
||||
|
||||
// get the list of entries.
|
||||
var read
|
||||
if (prefix === null) read = "."
|
||||
else if (isAbsolute(prefix) || isAbsolute(pattern.join("/"))) {
|
||||
if (!prefix || !isAbsolute(prefix)) {
|
||||
prefix = path.join("/", prefix)
|
||||
}
|
||||
read = prefix = path.resolve(prefix)
|
||||
|
||||
// if (process.platform === "win32")
|
||||
// read = prefix = prefix.replace(/^[a-zA-Z]:|\\/g, "/")
|
||||
|
||||
this.log('absolute: ', prefix, this.root, pattern, read)
|
||||
} else {
|
||||
read = prefix
|
||||
}
|
||||
|
||||
this.log('readdir(%j)', read, this.cwd, this.root)
|
||||
|
||||
return this._readdir(read, function (er, entries) {
|
||||
if (er) {
|
||||
// not a directory!
|
||||
// this means that, whatever else comes after this, it can never match
|
||||
return cb()
|
||||
}
|
||||
|
||||
// globstar is special
|
||||
if (pattern[n] === minimatch.GLOBSTAR) {
|
||||
// test without the globstar, and with every child both below
|
||||
// and replacing the globstar.
|
||||
var s = [ pattern.slice(0, n).concat(pattern.slice(n + 1)) ]
|
||||
entries.forEach(function (e) {
|
||||
if (e.charAt(0) === "." && !this.dot) return
|
||||
// instead of the globstar
|
||||
s.push(pattern.slice(0, n).concat(e).concat(pattern.slice(n + 1)))
|
||||
// below the globstar
|
||||
s.push(pattern.slice(0, n).concat(e).concat(pattern.slice(n)))
|
||||
}, this)
|
||||
|
||||
s = s.filter(function (pattern) {
|
||||
var key = gsKey(pattern)
|
||||
var seen = !this._globstars[key]
|
||||
this._globstars[key] = true
|
||||
return seen
|
||||
}, this)
|
||||
|
||||
if (!s.length)
|
||||
return cb()
|
||||
|
||||
// now asyncForEach over this
|
||||
var l = s.length
|
||||
, errState = null
|
||||
s.forEach(function (gsPattern) {
|
||||
this._process(gsPattern, depth + 1, index, function (er) {
|
||||
if (errState) return
|
||||
if (er) return cb(errState = er)
|
||||
if (--l <= 0) return cb()
|
||||
})
|
||||
}, this)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// not a globstar
|
||||
// It will only match dot entries if it starts with a dot, or if
|
||||
// dot is set. Stuff like @(.foo|.bar) isn't allowed.
|
||||
var pn = pattern[n]
|
||||
var rawGlob = pattern[n]._glob
|
||||
, dotOk = this.dot || rawGlob.charAt(0) === "."
|
||||
|
||||
entries = entries.filter(function (e) {
|
||||
return (e.charAt(0) !== "." || dotOk) &&
|
||||
e.match(pattern[n])
|
||||
})
|
||||
|
||||
// If n === pattern.length - 1, then there's no need for the extra stat
|
||||
// *unless* the user has specified "mark" or "stat" explicitly.
|
||||
// We know that they exist, since the readdir returned them.
|
||||
if (n === pattern.length - 1 &&
|
||||
!this.mark &&
|
||||
!this.stat) {
|
||||
entries.forEach(function (e) {
|
||||
if (prefix) {
|
||||
if (prefix !== "/") e = prefix + "/" + e
|
||||
else e = prefix + e
|
||||
}
|
||||
if (e.charAt(0) === "/" && !this.nomount) {
|
||||
e = path.join(this.root, e)
|
||||
}
|
||||
|
||||
if (process.platform === "win32")
|
||||
e = e.replace(/\\/g, "/")
|
||||
|
||||
this.matches[index] = this.matches[index] || {}
|
||||
this.matches[index][e] = true
|
||||
this.emitMatch(e)
|
||||
}, this)
|
||||
return cb.call(this)
|
||||
}
|
||||
|
||||
|
||||
// now test all the remaining entries as stand-ins for that part
|
||||
// of the pattern.
|
||||
var l = entries.length
|
||||
, errState = null
|
||||
if (l === 0) return cb() // no matches possible
|
||||
entries.forEach(function (e) {
|
||||
var p = pattern.slice(0, n).concat(e).concat(pattern.slice(n + 1))
|
||||
this._process(p, depth + 1, index, function (er) {
|
||||
if (errState) return
|
||||
if (er) return cb(errState = er)
|
||||
if (--l === 0) return cb.call(this)
|
||||
})
|
||||
}, this)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
function gsKey (pattern) {
|
||||
return '**' + pattern.map(function (p) {
|
||||
return (p === minimatch.GLOBSTAR) ? '**' : (''+p)
|
||||
}).join('/')
|
||||
}
|
||||
|
||||
Glob.prototype._stat = function (f, cb) {
|
||||
assert(this instanceof Glob)
|
||||
var abs = f
|
||||
if (f.charAt(0) === "/") {
|
||||
abs = path.join(this.root, f)
|
||||
} else if (this.changedCwd) {
|
||||
abs = path.resolve(this.cwd, f)
|
||||
}
|
||||
|
||||
if (f.length > this.maxLength) {
|
||||
var er = new Error("Path name too long")
|
||||
er.code = "ENAMETOOLONG"
|
||||
er.path = f
|
||||
return this._afterStat(f, abs, cb, er)
|
||||
}
|
||||
|
||||
this.log('stat', [this.cwd, f, '=', abs])
|
||||
|
||||
if (!this.stat && this.cache.hasOwnProperty(f)) {
|
||||
var exists = this.cache[f]
|
||||
, isDir = exists && (Array.isArray(exists) || exists === 2)
|
||||
if (this.sync) return cb.call(this, !!exists, isDir)
|
||||
return process.nextTick(cb.bind(this, !!exists, isDir))
|
||||
}
|
||||
|
||||
var stat = this.statCache[abs]
|
||||
if (this.sync || stat) {
|
||||
var er
|
||||
try {
|
||||
stat = fs.statSync(abs)
|
||||
} catch (e) {
|
||||
er = e
|
||||
}
|
||||
this._afterStat(f, abs, cb, er, stat)
|
||||
} else {
|
||||
fs.stat(abs, this._afterStat.bind(this, f, abs, cb))
|
||||
}
|
||||
}
|
||||
|
||||
Glob.prototype._afterStat = function (f, abs, cb, er, stat) {
|
||||
var exists
|
||||
assert(this instanceof Glob)
|
||||
|
||||
if (abs.slice(-1) === "/" && stat && !stat.isDirectory()) {
|
||||
this.log("should be ENOTDIR, fake it")
|
||||
|
||||
er = new Error("ENOTDIR, not a directory '" + abs + "'")
|
||||
er.path = abs
|
||||
er.code = "ENOTDIR"
|
||||
stat = null
|
||||
}
|
||||
|
||||
var emit = !this.statCache[abs]
|
||||
this.statCache[abs] = stat
|
||||
|
||||
if (er || !stat) {
|
||||
exists = false
|
||||
} else {
|
||||
exists = stat.isDirectory() ? 2 : 1
|
||||
if (emit)
|
||||
this.emit('stat', f, stat)
|
||||
}
|
||||
this.cache[f] = this.cache[f] || exists
|
||||
cb.call(this, !!exists, exists === 2)
|
||||
}
|
||||
|
||||
Glob.prototype._readdir = function (f, cb) {
|
||||
assert(this instanceof Glob)
|
||||
var abs = f
|
||||
if (f.charAt(0) === "/") {
|
||||
abs = path.join(this.root, f)
|
||||
} else if (isAbsolute(f)) {
|
||||
abs = f
|
||||
} else if (this.changedCwd) {
|
||||
abs = path.resolve(this.cwd, f)
|
||||
}
|
||||
|
||||
if (f.length > this.maxLength) {
|
||||
var er = new Error("Path name too long")
|
||||
er.code = "ENAMETOOLONG"
|
||||
er.path = f
|
||||
return this._afterReaddir(f, abs, cb, er)
|
||||
}
|
||||
|
||||
this.log('readdir', [this.cwd, f, abs])
|
||||
if (this.cache.hasOwnProperty(f)) {
|
||||
var c = this.cache[f]
|
||||
if (Array.isArray(c)) {
|
||||
if (this.sync) return cb.call(this, null, c)
|
||||
return process.nextTick(cb.bind(this, null, c))
|
||||
}
|
||||
|
||||
if (!c || c === 1) {
|
||||
// either ENOENT or ENOTDIR
|
||||
var code = c ? "ENOTDIR" : "ENOENT"
|
||||
, er = new Error((c ? "Not a directory" : "Not found") + ": " + f)
|
||||
er.path = f
|
||||
er.code = code
|
||||
this.log(f, er)
|
||||
if (this.sync) return cb.call(this, er)
|
||||
return process.nextTick(cb.bind(this, er))
|
||||
}
|
||||
|
||||
// at this point, c === 2, meaning it's a dir, but we haven't
|
||||
// had to read it yet, or c === true, meaning it's *something*
|
||||
// but we don't have any idea what. Need to read it, either way.
|
||||
}
|
||||
|
||||
if (this.sync) {
|
||||
var er, entries
|
||||
try {
|
||||
entries = fs.readdirSync(abs)
|
||||
} catch (e) {
|
||||
er = e
|
||||
}
|
||||
return this._afterReaddir(f, abs, cb, er, entries)
|
||||
}
|
||||
|
||||
fs.readdir(abs, this._afterReaddir.bind(this, f, abs, cb))
|
||||
}
|
||||
|
||||
Glob.prototype._afterReaddir = function (f, abs, cb, er, entries) {
|
||||
assert(this instanceof Glob)
|
||||
if (entries && !er) {
|
||||
this.cache[f] = entries
|
||||
// if we haven't asked to stat everything for suresies, then just
|
||||
// assume that everything in there exists, so we can avoid
|
||||
// having to stat it a second time. This also gets us one step
|
||||
// further into ELOOP territory.
|
||||
if (!this.mark && !this.stat) {
|
||||
entries.forEach(function (e) {
|
||||
if (f === "/") e = f + e
|
||||
else e = f + "/" + e
|
||||
this.cache[e] = true
|
||||
}, this)
|
||||
}
|
||||
|
||||
return cb.call(this, er, entries)
|
||||
}
|
||||
|
||||
// now handle errors, and cache the information
|
||||
if (er) switch (er.code) {
|
||||
case "ENOTDIR": // totally normal. means it *does* exist.
|
||||
this.cache[f] = 1
|
||||
return cb.call(this, er)
|
||||
case "ENOENT": // not terribly unusual
|
||||
case "ELOOP":
|
||||
case "ENAMETOOLONG":
|
||||
case "UNKNOWN":
|
||||
this.cache[f] = false
|
||||
return cb.call(this, er)
|
||||
default: // some unusual error. Treat as failure.
|
||||
this.cache[f] = false
|
||||
if (this.strict) this.emit("error", er)
|
||||
if (!this.silent) console.error("glob error", er)
|
||||
return cb.call(this, er)
|
||||
}
|
||||
}
|
||||
|
||||
var isAbsolute = process.platform === "win32" ? absWin : absUnix
|
||||
|
||||
function absWin (p) {
|
||||
if (absUnix(p)) return true
|
||||
// pull off the device/UNC bit from a windows path.
|
||||
// from node's lib/path.js
|
||||
var splitDeviceRe =
|
||||
/^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/
|
||||
, result = splitDeviceRe.exec(p)
|
||||
, device = result[1] || ''
|
||||
, isUnc = device && device.charAt(1) !== ':'
|
||||
, isAbsolute = !!result[2] || isUnc // UNC paths are always absolute
|
||||
|
||||
return isAbsolute
|
||||
}
|
||||
|
||||
function absUnix (p) {
|
||||
return p.charAt(0) === "/" || p === ""
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
The ISC License
|
||||
|
||||
Copyright (c) Isaac Z. Schlueter
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
Browser-friendly inheritance fully compatible with standard node.js
|
||||
[inherits](http://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor).
|
||||
|
||||
This package exports standard `inherits` from node.js `util` module in
|
||||
node environment, but also provides alternative browser-friendly
|
||||
implementation through [browser
|
||||
field](https://gist.github.com/shtylman/4339901). Alternative
|
||||
implementation is a literal copy of standard one located in standalone
|
||||
module to avoid requiring of `util`. It also has a shim for old
|
||||
browsers with no `Object.create` support.
|
||||
|
||||
While keeping you sure you are using standard `inherits`
|
||||
implementation in node.js environment, it allows bundlers such as
|
||||
[browserify](https://github.com/substack/node-browserify) to not
|
||||
include full `util` package to your client code if all you need is
|
||||
just `inherits` function. It worth, because browser shim for `util`
|
||||
package is large and `inherits` is often the single function you need
|
||||
from it.
|
||||
|
||||
It's recommended to use this package instead of
|
||||
`require('util').inherits` for any code that has chances to be used
|
||||
not only in node.js but in browser too.
|
||||
|
||||
## usage
|
||||
|
||||
```js
|
||||
var inherits = require('inherits');
|
||||
// then use exactly as the standard one
|
||||
```
|
||||
|
||||
## note on version ~1.0
|
||||
|
||||
Version ~1.0 had completely different motivation and is not compatible
|
||||
neither with 2.0 nor with standard node.js `inherits`.
|
||||
|
||||
If you are using version ~1.0 and planning to switch to ~2.0, be
|
||||
careful:
|
||||
|
||||
* new version uses `super_` instead of `super` for referencing
|
||||
superclass
|
||||
* new version overwrites current prototype while old one preserves any
|
||||
existing fields on it
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('util').inherits
|
|
@ -1,23 +0,0 @@
|
|||
if (typeof Object.create === 'function') {
|
||||
// implementation from standard node.js 'util' module
|
||||
module.exports = function inherits(ctor, superCtor) {
|
||||
ctor.super_ = superCtor
|
||||
ctor.prototype = Object.create(superCtor.prototype, {
|
||||
constructor: {
|
||||
value: ctor,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
configurable: true
|
||||
}
|
||||
});
|
||||
};
|
||||
} else {
|
||||
// old school shim for old browsers
|
||||
module.exports = function inherits(ctor, superCtor) {
|
||||
ctor.super_ = superCtor
|
||||
var TempCtor = function () {}
|
||||
TempCtor.prototype = superCtor.prototype
|
||||
ctor.prototype = new TempCtor()
|
||||
ctor.prototype.constructor = ctor
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
{
|
||||
"name": "inherits",
|
||||
"description": "Browser-friendly inheritance fully compatible with standard node.js inherits()",
|
||||
"version": "2.0.1",
|
||||
"keywords": [
|
||||
"inheritance",
|
||||
"class",
|
||||
"klass",
|
||||
"oop",
|
||||
"object-oriented",
|
||||
"inherits",
|
||||
"browser",
|
||||
"browserify"
|
||||
],
|
||||
"main": "./inherits.js",
|
||||
"browser": "./inherits_browser.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/isaacs/inherits"
|
||||
},
|
||||
"license": "ISC",
|
||||
"scripts": {
|
||||
"test": "node test"
|
||||
},
|
||||
"readme": "Browser-friendly inheritance fully compatible with standard node.js\n[inherits](http://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor).\n\nThis package exports standard `inherits` from node.js `util` module in\nnode environment, but also provides alternative browser-friendly\nimplementation through [browser\nfield](https://gist.github.com/shtylman/4339901). Alternative\nimplementation is a literal copy of standard one located in standalone\nmodule to avoid requiring of `util`. It also has a shim for old\nbrowsers with no `Object.create` support.\n\nWhile keeping you sure you are using standard `inherits`\nimplementation in node.js environment, it allows bundlers such as\n[browserify](https://github.com/substack/node-browserify) to not\ninclude full `util` package to your client code if all you need is\njust `inherits` function. It worth, because browser shim for `util`\npackage is large and `inherits` is often the single function you need\nfrom it.\n\nIt's recommended to use this package instead of\n`require('util').inherits` for any code that has chances to be used\nnot only in node.js but in browser too.\n\n## usage\n\n```js\nvar inherits = require('inherits');\n// then use exactly as the standard one\n```\n\n## note on version ~1.0\n\nVersion ~1.0 had completely different motivation and is not compatible\nneither with 2.0 nor with standard node.js `inherits`.\n\nIf you are using version ~1.0 and planning to switch to ~2.0, be\ncareful:\n\n* new version uses `super_` instead of `super` for referencing\n superclass\n* new version overwrites current prototype while old one preserves any\n existing fields on it\n",
|
||||
"readmeFilename": "README.md",
|
||||
"bugs": {
|
||||
"url": "https://github.com/isaacs/inherits/issues"
|
||||
},
|
||||
"_id": "inherits@2.0.1",
|
||||
"dist": {
|
||||
"shasum": "b17d08d326b4423e568eff719f91b0b1cbdf69f1",
|
||||
"tarball": "http://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
|
||||
},
|
||||
"_from": "inherits@2",
|
||||
"_npmVersion": "1.3.8",
|
||||
"_npmUser": {
|
||||
"name": "isaacs",
|
||||
"email": "i@izs.me"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "isaacs",
|
||||
"email": "i@izs.me"
|
||||
}
|
||||
],
|
||||
"directories": {},
|
||||
"_shasum": "b17d08d326b4423e568eff719f91b0b1cbdf69f1",
|
||||
"_resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
|
||||
"homepage": "https://github.com/isaacs/inherits"
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
var inherits = require('./inherits.js')
|
||||
var assert = require('assert')
|
||||
|
||||
function test(c) {
|
||||
assert(c.constructor === Child)
|
||||
assert(c.constructor.super_ === Parent)
|
||||
assert(Object.getPrototypeOf(c) === Child.prototype)
|
||||
assert(Object.getPrototypeOf(Object.getPrototypeOf(c)) === Parent.prototype)
|
||||
assert(c instanceof Child)
|
||||
assert(c instanceof Parent)
|
||||
}
|
||||
|
||||
function Child() {
|
||||
Parent.call(this)
|
||||
test(this)
|
||||
}
|
||||
|
||||
function Parent() {}
|
||||
|
||||
inherits(Child, Parent)
|
||||
|
||||
var c = new Child
|
||||
test(c)
|
||||
|
||||
console.log('ok')
|
|
@ -1 +0,0 @@
|
|||
node_modules
|
|
@ -1,23 +0,0 @@
|
|||
Copyright 2009, 2010, 2011 Isaac Z. Schlueter.
|
||||
All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,218 +0,0 @@
|
|||
# minimatch
|
||||
|
||||
A minimal matching utility.
|
||||
|
||||
[![Build Status](https://secure.travis-ci.org/isaacs/minimatch.png)](http://travis-ci.org/isaacs/minimatch)
|
||||
|
||||
|
||||
This is the matching library used internally by npm.
|
||||
|
||||
Eventually, it will replace the C binding in node-glob.
|
||||
|
||||
It works by converting glob expressions into JavaScript `RegExp`
|
||||
objects.
|
||||
|
||||
## Usage
|
||||
|
||||
```javascript
|
||||
var minimatch = require("minimatch")
|
||||
|
||||
minimatch("bar.foo", "*.foo") // true!
|
||||
minimatch("bar.foo", "*.bar") // false!
|
||||
minimatch("bar.foo", "*.+(bar|foo)", { debug: true }) // true, and noisy!
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
Supports these glob features:
|
||||
|
||||
* Brace Expansion
|
||||
* Extended glob matching
|
||||
* "Globstar" `**` matching
|
||||
|
||||
See:
|
||||
|
||||
* `man sh`
|
||||
* `man bash`
|
||||
* `man 3 fnmatch`
|
||||
* `man 5 gitignore`
|
||||
|
||||
## Minimatch Class
|
||||
|
||||
Create a minimatch object by instanting the `minimatch.Minimatch` class.
|
||||
|
||||
```javascript
|
||||
var Minimatch = require("minimatch").Minimatch
|
||||
var mm = new Minimatch(pattern, options)
|
||||
```
|
||||
|
||||
### Properties
|
||||
|
||||
* `pattern` The original pattern the minimatch object represents.
|
||||
* `options` The options supplied to the constructor.
|
||||
* `set` A 2-dimensional array of regexp or string expressions.
|
||||
Each row in the
|
||||
array corresponds to a brace-expanded pattern. Each item in the row
|
||||
corresponds to a single path-part. For example, the pattern
|
||||
`{a,b/c}/d` would expand to a set of patterns like:
|
||||
|
||||
[ [ a, d ]
|
||||
, [ b, c, d ] ]
|
||||
|
||||
If a portion of the pattern doesn't have any "magic" in it
|
||||
(that is, it's something like `"foo"` rather than `fo*o?`), then it
|
||||
will be left as a string rather than converted to a regular
|
||||
expression.
|
||||
|
||||
* `regexp` Created by the `makeRe` method. A single regular expression
|
||||
expressing the entire pattern. This is useful in cases where you wish
|
||||
to use the pattern somewhat like `fnmatch(3)` with `FNM_PATH` enabled.
|
||||
* `negate` True if the pattern is negated.
|
||||
* `comment` True if the pattern is a comment.
|
||||
* `empty` True if the pattern is `""`.
|
||||
|
||||
### Methods
|
||||
|
||||
* `makeRe` Generate the `regexp` member if necessary, and return it.
|
||||
Will return `false` if the pattern is invalid.
|
||||
* `match(fname)` Return true if the filename matches the pattern, or
|
||||
false otherwise.
|
||||
* `matchOne(fileArray, patternArray, partial)` Take a `/`-split
|
||||
filename, and match it against a single row in the `regExpSet`. This
|
||||
method is mainly for internal use, but is exposed so that it can be
|
||||
used by a glob-walker that needs to avoid excessive filesystem calls.
|
||||
|
||||
All other methods are internal, and will be called as necessary.
|
||||
|
||||
## Functions
|
||||
|
||||
The top-level exported function has a `cache` property, which is an LRU
|
||||
cache set to store 100 items. So, calling these methods repeatedly
|
||||
with the same pattern and options will use the same Minimatch object,
|
||||
saving the cost of parsing it multiple times.
|
||||
|
||||
### minimatch(path, pattern, options)
|
||||
|
||||
Main export. Tests a path against the pattern using the options.
|
||||
|
||||
```javascript
|
||||
var isJS = minimatch(file, "*.js", { matchBase: true })
|
||||
```
|
||||
|
||||
### minimatch.filter(pattern, options)
|
||||
|
||||
Returns a function that tests its
|
||||
supplied argument, suitable for use with `Array.filter`. Example:
|
||||
|
||||
```javascript
|
||||
var javascripts = fileList.filter(minimatch.filter("*.js", {matchBase: true}))
|
||||
```
|
||||
|
||||
### minimatch.match(list, pattern, options)
|
||||
|
||||
Match against the list of
|
||||
files, in the style of fnmatch or glob. If nothing is matched, and
|
||||
options.nonull is set, then return a list containing the pattern itself.
|
||||
|
||||
```javascript
|
||||
var javascripts = minimatch.match(fileList, "*.js", {matchBase: true}))
|
||||
```
|
||||
|
||||
### minimatch.makeRe(pattern, options)
|
||||
|
||||
Make a regular expression object from the pattern.
|
||||
|
||||
## Options
|
||||
|
||||
All options are `false` by default.
|
||||
|
||||
### debug
|
||||
|
||||
Dump a ton of stuff to stderr.
|
||||
|
||||
### nobrace
|
||||
|
||||
Do not expand `{a,b}` and `{1..3}` brace sets.
|
||||
|
||||
### noglobstar
|
||||
|
||||
Disable `**` matching against multiple folder names.
|
||||
|
||||
### dot
|
||||
|
||||
Allow patterns to match filenames starting with a period, even if
|
||||
the pattern does not explicitly have a period in that spot.
|
||||
|
||||
Note that by default, `a/**/b` will **not** match `a/.d/b`, unless `dot`
|
||||
is set.
|
||||
|
||||
### noext
|
||||
|
||||
Disable "extglob" style patterns like `+(a|b)`.
|
||||
|
||||
### nocase
|
||||
|
||||
Perform a case-insensitive match.
|
||||
|
||||
### nonull
|
||||
|
||||
When a match is not found by `minimatch.match`, return a list containing
|
||||
the pattern itself if this option is set. When not set, an empty list
|
||||
is returned if there are no matches.
|
||||
|
||||
### matchBase
|
||||
|
||||
If set, then patterns without slashes will be matched
|
||||
against the basename of the path if it contains slashes. For example,
|
||||
`a?b` would match the path `/xyz/123/acb`, but not `/xyz/acb/123`.
|
||||
|
||||
### nocomment
|
||||
|
||||
Suppress the behavior of treating `#` at the start of a pattern as a
|
||||
comment.
|
||||
|
||||
### nonegate
|
||||
|
||||
Suppress the behavior of treating a leading `!` character as negation.
|
||||
|
||||
### flipNegate
|
||||
|
||||
Returns from negate expressions the same as if they were not negated.
|
||||
(Ie, true on a hit, false on a miss.)
|
||||
|
||||
|
||||
## Comparisons to other fnmatch/glob implementations
|
||||
|
||||
While strict compliance with the existing standards is a worthwhile
|
||||
goal, some discrepancies exist between minimatch and other
|
||||
implementations, and are intentional.
|
||||
|
||||
If the pattern starts with a `!` character, then it is negated. Set the
|
||||
`nonegate` flag to suppress this behavior, and treat leading `!`
|
||||
characters normally. This is perhaps relevant if you wish to start the
|
||||
pattern with a negative extglob pattern like `!(a|B)`. Multiple `!`
|
||||
characters at the start of a pattern will negate the pattern multiple
|
||||
times.
|
||||
|
||||
If a pattern starts with `#`, then it is treated as a comment, and
|
||||
will not match anything. Use `\#` to match a literal `#` at the
|
||||
start of a line, or set the `nocomment` flag to suppress this behavior.
|
||||
|
||||
The double-star character `**` is supported by default, unless the
|
||||
`noglobstar` flag is set. This is supported in the manner of bsdglob
|
||||
and bash 4.1, where `**` only has special significance if it is the only
|
||||
thing in a path part. That is, `a/**/b` will match `a/x/y/b`, but
|
||||
`a/**b` will not.
|
||||
|
||||
If an escaped pattern has no matches, and the `nonull` flag is set,
|
||||
then minimatch.match returns the pattern as-provided, rather than
|
||||
interpreting the character escapes. For example,
|
||||
`minimatch.match([], "\\*a\\?")` will return `"\\*a\\?"` rather than
|
||||
`"*a?"`. This is akin to setting the `nullglob` option in bash, except
|
||||
that it does not resolve escaped pattern characters.
|
||||
|
||||
If brace expansion is not disabled, then it is performed before any
|
||||
other interpretation of the glob pattern. Thus, a pattern like
|
||||
`+(a|{b),c)}`, which would not be valid in bash or zsh, is expanded
|
||||
**first** into the set of `+(a|b)` and `+(a|c)`, and those patterns are
|
||||
checked for validity. Since those two are valid, matching proceeds.
|
|
@ -1,1061 +0,0 @@
|
|||
;(function (require, exports, module, platform) {
|
||||
|
||||
if (module) module.exports = minimatch
|
||||
else exports.minimatch = minimatch
|
||||
|
||||
if (!require) {
|
||||
require = function (id) {
|
||||
switch (id) {
|
||||
case "sigmund": return function sigmund (obj) {
|
||||
return JSON.stringify(obj)
|
||||
}
|
||||
case "path": return { basename: function (f) {
|
||||
f = f.split(/[\/\\]/)
|
||||
var e = f.pop()
|
||||
if (!e) e = f.pop()
|
||||
return e
|
||||
}}
|
||||
case "lru-cache": return function LRUCache () {
|
||||
// not quite an LRU, but still space-limited.
|
||||
var cache = {}
|
||||
var cnt = 0
|
||||
this.set = function (k, v) {
|
||||
cnt ++
|
||||
if (cnt >= 100) cache = {}
|
||||
cache[k] = v
|
||||
}
|
||||
this.get = function (k) { return cache[k] }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
minimatch.Minimatch = Minimatch
|
||||
|
||||
var LRU = require("lru-cache")
|
||||
, cache = minimatch.cache = new LRU({max: 100})
|
||||
, GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {}
|
||||
, sigmund = require("sigmund")
|
||||
|
||||
var path = require("path")
|
||||
// any single thing other than /
|
||||
// don't need to escape / when using new RegExp()
|
||||
, qmark = "[^/]"
|
||||
|
||||
// * => any number of characters
|
||||
, star = qmark + "*?"
|
||||
|
||||
// ** when dots are allowed. Anything goes, except .. and .
|
||||
// not (^ or / followed by one or two dots followed by $ or /),
|
||||
// followed by anything, any number of times.
|
||||
, twoStarDot = "(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?"
|
||||
|
||||
// not a ^ or / followed by a dot,
|
||||
// followed by anything, any number of times.
|
||||
, twoStarNoDot = "(?:(?!(?:\\\/|^)\\.).)*?"
|
||||
|
||||
// characters that need to be escaped in RegExp.
|
||||
, reSpecials = charSet("().*{}+?[]^$\\!")
|
||||
|
||||
// "abc" -> { a:true, b:true, c:true }
|
||||
function charSet (s) {
|
||||
return s.split("").reduce(function (set, c) {
|
||||
set[c] = true
|
||||
return set
|
||||
}, {})
|
||||
}
|
||||
|
||||
// normalizes slashes.
|
||||
var slashSplit = /\/+/
|
||||
|
||||
minimatch.filter = filter
|
||||
function filter (pattern, options) {
|
||||
options = options || {}
|
||||
return function (p, i, list) {
|
||||
return minimatch(p, pattern, options)
|
||||
}
|
||||
}
|
||||
|
||||
function ext (a, b) {
|
||||
a = a || {}
|
||||
b = b || {}
|
||||
var t = {}
|
||||
Object.keys(b).forEach(function (k) {
|
||||
t[k] = b[k]
|
||||
})
|
||||
Object.keys(a).forEach(function (k) {
|
||||
t[k] = a[k]
|
||||
})
|
||||
return t
|
||||
}
|
||||
|
||||
minimatch.defaults = function (def) {
|
||||
if (!def || !Object.keys(def).length) return minimatch
|
||||
|
||||
var orig = minimatch
|
||||
|
||||
var m = function minimatch (p, pattern, options) {
|
||||
return orig.minimatch(p, pattern, ext(def, options))
|
||||
}
|
||||
|
||||
m.Minimatch = function Minimatch (pattern, options) {
|
||||
return new orig.Minimatch(pattern, ext(def, options))
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
Minimatch.defaults = function (def) {
|
||||
if (!def || !Object.keys(def).length) return Minimatch
|
||||
return minimatch.defaults(def).Minimatch
|
||||
}
|
||||
|
||||
|
||||
function minimatch (p, pattern, options) {
|
||||
if (typeof pattern !== "string") {
|
||||
throw new TypeError("glob pattern string required")
|
||||
}
|
||||
|
||||
if (!options) options = {}
|
||||
|
||||
// shortcut: comments match nothing.
|
||||
if (!options.nocomment && pattern.charAt(0) === "#") {
|
||||
return false
|
||||
}
|
||||
|
||||
// "" only matches ""
|
||||
if (pattern.trim() === "") return p === ""
|
||||
|
||||
return new Minimatch(pattern, options).match(p)
|
||||
}
|
||||
|
||||
function Minimatch (pattern, options) {
|
||||
if (!(this instanceof Minimatch)) {
|
||||
return new Minimatch(pattern, options, cache)
|
||||
}
|
||||
|
||||
if (typeof pattern !== "string") {
|
||||
throw new TypeError("glob pattern string required")
|
||||
}
|
||||
|
||||
if (!options) options = {}
|
||||
pattern = pattern.trim()
|
||||
|
||||
// windows: need to use /, not \
|
||||
// On other platforms, \ is a valid (albeit bad) filename char.
|
||||
if (platform === "win32") {
|
||||
pattern = pattern.split("\\").join("/")
|
||||
}
|
||||
|
||||
// lru storage.
|
||||
// these things aren't particularly big, but walking down the string
|
||||
// and turning it into a regexp can get pretty costly.
|
||||
var cacheKey = pattern + "\n" + sigmund(options)
|
||||
var cached = minimatch.cache.get(cacheKey)
|
||||
if (cached) return cached
|
||||
minimatch.cache.set(cacheKey, this)
|
||||
|
||||
this.options = options
|
||||
this.set = []
|
||||
this.pattern = pattern
|
||||
this.regexp = null
|
||||
this.negate = false
|
||||
this.comment = false
|
||||
this.empty = false
|
||||
|
||||
// make the set of regexps etc.
|
||||
this.make()
|
||||
}
|
||||
|
||||
Minimatch.prototype.debug = function() {}
|
||||
|
||||
Minimatch.prototype.make = make
|
||||
function make () {
|
||||
// don't do it more than once.
|
||||
if (this._made) return
|
||||
|
||||
var pattern = this.pattern
|
||||
var options = this.options
|
||||
|
||||
// empty patterns and comments match nothing.
|
||||
if (!options.nocomment && pattern.charAt(0) === "#") {
|
||||
this.comment = true
|
||||
return
|
||||
}
|
||||
if (!pattern) {
|
||||
this.empty = true
|
||||
return
|
||||
}
|
||||
|
||||
// step 1: figure out negation, etc.
|
||||
this.parseNegate()
|
||||
|
||||
// step 2: expand braces
|
||||
var set = this.globSet = this.braceExpand()
|
||||
|
||||
if (options.debug) this.debug = console.error
|
||||
|
||||
this.debug(this.pattern, set)
|
||||
|
||||
// step 3: now we have a set, so turn each one into a series of path-portion
|
||||
// matching patterns.
|
||||
// These will be regexps, except in the case of "**", which is
|
||||
// set to the GLOBSTAR object for globstar behavior,
|
||||
// and will not contain any / characters
|
||||
set = this.globParts = set.map(function (s) {
|
||||
return s.split(slashSplit)
|
||||
})
|
||||
|
||||
this.debug(this.pattern, set)
|
||||
|
||||
// glob --> regexps
|
||||
set = set.map(function (s, si, set) {
|
||||
return s.map(this.parse, this)
|
||||
}, this)
|
||||
|
||||
this.debug(this.pattern, set)
|
||||
|
||||
// filter out everything that didn't compile properly.
|
||||
set = set.filter(function (s) {
|
||||
return -1 === s.indexOf(false)
|
||||
})
|
||||
|
||||
this.debug(this.pattern, set)
|
||||
|
||||
this.set = set
|
||||
}
|
||||
|
||||
Minimatch.prototype.parseNegate = parseNegate
|
||||
function parseNegate () {
|
||||
var pattern = this.pattern
|
||||
, negate = false
|
||||
, options = this.options
|
||||
, negateOffset = 0
|
||||
|
||||
if (options.nonegate) return
|
||||
|
||||
for ( var i = 0, l = pattern.length
|
||||
; i < l && pattern.charAt(i) === "!"
|
||||
; i ++) {
|
||||
negate = !negate
|
||||
negateOffset ++
|
||||
}
|
||||
|
||||
if (negateOffset) this.pattern = pattern.substr(negateOffset)
|
||||
this.negate = negate
|
||||
}
|
||||
|
||||
// Brace expansion:
|
||||
// a{b,c}d -> abd acd
|
||||
// a{b,}c -> abc ac
|
||||
// a{0..3}d -> a0d a1d a2d a3d
|
||||
// a{b,c{d,e}f}g -> abg acdfg acefg
|
||||
// a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg
|
||||
//
|
||||
// Invalid sets are not expanded.
|
||||
// a{2..}b -> a{2..}b
|
||||
// a{b}c -> a{b}c
|
||||
minimatch.braceExpand = function (pattern, options) {
|
||||
return new Minimatch(pattern, options).braceExpand()
|
||||
}
|
||||
|
||||
Minimatch.prototype.braceExpand = braceExpand
|
||||
function braceExpand (pattern, options) {
|
||||
options = options || this.options
|
||||
pattern = typeof pattern === "undefined"
|
||||
? this.pattern : pattern
|
||||
|
||||
if (typeof pattern === "undefined") {
|
||||
throw new Error("undefined pattern")
|
||||
}
|
||||
|
||||
if (options.nobrace ||
|
||||
!pattern.match(/\{.*\}/)) {
|
||||
// shortcut. no need to expand.
|
||||
return [pattern]
|
||||
}
|
||||
|
||||
var escaping = false
|
||||
|
||||
// examples and comments refer to this crazy pattern:
|
||||
// a{b,c{d,e},{f,g}h}x{y,z}
|
||||
// expected:
|
||||
// abxy
|
||||
// abxz
|
||||
// acdxy
|
||||
// acdxz
|
||||
// acexy
|
||||
// acexz
|
||||
// afhxy
|
||||
// afhxz
|
||||
// aghxy
|
||||
// aghxz
|
||||
|
||||
// everything before the first \{ is just a prefix.
|
||||
// So, we pluck that off, and work with the rest,
|
||||
// and then prepend it to everything we find.
|
||||
if (pattern.charAt(0) !== "{") {
|
||||
this.debug(pattern)
|
||||
var prefix = null
|
||||
for (var i = 0, l = pattern.length; i < l; i ++) {
|
||||
var c = pattern.charAt(i)
|
||||
this.debug(i, c)
|
||||
if (c === "\\") {
|
||||
escaping = !escaping
|
||||
} else if (c === "{" && !escaping) {
|
||||
prefix = pattern.substr(0, i)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// actually no sets, all { were escaped.
|
||||
if (prefix === null) {
|
||||
this.debug("no sets")
|
||||
return [pattern]
|
||||
}
|
||||
|
||||
var tail = braceExpand.call(this, pattern.substr(i), options)
|
||||
return tail.map(function (t) {
|
||||
return prefix + t
|
||||
})
|
||||
}
|
||||
|
||||
// now we have something like:
|
||||
// {b,c{d,e},{f,g}h}x{y,z}
|
||||
// walk through the set, expanding each part, until
|
||||
// the set ends. then, we'll expand the suffix.
|
||||
// If the set only has a single member, then'll put the {} back
|
||||
|
||||
// first, handle numeric sets, since they're easier
|
||||
var numset = pattern.match(/^\{(-?[0-9]+)\.\.(-?[0-9]+)\}/)
|
||||
if (numset) {
|
||||
this.debug("numset", numset[1], numset[2])
|
||||
var suf = braceExpand.call(this, pattern.substr(numset[0].length), options)
|
||||
, start = +numset[1]
|
||||
, end = +numset[2]
|
||||
, inc = start > end ? -1 : 1
|
||||
, set = []
|
||||
for (var i = start; i != (end + inc); i += inc) {
|
||||
// append all the suffixes
|
||||
for (var ii = 0, ll = suf.length; ii < ll; ii ++) {
|
||||
set.push(i + suf[ii])
|
||||
}
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
// ok, walk through the set
|
||||
// We hope, somewhat optimistically, that there
|
||||
// will be a } at the end.
|
||||
// If the closing brace isn't found, then the pattern is
|
||||
// interpreted as braceExpand("\\" + pattern) so that
|
||||
// the leading \{ will be interpreted literally.
|
||||
var i = 1 // skip the \{
|
||||
, depth = 1
|
||||
, set = []
|
||||
, member = ""
|
||||
, sawEnd = false
|
||||
, escaping = false
|
||||
|
||||
function addMember () {
|
||||
set.push(member)
|
||||
member = ""
|
||||
}
|
||||
|
||||
this.debug("Entering for")
|
||||
FOR: for (i = 1, l = pattern.length; i < l; i ++) {
|
||||
var c = pattern.charAt(i)
|
||||
this.debug("", i, c)
|
||||
|
||||
if (escaping) {
|
||||
escaping = false
|
||||
member += "\\" + c
|
||||
} else {
|
||||
switch (c) {
|
||||
case "\\":
|
||||
escaping = true
|
||||
continue
|
||||
|
||||
case "{":
|
||||
depth ++
|
||||
member += "{"
|
||||
continue
|
||||
|
||||
case "}":
|
||||
depth --
|
||||
// if this closes the actual set, then we're done
|
||||
if (depth === 0) {
|
||||
addMember()
|
||||
// pluck off the close-brace
|
||||
i ++
|
||||
break FOR
|
||||
} else {
|
||||
member += c
|
||||
continue
|
||||
}
|
||||
|
||||
case ",":
|
||||
if (depth === 1) {
|
||||
addMember()
|
||||
} else {
|
||||
member += c
|
||||
}
|
||||
continue
|
||||
|
||||
default:
|
||||
member += c
|
||||
continue
|
||||
} // switch
|
||||
} // else
|
||||
} // for
|
||||
|
||||
// now we've either finished the set, and the suffix is
|
||||
// pattern.substr(i), or we have *not* closed the set,
|
||||
// and need to escape the leading brace
|
||||
if (depth !== 0) {
|
||||
this.debug("didn't close", pattern)
|
||||
return braceExpand.call(this, "\\" + pattern, options)
|
||||
}
|
||||
|
||||
// x{y,z} -> ["xy", "xz"]
|
||||
this.debug("set", set)
|
||||
this.debug("suffix", pattern.substr(i))
|
||||
var suf = braceExpand.call(this, pattern.substr(i), options)
|
||||
// ["b", "c{d,e}","{f,g}h"] ->
|
||||
// [["b"], ["cd", "ce"], ["fh", "gh"]]
|
||||
var addBraces = set.length === 1
|
||||
this.debug("set pre-expanded", set)
|
||||
set = set.map(function (p) {
|
||||
return braceExpand.call(this, p, options)
|
||||
}, this)
|
||||
this.debug("set expanded", set)
|
||||
|
||||
|
||||
// [["b"], ["cd", "ce"], ["fh", "gh"]] ->
|
||||
// ["b", "cd", "ce", "fh", "gh"]
|
||||
set = set.reduce(function (l, r) {
|
||||
return l.concat(r)
|
||||
})
|
||||
|
||||
if (addBraces) {
|
||||
set = set.map(function (s) {
|
||||
return "{" + s + "}"
|
||||
})
|
||||
}
|
||||
|
||||
// now attach the suffixes.
|
||||
var ret = []
|
||||
for (var i = 0, l = set.length; i < l; i ++) {
|
||||
for (var ii = 0, ll = suf.length; ii < ll; ii ++) {
|
||||
ret.push(set[i] + suf[ii])
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// parse a component of the expanded set.
|
||||
// At this point, no pattern may contain "/" in it
|
||||
// so we're going to return a 2d array, where each entry is the full
|
||||
// pattern, split on '/', and then turned into a regular expression.
|
||||
// A regexp is made at the end which joins each array with an
|
||||
// escaped /, and another full one which joins each regexp with |.
|
||||
//
|
||||
// Following the lead of Bash 4.1, note that "**" only has special meaning
|
||||
// when it is the *only* thing in a path portion. Otherwise, any series
|
||||
// of * is equivalent to a single *. Globstar behavior is enabled by
|
||||
// default, and can be disabled by setting options.noglobstar.
|
||||
Minimatch.prototype.parse = parse
|
||||
var SUBPARSE = {}
|
||||
function parse (pattern, isSub) {
|
||||
var options = this.options
|
||||
|
||||
// shortcuts
|
||||
if (!options.noglobstar && pattern === "**") return GLOBSTAR
|
||||
if (pattern === "") return ""
|
||||
|
||||
var re = ""
|
||||
, hasMagic = !!options.nocase
|
||||
, escaping = false
|
||||
// ? => one single character
|
||||
, patternListStack = []
|
||||
, plType
|
||||
, stateChar
|
||||
, inClass = false
|
||||
, reClassStart = -1
|
||||
, classStart = -1
|
||||
// . and .. never match anything that doesn't start with .,
|
||||
// even when options.dot is set.
|
||||
, patternStart = pattern.charAt(0) === "." ? "" // anything
|
||||
// not (start or / followed by . or .. followed by / or end)
|
||||
: options.dot ? "(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))"
|
||||
: "(?!\\.)"
|
||||
, self = this
|
||||
|
||||
function clearStateChar () {
|
||||
if (stateChar) {
|
||||
// we had some state-tracking character
|
||||
// that wasn't consumed by this pass.
|
||||
switch (stateChar) {
|
||||
case "*":
|
||||
re += star
|
||||
hasMagic = true
|
||||
break
|
||||
case "?":
|
||||
re += qmark
|
||||
hasMagic = true
|
||||
break
|
||||
default:
|
||||
re += "\\"+stateChar
|
||||
break
|
||||
}
|
||||
self.debug('clearStateChar %j %j', stateChar, re)
|
||||
stateChar = false
|
||||
}
|
||||
}
|
||||
|
||||
for ( var i = 0, len = pattern.length, c
|
||||
; (i < len) && (c = pattern.charAt(i))
|
||||
; i ++ ) {
|
||||
|
||||
this.debug("%s\t%s %s %j", pattern, i, re, c)
|
||||
|
||||
// skip over any that are escaped.
|
||||
if (escaping && reSpecials[c]) {
|
||||
re += "\\" + c
|
||||
escaping = false
|
||||
continue
|
||||
}
|
||||
|
||||
SWITCH: switch (c) {
|
||||
case "/":
|
||||
// completely not allowed, even escaped.
|
||||
// Should already be path-split by now.
|
||||
return false
|
||||
|
||||
case "\\":
|
||||
clearStateChar()
|
||||
escaping = true
|
||||
continue
|
||||
|
||||
// the various stateChar values
|
||||
// for the "extglob" stuff.
|
||||
case "?":
|
||||
case "*":
|
||||
case "+":
|
||||
case "@":
|
||||
case "!":
|
||||
this.debug("%s\t%s %s %j <-- stateChar", pattern, i, re, c)
|
||||
|
||||
// all of those are literals inside a class, except that
|
||||
// the glob [!a] means [^a] in regexp
|
||||
if (inClass) {
|
||||
this.debug(' in class')
|
||||
if (c === "!" && i === classStart + 1) c = "^"
|
||||
re += c
|
||||
continue
|
||||
}
|
||||
|
||||
// if we already have a stateChar, then it means
|
||||
// that there was something like ** or +? in there.
|
||||
// Handle the stateChar, then proceed with this one.
|
||||
self.debug('call clearStateChar %j', stateChar)
|
||||
clearStateChar()
|
||||
stateChar = c
|
||||
// if extglob is disabled, then +(asdf|foo) isn't a thing.
|
||||
// just clear the statechar *now*, rather than even diving into
|
||||
// the patternList stuff.
|
||||
if (options.noext) clearStateChar()
|
||||
continue
|
||||
|
||||
case "(":
|
||||
if (inClass) {
|
||||
re += "("
|
||||
continue
|
||||
}
|
||||
|
||||
if (!stateChar) {
|
||||
re += "\\("
|
||||
continue
|
||||
}
|
||||
|
||||
plType = stateChar
|
||||
patternListStack.push({ type: plType
|
||||
, start: i - 1
|
||||
, reStart: re.length })
|
||||
// negation is (?:(?!js)[^/]*)
|
||||
re += stateChar === "!" ? "(?:(?!" : "(?:"
|
||||
this.debug('plType %j %j', stateChar, re)
|
||||
stateChar = false
|
||||
continue
|
||||
|
||||
case ")":
|
||||
if (inClass || !patternListStack.length) {
|
||||
re += "\\)"
|
||||
continue
|
||||
}
|
||||
|
||||
clearStateChar()
|
||||
hasMagic = true
|
||||
re += ")"
|
||||
plType = patternListStack.pop().type
|
||||
// negation is (?:(?!js)[^/]*)
|
||||
// The others are (?:<pattern>)<type>
|
||||
switch (plType) {
|
||||
case "!":
|
||||
re += "[^/]*?)"
|
||||
break
|
||||
case "?":
|
||||
case "+":
|
||||
case "*": re += plType
|
||||
case "@": break // the default anyway
|
||||
}
|
||||
continue
|
||||
|
||||
case "|":
|
||||
if (inClass || !patternListStack.length || escaping) {
|
||||
re += "\\|"
|
||||
escaping = false
|
||||
continue
|
||||
}
|
||||
|
||||
clearStateChar()
|
||||
re += "|"
|
||||
continue
|
||||
|
||||
// these are mostly the same in regexp and glob
|
||||
case "[":
|
||||
// swallow any state-tracking char before the [
|
||||
clearStateChar()
|
||||
|
||||
if (inClass) {
|
||||
re += "\\" + c
|
||||
continue
|
||||
}
|
||||
|
||||
inClass = true
|
||||
classStart = i
|
||||
reClassStart = re.length
|
||||
re += c
|
||||
continue
|
||||
|
||||
case "]":
|
||||
// a right bracket shall lose its special
|
||||
// meaning and represent itself in
|
||||
// a bracket expression if it occurs
|
||||
// first in the list. -- POSIX.2 2.8.3.2
|
||||
if (i === classStart + 1 || !inClass) {
|
||||
re += "\\" + c
|
||||
escaping = false
|
||||
continue
|
||||
}
|
||||
|
||||
// finish up the class.
|
||||
hasMagic = true
|
||||
inClass = false
|
||||
re += c
|
||||
continue
|
||||
|
||||
default:
|
||||
// swallow any state char that wasn't consumed
|
||||
clearStateChar()
|
||||
|
||||
if (escaping) {
|
||||
// no need
|
||||
escaping = false
|
||||
} else if (reSpecials[c]
|
||||
&& !(c === "^" && inClass)) {
|
||||
re += "\\"
|
||||
}
|
||||
|
||||
re += c
|
||||
|
||||
} // switch
|
||||
} // for
|
||||
|
||||
|
||||
// handle the case where we left a class open.
|
||||
// "[abc" is valid, equivalent to "\[abc"
|
||||
if (inClass) {
|
||||
// split where the last [ was, and escape it
|
||||
// this is a huge pita. We now have to re-walk
|
||||
// the contents of the would-be class to re-translate
|
||||
// any characters that were passed through as-is
|
||||
var cs = pattern.substr(classStart + 1)
|
||||
, sp = this.parse(cs, SUBPARSE)
|
||||
re = re.substr(0, reClassStart) + "\\[" + sp[0]
|
||||
hasMagic = hasMagic || sp[1]
|
||||
}
|
||||
|
||||
// handle the case where we had a +( thing at the *end*
|
||||
// of the pattern.
|
||||
// each pattern list stack adds 3 chars, and we need to go through
|
||||
// and escape any | chars that were passed through as-is for the regexp.
|
||||
// Go through and escape them, taking care not to double-escape any
|
||||
// | chars that were already escaped.
|
||||
var pl
|
||||
while (pl = patternListStack.pop()) {
|
||||
var tail = re.slice(pl.reStart + 3)
|
||||
// maybe some even number of \, then maybe 1 \, followed by a |
|
||||
tail = tail.replace(/((?:\\{2})*)(\\?)\|/g, function (_, $1, $2) {
|
||||
if (!$2) {
|
||||
// the | isn't already escaped, so escape it.
|
||||
$2 = "\\"
|
||||
}
|
||||
|
||||
// need to escape all those slashes *again*, without escaping the
|
||||
// one that we need for escaping the | character. As it works out,
|
||||
// escaping an even number of slashes can be done by simply repeating
|
||||
// it exactly after itself. That's why this trick works.
|
||||
//
|
||||
// I am sorry that you have to see this.
|
||||
return $1 + $1 + $2 + "|"
|
||||
})
|
||||
|
||||
this.debug("tail=%j\n %s", tail, tail)
|
||||
var t = pl.type === "*" ? star
|
||||
: pl.type === "?" ? qmark
|
||||
: "\\" + pl.type
|
||||
|
||||
hasMagic = true
|
||||
re = re.slice(0, pl.reStart)
|
||||
+ t + "\\("
|
||||
+ tail
|
||||
}
|
||||
|
||||
// handle trailing things that only matter at the very end.
|
||||
clearStateChar()
|
||||
if (escaping) {
|
||||
// trailing \\
|
||||
re += "\\\\"
|
||||
}
|
||||
|
||||
// only need to apply the nodot start if the re starts with
|
||||
// something that could conceivably capture a dot
|
||||
var addPatternStart = false
|
||||
switch (re.charAt(0)) {
|
||||
case ".":
|
||||
case "[":
|
||||
case "(": addPatternStart = true
|
||||
}
|
||||
|
||||
// if the re is not "" at this point, then we need to make sure
|
||||
// it doesn't match against an empty path part.
|
||||
// Otherwise a/* will match a/, which it should not.
|
||||
if (re !== "" && hasMagic) re = "(?=.)" + re
|
||||
|
||||
if (addPatternStart) re = patternStart + re
|
||||
|
||||
// parsing just a piece of a larger pattern.
|
||||
if (isSub === SUBPARSE) {
|
||||
return [ re, hasMagic ]
|
||||
}
|
||||
|
||||
// skip the regexp for non-magical patterns
|
||||
// unescape anything in it, though, so that it'll be
|
||||
// an exact match against a file etc.
|
||||
if (!hasMagic) {
|
||||
return globUnescape(pattern)
|
||||
}
|
||||
|
||||
var flags = options.nocase ? "i" : ""
|
||||
, regExp = new RegExp("^" + re + "$", flags)
|
||||
|
||||
regExp._glob = pattern
|
||||
regExp._src = re
|
||||
|
||||
return regExp
|
||||
}
|
||||
|
||||
minimatch.makeRe = function (pattern, options) {
|
||||
return new Minimatch(pattern, options || {}).makeRe()
|
||||
}
|
||||
|
||||
Minimatch.prototype.makeRe = makeRe
|
||||
function makeRe () {
|
||||
if (this.regexp || this.regexp === false) return this.regexp
|
||||
|
||||
// at this point, this.set is a 2d array of partial
|
||||
// pattern strings, or "**".
|
||||
//
|
||||
// It's better to use .match(). This function shouldn't
|
||||
// be used, really, but it's pretty convenient sometimes,
|
||||
// when you just want to work with a regex.
|
||||
var set = this.set
|
||||
|
||||
if (!set.length) return this.regexp = false
|
||||
var options = this.options
|
||||
|
||||
var twoStar = options.noglobstar ? star
|
||||
: options.dot ? twoStarDot
|
||||
: twoStarNoDot
|
||||
, flags = options.nocase ? "i" : ""
|
||||
|
||||
var re = set.map(function (pattern) {
|
||||
return pattern.map(function (p) {
|
||||
return (p === GLOBSTAR) ? twoStar
|
||||
: (typeof p === "string") ? regExpEscape(p)
|
||||
: p._src
|
||||
}).join("\\\/")
|
||||
}).join("|")
|
||||
|
||||
// must match entire pattern
|
||||
// ending in a * or ** will make it less strict.
|
||||
re = "^(?:" + re + ")$"
|
||||
|
||||
// can match anything, as long as it's not this.
|
||||
if (this.negate) re = "^(?!" + re + ").*$"
|
||||
|
||||
try {
|
||||
return this.regexp = new RegExp(re, flags)
|
||||
} catch (ex) {
|
||||
return this.regexp = false
|
||||
}
|
||||
}
|
||||
|
||||
minimatch.match = function (list, pattern, options) {
|
||||
options = options || {}
|
||||
var mm = new Minimatch(pattern, options)
|
||||
list = list.filter(function (f) {
|
||||
return mm.match(f)
|
||||
})
|
||||
if (mm.options.nonull && !list.length) {
|
||||
list.push(pattern)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
Minimatch.prototype.match = match
|
||||
function match (f, partial) {
|
||||
this.debug("match", f, this.pattern)
|
||||
// short-circuit in the case of busted things.
|
||||
// comments, etc.
|
||||
if (this.comment) return false
|
||||
if (this.empty) return f === ""
|
||||
|
||||
if (f === "/" && partial) return true
|
||||
|
||||
var options = this.options
|
||||
|
||||
// windows: need to use /, not \
|
||||
// On other platforms, \ is a valid (albeit bad) filename char.
|
||||
if (platform === "win32") {
|
||||
f = f.split("\\").join("/")
|
||||
}
|
||||
|
||||
// treat the test path as a set of pathparts.
|
||||
f = f.split(slashSplit)
|
||||
this.debug(this.pattern, "split", f)
|
||||
|
||||
// just ONE of the pattern sets in this.set needs to match
|
||||
// in order for it to be valid. If negating, then just one
|
||||
// match means that we have failed.
|
||||
// Either way, return on the first hit.
|
||||
|
||||
var set = this.set
|
||||
this.debug(this.pattern, "set", set)
|
||||
|
||||
// Find the basename of the path by looking for the last non-empty segment
|
||||
var filename;
|
||||
for (var i = f.length - 1; i >= 0; i--) {
|
||||
filename = f[i]
|
||||
if (filename) break
|
||||
}
|
||||
|
||||
for (var i = 0, l = set.length; i < l; i ++) {
|
||||
var pattern = set[i], file = f
|
||||
if (options.matchBase && pattern.length === 1) {
|
||||
file = [filename]
|
||||
}
|
||||
var hit = this.matchOne(file, pattern, partial)
|
||||
if (hit) {
|
||||
if (options.flipNegate) return true
|
||||
return !this.negate
|
||||
}
|
||||
}
|
||||
|
||||
// didn't get any hits. this is success if it's a negative
|
||||
// pattern, failure otherwise.
|
||||
if (options.flipNegate) return false
|
||||
return this.negate
|
||||
}
|
||||
|
||||
// set partial to true to test if, for example,
|
||||
// "/a/b" matches the start of "/*/b/*/d"
|
||||
// Partial means, if you run out of file before you run
|
||||
// out of pattern, then that's fine, as long as all
|
||||
// the parts match.
|
||||
Minimatch.prototype.matchOne = function (file, pattern, partial) {
|
||||
var options = this.options
|
||||
|
||||
this.debug("matchOne",
|
||||
{ "this": this
|
||||
, file: file
|
||||
, pattern: pattern })
|
||||
|
||||
this.debug("matchOne", file.length, pattern.length)
|
||||
|
||||
for ( var fi = 0
|
||||
, pi = 0
|
||||
, fl = file.length
|
||||
, pl = pattern.length
|
||||
; (fi < fl) && (pi < pl)
|
||||
; fi ++, pi ++ ) {
|
||||
|
||||
this.debug("matchOne loop")
|
||||
var p = pattern[pi]
|
||||
, f = file[fi]
|
||||
|
||||
this.debug(pattern, p, f)
|
||||
|
||||
// should be impossible.
|
||||
// some invalid regexp stuff in the set.
|
||||
if (p === false) return false
|
||||
|
||||
if (p === GLOBSTAR) {
|
||||
this.debug('GLOBSTAR', [pattern, p, f])
|
||||
|
||||
// "**"
|
||||
// a/**/b/**/c would match the following:
|
||||
// a/b/x/y/z/c
|
||||
// a/x/y/z/b/c
|
||||
// a/b/x/b/x/c
|
||||
// a/b/c
|
||||
// To do this, take the rest of the pattern after
|
||||
// the **, and see if it would match the file remainder.
|
||||
// If so, return success.
|
||||
// If not, the ** "swallows" a segment, and try again.
|
||||
// This is recursively awful.
|
||||
//
|
||||
// a/**/b/**/c matching a/b/x/y/z/c
|
||||
// - a matches a
|
||||
// - doublestar
|
||||
// - matchOne(b/x/y/z/c, b/**/c)
|
||||
// - b matches b
|
||||
// - doublestar
|
||||
// - matchOne(x/y/z/c, c) -> no
|
||||
// - matchOne(y/z/c, c) -> no
|
||||
// - matchOne(z/c, c) -> no
|
||||
// - matchOne(c, c) yes, hit
|
||||
var fr = fi
|
||||
, pr = pi + 1
|
||||
if (pr === pl) {
|
||||
this.debug('** at the end')
|
||||
// a ** at the end will just swallow the rest.
|
||||
// We have found a match.
|
||||
// however, it will not swallow /.x, unless
|
||||
// options.dot is set.
|
||||
// . and .. are *never* matched by **, for explosively
|
||||
// exponential reasons.
|
||||
for ( ; fi < fl; fi ++) {
|
||||
if (file[fi] === "." || file[fi] === ".." ||
|
||||
(!options.dot && file[fi].charAt(0) === ".")) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ok, let's see if we can swallow whatever we can.
|
||||
WHILE: while (fr < fl) {
|
||||
var swallowee = file[fr]
|
||||
|
||||
this.debug('\nglobstar while',
|
||||
file, fr, pattern, pr, swallowee)
|
||||
|
||||
// XXX remove this slice. Just pass the start index.
|
||||
if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) {
|
||||
this.debug('globstar found match!', fr, fl, swallowee)
|
||||
// found a match.
|
||||
return true
|
||||
} else {
|
||||
// can't swallow "." or ".." ever.
|
||||
// can only swallow ".foo" when explicitly asked.
|
||||
if (swallowee === "." || swallowee === ".." ||
|
||||
(!options.dot && swallowee.charAt(0) === ".")) {
|
||||
this.debug("dot detected!", file, fr, pattern, pr)
|
||||
break WHILE
|
||||
}
|
||||
|
||||
// ** swallows a segment, and continue.
|
||||
this.debug('globstar swallow a segment, and continue')
|
||||
fr ++
|
||||
}
|
||||
}
|
||||
// no match was found.
|
||||
// However, in partial mode, we can't say this is necessarily over.
|
||||
// If there's more *pattern* left, then
|
||||
if (partial) {
|
||||
// ran out of file
|
||||
this.debug("\n>>> no match, partial?", file, fr, pattern, pr)
|
||||
if (fr === fl) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// something other than **
|
||||
// non-magic patterns just have to match exactly
|
||||
// patterns with magic have been turned into regexps.
|
||||
var hit
|
||||
if (typeof p === "string") {
|
||||
if (options.nocase) {
|
||||
hit = f.toLowerCase() === p.toLowerCase()
|
||||
} else {
|
||||
hit = f === p
|
||||
}
|
||||
this.debug("string match", p, f, hit)
|
||||
} else {
|
||||
hit = f.match(p)
|
||||
this.debug("pattern match", p, f, hit)
|
||||
}
|
||||
|
||||
if (!hit) return false
|
||||
}
|
||||
|
||||
// Note: ending in / means that we'll get a final ""
|
||||
// at the end of the pattern. This can only match a
|
||||
// corresponding "" at the end of the file.
|
||||
// If the file ends in /, then it can only match a
|
||||
// a pattern that ends in /, unless the pattern just
|
||||
// doesn't have any more for it. But, a/b/ should *not*
|
||||
// match "a/b/*", even though "" matches against the
|
||||
// [^/]*? pattern, except in partial mode, where it might
|
||||
// simply not be reached yet.
|
||||
// However, a/b/ should still satisfy a/*
|
||||
|
||||
// now either we fell off the end of the pattern, or we're done.
|
||||
if (fi === fl && pi === pl) {
|
||||
// ran out of pattern and filename at the same time.
|
||||
// an exact hit!
|
||||
return true
|
||||
} else if (fi === fl) {
|
||||
// ran out of file, but still had pattern left.
|
||||
// this is ok if we're doing the match as part of
|
||||
// a glob fs traversal.
|
||||
return partial
|
||||
} else if (pi === pl) {
|
||||
// ran out of pattern, still have file left.
|
||||
// this is only acceptable if we're on the very last
|
||||
// empty segment of a file with a trailing slash.
|
||||
// a/* should match a/b/
|
||||
var emptyFileEnd = (fi === fl - 1) && (file[fi] === "")
|
||||
return emptyFileEnd
|
||||
}
|
||||
|
||||
// should be unreachable.
|
||||
throw new Error("wtf?")
|
||||
}
|
||||
|
||||
|
||||
// replace stuff like \* with *
|
||||
function globUnescape (s) {
|
||||
return s.replace(/\\(.)/g, "$1")
|
||||
}
|
||||
|
||||
|
||||
function regExpEscape (s) {
|
||||
return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&")
|
||||
}
|
||||
|
||||
})( typeof require === "function" ? require : null,
|
||||
this,
|
||||
typeof module === "object" ? module : null,
|
||||
typeof process === "object" ? process.platform : "win32"
|
||||
)
|
|
@ -1 +0,0 @@
|
|||
/node_modules
|
|
@ -1,14 +0,0 @@
|
|||
# Authors, sorted by whether or not they are me
|
||||
Isaac Z. Schlueter <i@izs.me>
|
||||
Brian Cottingham <spiffytech@gmail.com>
|
||||
Carlos Brito Lage <carlos@carloslage.net>
|
||||
Jesse Dailey <jesse.dailey@gmail.com>
|
||||
Kevin O'Hara <kevinohara80@gmail.com>
|
||||
Marco Rogers <marco.rogers@gmail.com>
|
||||
Mark Cavage <mcavage@gmail.com>
|
||||
Marko Mikulicic <marko.mikulicic@isti.cnr.it>
|
||||
Nathan Rajlich <nathan@tootallnate.net>
|
||||
Satheesh Natesan <snateshan@myspace-inc.com>
|
||||
Trent Mick <trentm@gmail.com>
|
||||
ashleybrener <ashley@starlogik.com>
|
||||
n4kz <n4kz@n4kz.com>
|
|
@ -1,23 +0,0 @@
|
|||
Copyright 2009, 2010, 2011 Isaac Z. Schlueter.
|
||||
All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,97 +0,0 @@
|
|||
# lru cache
|
||||
|
||||
A cache object that deletes the least-recently-used items.
|
||||
|
||||
## Usage:
|
||||
|
||||
```javascript
|
||||
var LRU = require("lru-cache")
|
||||
, options = { max: 500
|
||||
, length: function (n) { return n * 2 }
|
||||
, dispose: function (key, n) { n.close() }
|
||||
, maxAge: 1000 * 60 * 60 }
|
||||
, cache = LRU(options)
|
||||
, otherCache = LRU(50) // sets just the max size
|
||||
|
||||
cache.set("key", "value")
|
||||
cache.get("key") // "value"
|
||||
|
||||
cache.reset() // empty the cache
|
||||
```
|
||||
|
||||
If you put more stuff in it, then items will fall out.
|
||||
|
||||
If you try to put an oversized thing in it, then it'll fall out right
|
||||
away.
|
||||
|
||||
## Options
|
||||
|
||||
* `max` The maximum size of the cache, checked by applying the length
|
||||
function to all values in the cache. Not setting this is kind of
|
||||
silly, since that's the whole purpose of this lib, but it defaults
|
||||
to `Infinity`.
|
||||
* `maxAge` Maximum age in ms. Items are not pro-actively pruned out
|
||||
as they age, but if you try to get an item that is too old, it'll
|
||||
drop it and return undefined instead of giving it to you.
|
||||
* `length` Function that is used to calculate the length of stored
|
||||
items. If you're storing strings or buffers, then you probably want
|
||||
to do something like `function(n){return n.length}`. The default is
|
||||
`function(n){return 1}`, which is fine if you want to store `n`
|
||||
like-sized things.
|
||||
* `dispose` Function that is called on items when they are dropped
|
||||
from the cache. This can be handy if you want to close file
|
||||
descriptors or do other cleanup tasks when items are no longer
|
||||
accessible. Called with `key, value`. It's called *before*
|
||||
actually removing the item from the internal cache, so if you want
|
||||
to immediately put it back in, you'll have to do that in a
|
||||
`nextTick` or `setTimeout` callback or it won't do anything.
|
||||
* `stale` By default, if you set a `maxAge`, it'll only actually pull
|
||||
stale items out of the cache when you `get(key)`. (That is, it's
|
||||
not pre-emptively doing a `setTimeout` or anything.) If you set
|
||||
`stale:true`, it'll return the stale value before deleting it. If
|
||||
you don't set this, then it'll return `undefined` when you try to
|
||||
get a stale entry, as if it had already been deleted.
|
||||
|
||||
## API
|
||||
|
||||
* `set(key, value)`
|
||||
* `get(key) => value`
|
||||
|
||||
Both of these will update the "recently used"-ness of the key.
|
||||
They do what you think.
|
||||
|
||||
* `peek(key)`
|
||||
|
||||
Returns the key value (or `undefined` if not found) without
|
||||
updating the "recently used"-ness of the key.
|
||||
|
||||
(If you find yourself using this a lot, you *might* be using the
|
||||
wrong sort of data structure, but there are some use cases where
|
||||
it's handy.)
|
||||
|
||||
* `del(key)`
|
||||
|
||||
Deletes a key out of the cache.
|
||||
|
||||
* `reset()`
|
||||
|
||||
Clear the cache entirely, throwing away all values.
|
||||
|
||||
* `has(key)`
|
||||
|
||||
Check if a key is in the cache, without updating the recent-ness
|
||||
or deleting it for being stale.
|
||||
|
||||
* `forEach(function(value,key,cache), [thisp])`
|
||||
|
||||
Just like `Array.prototype.forEach`. Iterates over all the keys
|
||||
in the cache, in order of recent-ness. (Ie, more recently used
|
||||
items are iterated over first.)
|
||||
|
||||
* `keys()`
|
||||
|
||||
Return an array of the keys in the cache.
|
||||
|
||||
* `values()`
|
||||
|
||||
Return an array of the values in the cache.
|
|
@ -1,252 +0,0 @@
|
|||
;(function () { // closure for web browsers
|
||||
|
||||
if (typeof module === 'object' && module.exports) {
|
||||
module.exports = LRUCache
|
||||
} else {
|
||||
// just set the global for non-node platforms.
|
||||
this.LRUCache = LRUCache
|
||||
}
|
||||
|
||||
function hOP (obj, key) {
|
||||
return Object.prototype.hasOwnProperty.call(obj, key)
|
||||
}
|
||||
|
||||
function naiveLength () { return 1 }
|
||||
|
||||
function LRUCache (options) {
|
||||
if (!(this instanceof LRUCache))
|
||||
return new LRUCache(options)
|
||||
|
||||
if (typeof options === 'number')
|
||||
options = { max: options }
|
||||
|
||||
if (!options)
|
||||
options = {}
|
||||
|
||||
this._max = options.max
|
||||
// Kind of weird to have a default max of Infinity, but oh well.
|
||||
if (!this._max || !(typeof this._max === "number") || this._max <= 0 )
|
||||
this._max = Infinity
|
||||
|
||||
this._lengthCalculator = options.length || naiveLength
|
||||
if (typeof this._lengthCalculator !== "function")
|
||||
this._lengthCalculator = naiveLength
|
||||
|
||||
this._allowStale = options.stale || false
|
||||
this._maxAge = options.maxAge || null
|
||||
this._dispose = options.dispose
|
||||
this.reset()
|
||||
}
|
||||
|
||||
// resize the cache when the max changes.
|
||||
Object.defineProperty(LRUCache.prototype, "max",
|
||||
{ set : function (mL) {
|
||||
if (!mL || !(typeof mL === "number") || mL <= 0 ) mL = Infinity
|
||||
this._max = mL
|
||||
if (this._length > this._max) trim(this)
|
||||
}
|
||||
, get : function () { return this._max }
|
||||
, enumerable : true
|
||||
})
|
||||
|
||||
// resize the cache when the lengthCalculator changes.
|
||||
Object.defineProperty(LRUCache.prototype, "lengthCalculator",
|
||||
{ set : function (lC) {
|
||||
if (typeof lC !== "function") {
|
||||
this._lengthCalculator = naiveLength
|
||||
this._length = this._itemCount
|
||||
for (var key in this._cache) {
|
||||
this._cache[key].length = 1
|
||||
}
|
||||
} else {
|
||||
this._lengthCalculator = lC
|
||||
this._length = 0
|
||||
for (var key in this._cache) {
|
||||
this._cache[key].length = this._lengthCalculator(this._cache[key].value)
|
||||
this._length += this._cache[key].length
|
||||
}
|
||||
}
|
||||
|
||||
if (this._length > this._max) trim(this)
|
||||
}
|
||||
, get : function () { return this._lengthCalculator }
|
||||
, enumerable : true
|
||||
})
|
||||
|
||||
Object.defineProperty(LRUCache.prototype, "length",
|
||||
{ get : function () { return this._length }
|
||||
, enumerable : true
|
||||
})
|
||||
|
||||
|
||||
Object.defineProperty(LRUCache.prototype, "itemCount",
|
||||
{ get : function () { return this._itemCount }
|
||||
, enumerable : true
|
||||
})
|
||||
|
||||
LRUCache.prototype.forEach = function (fn, thisp) {
|
||||
thisp = thisp || this
|
||||
var i = 0;
|
||||
for (var k = this._mru - 1; k >= 0 && i < this._itemCount; k--) if (this._lruList[k]) {
|
||||
i++
|
||||
var hit = this._lruList[k]
|
||||
if (this._maxAge && (Date.now() - hit.now > this._maxAge)) {
|
||||
del(this, hit)
|
||||
if (!this._allowStale) hit = undefined
|
||||
}
|
||||
if (hit) {
|
||||
fn.call(thisp, hit.value, hit.key, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LRUCache.prototype.keys = function () {
|
||||
var keys = new Array(this._itemCount)
|
||||
var i = 0
|
||||
for (var k = this._mru - 1; k >= 0 && i < this._itemCount; k--) if (this._lruList[k]) {
|
||||
var hit = this._lruList[k]
|
||||
keys[i++] = hit.key
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
LRUCache.prototype.values = function () {
|
||||
var values = new Array(this._itemCount)
|
||||
var i = 0
|
||||
for (var k = this._mru - 1; k >= 0 && i < this._itemCount; k--) if (this._lruList[k]) {
|
||||
var hit = this._lruList[k]
|
||||
values[i++] = hit.value
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
LRUCache.prototype.reset = function () {
|
||||
if (this._dispose && this._cache) {
|
||||
for (var k in this._cache) {
|
||||
this._dispose(k, this._cache[k].value)
|
||||
}
|
||||
}
|
||||
|
||||
this._cache = Object.create(null) // hash of items by key
|
||||
this._lruList = Object.create(null) // list of items in order of use recency
|
||||
this._mru = 0 // most recently used
|
||||
this._lru = 0 // least recently used
|
||||
this._length = 0 // number of items in the list
|
||||
this._itemCount = 0
|
||||
}
|
||||
|
||||
// Provided for debugging/dev purposes only. No promises whatsoever that
|
||||
// this API stays stable.
|
||||
LRUCache.prototype.dump = function () {
|
||||
return this._cache
|
||||
}
|
||||
|
||||
LRUCache.prototype.dumpLru = function () {
|
||||
return this._lruList
|
||||
}
|
||||
|
||||
LRUCache.prototype.set = function (key, value) {
|
||||
if (hOP(this._cache, key)) {
|
||||
// dispose of the old one before overwriting
|
||||
if (this._dispose) this._dispose(key, this._cache[key].value)
|
||||
if (this._maxAge) this._cache[key].now = Date.now()
|
||||
this._cache[key].value = value
|
||||
this.get(key)
|
||||
return true
|
||||
}
|
||||
|
||||
var len = this._lengthCalculator(value)
|
||||
var age = this._maxAge ? Date.now() : 0
|
||||
var hit = new Entry(key, value, this._mru++, len, age)
|
||||
|
||||
// oversized objects fall out of cache automatically.
|
||||
if (hit.length > this._max) {
|
||||
if (this._dispose) this._dispose(key, value)
|
||||
return false
|
||||
}
|
||||
|
||||
this._length += hit.length
|
||||
this._lruList[hit.lu] = this._cache[key] = hit
|
||||
this._itemCount ++
|
||||
|
||||
if (this._length > this._max) trim(this)
|
||||
return true
|
||||
}
|
||||
|
||||
LRUCache.prototype.has = function (key) {
|
||||
if (!hOP(this._cache, key)) return false
|
||||
var hit = this._cache[key]
|
||||
if (this._maxAge && (Date.now() - hit.now > this._maxAge)) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
LRUCache.prototype.get = function (key) {
|
||||
return get(this, key, true)
|
||||
}
|
||||
|
||||
LRUCache.prototype.peek = function (key) {
|
||||
return get(this, key, false)
|
||||
}
|
||||
|
||||
LRUCache.prototype.pop = function () {
|
||||
var hit = this._lruList[this._lru]
|
||||
del(this, hit)
|
||||
return hit || null
|
||||
}
|
||||
|
||||
LRUCache.prototype.del = function (key) {
|
||||
del(this, this._cache[key])
|
||||
}
|
||||
|
||||
function get (self, key, doUse) {
|
||||
var hit = self._cache[key]
|
||||
if (hit) {
|
||||
if (self._maxAge && (Date.now() - hit.now > self._maxAge)) {
|
||||
del(self, hit)
|
||||
if (!self._allowStale) hit = undefined
|
||||
} else {
|
||||
if (doUse) use(self, hit)
|
||||
}
|
||||
if (hit) hit = hit.value
|
||||
}
|
||||
return hit
|
||||
}
|
||||
|
||||
function use (self, hit) {
|
||||
shiftLU(self, hit)
|
||||
hit.lu = self._mru ++
|
||||
self._lruList[hit.lu] = hit
|
||||
}
|
||||
|
||||
function trim (self) {
|
||||
while (self._lru < self._mru && self._length > self._max)
|
||||
del(self, self._lruList[self._lru])
|
||||
}
|
||||
|
||||
function shiftLU (self, hit) {
|
||||
delete self._lruList[ hit.lu ]
|
||||
while (self._lru < self._mru && !self._lruList[self._lru]) self._lru ++
|
||||
}
|
||||
|
||||
function del (self, hit) {
|
||||
if (hit) {
|
||||
if (self._dispose) self._dispose(hit.key, hit.value)
|
||||
self._length -= hit.length
|
||||
self._itemCount --
|
||||
delete self._cache[ hit.key ]
|
||||
shiftLU(self, hit)
|
||||
}
|
||||
}
|
||||
|
||||
// classy, since V8 prefers predictable objects.
|
||||
function Entry (key, value, lu, length, now) {
|
||||
this.key = key
|
||||
this.value = value
|
||||
this.lu = lu
|
||||
this.length = length
|
||||
this.now = now
|
||||
}
|
||||
|
||||
})()
|
|
@ -1,50 +0,0 @@
|
|||
{
|
||||
"name": "lru-cache",
|
||||
"description": "A cache object that deletes the least-recently-used items.",
|
||||
"version": "2.5.0",
|
||||
"author": {
|
||||
"name": "Isaac Z. Schlueter",
|
||||
"email": "i@izs.me"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "tap test --gc"
|
||||
},
|
||||
"main": "lib/lru-cache.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/isaacs/node-lru-cache.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tap": "",
|
||||
"weak": ""
|
||||
},
|
||||
"license": {
|
||||
"type": "MIT",
|
||||
"url": "http://github.com/isaacs/node-lru-cache/raw/master/LICENSE"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/isaacs/node-lru-cache/issues"
|
||||
},
|
||||
"homepage": "https://github.com/isaacs/node-lru-cache",
|
||||
"_id": "lru-cache@2.5.0",
|
||||
"dist": {
|
||||
"shasum": "d82388ae9c960becbea0c73bb9eb79b6c6ce9aeb",
|
||||
"tarball": "http://registry.npmjs.org/lru-cache/-/lru-cache-2.5.0.tgz"
|
||||
},
|
||||
"_from": "lru-cache@2",
|
||||
"_npmVersion": "1.3.15",
|
||||
"_npmUser": {
|
||||
"name": "isaacs",
|
||||
"email": "i@izs.me"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "isaacs",
|
||||
"email": "i@izs.me"
|
||||
}
|
||||
],
|
||||
"directories": {},
|
||||
"_shasum": "d82388ae9c960becbea0c73bb9eb79b6c6ce9aeb",
|
||||
"_resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.5.0.tgz",
|
||||
"readme": "ERROR: No README data found!"
|
||||
}
|
|
@ -1,369 +0,0 @@
|
|||
var test = require("tap").test
|
||||
, LRU = require("../")
|
||||
|
||||
test("basic", function (t) {
|
||||
var cache = new LRU({max: 10})
|
||||
cache.set("key", "value")
|
||||
t.equal(cache.get("key"), "value")
|
||||
t.equal(cache.get("nada"), undefined)
|
||||
t.equal(cache.length, 1)
|
||||
t.equal(cache.max, 10)
|
||||
t.end()
|
||||
})
|
||||
|
||||
test("least recently set", function (t) {
|
||||
var cache = new LRU(2)
|
||||
cache.set("a", "A")
|
||||
cache.set("b", "B")
|
||||
cache.set("c", "C")
|
||||
t.equal(cache.get("c"), "C")
|
||||
t.equal(cache.get("b"), "B")
|
||||
t.equal(cache.get("a"), undefined)
|
||||
t.end()
|
||||
})
|
||||
|
||||
test("lru recently gotten", function (t) {
|
||||
var cache = new LRU(2)
|
||||
cache.set("a", "A")
|
||||
cache.set("b", "B")
|
||||
cache.get("a")
|
||||
cache.set("c", "C")
|
||||
t.equal(cache.get("c"), "C")
|
||||
t.equal(cache.get("b"), undefined)
|
||||
t.equal(cache.get("a"), "A")
|
||||
t.end()
|
||||
})
|
||||
|
||||
test("del", function (t) {
|
||||
var cache = new LRU(2)
|
||||
cache.set("a", "A")
|
||||
cache.del("a")
|
||||
t.equal(cache.get("a"), undefined)
|
||||
t.end()
|
||||
})
|
||||
|
||||
test("max", function (t) {
|
||||
var cache = new LRU(3)
|
||||
|
||||
// test changing the max, verify that the LRU items get dropped.
|
||||
cache.max = 100
|
||||
for (var i = 0; i < 100; i ++) cache.set(i, i)
|
||||
t.equal(cache.length, 100)
|
||||
for (var i = 0; i < 100; i ++) {
|
||||
t.equal(cache.get(i), i)
|
||||
}
|
||||
cache.max = 3
|
||||
t.equal(cache.length, 3)
|
||||
for (var i = 0; i < 97; i ++) {
|
||||
t.equal(cache.get(i), undefined)
|
||||
}
|
||||
for (var i = 98; i < 100; i ++) {
|
||||
t.equal(cache.get(i), i)
|
||||
}
|
||||
|
||||
// now remove the max restriction, and try again.
|
||||
cache.max = "hello"
|
||||
for (var i = 0; i < 100; i ++) cache.set(i, i)
|
||||
t.equal(cache.length, 100)
|
||||
for (var i = 0; i < 100; i ++) {
|
||||
t.equal(cache.get(i), i)
|
||||
}
|
||||
// should trigger an immediate resize
|
||||
cache.max = 3
|
||||
t.equal(cache.length, 3)
|
||||
for (var i = 0; i < 97; i ++) {
|
||||
t.equal(cache.get(i), undefined)
|
||||
}
|
||||
for (var i = 98; i < 100; i ++) {
|
||||
t.equal(cache.get(i), i)
|
||||
}
|
||||
t.end()
|
||||
})
|
||||
|
||||
test("reset", function (t) {
|
||||
var cache = new LRU(10)
|
||||
cache.set("a", "A")
|
||||
cache.set("b", "B")
|
||||
cache.reset()
|
||||
t.equal(cache.length, 0)
|
||||
t.equal(cache.max, 10)
|
||||
t.equal(cache.get("a"), undefined)
|
||||
t.equal(cache.get("b"), undefined)
|
||||
t.end()
|
||||
})
|
||||
|
||||
|
||||
// Note: `<cache>.dump()` is a debugging tool only. No guarantees are made
|
||||
// about the format/layout of the response.
|
||||
test("dump", function (t) {
|
||||
var cache = new LRU(10)
|
||||
var d = cache.dump();
|
||||
t.equal(Object.keys(d).length, 0, "nothing in dump for empty cache")
|
||||
cache.set("a", "A")
|
||||
var d = cache.dump() // { a: { key: "a", value: "A", lu: 0 } }
|
||||
t.ok(d.a)
|
||||
t.equal(d.a.key, "a")
|
||||
t.equal(d.a.value, "A")
|
||||
t.equal(d.a.lu, 0)
|
||||
|
||||
cache.set("b", "B")
|
||||
cache.get("b")
|
||||
d = cache.dump()
|
||||
t.ok(d.b)
|
||||
t.equal(d.b.key, "b")
|
||||
t.equal(d.b.value, "B")
|
||||
t.equal(d.b.lu, 2)
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
|
||||
test("basic with weighed length", function (t) {
|
||||
var cache = new LRU({
|
||||
max: 100,
|
||||
length: function (item) { return item.size }
|
||||
})
|
||||
cache.set("key", {val: "value", size: 50})
|
||||
t.equal(cache.get("key").val, "value")
|
||||
t.equal(cache.get("nada"), undefined)
|
||||
t.equal(cache.lengthCalculator(cache.get("key")), 50)
|
||||
t.equal(cache.length, 50)
|
||||
t.equal(cache.max, 100)
|
||||
t.end()
|
||||
})
|
||||
|
||||
|
||||
test("weighed length item too large", function (t) {
|
||||
var cache = new LRU({
|
||||
max: 10,
|
||||
length: function (item) { return item.size }
|
||||
})
|
||||
t.equal(cache.max, 10)
|
||||
|
||||
// should fall out immediately
|
||||
cache.set("key", {val: "value", size: 50})
|
||||
|
||||
t.equal(cache.length, 0)
|
||||
t.equal(cache.get("key"), undefined)
|
||||
t.end()
|
||||
})
|
||||
|
||||
test("least recently set with weighed length", function (t) {
|
||||
var cache = new LRU({
|
||||
max:8,
|
||||
length: function (item) { return item.length }
|
||||
})
|
||||
cache.set("a", "A")
|
||||
cache.set("b", "BB")
|
||||
cache.set("c", "CCC")
|
||||
cache.set("d", "DDDD")
|
||||
t.equal(cache.get("d"), "DDDD")
|
||||
t.equal(cache.get("c"), "CCC")
|
||||
t.equal(cache.get("b"), undefined)
|
||||
t.equal(cache.get("a"), undefined)
|
||||
t.end()
|
||||
})
|
||||
|
||||
test("lru recently gotten with weighed length", function (t) {
|
||||
var cache = new LRU({
|
||||
max: 8,
|
||||
length: function (item) { return item.length }
|
||||
})
|
||||
cache.set("a", "A")
|
||||
cache.set("b", "BB")
|
||||
cache.set("c", "CCC")
|
||||
cache.get("a")
|
||||
cache.get("b")
|
||||
cache.set("d", "DDDD")
|
||||
t.equal(cache.get("c"), undefined)
|
||||
t.equal(cache.get("d"), "DDDD")
|
||||
t.equal(cache.get("b"), "BB")
|
||||
t.equal(cache.get("a"), "A")
|
||||
t.end()
|
||||
})
|
||||
|
||||
test("set returns proper booleans", function(t) {
|
||||
var cache = new LRU({
|
||||
max: 5,
|
||||
length: function (item) { return item.length }
|
||||
})
|
||||
|
||||
t.equal(cache.set("a", "A"), true)
|
||||
|
||||
// should return false for max exceeded
|
||||
t.equal(cache.set("b", "donuts"), false)
|
||||
|
||||
t.equal(cache.set("b", "B"), true)
|
||||
t.equal(cache.set("c", "CCCC"), true)
|
||||
t.end()
|
||||
})
|
||||
|
||||
test("drop the old items", function(t) {
|
||||
var cache = new LRU({
|
||||
max: 5,
|
||||
maxAge: 50
|
||||
})
|
||||
|
||||
cache.set("a", "A")
|
||||
|
||||
setTimeout(function () {
|
||||
cache.set("b", "b")
|
||||
t.equal(cache.get("a"), "A")
|
||||
}, 25)
|
||||
|
||||
setTimeout(function () {
|
||||
cache.set("c", "C")
|
||||
// timed out
|
||||
t.notOk(cache.get("a"))
|
||||
}, 60)
|
||||
|
||||
setTimeout(function () {
|
||||
t.notOk(cache.get("b"))
|
||||
t.equal(cache.get("c"), "C")
|
||||
}, 90)
|
||||
|
||||
setTimeout(function () {
|
||||
t.notOk(cache.get("c"))
|
||||
t.end()
|
||||
}, 155)
|
||||
})
|
||||
|
||||
test("disposal function", function(t) {
|
||||
var disposed = false
|
||||
var cache = new LRU({
|
||||
max: 1,
|
||||
dispose: function (k, n) {
|
||||
disposed = n
|
||||
}
|
||||
})
|
||||
|
||||
cache.set(1, 1)
|
||||
cache.set(2, 2)
|
||||
t.equal(disposed, 1)
|
||||
cache.set(3, 3)
|
||||
t.equal(disposed, 2)
|
||||
cache.reset()
|
||||
t.equal(disposed, 3)
|
||||
t.end()
|
||||
})
|
||||
|
||||
test("disposal function on too big of item", function(t) {
|
||||
var disposed = false
|
||||
var cache = new LRU({
|
||||
max: 1,
|
||||
length: function (k) {
|
||||
return k.length
|
||||
},
|
||||
dispose: function (k, n) {
|
||||
disposed = n
|
||||
}
|
||||
})
|
||||
var obj = [ 1, 2 ]
|
||||
|
||||
t.equal(disposed, false)
|
||||
cache.set("obj", obj)
|
||||
t.equal(disposed, obj)
|
||||
t.end()
|
||||
})
|
||||
|
||||
test("has()", function(t) {
|
||||
var cache = new LRU({
|
||||
max: 1,
|
||||
maxAge: 10
|
||||
})
|
||||
|
||||
cache.set('foo', 'bar')
|
||||
t.equal(cache.has('foo'), true)
|
||||
cache.set('blu', 'baz')
|
||||
t.equal(cache.has('foo'), false)
|
||||
t.equal(cache.has('blu'), true)
|
||||
setTimeout(function() {
|
||||
t.equal(cache.has('blu'), false)
|
||||
t.end()
|
||||
}, 15)
|
||||
})
|
||||
|
||||
test("stale", function(t) {
|
||||
var cache = new LRU({
|
||||
maxAge: 10,
|
||||
stale: true
|
||||
})
|
||||
|
||||
cache.set('foo', 'bar')
|
||||
t.equal(cache.get('foo'), 'bar')
|
||||
t.equal(cache.has('foo'), true)
|
||||
setTimeout(function() {
|
||||
t.equal(cache.has('foo'), false)
|
||||
t.equal(cache.get('foo'), 'bar')
|
||||
t.equal(cache.get('foo'), undefined)
|
||||
t.end()
|
||||
}, 15)
|
||||
})
|
||||
|
||||
test("lru update via set", function(t) {
|
||||
var cache = LRU({ max: 2 });
|
||||
|
||||
cache.set('foo', 1);
|
||||
cache.set('bar', 2);
|
||||
cache.del('bar');
|
||||
cache.set('baz', 3);
|
||||
cache.set('qux', 4);
|
||||
|
||||
t.equal(cache.get('foo'), undefined)
|
||||
t.equal(cache.get('bar'), undefined)
|
||||
t.equal(cache.get('baz'), 3)
|
||||
t.equal(cache.get('qux'), 4)
|
||||
t.end()
|
||||
})
|
||||
|
||||
test("least recently set w/ peek", function (t) {
|
||||
var cache = new LRU(2)
|
||||
cache.set("a", "A")
|
||||
cache.set("b", "B")
|
||||
t.equal(cache.peek("a"), "A")
|
||||
cache.set("c", "C")
|
||||
t.equal(cache.get("c"), "C")
|
||||
t.equal(cache.get("b"), "B")
|
||||
t.equal(cache.get("a"), undefined)
|
||||
t.end()
|
||||
})
|
||||
|
||||
test("pop the least used item", function (t) {
|
||||
var cache = new LRU(3)
|
||||
, last
|
||||
|
||||
cache.set("a", "A")
|
||||
cache.set("b", "B")
|
||||
cache.set("c", "C")
|
||||
|
||||
t.equal(cache.length, 3)
|
||||
t.equal(cache.max, 3)
|
||||
|
||||
// Ensure we pop a, c, b
|
||||
cache.get("b", "B")
|
||||
|
||||
last = cache.pop()
|
||||
t.equal(last.key, "a")
|
||||
t.equal(last.value, "A")
|
||||
t.equal(cache.length, 2)
|
||||
t.equal(cache.max, 3)
|
||||
|
||||
last = cache.pop()
|
||||
t.equal(last.key, "c")
|
||||
t.equal(last.value, "C")
|
||||
t.equal(cache.length, 1)
|
||||
t.equal(cache.max, 3)
|
||||
|
||||
last = cache.pop()
|
||||
t.equal(last.key, "b")
|
||||
t.equal(last.value, "B")
|
||||
t.equal(cache.length, 0)
|
||||
t.equal(cache.max, 3)
|
||||
|
||||
last = cache.pop()
|
||||
t.equal(last, null)
|
||||
t.equal(cache.length, 0)
|
||||
t.equal(cache.max, 3)
|
||||
|
||||
t.end()
|
||||
})
|
|
@ -1,52 +0,0 @@
|
|||
var test = require('tap').test
|
||||
var LRU = require('../')
|
||||
|
||||
test('forEach', function (t) {
|
||||
var l = new LRU(5)
|
||||
for (var i = 0; i < 10; i ++) {
|
||||
l.set(i.toString(), i.toString(2))
|
||||
}
|
||||
|
||||
var i = 9
|
||||
l.forEach(function (val, key, cache) {
|
||||
t.equal(cache, l)
|
||||
t.equal(key, i.toString())
|
||||
t.equal(val, i.toString(2))
|
||||
i -= 1
|
||||
})
|
||||
|
||||
// get in order of most recently used
|
||||
l.get(6)
|
||||
l.get(8)
|
||||
|
||||
var order = [ 8, 6, 9, 7, 5 ]
|
||||
var i = 0
|
||||
|
||||
l.forEach(function (val, key, cache) {
|
||||
var j = order[i ++]
|
||||
t.equal(cache, l)
|
||||
t.equal(key, j.toString())
|
||||
t.equal(val, j.toString(2))
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('keys() and values()', function (t) {
|
||||
var l = new LRU(5)
|
||||
for (var i = 0; i < 10; i ++) {
|
||||
l.set(i.toString(), i.toString(2))
|
||||
}
|
||||
|
||||
t.similar(l.keys(), ['9', '8', '7', '6', '5'])
|
||||
t.similar(l.values(), ['1001', '1000', '111', '110', '101'])
|
||||
|
||||
// get in order of most recently used
|
||||
l.get(6)
|
||||
l.get(8)
|
||||
|
||||
t.similar(l.keys(), ['8', '6', '9', '7', '5'])
|
||||
t.similar(l.values(), ['1000', '110', '1001', '111', '101'])
|
||||
|
||||
t.end()
|
||||
})
|
|
@ -1,50 +0,0 @@
|
|||
#!/usr/bin/env node --expose_gc
|
||||
|
||||
var weak = require('weak');
|
||||
var test = require('tap').test
|
||||
var LRU = require('../')
|
||||
var l = new LRU({ max: 10 })
|
||||
var refs = 0
|
||||
function X() {
|
||||
refs ++
|
||||
weak(this, deref)
|
||||
}
|
||||
|
||||
function deref() {
|
||||
refs --
|
||||
}
|
||||
|
||||
test('no leaks', function (t) {
|
||||
// fill up the cache
|
||||
for (var i = 0; i < 100; i++) {
|
||||
l.set(i, new X);
|
||||
// throw some gets in there, too.
|
||||
if (i % 2 === 0)
|
||||
l.get(i / 2)
|
||||
}
|
||||
|
||||
gc()
|
||||
|
||||
var start = process.memoryUsage()
|
||||
|
||||
// capture the memory
|
||||
var startRefs = refs
|
||||
|
||||
// do it again, but more
|
||||
for (var i = 0; i < 10000; i++) {
|
||||
l.set(i, new X);
|
||||
// throw some gets in there, too.
|
||||
if (i % 2 === 0)
|
||||
l.get(i / 2)
|
||||
}
|
||||
|
||||
gc()
|
||||
|
||||
var end = process.memoryUsage()
|
||||
t.equal(refs, startRefs, 'no leaky refs')
|
||||
|
||||
console.error('start: %j\n' +
|
||||
'end: %j', start, end);
|
||||
t.pass();
|
||||
t.end();
|
||||
})
|
|
@ -1,27 +0,0 @@
|
|||
Copyright (c) Isaac Z. Schlueter ("Author")
|
||||
All rights reserved.
|
||||
|
||||
The BSD License
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. 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.
|
|
@ -1,53 +0,0 @@
|
|||
# sigmund
|
||||
|
||||
Quick and dirty signatures for Objects.
|
||||
|
||||
This is like a much faster `deepEquals` comparison, which returns a
|
||||
string key suitable for caches and the like.
|
||||
|
||||
## Usage
|
||||
|
||||
```javascript
|
||||
function doSomething (someObj) {
|
||||
var key = sigmund(someObj, maxDepth) // max depth defaults to 10
|
||||
var cached = cache.get(key)
|
||||
if (cached) return cached)
|
||||
|
||||
var result = expensiveCalculation(someObj)
|
||||
cache.set(key, result)
|
||||
return result
|
||||
}
|
||||
```
|
||||
|
||||
The resulting key will be as unique and reproducible as calling
|
||||
`JSON.stringify` or `util.inspect` on the object, but is much faster.
|
||||
In order to achieve this speed, some differences are glossed over.
|
||||
For example, the object `{0:'foo'}` will be treated identically to the
|
||||
array `['foo']`.
|
||||
|
||||
Also, just as there is no way to summon the soul from the scribblings
|
||||
of a cocain-addled psychoanalyst, there is no way to revive the object
|
||||
from the signature string that sigmund gives you. In fact, it's
|
||||
barely even readable.
|
||||
|
||||
As with `sys.inspect` and `JSON.stringify`, larger objects will
|
||||
produce larger signature strings.
|
||||
|
||||
Because sigmund is a bit less strict than the more thorough
|
||||
alternatives, the strings will be shorter, and also there is a
|
||||
slightly higher chance for collisions. For example, these objects
|
||||
have the same signature:
|
||||
|
||||
var obj1 = {a:'b',c:/def/,g:['h','i',{j:'',k:'l'}]}
|
||||
var obj2 = {a:'b',c:'/def/',g:['h','i','{jkl']}
|
||||
|
||||
Like a good Freudian, sigmund is most effective when you already have
|
||||
some understanding of what you're looking for. It can help you help
|
||||
yourself, but you must be willing to do some work as well.
|
||||
|
||||
Cycles are handled, and cyclical objects are silently omitted (though
|
||||
the key is included in the signature output.)
|
||||
|
||||
The second argument is the maximum depth, which defaults to 10,
|
||||
because that is the maximum object traversal depth covered by most
|
||||
insurance carriers.
|
|
@ -1,283 +0,0 @@
|
|||
// different ways to id objects
|
||||
// use a req/res pair, since it's crazy deep and cyclical
|
||||
|
||||
// sparseFE10 and sigmund are usually pretty close, which is to be expected,
|
||||
// since they are essentially the same algorithm, except that sigmund handles
|
||||
// regular expression objects properly.
|
||||
|
||||
|
||||
var http = require('http')
|
||||
var util = require('util')
|
||||
var sigmund = require('./sigmund.js')
|
||||
var sreq, sres, creq, cres, test
|
||||
|
||||
http.createServer(function (q, s) {
|
||||
sreq = q
|
||||
sres = s
|
||||
sres.end('ok')
|
||||
this.close(function () { setTimeout(function () {
|
||||
start()
|
||||
}, 200) })
|
||||
}).listen(1337, function () {
|
||||
creq = http.get({ port: 1337 })
|
||||
creq.on('response', function (s) { cres = s })
|
||||
})
|
||||
|
||||
function start () {
|
||||
test = [sreq, sres, creq, cres]
|
||||
// test = sreq
|
||||
// sreq.sres = sres
|
||||
// sreq.creq = creq
|
||||
// sreq.cres = cres
|
||||
|
||||
for (var i in exports.compare) {
|
||||
console.log(i)
|
||||
var hash = exports.compare[i]()
|
||||
console.log(hash)
|
||||
console.log(hash.length)
|
||||
console.log('')
|
||||
}
|
||||
|
||||
require('bench').runMain()
|
||||
}
|
||||
|
||||
function customWs (obj, md, d) {
|
||||
d = d || 0
|
||||
var to = typeof obj
|
||||
if (to === 'undefined' || to === 'function' || to === null) return ''
|
||||
if (d > md || !obj || to !== 'object') return ('' + obj).replace(/[\n ]+/g, '')
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map(function (i, _, __) {
|
||||
return customWs(i, md, d + 1)
|
||||
}).reduce(function (a, b) { return a + b }, '')
|
||||
}
|
||||
|
||||
var keys = Object.keys(obj)
|
||||
return keys.map(function (k, _, __) {
|
||||
return k + ':' + customWs(obj[k], md, d + 1)
|
||||
}).reduce(function (a, b) { return a + b }, '')
|
||||
}
|
||||
|
||||
function custom (obj, md, d) {
|
||||
d = d || 0
|
||||
var to = typeof obj
|
||||
if (to === 'undefined' || to === 'function' || to === null) return ''
|
||||
if (d > md || !obj || to !== 'object') return '' + obj
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map(function (i, _, __) {
|
||||
return custom(i, md, d + 1)
|
||||
}).reduce(function (a, b) { return a + b }, '')
|
||||
}
|
||||
|
||||
var keys = Object.keys(obj)
|
||||
return keys.map(function (k, _, __) {
|
||||
return k + ':' + custom(obj[k], md, d + 1)
|
||||
}).reduce(function (a, b) { return a + b }, '')
|
||||
}
|
||||
|
||||
function sparseFE2 (obj, maxDepth) {
|
||||
var seen = []
|
||||
var soFar = ''
|
||||
function ch (v, depth) {
|
||||
if (depth > maxDepth) return
|
||||
if (typeof v === 'function' || typeof v === 'undefined') return
|
||||
if (typeof v !== 'object' || !v) {
|
||||
soFar += v
|
||||
return
|
||||
}
|
||||
if (seen.indexOf(v) !== -1 || depth === maxDepth) return
|
||||
seen.push(v)
|
||||
soFar += '{'
|
||||
Object.keys(v).forEach(function (k, _, __) {
|
||||
// pseudo-private values. skip those.
|
||||
if (k.charAt(0) === '_') return
|
||||
var to = typeof v[k]
|
||||
if (to === 'function' || to === 'undefined') return
|
||||
soFar += k + ':'
|
||||
ch(v[k], depth + 1)
|
||||
})
|
||||
soFar += '}'
|
||||
}
|
||||
ch(obj, 0)
|
||||
return soFar
|
||||
}
|
||||
|
||||
function sparseFE (obj, maxDepth) {
|
||||
var seen = []
|
||||
var soFar = ''
|
||||
function ch (v, depth) {
|
||||
if (depth > maxDepth) return
|
||||
if (typeof v === 'function' || typeof v === 'undefined') return
|
||||
if (typeof v !== 'object' || !v) {
|
||||
soFar += v
|
||||
return
|
||||
}
|
||||
if (seen.indexOf(v) !== -1 || depth === maxDepth) return
|
||||
seen.push(v)
|
||||
soFar += '{'
|
||||
Object.keys(v).forEach(function (k, _, __) {
|
||||
// pseudo-private values. skip those.
|
||||
if (k.charAt(0) === '_') return
|
||||
var to = typeof v[k]
|
||||
if (to === 'function' || to === 'undefined') return
|
||||
soFar += k
|
||||
ch(v[k], depth + 1)
|
||||
})
|
||||
}
|
||||
ch(obj, 0)
|
||||
return soFar
|
||||
}
|
||||
|
||||
function sparse (obj, maxDepth) {
|
||||
var seen = []
|
||||
var soFar = ''
|
||||
function ch (v, depth) {
|
||||
if (depth > maxDepth) return
|
||||
if (typeof v === 'function' || typeof v === 'undefined') return
|
||||
if (typeof v !== 'object' || !v) {
|
||||
soFar += v
|
||||
return
|
||||
}
|
||||
if (seen.indexOf(v) !== -1 || depth === maxDepth) return
|
||||
seen.push(v)
|
||||
soFar += '{'
|
||||
for (var k in v) {
|
||||
// pseudo-private values. skip those.
|
||||
if (k.charAt(0) === '_') continue
|
||||
var to = typeof v[k]
|
||||
if (to === 'function' || to === 'undefined') continue
|
||||
soFar += k
|
||||
ch(v[k], depth + 1)
|
||||
}
|
||||
}
|
||||
ch(obj, 0)
|
||||
return soFar
|
||||
}
|
||||
|
||||
function noCommas (obj, maxDepth) {
|
||||
var seen = []
|
||||
var soFar = ''
|
||||
function ch (v, depth) {
|
||||
if (depth > maxDepth) return
|
||||
if (typeof v === 'function' || typeof v === 'undefined') return
|
||||
if (typeof v !== 'object' || !v) {
|
||||
soFar += v
|
||||
return
|
||||
}
|
||||
if (seen.indexOf(v) !== -1 || depth === maxDepth) return
|
||||
seen.push(v)
|
||||
soFar += '{'
|
||||
for (var k in v) {
|
||||
// pseudo-private values. skip those.
|
||||
if (k.charAt(0) === '_') continue
|
||||
var to = typeof v[k]
|
||||
if (to === 'function' || to === 'undefined') continue
|
||||
soFar += k + ':'
|
||||
ch(v[k], depth + 1)
|
||||
}
|
||||
soFar += '}'
|
||||
}
|
||||
ch(obj, 0)
|
||||
return soFar
|
||||
}
|
||||
|
||||
|
||||
function flatten (obj, maxDepth) {
|
||||
var seen = []
|
||||
var soFar = ''
|
||||
function ch (v, depth) {
|
||||
if (depth > maxDepth) return
|
||||
if (typeof v === 'function' || typeof v === 'undefined') return
|
||||
if (typeof v !== 'object' || !v) {
|
||||
soFar += v
|
||||
return
|
||||
}
|
||||
if (seen.indexOf(v) !== -1 || depth === maxDepth) return
|
||||
seen.push(v)
|
||||
soFar += '{'
|
||||
for (var k in v) {
|
||||
// pseudo-private values. skip those.
|
||||
if (k.charAt(0) === '_') continue
|
||||
var to = typeof v[k]
|
||||
if (to === 'function' || to === 'undefined') continue
|
||||
soFar += k + ':'
|
||||
ch(v[k], depth + 1)
|
||||
soFar += ','
|
||||
}
|
||||
soFar += '}'
|
||||
}
|
||||
ch(obj, 0)
|
||||
return soFar
|
||||
}
|
||||
|
||||
exports.compare =
|
||||
{
|
||||
// 'custom 2': function () {
|
||||
// return custom(test, 2, 0)
|
||||
// },
|
||||
// 'customWs 2': function () {
|
||||
// return customWs(test, 2, 0)
|
||||
// },
|
||||
'JSON.stringify (guarded)': function () {
|
||||
var seen = []
|
||||
return JSON.stringify(test, function (k, v) {
|
||||
if (typeof v !== 'object' || !v) return v
|
||||
if (seen.indexOf(v) !== -1) return undefined
|
||||
seen.push(v)
|
||||
return v
|
||||
})
|
||||
},
|
||||
|
||||
'flatten 10': function () {
|
||||
return flatten(test, 10)
|
||||
},
|
||||
|
||||
// 'flattenFE 10': function () {
|
||||
// return flattenFE(test, 10)
|
||||
// },
|
||||
|
||||
'noCommas 10': function () {
|
||||
return noCommas(test, 10)
|
||||
},
|
||||
|
||||
'sparse 10': function () {
|
||||
return sparse(test, 10)
|
||||
},
|
||||
|
||||
'sparseFE 10': function () {
|
||||
return sparseFE(test, 10)
|
||||
},
|
||||
|
||||
'sparseFE2 10': function () {
|
||||
return sparseFE2(test, 10)
|
||||
},
|
||||
|
||||
sigmund: function() {
|
||||
return sigmund(test, 10)
|
||||
},
|
||||
|
||||
|
||||
// 'util.inspect 1': function () {
|
||||
// return util.inspect(test, false, 1, false)
|
||||
// },
|
||||
// 'util.inspect undefined': function () {
|
||||
// util.inspect(test)
|
||||
// },
|
||||
// 'util.inspect 2': function () {
|
||||
// util.inspect(test, false, 2, false)
|
||||
// },
|
||||
// 'util.inspect 3': function () {
|
||||
// util.inspect(test, false, 3, false)
|
||||
// },
|
||||
// 'util.inspect 4': function () {
|
||||
// util.inspect(test, false, 4, false)
|
||||
// },
|
||||
// 'util.inspect Infinity': function () {
|
||||
// util.inspect(test, false, Infinity, false)
|
||||
// }
|
||||
}
|
||||
|
||||
/** results
|
||||
**/
|
|
@ -1,58 +0,0 @@
|
|||
{
|
||||
"name": "sigmund",
|
||||
"version": "1.0.0",
|
||||
"description": "Quick and dirty signatures for Objects.",
|
||||
"main": "sigmund.js",
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"tap": "~0.3.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "tap test/*.js",
|
||||
"bench": "node bench.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/isaacs/sigmund"
|
||||
},
|
||||
"keywords": [
|
||||
"object",
|
||||
"signature",
|
||||
"key",
|
||||
"data",
|
||||
"psychoanalysis"
|
||||
],
|
||||
"author": {
|
||||
"name": "Isaac Z. Schlueter",
|
||||
"email": "i@izs.me",
|
||||
"url": "http://blog.izs.me/"
|
||||
},
|
||||
"license": "BSD",
|
||||
"readme": "# sigmund\n\nQuick and dirty signatures for Objects.\n\nThis is like a much faster `deepEquals` comparison, which returns a\nstring key suitable for caches and the like.\n\n## Usage\n\n```javascript\nfunction doSomething (someObj) {\n var key = sigmund(someObj, maxDepth) // max depth defaults to 10\n var cached = cache.get(key)\n if (cached) return cached)\n\n var result = expensiveCalculation(someObj)\n cache.set(key, result)\n return result\n}\n```\n\nThe resulting key will be as unique and reproducible as calling\n`JSON.stringify` or `util.inspect` on the object, but is much faster.\nIn order to achieve this speed, some differences are glossed over.\nFor example, the object `{0:'foo'}` will be treated identically to the\narray `['foo']`.\n\nAlso, just as there is no way to summon the soul from the scribblings\nof a cocain-addled psychoanalyst, there is no way to revive the object\nfrom the signature string that sigmund gives you. In fact, it's\nbarely even readable.\n\nAs with `sys.inspect` and `JSON.stringify`, larger objects will\nproduce larger signature strings.\n\nBecause sigmund is a bit less strict than the more thorough\nalternatives, the strings will be shorter, and also there is a\nslightly higher chance for collisions. For example, these objects\nhave the same signature:\n\n var obj1 = {a:'b',c:/def/,g:['h','i',{j:'',k:'l'}]}\n var obj2 = {a:'b',c:'/def/',g:['h','i','{jkl']}\n\nLike a good Freudian, sigmund is most effective when you already have\nsome understanding of what you're looking for. It can help you help\nyourself, but you must be willing to do some work as well.\n\nCycles are handled, and cyclical objects are silently omitted (though\nthe key is included in the signature output.)\n\nThe second argument is the maximum depth, which defaults to 10,\nbecause that is the maximum object traversal depth covered by most\ninsurance carriers.\n",
|
||||
"_id": "sigmund@1.0.0",
|
||||
"dist": {
|
||||
"shasum": "66a2b3a749ae8b5fb89efd4fcc01dc94fbe02296",
|
||||
"tarball": "http://registry.npmjs.org/sigmund/-/sigmund-1.0.0.tgz"
|
||||
},
|
||||
"_npmVersion": "1.1.48",
|
||||
"_npmUser": {
|
||||
"name": "isaacs",
|
||||
"email": "i@izs.me"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "isaacs",
|
||||
"email": "i@izs.me"
|
||||
}
|
||||
],
|
||||
"_shasum": "66a2b3a749ae8b5fb89efd4fcc01dc94fbe02296",
|
||||
"_from": "sigmund@~1.0.0",
|
||||
"_resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.0.tgz",
|
||||
"bugs": {
|
||||
"url": "https://github.com/isaacs/sigmund/issues"
|
||||
},
|
||||
"homepage": "https://github.com/isaacs/sigmund"
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
module.exports = sigmund
|
||||
function sigmund (subject, maxSessions) {
|
||||
maxSessions = maxSessions || 10;
|
||||
var notes = [];
|
||||
var analysis = '';
|
||||
var RE = RegExp;
|
||||
|
||||
function psychoAnalyze (subject, session) {
|
||||
if (session > maxSessions) return;
|
||||
|
||||
if (typeof subject === 'function' ||
|
||||
typeof subject === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof subject !== 'object' || !subject ||
|
||||
(subject instanceof RE)) {
|
||||
analysis += subject;
|
||||
return;
|
||||
}
|
||||
|
||||
if (notes.indexOf(subject) !== -1 || session === maxSessions) return;
|
||||
|
||||
notes.push(subject);
|
||||
analysis += '{';
|
||||
Object.keys(subject).forEach(function (issue, _, __) {
|
||||
// pseudo-private values. skip those.
|
||||
if (issue.charAt(0) === '_') return;
|
||||
var to = typeof subject[issue];
|
||||
if (to === 'function' || to === 'undefined') return;
|
||||
analysis += issue;
|
||||
psychoAnalyze(subject[issue], session + 1);
|
||||
});
|
||||
}
|
||||
psychoAnalyze(subject, 0);
|
||||
return analysis;
|
||||
}
|
||||
|
||||
// vim: set softtabstop=4 shiftwidth=4:
|
|
@ -1,24 +0,0 @@
|
|||
var test = require('tap').test
|
||||
var sigmund = require('../sigmund.js')
|
||||
|
||||
|
||||
// occasionally there are duplicates
|
||||
// that's an acceptable edge-case. JSON.stringify and util.inspect
|
||||
// have some collision potential as well, though less, and collision
|
||||
// detection is expensive.
|
||||
var hash = '{abc/def/g{0h1i2{jkl'
|
||||
var obj1 = {a:'b',c:/def/,g:['h','i',{j:'',k:'l'}]}
|
||||
var obj2 = {a:'b',c:'/def/',g:['h','i','{jkl']}
|
||||
|
||||
var obj3 = JSON.parse(JSON.stringify(obj1))
|
||||
obj3.c = /def/
|
||||
obj3.g[2].cycle = obj3
|
||||
var cycleHash = '{abc/def/g{0h1i2{jklcycle'
|
||||
|
||||
test('basic', function (t) {
|
||||
t.equal(sigmund(obj1), hash)
|
||||
t.equal(sigmund(obj2), hash)
|
||||
t.equal(sigmund(obj3), cycleHash)
|
||||
t.end()
|
||||
})
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
{
|
||||
"author": {
|
||||
"name": "Isaac Z. Schlueter",
|
||||
"email": "i@izs.me",
|
||||
"url": "http://blog.izs.me"
|
||||
},
|
||||
"name": "minimatch",
|
||||
"description": "a glob matcher in javascript",
|
||||
"version": "0.3.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/isaacs/minimatch.git"
|
||||
},
|
||||
"main": "minimatch.js",
|
||||
"scripts": {
|
||||
"test": "tap test/*.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"lru-cache": "2",
|
||||
"sigmund": "~1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tap": ""
|
||||
},
|
||||
"license": {
|
||||
"type": "MIT",
|
||||
"url": "http://github.com/isaacs/minimatch/raw/master/LICENSE"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/isaacs/minimatch/issues"
|
||||
},
|
||||
"homepage": "https://github.com/isaacs/minimatch",
|
||||
"_id": "minimatch@0.3.0",
|
||||
"_shasum": "275d8edaac4f1bb3326472089e7949c8394699dd",
|
||||
"_from": "minimatch@0.3",
|
||||
"_npmVersion": "1.4.10",
|
||||
"_npmUser": {
|
||||
"name": "isaacs",
|
||||
"email": "i@izs.me"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "isaacs",
|
||||
"email": "i@izs.me"
|
||||
}
|
||||
],
|
||||
"dist": {
|
||||
"shasum": "275d8edaac4f1bb3326472089e7949c8394699dd",
|
||||
"tarball": "http://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz"
|
||||
},
|
||||
"directories": {},
|
||||
"_resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz",
|
||||
"readme": "ERROR: No README data found!"
|
||||
}
|
|
@ -1,399 +0,0 @@
|
|||
// http://www.bashcookbook.com/bashinfo/source/bash-1.14.7/tests/glob-test
|
||||
//
|
||||
// TODO: Some of these tests do very bad things with backslashes, and will
|
||||
// most likely fail badly on windows. They should probably be skipped.
|
||||
|
||||
var tap = require("tap")
|
||||
, globalBefore = Object.keys(global)
|
||||
, mm = require("../")
|
||||
, files = [ "a", "b", "c", "d", "abc"
|
||||
, "abd", "abe", "bb", "bcd"
|
||||
, "ca", "cb", "dd", "de"
|
||||
, "bdir/", "bdir/cfile"]
|
||||
, next = files.concat([ "a-b", "aXb"
|
||||
, ".x", ".y" ])
|
||||
|
||||
|
||||
var patterns =
|
||||
[ "http://www.bashcookbook.com/bashinfo/source/bash-1.14.7/tests/glob-test"
|
||||
, ["a*", ["a", "abc", "abd", "abe"]]
|
||||
, ["X*", ["X*"], {nonull: true}]
|
||||
|
||||
// allow null glob expansion
|
||||
, ["X*", []]
|
||||
|
||||
// isaacs: Slightly different than bash/sh/ksh
|
||||
// \\* is not un-escaped to literal "*" in a failed match,
|
||||
// but it does make it get treated as a literal star
|
||||
, ["\\*", ["\\*"], {nonull: true}]
|
||||
, ["\\**", ["\\**"], {nonull: true}]
|
||||
, ["\\*\\*", ["\\*\\*"], {nonull: true}]
|
||||
|
||||
, ["b*/", ["bdir/"]]
|
||||
, ["c*", ["c", "ca", "cb"]]
|
||||
, ["**", files]
|
||||
|
||||
, ["\\.\\./*/", ["\\.\\./*/"], {nonull: true}]
|
||||
, ["s/\\..*//", ["s/\\..*//"], {nonull: true}]
|
||||
|
||||
, "legendary larry crashes bashes"
|
||||
, ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\\1/"
|
||||
, ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\\1/"], {nonull: true}]
|
||||
, ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/"
|
||||
, ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/"], {nonull: true}]
|
||||
|
||||
, "character classes"
|
||||
, ["[a-c]b*", ["abc", "abd", "abe", "bb", "cb"]]
|
||||
, ["[a-y]*[^c]", ["abd", "abe", "bb", "bcd",
|
||||
"bdir/", "ca", "cb", "dd", "de"]]
|
||||
, ["a*[^c]", ["abd", "abe"]]
|
||||
, function () { files.push("a-b", "aXb") }
|
||||
, ["a[X-]b", ["a-b", "aXb"]]
|
||||
, function () { files.push(".x", ".y") }
|
||||
, ["[^a-c]*", ["d", "dd", "de"]]
|
||||
, function () { files.push("a*b/", "a*b/ooo") }
|
||||
, ["a\\*b/*", ["a*b/ooo"]]
|
||||
, ["a\\*?/*", ["a*b/ooo"]]
|
||||
, ["*\\\\!*", [], {null: true}, ["echo !7"]]
|
||||
, ["*\\!*", ["echo !7"], null, ["echo !7"]]
|
||||
, ["*.\\*", ["r.*"], null, ["r.*"]]
|
||||
, ["a[b]c", ["abc"]]
|
||||
, ["a[\\b]c", ["abc"]]
|
||||
, ["a?c", ["abc"]]
|
||||
, ["a\\*c", [], {null: true}, ["abc"]]
|
||||
, ["", [""], { null: true }, [""]]
|
||||
|
||||
, "http://www.opensource.apple.com/source/bash/bash-23/" +
|
||||
"bash/tests/glob-test"
|
||||
, function () { files.push("man/", "man/man1/", "man/man1/bash.1") }
|
||||
, ["*/man*/bash.*", ["man/man1/bash.1"]]
|
||||
, ["man/man1/bash.1", ["man/man1/bash.1"]]
|
||||
, ["a***c", ["abc"], null, ["abc"]]
|
||||
, ["a*****?c", ["abc"], null, ["abc"]]
|
||||
, ["?*****??", ["abc"], null, ["abc"]]
|
||||
, ["*****??", ["abc"], null, ["abc"]]
|
||||
, ["?*****?c", ["abc"], null, ["abc"]]
|
||||
, ["?***?****c", ["abc"], null, ["abc"]]
|
||||
, ["?***?****?", ["abc"], null, ["abc"]]
|
||||
, ["?***?****", ["abc"], null, ["abc"]]
|
||||
, ["*******c", ["abc"], null, ["abc"]]
|
||||
, ["*******?", ["abc"], null, ["abc"]]
|
||||
, ["a*cd**?**??k", ["abcdecdhjk"], null, ["abcdecdhjk"]]
|
||||
, ["a**?**cd**?**??k", ["abcdecdhjk"], null, ["abcdecdhjk"]]
|
||||
, ["a**?**cd**?**??k***", ["abcdecdhjk"], null, ["abcdecdhjk"]]
|
||||
, ["a**?**cd**?**??***k", ["abcdecdhjk"], null, ["abcdecdhjk"]]
|
||||
, ["a**?**cd**?**??***k**", ["abcdecdhjk"], null, ["abcdecdhjk"]]
|
||||
, ["a****c**?**??*****", ["abcdecdhjk"], null, ["abcdecdhjk"]]
|
||||
, ["[-abc]", ["-"], null, ["-"]]
|
||||
, ["[abc-]", ["-"], null, ["-"]]
|
||||
, ["\\", ["\\"], null, ["\\"]]
|
||||
, ["[\\\\]", ["\\"], null, ["\\"]]
|
||||
, ["[[]", ["["], null, ["["]]
|
||||
, ["[", ["["], null, ["["]]
|
||||
, ["[*", ["[abc"], null, ["[abc"]]
|
||||
, "a right bracket shall lose its special meaning and\n" +
|
||||
"represent itself in a bracket expression if it occurs\n" +
|
||||
"first in the list. -- POSIX.2 2.8.3.2"
|
||||
, ["[]]", ["]"], null, ["]"]]
|
||||
, ["[]-]", ["]"], null, ["]"]]
|
||||
, ["[a-\z]", ["p"], null, ["p"]]
|
||||
, ["??**********?****?", [], { null: true }, ["abc"]]
|
||||
, ["??**********?****c", [], { null: true }, ["abc"]]
|
||||
, ["?************c****?****", [], { null: true }, ["abc"]]
|
||||
, ["*c*?**", [], { null: true }, ["abc"]]
|
||||
, ["a*****c*?**", [], { null: true }, ["abc"]]
|
||||
, ["a********???*******", [], { null: true }, ["abc"]]
|
||||
, ["[]", [], { null: true }, ["a"]]
|
||||
, ["[abc", [], { null: true }, ["["]]
|
||||
|
||||
, "nocase tests"
|
||||
, ["XYZ", ["xYz"], { nocase: true, null: true }
|
||||
, ["xYz", "ABC", "IjK"]]
|
||||
, ["ab*", ["ABC"], { nocase: true, null: true }
|
||||
, ["xYz", "ABC", "IjK"]]
|
||||
, ["[ia]?[ck]", ["ABC", "IjK"], { nocase: true, null: true }
|
||||
, ["xYz", "ABC", "IjK"]]
|
||||
|
||||
// [ pattern, [matches], MM opts, files, TAP opts]
|
||||
, "onestar/twostar"
|
||||
, ["{/*,*}", [], {null: true}, ["/asdf/asdf/asdf"]]
|
||||
, ["{/?,*}", ["/a", "bb"], {null: true}
|
||||
, ["/a", "/b/b", "/a/b/c", "bb"]]
|
||||
|
||||
, "dots should not match unless requested"
|
||||
, ["**", ["a/b"], {}, ["a/b", "a/.d", ".a/.d"]]
|
||||
|
||||
// .. and . can only match patterns starting with .,
|
||||
// even when options.dot is set.
|
||||
, function () {
|
||||
files = ["a/./b", "a/../b", "a/c/b", "a/.d/b"]
|
||||
}
|
||||
, ["a/*/b", ["a/c/b", "a/.d/b"], {dot: true}]
|
||||
, ["a/.*/b", ["a/./b", "a/../b", "a/.d/b"], {dot: true}]
|
||||
, ["a/*/b", ["a/c/b"], {dot:false}]
|
||||
, ["a/.*/b", ["a/./b", "a/../b", "a/.d/b"], {dot: false}]
|
||||
|
||||
|
||||
// this also tests that changing the options needs
|
||||
// to change the cache key, even if the pattern is
|
||||
// the same!
|
||||
, ["**", ["a/b","a/.d",".a/.d"], { dot: true }
|
||||
, [ ".a/.d", "a/.d", "a/b"]]
|
||||
|
||||
, "paren sets cannot contain slashes"
|
||||
, ["*(a/b)", ["*(a/b)"], {nonull: true}, ["a/b"]]
|
||||
|
||||
// brace sets trump all else.
|
||||
//
|
||||
// invalid glob pattern. fails on bash4 and bsdglob.
|
||||
// however, in this implementation, it's easier just
|
||||
// to do the intuitive thing, and let brace-expansion
|
||||
// actually come before parsing any extglob patterns,
|
||||
// like the documentation seems to say.
|
||||
//
|
||||
// XXX: if anyone complains about this, either fix it
|
||||
// or tell them to grow up and stop complaining.
|
||||
//
|
||||
// bash/bsdglob says this:
|
||||
// , ["*(a|{b),c)}", ["*(a|{b),c)}"], {}, ["a", "ab", "ac", "ad"]]
|
||||
// but we do this instead:
|
||||
, ["*(a|{b),c)}", ["a", "ab", "ac"], {}, ["a", "ab", "ac", "ad"]]
|
||||
|
||||
// test partial parsing in the presence of comment/negation chars
|
||||
, ["[!a*", ["[!ab"], {}, ["[!ab", "[ab"]]
|
||||
, ["[#a*", ["[#ab"], {}, ["[#ab", "[ab"]]
|
||||
|
||||
// like: {a,b|c\\,d\\\|e} except it's unclosed, so it has to be escaped.
|
||||
, ["+(a|*\\|c\\\\|d\\\\\\|e\\\\\\\\|f\\\\\\\\\\|g"
|
||||
, ["+(a|b\\|c\\\\|d\\\\|e\\\\\\\\|f\\\\\\\\|g"]
|
||||
, {}
|
||||
, ["+(a|b\\|c\\\\|d\\\\|e\\\\\\\\|f\\\\\\\\|g", "a", "b\\c"]]
|
||||
|
||||
|
||||
// crazy nested {,,} and *(||) tests.
|
||||
, function () {
|
||||
files = [ "a", "b", "c", "d"
|
||||
, "ab", "ac", "ad"
|
||||
, "bc", "cb"
|
||||
, "bc,d", "c,db", "c,d"
|
||||
, "d)", "(b|c", "*(b|c"
|
||||
, "b|c", "b|cc", "cb|c"
|
||||
, "x(a|b|c)", "x(a|c)"
|
||||
, "(a|b|c)", "(a|c)"]
|
||||
}
|
||||
, ["*(a|{b,c})", ["a", "b", "c", "ab", "ac"]]
|
||||
, ["{a,*(b|c,d)}", ["a","(b|c", "*(b|c", "d)"]]
|
||||
// a
|
||||
// *(b|c)
|
||||
// *(b|d)
|
||||
, ["{a,*(b|{c,d})}", ["a","b", "bc", "cb", "c", "d"]]
|
||||
, ["*(a|{b|c,c})", ["a", "b", "c", "ab", "ac", "bc", "cb"]]
|
||||
|
||||
|
||||
// test various flag settings.
|
||||
, [ "*(a|{b|c,c})", ["x(a|b|c)", "x(a|c)", "(a|b|c)", "(a|c)"]
|
||||
, { noext: true } ]
|
||||
, ["a?b", ["x/y/acb", "acb/"], {matchBase: true}
|
||||
, ["x/y/acb", "acb/", "acb/d/e", "x/y/acb/d"] ]
|
||||
, ["#*", ["#a", "#b"], {nocomment: true}, ["#a", "#b", "c#d"]]
|
||||
|
||||
|
||||
// begin channelling Boole and deMorgan...
|
||||
, "negation tests"
|
||||
, function () {
|
||||
files = ["d", "e", "!ab", "!abc", "a!b", "\\!a"]
|
||||
}
|
||||
|
||||
// anything that is NOT a* matches.
|
||||
, ["!a*", ["\\!a", "d", "e", "!ab", "!abc"]]
|
||||
|
||||
// anything that IS !a* matches.
|
||||
, ["!a*", ["!ab", "!abc"], {nonegate: true}]
|
||||
|
||||
// anything that IS a* matches
|
||||
, ["!!a*", ["a!b"]]
|
||||
|
||||
// anything that is NOT !a* matches
|
||||
, ["!\\!a*", ["a!b", "d", "e", "\\!a"]]
|
||||
|
||||
// negation nestled within a pattern
|
||||
, function () {
|
||||
files = [ "foo.js"
|
||||
, "foo.bar"
|
||||
// can't match this one without negative lookbehind.
|
||||
, "foo.js.js"
|
||||
, "blar.js"
|
||||
, "foo."
|
||||
, "boo.js.boo" ]
|
||||
}
|
||||
, ["*.!(js)", ["foo.bar", "foo.", "boo.js.boo"] ]
|
||||
|
||||
// https://github.com/isaacs/minimatch/issues/5
|
||||
, function () {
|
||||
files = [ 'a/b/.x/c'
|
||||
, 'a/b/.x/c/d'
|
||||
, 'a/b/.x/c/d/e'
|
||||
, 'a/b/.x'
|
||||
, 'a/b/.x/'
|
||||
, 'a/.x/b'
|
||||
, '.x'
|
||||
, '.x/'
|
||||
, '.x/a'
|
||||
, '.x/a/b'
|
||||
, 'a/.x/b/.x/c'
|
||||
, '.x/.x' ]
|
||||
}
|
||||
, ["**/.x/**", [ '.x/'
|
||||
, '.x/a'
|
||||
, '.x/a/b'
|
||||
, 'a/.x/b'
|
||||
, 'a/b/.x/'
|
||||
, 'a/b/.x/c'
|
||||
, 'a/b/.x/c/d'
|
||||
, 'a/b/.x/c/d/e' ] ]
|
||||
|
||||
]
|
||||
|
||||
var regexps =
|
||||
[ '/^(?:(?=.)a[^/]*?)$/',
|
||||
'/^(?:(?=.)X[^/]*?)$/',
|
||||
'/^(?:(?=.)X[^/]*?)$/',
|
||||
'/^(?:\\*)$/',
|
||||
'/^(?:(?=.)\\*[^/]*?)$/',
|
||||
'/^(?:\\*\\*)$/',
|
||||
'/^(?:(?=.)b[^/]*?\\/)$/',
|
||||
'/^(?:(?=.)c[^/]*?)$/',
|
||||
'/^(?:(?:(?!(?:\\/|^)\\.).)*?)$/',
|
||||
'/^(?:\\.\\.\\/(?!\\.)(?=.)[^/]*?\\/)$/',
|
||||
'/^(?:s\\/(?=.)\\.\\.[^/]*?\\/)$/',
|
||||
'/^(?:\\/\\^root:\\/\\{s\\/(?=.)\\^[^:][^/]*?:[^:][^/]*?:\\([^:]\\)[^/]*?\\.[^/]*?\\$\\/1\\/)$/',
|
||||
'/^(?:\\/\\^root:\\/\\{s\\/(?=.)\\^[^:][^/]*?:[^:][^/]*?:\\([^:]\\)[^/]*?\\.[^/]*?\\$\\/\u0001\\/)$/',
|
||||
'/^(?:(?!\\.)(?=.)[a-c]b[^/]*?)$/',
|
||||
'/^(?:(?!\\.)(?=.)[a-y][^/]*?[^c])$/',
|
||||
'/^(?:(?=.)a[^/]*?[^c])$/',
|
||||
'/^(?:(?=.)a[X-]b)$/',
|
||||
'/^(?:(?!\\.)(?=.)[^a-c][^/]*?)$/',
|
||||
'/^(?:a\\*b\\/(?!\\.)(?=.)[^/]*?)$/',
|
||||
'/^(?:(?=.)a\\*[^/]\\/(?!\\.)(?=.)[^/]*?)$/',
|
||||
'/^(?:(?!\\.)(?=.)[^/]*?\\\\\\![^/]*?)$/',
|
||||
'/^(?:(?!\\.)(?=.)[^/]*?\\![^/]*?)$/',
|
||||
'/^(?:(?!\\.)(?=.)[^/]*?\\.\\*)$/',
|
||||
'/^(?:(?=.)a[b]c)$/',
|
||||
'/^(?:(?=.)a[b]c)$/',
|
||||
'/^(?:(?=.)a[^/]c)$/',
|
||||
'/^(?:a\\*c)$/',
|
||||
'false',
|
||||
'/^(?:(?!\\.)(?=.)[^/]*?\\/(?=.)man[^/]*?\\/(?=.)bash\\.[^/]*?)$/',
|
||||
'/^(?:man\\/man1\\/bash\\.1)$/',
|
||||
'/^(?:(?=.)a[^/]*?[^/]*?[^/]*?c)$/',
|
||||
'/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]c)$/',
|
||||
'/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/])$/',
|
||||
'/^(?:(?!\\.)(?=.)[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/])$/',
|
||||
'/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]c)$/',
|
||||
'/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?c)$/',
|
||||
'/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/])$/',
|
||||
'/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?)$/',
|
||||
'/^(?:(?!\\.)(?=.)[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?c)$/',
|
||||
'/^(?:(?!\\.)(?=.)[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/])$/',
|
||||
'/^(?:(?=.)a[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/]k)$/',
|
||||
'/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/]k)$/',
|
||||
'/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/]k[^/]*?[^/]*?[^/]*?)$/',
|
||||
'/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/][^/]*?[^/]*?[^/]*?k)$/',
|
||||
'/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/][^/]*?[^/]*?[^/]*?k[^/]*?[^/]*?)$/',
|
||||
'/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?c[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?)$/',
|
||||
'/^(?:(?!\\.)(?=.)[-abc])$/',
|
||||
'/^(?:(?!\\.)(?=.)[abc-])$/',
|
||||
'/^(?:\\\\)$/',
|
||||
'/^(?:(?!\\.)(?=.)[\\\\])$/',
|
||||
'/^(?:(?!\\.)(?=.)[\\[])$/',
|
||||
'/^(?:\\[)$/',
|
||||
'/^(?:(?=.)\\[(?!\\.)(?=.)[^/]*?)$/',
|
||||
'/^(?:(?!\\.)(?=.)[\\]])$/',
|
||||
'/^(?:(?!\\.)(?=.)[\\]-])$/',
|
||||
'/^(?:(?!\\.)(?=.)[a-z])$/',
|
||||
'/^(?:(?!\\.)(?=.)[^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/])$/',
|
||||
'/^(?:(?!\\.)(?=.)[^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?c)$/',
|
||||
'/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?c[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?)$/',
|
||||
'/^(?:(?!\\.)(?=.)[^/]*?c[^/]*?[^/][^/]*?[^/]*?)$/',
|
||||
'/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?c[^/]*?[^/][^/]*?[^/]*?)$/',
|
||||
'/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?)$/',
|
||||
'/^(?:\\[\\])$/',
|
||||
'/^(?:\\[abc)$/',
|
||||
'/^(?:(?=.)XYZ)$/i',
|
||||
'/^(?:(?=.)ab[^/]*?)$/i',
|
||||
'/^(?:(?!\\.)(?=.)[ia][^/][ck])$/i',
|
||||
'/^(?:\\/(?!\\.)(?=.)[^/]*?|(?!\\.)(?=.)[^/]*?)$/',
|
||||
'/^(?:\\/(?!\\.)(?=.)[^/]|(?!\\.)(?=.)[^/]*?)$/',
|
||||
'/^(?:(?:(?!(?:\\/|^)\\.).)*?)$/',
|
||||
'/^(?:a\\/(?!(?:^|\\/)\\.{1,2}(?:$|\\/))(?=.)[^/]*?\\/b)$/',
|
||||
'/^(?:a\\/(?=.)\\.[^/]*?\\/b)$/',
|
||||
'/^(?:a\\/(?!\\.)(?=.)[^/]*?\\/b)$/',
|
||||
'/^(?:a\\/(?=.)\\.[^/]*?\\/b)$/',
|
||||
'/^(?:(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?)$/',
|
||||
'/^(?:(?!\\.)(?=.)[^/]*?\\(a\\/b\\))$/',
|
||||
'/^(?:(?!\\.)(?=.)(?:a|b)*|(?!\\.)(?=.)(?:a|c)*)$/',
|
||||
'/^(?:(?=.)\\[(?=.)\\!a[^/]*?)$/',
|
||||
'/^(?:(?=.)\\[(?=.)#a[^/]*?)$/',
|
||||
'/^(?:(?=.)\\+\\(a\\|[^/]*?\\|c\\\\\\\\\\|d\\\\\\\\\\|e\\\\\\\\\\\\\\\\\\|f\\\\\\\\\\\\\\\\\\|g)$/',
|
||||
'/^(?:(?!\\.)(?=.)(?:a|b)*|(?!\\.)(?=.)(?:a|c)*)$/',
|
||||
'/^(?:a|(?!\\.)(?=.)[^/]*?\\(b\\|c|d\\))$/',
|
||||
'/^(?:a|(?!\\.)(?=.)(?:b|c)*|(?!\\.)(?=.)(?:b|d)*)$/',
|
||||
'/^(?:(?!\\.)(?=.)(?:a|b|c)*|(?!\\.)(?=.)(?:a|c)*)$/',
|
||||
'/^(?:(?!\\.)(?=.)[^/]*?\\(a\\|b\\|c\\)|(?!\\.)(?=.)[^/]*?\\(a\\|c\\))$/',
|
||||
'/^(?:(?=.)a[^/]b)$/',
|
||||
'/^(?:(?=.)#[^/]*?)$/',
|
||||
'/^(?!^(?:(?=.)a[^/]*?)$).*$/',
|
||||
'/^(?:(?=.)\\!a[^/]*?)$/',
|
||||
'/^(?:(?=.)a[^/]*?)$/',
|
||||
'/^(?!^(?:(?=.)\\!a[^/]*?)$).*$/',
|
||||
'/^(?:(?!\\.)(?=.)[^/]*?\\.(?:(?!js)[^/]*?))$/',
|
||||
'/^(?:(?:(?!(?:\\/|^)\\.).)*?\\/\\.x\\/(?:(?!(?:\\/|^)\\.).)*?)$/' ]
|
||||
var re = 0;
|
||||
|
||||
tap.test("basic tests", function (t) {
|
||||
var start = Date.now()
|
||||
|
||||
// [ pattern, [matches], MM opts, files, TAP opts]
|
||||
patterns.forEach(function (c) {
|
||||
if (typeof c === "function") return c()
|
||||
if (typeof c === "string") return t.comment(c)
|
||||
|
||||
var pattern = c[0]
|
||||
, expect = c[1].sort(alpha)
|
||||
, options = c[2] || {}
|
||||
, f = c[3] || files
|
||||
, tapOpts = c[4] || {}
|
||||
|
||||
// options.debug = true
|
||||
var m = new mm.Minimatch(pattern, options)
|
||||
var r = m.makeRe()
|
||||
var expectRe = regexps[re++]
|
||||
tapOpts.re = String(r) || JSON.stringify(r)
|
||||
tapOpts.files = JSON.stringify(f)
|
||||
tapOpts.pattern = pattern
|
||||
tapOpts.set = m.set
|
||||
tapOpts.negated = m.negate
|
||||
|
||||
var actual = mm.match(f, pattern, options)
|
||||
actual.sort(alpha)
|
||||
|
||||
t.equivalent( actual, expect
|
||||
, JSON.stringify(pattern) + " " + JSON.stringify(expect)
|
||||
, tapOpts )
|
||||
|
||||
t.equal(tapOpts.re, expectRe, tapOpts)
|
||||
})
|
||||
|
||||
t.comment("time=" + (Date.now() - start) + "ms")
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test("global leak test", function (t) {
|
||||
var globalAfter = Object.keys(global)
|
||||
t.equivalent(globalAfter, globalBefore, "no new globals, please")
|
||||
t.end()
|
||||
})
|
||||
|
||||
function alpha (a, b) {
|
||||
return a > b ? 1 : -1
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
var tap = require("tap")
|
||||
, minimatch = require("../")
|
||||
|
||||
tap.test("brace expansion", function (t) {
|
||||
// [ pattern, [expanded] ]
|
||||
; [ [ "a{b,c{d,e},{f,g}h}x{y,z}"
|
||||
, [ "abxy"
|
||||
, "abxz"
|
||||
, "acdxy"
|
||||
, "acdxz"
|
||||
, "acexy"
|
||||
, "acexz"
|
||||
, "afhxy"
|
||||
, "afhxz"
|
||||
, "aghxy"
|
||||
, "aghxz" ] ]
|
||||
, [ "a{1..5}b"
|
||||
, [ "a1b"
|
||||
, "a2b"
|
||||
, "a3b"
|
||||
, "a4b"
|
||||
, "a5b" ] ]
|
||||
, [ "a{b}c", ["a{b}c"] ]
|
||||
].forEach(function (tc) {
|
||||
var p = tc[0]
|
||||
, expect = tc[1]
|
||||
t.equivalent(minimatch.braceExpand(p), expect, p)
|
||||
})
|
||||
console.error("ending")
|
||||
t.end()
|
||||
})
|
||||
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
var Minimatch = require("../minimatch.js").Minimatch
|
||||
var tap = require("tap")
|
||||
tap.test("cache test", function (t) {
|
||||
var mm1 = new Minimatch("a?b")
|
||||
var mm2 = new Minimatch("a?b")
|
||||
t.equal(mm1, mm2, "should get the same object")
|
||||
// the lru should drop it after 100 entries
|
||||
for (var i = 0; i < 100; i ++) {
|
||||
new Minimatch("a"+i)
|
||||
}
|
||||
mm2 = new Minimatch("a?b")
|
||||
t.notEqual(mm1, mm2, "cache should have dropped")
|
||||
t.end()
|
||||
})
|
|
@ -1,274 +0,0 @@
|
|||
// http://www.bashcookbook.com/bashinfo/source/bash-1.14.7/tests/glob-test
|
||||
//
|
||||
// TODO: Some of these tests do very bad things with backslashes, and will
|
||||
// most likely fail badly on windows. They should probably be skipped.
|
||||
|
||||
var tap = require("tap")
|
||||
, globalBefore = Object.keys(global)
|
||||
, mm = require("../")
|
||||
, files = [ "a", "b", "c", "d", "abc"
|
||||
, "abd", "abe", "bb", "bcd"
|
||||
, "ca", "cb", "dd", "de"
|
||||
, "bdir/", "bdir/cfile"]
|
||||
, next = files.concat([ "a-b", "aXb"
|
||||
, ".x", ".y" ])
|
||||
|
||||
tap.test("basic tests", function (t) {
|
||||
var start = Date.now()
|
||||
|
||||
// [ pattern, [matches], MM opts, files, TAP opts]
|
||||
; [ "http://www.bashcookbook.com/bashinfo" +
|
||||
"/source/bash-1.14.7/tests/glob-test"
|
||||
, ["a*", ["a", "abc", "abd", "abe"]]
|
||||
, ["X*", ["X*"], {nonull: true}]
|
||||
|
||||
// allow null glob expansion
|
||||
, ["X*", []]
|
||||
|
||||
// isaacs: Slightly different than bash/sh/ksh
|
||||
// \\* is not un-escaped to literal "*" in a failed match,
|
||||
// but it does make it get treated as a literal star
|
||||
, ["\\*", ["\\*"], {nonull: true}]
|
||||
, ["\\**", ["\\**"], {nonull: true}]
|
||||
, ["\\*\\*", ["\\*\\*"], {nonull: true}]
|
||||
|
||||
, ["b*/", ["bdir/"]]
|
||||
, ["c*", ["c", "ca", "cb"]]
|
||||
, ["**", files]
|
||||
|
||||
, ["\\.\\./*/", ["\\.\\./*/"], {nonull: true}]
|
||||
, ["s/\\..*//", ["s/\\..*//"], {nonull: true}]
|
||||
|
||||
, "legendary larry crashes bashes"
|
||||
, ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\\1/"
|
||||
, ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\\1/"], {nonull: true}]
|
||||
, ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/"
|
||||
, ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/"], {nonull: true}]
|
||||
|
||||
, "character classes"
|
||||
, ["[a-c]b*", ["abc", "abd", "abe", "bb", "cb"]]
|
||||
, ["[a-y]*[^c]", ["abd", "abe", "bb", "bcd",
|
||||
"bdir/", "ca", "cb", "dd", "de"]]
|
||||
, ["a*[^c]", ["abd", "abe"]]
|
||||
, function () { files.push("a-b", "aXb") }
|
||||
, ["a[X-]b", ["a-b", "aXb"]]
|
||||
, function () { files.push(".x", ".y") }
|
||||
, ["[^a-c]*", ["d", "dd", "de"]]
|
||||
, function () { files.push("a*b/", "a*b/ooo") }
|
||||
, ["a\\*b/*", ["a*b/ooo"]]
|
||||
, ["a\\*?/*", ["a*b/ooo"]]
|
||||
, ["*\\\\!*", [], {null: true}, ["echo !7"]]
|
||||
, ["*\\!*", ["echo !7"], null, ["echo !7"]]
|
||||
, ["*.\\*", ["r.*"], null, ["r.*"]]
|
||||
, ["a[b]c", ["abc"]]
|
||||
, ["a[\\b]c", ["abc"]]
|
||||
, ["a?c", ["abc"]]
|
||||
, ["a\\*c", [], {null: true}, ["abc"]]
|
||||
, ["", [""], { null: true }, [""]]
|
||||
|
||||
, "http://www.opensource.apple.com/source/bash/bash-23/" +
|
||||
"bash/tests/glob-test"
|
||||
, function () { files.push("man/", "man/man1/", "man/man1/bash.1") }
|
||||
, ["*/man*/bash.*", ["man/man1/bash.1"]]
|
||||
, ["man/man1/bash.1", ["man/man1/bash.1"]]
|
||||
, ["a***c", ["abc"], null, ["abc"]]
|
||||
, ["a*****?c", ["abc"], null, ["abc"]]
|
||||
, ["?*****??", ["abc"], null, ["abc"]]
|
||||
, ["*****??", ["abc"], null, ["abc"]]
|
||||
, ["?*****?c", ["abc"], null, ["abc"]]
|
||||
, ["?***?****c", ["abc"], null, ["abc"]]
|
||||
, ["?***?****?", ["abc"], null, ["abc"]]
|
||||
, ["?***?****", ["abc"], null, ["abc"]]
|
||||
, ["*******c", ["abc"], null, ["abc"]]
|
||||
, ["*******?", ["abc"], null, ["abc"]]
|
||||
, ["a*cd**?**??k", ["abcdecdhjk"], null, ["abcdecdhjk"]]
|
||||
, ["a**?**cd**?**??k", ["abcdecdhjk"], null, ["abcdecdhjk"]]
|
||||
, ["a**?**cd**?**??k***", ["abcdecdhjk"], null, ["abcdecdhjk"]]
|
||||
, ["a**?**cd**?**??***k", ["abcdecdhjk"], null, ["abcdecdhjk"]]
|
||||
, ["a**?**cd**?**??***k**", ["abcdecdhjk"], null, ["abcdecdhjk"]]
|
||||
, ["a****c**?**??*****", ["abcdecdhjk"], null, ["abcdecdhjk"]]
|
||||
, ["[-abc]", ["-"], null, ["-"]]
|
||||
, ["[abc-]", ["-"], null, ["-"]]
|
||||
, ["\\", ["\\"], null, ["\\"]]
|
||||
, ["[\\\\]", ["\\"], null, ["\\"]]
|
||||
, ["[[]", ["["], null, ["["]]
|
||||
, ["[", ["["], null, ["["]]
|
||||
, ["[*", ["[abc"], null, ["[abc"]]
|
||||
, "a right bracket shall lose its special meaning and\n" +
|
||||
"represent itself in a bracket expression if it occurs\n" +
|
||||
"first in the list. -- POSIX.2 2.8.3.2"
|
||||
, ["[]]", ["]"], null, ["]"]]
|
||||
, ["[]-]", ["]"], null, ["]"]]
|
||||
, ["[a-\z]", ["p"], null, ["p"]]
|
||||
, ["??**********?****?", [], { null: true }, ["abc"]]
|
||||
, ["??**********?****c", [], { null: true }, ["abc"]]
|
||||
, ["?************c****?****", [], { null: true }, ["abc"]]
|
||||
, ["*c*?**", [], { null: true }, ["abc"]]
|
||||
, ["a*****c*?**", [], { null: true }, ["abc"]]
|
||||
, ["a********???*******", [], { null: true }, ["abc"]]
|
||||
, ["[]", [], { null: true }, ["a"]]
|
||||
, ["[abc", [], { null: true }, ["["]]
|
||||
|
||||
, "nocase tests"
|
||||
, ["XYZ", ["xYz"], { nocase: true, null: true }
|
||||
, ["xYz", "ABC", "IjK"]]
|
||||
, ["ab*", ["ABC"], { nocase: true, null: true }
|
||||
, ["xYz", "ABC", "IjK"]]
|
||||
, ["[ia]?[ck]", ["ABC", "IjK"], { nocase: true, null: true }
|
||||
, ["xYz", "ABC", "IjK"]]
|
||||
|
||||
// [ pattern, [matches], MM opts, files, TAP opts]
|
||||
, "onestar/twostar"
|
||||
, ["{/*,*}", [], {null: true}, ["/asdf/asdf/asdf"]]
|
||||
, ["{/?,*}", ["/a", "bb"], {null: true}
|
||||
, ["/a", "/b/b", "/a/b/c", "bb"]]
|
||||
|
||||
, "dots should not match unless requested"
|
||||
, ["**", ["a/b"], {}, ["a/b", "a/.d", ".a/.d"]]
|
||||
|
||||
// .. and . can only match patterns starting with .,
|
||||
// even when options.dot is set.
|
||||
, function () {
|
||||
files = ["a/./b", "a/../b", "a/c/b", "a/.d/b"]
|
||||
}
|
||||
, ["a/*/b", ["a/c/b", "a/.d/b"], {dot: true}]
|
||||
, ["a/.*/b", ["a/./b", "a/../b", "a/.d/b"], {dot: true}]
|
||||
, ["a/*/b", ["a/c/b"], {dot:false}]
|
||||
, ["a/.*/b", ["a/./b", "a/../b", "a/.d/b"], {dot: false}]
|
||||
|
||||
|
||||
// this also tests that changing the options needs
|
||||
// to change the cache key, even if the pattern is
|
||||
// the same!
|
||||
, ["**", ["a/b","a/.d",".a/.d"], { dot: true }
|
||||
, [ ".a/.d", "a/.d", "a/b"]]
|
||||
|
||||
, "paren sets cannot contain slashes"
|
||||
, ["*(a/b)", ["*(a/b)"], {nonull: true}, ["a/b"]]
|
||||
|
||||
// brace sets trump all else.
|
||||
//
|
||||
// invalid glob pattern. fails on bash4 and bsdglob.
|
||||
// however, in this implementation, it's easier just
|
||||
// to do the intuitive thing, and let brace-expansion
|
||||
// actually come before parsing any extglob patterns,
|
||||
// like the documentation seems to say.
|
||||
//
|
||||
// XXX: if anyone complains about this, either fix it
|
||||
// or tell them to grow up and stop complaining.
|
||||
//
|
||||
// bash/bsdglob says this:
|
||||
// , ["*(a|{b),c)}", ["*(a|{b),c)}"], {}, ["a", "ab", "ac", "ad"]]
|
||||
// but we do this instead:
|
||||
, ["*(a|{b),c)}", ["a", "ab", "ac"], {}, ["a", "ab", "ac", "ad"]]
|
||||
|
||||
// test partial parsing in the presence of comment/negation chars
|
||||
, ["[!a*", ["[!ab"], {}, ["[!ab", "[ab"]]
|
||||
, ["[#a*", ["[#ab"], {}, ["[#ab", "[ab"]]
|
||||
|
||||
// like: {a,b|c\\,d\\\|e} except it's unclosed, so it has to be escaped.
|
||||
, ["+(a|*\\|c\\\\|d\\\\\\|e\\\\\\\\|f\\\\\\\\\\|g"
|
||||
, ["+(a|b\\|c\\\\|d\\\\|e\\\\\\\\|f\\\\\\\\|g"]
|
||||
, {}
|
||||
, ["+(a|b\\|c\\\\|d\\\\|e\\\\\\\\|f\\\\\\\\|g", "a", "b\\c"]]
|
||||
|
||||
|
||||
// crazy nested {,,} and *(||) tests.
|
||||
, function () {
|
||||
files = [ "a", "b", "c", "d"
|
||||
, "ab", "ac", "ad"
|
||||
, "bc", "cb"
|
||||
, "bc,d", "c,db", "c,d"
|
||||
, "d)", "(b|c", "*(b|c"
|
||||
, "b|c", "b|cc", "cb|c"
|
||||
, "x(a|b|c)", "x(a|c)"
|
||||
, "(a|b|c)", "(a|c)"]
|
||||
}
|
||||
, ["*(a|{b,c})", ["a", "b", "c", "ab", "ac"]]
|
||||
, ["{a,*(b|c,d)}", ["a","(b|c", "*(b|c", "d)"]]
|
||||
// a
|
||||
// *(b|c)
|
||||
// *(b|d)
|
||||
, ["{a,*(b|{c,d})}", ["a","b", "bc", "cb", "c", "d"]]
|
||||
, ["*(a|{b|c,c})", ["a", "b", "c", "ab", "ac", "bc", "cb"]]
|
||||
|
||||
|
||||
// test various flag settings.
|
||||
, [ "*(a|{b|c,c})", ["x(a|b|c)", "x(a|c)", "(a|b|c)", "(a|c)"]
|
||||
, { noext: true } ]
|
||||
, ["a?b", ["x/y/acb", "acb/"], {matchBase: true}
|
||||
, ["x/y/acb", "acb/", "acb/d/e", "x/y/acb/d"] ]
|
||||
, ["#*", ["#a", "#b"], {nocomment: true}, ["#a", "#b", "c#d"]]
|
||||
|
||||
|
||||
// begin channelling Boole and deMorgan...
|
||||
, "negation tests"
|
||||
, function () {
|
||||
files = ["d", "e", "!ab", "!abc", "a!b", "\\!a"]
|
||||
}
|
||||
|
||||
// anything that is NOT a* matches.
|
||||
, ["!a*", ["\\!a", "d", "e", "!ab", "!abc"]]
|
||||
|
||||
// anything that IS !a* matches.
|
||||
, ["!a*", ["!ab", "!abc"], {nonegate: true}]
|
||||
|
||||
// anything that IS a* matches
|
||||
, ["!!a*", ["a!b"]]
|
||||
|
||||
// anything that is NOT !a* matches
|
||||
, ["!\\!a*", ["a!b", "d", "e", "\\!a"]]
|
||||
|
||||
// negation nestled within a pattern
|
||||
, function () {
|
||||
files = [ "foo.js"
|
||||
, "foo.bar"
|
||||
// can't match this one without negative lookbehind.
|
||||
, "foo.js.js"
|
||||
, "blar.js"
|
||||
, "foo."
|
||||
, "boo.js.boo" ]
|
||||
}
|
||||
, ["*.!(js)", ["foo.bar", "foo.", "boo.js.boo"] ]
|
||||
|
||||
].forEach(function (c) {
|
||||
if (typeof c === "function") return c()
|
||||
if (typeof c === "string") return t.comment(c)
|
||||
|
||||
var pattern = c[0]
|
||||
, expect = c[1].sort(alpha)
|
||||
, options = c[2]
|
||||
, f = c[3] || files
|
||||
, tapOpts = c[4] || {}
|
||||
|
||||
// options.debug = true
|
||||
var Class = mm.defaults(options).Minimatch
|
||||
var m = new Class(pattern, {})
|
||||
var r = m.makeRe()
|
||||
tapOpts.re = String(r) || JSON.stringify(r)
|
||||
tapOpts.files = JSON.stringify(f)
|
||||
tapOpts.pattern = pattern
|
||||
tapOpts.set = m.set
|
||||
tapOpts.negated = m.negate
|
||||
|
||||
var actual = mm.match(f, pattern, options)
|
||||
actual.sort(alpha)
|
||||
|
||||
t.equivalent( actual, expect
|
||||
, JSON.stringify(pattern) + " " + JSON.stringify(expect)
|
||||
, tapOpts )
|
||||
})
|
||||
|
||||
t.comment("time=" + (Date.now() - start) + "ms")
|
||||
t.end()
|
||||
})
|
||||
|
||||
tap.test("global leak test", function (t) {
|
||||
var globalAfter = Object.keys(global)
|
||||
t.equivalent(globalAfter, globalBefore, "no new globals, please")
|
||||
t.end()
|
||||
})
|
||||
|
||||
function alpha (a, b) {
|
||||
return a > b ? 1 : -1
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
var test = require('tap').test
|
||||
var minimatch = require('../')
|
||||
|
||||
test('extglob ending with statechar', function(t) {
|
||||
t.notOk(minimatch('ax', 'a?(b*)'))
|
||||
t.ok(minimatch('ax', '?(a*|b)'))
|
||||
t.end()
|
||||
})
|
|
@ -1,58 +0,0 @@
|
|||
{
|
||||
"author": {
|
||||
"name": "Isaac Z. Schlueter",
|
||||
"email": "i@izs.me",
|
||||
"url": "http://blog.izs.me/"
|
||||
},
|
||||
"name": "glob",
|
||||
"description": "a little globber",
|
||||
"version": "3.2.11",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/isaacs/node-glob.git"
|
||||
},
|
||||
"main": "glob.js",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"dependencies": {
|
||||
"inherits": "2",
|
||||
"minimatch": "0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tap": "~0.4.0",
|
||||
"mkdirp": "0",
|
||||
"rimraf": "1"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "tap test/*.js",
|
||||
"test-regen": "TEST_REGEN=1 node test/00-setup.js"
|
||||
},
|
||||
"license": "BSD",
|
||||
"gitHead": "73f57e99510582b2024b762305970ebcf9b70aa2",
|
||||
"bugs": {
|
||||
"url": "https://github.com/isaacs/node-glob/issues"
|
||||
},
|
||||
"homepage": "https://github.com/isaacs/node-glob",
|
||||
"_id": "glob@3.2.11",
|
||||
"_shasum": "4a973f635b9190f715d10987d5c00fd2815ebe3d",
|
||||
"_from": "glob@~3.2.9",
|
||||
"_npmVersion": "1.4.10",
|
||||
"_npmUser": {
|
||||
"name": "isaacs",
|
||||
"email": "i@izs.me"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "isaacs",
|
||||
"email": "i@izs.me"
|
||||
}
|
||||
],
|
||||
"dist": {
|
||||
"shasum": "4a973f635b9190f715d10987d5c00fd2815ebe3d",
|
||||
"tarball": "http://registry.npmjs.org/glob/-/glob-3.2.11.tgz"
|
||||
},
|
||||
"directories": {},
|
||||
"_resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz",
|
||||
"readme": "ERROR: No README data found!"
|
||||
}
|
|
@ -1,176 +0,0 @@
|
|||
// just a little pre-run script to set up the fixtures.
|
||||
// zz-finish cleans it up
|
||||
|
||||
var mkdirp = require("mkdirp")
|
||||
var path = require("path")
|
||||
var i = 0
|
||||
var tap = require("tap")
|
||||
var fs = require("fs")
|
||||
var rimraf = require("rimraf")
|
||||
|
||||
var files =
|
||||
[ "a/.abcdef/x/y/z/a"
|
||||
, "a/abcdef/g/h"
|
||||
, "a/abcfed/g/h"
|
||||
, "a/b/c/d"
|
||||
, "a/bc/e/f"
|
||||
, "a/c/d/c/b"
|
||||
, "a/cb/e/f"
|
||||
]
|
||||
|
||||
var symlinkTo = path.resolve(__dirname, "a/symlink/a/b/c")
|
||||
var symlinkFrom = "../.."
|
||||
|
||||
files = files.map(function (f) {
|
||||
return path.resolve(__dirname, f)
|
||||
})
|
||||
|
||||
tap.test("remove fixtures", function (t) {
|
||||
rimraf(path.resolve(__dirname, "a"), function (er) {
|
||||
t.ifError(er, "remove fixtures")
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
files.forEach(function (f) {
|
||||
tap.test(f, function (t) {
|
||||
var d = path.dirname(f)
|
||||
mkdirp(d, 0755, function (er) {
|
||||
if (er) {
|
||||
t.fail(er)
|
||||
return t.bailout()
|
||||
}
|
||||
fs.writeFile(f, "i like tests", function (er) {
|
||||
t.ifError(er, "make file")
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
if (process.platform !== "win32") {
|
||||
tap.test("symlinky", function (t) {
|
||||
var d = path.dirname(symlinkTo)
|
||||
console.error("mkdirp", d)
|
||||
mkdirp(d, 0755, function (er) {
|
||||
t.ifError(er)
|
||||
fs.symlink(symlinkFrom, symlinkTo, "dir", function (er) {
|
||||
t.ifError(er, "make symlink")
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
;["foo","bar","baz","asdf","quux","qwer","rewq"].forEach(function (w) {
|
||||
w = "/tmp/glob-test/" + w
|
||||
tap.test("create " + w, function (t) {
|
||||
mkdirp(w, function (er) {
|
||||
if (er)
|
||||
throw er
|
||||
t.pass(w)
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
// generate the bash pattern test-fixtures if possible
|
||||
if (process.platform === "win32" || !process.env.TEST_REGEN) {
|
||||
console.error("Windows, or TEST_REGEN unset. Using cached fixtures.")
|
||||
return
|
||||
}
|
||||
|
||||
var spawn = require("child_process").spawn;
|
||||
var globs =
|
||||
// put more patterns here.
|
||||
// anything that would be directly in / should be in /tmp/glob-test
|
||||
["test/a/*/+(c|g)/./d"
|
||||
,"test/a/**/[cg]/../[cg]"
|
||||
,"test/a/{b,c,d,e,f}/**/g"
|
||||
,"test/a/b/**"
|
||||
,"test/**/g"
|
||||
,"test/a/abc{fed,def}/g/h"
|
||||
,"test/a/abc{fed/g,def}/**/"
|
||||
,"test/a/abc{fed/g,def}/**///**/"
|
||||
,"test/**/a/**/"
|
||||
,"test/+(a|b|c)/a{/,bc*}/**"
|
||||
,"test/*/*/*/f"
|
||||
,"test/**/f"
|
||||
,"test/a/symlink/a/b/c/a/b/c/a/b/c//a/b/c////a/b/c/**/b/c/**"
|
||||
,"{./*/*,/tmp/glob-test/*}"
|
||||
,"{/tmp/glob-test/*,*}" // evil owl face! how you taunt me!
|
||||
,"test/a/!(symlink)/**"
|
||||
]
|
||||
var bashOutput = {}
|
||||
var fs = require("fs")
|
||||
|
||||
globs.forEach(function (pattern) {
|
||||
tap.test("generate fixture " + pattern, function (t) {
|
||||
var cmd = "shopt -s globstar && " +
|
||||
"shopt -s extglob && " +
|
||||
"shopt -s nullglob && " +
|
||||
// "shopt >&2; " +
|
||||
"eval \'for i in " + pattern + "; do echo $i; done\'"
|
||||
var cp = spawn("bash", ["-c", cmd], { cwd: path.dirname(__dirname) })
|
||||
var out = []
|
||||
cp.stdout.on("data", function (c) {
|
||||
out.push(c)
|
||||
})
|
||||
cp.stderr.pipe(process.stderr)
|
||||
cp.on("close", function (code) {
|
||||
out = flatten(out)
|
||||
if (!out)
|
||||
out = []
|
||||
else
|
||||
out = cleanResults(out.split(/\r*\n/))
|
||||
|
||||
bashOutput[pattern] = out
|
||||
t.notOk(code, "bash test should finish nicely")
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
tap.test("save fixtures", function (t) {
|
||||
var fname = path.resolve(__dirname, "bash-results.json")
|
||||
var data = JSON.stringify(bashOutput, null, 2) + "\n"
|
||||
fs.writeFile(fname, data, function (er) {
|
||||
t.ifError(er)
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
function cleanResults (m) {
|
||||
// normalize discrepancies in ordering, duplication,
|
||||
// and ending slashes.
|
||||
return m.map(function (m) {
|
||||
return m.replace(/\/+/g, "/").replace(/\/$/, "")
|
||||
}).sort(alphasort).reduce(function (set, f) {
|
||||
if (f !== set[set.length - 1]) set.push(f)
|
||||
return set
|
||||
}, []).sort(alphasort).map(function (f) {
|
||||
// de-windows
|
||||
return (process.platform !== 'win32') ? f
|
||||
: f.replace(/^[a-zA-Z]:\\\\/, '/').replace(/\\/g, '/')
|
||||
})
|
||||
}
|
||||
|
||||
function flatten (chunks) {
|
||||
var s = 0
|
||||
chunks.forEach(function (c) { s += c.length })
|
||||
var out = new Buffer(s)
|
||||
s = 0
|
||||
chunks.forEach(function (c) {
|
||||
c.copy(out, s)
|
||||
s += c.length
|
||||
})
|
||||
|
||||
return out.toString().trim()
|
||||
}
|
||||
|
||||
function alphasort (a, b) {
|
||||
a = a.toLowerCase()
|
||||
b = b.toLowerCase()
|
||||
return a > b ? 1 : a < b ? -1 : 0
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
// basic test
|
||||
// show that it does the same thing by default as the shell.
|
||||
var tap = require("tap")
|
||||
, child_process = require("child_process")
|
||||
, bashResults = require("./bash-results.json")
|
||||
, globs = Object.keys(bashResults)
|
||||
, glob = require("../")
|
||||
, path = require("path")
|
||||
|
||||
// run from the root of the project
|
||||
// this is usually where you're at anyway, but be sure.
|
||||
process.chdir(path.resolve(__dirname, ".."))
|
||||
|
||||
function alphasort (a, b) {
|
||||
a = a.toLowerCase()
|
||||
b = b.toLowerCase()
|
||||
return a > b ? 1 : a < b ? -1 : 0
|
||||
}
|
||||
|
||||
globs.forEach(function (pattern) {
|
||||
var expect = bashResults[pattern]
|
||||
// anything regarding the symlink thing will fail on windows, so just skip it
|
||||
if (process.platform === "win32" &&
|
||||
expect.some(function (m) {
|
||||
return /\/symlink\//.test(m)
|
||||
}))
|
||||
return
|
||||
|
||||
tap.test(pattern, function (t) {
|
||||
glob(pattern, function (er, matches) {
|
||||
if (er)
|
||||
throw er
|
||||
|
||||
// sort and unmark, just to match the shell results
|
||||
matches = cleanResults(matches)
|
||||
|
||||
t.deepEqual(matches, expect, pattern)
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
tap.test(pattern + " sync", function (t) {
|
||||
var matches = cleanResults(glob.sync(pattern))
|
||||
|
||||
t.deepEqual(matches, expect, "should match shell")
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
function cleanResults (m) {
|
||||
// normalize discrepancies in ordering, duplication,
|
||||
// and ending slashes.
|
||||
return m.map(function (m) {
|
||||
return m.replace(/\/+/g, "/").replace(/\/$/, "")
|
||||
}).sort(alphasort).reduce(function (set, f) {
|
||||
if (f !== set[set.length - 1]) set.push(f)
|
||||
return set
|
||||
}, []).sort(alphasort).map(function (f) {
|
||||
// de-windows
|
||||
return (process.platform !== 'win32') ? f
|
||||
: f.replace(/^[a-zA-Z]:[\/\\]+/, '/').replace(/[\\\/]+/g, '/')
|
||||
})
|
||||
}
|
|
@ -1,351 +0,0 @@
|
|||
{
|
||||
"test/a/*/+(c|g)/./d": [
|
||||
"test/a/b/c/./d"
|
||||
],
|
||||
"test/a/**/[cg]/../[cg]": [
|
||||
"test/a/abcdef/g/../g",
|
||||
"test/a/abcfed/g/../g",
|
||||
"test/a/b/c/../c",
|
||||
"test/a/c/../c",
|
||||
"test/a/c/d/c/../c",
|
||||
"test/a/symlink/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c"
|
||||
],
|
||||
"test/a/{b,c,d,e,f}/**/g": [],
|
||||
"test/a/b/**": [
|
||||
"test/a/b",
|
||||
"test/a/b/c",
|
||||
"test/a/b/c/d"
|
||||
],
|
||||
"test/**/g": [
|
||||
"test/a/abcdef/g",
|
||||
"test/a/abcfed/g"
|
||||
],
|
||||
"test/a/abc{fed,def}/g/h": [
|
||||
"test/a/abcdef/g/h",
|
||||
"test/a/abcfed/g/h"
|
||||
],
|
||||
"test/a/abc{fed/g,def}/**/": [
|
||||
"test/a/abcdef",
|
||||
"test/a/abcdef/g",
|
||||
"test/a/abcfed/g"
|
||||
],
|
||||
"test/a/abc{fed/g,def}/**///**/": [
|
||||
"test/a/abcdef",
|
||||
"test/a/abcdef/g",
|
||||
"test/a/abcfed/g"
|
||||
],
|
||||
"test/**/a/**/": [
|
||||
"test/a",
|
||||
"test/a/abcdef",
|
||||
"test/a/abcdef/g",
|
||||
"test/a/abcfed",
|
||||
"test/a/abcfed/g",
|
||||
"test/a/b",
|
||||
"test/a/b/c",
|
||||
"test/a/bc",
|
||||
"test/a/bc/e",
|
||||
"test/a/c",
|
||||
"test/a/c/d",
|
||||
"test/a/c/d/c",
|
||||
"test/a/cb",
|
||||
"test/a/cb/e",
|
||||
"test/a/symlink",
|
||||
"test/a/symlink/a",
|
||||
"test/a/symlink/a/b",
|
||||
"test/a/symlink/a/b/c",
|
||||
"test/a/symlink/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b"
|
||||
],
|
||||
"test/+(a|b|c)/a{/,bc*}/**": [
|
||||
"test/a/abcdef",
|
||||
"test/a/abcdef/g",
|
||||
"test/a/abcdef/g/h",
|
||||
"test/a/abcfed",
|
||||
"test/a/abcfed/g",
|
||||
"test/a/abcfed/g/h"
|
||||
],
|
||||
"test/*/*/*/f": [
|
||||
"test/a/bc/e/f",
|
||||
"test/a/cb/e/f"
|
||||
],
|
||||
"test/**/f": [
|
||||
"test/a/bc/e/f",
|
||||
"test/a/cb/e/f"
|
||||
],
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c//a/b/c////a/b/c/**/b/c/**": [
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b",
|
||||
"test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c"
|
||||
],
|
||||
"{./*/*,/tmp/glob-test/*}": [
|
||||
"./examples/g.js",
|
||||
"./examples/usr-local.js",
|
||||
"./node_modules/inherits",
|
||||
"./node_modules/minimatch",
|
||||
"./node_modules/mkdirp",
|
||||
"./node_modules/rimraf",
|
||||
"./node_modules/tap",
|
||||
"./test/00-setup.js",
|
||||
"./test/a",
|
||||
"./test/bash-comparison.js",
|
||||
"./test/bash-results.json",
|
||||
"./test/cwd-test.js",
|
||||
"./test/globstar-match.js",
|
||||
"./test/mark.js",
|
||||
"./test/new-glob-optional-options.js",
|
||||
"./test/nocase-nomagic.js",
|
||||
"./test/pause-resume.js",
|
||||
"./test/readme-issue.js",
|
||||
"./test/root-nomount.js",
|
||||
"./test/root.js",
|
||||
"./test/stat.js",
|
||||
"./test/zz-cleanup.js",
|
||||
"/tmp/glob-test/asdf",
|
||||
"/tmp/glob-test/bar",
|
||||
"/tmp/glob-test/baz",
|
||||
"/tmp/glob-test/foo",
|
||||
"/tmp/glob-test/quux",
|
||||
"/tmp/glob-test/qwer",
|
||||
"/tmp/glob-test/rewq"
|
||||
],
|
||||
"{/tmp/glob-test/*,*}": [
|
||||
"/tmp/glob-test/asdf",
|
||||
"/tmp/glob-test/bar",
|
||||
"/tmp/glob-test/baz",
|
||||
"/tmp/glob-test/foo",
|
||||
"/tmp/glob-test/quux",
|
||||
"/tmp/glob-test/qwer",
|
||||
"/tmp/glob-test/rewq",
|
||||
"examples",
|
||||
"glob.js",
|
||||
"LICENSE",
|
||||
"node_modules",
|
||||
"package.json",
|
||||
"README.md",
|
||||
"test"
|
||||
],
|
||||
"test/a/!(symlink)/**": [
|
||||
"test/a/abcdef",
|
||||
"test/a/abcdef/g",
|
||||
"test/a/abcdef/g/h",
|
||||
"test/a/abcfed",
|
||||
"test/a/abcfed/g",
|
||||
"test/a/abcfed/g/h",
|
||||
"test/a/b",
|
||||
"test/a/b/c",
|
||||
"test/a/b/c/d",
|
||||
"test/a/bc",
|
||||
"test/a/bc/e",
|
||||
"test/a/bc/e/f",
|
||||
"test/a/c",
|
||||
"test/a/c/d",
|
||||
"test/a/c/d/c",
|
||||
"test/a/c/d/c/b",
|
||||
"test/a/cb",
|
||||
"test/a/cb/e",
|
||||
"test/a/cb/e/f"
|
||||
]
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
var tap = require("tap")
|
||||
|
||||
var origCwd = process.cwd()
|
||||
process.chdir(__dirname)
|
||||
|
||||
tap.test("changing cwd and searching for **/d", function (t) {
|
||||
var glob = require('../')
|
||||
var path = require('path')
|
||||
t.test('.', function (t) {
|
||||
glob('**/d', function (er, matches) {
|
||||
t.ifError(er)
|
||||
t.like(matches, [ 'a/b/c/d', 'a/c/d' ])
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
t.test('a', function (t) {
|
||||
glob('**/d', {cwd:path.resolve('a')}, function (er, matches) {
|
||||
t.ifError(er)
|
||||
t.like(matches, [ 'b/c/d', 'c/d' ])
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
t.test('a/b', function (t) {
|
||||
glob('**/d', {cwd:path.resolve('a/b')}, function (er, matches) {
|
||||
t.ifError(er)
|
||||
t.like(matches, [ 'c/d' ])
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
t.test('a/b/', function (t) {
|
||||
glob('**/d', {cwd:path.resolve('a/b/')}, function (er, matches) {
|
||||
t.ifError(er)
|
||||
t.like(matches, [ 'c/d' ])
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
t.test('.', function (t) {
|
||||
glob('**/d', {cwd: process.cwd()}, function (er, matches) {
|
||||
t.ifError(er)
|
||||
t.like(matches, [ 'a/b/c/d', 'a/c/d' ])
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
t.test('cd -', function (t) {
|
||||
process.chdir(origCwd)
|
||||
t.end()
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
|
@ -1,19 +0,0 @@
|
|||
var Glob = require("../glob.js").Glob
|
||||
var test = require('tap').test
|
||||
|
||||
test('globstar should not have dupe matches', function(t) {
|
||||
var pattern = 'a/**/[gh]'
|
||||
var g = new Glob(pattern, { cwd: __dirname })
|
||||
var matches = []
|
||||
g.on('match', function(m) {
|
||||
console.error('match %j', m)
|
||||
matches.push(m)
|
||||
})
|
||||
g.on('end', function(set) {
|
||||
console.error('set', set)
|
||||
matches = matches.sort()
|
||||
set = set.sort()
|
||||
t.same(matches, set, 'should have same set of matches')
|
||||
t.end()
|
||||
})
|
||||
})
|
|
@ -1,118 +0,0 @@
|
|||
var test = require("tap").test
|
||||
var glob = require('../')
|
||||
process.chdir(__dirname)
|
||||
|
||||
// expose timing issues
|
||||
var lag = 5
|
||||
glob.Glob.prototype._stat = function(o) { return function(f, cb) {
|
||||
var args = arguments
|
||||
setTimeout(function() {
|
||||
o.call(this, f, cb)
|
||||
}.bind(this), lag += 5)
|
||||
}}(glob.Glob.prototype._stat)
|
||||
|
||||
|
||||
test("mark, with **", function (t) {
|
||||
glob("a/*b*/**", {mark: true}, function (er, results) {
|
||||
if (er)
|
||||
throw er
|
||||
var expect =
|
||||
[ 'a/abcdef/',
|
||||
'a/abcdef/g/',
|
||||
'a/abcdef/g/h',
|
||||
'a/abcfed/',
|
||||
'a/abcfed/g/',
|
||||
'a/abcfed/g/h',
|
||||
'a/b/',
|
||||
'a/b/c/',
|
||||
'a/b/c/d',
|
||||
'a/bc/',
|
||||
'a/bc/e/',
|
||||
'a/bc/e/f',
|
||||
'a/cb/',
|
||||
'a/cb/e/',
|
||||
'a/cb/e/f' ]
|
||||
|
||||
t.same(results, expect)
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
test("mark, no / on pattern", function (t) {
|
||||
glob("a/*", {mark: true}, function (er, results) {
|
||||
if (er)
|
||||
throw er
|
||||
var expect = [ 'a/abcdef/',
|
||||
'a/abcfed/',
|
||||
'a/b/',
|
||||
'a/bc/',
|
||||
'a/c/',
|
||||
'a/cb/' ]
|
||||
|
||||
if (process.platform !== "win32")
|
||||
expect.push('a/symlink/')
|
||||
|
||||
t.same(results, expect)
|
||||
t.end()
|
||||
}).on('match', function(m) {
|
||||
t.similar(m, /\/$/)
|
||||
})
|
||||
})
|
||||
|
||||
test("mark=false, no / on pattern", function (t) {
|
||||
glob("a/*", function (er, results) {
|
||||
if (er)
|
||||
throw er
|
||||
var expect = [ 'a/abcdef',
|
||||
'a/abcfed',
|
||||
'a/b',
|
||||
'a/bc',
|
||||
'a/c',
|
||||
'a/cb' ]
|
||||
|
||||
if (process.platform !== "win32")
|
||||
expect.push('a/symlink')
|
||||
t.same(results, expect)
|
||||
t.end()
|
||||
}).on('match', function(m) {
|
||||
t.similar(m, /[^\/]$/)
|
||||
})
|
||||
})
|
||||
|
||||
test("mark=true, / on pattern", function (t) {
|
||||
glob("a/*/", {mark: true}, function (er, results) {
|
||||
if (er)
|
||||
throw er
|
||||
var expect = [ 'a/abcdef/',
|
||||
'a/abcfed/',
|
||||
'a/b/',
|
||||
'a/bc/',
|
||||
'a/c/',
|
||||
'a/cb/' ]
|
||||
if (process.platform !== "win32")
|
||||
expect.push('a/symlink/')
|
||||
t.same(results, expect)
|
||||
t.end()
|
||||
}).on('match', function(m) {
|
||||
t.similar(m, /\/$/)
|
||||
})
|
||||
})
|
||||
|
||||
test("mark=false, / on pattern", function (t) {
|
||||
glob("a/*/", function (er, results) {
|
||||
if (er)
|
||||
throw er
|
||||
var expect = [ 'a/abcdef/',
|
||||
'a/abcfed/',
|
||||
'a/b/',
|
||||
'a/bc/',
|
||||
'a/c/',
|
||||
'a/cb/' ]
|
||||
if (process.platform !== "win32")
|
||||
expect.push('a/symlink/')
|
||||
t.same(results, expect)
|
||||
t.end()
|
||||
}).on('match', function(m) {
|
||||
t.similar(m, /\/$/)
|
||||
})
|
||||
})
|
|
@ -1,10 +0,0 @@
|
|||
var Glob = require('../glob.js').Glob;
|
||||
var test = require('tap').test;
|
||||
|
||||
test('new glob, with cb, and no options', function (t) {
|
||||
new Glob(__filename, function(er, results) {
|
||||
if (er) throw er;
|
||||
t.same(results, [__filename]);
|
||||
t.end();
|
||||
});
|
||||
});
|
|
@ -1,113 +0,0 @@
|
|||
var fs = require('fs');
|
||||
var test = require('tap').test;
|
||||
var glob = require('../');
|
||||
|
||||
test('mock fs', function(t) {
|
||||
var stat = fs.stat
|
||||
var statSync = fs.statSync
|
||||
var readdir = fs.readdir
|
||||
var readdirSync = fs.readdirSync
|
||||
|
||||
function fakeStat(path) {
|
||||
var ret
|
||||
switch (path.toLowerCase()) {
|
||||
case '/tmp': case '/tmp/':
|
||||
ret = { isDirectory: function() { return true } }
|
||||
break
|
||||
case '/tmp/a':
|
||||
ret = { isDirectory: function() { return false } }
|
||||
break
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
fs.stat = function(path, cb) {
|
||||
var f = fakeStat(path);
|
||||
if (f) {
|
||||
process.nextTick(function() {
|
||||
cb(null, f)
|
||||
})
|
||||
} else {
|
||||
stat.call(fs, path, cb)
|
||||
}
|
||||
}
|
||||
|
||||
fs.statSync = function(path) {
|
||||
return fakeStat(path) || statSync.call(fs, path)
|
||||
}
|
||||
|
||||
function fakeReaddir(path) {
|
||||
var ret
|
||||
switch (path.toLowerCase()) {
|
||||
case '/tmp': case '/tmp/':
|
||||
ret = [ 'a', 'A' ]
|
||||
break
|
||||
case '/':
|
||||
ret = ['tmp', 'tMp', 'tMP', 'TMP']
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
fs.readdir = function(path, cb) {
|
||||
var f = fakeReaddir(path)
|
||||
if (f)
|
||||
process.nextTick(function() {
|
||||
cb(null, f)
|
||||
})
|
||||
else
|
||||
readdir.call(fs, path, cb)
|
||||
}
|
||||
|
||||
fs.readdirSync = function(path) {
|
||||
return fakeReaddir(path) || readdirSync.call(fs, path)
|
||||
}
|
||||
|
||||
t.pass('mocked')
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('nocase, nomagic', function(t) {
|
||||
var n = 2
|
||||
var want = [ '/TMP/A',
|
||||
'/TMP/a',
|
||||
'/tMP/A',
|
||||
'/tMP/a',
|
||||
'/tMp/A',
|
||||
'/tMp/a',
|
||||
'/tmp/A',
|
||||
'/tmp/a' ]
|
||||
glob('/tmp/a', { nocase: true }, function(er, res) {
|
||||
if (er)
|
||||
throw er
|
||||
t.same(res.sort(), want)
|
||||
if (--n === 0) t.end()
|
||||
})
|
||||
glob('/tmp/A', { nocase: true }, function(er, res) {
|
||||
if (er)
|
||||
throw er
|
||||
t.same(res.sort(), want)
|
||||
if (--n === 0) t.end()
|
||||
})
|
||||
})
|
||||
|
||||
test('nocase, with some magic', function(t) {
|
||||
t.plan(2)
|
||||
var want = [ '/TMP/A',
|
||||
'/TMP/a',
|
||||
'/tMP/A',
|
||||
'/tMP/a',
|
||||
'/tMp/A',
|
||||
'/tMp/a',
|
||||
'/tmp/A',
|
||||
'/tmp/a' ]
|
||||
glob('/tmp/*', { nocase: true }, function(er, res) {
|
||||
if (er)
|
||||
throw er
|
||||
t.same(res.sort(), want)
|
||||
})
|
||||
glob('/tmp/*', { nocase: true }, function(er, res) {
|
||||
if (er)
|
||||
throw er
|
||||
t.same(res.sort(), want)
|
||||
})
|
||||
})
|
|
@ -1,73 +0,0 @@
|
|||
// show that no match events happen while paused.
|
||||
var tap = require("tap")
|
||||
, child_process = require("child_process")
|
||||
// just some gnarly pattern with lots of matches
|
||||
, pattern = "test/a/!(symlink)/**"
|
||||
, bashResults = require("./bash-results.json")
|
||||
, patterns = Object.keys(bashResults)
|
||||
, glob = require("../")
|
||||
, Glob = glob.Glob
|
||||
, path = require("path")
|
||||
|
||||
// run from the root of the project
|
||||
// this is usually where you're at anyway, but be sure.
|
||||
process.chdir(path.resolve(__dirname, ".."))
|
||||
|
||||
function alphasort (a, b) {
|
||||
a = a.toLowerCase()
|
||||
b = b.toLowerCase()
|
||||
return a > b ? 1 : a < b ? -1 : 0
|
||||
}
|
||||
|
||||
function cleanResults (m) {
|
||||
// normalize discrepancies in ordering, duplication,
|
||||
// and ending slashes.
|
||||
return m.map(function (m) {
|
||||
return m.replace(/\/+/g, "/").replace(/\/$/, "")
|
||||
}).sort(alphasort).reduce(function (set, f) {
|
||||
if (f !== set[set.length - 1]) set.push(f)
|
||||
return set
|
||||
}, []).sort(alphasort).map(function (f) {
|
||||
// de-windows
|
||||
return (process.platform !== 'win32') ? f
|
||||
: f.replace(/^[a-zA-Z]:\\\\/, '/').replace(/\\/g, '/')
|
||||
})
|
||||
}
|
||||
|
||||
var globResults = []
|
||||
tap.test("use a Glob object, and pause/resume it", function (t) {
|
||||
var g = new Glob(pattern)
|
||||
, paused = false
|
||||
, res = []
|
||||
, expect = bashResults[pattern]
|
||||
|
||||
g.on("pause", function () {
|
||||
console.error("pause")
|
||||
})
|
||||
|
||||
g.on("resume", function () {
|
||||
console.error("resume")
|
||||
})
|
||||
|
||||
g.on("match", function (m) {
|
||||
t.notOk(g.paused, "must not be paused")
|
||||
globResults.push(m)
|
||||
g.pause()
|
||||
t.ok(g.paused, "must be paused")
|
||||
setTimeout(g.resume.bind(g), 10)
|
||||
})
|
||||
|
||||
g.on("end", function (matches) {
|
||||
t.pass("reached glob end")
|
||||
globResults = cleanResults(globResults)
|
||||
matches = cleanResults(matches)
|
||||
t.deepEqual(matches, globResults,
|
||||
"end event matches should be the same as match events")
|
||||
|
||||
t.deepEqual(matches, expect,
|
||||
"glob matches should be the same as bash results")
|
||||
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
var test = require("tap").test
|
||||
var glob = require("../")
|
||||
|
||||
var mkdirp = require("mkdirp")
|
||||
var fs = require("fs")
|
||||
var rimraf = require("rimraf")
|
||||
var dir = __dirname + "/package"
|
||||
|
||||
test("setup", function (t) {
|
||||
mkdirp.sync(dir)
|
||||
fs.writeFileSync(dir + "/package.json", "{}", "ascii")
|
||||
fs.writeFileSync(dir + "/README", "x", "ascii")
|
||||
t.pass("setup done")
|
||||
t.end()
|
||||
})
|
||||
|
||||
test("glob", function (t) {
|
||||
var opt = {
|
||||
cwd: dir,
|
||||
nocase: true,
|
||||
mark: true
|
||||
}
|
||||
|
||||
glob("README?(.*)", opt, function (er, files) {
|
||||
if (er)
|
||||
throw er
|
||||
t.same(files, ["README"])
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
test("cleanup", function (t) {
|
||||
rimraf.sync(dir)
|
||||
t.pass("clean")
|
||||
t.end()
|
||||
})
|
|
@ -1,39 +0,0 @@
|
|||
var tap = require("tap")
|
||||
|
||||
var origCwd = process.cwd()
|
||||
process.chdir(__dirname)
|
||||
|
||||
tap.test("changing root and searching for /b*/**", function (t) {
|
||||
var glob = require('../')
|
||||
var path = require('path')
|
||||
t.test('.', function (t) {
|
||||
glob('/b*/**', { globDebug: true, root: '.', nomount: true }, function (er, matches) {
|
||||
t.ifError(er)
|
||||
t.like(matches, [])
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
t.test('a', function (t) {
|
||||
glob('/b*/**', { globDebug: true, root: path.resolve('a'), nomount: true }, function (er, matches) {
|
||||
t.ifError(er)
|
||||
t.like(matches, [ '/b', '/b/c', '/b/c/d', '/bc', '/bc/e', '/bc/e/f' ])
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
t.test('root=a, cwd=a/b', function (t) {
|
||||
glob('/b*/**', { globDebug: true, root: 'a', cwd: path.resolve('a/b'), nomount: true }, function (er, matches) {
|
||||
t.ifError(er)
|
||||
t.like(matches, [ '/b', '/b/c', '/b/c/d', '/bc', '/bc/e', '/bc/e/f' ])
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
t.test('cd -', function (t) {
|
||||
process.chdir(origCwd)
|
||||
t.end()
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
|
@ -1,46 +0,0 @@
|
|||
var t = require("tap")
|
||||
|
||||
var origCwd = process.cwd()
|
||||
process.chdir(__dirname)
|
||||
|
||||
var glob = require('../')
|
||||
var path = require('path')
|
||||
|
||||
t.test('.', function (t) {
|
||||
glob('/b*/**', { globDebug: true, root: '.' }, function (er, matches) {
|
||||
t.ifError(er)
|
||||
t.like(matches, [])
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
t.test('a', function (t) {
|
||||
console.error("root=" + path.resolve('a'))
|
||||
glob('/b*/**', { globDebug: true, root: path.resolve('a') }, function (er, matches) {
|
||||
t.ifError(er)
|
||||
var wanted = [
|
||||
'/b', '/b/c', '/b/c/d', '/bc', '/bc/e', '/bc/e/f'
|
||||
].map(function (m) {
|
||||
return path.join(path.resolve('a'), m).replace(/\\/g, '/')
|
||||
})
|
||||
|
||||
t.like(matches, wanted)
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
t.test('root=a, cwd=a/b', function (t) {
|
||||
glob('/b*/**', { globDebug: true, root: 'a', cwd: path.resolve('a/b') }, function (er, matches) {
|
||||
t.ifError(er)
|
||||
t.like(matches, [ '/b', '/b/c', '/b/c/d', '/bc', '/bc/e', '/bc/e/f' ].map(function (m) {
|
||||
return path.join(path.resolve('a'), m).replace(/\\/g, '/')
|
||||
}))
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
t.test('cd -', function (t) {
|
||||
process.chdir(origCwd)
|
||||
t.end()
|
||||
})
|
|
@ -1,32 +0,0 @@
|
|||
var glob = require('../')
|
||||
var test = require('tap').test
|
||||
var path = require('path')
|
||||
|
||||
test('stat all the things', function(t) {
|
||||
var g = new glob.Glob('a/*abc*/**', { stat: true, cwd: __dirname })
|
||||
var matches = []
|
||||
g.on('match', function(m) {
|
||||
matches.push(m)
|
||||
})
|
||||
var stats = []
|
||||
g.on('stat', function(m) {
|
||||
stats.push(m)
|
||||
})
|
||||
g.on('end', function(eof) {
|
||||
stats = stats.sort()
|
||||
matches = matches.sort()
|
||||
eof = eof.sort()
|
||||
t.same(stats, matches)
|
||||
t.same(eof, matches)
|
||||
var cache = Object.keys(this.statCache)
|
||||
t.same(cache.map(function (f) {
|
||||
return path.relative(__dirname, f)
|
||||
}).sort(), matches)
|
||||
|
||||
cache.forEach(function(c) {
|
||||
t.equal(typeof this.statCache[c], 'object')
|
||||
}, this)
|
||||
|
||||
t.end()
|
||||
})
|
||||
})
|
|
@ -1,11 +0,0 @@
|
|||
// remove the fixtures
|
||||
var tap = require("tap")
|
||||
, rimraf = require("rimraf")
|
||||
, path = require("path")
|
||||
|
||||
tap.test("cleanup fixtures", function (t) {
|
||||
rimraf(path.resolve(__dirname, "a"), function (er) {
|
||||
t.ifError(er, "removed")
|
||||
t.end()
|
||||
})
|
||||
})
|
|
@ -1,22 +0,0 @@
|
|||
Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
|
||||
Based on Underscore.js 1.5.2, copyright 2009-2013 Jeremy Ashkenas,
|
||||
DocumentCloud and Investigative Reporters & Editors <http://underscorejs.org/>
|
||||
|
||||
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.
|
|
@ -1,163 +0,0 @@
|
|||
# Lo-Dash v2.4.1
|
||||
A utility library delivering consistency, [customization](http://lodash.com/custom-builds), [performance](http://lodash.com/benchmarks), & [extras](http://lodash.com/#features).
|
||||
|
||||
## Download
|
||||
|
||||
Check out our [wiki]([https://github.com/lodash/lodash/wiki/build-differences]) for details over the differences between builds.
|
||||
|
||||
* Modern builds perfect for newer browsers/environments:<br>
|
||||
[Development](https://raw.github.com/lodash/lodash/2.4.1/dist/lodash.js) &
|
||||
[Production](https://raw.github.com/lodash/lodash/2.4.1/dist/lodash.min.js)
|
||||
|
||||
* Compatibility builds for older environment support too:<br>
|
||||
[Development](https://raw.github.com/lodash/lodash/2.4.1/dist/lodash.compat.js) &
|
||||
[Production](https://raw.github.com/lodash/lodash/2.4.1/dist/lodash.compat.min.js)
|
||||
|
||||
* Underscore builds to use as a drop-in replacement:<br>
|
||||
[Development](https://raw.github.com/lodash/lodash/2.4.1/dist/lodash.underscore.js) &
|
||||
[Production](https://raw.github.com/lodash/lodash/2.4.1/dist/lodash.underscore.min.js)
|
||||
|
||||
CDN copies are available on [cdnjs](http://cdnjs.com/libraries/lodash.js/) & [jsDelivr](http://www.jsdelivr.com/#!lodash). For smaller file sizes, create [custom builds](http://lodash.com/custom-builds) with only the features needed.
|
||||
|
||||
Love modules? We’ve got you covered with [lodash-amd](https://npmjs.org/package/lodash-amd), [lodash-es6](https://github.com/lodash/lodash-es6), [lodash-node](https://npmjs.org/package/lodash-node), & [npm packages](https://npmjs.org/browse/keyword/lodash-modularized) per method.
|
||||
|
||||
## Dive in
|
||||
|
||||
There’s plenty of **[documentation](http://lodash.com/docs)**, [unit tests](http://lodash.com/tests), & [benchmarks](http://lodash.com/benchmarks).<br>
|
||||
Check out <a href="http://devdocs.io/lodash/">DevDocs</a> as a fast, organized, & searchable interface for our documentation.
|
||||
|
||||
The full changelog for this release is available on our [wiki](https://github.com/lodash/lodash/wiki/Changelog).<br>
|
||||
A list of upcoming features is available on our [roadmap](https://github.com/lodash/lodash/wiki/Roadmap).
|
||||
|
||||
## Features *not* in Underscore
|
||||
|
||||
* AMD loader support ([curl](https://github.com/cujojs/curl), [dojo](http://dojotoolkit.org/), [requirejs](http://requirejs.org/), etc.)
|
||||
* [_(…)](http://lodash.com/docs#_) supports intuitive chaining
|
||||
* [_.at](http://lodash.com/docs#at) for cherry-picking collection values
|
||||
* [_.bindKey](http://lodash.com/docs#bindKey) for binding [*“lazy”*](http://michaux.ca/articles/lazy-function-definition-pattern) defined methods
|
||||
* [_.clone](http://lodash.com/docs#clone) supports shallow cloning of `Date` & `RegExp` objects
|
||||
* [_.cloneDeep](http://lodash.com/docs#cloneDeep) for deep cloning arrays & objects
|
||||
* [_.constant](http://lodash.com/docs#constant) & [_.property](http://lodash.com/docs#property) function generators for composing functions
|
||||
* [_.contains](http://lodash.com/docs#contains) accepts a `fromIndex`
|
||||
* [_.create](http://lodash.com/docs#create) for easier object inheritance
|
||||
* [_.createCallback](http://lodash.com/docs#createCallback) for extending callbacks in methods & mixins
|
||||
* [_.curry](http://lodash.com/docs#curry) for creating [curried](http://hughfdjackson.com/javascript/2013/07/06/why-curry-helps/) functions
|
||||
* [_.debounce](http://lodash.com/docs#debounce) & [_.throttle](http://lodash.com/docs#throttle) accept additional `options` for more control
|
||||
* [_.findIndex](http://lodash.com/docs#findIndex) & [_.findKey](http://lodash.com/docs#findKey) for finding indexes & keys
|
||||
* [_.forEach](http://lodash.com/docs#forEach) is chainable & supports exiting early
|
||||
* [_.forIn](http://lodash.com/docs#forIn) for iterating own & inherited properties
|
||||
* [_.forOwn](http://lodash.com/docs#forOwn) for iterating own properties
|
||||
* [_.isPlainObject](http://lodash.com/docs#isPlainObject) for checking if values are created by `Object`
|
||||
* [_.mapValues](http://lodash.com/docs#mapValues) for [mapping](http://lodash.com/docs#map) values to an object
|
||||
* [_.memoize](http://lodash.com/docs#memoize) exposes the `cache` of memoized functions
|
||||
* [_.merge](http://lodash.com/docs#merge) for a deep [_.extend](http://lodash.com/docs#extend)
|
||||
* [_.noop](http://lodash.com/docs#noop) for function placeholders
|
||||
* [_.now](http://lodash.com/docs#now) as a cross-browser `Date.now` alternative
|
||||
* [_.parseInt](http://lodash.com/docs#parseInt) for consistent behavior
|
||||
* [_.pull](http://lodash.com/docs#pull) & [_.remove](http://lodash.com/docs#remove) for mutating arrays
|
||||
* [_.random](http://lodash.com/docs#random) supports returning floating-point numbers
|
||||
* [_.runInContext](http://lodash.com/docs#runInContext) for easier mocking
|
||||
* [_.sortBy](http://lodash.com/docs#sortBy) supports sorting by multiple properties
|
||||
* [_.support](http://lodash.com/docs#support) for flagging environment features
|
||||
* [_.template](http://lodash.com/docs#template) supports [*“imports”*](http://lodash.com/docs#templateSettings_imports) options & [ES6 template delimiters](http://people.mozilla.org/~jorendorff/es6-draft.html#sec-literals-string-literals)
|
||||
* [_.transform](http://lodash.com/docs#transform) as a powerful alternative to [_.reduce](http://lodash.com/docs#reduce) for transforming objects
|
||||
* [_.where](http://lodash.com/docs#where) supports deep object comparisons
|
||||
* [_.xor](http://lodash.com/docs#xor) as a companion to [_.difference](http://lodash.com/docs#difference), [_.intersection](http://lodash.com/docs#intersection), & [_.union](http://lodash.com/docs#union)
|
||||
* [_.zip](http://lodash.com/docs#zip) is capable of unzipping values
|
||||
* [_.omit](http://lodash.com/docs#omit), [_.pick](http://lodash.com/docs#pick), &
|
||||
[more](http://lodash.com/docs "_.assign, _.clone, _.cloneDeep, _.first, _.initial, _.isEqual, _.last, _.merge, _.rest") accept callbacks
|
||||
* [_.contains](http://lodash.com/docs#contains), [_.toArray](http://lodash.com/docs#toArray), &
|
||||
[more](http://lodash.com/docs "_.at, _.countBy, _.every, _.filter, _.find, _.forEach, _.forEachRight, _.groupBy, _.invoke, _.map, _.max, _.min, _.pluck, _.reduce, _.reduceRight, _.reject, _.shuffle, _.size, _.some, _.sortBy, _.where") accept strings
|
||||
* [_.filter](http://lodash.com/docs#filter), [_.map](http://lodash.com/docs#map), &
|
||||
[more](http://lodash.com/docs "_.countBy, _.every, _.find, _.findKey, _.findLast, _.findLastIndex, _.findLastKey, _.first, _.groupBy, _.initial, _.last, _.max, _.min, _.reject, _.rest, _.some, _.sortBy, _.sortedIndex, _.uniq") support *“_.pluck”* & *“_.where”* shorthands
|
||||
* [_.findLast](http://lodash.com/docs#findLast), [_.findLastIndex](http://lodash.com/docs#findLastIndex), &
|
||||
[more](http://lodash.com/docs "_.findLastKey, _.forEachRight, _.forInRight, _.forOwnRight, _.partialRight") right-associative methods
|
||||
|
||||
## Resources
|
||||
|
||||
* Podcasts
|
||||
- [JavaScript Jabber](http://javascriptjabber.com/079-jsj-lo-dash-with-john-david-dalton/)
|
||||
|
||||
* Posts
|
||||
- [Say “Hello” to Lo-Dash](http://kitcambridge.be/blog/say-hello-to-lo-dash/)
|
||||
- [Custom builds in Lo-Dash 2.0](http://kitcambridge.be/blog/custom-builds-in-lo-dash-2-dot-0/)
|
||||
|
||||
* Videos
|
||||
- [Introduction](https://vimeo.com/44154599)
|
||||
- [Origins](https://vimeo.com/44154600)
|
||||
- [Optimizations & builds](https://vimeo.com/44154601)
|
||||
- [Native method use](https://vimeo.com/48576012)
|
||||
- [Testing](https://vimeo.com/45865290)
|
||||
- [CascadiaJS ’12](http://www.youtube.com/watch?v=dpPy4f_SeEk)
|
||||
|
||||
A list of other community created podcasts, posts, & videos is available on our [wiki](https://github.com/lodash/lodash/wiki/Resources).
|
||||
|
||||
## Support
|
||||
|
||||
Tested in Chrome 5~31, Firefox 2~25, IE 6-11, Opera 9.25~17, Safari 3-7, Node.js 0.6.21~0.10.22, Narwhal 0.3.2, PhantomJS 1.9.2, RingoJS 0.9, & Rhino 1.7RC5.<br>
|
||||
Automated browser test results [are available](https://saucelabs.com/u/lodash) as well as [Travis CI](https://travis-ci.org/) builds for [lodash](https://travis-ci.org/lodash/lodash/), [lodash-cli](https://travis-ci.org/lodash/lodash-cli/), [lodash-amd](https://travis-ci.org/lodash/lodash-amd/), [lodash-node](https://travis-ci.org/lodash/lodash-node/), & [grunt-lodash](https://travis-ci.org/lodash/grunt-lodash).
|
||||
|
||||
Special thanks to [Sauce Labs](https://saucelabs.com/) for providing automated browser testing.<br>
|
||||
[![Sauce Labs](http://lodash.com/_img/sauce.png)](https://saucelabs.com/ "Sauce Labs: Selenium Testing & More")
|
||||
|
||||
## Installation & usage
|
||||
|
||||
In browsers:
|
||||
|
||||
```html
|
||||
<script src="lodash.js"></script>
|
||||
```
|
||||
|
||||
Using [`npm`](http://npmjs.org/):
|
||||
|
||||
```bash
|
||||
npm i --save lodash
|
||||
|
||||
{sudo} npm i -g lodash
|
||||
npm ln lodash
|
||||
```
|
||||
|
||||
In [Node.js](http://nodejs.org/) & [Ringo](http://ringojs.org/):
|
||||
|
||||
```js
|
||||
var _ = require('lodash');
|
||||
// or as Underscore
|
||||
var _ = require('lodash/dist/lodash.underscore');
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
* Don’t assign values to [special variable](http://nodejs.org/api/repl.html#repl_repl_features) `_` when in the REPL
|
||||
* If Lo-Dash is installed globally, run [`npm ln lodash`](http://blog.nodejs.org/2011/03/23/npm-1-0-global-vs-local-installation/) in your project’s root directory *before* requiring it
|
||||
|
||||
In [Rhino](http://www.mozilla.org/rhino/):
|
||||
|
||||
```js
|
||||
load('lodash.js');
|
||||
```
|
||||
|
||||
In an AMD loader:
|
||||
|
||||
```js
|
||||
require({
|
||||
'packages': [
|
||||
{ 'name': 'lodash', 'location': 'path/to/lodash', 'main': 'lodash' }
|
||||
]
|
||||
},
|
||||
['lodash'], function(_) {
|
||||
console.log(_.VERSION);
|
||||
});
|
||||
```
|
||||
|
||||
## Author
|
||||
|
||||
| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") |
|
||||
|---|
|
||||
| [John-David Dalton](http://allyoucanleet.com/) |
|
||||
|
||||
## Contributors
|
||||
|
||||
| [![twitter/blainebublitz](http://gravatar.com/avatar/ac1c67fd906c9fecd823ce302283b4c1?s=70)](https://twitter.com/blainebublitz "Follow @BlaineBublitz on Twitter") | [![twitter/kitcambridge](http://gravatar.com/avatar/6662a1d02f351b5ef2f8b4d815804661?s=70)](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter") | [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") |
|
||||
|---|---|---|
|
||||
| [Blaine Bublitz](http://www.iceddev.com/) | [Kit Cambridge](http://kitcambridge.be/) | [Mathias Bynens](http://mathiasbynens.be/) |
|
||||
|
||||
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/lodash/lodash/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
|
|
@ -1,7179 +0,0 @@
|
|||
/**
|
||||
* @license
|
||||
* Lo-Dash 2.4.1 <http://lodash.com/>
|
||||
* Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
|
||||
* Based on Underscore.js 1.5.2 <http://underscorejs.org/LICENSE>
|
||||
* Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
||||
* Available under MIT license <http://lodash.com/license>
|
||||
*/
|
||||
;(function() {
|
||||
|
||||
/** Used as a safe reference for `undefined` in pre ES5 environments */
|
||||
var undefined;
|
||||
|
||||
/** Used to pool arrays and objects used internally */
|
||||
var arrayPool = [],
|
||||
objectPool = [];
|
||||
|
||||
/** Used to generate unique IDs */
|
||||
var idCounter = 0;
|
||||
|
||||
/** Used internally to indicate various things */
|
||||
var indicatorObject = {};
|
||||
|
||||
/** Used to prefix keys to avoid issues with `__proto__` and properties on `Object.prototype` */
|
||||
var keyPrefix = +new Date + '';
|
||||
|
||||
/** Used as the size when optimizations are enabled for large arrays */
|
||||
var largeArraySize = 75;
|
||||
|
||||
/** Used as the max size of the `arrayPool` and `objectPool` */
|
||||
var maxPoolSize = 40;
|
||||
|
||||
/** Used to detect and test whitespace */
|
||||
var whitespace = (
|
||||
// whitespace
|
||||
' \t\x0B\f\xA0\ufeff' +
|
||||
|
||||
// line terminators
|
||||
'\n\r\u2028\u2029' +
|
||||
|
||||
// unicode category "Zs" space separators
|
||||
'\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'
|
||||
);
|
||||
|
||||
/** Used to match empty string literals in compiled template source */
|
||||
var reEmptyStringLeading = /\b__p \+= '';/g,
|
||||
reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
|
||||
reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
|
||||
|
||||
/**
|
||||
* Used to match ES6 template delimiters
|
||||
* http://people.mozilla.org/~jorendorff/es6-draft.html#sec-literals-string-literals
|
||||
*/
|
||||
var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
|
||||
|
||||
/** Used to match regexp flags from their coerced string values */
|
||||
var reFlags = /\w*$/;
|
||||
|
||||
/** Used to detected named functions */
|
||||
var reFuncName = /^\s*function[ \n\r\t]+\w/;
|
||||
|
||||
/** Used to match "interpolate" template delimiters */
|
||||
var reInterpolate = /<%=([\s\S]+?)%>/g;
|
||||
|
||||
/** Used to match leading whitespace and zeros to be removed */
|
||||
var reLeadingSpacesAndZeros = RegExp('^[' + whitespace + ']*0+(?=.$)');
|
||||
|
||||
/** Used to ensure capturing order of template delimiters */
|
||||
var reNoMatch = /($^)/;
|
||||
|
||||
/** Used to detect functions containing a `this` reference */
|
||||
var reThis = /\bthis\b/;
|
||||
|
||||
/** Used to match unescaped characters in compiled string literals */
|
||||
var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g;
|
||||
|
||||
/** Used to assign default `context` object properties */
|
||||
var contextProps = [
|
||||
'Array', 'Boolean', 'Date', 'Error', 'Function', 'Math', 'Number', 'Object',
|
||||
'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN',
|
||||
'parseInt', 'setTimeout'
|
||||
];
|
||||
|
||||
/** Used to fix the JScript [[DontEnum]] bug */
|
||||
var shadowedProps = [
|
||||
'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable',
|
||||
'toLocaleString', 'toString', 'valueOf'
|
||||
];
|
||||
|
||||
/** Used to make template sourceURLs easier to identify */
|
||||
var templateCounter = 0;
|
||||
|
||||
/** `Object#toString` result shortcuts */
|
||||
var argsClass = '[object Arguments]',
|
||||
arrayClass = '[object Array]',
|
||||
boolClass = '[object Boolean]',
|
||||
dateClass = '[object Date]',
|
||||
errorClass = '[object Error]',
|
||||
funcClass = '[object Function]',
|
||||
numberClass = '[object Number]',
|
||||
objectClass = '[object Object]',
|
||||
regexpClass = '[object RegExp]',
|
||||
stringClass = '[object String]';
|
||||
|
||||
/** Used to identify object classifications that `_.clone` supports */
|
||||
var cloneableClasses = {};
|
||||
cloneableClasses[funcClass] = false;
|
||||
cloneableClasses[argsClass] = cloneableClasses[arrayClass] =
|
||||
cloneableClasses[boolClass] = cloneableClasses[dateClass] =
|
||||
cloneableClasses[numberClass] = cloneableClasses[objectClass] =
|
||||
cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true;
|
||||
|
||||
/** Used as an internal `_.debounce` options object */
|
||||
var debounceOptions = {
|
||||
'leading': false,
|
||||
'maxWait': 0,
|
||||
'trailing': false
|
||||
};
|
||||
|
||||
/** Used as the property descriptor for `__bindData__` */
|
||||
var descriptor = {
|
||||
'configurable': false,
|
||||
'enumerable': false,
|
||||
'value': null,
|
||||
'writable': false
|
||||
};
|
||||
|
||||
/** Used as the data object for `iteratorTemplate` */
|
||||
var iteratorData = {
|
||||
'args': '',
|
||||
'array': null,
|
||||
'bottom': '',
|
||||
'firstArg': '',
|
||||
'init': '',
|
||||
'keys': null,
|
||||
'loop': '',
|
||||
'shadowedProps': null,
|
||||
'support': null,
|
||||
'top': '',
|
||||
'useHas': false
|
||||
};
|
||||
|
||||
/** Used to determine if values are of the language type Object */
|
||||
var objectTypes = {
|
||||
'boolean': false,
|
||||
'function': true,
|
||||
'object': true,
|
||||
'number': false,
|
||||
'string': false,
|
||||
'undefined': false
|
||||
};
|
||||
|
||||
/** Used to escape characters for inclusion in compiled string literals */
|
||||
var stringEscapes = {
|
||||
'\\': '\\',
|
||||
"'": "'",
|
||||
'\n': 'n',
|
||||
'\r': 'r',
|
||||
'\t': 't',
|
||||
'\u2028': 'u2028',
|
||||
'\u2029': 'u2029'
|
||||
};
|
||||
|
||||
/** Used as a reference to the global object */
|
||||
var root = (objectTypes[typeof window] && window) || this;
|
||||
|
||||
/** Detect free variable `exports` */
|
||||
var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
|
||||
|
||||
/** Detect free variable `module` */
|
||||
var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
|
||||
|
||||
/** Detect the popular CommonJS extension `module.exports` */
|
||||
var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
|
||||
|
||||
/** Detect free variable `global` from Node.js or Browserified code and use it as `root` */
|
||||
var freeGlobal = objectTypes[typeof global] && global;
|
||||
if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) {
|
||||
root = freeGlobal;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* The base implementation of `_.indexOf` without support for binary searches
|
||||
* or `fromIndex` constraints.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} array The array to search.
|
||||
* @param {*} value The value to search for.
|
||||
* @param {number} [fromIndex=0] The index to search from.
|
||||
* @returns {number} Returns the index of the matched value or `-1`.
|
||||
*/
|
||||
function baseIndexOf(array, value, fromIndex) {
|
||||
var index = (fromIndex || 0) - 1,
|
||||
length = array ? array.length : 0;
|
||||
|
||||
while (++index < length) {
|
||||
if (array[index] === value) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of `_.contains` for cache objects that mimics the return
|
||||
* signature of `_.indexOf` by returning `0` if the value is found, else `-1`.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} cache The cache object to inspect.
|
||||
* @param {*} value The value to search for.
|
||||
* @returns {number} Returns `0` if `value` is found, else `-1`.
|
||||
*/
|
||||
function cacheIndexOf(cache, value) {
|
||||
var type = typeof value;
|
||||
cache = cache.cache;
|
||||
|
||||
if (type == 'boolean' || value == null) {
|
||||
return cache[value] ? 0 : -1;
|
||||
}
|
||||
if (type != 'number' && type != 'string') {
|
||||
type = 'object';
|
||||
}
|
||||
var key = type == 'number' ? value : keyPrefix + value;
|
||||
cache = (cache = cache[type]) && cache[key];
|
||||
|
||||
return type == 'object'
|
||||
? (cache && baseIndexOf(cache, value) > -1 ? 0 : -1)
|
||||
: (cache ? 0 : -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a given value to the corresponding cache object.
|
||||
*
|
||||
* @private
|
||||
* @param {*} value The value to add to the cache.
|
||||
*/
|
||||
function cachePush(value) {
|
||||
var cache = this.cache,
|
||||
type = typeof value;
|
||||
|
||||
if (type == 'boolean' || value == null) {
|
||||
cache[value] = true;
|
||||
} else {
|
||||
if (type != 'number' && type != 'string') {
|
||||
type = 'object';
|
||||
}
|
||||
var key = type == 'number' ? value : keyPrefix + value,
|
||||
typeCache = cache[type] || (cache[type] = {});
|
||||
|
||||
if (type == 'object') {
|
||||
(typeCache[key] || (typeCache[key] = [])).push(value);
|
||||
} else {
|
||||
typeCache[key] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by `_.max` and `_.min` as the default callback when a given
|
||||
* collection is a string value.
|
||||
*
|
||||
* @private
|
||||
* @param {string} value The character to inspect.
|
||||
* @returns {number} Returns the code unit of given character.
|
||||
*/
|
||||
function charAtCallback(value) {
|
||||
return value.charCodeAt(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by `sortBy` to compare transformed `collection` elements, stable sorting
|
||||
* them in ascending order.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} a The object to compare to `b`.
|
||||
* @param {Object} b The object to compare to `a`.
|
||||
* @returns {number} Returns the sort order indicator of `1` or `-1`.
|
||||
*/
|
||||
function compareAscending(a, b) {
|
||||
var ac = a.criteria,
|
||||
bc = b.criteria,
|
||||
index = -1,
|
||||
length = ac.length;
|
||||
|
||||
while (++index < length) {
|
||||
var value = ac[index],
|
||||
other = bc[index];
|
||||
|
||||
if (value !== other) {
|
||||
if (value > other || typeof value == 'undefined') {
|
||||
return 1;
|
||||
}
|
||||
if (value < other || typeof other == 'undefined') {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
|
||||
// that causes it, under certain circumstances, to return the same value for
|
||||
// `a` and `b`. See https://github.com/jashkenas/underscore/pull/1247
|
||||
//
|
||||
// This also ensures a stable sort in V8 and other engines.
|
||||
// See http://code.google.com/p/v8/issues/detail?id=90
|
||||
return a.index - b.index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a cache object to optimize linear searches of large arrays.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} [array=[]] The array to search.
|
||||
* @returns {null|Object} Returns the cache object or `null` if caching should not be used.
|
||||
*/
|
||||
function createCache(array) {
|
||||
var index = -1,
|
||||
length = array.length,
|
||||
first = array[0],
|
||||
mid = array[(length / 2) | 0],
|
||||
last = array[length - 1];
|
||||
|
||||
if (first && typeof first == 'object' &&
|
||||
mid && typeof mid == 'object' && last && typeof last == 'object') {
|
||||
return false;
|
||||
}
|
||||
var cache = getObject();
|
||||
cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false;
|
||||
|
||||
var result = getObject();
|
||||
result.array = array;
|
||||
result.cache = cache;
|
||||
result.push = cachePush;
|
||||
|
||||
while (++index < length) {
|
||||
result.push(array[index]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by `template` to escape characters for inclusion in compiled
|
||||
* string literals.
|
||||
*
|
||||
* @private
|
||||
* @param {string} match The matched character to escape.
|
||||
* @returns {string} Returns the escaped character.
|
||||
*/
|
||||
function escapeStringChar(match) {
|
||||
return '\\' + stringEscapes[match];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array from the array pool or creates a new one if the pool is empty.
|
||||
*
|
||||
* @private
|
||||
* @returns {Array} The array from the pool.
|
||||
*/
|
||||
function getArray() {
|
||||
return arrayPool.pop() || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an object from the object pool or creates a new one if the pool is empty.
|
||||
*
|
||||
* @private
|
||||
* @returns {Object} The object from the pool.
|
||||
*/
|
||||
function getObject() {
|
||||
return objectPool.pop() || {
|
||||
'array': null,
|
||||
'cache': null,
|
||||
'criteria': null,
|
||||
'false': false,
|
||||
'index': 0,
|
||||
'null': false,
|
||||
'number': null,
|
||||
'object': null,
|
||||
'push': null,
|
||||
'string': null,
|
||||
'true': false,
|
||||
'undefined': false,
|
||||
'value': null
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if `value` is a DOM node in IE < 9.
|
||||
*
|
||||
* @private
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if the `value` is a DOM node, else `false`.
|
||||
*/
|
||||
function isNode(value) {
|
||||
// IE < 9 presents DOM nodes as `Object` objects except they have `toString`
|
||||
// methods that are `typeof` "string" and still can coerce nodes to strings
|
||||
return typeof value.toString != 'function' && typeof (value + '') == 'string';
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the given array back to the array pool.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} [array] The array to release.
|
||||
*/
|
||||
function releaseArray(array) {
|
||||
array.length = 0;
|
||||
if (arrayPool.length < maxPoolSize) {
|
||||
arrayPool.push(array);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the given object back to the object pool.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} [object] The object to release.
|
||||
*/
|
||||
function releaseObject(object) {
|
||||
var cache = object.cache;
|
||||
if (cache) {
|
||||
releaseObject(cache);
|
||||
}
|
||||
object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null;
|
||||
if (objectPool.length < maxPoolSize) {
|
||||
objectPool.push(object);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Slices the `collection` from the `start` index up to, but not including,
|
||||
* the `end` index.
|
||||
*
|
||||
* Note: This function is used instead of `Array#slice` to support node lists
|
||||
* in IE < 9 and to ensure dense arrays are returned.
|
||||
*
|
||||
* @private
|
||||
* @param {Array|Object|string} collection The collection to slice.
|
||||
* @param {number} start The start index.
|
||||
* @param {number} end The end index.
|
||||
* @returns {Array} Returns the new array.
|
||||
*/
|
||||
function slice(array, start, end) {
|
||||
start || (start = 0);
|
||||
if (typeof end == 'undefined') {
|
||||
end = array ? array.length : 0;
|
||||
}
|
||||
var index = -1,
|
||||
length = end - start || 0,
|
||||
result = Array(length < 0 ? 0 : length);
|
||||
|
||||
while (++index < length) {
|
||||
result[index] = array[start + index];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Create a new `lodash` function using the given context object.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Utilities
|
||||
* @param {Object} [context=root] The context object.
|
||||
* @returns {Function} Returns the `lodash` function.
|
||||
*/
|
||||
function runInContext(context) {
|
||||
// Avoid issues with some ES3 environments that attempt to use values, named
|
||||
// after built-in constructors like `Object`, for the creation of literals.
|
||||
// ES5 clears this up by stating that literals must use built-in constructors.
|
||||
// See http://es5.github.io/#x11.1.5.
|
||||
context = context ? _.defaults(root.Object(), context, _.pick(root, contextProps)) : root;
|
||||
|
||||
/** Native constructor references */
|
||||
var Array = context.Array,
|
||||
Boolean = context.Boolean,
|
||||
Date = context.Date,
|
||||
Error = context.Error,
|
||||
Function = context.Function,
|
||||
Math = context.Math,
|
||||
Number = context.Number,
|
||||
Object = context.Object,
|
||||
RegExp = context.RegExp,
|
||||
String = context.String,
|
||||
TypeError = context.TypeError;
|
||||
|
||||
/**
|
||||
* Used for `Array` method references.
|
||||
*
|
||||
* Normally `Array.prototype` would suffice, however, using an array literal
|
||||
* avoids issues in Narwhal.
|
||||
*/
|
||||
var arrayRef = [];
|
||||
|
||||
/** Used for native method references */
|
||||
var errorProto = Error.prototype,
|
||||
objectProto = Object.prototype,
|
||||
stringProto = String.prototype;
|
||||
|
||||
/** Used to restore the original `_` reference in `noConflict` */
|
||||
var oldDash = context._;
|
||||
|
||||
/** Used to resolve the internal [[Class]] of values */
|
||||
var toString = objectProto.toString;
|
||||
|
||||
/** Used to detect if a method is native */
|
||||
var reNative = RegExp('^' +
|
||||
String(toString)
|
||||
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
||||
.replace(/toString| for [^\]]+/g, '.*?') + '$'
|
||||
);
|
||||
|
||||
/** Native method shortcuts */
|
||||
var ceil = Math.ceil,
|
||||
clearTimeout = context.clearTimeout,
|
||||
floor = Math.floor,
|
||||
fnToString = Function.prototype.toString,
|
||||
getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
|
||||
hasOwnProperty = objectProto.hasOwnProperty,
|
||||
push = arrayRef.push,
|
||||
propertyIsEnumerable = objectProto.propertyIsEnumerable,
|
||||
setTimeout = context.setTimeout,
|
||||
splice = arrayRef.splice,
|
||||
unshift = arrayRef.unshift;
|
||||
|
||||
/** Used to set meta data on functions */
|
||||
var defineProperty = (function() {
|
||||
// IE 8 only accepts DOM elements
|
||||
try {
|
||||
var o = {},
|
||||
func = isNative(func = Object.defineProperty) && func,
|
||||
result = func(o, o, o) && func;
|
||||
} catch(e) { }
|
||||
return result;
|
||||
}());
|
||||
|
||||
/* Native method shortcuts for methods with the same name as other `lodash` methods */
|
||||
var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate,
|
||||
nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray,
|
||||
nativeIsFinite = context.isFinite,
|
||||
nativeIsNaN = context.isNaN,
|
||||
nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys,
|
||||
nativeMax = Math.max,
|
||||
nativeMin = Math.min,
|
||||
nativeParseInt = context.parseInt,
|
||||
nativeRandom = Math.random;
|
||||
|
||||
/** Used to lookup a built-in constructor by [[Class]] */
|
||||
var ctorByClass = {};
|
||||
ctorByClass[arrayClass] = Array;
|
||||
ctorByClass[boolClass] = Boolean;
|
||||
ctorByClass[dateClass] = Date;
|
||||
ctorByClass[funcClass] = Function;
|
||||
ctorByClass[objectClass] = Object;
|
||||
ctorByClass[numberClass] = Number;
|
||||
ctorByClass[regexpClass] = RegExp;
|
||||
ctorByClass[stringClass] = String;
|
||||
|
||||
/** Used to avoid iterating non-enumerable properties in IE < 9 */
|
||||
var nonEnumProps = {};
|
||||
nonEnumProps[arrayClass] = nonEnumProps[dateClass] = nonEnumProps[numberClass] = { 'constructor': true, 'toLocaleString': true, 'toString': true, 'valueOf': true };
|
||||
nonEnumProps[boolClass] = nonEnumProps[stringClass] = { 'constructor': true, 'toString': true, 'valueOf': true };
|
||||
nonEnumProps[errorClass] = nonEnumProps[funcClass] = nonEnumProps[regexpClass] = { 'constructor': true, 'toString': true };
|
||||
nonEnumProps[objectClass] = { 'constructor': true };
|
||||
|
||||
(function() {
|
||||
var length = shadowedProps.length;
|
||||
while (length--) {
|
||||
var key = shadowedProps[length];
|
||||
for (var className in nonEnumProps) {
|
||||
if (hasOwnProperty.call(nonEnumProps, className) && !hasOwnProperty.call(nonEnumProps[className], key)) {
|
||||
nonEnumProps[className][key] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Creates a `lodash` object which wraps the given value to enable intuitive
|
||||
* method chaining.
|
||||
*
|
||||
* In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
|
||||
* `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
|
||||
* and `unshift`
|
||||
*
|
||||
* Chaining is supported in custom builds as long as the `value` method is
|
||||
* implicitly or explicitly included in the build.
|
||||
*
|
||||
* The chainable wrapper functions are:
|
||||
* `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`,
|
||||
* `compose`, `concat`, `countBy`, `create`, `createCallback`, `curry`,
|
||||
* `debounce`, `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`,
|
||||
* `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`,
|
||||
* `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`,
|
||||
* `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`,
|
||||
* `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `pull`, `push`,
|
||||
* `range`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`,
|
||||
* `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`, `transform`,
|
||||
* `union`, `uniq`, `unshift`, `unzip`, `values`, `where`, `without`, `wrap`,
|
||||
* and `zip`
|
||||
*
|
||||
* The non-chainable wrapper functions are:
|
||||
* `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `findIndex`,
|
||||
* `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `has`, `identity`,
|
||||
* `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`,
|
||||
* `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`,
|
||||
* `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`,
|
||||
* `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, `pop`, `random`, `reduce`,
|
||||
* `reduceRight`, `result`, `shift`, `size`, `some`, `sortedIndex`, `runInContext`,
|
||||
* `template`, `unescape`, `uniqueId`, and `value`
|
||||
*
|
||||
* The wrapper functions `first` and `last` return wrapped values when `n` is
|
||||
* provided, otherwise they return unwrapped values.
|
||||
*
|
||||
* Explicit chaining can be enabled by using the `_.chain` method.
|
||||
*
|
||||
* @name _
|
||||
* @constructor
|
||||
* @category Chaining
|
||||
* @param {*} value The value to wrap in a `lodash` instance.
|
||||
* @returns {Object} Returns a `lodash` instance.
|
||||
* @example
|
||||
*
|
||||
* var wrapped = _([1, 2, 3]);
|
||||
*
|
||||
* // returns an unwrapped value
|
||||
* wrapped.reduce(function(sum, num) {
|
||||
* return sum + num;
|
||||
* });
|
||||
* // => 6
|
||||
*
|
||||
* // returns a wrapped value
|
||||
* var squares = wrapped.map(function(num) {
|
||||
* return num * num;
|
||||
* });
|
||||
*
|
||||
* _.isArray(squares);
|
||||
* // => false
|
||||
*
|
||||
* _.isArray(squares.value());
|
||||
* // => true
|
||||
*/
|
||||
function lodash(value) {
|
||||
// don't wrap if already wrapped, even if wrapped by a different `lodash` constructor
|
||||
return (value && typeof value == 'object' && !isArray(value) && hasOwnProperty.call(value, '__wrapped__'))
|
||||
? value
|
||||
: new lodashWrapper(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* A fast path for creating `lodash` wrapper objects.
|
||||
*
|
||||
* @private
|
||||
* @param {*} value The value to wrap in a `lodash` instance.
|
||||
* @param {boolean} chainAll A flag to enable chaining for all methods
|
||||
* @returns {Object} Returns a `lodash` instance.
|
||||
*/
|
||||
function lodashWrapper(value, chainAll) {
|
||||
this.__chain__ = !!chainAll;
|
||||
this.__wrapped__ = value;
|
||||
}
|
||||
// ensure `new lodashWrapper` is an instance of `lodash`
|
||||
lodashWrapper.prototype = lodash.prototype;
|
||||
|
||||
/**
|
||||
* An object used to flag environments features.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @type Object
|
||||
*/
|
||||
var support = lodash.support = {};
|
||||
|
||||
(function() {
|
||||
var ctor = function() { this.x = 1; },
|
||||
object = { '0': 1, 'length': 1 },
|
||||
props = [];
|
||||
|
||||
ctor.prototype = { 'valueOf': 1, 'y': 1 };
|
||||
for (var key in new ctor) { props.push(key); }
|
||||
for (key in arguments) { }
|
||||
|
||||
/**
|
||||
* Detect if an `arguments` object's [[Class]] is resolvable (all but Firefox < 4, IE < 9).
|
||||
*
|
||||
* @memberOf _.support
|
||||
* @type boolean
|
||||
*/
|
||||
support.argsClass = toString.call(arguments) == argsClass;
|
||||
|
||||
/**
|
||||
* Detect if `arguments` objects are `Object` objects (all but Narwhal and Opera < 10.5).
|
||||
*
|
||||
* @memberOf _.support
|
||||
* @type boolean
|
||||
*/
|
||||
support.argsObject = arguments.constructor == Object && !(arguments instanceof Array);
|
||||
|
||||
/**
|
||||
* Detect if `name` or `message` properties of `Error.prototype` are
|
||||
* enumerable by default. (IE < 9, Safari < 5.1)
|
||||
*
|
||||
* @memberOf _.support
|
||||
* @type boolean
|
||||
*/
|
||||
support.enumErrorProps = propertyIsEnumerable.call(errorProto, 'message') || propertyIsEnumerable.call(errorProto, 'name');
|
||||
|
||||
/**
|
||||
* Detect if `prototype` properties are enumerable by default.
|
||||
*
|
||||
* Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1
|
||||
* (if the prototype or a property on the prototype has been set)
|
||||
* incorrectly sets a function's `prototype` property [[Enumerable]]
|
||||
* value to `true`.
|
||||
*
|
||||
* @memberOf _.support
|
||||
* @type boolean
|
||||
*/
|
||||
support.enumPrototypes = propertyIsEnumerable.call(ctor, 'prototype');
|
||||
|
||||
/**
|
||||
* Detect if functions can be decompiled by `Function#toString`
|
||||
* (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps).
|
||||
*
|
||||
* @memberOf _.support
|
||||
* @type boolean
|
||||
*/
|
||||
support.funcDecomp = !isNative(context.WinRTError) && reThis.test(runInContext);
|
||||
|
||||
/**
|
||||
* Detect if `Function#name` is supported (all but IE).
|
||||
*
|
||||
* @memberOf _.support
|
||||
* @type boolean
|
||||
*/
|
||||
support.funcNames = typeof Function.name == 'string';
|
||||
|
||||
/**
|
||||
* Detect if `arguments` object indexes are non-enumerable
|
||||
* (Firefox < 4, IE < 9, PhantomJS, Safari < 5.1).
|
||||
*
|
||||
* @memberOf _.support
|
||||
* @type boolean
|
||||
*/
|
||||
support.nonEnumArgs = key != 0;
|
||||
|
||||
/**
|
||||
* Detect if properties shadowing those on `Object.prototype` are non-enumerable.
|
||||
*
|
||||
* In IE < 9 an objects own properties, shadowing non-enumerable ones, are
|
||||
* made non-enumerable as well (a.k.a the JScript [[DontEnum]] bug).
|
||||
*
|
||||
* @memberOf _.support
|
||||
* @type boolean
|
||||
*/
|
||||
support.nonEnumShadows = !/valueOf/.test(props);
|
||||
|
||||
/**
|
||||
* Detect if own properties are iterated after inherited properties (all but IE < 9).
|
||||
*
|
||||
* @memberOf _.support
|
||||
* @type boolean
|
||||
*/
|
||||
support.ownLast = props[0] != 'x';
|
||||
|
||||
/**
|
||||
* Detect if `Array#shift` and `Array#splice` augment array-like objects correctly.
|
||||
*
|
||||
* Firefox < 10, IE compatibility mode, and IE < 9 have buggy Array `shift()`
|
||||
* and `splice()` functions that fail to remove the last element, `value[0]`,
|
||||
* of array-like objects even though the `length` property is set to `0`.
|
||||
* The `shift()` method is buggy in IE 8 compatibility mode, while `splice()`
|
||||
* is buggy regardless of mode in IE < 9 and buggy in compatibility mode in IE 9.
|
||||
*
|
||||
* @memberOf _.support
|
||||
* @type boolean
|
||||
*/
|
||||
support.spliceObjects = (arrayRef.splice.call(object, 0, 1), !object[0]);
|
||||
|
||||
/**
|
||||
* Detect lack of support for accessing string characters by index.
|
||||
*
|
||||
* IE < 8 can't access characters by index and IE 8 can only access
|
||||
* characters by index on string literals.
|
||||
*
|
||||
* @memberOf _.support
|
||||
* @type boolean
|
||||
*/
|
||||
support.unindexedChars = ('x'[0] + Object('x')[0]) != 'xx';
|
||||
|
||||
/**
|
||||
* Detect if a DOM node's [[Class]] is resolvable (all but IE < 9)
|
||||
* and that the JS engine errors when attempting to coerce an object to
|
||||
* a string without a `toString` function.
|
||||
*
|
||||
* @memberOf _.support
|
||||
* @type boolean
|
||||
*/
|
||||
try {
|
||||
support.nodeClass = !(toString.call(document) == objectClass && !({ 'toString': 0 } + ''));
|
||||
} catch(e) {
|
||||
support.nodeClass = true;
|
||||
}
|
||||
}(1));
|
||||
|
||||
/**
|
||||
* By default, the template delimiters used by Lo-Dash are similar to those in
|
||||
* embedded Ruby (ERB). Change the following template settings to use alternative
|
||||
* delimiters.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @type Object
|
||||
*/
|
||||
lodash.templateSettings = {
|
||||
|
||||
/**
|
||||
* Used to detect `data` property values to be HTML-escaped.
|
||||
*
|
||||
* @memberOf _.templateSettings
|
||||
* @type RegExp
|
||||
*/
|
||||
'escape': /<%-([\s\S]+?)%>/g,
|
||||
|
||||
/**
|
||||
* Used to detect code to be evaluated.
|
||||
*
|
||||
* @memberOf _.templateSettings
|
||||
* @type RegExp
|
||||
*/
|
||||
'evaluate': /<%([\s\S]+?)%>/g,
|
||||
|
||||
/**
|
||||
* Used to detect `data` property values to inject.
|
||||
*
|
||||
* @memberOf _.templateSettings
|
||||
* @type RegExp
|
||||
*/
|
||||
'interpolate': reInterpolate,
|
||||
|
||||
/**
|
||||
* Used to reference the data object in the template text.
|
||||
*
|
||||
* @memberOf _.templateSettings
|
||||
* @type string
|
||||
*/
|
||||
'variable': '',
|
||||
|
||||
/**
|
||||
* Used to import variables into the compiled template.
|
||||
*
|
||||
* @memberOf _.templateSettings
|
||||
* @type Object
|
||||
*/
|
||||
'imports': {
|
||||
|
||||
/**
|
||||
* A reference to the `lodash` function.
|
||||
*
|
||||
* @memberOf _.templateSettings.imports
|
||||
* @type Function
|
||||
*/
|
||||
'_': lodash
|
||||
}
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* The template used to create iterator functions.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} data The data object used to populate the text.
|
||||
* @returns {string} Returns the interpolated text.
|
||||
*/
|
||||
var iteratorTemplate = template(
|
||||
// the `iterable` may be reassigned by the `top` snippet
|
||||
'var index, iterable = <%= firstArg %>, ' +
|
||||
// assign the `result` variable an initial value
|
||||
'result = <%= init %>;\n' +
|
||||
// exit early if the first argument is falsey
|
||||
'if (!iterable) return result;\n' +
|
||||
// add code before the iteration branches
|
||||
'<%= top %>;' +
|
||||
|
||||
// array-like iteration:
|
||||
'<% if (array) { %>\n' +
|
||||
'var length = iterable.length; index = -1;\n' +
|
||||
'if (<%= array %>) {' +
|
||||
|
||||
// add support for accessing string characters by index if needed
|
||||
' <% if (support.unindexedChars) { %>\n' +
|
||||
' if (isString(iterable)) {\n' +
|
||||
" iterable = iterable.split('')\n" +
|
||||
' }' +
|
||||
' <% } %>\n' +
|
||||
|
||||
// iterate over the array-like value
|
||||
' while (++index < length) {\n' +
|
||||
' <%= loop %>;\n' +
|
||||
' }\n' +
|
||||
'}\n' +
|
||||
'else {' +
|
||||
|
||||
// object iteration:
|
||||
// add support for iterating over `arguments` objects if needed
|
||||
' <% } else if (support.nonEnumArgs) { %>\n' +
|
||||
' var length = iterable.length; index = -1;\n' +
|
||||
' if (length && isArguments(iterable)) {\n' +
|
||||
' while (++index < length) {\n' +
|
||||
" index += '';\n" +
|
||||
' <%= loop %>;\n' +
|
||||
' }\n' +
|
||||
' } else {' +
|
||||
' <% } %>' +
|
||||
|
||||
// avoid iterating over `prototype` properties in older Firefox, Opera, and Safari
|
||||
' <% if (support.enumPrototypes) { %>\n' +
|
||||
" var skipProto = typeof iterable == 'function';\n" +
|
||||
' <% } %>' +
|
||||
|
||||
// avoid iterating over `Error.prototype` properties in older IE and Safari
|
||||
' <% if (support.enumErrorProps) { %>\n' +
|
||||
' var skipErrorProps = iterable === errorProto || iterable instanceof Error;\n' +
|
||||
' <% } %>' +
|
||||
|
||||
// define conditions used in the loop
|
||||
' <%' +
|
||||
' var conditions = [];' +
|
||||
' if (support.enumPrototypes) { conditions.push(\'!(skipProto && index == "prototype")\'); }' +
|
||||
' if (support.enumErrorProps) { conditions.push(\'!(skipErrorProps && (index == "message" || index == "name"))\'); }' +
|
||||
' %>' +
|
||||
|
||||
// iterate own properties using `Object.keys`
|
||||
' <% if (useHas && keys) { %>\n' +
|
||||
' var ownIndex = -1,\n' +
|
||||
' ownProps = objectTypes[typeof iterable] && keys(iterable),\n' +
|
||||
' length = ownProps ? ownProps.length : 0;\n\n' +
|
||||
' while (++ownIndex < length) {\n' +
|
||||
' index = ownProps[ownIndex];\n<%' +
|
||||
" if (conditions.length) { %> if (<%= conditions.join(' && ') %>) {\n <% } %>" +
|
||||
' <%= loop %>;' +
|
||||
' <% if (conditions.length) { %>\n }<% } %>\n' +
|
||||
' }' +
|
||||
|
||||
// else using a for-in loop
|
||||
' <% } else { %>\n' +
|
||||
' for (index in iterable) {\n<%' +
|
||||
' if (useHas) { conditions.push("hasOwnProperty.call(iterable, index)"); }' +
|
||||
" if (conditions.length) { %> if (<%= conditions.join(' && ') %>) {\n <% } %>" +
|
||||
' <%= loop %>;' +
|
||||
' <% if (conditions.length) { %>\n }<% } %>\n' +
|
||||
' }' +
|
||||
|
||||
// Because IE < 9 can't set the `[[Enumerable]]` attribute of an
|
||||
// existing property and the `constructor` property of a prototype
|
||||
// defaults to non-enumerable, Lo-Dash skips the `constructor`
|
||||
// property when it infers it's iterating over a `prototype` object.
|
||||
' <% if (support.nonEnumShadows) { %>\n\n' +
|
||||
' if (iterable !== objectProto) {\n' +
|
||||
" var ctor = iterable.constructor,\n" +
|
||||
' isProto = iterable === (ctor && ctor.prototype),\n' +
|
||||
' className = iterable === stringProto ? stringClass : iterable === errorProto ? errorClass : toString.call(iterable),\n' +
|
||||
' nonEnum = nonEnumProps[className];\n' +
|
||||
' <% for (k = 0; k < 7; k++) { %>\n' +
|
||||
" index = '<%= shadowedProps[k] %>';\n" +
|
||||
' if ((!(isProto && nonEnum[index]) && hasOwnProperty.call(iterable, index))<%' +
|
||||
' if (!useHas) { %> || (!nonEnum[index] && iterable[index] !== objectProto[index])<% }' +
|
||||
' %>) {\n' +
|
||||
' <%= loop %>;\n' +
|
||||
' }' +
|
||||
' <% } %>\n' +
|
||||
' }' +
|
||||
' <% } %>' +
|
||||
' <% } %>' +
|
||||
' <% if (array || support.nonEnumArgs) { %>\n}<% } %>\n' +
|
||||
|
||||
// add code to the bottom of the iteration function
|
||||
'<%= bottom %>;\n' +
|
||||
// finally, return the `result`
|
||||
'return result'
|
||||
);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* The base implementation of `_.bind` that creates the bound function and
|
||||
* sets its meta data.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} bindData The bind data array.
|
||||
* @returns {Function} Returns the new bound function.
|
||||
*/
|
||||
function baseBind(bindData) {
|
||||
var func = bindData[0],
|
||||
partialArgs = bindData[2],
|
||||
thisArg = bindData[4];
|
||||
|
||||
function bound() {
|
||||
// `Function#bind` spec
|
||||
// http://es5.github.io/#x15.3.4.5
|
||||
if (partialArgs) {
|
||||
// avoid `arguments` object deoptimizations by using `slice` instead
|
||||
// of `Array.prototype.slice.call` and not assigning `arguments` to a
|
||||
// variable as a ternary expression
|
||||
var args = slice(partialArgs);
|
||||
push.apply(args, arguments);
|
||||
}
|
||||
// mimic the constructor's `return` behavior
|
||||
// http://es5.github.io/#x13.2.2
|
||||
if (this instanceof bound) {
|
||||
// ensure `new bound` is an instance of `func`
|
||||
var thisBinding = baseCreate(func.prototype),
|
||||
result = func.apply(thisBinding, args || arguments);
|
||||
return isObject(result) ? result : thisBinding;
|
||||
}
|
||||
return func.apply(thisArg, args || arguments);
|
||||
}
|
||||
setBindData(bound, bindData);
|
||||
return bound;
|
||||
}
|
||||
|
||||
/**
|
||||
* The base implementation of `_.clone` without argument juggling or support
|
||||
* for `thisArg` binding.
|
||||
*
|
||||
* @private
|
||||
* @param {*} value The value to clone.
|
||||
* @param {boolean} [isDeep=false] Specify a deep clone.
|
||||
* @param {Function} [callback] The function to customize cloning values.
|
||||
* @param {Array} [stackA=[]] Tracks traversed source objects.
|
||||
* @param {Array} [stackB=[]] Associates clones with source counterparts.
|
||||
* @returns {*} Returns the cloned value.
|
||||
*/
|
||||
function baseClone(value, isDeep, callback, stackA, stackB) {
|
||||
if (callback) {
|
||||
var result = callback(value);
|
||||
if (typeof result != 'undefined') {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// inspect [[Class]]
|
||||
var isObj = isObject(value);
|
||||
if (isObj) {
|
||||
var className = toString.call(value);
|
||||
if (!cloneableClasses[className] || (!support.nodeClass && isNode(value))) {
|
||||
return value;
|
||||
}
|
||||
var ctor = ctorByClass[className];
|
||||
switch (className) {
|
||||
case boolClass:
|
||||
case dateClass:
|
||||
return new ctor(+value);
|
||||
|
||||
case numberClass:
|
||||
case stringClass:
|
||||
return new ctor(value);
|
||||
|
||||
case regexpClass:
|
||||
result = ctor(value.source, reFlags.exec(value));
|
||||
result.lastIndex = value.lastIndex;
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
var isArr = isArray(value);
|
||||
if (isDeep) {
|
||||
// check for circular references and return corresponding clone
|
||||
var initedStack = !stackA;
|
||||
stackA || (stackA = getArray());
|
||||
stackB || (stackB = getArray());
|
||||
|
||||
var length = stackA.length;
|
||||
while (length--) {
|
||||
if (stackA[length] == value) {
|
||||
return stackB[length];
|
||||
}
|
||||
}
|
||||
result = isArr ? ctor(value.length) : {};
|
||||
}
|
||||
else {
|
||||
result = isArr ? slice(value) : assign({}, value);
|
||||
}
|
||||
// add array properties assigned by `RegExp#exec`
|
||||
if (isArr) {
|
||||
if (hasOwnProperty.call(value, 'index')) {
|
||||
result.index = value.index;
|
||||
}
|
||||
if (hasOwnProperty.call(value, 'input')) {
|
||||
result.input = value.input;
|
||||
}
|
||||
}
|
||||
// exit for shallow clone
|
||||
if (!isDeep) {
|
||||
return result;
|
||||
}
|
||||
// add the source value to the stack of traversed objects
|
||||
// and associate it with its clone
|
||||
stackA.push(value);
|
||||
stackB.push(result);
|
||||
|
||||
// recursively populate clone (susceptible to call stack limits)
|
||||
(isArr ? baseEach : forOwn)(value, function(objValue, key) {
|
||||
result[key] = baseClone(objValue, isDeep, callback, stackA, stackB);
|
||||
});
|
||||
|
||||
if (initedStack) {
|
||||
releaseArray(stackA);
|
||||
releaseArray(stackB);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* The base implementation of `_.create` without support for assigning
|
||||
* properties to the created object.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} prototype The object to inherit from.
|
||||
* @returns {Object} Returns the new object.
|
||||
*/
|
||||
function baseCreate(prototype, properties) {
|
||||
return isObject(prototype) ? nativeCreate(prototype) : {};
|
||||
}
|
||||
// fallback for browsers without `Object.create`
|
||||
if (!nativeCreate) {
|
||||
baseCreate = (function() {
|
||||
function Object() {}
|
||||
return function(prototype) {
|
||||
if (isObject(prototype)) {
|
||||
Object.prototype = prototype;
|
||||
var result = new Object;
|
||||
Object.prototype = null;
|
||||
}
|
||||
return result || context.Object();
|
||||
};
|
||||
}());
|
||||
}
|
||||
|
||||
/**
|
||||
* The base implementation of `_.createCallback` without support for creating
|
||||
* "_.pluck" or "_.where" style callbacks.
|
||||
*
|
||||
* @private
|
||||
* @param {*} [func=identity] The value to convert to a callback.
|
||||
* @param {*} [thisArg] The `this` binding of the created callback.
|
||||
* @param {number} [argCount] The number of arguments the callback accepts.
|
||||
* @returns {Function} Returns a callback function.
|
||||
*/
|
||||
function baseCreateCallback(func, thisArg, argCount) {
|
||||
if (typeof func != 'function') {
|
||||
return identity;
|
||||
}
|
||||
// exit early for no `thisArg` or already bound by `Function#bind`
|
||||
if (typeof thisArg == 'undefined' || !('prototype' in func)) {
|
||||
return func;
|
||||
}
|
||||
var bindData = func.__bindData__;
|
||||
if (typeof bindData == 'undefined') {
|
||||
if (support.funcNames) {
|
||||
bindData = !func.name;
|
||||
}
|
||||
bindData = bindData || !support.funcDecomp;
|
||||
if (!bindData) {
|
||||
var source = fnToString.call(func);
|
||||
if (!support.funcNames) {
|
||||
bindData = !reFuncName.test(source);
|
||||
}
|
||||
if (!bindData) {
|
||||
// checks if `func` references the `this` keyword and stores the result
|
||||
bindData = reThis.test(source);
|
||||
setBindData(func, bindData);
|
||||
}
|
||||
}
|
||||
}
|
||||
// exit early if there are no `this` references or `func` is bound
|
||||
if (bindData === false || (bindData !== true && bindData[1] & 1)) {
|
||||
return func;
|
||||
}
|
||||
switch (argCount) {
|
||||
case 1: return function(value) {
|
||||
return func.call(thisArg, value);
|
||||
};
|
||||
case 2: return function(a, b) {
|
||||
return func.call(thisArg, a, b);
|
||||
};
|
||||
case 3: return function(value, index, collection) {
|
||||
return func.call(thisArg, value, index, collection);
|
||||
};
|
||||
case 4: return function(accumulator, value, index, collection) {
|
||||
return func.call(thisArg, accumulator, value, index, collection);
|
||||
};
|
||||
}
|
||||
return bind(func, thisArg);
|
||||
}
|
||||
|
||||
/**
|
||||
* The base implementation of `createWrapper` that creates the wrapper and
|
||||
* sets its meta data.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} bindData The bind data array.
|
||||
* @returns {Function} Returns the new function.
|
||||
*/
|
||||
function baseCreateWrapper(bindData) {
|
||||
var func = bindData[0],
|
||||
bitmask = bindData[1],
|
||||
partialArgs = bindData[2],
|
||||
partialRightArgs = bindData[3],
|
||||
thisArg = bindData[4],
|
||||
arity = bindData[5];
|
||||
|
||||
var isBind = bitmask & 1,
|
||||
isBindKey = bitmask & 2,
|
||||
isCurry = bitmask & 4,
|
||||
isCurryBound = bitmask & 8,
|
||||
key = func;
|
||||
|
||||
function bound() {
|
||||
var thisBinding = isBind ? thisArg : this;
|
||||
if (partialArgs) {
|
||||
var args = slice(partialArgs);
|
||||
push.apply(args, arguments);
|
||||
}
|
||||
if (partialRightArgs || isCurry) {
|
||||
args || (args = slice(arguments));
|
||||
if (partialRightArgs) {
|
||||
push.apply(args, partialRightArgs);
|
||||
}
|
||||
if (isCurry && args.length < arity) {
|
||||
bitmask |= 16 & ~32;
|
||||
return baseCreateWrapper([func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity]);
|
||||
}
|
||||
}
|
||||
args || (args = arguments);
|
||||
if (isBindKey) {
|
||||
func = thisBinding[key];
|
||||
}
|
||||
if (this instanceof bound) {
|
||||
thisBinding = baseCreate(func.prototype);
|
||||
var result = func.apply(thisBinding, args);
|
||||
return isObject(result) ? result : thisBinding;
|
||||
}
|
||||
return func.apply(thisBinding, args);
|
||||
}
|
||||
setBindData(bound, bindData);
|
||||
return bound;
|
||||
}
|
||||
|
||||
/**
|
||||
* The base implementation of `_.difference` that accepts a single array
|
||||
* of values to exclude.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} array The array to process.
|
||||
* @param {Array} [values] The array of values to exclude.
|
||||
* @returns {Array} Returns a new array of filtered values.
|
||||
*/
|
||||
function baseDifference(array, values) {
|
||||
var index = -1,
|
||||
indexOf = getIndexOf(),
|
||||
length = array ? array.length : 0,
|
||||
isLarge = length >= largeArraySize && indexOf === baseIndexOf,
|
||||
result = [];
|
||||
|
||||
if (isLarge) {
|
||||
var cache = createCache(values);
|
||||
if (cache) {
|
||||
indexOf = cacheIndexOf;
|
||||
values = cache;
|
||||
} else {
|
||||
isLarge = false;
|
||||
}
|
||||
}
|
||||
while (++index < length) {
|
||||
var value = array[index];
|
||||
if (indexOf(values, value) < 0) {
|
||||
result.push(value);
|
||||
}
|
||||
}
|
||||
if (isLarge) {
|
||||
releaseObject(values);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* The base implementation of `_.flatten` without support for callback
|
||||
* shorthands or `thisArg` binding.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} array The array to flatten.
|
||||
* @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
|
||||
* @param {boolean} [isStrict=false] A flag to restrict flattening to arrays and `arguments` objects.
|
||||
* @param {number} [fromIndex=0] The index to start from.
|
||||
* @returns {Array} Returns a new flattened array.
|
||||
*/
|
||||
function baseFlatten(array, isShallow, isStrict, fromIndex) {
|
||||
var index = (fromIndex || 0) - 1,
|
||||
length = array ? array.length : 0,
|
||||
result = [];
|
||||
|
||||
while (++index < length) {
|
||||
var value = array[index];
|
||||
|
||||
if (value && typeof value == 'object' && typeof value.length == 'number'
|
||||
&& (isArray(value) || isArguments(value))) {
|
||||
// recursively flatten arrays (susceptible to call stack limits)
|
||||
if (!isShallow) {
|
||||
value = baseFlatten(value, isShallow, isStrict);
|
||||
}
|
||||
var valIndex = -1,
|
||||
valLength = value.length,
|
||||
resIndex = result.length;
|
||||
|
||||
result.length += valLength;
|
||||
while (++valIndex < valLength) {
|
||||
result[resIndex++] = value[valIndex];
|
||||
}
|
||||
} else if (!isStrict) {
|
||||
result.push(value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* The base implementation of `_.isEqual`, without support for `thisArg` binding,
|
||||
* that allows partial "_.where" style comparisons.
|
||||
*
|
||||
* @private
|
||||
* @param {*} a The value to compare.
|
||||
* @param {*} b The other value to compare.
|
||||
* @param {Function} [callback] The function to customize comparing values.
|
||||
* @param {Function} [isWhere=false] A flag to indicate performing partial comparisons.
|
||||
* @param {Array} [stackA=[]] Tracks traversed `a` objects.
|
||||
* @param {Array} [stackB=[]] Tracks traversed `b` objects.
|
||||
* @returns {boolean} Returns `true` if the values are equivalent, else `false`.
|
||||
*/
|
||||
function baseIsEqual(a, b, callback, isWhere, stackA, stackB) {
|
||||
// used to indicate that when comparing objects, `a` has at least the properties of `b`
|
||||
if (callback) {
|
||||
var result = callback(a, b);
|
||||
if (typeof result != 'undefined') {
|
||||
return !!result;
|
||||
}
|
||||
}
|
||||
// exit early for identical values
|
||||
if (a === b) {
|
||||
// treat `+0` vs. `-0` as not equal
|
||||
return a !== 0 || (1 / a == 1 / b);
|
||||
}
|
||||
var type = typeof a,
|
||||
otherType = typeof b;
|
||||
|
||||
// exit early for unlike primitive values
|
||||
if (a === a &&
|
||||
!(a && objectTypes[type]) &&
|
||||
!(b && objectTypes[otherType])) {
|
||||
return false;
|
||||
}
|
||||
// exit early for `null` and `undefined` avoiding ES3's Function#call behavior
|
||||
// http://es5.github.io/#x15.3.4.4
|
||||
if (a == null || b == null) {
|
||||
return a === b;
|
||||
}
|
||||
// compare [[Class]] names
|
||||
var className = toString.call(a),
|
||||
otherClass = toString.call(b);
|
||||
|
||||
if (className == argsClass) {
|
||||
className = objectClass;
|
||||
}
|
||||
if (otherClass == argsClass) {
|
||||
otherClass = objectClass;
|
||||
}
|
||||
if (className != otherClass) {
|
||||
return false;
|
||||
}
|
||||
switch (className) {
|
||||
case boolClass:
|
||||
case dateClass:
|
||||
// coerce dates and booleans to numbers, dates to milliseconds and booleans
|
||||
// to `1` or `0` treating invalid dates coerced to `NaN` as not equal
|
||||
return +a == +b;
|
||||
|
||||
case numberClass:
|
||||
// treat `NaN` vs. `NaN` as equal
|
||||
return (a != +a)
|
||||
? b != +b
|
||||
// but treat `+0` vs. `-0` as not equal
|
||||
: (a == 0 ? (1 / a == 1 / b) : a == +b);
|
||||
|
||||
case regexpClass:
|
||||
case stringClass:
|
||||
// coerce regexes to strings (http://es5.github.io/#x15.10.6.4)
|
||||
// treat string primitives and their corresponding object instances as equal
|
||||
return a == String(b);
|
||||
}
|
||||
var isArr = className == arrayClass;
|
||||
if (!isArr) {
|
||||
// unwrap any `lodash` wrapped values
|
||||
var aWrapped = hasOwnProperty.call(a, '__wrapped__'),
|
||||
bWrapped = hasOwnProperty.call(b, '__wrapped__');
|
||||
|
||||
if (aWrapped || bWrapped) {
|
||||
return baseIsEqual(aWrapped ? a.__wrapped__ : a, bWrapped ? b.__wrapped__ : b, callback, isWhere, stackA, stackB);
|
||||
}
|
||||
// exit for functions and DOM nodes
|
||||
if (className != objectClass || (!support.nodeClass && (isNode(a) || isNode(b)))) {
|
||||
return false;
|
||||
}
|
||||
// in older versions of Opera, `arguments` objects have `Array` constructors
|
||||
var ctorA = !support.argsObject && isArguments(a) ? Object : a.constructor,
|
||||
ctorB = !support.argsObject && isArguments(b) ? Object : b.constructor;
|
||||
|
||||
// non `Object` object instances with different constructors are not equal
|
||||
if (ctorA != ctorB &&
|
||||
!(isFunction(ctorA) && ctorA instanceof ctorA && isFunction(ctorB) && ctorB instanceof ctorB) &&
|
||||
('constructor' in a && 'constructor' in b)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// assume cyclic structures are equal
|
||||
// the algorithm for detecting cyclic structures is adapted from ES 5.1
|
||||
// section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3)
|
||||
var initedStack = !stackA;
|
||||
stackA || (stackA = getArray());
|
||||
stackB || (stackB = getArray());
|
||||
|
||||
var length = stackA.length;
|
||||
while (length--) {
|
||||
if (stackA[length] == a) {
|
||||
return stackB[length] == b;
|
||||
}
|
||||
}
|
||||
var size = 0;
|
||||
result = true;
|
||||
|
||||
// add `a` and `b` to the stack of traversed objects
|
||||
stackA.push(a);
|
||||
stackB.push(b);
|
||||
|
||||
// recursively compare objects and arrays (susceptible to call stack limits)
|
||||
if (isArr) {
|
||||
// compare lengths to determine if a deep comparison is necessary
|
||||
length = a.length;
|
||||
size = b.length;
|
||||
result = size == length;
|
||||
|
||||
if (result || isWhere) {
|
||||
// deep compare the contents, ignoring non-numeric properties
|
||||
while (size--) {
|
||||
var index = length,
|
||||
value = b[size];
|
||||
|
||||
if (isWhere) {
|
||||
while (index--) {
|
||||
if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (!(result = baseIsEqual(a[size], value, callback, isWhere, stackA, stackB))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys`
|
||||
// which, in this case, is more costly
|
||||
forIn(b, function(value, key, b) {
|
||||
if (hasOwnProperty.call(b, key)) {
|
||||
// count the number of properties.
|
||||
size++;
|
||||
// deep compare each property value.
|
||||
return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB));
|
||||
}
|
||||
});
|
||||
|
||||
if (result && !isWhere) {
|
||||
// ensure both objects have the same number of properties
|
||||
forIn(a, function(value, key, a) {
|
||||
if (hasOwnProperty.call(a, key)) {
|
||||
// `size` will be `-1` if `a` has more properties than `b`
|
||||
return (result = --size > -1);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
stackA.pop();
|
||||
stackB.pop();
|
||||
|
||||
if (initedStack) {
|
||||
releaseArray(stackA);
|
||||
releaseArray(stackB);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* The base implementation of `_.merge` without argument juggling or support
|
||||
* for `thisArg` binding.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} object The destination object.
|
||||
* @param {Object} source The source object.
|
||||
* @param {Function} [callback] The function to customize merging properties.
|
||||
* @param {Array} [stackA=[]] Tracks traversed source objects.
|
||||
* @param {Array} [stackB=[]] Associates values with source counterparts.
|
||||
*/
|
||||
function baseMerge(object, source, callback, stackA, stackB) {
|
||||
(isArray(source) ? forEach : forOwn)(source, function(source, key) {
|
||||
var found,
|
||||
isArr,
|
||||
result = source,
|
||||
value = object[key];
|
||||
|
||||
if (source && ((isArr = isArray(source)) || isPlainObject(source))) {
|
||||
// avoid merging previously merged cyclic sources
|
||||
var stackLength = stackA.length;
|
||||
while (stackLength--) {
|
||||
if ((found = stackA[stackLength] == source)) {
|
||||
value = stackB[stackLength];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
var isShallow;
|
||||
if (callback) {
|
||||
result = callback(value, source);
|
||||
if ((isShallow = typeof result != 'undefined')) {
|
||||
value = result;
|
||||
}
|
||||
}
|
||||
if (!isShallow) {
|
||||
value = isArr
|
||||
? (isArray(value) ? value : [])
|
||||
: (isPlainObject(value) ? value : {});
|
||||
}
|
||||
// add `source` and associated `value` to the stack of traversed objects
|
||||
stackA.push(source);
|
||||
stackB.push(value);
|
||||
|
||||
// recursively merge objects and arrays (susceptible to call stack limits)
|
||||
if (!isShallow) {
|
||||
baseMerge(value, source, callback, stackA, stackB);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (callback) {
|
||||
result = callback(value, source);
|
||||
if (typeof result == 'undefined') {
|
||||
result = source;
|
||||
}
|
||||
}
|
||||
if (typeof result != 'undefined') {
|
||||
value = result;
|
||||
}
|
||||
}
|
||||
object[key] = value;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The base implementation of `_.random` without argument juggling or support
|
||||
* for returning floating-point numbers.
|
||||
*
|
||||
* @private
|
||||
* @param {number} min The minimum possible value.
|
||||
* @param {number} max The maximum possible value.
|
||||
* @returns {number} Returns a random number.
|
||||
*/
|
||||
function baseRandom(min, max) {
|
||||
return min + floor(nativeRandom() * (max - min + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* The base implementation of `_.uniq` without support for callback shorthands
|
||||
* or `thisArg` binding.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} array The array to process.
|
||||
* @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
|
||||
* @param {Function} [callback] The function called per iteration.
|
||||
* @returns {Array} Returns a duplicate-value-free array.
|
||||
*/
|
||||
function baseUniq(array, isSorted, callback) {
|
||||
var index = -1,
|
||||
indexOf = getIndexOf(),
|
||||
length = array ? array.length : 0,
|
||||
result = [];
|
||||
|
||||
var isLarge = !isSorted && length >= largeArraySize && indexOf === baseIndexOf,
|
||||
seen = (callback || isLarge) ? getArray() : result;
|
||||
|
||||
if (isLarge) {
|
||||
var cache = createCache(seen);
|
||||
indexOf = cacheIndexOf;
|
||||
seen = cache;
|
||||
}
|
||||
while (++index < length) {
|
||||
var value = array[index],
|
||||
computed = callback ? callback(value, index, array) : value;
|
||||
|
||||
if (isSorted
|
||||
? !index || seen[seen.length - 1] !== computed
|
||||
: indexOf(seen, computed) < 0
|
||||
) {
|
||||
if (callback || isLarge) {
|
||||
seen.push(computed);
|
||||
}
|
||||
result.push(value);
|
||||
}
|
||||
}
|
||||
if (isLarge) {
|
||||
releaseArray(seen.array);
|
||||
releaseObject(seen);
|
||||
} else if (callback) {
|
||||
releaseArray(seen);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that aggregates a collection, creating an object composed
|
||||
* of keys generated from the results of running each element of the collection
|
||||
* through a callback. The given `setter` function sets the keys and values
|
||||
* of the composed object.
|
||||
*
|
||||
* @private
|
||||
* @param {Function} setter The setter function.
|
||||
* @returns {Function} Returns the new aggregator function.
|
||||
*/
|
||||
function createAggregator(setter) {
|
||||
return function(collection, callback, thisArg) {
|
||||
var result = {};
|
||||
callback = lodash.createCallback(callback, thisArg, 3);
|
||||
|
||||
if (isArray(collection)) {
|
||||
var index = -1,
|
||||
length = collection.length;
|
||||
|
||||
while (++index < length) {
|
||||
var value = collection[index];
|
||||
setter(result, value, callback(value, index, collection), collection);
|
||||
}
|
||||
} else {
|
||||
baseEach(collection, function(value, key, collection) {
|
||||
setter(result, value, callback(value, key, collection), collection);
|
||||
});
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that, when called, either curries or invokes `func`
|
||||
* with an optional `this` binding and partially applied arguments.
|
||||
*
|
||||
* @private
|
||||
* @param {Function|string} func The function or method name to reference.
|
||||
* @param {number} bitmask The bitmask of method flags to compose.
|
||||
* The bitmask may be composed of the following flags:
|
||||
* 1 - `_.bind`
|
||||
* 2 - `_.bindKey`
|
||||
* 4 - `_.curry`
|
||||
* 8 - `_.curry` (bound)
|
||||
* 16 - `_.partial`
|
||||
* 32 - `_.partialRight`
|
||||
* @param {Array} [partialArgs] An array of arguments to prepend to those
|
||||
* provided to the new function.
|
||||
* @param {Array} [partialRightArgs] An array of arguments to append to those
|
||||
* provided to the new function.
|
||||
* @param {*} [thisArg] The `this` binding of `func`.
|
||||
* @param {number} [arity] The arity of `func`.
|
||||
* @returns {Function} Returns the new function.
|
||||
*/
|
||||
function createWrapper(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) {
|
||||
var isBind = bitmask & 1,
|
||||
isBindKey = bitmask & 2,
|
||||
isCurry = bitmask & 4,
|
||||
isCurryBound = bitmask & 8,
|
||||
isPartial = bitmask & 16,
|
||||
isPartialRight = bitmask & 32;
|
||||
|
||||
if (!isBindKey && !isFunction(func)) {
|
||||
throw new TypeError;
|
||||
}
|
||||
if (isPartial && !partialArgs.length) {
|
||||
bitmask &= ~16;
|
||||
isPartial = partialArgs = false;
|
||||
}
|
||||
if (isPartialRight && !partialRightArgs.length) {
|
||||
bitmask &= ~32;
|
||||
isPartialRight = partialRightArgs = false;
|
||||
}
|
||||
var bindData = func && func.__bindData__;
|
||||
if (bindData && bindData !== true) {
|
||||
// clone `bindData`
|
||||
bindData = slice(bindData);
|
||||
if (bindData[2]) {
|
||||
bindData[2] = slice(bindData[2]);
|
||||
}
|
||||
if (bindData[3]) {
|
||||
bindData[3] = slice(bindData[3]);
|
||||
}
|
||||
// set `thisBinding` is not previously bound
|
||||
if (isBind && !(bindData[1] & 1)) {
|
||||
bindData[4] = thisArg;
|
||||
}
|
||||
// set if previously bound but not currently (subsequent curried functions)
|
||||
if (!isBind && bindData[1] & 1) {
|
||||
bitmask |= 8;
|
||||
}
|
||||
// set curried arity if not yet set
|
||||
if (isCurry && !(bindData[1] & 4)) {
|
||||
bindData[5] = arity;
|
||||
}
|
||||
// append partial left arguments
|
||||
if (isPartial) {
|
||||
push.apply(bindData[2] || (bindData[2] = []), partialArgs);
|
||||
}
|
||||
// append partial right arguments
|
||||
if (isPartialRight) {
|
||||
unshift.apply(bindData[3] || (bindData[3] = []), partialRightArgs);
|
||||
}
|
||||
// merge flags
|
||||
bindData[1] |= bitmask;
|
||||
return createWrapper.apply(null, bindData);
|
||||
}
|
||||
// fast path for `_.bind`
|
||||
var creater = (bitmask == 1 || bitmask === 17) ? baseBind : baseCreateWrapper;
|
||||
return creater([func, bitmask, partialArgs, partialRightArgs, thisArg, arity]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates compiled iteration functions.
|
||||
*
|
||||
* @private
|
||||
* @param {...Object} [options] The compile options object(s).
|
||||
* @param {string} [options.array] Code to determine if the iterable is an array or array-like.
|
||||
* @param {boolean} [options.useHas] Specify using `hasOwnProperty` checks in the object loop.
|
||||
* @param {Function} [options.keys] A reference to `_.keys` for use in own property iteration.
|
||||
* @param {string} [options.args] A comma separated string of iteration function arguments.
|
||||
* @param {string} [options.top] Code to execute before the iteration branches.
|
||||
* @param {string} [options.loop] Code to execute in the object loop.
|
||||
* @param {string} [options.bottom] Code to execute after the iteration branches.
|
||||
* @returns {Function} Returns the compiled function.
|
||||
*/
|
||||
function createIterator() {
|
||||
// data properties
|
||||
iteratorData.shadowedProps = shadowedProps;
|
||||
iteratorData.support = support;
|
||||
|
||||
// iterator options
|
||||
iteratorData.array = iteratorData.bottom = iteratorData.loop = iteratorData.top = '';
|
||||
iteratorData.init = 'iterable';
|
||||
iteratorData.useHas = true;
|
||||
|
||||
// merge options into a template data object
|
||||
for (var object, index = 0; object = arguments[index]; index++) {
|
||||
for (var key in object) {
|
||||
iteratorData[key] = object[key];
|
||||
}
|
||||
}
|
||||
var args = iteratorData.args;
|
||||
iteratorData.firstArg = /^[^,]+/.exec(args)[0];
|
||||
|
||||
// create the function factory
|
||||
var factory = Function(
|
||||
'baseCreateCallback, errorClass, errorProto, hasOwnProperty, ' +
|
||||
'indicatorObject, isArguments, isArray, isString, keys, objectProto, ' +
|
||||
'objectTypes, nonEnumProps, stringClass, stringProto, toString',
|
||||
'return function(' + args + ') {\n' + iteratorTemplate(iteratorData) + '\n}'
|
||||
);
|
||||
|
||||
// return the compiled function
|
||||
return factory(
|
||||
baseCreateCallback, errorClass, errorProto, hasOwnProperty,
|
||||
indicatorObject, isArguments, isArray, isString, iteratorData.keys, objectProto,
|
||||
objectTypes, nonEnumProps, stringClass, stringProto, toString
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by `escape` to convert characters to HTML entities.
|
||||
*
|
||||
* @private
|
||||
* @param {string} match The matched character to escape.
|
||||
* @returns {string} Returns the escaped character.
|
||||
*/
|
||||
function escapeHtmlChar(match) {
|
||||
return htmlEscapes[match];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the appropriate "indexOf" function. If the `_.indexOf` method is
|
||||
* customized, this method returns the custom method, otherwise it returns
|
||||
* the `baseIndexOf` function.
|
||||
*
|
||||
* @private
|
||||
* @returns {Function} Returns the "indexOf" function.
|
||||
*/
|
||||
function getIndexOf() {
|
||||
var result = (result = lodash.indexOf) === indexOf ? baseIndexOf : result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if `value` is a native function.
|
||||
*
|
||||
* @private
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if the `value` is a native function, else `false`.
|
||||
*/
|
||||
function isNative(value) {
|
||||
return typeof value == 'function' && reNative.test(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets `this` binding data on a given function.
|
||||
*
|
||||
* @private
|
||||
* @param {Function} func The function to set data on.
|
||||
* @param {Array} value The data array to set.
|
||||
*/
|
||||
var setBindData = !defineProperty ? noop : function(func, value) {
|
||||
descriptor.value = value;
|
||||
defineProperty(func, '__bindData__', descriptor);
|
||||
};
|
||||
|
||||
/**
|
||||
* A fallback implementation of `isPlainObject` which checks if a given value
|
||||
* is an object created by the `Object` constructor, assuming objects created
|
||||
* by the `Object` constructor have no inherited enumerable properties and that
|
||||
* there are no `Object.prototype` extensions.
|
||||
*
|
||||
* @private
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
|
||||
*/
|
||||
function shimIsPlainObject(value) {
|
||||
var ctor,
|
||||
result;
|
||||
|
||||
// avoid non Object objects, `arguments` objects, and DOM elements
|
||||
if (!(value && toString.call(value) == objectClass) ||
|
||||
(ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor)) ||
|
||||
(!support.argsClass && isArguments(value)) ||
|
||||
(!support.nodeClass && isNode(value))) {
|
||||
return false;
|
||||
}
|
||||
// IE < 9 iterates inherited properties before own properties. If the first
|
||||
// iterated property is an object's own property then there are no inherited
|
||||
// enumerable properties.
|
||||
if (support.ownLast) {
|
||||
forIn(value, function(value, key, object) {
|
||||
result = hasOwnProperty.call(object, key);
|
||||
return false;
|
||||
});
|
||||
return result !== false;
|
||||
}
|
||||
// In most environments an object's own properties are iterated before
|
||||
// its inherited properties. If the last iterated property is an object's
|
||||
// own property then there are no inherited enumerable properties.
|
||||
forIn(value, function(value, key) {
|
||||
result = key;
|
||||
});
|
||||
return typeof result == 'undefined' || hasOwnProperty.call(value, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by `unescape` to convert HTML entities to characters.
|
||||
*
|
||||
* @private
|
||||
* @param {string} match The matched character to unescape.
|
||||
* @returns {string} Returns the unescaped character.
|
||||
*/
|
||||
function unescapeHtmlChar(match) {
|
||||
return htmlUnescapes[match];
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Checks if `value` is an `arguments` object.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if the `value` is an `arguments` object, else `false`.
|
||||
* @example
|
||||
*
|
||||
* (function() { return _.isArguments(arguments); })(1, 2, 3);
|
||||
* // => true
|
||||
*
|
||||
* _.isArguments([1, 2, 3]);
|
||||
* // => false
|
||||
*/
|
||||
function isArguments(value) {
|
||||
return value && typeof value == 'object' && typeof value.length == 'number' &&
|
||||
toString.call(value) == argsClass || false;
|
||||
}
|
||||
// fallback for browsers that can't detect `arguments` objects by [[Class]]
|
||||
if (!support.argsClass) {
|
||||
isArguments = function(value) {
|
||||
return value && typeof value == 'object' && typeof value.length == 'number' &&
|
||||
hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee') || false;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if `value` is an array.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @type Function
|
||||
* @category Objects
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if the `value` is an array, else `false`.
|
||||
* @example
|
||||
*
|
||||
* (function() { return _.isArray(arguments); })();
|
||||
* // => false
|
||||
*
|
||||
* _.isArray([1, 2, 3]);
|
||||
* // => true
|
||||
*/
|
||||
var isArray = nativeIsArray || function(value) {
|
||||
return value && typeof value == 'object' && typeof value.length == 'number' &&
|
||||
toString.call(value) == arrayClass || false;
|
||||
};
|
||||
|
||||
/**
|
||||
* A fallback implementation of `Object.keys` which produces an array of the
|
||||
* given object's own enumerable property names.
|
||||
*
|
||||
* @private
|
||||
* @type Function
|
||||
* @param {Object} object The object to inspect.
|
||||
* @returns {Array} Returns an array of property names.
|
||||
*/
|
||||
var shimKeys = createIterator({
|
||||
'args': 'object',
|
||||
'init': '[]',
|
||||
'top': 'if (!(objectTypes[typeof object])) return result',
|
||||
'loop': 'result.push(index)'
|
||||
});
|
||||
|
||||
/**
|
||||
* Creates an array composed of the own enumerable property names of an object.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {Object} object The object to inspect.
|
||||
* @returns {Array} Returns an array of property names.
|
||||
* @example
|
||||
*
|
||||
* _.keys({ 'one': 1, 'two': 2, 'three': 3 });
|
||||
* // => ['one', 'two', 'three'] (property order is not guaranteed across environments)
|
||||
*/
|
||||
var keys = !nativeKeys ? shimKeys : function(object) {
|
||||
if (!isObject(object)) {
|
||||
return [];
|
||||
}
|
||||
if ((support.enumPrototypes && typeof object == 'function') ||
|
||||
(support.nonEnumArgs && object.length && isArguments(object))) {
|
||||
return shimKeys(object);
|
||||
}
|
||||
return nativeKeys(object);
|
||||
};
|
||||
|
||||
/** Reusable iterator options shared by `each`, `forIn`, and `forOwn` */
|
||||
var eachIteratorOptions = {
|
||||
'args': 'collection, callback, thisArg',
|
||||
'top': "callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3)",
|
||||
'array': "typeof length == 'number'",
|
||||
'keys': keys,
|
||||
'loop': 'if (callback(iterable[index], index, collection) === false) return result'
|
||||
};
|
||||
|
||||
/** Reusable iterator options for `assign` and `defaults` */
|
||||
var defaultsIteratorOptions = {
|
||||
'args': 'object, source, guard',
|
||||
'top':
|
||||
'var args = arguments,\n' +
|
||||
' argsIndex = 0,\n' +
|
||||
" argsLength = typeof guard == 'number' ? 2 : args.length;\n" +
|
||||
'while (++argsIndex < argsLength) {\n' +
|
||||
' iterable = args[argsIndex];\n' +
|
||||
' if (iterable && objectTypes[typeof iterable]) {',
|
||||
'keys': keys,
|
||||
'loop': "if (typeof result[index] == 'undefined') result[index] = iterable[index]",
|
||||
'bottom': ' }\n}'
|
||||
};
|
||||
|
||||
/** Reusable iterator options for `forIn` and `forOwn` */
|
||||
var forOwnIteratorOptions = {
|
||||
'top': 'if (!objectTypes[typeof iterable]) return result;\n' + eachIteratorOptions.top,
|
||||
'array': false
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to convert characters to HTML entities:
|
||||
*
|
||||
* Though the `>` character is escaped for symmetry, characters like `>` and `/`
|
||||
* don't require escaping in HTML and have no special meaning unless they're part
|
||||
* of a tag or an unquoted attribute value.
|
||||
* http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact")
|
||||
*/
|
||||
var htmlEscapes = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": '''
|
||||
};
|
||||
|
||||
/** Used to convert HTML entities to characters */
|
||||
var htmlUnescapes = invert(htmlEscapes);
|
||||
|
||||
/** Used to match HTML entities and HTML characters */
|
||||
var reEscapedHtml = RegExp('(' + keys(htmlUnescapes).join('|') + ')', 'g'),
|
||||
reUnescapedHtml = RegExp('[' + keys(htmlEscapes).join('') + ']', 'g');
|
||||
|
||||
/**
|
||||
* A function compiled to iterate `arguments` objects, arrays, objects, and
|
||||
* strings consistenly across environments, executing the callback for each
|
||||
* element in the collection. The callback is bound to `thisArg` and invoked
|
||||
* with three arguments; (value, index|key, collection). Callbacks may exit
|
||||
* iteration early by explicitly returning `false`.
|
||||
*
|
||||
* @private
|
||||
* @type Function
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {Function} [callback=identity] The function called per iteration.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Array|Object|string} Returns `collection`.
|
||||
*/
|
||||
var baseEach = createIterator(eachIteratorOptions);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Assigns own enumerable properties of source object(s) to the destination
|
||||
* object. Subsequent sources will overwrite property assignments of previous
|
||||
* sources. If a callback is provided it will be executed to produce the
|
||||
* assigned values. The callback is bound to `thisArg` and invoked with two
|
||||
* arguments; (objectValue, sourceValue).
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @type Function
|
||||
* @alias extend
|
||||
* @category Objects
|
||||
* @param {Object} object The destination object.
|
||||
* @param {...Object} [source] The source objects.
|
||||
* @param {Function} [callback] The function to customize assigning values.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Object} Returns the destination object.
|
||||
* @example
|
||||
*
|
||||
* _.assign({ 'name': 'fred' }, { 'employer': 'slate' });
|
||||
* // => { 'name': 'fred', 'employer': 'slate' }
|
||||
*
|
||||
* var defaults = _.partialRight(_.assign, function(a, b) {
|
||||
* return typeof a == 'undefined' ? b : a;
|
||||
* });
|
||||
*
|
||||
* var object = { 'name': 'barney' };
|
||||
* defaults(object, { 'name': 'fred', 'employer': 'slate' });
|
||||
* // => { 'name': 'barney', 'employer': 'slate' }
|
||||
*/
|
||||
var assign = createIterator(defaultsIteratorOptions, {
|
||||
'top':
|
||||
defaultsIteratorOptions.top.replace(';',
|
||||
';\n' +
|
||||
"if (argsLength > 3 && typeof args[argsLength - 2] == 'function') {\n" +
|
||||
' var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2);\n' +
|
||||
"} else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {\n" +
|
||||
' callback = args[--argsLength];\n' +
|
||||
'}'
|
||||
),
|
||||
'loop': 'result[index] = callback ? callback(result[index], iterable[index]) : iterable[index]'
|
||||
});
|
||||
|
||||
/**
|
||||
* Creates a clone of `value`. If `isDeep` is `true` nested objects will also
|
||||
* be cloned, otherwise they will be assigned by reference. If a callback
|
||||
* is provided it will be executed to produce the cloned values. If the
|
||||
* callback returns `undefined` cloning will be handled by the method instead.
|
||||
* The callback is bound to `thisArg` and invoked with one argument; (value).
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {*} value The value to clone.
|
||||
* @param {boolean} [isDeep=false] Specify a deep clone.
|
||||
* @param {Function} [callback] The function to customize cloning values.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {*} Returns the cloned value.
|
||||
* @example
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'barney', 'age': 36 },
|
||||
* { 'name': 'fred', 'age': 40 }
|
||||
* ];
|
||||
*
|
||||
* var shallow = _.clone(characters);
|
||||
* shallow[0] === characters[0];
|
||||
* // => true
|
||||
*
|
||||
* var deep = _.clone(characters, true);
|
||||
* deep[0] === characters[0];
|
||||
* // => false
|
||||
*
|
||||
* _.mixin({
|
||||
* 'clone': _.partialRight(_.clone, function(value) {
|
||||
* return _.isElement(value) ? value.cloneNode(false) : undefined;
|
||||
* })
|
||||
* });
|
||||
*
|
||||
* var clone = _.clone(document.body);
|
||||
* clone.childNodes.length;
|
||||
* // => 0
|
||||
*/
|
||||
function clone(value, isDeep, callback, thisArg) {
|
||||
// allows working with "Collections" methods without using their `index`
|
||||
// and `collection` arguments for `isDeep` and `callback`
|
||||
if (typeof isDeep != 'boolean' && isDeep != null) {
|
||||
thisArg = callback;
|
||||
callback = isDeep;
|
||||
isDeep = false;
|
||||
}
|
||||
return baseClone(value, isDeep, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a deep clone of `value`. If a callback is provided it will be
|
||||
* executed to produce the cloned values. If the callback returns `undefined`
|
||||
* cloning will be handled by the method instead. The callback is bound to
|
||||
* `thisArg` and invoked with one argument; (value).
|
||||
*
|
||||
* Note: This method is loosely based on the structured clone algorithm. Functions
|
||||
* and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and
|
||||
* objects created by constructors other than `Object` are cloned to plain `Object` objects.
|
||||
* See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {*} value The value to deep clone.
|
||||
* @param {Function} [callback] The function to customize cloning values.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {*} Returns the deep cloned value.
|
||||
* @example
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'barney', 'age': 36 },
|
||||
* { 'name': 'fred', 'age': 40 }
|
||||
* ];
|
||||
*
|
||||
* var deep = _.cloneDeep(characters);
|
||||
* deep[0] === characters[0];
|
||||
* // => false
|
||||
*
|
||||
* var view = {
|
||||
* 'label': 'docs',
|
||||
* 'node': element
|
||||
* };
|
||||
*
|
||||
* var clone = _.cloneDeep(view, function(value) {
|
||||
* return _.isElement(value) ? value.cloneNode(true) : undefined;
|
||||
* });
|
||||
*
|
||||
* clone.node == view.node;
|
||||
* // => false
|
||||
*/
|
||||
function cloneDeep(value, callback, thisArg) {
|
||||
return baseClone(value, true, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an object that inherits from the given `prototype` object. If a
|
||||
* `properties` object is provided its own enumerable properties are assigned
|
||||
* to the created object.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {Object} prototype The object to inherit from.
|
||||
* @param {Object} [properties] The properties to assign to the object.
|
||||
* @returns {Object} Returns the new object.
|
||||
* @example
|
||||
*
|
||||
* function Shape() {
|
||||
* this.x = 0;
|
||||
* this.y = 0;
|
||||
* }
|
||||
*
|
||||
* function Circle() {
|
||||
* Shape.call(this);
|
||||
* }
|
||||
*
|
||||
* Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle });
|
||||
*
|
||||
* var circle = new Circle;
|
||||
* circle instanceof Circle;
|
||||
* // => true
|
||||
*
|
||||
* circle instanceof Shape;
|
||||
* // => true
|
||||
*/
|
||||
function create(prototype, properties) {
|
||||
var result = baseCreate(prototype);
|
||||
return properties ? assign(result, properties) : result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns own enumerable properties of source object(s) to the destination
|
||||
* object for all destination properties that resolve to `undefined`. Once a
|
||||
* property is set, additional defaults of the same property will be ignored.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @type Function
|
||||
* @category Objects
|
||||
* @param {Object} object The destination object.
|
||||
* @param {...Object} [source] The source objects.
|
||||
* @param- {Object} [guard] Allows working with `_.reduce` without using its
|
||||
* `key` and `object` arguments as sources.
|
||||
* @returns {Object} Returns the destination object.
|
||||
* @example
|
||||
*
|
||||
* var object = { 'name': 'barney' };
|
||||
* _.defaults(object, { 'name': 'fred', 'employer': 'slate' });
|
||||
* // => { 'name': 'barney', 'employer': 'slate' }
|
||||
*/
|
||||
var defaults = createIterator(defaultsIteratorOptions);
|
||||
|
||||
/**
|
||||
* This method is like `_.findIndex` except that it returns the key of the
|
||||
* first element that passes the callback check, instead of the element itself.
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {Object} object The object to search.
|
||||
* @param {Function|Object|string} [callback=identity] The function called per
|
||||
* iteration. If a property name or object is provided it will be used to
|
||||
* create a "_.pluck" or "_.where" style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {string|undefined} Returns the key of the found element, else `undefined`.
|
||||
* @example
|
||||
*
|
||||
* var characters = {
|
||||
* 'barney': { 'age': 36, 'blocked': false },
|
||||
* 'fred': { 'age': 40, 'blocked': true },
|
||||
* 'pebbles': { 'age': 1, 'blocked': false }
|
||||
* };
|
||||
*
|
||||
* _.findKey(characters, function(chr) {
|
||||
* return chr.age < 40;
|
||||
* });
|
||||
* // => 'barney' (property order is not guaranteed across environments)
|
||||
*
|
||||
* // using "_.where" callback shorthand
|
||||
* _.findKey(characters, { 'age': 1 });
|
||||
* // => 'pebbles'
|
||||
*
|
||||
* // using "_.pluck" callback shorthand
|
||||
* _.findKey(characters, 'blocked');
|
||||
* // => 'fred'
|
||||
*/
|
||||
function findKey(object, callback, thisArg) {
|
||||
var result;
|
||||
callback = lodash.createCallback(callback, thisArg, 3);
|
||||
forOwn(object, function(value, key, object) {
|
||||
if (callback(value, key, object)) {
|
||||
result = key;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is like `_.findKey` except that it iterates over elements
|
||||
* of a `collection` in the opposite order.
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {Object} object The object to search.
|
||||
* @param {Function|Object|string} [callback=identity] The function called per
|
||||
* iteration. If a property name or object is provided it will be used to
|
||||
* create a "_.pluck" or "_.where" style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {string|undefined} Returns the key of the found element, else `undefined`.
|
||||
* @example
|
||||
*
|
||||
* var characters = {
|
||||
* 'barney': { 'age': 36, 'blocked': true },
|
||||
* 'fred': { 'age': 40, 'blocked': false },
|
||||
* 'pebbles': { 'age': 1, 'blocked': true }
|
||||
* };
|
||||
*
|
||||
* _.findLastKey(characters, function(chr) {
|
||||
* return chr.age < 40;
|
||||
* });
|
||||
* // => returns `pebbles`, assuming `_.findKey` returns `barney`
|
||||
*
|
||||
* // using "_.where" callback shorthand
|
||||
* _.findLastKey(characters, { 'age': 40 });
|
||||
* // => 'fred'
|
||||
*
|
||||
* // using "_.pluck" callback shorthand
|
||||
* _.findLastKey(characters, 'blocked');
|
||||
* // => 'pebbles'
|
||||
*/
|
||||
function findLastKey(object, callback, thisArg) {
|
||||
var result;
|
||||
callback = lodash.createCallback(callback, thisArg, 3);
|
||||
forOwnRight(object, function(value, key, object) {
|
||||
if (callback(value, key, object)) {
|
||||
result = key;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over own and inherited enumerable properties of an object,
|
||||
* executing the callback for each property. The callback is bound to `thisArg`
|
||||
* and invoked with three arguments; (value, key, object). Callbacks may exit
|
||||
* iteration early by explicitly returning `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @type Function
|
||||
* @category Objects
|
||||
* @param {Object} object The object to iterate over.
|
||||
* @param {Function} [callback=identity] The function called per iteration.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Object} Returns `object`.
|
||||
* @example
|
||||
*
|
||||
* function Shape() {
|
||||
* this.x = 0;
|
||||
* this.y = 0;
|
||||
* }
|
||||
*
|
||||
* Shape.prototype.move = function(x, y) {
|
||||
* this.x += x;
|
||||
* this.y += y;
|
||||
* };
|
||||
*
|
||||
* _.forIn(new Shape, function(value, key) {
|
||||
* console.log(key);
|
||||
* });
|
||||
* // => logs 'x', 'y', and 'move' (property order is not guaranteed across environments)
|
||||
*/
|
||||
var forIn = createIterator(eachIteratorOptions, forOwnIteratorOptions, {
|
||||
'useHas': false
|
||||
});
|
||||
|
||||
/**
|
||||
* This method is like `_.forIn` except that it iterates over elements
|
||||
* of a `collection` in the opposite order.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {Object} object The object to iterate over.
|
||||
* @param {Function} [callback=identity] The function called per iteration.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Object} Returns `object`.
|
||||
* @example
|
||||
*
|
||||
* function Shape() {
|
||||
* this.x = 0;
|
||||
* this.y = 0;
|
||||
* }
|
||||
*
|
||||
* Shape.prototype.move = function(x, y) {
|
||||
* this.x += x;
|
||||
* this.y += y;
|
||||
* };
|
||||
*
|
||||
* _.forInRight(new Shape, function(value, key) {
|
||||
* console.log(key);
|
||||
* });
|
||||
* // => logs 'move', 'y', and 'x' assuming `_.forIn ` logs 'x', 'y', and 'move'
|
||||
*/
|
||||
function forInRight(object, callback, thisArg) {
|
||||
var pairs = [];
|
||||
|
||||
forIn(object, function(value, key) {
|
||||
pairs.push(key, value);
|
||||
});
|
||||
|
||||
var length = pairs.length;
|
||||
callback = baseCreateCallback(callback, thisArg, 3);
|
||||
while (length--) {
|
||||
if (callback(pairs[length--], pairs[length], object) === false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over own enumerable properties of an object, executing the callback
|
||||
* for each property. The callback is bound to `thisArg` and invoked with three
|
||||
* arguments; (value, key, object). Callbacks may exit iteration early by
|
||||
* explicitly returning `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @type Function
|
||||
* @category Objects
|
||||
* @param {Object} object The object to iterate over.
|
||||
* @param {Function} [callback=identity] The function called per iteration.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Object} Returns `object`.
|
||||
* @example
|
||||
*
|
||||
* _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
|
||||
* console.log(key);
|
||||
* });
|
||||
* // => logs '0', '1', and 'length' (property order is not guaranteed across environments)
|
||||
*/
|
||||
var forOwn = createIterator(eachIteratorOptions, forOwnIteratorOptions);
|
||||
|
||||
/**
|
||||
* This method is like `_.forOwn` except that it iterates over elements
|
||||
* of a `collection` in the opposite order.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {Object} object The object to iterate over.
|
||||
* @param {Function} [callback=identity] The function called per iteration.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Object} Returns `object`.
|
||||
* @example
|
||||
*
|
||||
* _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
|
||||
* console.log(key);
|
||||
* });
|
||||
* // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length'
|
||||
*/
|
||||
function forOwnRight(object, callback, thisArg) {
|
||||
var props = keys(object),
|
||||
length = props.length;
|
||||
|
||||
callback = baseCreateCallback(callback, thisArg, 3);
|
||||
while (length--) {
|
||||
var key = props[length];
|
||||
if (callback(object[key], key, object) === false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a sorted array of property names of all enumerable properties,
|
||||
* own and inherited, of `object` that have function values.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @alias methods
|
||||
* @category Objects
|
||||
* @param {Object} object The object to inspect.
|
||||
* @returns {Array} Returns an array of property names that have function values.
|
||||
* @example
|
||||
*
|
||||
* _.functions(_);
|
||||
* // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
|
||||
*/
|
||||
function functions(object) {
|
||||
var result = [];
|
||||
forIn(object, function(value, key) {
|
||||
if (isFunction(value)) {
|
||||
result.push(key);
|
||||
}
|
||||
});
|
||||
return result.sort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified property name exists as a direct property of `object`,
|
||||
* instead of an inherited property.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {Object} object The object to inspect.
|
||||
* @param {string} key The name of the property to check.
|
||||
* @returns {boolean} Returns `true` if key is a direct property, else `false`.
|
||||
* @example
|
||||
*
|
||||
* _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
|
||||
* // => true
|
||||
*/
|
||||
function has(object, key) {
|
||||
return object ? hasOwnProperty.call(object, key) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an object composed of the inverted keys and values of the given object.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {Object} object The object to invert.
|
||||
* @returns {Object} Returns the created inverted object.
|
||||
* @example
|
||||
*
|
||||
* _.invert({ 'first': 'fred', 'second': 'barney' });
|
||||
* // => { 'fred': 'first', 'barney': 'second' }
|
||||
*/
|
||||
function invert(object) {
|
||||
var index = -1,
|
||||
props = keys(object),
|
||||
length = props.length,
|
||||
result = {};
|
||||
|
||||
while (++index < length) {
|
||||
var key = props[index];
|
||||
result[object[key]] = key;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if `value` is a boolean value.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if the `value` is a boolean value, else `false`.
|
||||
* @example
|
||||
*
|
||||
* _.isBoolean(null);
|
||||
* // => false
|
||||
*/
|
||||
function isBoolean(value) {
|
||||
return value === true || value === false ||
|
||||
value && typeof value == 'object' && toString.call(value) == boolClass || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if `value` is a date.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if the `value` is a date, else `false`.
|
||||
* @example
|
||||
*
|
||||
* _.isDate(new Date);
|
||||
* // => true
|
||||
*/
|
||||
function isDate(value) {
|
||||
return value && typeof value == 'object' && toString.call(value) == dateClass || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if `value` is a DOM element.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if the `value` is a DOM element, else `false`.
|
||||
* @example
|
||||
*
|
||||
* _.isElement(document.body);
|
||||
* // => true
|
||||
*/
|
||||
function isElement(value) {
|
||||
return value && value.nodeType === 1 || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if `value` is empty. Arrays, strings, or `arguments` objects with a
|
||||
* length of `0` and objects with no own enumerable properties are considered
|
||||
* "empty".
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {Array|Object|string} value The value to inspect.
|
||||
* @returns {boolean} Returns `true` if the `value` is empty, else `false`.
|
||||
* @example
|
||||
*
|
||||
* _.isEmpty([1, 2, 3]);
|
||||
* // => false
|
||||
*
|
||||
* _.isEmpty({});
|
||||
* // => true
|
||||
*
|
||||
* _.isEmpty('');
|
||||
* // => true
|
||||
*/
|
||||
function isEmpty(value) {
|
||||
var result = true;
|
||||
if (!value) {
|
||||
return result;
|
||||
}
|
||||
var className = toString.call(value),
|
||||
length = value.length;
|
||||
|
||||
if ((className == arrayClass || className == stringClass ||
|
||||
(support.argsClass ? className == argsClass : isArguments(value))) ||
|
||||
(className == objectClass && typeof length == 'number' && isFunction(value.splice))) {
|
||||
return !length;
|
||||
}
|
||||
forOwn(value, function() {
|
||||
return (result = false);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a deep comparison between two values to determine if they are
|
||||
* equivalent to each other. If a callback is provided it will be executed
|
||||
* to compare values. If the callback returns `undefined` comparisons will
|
||||
* be handled by the method instead. The callback is bound to `thisArg` and
|
||||
* invoked with two arguments; (a, b).
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {*} a The value to compare.
|
||||
* @param {*} b The other value to compare.
|
||||
* @param {Function} [callback] The function to customize comparing values.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {boolean} Returns `true` if the values are equivalent, else `false`.
|
||||
* @example
|
||||
*
|
||||
* var object = { 'name': 'fred' };
|
||||
* var copy = { 'name': 'fred' };
|
||||
*
|
||||
* object == copy;
|
||||
* // => false
|
||||
*
|
||||
* _.isEqual(object, copy);
|
||||
* // => true
|
||||
*
|
||||
* var words = ['hello', 'goodbye'];
|
||||
* var otherWords = ['hi', 'goodbye'];
|
||||
*
|
||||
* _.isEqual(words, otherWords, function(a, b) {
|
||||
* var reGreet = /^(?:hello|hi)$/i,
|
||||
* aGreet = _.isString(a) && reGreet.test(a),
|
||||
* bGreet = _.isString(b) && reGreet.test(b);
|
||||
*
|
||||
* return (aGreet || bGreet) ? (aGreet == bGreet) : undefined;
|
||||
* });
|
||||
* // => true
|
||||
*/
|
||||
function isEqual(a, b, callback, thisArg) {
|
||||
return baseIsEqual(a, b, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if `value` is, or can be coerced to, a finite number.
|
||||
*
|
||||
* Note: This is not the same as native `isFinite` which will return true for
|
||||
* booleans and empty strings. See http://es5.github.io/#x15.1.2.5.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if the `value` is finite, else `false`.
|
||||
* @example
|
||||
*
|
||||
* _.isFinite(-101);
|
||||
* // => true
|
||||
*
|
||||
* _.isFinite('10');
|
||||
* // => true
|
||||
*
|
||||
* _.isFinite(true);
|
||||
* // => false
|
||||
*
|
||||
* _.isFinite('');
|
||||
* // => false
|
||||
*
|
||||
* _.isFinite(Infinity);
|
||||
* // => false
|
||||
*/
|
||||
function isFinite(value) {
|
||||
return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if `value` is a function.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if the `value` is a function, else `false`.
|
||||
* @example
|
||||
*
|
||||
* _.isFunction(_);
|
||||
* // => true
|
||||
*/
|
||||
function isFunction(value) {
|
||||
return typeof value == 'function';
|
||||
}
|
||||
// fallback for older versions of Chrome and Safari
|
||||
if (isFunction(/x/)) {
|
||||
isFunction = function(value) {
|
||||
return typeof value == 'function' && toString.call(value) == funcClass;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if `value` is the language type of Object.
|
||||
* (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if the `value` is an object, else `false`.
|
||||
* @example
|
||||
*
|
||||
* _.isObject({});
|
||||
* // => true
|
||||
*
|
||||
* _.isObject([1, 2, 3]);
|
||||
* // => true
|
||||
*
|
||||
* _.isObject(1);
|
||||
* // => false
|
||||
*/
|
||||
function isObject(value) {
|
||||
// check if the value is the ECMAScript language type of Object
|
||||
// http://es5.github.io/#x8
|
||||
// and avoid a V8 bug
|
||||
// http://code.google.com/p/v8/issues/detail?id=2291
|
||||
return !!(value && objectTypes[typeof value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if `value` is `NaN`.
|
||||
*
|
||||
* Note: This is not the same as native `isNaN` which will return `true` for
|
||||
* `undefined` and other non-numeric values. See http://es5.github.io/#x15.1.2.4.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if the `value` is `NaN`, else `false`.
|
||||
* @example
|
||||
*
|
||||
* _.isNaN(NaN);
|
||||
* // => true
|
||||
*
|
||||
* _.isNaN(new Number(NaN));
|
||||
* // => true
|
||||
*
|
||||
* isNaN(undefined);
|
||||
* // => true
|
||||
*
|
||||
* _.isNaN(undefined);
|
||||
* // => false
|
||||
*/
|
||||
function isNaN(value) {
|
||||
// `NaN` as a primitive is the only value that is not equal to itself
|
||||
// (perform the [[Class]] check first to avoid errors with some host objects in IE)
|
||||
return isNumber(value) && value != +value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if `value` is `null`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if the `value` is `null`, else `false`.
|
||||
* @example
|
||||
*
|
||||
* _.isNull(null);
|
||||
* // => true
|
||||
*
|
||||
* _.isNull(undefined);
|
||||
* // => false
|
||||
*/
|
||||
function isNull(value) {
|
||||
return value === null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if `value` is a number.
|
||||
*
|
||||
* Note: `NaN` is considered a number. See http://es5.github.io/#x8.5.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if the `value` is a number, else `false`.
|
||||
* @example
|
||||
*
|
||||
* _.isNumber(8.4 * 5);
|
||||
* // => true
|
||||
*/
|
||||
function isNumber(value) {
|
||||
return typeof value == 'number' ||
|
||||
value && typeof value == 'object' && toString.call(value) == numberClass || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if `value` is an object created by the `Object` constructor.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
|
||||
* @example
|
||||
*
|
||||
* function Shape() {
|
||||
* this.x = 0;
|
||||
* this.y = 0;
|
||||
* }
|
||||
*
|
||||
* _.isPlainObject(new Shape);
|
||||
* // => false
|
||||
*
|
||||
* _.isPlainObject([1, 2, 3]);
|
||||
* // => false
|
||||
*
|
||||
* _.isPlainObject({ 'x': 0, 'y': 0 });
|
||||
* // => true
|
||||
*/
|
||||
var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) {
|
||||
if (!(value && toString.call(value) == objectClass) || (!support.argsClass && isArguments(value))) {
|
||||
return false;
|
||||
}
|
||||
var valueOf = value.valueOf,
|
||||
objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
|
||||
|
||||
return objProto
|
||||
? (value == objProto || getPrototypeOf(value) == objProto)
|
||||
: shimIsPlainObject(value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if `value` is a regular expression.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if the `value` is a regular expression, else `false`.
|
||||
* @example
|
||||
*
|
||||
* _.isRegExp(/fred/);
|
||||
* // => true
|
||||
*/
|
||||
function isRegExp(value) {
|
||||
return value && objectTypes[typeof value] && toString.call(value) == regexpClass || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if `value` is a string.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if the `value` is a string, else `false`.
|
||||
* @example
|
||||
*
|
||||
* _.isString('fred');
|
||||
* // => true
|
||||
*/
|
||||
function isString(value) {
|
||||
return typeof value == 'string' ||
|
||||
value && typeof value == 'object' && toString.call(value) == stringClass || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if `value` is `undefined`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if the `value` is `undefined`, else `false`.
|
||||
* @example
|
||||
*
|
||||
* _.isUndefined(void 0);
|
||||
* // => true
|
||||
*/
|
||||
function isUndefined(value) {
|
||||
return typeof value == 'undefined';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an object with the same keys as `object` and values generated by
|
||||
* running each own enumerable property of `object` through the callback.
|
||||
* The callback is bound to `thisArg` and invoked with three arguments;
|
||||
* (value, key, object).
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {Object} object The object to iterate over.
|
||||
* @param {Function|Object|string} [callback=identity] The function called
|
||||
* per iteration. If a property name or object is provided it will be used
|
||||
* to create a "_.pluck" or "_.where" style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Array} Returns a new object with values of the results of each `callback` execution.
|
||||
* @example
|
||||
*
|
||||
* _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; });
|
||||
* // => { 'a': 3, 'b': 6, 'c': 9 }
|
||||
*
|
||||
* var characters = {
|
||||
* 'fred': { 'name': 'fred', 'age': 40 },
|
||||
* 'pebbles': { 'name': 'pebbles', 'age': 1 }
|
||||
* };
|
||||
*
|
||||
* // using "_.pluck" callback shorthand
|
||||
* _.mapValues(characters, 'age');
|
||||
* // => { 'fred': 40, 'pebbles': 1 }
|
||||
*/
|
||||
function mapValues(object, callback, thisArg) {
|
||||
var result = {};
|
||||
callback = lodash.createCallback(callback, thisArg, 3);
|
||||
|
||||
forOwn(object, function(value, key, object) {
|
||||
result[key] = callback(value, key, object);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively merges own enumerable properties of the source object(s), that
|
||||
* don't resolve to `undefined` into the destination object. Subsequent sources
|
||||
* will overwrite property assignments of previous sources. If a callback is
|
||||
* provided it will be executed to produce the merged values of the destination
|
||||
* and source properties. If the callback returns `undefined` merging will
|
||||
* be handled by the method instead. The callback is bound to `thisArg` and
|
||||
* invoked with two arguments; (objectValue, sourceValue).
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {Object} object The destination object.
|
||||
* @param {...Object} [source] The source objects.
|
||||
* @param {Function} [callback] The function to customize merging properties.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Object} Returns the destination object.
|
||||
* @example
|
||||
*
|
||||
* var names = {
|
||||
* 'characters': [
|
||||
* { 'name': 'barney' },
|
||||
* { 'name': 'fred' }
|
||||
* ]
|
||||
* };
|
||||
*
|
||||
* var ages = {
|
||||
* 'characters': [
|
||||
* { 'age': 36 },
|
||||
* { 'age': 40 }
|
||||
* ]
|
||||
* };
|
||||
*
|
||||
* _.merge(names, ages);
|
||||
* // => { 'characters': [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] }
|
||||
*
|
||||
* var food = {
|
||||
* 'fruits': ['apple'],
|
||||
* 'vegetables': ['beet']
|
||||
* };
|
||||
*
|
||||
* var otherFood = {
|
||||
* 'fruits': ['banana'],
|
||||
* 'vegetables': ['carrot']
|
||||
* };
|
||||
*
|
||||
* _.merge(food, otherFood, function(a, b) {
|
||||
* return _.isArray(a) ? a.concat(b) : undefined;
|
||||
* });
|
||||
* // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] }
|
||||
*/
|
||||
function merge(object) {
|
||||
var args = arguments,
|
||||
length = 2;
|
||||
|
||||
if (!isObject(object)) {
|
||||
return object;
|
||||
}
|
||||
// allows working with `_.reduce` and `_.reduceRight` without using
|
||||
// their `index` and `collection` arguments
|
||||
if (typeof args[2] != 'number') {
|
||||
length = args.length;
|
||||
}
|
||||
if (length > 3 && typeof args[length - 2] == 'function') {
|
||||
var callback = baseCreateCallback(args[--length - 1], args[length--], 2);
|
||||
} else if (length > 2 && typeof args[length - 1] == 'function') {
|
||||
callback = args[--length];
|
||||
}
|
||||
var sources = slice(arguments, 1, length),
|
||||
index = -1,
|
||||
stackA = getArray(),
|
||||
stackB = getArray();
|
||||
|
||||
while (++index < length) {
|
||||
baseMerge(object, sources[index], callback, stackA, stackB);
|
||||
}
|
||||
releaseArray(stackA);
|
||||
releaseArray(stackB);
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a shallow clone of `object` excluding the specified properties.
|
||||
* Property names may be specified as individual arguments or as arrays of
|
||||
* property names. If a callback is provided it will be executed for each
|
||||
* property of `object` omitting the properties the callback returns truey
|
||||
* for. The callback is bound to `thisArg` and invoked with three arguments;
|
||||
* (value, key, object).
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {Object} object The source object.
|
||||
* @param {Function|...string|string[]} [callback] The properties to omit or the
|
||||
* function called per iteration.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Object} Returns an object without the omitted properties.
|
||||
* @example
|
||||
*
|
||||
* _.omit({ 'name': 'fred', 'age': 40 }, 'age');
|
||||
* // => { 'name': 'fred' }
|
||||
*
|
||||
* _.omit({ 'name': 'fred', 'age': 40 }, function(value) {
|
||||
* return typeof value == 'number';
|
||||
* });
|
||||
* // => { 'name': 'fred' }
|
||||
*/
|
||||
function omit(object, callback, thisArg) {
|
||||
var result = {};
|
||||
if (typeof callback != 'function') {
|
||||
var props = [];
|
||||
forIn(object, function(value, key) {
|
||||
props.push(key);
|
||||
});
|
||||
props = baseDifference(props, baseFlatten(arguments, true, false, 1));
|
||||
|
||||
var index = -1,
|
||||
length = props.length;
|
||||
|
||||
while (++index < length) {
|
||||
var key = props[index];
|
||||
result[key] = object[key];
|
||||
}
|
||||
} else {
|
||||
callback = lodash.createCallback(callback, thisArg, 3);
|
||||
forIn(object, function(value, key, object) {
|
||||
if (!callback(value, key, object)) {
|
||||
result[key] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a two dimensional array of an object's key-value pairs,
|
||||
* i.e. `[[key1, value1], [key2, value2]]`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {Object} object The object to inspect.
|
||||
* @returns {Array} Returns new array of key-value pairs.
|
||||
* @example
|
||||
*
|
||||
* _.pairs({ 'barney': 36, 'fred': 40 });
|
||||
* // => [['barney', 36], ['fred', 40]] (property order is not guaranteed across environments)
|
||||
*/
|
||||
function pairs(object) {
|
||||
var index = -1,
|
||||
props = keys(object),
|
||||
length = props.length,
|
||||
result = Array(length);
|
||||
|
||||
while (++index < length) {
|
||||
var key = props[index];
|
||||
result[index] = [key, object[key]];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a shallow clone of `object` composed of the specified properties.
|
||||
* Property names may be specified as individual arguments or as arrays of
|
||||
* property names. If a callback is provided it will be executed for each
|
||||
* property of `object` picking the properties the callback returns truey
|
||||
* for. The callback is bound to `thisArg` and invoked with three arguments;
|
||||
* (value, key, object).
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {Object} object The source object.
|
||||
* @param {Function|...string|string[]} [callback] The function called per
|
||||
* iteration or property names to pick, specified as individual property
|
||||
* names or arrays of property names.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Object} Returns an object composed of the picked properties.
|
||||
* @example
|
||||
*
|
||||
* _.pick({ 'name': 'fred', '_userid': 'fred1' }, 'name');
|
||||
* // => { 'name': 'fred' }
|
||||
*
|
||||
* _.pick({ 'name': 'fred', '_userid': 'fred1' }, function(value, key) {
|
||||
* return key.charAt(0) != '_';
|
||||
* });
|
||||
* // => { 'name': 'fred' }
|
||||
*/
|
||||
function pick(object, callback, thisArg) {
|
||||
var result = {};
|
||||
if (typeof callback != 'function') {
|
||||
var index = -1,
|
||||
props = baseFlatten(arguments, true, false, 1),
|
||||
length = isObject(object) ? props.length : 0;
|
||||
|
||||
while (++index < length) {
|
||||
var key = props[index];
|
||||
if (key in object) {
|
||||
result[key] = object[key];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
callback = lodash.createCallback(callback, thisArg, 3);
|
||||
forIn(object, function(value, key, object) {
|
||||
if (callback(value, key, object)) {
|
||||
result[key] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* An alternative to `_.reduce` this method transforms `object` to a new
|
||||
* `accumulator` object which is the result of running each of its own
|
||||
* enumerable properties through a callback, with each callback execution
|
||||
* potentially mutating the `accumulator` object. The callback is bound to
|
||||
* `thisArg` and invoked with four arguments; (accumulator, value, key, object).
|
||||
* Callbacks may exit iteration early by explicitly returning `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {Array|Object} object The object to iterate over.
|
||||
* @param {Function} [callback=identity] The function called per iteration.
|
||||
* @param {*} [accumulator] The custom accumulator value.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {*} Returns the accumulated value.
|
||||
* @example
|
||||
*
|
||||
* var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) {
|
||||
* num *= num;
|
||||
* if (num % 2) {
|
||||
* return result.push(num) < 3;
|
||||
* }
|
||||
* });
|
||||
* // => [1, 9, 25]
|
||||
*
|
||||
* var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
|
||||
* result[key] = num * 3;
|
||||
* });
|
||||
* // => { 'a': 3, 'b': 6, 'c': 9 }
|
||||
*/
|
||||
function transform(object, callback, accumulator, thisArg) {
|
||||
var isArr = isArray(object);
|
||||
if (accumulator == null) {
|
||||
if (isArr) {
|
||||
accumulator = [];
|
||||
} else {
|
||||
var ctor = object && object.constructor,
|
||||
proto = ctor && ctor.prototype;
|
||||
|
||||
accumulator = baseCreate(proto);
|
||||
}
|
||||
}
|
||||
if (callback) {
|
||||
callback = lodash.createCallback(callback, thisArg, 4);
|
||||
(isArr ? baseEach : forOwn)(object, function(value, index, object) {
|
||||
return callback(accumulator, value, index, object);
|
||||
});
|
||||
}
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array composed of the own enumerable property values of `object`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {Object} object The object to inspect.
|
||||
* @returns {Array} Returns an array of property values.
|
||||
* @example
|
||||
*
|
||||
* _.values({ 'one': 1, 'two': 2, 'three': 3 });
|
||||
* // => [1, 2, 3] (property order is not guaranteed across environments)
|
||||
*/
|
||||
function values(object) {
|
||||
var index = -1,
|
||||
props = keys(object),
|
||||
length = props.length,
|
||||
result = Array(length);
|
||||
|
||||
while (++index < length) {
|
||||
result[index] = object[props[index]];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Creates an array of elements from the specified indexes, or keys, of the
|
||||
* `collection`. Indexes may be specified as individual arguments or as arrays
|
||||
* of indexes.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {...(number|number[]|string|string[])} [index] The indexes of `collection`
|
||||
* to retrieve, specified as individual indexes or arrays of indexes.
|
||||
* @returns {Array} Returns a new array of elements corresponding to the
|
||||
* provided indexes.
|
||||
* @example
|
||||
*
|
||||
* _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
|
||||
* // => ['a', 'c', 'e']
|
||||
*
|
||||
* _.at(['fred', 'barney', 'pebbles'], 0, 2);
|
||||
* // => ['fred', 'pebbles']
|
||||
*/
|
||||
function at(collection) {
|
||||
var args = arguments,
|
||||
index = -1,
|
||||
props = baseFlatten(args, true, false, 1),
|
||||
length = (args[2] && args[2][args[1]] === collection) ? 1 : props.length,
|
||||
result = Array(length);
|
||||
|
||||
if (support.unindexedChars && isString(collection)) {
|
||||
collection = collection.split('');
|
||||
}
|
||||
while(++index < length) {
|
||||
result[index] = collection[props[index]];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given value is present in a collection using strict equality
|
||||
* for comparisons, i.e. `===`. If `fromIndex` is negative, it is used as the
|
||||
* offset from the end of the collection.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @alias include
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {*} target The value to check for.
|
||||
* @param {number} [fromIndex=0] The index to search from.
|
||||
* @returns {boolean} Returns `true` if the `target` element is found, else `false`.
|
||||
* @example
|
||||
*
|
||||
* _.contains([1, 2, 3], 1);
|
||||
* // => true
|
||||
*
|
||||
* _.contains([1, 2, 3], 1, 2);
|
||||
* // => false
|
||||
*
|
||||
* _.contains({ 'name': 'fred', 'age': 40 }, 'fred');
|
||||
* // => true
|
||||
*
|
||||
* _.contains('pebbles', 'eb');
|
||||
* // => true
|
||||
*/
|
||||
function contains(collection, target, fromIndex) {
|
||||
var index = -1,
|
||||
indexOf = getIndexOf(),
|
||||
length = collection ? collection.length : 0,
|
||||
result = false;
|
||||
|
||||
fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0;
|
||||
if (isArray(collection)) {
|
||||
result = indexOf(collection, target, fromIndex) > -1;
|
||||
} else if (typeof length == 'number') {
|
||||
result = (isString(collection) ? collection.indexOf(target, fromIndex) : indexOf(collection, target, fromIndex)) > -1;
|
||||
} else {
|
||||
baseEach(collection, function(value) {
|
||||
if (++index >= fromIndex) {
|
||||
return !(result = value === target);
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an object composed of keys generated from the results of running
|
||||
* each element of `collection` through the callback. The corresponding value
|
||||
* of each key is the number of times the key was returned by the callback.
|
||||
* The callback is bound to `thisArg` and invoked with three arguments;
|
||||
* (value, index|key, collection).
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {Function|Object|string} [callback=identity] The function called
|
||||
* per iteration. If a property name or object is provided it will be used
|
||||
* to create a "_.pluck" or "_.where" style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Object} Returns the composed aggregate object.
|
||||
* @example
|
||||
*
|
||||
* _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); });
|
||||
* // => { '4': 1, '6': 2 }
|
||||
*
|
||||
* _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
|
||||
* // => { '4': 1, '6': 2 }
|
||||
*
|
||||
* _.countBy(['one', 'two', 'three'], 'length');
|
||||
* // => { '3': 2, '5': 1 }
|
||||
*/
|
||||
var countBy = createAggregator(function(result, value, key) {
|
||||
(hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1);
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks if the given callback returns truey value for **all** elements of
|
||||
* a collection. The callback is bound to `thisArg` and invoked with three
|
||||
* arguments; (value, index|key, collection).
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @alias all
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {Function|Object|string} [callback=identity] The function called
|
||||
* per iteration. If a property name or object is provided it will be used
|
||||
* to create a "_.pluck" or "_.where" style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {boolean} Returns `true` if all elements passed the callback check,
|
||||
* else `false`.
|
||||
* @example
|
||||
*
|
||||
* _.every([true, 1, null, 'yes']);
|
||||
* // => false
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'barney', 'age': 36 },
|
||||
* { 'name': 'fred', 'age': 40 }
|
||||
* ];
|
||||
*
|
||||
* // using "_.pluck" callback shorthand
|
||||
* _.every(characters, 'age');
|
||||
* // => true
|
||||
*
|
||||
* // using "_.where" callback shorthand
|
||||
* _.every(characters, { 'age': 36 });
|
||||
* // => false
|
||||
*/
|
||||
function every(collection, callback, thisArg) {
|
||||
var result = true;
|
||||
callback = lodash.createCallback(callback, thisArg, 3);
|
||||
|
||||
if (isArray(collection)) {
|
||||
var index = -1,
|
||||
length = collection.length;
|
||||
|
||||
while (++index < length) {
|
||||
if (!(result = !!callback(collection[index], index, collection))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
baseEach(collection, function(value, index, collection) {
|
||||
return (result = !!callback(value, index, collection));
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over elements of a collection, returning an array of all elements
|
||||
* the callback returns truey for. The callback is bound to `thisArg` and
|
||||
* invoked with three arguments; (value, index|key, collection).
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @alias select
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {Function|Object|string} [callback=identity] The function called
|
||||
* per iteration. If a property name or object is provided it will be used
|
||||
* to create a "_.pluck" or "_.where" style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Array} Returns a new array of elements that passed the callback check.
|
||||
* @example
|
||||
*
|
||||
* var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
|
||||
* // => [2, 4, 6]
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'barney', 'age': 36, 'blocked': false },
|
||||
* { 'name': 'fred', 'age': 40, 'blocked': true }
|
||||
* ];
|
||||
*
|
||||
* // using "_.pluck" callback shorthand
|
||||
* _.filter(characters, 'blocked');
|
||||
* // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
|
||||
*
|
||||
* // using "_.where" callback shorthand
|
||||
* _.filter(characters, { 'age': 36 });
|
||||
* // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
|
||||
*/
|
||||
function filter(collection, callback, thisArg) {
|
||||
var result = [];
|
||||
callback = lodash.createCallback(callback, thisArg, 3);
|
||||
|
||||
if (isArray(collection)) {
|
||||
var index = -1,
|
||||
length = collection.length;
|
||||
|
||||
while (++index < length) {
|
||||
var value = collection[index];
|
||||
if (callback(value, index, collection)) {
|
||||
result.push(value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
baseEach(collection, function(value, index, collection) {
|
||||
if (callback(value, index, collection)) {
|
||||
result.push(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over elements of a collection, returning the first element that
|
||||
* the callback returns truey for. The callback is bound to `thisArg` and
|
||||
* invoked with three arguments; (value, index|key, collection).
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @alias detect, findWhere
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {Function|Object|string} [callback=identity] The function called
|
||||
* per iteration. If a property name or object is provided it will be used
|
||||
* to create a "_.pluck" or "_.where" style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {*} Returns the found element, else `undefined`.
|
||||
* @example
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'barney', 'age': 36, 'blocked': false },
|
||||
* { 'name': 'fred', 'age': 40, 'blocked': true },
|
||||
* { 'name': 'pebbles', 'age': 1, 'blocked': false }
|
||||
* ];
|
||||
*
|
||||
* _.find(characters, function(chr) {
|
||||
* return chr.age < 40;
|
||||
* });
|
||||
* // => { 'name': 'barney', 'age': 36, 'blocked': false }
|
||||
*
|
||||
* // using "_.where" callback shorthand
|
||||
* _.find(characters, { 'age': 1 });
|
||||
* // => { 'name': 'pebbles', 'age': 1, 'blocked': false }
|
||||
*
|
||||
* // using "_.pluck" callback shorthand
|
||||
* _.find(characters, 'blocked');
|
||||
* // => { 'name': 'fred', 'age': 40, 'blocked': true }
|
||||
*/
|
||||
function find(collection, callback, thisArg) {
|
||||
callback = lodash.createCallback(callback, thisArg, 3);
|
||||
|
||||
if (isArray(collection)) {
|
||||
var index = -1,
|
||||
length = collection.length;
|
||||
|
||||
while (++index < length) {
|
||||
var value = collection[index];
|
||||
if (callback(value, index, collection)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var result;
|
||||
baseEach(collection, function(value, index, collection) {
|
||||
if (callback(value, index, collection)) {
|
||||
result = value;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is like `_.find` except that it iterates over elements
|
||||
* of a `collection` from right to left.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {Function|Object|string} [callback=identity] The function called
|
||||
* per iteration. If a property name or object is provided it will be used
|
||||
* to create a "_.pluck" or "_.where" style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {*} Returns the found element, else `undefined`.
|
||||
* @example
|
||||
*
|
||||
* _.findLast([1, 2, 3, 4], function(num) {
|
||||
* return num % 2 == 1;
|
||||
* });
|
||||
* // => 3
|
||||
*/
|
||||
function findLast(collection, callback, thisArg) {
|
||||
var result;
|
||||
callback = lodash.createCallback(callback, thisArg, 3);
|
||||
forEachRight(collection, function(value, index, collection) {
|
||||
if (callback(value, index, collection)) {
|
||||
result = value;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over elements of a collection, executing the callback for each
|
||||
* element. The callback is bound to `thisArg` and invoked with three arguments;
|
||||
* (value, index|key, collection). Callbacks may exit iteration early by
|
||||
* explicitly returning `false`.
|
||||
*
|
||||
* Note: As with other "Collections" methods, objects with a `length` property
|
||||
* are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
|
||||
* may be used for object iteration.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @alias each
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {Function} [callback=identity] The function called per iteration.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Array|Object|string} Returns `collection`.
|
||||
* @example
|
||||
*
|
||||
* _([1, 2, 3]).forEach(function(num) { console.log(num); }).join(',');
|
||||
* // => logs each number and returns '1,2,3'
|
||||
*
|
||||
* _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { console.log(num); });
|
||||
* // => logs each number and returns the object (property order is not guaranteed across environments)
|
||||
*/
|
||||
function forEach(collection, callback, thisArg) {
|
||||
if (callback && typeof thisArg == 'undefined' && isArray(collection)) {
|
||||
var index = -1,
|
||||
length = collection.length;
|
||||
|
||||
while (++index < length) {
|
||||
if (callback(collection[index], index, collection) === false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
baseEach(collection, callback, thisArg);
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is like `_.forEach` except that it iterates over elements
|
||||
* of a `collection` from right to left.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @alias eachRight
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {Function} [callback=identity] The function called per iteration.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Array|Object|string} Returns `collection`.
|
||||
* @example
|
||||
*
|
||||
* _([1, 2, 3]).forEachRight(function(num) { console.log(num); }).join(',');
|
||||
* // => logs each number from right to left and returns '3,2,1'
|
||||
*/
|
||||
function forEachRight(collection, callback, thisArg) {
|
||||
var iterable = collection,
|
||||
length = collection ? collection.length : 0;
|
||||
|
||||
callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);
|
||||
if (isArray(collection)) {
|
||||
while (length--) {
|
||||
if (callback(collection[length], length, collection) === false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (typeof length != 'number') {
|
||||
var props = keys(collection);
|
||||
length = props.length;
|
||||
} else if (support.unindexedChars && isString(collection)) {
|
||||
iterable = collection.split('');
|
||||
}
|
||||
baseEach(collection, function(value, key, collection) {
|
||||
key = props ? props[--length] : --length;
|
||||
return callback(iterable[key], key, collection);
|
||||
});
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an object composed of keys generated from the results of running
|
||||
* each element of a collection through the callback. The corresponding value
|
||||
* of each key is an array of the elements responsible for generating the key.
|
||||
* The callback is bound to `thisArg` and invoked with three arguments;
|
||||
* (value, index|key, collection).
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {Function|Object|string} [callback=identity] The function called
|
||||
* per iteration. If a property name or object is provided it will be used
|
||||
* to create a "_.pluck" or "_.where" style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Object} Returns the composed aggregate object.
|
||||
* @example
|
||||
*
|
||||
* _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); });
|
||||
* // => { '4': [4.2], '6': [6.1, 6.4] }
|
||||
*
|
||||
* _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
|
||||
* // => { '4': [4.2], '6': [6.1, 6.4] }
|
||||
*
|
||||
* // using "_.pluck" callback shorthand
|
||||
* _.groupBy(['one', 'two', 'three'], 'length');
|
||||
* // => { '3': ['one', 'two'], '5': ['three'] }
|
||||
*/
|
||||
var groupBy = createAggregator(function(result, value, key) {
|
||||
(hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value);
|
||||
});
|
||||
|
||||
/**
|
||||
* Creates an object composed of keys generated from the results of running
|
||||
* each element of the collection through the given callback. The corresponding
|
||||
* value of each key is the last element responsible for generating the key.
|
||||
* The callback is bound to `thisArg` and invoked with three arguments;
|
||||
* (value, index|key, collection).
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {Function|Object|string} [callback=identity] The function called
|
||||
* per iteration. If a property name or object is provided it will be used
|
||||
* to create a "_.pluck" or "_.where" style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Object} Returns the composed aggregate object.
|
||||
* @example
|
||||
*
|
||||
* var keys = [
|
||||
* { 'dir': 'left', 'code': 97 },
|
||||
* { 'dir': 'right', 'code': 100 }
|
||||
* ];
|
||||
*
|
||||
* _.indexBy(keys, 'dir');
|
||||
* // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
|
||||
*
|
||||
* _.indexBy(keys, function(key) { return String.fromCharCode(key.code); });
|
||||
* // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
|
||||
*
|
||||
* _.indexBy(characters, function(key) { this.fromCharCode(key.code); }, String);
|
||||
* // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
|
||||
*/
|
||||
var indexBy = createAggregator(function(result, value, key) {
|
||||
result[key] = value;
|
||||
});
|
||||
|
||||
/**
|
||||
* Invokes the method named by `methodName` on each element in the `collection`
|
||||
* returning an array of the results of each invoked method. Additional arguments
|
||||
* will be provided to each invoked method. If `methodName` is a function it
|
||||
* will be invoked for, and `this` bound to, each element in the `collection`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {Function|string} methodName The name of the method to invoke or
|
||||
* the function invoked per iteration.
|
||||
* @param {...*} [arg] Arguments to invoke the method with.
|
||||
* @returns {Array} Returns a new array of the results of each invoked method.
|
||||
* @example
|
||||
*
|
||||
* _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
|
||||
* // => [[1, 5, 7], [1, 2, 3]]
|
||||
*
|
||||
* _.invoke([123, 456], String.prototype.split, '');
|
||||
* // => [['1', '2', '3'], ['4', '5', '6']]
|
||||
*/
|
||||
function invoke(collection, methodName) {
|
||||
var args = slice(arguments, 2),
|
||||
index = -1,
|
||||
isFunc = typeof methodName == 'function',
|
||||
length = collection ? collection.length : 0,
|
||||
result = Array(typeof length == 'number' ? length : 0);
|
||||
|
||||
forEach(collection, function(value) {
|
||||
result[++index] = (isFunc ? methodName : value[methodName]).apply(value, args);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of values by running each element in the collection
|
||||
* through the callback. The callback is bound to `thisArg` and invoked with
|
||||
* three arguments; (value, index|key, collection).
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @alias collect
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {Function|Object|string} [callback=identity] The function called
|
||||
* per iteration. If a property name or object is provided it will be used
|
||||
* to create a "_.pluck" or "_.where" style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Array} Returns a new array of the results of each `callback` execution.
|
||||
* @example
|
||||
*
|
||||
* _.map([1, 2, 3], function(num) { return num * 3; });
|
||||
* // => [3, 6, 9]
|
||||
*
|
||||
* _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
|
||||
* // => [3, 6, 9] (property order is not guaranteed across environments)
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'barney', 'age': 36 },
|
||||
* { 'name': 'fred', 'age': 40 }
|
||||
* ];
|
||||
*
|
||||
* // using "_.pluck" callback shorthand
|
||||
* _.map(characters, 'name');
|
||||
* // => ['barney', 'fred']
|
||||
*/
|
||||
function map(collection, callback, thisArg) {
|
||||
var index = -1,
|
||||
length = collection ? collection.length : 0,
|
||||
result = Array(typeof length == 'number' ? length : 0);
|
||||
|
||||
callback = lodash.createCallback(callback, thisArg, 3);
|
||||
if (isArray(collection)) {
|
||||
while (++index < length) {
|
||||
result[index] = callback(collection[index], index, collection);
|
||||
}
|
||||
} else {
|
||||
baseEach(collection, function(value, key, collection) {
|
||||
result[++index] = callback(value, key, collection);
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the maximum value of a collection. If the collection is empty or
|
||||
* falsey `-Infinity` is returned. If a callback is provided it will be executed
|
||||
* for each value in the collection to generate the criterion by which the value
|
||||
* is ranked. The callback is bound to `thisArg` and invoked with three
|
||||
* arguments; (value, index, collection).
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {Function|Object|string} [callback=identity] The function called
|
||||
* per iteration. If a property name or object is provided it will be used
|
||||
* to create a "_.pluck" or "_.where" style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {*} Returns the maximum value.
|
||||
* @example
|
||||
*
|
||||
* _.max([4, 2, 8, 6]);
|
||||
* // => 8
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'barney', 'age': 36 },
|
||||
* { 'name': 'fred', 'age': 40 }
|
||||
* ];
|
||||
*
|
||||
* _.max(characters, function(chr) { return chr.age; });
|
||||
* // => { 'name': 'fred', 'age': 40 };
|
||||
*
|
||||
* // using "_.pluck" callback shorthand
|
||||
* _.max(characters, 'age');
|
||||
* // => { 'name': 'fred', 'age': 40 };
|
||||
*/
|
||||
function max(collection, callback, thisArg) {
|
||||
var computed = -Infinity,
|
||||
result = computed;
|
||||
|
||||
// allows working with functions like `_.map` without using
|
||||
// their `index` argument as a callback
|
||||
if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) {
|
||||
callback = null;
|
||||
}
|
||||
if (callback == null && isArray(collection)) {
|
||||
var index = -1,
|
||||
length = collection.length;
|
||||
|
||||
while (++index < length) {
|
||||
var value = collection[index];
|
||||
if (value > result) {
|
||||
result = value;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
callback = (callback == null && isString(collection))
|
||||
? charAtCallback
|
||||
: lodash.createCallback(callback, thisArg, 3);
|
||||
|
||||
baseEach(collection, function(value, index, collection) {
|
||||
var current = callback(value, index, collection);
|
||||
if (current > computed) {
|
||||
computed = current;
|
||||
result = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the minimum value of a collection. If the collection is empty or
|
||||
* falsey `Infinity` is returned. If a callback is provided it will be executed
|
||||
* for each value in the collection to generate the criterion by which the value
|
||||
* is ranked. The callback is bound to `thisArg` and invoked with three
|
||||
* arguments; (value, index, collection).
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {Function|Object|string} [callback=identity] The function called
|
||||
* per iteration. If a property name or object is provided it will be used
|
||||
* to create a "_.pluck" or "_.where" style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {*} Returns the minimum value.
|
||||
* @example
|
||||
*
|
||||
* _.min([4, 2, 8, 6]);
|
||||
* // => 2
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'barney', 'age': 36 },
|
||||
* { 'name': 'fred', 'age': 40 }
|
||||
* ];
|
||||
*
|
||||
* _.min(characters, function(chr) { return chr.age; });
|
||||
* // => { 'name': 'barney', 'age': 36 };
|
||||
*
|
||||
* // using "_.pluck" callback shorthand
|
||||
* _.min(characters, 'age');
|
||||
* // => { 'name': 'barney', 'age': 36 };
|
||||
*/
|
||||
function min(collection, callback, thisArg) {
|
||||
var computed = Infinity,
|
||||
result = computed;
|
||||
|
||||
// allows working with functions like `_.map` without using
|
||||
// their `index` argument as a callback
|
||||
if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) {
|
||||
callback = null;
|
||||
}
|
||||
if (callback == null && isArray(collection)) {
|
||||
var index = -1,
|
||||
length = collection.length;
|
||||
|
||||
while (++index < length) {
|
||||
var value = collection[index];
|
||||
if (value < result) {
|
||||
result = value;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
callback = (callback == null && isString(collection))
|
||||
? charAtCallback
|
||||
: lodash.createCallback(callback, thisArg, 3);
|
||||
|
||||
baseEach(collection, function(value, index, collection) {
|
||||
var current = callback(value, index, collection);
|
||||
if (current < computed) {
|
||||
computed = current;
|
||||
result = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the value of a specified property from all elements in the collection.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @type Function
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {string} property The name of the property to pluck.
|
||||
* @returns {Array} Returns a new array of property values.
|
||||
* @example
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'barney', 'age': 36 },
|
||||
* { 'name': 'fred', 'age': 40 }
|
||||
* ];
|
||||
*
|
||||
* _.pluck(characters, 'name');
|
||||
* // => ['barney', 'fred']
|
||||
*/
|
||||
var pluck = map;
|
||||
|
||||
/**
|
||||
* Reduces a collection to a value which is the accumulated result of running
|
||||
* each element in the collection through the callback, where each successive
|
||||
* callback execution consumes the return value of the previous execution. If
|
||||
* `accumulator` is not provided the first element of the collection will be
|
||||
* used as the initial `accumulator` value. The callback is bound to `thisArg`
|
||||
* and invoked with four arguments; (accumulator, value, index|key, collection).
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @alias foldl, inject
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {Function} [callback=identity] The function called per iteration.
|
||||
* @param {*} [accumulator] Initial value of the accumulator.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {*} Returns the accumulated value.
|
||||
* @example
|
||||
*
|
||||
* var sum = _.reduce([1, 2, 3], function(sum, num) {
|
||||
* return sum + num;
|
||||
* });
|
||||
* // => 6
|
||||
*
|
||||
* var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
|
||||
* result[key] = num * 3;
|
||||
* return result;
|
||||
* }, {});
|
||||
* // => { 'a': 3, 'b': 6, 'c': 9 }
|
||||
*/
|
||||
function reduce(collection, callback, accumulator, thisArg) {
|
||||
var noaccum = arguments.length < 3;
|
||||
callback = lodash.createCallback(callback, thisArg, 4);
|
||||
|
||||
if (isArray(collection)) {
|
||||
var index = -1,
|
||||
length = collection.length;
|
||||
|
||||
if (noaccum) {
|
||||
accumulator = collection[++index];
|
||||
}
|
||||
while (++index < length) {
|
||||
accumulator = callback(accumulator, collection[index], index, collection);
|
||||
}
|
||||
} else {
|
||||
baseEach(collection, function(value, index, collection) {
|
||||
accumulator = noaccum
|
||||
? (noaccum = false, value)
|
||||
: callback(accumulator, value, index, collection)
|
||||
});
|
||||
}
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is like `_.reduce` except that it iterates over elements
|
||||
* of a `collection` from right to left.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @alias foldr
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {Function} [callback=identity] The function called per iteration.
|
||||
* @param {*} [accumulator] Initial value of the accumulator.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {*} Returns the accumulated value.
|
||||
* @example
|
||||
*
|
||||
* var list = [[0, 1], [2, 3], [4, 5]];
|
||||
* var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
|
||||
* // => [4, 5, 2, 3, 0, 1]
|
||||
*/
|
||||
function reduceRight(collection, callback, accumulator, thisArg) {
|
||||
var noaccum = arguments.length < 3;
|
||||
callback = lodash.createCallback(callback, thisArg, 4);
|
||||
forEachRight(collection, function(value, index, collection) {
|
||||
accumulator = noaccum
|
||||
? (noaccum = false, value)
|
||||
: callback(accumulator, value, index, collection);
|
||||
});
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
/**
|
||||
* The opposite of `_.filter` this method returns the elements of a
|
||||
* collection that the callback does **not** return truey for.
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {Function|Object|string} [callback=identity] The function called
|
||||
* per iteration. If a property name or object is provided it will be used
|
||||
* to create a "_.pluck" or "_.where" style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Array} Returns a new array of elements that failed the callback check.
|
||||
* @example
|
||||
*
|
||||
* var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
|
||||
* // => [1, 3, 5]
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'barney', 'age': 36, 'blocked': false },
|
||||
* { 'name': 'fred', 'age': 40, 'blocked': true }
|
||||
* ];
|
||||
*
|
||||
* // using "_.pluck" callback shorthand
|
||||
* _.reject(characters, 'blocked');
|
||||
* // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
|
||||
*
|
||||
* // using "_.where" callback shorthand
|
||||
* _.reject(characters, { 'age': 36 });
|
||||
* // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
|
||||
*/
|
||||
function reject(collection, callback, thisArg) {
|
||||
callback = lodash.createCallback(callback, thisArg, 3);
|
||||
return filter(collection, function(value, index, collection) {
|
||||
return !callback(value, index, collection);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a random element or `n` random elements from a collection.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to sample.
|
||||
* @param {number} [n] The number of elements to sample.
|
||||
* @param- {Object} [guard] Allows working with functions like `_.map`
|
||||
* without using their `index` arguments as `n`.
|
||||
* @returns {Array} Returns the random sample(s) of `collection`.
|
||||
* @example
|
||||
*
|
||||
* _.sample([1, 2, 3, 4]);
|
||||
* // => 2
|
||||
*
|
||||
* _.sample([1, 2, 3, 4], 2);
|
||||
* // => [3, 1]
|
||||
*/
|
||||
function sample(collection, n, guard) {
|
||||
if (collection && typeof collection.length != 'number') {
|
||||
collection = values(collection);
|
||||
} else if (support.unindexedChars && isString(collection)) {
|
||||
collection = collection.split('');
|
||||
}
|
||||
if (n == null || guard) {
|
||||
return collection ? collection[baseRandom(0, collection.length - 1)] : undefined;
|
||||
}
|
||||
var result = shuffle(collection);
|
||||
result.length = nativeMin(nativeMax(0, n), result.length);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of shuffled values, using a version of the Fisher-Yates
|
||||
* shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to shuffle.
|
||||
* @returns {Array} Returns a new shuffled collection.
|
||||
* @example
|
||||
*
|
||||
* _.shuffle([1, 2, 3, 4, 5, 6]);
|
||||
* // => [4, 1, 6, 3, 5, 2]
|
||||
*/
|
||||
function shuffle(collection) {
|
||||
var index = -1,
|
||||
length = collection ? collection.length : 0,
|
||||
result = Array(typeof length == 'number' ? length : 0);
|
||||
|
||||
forEach(collection, function(value) {
|
||||
var rand = baseRandom(0, ++index);
|
||||
result[index] = result[rand];
|
||||
result[rand] = value;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of the `collection` by returning `collection.length` for arrays
|
||||
* and array-like objects or the number of own enumerable properties for objects.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to inspect.
|
||||
* @returns {number} Returns `collection.length` or number of own enumerable properties.
|
||||
* @example
|
||||
*
|
||||
* _.size([1, 2]);
|
||||
* // => 2
|
||||
*
|
||||
* _.size({ 'one': 1, 'two': 2, 'three': 3 });
|
||||
* // => 3
|
||||
*
|
||||
* _.size('pebbles');
|
||||
* // => 7
|
||||
*/
|
||||
function size(collection) {
|
||||
var length = collection ? collection.length : 0;
|
||||
return typeof length == 'number' ? length : keys(collection).length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the callback returns a truey value for **any** element of a
|
||||
* collection. The function returns as soon as it finds a passing value and
|
||||
* does not iterate over the entire collection. The callback is bound to
|
||||
* `thisArg` and invoked with three arguments; (value, index|key, collection).
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @alias any
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {Function|Object|string} [callback=identity] The function called
|
||||
* per iteration. If a property name or object is provided it will be used
|
||||
* to create a "_.pluck" or "_.where" style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {boolean} Returns `true` if any element passed the callback check,
|
||||
* else `false`.
|
||||
* @example
|
||||
*
|
||||
* _.some([null, 0, 'yes', false], Boolean);
|
||||
* // => true
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'barney', 'age': 36, 'blocked': false },
|
||||
* { 'name': 'fred', 'age': 40, 'blocked': true }
|
||||
* ];
|
||||
*
|
||||
* // using "_.pluck" callback shorthand
|
||||
* _.some(characters, 'blocked');
|
||||
* // => true
|
||||
*
|
||||
* // using "_.where" callback shorthand
|
||||
* _.some(characters, { 'age': 1 });
|
||||
* // => false
|
||||
*/
|
||||
function some(collection, callback, thisArg) {
|
||||
var result;
|
||||
callback = lodash.createCallback(callback, thisArg, 3);
|
||||
|
||||
if (isArray(collection)) {
|
||||
var index = -1,
|
||||
length = collection.length;
|
||||
|
||||
while (++index < length) {
|
||||
if ((result = callback(collection[index], index, collection))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
baseEach(collection, function(value, index, collection) {
|
||||
return !(result = callback(value, index, collection));
|
||||
});
|
||||
}
|
||||
return !!result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of elements, sorted in ascending order by the results of
|
||||
* running each element in a collection through the callback. This method
|
||||
* performs a stable sort, that is, it will preserve the original sort order
|
||||
* of equal elements. The callback is bound to `thisArg` and invoked with
|
||||
* three arguments; (value, index|key, collection).
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an array of property names is provided for `callback` the collection
|
||||
* will be sorted by each property value.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {Array|Function|Object|string} [callback=identity] The function called
|
||||
* per iteration. If a property name or object is provided it will be used
|
||||
* to create a "_.pluck" or "_.where" style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Array} Returns a new array of sorted elements.
|
||||
* @example
|
||||
*
|
||||
* _.sortBy([1, 2, 3], function(num) { return Math.sin(num); });
|
||||
* // => [3, 1, 2]
|
||||
*
|
||||
* _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math);
|
||||
* // => [3, 1, 2]
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'barney', 'age': 36 },
|
||||
* { 'name': 'fred', 'age': 40 },
|
||||
* { 'name': 'barney', 'age': 26 },
|
||||
* { 'name': 'fred', 'age': 30 }
|
||||
* ];
|
||||
*
|
||||
* // using "_.pluck" callback shorthand
|
||||
* _.map(_.sortBy(characters, 'age'), _.values);
|
||||
* // => [['barney', 26], ['fred', 30], ['barney', 36], ['fred', 40]]
|
||||
*
|
||||
* // sorting by multiple properties
|
||||
* _.map(_.sortBy(characters, ['name', 'age']), _.values);
|
||||
* // = > [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]]
|
||||
*/
|
||||
function sortBy(collection, callback, thisArg) {
|
||||
var index = -1,
|
||||
isArr = isArray(callback),
|
||||
length = collection ? collection.length : 0,
|
||||
result = Array(typeof length == 'number' ? length : 0);
|
||||
|
||||
if (!isArr) {
|
||||
callback = lodash.createCallback(callback, thisArg, 3);
|
||||
}
|
||||
forEach(collection, function(value, key, collection) {
|
||||
var object = result[++index] = getObject();
|
||||
if (isArr) {
|
||||
object.criteria = map(callback, function(key) { return value[key]; });
|
||||
} else {
|
||||
(object.criteria = getArray())[0] = callback(value, key, collection);
|
||||
}
|
||||
object.index = index;
|
||||
object.value = value;
|
||||
});
|
||||
|
||||
length = result.length;
|
||||
result.sort(compareAscending);
|
||||
while (length--) {
|
||||
var object = result[length];
|
||||
result[length] = object.value;
|
||||
if (!isArr) {
|
||||
releaseArray(object.criteria);
|
||||
}
|
||||
releaseObject(object);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the `collection` to an array.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to convert.
|
||||
* @returns {Array} Returns the new converted array.
|
||||
* @example
|
||||
*
|
||||
* (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
|
||||
* // => [2, 3, 4]
|
||||
*/
|
||||
function toArray(collection) {
|
||||
if (collection && typeof collection.length == 'number') {
|
||||
return (support.unindexedChars && isString(collection))
|
||||
? collection.split('')
|
||||
: slice(collection);
|
||||
}
|
||||
return values(collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a deep comparison of each element in a `collection` to the given
|
||||
* `properties` object, returning an array of all elements that have equivalent
|
||||
* property values.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @type Function
|
||||
* @category Collections
|
||||
* @param {Array|Object|string} collection The collection to iterate over.
|
||||
* @param {Object} props The object of property values to filter by.
|
||||
* @returns {Array} Returns a new array of elements that have the given properties.
|
||||
* @example
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'barney', 'age': 36, 'pets': ['hoppy'] },
|
||||
* { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }
|
||||
* ];
|
||||
*
|
||||
* _.where(characters, { 'age': 36 });
|
||||
* // => [{ 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }]
|
||||
*
|
||||
* _.where(characters, { 'pets': ['dino'] });
|
||||
* // => [{ 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }]
|
||||
*/
|
||||
var where = filter;
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Creates an array with all falsey values removed. The values `false`, `null`,
|
||||
* `0`, `""`, `undefined`, and `NaN` are all falsey.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Arrays
|
||||
* @param {Array} array The array to compact.
|
||||
* @returns {Array} Returns a new array of filtered values.
|
||||
* @example
|
||||
*
|
||||
* _.compact([0, 1, false, 2, '', 3]);
|
||||
* // => [1, 2, 3]
|
||||
*/
|
||||
function compact(array) {
|
||||
var index = -1,
|
||||
length = array ? array.length : 0,
|
||||
result = [];
|
||||
|
||||
while (++index < length) {
|
||||
var value = array[index];
|
||||
if (value) {
|
||||
result.push(value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array excluding all values of the provided arrays using strict
|
||||
* equality for comparisons, i.e. `===`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Arrays
|
||||
* @param {Array} array The array to process.
|
||||
* @param {...Array} [values] The arrays of values to exclude.
|
||||
* @returns {Array} Returns a new array of filtered values.
|
||||
* @example
|
||||
*
|
||||
* _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
|
||||
* // => [1, 3, 4]
|
||||
*/
|
||||
function difference(array) {
|
||||
return baseDifference(array, baseFlatten(arguments, true, true, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is like `_.find` except that it returns the index of the first
|
||||
* element that passes the callback check, instead of the element itself.
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Arrays
|
||||
* @param {Array} array The array to search.
|
||||
* @param {Function|Object|string} [callback=identity] The function called
|
||||
* per iteration. If a property name or object is provided it will be used
|
||||
* to create a "_.pluck" or "_.where" style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {number} Returns the index of the found element, else `-1`.
|
||||
* @example
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'barney', 'age': 36, 'blocked': false },
|
||||
* { 'name': 'fred', 'age': 40, 'blocked': true },
|
||||
* { 'name': 'pebbles', 'age': 1, 'blocked': false }
|
||||
* ];
|
||||
*
|
||||
* _.findIndex(characters, function(chr) {
|
||||
* return chr.age < 20;
|
||||
* });
|
||||
* // => 2
|
||||
*
|
||||
* // using "_.where" callback shorthand
|
||||
* _.findIndex(characters, { 'age': 36 });
|
||||
* // => 0
|
||||
*
|
||||
* // using "_.pluck" callback shorthand
|
||||
* _.findIndex(characters, 'blocked');
|
||||
* // => 1
|
||||
*/
|
||||
function findIndex(array, callback, thisArg) {
|
||||
var index = -1,
|
||||
length = array ? array.length : 0;
|
||||
|
||||
callback = lodash.createCallback(callback, thisArg, 3);
|
||||
while (++index < length) {
|
||||
if (callback(array[index], index, array)) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is like `_.findIndex` except that it iterates over elements
|
||||
* of a `collection` from right to left.
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Arrays
|
||||
* @param {Array} array The array to search.
|
||||
* @param {Function|Object|string} [callback=identity] The function called
|
||||
* per iteration. If a property name or object is provided it will be used
|
||||
* to create a "_.pluck" or "_.where" style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {number} Returns the index of the found element, else `-1`.
|
||||
* @example
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'barney', 'age': 36, 'blocked': true },
|
||||
* { 'name': 'fred', 'age': 40, 'blocked': false },
|
||||
* { 'name': 'pebbles', 'age': 1, 'blocked': true }
|
||||
* ];
|
||||
*
|
||||
* _.findLastIndex(characters, function(chr) {
|
||||
* return chr.age > 30;
|
||||
* });
|
||||
* // => 1
|
||||
*
|
||||
* // using "_.where" callback shorthand
|
||||
* _.findLastIndex(characters, { 'age': 36 });
|
||||
* // => 0
|
||||
*
|
||||
* // using "_.pluck" callback shorthand
|
||||
* _.findLastIndex(characters, 'blocked');
|
||||
* // => 2
|
||||
*/
|
||||
function findLastIndex(array, callback, thisArg) {
|
||||
var length = array ? array.length : 0;
|
||||
callback = lodash.createCallback(callback, thisArg, 3);
|
||||
while (length--) {
|
||||
if (callback(array[length], length, array)) {
|
||||
return length;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first element or first `n` elements of an array. If a callback
|
||||
* is provided elements at the beginning of the array are returned as long
|
||||
* as the callback returns truey. The callback is bound to `thisArg` and
|
||||
* invoked with three arguments; (value, index, array).
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @alias head, take
|
||||
* @category Arrays
|
||||
* @param {Array} array The array to query.
|
||||
* @param {Function|Object|number|string} [callback] The function called
|
||||
* per element or the number of elements to return. If a property name or
|
||||
* object is provided it will be used to create a "_.pluck" or "_.where"
|
||||
* style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {*} Returns the first element(s) of `array`.
|
||||
* @example
|
||||
*
|
||||
* _.first([1, 2, 3]);
|
||||
* // => 1
|
||||
*
|
||||
* _.first([1, 2, 3], 2);
|
||||
* // => [1, 2]
|
||||
*
|
||||
* _.first([1, 2, 3], function(num) {
|
||||
* return num < 3;
|
||||
* });
|
||||
* // => [1, 2]
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'barney', 'blocked': true, 'employer': 'slate' },
|
||||
* { 'name': 'fred', 'blocked': false, 'employer': 'slate' },
|
||||
* { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
|
||||
* ];
|
||||
*
|
||||
* // using "_.pluck" callback shorthand
|
||||
* _.first(characters, 'blocked');
|
||||
* // => [{ 'name': 'barney', 'blocked': true, 'employer': 'slate' }]
|
||||
*
|
||||
* // using "_.where" callback shorthand
|
||||
* _.pluck(_.first(characters, { 'employer': 'slate' }), 'name');
|
||||
* // => ['barney', 'fred']
|
||||
*/
|
||||
function first(array, callback, thisArg) {
|
||||
var n = 0,
|
||||
length = array ? array.length : 0;
|
||||
|
||||
if (typeof callback != 'number' && callback != null) {
|
||||
var index = -1;
|
||||
callback = lodash.createCallback(callback, thisArg, 3);
|
||||
while (++index < length && callback(array[index], index, array)) {
|
||||
n++;
|
||||
}
|
||||
} else {
|
||||
n = callback;
|
||||
if (n == null || thisArg) {
|
||||
return array ? array[0] : undefined;
|
||||
}
|
||||
}
|
||||
return slice(array, 0, nativeMin(nativeMax(0, n), length));
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens a nested array (the nesting can be to any depth). If `isShallow`
|
||||
* is truey, the array will only be flattened a single level. If a callback
|
||||
* is provided each element of the array is passed through the callback before
|
||||
* flattening. The callback is bound to `thisArg` and invoked with three
|
||||
* arguments; (value, index, array).
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Arrays
|
||||
* @param {Array} array The array to flatten.
|
||||
* @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
|
||||
* @param {Function|Object|string} [callback=identity] The function called
|
||||
* per iteration. If a property name or object is provided it will be used
|
||||
* to create a "_.pluck" or "_.where" style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Array} Returns a new flattened array.
|
||||
* @example
|
||||
*
|
||||
* _.flatten([1, [2], [3, [[4]]]]);
|
||||
* // => [1, 2, 3, 4];
|
||||
*
|
||||
* _.flatten([1, [2], [3, [[4]]]], true);
|
||||
* // => [1, 2, 3, [[4]]];
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'barney', 'age': 30, 'pets': ['hoppy'] },
|
||||
* { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }
|
||||
* ];
|
||||
*
|
||||
* // using "_.pluck" callback shorthand
|
||||
* _.flatten(characters, 'pets');
|
||||
* // => ['hoppy', 'baby puss', 'dino']
|
||||
*/
|
||||
function flatten(array, isShallow, callback, thisArg) {
|
||||
// juggle arguments
|
||||
if (typeof isShallow != 'boolean' && isShallow != null) {
|
||||
thisArg = callback;
|
||||
callback = (typeof isShallow != 'function' && thisArg && thisArg[isShallow] === array) ? null : isShallow;
|
||||
isShallow = false;
|
||||
}
|
||||
if (callback != null) {
|
||||
array = map(array, callback, thisArg);
|
||||
}
|
||||
return baseFlatten(array, isShallow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index at which the first occurrence of `value` is found using
|
||||
* strict equality for comparisons, i.e. `===`. If the array is already sorted
|
||||
* providing `true` for `fromIndex` will run a faster binary search.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Arrays
|
||||
* @param {Array} array The array to search.
|
||||
* @param {*} value The value to search for.
|
||||
* @param {boolean|number} [fromIndex=0] The index to search from or `true`
|
||||
* to perform a binary search on a sorted array.
|
||||
* @returns {number} Returns the index of the matched value or `-1`.
|
||||
* @example
|
||||
*
|
||||
* _.indexOf([1, 2, 3, 1, 2, 3], 2);
|
||||
* // => 1
|
||||
*
|
||||
* _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
|
||||
* // => 4
|
||||
*
|
||||
* _.indexOf([1, 1, 2, 2, 3, 3], 2, true);
|
||||
* // => 2
|
||||
*/
|
||||
function indexOf(array, value, fromIndex) {
|
||||
if (typeof fromIndex == 'number') {
|
||||
var length = array ? array.length : 0;
|
||||
fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0);
|
||||
} else if (fromIndex) {
|
||||
var index = sortedIndex(array, value);
|
||||
return array[index] === value ? index : -1;
|
||||
}
|
||||
return baseIndexOf(array, value, fromIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all but the last element or last `n` elements of an array. If a
|
||||
* callback is provided elements at the end of the array are excluded from
|
||||
* the result as long as the callback returns truey. The callback is bound
|
||||
* to `thisArg` and invoked with three arguments; (value, index, array).
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Arrays
|
||||
* @param {Array} array The array to query.
|
||||
* @param {Function|Object|number|string} [callback=1] The function called
|
||||
* per element or the number of elements to exclude. If a property name or
|
||||
* object is provided it will be used to create a "_.pluck" or "_.where"
|
||||
* style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Array} Returns a slice of `array`.
|
||||
* @example
|
||||
*
|
||||
* _.initial([1, 2, 3]);
|
||||
* // => [1, 2]
|
||||
*
|
||||
* _.initial([1, 2, 3], 2);
|
||||
* // => [1]
|
||||
*
|
||||
* _.initial([1, 2, 3], function(num) {
|
||||
* return num > 1;
|
||||
* });
|
||||
* // => [1]
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'barney', 'blocked': false, 'employer': 'slate' },
|
||||
* { 'name': 'fred', 'blocked': true, 'employer': 'slate' },
|
||||
* { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
|
||||
* ];
|
||||
*
|
||||
* // using "_.pluck" callback shorthand
|
||||
* _.initial(characters, 'blocked');
|
||||
* // => [{ 'name': 'barney', 'blocked': false, 'employer': 'slate' }]
|
||||
*
|
||||
* // using "_.where" callback shorthand
|
||||
* _.pluck(_.initial(characters, { 'employer': 'na' }), 'name');
|
||||
* // => ['barney', 'fred']
|
||||
*/
|
||||
function initial(array, callback, thisArg) {
|
||||
var n = 0,
|
||||
length = array ? array.length : 0;
|
||||
|
||||
if (typeof callback != 'number' && callback != null) {
|
||||
var index = length;
|
||||
callback = lodash.createCallback(callback, thisArg, 3);
|
||||
while (index-- && callback(array[index], index, array)) {
|
||||
n++;
|
||||
}
|
||||
} else {
|
||||
n = (callback == null || thisArg) ? 1 : callback || n;
|
||||
}
|
||||
return slice(array, 0, nativeMin(nativeMax(0, length - n), length));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of unique values present in all provided arrays using
|
||||
* strict equality for comparisons, i.e. `===`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Arrays
|
||||
* @param {...Array} [array] The arrays to inspect.
|
||||
* @returns {Array} Returns an array of shared values.
|
||||
* @example
|
||||
*
|
||||
* _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]);
|
||||
* // => [1, 2]
|
||||
*/
|
||||
function intersection() {
|
||||
var args = [],
|
||||
argsIndex = -1,
|
||||
argsLength = arguments.length,
|
||||
caches = getArray(),
|
||||
indexOf = getIndexOf(),
|
||||
trustIndexOf = indexOf === baseIndexOf,
|
||||
seen = getArray();
|
||||
|
||||
while (++argsIndex < argsLength) {
|
||||
var value = arguments[argsIndex];
|
||||
if (isArray(value) || isArguments(value)) {
|
||||
args.push(value);
|
||||
caches.push(trustIndexOf && value.length >= largeArraySize &&
|
||||
createCache(argsIndex ? args[argsIndex] : seen));
|
||||
}
|
||||
}
|
||||
var array = args[0],
|
||||
index = -1,
|
||||
length = array ? array.length : 0,
|
||||
result = [];
|
||||
|
||||
outer:
|
||||
while (++index < length) {
|
||||
var cache = caches[0];
|
||||
value = array[index];
|
||||
|
||||
if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) {
|
||||
argsIndex = argsLength;
|
||||
(cache || seen).push(value);
|
||||
while (--argsIndex) {
|
||||
cache = caches[argsIndex];
|
||||
if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) {
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
result.push(value);
|
||||
}
|
||||
}
|
||||
while (argsLength--) {
|
||||
cache = caches[argsLength];
|
||||
if (cache) {
|
||||
releaseObject(cache);
|
||||
}
|
||||
}
|
||||
releaseArray(caches);
|
||||
releaseArray(seen);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last element or last `n` elements of an array. If a callback is
|
||||
* provided elements at the end of the array are returned as long as the
|
||||
* callback returns truey. The callback is bound to `thisArg` and invoked
|
||||
* with three arguments; (value, index, array).
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Arrays
|
||||
* @param {Array} array The array to query.
|
||||
* @param {Function|Object|number|string} [callback] The function called
|
||||
* per element or the number of elements to return. If a property name or
|
||||
* object is provided it will be used to create a "_.pluck" or "_.where"
|
||||
* style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {*} Returns the last element(s) of `array`.
|
||||
* @example
|
||||
*
|
||||
* _.last([1, 2, 3]);
|
||||
* // => 3
|
||||
*
|
||||
* _.last([1, 2, 3], 2);
|
||||
* // => [2, 3]
|
||||
*
|
||||
* _.last([1, 2, 3], function(num) {
|
||||
* return num > 1;
|
||||
* });
|
||||
* // => [2, 3]
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'barney', 'blocked': false, 'employer': 'slate' },
|
||||
* { 'name': 'fred', 'blocked': true, 'employer': 'slate' },
|
||||
* { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
|
||||
* ];
|
||||
*
|
||||
* // using "_.pluck" callback shorthand
|
||||
* _.pluck(_.last(characters, 'blocked'), 'name');
|
||||
* // => ['fred', 'pebbles']
|
||||
*
|
||||
* // using "_.where" callback shorthand
|
||||
* _.last(characters, { 'employer': 'na' });
|
||||
* // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
|
||||
*/
|
||||
function last(array, callback, thisArg) {
|
||||
var n = 0,
|
||||
length = array ? array.length : 0;
|
||||
|
||||
if (typeof callback != 'number' && callback != null) {
|
||||
var index = length;
|
||||
callback = lodash.createCallback(callback, thisArg, 3);
|
||||
while (index-- && callback(array[index], index, array)) {
|
||||
n++;
|
||||
}
|
||||
} else {
|
||||
n = callback;
|
||||
if (n == null || thisArg) {
|
||||
return array ? array[length - 1] : undefined;
|
||||
}
|
||||
}
|
||||
return slice(array, nativeMax(0, length - n));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index at which the last occurrence of `value` is found using strict
|
||||
* equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
|
||||
* as the offset from the end of the collection.
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Arrays
|
||||
* @param {Array} array The array to search.
|
||||
* @param {*} value The value to search for.
|
||||
* @param {number} [fromIndex=array.length-1] The index to search from.
|
||||
* @returns {number} Returns the index of the matched value or `-1`.
|
||||
* @example
|
||||
*
|
||||
* _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
|
||||
* // => 4
|
||||
*
|
||||
* _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
|
||||
* // => 1
|
||||
*/
|
||||
function lastIndexOf(array, value, fromIndex) {
|
||||
var index = array ? array.length : 0;
|
||||
if (typeof fromIndex == 'number') {
|
||||
index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1;
|
||||
}
|
||||
while (index--) {
|
||||
if (array[index] === value) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all provided values from the given array using strict equality for
|
||||
* comparisons, i.e. `===`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Arrays
|
||||
* @param {Array} array The array to modify.
|
||||
* @param {...*} [value] The values to remove.
|
||||
* @returns {Array} Returns `array`.
|
||||
* @example
|
||||
*
|
||||
* var array = [1, 2, 3, 1, 2, 3];
|
||||
* _.pull(array, 2, 3);
|
||||
* console.log(array);
|
||||
* // => [1, 1]
|
||||
*/
|
||||
function pull(array) {
|
||||
var args = arguments,
|
||||
argsIndex = 0,
|
||||
argsLength = args.length,
|
||||
length = array ? array.length : 0;
|
||||
|
||||
while (++argsIndex < argsLength) {
|
||||
var index = -1,
|
||||
value = args[argsIndex];
|
||||
while (++index < length) {
|
||||
if (array[index] === value) {
|
||||
splice.call(array, index--, 1);
|
||||
length--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of numbers (positive and/or negative) progressing from
|
||||
* `start` up to but not including `end`. If `start` is less than `stop` a
|
||||
* zero-length range is created unless a negative `step` is specified.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Arrays
|
||||
* @param {number} [start=0] The start of the range.
|
||||
* @param {number} end The end of the range.
|
||||
* @param {number} [step=1] The value to increment or decrement by.
|
||||
* @returns {Array} Returns a new range array.
|
||||
* @example
|
||||
*
|
||||
* _.range(4);
|
||||
* // => [0, 1, 2, 3]
|
||||
*
|
||||
* _.range(1, 5);
|
||||
* // => [1, 2, 3, 4]
|
||||
*
|
||||
* _.range(0, 20, 5);
|
||||
* // => [0, 5, 10, 15]
|
||||
*
|
||||
* _.range(0, -4, -1);
|
||||
* // => [0, -1, -2, -3]
|
||||
*
|
||||
* _.range(1, 4, 0);
|
||||
* // => [1, 1, 1]
|
||||
*
|
||||
* _.range(0);
|
||||
* // => []
|
||||
*/
|
||||
function range(start, end, step) {
|
||||
start = +start || 0;
|
||||
step = typeof step == 'number' ? step : (+step || 1);
|
||||
|
||||
if (end == null) {
|
||||
end = start;
|
||||
start = 0;
|
||||
}
|
||||
// use `Array(length)` so engines like Chakra and V8 avoid slower modes
|
||||
// http://youtu.be/XAqIpGU8ZZk#t=17m25s
|
||||
var index = -1,
|
||||
length = nativeMax(0, ceil((end - start) / (step || 1))),
|
||||
result = Array(length);
|
||||
|
||||
while (++index < length) {
|
||||
result[index] = start;
|
||||
start += step;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all elements from an array that the callback returns truey for
|
||||
* and returns an array of removed elements. The callback is bound to `thisArg`
|
||||
* and invoked with three arguments; (value, index, array).
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Arrays
|
||||
* @param {Array} array The array to modify.
|
||||
* @param {Function|Object|string} [callback=identity] The function called
|
||||
* per iteration. If a property name or object is provided it will be used
|
||||
* to create a "_.pluck" or "_.where" style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Array} Returns a new array of removed elements.
|
||||
* @example
|
||||
*
|
||||
* var array = [1, 2, 3, 4, 5, 6];
|
||||
* var evens = _.remove(array, function(num) { return num % 2 == 0; });
|
||||
*
|
||||
* console.log(array);
|
||||
* // => [1, 3, 5]
|
||||
*
|
||||
* console.log(evens);
|
||||
* // => [2, 4, 6]
|
||||
*/
|
||||
function remove(array, callback, thisArg) {
|
||||
var index = -1,
|
||||
length = array ? array.length : 0,
|
||||
result = [];
|
||||
|
||||
callback = lodash.createCallback(callback, thisArg, 3);
|
||||
while (++index < length) {
|
||||
var value = array[index];
|
||||
if (callback(value, index, array)) {
|
||||
result.push(value);
|
||||
splice.call(array, index--, 1);
|
||||
length--;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* The opposite of `_.initial` this method gets all but the first element or
|
||||
* first `n` elements of an array. If a callback function is provided elements
|
||||
* at the beginning of the array are excluded from the result as long as the
|
||||
* callback returns truey. The callback is bound to `thisArg` and invoked
|
||||
* with three arguments; (value, index, array).
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @alias drop, tail
|
||||
* @category Arrays
|
||||
* @param {Array} array The array to query.
|
||||
* @param {Function|Object|number|string} [callback=1] The function called
|
||||
* per element or the number of elements to exclude. If a property name or
|
||||
* object is provided it will be used to create a "_.pluck" or "_.where"
|
||||
* style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Array} Returns a slice of `array`.
|
||||
* @example
|
||||
*
|
||||
* _.rest([1, 2, 3]);
|
||||
* // => [2, 3]
|
||||
*
|
||||
* _.rest([1, 2, 3], 2);
|
||||
* // => [3]
|
||||
*
|
||||
* _.rest([1, 2, 3], function(num) {
|
||||
* return num < 3;
|
||||
* });
|
||||
* // => [3]
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'barney', 'blocked': true, 'employer': 'slate' },
|
||||
* { 'name': 'fred', 'blocked': false, 'employer': 'slate' },
|
||||
* { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
|
||||
* ];
|
||||
*
|
||||
* // using "_.pluck" callback shorthand
|
||||
* _.pluck(_.rest(characters, 'blocked'), 'name');
|
||||
* // => ['fred', 'pebbles']
|
||||
*
|
||||
* // using "_.where" callback shorthand
|
||||
* _.rest(characters, { 'employer': 'slate' });
|
||||
* // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
|
||||
*/
|
||||
function rest(array, callback, thisArg) {
|
||||
if (typeof callback != 'number' && callback != null) {
|
||||
var n = 0,
|
||||
index = -1,
|
||||
length = array ? array.length : 0;
|
||||
|
||||
callback = lodash.createCallback(callback, thisArg, 3);
|
||||
while (++index < length && callback(array[index], index, array)) {
|
||||
n++;
|
||||
}
|
||||
} else {
|
||||
n = (callback == null || thisArg) ? 1 : nativeMax(0, callback);
|
||||
}
|
||||
return slice(array, n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses a binary search to determine the smallest index at which a value
|
||||
* should be inserted into a given sorted array in order to maintain the sort
|
||||
* order of the array. If a callback is provided it will be executed for
|
||||
* `value` and each element of `array` to compute their sort ranking. The
|
||||
* callback is bound to `thisArg` and invoked with one argument; (value).
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Arrays
|
||||
* @param {Array} array The array to inspect.
|
||||
* @param {*} value The value to evaluate.
|
||||
* @param {Function|Object|string} [callback=identity] The function called
|
||||
* per iteration. If a property name or object is provided it will be used
|
||||
* to create a "_.pluck" or "_.where" style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {number} Returns the index at which `value` should be inserted
|
||||
* into `array`.
|
||||
* @example
|
||||
*
|
||||
* _.sortedIndex([20, 30, 50], 40);
|
||||
* // => 2
|
||||
*
|
||||
* // using "_.pluck" callback shorthand
|
||||
* _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
|
||||
* // => 2
|
||||
*
|
||||
* var dict = {
|
||||
* 'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 }
|
||||
* };
|
||||
*
|
||||
* _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
|
||||
* return dict.wordToNumber[word];
|
||||
* });
|
||||
* // => 2
|
||||
*
|
||||
* _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
|
||||
* return this.wordToNumber[word];
|
||||
* }, dict);
|
||||
* // => 2
|
||||
*/
|
||||
function sortedIndex(array, value, callback, thisArg) {
|
||||
var low = 0,
|
||||
high = array ? array.length : low;
|
||||
|
||||
// explicitly reference `identity` for better inlining in Firefox
|
||||
callback = callback ? lodash.createCallback(callback, thisArg, 1) : identity;
|
||||
value = callback(value);
|
||||
|
||||
while (low < high) {
|
||||
var mid = (low + high) >>> 1;
|
||||
(callback(array[mid]) < value)
|
||||
? low = mid + 1
|
||||
: high = mid;
|
||||
}
|
||||
return low;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of unique values, in order, of the provided arrays using
|
||||
* strict equality for comparisons, i.e. `===`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Arrays
|
||||
* @param {...Array} [array] The arrays to inspect.
|
||||
* @returns {Array} Returns an array of combined values.
|
||||
* @example
|
||||
*
|
||||
* _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]);
|
||||
* // => [1, 2, 3, 5, 4]
|
||||
*/
|
||||
function union() {
|
||||
return baseUniq(baseFlatten(arguments, true, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a duplicate-value-free version of an array using strict equality
|
||||
* for comparisons, i.e. `===`. If the array is sorted, providing
|
||||
* `true` for `isSorted` will use a faster algorithm. If a callback is provided
|
||||
* each element of `array` is passed through the callback before uniqueness
|
||||
* is computed. The callback is bound to `thisArg` and invoked with three
|
||||
* arguments; (value, index, array).
|
||||
*
|
||||
* If a property name is provided for `callback` the created "_.pluck" style
|
||||
* callback will return the property value of the given element.
|
||||
*
|
||||
* If an object is provided for `callback` the created "_.where" style callback
|
||||
* will return `true` for elements that have the properties of the given object,
|
||||
* else `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @alias unique
|
||||
* @category Arrays
|
||||
* @param {Array} array The array to process.
|
||||
* @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
|
||||
* @param {Function|Object|string} [callback=identity] The function called
|
||||
* per iteration. If a property name or object is provided it will be used
|
||||
* to create a "_.pluck" or "_.where" style callback, respectively.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Array} Returns a duplicate-value-free array.
|
||||
* @example
|
||||
*
|
||||
* _.uniq([1, 2, 1, 3, 1]);
|
||||
* // => [1, 2, 3]
|
||||
*
|
||||
* _.uniq([1, 1, 2, 2, 3], true);
|
||||
* // => [1, 2, 3]
|
||||
*
|
||||
* _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); });
|
||||
* // => ['A', 'b', 'C']
|
||||
*
|
||||
* _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math);
|
||||
* // => [1, 2.5, 3]
|
||||
*
|
||||
* // using "_.pluck" callback shorthand
|
||||
* _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
|
||||
* // => [{ 'x': 1 }, { 'x': 2 }]
|
||||
*/
|
||||
function uniq(array, isSorted, callback, thisArg) {
|
||||
// juggle arguments
|
||||
if (typeof isSorted != 'boolean' && isSorted != null) {
|
||||
thisArg = callback;
|
||||
callback = (typeof isSorted != 'function' && thisArg && thisArg[isSorted] === array) ? null : isSorted;
|
||||
isSorted = false;
|
||||
}
|
||||
if (callback != null) {
|
||||
callback = lodash.createCallback(callback, thisArg, 3);
|
||||
}
|
||||
return baseUniq(array, isSorted, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array excluding all provided values using strict equality for
|
||||
* comparisons, i.e. `===`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Arrays
|
||||
* @param {Array} array The array to filter.
|
||||
* @param {...*} [value] The values to exclude.
|
||||
* @returns {Array} Returns a new array of filtered values.
|
||||
* @example
|
||||
*
|
||||
* _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
|
||||
* // => [2, 3, 4]
|
||||
*/
|
||||
function without(array) {
|
||||
return baseDifference(array, slice(arguments, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array that is the symmetric difference of the provided arrays.
|
||||
* See http://en.wikipedia.org/wiki/Symmetric_difference.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Arrays
|
||||
* @param {...Array} [array] The arrays to inspect.
|
||||
* @returns {Array} Returns an array of values.
|
||||
* @example
|
||||
*
|
||||
* _.xor([1, 2, 3], [5, 2, 1, 4]);
|
||||
* // => [3, 5, 4]
|
||||
*
|
||||
* _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]);
|
||||
* // => [1, 4, 5]
|
||||
*/
|
||||
function xor() {
|
||||
var index = -1,
|
||||
length = arguments.length;
|
||||
|
||||
while (++index < length) {
|
||||
var array = arguments[index];
|
||||
if (isArray(array) || isArguments(array)) {
|
||||
var result = result
|
||||
? baseUniq(baseDifference(result, array).concat(baseDifference(array, result)))
|
||||
: array;
|
||||
}
|
||||
}
|
||||
return result || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of grouped elements, the first of which contains the first
|
||||
* elements of the given arrays, the second of which contains the second
|
||||
* elements of the given arrays, and so on.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @alias unzip
|
||||
* @category Arrays
|
||||
* @param {...Array} [array] Arrays to process.
|
||||
* @returns {Array} Returns a new array of grouped elements.
|
||||
* @example
|
||||
*
|
||||
* _.zip(['fred', 'barney'], [30, 40], [true, false]);
|
||||
* // => [['fred', 30, true], ['barney', 40, false]]
|
||||
*/
|
||||
function zip() {
|
||||
var array = arguments.length > 1 ? arguments : arguments[0],
|
||||
index = -1,
|
||||
length = array ? max(pluck(array, 'length')) : 0,
|
||||
result = Array(length < 0 ? 0 : length);
|
||||
|
||||
while (++index < length) {
|
||||
result[index] = pluck(array, index);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an object composed from arrays of `keys` and `values`. Provide
|
||||
* either a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`
|
||||
* or two arrays, one of `keys` and one of corresponding `values`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @alias object
|
||||
* @category Arrays
|
||||
* @param {Array} keys The array of keys.
|
||||
* @param {Array} [values=[]] The array of values.
|
||||
* @returns {Object} Returns an object composed of the given keys and
|
||||
* corresponding values.
|
||||
* @example
|
||||
*
|
||||
* _.zipObject(['fred', 'barney'], [30, 40]);
|
||||
* // => { 'fred': 30, 'barney': 40 }
|
||||
*/
|
||||
function zipObject(keys, values) {
|
||||
var index = -1,
|
||||
length = keys ? keys.length : 0,
|
||||
result = {};
|
||||
|
||||
if (!values && length && !isArray(keys[0])) {
|
||||
values = [];
|
||||
}
|
||||
while (++index < length) {
|
||||
var key = keys[index];
|
||||
if (values) {
|
||||
result[key] = values[index];
|
||||
} else if (key) {
|
||||
result[key[0]] = key[1];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Creates a function that executes `func`, with the `this` binding and
|
||||
* arguments of the created function, only after being called `n` times.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Functions
|
||||
* @param {number} n The number of times the function must be called before
|
||||
* `func` is executed.
|
||||
* @param {Function} func The function to restrict.
|
||||
* @returns {Function} Returns the new restricted function.
|
||||
* @example
|
||||
*
|
||||
* var saves = ['profile', 'settings'];
|
||||
*
|
||||
* var done = _.after(saves.length, function() {
|
||||
* console.log('Done saving!');
|
||||
* });
|
||||
*
|
||||
* _.forEach(saves, function(type) {
|
||||
* asyncSave({ 'type': type, 'complete': done });
|
||||
* });
|
||||
* // => logs 'Done saving!', after all saves have completed
|
||||
*/
|
||||
function after(n, func) {
|
||||
if (!isFunction(func)) {
|
||||
throw new TypeError;
|
||||
}
|
||||
return function() {
|
||||
if (--n < 1) {
|
||||
return func.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that, when called, invokes `func` with the `this`
|
||||
* binding of `thisArg` and prepends any additional `bind` arguments to those
|
||||
* provided to the bound function.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Functions
|
||||
* @param {Function} func The function to bind.
|
||||
* @param {*} [thisArg] The `this` binding of `func`.
|
||||
* @param {...*} [arg] Arguments to be partially applied.
|
||||
* @returns {Function} Returns the new bound function.
|
||||
* @example
|
||||
*
|
||||
* var func = function(greeting) {
|
||||
* return greeting + ' ' + this.name;
|
||||
* };
|
||||
*
|
||||
* func = _.bind(func, { 'name': 'fred' }, 'hi');
|
||||
* func();
|
||||
* // => 'hi fred'
|
||||
*/
|
||||
function bind(func, thisArg) {
|
||||
return arguments.length > 2
|
||||
? createWrapper(func, 17, slice(arguments, 2), null, thisArg)
|
||||
: createWrapper(func, 1, null, null, thisArg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds methods of an object to the object itself, overwriting the existing
|
||||
* method. Method names may be specified as individual arguments or as arrays
|
||||
* of method names. If no method names are provided all the function properties
|
||||
* of `object` will be bound.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Functions
|
||||
* @param {Object} object The object to bind and assign the bound methods to.
|
||||
* @param {...string} [methodName] The object method names to
|
||||
* bind, specified as individual method names or arrays of method names.
|
||||
* @returns {Object} Returns `object`.
|
||||
* @example
|
||||
*
|
||||
* var view = {
|
||||
* 'label': 'docs',
|
||||
* 'onClick': function() { console.log('clicked ' + this.label); }
|
||||
* };
|
||||
*
|
||||
* _.bindAll(view);
|
||||
* jQuery('#docs').on('click', view.onClick);
|
||||
* // => logs 'clicked docs', when the button is clicked
|
||||
*/
|
||||
function bindAll(object) {
|
||||
var funcs = arguments.length > 1 ? baseFlatten(arguments, true, false, 1) : functions(object),
|
||||
index = -1,
|
||||
length = funcs.length;
|
||||
|
||||
while (++index < length) {
|
||||
var key = funcs[index];
|
||||
object[key] = createWrapper(object[key], 1, null, null, object);
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that, when called, invokes the method at `object[key]`
|
||||
* and prepends any additional `bindKey` arguments to those provided to the bound
|
||||
* function. This method differs from `_.bind` by allowing bound functions to
|
||||
* reference methods that will be redefined or don't yet exist.
|
||||
* See http://michaux.ca/articles/lazy-function-definition-pattern.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Functions
|
||||
* @param {Object} object The object the method belongs to.
|
||||
* @param {string} key The key of the method.
|
||||
* @param {...*} [arg] Arguments to be partially applied.
|
||||
* @returns {Function} Returns the new bound function.
|
||||
* @example
|
||||
*
|
||||
* var object = {
|
||||
* 'name': 'fred',
|
||||
* 'greet': function(greeting) {
|
||||
* return greeting + ' ' + this.name;
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* var func = _.bindKey(object, 'greet', 'hi');
|
||||
* func();
|
||||
* // => 'hi fred'
|
||||
*
|
||||
* object.greet = function(greeting) {
|
||||
* return greeting + 'ya ' + this.name + '!';
|
||||
* };
|
||||
*
|
||||
* func();
|
||||
* // => 'hiya fred!'
|
||||
*/
|
||||
function bindKey(object, key) {
|
||||
return arguments.length > 2
|
||||
? createWrapper(key, 19, slice(arguments, 2), null, object)
|
||||
: createWrapper(key, 3, null, null, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that is the composition of the provided functions,
|
||||
* where each function consumes the return value of the function that follows.
|
||||
* For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`.
|
||||
* Each function is executed with the `this` binding of the composed function.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Functions
|
||||
* @param {...Function} [func] Functions to compose.
|
||||
* @returns {Function} Returns the new composed function.
|
||||
* @example
|
||||
*
|
||||
* var realNameMap = {
|
||||
* 'pebbles': 'penelope'
|
||||
* };
|
||||
*
|
||||
* var format = function(name) {
|
||||
* name = realNameMap[name.toLowerCase()] || name;
|
||||
* return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();
|
||||
* };
|
||||
*
|
||||
* var greet = function(formatted) {
|
||||
* return 'Hiya ' + formatted + '!';
|
||||
* };
|
||||
*
|
||||
* var welcome = _.compose(greet, format);
|
||||
* welcome('pebbles');
|
||||
* // => 'Hiya Penelope!'
|
||||
*/
|
||||
function compose() {
|
||||
var funcs = arguments,
|
||||
length = funcs.length;
|
||||
|
||||
while (length--) {
|
||||
if (!isFunction(funcs[length])) {
|
||||
throw new TypeError;
|
||||
}
|
||||
}
|
||||
return function() {
|
||||
var args = arguments,
|
||||
length = funcs.length;
|
||||
|
||||
while (length--) {
|
||||
args = [funcs[length].apply(this, args)];
|
||||
}
|
||||
return args[0];
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function which accepts one or more arguments of `func` that when
|
||||
* invoked either executes `func` returning its result, if all `func` arguments
|
||||
* have been provided, or returns a function that accepts one or more of the
|
||||
* remaining `func` arguments, and so on. The arity of `func` can be specified
|
||||
* if `func.length` is not sufficient.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Functions
|
||||
* @param {Function} func The function to curry.
|
||||
* @param {number} [arity=func.length] The arity of `func`.
|
||||
* @returns {Function} Returns the new curried function.
|
||||
* @example
|
||||
*
|
||||
* var curried = _.curry(function(a, b, c) {
|
||||
* console.log(a + b + c);
|
||||
* });
|
||||
*
|
||||
* curried(1)(2)(3);
|
||||
* // => 6
|
||||
*
|
||||
* curried(1, 2)(3);
|
||||
* // => 6
|
||||
*
|
||||
* curried(1, 2, 3);
|
||||
* // => 6
|
||||
*/
|
||||
function curry(func, arity) {
|
||||
arity = typeof arity == 'number' ? arity : (+arity || func.length);
|
||||
return createWrapper(func, 4, null, null, null, arity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that will delay the execution of `func` until after
|
||||
* `wait` milliseconds have elapsed since the last time it was invoked.
|
||||
* Provide an options object to indicate that `func` should be invoked on
|
||||
* the leading and/or trailing edge of the `wait` timeout. Subsequent calls
|
||||
* to the debounced function will return the result of the last `func` call.
|
||||
*
|
||||
* Note: If `leading` and `trailing` options are `true` `func` will be called
|
||||
* on the trailing edge of the timeout only if the the debounced function is
|
||||
* invoked more than once during the `wait` timeout.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Functions
|
||||
* @param {Function} func The function to debounce.
|
||||
* @param {number} wait The number of milliseconds to delay.
|
||||
* @param {Object} [options] The options object.
|
||||
* @param {boolean} [options.leading=false] Specify execution on the leading edge of the timeout.
|
||||
* @param {number} [options.maxWait] The maximum time `func` is allowed to be delayed before it's called.
|
||||
* @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
|
||||
* @returns {Function} Returns the new debounced function.
|
||||
* @example
|
||||
*
|
||||
* // avoid costly calculations while the window size is in flux
|
||||
* var lazyLayout = _.debounce(calculateLayout, 150);
|
||||
* jQuery(window).on('resize', lazyLayout);
|
||||
*
|
||||
* // execute `sendMail` when the click event is fired, debouncing subsequent calls
|
||||
* jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
|
||||
* 'leading': true,
|
||||
* 'trailing': false
|
||||
* });
|
||||
*
|
||||
* // ensure `batchLog` is executed once after 1 second of debounced calls
|
||||
* var source = new EventSource('/stream');
|
||||
* source.addEventListener('message', _.debounce(batchLog, 250, {
|
||||
* 'maxWait': 1000
|
||||
* }, false);
|
||||
*/
|
||||
function debounce(func, wait, options) {
|
||||
var args,
|
||||
maxTimeoutId,
|
||||
result,
|
||||
stamp,
|
||||
thisArg,
|
||||
timeoutId,
|
||||
trailingCall,
|
||||
lastCalled = 0,
|
||||
maxWait = false,
|
||||
trailing = true;
|
||||
|
||||
if (!isFunction(func)) {
|
||||
throw new TypeError;
|
||||
}
|
||||
wait = nativeMax(0, wait) || 0;
|
||||
if (options === true) {
|
||||
var leading = true;
|
||||
trailing = false;
|
||||
} else if (isObject(options)) {
|
||||
leading = options.leading;
|
||||
maxWait = 'maxWait' in options && (nativeMax(wait, options.maxWait) || 0);
|
||||
trailing = 'trailing' in options ? options.trailing : trailing;
|
||||
}
|
||||
var delayed = function() {
|
||||
var remaining = wait - (now() - stamp);
|
||||
if (remaining <= 0) {
|
||||
if (maxTimeoutId) {
|
||||
clearTimeout(maxTimeoutId);
|
||||
}
|
||||
var isCalled = trailingCall;
|
||||
maxTimeoutId = timeoutId = trailingCall = undefined;
|
||||
if (isCalled) {
|
||||
lastCalled = now();
|
||||
result = func.apply(thisArg, args);
|
||||
if (!timeoutId && !maxTimeoutId) {
|
||||
args = thisArg = null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
timeoutId = setTimeout(delayed, remaining);
|
||||
}
|
||||
};
|
||||
|
||||
var maxDelayed = function() {
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
maxTimeoutId = timeoutId = trailingCall = undefined;
|
||||
if (trailing || (maxWait !== wait)) {
|
||||
lastCalled = now();
|
||||
result = func.apply(thisArg, args);
|
||||
if (!timeoutId && !maxTimeoutId) {
|
||||
args = thisArg = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return function() {
|
||||
args = arguments;
|
||||
stamp = now();
|
||||
thisArg = this;
|
||||
trailingCall = trailing && (timeoutId || !leading);
|
||||
|
||||
if (maxWait === false) {
|
||||
var leadingCall = leading && !timeoutId;
|
||||
} else {
|
||||
if (!maxTimeoutId && !leading) {
|
||||
lastCalled = stamp;
|
||||
}
|
||||
var remaining = maxWait - (stamp - lastCalled),
|
||||
isCalled = remaining <= 0;
|
||||
|
||||
if (isCalled) {
|
||||
if (maxTimeoutId) {
|
||||
maxTimeoutId = clearTimeout(maxTimeoutId);
|
||||
}
|
||||
lastCalled = stamp;
|
||||
result = func.apply(thisArg, args);
|
||||
}
|
||||
else if (!maxTimeoutId) {
|
||||
maxTimeoutId = setTimeout(maxDelayed, remaining);
|
||||
}
|
||||
}
|
||||
if (isCalled && timeoutId) {
|
||||
timeoutId = clearTimeout(timeoutId);
|
||||
}
|
||||
else if (!timeoutId && wait !== maxWait) {
|
||||
timeoutId = setTimeout(delayed, wait);
|
||||
}
|
||||
if (leadingCall) {
|
||||
isCalled = true;
|
||||
result = func.apply(thisArg, args);
|
||||
}
|
||||
if (isCalled && !timeoutId && !maxTimeoutId) {
|
||||
args = thisArg = null;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Defers executing the `func` function until the current call stack has cleared.
|
||||
* Additional arguments will be provided to `func` when it is invoked.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Functions
|
||||
* @param {Function} func The function to defer.
|
||||
* @param {...*} [arg] Arguments to invoke the function with.
|
||||
* @returns {number} Returns the timer id.
|
||||
* @example
|
||||
*
|
||||
* _.defer(function(text) { console.log(text); }, 'deferred');
|
||||
* // logs 'deferred' after one or more milliseconds
|
||||
*/
|
||||
function defer(func) {
|
||||
if (!isFunction(func)) {
|
||||
throw new TypeError;
|
||||
}
|
||||
var args = slice(arguments, 1);
|
||||
return setTimeout(function() { func.apply(undefined, args); }, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the `func` function after `wait` milliseconds. Additional arguments
|
||||
* will be provided to `func` when it is invoked.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Functions
|
||||
* @param {Function} func The function to delay.
|
||||
* @param {number} wait The number of milliseconds to delay execution.
|
||||
* @param {...*} [arg] Arguments to invoke the function with.
|
||||
* @returns {number} Returns the timer id.
|
||||
* @example
|
||||
*
|
||||
* _.delay(function(text) { console.log(text); }, 1000, 'later');
|
||||
* // => logs 'later' after one second
|
||||
*/
|
||||
function delay(func, wait) {
|
||||
if (!isFunction(func)) {
|
||||
throw new TypeError;
|
||||
}
|
||||
var args = slice(arguments, 2);
|
||||
return setTimeout(function() { func.apply(undefined, args); }, wait);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that memoizes the result of `func`. If `resolver` is
|
||||
* provided it will be used to determine the cache key for storing the result
|
||||
* based on the arguments provided to the memoized function. By default, the
|
||||
* first argument provided to the memoized function is used as the cache key.
|
||||
* The `func` is executed with the `this` binding of the memoized function.
|
||||
* The result cache is exposed as the `cache` property on the memoized function.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Functions
|
||||
* @param {Function} func The function to have its output memoized.
|
||||
* @param {Function} [resolver] A function used to resolve the cache key.
|
||||
* @returns {Function} Returns the new memoizing function.
|
||||
* @example
|
||||
*
|
||||
* var fibonacci = _.memoize(function(n) {
|
||||
* return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
|
||||
* });
|
||||
*
|
||||
* fibonacci(9)
|
||||
* // => 34
|
||||
*
|
||||
* var data = {
|
||||
* 'fred': { 'name': 'fred', 'age': 40 },
|
||||
* 'pebbles': { 'name': 'pebbles', 'age': 1 }
|
||||
* };
|
||||
*
|
||||
* // modifying the result cache
|
||||
* var get = _.memoize(function(name) { return data[name]; }, _.identity);
|
||||
* get('pebbles');
|
||||
* // => { 'name': 'pebbles', 'age': 1 }
|
||||
*
|
||||
* get.cache.pebbles.name = 'penelope';
|
||||
* get('pebbles');
|
||||
* // => { 'name': 'penelope', 'age': 1 }
|
||||
*/
|
||||
function memoize(func, resolver) {
|
||||
if (!isFunction(func)) {
|
||||
throw new TypeError;
|
||||
}
|
||||
var memoized = function() {
|
||||
var cache = memoized.cache,
|
||||
key = resolver ? resolver.apply(this, arguments) : keyPrefix + arguments[0];
|
||||
|
||||
return hasOwnProperty.call(cache, key)
|
||||
? cache[key]
|
||||
: (cache[key] = func.apply(this, arguments));
|
||||
}
|
||||
memoized.cache = {};
|
||||
return memoized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that is restricted to execute `func` once. Repeat calls to
|
||||
* the function will return the value of the first call. The `func` is executed
|
||||
* with the `this` binding of the created function.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Functions
|
||||
* @param {Function} func The function to restrict.
|
||||
* @returns {Function} Returns the new restricted function.
|
||||
* @example
|
||||
*
|
||||
* var initialize = _.once(createApplication);
|
||||
* initialize();
|
||||
* initialize();
|
||||
* // `initialize` executes `createApplication` once
|
||||
*/
|
||||
function once(func) {
|
||||
var ran,
|
||||
result;
|
||||
|
||||
if (!isFunction(func)) {
|
||||
throw new TypeError;
|
||||
}
|
||||
return function() {
|
||||
if (ran) {
|
||||
return result;
|
||||
}
|
||||
ran = true;
|
||||
result = func.apply(this, arguments);
|
||||
|
||||
// clear the `func` variable so the function may be garbage collected
|
||||
func = null;
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that, when called, invokes `func` with any additional
|
||||
* `partial` arguments prepended to those provided to the new function. This
|
||||
* method is similar to `_.bind` except it does **not** alter the `this` binding.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Functions
|
||||
* @param {Function} func The function to partially apply arguments to.
|
||||
* @param {...*} [arg] Arguments to be partially applied.
|
||||
* @returns {Function} Returns the new partially applied function.
|
||||
* @example
|
||||
*
|
||||
* var greet = function(greeting, name) { return greeting + ' ' + name; };
|
||||
* var hi = _.partial(greet, 'hi');
|
||||
* hi('fred');
|
||||
* // => 'hi fred'
|
||||
*/
|
||||
function partial(func) {
|
||||
return createWrapper(func, 16, slice(arguments, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is like `_.partial` except that `partial` arguments are
|
||||
* appended to those provided to the new function.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Functions
|
||||
* @param {Function} func The function to partially apply arguments to.
|
||||
* @param {...*} [arg] Arguments to be partially applied.
|
||||
* @returns {Function} Returns the new partially applied function.
|
||||
* @example
|
||||
*
|
||||
* var defaultsDeep = _.partialRight(_.merge, _.defaults);
|
||||
*
|
||||
* var options = {
|
||||
* 'variable': 'data',
|
||||
* 'imports': { 'jq': $ }
|
||||
* };
|
||||
*
|
||||
* defaultsDeep(options, _.templateSettings);
|
||||
*
|
||||
* options.variable
|
||||
* // => 'data'
|
||||
*
|
||||
* options.imports
|
||||
* // => { '_': _, 'jq': $ }
|
||||
*/
|
||||
function partialRight(func) {
|
||||
return createWrapper(func, 32, null, slice(arguments, 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that, when executed, will only call the `func` function
|
||||
* at most once per every `wait` milliseconds. Provide an options object to
|
||||
* indicate that `func` should be invoked on the leading and/or trailing edge
|
||||
* of the `wait` timeout. Subsequent calls to the throttled function will
|
||||
* return the result of the last `func` call.
|
||||
*
|
||||
* Note: If `leading` and `trailing` options are `true` `func` will be called
|
||||
* on the trailing edge of the timeout only if the the throttled function is
|
||||
* invoked more than once during the `wait` timeout.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Functions
|
||||
* @param {Function} func The function to throttle.
|
||||
* @param {number} wait The number of milliseconds to throttle executions to.
|
||||
* @param {Object} [options] The options object.
|
||||
* @param {boolean} [options.leading=true] Specify execution on the leading edge of the timeout.
|
||||
* @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
|
||||
* @returns {Function} Returns the new throttled function.
|
||||
* @example
|
||||
*
|
||||
* // avoid excessively updating the position while scrolling
|
||||
* var throttled = _.throttle(updatePosition, 100);
|
||||
* jQuery(window).on('scroll', throttled);
|
||||
*
|
||||
* // execute `renewToken` when the click event is fired, but not more than once every 5 minutes
|
||||
* jQuery('.interactive').on('click', _.throttle(renewToken, 300000, {
|
||||
* 'trailing': false
|
||||
* }));
|
||||
*/
|
||||
function throttle(func, wait, options) {
|
||||
var leading = true,
|
||||
trailing = true;
|
||||
|
||||
if (!isFunction(func)) {
|
||||
throw new TypeError;
|
||||
}
|
||||
if (options === false) {
|
||||
leading = false;
|
||||
} else if (isObject(options)) {
|
||||
leading = 'leading' in options ? options.leading : leading;
|
||||
trailing = 'trailing' in options ? options.trailing : trailing;
|
||||
}
|
||||
debounceOptions.leading = leading;
|
||||
debounceOptions.maxWait = wait;
|
||||
debounceOptions.trailing = trailing;
|
||||
|
||||
return debounce(func, wait, debounceOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function that provides `value` to the wrapper function as its
|
||||
* first argument. Additional arguments provided to the function are appended
|
||||
* to those provided to the wrapper function. The wrapper is executed with
|
||||
* the `this` binding of the created function.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Functions
|
||||
* @param {*} value The value to wrap.
|
||||
* @param {Function} wrapper The wrapper function.
|
||||
* @returns {Function} Returns the new function.
|
||||
* @example
|
||||
*
|
||||
* var p = _.wrap(_.escape, function(func, text) {
|
||||
* return '<p>' + func(text) + '</p>';
|
||||
* });
|
||||
*
|
||||
* p('Fred, Wilma, & Pebbles');
|
||||
* // => '<p>Fred, Wilma, & Pebbles</p>'
|
||||
*/
|
||||
function wrap(value, wrapper) {
|
||||
return createWrapper(wrapper, 16, [value]);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Creates a function that returns `value`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Utilities
|
||||
* @param {*} value The value to return from the new function.
|
||||
* @returns {Function} Returns the new function.
|
||||
* @example
|
||||
*
|
||||
* var object = { 'name': 'fred' };
|
||||
* var getter = _.constant(object);
|
||||
* getter() === object;
|
||||
* // => true
|
||||
*/
|
||||
function constant(value) {
|
||||
return function() {
|
||||
return value;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces a callback bound to an optional `thisArg`. If `func` is a property
|
||||
* name the created callback will return the property value for a given element.
|
||||
* If `func` is an object the created callback will return `true` for elements
|
||||
* that contain the equivalent object properties, otherwise it will return `false`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Utilities
|
||||
* @param {*} [func=identity] The value to convert to a callback.
|
||||
* @param {*} [thisArg] The `this` binding of the created callback.
|
||||
* @param {number} [argCount] The number of arguments the callback accepts.
|
||||
* @returns {Function} Returns a callback function.
|
||||
* @example
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'barney', 'age': 36 },
|
||||
* { 'name': 'fred', 'age': 40 }
|
||||
* ];
|
||||
*
|
||||
* // wrap to create custom callback shorthands
|
||||
* _.createCallback = _.wrap(_.createCallback, function(func, callback, thisArg) {
|
||||
* var match = /^(.+?)__([gl]t)(.+)$/.exec(callback);
|
||||
* return !match ? func(callback, thisArg) : function(object) {
|
||||
* return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3];
|
||||
* };
|
||||
* });
|
||||
*
|
||||
* _.filter(characters, 'age__gt38');
|
||||
* // => [{ 'name': 'fred', 'age': 40 }]
|
||||
*/
|
||||
function createCallback(func, thisArg, argCount) {
|
||||
var type = typeof func;
|
||||
if (func == null || type == 'function') {
|
||||
return baseCreateCallback(func, thisArg, argCount);
|
||||
}
|
||||
// handle "_.pluck" style callback shorthands
|
||||
if (type != 'object') {
|
||||
return property(func);
|
||||
}
|
||||
var props = keys(func),
|
||||
key = props[0],
|
||||
a = func[key];
|
||||
|
||||
// handle "_.where" style callback shorthands
|
||||
if (props.length == 1 && a === a && !isObject(a)) {
|
||||
// fast path the common case of providing an object with a single
|
||||
// property containing a primitive value
|
||||
return function(object) {
|
||||
var b = object[key];
|
||||
return a === b && (a !== 0 || (1 / a == 1 / b));
|
||||
};
|
||||
}
|
||||
return function(object) {
|
||||
var length = props.length,
|
||||
result = false;
|
||||
|
||||
while (length--) {
|
||||
if (!(result = baseIsEqual(object[props[length]], func[props[length]], null, true))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their
|
||||
* corresponding HTML entities.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Utilities
|
||||
* @param {string} string The string to escape.
|
||||
* @returns {string} Returns the escaped string.
|
||||
* @example
|
||||
*
|
||||
* _.escape('Fred, Wilma, & Pebbles');
|
||||
* // => 'Fred, Wilma, & Pebbles'
|
||||
*/
|
||||
function escape(string) {
|
||||
return string == null ? '' : String(string).replace(reUnescapedHtml, escapeHtmlChar);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the first argument provided to it.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Utilities
|
||||
* @param {*} value Any value.
|
||||
* @returns {*} Returns `value`.
|
||||
* @example
|
||||
*
|
||||
* var object = { 'name': 'fred' };
|
||||
* _.identity(object) === object;
|
||||
* // => true
|
||||
*/
|
||||
function identity(value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds function properties of a source object to the destination object.
|
||||
* If `object` is a function methods will be added to its prototype as well.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Utilities
|
||||
* @param {Function|Object} [object=lodash] object The destination object.
|
||||
* @param {Object} source The object of functions to add.
|
||||
* @param {Object} [options] The options object.
|
||||
* @param {boolean} [options.chain=true] Specify whether the functions added are chainable.
|
||||
* @example
|
||||
*
|
||||
* function capitalize(string) {
|
||||
* return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
|
||||
* }
|
||||
*
|
||||
* _.mixin({ 'capitalize': capitalize });
|
||||
* _.capitalize('fred');
|
||||
* // => 'Fred'
|
||||
*
|
||||
* _('fred').capitalize().value();
|
||||
* // => 'Fred'
|
||||
*
|
||||
* _.mixin({ 'capitalize': capitalize }, { 'chain': false });
|
||||
* _('fred').capitalize();
|
||||
* // => 'Fred'
|
||||
*/
|
||||
function mixin(object, source, options) {
|
||||
var chain = true,
|
||||
methodNames = source && functions(source);
|
||||
|
||||
if (!source || (!options && !methodNames.length)) {
|
||||
if (options == null) {
|
||||
options = source;
|
||||
}
|
||||
ctor = lodashWrapper;
|
||||
source = object;
|
||||
object = lodash;
|
||||
methodNames = functions(source);
|
||||
}
|
||||
if (options === false) {
|
||||
chain = false;
|
||||
} else if (isObject(options) && 'chain' in options) {
|
||||
chain = options.chain;
|
||||
}
|
||||
var ctor = object,
|
||||
isFunc = isFunction(ctor);
|
||||
|
||||
forEach(methodNames, function(methodName) {
|
||||
var func = object[methodName] = source[methodName];
|
||||
if (isFunc) {
|
||||
ctor.prototype[methodName] = function() {
|
||||
var chainAll = this.__chain__,
|
||||
value = this.__wrapped__,
|
||||
args = [value];
|
||||
|
||||
push.apply(args, arguments);
|
||||
var result = func.apply(object, args);
|
||||
if (chain || chainAll) {
|
||||
if (value === result && isObject(result)) {
|
||||
return this;
|
||||
}
|
||||
result = new ctor(result);
|
||||
result.__chain__ = chainAll;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverts the '_' variable to its previous value and returns a reference to
|
||||
* the `lodash` function.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Utilities
|
||||
* @returns {Function} Returns the `lodash` function.
|
||||
* @example
|
||||
*
|
||||
* var lodash = _.noConflict();
|
||||
*/
|
||||
function noConflict() {
|
||||
context._ = oldDash;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A no-operation function.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Utilities
|
||||
* @example
|
||||
*
|
||||
* var object = { 'name': 'fred' };
|
||||
* _.noop(object) === undefined;
|
||||
* // => true
|
||||
*/
|
||||
function noop() {
|
||||
// no operation performed
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of milliseconds that have elapsed since the Unix epoch
|
||||
* (1 January 1970 00:00:00 UTC).
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Utilities
|
||||
* @example
|
||||
*
|
||||
* var stamp = _.now();
|
||||
* _.defer(function() { console.log(_.now() - stamp); });
|
||||
* // => logs the number of milliseconds it took for the deferred function to be called
|
||||
*/
|
||||
var now = isNative(now = Date.now) && now || function() {
|
||||
return new Date().getTime();
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts the given value into an integer of the specified radix.
|
||||
* If `radix` is `undefined` or `0` a `radix` of `10` is used unless the
|
||||
* `value` is a hexadecimal, in which case a `radix` of `16` is used.
|
||||
*
|
||||
* Note: This method avoids differences in native ES3 and ES5 `parseInt`
|
||||
* implementations. See http://es5.github.io/#E.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Utilities
|
||||
* @param {string} value The value to parse.
|
||||
* @param {number} [radix] The radix used to interpret the value to parse.
|
||||
* @returns {number} Returns the new integer value.
|
||||
* @example
|
||||
*
|
||||
* _.parseInt('08');
|
||||
* // => 8
|
||||
*/
|
||||
var parseInt = nativeParseInt(whitespace + '08') == 8 ? nativeParseInt : function(value, radix) {
|
||||
// Firefox < 21 and Opera < 15 follow the ES3 specified implementation of `parseInt`
|
||||
return nativeParseInt(isString(value) ? value.replace(reLeadingSpacesAndZeros, '') : value, radix || 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a "_.pluck" style function, which returns the `key` value of a
|
||||
* given object.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Utilities
|
||||
* @param {string} key The name of the property to retrieve.
|
||||
* @returns {Function} Returns the new function.
|
||||
* @example
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'fred', 'age': 40 },
|
||||
* { 'name': 'barney', 'age': 36 }
|
||||
* ];
|
||||
*
|
||||
* var getName = _.property('name');
|
||||
*
|
||||
* _.map(characters, getName);
|
||||
* // => ['barney', 'fred']
|
||||
*
|
||||
* _.sortBy(characters, getName);
|
||||
* // => [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }]
|
||||
*/
|
||||
function property(key) {
|
||||
return function(object) {
|
||||
return object[key];
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces a random number between `min` and `max` (inclusive). If only one
|
||||
* argument is provided a number between `0` and the given number will be
|
||||
* returned. If `floating` is truey or either `min` or `max` are floats a
|
||||
* floating-point number will be returned instead of an integer.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Utilities
|
||||
* @param {number} [min=0] The minimum possible value.
|
||||
* @param {number} [max=1] The maximum possible value.
|
||||
* @param {boolean} [floating=false] Specify returning a floating-point number.
|
||||
* @returns {number} Returns a random number.
|
||||
* @example
|
||||
*
|
||||
* _.random(0, 5);
|
||||
* // => an integer between 0 and 5
|
||||
*
|
||||
* _.random(5);
|
||||
* // => also an integer between 0 and 5
|
||||
*
|
||||
* _.random(5, true);
|
||||
* // => a floating-point number between 0 and 5
|
||||
*
|
||||
* _.random(1.2, 5.2);
|
||||
* // => a floating-point number between 1.2 and 5.2
|
||||
*/
|
||||
function random(min, max, floating) {
|
||||
var noMin = min == null,
|
||||
noMax = max == null;
|
||||
|
||||
if (floating == null) {
|
||||
if (typeof min == 'boolean' && noMax) {
|
||||
floating = min;
|
||||
min = 1;
|
||||
}
|
||||
else if (!noMax && typeof max == 'boolean') {
|
||||
floating = max;
|
||||
noMax = true;
|
||||
}
|
||||
}
|
||||
if (noMin && noMax) {
|
||||
max = 1;
|
||||
}
|
||||
min = +min || 0;
|
||||
if (noMax) {
|
||||
max = min;
|
||||
min = 0;
|
||||
} else {
|
||||
max = +max || 0;
|
||||
}
|
||||
if (floating || min % 1 || max % 1) {
|
||||
var rand = nativeRandom();
|
||||
return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1)))), max);
|
||||
}
|
||||
return baseRandom(min, max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the value of property `key` on `object`. If `key` is a function
|
||||
* it will be invoked with the `this` binding of `object` and its result returned,
|
||||
* else the property value is returned. If `object` is falsey then `undefined`
|
||||
* is returned.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Utilities
|
||||
* @param {Object} object The object to inspect.
|
||||
* @param {string} key The name of the property to resolve.
|
||||
* @returns {*} Returns the resolved value.
|
||||
* @example
|
||||
*
|
||||
* var object = {
|
||||
* 'cheese': 'crumpets',
|
||||
* 'stuff': function() {
|
||||
* return 'nonsense';
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* _.result(object, 'cheese');
|
||||
* // => 'crumpets'
|
||||
*
|
||||
* _.result(object, 'stuff');
|
||||
* // => 'nonsense'
|
||||
*/
|
||||
function result(object, key) {
|
||||
if (object) {
|
||||
var value = object[key];
|
||||
return isFunction(value) ? object[key]() : value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A micro-templating method that handles arbitrary delimiters, preserves
|
||||
* whitespace, and correctly escapes quotes within interpolated code.
|
||||
*
|
||||
* Note: In the development build, `_.template` utilizes sourceURLs for easier
|
||||
* debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
|
||||
*
|
||||
* For more information on precompiling templates see:
|
||||
* http://lodash.com/custom-builds
|
||||
*
|
||||
* For more information on Chrome extension sandboxes see:
|
||||
* http://developer.chrome.com/stable/extensions/sandboxingEval.html
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Utilities
|
||||
* @param {string} text The template text.
|
||||
* @param {Object} data The data object used to populate the text.
|
||||
* @param {Object} [options] The options object.
|
||||
* @param {RegExp} [options.escape] The "escape" delimiter.
|
||||
* @param {RegExp} [options.evaluate] The "evaluate" delimiter.
|
||||
* @param {Object} [options.imports] An object to import into the template as local variables.
|
||||
* @param {RegExp} [options.interpolate] The "interpolate" delimiter.
|
||||
* @param {string} [sourceURL] The sourceURL of the template's compiled source.
|
||||
* @param {string} [variable] The data object variable name.
|
||||
* @returns {Function|string} Returns a compiled function when no `data` object
|
||||
* is given, else it returns the interpolated text.
|
||||
* @example
|
||||
*
|
||||
* // using the "interpolate" delimiter to create a compiled template
|
||||
* var compiled = _.template('hello <%= name %>');
|
||||
* compiled({ 'name': 'fred' });
|
||||
* // => 'hello fred'
|
||||
*
|
||||
* // using the "escape" delimiter to escape HTML in data property values
|
||||
* _.template('<b><%- value %></b>', { 'value': '<script>' });
|
||||
* // => '<b><script></b>'
|
||||
*
|
||||
* // using the "evaluate" delimiter to generate HTML
|
||||
* var list = '<% _.forEach(people, function(name) { %><li><%- name %></li><% }); %>';
|
||||
* _.template(list, { 'people': ['fred', 'barney'] });
|
||||
* // => '<li>fred</li><li>barney</li>'
|
||||
*
|
||||
* // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
|
||||
* _.template('hello ${ name }', { 'name': 'pebbles' });
|
||||
* // => 'hello pebbles'
|
||||
*
|
||||
* // using the internal `print` function in "evaluate" delimiters
|
||||
* _.template('<% print("hello " + name); %>!', { 'name': 'barney' });
|
||||
* // => 'hello barney!'
|
||||
*
|
||||
* // using a custom template delimiters
|
||||
* _.templateSettings = {
|
||||
* 'interpolate': /{{([\s\S]+?)}}/g
|
||||
* };
|
||||
*
|
||||
* _.template('hello {{ name }}!', { 'name': 'mustache' });
|
||||
* // => 'hello mustache!'
|
||||
*
|
||||
* // using the `imports` option to import jQuery
|
||||
* var list = '<% jq.each(people, function(name) { %><li><%- name %></li><% }); %>';
|
||||
* _.template(list, { 'people': ['fred', 'barney'] }, { 'imports': { 'jq': jQuery } });
|
||||
* // => '<li>fred</li><li>barney</li>'
|
||||
*
|
||||
* // using the `sourceURL` option to specify a custom sourceURL for the template
|
||||
* var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' });
|
||||
* compiled(data);
|
||||
* // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
|
||||
*
|
||||
* // using the `variable` option to ensure a with-statement isn't used in the compiled template
|
||||
* var compiled = _.template('hi <%= data.name %>!', null, { 'variable': 'data' });
|
||||
* compiled.source;
|
||||
* // => function(data) {
|
||||
* var __t, __p = '', __e = _.escape;
|
||||
* __p += 'hi ' + ((__t = ( data.name )) == null ? '' : __t) + '!';
|
||||
* return __p;
|
||||
* }
|
||||
*
|
||||
* // using the `source` property to inline compiled templates for meaningful
|
||||
* // line numbers in error messages and a stack trace
|
||||
* fs.writeFileSync(path.join(cwd, 'jst.js'), '\
|
||||
* var JST = {\
|
||||
* "main": ' + _.template(mainText).source + '\
|
||||
* };\
|
||||
* ');
|
||||
*/
|
||||
function template(text, data, options) {
|
||||
// based on John Resig's `tmpl` implementation
|
||||
// http://ejohn.org/blog/javascript-micro-templating/
|
||||
// and Laura Doktorova's doT.js
|
||||
// https://github.com/olado/doT
|
||||
var settings = lodash.templateSettings;
|
||||
text = String(text || '');
|
||||
|
||||
// avoid missing dependencies when `iteratorTemplate` is not defined
|
||||
options = iteratorTemplate ? defaults({}, options, settings) : settings;
|
||||
|
||||
var imports = iteratorTemplate && defaults({}, options.imports, settings.imports),
|
||||
importsKeys = iteratorTemplate ? keys(imports) : ['_'],
|
||||
importsValues = iteratorTemplate ? values(imports) : [lodash];
|
||||
|
||||
var isEvaluating,
|
||||
index = 0,
|
||||
interpolate = options.interpolate || reNoMatch,
|
||||
source = "__p += '";
|
||||
|
||||
// compile the regexp to match each delimiter
|
||||
var reDelimiters = RegExp(
|
||||
(options.escape || reNoMatch).source + '|' +
|
||||
interpolate.source + '|' +
|
||||
(interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
|
||||
(options.evaluate || reNoMatch).source + '|$'
|
||||
, 'g');
|
||||
|
||||
text.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
|
||||
interpolateValue || (interpolateValue = esTemplateValue);
|
||||
|
||||
// escape characters that cannot be included in string literals
|
||||
source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar);
|
||||
|
||||
// replace delimiters with snippets
|
||||
if (escapeValue) {
|
||||
source += "' +\n__e(" + escapeValue + ") +\n'";
|
||||
}
|
||||
if (evaluateValue) {
|
||||
isEvaluating = true;
|
||||
source += "';\n" + evaluateValue + ";\n__p += '";
|
||||
}
|
||||
if (interpolateValue) {
|
||||
source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
|
||||
}
|
||||
index = offset + match.length;
|
||||
|
||||
// the JS engine embedded in Adobe products requires returning the `match`
|
||||
// string in order to produce the correct `offset` value
|
||||
return match;
|
||||
});
|
||||
|
||||
source += "';\n";
|
||||
|
||||
// if `variable` is not specified, wrap a with-statement around the generated
|
||||
// code to add the data object to the top of the scope chain
|
||||
var variable = options.variable,
|
||||
hasVariable = variable;
|
||||
|
||||
if (!hasVariable) {
|
||||
variable = 'obj';
|
||||
source = 'with (' + variable + ') {\n' + source + '\n}\n';
|
||||
}
|
||||
// cleanup code by stripping empty strings
|
||||
source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
|
||||
.replace(reEmptyStringMiddle, '$1')
|
||||
.replace(reEmptyStringTrailing, '$1;');
|
||||
|
||||
// frame code as the function body
|
||||
source = 'function(' + variable + ') {\n' +
|
||||
(hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') +
|
||||
"var __t, __p = '', __e = _.escape" +
|
||||
(isEvaluating
|
||||
? ', __j = Array.prototype.join;\n' +
|
||||
"function print() { __p += __j.call(arguments, '') }\n"
|
||||
: ';\n'
|
||||
) +
|
||||
source +
|
||||
'return __p\n}';
|
||||
|
||||
// Use a sourceURL for easier debugging.
|
||||
// http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
|
||||
var sourceURL = '\n/*\n//# sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']') + '\n*/';
|
||||
|
||||
try {
|
||||
var result = Function(importsKeys, 'return ' + source + sourceURL).apply(undefined, importsValues);
|
||||
} catch(e) {
|
||||
e.source = source;
|
||||
throw e;
|
||||
}
|
||||
if (data) {
|
||||
return result(data);
|
||||
}
|
||||
// provide the compiled function's source by its `toString` method, in
|
||||
// supported environments, or the `source` property as a convenience for
|
||||
// inlining compiled templates during the build process
|
||||
result.source = source;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the callback `n` times, returning an array of the results
|
||||
* of each callback execution. The callback is bound to `thisArg` and invoked
|
||||
* with one argument; (index).
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Utilities
|
||||
* @param {number} n The number of times to execute the callback.
|
||||
* @param {Function} callback The function called per iteration.
|
||||
* @param {*} [thisArg] The `this` binding of `callback`.
|
||||
* @returns {Array} Returns an array of the results of each `callback` execution.
|
||||
* @example
|
||||
*
|
||||
* var diceRolls = _.times(3, _.partial(_.random, 1, 6));
|
||||
* // => [3, 6, 4]
|
||||
*
|
||||
* _.times(3, function(n) { mage.castSpell(n); });
|
||||
* // => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, and `2` respectively
|
||||
*
|
||||
* _.times(3, function(n) { this.cast(n); }, mage);
|
||||
* // => also calls `mage.castSpell(n)` three times
|
||||
*/
|
||||
function times(n, callback, thisArg) {
|
||||
n = (n = +n) > -1 ? n : 0;
|
||||
var index = -1,
|
||||
result = Array(n);
|
||||
|
||||
callback = baseCreateCallback(callback, thisArg, 1);
|
||||
while (++index < n) {
|
||||
result[index] = callback(index);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* The inverse of `_.escape` this method converts the HTML entities
|
||||
* `&`, `<`, `>`, `"`, and `'` in `string` to their
|
||||
* corresponding characters.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Utilities
|
||||
* @param {string} string The string to unescape.
|
||||
* @returns {string} Returns the unescaped string.
|
||||
* @example
|
||||
*
|
||||
* _.unescape('Fred, Barney & Pebbles');
|
||||
* // => 'Fred, Barney & Pebbles'
|
||||
*/
|
||||
function unescape(string) {
|
||||
return string == null ? '' : String(string).replace(reEscapedHtml, unescapeHtmlChar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a unique ID. If `prefix` is provided the ID will be appended to it.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Utilities
|
||||
* @param {string} [prefix] The value to prefix the ID with.
|
||||
* @returns {string} Returns the unique ID.
|
||||
* @example
|
||||
*
|
||||
* _.uniqueId('contact_');
|
||||
* // => 'contact_104'
|
||||
*
|
||||
* _.uniqueId();
|
||||
* // => '105'
|
||||
*/
|
||||
function uniqueId(prefix) {
|
||||
var id = ++idCounter;
|
||||
return String(prefix == null ? '' : prefix) + id;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Creates a `lodash` object that wraps the given value with explicit
|
||||
* method chaining enabled.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Chaining
|
||||
* @param {*} value The value to wrap.
|
||||
* @returns {Object} Returns the wrapper object.
|
||||
* @example
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'barney', 'age': 36 },
|
||||
* { 'name': 'fred', 'age': 40 },
|
||||
* { 'name': 'pebbles', 'age': 1 }
|
||||
* ];
|
||||
*
|
||||
* var youngest = _.chain(characters)
|
||||
* .sortBy('age')
|
||||
* .map(function(chr) { return chr.name + ' is ' + chr.age; })
|
||||
* .first()
|
||||
* .value();
|
||||
* // => 'pebbles is 1'
|
||||
*/
|
||||
function chain(value) {
|
||||
value = new lodashWrapper(value);
|
||||
value.__chain__ = true;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes `interceptor` with the `value` as the first argument and then
|
||||
* returns `value`. The purpose of this method is to "tap into" a method
|
||||
* chain in order to perform operations on intermediate results within
|
||||
* the chain.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @category Chaining
|
||||
* @param {*} value The value to provide to `interceptor`.
|
||||
* @param {Function} interceptor The function to invoke.
|
||||
* @returns {*} Returns `value`.
|
||||
* @example
|
||||
*
|
||||
* _([1, 2, 3, 4])
|
||||
* .tap(function(array) { array.pop(); })
|
||||
* .reverse()
|
||||
* .value();
|
||||
* // => [3, 2, 1]
|
||||
*/
|
||||
function tap(value, interceptor) {
|
||||
interceptor(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables explicit method chaining on the wrapper object.
|
||||
*
|
||||
* @name chain
|
||||
* @memberOf _
|
||||
* @category Chaining
|
||||
* @returns {*} Returns the wrapper object.
|
||||
* @example
|
||||
*
|
||||
* var characters = [
|
||||
* { 'name': 'barney', 'age': 36 },
|
||||
* { 'name': 'fred', 'age': 40 }
|
||||
* ];
|
||||
*
|
||||
* // without explicit chaining
|
||||
* _(characters).first();
|
||||
* // => { 'name': 'barney', 'age': 36 }
|
||||
*
|
||||
* // with explicit chaining
|
||||
* _(characters).chain()
|
||||
* .first()
|
||||
* .pick('age')
|
||||
* .value();
|
||||
* // => { 'age': 36 }
|
||||
*/
|
||||
function wrapperChain() {
|
||||
this.__chain__ = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces the `toString` result of the wrapped value.
|
||||
*
|
||||
* @name toString
|
||||
* @memberOf _
|
||||
* @category Chaining
|
||||
* @returns {string} Returns the string result.
|
||||
* @example
|
||||
*
|
||||
* _([1, 2, 3]).toString();
|
||||
* // => '1,2,3'
|
||||
*/
|
||||
function wrapperToString() {
|
||||
return String(this.__wrapped__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the wrapped value.
|
||||
*
|
||||
* @name valueOf
|
||||
* @memberOf _
|
||||
* @alias value
|
||||
* @category Chaining
|
||||
* @returns {*} Returns the wrapped value.
|
||||
* @example
|
||||
*
|
||||
* _([1, 2, 3]).valueOf();
|
||||
* // => [1, 2, 3]
|
||||
*/
|
||||
function wrapperValueOf() {
|
||||
return this.__wrapped__;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
// add functions that return wrapped values when chaining
|
||||
lodash.after = after;
|
||||
lodash.assign = assign;
|
||||
lodash.at = at;
|
||||
lodash.bind = bind;
|
||||
lodash.bindAll = bindAll;
|
||||
lodash.bindKey = bindKey;
|
||||
lodash.chain = chain;
|
||||
lodash.compact = compact;
|
||||
lodash.compose = compose;
|
||||
lodash.constant = constant;
|
||||
lodash.countBy = countBy;
|
||||
lodash.create = create;
|
||||
lodash.createCallback = createCallback;
|
||||
lodash.curry = curry;
|
||||
lodash.debounce = debounce;
|
||||
lodash.defaults = defaults;
|
||||
lodash.defer = defer;
|
||||
lodash.delay = delay;
|
||||
lodash.difference = difference;
|
||||
lodash.filter = filter;
|
||||
lodash.flatten = flatten;
|
||||
lodash.forEach = forEach;
|
||||
lodash.forEachRight = forEachRight;
|
||||
lodash.forIn = forIn;
|
||||
lodash.forInRight = forInRight;
|
||||
lodash.forOwn = forOwn;
|
||||
lodash.forOwnRight = forOwnRight;
|
||||
lodash.functions = functions;
|
||||
lodash.groupBy = groupBy;
|
||||
lodash.indexBy = indexBy;
|
||||
lodash.initial = initial;
|
||||
lodash.intersection = intersection;
|
||||
lodash.invert = invert;
|
||||
lodash.invoke = invoke;
|
||||
lodash.keys = keys;
|
||||
lodash.map = map;
|
||||
lodash.mapValues = mapValues;
|
||||
lodash.max = max;
|
||||
lodash.memoize = memoize;
|
||||
lodash.merge = merge;
|
||||
lodash.min = min;
|
||||
lodash.omit = omit;
|
||||
lodash.once = once;
|
||||
lodash.pairs = pairs;
|
||||
lodash.partial = partial;
|
||||
lodash.partialRight = partialRight;
|
||||
lodash.pick = pick;
|
||||
lodash.pluck = pluck;
|
||||
lodash.property = property;
|
||||
lodash.pull = pull;
|
||||
lodash.range = range;
|
||||
lodash.reject = reject;
|
||||
lodash.remove = remove;
|
||||
lodash.rest = rest;
|
||||
lodash.shuffle = shuffle;
|
||||
lodash.sortBy = sortBy;
|
||||
lodash.tap = tap;
|
||||
lodash.throttle = throttle;
|
||||
lodash.times = times;
|
||||
lodash.toArray = toArray;
|
||||
lodash.transform = transform;
|
||||
lodash.union = union;
|
||||
lodash.uniq = uniq;
|
||||
lodash.values = values;
|
||||
lodash.where = where;
|
||||
lodash.without = without;
|
||||
lodash.wrap = wrap;
|
||||
lodash.xor = xor;
|
||||
lodash.zip = zip;
|
||||
lodash.zipObject = zipObject;
|
||||
|
||||
// add aliases
|
||||
lodash.collect = map;
|
||||
lodash.drop = rest;
|
||||
lodash.each = forEach;
|
||||
lodash.eachRight = forEachRight;
|
||||
lodash.extend = assign;
|
||||
lodash.methods = functions;
|
||||
lodash.object = zipObject;
|
||||
lodash.select = filter;
|
||||
lodash.tail = rest;
|
||||
lodash.unique = uniq;
|
||||
lodash.unzip = zip;
|
||||
|
||||
// add functions to `lodash.prototype`
|
||||
mixin(lodash);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
// add functions that return unwrapped values when chaining
|
||||
lodash.clone = clone;
|
||||
lodash.cloneDeep = cloneDeep;
|
||||
lodash.contains = contains;
|
||||
lodash.escape = escape;
|
||||
lodash.every = every;
|
||||
lodash.find = find;
|
||||
lodash.findIndex = findIndex;
|
||||
lodash.findKey = findKey;
|
||||
lodash.findLast = findLast;
|
||||
lodash.findLastIndex = findLastIndex;
|
||||
lodash.findLastKey = findLastKey;
|
||||
lodash.has = has;
|
||||
lodash.identity = identity;
|
||||
lodash.indexOf = indexOf;
|
||||
lodash.isArguments = isArguments;
|
||||
lodash.isArray = isArray;
|
||||
lodash.isBoolean = isBoolean;
|
||||
lodash.isDate = isDate;
|
||||
lodash.isElement = isElement;
|
||||
lodash.isEmpty = isEmpty;
|
||||
lodash.isEqual = isEqual;
|
||||
lodash.isFinite = isFinite;
|
||||
lodash.isFunction = isFunction;
|
||||
lodash.isNaN = isNaN;
|
||||
lodash.isNull = isNull;
|
||||
lodash.isNumber = isNumber;
|
||||
lodash.isObject = isObject;
|
||||
lodash.isPlainObject = isPlainObject;
|
||||
lodash.isRegExp = isRegExp;
|
||||
lodash.isString = isString;
|
||||
lodash.isUndefined = isUndefined;
|
||||
lodash.lastIndexOf = lastIndexOf;
|
||||
lodash.mixin = mixin;
|
||||
lodash.noConflict = noConflict;
|
||||
lodash.noop = noop;
|
||||
lodash.now = now;
|
||||
lodash.parseInt = parseInt;
|
||||
lodash.random = random;
|
||||
lodash.reduce = reduce;
|
||||
lodash.reduceRight = reduceRight;
|
||||
lodash.result = result;
|
||||
lodash.runInContext = runInContext;
|
||||
lodash.size = size;
|
||||
lodash.some = some;
|
||||
lodash.sortedIndex = sortedIndex;
|
||||
lodash.template = template;
|
||||
lodash.unescape = unescape;
|
||||
lodash.uniqueId = uniqueId;
|
||||
|
||||
// add aliases
|
||||
lodash.all = every;
|
||||
lodash.any = some;
|
||||
lodash.detect = find;
|
||||
lodash.findWhere = find;
|
||||
lodash.foldl = reduce;
|
||||
lodash.foldr = reduceRight;
|
||||
lodash.include = contains;
|
||||
lodash.inject = reduce;
|
||||
|
||||
mixin(function() {
|
||||
var source = {}
|
||||
forOwn(lodash, function(func, methodName) {
|
||||
if (!lodash.prototype[methodName]) {
|
||||
source[methodName] = func;
|
||||
}
|
||||
});
|
||||
return source;
|
||||
}(), false);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
// add functions capable of returning wrapped and unwrapped values when chaining
|
||||
lodash.first = first;
|
||||
lodash.last = last;
|
||||
lodash.sample = sample;
|
||||
|
||||
// add aliases
|
||||
lodash.take = first;
|
||||
lodash.head = first;
|
||||
|
||||
forOwn(lodash, function(func, methodName) {
|
||||
var callbackable = methodName !== 'sample';
|
||||
if (!lodash.prototype[methodName]) {
|
||||
lodash.prototype[methodName]= function(n, guard) {
|
||||
var chainAll = this.__chain__,
|
||||
result = func(this.__wrapped__, n, guard);
|
||||
|
||||
return !chainAll && (n == null || (guard && !(callbackable && typeof n == 'function')))
|
||||
? result
|
||||
: new lodashWrapper(result, chainAll);
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* The semantic version number.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @type string
|
||||
*/
|
||||
lodash.VERSION = '2.4.1';
|
||||
|
||||
// add "Chaining" functions to the wrapper
|
||||
lodash.prototype.chain = wrapperChain;
|
||||
lodash.prototype.toString = wrapperToString;
|
||||
lodash.prototype.value = wrapperValueOf;
|
||||
lodash.prototype.valueOf = wrapperValueOf;
|
||||
|
||||
// add `Array` functions that return unwrapped values
|
||||
baseEach(['join', 'pop', 'shift'], function(methodName) {
|
||||
var func = arrayRef[methodName];
|
||||
lodash.prototype[methodName] = function() {
|
||||
var chainAll = this.__chain__,
|
||||
result = func.apply(this.__wrapped__, arguments);
|
||||
|
||||
return chainAll
|
||||
? new lodashWrapper(result, chainAll)
|
||||
: result;
|
||||
};
|
||||
});
|
||||
|
||||
// add `Array` functions that return the existing wrapped value
|
||||
baseEach(['push', 'reverse', 'sort', 'unshift'], function(methodName) {
|
||||
var func = arrayRef[methodName];
|
||||
lodash.prototype[methodName] = function() {
|
||||
func.apply(this.__wrapped__, arguments);
|
||||
return this;
|
||||
};
|
||||
});
|
||||
|
||||
// add `Array` functions that return new wrapped values
|
||||
baseEach(['concat', 'slice', 'splice'], function(methodName) {
|
||||
var func = arrayRef[methodName];
|
||||
lodash.prototype[methodName] = function() {
|
||||
return new lodashWrapper(func.apply(this.__wrapped__, arguments), this.__chain__);
|
||||
};
|
||||
});
|
||||
|
||||
// avoid array-like object bugs with `Array#shift` and `Array#splice`
|
||||
// in IE < 9, Firefox < 10, Narwhal, and RingoJS
|
||||
if (!support.spliceObjects) {
|
||||
baseEach(['pop', 'shift', 'splice'], function(methodName) {
|
||||
var func = arrayRef[methodName],
|
||||
isSplice = methodName == 'splice';
|
||||
|
||||
lodash.prototype[methodName] = function() {
|
||||
var chainAll = this.__chain__,
|
||||
value = this.__wrapped__,
|
||||
result = func.apply(value, arguments);
|
||||
|
||||
if (value.length === 0) {
|
||||
delete value[0];
|
||||
}
|
||||
return (chainAll || isSplice)
|
||||
? new lodashWrapper(result, chainAll)
|
||||
: result;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// add pseudo private property to be used and removed during the build process
|
||||
lodash._baseEach = baseEach;
|
||||
lodash._iteratorTemplate = iteratorTemplate;
|
||||
lodash._shimKeys = shimKeys;
|
||||
|
||||
return lodash;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
// expose Lo-Dash
|
||||
var _ = runInContext();
|
||||
|
||||
// some AMD build optimizers like r.js check for condition patterns like the following:
|
||||
if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
|
||||
// Expose Lo-Dash to the global object even when an AMD loader is present in
|
||||
// case Lo-Dash is loaded with a RequireJS shim config.
|
||||
// See http://requirejs.org/docs/api.html#config-shim
|
||||
root._ = _;
|
||||
|
||||
// define as an anonymous module so, through path mapping, it can be
|
||||
// referenced as the "underscore" module
|
||||
define(function() {
|
||||
return _;
|
||||
});
|
||||
}
|
||||
// check for `exports` after `define` in case a build optimizer adds an `exports` object
|
||||
else if (freeExports && freeModule) {
|
||||
// in Node.js or RingoJS
|
||||
if (moduleExports) {
|
||||
(freeModule.exports = _)._ = _;
|
||||
}
|
||||
// in Narwhal or Rhino -require
|
||||
else {
|
||||
freeExports._ = _;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// in a browser or Rhino
|
||||
root._ = _;
|
||||
}
|
||||
}.call(this));
|
|
@ -1,132 +0,0 @@
|
|||
{
|
||||
"name": "lodash",
|
||||
"version": "2.4.1",
|
||||
"description": "A utility library delivering consistency, customization, performance, & extras.",
|
||||
"homepage": "http://lodash.com/",
|
||||
"license": "MIT",
|
||||
"main": "dist/lodash.js",
|
||||
"keywords": [
|
||||
"amd",
|
||||
"browser",
|
||||
"client",
|
||||
"customize",
|
||||
"functional",
|
||||
"server",
|
||||
"util"
|
||||
],
|
||||
"author": {
|
||||
"name": "John-David Dalton",
|
||||
"email": "john.david.dalton@gmail.com",
|
||||
"url": "http://allyoucanleet.com/"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "John-David Dalton",
|
||||
"email": "john.david.dalton@gmail.com",
|
||||
"url": "http://allyoucanleet.com/"
|
||||
},
|
||||
{
|
||||
"name": "Blaine Bublitz",
|
||||
"email": "blaine@iceddev.com",
|
||||
"url": "http://www.iceddev.com/"
|
||||
},
|
||||
{
|
||||
"name": "Kit Cambridge",
|
||||
"email": "github@kitcambridge.be",
|
||||
"url": "http://kitcambridge.be/"
|
||||
},
|
||||
{
|
||||
"name": "Mathias Bynens",
|
||||
"email": "mathias@qiwi.be",
|
||||
"url": "http://mathiasbynens.be/"
|
||||
}
|
||||
],
|
||||
"bugs": {
|
||||
"url": "https://github.com/lodash/lodash/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/lodash/lodash.git"
|
||||
},
|
||||
"engines": [
|
||||
"node",
|
||||
"rhino"
|
||||
],
|
||||
"files": [
|
||||
"LICENSE.txt",
|
||||
"lodash.js",
|
||||
"dist/lodash.js",
|
||||
"dist/lodash.min.js",
|
||||
"dist/lodash.compat.js",
|
||||
"dist/lodash.compat.min.js",
|
||||
"dist/lodash.underscore.js",
|
||||
"dist/lodash.underscore.min.js"
|
||||
],
|
||||
"jam": {
|
||||
"main": "dist/lodash.compat.js",
|
||||
"include": [
|
||||
"LICENSE.txt",
|
||||
"dist/lodash.js",
|
||||
"dist/lodash.min.js",
|
||||
"dist/lodash.compat.js",
|
||||
"dist/lodash.compat.min.js",
|
||||
"dist/lodash.underscore.js",
|
||||
"dist/lodash.underscore.min.js"
|
||||
]
|
||||
},
|
||||
"volo": {
|
||||
"type": "directory",
|
||||
"ignore": [
|
||||
".*",
|
||||
"*.custom.*",
|
||||
"*.min.*",
|
||||
"*.template.*",
|
||||
"*.map",
|
||||
"*.md",
|
||||
"lodash.js",
|
||||
"index.js",
|
||||
"bower.json",
|
||||
"component.json",
|
||||
"doc",
|
||||
"modularize",
|
||||
"node_modules",
|
||||
"perf",
|
||||
"test",
|
||||
"vendor"
|
||||
]
|
||||
},
|
||||
"_id": "lodash@2.4.1",
|
||||
"dist": {
|
||||
"shasum": "5b7723034dda4d262e5a46fb2c58d7cc22f71420",
|
||||
"tarball": "http://registry.npmjs.org/lodash/-/lodash-2.4.1.tgz"
|
||||
},
|
||||
"_from": "lodash@~2.4.1",
|
||||
"_npmVersion": "1.3.14",
|
||||
"_npmUser": {
|
||||
"name": "jdalton",
|
||||
"email": "john.david.dalton@gmail.com"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "jdalton",
|
||||
"email": "john.david.dalton@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "mathias",
|
||||
"email": "mathias@qiwi.be"
|
||||
},
|
||||
{
|
||||
"name": "phated",
|
||||
"email": "blaine@iceddev.com"
|
||||
},
|
||||
{
|
||||
"name": "kitcambridge",
|
||||
"email": "github@kitcambridge.be"
|
||||
}
|
||||
],
|
||||
"directories": {},
|
||||
"_shasum": "5b7723034dda4d262e5a46fb2c58d7cc22f71420",
|
||||
"_resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.1.tgz",
|
||||
"readme": "ERROR: No README data found!",
|
||||
"scripts": {}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
{
|
||||
"name": "findup-sync",
|
||||
"description": "Find the first file matching a given pattern in the current directory or the nearest ancestor directory.",
|
||||
"version": "0.1.3",
|
||||
"homepage": "https://github.com/cowboy/node-findup-sync",
|
||||
"author": {
|
||||
"name": "\"Cowboy\" Ben Alman",
|
||||
"url": "http://benalman.com/"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/cowboy/node-findup-sync.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/cowboy/node-findup-sync/issues"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT",
|
||||
"url": "https://github.com/cowboy/node-findup-sync/blob/master/LICENSE-MIT"
|
||||
}
|
||||
],
|
||||
"main": "lib/findup-sync",
|
||||
"engines": {
|
||||
"node": ">= 0.6.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "grunt nodeunit"
|
||||
},
|
||||
"dependencies": {
|
||||
"glob": "~3.2.9",
|
||||
"lodash": "~2.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"grunt": "~0.4.4",
|
||||
"grunt-contrib-jshint": "~0.9.2",
|
||||
"grunt-contrib-nodeunit": "~0.3.3"
|
||||
},
|
||||
"keywords": [
|
||||
"find",
|
||||
"glob",
|
||||
"file"
|
||||
],
|
||||
"_id": "findup-sync@0.1.3",
|
||||
"dist": {
|
||||
"shasum": "7f3e7a97b82392c653bf06589bd85190e93c3683",
|
||||
"tarball": "http://registry.npmjs.org/findup-sync/-/findup-sync-0.1.3.tgz"
|
||||
},
|
||||
"_from": "findup-sync@~0.1.0",
|
||||
"_npmVersion": "1.4.4",
|
||||
"_npmUser": {
|
||||
"name": "cowboy",
|
||||
"email": "cowboy@rj3.net"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "cowboy",
|
||||
"email": "cowboy@rj3.net"
|
||||
}
|
||||
],
|
||||
"directories": {},
|
||||
"_shasum": "7f3e7a97b82392c653bf06589bd85190e93c3683",
|
||||
"_resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.1.3.tgz",
|
||||
"readme": "ERROR: No README data found!"
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
// Nodejs lib.
|
||||
var path = require('path');
|
||||
|
||||
var findup = require('../lib/findup-sync.js');
|
||||
|
||||
// Get a relative path.
|
||||
var rel = function(abspath) {
|
||||
return typeof abspath === 'string' ? path.relative('.', abspath) : abspath;
|
||||
};
|
||||
|
||||
exports['findup'] = {
|
||||
setUp: function(done) {
|
||||
this.cwd = process.cwd();
|
||||
done();
|
||||
},
|
||||
tearDown: function(done) {
|
||||
process.chdir(this.cwd);
|
||||
done();
|
||||
},
|
||||
'simple': function(test) {
|
||||
test.expect(8);
|
||||
var opts = {cwd: 'test/fixtures/a/b'};
|
||||
test.equal(rel(findup('foo.txt', opts)), path.normalize('test/fixtures/a/foo.txt'), 'should find files');
|
||||
test.equal(rel(findup('bar.txt', opts)), path.normalize('test/fixtures/a/b/bar.txt'), 'should find files');
|
||||
test.equal(rel(findup('a.txt', opts)), path.normalize('test/fixtures/a.txt'), 'should find files');
|
||||
test.equal(rel(findup('?.txt', opts)), path.normalize('test/fixtures/a.txt'), 'should support glob patterns');
|
||||
test.equal(rel(findup('*.txt', opts)), path.normalize('test/fixtures/a/b/bar.txt'), 'should find the first thing that matches the glob pattern');
|
||||
test.equal(rel(findup(['b*.txt', 'f*.txt'], opts)), path.normalize('test/fixtures/a/b/bar.txt'), 'should find the first thing that matches any of the glob patterns');
|
||||
test.equal(rel(findup(['f*.txt', 'b*.txt'], opts)), path.normalize('test/fixtures/a/b/bar.txt'), 'should find the first thing that matches any of the glob patterns');
|
||||
test.equal(findup('not-gonna-exist-i-hope.txt', opts), null, 'should returning null if no files found');
|
||||
test.done();
|
||||
},
|
||||
'cwd': function(test) {
|
||||
test.expect(8);
|
||||
process.chdir('test/fixtures/a/b');
|
||||
test.equal(rel(findup('foo.txt')), path.normalize('../foo.txt'), 'should find files');
|
||||
test.equal(rel(findup('bar.txt')), 'bar.txt', 'should find files');
|
||||
test.equal(rel(findup('a.txt')), path.normalize('../../a.txt'), 'should find files');
|
||||
test.equal(rel(findup('?.txt')), path.normalize('../../a.txt'), 'should support glob patterns');
|
||||
test.equal(rel(findup('*.txt')), 'bar.txt', 'should find the first thing that matches the glob pattern');
|
||||
test.equal(rel(findup(['b*.txt', 'f*.txt'])), 'bar.txt', 'should find the first thing that matches any of the glob patterns');
|
||||
test.equal(rel(findup(['f*.txt', 'b*.txt'])), 'bar.txt', 'should find the first thing that matches any of the glob patterns');
|
||||
test.equal(findup('not-gonna-exist-i-hope.txt'), null, 'should returning null if no files found');
|
||||
test.done();
|
||||
},
|
||||
};
|
|
@ -1,23 +0,0 @@
|
|||
Copyright 2009, 2010, 2011 Isaac Z. Schlueter.
|
||||
All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
208
javascript/base/exercices/pipeline/grunt/node_modules/grunt-cli/node_modules/nopt/README.md
generated
vendored
208
javascript/base/exercices/pipeline/grunt/node_modules/grunt-cli/node_modules/nopt/README.md
generated
vendored
|
@ -1,208 +0,0 @@
|
|||
If you want to write an option parser, and have it be good, there are
|
||||
two ways to do it. The Right Way, and the Wrong Way.
|
||||
|
||||
The Wrong Way is to sit down and write an option parser. We've all done
|
||||
that.
|
||||
|
||||
The Right Way is to write some complex configurable program with so many
|
||||
options that you go half-insane just trying to manage them all, and put
|
||||
it off with duct-tape solutions until you see exactly to the core of the
|
||||
problem, and finally snap and write an awesome option parser.
|
||||
|
||||
If you want to write an option parser, don't write an option parser.
|
||||
Write a package manager, or a source control system, or a service
|
||||
restarter, or an operating system. You probably won't end up with a
|
||||
good one of those, but if you don't give up, and you are relentless and
|
||||
diligent enough in your procrastination, you may just end up with a very
|
||||
nice option parser.
|
||||
|
||||
## USAGE
|
||||
|
||||
// my-program.js
|
||||
var nopt = require("nopt")
|
||||
, Stream = require("stream").Stream
|
||||
, path = require("path")
|
||||
, knownOpts = { "foo" : [String, null]
|
||||
, "bar" : [Stream, Number]
|
||||
, "baz" : path
|
||||
, "bloo" : [ "big", "medium", "small" ]
|
||||
, "flag" : Boolean
|
||||
, "pick" : Boolean
|
||||
, "many" : [String, Array]
|
||||
}
|
||||
, shortHands = { "foofoo" : ["--foo", "Mr. Foo"]
|
||||
, "b7" : ["--bar", "7"]
|
||||
, "m" : ["--bloo", "medium"]
|
||||
, "p" : ["--pick"]
|
||||
, "f" : ["--flag"]
|
||||
}
|
||||
// everything is optional.
|
||||
// knownOpts and shorthands default to {}
|
||||
// arg list defaults to process.argv
|
||||
// slice defaults to 2
|
||||
, parsed = nopt(knownOpts, shortHands, process.argv, 2)
|
||||
console.log(parsed)
|
||||
|
||||
This would give you support for any of the following:
|
||||
|
||||
```bash
|
||||
$ node my-program.js --foo "blerp" --no-flag
|
||||
{ "foo" : "blerp", "flag" : false }
|
||||
|
||||
$ node my-program.js ---bar 7 --foo "Mr. Hand" --flag
|
||||
{ bar: 7, foo: "Mr. Hand", flag: true }
|
||||
|
||||
$ node my-program.js --foo "blerp" -f -----p
|
||||
{ foo: "blerp", flag: true, pick: true }
|
||||
|
||||
$ node my-program.js -fp --foofoo
|
||||
{ foo: "Mr. Foo", flag: true, pick: true }
|
||||
|
||||
$ node my-program.js --foofoo -- -fp # -- stops the flag parsing.
|
||||
{ foo: "Mr. Foo", argv: { remain: ["-fp"] } }
|
||||
|
||||
$ node my-program.js --blatzk 1000 -fp # unknown opts are ok.
|
||||
{ blatzk: 1000, flag: true, pick: true }
|
||||
|
||||
$ node my-program.js --blatzk true -fp # but they need a value
|
||||
{ blatzk: true, flag: true, pick: true }
|
||||
|
||||
$ node my-program.js --no-blatzk -fp # unless they start with "no-"
|
||||
{ blatzk: false, flag: true, pick: true }
|
||||
|
||||
$ node my-program.js --baz b/a/z # known paths are resolved.
|
||||
{ baz: "/Users/isaacs/b/a/z" }
|
||||
|
||||
# if Array is one of the types, then it can take many
|
||||
# values, and will always be an array. The other types provided
|
||||
# specify what types are allowed in the list.
|
||||
|
||||
$ node my-program.js --many 1 --many null --many foo
|
||||
{ many: ["1", "null", "foo"] }
|
||||
|
||||
$ node my-program.js --many foo
|
||||
{ many: ["foo"] }
|
||||
```
|
||||
|
||||
Read the tests at the bottom of `lib/nopt.js` for more examples of
|
||||
what this puppy can do.
|
||||
|
||||
## Types
|
||||
|
||||
The following types are supported, and defined on `nopt.typeDefs`
|
||||
|
||||
* String: A normal string. No parsing is done.
|
||||
* path: A file system path. Gets resolved against cwd if not absolute.
|
||||
* url: A url. If it doesn't parse, it isn't accepted.
|
||||
* Number: Must be numeric.
|
||||
* Date: Must parse as a date. If it does, and `Date` is one of the options,
|
||||
then it will return a Date object, not a string.
|
||||
* Boolean: Must be either `true` or `false`. If an option is a boolean,
|
||||
then it does not need a value, and its presence will imply `true` as
|
||||
the value. To negate boolean flags, do `--no-whatever` or `--whatever
|
||||
false`
|
||||
* NaN: Means that the option is strictly not allowed. Any value will
|
||||
fail.
|
||||
* Stream: An object matching the "Stream" class in node. Valuable
|
||||
for use when validating programmatically. (npm uses this to let you
|
||||
supply any WriteStream on the `outfd` and `logfd` config options.)
|
||||
* Array: If `Array` is specified as one of the types, then the value
|
||||
will be parsed as a list of options. This means that multiple values
|
||||
can be specified, and that the value will always be an array.
|
||||
|
||||
If a type is an array of values not on this list, then those are
|
||||
considered valid values. For instance, in the example above, the
|
||||
`--bloo` option can only be one of `"big"`, `"medium"`, or `"small"`,
|
||||
and any other value will be rejected.
|
||||
|
||||
When parsing unknown fields, `"true"`, `"false"`, and `"null"` will be
|
||||
interpreted as their JavaScript equivalents, and numeric values will be
|
||||
interpreted as a number.
|
||||
|
||||
You can also mix types and values, or multiple types, in a list. For
|
||||
instance `{ blah: [Number, null] }` would allow a value to be set to
|
||||
either a Number or null.
|
||||
|
||||
To define a new type, add it to `nopt.typeDefs`. Each item in that
|
||||
hash is an object with a `type` member and a `validate` method. The
|
||||
`type` member is an object that matches what goes in the type list. The
|
||||
`validate` method is a function that gets called with `validate(data,
|
||||
key, val)`. Validate methods should assign `data[key]` to the valid
|
||||
value of `val` if it can be handled properly, or return boolean
|
||||
`false` if it cannot.
|
||||
|
||||
You can also call `nopt.clean(data, types, typeDefs)` to clean up a
|
||||
config object and remove its invalid properties.
|
||||
|
||||
## Error Handling
|
||||
|
||||
By default, nopt outputs a warning to standard error when invalid
|
||||
options are found. You can change this behavior by assigning a method
|
||||
to `nopt.invalidHandler`. This method will be called with
|
||||
the offending `nopt.invalidHandler(key, val, types)`.
|
||||
|
||||
If no `nopt.invalidHandler` is assigned, then it will console.error
|
||||
its whining. If it is assigned to boolean `false` then the warning is
|
||||
suppressed.
|
||||
|
||||
## Abbreviations
|
||||
|
||||
Yes, they are supported. If you define options like this:
|
||||
|
||||
```javascript
|
||||
{ "foolhardyelephants" : Boolean
|
||||
, "pileofmonkeys" : Boolean }
|
||||
```
|
||||
|
||||
Then this will work:
|
||||
|
||||
```bash
|
||||
node program.js --foolhar --pil
|
||||
node program.js --no-f --pileofmon
|
||||
# etc.
|
||||
```
|
||||
|
||||
## Shorthands
|
||||
|
||||
Shorthands are a hash of shorter option names to a snippet of args that
|
||||
they expand to.
|
||||
|
||||
If multiple one-character shorthands are all combined, and the
|
||||
combination does not unambiguously match any other option or shorthand,
|
||||
then they will be broken up into their constituent parts. For example:
|
||||
|
||||
```json
|
||||
{ "s" : ["--loglevel", "silent"]
|
||||
, "g" : "--global"
|
||||
, "f" : "--force"
|
||||
, "p" : "--parseable"
|
||||
, "l" : "--long"
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
npm ls -sgflp
|
||||
# just like doing this:
|
||||
npm ls --loglevel silent --global --force --long --parseable
|
||||
```
|
||||
|
||||
## The Rest of the args
|
||||
|
||||
The config object returned by nopt is given a special member called
|
||||
`argv`, which is an object with the following fields:
|
||||
|
||||
* `remain`: The remaining args after all the parsing has occurred.
|
||||
* `original`: The args as they originally appeared.
|
||||
* `cooked`: The args after flags and shorthands are expanded.
|
||||
|
||||
## Slicing
|
||||
|
||||
Node programs are called with more or less the exact argv as it appears
|
||||
in C land, after the v8 and node-specific options have been plucked off.
|
||||
As such, `argv[0]` is always `node` and `argv[1]` is always the
|
||||
JavaScript program being run.
|
||||
|
||||
That's usually not very useful to you. So they're sliced off by
|
||||
default. If you want them, then you can pass in `0` as the last
|
||||
argument, or any other number that you'd like to slice off the start of
|
||||
the list.
|
|
@ -1,44 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
var nopt = require("../lib/nopt")
|
||||
, types = { num: Number
|
||||
, bool: Boolean
|
||||
, help: Boolean
|
||||
, list: Array
|
||||
, "num-list": [Number, Array]
|
||||
, "str-list": [String, Array]
|
||||
, "bool-list": [Boolean, Array]
|
||||
, str: String }
|
||||
, shorthands = { s: [ "--str", "astring" ]
|
||||
, b: [ "--bool" ]
|
||||
, nb: [ "--no-bool" ]
|
||||
, tft: [ "--bool-list", "--no-bool-list", "--bool-list", "true" ]
|
||||
, "?": ["--help"]
|
||||
, h: ["--help"]
|
||||
, H: ["--help"]
|
||||
, n: [ "--num", "125" ] }
|
||||
, parsed = nopt( types
|
||||
, shorthands
|
||||
, process.argv
|
||||
, 2 )
|
||||
|
||||
console.log("parsed", parsed)
|
||||
|
||||
if (parsed.help) {
|
||||
console.log("")
|
||||
console.log("nopt cli tester")
|
||||
console.log("")
|
||||
console.log("types")
|
||||
console.log(Object.keys(types).map(function M (t) {
|
||||
var type = types[t]
|
||||
if (Array.isArray(type)) {
|
||||
return [t, type.map(function (type) { return type.name })]
|
||||
}
|
||||
return [t, type && type.name]
|
||||
}).reduce(function (s, i) {
|
||||
s[i[0]] = i[1]
|
||||
return s
|
||||
}, {}))
|
||||
console.log("")
|
||||
console.log("shorthands")
|
||||
console.log(shorthands)
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
//process.env.DEBUG_NOPT = 1
|
||||
|
||||
// my-program.js
|
||||
var nopt = require("../lib/nopt")
|
||||
, Stream = require("stream").Stream
|
||||
, path = require("path")
|
||||
, knownOpts = { "foo" : [String, null]
|
||||
, "bar" : [Stream, Number]
|
||||
, "baz" : path
|
||||
, "bloo" : [ "big", "medium", "small" ]
|
||||
, "flag" : Boolean
|
||||
, "pick" : Boolean
|
||||
}
|
||||
, shortHands = { "foofoo" : ["--foo", "Mr. Foo"]
|
||||
, "b7" : ["--bar", "7"]
|
||||
, "m" : ["--bloo", "medium"]
|
||||
, "p" : ["--pick"]
|
||||
, "f" : ["--flag", "true"]
|
||||
, "g" : ["--flag"]
|
||||
, "s" : "--flag"
|
||||
}
|
||||
// everything is optional.
|
||||
// knownOpts and shorthands default to {}
|
||||
// arg list defaults to process.argv
|
||||
// slice defaults to 2
|
||||
, parsed = nopt(knownOpts, shortHands, process.argv, 2)
|
||||
|
||||
console.log("parsed =\n"+ require("util").inspect(parsed))
|
|
@ -1,552 +0,0 @@
|
|||
// info about each config option.
|
||||
|
||||
var debug = process.env.DEBUG_NOPT || process.env.NOPT_DEBUG
|
||||
? function () { console.error.apply(console, arguments) }
|
||||
: function () {}
|
||||
|
||||
var url = require("url")
|
||||
, path = require("path")
|
||||
, Stream = require("stream").Stream
|
||||
, abbrev = require("abbrev")
|
||||
|
||||
module.exports = exports = nopt
|
||||
exports.clean = clean
|
||||
|
||||
exports.typeDefs =
|
||||
{ String : { type: String, validate: validateString }
|
||||
, Boolean : { type: Boolean, validate: validateBoolean }
|
||||
, url : { type: url, validate: validateUrl }
|
||||
, Number : { type: Number, validate: validateNumber }
|
||||
, path : { type: path, validate: validatePath }
|
||||
, Stream : { type: Stream, validate: validateStream }
|
||||
, Date : { type: Date, validate: validateDate }
|
||||
}
|
||||
|
||||
function nopt (types, shorthands, args, slice) {
|
||||
args = args || process.argv
|
||||
types = types || {}
|
||||
shorthands = shorthands || {}
|
||||
if (typeof slice !== "number") slice = 2
|
||||
|
||||
debug(types, shorthands, args, slice)
|
||||
|
||||
args = args.slice(slice)
|
||||
var data = {}
|
||||
, key
|
||||
, remain = []
|
||||
, cooked = args
|
||||
, original = args.slice(0)
|
||||
|
||||
parse(args, data, remain, types, shorthands)
|
||||
// now data is full
|
||||
clean(data, types, exports.typeDefs)
|
||||
data.argv = {remain:remain,cooked:cooked,original:original}
|
||||
data.argv.toString = function () {
|
||||
return this.original.map(JSON.stringify).join(" ")
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
function clean (data, types, typeDefs) {
|
||||
typeDefs = typeDefs || exports.typeDefs
|
||||
var remove = {}
|
||||
, typeDefault = [false, true, null, String, Number]
|
||||
|
||||
Object.keys(data).forEach(function (k) {
|
||||
if (k === "argv") return
|
||||
var val = data[k]
|
||||
, isArray = Array.isArray(val)
|
||||
, type = types[k]
|
||||
if (!isArray) val = [val]
|
||||
if (!type) type = typeDefault
|
||||
if (type === Array) type = typeDefault.concat(Array)
|
||||
if (!Array.isArray(type)) type = [type]
|
||||
|
||||
debug("val=%j", val)
|
||||
debug("types=", type)
|
||||
val = val.map(function (val) {
|
||||
// if it's an unknown value, then parse false/true/null/numbers/dates
|
||||
if (typeof val === "string") {
|
||||
debug("string %j", val)
|
||||
val = val.trim()
|
||||
if ((val === "null" && ~type.indexOf(null))
|
||||
|| (val === "true" &&
|
||||
(~type.indexOf(true) || ~type.indexOf(Boolean)))
|
||||
|| (val === "false" &&
|
||||
(~type.indexOf(false) || ~type.indexOf(Boolean)))) {
|
||||
val = JSON.parse(val)
|
||||
debug("jsonable %j", val)
|
||||
} else if (~type.indexOf(Number) && !isNaN(val)) {
|
||||
debug("convert to number", val)
|
||||
val = +val
|
||||
} else if (~type.indexOf(Date) && !isNaN(Date.parse(val))) {
|
||||
debug("convert to date", val)
|
||||
val = new Date(val)
|
||||
}
|
||||
}
|
||||
|
||||
if (!types.hasOwnProperty(k)) {
|
||||
return val
|
||||
}
|
||||
|
||||
// allow `--no-blah` to set 'blah' to null if null is allowed
|
||||
if (val === false && ~type.indexOf(null) &&
|
||||
!(~type.indexOf(false) || ~type.indexOf(Boolean))) {
|
||||
val = null
|
||||
}
|
||||
|
||||
var d = {}
|
||||
d[k] = val
|
||||
debug("prevalidated val", d, val, types[k])
|
||||
if (!validate(d, k, val, types[k], typeDefs)) {
|
||||
if (exports.invalidHandler) {
|
||||
exports.invalidHandler(k, val, types[k], data)
|
||||
} else if (exports.invalidHandler !== false) {
|
||||
debug("invalid: "+k+"="+val, types[k])
|
||||
}
|
||||
return remove
|
||||
}
|
||||
debug("validated val", d, val, types[k])
|
||||
return d[k]
|
||||
}).filter(function (val) { return val !== remove })
|
||||
|
||||
if (!val.length) delete data[k]
|
||||
else if (isArray) {
|
||||
debug(isArray, data[k], val)
|
||||
data[k] = val
|
||||
} else data[k] = val[0]
|
||||
|
||||
debug("k=%s val=%j", k, val, data[k])
|
||||
})
|
||||
}
|
||||
|
||||
function validateString (data, k, val) {
|
||||
data[k] = String(val)
|
||||
}
|
||||
|
||||
function validatePath (data, k, val) {
|
||||
data[k] = path.resolve(String(val))
|
||||
return true
|
||||
}
|
||||
|
||||
function validateNumber (data, k, val) {
|
||||
debug("validate Number %j %j %j", k, val, isNaN(val))
|
||||
if (isNaN(val)) return false
|
||||
data[k] = +val
|
||||
}
|
||||
|
||||
function validateDate (data, k, val) {
|
||||
debug("validate Date %j %j %j", k, val, Date.parse(val))
|
||||
var s = Date.parse(val)
|
||||
if (isNaN(s)) return false
|
||||
data[k] = new Date(val)
|
||||
}
|
||||
|
||||
function validateBoolean (data, k, val) {
|
||||
if (val instanceof Boolean) val = val.valueOf()
|
||||
else if (typeof val === "string") {
|
||||
if (!isNaN(val)) val = !!(+val)
|
||||
else if (val === "null" || val === "false") val = false
|
||||
else val = true
|
||||
} else val = !!val
|
||||
data[k] = val
|
||||
}
|
||||
|
||||
function validateUrl (data, k, val) {
|
||||
val = url.parse(String(val))
|
||||
if (!val.host) return false
|
||||
data[k] = val.href
|
||||
}
|
||||
|
||||
function validateStream (data, k, val) {
|
||||
if (!(val instanceof Stream)) return false
|
||||
data[k] = val
|
||||
}
|
||||
|
||||
function validate (data, k, val, type, typeDefs) {
|
||||
// arrays are lists of types.
|
||||
if (Array.isArray(type)) {
|
||||
for (var i = 0, l = type.length; i < l; i ++) {
|
||||
if (type[i] === Array) continue
|
||||
if (validate(data, k, val, type[i], typeDefs)) return true
|
||||
}
|
||||
delete data[k]
|
||||
return false
|
||||
}
|
||||
|
||||
// an array of anything?
|
||||
if (type === Array) return true
|
||||
|
||||
// NaN is poisonous. Means that something is not allowed.
|
||||
if (type !== type) {
|
||||
debug("Poison NaN", k, val, type)
|
||||
delete data[k]
|
||||
return false
|
||||
}
|
||||
|
||||
// explicit list of values
|
||||
if (val === type) {
|
||||
debug("Explicitly allowed %j", val)
|
||||
// if (isArray) (data[k] = data[k] || []).push(val)
|
||||
// else data[k] = val
|
||||
data[k] = val
|
||||
return true
|
||||
}
|
||||
|
||||
// now go through the list of typeDefs, validate against each one.
|
||||
var ok = false
|
||||
, types = Object.keys(typeDefs)
|
||||
for (var i = 0, l = types.length; i < l; i ++) {
|
||||
debug("test type %j %j %j", k, val, types[i])
|
||||
var t = typeDefs[types[i]]
|
||||
if (t && type === t.type) {
|
||||
var d = {}
|
||||
ok = false !== t.validate(d, k, val)
|
||||
val = d[k]
|
||||
if (ok) {
|
||||
// if (isArray) (data[k] = data[k] || []).push(val)
|
||||
// else data[k] = val
|
||||
data[k] = val
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
debug("OK? %j (%j %j %j)", ok, k, val, types[i])
|
||||
|
||||
if (!ok) delete data[k]
|
||||
return ok
|
||||
}
|
||||
|
||||
function parse (args, data, remain, types, shorthands) {
|
||||
debug("parse", args, data, remain)
|
||||
|
||||
var key = null
|
||||
, abbrevs = abbrev(Object.keys(types))
|
||||
, shortAbbr = abbrev(Object.keys(shorthands))
|
||||
|
||||
for (var i = 0; i < args.length; i ++) {
|
||||
var arg = args[i]
|
||||
debug("arg", arg)
|
||||
|
||||
if (arg.match(/^-{2,}$/)) {
|
||||
// done with keys.
|
||||
// the rest are args.
|
||||
remain.push.apply(remain, args.slice(i + 1))
|
||||
args[i] = "--"
|
||||
break
|
||||
}
|
||||
if (arg.charAt(0) === "-") {
|
||||
if (arg.indexOf("=") !== -1) {
|
||||
var v = arg.split("=")
|
||||
arg = v.shift()
|
||||
v = v.join("=")
|
||||
args.splice.apply(args, [i, 1].concat([arg, v]))
|
||||
}
|
||||
// see if it's a shorthand
|
||||
// if so, splice and back up to re-parse it.
|
||||
var shRes = resolveShort(arg, shorthands, shortAbbr, abbrevs)
|
||||
debug("arg=%j shRes=%j", arg, shRes)
|
||||
if (shRes) {
|
||||
debug(arg, shRes)
|
||||
args.splice.apply(args, [i, 1].concat(shRes))
|
||||
if (arg !== shRes[0]) {
|
||||
i --
|
||||
continue
|
||||
}
|
||||
}
|
||||
arg = arg.replace(/^-+/, "")
|
||||
var no = false
|
||||
while (arg.toLowerCase().indexOf("no-") === 0) {
|
||||
no = !no
|
||||
arg = arg.substr(3)
|
||||
}
|
||||
|
||||
if (abbrevs[arg]) arg = abbrevs[arg]
|
||||
|
||||
var isArray = types[arg] === Array ||
|
||||
Array.isArray(types[arg]) && types[arg].indexOf(Array) !== -1
|
||||
|
||||
var val
|
||||
, la = args[i + 1]
|
||||
|
||||
var isBool = no ||
|
||||
types[arg] === Boolean ||
|
||||
Array.isArray(types[arg]) && types[arg].indexOf(Boolean) !== -1 ||
|
||||
(la === "false" &&
|
||||
(types[arg] === null ||
|
||||
Array.isArray(types[arg]) && ~types[arg].indexOf(null)))
|
||||
|
||||
if (isBool) {
|
||||
// just set and move along
|
||||
val = !no
|
||||
// however, also support --bool true or --bool false
|
||||
if (la === "true" || la === "false") {
|
||||
val = JSON.parse(la)
|
||||
la = null
|
||||
if (no) val = !val
|
||||
i ++
|
||||
}
|
||||
|
||||
// also support "foo":[Boolean, "bar"] and "--foo bar"
|
||||
if (Array.isArray(types[arg]) && la) {
|
||||
if (~types[arg].indexOf(la)) {
|
||||
// an explicit type
|
||||
val = la
|
||||
i ++
|
||||
} else if ( la === "null" && ~types[arg].indexOf(null) ) {
|
||||
// null allowed
|
||||
val = null
|
||||
i ++
|
||||
} else if ( !la.match(/^-{2,}[^-]/) &&
|
||||
!isNaN(la) &&
|
||||
~types[arg].indexOf(Number) ) {
|
||||
// number
|
||||
val = +la
|
||||
i ++
|
||||
} else if ( !la.match(/^-[^-]/) && ~types[arg].indexOf(String) ) {
|
||||
// string
|
||||
val = la
|
||||
i ++
|
||||
}
|
||||
}
|
||||
|
||||
if (isArray) (data[arg] = data[arg] || []).push(val)
|
||||
else data[arg] = val
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if (la && la.match(/^-{2,}$/)) {
|
||||
la = undefined
|
||||
i --
|
||||
}
|
||||
|
||||
val = la === undefined ? true : la
|
||||
if (isArray) (data[arg] = data[arg] || []).push(val)
|
||||
else data[arg] = val
|
||||
|
||||
i ++
|
||||
continue
|
||||
}
|
||||
remain.push(arg)
|
||||
}
|
||||
}
|
||||
|
||||
function resolveShort (arg, shorthands, shortAbbr, abbrevs) {
|
||||
// handle single-char shorthands glommed together, like
|
||||
// npm ls -glp, but only if there is one dash, and only if
|
||||
// all of the chars are single-char shorthands, and it's
|
||||
// not a match to some other abbrev.
|
||||
arg = arg.replace(/^-+/, '')
|
||||
if (abbrevs[arg] && !shorthands[arg]) {
|
||||
return null
|
||||
}
|
||||
if (shortAbbr[arg]) {
|
||||
arg = shortAbbr[arg]
|
||||
} else {
|
||||
var singles = shorthands.___singles
|
||||
if (!singles) {
|
||||
singles = Object.keys(shorthands).filter(function (s) {
|
||||
return s.length === 1
|
||||
}).reduce(function (l,r) { l[r] = true ; return l }, {})
|
||||
shorthands.___singles = singles
|
||||
}
|
||||
var chrs = arg.split("").filter(function (c) {
|
||||
return singles[c]
|
||||
})
|
||||
if (chrs.join("") === arg) return chrs.map(function (c) {
|
||||
return shorthands[c]
|
||||
}).reduce(function (l, r) {
|
||||
return l.concat(r)
|
||||
}, [])
|
||||
}
|
||||
|
||||
if (shorthands[arg] && !Array.isArray(shorthands[arg])) {
|
||||
shorthands[arg] = shorthands[arg].split(/\s+/)
|
||||
}
|
||||
return shorthands[arg]
|
||||
}
|
||||
|
||||
if (module === require.main) {
|
||||
var assert = require("assert")
|
||||
, util = require("util")
|
||||
|
||||
, shorthands =
|
||||
{ s : ["--loglevel", "silent"]
|
||||
, d : ["--loglevel", "info"]
|
||||
, dd : ["--loglevel", "verbose"]
|
||||
, ddd : ["--loglevel", "silly"]
|
||||
, noreg : ["--no-registry"]
|
||||
, reg : ["--registry"]
|
||||
, "no-reg" : ["--no-registry"]
|
||||
, silent : ["--loglevel", "silent"]
|
||||
, verbose : ["--loglevel", "verbose"]
|
||||
, h : ["--usage"]
|
||||
, H : ["--usage"]
|
||||
, "?" : ["--usage"]
|
||||
, help : ["--usage"]
|
||||
, v : ["--version"]
|
||||
, f : ["--force"]
|
||||
, desc : ["--description"]
|
||||
, "no-desc" : ["--no-description"]
|
||||
, "local" : ["--no-global"]
|
||||
, l : ["--long"]
|
||||
, p : ["--parseable"]
|
||||
, porcelain : ["--parseable"]
|
||||
, g : ["--global"]
|
||||
}
|
||||
|
||||
, types =
|
||||
{ aoa: Array
|
||||
, nullstream: [null, Stream]
|
||||
, date: Date
|
||||
, str: String
|
||||
, browser : String
|
||||
, cache : path
|
||||
, color : ["always", Boolean]
|
||||
, depth : Number
|
||||
, description : Boolean
|
||||
, dev : Boolean
|
||||
, editor : path
|
||||
, force : Boolean
|
||||
, global : Boolean
|
||||
, globalconfig : path
|
||||
, group : [String, Number]
|
||||
, gzipbin : String
|
||||
, logfd : [Number, Stream]
|
||||
, loglevel : ["silent","win","error","warn","info","verbose","silly"]
|
||||
, long : Boolean
|
||||
, "node-version" : [false, String]
|
||||
, npaturl : url
|
||||
, npat : Boolean
|
||||
, "onload-script" : [false, String]
|
||||
, outfd : [Number, Stream]
|
||||
, parseable : Boolean
|
||||
, pre: Boolean
|
||||
, prefix: path
|
||||
, proxy : url
|
||||
, "rebuild-bundle" : Boolean
|
||||
, registry : url
|
||||
, searchopts : String
|
||||
, searchexclude: [null, String]
|
||||
, shell : path
|
||||
, t: [Array, String]
|
||||
, tag : String
|
||||
, tar : String
|
||||
, tmp : path
|
||||
, "unsafe-perm" : Boolean
|
||||
, usage : Boolean
|
||||
, user : String
|
||||
, username : String
|
||||
, userconfig : path
|
||||
, version : Boolean
|
||||
, viewer: path
|
||||
, _exit : Boolean
|
||||
}
|
||||
|
||||
; [["-v", {version:true}, []]
|
||||
,["---v", {version:true}, []]
|
||||
,["ls -s --no-reg connect -d",
|
||||
{loglevel:"info",registry:null},["ls","connect"]]
|
||||
,["ls ---s foo",{loglevel:"silent"},["ls","foo"]]
|
||||
,["ls --registry blargle", {}, ["ls"]]
|
||||
,["--no-registry", {registry:null}, []]
|
||||
,["--no-color true", {color:false}, []]
|
||||
,["--no-color false", {color:true}, []]
|
||||
,["--no-color", {color:false}, []]
|
||||
,["--color false", {color:false}, []]
|
||||
,["--color --logfd 7", {logfd:7,color:true}, []]
|
||||
,["--color=true", {color:true}, []]
|
||||
,["--logfd=10", {logfd:10}, []]
|
||||
,["--tmp=/tmp -tar=gtar",{tmp:"/tmp",tar:"gtar"},[]]
|
||||
,["--tmp=tmp -tar=gtar",
|
||||
{tmp:path.resolve(process.cwd(), "tmp"),tar:"gtar"},[]]
|
||||
,["--logfd x", {}, []]
|
||||
,["a -true -- -no-false", {true:true},["a","-no-false"]]
|
||||
,["a -no-false", {false:false},["a"]]
|
||||
,["a -no-no-true", {true:true}, ["a"]]
|
||||
,["a -no-no-no-false", {false:false}, ["a"]]
|
||||
,["---NO-no-No-no-no-no-nO-no-no"+
|
||||
"-No-no-no-no-no-no-no-no-no"+
|
||||
"-no-no-no-no-NO-NO-no-no-no-no-no-no"+
|
||||
"-no-body-can-do-the-boogaloo-like-I-do"
|
||||
,{"body-can-do-the-boogaloo-like-I-do":false}, []]
|
||||
,["we are -no-strangers-to-love "+
|
||||
"--you-know the-rules --and so-do-i "+
|
||||
"---im-thinking-of=a-full-commitment "+
|
||||
"--no-you-would-get-this-from-any-other-guy "+
|
||||
"--no-gonna-give-you-up "+
|
||||
"-no-gonna-let-you-down=true "+
|
||||
"--no-no-gonna-run-around false "+
|
||||
"--desert-you=false "+
|
||||
"--make-you-cry false "+
|
||||
"--no-tell-a-lie "+
|
||||
"--no-no-and-hurt-you false"
|
||||
,{"strangers-to-love":false
|
||||
,"you-know":"the-rules"
|
||||
,"and":"so-do-i"
|
||||
,"you-would-get-this-from-any-other-guy":false
|
||||
,"gonna-give-you-up":false
|
||||
,"gonna-let-you-down":false
|
||||
,"gonna-run-around":false
|
||||
,"desert-you":false
|
||||
,"make-you-cry":false
|
||||
,"tell-a-lie":false
|
||||
,"and-hurt-you":false
|
||||
},["we", "are"]]
|
||||
,["-t one -t two -t three"
|
||||
,{t: ["one", "two", "three"]}
|
||||
,[]]
|
||||
,["-t one -t null -t three four five null"
|
||||
,{t: ["one", "null", "three"]}
|
||||
,["four", "five", "null"]]
|
||||
,["-t foo"
|
||||
,{t:["foo"]}
|
||||
,[]]
|
||||
,["--no-t"
|
||||
,{t:["false"]}
|
||||
,[]]
|
||||
,["-no-no-t"
|
||||
,{t:["true"]}
|
||||
,[]]
|
||||
,["-aoa one -aoa null -aoa 100"
|
||||
,{aoa:["one", null, 100]}
|
||||
,[]]
|
||||
,["-str 100"
|
||||
,{str:"100"}
|
||||
,[]]
|
||||
,["--color always"
|
||||
,{color:"always"}
|
||||
,[]]
|
||||
,["--no-nullstream"
|
||||
,{nullstream:null}
|
||||
,[]]
|
||||
,["--nullstream false"
|
||||
,{nullstream:null}
|
||||
,[]]
|
||||
,["--notadate 2011-01-25"
|
||||
,{notadate: "2011-01-25"}
|
||||
,[]]
|
||||
,["--date 2011-01-25"
|
||||
,{date: new Date("2011-01-25")}
|
||||
,[]]
|
||||
].forEach(function (test) {
|
||||
var argv = test[0].split(/\s+/)
|
||||
, opts = test[1]
|
||||
, rem = test[2]
|
||||
, actual = nopt(types, shorthands, argv, 0)
|
||||
, parsed = actual.argv
|
||||
delete actual.argv
|
||||
console.log(util.inspect(actual, false, 2, true), parsed.remain)
|
||||
for (var i in opts) {
|
||||
var e = JSON.stringify(opts[i])
|
||||
, a = JSON.stringify(actual[i] === undefined ? null : actual[i])
|
||||
if (e && typeof e === "object") {
|
||||
assert.deepEqual(e, a)
|
||||
} else {
|
||||
assert.equal(e, a)
|
||||
}
|
||||
}
|
||||
assert.deepEqual(rem, parsed.remain)
|
||||
})
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
To get started, <a
|
||||
href="http://www.clahub.com/agreements/isaacs/abbrev-js">sign the
|
||||
Contributor License Agreement</a>.
|
|
@ -1,23 +0,0 @@
|
|||
Copyright 2009, 2010, 2011 Isaac Z. Schlueter.
|
||||
All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,23 +0,0 @@
|
|||
# abbrev-js
|
||||
|
||||
Just like [ruby's Abbrev](http://apidock.com/ruby/Abbrev).
|
||||
|
||||
Usage:
|
||||
|
||||
var abbrev = require("abbrev");
|
||||
abbrev("foo", "fool", "folding", "flop");
|
||||
|
||||
// returns:
|
||||
{ fl: 'flop'
|
||||
, flo: 'flop'
|
||||
, flop: 'flop'
|
||||
, fol: 'folding'
|
||||
, fold: 'folding'
|
||||
, foldi: 'folding'
|
||||
, foldin: 'folding'
|
||||
, folding: 'folding'
|
||||
, foo: 'foo'
|
||||
, fool: 'fool'
|
||||
}
|
||||
|
||||
This is handy for command-line scripts, or other cases where you want to be able to accept shorthands.
|
|
@ -1,62 +0,0 @@
|
|||
|
||||
module.exports = exports = abbrev.abbrev = abbrev
|
||||
|
||||
abbrev.monkeyPatch = monkeyPatch
|
||||
|
||||
function monkeyPatch () {
|
||||
Object.defineProperty(Array.prototype, 'abbrev', {
|
||||
value: function () { return abbrev(this) },
|
||||
enumerable: false, configurable: true, writable: true
|
||||
})
|
||||
|
||||
Object.defineProperty(Object.prototype, 'abbrev', {
|
||||
value: function () { return abbrev(Object.keys(this)) },
|
||||
enumerable: false, configurable: true, writable: true
|
||||
})
|
||||
}
|
||||
|
||||
function abbrev (list) {
|
||||
if (arguments.length !== 1 || !Array.isArray(list)) {
|
||||
list = Array.prototype.slice.call(arguments, 0)
|
||||
}
|
||||
for (var i = 0, l = list.length, args = [] ; i < l ; i ++) {
|
||||
args[i] = typeof list[i] === "string" ? list[i] : String(list[i])
|
||||
}
|
||||
|
||||
// sort them lexicographically, so that they're next to their nearest kin
|
||||
args = args.sort(lexSort)
|
||||
|
||||
// walk through each, seeing how much it has in common with the next and previous
|
||||
var abbrevs = {}
|
||||
, prev = ""
|
||||
for (var i = 0, l = args.length ; i < l ; i ++) {
|
||||
var current = args[i]
|
||||
, next = args[i + 1] || ""
|
||||
, nextMatches = true
|
||||
, prevMatches = true
|
||||
if (current === next) continue
|
||||
for (var j = 0, cl = current.length ; j < cl ; j ++) {
|
||||
var curChar = current.charAt(j)
|
||||
nextMatches = nextMatches && curChar === next.charAt(j)
|
||||
prevMatches = prevMatches && curChar === prev.charAt(j)
|
||||
if (!nextMatches && !prevMatches) {
|
||||
j ++
|
||||
break
|
||||
}
|
||||
}
|
||||
prev = current
|
||||
if (j === cl) {
|
||||
abbrevs[current] = current
|
||||
continue
|
||||
}
|
||||
for (var a = current.substr(0, j) ; j <= cl ; j ++) {
|
||||
abbrevs[a] = current
|
||||
a += current.charAt(j)
|
||||
}
|
||||
}
|
||||
return abbrevs
|
||||
}
|
||||
|
||||
function lexSort (a, b) {
|
||||
return a === b ? 0 : a > b ? 1 : -1
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
{
|
||||
"name": "abbrev",
|
||||
"version": "1.0.5",
|
||||
"description": "Like ruby's abbrev module, but in js",
|
||||
"author": {
|
||||
"name": "Isaac Z. Schlueter",
|
||||
"email": "i@izs.me"
|
||||
},
|
||||
"main": "abbrev.js",
|
||||
"scripts": {
|
||||
"test": "node test.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://github.com/isaacs/abbrev-js"
|
||||
},
|
||||
"license": {
|
||||
"type": "MIT",
|
||||
"url": "https://github.com/isaacs/abbrev-js/raw/master/LICENSE"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/isaacs/abbrev-js/issues"
|
||||
},
|
||||
"homepage": "https://github.com/isaacs/abbrev-js",
|
||||
"_id": "abbrev@1.0.5",
|
||||
"_shasum": "5d8257bd9ebe435e698b2fa431afde4fe7b10b03",
|
||||
"_from": "abbrev@1",
|
||||
"_npmVersion": "1.4.7",
|
||||
"_npmUser": {
|
||||
"name": "isaacs",
|
||||
"email": "i@izs.me"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "isaacs",
|
||||
"email": "i@izs.me"
|
||||
}
|
||||
],
|
||||
"dist": {
|
||||
"shasum": "5d8257bd9ebe435e698b2fa431afde4fe7b10b03",
|
||||
"tarball": "http://registry.npmjs.org/abbrev/-/abbrev-1.0.5.tgz"
|
||||
},
|
||||
"directories": {},
|
||||
"_resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.5.tgz",
|
||||
"readme": "ERROR: No README data found!"
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
var abbrev = require('./abbrev.js')
|
||||
var assert = require("assert")
|
||||
var util = require("util")
|
||||
|
||||
console.log("TAP Version 13")
|
||||
var count = 0
|
||||
|
||||
function test (list, expect) {
|
||||
count++
|
||||
var actual = abbrev(list)
|
||||
assert.deepEqual(actual, expect,
|
||||
"abbrev("+util.inspect(list)+") === " + util.inspect(expect) + "\n"+
|
||||
"actual: "+util.inspect(actual))
|
||||
actual = abbrev.apply(exports, list)
|
||||
assert.deepEqual(abbrev.apply(exports, list), expect,
|
||||
"abbrev("+list.map(JSON.stringify).join(",")+") === " + util.inspect(expect) + "\n"+
|
||||
"actual: "+util.inspect(actual))
|
||||
console.log('ok - ' + list.join(' '))
|
||||
}
|
||||
|
||||
test([ "ruby", "ruby", "rules", "rules", "rules" ],
|
||||
{ rub: 'ruby'
|
||||
, ruby: 'ruby'
|
||||
, rul: 'rules'
|
||||
, rule: 'rules'
|
||||
, rules: 'rules'
|
||||
})
|
||||
test(["fool", "foom", "pool", "pope"],
|
||||
{ fool: 'fool'
|
||||
, foom: 'foom'
|
||||
, poo: 'pool'
|
||||
, pool: 'pool'
|
||||
, pop: 'pope'
|
||||
, pope: 'pope'
|
||||
})
|
||||
test(["a", "ab", "abc", "abcd", "abcde", "acde"],
|
||||
{ a: 'a'
|
||||
, ab: 'ab'
|
||||
, abc: 'abc'
|
||||
, abcd: 'abcd'
|
||||
, abcde: 'abcde'
|
||||
, ac: 'acde'
|
||||
, acd: 'acde'
|
||||
, acde: 'acde'
|
||||
})
|
||||
|
||||
console.log("0..%d", count)
|
|
@ -1,60 +0,0 @@
|
|||
{
|
||||
"name": "nopt",
|
||||
"version": "1.0.10",
|
||||
"description": "Option parsing for Node, supporting types, shorthands, etc. Used by npm.",
|
||||
"author": {
|
||||
"name": "Isaac Z. Schlueter",
|
||||
"email": "i@izs.me",
|
||||
"url": "http://blog.izs.me/"
|
||||
},
|
||||
"main": "lib/nopt.js",
|
||||
"scripts": {
|
||||
"test": "node lib/nopt.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/isaacs/nopt.git"
|
||||
},
|
||||
"bin": {
|
||||
"nopt": "./bin/nopt.js"
|
||||
},
|
||||
"license": {
|
||||
"type": "MIT",
|
||||
"url": "https://github.com/isaacs/nopt/raw/master/LICENSE"
|
||||
},
|
||||
"dependencies": {
|
||||
"abbrev": "1"
|
||||
},
|
||||
"_npmUser": {
|
||||
"name": "isaacs",
|
||||
"email": "i@izs.me"
|
||||
},
|
||||
"_id": "nopt@1.0.10",
|
||||
"devDependencies": {},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"_engineSupported": true,
|
||||
"_npmVersion": "1.0.93",
|
||||
"_nodeVersion": "v0.5.9-pre",
|
||||
"_defaultsLoaded": true,
|
||||
"dist": {
|
||||
"shasum": "6ddd21bd2a31417b92727dd585f8a6f37608ebee",
|
||||
"tarball": "http://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "isaacs",
|
||||
"email": "i@izs.me"
|
||||
}
|
||||
],
|
||||
"directories": {},
|
||||
"_shasum": "6ddd21bd2a31417b92727dd585f8a6f37608ebee",
|
||||
"_from": "nopt@~1.0.10",
|
||||
"_resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
|
||||
"bugs": {
|
||||
"url": "https://github.com/isaacs/nopt/issues"
|
||||
},
|
||||
"readme": "ERROR: No README data found!",
|
||||
"homepage": "https://github.com/isaacs/nopt"
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- 0.6
|
||||
- 0.8
|
|
@ -1,18 +0,0 @@
|
|||
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.
|
|
@ -1,5 +0,0 @@
|
|||
var resolve = require('../');
|
||||
resolve('tap', { basedir: __dirname }, function (err, res) {
|
||||
if (err) console.error(err)
|
||||
else console.log(res)
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue