From 345ac776ef3721977b545ee0b2a398c917f25869 Mon Sep 17 00:00:00 2001 From: Spencer Alger Date: Thu, 12 Dec 2013 15:39:42 -0700 Subject: [PATCH] Major updates for testing and grunt, jenkins tests are now powered by the jenkins.sh script in the scripts directory. --- .gitignore | 1 + .gitmodules | 3 + LICENSE.md => LICENSE | 0 README.md | 18 + grunt/{build.js => browser_clients_build.js} | 2 +- grunt/browser_clients_export.js | 30 + grunt/browser_clients_publish.js | 10 + grunt/browser_clients_release.js | 10 + grunt/config/browserify.js | 14 + grunt/config/compress.js | 14 + grunt/config/jshint.js | 1 + grunt/config/mocha.js | 8 + grunt/config/run.js | 43 + grunt/config/s3.js | 17 +- grunt/default.js | 3 +- grunt/generate.js | 5 + grunt/publish.js | 8 - grunt/release.js | 8 - grunt/test.js | 15 + package.json | 22 +- scripts/export_all_clients.js | 33 - scripts/export_client.js | 49 - scripts/export_docs.js | 2 +- scripts/generate/_force.js | 24 - scripts/generate/index.js | 71 + scripts/generate/js_api.js | 344 + scripts/generate/js_api/README.md | 3 - scripts/generate/js_api/actions.js | 240 - scripts/generate/js_api/aliases.js | 63 - scripts/generate/js_api/generate.js | 59 - scripts/generate/js_api/index.js | 1 - scripts/generate/logs/index.js | 3 - .../{js_api => }/templates/api_file.tmpl | 3 +- .../templates/api_method_list.tmpl | 0 .../{js_api => }/templates/api_methods.tmpl | 0 .../{js_api => }/templates/client_action.tmpl | 2 +- .../templates/client_action_proxy.tmpl | 2 +- .../generate/{js_api => }/templates/index.js | 2 +- scripts/generate/yaml_tests.js | 46 + scripts/generate/yaml_tests/README.md | 3 - scripts/generate/yaml_tests/generate.js | 44 - scripts/generate/yaml_tests/index.js | 1 - scripts/jenkins.sh | 19 + .../run_browser_integration_suite/index.js | 120 +- .../run_browser_integration_suite/server.js | 12 +- scripts/run_tests.js | 28 +- src/elasticsearch.angular.js | 1 + src/lib/api.js | 64 +- src/lib/connectors/angular.js | 2 +- src/lib/connectors/http.js | 6 + src/lib/connectors/xhr.js | 4 +- src/lib/log.js | 1 + src/lib/transport.js | 31 +- src/rest-api-spec | 1 + .../browser_yaml_suite/yaml_tests.js | 8012 +---------------- test/integration/yaml_suite/index.js | 40 +- test/mocks/browser_http.js | 484 + test/mocks/browser_server.js | 83 + test/mocks/server.js | 3 + test/unit/auto_release_stub.js | 4 +- test/unit/test_connection_abstract.js | 37 +- test/unit/test_connection_pool.js | 9 +- test/unit/test_console_logger.js | 3 +- test/unit/test_http_connector.js | 6 +- test/unit/test_stream_logger.js | 1 - test/unit/test_transport.js | 123 +- .../reporter.js => utils/jenkins-reporter.js} | 75 +- {scripts => test/utils}/make_j_unit_xml.js | 22 +- 68 files changed, 1628 insertions(+), 8790 deletions(-) create mode 100644 .gitmodules rename LICENSE.md => LICENSE (100%) rename grunt/{build.js => browser_clients_build.js} (72%) create mode 100644 grunt/browser_clients_export.js create mode 100644 grunt/browser_clients_publish.js create mode 100644 grunt/browser_clients_release.js create mode 100644 grunt/config/compress.js create mode 100644 grunt/config/mocha.js create mode 100644 grunt/config/run.js create mode 100644 grunt/generate.js delete mode 100644 grunt/publish.js delete mode 100644 grunt/release.js create mode 100644 grunt/test.js delete mode 100644 scripts/export_all_clients.js delete mode 100644 scripts/export_client.js delete mode 100644 scripts/generate/_force.js create mode 100644 scripts/generate/index.js create mode 100644 scripts/generate/js_api.js delete mode 100644 scripts/generate/js_api/README.md delete mode 100644 scripts/generate/js_api/actions.js delete mode 100644 scripts/generate/js_api/aliases.js delete mode 100644 scripts/generate/js_api/generate.js delete mode 100644 scripts/generate/js_api/index.js rename scripts/generate/{js_api => }/templates/api_file.tmpl (99%) rename scripts/generate/{js_api => }/templates/api_method_list.tmpl (100%) rename scripts/generate/{js_api => }/templates/api_methods.tmpl (100%) rename scripts/generate/{js_api => }/templates/client_action.tmpl (94%) rename scripts/generate/{js_api => }/templates/client_action_proxy.tmpl (99%) rename scripts/generate/{js_api => }/templates/index.js (98%) create mode 100644 scripts/generate/yaml_tests.js delete mode 100644 scripts/generate/yaml_tests/README.md delete mode 100644 scripts/generate/yaml_tests/generate.js delete mode 100644 scripts/generate/yaml_tests/index.js create mode 100755 scripts/jenkins.sh create mode 160000 src/rest-api-spec create mode 100644 test/mocks/browser_http.js create mode 100644 test/mocks/browser_server.js create mode 100644 test/mocks/server.js rename test/{integration/yaml_suite/reporter.js => utils/jenkins-reporter.js} (71%) rename {scripts => test/utils}/make_j_unit_xml.js (78%) diff --git a/.gitignore b/.gitignore index 00e163a87..435807992 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ test/integration/yaml_suite/log ## generated files scripts/last_rest_spec_update.sha +test/integration/yaml_suite/yaml_tests.json test/browser_integration/yaml_tests.js test-output-*.xml coverage.html diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..e84498a47 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/rest-api-spec"] + path = src/rest-api-spec + url = git@github.com:elasticsearch/elasticsearch-rest-api-spec.git diff --git a/LICENSE.md b/LICENSE similarity index 100% rename from LICENSE.md rename to LICENSE diff --git a/README.md b/README.md index 7a1434308..98efdede2 100644 --- a/README.md +++ b/README.md @@ -66,3 +66,21 @@ bower install elasticsearch-jquery - [Extending Core Components](http://spenceralger.github.io/elasticsearch-js/index.html#extending) - [Logging](http://spenceralger.github.io/elasticsearch-js/index.html#logging) - [Contributing](http://spenceralger.github.io/elasticsearch-js/index.html#contributing) + +## License + +This software is licensed under the Apache 2 license, quoted below. + + Copyright (c) 2013 Elasticsearch + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/grunt/build.js b/grunt/browser_clients_build.js similarity index 72% rename from grunt/build.js rename to grunt/browser_clients_build.js index 189be3c5d..322ac1547 100644 --- a/grunt/build.js +++ b/grunt/browser_clients_build.js @@ -1,5 +1,5 @@ module.exports = function (grunt) { - grunt.registerTask('build', [ + grunt.registerTask('browser_clients_build', [ 'clean:dist', 'browserify', 'uglify:dist', diff --git a/grunt/browser_clients_export.js b/grunt/browser_clients_export.js new file mode 100644 index 000000000..d78b798cd --- /dev/null +++ b/grunt/browser_clients_export.js @@ -0,0 +1,30 @@ +module.exports = function (grunt) { + grunt.registerTask('export_client', function (build, outDir) { + var path = require('path'); + + grunt.config.set('copy.export_client', { + expand: true, + cwd: './dist/', + src: 'elasticsearch' + (build ? '.' + build : '') + '{.min,}.js', + dest: outDir, + rename: function (dest, src) { + return path.join(dest, 'elasticsearch' + (~src.indexOf('.min') ? '.min' : '') + '.js'); + } + }); + + this.requires('build'); + + grunt.task.run([ + 'copy:export_client' + ]); + }); + + grunt.registerTask('export_all_clients', function () { + grunt.task.run([ + 'build', + 'export_client:angular:../bower-elasticsearch-angular', + 'export_client::../bower-elasticsearch-browser', + 'export_client:jquery:../bower-elasticsearch-jquery' + ]); + }); +}; \ No newline at end of file diff --git a/grunt/browser_clients_publish.js b/grunt/browser_clients_publish.js new file mode 100644 index 000000000..66a0fa37f --- /dev/null +++ b/grunt/browser_clients_publish.js @@ -0,0 +1,10 @@ +module.exports = function (grunt) { + + grunt.registerTask('browser_clients_publish', [ + 'build_browser_clients', + 'compress:dist_zip', + 'compress:dist_tarball', + 's3:latest' + ]); + +}; \ No newline at end of file diff --git a/grunt/browser_clients_release.js b/grunt/browser_clients_release.js new file mode 100644 index 000000000..8aa0c8a29 --- /dev/null +++ b/grunt/browser_clients_release.js @@ -0,0 +1,10 @@ +module.exports = function (grunt) { + + grunt.registerTask('browser_clients_release', [ + 'build_browser_clients', + 'compress:dist_zip', + 'compress:dist_tarball', + 's3:release' + ]); + +}; \ No newline at end of file diff --git a/grunt/config/browserify.js b/grunt/config/browserify.js index 49bba2076..8f2d65e9d 100644 --- a/grunt/config/browserify.js +++ b/grunt/config/browserify.js @@ -1,4 +1,18 @@ module.exports = { + yaml_suite: { + options: { + external: [ + 'optimist' + ], + ignore: [ + 'test/integration/yaml_suite/reporter', + 'src/elasticsearch.js' + ] + }, + files: { + 'test/integration/browser_yaml_suite/yaml_tests.js': 'test/integration/yaml_suite/index.js' + } + }, browser_client: { files: { '<%= distDir %>/elasticsearch.js': 'src/elasticsearch.js' diff --git a/grunt/config/compress.js b/grunt/config/compress.js new file mode 100644 index 000000000..b6290139d --- /dev/null +++ b/grunt/config/compress.js @@ -0,0 +1,14 @@ +module.exports = { + dist_zip: { + src: '<%= distDir %>/*.js', + options: { + archive: '<%= distDir %>/archives/elasticsearch-js.zip' + } + }, + dist_tarball: { + src: '<%= distDir %>/*.js', + options: { + archive: '<%= distDir %>/archives/elasticsearch-js.tar.gz' + } + } +}; \ No newline at end of file diff --git a/grunt/config/jshint.js b/grunt/config/jshint.js index c09e98c9d..98c711826 100644 --- a/grunt/config/jshint.js +++ b/grunt/config/jshint.js @@ -4,6 +4,7 @@ module.exports = { 'src/**/*.js', 'scripts/**/*.js', 'test/**/*.js -test/browser_integration/yaml_tests.js', + 'grunt/**/*.js', 'Gruntfile.js' ], options: { diff --git a/grunt/config/mocha.js b/grunt/config/mocha.js new file mode 100644 index 000000000..6a180debc --- /dev/null +++ b/grunt/config/mocha.js @@ -0,0 +1,8 @@ +module.exports = { + unit: { + src: ['test/unit/test_*.js'], + reporter: 'XUnit', + dest: './test-output-phantom-unit.xml', + run: true + } +}; \ No newline at end of file diff --git a/grunt/config/run.js b/grunt/config/run.js new file mode 100644 index 000000000..e52130ead --- /dev/null +++ b/grunt/config/run.js @@ -0,0 +1,43 @@ +module.exports = { + generate: { + exec: 'node scripts/generate' + }, + unit_tests: { + exec: 'node scripts/run_tests --unit --no-browsers', + options: { + passArgs: [ + 'port', + 'host' + ] + } + }, + integration_tests: { + exec: 'node scripts/run_tests --integration --no-browsers', + options: { + passArgs: [ + 'port', + 'host' + ] + } + }, + browser_unit_tests: { + exec: 'node scripts/run_tests --unit --no-server', + options: { + cwd: '.', + passArgs: [ + 'port', + 'host' + ] + } + }, + browser_integration_tests: { + exec: 'node scripts/run_tests --integration --no-server', + options: { + cwd: '.', + passArgs: [ + 'port', + 'host' + ] + } + } +}; \ No newline at end of file diff --git a/grunt/config/s3.js b/grunt/config/s3.js index 41a91e8bf..0208a4695 100644 --- a/grunt/config/s3.js +++ b/grunt/config/s3.js @@ -1,17 +1,26 @@ -var config = require('../../.aws-config.json'); +var config = {}; +try { + config = require('../../.aws-config.json'); +} catch (e) {} + module.exports = { options: { key: config.key, secret: config.secret, bucket: 'download.elasticsearch.org', - access: 'public-read' + access: 'public-read', + headers: { + 'Content-Type': 'text/plain', + 'X-Content-Type-Options': 'nosniff', + 'Content-Disposition': 'attachment' + } }, latest: { upload: [ { - src: '<%= distDir %>/*.js', + src: '<%= distDir %>/archives/*', dest: 'elasticsearch/elasticsearch-js/latest' } ] @@ -20,7 +29,7 @@ module.exports = { release: { upload: [ { - src: '<%= distDir %>/*.js', + src: '<%= distDir %>/archives/*', dest: 'elasticsearch/elasticsearch-js/<%= package.version %>' } ] diff --git a/grunt/default.js b/grunt/default.js index b15d02f27..fdeb3f65b 100644 --- a/grunt/default.js +++ b/grunt/default.js @@ -2,7 +2,8 @@ module.exports = function (grunt) { // Default task runs the build process. grunt.registerTask('default', [ - 'build' + 'run:generate', + 'test' ]); }; \ No newline at end of file diff --git a/grunt/generate.js b/grunt/generate.js new file mode 100644 index 000000000..4fe78077b --- /dev/null +++ b/grunt/generate.js @@ -0,0 +1,5 @@ +module.exports = function (grunt) { + grunt.registerTask('generate', [ + 'run:generate' + ]); +}; \ No newline at end of file diff --git a/grunt/publish.js b/grunt/publish.js deleted file mode 100644 index 00e32992b..000000000 --- a/grunt/publish.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = function (grunt) { - - grunt.registerTask('publish', [ - 'build', - 's3:latest' - ]); - -}; \ No newline at end of file diff --git a/grunt/release.js b/grunt/release.js deleted file mode 100644 index 684c236c9..000000000 --- a/grunt/release.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = function (grunt) { - - grunt.registerTask('release', [ - 'build', - 's3:release' - ]); - -}; \ No newline at end of file diff --git a/grunt/test.js b/grunt/test.js new file mode 100644 index 000000000..9c8b36baa --- /dev/null +++ b/grunt/test.js @@ -0,0 +1,15 @@ +module.exports = function (grunt) { + + grunt.registerTask('test', [ + 'jshint', + 'run:unit_tests', + 'run:integration_tests' + ]); + + grunt.registerTask('browser_clients_test', [ + 'build', + 'run:browser_unit_tests', + 'run:browser_integration_tests' + ]); + +}; \ No newline at end of file diff --git a/package.json b/package.json index 359e9e17b..89426884a 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "version": "0.0.1", "browser": { "./src/lib/connectors/index.js": "./src/lib/connectors/browser_index.js", - "./src/lib/loggers/index.js": "./src/lib/loggers/browser_index.js" + "./src/lib/loggers/index.js": "./src/lib/loggers/browser_index.js", + "./test/mocks/server.js": "./test/mocks/browser_server.js" }, "devDependencies": { "tar": "~0.1.18", @@ -36,12 +37,17 @@ "mocha-lcov-reporter": "0.0.1", "blanket": "~1.1.5", "sinon": "~1.7.3", - "nock": "~0.23.0", + "nock": "git://github.com/spenceralger/nock.git#c5b07103eb3058035b99118d343ee0dfca666107", "open": "0.0.4", "testling": "git://github.com/spenceralger/testling.git", "load-grunt-tasks": "~0.2.0", "load-grunt-config": "~0.7.0", - "grunt-s3": "~0.2.0-alpha.3" + "grunt-s3": "~0.2.0-alpha.3", + "grunt-run": "~0.1.5", + "relative-fs": "0.0.1", + "grunt-contrib-compress": "~0.5.3", + "grunt-contrib-copy": "~0.4.1", + "grunt-mocha": "~0.4.7" }, "license": "Apache 2.0", "dependencies": { @@ -51,14 +57,12 @@ "chalk": "~0.3.0" }, "repository": { - "type" : "git", - "url" : "http://github.com/elasticsearch/elasticsearch-js.git" + "type": "git", + "url": "http://github.com/elasticsearch/elasticsearch-js.git" }, "scripts": { - "test": "node scripts/run_tests.js --integration --unit --browsers=chrome,safari,firefox,opera", - "coverage": "mocha test/unit/test_*.js --require blanket -R html-cov > coverage.html && open -a \"Google Chrome\" ./coverage.html", - "build_clients": "grunt", - "generate": "node scripts/generate/js_api && node scripts/generate/yaml_tests", + "test": "grunt test", + "coverage": "mocha test/unit/test_*.js --require blanket -R html-cov > coverage.html && open -a \"Google Chrome\"./coverage.html", "blanket": { "pattern": "src" } diff --git a/scripts/export_all_clients.js b/scripts/export_all_clients.js deleted file mode 100644 index b8f6d8b36..000000000 --- a/scripts/export_all_clients.js +++ /dev/null @@ -1,33 +0,0 @@ -var path = require('path'); -var fs = require('fs'); - -var argv = require('optimist') - .default({ - verbose: false - }) - .alias({ - v: 'verbose' - }) - .argv; - -var steps = []; - -['browser', 'jquery', 'angular'].forEach(function (build) { - - if (!fs.existsSync('../bower-elasticsearch-' + build) || - !fs.existsSync('../bower-elasticsearch-' + build + '/.git') - ) { - throw new Error('Ensure that all of the bower repos are checked out next to this repo'); - } - - steps.push([ - 'run', { - cwd: '../bower-elasticsearch-' + build + '/', - cmd: 'npm', - args: ['run', 'generate'] - } - ]); - -}); - -require('./_steps')(argv, steps); \ No newline at end of file diff --git a/scripts/export_client.js b/scripts/export_client.js deleted file mode 100644 index 981cab9cc..000000000 --- a/scripts/export_client.js +++ /dev/null @@ -1,49 +0,0 @@ -var path = require('path'); - -var argv = require('optimist') - .default({ - buildName: '', - outputDir: '.', - verbose: false - }) - .alias({ - b: 'buildName', - o: 'outputDir', - v: 'verbose' - }) - .argv; - -switch (argv.buildName) { -case 'jquery': - var buildFile = './dist/elasticsearch.jquery.js'; - var minifiedBuildFile = './dist/elasticsearch.jquery.min.js'; - break; -case 'angular': - var buildFile = './dist/elasticsearch.angular.js'; - var minifiedBuildFile = './dist/elasticsearch.angular.min.js'; - break; -default: - var buildFile = './dist/elasticsearch.js'; - var minifiedBuildFile = './dist/elasticsearch.min.js'; - break; -} - -var outputFile = path.join(argv.outputDir, 'elasticsearch.js'); -var minifiedOutputFile = path.join(argv.outputDir, 'elasticsearch.min.js'); - -require('./_steps')(argv, [ - ['run', { - cmd: 'npm', - args: ['run', 'build_clients'] - }], - ['copy', { - from: buildFile, - to: outputFile - }], - ['copy', { - from: minifiedBuildFile, - to: minifiedOutputFile - }] -]); - - diff --git a/scripts/export_docs.js b/scripts/export_docs.js index ae4be937c..495a8ef81 100644 --- a/scripts/export_docs.js +++ b/scripts/export_docs.js @@ -14,7 +14,7 @@ var argv = require('optimist') require('./_steps')(argv, [ ['runInModule', { cmd: 'node', - args: [path.join(__dirname, './generate/js_api'), '--force'] + args: [path.join(__dirname, './generate'), '--force'] }], ['copy', { from: path.join(__dirname, '../docs/_methods.jade'), diff --git a/scripts/generate/_force.js b/scripts/generate/_force.js deleted file mode 100644 index 9b411b33b..000000000 --- a/scripts/generate/_force.js +++ /dev/null @@ -1,24 +0,0 @@ -var force = process.env.FORCE || process.env.FORCE_GEN; - -if (!force) { - var argv = require('optimist') - .options({ - force: { - alias: 'f', - default: false, - boolean: true - } - }); - - if (process.env.npm_config_argv) { - // when called by NPM - argv = argv.parse(JSON.parse(process.env.npm_config_argv).original); - } else { - // when called directly - argv = argv.argv; - } - - force = argv.force; -} - -module.exports = force; \ No newline at end of file diff --git a/scripts/generate/index.js b/scripts/generate/index.js new file mode 100644 index 000000000..ac689d2a0 --- /dev/null +++ b/scripts/generate/index.js @@ -0,0 +1,71 @@ +var cp = require('child_process'); +var async = require('async'); +var argv = require('optimist') + .options({ + force: { + alias: 'f', + default: false, + boolean: true + }, + verbose: { + alias: 'v', + default: false, + boolean: true + }, + api: { + default: true, + boolean: true + }, + tests: { + default: true, + boolean: true + } + }); + +if (process.env.npm_config_argv) { + // when called by NPM + argv = argv.parse(JSON.parse(process.env.npm_config_argv).original); +} else { + // when called directly + argv = argv.argv; +} + +if (!argv.force && process.env.FORCE || process.env.FORCE_GEN) { + argv.force = argv.f = process.env.FORCE || process.env.FORCE_GEN; +} + +function updateSubmodules(done) { + cp.exec('git submodule update --init --recursive', function (err, stdout, stderr) { + stdout = stdout.trim(); + stderr = stderr.trim(); + + if (err) { + done(new Error('Unable to update submodules: ' + err.message)); + return; + } else if (argv.verbose && stdout) { + console.log(stdout); + } + + if (stderr) { + console.error(stderr); + } + done(); + }); +} + +updateSubmodules(function (err) { + if (err) { + throw err; + } + + var tasks = []; + + if (argv.api) { + tasks.push(require('./js_api')); + } + if (argv.tests) { + tasks.push(require('./yaml_tests')); + } + + async.parallel(tasks, function () {}); +}); \ No newline at end of file diff --git a/scripts/generate/js_api.js b/scripts/generate/js_api.js new file mode 100644 index 000000000..da7be5c93 --- /dev/null +++ b/scripts/generate/js_api.js @@ -0,0 +1,344 @@ +var aliases; // defined at the bottom of this file. + +module.exports = function (done) { + /** + * Read the API actions form the rest-api-spec repo. + * @type {[type]} + */ + var _ = require('../../src/lib/utils'); + var fs = require('relative-fs').relativeTo(__dirname); + var async = require('async'); + var templates = require('./templates'); + var castExistsRE = /exists/; + var usesBulkBodyRE = /^(bulk|msearch)$/; + var urlParamRE = /\{(\w+)\}/g; + + var files; // populated in readSpecFiles + var apiSpec; // populated by parseSpecFiles + + // generate the API + async.series([ + readSpecFiles, + parseSpecFiles, + writeApiFile, + ensureDocsDir, + writeMethodList, + writeMethodDocs + ], done); + + function readSpecFiles(done) { + var apiDir = '../../src/rest-api-spec/api/'; + files = fs.readdirSync(apiDir).map(function (filename) { + return require(apiDir + filename); + }); + done(); + } + + function parseSpecFiles(done) { + var actions = []; + + files.forEach(function (spec) { + __puke__transformSpec(spec).forEach(function (action) { + actions.push(action); + }); + }); + + // collect the namespaces from the action locations + var namespaces = _.filter(_.map(actions, function (action) { + if (~action.location.indexOf('.')) { + var path = action.location.split('.').slice(0, -1); + _.pull(path, 'prototype'); + return path.join('.'); + } + })); + + // seperate the proxy actions + var groups = _.groupBy(actions, function (action) { + return action.proxy ? 'proxies' : 'normal'; + }); + + apiSpec = { + actions: groups.normal, + proxies: groups.proxies, + namespaces: _.unique(namespaces.sort(), true) + }; + + done(); + } + + function writeApiFile(done) { + var outputPath = require('path').join(__dirname, '../../src/lib/api.js'); + console.log('writing', apiSpec.actions.length, 'api actions to', outputPath); + fs.writeFile(outputPath, templates.apiFile(apiSpec), done); + } + + function ensureDocsDir(done) { + fs.stat('../../docs', function (err, stat) { + if (err) { + if (err.message.match(/enoent/i)) { + fs.mkdir('../../docs', done); + } else { + done(err); + } + } else if (stat.isDirectory()) { + done(); + } else { + done(new Error('../../docs exists, but it is not a directory')); + } + }); + } + + function writeMethodList(done) { + fs.writeFile( + '../../docs/_method_list.jade', + templates.apiMethodList(apiSpec), + done + ); + } + + function writeMethodDocs(done) { + fs.writeFile( + '../../docs/_methods.jade', + templates.apiMethods(apiSpec), + done + ); + } + + function __puke__transformSpec(spec) { + var actions = []; + + // itterate all of the specs within the file, should only be one + _.each(spec, function (def, name) { + //camelcase the name + name = _.map(name.split('.'), _.camelCase).join('.'); + + var steps = name.split('.'); + + function transformParamKeys(note, param, key) { + var cmlKey = _.camelCase(key); + if (cmlKey !== key) { + param.name = key; + } + note[cmlKey] = param; + } + + def.url.params = _.transform(def.url.params, transformParamKeys, {}); + def.url.parts = _.transform(def.url.parts, transformParamKeys, {}); + + var allParams = _.extend({}, def.url.params, def.url.parts); + var spec = { + name: name, + methods: _.map(def.methods, function (m) { return m.toUpperCase(); }), + params: def.url.params, + body: def.body || null, + path2lib: _.repeat('../', steps.length + 1) + 'lib/' + }; + + if (def.body && def.body.requires) { + spec.needBody = true; + } + + if (usesBulkBodyRE.test(name)) { + spec.bulkBody = true; + } + + if (castExistsRE.test(name)) { + spec.castExists = true; + } + + var urls = _.difference(def.url.paths, aliases[name]); + urls = _.map(urls, function (url) { + var optionalVars = {}; + var requiredVars = {}; + var param; + var name; + var target; + var match; + + if (url.charAt(0) !== '/') { + url = '/' + url; + } + + while (match = urlParamRE.exec(url)) { + name = _.camelCase(match[1]); + param = def.url.parts[name] || {}; + target = (param.required || !param.default) ? requiredVars : optionalVars; + target[name] = _.omit(param, 'required', 'description', 'name'); + } + + return _.omit({ + fmt: url.replace(urlParamRE, function (full, match) { + return '<%=' + _.camelCase(match) + '%>'; + }), + opt: _.size(optionalVars) ? optionalVars : null, + req: _.size(requiredVars) ? requiredVars : null, + sortOrder: _.size(requiredVars) * -1 + }, function (v) { + return !v; + }); + }); + + if (urls.length > 1) { + spec.urls = _.map(_.sortBy(urls, 'sortOrder'), function (url) { + return _.omit(url, 'sortOrder'); + }); + } else { + spec.url = urls[0]; + } + + spec.params = _.transform(spec.params, function (note, param, name) { + // param.name = name; + note[name] = _.pick(param, [ + 'type', 'default', 'options', 'required', 'name' + ]); + }, {}); + + if (_.size(spec.params) === 0) { + delete spec.params; + } + + // escape method names with "special" keywords + var location = spec.name.split('.').join('.prototype.') + .replace(/(^|\.)(delete|default)(\.|$)/g, '[\'$2\']'); + + var action = { + _methods: spec.methods, + spec: _.pick(spec, [ + 'params', + 'url', + 'urls', + 'needBody', + 'bulkBody', + 'castExists', + 'castNotFound' + ]), + location: location, + docUrl: def.documentation, + name: spec.name, + allParams: allParams + }; + + function hasMethod(/* ...methods */) { + for (var i = 0; i < arguments.length; i++) { + if (~action._methods.indexOf(arguments[i])) { + continue; + } else { + return false; + } + } + return true; + } + function methodsAre(/* ...methods */) { + return hasMethod.apply(null, arguments) && arguments.length === action._methods.length; + } + + var method; + + if (action._methods.length === 1) { + method = action._methods[0]; + } else { + // we need to define what the default method(s) will be + if (hasMethod('DELETE', 'POST')) { + method = 'POST'; + } + else if (methodsAre('DELETE')) { + method = 'DELETE'; + } + else if (methodsAre('POST', 'PUT')) { + method = action.name.match(/put/i) ? 'PUT' : 'POST'; + } + else if (methodsAre('GET', 'POST')) { + method = 'POST'; + } + else if (methodsAre('GET', 'HEAD')) { + if (action.spec.castExists) { + method = 'HEAD'; + } else { + method = 'GET'; + } + } + } + + if (method) { + if (method !== 'GET') { + action.spec.method = method; + } + } else { + throw new Error('unable to pick a method for ' + JSON.stringify(action, null, ' ')); + } + + if (action.name === 'create') { + action.proxy = 'index'; + action.transformBody = 'params.op_type = \'create\';'; + } + + actions.push(action); + }); + + return actions; + } +}; + +aliases = { + 'cluster.nodeHotThreads': [ + '/_cluster/nodes/hotthreads', + '/_cluster/nodes/hot_threads', + '/_nodes/hot_threads', + '/_cluster/nodes/{node_id}/hotthreads', + '/_cluster/nodes/{node_id}/hot_threads', + '/_nodes/{node_id}/hot_threads' + ], + 'cluster.nodeInfo': [ + '/_cluster/nodes', + '/_nodes/settings', + '/_nodes/os', + '/_nodes/process', + '/_nodes/jvm', + '/_nodes/thread_pool', + '/_nodes/network', + '/_nodes/transport', + '/_nodes/http', + '/_nodes/plugin', + '/_cluster/nodes/{node_id}', + '/_nodes/{node_id}/settings', + '/_nodes/{node_id}/os', + '/_nodes/{node_id}/process', + '/_nodes/{node_id}/jvm', + '/_nodes/{node_id}/thread_pool', + '/_nodes/{node_id}/network', + '/_nodes/{node_id}/transport', + '/_nodes/{node_id}/http', + '/_nodes/{node_id}/plugin' + ], + 'cluster.nodeShutdown': [ + '/_cluster/nodes/_shutdown' + ], + 'cluster.nodeStats': [ + '/_cluster/nodes/stats', + '/_nodes/stats/{metric_family}', + '/_nodes/stats/indices/{metric}/{fields}', + '/_cluster/nodes/{node_id}/stats', + '/_nodes/{node_id}/stats/{metric_family}', + '/_nodes/{node_id}/stats/indices/{metric}/{fields}' + ], + 'get': [ + '/{index}/{type}/{id}/_source' + ], + 'indices.deleteMapping': [ + '/{index}/{type}/_mapping' + ], + 'indices.stats': [ + '_stats/{metric_family}', + '/_stats/indexing', + '/_stats/indexing/{indexing_types}', + '/_stats/search/{search_groups}', + '/_stats/fielddata/{fields}', + '/{index}/_stats/{metric_family}', + '/{index}/_stats/indexing', + '/{index}/_stats/search/{search_groups}', + '/{index}/_stats/fielddata/{fields}' + ], + 'search': [ + '/_search' + ] +}; \ No newline at end of file diff --git a/scripts/generate/js_api/README.md b/scripts/generate/js_api/README.md deleted file mode 100644 index e1fee6372..000000000 --- a/scripts/generate/js_api/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Generate the API using the es [REST api spec](https://github.com/elasticsearch/elasticsearch-rest-api-spec). - -run by calling `npm run generate`. Force it to update, even if their has not been a new commit, but calling with `--force` or `-f` diff --git a/scripts/generate/js_api/actions.js b/scripts/generate/js_api/actions.js deleted file mode 100644 index 0fd0c8552..000000000 --- a/scripts/generate/js_api/actions.js +++ /dev/null @@ -1,240 +0,0 @@ -var _ = require('../../../src/lib/utils'); - -var EventEmitter = require('events').EventEmitter; -var aliases = require('./aliases'); - -var castExistsRE = /exists/; -var usesBulkBodyRE = /^(bulk|msearch)$/; -var urlParamRE = /\{(\w+)\}/g; - -var specCount = 0; -var actions = []; -var doneParsing = false; - -require('../../get_spec') - .get('api/*.json') - .on('entry', transformFile) - .on('end', function () { - doneParsing = true; - if (actions.length === specCount) { - module.exports.emit('ready', actions); - } - }); - -function transformFile(entry) { - specCount++; - - // itterate all of the specs within the file, should only be one - _.each(JSON.parse(entry.data), function (def, name) { - //camelcase the name - name = _.map(name.split('.'), _.camelCase).join('.'); - - var steps = name.split('.'); - - function transformParamKeys(note, param, key) { - var cmlKey = _.camelCase(key); - if (cmlKey !== key) { - param.name = key; - } - note[cmlKey] = param; - } - - def.url.params = _.transform(def.url.params, transformParamKeys, {}); - def.url.parts = _.transform(def.url.parts, transformParamKeys, {}); - - var allParams = _.extend({}, def.url.params, def.url.parts); - var spec = { - name: name, - methods: _.map(def.methods, function (m) { return m.toUpperCase(); }), - params: def.url.params, - body: def.body || null, - path2lib: _.repeat('../', steps.length + 1) + 'lib/' - }; - - if (def.body && def.body.requires) { - spec.needBody = true; - } - - if (usesBulkBodyRE.test(name)) { - spec.bulkBody = true; - } - - if (castExistsRE.test(name)) { - spec.castExists = true; - } - - var urls = _.difference(def.url.paths, aliases[name]); - urls = _.map(urls, function (url) { - var optionalVars = {}; - var requiredVars = {}; - var param; - var name; - var target; - var match; - - if (url.charAt(0) !== '/') { - url = '/' + url; - } - - while (match = urlParamRE.exec(url)) { - name = _.camelCase(match[1]); - param = def.url.parts[name] || {}; - target = (param.required || !param.default) ? requiredVars : optionalVars; - target[name] = _.omit(param, 'required', 'description', 'name'); - } - - return _.omit({ - fmt: url.replace(urlParamRE, function (full, match) { - return '<%=' + _.camelCase(match) + '%>'; - }), - opt: _.size(optionalVars) ? optionalVars : null, - req: _.size(requiredVars) ? requiredVars : null, - sortOrder: _.size(requiredVars) * -1 - }, function (v) { - return !v; - }); - }); - - if (urls.length > 1) { - spec.urls = _.map(_.sortBy(urls, 'sortOrder'), function (url) { - return _.omit(url, 'sortOrder'); - }); - } else { - spec.url = urls[0]; - } - - spec.params = _.transform(spec.params, function (note, param, name) { - // param.name = name; - note[name] = _.pick(param, [ - 'type', 'default', 'options', 'required', 'name' - ]); - }, {}); - - if (_.size(spec.params) === 0) { - delete spec.params; - } - - // escape method names with "special" keywords - var location = spec.name.split('.').join('.prototype.') - .replace(/(^|\.)(delete|default)(\.|$)/g, '[\'$2\']'); - - var action = { - _methods: spec.methods, - spec: _.pick(spec, [ - 'params', - 'url', - 'urls', - 'needBody', - 'bulkBody', - 'castExists', - 'castNotFound' - ]), - location: location, - docUrl: def.documentation, - name: spec.name, - allParams: allParams - }; - - function hasMethod(/* ...methods */) { - for (var i = 0; i < arguments.length; i++) { - if (~action._methods.indexOf(arguments[i])) { - continue; - } else { - return false; - } - } - return true; - } - function methodsAre(/* ...methods */) { - return hasMethod.apply(null, arguments) && arguments.length === action._methods.length; - } - - var method; - - if (action._methods.length === 1) { - method = action._methods[0]; - } else { - // we need to define what the default method(s) will be - if (hasMethod('DELETE', 'POST')) { - method = 'POST'; - } - else if (methodsAre('DELETE')) { - method = 'DELETE'; - } - else if (methodsAre('POST', 'PUT')) { - method = action.name.match(/put/i) ? 'PUT' : 'POST'; - } - else if (methodsAre('GET', 'POST')) { - method = 'POST'; - } - else if (methodsAre('GET', 'HEAD')) { - if (action.spec.castExists) { - method = 'HEAD'; - } else { - method = 'GET'; - } - } - } - - if (method) { - if (method !== 'GET') { - action.spec.method = method; - } - } else { - throw new Error('unable to pick a method for ' + JSON.stringify(action, null, ' ')); - } - - if (action.name === 'create') { - action.proxy = 'index'; - action.transformBody = 'params.op_type = \'create\';'; - } - - if (actions.push(action) === specCount && doneParsing) { - module.exports.emit('ready', actions); - } - }); -} - -/** - * un-comment to print out the default method for any action that has multiple options - */ -module.exports = new EventEmitter(); -// module.exports.on('ready', function (actions) { -// var longestName = 0; -// var reports = { -// multi_methods: [], -// get_with_body: [] -// }; -// actions.forEach(function (action) { -// var name; - -// // console.log(action); -// if (action._methods.length > 1) { -// name = action.name + ' (' + action._methods.join('/') + ')'; -// longestName = Math.max(name.length, longestName); -// reports.multi_methods.push([name, action.spec.method || 'GET', action.docUrl]); -// } - -// if (action._methods.length === 1 && action._methods[0] === 'GET' && action.body) { -// name = action.name + ' (' + action._methods.join('/') + ')'; -// longestName = Math.max(name.length, longestName); -// reports.get_with_body.push([name, action.spec.method || 'GET', action.docUrl]); -// } -// }); - -// Object.keys(reports).forEach(function (key) { -// console.log('\n' + key); -// if (reports[key].length) { -// reports[key].forEach(function (line) { -// var name = line[0]; -// var def = line[1]; -// var docUrl = line[2]; -// var spacing = (new Array(longestName - name.length + 1)).join(' '); -// console.log(name + spacing + ' [' + def + (def.length === 3 ? ' ' : '') + '] -> ' + docUrl); -// }); -// } else { -// console.log('--nada--'); -// } -// console.log('\n'); -// }); -// }); diff --git a/scripts/generate/js_api/aliases.js b/scripts/generate/js_api/aliases.js deleted file mode 100644 index 667b76099..000000000 --- a/scripts/generate/js_api/aliases.js +++ /dev/null @@ -1,63 +0,0 @@ -module.exports = { - 'cluster.nodeHotThreads': [ - '/_cluster/nodes/hotthreads', - '/_cluster/nodes/hot_threads', - '/_nodes/hot_threads', - '/_cluster/nodes/{node_id}/hotthreads', - '/_cluster/nodes/{node_id}/hot_threads', - '/_nodes/{node_id}/hot_threads' - ], - 'cluster.nodeInfo': [ - '/_cluster/nodes', - '/_nodes/settings', - '/_nodes/os', - '/_nodes/process', - '/_nodes/jvm', - '/_nodes/thread_pool', - '/_nodes/network', - '/_nodes/transport', - '/_nodes/http', - '/_nodes/plugin', - '/_cluster/nodes/{node_id}', - '/_nodes/{node_id}/settings', - '/_nodes/{node_id}/os', - '/_nodes/{node_id}/process', - '/_nodes/{node_id}/jvm', - '/_nodes/{node_id}/thread_pool', - '/_nodes/{node_id}/network', - '/_nodes/{node_id}/transport', - '/_nodes/{node_id}/http', - '/_nodes/{node_id}/plugin' - ], - 'cluster.nodeShutdown': [ - '/_cluster/nodes/_shutdown' - ], - 'cluster.nodeStats': [ - '/_cluster/nodes/stats', - '/_nodes/stats/{metric_family}', - '/_nodes/stats/indices/{metric}/{fields}', - '/_cluster/nodes/{node_id}/stats', - '/_nodes/{node_id}/stats/{metric_family}', - '/_nodes/{node_id}/stats/indices/{metric}/{fields}' - ], - 'get': [ - '/{index}/{type}/{id}/_source' - ], - 'indices.deleteMapping': [ - '/{index}/{type}/_mapping' - ], - 'indices.stats': [ - '_stats/{metric_family}', - '/_stats/indexing', - '/_stats/indexing/{indexing_types}', - '/_stats/search/{search_groups}', - '/_stats/fielddata/{fields}', - '/{index}/_stats/{metric_family}', - '/{index}/_stats/indexing', - '/{index}/_stats/search/{search_groups}', - '/{index}/_stats/fielddata/{fields}' - ], - 'search': [ - '/_search' - ] -}; diff --git a/scripts/generate/js_api/generate.js b/scripts/generate/js_api/generate.js deleted file mode 100644 index beea98a9f..000000000 --- a/scripts/generate/js_api/generate.js +++ /dev/null @@ -1,59 +0,0 @@ -module.exports = function (force) { - var _ = require('../../../src/lib/utils'); - var fs = require('fs'); - var templates = require('./templates'); - var restSpecUpdated = require('../../rest_spec_updated'); - - var outputPath = _.joinPath(__dirname, '../../../src/lib/api.js'); - var docOutputDir = _.joinPath(__dirname, '../../../docs/'); - - function download() { - require('./actions').on('ready', function (actions) { - var namespaces = _.filter(_.map(actions, function (action) { - if (~action.location.indexOf('.')) { - var path = action.location.split('.').slice(0, -1); - _.pull(path, 'prototype'); - return path.join('.'); - } - })); - - // seperate the proxy actions - var groups = _.groupBy(actions, function (action) { - return action.proxy ? 'proxies' : 'normal'; - }); - - fs.unlink(outputPath, function () { - console.log('writing', actions.length, 'api actions to', outputPath); - - fs.writeFileSync(outputPath, templates.apiFile({ - actions: groups.normal, - proxies: groups.proxies, - namespaces: _.unique(namespaces.sort(), true) - })); - - if (!fs.existsSync(docOutputDir)) { - fs.mkdirSync(docOutputDir); - } - - fs.writeFileSync(docOutputDir + '_method_list.jade', templates.apiMethodList({ - actions: actions - })); - - fs.writeFileSync(docOutputDir + '_methods.jade', templates.apiMethods({ - actions: actions - })); - - }); - }); - } - - if (force) { - download(); - } else { - restSpecUpdated(function (err, updated) { - if (err || updated) { - download(); - } - }); - } -}; \ No newline at end of file diff --git a/scripts/generate/js_api/index.js b/scripts/generate/js_api/index.js deleted file mode 100644 index 87e34c605..000000000 --- a/scripts/generate/js_api/index.js +++ /dev/null @@ -1 +0,0 @@ -require('./generate')(require('../_force')); \ No newline at end of file diff --git a/scripts/generate/logs/index.js b/scripts/generate/logs/index.js index 099400b03..6defce53d 100644 --- a/scripts/generate/logs/index.js +++ b/scripts/generate/logs/index.js @@ -19,9 +19,6 @@ var argv = require('optimist') }) .argv; -// Error.stackTraceLimit = Infinity; -// process.exit(); - var es = require('../../../src/elasticsearch'); var _ = require('../../../src/lib/utils'); var async = require('async'); diff --git a/scripts/generate/js_api/templates/api_file.tmpl b/scripts/generate/templates/api_file.tmpl similarity index 99% rename from scripts/generate/js_api/templates/api_file.tmpl rename to scripts/generate/templates/api_file.tmpl index cffffac5d..ad8bb39f1 100644 --- a/scripts/generate/js_api/templates/api_file.tmpl +++ b/scripts/generate/templates/api_file.tmpl @@ -22,6 +22,7 @@ api.<%= namespace %> = function <%= className %>(transport) { }); _.each(proxies, function (action) {%> + <%= partials.client_action_proxy(action) %><% }); -%> +%> \ No newline at end of file diff --git a/scripts/generate/js_api/templates/api_method_list.tmpl b/scripts/generate/templates/api_method_list.tmpl similarity index 100% rename from scripts/generate/js_api/templates/api_method_list.tmpl rename to scripts/generate/templates/api_method_list.tmpl diff --git a/scripts/generate/js_api/templates/api_methods.tmpl b/scripts/generate/templates/api_methods.tmpl similarity index 100% rename from scripts/generate/js_api/templates/api_methods.tmpl rename to scripts/generate/templates/api_methods.tmpl diff --git a/scripts/generate/js_api/templates/client_action.tmpl b/scripts/generate/templates/client_action.tmpl similarity index 94% rename from scripts/generate/js_api/templates/client_action.tmpl rename to scripts/generate/templates/client_action.tmpl index 81477174b..4a80b7f0f 100644 --- a/scripts/generate/js_api/templates/client_action.tmpl +++ b/scripts/generate/templates/client_action.tmpl @@ -9,4 +9,4 @@ _.each(allParams, function(param, paramName) { %> } %><% }) %> */ -api<%= (location[0] === '[' ? '' : '.') + location %> = ca(<%= stringify(spec, true) %>); +api<%= (location[0] === '[' ? '' : '.') + location %> = ca(<%= stringify(spec, true) %>); \ No newline at end of file diff --git a/scripts/generate/js_api/templates/client_action_proxy.tmpl b/scripts/generate/templates/client_action_proxy.tmpl similarity index 99% rename from scripts/generate/js_api/templates/client_action_proxy.tmpl rename to scripts/generate/templates/client_action_proxy.tmpl index d708f1401..f5dd98929 100644 --- a/scripts/generate/js_api/templates/client_action_proxy.tmpl +++ b/scripts/generate/templates/client_action_proxy.tmpl @@ -16,4 +16,4 @@ if (typeof transformBody === 'string') { %>, { } }<% } -%>); +%>); \ No newline at end of file diff --git a/scripts/generate/js_api/templates/index.js b/scripts/generate/templates/index.js similarity index 98% rename from scripts/generate/js_api/templates/index.js rename to scripts/generate/templates/index.js index ce1ffab75..f1ba48c40 100644 --- a/scripts/generate/js_api/templates/index.js +++ b/scripts/generate/templates/index.js @@ -1,5 +1,5 @@ -var _ = require('../../../../src/lib/utils'); +var _ = require('../../../src/lib/utils'); var fs = require('fs'); var path = require('path'); diff --git a/scripts/generate/yaml_tests.js b/scripts/generate/yaml_tests.js new file mode 100644 index 000000000..9ac0bc8f6 --- /dev/null +++ b/scripts/generate/yaml_tests.js @@ -0,0 +1,46 @@ +module.exports = function (done) { + + /** + * Creates a JSON version of the YAML test suite that can be simply bundled for use in the browser. + */ + var jsYaml = require('js-yaml'); + var fs = require('relative-fs').relativeTo(__dirname); + var async = require('async'); + var path = require('path'); + var tests = {}; // populated in readYamlTests + + // generate the yaml tests + async.series([ + readYamlTests, + writeYamlTests + ], done); + + function readYamlTests(done) { + var testDir = path.join(__dirname, '../../src/rest-api-spec/test/'); + + function readDirectories(dir) { + fs.readdirSync(dir).forEach(function (filename) { + var filePath = path.join(dir, filename); + var stat = fs.statSync(filePath); + if (stat.isDirectory()) { + readDirectories(filePath); + } else if (filename.match(/\.yaml$/)) { + var file = tests[path.relative(testDir, filePath)] = []; + jsYaml.loadAll(fs.readFileSync(filePath, 'utf8'), function (doc) { + file.push(doc); + }); + } + }); + } + + readDirectories(testDir); + done(); + } + + function writeYamlTests(done) { + var testFile = require('path').resolve(__dirname, '../../test/integration/yaml_suite/yaml_tests.json'); + fs.writeFileSync(testFile, JSON.stringify(tests, null, ' '), 'utf8'); + console.log('wrote YAML tests as JSON to', testFile); + done(); + } +}; \ No newline at end of file diff --git a/scripts/generate/yaml_tests/README.md b/scripts/generate/yaml_tests/README.md deleted file mode 100644 index c4ef05746..000000000 --- a/scripts/generate/yaml_tests/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Download the yaml suite's test specs, runs before each run of the suite to ensure they are up to date. - -run by calling `npm run generate`. Force it to update, even if their has not been a new commit, but calling with `--force` or `-f` diff --git a/scripts/generate/yaml_tests/generate.js b/scripts/generate/yaml_tests/generate.js deleted file mode 100644 index 75103c2e0..000000000 --- a/scripts/generate/yaml_tests/generate.js +++ /dev/null @@ -1,44 +0,0 @@ -module.exports = function (force) { - /** - * Check that the test directory exists, and is less than a day old, otherwise wipe it out - * and rebuild - */ - var fs = require('fs'); - var path = require('path'); - var jsYaml = require('js-yaml'); - var spec = require('../../get_spec'); - var restSpecUpdated = require('../../rest_spec_updated'); - - var testFile = path.resolve(__dirname, '../../../test/integration/yaml_suite/yaml_tests.json'); - - function download() { - - var tests = {}; - - fs.unlink(testFile, function () { - spec.get('test/**/*.yaml') - .on('entry', function (entry) { - var filename = path.relative('test', entry.path); - var file = tests[filename] = []; - jsYaml.loadAll(entry.data, function (doc) { - file.push(doc); - }); - }) - .on('end', function () { - fs.writeFileSync(testFile, JSON.stringify(tests, null, ' '), 'utf8'); - console.log('download yaml tests to', testFile); - }); - }); - } - - - if (force) { - download(); - } else { - restSpecUpdated(function (err, updated) { - if (err || updated) { - download(); - } - }); - } -}; \ No newline at end of file diff --git a/scripts/generate/yaml_tests/index.js b/scripts/generate/yaml_tests/index.js deleted file mode 100644 index 87e34c605..000000000 --- a/scripts/generate/yaml_tests/index.js +++ /dev/null @@ -1 +0,0 @@ -require('./generate')(require('../_force')); \ No newline at end of file diff --git a/scripts/jenkins.sh b/scripts/jenkins.sh new file mode 100755 index 000000000..1cbcd1660 --- /dev/null +++ b/scripts/jenkins.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +echo "generate the latest version of the yaml-tests" +node scripts/generate/ --no-api 2>&1 > /dev/null + +echo "\n--- unit ---" +./node_modules/.bin/mocha test/unit/test_*.js \ + --require should \ + --reporter ../../../test/utils/jenkins-reporter.js \ + 2> test-output-node-unit.xml + +echo "\n--- integration ---" +# run the integration tests +./node_modules/.bin/mocha test/integration/yaml_suite/index.js \ + --require should \ + --host localhost \ + --port $es_port \ + --reporter ../../../test/utils/jenkins-reporter.js \ + 2> test-output-node-integration.xml \ No newline at end of file diff --git a/scripts/run_browser_integration_suite/index.js b/scripts/run_browser_integration_suite/index.js index 1cf6c22f0..20959376b 100644 --- a/scripts/run_browser_integration_suite/index.js +++ b/scripts/run_browser_integration_suite/index.js @@ -1,16 +1,9 @@ var server = require('./server'); -var child_process = require('child_process'); var _ = require('lodash'); var open = require('open'); -var fs = require('fs'); -var path = require('path'); var async = require('async'); var chalk = require('chalk'); -var yamlTestSourceFile = path.join(__dirname, '../../test/integration/yaml_suite/index.js'); -var yamlTestBundleFile = path.join(__dirname, '../../test/integration/browser_yaml_suite/yaml_tests.js'); -var clientEntryFile = path.join(__dirname, '../../src/elasticsearch.js'); - var browserAppNames = _.transform({ safari: { darwin: 'Safari' @@ -79,102 +72,45 @@ if (badKeys.length) { console.log('opening browser suite in', server.browsers); } +server.on('tests done', function (report) { + var reports = []; + var success = true; + _.each(report, function (testSucceeded, browser) { + var msg = browser + ':' + (success ? '✔︎' : '⚑'); + if (testSucceeded) { + msg = chalk.green(msg); + } else { + msg = chalk.red(msg); + success = false; + } + reports.push(' - ' + msg); + }); + console.log('test completed!\n', reports.join('\n')); + process.exit(success ? 0 : 1); +}); + async.series([ function (done) { - fs.exists('dist', function (yes) { - if (!argv.forceGen && yes) { - done(); - return; - } - - console.log('generating client with "grunt build"'); - child_process.spawn('npm', ['run', 'build_clients'], { - stdio: 'inherit' - }).on('close', function (status) { - done(status && 'grunt closed with a status code of ' + status + '. aborting.'); - }); + server.listen(0, function () { + server.port = server.address().port; + console.log('server listening on port', server.port); + done(); }); }, function (done) { - fs.exists(yamlTestBundleFile, function (yes) { - if (!argv.forceGen && yes) { - done(); - return; - } + async.eachSeries(_.clone(server.browsers), function (browser, browserDone) { + open('http://localhost:' + server.port + + '?es_hostname=' + encodeURIComponent(argv.host) + + '&es_port=' + encodeURIComponent(argv.port) + + '&browser=' + encodeURIComponent(browser), browserAppNames[browser]); - console.log('generating browser\'s yaml_tests.js bundle'); - var b = require('browserify')(); - - b.add(yamlTestSourceFile); - var bundle = b.bundle({ - external: [ - 'optimist' - ], - ignore: [ - 'test/integration/yaml_suite/reporter', - clientEntryFile - ] - }); - var file = fs.createWriteStream(yamlTestBundleFile, { - flags: 'w', - encoding: 'utf8', - mode: 0666 - }); - - bundle.pipe(file); - - file.once('error', function (err) { - done(err); - }); - - bundle.once('error', function (err) { - done(err); - }); - - bundle.once('end', function () { - done(); - }); - - }); + server.once('browser complete', _.bind(browserDone, null, null)); + }, done); } ], function (err) { if (err) { console.error(err); process.exit(1); - } else { - server.listen(0, function () { - var port = server.address().port; - console.log('server listening on port', port); - - async.eachSeries(_.clone(server.browsers), function (browser, done) { - open('http://localhost:' + port + - '?es_hostname=' + encodeURIComponent(argv.host) + - '&es_port=' + encodeURIComponent(argv.port) + - '&browser=' + encodeURIComponent(browser), browserAppNames[browser]); - - server.once('browser complete', function () { - done(); - }); - }); - }); - - server.on('tests done', function (report) { - var reports = []; - var success = true; - _.each(report, function (testSucceeded, browser) { - var msg = browser + ':' + (success ? '✔︎' : '⚑'); - if (testSucceeded) { - msg = chalk.green(msg); - } else { - msg = chalk.red(msg); - success = false; - } - reports.push(' - ' + msg); - }); - console.log('test completed!\n', reports.join('\n')); - process.exit(success ? 0 : 1); - }); } - }); diff --git a/scripts/run_browser_integration_suite/server.js b/scripts/run_browser_integration_suite/server.js index f52bde59e..01b491db2 100644 --- a/scripts/run_browser_integration_suite/server.js +++ b/scripts/run_browser_integration_suite/server.js @@ -4,7 +4,7 @@ var path = require('path'); var fs = require('fs'); var _ = require('lodash'); var chalk = require('chalk'); -var makeJUnitXml = require('../make_j_unit_xml'); +var makeJUnitXml = require('../../test/utils/make_j_unit_xml'); var docRoot = path.join(__dirname, '../../test/integration/browser_yaml_suite'); chalk.enabled = true; @@ -21,8 +21,14 @@ var server = http.createServer(function (req, resp) { req.filename = path.join(docRoot, req.uri); var end = resp.end; - resp.end = function () { - console.log(chalk[this.statusCode < 300 ? 'green' : 'red'](this.statusCode), req.uri); + resp.end = function (data) { + console.log( + chalk[this.statusCode < 300 ? 'green' : 'red'](this.statusCode), + req.uri, + '-', + Buffer.byteLength(data || ''), + 'bytes' + ); end.apply(resp, arguments); }; diff --git a/scripts/run_tests.js b/scripts/run_tests.js index b74cbe5c1..e1d63877f 100644 --- a/scripts/run_tests.js +++ b/scripts/run_tests.js @@ -1,7 +1,6 @@ var async = require('async'); var cp = require('child_process'); var chalk = require('chalk'); -var path = require('path'); var argv = require('optimist') .usage([ 'Runner for the Elasticsearch.js unit and integration tests in both node and the browser.', @@ -25,7 +24,7 @@ var argv = require('optimist') alias: 's' }, unit: { - default: true, + default: false, alias: 'u' }, integration: { @@ -44,10 +43,6 @@ var argv = require('optimist') default: '*', alias: 'b' }, - 'xml-output': { - default: true, - alias: 'x' - }, 'check-upstream': { default: false, description: 'check for remote updates to the yaml test suite' @@ -61,22 +56,17 @@ if (process.argv.indexOf('help') + process.argv.indexOf('--help') + process.argv if (process.env.npm_config_argv) { // when called by NPM - argv = argv.parse(JSON.parse(process.env.npm_config_argv).original); + argv = argv.parse([].concat(process.argv).concat(JSON.parse(process.env.npm_config_argv).original)); } else { - // when called by NPM - via `npm test` + // when called directly argv = argv.argv; } var commands = []; var command; -if (argv['just-browser']) { - argv.server = false; - argv.browsers = '*'; -} - if (argv['check-upstream']) { - command = ['node', 'scripts/generate/yaml_tests/index.js']; + command = ['node', 'scripts/generate']; if (argv.force) { command.push('--force'); } @@ -85,21 +75,20 @@ if (argv['check-upstream']) { if (argv.unit) { if (argv.server) { - commands.push(['mocha', 'test/unit/test_*.js', '--require should']); + commands.push(['./node_modules/.bin/mocha', 'test/unit/test_*.js', '--require should']); } if (argv.browsers) { - commands.push(['testling', '.']); + commands.push(['./node_modules/.bin/testling', '.']); } } if (argv.integration) { if (argv.server) { commands.push([ - 'mocha', + './node_modules/.bin/mocha', 'test/integration/yaml_suite/index.js', - '-b', + // '-b', '--require', 'should', - argv.x ? '--reporter' : '', argv.x ? path.join(__dirname, '../test/integration/yaml_suite/reporter.js') : '', '--host', argv.host, '--port', argv.port ].filter(Boolean)); @@ -125,6 +114,7 @@ if (commands.length) { async.forEachSeries(commands, function (args, done) { var command = args.shift(); console.log(chalk.gray.bold('\n\n' + '# ' + command + ' ' + args.join(' '))); + proc = cp.spawn(command, args, { stdio: 'inherit' }); diff --git a/src/elasticsearch.angular.js b/src/elasticsearch.angular.js index 8ac011bc9..bbff6cd99 100644 --- a/src/elasticsearch.angular.js +++ b/src/elasticsearch.angular.js @@ -29,4 +29,5 @@ angular.module('elasticsearch.client', []) factory.ConnectionPool = require('./lib/connection_pool'); factory.Transport = require('./lib/transport'); + return factory; }]); diff --git a/src/lib/api.js b/src/lib/api.js index 1d884fd7f..16e276975 100644 --- a/src/lib/api.js +++ b/src/lib/api.js @@ -72,7 +72,6 @@ api.bulk = ca({ method: 'POST' }); - /** * Perform a [clearScroll](http://www.elasticsearch.org/guide/reference/api/search/scroll/) request * @@ -92,7 +91,6 @@ api.clearScroll = ca({ method: 'DELETE' }); - api.cluster = function ClusterNS(transport) { this.transport = transport; }; @@ -108,7 +106,6 @@ api.cluster.prototype.getSettings = ca({ } }); - /** * Perform a [cluster.health](http://elasticsearch.org/guide/reference/api/admin-cluster-health/) request * @@ -182,7 +179,6 @@ api.cluster.prototype.health = ca({ ] }); - /** * Perform a [cluster.nodeHotThreads](http://www.elasticsearch.org/guide/reference/api/admin-cluster-nodes-hot-threads/) request * @@ -228,7 +224,6 @@ api.cluster.prototype.nodeHotThreads = ca({ ] }); - /** * Perform a [cluster.nodeInfo](http://elasticsearch.org/guide/reference/api/admin-cluster-nodes-info/) request * @@ -302,7 +297,6 @@ api.cluster.prototype.nodeInfo = ca({ ] }); - /** * Perform a [cluster.nodeShutdown](http://elasticsearch.org/guide/reference/api/admin-cluster-nodes-shutdown/) request * @@ -336,7 +330,6 @@ api.cluster.prototype.nodeShutdown = ca({ method: 'POST' }); - /** * Perform a [cluster.nodeStats](http://elasticsearch.org/guide/reference/api/admin-cluster-nodes-stats/) request * @@ -412,7 +405,6 @@ api.cluster.prototype.nodeStats = ca({ ] }); - /** * Perform a [cluster.putSettings](http://elasticsearch.org/guide/reference/api/admin-cluster-update-settings/) request * @@ -425,7 +417,6 @@ api.cluster.prototype.putSettings = ca({ method: 'PUT' }); - /** * Perform a [cluster.reroute](http://elasticsearch.org/guide/reference/api/admin-cluster-reroute/) request * @@ -450,7 +441,6 @@ api.cluster.prototype.reroute = ca({ method: 'POST' }); - /** * Perform a [cluster.state](http://elasticsearch.org/guide/reference/api/admin-cluster-state/) request * @@ -503,7 +493,6 @@ api.cluster.prototype.state = ca({ } }); - /** * Perform a [count](http://elasticsearch.org/guide/reference/api/count/) request * @@ -568,7 +557,6 @@ api.count = ca({ method: 'POST' }); - /** * Perform a [delete](http://elasticsearch.org/guide/reference/api/delete/) request * @@ -645,7 +633,6 @@ api['delete'] = ca({ method: 'DELETE' }); - /** * Perform a [deleteByQuery](http://www.elasticsearch.org/guide/reference/api/delete-by-query/) request * @@ -742,7 +729,6 @@ api.deleteByQuery = ca({ method: 'DELETE' }); - /** * Perform a [exists](http://elasticsearch.org/guide/reference/api/get/) request * @@ -796,7 +782,6 @@ api.exists = ca({ method: 'HEAD' }); - /** * Perform a [explain](http://elasticsearch.org/guide/reference/api/explain/) request * @@ -896,7 +881,6 @@ api.explain = ca({ method: 'POST' }); - /** * Perform a [get](http://elasticsearch.org/guide/reference/api/get/) request * @@ -966,7 +950,6 @@ api.get = ca({ } }); - /** * Perform a [getSource](http://elasticsearch.org/guide/reference/api/get/) request * @@ -1026,7 +1009,6 @@ api.getSource = ca({ } }); - /** * Perform a [index](http://elasticsearch.org/guide/reference/api/index_/) request * @@ -1137,7 +1119,6 @@ api.index = ca({ method: 'POST' }); - api.indices = function IndicesNS(transport) { this.transport = transport; }; @@ -1204,7 +1185,6 @@ api.indices.prototype.analyze = ca({ method: 'POST' }); - /** * Perform a [indices.clearCache](http://www.elasticsearch.org/guide/reference/api/admin-indices-clearcache/) request * @@ -1283,7 +1263,6 @@ api.indices.prototype.clearCache = ca({ method: 'POST' }); - /** * Perform a [indices.close](http://www.elasticsearch.org/guide/reference/api/admin-indices-open-close/) request * @@ -1314,7 +1293,6 @@ api.indices.prototype.close = ca({ method: 'POST' }); - /** * Perform a [indices.create](http://www.elasticsearch.org/guide/reference/api/admin-indices-create-index/) request * @@ -1345,7 +1323,6 @@ api.indices.prototype.create = ca({ method: 'POST' }); - /** * Perform a [indices.delete](http://www.elasticsearch.org/guide/reference/api/admin-indices-delete-index/) request * @@ -1380,7 +1357,6 @@ api.indices.prototype['delete'] = ca({ method: 'DELETE' }); - /** * Perform a [indices.deleteAlias](http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases/) request * @@ -1415,7 +1391,6 @@ api.indices.prototype.deleteAlias = ca({ method: 'DELETE' }); - /** * Perform a [indices.deleteMapping](http://www.elasticsearch.org/guide/reference/api/admin-indices-delete-mapping/) request * @@ -1446,7 +1421,6 @@ api.indices.prototype.deleteMapping = ca({ method: 'DELETE' }); - /** * Perform a [indices.deleteTemplate](http://www.elasticsearch.org/guide/reference/api/admin-indices-templates/) request * @@ -1477,7 +1451,6 @@ api.indices.prototype.deleteTemplate = ca({ method: 'DELETE' }); - /** * Perform a [indices.deleteWarmer](http://www.elasticsearch.org/guide/reference/api/admin-indices-warmers/) request * @@ -1532,7 +1505,6 @@ api.indices.prototype.deleteWarmer = ca({ method: 'DELETE' }); - /** * Perform a [indices.exists](http://www.elasticsearch.org/guide/reference/api/admin-indices-indices-exists/) request * @@ -1553,7 +1525,6 @@ api.indices.prototype.exists = ca({ method: 'HEAD' }); - /** * Perform a [indices.existsAlias](http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases/) request * @@ -1599,7 +1570,6 @@ api.indices.prototype.existsAlias = ca({ method: 'HEAD' }); - /** * Perform a [indices.existsType](http://www.elasticsearch.org/guide/reference/api/admin-indices-types-exists/) request * @@ -1636,7 +1606,6 @@ api.indices.prototype.existsType = ca({ method: 'HEAD' }); - /** * Perform a [indices.flush](http://www.elasticsearch.org/guide/reference/api/admin-indices-flush/) request * @@ -1684,7 +1653,6 @@ api.indices.prototype.flush = ca({ method: 'POST' }); - /** * Perform a [indices.getAlias](http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases/) request * @@ -1728,7 +1696,6 @@ api.indices.prototype.getAlias = ca({ ] }); - /** * Perform a [indices.getAliases](http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases/) request * @@ -1757,7 +1724,6 @@ api.indices.prototype.getAliases = ca({ ] }); - /** * Perform a [indices.getFieldMapping](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-get-field-mapping.html) request * @@ -1811,7 +1777,6 @@ api.indices.prototype.getFieldMapping = ca({ ] }); - /** * Perform a [indices.getMapping](http://www.elasticsearch.org/guide/reference/api/admin-indices-get-mapping/) request * @@ -1846,7 +1811,6 @@ api.indices.prototype.getMapping = ca({ ] }); - /** * Perform a [indices.getSettings](http://www.elasticsearch.org/guide/reference/api/admin-indices-get-settings/) request * @@ -1869,7 +1833,6 @@ api.indices.prototype.getSettings = ca({ ] }); - /** * Perform a [indices.getTemplate](http://www.elasticsearch.org/guide/reference/api/admin-indices-templates/) request * @@ -1892,7 +1855,6 @@ api.indices.prototype.getTemplate = ca({ ] }); - /** * Perform a [indices.getWarmer](http://www.elasticsearch.org/guide/reference/api/admin-indices-warmers/) request * @@ -1939,7 +1901,6 @@ api.indices.prototype.getWarmer = ca({ ] }); - /** * Perform a [indices.open](http://www.elasticsearch.org/guide/reference/api/admin-indices-open-close/) request * @@ -1970,7 +1931,6 @@ api.indices.prototype.open = ca({ method: 'POST' }); - /** * Perform a [indices.optimize](http://www.elasticsearch.org/guide/reference/api/admin-indices-optimize/) request * @@ -2033,7 +1993,6 @@ api.indices.prototype.optimize = ca({ method: 'POST' }); - /** * Perform a [indices.putAlias](http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases/) request * @@ -2088,7 +2047,6 @@ api.indices.prototype.putAlias = ca({ method: 'PUT' }); - /** * Perform a [indices.putMapping](http://www.elasticsearch.org/guide/reference/api/admin-indices-put-mapping/) request * @@ -2128,7 +2086,6 @@ api.indices.prototype.putMapping = ca({ method: 'PUT' }); - /** * Perform a [indices.putSettings](http://www.elasticsearch.org/guide/reference/api/admin-indices-update-settings/) request * @@ -2159,7 +2116,6 @@ api.indices.prototype.putSettings = ca({ method: 'PUT' }); - /** * Perform a [indices.putTemplate](http://www.elasticsearch.org/guide/reference/api/admin-indices-templates/) request * @@ -2194,7 +2150,6 @@ api.indices.prototype.putTemplate = ca({ method: 'PUT' }); - /** * Perform a [indices.putWarmer](http://www.elasticsearch.org/guide/reference/api/admin-indices-warmers/) request * @@ -2241,7 +2196,6 @@ api.indices.prototype.putWarmer = ca({ method: 'PUT' }); - /** * Perform a [indices.refresh](http://www.elasticsearch.org/guide/reference/api/admin-indices-refresh/) request * @@ -2281,7 +2235,6 @@ api.indices.prototype.refresh = ca({ method: 'POST' }); - /** * Perform a [indices.segments](http://elasticsearch.org/guide/reference/api/admin-indices-segments/) request * @@ -2320,7 +2273,6 @@ api.indices.prototype.segments = ca({ ] }); - /** * Perform a [indices.snapshotIndex](http://www.elasticsearch.org/guide/reference/api/admin-indices-gateway-snapshot/) request * @@ -2356,7 +2308,6 @@ api.indices.prototype.snapshotIndex = ca({ method: 'POST' }); - /** * Perform a [indices.stats](http://elasticsearch.org/guide/reference/api/admin-indices-stats/) request * @@ -2474,7 +2425,6 @@ api.indices.prototype.stats = ca({ ] }); - /** * Perform a [indices.status](http://elasticsearch.org/guide/reference/api/admin-indices-status/) request * @@ -2521,7 +2471,6 @@ api.indices.prototype.status = ca({ ] }); - /** * Perform a [indices.updateAliases](http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases/) request * @@ -2546,7 +2495,6 @@ api.indices.prototype.updateAliases = ca({ method: 'POST' }); - /** * Perform a [indices.validateQuery](http://www.elasticsearch.org/guide/reference/api/validate/) request * @@ -2610,7 +2558,6 @@ api.indices.prototype.validateQuery = ca({ method: 'POST' }); - /** * Perform a [info](http://elasticsearch.org/guide/) request * @@ -2622,7 +2569,6 @@ api.info = ca({ } }); - /** * Perform a [mget](http://elasticsearch.org/guide/reference/api/multi-get/) request * @@ -2690,7 +2636,6 @@ api.mget = ca({ method: 'POST' }); - /** * Perform a [mlt](http://elasticsearch.org/guide/reference/api/more-like-this/) request * @@ -2814,7 +2759,6 @@ api.mlt = ca({ method: 'POST' }); - /** * Perform a [msearch](http://www.elasticsearch.org/guide/reference/api/multi-search/) request * @@ -2866,7 +2810,6 @@ api.msearch = ca({ method: 'POST' }); - /** * Perform a [percolate](http://elasticsearch.org/guide/reference/api/percolate/) request * @@ -2897,7 +2840,6 @@ api.percolate = ca({ method: 'POST' }); - /** * Perform a [scroll](http://www.elasticsearch.org/guide/reference/api/search/scroll/) request * @@ -2931,7 +2873,6 @@ api.scroll = ca({ method: 'POST' }); - /** * Perform a [search](http://www.elasticsearch.org/guide/reference/api/search/) request * @@ -3122,7 +3063,6 @@ api.search = ca({ method: 'POST' }); - /** * Perform a [suggest](http://elasticsearch.org/guide/reference/api/search/suggest/) request * @@ -3170,7 +3110,6 @@ api.suggest = ca({ method: 'POST' }); - /** * Perform a [update](http://elasticsearch.org/guide/reference/api/update/) request * @@ -3297,5 +3236,4 @@ api.create = ca.proxy(api.index, { transform: function (params) { params.op_type = 'create'; } -}); - +}); \ No newline at end of file diff --git a/src/lib/connectors/angular.js b/src/lib/connectors/angular.js index 4ae0a4af2..7644a1a1f 100644 --- a/src/lib/connectors/angular.js +++ b/src/lib/connectors/angular.js @@ -24,7 +24,7 @@ AngularConnector.prototype.request = function (params, cb) { cache: false, timeout: abort.promise }).then(function (response) { - cb(null, response.data, response.status); + cb(null, response.data, response.status, response.headers); }, function (err) { cb(new ConnectionFault(err.message)); }); diff --git a/src/lib/connectors/http.js b/src/lib/connectors/http.js index 6a55329a6..6622803c4 100644 --- a/src/lib/connectors/http.js +++ b/src/lib/connectors/http.js @@ -68,6 +68,10 @@ HttpConnector.prototype.makeReqParams = function (params) { agent: this.agent }; + if (!reqParams.path) { + reqParams.path = '/'; + } + var query = this.host.query ? _.clone(this.host.query) : {}; if (params.query) { @@ -87,6 +91,7 @@ HttpConnector.prototype.request = function (params, cb) { var request; var response; var status = 0; + var headers; var log = this.log; var reqParams = this.makeReqParams(params); @@ -116,6 +121,7 @@ HttpConnector.prototype.request = function (params, cb) { request = this.hand.request(reqParams, function (_incoming) { incoming = _incoming; status = incoming.statusCode; + headers = incoming.headers; incoming.setEncoding('utf8'); response = ''; diff --git a/src/lib/connectors/xhr.js b/src/lib/connectors/xhr.js index ed907f0d8..7c23a714f 100644 --- a/src/lib/connectors/xhr.js +++ b/src/lib/connectors/xhr.js @@ -55,9 +55,9 @@ XhrConnector.prototype.request = function (params, cb) { var async = params.async === false ? false : asyncDefault; if (params.auth) { - xhr.open(params.method, url, async, params.auth.user, params.auth.pass); + xhr.open(params.method || 'GET', url, async, params.auth.user, params.auth.pass); } else { - xhr.open(params.method, url, async); + xhr.open(params.method || 'GET', url, async); } xhr.onreadystatechange = function () { diff --git a/src/lib/log.js b/src/lib/log.js index 400875674..a5f0d014f 100755 --- a/src/lib/log.js +++ b/src/lib/log.js @@ -305,6 +305,7 @@ Log.prototype.trace = function (method, requestUrl, body, responseBody, response function prettyJSON(body) { try { + // TESTME return JSON.stringify(JSON.parse(body), null, ' ').replace(/'/g, '\\\''); } catch (e) { return body || ''; diff --git a/src/lib/transport.js b/src/lib/transport.js index f735615bb..f7ac40228 100644 --- a/src/lib/transport.js +++ b/src/lib/transport.js @@ -35,7 +35,7 @@ function Transport(config) { this.maxRetries = config.hasOwnProperty('maxRetries') ? config.maxRetries : 3; // setup requestTimeout default - this.requestTimeout = config.hasOwnProperty('requestTimeout') ? config.requestTimeout : 10000; + this.requestTimeout = config.hasOwnProperty('requestTimeout') ? config.requestTimeout : 30000; // randomizeHosts option var randomizeHosts = config.hasOwnProperty('randomizeHosts') ? !!config.randomizeHosts : true; @@ -98,7 +98,7 @@ Transport.prototype.request = function (params, cb) { var remainingRetries = this.maxRetries; var connection; // set in sendReqWithConnection var aborted = false; // several connector will respond with an error when the request is aborted - var requestAbort; // an abort function, returned by connection#request() + var requestAborter; // an abort function, returned by connection#request() var requestTimeout; // the general timeout for the total request (inculding all retries) var requestTimeoutId; // the id of the ^timeout var request; // the object returned to the user, might be a promise @@ -118,7 +118,7 @@ Transport.prototype.request = function (params, cb) { params.req = { method: params.method, - path: params.path, + path: params.path || '/', query: params.query, body: params.body, }; @@ -132,18 +132,20 @@ Transport.prototype.request = function (params, cb) { respond(err); } else if (_connection) { connection = _connection; - requestAbort = connection.request(params.req, checkRespForFailure); + requestAborter = connection.request(params.req, checkRespForFailure); } else { self.log.warning('No living connections'); respond(new errors.NoConnections()); } } - function checkRespForFailure(err, body, status) { + function checkRespForFailure(err, body, status, headers) { if (aborted) { return; } + requestAborter = void 0; + if (err) { connection.setStatus('dead'); if (remainingRetries) { @@ -156,21 +158,26 @@ Transport.prototype.request = function (params, cb) { } } else { self.log.info('Request complete'); - respond(void 0, body, status); + respond(void 0, body, status, headers); } } - function respond(err, body, status) { + function respond(err, body, status, headers) { if (aborted) { return; } + clearTimeout(requestTimeoutId); var parsedBody; if (!err && body) { - parsedBody = self.serializer.deserialize(body); - if (parsedBody == null) { - err = new errors.Serialization(); + if (!headers || headers['content-type'] === 'application/json') { + parsedBody = self.serializer.deserialize(body); + if (parsedBody == null) { + err = new errors.Serialization(); + } + } else { + parsedBody = body; } } @@ -222,8 +229,8 @@ Transport.prototype.request = function (params, cb) { aborted = true; remainingRetries = 0; clearTimeout(requestTimeoutId); - if (typeof requestAbort === 'function') { - requestAbort(); + if (typeof requestAborter === 'function') { + requestAborter(); } } diff --git a/src/rest-api-spec b/src/rest-api-spec new file mode 160000 index 000000000..bd7f4e3c5 --- /dev/null +++ b/src/rest-api-spec @@ -0,0 +1 @@ +Subproject commit bd7f4e3c5d00885ccced48ddb605779c036cd236 diff --git a/test/integration/browser_yaml_suite/yaml_tests.js b/test/integration/browser_yaml_suite/yaml_tests.js index 6b75e1db8..9e4656212 100644 --- a/test/integration/browser_yaml_suite/yaml_tests.js +++ b/test/integration/browser_yaml_suite/yaml_tests.js @@ -955,7 +955,9 @@ var process=require("__browserify_process");/*global setImmediate: false, setTim }()); -},{"__browserify_process":15}],2:[function(require,module,exports){ +},{"__browserify_process":14}],2:[function(require,module,exports){ + +},{}],3:[function(require,module,exports){ // @@ -1173,7 +1175,7 @@ if (typeof Object.getOwnPropertyDescriptor === 'function') { exports.getOwnPropertyDescriptor = valueObject; } -},{}],3:[function(require,module,exports){ +},{}],4:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -1490,13 +1492,13 @@ assert.doesNotThrow = function(block, /*optional*/message) { }; assert.ifError = function(err) { if (err) {throw err;}}; -},{"_shims":2,"util":10}],4:[function(require,module,exports){ +},{"_shims":3,"util":9}],5:[function(require,module,exports){ // not implemented // The reason for having an empty file and not throwing is to allow // untraditional implementation of this module. -},{}],5:[function(require,module,exports){ +},{}],6:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -1777,9 +1779,9 @@ EventEmitter.listenerCount = function(emitter, type) { ret = emitter._events[type].length; return ret; }; -},{"util":10}],6:[function(require,module,exports){ -module.exports=require(4) -},{}],7:[function(require,module,exports){ +},{"util":9}],7:[function(require,module,exports){ +module.exports=require(5) +},{}],8:[function(require,module,exports){ var process=require("__browserify_process");// Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -1990,913 +1992,7 @@ exports.extname = function(path) { return splitPath(path)[3]; }; -},{"__browserify_process":15,"_shims":2,"util":10}],8:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// Query String Utilities - -var QueryString = exports; -var util = require('util'); -var shims = require('_shims'); -var Buffer = require('buffer').Buffer; - -// If obj.hasOwnProperty has been overridden, then calling -// obj.hasOwnProperty(prop) will break. -// See: https://github.com/joyent/node/issues/1707 -function hasOwnProperty(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); -} - - -function charCode(c) { - return c.charCodeAt(0); -} - - -// a safe fast alternative to decodeURIComponent -QueryString.unescapeBuffer = function(s, decodeSpaces) { - var out = new Buffer(s.length); - var state = 'CHAR'; // states: CHAR, HEX0, HEX1 - var n, m, hexchar; - - for (var inIndex = 0, outIndex = 0; inIndex <= s.length; inIndex++) { - var c = s.charCodeAt(inIndex); - switch (state) { - case 'CHAR': - switch (c) { - case charCode('%'): - n = 0; - m = 0; - state = 'HEX0'; - break; - case charCode('+'): - if (decodeSpaces) c = charCode(' '); - // pass thru - default: - out[outIndex++] = c; - break; - } - break; - - case 'HEX0': - state = 'HEX1'; - hexchar = c; - if (charCode('0') <= c && c <= charCode('9')) { - n = c - charCode('0'); - } else if (charCode('a') <= c && c <= charCode('f')) { - n = c - charCode('a') + 10; - } else if (charCode('A') <= c && c <= charCode('F')) { - n = c - charCode('A') + 10; - } else { - out[outIndex++] = charCode('%'); - out[outIndex++] = c; - state = 'CHAR'; - break; - } - break; - - case 'HEX1': - state = 'CHAR'; - if (charCode('0') <= c && c <= charCode('9')) { - m = c - charCode('0'); - } else if (charCode('a') <= c && c <= charCode('f')) { - m = c - charCode('a') + 10; - } else if (charCode('A') <= c && c <= charCode('F')) { - m = c - charCode('A') + 10; - } else { - out[outIndex++] = charCode('%'); - out[outIndex++] = hexchar; - out[outIndex++] = c; - break; - } - out[outIndex++] = 16 * n + m; - break; - } - } - - // TODO support returning arbitrary buffers. - - return out.slice(0, outIndex - 1); -}; - - -QueryString.unescape = function(s, decodeSpaces) { - return QueryString.unescapeBuffer(s, decodeSpaces).toString(); -}; - - -QueryString.escape = function(str) { - return encodeURIComponent(str); -}; - -var stringifyPrimitive = function(v) { - if (util.isString(v)) - return v; - if (util.isBoolean(v)) - return v ? 'true' : 'false'; - if (util.isNumber(v)) - return isFinite(v) ? v : ''; - return ''; -}; - - -QueryString.stringify = QueryString.encode = function(obj, sep, eq, name) { - sep = sep || '&'; - eq = eq || '='; - if (util.isNull(obj)) { - obj = undefined; - } - - if (util.isObject(obj)) { - return shims.map(shims.keys(obj), function(k) { - var ks = QueryString.escape(stringifyPrimitive(k)) + eq; - if (util.isArray(obj[k])) { - return shims.map(obj[k], function(v) { - return ks + QueryString.escape(stringifyPrimitive(v)); - }).join(sep); - } else { - return ks + QueryString.escape(stringifyPrimitive(obj[k])); - } - }).join(sep); - - } - - if (!name) return ''; - return QueryString.escape(stringifyPrimitive(name)) + eq + - QueryString.escape(stringifyPrimitive(obj)); -}; - -// Parse a key=val string. -QueryString.parse = QueryString.decode = function(qs, sep, eq, options) { - sep = sep || '&'; - eq = eq || '='; - var obj = {}; - - if (!util.isString(qs) || qs.length === 0) { - return obj; - } - - var regexp = /\+/g; - qs = qs.split(sep); - - var maxKeys = 1000; - if (options && util.isNumber(options.maxKeys)) { - maxKeys = options.maxKeys; - } - - var len = qs.length; - // maxKeys <= 0 means that we should not limit keys count - if (maxKeys > 0 && len > maxKeys) { - len = maxKeys; - } - - for (var i = 0; i < len; ++i) { - var x = qs[i].replace(regexp, '%20'), - idx = x.indexOf(eq), - kstr, vstr, k, v; - - if (idx >= 0) { - kstr = x.substr(0, idx); - vstr = x.substr(idx + 1); - } else { - kstr = x; - vstr = ''; - } - - try { - k = decodeURIComponent(kstr); - v = decodeURIComponent(vstr); - } catch (e) { - k = QueryString.unescape(kstr, true); - v = QueryString.unescape(vstr, true); - } - - if (!hasOwnProperty(obj, k)) { - obj[k] = v; - } else if (util.isArray(obj[k])) { - obj[k].push(v); - } else { - obj[k] = [obj[k], v]; - } - } - - return obj; -}; -},{"_shims":2,"buffer":12,"util":10}],9:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var punycode = { encode : function (s) { return s } }; -var util = require('util'); -var shims = require('_shims'); - -exports.parse = urlParse; -exports.resolve = urlResolve; -exports.resolveObject = urlResolveObject; -exports.format = urlFormat; - -exports.Url = Url; - -function Url() { - this.protocol = null; - this.slashes = null; - this.auth = null; - this.host = null; - this.port = null; - this.hostname = null; - this.hash = null; - this.search = null; - this.query = null; - this.pathname = null; - this.path = null; - this.href = null; -} - -// Reference: RFC 3986, RFC 1808, RFC 2396 - -// define these here so at least they only have to be -// compiled once on the first module load. -var protocolPattern = /^([a-z0-9.+-]+:)/i, - portPattern = /:[0-9]*$/, - - // RFC 2396: characters reserved for delimiting URLs. - // We actually just auto-escape these. - delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'], - - // RFC 2396: characters not allowed for various reasons. - unwise = ['{', '}', '|', '\\', '^', '`'].concat(delims), - - // Allowed by RFCs, but cause of XSS attacks. Always escape these. - autoEscape = ['\''].concat(unwise), - // Characters that are never ever allowed in a hostname. - // Note that any invalid chars are also handled, but these - // are the ones that are *expected* to be seen, so we fast-path - // them. - nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape), - hostEndingChars = ['/', '?', '#'], - hostnameMaxLen = 255, - hostnamePartPattern = /^[a-z0-9A-Z_-]{0,63}$/, - hostnamePartStart = /^([a-z0-9A-Z_-]{0,63})(.*)$/, - // protocols that can allow "unsafe" and "unwise" chars. - unsafeProtocol = { - 'javascript': true, - 'javascript:': true - }, - // protocols that never have a hostname. - hostlessProtocol = { - 'javascript': true, - 'javascript:': true - }, - // protocols that always contain a // bit. - slashedProtocol = { - 'http': true, - 'https': true, - 'ftp': true, - 'gopher': true, - 'file': true, - 'http:': true, - 'https:': true, - 'ftp:': true, - 'gopher:': true, - 'file:': true - }, - querystring = require('querystring'); - -function urlParse(url, parseQueryString, slashesDenoteHost) { - if (url && util.isObject(url) && url instanceof Url) return url; - - var u = new Url; - u.parse(url, parseQueryString, slashesDenoteHost); - return u; -} - -Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) { - if (!util.isString(url)) { - throw new TypeError("Parameter 'url' must be a string, not " + typeof url); - } - - var rest = url; - - // trim before proceeding. - // This is to support parse stuff like " http://foo.com \n" - rest = shims.trim(rest); - - var proto = protocolPattern.exec(rest); - if (proto) { - proto = proto[0]; - var lowerProto = proto.toLowerCase(); - this.protocol = lowerProto; - rest = rest.substr(proto.length); - } - - // figure out if it's got a host - // user@server is *always* interpreted as a hostname, and url - // resolution will treat //foo/bar as host=foo,path=bar because that's - // how the browser resolves relative URLs. - if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) { - var slashes = rest.substr(0, 2) === '//'; - if (slashes && !(proto && hostlessProtocol[proto])) { - rest = rest.substr(2); - this.slashes = true; - } - } - - if (!hostlessProtocol[proto] && - (slashes || (proto && !slashedProtocol[proto]))) { - - // there's a hostname. - // the first instance of /, ?, ;, or # ends the host. - // - // If there is an @ in the hostname, then non-host chars *are* allowed - // to the left of the last @ sign, unless some host-ending character - // comes *before* the @-sign. - // URLs are obnoxious. - // - // ex: - // http://a@b@c/ => user:a@b host:c - // http://a@b?@c => user:a host:c path:/?@c - - // v0.12 TODO(isaacs): This is not quite how Chrome does things. - // Review our test case against browsers more comprehensively. - - // find the first instance of any hostEndingChars - var hostEnd = -1; - for (var i = 0; i < hostEndingChars.length; i++) { - var hec = rest.indexOf(hostEndingChars[i]); - if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) - hostEnd = hec; - } - - // at this point, either we have an explicit point where the - // auth portion cannot go past, or the last @ char is the decider. - var auth, atSign; - if (hostEnd === -1) { - // atSign can be anywhere. - atSign = rest.lastIndexOf('@'); - } else { - // atSign must be in auth portion. - // http://a@b/c@d => host:b auth:a path:/c@d - atSign = rest.lastIndexOf('@', hostEnd); - } - - // Now we have a portion which is definitely the auth. - // Pull that off. - if (atSign !== -1) { - auth = rest.slice(0, atSign); - rest = rest.slice(atSign + 1); - this.auth = decodeURIComponent(auth); - } - - // the host is the remaining to the left of the first non-host char - hostEnd = -1; - for (var i = 0; i < nonHostChars.length; i++) { - var hec = rest.indexOf(nonHostChars[i]); - if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) - hostEnd = hec; - } - // if we still have not hit it, then the entire thing is a host. - if (hostEnd === -1) - hostEnd = rest.length; - - this.host = rest.slice(0, hostEnd); - rest = rest.slice(hostEnd); - - // pull out port. - this.parseHost(); - - // we've indicated that there is a hostname, - // so even if it's empty, it has to be present. - this.hostname = this.hostname || ''; - - // if hostname begins with [ and ends with ] - // assume that it's an IPv6 address. - var ipv6Hostname = this.hostname[0] === '[' && - this.hostname[this.hostname.length - 1] === ']'; - - // validate a little. - if (!ipv6Hostname) { - var hostparts = this.hostname.split(/\./); - for (var i = 0, l = hostparts.length; i < l; i++) { - var part = hostparts[i]; - if (!part) continue; - if (!part.match(hostnamePartPattern)) { - var newpart = ''; - for (var j = 0, k = part.length; j < k; j++) { - if (part.charCodeAt(j) > 127) { - // we replace non-ASCII char with a temporary placeholder - // we need this to make sure size of hostname is not - // broken by replacing non-ASCII by nothing - newpart += 'x'; - } else { - newpart += part[j]; - } - } - // we test again with ASCII char only - if (!newpart.match(hostnamePartPattern)) { - var validParts = hostparts.slice(0, i); - var notHost = hostparts.slice(i + 1); - var bit = part.match(hostnamePartStart); - if (bit) { - validParts.push(bit[1]); - notHost.unshift(bit[2]); - } - if (notHost.length) { - rest = '/' + notHost.join('.') + rest; - } - this.hostname = validParts.join('.'); - break; - } - } - } - } - - if (this.hostname.length > hostnameMaxLen) { - this.hostname = ''; - } else { - // hostnames are always lower case. - this.hostname = this.hostname.toLowerCase(); - } - - if (!ipv6Hostname) { - // IDNA Support: Returns a puny coded representation of "domain". - // It only converts the part of the domain name that - // has non ASCII characters. I.e. it dosent matter if - // you call it with a domain that already is in ASCII. - var domainArray = this.hostname.split('.'); - var newOut = []; - for (var i = 0; i < domainArray.length; ++i) { - var s = domainArray[i]; - newOut.push(s.match(/[^A-Za-z0-9_-]/) ? - 'xn--' + punycode.encode(s) : s); - } - this.hostname = newOut.join('.'); - } - - var p = this.port ? ':' + this.port : ''; - var h = this.hostname || ''; - this.host = h + p; - this.href += this.host; - - // strip [ and ] from the hostname - // the host field still retains them, though - if (ipv6Hostname) { - this.hostname = this.hostname.substr(1, this.hostname.length - 2); - if (rest[0] !== '/') { - rest = '/' + rest; - } - } - } - - // now rest is set to the post-host stuff. - // chop off any delim chars. - if (!unsafeProtocol[lowerProto]) { - - // First, make 100% sure that any "autoEscape" chars get - // escaped, even if encodeURIComponent doesn't think they - // need to be. - for (var i = 0, l = autoEscape.length; i < l; i++) { - var ae = autoEscape[i]; - var esc = encodeURIComponent(ae); - if (esc === ae) { - esc = escape(ae); - } - rest = rest.split(ae).join(esc); - } - } - - - // chop off from the tail first. - var hash = rest.indexOf('#'); - if (hash !== -1) { - // got a fragment string. - this.hash = rest.substr(hash); - rest = rest.slice(0, hash); - } - var qm = rest.indexOf('?'); - if (qm !== -1) { - this.search = rest.substr(qm); - this.query = rest.substr(qm + 1); - if (parseQueryString) { - this.query = querystring.parse(this.query); - } - rest = rest.slice(0, qm); - } else if (parseQueryString) { - // no query string, but parseQueryString still requested - this.search = ''; - this.query = {}; - } - if (rest) this.pathname = rest; - if (slashedProtocol[lowerProto] && - this.hostname && !this.pathname) { - this.pathname = '/'; - } - - //to support http.request - if (this.pathname || this.search) { - var p = this.pathname || ''; - var s = this.search || ''; - this.path = p + s; - } - - // finally, reconstruct the href based on what has been validated. - this.href = this.format(); - return this; -}; - -// format a parsed object into a url string -function urlFormat(obj) { - // ensure it's an object, and not a string url. - // If it's an obj, this is a no-op. - // this way, you can call url_format() on strings - // to clean up potentially wonky urls. - if (util.isString(obj)) obj = urlParse(obj); - if (!(obj instanceof Url)) return Url.prototype.format.call(obj); - return obj.format(); -} - -Url.prototype.format = function() { - var auth = this.auth || ''; - if (auth) { - auth = encodeURIComponent(auth); - auth = auth.replace(/%3A/i, ':'); - auth += '@'; - } - - var protocol = this.protocol || '', - pathname = this.pathname || '', - hash = this.hash || '', - host = false, - query = ''; - - if (this.host) { - host = auth + this.host; - } else if (this.hostname) { - host = auth + (this.hostname.indexOf(':') === -1 ? - this.hostname : - '[' + this.hostname + ']'); - if (this.port) { - host += ':' + this.port; - } - } - - if (this.query && - util.isObject(this.query) && - shims.keys(this.query).length) { - query = querystring.stringify(this.query); - } - - var search = this.search || (query && ('?' + query)) || ''; - - if (protocol && shims.substr(protocol, -1) !== ':') protocol += ':'; - - // only the slashedProtocols get the //. Not mailto:, xmpp:, etc. - // unless they had them to begin with. - if (this.slashes || - (!protocol || slashedProtocol[protocol]) && host !== false) { - host = '//' + (host || ''); - if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname; - } else if (!host) { - host = ''; - } - - if (hash && hash.charAt(0) !== '#') hash = '#' + hash; - if (search && search.charAt(0) !== '?') search = '?' + search; - - pathname = pathname.replace(/[?#]/g, function(match) { - return encodeURIComponent(match); - }); - search = search.replace('#', '%23'); - - return protocol + host + pathname + search + hash; -}; - -function urlResolve(source, relative) { - return urlParse(source, false, true).resolve(relative); -} - -Url.prototype.resolve = function(relative) { - return this.resolveObject(urlParse(relative, false, true)).format(); -}; - -function urlResolveObject(source, relative) { - if (!source) return relative; - return urlParse(source, false, true).resolveObject(relative); -} - -Url.prototype.resolveObject = function(relative) { - if (util.isString(relative)) { - var rel = new Url(); - rel.parse(relative, false, true); - relative = rel; - } - - var result = new Url(); - shims.forEach(shims.keys(this), function(k) { - result[k] = this[k]; - }, this); - - // hash is always overridden, no matter what. - // even href="" will remove it. - result.hash = relative.hash; - - // if the relative url is empty, then there's nothing left to do here. - if (relative.href === '') { - result.href = result.format(); - return result; - } - - // hrefs like //foo/bar always cut to the protocol. - if (relative.slashes && !relative.protocol) { - // take everything except the protocol from relative - shims.forEach(shims.keys(relative), function(k) { - if (k !== 'protocol') - result[k] = relative[k]; - }); - - //urlParse appends trailing / to urls like http://www.example.com - if (slashedProtocol[result.protocol] && - result.hostname && !result.pathname) { - result.path = result.pathname = '/'; - } - - result.href = result.format(); - return result; - } - - if (relative.protocol && relative.protocol !== result.protocol) { - // if it's a known url protocol, then changing - // the protocol does weird things - // first, if it's not file:, then we MUST have a host, - // and if there was a path - // to begin with, then we MUST have a path. - // if it is file:, then the host is dropped, - // because that's known to be hostless. - // anything else is assumed to be absolute. - if (!slashedProtocol[relative.protocol]) { - shims.forEach(shims.keys(relative), function(k) { - result[k] = relative[k]; - }); - result.href = result.format(); - return result; - } - - result.protocol = relative.protocol; - if (!relative.host && !hostlessProtocol[relative.protocol]) { - var relPath = (relative.pathname || '').split('/'); - while (relPath.length && !(relative.host = relPath.shift())); - if (!relative.host) relative.host = ''; - if (!relative.hostname) relative.hostname = ''; - if (relPath[0] !== '') relPath.unshift(''); - if (relPath.length < 2) relPath.unshift(''); - result.pathname = relPath.join('/'); - } else { - result.pathname = relative.pathname; - } - result.search = relative.search; - result.query = relative.query; - result.host = relative.host || ''; - result.auth = relative.auth; - result.hostname = relative.hostname || relative.host; - result.port = relative.port; - // to support http.request - if (result.pathname || result.search) { - var p = result.pathname || ''; - var s = result.search || ''; - result.path = p + s; - } - result.slashes = result.slashes || relative.slashes; - result.href = result.format(); - return result; - } - - var isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/'), - isRelAbs = ( - relative.host || - relative.pathname && relative.pathname.charAt(0) === '/' - ), - mustEndAbs = (isRelAbs || isSourceAbs || - (result.host && relative.pathname)), - removeAllDots = mustEndAbs, - srcPath = result.pathname && result.pathname.split('/') || [], - relPath = relative.pathname && relative.pathname.split('/') || [], - psychotic = result.protocol && !slashedProtocol[result.protocol]; - - // if the url is a non-slashed url, then relative - // links like ../.. should be able - // to crawl up to the hostname, as well. This is strange. - // result.protocol has already been set by now. - // Later on, put the first path part into the host field. - if (psychotic) { - result.hostname = ''; - result.port = null; - if (result.host) { - if (srcPath[0] === '') srcPath[0] = result.host; - else srcPath.unshift(result.host); - } - result.host = ''; - if (relative.protocol) { - relative.hostname = null; - relative.port = null; - if (relative.host) { - if (relPath[0] === '') relPath[0] = relative.host; - else relPath.unshift(relative.host); - } - relative.host = null; - } - mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === ''); - } - - if (isRelAbs) { - // it's absolute. - result.host = (relative.host || relative.host === '') ? - relative.host : result.host; - result.hostname = (relative.hostname || relative.hostname === '') ? - relative.hostname : result.hostname; - result.search = relative.search; - result.query = relative.query; - srcPath = relPath; - // fall through to the dot-handling below. - } else if (relPath.length) { - // it's relative - // throw away the existing file, and take the new path instead. - if (!srcPath) srcPath = []; - srcPath.pop(); - srcPath = srcPath.concat(relPath); - result.search = relative.search; - result.query = relative.query; - } else if (!util.isNullOrUndefined(relative.search)) { - // just pull out the search. - // like href='?foo'. - // Put this after the other two cases because it simplifies the booleans - if (psychotic) { - result.hostname = result.host = srcPath.shift(); - //occationaly the auth can get stuck only in host - //this especialy happens in cases like - //url.resolveObject('mailto:local1@domain1', 'local2@domain2') - var authInHost = result.host && result.host.indexOf('@') > 0 ? - result.host.split('@') : false; - if (authInHost) { - result.auth = authInHost.shift(); - result.host = result.hostname = authInHost.shift(); - } - } - result.search = relative.search; - result.query = relative.query; - //to support http.request - if (!util.isNull(result.pathname) || !util.isNull(result.search)) { - result.path = (result.pathname ? result.pathname : '') + - (result.search ? result.search : ''); - } - result.href = result.format(); - return result; - } - - if (!srcPath.length) { - // no path at all. easy. - // we've already handled the other stuff above. - result.pathname = null; - //to support http.request - if (result.search) { - result.path = '/' + result.search; - } else { - result.path = null; - } - result.href = result.format(); - return result; - } - - // if a url ENDs in . or .., then it must get a trailing slash. - // however, if it ends in anything else non-slashy, - // then it must NOT get a trailing slash. - var last = srcPath.slice(-1)[0]; - var hasTrailingSlash = ( - (result.host || relative.host) && (last === '.' || last === '..') || - last === ''); - - // strip single dots, resolve double dots to parent dir - // if the path tries to go above the root, `up` ends up > 0 - var up = 0; - for (var i = srcPath.length; i >= 0; i--) { - last = srcPath[i]; - if (last == '.') { - srcPath.splice(i, 1); - } else if (last === '..') { - srcPath.splice(i, 1); - up++; - } else if (up) { - srcPath.splice(i, 1); - up--; - } - } - - // if the path is allowed to go above the root, restore leading ..s - if (!mustEndAbs && !removeAllDots) { - for (; up--; up) { - srcPath.unshift('..'); - } - } - - if (mustEndAbs && srcPath[0] !== '' && - (!srcPath[0] || srcPath[0].charAt(0) !== '/')) { - srcPath.unshift(''); - } - - if (hasTrailingSlash && (shims.substr(srcPath.join('/'), -1) !== '/')) { - srcPath.push(''); - } - - var isAbsolute = srcPath[0] === '' || - (srcPath[0] && srcPath[0].charAt(0) === '/'); - - // put the host back - if (psychotic) { - result.hostname = result.host = isAbsolute ? '' : - srcPath.length ? srcPath.shift() : ''; - //occationaly the auth can get stuck only in host - //this especialy happens in cases like - //url.resolveObject('mailto:local1@domain1', 'local2@domain2') - var authInHost = result.host && result.host.indexOf('@') > 0 ? - result.host.split('@') : false; - if (authInHost) { - result.auth = authInHost.shift(); - result.host = result.hostname = authInHost.shift(); - } - } - - mustEndAbs = mustEndAbs || (result.host && srcPath.length); - - if (mustEndAbs && !isAbsolute) { - srcPath.unshift(''); - } - - if (!srcPath.length) { - result.pathname = null; - result.path = null; - } else { - result.pathname = srcPath.join('/'); - } - - //to support request.http - if (!util.isNull(result.pathname) || !util.isNull(result.search)) { - result.path = (result.pathname ? result.pathname : '') + - (result.search ? result.search : ''); - } - result.auth = relative.auth || result.auth; - result.slashes = result.slashes || relative.slashes; - result.href = result.format(); - return result; -}; - -Url.prototype.parseHost = function() { - var host = this.host; - var port = portPattern.exec(host); - if (port) { - port = port[0]; - if (port !== ':') { - this.port = port.substr(1); - } - host = host.substr(0, host.length - port.length); - } - if (host) this.hostname = host; -}; -},{"_shims":2,"querystring":8,"util":10}],10:[function(require,module,exports){ +},{"__browserify_process":14,"_shims":3,"util":9}],9:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -3441,7 +2537,7 @@ function hasOwnProperty(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } -},{"_shims":2}],11:[function(require,module,exports){ +},{"_shims":3}],10:[function(require,module,exports){ exports.readIEEE754 = function(buffer, offset, isBE, mLen, nBytes) { var e, m, eLen = nBytes * 8 - mLen - 1, @@ -3527,7 +2623,7 @@ exports.writeIEEE754 = function(buffer, value, offset, isBE, mLen, nBytes) { buffer[offset + i - d] |= s * 128; }; -},{}],12:[function(require,module,exports){ +},{}],11:[function(require,module,exports){ var assert; exports.Buffer = Buffer; exports.SlowBuffer = Buffer; @@ -3553,7 +2649,7 @@ function Buffer(subject, encoding, offset) { if (encoding == "base64" && typeof subject == "string") { subject = stringtrim(subject); while (subject.length % 4 != 0) { - subject = subject + "="; + subject = subject + "="; } } @@ -4653,7 +3749,7 @@ Buffer.prototype.writeDoubleBE = function(value, offset, noAssert) { writeDouble(this, value, offset, true, noAssert); }; -},{"./buffer_ieee754":11,"assert":3,"base64-js":13}],13:[function(require,module,exports){ +},{"./buffer_ieee754":10,"assert":4,"base64-js":12}],12:[function(require,module,exports){ (function (exports) { 'use strict'; @@ -4661,7 +3757,7 @@ Buffer.prototype.writeDoubleBE = function(value, offset, noAssert) { function b64ToByteArray(b64) { var i, j, l, tmp, placeHolders, arr; - + if (b64.length % 4 > 0) { throw 'Invalid string. Length must be a multiple of 4'; } @@ -4739,7 +3835,7 @@ Buffer.prototype.writeDoubleBE = function(value, offset, noAssert) { module.exports.fromByteArray = uint8ToBase64; }()); -},{}],14:[function(require,module,exports){ +},{}],13:[function(require,module,exports){ require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0) { throw 'Invalid string. Length must be a multiple of 4'; } @@ -7119,7 +6215,7 @@ function hasOwnProperty(obj, prop) { },{"_shims":5}]},{},[]) ;;module.exports=require("buffer-browserify") -},{}],15:[function(require,module,exports){ +},{}],14:[function(require,module,exports){ // shim for using process in browser var process = module.exports = {}; @@ -7173,7 +6269,7 @@ process.chdir = function (dir) { throw new Error('process.chdir is not supported'); }; -},{}],16:[function(require,module,exports){ +},{}],15:[function(require,module,exports){ var Buffer=require("__browserify_Buffer").Buffer; (function (global, module) { @@ -8428,35 +7524,10 @@ var Buffer=require("__browserify_Buffer").Buffer; , 'undefined' != typeof exports ? exports : {} ); -},{"__browserify_Buffer":14}],17:[function(require,module,exports){ -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 - } -} - -},{}],18:[function(require,module,exports){ +},{"__browserify_Buffer":13}],16:[function(require,module,exports){ module.exports = require('./lib/js-yaml.js'); -},{"./lib/js-yaml.js":19}],19:[function(require,module,exports){ +},{"./lib/js-yaml.js":17}],17:[function(require,module,exports){ 'use strict'; @@ -8501,7 +7572,7 @@ module.exports.addConstructor = deprecated('addConstructor'); require('./js-yaml/require'); -},{"./js-yaml/common":20,"./js-yaml/dumper":21,"./js-yaml/exception":22,"./js-yaml/loader":23,"./js-yaml/require":25,"./js-yaml/schema":26,"./js-yaml/schema/core":27,"./js-yaml/schema/default_full":28,"./js-yaml/schema/default_safe":29,"./js-yaml/schema/failsafe":30,"./js-yaml/schema/json":31,"./js-yaml/type":32}],20:[function(require,module,exports){ +},{"./js-yaml/common":18,"./js-yaml/dumper":19,"./js-yaml/exception":20,"./js-yaml/loader":21,"./js-yaml/require":23,"./js-yaml/schema":24,"./js-yaml/schema/core":25,"./js-yaml/schema/default_full":26,"./js-yaml/schema/default_safe":27,"./js-yaml/schema/failsafe":28,"./js-yaml/schema/json":29,"./js-yaml/type":30}],18:[function(require,module,exports){ 'use strict'; @@ -8563,7 +7634,7 @@ module.exports.toArray = toArray; module.exports.repeat = repeat; module.exports.extend = extend; -},{}],21:[function(require,module,exports){ +},{}],19:[function(require,module,exports){ 'use strict'; @@ -9050,7 +8121,7 @@ function safeDump(input, options) { module.exports.dump = dump; module.exports.safeDump = safeDump; -},{"./common":20,"./exception":22,"./schema/default_full":28,"./schema/default_safe":29}],22:[function(require,module,exports){ +},{"./common":18,"./exception":20,"./schema/default_full":26,"./schema/default_safe":27}],20:[function(require,module,exports){ 'use strict'; @@ -9077,7 +8148,7 @@ YAMLException.prototype.toString = function toString(compact) { module.exports = YAMLException; -},{}],23:[function(require,module,exports){ +},{}],21:[function(require,module,exports){ 'use strict'; @@ -10664,7 +9735,7 @@ module.exports.load = load; module.exports.safeLoadAll = safeLoadAll; module.exports.safeLoad = safeLoad; -},{"./common":20,"./exception":22,"./mark":24,"./schema/default_full":28,"./schema/default_safe":29}],24:[function(require,module,exports){ +},{"./common":18,"./exception":20,"./mark":22,"./schema/default_full":26,"./schema/default_safe":27}],22:[function(require,module,exports){ 'use strict'; @@ -10744,7 +9815,7 @@ Mark.prototype.toString = function toString(compact) { module.exports = Mark; -},{"./common":20}],25:[function(require,module,exports){ +},{"./common":18}],23:[function(require,module,exports){ 'use strict'; @@ -10769,7 +9840,7 @@ if (undefined !== require.extensions) { module.exports = require; -},{"./loader":23,"fs":6}],26:[function(require,module,exports){ +},{"./loader":21,"fs":7}],24:[function(require,module,exports){ 'use strict'; @@ -10874,7 +9945,7 @@ Schema.create = function createSchema() { module.exports = Schema; -},{"./common":20,"./exception":22,"./type":32}],27:[function(require,module,exports){ +},{"./common":18,"./exception":20,"./type":30}],25:[function(require,module,exports){ // Standard YAML's Core schema. // http://www.yaml.org/spec/1.2/spec.html#id2804923 // @@ -10894,7 +9965,7 @@ module.exports = new Schema({ ] }); -},{"../schema":26,"./json":31}],28:[function(require,module,exports){ +},{"../schema":24,"./json":29}],26:[function(require,module,exports){ // JS-YAML's default schema for `load` function. // It is not described in the YAML specification. // @@ -10921,7 +9992,7 @@ module.exports = Schema.DEFAULT = new Schema({ ] }); -},{"../schema":26,"../type/js/function":37,"../type/js/regexp":38,"../type/js/undefined":39,"./default_safe":29}],29:[function(require,module,exports){ +},{"../schema":24,"../type/js/function":35,"../type/js/regexp":36,"../type/js/undefined":37,"./default_safe":27}],27:[function(require,module,exports){ // JS-YAML's default schema for `safeLoad` function. // It is not described in the YAML specification. // @@ -10951,7 +10022,7 @@ module.exports = new Schema({ ] }); -},{"../schema":26,"../type/binary":33,"../type/merge":41,"../type/omap":43,"../type/pairs":44,"../type/set":46,"../type/timestamp":48,"./core":27}],30:[function(require,module,exports){ +},{"../schema":24,"../type/binary":31,"../type/merge":39,"../type/omap":41,"../type/pairs":42,"../type/set":44,"../type/timestamp":46,"./core":25}],28:[function(require,module,exports){ // Standard YAML's Failsafe schema. // http://www.yaml.org/spec/1.2/spec.html#id2802346 @@ -10970,7 +10041,7 @@ module.exports = new Schema({ ] }); -},{"../schema":26,"../type/map":40,"../type/seq":45,"../type/str":47}],31:[function(require,module,exports){ +},{"../schema":24,"../type/map":38,"../type/seq":43,"../type/str":45}],29:[function(require,module,exports){ // Standard YAML's JSON schema. // http://www.yaml.org/spec/1.2/spec.html#id2803231 // @@ -10997,7 +10068,7 @@ module.exports = new Schema({ ] }); -},{"../schema":26,"../type/bool":34,"../type/float":35,"../type/int":36,"../type/null":42,"./failsafe":30}],32:[function(require,module,exports){ +},{"../schema":24,"../type/bool":32,"../type/float":33,"../type/int":34,"../type/null":40,"./failsafe":28}],30:[function(require,module,exports){ 'use strict'; @@ -11081,7 +10152,7 @@ Type.Dumper = function TypeDumper(options) { module.exports = Type; -},{"./exception":22}],33:[function(require,module,exports){ +},{"./exception":20}],31:[function(require,module,exports){ // Modified from: // https://raw.github.com/kanaka/noVNC/d890e8640f20fba3215ba7be8e0ff145aeb8c17c/include/base64.js @@ -11201,7 +10272,7 @@ module.exports = new Type('tag:yaml.org,2002:binary', { } }); -},{"../common":20,"../type":32,"buffer":12}],34:[function(require,module,exports){ +},{"../common":18,"../type":30,"buffer":11}],32:[function(require,module,exports){ 'use strict'; @@ -11277,7 +10348,7 @@ module.exports = new Type('tag:yaml.org,2002:bool', { } }); -},{"../common":20,"../type":32}],35:[function(require,module,exports){ +},{"../common":18,"../type":30}],33:[function(require,module,exports){ 'use strict'; @@ -11381,7 +10452,7 @@ module.exports = new Type('tag:yaml.org,2002:float', { } }); -},{"../common":20,"../type":32}],36:[function(require,module,exports){ +},{"../common":18,"../type":30}],34:[function(require,module,exports){ 'use strict'; @@ -11468,7 +10539,7 @@ module.exports = new Type('tag:yaml.org,2002:int', { } }); -},{"../common":20,"../type":32}],37:[function(require,module,exports){ +},{"../common":18,"../type":30}],35:[function(require,module,exports){ 'use strict'; @@ -11526,7 +10597,7 @@ module.exports = new Type('tag:yaml.org,2002:js/function', { } }); -},{"../../common":20,"../../type":32,"esprima":49}],38:[function(require,module,exports){ +},{"../../common":18,"../../type":30,"esprima":47}],36:[function(require,module,exports){ 'use strict'; @@ -11584,7 +10655,7 @@ module.exports = new Type('tag:yaml.org,2002:js/regexp', { } }); -},{"../../common":20,"../../type":32}],39:[function(require,module,exports){ +},{"../../common":18,"../../type":30}],37:[function(require,module,exports){ 'use strict'; @@ -11614,7 +10685,7 @@ module.exports = new Type('tag:yaml.org,2002:js/undefined', { } }); -},{"../../type":32}],40:[function(require,module,exports){ +},{"../../type":30}],38:[function(require,module,exports){ 'use strict'; @@ -11627,7 +10698,7 @@ module.exports = new Type('tag:yaml.org,2002:map', { } }); -},{"../type":32}],41:[function(require,module,exports){ +},{"../type":30}],39:[function(require,module,exports){ 'use strict'; @@ -11647,7 +10718,7 @@ module.exports = new Type('tag:yaml.org,2002:merge', { } }); -},{"../common":20,"../type":32}],42:[function(require,module,exports){ +},{"../common":18,"../type":30}],40:[function(require,module,exports){ 'use strict'; @@ -11685,7 +10756,7 @@ module.exports = new Type('tag:yaml.org,2002:null', { } }); -},{"../common":20,"../type":32}],43:[function(require,module,exports){ +},{"../common":18,"../type":30}],41:[function(require,module,exports){ 'use strict'; @@ -11740,7 +10811,7 @@ module.exports = new Type('tag:yaml.org,2002:omap', { } }); -},{"../common":20,"../type":32}],44:[function(require,module,exports){ +},{"../common":18,"../type":30}],42:[function(require,module,exports){ 'use strict'; @@ -11783,7 +10854,7 @@ module.exports = new Type('tag:yaml.org,2002:pairs', { } }); -},{"../common":20,"../type":32}],45:[function(require,module,exports){ +},{"../common":18,"../type":30}],43:[function(require,module,exports){ 'use strict'; @@ -11796,7 +10867,7 @@ module.exports = new Type('tag:yaml.org,2002:seq', { } }); -},{"../type":32}],46:[function(require,module,exports){ +},{"../type":30}],44:[function(require,module,exports){ 'use strict'; @@ -11829,7 +10900,7 @@ module.exports = new Type('tag:yaml.org,2002:set', { } }); -},{"../common":20,"../type":32}],47:[function(require,module,exports){ +},{"../common":18,"../type":30}],45:[function(require,module,exports){ 'use strict'; @@ -11842,7 +10913,7 @@ module.exports = new Type('tag:yaml.org,2002:str', { } }); -},{"../type":32}],48:[function(require,module,exports){ +},{"../type":30}],46:[function(require,module,exports){ 'use strict'; @@ -11935,7 +11006,7 @@ module.exports = new Type('tag:yaml.org,2002:timestamp', { } }); -},{"../common":20,"../type":32}],49:[function(require,module,exports){ +},{"../common":18,"../type":30}],47:[function(require,module,exports){ /* Copyright (C) 2012 Ariya Hidayat Copyright (C) 2012 Mathias Bynens @@ -15845,7 +14916,7 @@ parseStatement: true, parseSourceElement: true */ })); /* vim: set sw=4 ts=4 et tw=80 : */ -},{}],50:[function(require,module,exports){ +},{}],48:[function(require,module,exports){ var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};/** * @license * Lo-Dash 2.3.0 (Custom Build) @@ -22438,7 +21509,7 @@ var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? } }.call(this)); -},{}],51:[function(require,module,exports){ +},{}],49:[function(require,module,exports){ var process=require("__browserify_process");;(function (require, exports, module, platform) { if (module) module.exports = minimatch @@ -23436,7 +22507,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) { } // no match was found. // However, in partial mode, we can't say this is necessarily over. - // If there's more *pattern* left, then + // If there's more *pattern* left, then if (partial) { // ran out of file // console.error("\n>>> no match, partial?", file, fr, pattern, pr) @@ -23519,7 +22590,7 @@ function regExpEscape (s) { typeof process === "object" ? process.platform : "win32" ) -},{"__browserify_process":15,"lru-cache":52,"path":7,"sigmund":53}],52:[function(require,module,exports){ +},{"__browserify_process":14,"lru-cache":50,"path":8,"sigmund":51}],50:[function(require,module,exports){ ;(function () { // closure for web browsers if (typeof module === 'object' && module.exports) { @@ -23773,7 +22844,7 @@ function Entry (key, value, lu, length, now) { })() -},{}],53:[function(require,module,exports){ +},{}],51:[function(require,module,exports){ module.exports = sigmund function sigmund (subject, maxSessions) { maxSessions = maxSessions || 10; @@ -23814,6816 +22885,10 @@ function sigmund (subject, maxSessions) { // vim: set softtabstop=4 shiftwidth=4: -},{}],54:[function(require,module,exports){ -var process=require("__browserify_process");var path = require('path'); -var minimist = require('minimist'); -var wordwrap = require('wordwrap'); - -/* Hack an instance of Argv with process.argv into Argv - so people can do - require('optimist')(['--beeble=1','-z','zizzle']).argv - to parse a list of args and - require('optimist').argv - to get a parsed version of process.argv. -*/ - -var inst = Argv(process.argv.slice(2)); -Object.keys(inst).forEach(function (key) { - Argv[key] = typeof inst[key] == 'function' - ? inst[key].bind(inst) - : inst[key]; -}); - -var exports = module.exports = Argv; -function Argv (processArgs, cwd) { - var self = {}; - if (!cwd) cwd = process.cwd(); - - self.$0 = process.argv - .slice(0,2) - .map(function (x) { - var b = rebase(cwd, x); - return x.match(/^\//) && b.length < x.length - ? b : x - }) - .join(' ') - ; - - if (process.env._ != undefined && process.argv[1] == process.env._) { - self.$0 = process.env._.replace( - path.dirname(process.execPath) + '/', '' - ); - } - - var options = { - boolean: [], - string: [], - alias: {}, - default: [] - }; - - self.boolean = function (bools) { - options.boolean.push.apply(options.boolean, [].concat(bools)); - return self; - }; - - self.string = function (strings) { - options.string.push.apply(options.string, [].concat(strings)); - return self; - }; - - self.default = function (key, value) { - if (typeof key === 'object') { - Object.keys(key).forEach(function (k) { - self.default(k, key[k]); - }); - } - else { - options.default[key] = value; - } - return self; - }; - - self.alias = function (x, y) { - if (typeof x === 'object') { - Object.keys(x).forEach(function (key) { - self.alias(key, x[key]); - }); - } - else { - options.alias[x] = (options.alias[x] || []).concat(y); - } - return self; - }; - - var demanded = {}; - self.demand = function (keys) { - if (typeof keys == 'number') { - if (!demanded._) demanded._ = 0; - demanded._ += keys; - } - else if (Array.isArray(keys)) { - keys.forEach(function (key) { - self.demand(key); - }); - } - else { - demanded[keys] = true; - } - - return self; - }; - - var usage; - self.usage = function (msg, opts) { - if (!opts && typeof msg === 'object') { - opts = msg; - msg = null; - } - - usage = msg; - - if (opts) self.options(opts); - - return self; - }; - - function fail (msg) { - self.showHelp(); - if (msg) console.error(msg); - process.exit(1); - } - - var checks = []; - self.check = function (f) { - checks.push(f); - return self; - }; - - var descriptions = {}; - self.describe = function (key, desc) { - if (typeof key === 'object') { - Object.keys(key).forEach(function (k) { - self.describe(k, key[k]); - }); - } - else { - descriptions[key] = desc; - } - return self; - }; - - self.parse = function (args) { - return parseArgs(args); - }; - - self.option = self.options = function (key, opt) { - if (typeof key === 'object') { - Object.keys(key).forEach(function (k) { - self.options(k, key[k]); - }); - } - else { - if (opt.alias) self.alias(key, opt.alias); - if (opt.demand) self.demand(key); - if (typeof opt.default !== 'undefined') { - self.default(key, opt.default); - } - - if (opt.boolean || opt.type === 'boolean') { - self.boolean(key); - } - if (opt.string || opt.type === 'string') { - self.string(key); - } - - var desc = opt.describe || opt.description || opt.desc; - if (desc) { - self.describe(key, desc); - } - } - - return self; - }; - - var wrap = null; - self.wrap = function (cols) { - wrap = cols; - return self; - }; - - self.showHelp = function (fn) { - if (!fn) fn = console.error; - fn(self.help()); - }; - - self.help = function () { - var keys = Object.keys( - Object.keys(descriptions) - .concat(Object.keys(demanded)) - .concat(Object.keys(options.default)) - .reduce(function (acc, key) { - if (key !== '_') acc[key] = true; - return acc; - }, {}) - ); - - var help = keys.length ? [ 'Options:' ] : []; - - if (usage) { - help.unshift(usage.replace(/\$0/g, self.$0), ''); - } - - var switches = keys.reduce(function (acc, key) { - acc[key] = [ key ].concat(options.alias[key] || []) - .map(function (sw) { - return (sw.length > 1 ? '--' : '-') + sw - }) - .join(', ') - ; - return acc; - }, {}); - - var switchlen = longest(Object.keys(switches).map(function (s) { - return switches[s] || ''; - })); - - var desclen = longest(Object.keys(descriptions).map(function (d) { - return descriptions[d] || ''; - })); - - keys.forEach(function (key) { - var kswitch = switches[key]; - var desc = descriptions[key] || ''; - - if (wrap) { - desc = wordwrap(switchlen + 4, wrap)(desc) - .slice(switchlen + 4) - ; - } - - var spadding = new Array( - Math.max(switchlen - kswitch.length + 3, 0) - ).join(' '); - - var dpadding = new Array( - Math.max(desclen - desc.length + 1, 0) - ).join(' '); - - var type = null; - - if (options.boolean[key]) type = '[boolean]'; - if (options.string[key]) type = '[string]'; - - if (!wrap && dpadding.length > 0) { - desc += dpadding; - } - - var prelude = ' ' + kswitch + spadding; - var extra = [ - type, - demanded[key] - ? '[required]' - : null - , - options.default[key] !== undefined - ? '[default: ' + JSON.stringify(options.default[key]) + ']' - : null - , - ].filter(Boolean).join(' '); - - var body = [ desc, extra ].filter(Boolean).join(' '); - - if (wrap) { - var dlines = desc.split('\n'); - var dlen = dlines.slice(-1)[0].length - + (dlines.length === 1 ? prelude.length : 0) - - body = desc + (dlen + extra.length > wrap - 2 - ? '\n' - + new Array(wrap - extra.length + 1).join(' ') - + extra - : new Array(wrap - extra.length - dlen + 1).join(' ') - + extra - ); - } - - help.push(prelude + body); - }); - - help.push(''); - return help.join('\n'); - }; - - Object.defineProperty(self, 'argv', { - get : function () { return parseArgs(processArgs) }, - enumerable : true, - }); - - function parseArgs (args) { - var argv = minimist(args, options); - argv.$0 = self.$0; - - if (demanded._ && argv._.length < demanded._) { - fail('Not enough non-option arguments: got ' - + argv._.length + ', need at least ' + demanded._ - ); - } - - var missing = []; - Object.keys(demanded).forEach(function (key) { - if (!argv[key]) missing.push(key); - }); - - if (missing.length) { - fail('Missing required arguments: ' + missing.join(', ')); - } - - checks.forEach(function (f) { - try { - if (f(argv) === false) { - fail('Argument check failed: ' + f.toString()); - } - } - catch (err) { - fail(err) - } - }); - - return argv; - } - - function longest (xs) { - return Math.max.apply( - null, - xs.map(function (x) { return x.length }) - ); - } - - return self; -}; - -// rebase an absolute path to a relative one with respect to a base directory -// exported for tests -exports.rebase = rebase; -function rebase (base, dir) { - var ds = path.normalize(dir).split('/').slice(1); - var bs = path.normalize(base).split('/').slice(1); - - for (var i = 0; ds[i] && ds[i] == bs[i]; i++); - ds.splice(0, i); bs.splice(0, i); - - var p = path.normalize( - bs.map(function () { return '..' }).concat(ds).join('/') - ).replace(/\/$/,'').replace(/^$/, '.'); - return p.match(/^[.\/]/) ? p : './' + p; -}; - -},{"__browserify_process":15,"minimist":55,"path":7,"wordwrap":56}],55:[function(require,module,exports){ -module.exports = function (args, opts) { - if (!opts) opts = {}; - - var flags = { bools : {}, strings : {} }; - - [].concat(opts['boolean']).filter(Boolean).forEach(function (key) { - flags.bools[key] = true; - }); - - [].concat(opts.string).filter(Boolean).forEach(function (key) { - flags.strings[key] = true; - }); - - var aliases = {}; - Object.keys(opts.alias || {}).forEach(function (key) { - aliases[key] = [].concat(opts.alias[key]); - aliases[key].forEach(function (x) { - aliases[x] = [key].concat(aliases[key].filter(function (y) { - return x !== y; - })); - }); - }); - - var defaults = opts['default'] || {}; - - var argv = { _ : [] }; - Object.keys(flags.bools).forEach(function (key) { - setArg(key, defaults[key] === undefined ? false : defaults[key]); - }); - - var notFlags = []; - - if (args.indexOf('--') !== -1) { - notFlags = args.slice(args.indexOf('--')+1); - args = args.slice(0, args.indexOf('--')); - } - - function setArg (key, val) { - var value = !flags.strings[key] && isNumber(val) - ? Number(val) : val - ; - setKey(argv, key.split('.'), value); - - (aliases[key] || []).forEach(function (x) { - setKey(argv, x.split('.'), value); - }); - } - - for (var i = 0; i < args.length; i++) { - var arg = args[i]; - - if (arg.match(/^--.+=/)) { - // Using [\s\S] instead of . because js doesn't support the - // 'dotall' regex modifier. See: - // http://stackoverflow.com/a/1068308/13216 - var m = arg.match(/^--([^=]+)=([\s\S]*)$/); - setArg(m[1], m[2]); - } - else if (arg.match(/^--no-.+/)) { - var key = arg.match(/^--no-(.+)/)[1]; - setArg(key, false); - } - else if (arg.match(/^--.+/)) { - var key = arg.match(/^--(.+)/)[1]; - var next = args[i + 1]; - if (next !== undefined && !next.match(/^-/) - && !flags.bools[key] - && (aliases[key] ? !flags.bools[aliases[key]] : true)) { - setArg(key, next); - i++; - } - else if (/^(true|false)$/.test(next)) { - setArg(key, next === 'true'); - i++; - } - else { - setArg(key, true); - } - } - else if (arg.match(/^-[^-]+/)) { - var letters = arg.slice(1,-1).split(''); - - var broken = false; - for (var j = 0; j < letters.length; j++) { - var next = arg.slice(j+2); - - if (letters[j+1] && letters[j+1] === '=') { - setArg(letters[j], arg.slice(j+3)); - broken = true; - break; - } - - if (next === '-') { - setArg(letters[j], next) - continue; - } - - if (/[A-Za-z]/.test(letters[j]) - && /-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) { - setArg(letters[j], next); - broken = true; - break; - } - - if (letters[j+1] && letters[j+1].match(/\W/)) { - setArg(letters[j], arg.slice(j+2)); - broken = true; - break; - } - else { - setArg(letters[j], true); - } - } - - var key = arg.slice(-1)[0]; - if (!broken && key !== '-') { - if (args[i+1] && !/^(-|--)[^-]/.test(args[i+1]) - && !flags.bools[key] - && (aliases[key] ? !flags.bools[aliases[key]] : true)) { - setArg(key, args[i+1]); - i++; - } - else if (args[i+1] && /true|false/.test(args[i+1])) { - setArg(key, args[i+1] === 'true'); - i++; - } - else { - setArg(key, true); - } - } - } - else { - argv._.push( - flags.strings['_'] || !isNumber(arg) ? arg : Number(arg) - ); - } - } - - Object.keys(defaults).forEach(function (key) { - if (!hasKey(argv, key.split('.'))) { - setKey(argv, key.split('.'), defaults[key]); - - (aliases[key] || []).forEach(function (x) { - setKey(argv, x.split('.'), defaults[key]); - }); - } - }); - - notFlags.forEach(function(key) { - argv._.push(key); - }); - - return argv; -}; - -function hasKey (obj, keys) { - var o = obj; - keys.slice(0,-1).forEach(function (key) { - o = (o[key] || {}); - }); - - var key = keys[keys.length - 1]; - return key in o; -} - -function setKey (obj, keys, value) { - var o = obj; - keys.slice(0,-1).forEach(function (key) { - if (o[key] === undefined) o[key] = {}; - o = o[key]; - }); - - var key = keys[keys.length - 1]; - if (o[key] === undefined || typeof o[key] === 'boolean') { - o[key] = value; - } - else if (Array.isArray(o[key])) { - o[key].push(value); - } - else { - o[key] = [ o[key], value ]; - } -} - -function isNumber (x) { - if (typeof x === 'number') return true; - if (/^0x[0-9a-f]+$/i.test(x)) return true; - return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x); -} - -function longest (xs) { - return Math.max.apply(null, xs.map(function (x) { return x.length })); -} - -},{}],56:[function(require,module,exports){ -var wordwrap = module.exports = function (start, stop, params) { - if (typeof start === 'object') { - params = start; - start = params.start; - stop = params.stop; - } - - if (typeof stop === 'object') { - params = stop; - start = start || params.start; - stop = undefined; - } - - if (!stop) { - stop = start; - start = 0; - } - - if (!params) params = {}; - var mode = params.mode || 'soft'; - var re = mode === 'hard' ? /\b/ : /(\S+\s+)/; - - return function (text) { - var chunks = text.toString() - .split(re) - .reduce(function (acc, x) { - if (mode === 'hard') { - for (var i = 0; i < x.length; i += stop - start) { - acc.push(x.slice(i, i + stop - start)); - } - } - else acc.push(x) - return acc; - }, []) - ; - - return chunks.reduce(function (lines, rawChunk) { - if (rawChunk === '') return lines; - - var chunk = rawChunk.replace(/\t/g, ' '); - - var i = lines.length - 1; - if (lines[i].length + chunk.length > stop) { - lines[i] = lines[i].replace(/\s+$/, ''); - - chunk.split(/\n/).forEach(function (c) { - lines.push( - new Array(start + 1).join(' ') - + c.replace(/^\s+/, '') - ); - }); - } - else if (chunk.match(/\n/)) { - var xs = chunk.split(/\n/); - lines[i] += xs.shift(); - xs.forEach(function (c) { - lines.push( - new Array(start + 1).join(' ') - + c.replace(/^\s+/, '') - ); - }); - } - else { - lines[i] += chunk; - } - - return lines; - }, [ new Array(start + 1).join(' ') ]).join('\n'); - }; -}; - -wordwrap.soft = wordwrap; - -wordwrap.hard = function (start, stop) { - return wordwrap(start, stop, { mode : 'hard' }); -}; - -},{}],57:[function(require,module,exports){ -var process=require("__browserify_process");/** @license MIT License (c) copyright 2011-2013 original author or authors */ - -/** - * A lightweight CommonJS Promises/A and when() implementation - * when is part of the cujo.js family of libraries (http://cujojs.com/) - * - * Licensed under the MIT License at: - * http://www.opensource.org/licenses/mit-license.php - * - * @author Brian Cavalier - * @author John Hann - * @version 2.6.0 - */ -(function(define, global) { 'use strict'; -define(function (require) { - - // Public API - - when.promise = promise; // Create a pending promise - when.resolve = resolve; // Create a resolved promise - when.reject = reject; // Create a rejected promise - when.defer = defer; // Create a {promise, resolver} pair - - when.join = join; // Join 2 or more promises - - when.all = all; // Resolve a list of promises - when.map = map; // Array.map() for promises - when.reduce = reduce; // Array.reduce() for promises - when.settle = settle; // Settle a list of promises - - when.any = any; // One-winner race - when.some = some; // Multi-winner race - - when.isPromise = isPromiseLike; // DEPRECATED: use isPromiseLike - when.isPromiseLike = isPromiseLike; // Is something promise-like, aka thenable - - /** - * Register an observer for a promise or immediate value. - * - * @param {*} promiseOrValue - * @param {function?} [onFulfilled] callback to be called when promiseOrValue is - * successfully fulfilled. If promiseOrValue is an immediate value, callback - * will be invoked immediately. - * @param {function?} [onRejected] callback to be called when promiseOrValue is - * rejected. - * @param {function?} [onProgress] callback to be called when progress updates - * are issued for promiseOrValue. - * @returns {Promise} a new {@link Promise} that will complete with the return - * value of callback or errback or the completion value of promiseOrValue if - * callback and/or errback is not supplied. - */ - function when(promiseOrValue, onFulfilled, onRejected, onProgress) { - // Get a trusted promise for the input promiseOrValue, and then - // register promise handlers - return cast(promiseOrValue).then(onFulfilled, onRejected, onProgress); - } - - function cast(x) { - return x instanceof Promise ? x : resolve(x); - } - - /** - * Trusted Promise constructor. A Promise created from this constructor is - * a trusted when.js promise. Any other duck-typed promise is considered - * untrusted. - * @constructor - * @param {function} sendMessage function to deliver messages to the promise's handler - * @param {function?} inspect function that reports the promise's state - * @name Promise - */ - function Promise(sendMessage, inspect) { - this._message = sendMessage; - this.inspect = inspect; - } - - Promise.prototype = { - /** - * Register handlers for this promise. - * @param [onFulfilled] {Function} fulfillment handler - * @param [onRejected] {Function} rejection handler - * @param [onProgress] {Function} progress handler - * @return {Promise} new Promise - */ - then: function(onFulfilled, onRejected, onProgress) { - /*jshint unused:false*/ - var args, sendMessage; - - args = arguments; - sendMessage = this._message; - - return _promise(function(resolve, reject, notify) { - sendMessage('when', args, resolve, notify); - }, this._status && this._status.observed()); - }, - - /** - * Register a rejection handler. Shortcut for .then(undefined, onRejected) - * @param {function?} onRejected - * @return {Promise} - */ - otherwise: function(onRejected) { - return this.then(undef, onRejected); - }, - - /** - * Ensures that onFulfilledOrRejected will be called regardless of whether - * this promise is fulfilled or rejected. onFulfilledOrRejected WILL NOT - * receive the promises' value or reason. Any returned value will be disregarded. - * onFulfilledOrRejected may throw or return a rejected promise to signal - * an additional error. - * @param {function} onFulfilledOrRejected handler to be called regardless of - * fulfillment or rejection - * @returns {Promise} - */ - ensure: function(onFulfilledOrRejected) { - return typeof onFulfilledOrRejected === 'function' - ? this.then(injectHandler, injectHandler)['yield'](this) - : this; - - function injectHandler() { - return resolve(onFulfilledOrRejected()); - } - }, - - /** - * Terminate a promise chain by handling the ultimate fulfillment value or - * rejection reason, and assuming responsibility for all errors. if an - * error propagates out of handleResult or handleFatalError, it will be - * rethrown to the host, resulting in a loud stack track on most platforms - * and a crash on some. - * @param {function?} handleResult - * @param {function?} handleError - * @returns {undefined} - */ - done: function(handleResult, handleError) { - this.then(handleResult, handleError).otherwise(crash); - }, - - /** - * Shortcut for .then(function() { return value; }) - * @param {*} value - * @return {Promise} a promise that: - * - is fulfilled if value is not a promise, or - * - if value is a promise, will fulfill with its value, or reject - * with its reason. - */ - 'yield': function(value) { - return this.then(function() { - return value; - }); - }, - - /** - * Runs a side effect when this promise fulfills, without changing the - * fulfillment value. - * @param {function} onFulfilledSideEffect - * @returns {Promise} - */ - tap: function(onFulfilledSideEffect) { - return this.then(onFulfilledSideEffect)['yield'](this); - }, - - /** - * Assumes that this promise will fulfill with an array, and arranges - * for the onFulfilled to be called with the array as its argument list - * i.e. onFulfilled.apply(undefined, array). - * @param {function} onFulfilled function to receive spread arguments - * @return {Promise} - */ - spread: function(onFulfilled) { - return this.then(function(array) { - // array may contain promises, so resolve its contents. - return all(array, function(array) { - return onFulfilled.apply(undef, array); - }); - }); - }, - - /** - * Shortcut for .then(onFulfilledOrRejected, onFulfilledOrRejected) - * @deprecated - */ - always: function(onFulfilledOrRejected, onProgress) { - return this.then(onFulfilledOrRejected, onFulfilledOrRejected, onProgress); - } - }; - - /** - * Returns a resolved promise. The returned promise will be - * - fulfilled with promiseOrValue if it is a value, or - * - if promiseOrValue is a promise - * - fulfilled with promiseOrValue's value after it is fulfilled - * - rejected with promiseOrValue's reason after it is rejected - * @param {*} value - * @return {Promise} - */ - function resolve(value) { - return promise(function(resolve) { - resolve(value); - }); - } - - /** - * Returns a rejected promise for the supplied promiseOrValue. The returned - * promise will be rejected with: - * - promiseOrValue, if it is a value, or - * - if promiseOrValue is a promise - * - promiseOrValue's value after it is fulfilled - * - promiseOrValue's reason after it is rejected - * @param {*} promiseOrValue the rejected value of the returned {@link Promise} - * @return {Promise} rejected {@link Promise} - */ - function reject(promiseOrValue) { - return when(promiseOrValue, rejected); - } - - /** - * Creates a {promise, resolver} pair, either or both of which - * may be given out safely to consumers. - * The resolver has resolve, reject, and progress. The promise - * has then plus extended promise API. - * - * @return {{ - * promise: Promise, - * resolve: function:Promise, - * reject: function:Promise, - * notify: function:Promise - * resolver: { - * resolve: function:Promise, - * reject: function:Promise, - * notify: function:Promise - * }}} - */ - function defer() { - var deferred, pending, resolved; - - // Optimize object shape - deferred = { - promise: undef, resolve: undef, reject: undef, notify: undef, - resolver: { resolve: undef, reject: undef, notify: undef } - }; - - deferred.promise = pending = promise(makeDeferred); - - return deferred; - - function makeDeferred(resolvePending, rejectPending, notifyPending) { - deferred.resolve = deferred.resolver.resolve = function(value) { - if(resolved) { - return resolve(value); - } - resolved = true; - resolvePending(value); - return pending; - }; - - deferred.reject = deferred.resolver.reject = function(reason) { - if(resolved) { - return resolve(rejected(reason)); - } - resolved = true; - rejectPending(reason); - return pending; - }; - - deferred.notify = deferred.resolver.notify = function(update) { - notifyPending(update); - return update; - }; - } - } - - /** - * Creates a new promise whose fate is determined by resolver. - * @param {function} resolver function(resolve, reject, notify) - * @returns {Promise} promise whose fate is determine by resolver - */ - function promise(resolver) { - return _promise(resolver, monitorApi.PromiseStatus && monitorApi.PromiseStatus()); - } - - /** - * Creates a new promise, linked to parent, whose fate is determined - * by resolver. - * @param {function} resolver function(resolve, reject, notify) - * @param {Promise?} status promise from which the new promise is begotten - * @returns {Promise} promise whose fate is determine by resolver - * @private - */ - function _promise(resolver, status) { - var self, value, consumers = []; - - self = new Promise(_message, inspect); - self._status = status; - - // Call the provider resolver to seal the promise's fate - try { - resolver(promiseResolve, promiseReject, promiseNotify); - } catch(e) { - promiseReject(e); - } - - // Return the promise - return self; - - /** - * Private message delivery. Queues and delivers messages to - * the promise's ultimate fulfillment value or rejection reason. - * @private - * @param {String} type - * @param {Array} args - * @param {Function} resolve - * @param {Function} notify - */ - function _message(type, args, resolve, notify) { - consumers ? consumers.push(deliver) : enqueue(function() { deliver(value); }); - - function deliver(p) { - p._message(type, args, resolve, notify); - } - } - - /** - * Returns a snapshot of the promise's state at the instant inspect() - * is called. The returned object is not live and will not update as - * the promise's state changes. - * @returns {{ state:String, value?:*, reason?:* }} status snapshot - * of the promise. - */ - function inspect() { - return value ? value.inspect() : toPendingState(); - } - - /** - * Transition from pre-resolution state to post-resolution state, notifying - * all listeners of the ultimate fulfillment or rejection - * @param {*|Promise} val resolution value - */ - function promiseResolve(val) { - if(!consumers) { - return; - } - - var queue = consumers; - consumers = undef; - - enqueue(function () { - value = coerce(self, val); - if(status) { - updateStatus(value, status); - } - runHandlers(queue, value); - }); - - } - - /** - * Reject this promise with the supplied reason, which will be used verbatim. - * @param {*} reason reason for the rejection - */ - function promiseReject(reason) { - promiseResolve(rejected(reason)); - } - - /** - * Issue a progress event, notifying all progress listeners - * @param {*} update progress event payload to pass to all listeners - */ - function promiseNotify(update) { - if(consumers) { - var queue = consumers; - enqueue(function () { - runHandlers(queue, progressed(update)); - }); - } - } - } - - /** - * Run a queue of functions as quickly as possible, passing - * value to each. - */ - function runHandlers(queue, value) { - for (var i = 0; i < queue.length; i++) { - queue[i](value); - } - } - - /** - * Creates a fulfilled, local promise as a proxy for a value - * NOTE: must never be exposed - * @param {*} value fulfillment value - * @returns {Promise} - */ - function fulfilled(value) { - return near( - new NearFulfilledProxy(value), - function() { return toFulfilledState(value); } - ); - } - - /** - * Creates a rejected, local promise with the supplied reason - * NOTE: must never be exposed - * @param {*} reason rejection reason - * @returns {Promise} - */ - function rejected(reason) { - return near( - new NearRejectedProxy(reason), - function() { return toRejectedState(reason); } - ); - } - - /** - * Creates a near promise using the provided proxy - * NOTE: must never be exposed - * @param {object} proxy proxy for the promise's ultimate value or reason - * @param {function} inspect function that returns a snapshot of the - * returned near promise's state - * @returns {Promise} - */ - function near(proxy, inspect) { - return new Promise(function (type, args, resolve) { - try { - resolve(proxy[type].apply(proxy, args)); - } catch(e) { - resolve(rejected(e)); - } - }, inspect); - } - - /** - * Create a progress promise with the supplied update. - * @private - * @param {*} update - * @return {Promise} progress promise - */ - function progressed(update) { - return new Promise(function (type, args, _, notify) { - var onProgress = args[2]; - try { - notify(typeof onProgress === 'function' ? onProgress(update) : update); - } catch(e) { - notify(e); - } - }); - } - - /** - * Coerces x to a trusted Promise - * @param {*} x thing to coerce - * @returns {*} Guaranteed to return a trusted Promise. If x - * is trusted, returns x, otherwise, returns a new, trusted, already-resolved - * Promise whose resolution value is: - * * the resolution value of x if it's a foreign promise, or - * * x if it's a value - */ - function coerce(self, x) { - if (x === self) { - return rejected(new TypeError()); - } - - if (x instanceof Promise) { - return x; - } - - try { - var untrustedThen = x === Object(x) && x.then; - - return typeof untrustedThen === 'function' - ? assimilate(untrustedThen, x) - : fulfilled(x); - } catch(e) { - return rejected(e); - } - } - - /** - * Safely assimilates a foreign thenable by wrapping it in a trusted promise - * @param {function} untrustedThen x's then() method - * @param {object|function} x thenable - * @returns {Promise} - */ - function assimilate(untrustedThen, x) { - return promise(function (resolve, reject) { - fcall(untrustedThen, x, resolve, reject); - }); - } - - /** - * Proxy for a near, fulfilled value - * @param {*} value - * @constructor - */ - function NearFulfilledProxy(value) { - this.value = value; - } - - NearFulfilledProxy.prototype.when = function(onResult) { - return typeof onResult === 'function' ? onResult(this.value) : this.value; - }; - - /** - * Proxy for a near rejection - * @param {*} reason - * @constructor - */ - function NearRejectedProxy(reason) { - this.reason = reason; - } - - NearRejectedProxy.prototype.when = function(_, onError) { - if(typeof onError === 'function') { - return onError(this.reason); - } else { - throw this.reason; - } - }; - - function updateStatus(value, status) { - value.then(statusFulfilled, statusRejected); - - function statusFulfilled() { status.fulfilled(); } - function statusRejected(r) { status.rejected(r); } - } - - /** - * Determines if x is promise-like, i.e. a thenable object - * NOTE: Will return true for *any thenable object*, and isn't truly - * safe, since it may attempt to access the `then` property of x (i.e. - * clever/malicious getters may do weird things) - * @param {*} x anything - * @returns {boolean} true if x is promise-like - */ - function isPromiseLike(x) { - return x && typeof x.then === 'function'; - } - - /** - * Initiates a competitive race, returning a promise that will resolve when - * howMany of the supplied promisesOrValues have resolved, or will reject when - * it becomes impossible for howMany to resolve, for example, when - * (promisesOrValues.length - howMany) + 1 input promises reject. - * - * @param {Array} promisesOrValues array of anything, may contain a mix - * of promises and values - * @param howMany {number} number of promisesOrValues to resolve - * @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then() - * @param {function?} [onRejected] DEPRECATED, use returnedPromise.then() - * @param {function?} [onProgress] DEPRECATED, use returnedPromise.then() - * @returns {Promise} promise that will resolve to an array of howMany values that - * resolved first, or will reject with an array of - * (promisesOrValues.length - howMany) + 1 rejection reasons. - */ - function some(promisesOrValues, howMany, onFulfilled, onRejected, onProgress) { - - return when(promisesOrValues, function(promisesOrValues) { - - return promise(resolveSome).then(onFulfilled, onRejected, onProgress); - - function resolveSome(resolve, reject, notify) { - var toResolve, toReject, values, reasons, fulfillOne, rejectOne, len, i; - - len = promisesOrValues.length >>> 0; - - toResolve = Math.max(0, Math.min(howMany, len)); - values = []; - - toReject = (len - toResolve) + 1; - reasons = []; - - // No items in the input, resolve immediately - if (!toResolve) { - resolve(values); - - } else { - rejectOne = function(reason) { - reasons.push(reason); - if(!--toReject) { - fulfillOne = rejectOne = identity; - reject(reasons); - } - }; - - fulfillOne = function(val) { - // This orders the values based on promise resolution order - values.push(val); - if (!--toResolve) { - fulfillOne = rejectOne = identity; - resolve(values); - } - }; - - for(i = 0; i < len; ++i) { - if(i in promisesOrValues) { - when(promisesOrValues[i], fulfiller, rejecter, notify); - } - } - } - - function rejecter(reason) { - rejectOne(reason); - } - - function fulfiller(val) { - fulfillOne(val); - } - } - }); - } - - /** - * Initiates a competitive race, returning a promise that will resolve when - * any one of the supplied promisesOrValues has resolved or will reject when - * *all* promisesOrValues have rejected. - * - * @param {Array|Promise} promisesOrValues array of anything, may contain a mix - * of {@link Promise}s and values - * @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then() - * @param {function?} [onRejected] DEPRECATED, use returnedPromise.then() - * @param {function?} [onProgress] DEPRECATED, use returnedPromise.then() - * @returns {Promise} promise that will resolve to the value that resolved first, or - * will reject with an array of all rejected inputs. - */ - function any(promisesOrValues, onFulfilled, onRejected, onProgress) { - - function unwrapSingleResult(val) { - return onFulfilled ? onFulfilled(val[0]) : val[0]; - } - - return some(promisesOrValues, 1, unwrapSingleResult, onRejected, onProgress); - } - - /** - * Return a promise that will resolve only once all the supplied promisesOrValues - * have resolved. The resolution value of the returned promise will be an array - * containing the resolution values of each of the promisesOrValues. - * @memberOf when - * - * @param {Array|Promise} promisesOrValues array of anything, may contain a mix - * of {@link Promise}s and values - * @param {function?} [onFulfilled] DEPRECATED, use returnedPromise.then() - * @param {function?} [onRejected] DEPRECATED, use returnedPromise.then() - * @param {function?} [onProgress] DEPRECATED, use returnedPromise.then() - * @returns {Promise} - */ - function all(promisesOrValues, onFulfilled, onRejected, onProgress) { - return _map(promisesOrValues, identity).then(onFulfilled, onRejected, onProgress); - } - - /** - * Joins multiple promises into a single returned promise. - * @return {Promise} a promise that will fulfill when *all* the input promises - * have fulfilled, or will reject when *any one* of the input promises rejects. - */ - function join(/* ...promises */) { - return _map(arguments, identity); - } - - /** - * Settles all input promises such that they are guaranteed not to - * be pending once the returned promise fulfills. The returned promise - * will always fulfill, except in the case where `array` is a promise - * that rejects. - * @param {Array|Promise} array or promise for array of promises to settle - * @returns {Promise} promise that always fulfills with an array of - * outcome snapshots for each input promise. - */ - function settle(array) { - return _map(array, toFulfilledState, toRejectedState); - } - - /** - * Promise-aware array map function, similar to `Array.prototype.map()`, - * but input array may contain promises or values. - * @param {Array|Promise} array array of anything, may contain promises and values - * @param {function} mapFunc map function which may return a promise or value - * @returns {Promise} promise that will fulfill with an array of mapped values - * or reject if any input promise rejects. - */ - function map(array, mapFunc) { - return _map(array, mapFunc); - } - - /** - * Internal map that allows a fallback to handle rejections - * @param {Array|Promise} array array of anything, may contain promises and values - * @param {function} mapFunc map function which may return a promise or value - * @param {function?} fallback function to handle rejected promises - * @returns {Promise} promise that will fulfill with an array of mapped values - * or reject if any input promise rejects. - */ - function _map(array, mapFunc, fallback) { - return when(array, function(array) { - - return _promise(resolveMap); - - function resolveMap(resolve, reject, notify) { - var results, len, toResolve, i; - - // Since we know the resulting length, we can preallocate the results - // array to avoid array expansions. - toResolve = len = array.length >>> 0; - results = []; - - if(!toResolve) { - resolve(results); - return; - } - - // Since mapFunc may be async, get all invocations of it into flight - for(i = 0; i < len; i++) { - if(i in array) { - resolveOne(array[i], i); - } else { - --toResolve; - } - } - - function resolveOne(item, i) { - when(item, mapFunc, fallback).then(function(mapped) { - results[i] = mapped; - - if(!--toResolve) { - resolve(results); - } - }, reject, notify); - } - } - }); - } - - /** - * Traditional reduce function, similar to `Array.prototype.reduce()`, but - * input may contain promises and/or values, and reduceFunc - * may return either a value or a promise, *and* initialValue may - * be a promise for the starting value. - * - * @param {Array|Promise} promise array or promise for an array of anything, - * may contain a mix of promises and values. - * @param {function} reduceFunc reduce function reduce(currentValue, nextValue, index, total), - * where total is the total number of items being reduced, and will be the same - * in each call to reduceFunc. - * @returns {Promise} that will resolve to the final reduced value - */ - function reduce(promise, reduceFunc /*, initialValue */) { - var args = fcall(slice, arguments, 1); - - return when(promise, function(array) { - var total; - - total = array.length; - - // Wrap the supplied reduceFunc with one that handles promises and then - // delegates to the supplied. - args[0] = function (current, val, i) { - return when(current, function (c) { - return when(val, function (value) { - return reduceFunc(c, value, i, total); - }); - }); - }; - - return reduceArray.apply(array, args); - }); - } - - // Snapshot states - - /** - * Creates a fulfilled state snapshot - * @private - * @param {*} x any value - * @returns {{state:'fulfilled',value:*}} - */ - function toFulfilledState(x) { - return { state: 'fulfilled', value: x }; - } - - /** - * Creates a rejected state snapshot - * @private - * @param {*} x any reason - * @returns {{state:'rejected',reason:*}} - */ - function toRejectedState(x) { - return { state: 'rejected', reason: x }; - } - - /** - * Creates a pending state snapshot - * @private - * @returns {{state:'pending'}} - */ - function toPendingState() { - return { state: 'pending' }; - } - - // - // Internals, utilities, etc. - // - - var reduceArray, slice, fcall, nextTick, handlerQueue, - setTimeout, funcProto, call, arrayProto, monitorApi, - cjsRequire, MutationObserver, undef; - - cjsRequire = require; - - // - // Shared handler queue processing - // - // Credit to Twisol (https://github.com/Twisol) for suggesting - // this type of extensible queue + trampoline approach for - // next-tick conflation. - - handlerQueue = []; - - /** - * Enqueue a task. If the queue is not currently scheduled to be - * drained, schedule it. - * @param {function} task - */ - function enqueue(task) { - if(handlerQueue.push(task) === 1) { - nextTick(drainQueue); - } - } - - /** - * Drain the handler queue entirely, being careful to allow the - * queue to be extended while it is being processed, and to continue - * processing until it is truly empty. - */ - function drainQueue() { - runHandlers(handlerQueue); - handlerQueue = []; - } - - // capture setTimeout to avoid being caught by fake timers - // used in time based tests - setTimeout = global.setTimeout; - - // Allow attaching the monitor to when() if env has no console - monitorApi = typeof console !== 'undefined' ? console : when; - - // Sniff "best" async scheduling option - // Prefer process.nextTick or MutationObserver, then check for - // vertx and finally fall back to setTimeout - /*global process*/ - if (typeof process === 'object' && process.nextTick) { - nextTick = process.nextTick; - } else if(MutationObserver = global.MutationObserver || global.WebKitMutationObserver) { - nextTick = (function(document, MutationObserver, drainQueue) { - var el = document.createElement('div'); - new MutationObserver(drainQueue).observe(el, { attributes: true }); - - return function() { - el.setAttribute('x', 'x'); - }; - }(document, MutationObserver, drainQueue)); - } else { - try { - // vert.x 1.x || 2.x - nextTick = cjsRequire('vertx').runOnLoop || cjsRequire('vertx').runOnContext; - } catch(ignore) { - nextTick = function(t) { setTimeout(t, 0); }; - } - } - - // - // Capture/polyfill function and array utils - // - - // Safe function calls - funcProto = Function.prototype; - call = funcProto.call; - fcall = funcProto.bind - ? call.bind(call) - : function(f, context) { - return f.apply(context, slice.call(arguments, 2)); - }; - - // Safe array ops - arrayProto = []; - slice = arrayProto.slice; - - // ES5 reduce implementation if native not available - // See: http://es5.github.com/#x15.4.4.21 as there are many - // specifics and edge cases. ES5 dictates that reduce.length === 1 - // This implementation deviates from ES5 spec in the following ways: - // 1. It does not check if reduceFunc is a Callable - reduceArray = arrayProto.reduce || - function(reduceFunc /*, initialValue */) { - /*jshint maxcomplexity: 7*/ - var arr, args, reduced, len, i; - - i = 0; - arr = Object(this); - len = arr.length >>> 0; - args = arguments; - - // If no initialValue, use first item of array (we know length !== 0 here) - // and adjust i to start at second item - if(args.length <= 1) { - // Skip to the first real element in the array - for(;;) { - if(i in arr) { - reduced = arr[i++]; - break; - } - - // If we reached the end of the array without finding any real - // elements, it's a TypeError - if(++i >= len) { - throw new TypeError(); - } - } - } else { - // If initialValue provided, use it - reduced = args[1]; - } - - // Do the actual reduce - for(;i < len; ++i) { - if(i in arr) { - reduced = reduceFunc(reduced, arr[i], i, arr); - } - } - - return reduced; - }; - - function identity(x) { - return x; - } - - function crash(fatalError) { - if(typeof monitorApi.reportUnhandled === 'function') { - monitorApi.reportUnhandled(); - } else { - enqueue(function() { - throw fatalError; - }); - } - - throw fatalError; - } - - return when; -}); -})(typeof define === 'function' && define.amd ? define : function (factory) { module.exports = factory(require); }, this); - -},{"__browserify_process":15}],58:[function(require,module,exports){ -var es = { - Client: require('./lib/client'), - errors: require('./lib/errors'), - ConnectionPool: require('./lib/connection_pool'), - Transport: require('./lib/transport') -}; - -module.exports = es; - -},{"./lib/client":60,"./lib/connection_pool":63,"./lib/errors":68,"./lib/transport":78}],59:[function(require,module,exports){ -/* jshint maxlen: false */ - -var ca = require('./client_action'); -var api = module.exports = {}; - -api._namespaces = ['cluster', 'indices']; - -/** - * Perform a [bulk](http://elasticsearch.org/guide/reference/api/bulk/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} params.consistency - Explicit write consistency setting for the operation - * @param {Boolean} params.refresh - Refresh the index after performing the operation - * @param {String} [params.replication=sync] - Explicitely set the replication type - * @param {String} params.type - Default document type for items which don't provide one - * @param {String} params.index - Default index for items which don't provide one - */ -api.bulk = ca({ - params: { - consistency: { - type: 'enum', - options: [ - 'one', - 'quorum', - 'all' - ] - }, - refresh: { - type: 'boolean' - }, - replication: { - type: 'enum', - 'default': 'sync', - options: [ - 'sync', - 'async' - ] - }, - type: { - type: 'string' - } - }, - urls: [ - { - fmt: '/<%=index%>/<%=type%>/_bulk', - req: { - index: { - type: 'string' - }, - type: { - type: 'string' - } - } - }, - { - fmt: '/<%=index%>/_bulk', - req: { - index: { - type: 'string' - } - } - }, - { - fmt: '/_bulk' - } - ], - bulkBody: true, - method: 'POST' -}); - - -/** - * Perform a [clearScroll](http://www.elasticsearch.org/guide/reference/api/search/scroll/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String or String[] or Boolean} params.scrollId - A comma-separated list of scroll IDs to clear - */ -api.clearScroll = ca({ - url: { - fmt: '/_search/scroll/<%=scrollId%>', - req: { - scrollId: { - type: 'list' - } - }, - sortOrder: -1 - }, - method: 'DELETE' -}); - - -api.cluster = function ClusterNS(transport) { - this.transport = transport; -}; - -/** - * Perform a [cluster.getSettings](http://elasticsearch.org/guide/reference/api/admin-cluster-update-settings/) request - * - * @param {Object} params - An object with parameters used to carry out this action - */ -api.cluster.prototype.getSettings = ca({ - url: { - fmt: '/_cluster/settings' - } -}); - - -/** - * Perform a [cluster.health](http://elasticsearch.org/guide/reference/api/admin-cluster-health/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} [params.level=cluster] - Specify the level of detail for returned information - * @param {Boolean} params.local - Return local information, do not retrieve the state from master node (default: false) - * @param {Date or Number} params.masterTimeout - Explicit operation timeout for connection to master node - * @param {Date or Number} params.timeout - Explicit operation timeout - * @param {Number} params.waitForActiveShards - Wait until the specified number of shards is active - * @param {String} params.waitForNodes - Wait until the specified number of nodes is available - * @param {Number} params.waitForRelocatingShards - Wait until the specified number of relocating shards is finished - * @param {String} params.waitForStatus - Wait until cluster is in a specific state - * @param {String} params.index - Limit the information returned to a specific index - */ -api.cluster.prototype.health = ca({ - params: { - level: { - type: 'enum', - 'default': 'cluster', - options: [ - 'cluster', - 'indices', - 'shards' - ] - }, - local: { - type: 'boolean' - }, - masterTimeout: { - type: 'time', - name: 'master_timeout' - }, - timeout: { - type: 'time' - }, - waitForActiveShards: { - type: 'number', - name: 'wait_for_active_shards' - }, - waitForNodes: { - type: 'string', - name: 'wait_for_nodes' - }, - waitForRelocatingShards: { - type: 'number', - name: 'wait_for_relocating_shards' - }, - waitForStatus: { - type: 'enum', - 'default': null, - options: [ - 'green', - 'yellow', - 'red' - ], - name: 'wait_for_status' - } - }, - urls: [ - { - fmt: '/_cluster/health/<%=index%>', - req: { - index: { - type: 'string' - } - } - }, - { - fmt: '/_cluster/health' - } - ] -}); - - -/** - * Perform a [cluster.nodeHotThreads](http://www.elasticsearch.org/guide/reference/api/admin-cluster-nodes-hot-threads/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Date or Number} params.interval - The interval for the second sampling of threads - * @param {Number} params.snapshots - Number of samples of thread stacktrace (default: 10) - * @param {Number} params.threads - Specify the number of threads to provide information for (default: 3) - * @param {String} params.type - The type to sample (default: cpu) - * @param {String or String[] or Boolean} params.nodeId - A comma-separated list of node IDs or names to limit the returned information; use `_local` to return information from the node you're connecting to, leave empty to get information from all nodes - */ -api.cluster.prototype.nodeHotThreads = ca({ - params: { - interval: { - type: 'time' - }, - snapshots: { - type: 'number' - }, - threads: { - type: 'number' - }, - type: { - type: 'enum', - options: [ - 'cpu', - 'wait', - 'block' - ] - } - }, - urls: [ - { - fmt: '/_nodes/<%=nodeId%>/hotthreads', - req: { - nodeId: { - type: 'list' - } - } - }, - { - fmt: '/_nodes/hotthreads' - } - ] -}); - - -/** - * Perform a [cluster.nodeInfo](http://elasticsearch.org/guide/reference/api/admin-cluster-nodes-info/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Boolean} params.all - Return all available information - * @param {Boolean} params.clear - Reset the default settings - * @param {Boolean} params.http - Return information about HTTP - * @param {Boolean} params.jvm - Return information about the JVM - * @param {Boolean} params.network - Return information about network - * @param {Boolean} params.os - Return information about the operating system - * @param {Boolean} params.plugin - Return information about plugins - * @param {Boolean} params.process - Return information about the Elasticsearch process - * @param {Boolean} params.settings - Return information about node settings - * @param {Boolean} params.threadPool - Return information about the thread pool - * @param {Date or Number} params.timeout - Explicit operation timeout - * @param {Boolean} params.transport - Return information about transport - * @param {String or String[] or Boolean} params.nodeId - A comma-separated list of node IDs or names to limit the returned information; use `_local` to return information from the node you're connecting to, leave empty to get information from all nodes - */ -api.cluster.prototype.nodeInfo = ca({ - params: { - all: { - type: 'boolean' - }, - clear: { - type: 'boolean' - }, - http: { - type: 'boolean' - }, - jvm: { - type: 'boolean' - }, - network: { - type: 'boolean' - }, - os: { - type: 'boolean' - }, - plugin: { - type: 'boolean' - }, - process: { - type: 'boolean' - }, - settings: { - type: 'boolean' - }, - threadPool: { - type: 'boolean', - name: 'thread_pool' - }, - timeout: { - type: 'time' - }, - transport: { - type: 'boolean' - } - }, - urls: [ - { - fmt: '/_nodes/<%=nodeId%>', - req: { - nodeId: { - type: 'list' - } - } - }, - { - fmt: '/_nodes' - } - ] -}); - - -/** - * Perform a [cluster.nodeShutdown](http://elasticsearch.org/guide/reference/api/admin-cluster-nodes-shutdown/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Date or Number} params.delay - Set the delay for the operation (default: 1s) - * @param {Boolean} params.exit - Exit the JVM as well (default: true) - * @param {String or String[] or Boolean} params.nodeId - A comma-separated list of node IDs or names to perform the operation on; use `_local` to perform the operation on the node you're connected to, leave empty to perform the operation on all nodes - */ -api.cluster.prototype.nodeShutdown = ca({ - params: { - delay: { - type: 'time' - }, - exit: { - type: 'boolean' - } - }, - urls: [ - { - fmt: '/_cluster/nodes/<%=nodeId%>/_shutdown', - req: { - nodeId: { - type: 'list' - } - } - }, - { - fmt: '/_shutdown' - } - ], - method: 'POST' -}); - - -/** - * Perform a [cluster.nodeStats](http://elasticsearch.org/guide/reference/api/admin-cluster-nodes-stats/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Boolean} params.all - Return all available information - * @param {Boolean} params.clear - Reset the default level of detail - * @param {String or String[] or Boolean} params.fields - A comma-separated list of fields to return detailed information for, when returning the `indices` metric family (supports wildcards) - * @param {Boolean} params.fs - Return information about the filesystem - * @param {Boolean} params.http - Return information about HTTP - * @param {Boolean} params.indices - Return information about indices - * @param {Boolean} params.jvm - Return information about the JVM - * @param {Boolean} params.network - Return information about network - * @param {Boolean} params.os - Return information about the operating system - * @param {Boolean} params.process - Return information about the Elasticsearch process - * @param {Boolean} params.threadPool - Return information about the thread pool - * @param {Boolean} params.transport - Return information about transport - * @param {String} params.metricFamily - Limit the information returned to a certain metric family - * @param {String} params.metric - Limit the information returned for `indices` family to a specific metric - * @param {String or String[] or Boolean} params.nodeId - A comma-separated list of node IDs or names to limit the returned information; use `_local` to return information from the node you're connecting to, leave empty to get information from all nodes - */ -api.cluster.prototype.nodeStats = ca({ - params: { - all: { - type: 'boolean' - }, - clear: { - type: 'boolean' - }, - fields: { - type: 'list' - }, - fs: { - type: 'boolean' - }, - http: { - type: 'boolean' - }, - indices: { - type: 'boolean' - }, - jvm: { - type: 'boolean' - }, - network: { - type: 'boolean' - }, - os: { - type: 'boolean' - }, - process: { - type: 'boolean' - }, - threadPool: { - type: 'boolean', - name: 'thread_pool' - }, - transport: { - type: 'boolean' - } - }, - urls: [ - { - fmt: '/_nodes/<%=nodeId%>/stats', - req: { - nodeId: { - type: 'list' - } - } - }, - { - fmt: '/_nodes/stats' - } - ] -}); - - -/** - * Perform a [cluster.putSettings](http://elasticsearch.org/guide/reference/api/admin-cluster-update-settings/) request - * - * @param {Object} params - An object with parameters used to carry out this action - */ -api.cluster.prototype.putSettings = ca({ - url: { - fmt: '/_cluster/settings' - }, - method: 'PUT' -}); - - -/** - * Perform a [cluster.reroute](http://elasticsearch.org/guide/reference/api/admin-cluster-reroute/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Boolean} params.dryRun - Simulate the operation only and return the resulting state - * @param {Boolean} params.filterMetadata - Don't return cluster state metadata (default: false) - */ -api.cluster.prototype.reroute = ca({ - params: { - dryRun: { - type: 'boolean', - name: 'dry_run' - }, - filterMetadata: { - type: 'boolean', - name: 'filter_metadata' - } - }, - url: { - fmt: '/_cluster/reroute' - }, - method: 'POST' -}); - - -/** - * Perform a [cluster.state](http://elasticsearch.org/guide/reference/api/admin-cluster-state/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Boolean} params.filterBlocks - Do not return information about blocks - * @param {Boolean} params.filterIndexTemplates - Do not return information about index templates - * @param {String or String[] or Boolean} params.filterIndices - Limit returned metadata information to specific indices - * @param {Boolean} params.filterMetadata - Do not return information about indices metadata - * @param {Boolean} params.filterNodes - Do not return information about nodes - * @param {Boolean} params.filterRoutingTable - Do not return information about shard allocation (`routing_table` and `routing_nodes`) - * @param {Boolean} params.local - Return local information, do not retrieve the state from master node (default: false) - * @param {Date or Number} params.masterTimeout - Specify timeout for connection to master - */ -api.cluster.prototype.state = ca({ - params: { - filterBlocks: { - type: 'boolean', - name: 'filter_blocks' - }, - filterIndexTemplates: { - type: 'boolean', - name: 'filter_index_templates' - }, - filterIndices: { - type: 'list', - name: 'filter_indices' - }, - filterMetadata: { - type: 'boolean', - name: 'filter_metadata' - }, - filterNodes: { - type: 'boolean', - name: 'filter_nodes' - }, - filterRoutingTable: { - type: 'boolean', - name: 'filter_routing_table' - }, - local: { - type: 'boolean' - }, - masterTimeout: { - type: 'time', - name: 'master_timeout' - } - }, - url: { - fmt: '/_cluster/state' - } -}); - - -/** - * Perform a [count](http://elasticsearch.org/guide/reference/api/count/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} [params.ignoreIndices=none] - When performed on multiple indices, allows to ignore `missing` ones - * @param {Number} params.minScore - Include only documents with a specific `_score` value in the result - * @param {String} params.preference - Specify the node or shard the operation should be performed on (default: random) - * @param {String} params.routing - Specific routing value - * @param {String} params.source - The URL-encoded query definition (instead of using the request body) - * @param {String or String[] or Boolean} params.index - A comma-separated list of indices to restrict the results - * @param {String or String[] or Boolean} params.type - A comma-separated list of types to restrict the results - */ -api.count = ca({ - params: { - ignoreIndices: { - type: 'enum', - 'default': 'none', - options: [ - 'none', - 'missing' - ], - name: 'ignore_indices' - }, - minScore: { - type: 'number', - name: 'min_score' - }, - preference: { - type: 'string' - }, - routing: { - type: 'string' - }, - source: { - type: 'string' - } - }, - urls: [ - { - fmt: '/<%=index%>/<%=type%>/_count', - req: { - index: { - type: 'list' - }, - type: { - type: 'list' - } - } - }, - { - fmt: '/<%=index%>/_count', - req: { - index: { - type: 'list' - } - } - }, - { - fmt: '/_count' - } - ], - method: 'POST' -}); - - -/** - * Perform a [delete](http://elasticsearch.org/guide/reference/api/delete/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} params.consistency - Specific write consistency setting for the operation - * @param {String} params.parent - ID of parent document - * @param {Boolean} params.refresh - Refresh the index after performing the operation - * @param {String} [params.replication=sync] - Specific replication type - * @param {String} params.routing - Specific routing value - * @param {Date or Number} params.timeout - Explicit operation timeout - * @param {Number} params.version - Explicit version number for concurrency control - * @param {String} params.versionType - Specific version type - * @param {String} params.id - The document ID - * @param {String} params.index - The name of the index - * @param {String} params.type - The type of the document - */ -api['delete'] = ca({ - params: { - consistency: { - type: 'enum', - options: [ - 'one', - 'quorum', - 'all' - ] - }, - parent: { - type: 'string' - }, - refresh: { - type: 'boolean' - }, - replication: { - type: 'enum', - 'default': 'sync', - options: [ - 'sync', - 'async' - ] - }, - routing: { - type: 'string' - }, - timeout: { - type: 'time' - }, - version: { - type: 'number' - }, - versionType: { - type: 'enum', - options: [ - 'internal', - 'external' - ], - name: 'version_type' - } - }, - url: { - fmt: '/<%=index%>/<%=type%>/<%=id%>', - req: { - index: { - type: 'string' - }, - type: { - type: 'string' - }, - id: { - type: 'string' - } - }, - sortOrder: -3 - }, - method: 'DELETE' -}); - - -/** - * Perform a [deleteByQuery](http://www.elasticsearch.org/guide/reference/api/delete-by-query/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} params.analyzer - The analyzer to use for the query string - * @param {String} params.consistency - Specific write consistency setting for the operation - * @param {String} [params.defaultOperator=OR] - The default operator for query string query (AND or OR) - * @param {String} params.df - The field to use as default where no field prefix is given in the query string - * @param {String} [params.ignoreIndices=none] - When performed on multiple indices, allows to ignore `missing` ones - * @param {String} [params.replication=sync] - Specific replication type - * @param {String} params.q - Query in the Lucene query string syntax - * @param {String} params.routing - Specific routing value - * @param {String} params.source - The URL-encoded query definition (instead of using the request body) - * @param {Date or Number} params.timeout - Explicit operation timeout - * @param {String or String[] or Boolean} params.index - A comma-separated list of indices to restrict the operation; use `_all` to perform the operation on all indices - * @param {String or String[] or Boolean} params.type - A comma-separated list of types to restrict the operation - */ -api.deleteByQuery = ca({ - params: { - analyzer: { - type: 'string' - }, - consistency: { - type: 'enum', - options: [ - 'one', - 'quorum', - 'all' - ] - }, - defaultOperator: { - type: 'enum', - 'default': 'OR', - options: [ - 'AND', - 'OR' - ], - name: 'default_operator' - }, - df: { - type: 'string' - }, - ignoreIndices: { - type: 'enum', - 'default': 'none', - options: [ - 'none', - 'missing' - ], - name: 'ignore_indices' - }, - replication: { - type: 'enum', - 'default': 'sync', - options: [ - 'sync', - 'async' - ] - }, - q: { - type: 'string' - }, - routing: { - type: 'string' - }, - source: { - type: 'string' - }, - timeout: { - type: 'time' - } - }, - urls: [ - { - fmt: '/<%=index%>/<%=type%>/_query', - req: { - index: { - type: 'list' - }, - type: { - type: 'list' - } - } - }, - { - fmt: '/<%=index%>/_query', - req: { - index: { - type: 'list' - } - } - } - ], - method: 'DELETE' -}); - - -/** - * Perform a [exists](http://elasticsearch.org/guide/reference/api/get/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} params.parent - The ID of the parent document - * @param {String} params.preference - Specify the node or shard the operation should be performed on (default: random) - * @param {Boolean} params.realtime - Specify whether to perform the operation in realtime or search mode - * @param {Boolean} params.refresh - Refresh the shard containing the document before performing the operation - * @param {String} params.routing - Specific routing value - * @param {String} params.id - The document ID - * @param {String} params.index - The name of the index - * @param {String} [params.type=_all] - The type of the document (use `_all` to fetch the first document matching the ID across all types) - */ -api.exists = ca({ - params: { - parent: { - type: 'string' - }, - preference: { - type: 'string' - }, - realtime: { - type: 'boolean' - }, - refresh: { - type: 'boolean' - }, - routing: { - type: 'string' - } - }, - url: { - fmt: '/<%=index%>/<%=type%>/<%=id%>', - opt: { - type: { - type: 'string', - 'default': '_all' - } - }, - req: { - index: { - type: 'string' - }, - id: { - type: 'string' - } - }, - sortOrder: -2 - }, - castExists: true, - method: 'HEAD' -}); - - -/** - * Perform a [explain](http://elasticsearch.org/guide/reference/api/explain/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Boolean} params.analyzeWildcard - Specify whether wildcards and prefix queries in the query string query should be analyzed (default: false) - * @param {String} params.analyzer - The analyzer for the query string query - * @param {String} [params.defaultOperator=OR] - The default operator for query string query (AND or OR) - * @param {String} params.df - The default field for query string query (default: _all) - * @param {String or String[] or Boolean} params.fields - A comma-separated list of fields to return in the response - * @param {Boolean} params.lenient - Specify whether format-based query failures (such as providing text to a numeric field) should be ignored - * @param {Boolean} params.lowercaseExpandedTerms - Specify whether query terms should be lowercased - * @param {String} params.parent - The ID of the parent document - * @param {String} params.preference - Specify the node or shard the operation should be performed on (default: random) - * @param {String} params.q - Query in the Lucene query string syntax - * @param {String} params.routing - Specific routing value - * @param {String or String[] or Boolean} params.source - True or false to return the _source field or not, or a list of fields to return - * @param {String or String[] or Boolean} params.sourceExclude - A list of fields to exclude from the returned _source field - * @param {String or String[] or Boolean} params.sourceInclude - A list of fields to extract and return from the _source field - * @param {String} params.id - The document ID - * @param {String} params.index - The name of the index - * @param {String} params.type - The type of the document - */ -api.explain = ca({ - params: { - analyzeWildcard: { - type: 'boolean', - name: 'analyze_wildcard' - }, - analyzer: { - type: 'string' - }, - defaultOperator: { - type: 'enum', - 'default': 'OR', - options: [ - 'AND', - 'OR' - ], - name: 'default_operator' - }, - df: { - type: 'string' - }, - fields: { - type: 'list' - }, - lenient: { - type: 'boolean' - }, - lowercaseExpandedTerms: { - type: 'boolean', - name: 'lowercase_expanded_terms' - }, - parent: { - type: 'string' - }, - preference: { - type: 'string' - }, - q: { - type: 'string' - }, - routing: { - type: 'string' - }, - source: { - type: 'list', - name: '_source' - }, - sourceExclude: { - type: 'list', - name: '_source_exclude' - }, - sourceInclude: { - type: 'list', - name: '_source_include' - } - }, - url: { - fmt: '/<%=index%>/<%=type%>/<%=id%>/_explain', - req: { - index: { - type: 'string' - }, - type: { - type: 'string' - }, - id: { - type: 'string' - } - }, - sortOrder: -3 - }, - method: 'POST' -}); - - -/** - * Perform a [get](http://elasticsearch.org/guide/reference/api/get/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String or String[] or Boolean} params.fields - A comma-separated list of fields to return in the response - * @param {String} params.parent - The ID of the parent document - * @param {String} params.preference - Specify the node or shard the operation should be performed on (default: random) - * @param {Boolean} params.realtime - Specify whether to perform the operation in realtime or search mode - * @param {Boolean} params.refresh - Refresh the shard containing the document before performing the operation - * @param {String} params.routing - Specific routing value - * @param {String or String[] or Boolean} params.source - True or false to return the _source field or not, or a list of fields to return - * @param {String or String[] or Boolean} params.sourceExclude - A list of fields to exclude from the returned _source field - * @param {String or String[] or Boolean} params.sourceInclude - A list of fields to extract and return from the _source field - * @param {String} params.id - The document ID - * @param {String} params.index - The name of the index - * @param {String} [params.type=_all] - The type of the document (use `_all` to fetch the first document matching the ID across all types) - */ -api.get = ca({ - params: { - fields: { - type: 'list' - }, - parent: { - type: 'string' - }, - preference: { - type: 'string' - }, - realtime: { - type: 'boolean' - }, - refresh: { - type: 'boolean' - }, - routing: { - type: 'string' - }, - source: { - type: 'list', - name: '_source' - }, - sourceExclude: { - type: 'list', - name: '_source_exclude' - }, - sourceInclude: { - type: 'list', - name: '_source_include' - } - }, - url: { - fmt: '/<%=index%>/<%=type%>/<%=id%>', - opt: { - type: { - type: 'string', - 'default': '_all' - } - }, - req: { - index: { - type: 'string' - }, - id: { - type: 'string' - } - }, - sortOrder: -2 - } -}); - - -/** - * Perform a [getSource](http://elasticsearch.org/guide/reference/api/get/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String or String[] or Boolean} params.exclude - A list of fields to exclude from the returned _source field - * @param {String or String[] or Boolean} params.include - A list of fields to extract and return from the _source field - * @param {String} params.parent - The ID of the parent document - * @param {String} params.preference - Specify the node or shard the operation should be performed on (default: random) - * @param {Boolean} params.realtime - Specify whether to perform the operation in realtime or search mode - * @param {Boolean} params.refresh - Refresh the shard containing the document before performing the operation - * @param {String} params.routing - Specific routing value - * @param {String} params.id - The document ID - * @param {String} params.index - The name of the index - * @param {String} [params.type=_all] - The type of the document; use `_all` to fetch the first document matching the ID across all types - */ -api.getSource = ca({ - params: { - exclude: { - type: 'list' - }, - include: { - type: 'list' - }, - parent: { - type: 'string' - }, - preference: { - type: 'string' - }, - realtime: { - type: 'boolean' - }, - refresh: { - type: 'boolean' - }, - routing: { - type: 'string' - } - }, - url: { - fmt: '/<%=index%>/<%=type%>/<%=id%>/_source', - opt: { - type: { - type: 'string', - 'default': '_all' - } - }, - req: { - index: { - type: 'string' - }, - id: { - type: 'string' - } - }, - sortOrder: -2 - } -}); - - -/** - * Perform a [index](http://elasticsearch.org/guide/reference/api/index_/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} params.consistency - Explicit write consistency setting for the operation - * @param {String} [params.opType=index] - Explicit operation type - * @param {String} params.parent - ID of the parent document - * @param {String} params.percolate - Percolator queries to execute while indexing the document - * @param {Boolean} params.refresh - Refresh the index after performing the operation - * @param {String} [params.replication=sync] - Specific replication type - * @param {String} params.routing - Specific routing value - * @param {Date or Number} params.timeout - Explicit operation timeout - * @param {Date or Number} params.timestamp - Explicit timestamp for the document - * @param {Duration} params.ttl - Expiration time for the document - * @param {Number} params.version - Explicit version number for concurrency control - * @param {String} params.versionType - Specific version type - * @param {String} params.id - Document ID - * @param {String} params.index - The name of the index - * @param {String} params.type - The type of the document - */ -api.index = ca({ - params: { - consistency: { - type: 'enum', - options: [ - 'one', - 'quorum', - 'all' - ] - }, - opType: { - type: 'enum', - 'default': 'index', - options: [ - 'index', - 'create' - ], - name: 'op_type' - }, - parent: { - type: 'string' - }, - percolate: { - type: 'string' - }, - refresh: { - type: 'boolean' - }, - replication: { - type: 'enum', - 'default': 'sync', - options: [ - 'sync', - 'async' - ] - }, - routing: { - type: 'string' - }, - timeout: { - type: 'time' - }, - timestamp: { - type: 'time' - }, - ttl: { - type: 'duration' - }, - version: { - type: 'number' - }, - versionType: { - type: 'enum', - options: [ - 'internal', - 'external' - ], - name: 'version_type' - } - }, - urls: [ - { - fmt: '/<%=index%>/<%=type%>/<%=id%>', - req: { - index: { - type: 'string' - }, - type: { - type: 'string' - }, - id: { - type: 'string' - } - } - }, - { - fmt: '/<%=index%>/<%=type%>', - req: { - index: { - type: 'string' - }, - type: { - type: 'string' - } - } - } - ], - method: 'POST' -}); - - -api.indices = function IndicesNS(transport) { - this.transport = transport; -}; - -/** - * Perform a [indices.analyze](http://www.elasticsearch.org/guide/reference/api/admin-indices-analyze/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} params.analyzer - The name of the analyzer to use - * @param {String} params.field - Use the analyzer configured for this field (instead of passing the analyzer name) - * @param {String or String[] or Boolean} params.filters - A comma-separated list of filters to use for the analysis - * @param {String} params.index - The name of the index to scope the operation - * @param {Boolean} params.preferLocal - With `true`, specify that a local shard should be used if available, with `false`, use a random shard (default: true) - * @param {String} params.text - The text on which the analysis should be performed (when request body is not used) - * @param {String} params.tokenizer - The name of the tokenizer to use for the analysis - * @param {String} [params.format=detailed] - Format of the output - */ -api.indices.prototype.analyze = ca({ - params: { - analyzer: { - type: 'string' - }, - field: { - type: 'string' - }, - filters: { - type: 'list' - }, - index: { - type: 'string' - }, - preferLocal: { - type: 'boolean', - name: 'prefer_local' - }, - text: { - type: 'string' - }, - tokenizer: { - type: 'string' - }, - format: { - type: 'enum', - 'default': 'detailed', - options: [ - 'detailed', - 'text' - ] - } - }, - urls: [ - { - fmt: '/<%=index%>/_analyze', - req: { - index: { - type: 'string' - } - } - }, - { - fmt: '/_analyze' - } - ], - method: 'POST' -}); - - -/** - * Perform a [indices.clearCache](http://www.elasticsearch.org/guide/reference/api/admin-indices-clearcache/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Boolean} params.fieldData - Clear field data - * @param {Boolean} params.fielddata - Clear field data - * @param {String or String[] or Boolean} params.fields - A comma-separated list of fields to clear when using the `field_data` parameter (default: all) - * @param {Boolean} params.filter - Clear filter caches - * @param {Boolean} params.filterCache - Clear filter caches - * @param {Boolean} params.filterKeys - A comma-separated list of keys to clear when using the `filter_cache` parameter (default: all) - * @param {Boolean} params.id - Clear ID caches for parent/child - * @param {Boolean} params.idCache - Clear ID caches for parent/child - * @param {String} [params.ignoreIndices=none] - When performed on multiple indices, allows to ignore `missing` ones - * @param {String or String[] or Boolean} params.index - A comma-separated list of index name to limit the operation - * @param {Boolean} params.recycler - Clear the recycler cache - */ -api.indices.prototype.clearCache = ca({ - params: { - fieldData: { - type: 'boolean', - name: 'field_data' - }, - fielddata: { - type: 'boolean' - }, - fields: { - type: 'list' - }, - filter: { - type: 'boolean' - }, - filterCache: { - type: 'boolean', - name: 'filter_cache' - }, - filterKeys: { - type: 'boolean', - name: 'filter_keys' - }, - id: { - type: 'boolean' - }, - idCache: { - type: 'boolean', - name: 'id_cache' - }, - ignoreIndices: { - type: 'enum', - 'default': 'none', - options: [ - 'none', - 'missing' - ], - name: 'ignore_indices' - }, - index: { - type: 'list' - }, - recycler: { - type: 'boolean' - } - }, - urls: [ - { - fmt: '/<%=index%>/_cache/clear', - req: { - index: { - type: 'list' - } - } - }, - { - fmt: '/_cache/clear' - } - ], - method: 'POST' -}); - - -/** - * Perform a [indices.close](http://www.elasticsearch.org/guide/reference/api/admin-indices-open-close/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Date or Number} params.timeout - Explicit operation timeout - * @param {Date or Number} params.masterTimeout - Specify timeout for connection to master - * @param {String} params.index - The name of the index - */ -api.indices.prototype.close = ca({ - params: { - timeout: { - type: 'time' - }, - masterTimeout: { - type: 'time', - name: 'master_timeout' - } - }, - url: { - fmt: '/<%=index%>/_close', - req: { - index: { - type: 'string' - } - }, - sortOrder: -1 - }, - method: 'POST' -}); - - -/** - * Perform a [indices.create](http://www.elasticsearch.org/guide/reference/api/admin-indices-create-index/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Date or Number} params.timeout - Explicit operation timeout - * @param {Date or Number} params.masterTimeout - Specify timeout for connection to master - * @param {String} params.index - The name of the index - */ -api.indices.prototype.create = ca({ - params: { - timeout: { - type: 'time' - }, - masterTimeout: { - type: 'time', - name: 'master_timeout' - } - }, - url: { - fmt: '/<%=index%>', - req: { - index: { - type: 'string' - } - }, - sortOrder: -1 - }, - method: 'POST' -}); - - -/** - * Perform a [indices.delete](http://www.elasticsearch.org/guide/reference/api/admin-indices-delete-index/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Date or Number} params.timeout - Explicit operation timeout - * @param {Date or Number} params.masterTimeout - Specify timeout for connection to master - * @param {String or String[] or Boolean} params.index - A comma-separated list of indices to delete; use `_all` or empty string to delete all indices - */ -api.indices.prototype['delete'] = ca({ - params: { - timeout: { - type: 'time' - }, - masterTimeout: { - type: 'time', - name: 'master_timeout' - } - }, - urls: [ - { - fmt: '/<%=index%>', - req: { - index: { - type: 'list' - } - } - }, - { - fmt: '/' - } - ], - method: 'DELETE' -}); - - -/** - * Perform a [indices.deleteAlias](http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Date or Number} params.timeout - Explicit timestamp for the document - * @param {Date or Number} params.masterTimeout - Specify timeout for connection to master - * @param {String} params.index - The name of the index with an alias - * @param {String} params.name - The name of the alias to be deleted - */ -api.indices.prototype.deleteAlias = ca({ - params: { - timeout: { - type: 'time' - }, - masterTimeout: { - type: 'time', - name: 'master_timeout' - } - }, - url: { - fmt: '/<%=index%>/_alias/<%=name%>', - req: { - index: { - type: 'string' - }, - name: { - type: 'string' - } - }, - sortOrder: -2 - }, - method: 'DELETE' -}); - - -/** - * Perform a [indices.deleteMapping](http://www.elasticsearch.org/guide/reference/api/admin-indices-delete-mapping/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Date or Number} params.masterTimeout - Specify timeout for connection to master - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names; use `_all` for all indices - * @param {String} params.type - The name of the document type to delete - */ -api.indices.prototype.deleteMapping = ca({ - params: { - masterTimeout: { - type: 'time', - name: 'master_timeout' - } - }, - url: { - fmt: '/<%=index%>/<%=type%>', - req: { - index: { - type: 'list' - }, - type: { - type: 'string' - } - }, - sortOrder: -2 - }, - method: 'DELETE' -}); - - -/** - * Perform a [indices.deleteTemplate](http://www.elasticsearch.org/guide/reference/api/admin-indices-templates/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Date or Number} params.timeout - Explicit operation timeout - * @param {Date or Number} params.masterTimeout - Specify timeout for connection to master - * @param {String} params.name - The name of the template - */ -api.indices.prototype.deleteTemplate = ca({ - params: { - timeout: { - type: 'time' - }, - masterTimeout: { - type: 'time', - name: 'master_timeout' - } - }, - url: { - fmt: '/_template/<%=name%>', - req: { - name: { - type: 'string' - } - }, - sortOrder: -1 - }, - method: 'DELETE' -}); - - -/** - * Perform a [indices.deleteWarmer](http://www.elasticsearch.org/guide/reference/api/admin-indices-warmers/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Date or Number} params.masterTimeout - Specify timeout for connection to master - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names to register warmer for; use `_all` or empty string to perform the operation on all indices - * @param {String} params.name - The name of the warmer (supports wildcards); leave empty to delete all warmers - * @param {String or String[] or Boolean} params.type - A comma-separated list of document types to register warmer for; use `_all` or empty string to perform the operation on all types - */ -api.indices.prototype.deleteWarmer = ca({ - params: { - masterTimeout: { - type: 'time', - name: 'master_timeout' - } - }, - urls: [ - { - fmt: '/<%=index%>/<%=type%>/_warmer/<%=name%>', - req: { - index: { - type: 'list' - }, - type: { - type: 'list' - }, - name: { - type: 'string' - } - } - }, - { - fmt: '/<%=index%>/_warmer/<%=name%>', - req: { - index: { - type: 'list' - }, - name: { - type: 'string' - } - } - }, - { - fmt: '/<%=index%>/_warmer', - req: { - index: { - type: 'list' - } - } - } - ], - method: 'DELETE' -}); - - -/** - * Perform a [indices.exists](http://www.elasticsearch.org/guide/reference/api/admin-indices-indices-exists/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String or String[] or Boolean} params.index - A comma-separated list of indices to check - */ -api.indices.prototype.exists = ca({ - url: { - fmt: '/<%=index%>', - req: { - index: { - type: 'list' - } - }, - sortOrder: -1 - }, - castExists: true, - method: 'HEAD' -}); - - -/** - * Perform a [indices.existsAlias](http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} [params.ignoreIndices=none] - When performed on multiple indices, allows to ignore `missing` ones - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names to filter aliases - * @param {String or String[] or Boolean} params.name - A comma-separated list of alias names to return - */ -api.indices.prototype.existsAlias = ca({ - params: { - ignoreIndices: { - type: 'enum', - 'default': 'none', - options: [ - 'none', - 'missing' - ], - name: 'ignore_indices' - } - }, - urls: [ - { - fmt: '/<%=index%>/_alias/<%=name%>', - req: { - index: { - type: 'list' - }, - name: { - type: 'list' - } - } - }, - { - fmt: '/_alias/<%=name%>', - req: { - name: { - type: 'list' - } - } - } - ], - castExists: true, - method: 'HEAD' -}); - - -/** - * Perform a [indices.existsType](http://www.elasticsearch.org/guide/reference/api/admin-indices-types-exists/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} [params.ignoreIndices=none] - When performed on multiple indices, allows to ignore `missing` ones - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names; use `_all` to check the types across all indices - * @param {String or String[] or Boolean} params.type - A comma-separated list of document types to check - */ -api.indices.prototype.existsType = ca({ - params: { - ignoreIndices: { - type: 'enum', - 'default': 'none', - options: [ - 'none', - 'missing' - ], - name: 'ignore_indices' - } - }, - url: { - fmt: '/<%=index%>/<%=type%>', - req: { - index: { - type: 'list' - }, - type: { - type: 'list' - } - }, - sortOrder: -2 - }, - castExists: true, - method: 'HEAD' -}); - - -/** - * Perform a [indices.flush](http://www.elasticsearch.org/guide/reference/api/admin-indices-flush/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Boolean} params.force - TODO: ? - * @param {Boolean} params.full - TODO: ? - * @param {String} [params.ignoreIndices=none] - When performed on multiple indices, allows to ignore `missing` ones - * @param {Boolean} params.refresh - Refresh the index after performing the operation - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names; use `_all` or empty string for all indices - */ -api.indices.prototype.flush = ca({ - params: { - force: { - type: 'boolean' - }, - full: { - type: 'boolean' - }, - ignoreIndices: { - type: 'enum', - 'default': 'none', - options: [ - 'none', - 'missing' - ], - name: 'ignore_indices' - }, - refresh: { - type: 'boolean' - } - }, - urls: [ - { - fmt: '/<%=index%>/_flush', - req: { - index: { - type: 'list' - } - } - }, - { - fmt: '/_flush' - } - ], - method: 'POST' -}); - - -/** - * Perform a [indices.getAlias](http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} [params.ignoreIndices=none] - When performed on multiple indices, allows to ignore `missing` ones - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names to filter aliases - * @param {String or String[] or Boolean} params.name - A comma-separated list of alias names to return - */ -api.indices.prototype.getAlias = ca({ - params: { - ignoreIndices: { - type: 'enum', - 'default': 'none', - options: [ - 'none', - 'missing' - ], - name: 'ignore_indices' - } - }, - urls: [ - { - fmt: '/<%=index%>/_alias/<%=name%>', - req: { - index: { - type: 'list' - }, - name: { - type: 'list' - } - } - }, - { - fmt: '/_alias/<%=name%>', - req: { - name: { - type: 'list' - } - } - } - ] -}); - - -/** - * Perform a [indices.getAliases](http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Date or Number} params.timeout - Explicit operation timeout - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names to filter aliases - */ -api.indices.prototype.getAliases = ca({ - params: { - timeout: { - type: 'time' - } - }, - urls: [ - { - fmt: '/<%=index%>/_aliases', - req: { - index: { - type: 'list' - } - } - }, - { - fmt: '/_aliases' - } - ] -}); - - -/** - * Perform a [indices.getFieldMapping](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-get-field-mapping.html) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Boolean} params.includeDefaults - Whether the default mapping values should be returned as well - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names - * @param {String or String[] or Boolean} params.type - A comma-separated list of document types - * @param {String or String[] or Boolean} params.field - A comma-separated list of fields - */ -api.indices.prototype.getFieldMapping = ca({ - params: { - includeDefaults: { - type: 'boolean', - name: 'include_defaults' - } - }, - urls: [ - { - fmt: '/<%=index%>/<%=type%>/_mapping/field/<%=field%>', - req: { - index: { - type: 'list' - }, - type: { - type: 'list' - }, - field: { - type: 'list' - } - } - }, - { - fmt: '/<%=index%>/_mapping/field/<%=field%>', - req: { - index: { - type: 'list' - }, - field: { - type: 'list' - } - } - }, - { - fmt: '/_mapping/field/<%=field%>', - req: { - field: { - type: 'list' - } - } - } - ] -}); - - -/** - * Perform a [indices.getMapping](http://www.elasticsearch.org/guide/reference/api/admin-indices-get-mapping/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names - * @param {String or String[] or Boolean} params.type - A comma-separated list of document types - */ -api.indices.prototype.getMapping = ca({ - urls: [ - { - fmt: '/<%=index%>/<%=type%>/_mapping', - req: { - index: { - type: 'list' - }, - type: { - type: 'list' - } - } - }, - { - fmt: '/<%=index%>/_mapping', - req: { - index: { - type: 'list' - } - } - }, - { - fmt: '/_mapping' - } - ] -}); - - -/** - * Perform a [indices.getSettings](http://www.elasticsearch.org/guide/reference/api/admin-indices-get-settings/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices - */ -api.indices.prototype.getSettings = ca({ - urls: [ - { - fmt: '/<%=index%>/_settings', - req: { - index: { - type: 'list' - } - } - }, - { - fmt: '/_settings' - } - ] -}); - - -/** - * Perform a [indices.getTemplate](http://www.elasticsearch.org/guide/reference/api/admin-indices-templates/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} params.name - The name of the template - */ -api.indices.prototype.getTemplate = ca({ - urls: [ - { - fmt: '/_template/<%=name%>', - req: { - name: { - type: 'string' - } - } - }, - { - fmt: '/_template' - } - ] -}); - - -/** - * Perform a [indices.getWarmer](http://www.elasticsearch.org/guide/reference/api/admin-indices-warmers/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names to restrict the operation; use `_all` to perform the operation on all indices - * @param {String} params.name - The name of the warmer (supports wildcards); leave empty to get all warmers - * @param {String or String[] or Boolean} params.type - A comma-separated list of document types to restrict the operation; leave empty to perform the operation on all types - */ -api.indices.prototype.getWarmer = ca({ - urls: [ - { - fmt: '/<%=index%>/<%=type%>/_warmer/<%=name%>', - req: { - index: { - type: 'list' - }, - type: { - type: 'list' - }, - name: { - type: 'string' - } - } - }, - { - fmt: '/<%=index%>/_warmer/<%=name%>', - req: { - index: { - type: 'list' - }, - name: { - type: 'string' - } - } - }, - { - fmt: '/<%=index%>/_warmer', - req: { - index: { - type: 'list' - } - } - } - ] -}); - - -/** - * Perform a [indices.open](http://www.elasticsearch.org/guide/reference/api/admin-indices-open-close/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Date or Number} params.timeout - Explicit operation timeout - * @param {Date or Number} params.masterTimeout - Specify timeout for connection to master - * @param {String} params.index - The name of the index - */ -api.indices.prototype.open = ca({ - params: { - timeout: { - type: 'time' - }, - masterTimeout: { - type: 'time', - name: 'master_timeout' - } - }, - url: { - fmt: '/<%=index%>/_open', - req: { - index: { - type: 'string' - } - }, - sortOrder: -1 - }, - method: 'POST' -}); - - -/** - * Perform a [indices.optimize](http://www.elasticsearch.org/guide/reference/api/admin-indices-optimize/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Boolean} params.flush - Specify whether the index should be flushed after performing the operation (default: true) - * @param {String} [params.ignoreIndices=none] - When performed on multiple indices, allows to ignore `missing` ones - * @param {Number} params.maxNumSegments - The number of segments the index should be merged into (default: dynamic) - * @param {Boolean} params.onlyExpungeDeletes - Specify whether the operation should only expunge deleted documents - * @param {*} params.operationThreading - TODO: ? - * @param {Boolean} params.refresh - Specify whether the index should be refreshed after performing the operation (default: true) - * @param {Boolean} params.waitForMerge - Specify whether the request should block until the merge process is finished (default: true) - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices - */ -api.indices.prototype.optimize = ca({ - params: { - flush: { - type: 'boolean' - }, - ignoreIndices: { - type: 'enum', - 'default': 'none', - options: [ - 'none', - 'missing' - ], - name: 'ignore_indices' - }, - maxNumSegments: { - type: 'number', - name: 'max_num_segments' - }, - onlyExpungeDeletes: { - type: 'boolean', - name: 'only_expunge_deletes' - }, - operationThreading: { - name: 'operation_threading' - }, - refresh: { - type: 'boolean' - }, - waitForMerge: { - type: 'boolean', - name: 'wait_for_merge' - } - }, - urls: [ - { - fmt: '/<%=index%>/_optimize', - req: { - index: { - type: 'list' - } - } - }, - { - fmt: '/_optimize' - } - ], - method: 'POST' -}); - - -/** - * Perform a [indices.putAlias](http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Date or Number} params.timeout - Explicit timestamp for the document - * @param {Date or Number} params.masterTimeout - Specify timeout for connection to master - * @param {String} params.index - The name of the index with an alias - * @param {String} params.name - The name of the alias to be created or updated - */ -api.indices.prototype.putAlias = ca({ - params: { - timeout: { - type: 'time' - }, - masterTimeout: { - type: 'time', - name: 'master_timeout' - } - }, - urls: [ - { - fmt: '/<%=index%>/_alias/<%=name%>', - req: { - index: { - type: 'string' - }, - name: { - type: 'string' - } - } - }, - { - fmt: '/_alias/<%=name%>', - req: { - name: { - type: 'string' - } - } - }, - { - fmt: '/<%=index%>/_alias', - req: { - index: { - type: 'string' - } - } - }, - { - fmt: '/_alias' - } - ], - method: 'PUT' -}); - - -/** - * Perform a [indices.putMapping](http://www.elasticsearch.org/guide/reference/api/admin-indices-put-mapping/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Boolean} params.ignoreConflicts - Specify whether to ignore conflicts while updating the mapping (default: false) - * @param {Date or Number} params.timeout - Explicit operation timeout - * @param {Date or Number} params.masterTimeout - Specify timeout for connection to master - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names; use `_all` to perform the operation on all indices - * @param {String} params.type - The name of the document type - */ -api.indices.prototype.putMapping = ca({ - params: { - ignoreConflicts: { - type: 'boolean', - name: 'ignore_conflicts' - }, - timeout: { - type: 'time' - }, - masterTimeout: { - type: 'time', - name: 'master_timeout' - } - }, - url: { - fmt: '/<%=index%>/<%=type%>/_mapping', - req: { - index: { - type: 'list' - }, - type: { - type: 'string' - } - }, - sortOrder: -2 - }, - method: 'POST' -}); - - -/** - * Perform a [indices.putSettings](http://www.elasticsearch.org/guide/reference/api/admin-indices-update-settings/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Date or Number} params.masterTimeout - Specify timeout for connection to master - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices - */ -api.indices.prototype.putSettings = ca({ - params: { - masterTimeout: { - type: 'time', - name: 'master_timeout' - } - }, - urls: [ - { - fmt: '/<%=index%>/_settings', - req: { - index: { - type: 'list' - } - } - }, - { - fmt: '/_settings' - } - ], - method: 'PUT' -}); - - -/** - * Perform a [indices.putTemplate](http://www.elasticsearch.org/guide/reference/api/admin-indices-templates/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Number} params.order - The order for this template when merging multiple matching ones (higher numbers are merged later, overriding the lower numbers) - * @param {Date or Number} params.timeout - Explicit operation timeout - * @param {Date or Number} params.masterTimeout - Specify timeout for connection to master - * @param {String} params.name - The name of the template - */ -api.indices.prototype.putTemplate = ca({ - params: { - order: { - type: 'number' - }, - timeout: { - type: 'time' - }, - masterTimeout: { - type: 'time', - name: 'master_timeout' - } - }, - url: { - fmt: '/_template/<%=name%>', - req: { - name: { - type: 'string' - } - }, - sortOrder: -1 - }, - method: 'POST' -}); - - -/** - * Perform a [indices.putWarmer](http://www.elasticsearch.org/guide/reference/api/admin-indices-warmers/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Date or Number} params.masterTimeout - Specify timeout for connection to master - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names to register the warmer for; use `_all` or empty string to perform the operation on all indices - * @param {String} params.name - The name of the warmer - * @param {String or String[] or Boolean} params.type - A comma-separated list of document types to register the warmer for; leave empty to perform the operation on all types - */ -api.indices.prototype.putWarmer = ca({ - params: { - masterTimeout: { - type: 'time', - name: 'master_timeout' - } - }, - urls: [ - { - fmt: '/<%=index%>/<%=type%>/_warmer/<%=name%>', - req: { - index: { - type: 'list' - }, - type: { - type: 'list' - }, - name: { - type: 'string' - } - } - }, - { - fmt: '/<%=index%>/_warmer/<%=name%>', - req: { - index: { - type: 'list' - }, - name: { - type: 'string' - } - } - } - ], - method: 'PUT' -}); - - -/** - * Perform a [indices.refresh](http://www.elasticsearch.org/guide/reference/api/admin-indices-refresh/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} [params.ignoreIndices=none] - When performed on multiple indices, allows to ignore `missing` ones - * @param {*} params.operationThreading - TODO: ? - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices - */ -api.indices.prototype.refresh = ca({ - params: { - ignoreIndices: { - type: 'enum', - 'default': 'none', - options: [ - 'none', - 'missing' - ], - name: 'ignore_indices' - }, - operationThreading: { - name: 'operation_threading' - } - }, - urls: [ - { - fmt: '/<%=index%>/_refresh', - req: { - index: { - type: 'list' - } - } - }, - { - fmt: '/_refresh' - } - ], - method: 'POST' -}); - - -/** - * Perform a [indices.segments](http://elasticsearch.org/guide/reference/api/admin-indices-segments/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} [params.ignoreIndices=none] - When performed on multiple indices, allows to ignore `missing` ones - * @param {*} params.operationThreading - TODO: ? - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices - */ -api.indices.prototype.segments = ca({ - params: { - ignoreIndices: { - type: 'enum', - 'default': 'none', - options: [ - 'none', - 'missing' - ], - name: 'ignore_indices' - }, - operationThreading: { - name: 'operation_threading' - } - }, - urls: [ - { - fmt: '/<%=index%>/_segments', - req: { - index: { - type: 'list' - } - } - }, - { - fmt: '/_segments' - } - ] -}); - - -/** - * Perform a [indices.snapshotIndex](http://www.elasticsearch.org/guide/reference/api/admin-indices-gateway-snapshot/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} [params.ignoreIndices=none] - When performed on multiple indices, allows to ignore `missing` ones - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names; use `_all` or empty string for all indices - */ -api.indices.prototype.snapshotIndex = ca({ - params: { - ignoreIndices: { - type: 'enum', - 'default': 'none', - options: [ - 'none', - 'missing' - ], - name: 'ignore_indices' - } - }, - urls: [ - { - fmt: '/<%=index%>/_gateway/snapshot', - req: { - index: { - type: 'list' - } - } - }, - { - fmt: '/_gateway/snapshot' - } - ], - method: 'POST' -}); - - -/** - * Perform a [indices.stats](http://elasticsearch.org/guide/reference/api/admin-indices-stats/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Boolean} params.all - Return all available information - * @param {Boolean} params.clear - Reset the default level of detail - * @param {Boolean} params.completion - Return information about completion suggester stats - * @param {String or String[] or Boolean} params.completionFields - A comma-separated list of fields for `completion` metric (supports wildcards) - * @param {Boolean} params.docs - Return information about indexed and deleted documents - * @param {Boolean} params.fielddata - Return information about field data - * @param {String or String[] or Boolean} params.fielddataFields - A comma-separated list of fields for `fielddata` metric (supports wildcards) - * @param {String or String[] or Boolean} params.fields - A comma-separated list of fields to return detailed information for, when returning the `search` statistics - * @param {Boolean} params.filterCache - Return information about filter cache - * @param {Boolean} params.flush - Return information about flush operations - * @param {Boolean} params.get - Return information about get operations - * @param {Boolean} params.groups - A comma-separated list of search groups for `search` statistics - * @param {Boolean} params.idCache - Return information about ID cache - * @param {String} [params.ignoreIndices=none] - When performed on multiple indices, allows to ignore `missing` ones - * @param {Boolean} params.indexing - Return information about indexing operations - * @param {Boolean} params.merge - Return information about merge operations - * @param {Boolean} params.refresh - Return information about refresh operations - * @param {Boolean} params.search - Return information about search operations; use the `groups` parameter to include information for specific search groups - * @param {Boolean} params.store - Return information about the size of the index - * @param {Boolean} params.warmer - Return information about warmers - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices - * @param {String or String[] or Boolean} params.indexingTypes - A comma-separated list of document types to include in the `indexing` statistics - * @param {String} params.metricFamily - Limit the information returned to a specific metric - * @param {String or String[] or Boolean} params.searchGroups - A comma-separated list of search groups to include in the `search` statistics - */ -api.indices.prototype.stats = ca({ - params: { - all: { - type: 'boolean' - }, - clear: { - type: 'boolean' - }, - completion: { - type: 'boolean' - }, - completionFields: { - type: 'list', - name: 'completion_fields' - }, - docs: { - type: 'boolean' - }, - fielddata: { - type: 'boolean' - }, - fielddataFields: { - type: 'list', - name: 'fielddata_fields' - }, - fields: { - type: 'list' - }, - filterCache: { - type: 'boolean', - name: 'filter_cache' - }, - flush: { - type: 'boolean' - }, - get: { - type: 'boolean' - }, - groups: { - type: 'boolean' - }, - idCache: { - type: 'boolean', - name: 'id_cache' - }, - ignoreIndices: { - type: 'enum', - 'default': 'none', - options: [ - 'none', - 'missing' - ], - name: 'ignore_indices' - }, - indexing: { - type: 'boolean' - }, - merge: { - type: 'boolean' - }, - refresh: { - type: 'boolean' - }, - search: { - type: 'boolean' - }, - store: { - type: 'boolean' - }, - warmer: { - type: 'boolean' - } - }, - urls: [ - { - fmt: '/<%=index%>/_stats', - req: { - index: { - type: 'list' - } - } - }, - { - fmt: '/_stats' - } - ] -}); - - -/** - * Perform a [indices.status](http://elasticsearch.org/guide/reference/api/admin-indices-status/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} [params.ignoreIndices=none] - When performed on multiple indices, allows to ignore `missing` ones - * @param {*} params.operationThreading - TODO: ? - * @param {Boolean} params.recovery - Return information about shard recovery - * @param {Boolean} params.snapshot - TODO: ? - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices - */ -api.indices.prototype.status = ca({ - params: { - ignoreIndices: { - type: 'enum', - 'default': 'none', - options: [ - 'none', - 'missing' - ], - name: 'ignore_indices' - }, - operationThreading: { - name: 'operation_threading' - }, - recovery: { - type: 'boolean' - }, - snapshot: { - type: 'boolean' - } - }, - urls: [ - { - fmt: '/<%=index%>/_status', - req: { - index: { - type: 'list' - } - } - }, - { - fmt: '/_status' - } - ] -}); - - -/** - * Perform a [indices.updateAliases](http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Date or Number} params.timeout - Request timeout - * @param {Date or Number} params.masterTimeout - Specify timeout for connection to master - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names to filter aliases - */ -api.indices.prototype.updateAliases = ca({ - params: { - timeout: { - type: 'time' - }, - masterTimeout: { - type: 'time', - name: 'master_timeout' - } - }, - url: { - fmt: '/_aliases' - }, - method: 'POST' -}); - - -/** - * Perform a [indices.validateQuery](http://www.elasticsearch.org/guide/reference/api/validate/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Boolean} params.explain - Return detailed information about the error - * @param {String} [params.ignoreIndices=none] - When performed on multiple indices, allows to ignore `missing` ones - * @param {*} params.operationThreading - TODO: ? - * @param {String} params.source - The URL-encoded query definition (instead of using the request body) - * @param {String} params.q - Query in the Lucene query string syntax - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names to restrict the operation; use `_all` or empty string to perform the operation on all indices - * @param {String or String[] or Boolean} params.type - A comma-separated list of document types to restrict the operation; leave empty to perform the operation on all types - */ -api.indices.prototype.validateQuery = ca({ - params: { - explain: { - type: 'boolean' - }, - ignoreIndices: { - type: 'enum', - 'default': 'none', - options: [ - 'none', - 'missing' - ], - name: 'ignore_indices' - }, - operationThreading: { - name: 'operation_threading' - }, - source: { - type: 'string' - }, - q: { - type: 'string' - } - }, - urls: [ - { - fmt: '/<%=index%>/<%=type%>/_validate/query', - req: { - index: { - type: 'list' - }, - type: { - type: 'list' - } - } - }, - { - fmt: '/<%=index%>/_validate/query', - req: { - index: { - type: 'list' - } - } - }, - { - fmt: '/_validate/query' - } - ], - method: 'POST' -}); - - -/** - * Perform a [info](http://elasticsearch.org/guide/) request - * - * @param {Object} params - An object with parameters used to carry out this action - */ -api.info = ca({ - url: { - fmt: '/' - } -}); - - -/** - * Perform a [mget](http://elasticsearch.org/guide/reference/api/multi-get/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String or String[] or Boolean} params.fields - A comma-separated list of fields to return in the response - * @param {String} params.preference - Specify the node or shard the operation should be performed on (default: random) - * @param {Boolean} params.realtime - Specify whether to perform the operation in realtime or search mode - * @param {Boolean} params.refresh - Refresh the shard containing the document before performing the operation - * @param {String or String[] or Boolean} params.source - True or false to return the _source field or not, or a list of fields to return - * @param {String or String[] or Boolean} params.sourceExclude - A list of fields to exclude from the returned _source field - * @param {String or String[] or Boolean} params.sourceInclude - A list of fields to extract and return from the _source field - * @param {String} params.index - The name of the index - * @param {String} params.type - The type of the document - */ -api.mget = ca({ - params: { - fields: { - type: 'list' - }, - preference: { - type: 'string' - }, - realtime: { - type: 'boolean' - }, - refresh: { - type: 'boolean' - }, - source: { - type: 'list', - name: '_source' - }, - sourceExclude: { - type: 'list', - name: '_source_exclude' - }, - sourceInclude: { - type: 'list', - name: '_source_include' - } - }, - urls: [ - { - fmt: '/<%=index%>/<%=type%>/_mget', - req: { - index: { - type: 'string' - }, - type: { - type: 'string' - } - } - }, - { - fmt: '/<%=index%>/_mget', - req: { - index: { - type: 'string' - } - } - }, - { - fmt: '/_mget' - } - ], - method: 'POST' -}); - - -/** - * Perform a [mlt](http://elasticsearch.org/guide/reference/api/more-like-this/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Number} params.boostTerms - The boost factor - * @param {Number} params.maxDocFreq - The word occurrence frequency as count: words with higher occurrence in the corpus will be ignored - * @param {Number} params.maxQueryTerms - The maximum query terms to be included in the generated query - * @param {Number} params.maxWordLen - The minimum length of the word: longer words will be ignored - * @param {Number} params.minDocFreq - The word occurrence frequency as count: words with lower occurrence in the corpus will be ignored - * @param {Number} params.minTermFreq - The term frequency as percent: terms with lower occurence in the source document will be ignored - * @param {Number} params.minWordLen - The minimum length of the word: shorter words will be ignored - * @param {String or String[] or Boolean} params.mltFields - Specific fields to perform the query against - * @param {Number} params.percentTermsToMatch - How many terms have to match in order to consider the document a match (default: 0.3) - * @param {String} params.routing - Specific routing value - * @param {Number} params.searchFrom - The offset from which to return results - * @param {String or String[] or Boolean} params.searchIndices - A comma-separated list of indices to perform the query against (default: the index containing the document) - * @param {String} params.searchQueryHint - The search query hint - * @param {String} params.searchScroll - A scroll search request definition - * @param {Number} params.searchSize - The number of documents to return (default: 10) - * @param {String} params.searchSource - A specific search request definition (instead of using the request body) - * @param {String} params.searchType - Specific search type (eg. `dfs_then_fetch`, `count`, etc) - * @param {String or String[] or Boolean} params.searchTypes - A comma-separated list of types to perform the query against (default: the same type as the document) - * @param {String or String[] or Boolean} params.stopWords - A list of stop words to be ignored - * @param {String} params.id - The document ID - * @param {String} params.index - The name of the index - * @param {String} params.type - The type of the document (use `_all` to fetch the first document matching the ID across all types) - */ -api.mlt = ca({ - params: { - boostTerms: { - type: 'number', - name: 'boost_terms' - }, - maxDocFreq: { - type: 'number', - name: 'max_doc_freq' - }, - maxQueryTerms: { - type: 'number', - name: 'max_query_terms' - }, - maxWordLen: { - type: 'number', - name: 'max_word_len' - }, - minDocFreq: { - type: 'number', - name: 'min_doc_freq' - }, - minTermFreq: { - type: 'number', - name: 'min_term_freq' - }, - minWordLen: { - type: 'number', - name: 'min_word_len' - }, - mltFields: { - type: 'list', - name: 'mlt_fields' - }, - percentTermsToMatch: { - type: 'number', - name: 'percent_terms_to_match' - }, - routing: { - type: 'string' - }, - searchFrom: { - type: 'number', - name: 'search_from' - }, - searchIndices: { - type: 'list', - name: 'search_indices' - }, - searchQueryHint: { - type: 'string', - name: 'search_query_hint' - }, - searchScroll: { - type: 'string', - name: 'search_scroll' - }, - searchSize: { - type: 'number', - name: 'search_size' - }, - searchSource: { - type: 'string', - name: 'search_source' - }, - searchType: { - type: 'string', - name: 'search_type' - }, - searchTypes: { - type: 'list', - name: 'search_types' - }, - stopWords: { - type: 'list', - name: 'stop_words' - } - }, - url: { - fmt: '/<%=index%>/<%=type%>/<%=id%>/_mlt', - req: { - index: { - type: 'string' - }, - type: { - type: 'string' - }, - id: { - type: 'string' - } - }, - sortOrder: -3 - }, - method: 'POST' -}); - - -/** - * Perform a [msearch](http://www.elasticsearch.org/guide/reference/api/multi-search/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} params.searchType - Search operation type - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names to use as default - * @param {String or String[] or Boolean} params.type - A comma-separated list of document types to use as default - */ -api.msearch = ca({ - params: { - searchType: { - type: 'enum', - options: [ - 'query_then_fetch', - 'query_and_fetch', - 'dfs_query_then_fetch', - 'dfs_query_and_fetch', - 'count', - 'scan' - ], - name: 'search_type' - } - }, - urls: [ - { - fmt: '/<%=index%>/<%=type%>/_msearch', - req: { - index: { - type: 'list' - }, - type: { - type: 'list' - } - } - }, - { - fmt: '/<%=index%>/_msearch', - req: { - index: { - type: 'list' - } - } - }, - { - fmt: '/_msearch' - } - ], - bulkBody: true, - method: 'POST' -}); - - -/** - * Perform a [percolate](http://elasticsearch.org/guide/reference/api/percolate/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Boolean} params.preferLocal - With `true`, specify that a local shard should be used if available, with `false`, use a random shard (default: true) - * @param {String} params.index - The name of the index with a registered percolator query - * @param {String} params.type - The document type - */ -api.percolate = ca({ - params: { - preferLocal: { - type: 'boolean', - name: 'prefer_local' - } - }, - url: { - fmt: '/<%=index%>/<%=type%>/_percolate', - req: { - index: { - type: 'string' - }, - type: { - type: 'string' - } - }, - sortOrder: -2 - }, - method: 'POST' -}); - - -/** - * Perform a [scroll](http://www.elasticsearch.org/guide/reference/api/search/scroll/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {Duration} params.scroll - Specify how long a consistent view of the index should be maintained for scrolled search - * @param {String} params.scrollId - The scroll ID - */ -api.scroll = ca({ - params: { - scroll: { - type: 'duration' - }, - scrollId: { - type: 'string', - name: 'scroll_id' - } - }, - urls: [ - { - fmt: '/_search/scroll/<%=scrollId%>', - req: { - scrollId: { - type: 'string' - } - } - }, - { - fmt: '/_search/scroll' - } - ], - method: 'POST' -}); - - -/** - * Perform a [search](http://www.elasticsearch.org/guide/reference/api/search/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} params.analyzer - The analyzer to use for the query string - * @param {Boolean} params.analyzeWildcard - Specify whether wildcard and prefix queries should be analyzed (default: false) - * @param {String} [params.defaultOperator=OR] - The default operator for query string query (AND or OR) - * @param {String} params.df - The field to use as default where no field prefix is given in the query string - * @param {Boolean} params.explain - Specify whether to return detailed information about score computation as part of a hit - * @param {String or String[] or Boolean} params.fields - A comma-separated list of fields to return as part of a hit - * @param {Number} params.from - Starting offset (default: 0) - * @param {String} [params.ignoreIndices=none] - When performed on multiple indices, allows to ignore `missing` ones - * @param {String or String[] or Boolean} params.indicesBoost - Comma-separated list of index boosts - * @param {Boolean} params.lenient - Specify whether format-based query failures (such as providing text to a numeric field) should be ignored - * @param {Boolean} params.lowercaseExpandedTerms - Specify whether query terms should be lowercased - * @param {String} params.preference - Specify the node or shard the operation should be performed on (default: random) - * @param {String} params.q - Query in the Lucene query string syntax - * @param {String or String[] or Boolean} params.routing - A comma-separated list of specific routing values - * @param {Duration} params.scroll - Specify how long a consistent view of the index should be maintained for scrolled search - * @param {String} params.searchType - Search operation type - * @param {Number} params.size - Number of hits to return (default: 10) - * @param {String or String[] or Boolean} params.sort - A comma-separated list of : pairs - * @param {String or String[] or Boolean} params.source - True or false to return the _source field or not, or a list of fields to return - * @param {String or String[] or Boolean} params.sourceExclude - A list of fields to exclude from the returned _source field - * @param {String or String[] or Boolean} params.sourceInclude - A list of fields to extract and return from the _source field - * @param {String or String[] or Boolean} params.stats - Specific 'tag' of the request for logging and statistical purposes - * @param {String} params.suggestField - Specify which field to use for suggestions - * @param {String} [params.suggestMode=missing] - Specify suggest mode - * @param {Number} params.suggestSize - How many suggestions to return in response - * @param {Text} params.suggestText - The source text for which the suggestions should be returned - * @param {Date or Number} params.timeout - Explicit operation timeout - * @param {Boolean} params.version - Specify whether to return document version as part of a hit - * @param {String or String[] or Boolean} [params.index=_all] - A comma-separated list of index names to search; use `_all` or empty string to perform the operation on all indices - * @param {String or String[] or Boolean} params.type - A comma-separated list of document types to search; leave empty to perform the operation on all types - */ -api.search = ca({ - params: { - analyzer: { - type: 'string' - }, - analyzeWildcard: { - type: 'boolean', - name: 'analyze_wildcard' - }, - defaultOperator: { - type: 'enum', - 'default': 'OR', - options: [ - 'AND', - 'OR' - ], - name: 'default_operator' - }, - df: { - type: 'string' - }, - explain: { - type: 'boolean' - }, - fields: { - type: 'list' - }, - from: { - type: 'number' - }, - ignoreIndices: { - type: 'enum', - 'default': 'none', - options: [ - 'none', - 'missing' - ], - name: 'ignore_indices' - }, - indicesBoost: { - type: 'list', - name: 'indices_boost' - }, - lenient: { - type: 'boolean' - }, - lowercaseExpandedTerms: { - type: 'boolean', - name: 'lowercase_expanded_terms' - }, - preference: { - type: 'string' - }, - q: { - type: 'string' - }, - routing: { - type: 'list' - }, - scroll: { - type: 'duration' - }, - searchType: { - type: 'enum', - options: [ - 'query_then_fetch', - 'query_and_fetch', - 'dfs_query_then_fetch', - 'dfs_query_and_fetch', - 'count', - 'scan' - ], - name: 'search_type' - }, - size: { - type: 'number' - }, - sort: { - type: 'list' - }, - source: { - type: 'list', - name: '_source' - }, - sourceExclude: { - type: 'list', - name: '_source_exclude' - }, - sourceInclude: { - type: 'list', - name: '_source_include' - }, - stats: { - type: 'list' - }, - suggestField: { - type: 'string', - name: 'suggest_field' - }, - suggestMode: { - type: 'enum', - 'default': 'missing', - options: [ - 'missing', - 'popular', - 'always' - ], - name: 'suggest_mode' - }, - suggestSize: { - type: 'number', - name: 'suggest_size' - }, - suggestText: { - type: 'text', - name: 'suggest_text' - }, - timeout: { - type: 'time' - }, - version: { - type: 'boolean' - } - }, - urls: [ - { - fmt: '/<%=index%>/<%=type%>/_search', - opt: { - index: { - type: 'list', - 'default': '_all' - } - }, - req: { - type: { - type: 'list' - } - } - }, - { - fmt: '/<%=index%>/_search', - opt: { - index: { - type: 'list', - 'default': '_all' - } - } - } - ], - method: 'POST' -}); - - -/** - * Perform a [suggest](http://elasticsearch.org/guide/reference/api/search/suggest/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} [params.ignoreIndices=none] - When performed on multiple indices, allows to ignore `missing` ones - * @param {String} params.preference - Specify the node or shard the operation should be performed on (default: random) - * @param {String} params.routing - Specific routing value - * @param {String} params.source - The URL-encoded request definition (instead of using request body) - * @param {String or String[] or Boolean} params.index - A comma-separated list of index names to restrict the operation; use `_all` or empty string to perform the operation on all indices - */ -api.suggest = ca({ - params: { - ignoreIndices: { - type: 'enum', - 'default': 'none', - options: [ - 'none', - 'missing' - ], - name: 'ignore_indices' - }, - preference: { - type: 'string' - }, - routing: { - type: 'string' - }, - source: { - type: 'string' - } - }, - urls: [ - { - fmt: '/<%=index%>/_suggest', - req: { - index: { - type: 'list' - } - } - }, - { - fmt: '/_suggest' - } - ], - method: 'POST' -}); - - -/** - * Perform a [update](http://elasticsearch.org/guide/reference/api/update/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} params.consistency - Explicit write consistency setting for the operation - * @param {String or String[] or Boolean} params.fields - A comma-separated list of fields to return in the response - * @param {String} params.lang - The script language (default: mvel) - * @param {String} params.parent - ID of the parent document - * @param {String} params.percolate - Perform percolation during the operation; use specific registered query name, attribute, or wildcard - * @param {Boolean} params.refresh - Refresh the index after performing the operation - * @param {String} [params.replication=sync] - Specific replication type - * @param {Number} params.retryOnConflict - Specify how many times should the operation be retried when a conflict occurs (default: 0) - * @param {String} params.routing - Specific routing value - * @param {*} params.script - The URL-encoded script definition (instead of using request body) - * @param {Date or Number} params.timeout - Explicit operation timeout - * @param {Date or Number} params.timestamp - Explicit timestamp for the document - * @param {Duration} params.ttl - Expiration time for the document - * @param {Number} params.version - Explicit version number for concurrency control - * @param {String} params.versionType - Specific version type - * @param {String} params.id - Document ID - * @param {String} params.index - The name of the index - * @param {String} params.type - The type of the document - */ -api.update = ca({ - params: { - consistency: { - type: 'enum', - options: [ - 'one', - 'quorum', - 'all' - ] - }, - fields: { - type: 'list' - }, - lang: { - type: 'string' - }, - parent: { - type: 'string' - }, - percolate: { - type: 'string' - }, - refresh: { - type: 'boolean' - }, - replication: { - type: 'enum', - 'default': 'sync', - options: [ - 'sync', - 'async' - ] - }, - retryOnConflict: { - type: 'number', - name: 'retry_on_conflict' - }, - routing: { - type: 'string' - }, - script: {}, - timeout: { - type: 'time' - }, - timestamp: { - type: 'time' - }, - ttl: { - type: 'duration' - }, - version: { - type: 'number' - }, - versionType: { - type: 'enum', - options: [ - 'internal', - 'external' - ], - name: 'version_type' - } - }, - url: { - fmt: '/<%=index%>/<%=type%>/<%=id%>/_update', - req: { - index: { - type: 'string' - }, - type: { - type: 'string' - }, - id: { - type: 'string' - } - }, - sortOrder: -3 - }, - method: 'POST' -}); - -/** - * Perform a [create](http://elasticsearch.org/guide/reference/api/index_/) request - * - * @param {Object} params - An object with parameters used to carry out this action - * @param {String} params.consistency - Explicit write consistency setting for the operation - * @param {String} params.id - Document ID - * @param {String} params.parent - ID of the parent document - * @param {String} params.percolate - Percolator queries to execute while indexing the document - * @param {Boolean} params.refresh - Refresh the index after performing the operation - * @param {String} [params.replication=sync] - Specific replication type - * @param {String} params.routing - Specific routing value - * @param {Date or Number} params.timeout - Explicit operation timeout - * @param {Date or Number} params.timestamp - Explicit timestamp for the document - * @param {Duration} params.ttl - Expiration time for the document - * @param {Number} params.version - Explicit version number for concurrency control - * @param {String} params.versionType - Specific version type - * @param {String} params.index - The name of the index - * @param {String} params.type - The type of the document - */ -api.create = ca.proxy(api.index, { - transform: function (params) { - params.op_type = 'create'; - } -}); - - -},{"./client_action":61}],60:[function(require,module,exports){ -/** - * A client that makes requests to Elasticsearch via a {{#crossLink "Transport"}}Transport{{/crossLink}} - * - * Initializing a client might look something like: - * - * ``` - * var client = new es.Client({ - * hosts: [ - * 'es1.net:9200', - * { - * host: 'es2.net', - * port: 9200 - * } - * ], - * sniffOnStart: true, - * log: { - * type: 'file', - * level: 'warning' - * } - * }); - * ``` - * - * @class Client - * @constructor - */ - -module.exports = Client; - -var api = require('./api.js'); -var ca = require('./client_action'); -var Transport = require('./transport'); - -function Client(config) { - this.transport = new Transport(config); - - // instantiate the api's namespaces - for (var i = 0; i < this._namespaces.length; i++) { - this[this._namespaces[i]] = new this[this._namespaces[i]](this.transport); - } -} - -Client.prototype = api; - -/** - * Ping some node to ensure that the cluster is available in some respect - * - * @param {Object} params - Currently just a placeholder, no params used at this time - * @param {Function} cb - callback - */ -Client.prototype.ping = ca({ - method: 'HEAD', - url: { - fmt: '/' - }, - timeout: 100 -}); - -Client.prototype.close = function () { - this.transport.close(); -}; - -},{"./api.js":59,"./client_action":61,"./transport":78}],61:[function(require,module,exports){ -/** - * Constructs a function that can be called to make a request to ES - * @type {[type]} - */ -module.exports = ClientAction; - -var _ = require('./utils'); -var when = require('when'); - -function ClientAction(spec) { - if (!_.isPlainObject(spec.params)) { - spec.params = {}; - } - - if (!spec.method) { - spec.method = 'GET'; - } - - return function (params, cb) { - if (typeof params === 'function') { - cb = params; - params = {}; - } else { - params = params || {}; - cb = typeof cb === 'function' ? cb : null; - } - - try { - return exec(this.transport, spec, params, cb); - } catch (e) { - if (typeof cb === 'function') { - _.nextTick(cb, e); - } else { - return when.reject(e); - } - } - }; -} - -var castType = { - enum: function (param, val, name) { - /* jshint eqeqeq: false */ - for (var i = 0; i < param.options.length; i++) { - if (param.options[i] == val) { - return param.options[i]; - } - } - throw new TypeError('Invalid ' + name + ': expected one of ' + param.options.join(',')); - }, - duration: function (param, val, name) { - if (_.isNumeric(val) || _.isInterval(val)) { - return val; - } else { - throw new TypeError( - 'Invalid ' + name + ': expected a number or interval ' + - '(an integer followed by one of Mwdhmsy).' - ); - } - }, - list: function (param, val, name) { - switch (typeof val) { - case 'number': - case 'string': - return val; - case 'object': - if (_.isArray(val)) { - return val.join(','); - } - /* falls through */ - default: - throw new TypeError('Invalid ' + name + ': expected be a comma seperated list, array, number or string.'); - } - }, - boolean: function (param, val) { - val = _.isString(val) ? val.toLowerCase() : val; - return (val === 'no' || val === 'off') ? false : !!val; - }, - number: function (param, val, name) { - if (_.isNumeric(val)) { - return val * 1; - } else { - throw new TypeError('Invalid ' + name + ': expected a number.'); - } - }, - string: function (param, val, name) { - switch (typeof val) { - case 'number': - case 'string': - return '' + val; - default: - throw new TypeError('Invalid ' + name + ': expected a string.'); - } - }, - time: function (param, val, name) { - if (typeof val === 'string') { - return val; - } - else if (_.isNumeric(val)) { - return '' + val; - } - else if (val instanceof Date) { - return '' + val.getTime(); - } - else { - throw new TypeError('Invalid ' + name + ': expected some sort of time.'); - } - } -}; - -function resolveUrl(url, params) { - var vars = {}, i, key; - - if (url.req) { - // url has required params - if (!url.reqParamKeys) { - // create cached key list on demand - url.reqParamKeys = _.keys(url.req); - } - - for (i = 0; i < url.reqParamKeys.length; i ++) { - key = url.reqParamKeys[i]; - if (!params.hasOwnProperty(key)) { - // missing a required param - return false; - } else { - // cast of copy required param - if (castType[url.req[key].type]) { - vars[key] = castType[url.req[key].type](url.req[key], params[key], key); - } else { - vars[key] = params[key]; - } - } - } - } - - if (url.opt) { - // url has optional params - if (!url.optParamKeys) { - url.optParamKeys = _.keys(url.opt); - } - - for (i = 0; i < url.optParamKeys.length; i ++) { - key = url.optParamKeys[i]; - if (params[key]) { - if (castType[url.opt[key].type]) { - vars[key] = castType[url.opt[key].type](url.opt[key], params[key], key); - } else { - vars[key] = params[key]; - } - } else { - vars[key] = url.opt[key]['default']; - } - } - } - - if (!url.template) { - // compile the template on demand - url.template = _.template(url.fmt); - } - - return url.template(_.transform(vars, function (note, val, name) { - // encode each value - note[name] = encodeURIComponent(val); - // remove it from the params so that it isn't sent to the final request - delete params[name]; - }, {})); -} - -// export so that we can test this -ClientAction.resolveUrl = resolveUrl; - -function exec(transport, spec, params, cb) { - var request = { - method: spec.method, - timeout: spec.timeout || 10000 - }; - var query = {}; - var i; - - // verify that we have the body if needed - if (spec.needsBody && !params.body) { - throw new TypeError('A request body is required.'); - } - - // control params - spec.bulkBody && (request.bulkBody = true); - spec.castExists && (request.castExists = true); - - // pick the url - if (spec.url) { - // only one url option - request.path = resolveUrl(spec.url, params); - } else { - for (i = 0; i < spec.urls.length; i++) { - if (request.path = resolveUrl(spec.urls[i], params)) { - break; - } - } - } - - if (!request.path) { - // there must have been some mimimun requirements that were not met - throw new TypeError( - 'Unable to build a path with those params. Supply at least ' + - _.keys(spec.urls[spec.urls.length - 1].req).join(', ') - ); - } - - // build the query string - if (!spec.paramKeys) { - // build a key list on demand - spec.paramKeys = _.keys(spec.params); - spec.requireParamKeys = _.transform(spec.params, function (req, param, key) { - if (param.required) { - req.push(key); - } - }, []); - } - - var key, paramSpec; - - for (key in params) { - if (params.hasOwnProperty(key) && params[key] != null) { - switch (key) { - case 'body': - request.body = params.body; - break; - case 'ignore': - request.ignore = _.isArray(params.ignore) ? params.ignore : [params.ignore]; - break; - case 'timeout': - request.timeout = params.timeout; - break; - case 'method': - request.method = _.toUpperString(params.method); - break; - default: - paramSpec = spec.params[key]; - if (paramSpec) { - // param keys don't always match the param name, in those cases it's stored in the param def as "name" - paramSpec.name = paramSpec.name || key; - if (params[key] != null) { - if (castType[paramSpec.type]) { - query[paramSpec.name] = castType[paramSpec.type](paramSpec, params[key], key); - } else { - query[paramSpec.name] = params[key]; - } - - if (paramSpec['default'] && query[paramSpec.name] === paramSpec['default']) { - delete query[paramSpec.name]; - } - } - } else { - query[key] = params[key]; - } - } - } - } - - for (i = 0; i < spec.requireParamKeys.length; i ++) { - if (!query.hasOwnProperty(spec.requireParamKeys[i])) { - throw new TypeError('Missing required parameter ' + spec.requireParamKeys[i]); - } - } - - request.query = query; - - return transport.request(request, cb); -} - - - -ClientAction.proxy = function (fn, spec) { - return function (params, cb) { - if (typeof params === 'function') { - cb = params; - params = {}; - } else { - params = params || {}; - cb = typeof cb === 'function' ? cb : null; - } - - if (spec.transform) { - spec.transform(params); - } - - return fn.call(this, params, cb); - }; -}; - -},{"./utils":79,"when":57}],62:[function(require,module,exports){ -module.exports = ConnectionAbstract; - -var _ = require('./utils'); -var EventEmitter = require('events').EventEmitter; - -/** - * Abstract class used for Connection classes - * @class ConnectionAbstract - * @constructor - */ -function ConnectionAbstract(host, config) { - config = _.defaults(config || {}, { - deadTimeout: 30000 - }); - EventEmitter.call(this); - this.deadTimeout = config.deadTimeout; - this.requestCount = 0; - - if (!host) { - throw new TypeError('Missing host'); - } else if (host.makeUrl) { - this.host = host; - } else { - throw new TypeError('Invalid host'); - } - - _.makeBoundMethods(this); -} -_.inherits(ConnectionAbstract, EventEmitter); - -/** - * Make a request using this connection. Must be overridden by Connection classes, which can add whatever keys to - * params that they like. These are just the basics. - * - * @param [params] {Object} - The parameters for the request - * @param params.path {String} - The path for which you are requesting - * @param params.method {String} - The HTTP method for the request (GET, HEAD, etc.) - * @param params.timeout {Integer} - The amount of time in milliseconds that this request should be allowed to run for. - * @param cb {Function} - A callback to be called once with `cb(err, responseBody, responseStatus)` - */ -ConnectionAbstract.prototype.request = function () { - throw new Error('Connection#request must be overwritten by the Connector'); -}; - -ConnectionAbstract.prototype.ping = function (cb) { - if (typeof cb !== 'function') { - throw new TypeError('Callback must be a function'); - } - - return this.request({ - path: '/', - method: 'HEAD', - timeout: 100 - }, cb); -}; - -ConnectionAbstract.prototype.setStatus = function (status) { - var origStatus = this.status; - - this.status = status; - - if (this._deadTimeoutId) { - clearTimeout(this._deadTimeoutId); - this._deadTimeoutId = null; - } - - if (status === 'dead') { - this._deadTimeoutId = setTimeout(this.bound.resuscitate, this.deadTimeout); - } - - this.emit('status set', status, origStatus, this); - - if (status === 'closed') { - this.removeAllListeners(); - } -}; - -ConnectionAbstract.prototype.resuscitate = _.scheduled(function () { - var self = this; - - if (self.status === 'dead') { - self.ping(function (err) { - if (!err) { - self.setStatus('alive'); - } else { - self.setStatus('dead'); - } - }); - } -}); - -},{"./utils":79,"events":5}],63:[function(require,module,exports){ -/** - * Manager of connections to a node(s), capable of ensuring that connections are clear and living - * before providing them to the application - * - * @class ConnectionPool - * @constructor - * @param {Object} config - The config object passed to the transport. - */ - -module.exports = ConnectionPool; - -var _ = require('./utils'); -var Log = require('./log'); - -function ConnectionPool(config) { - _.makeBoundMethods(this); - - this.log = config.log; - if (!this.log) { - this.log = new Log(); - } - - // get the selector config var - this.selector = _.funcEnum(config, 'selector', ConnectionPool.selectors, ConnectionPool.defaultSelectors); - // get the connection class - this.Connection = _.funcEnum(config, 'connectionClass', ConnectionPool.connectionClasses, - ConnectionPool.defaultConnectionClass); - - // a map of connections to their "id" property, used when sniffing - this.index = {}; - - this.connections = { - alive: [], - dead: [] - }; -} - -// selector options -ConnectionPool.selectors = require('./selectors'); -ConnectionPool.defaultSelectors = 'round_robin'; - -// get the connection options -ConnectionPool.connectionClasses = require('./connectors'); -ConnectionPool.defaultConnectionClass = ConnectionPool.connectionClasses._default; -delete ConnectionPool.connectionClasses._default; - -/** - * Selects a connection from the list using the this.selector - * Features: - * - detects if the selector is async or not - * - sync selectors should still return asynchronously - * - catches errors in sync selectors - * - automatically selects the first dead connection when there no living connections - * - * @param {Function} cb [description] - * @return {[type]} [description] - */ -ConnectionPool.prototype.select = function (cb) { - if (this.connections.alive.length) { - if (this.selector.length > 1) { - this.selector(this.connections.alive, cb); - } else { - try { - _.nextTick(cb, null, this.selector(this.connections.alive)); - } catch (e) { - cb(e); - } - } - } else { - _.nextTick(cb, null, this.connections.dead[0]); - } -}; - -ConnectionPool.prototype.onStatusSet = _.handler(function (status, oldStatus, connection) { - var from, to, index; - - if (oldStatus === status) { - if (status === 'dead') { - // we want to remove the connection from it's current possition and move it to the end - status = 'redead'; - } else { - return true; - } - } - - switch (status) { - case 'alive': - from = this.connections.dead; - to = this.connections.alive; - break; - case 'dead': - from = this.connections.alive; - to = this.connections.dead; - break; - case 'redead': - from = this.connections.dead; - to = this.connections.dead; - break; - case 'closed': - from = this.connections[oldStatus]; - break; - } - - if (from && from.indexOf) { - index = from.indexOf(connection); - if (~index) { - from.splice(index, 1); - } - } - - if (to && to.indexOf) { - index = to.indexOf(connection); - if (!~index) { - to.push(connection); - } - } -}); - -ConnectionPool.prototype.addConnection = function (connection) { - if (!connection.id) { - connection.id = connection.host.toString(); - } - - if (!this.index[connection.id]) { - this.log.info('Adding connection to', connection.id); - this.index[connection.id] = connection; - connection.on('status set', this.bound.onStatusSet); - connection.setStatus('alive'); - } -}; - -ConnectionPool.prototype.removeConnection = function (connection) { - if (!connection.id) { - connection.id = connection.host.toString(); - } - - if (this.index[connection.id]) { - delete this.index[connection.id]; - connection.setStatus('closed'); - connection.removeListener('status set', this.bound.onStatusSet); - } -}; - -ConnectionPool.prototype.setHosts = function (hosts) { - var connection; - var i; - var id; - var host; - var toRemove = _.clone(this.index); - - for (i = 0; i < hosts.length; i++) { - host = hosts[i]; - id = host.toString(); - if (this.index[id]) { - delete toRemove[id]; - } else { - connection = new this.Connection(host); - connection.id = id; - this.addConnection(connection); - } - } - - var removeIds = _.keys(toRemove); - for (i = 0; i < removeIds.length; i++) { - this.removeConnection(this.index[removeIds[i]]); - } -}; - -ConnectionPool.prototype.close = function () { - this.setHosts([]); -}; -ConnectionPool.prototype.empty = ConnectionPool.prototype.close; - -},{"./connectors":65,"./log":70,"./selectors":74,"./utils":79}],64:[function(require,module,exports){ -/** - * Connection that registers a module with angular, using angular's $http service - * to communicate with ES. - * - * @class connections.Angular - */ -module.exports = AngularConnector; - -var _ = require('../utils'); -var ConnectionAbstract = require('../connection'); -var ConnectionFault = require('../errors').ConnectionFault; - -function AngularConnector(host, config) { - ConnectionAbstract.call(this, host, config); -} -_.inherits(AngularConnector, ConnectionAbstract); - -AngularConnector.prototype.request = function (params, cb) { - this.$http({ - method: params.method, - url: this.host.makeUrl(params), - data: params.body, - cache: false, - timeout: params.timeout !== Infinity ? params.timeout : 0 - }).then(function (response) { - cb(null, response.data, response.status); - }, function (err) { - cb(new ConnectionFault(err.message)); - }); -}; - -// must be overwritten before this connection can be used -AngularConnector.prototype.$http = null; - -},{"../connection":62,"../errors":68,"../utils":79}],65:[function(require,module,exports){ -var opts = { - xhr: require('./xhr'), - jquery: require('./jquery'), - angular: require('./angular') -}; -var _ = require('../utils'); - -// remove modules that have been ignored by browserify -_.each(opts, function (conn, name) { - if (typeof conn !== 'function') { - delete opts[name]; - } -}); - -// custom __default specification -if (opts.xhr) { - opts._default = 'xhr'; -} else if (opts.angular) { - opts._default = 'angular'; -} else { - opts._default = 'jquery'; -} - -module.exports = opts; - -},{"../utils":79,"./angular":64,"./jquery":66,"./xhr":67}],66:[function(require,module,exports){ -/* jshint browser: true, jquery: true */ - -/** - * Simple connection class for using the XHR object in browsers - * - * @class {XhrConnection} - */ -module.exports = JqueryConnector; - -function JqueryConnector() {} - -JqueryConnector.prototype.request = function (params, cb) { - jQuery.ajax(params).done(cb); -}; - - - -},{}],67:[function(require,module,exports){ -/** - * Generic Transport for the browser, using the XmlHttpRequest object - * - * @class connections.Xhr - */ -module.exports = XhrConnector; - -/* jshint browser:true */ - -var _ = require('../utils'); -var ConnectionAbstract = require('../connection'); -var ConnectionFault = require('../errors').ConnectionFault; -var TimeoutError = require('../errors').RequestTimeout; -var asyncDefault = !(navigator && /PhantomJS/i.test(navigator.userAgent)); - -function XhrConnector(host, config) { - ConnectionAbstract.call(this, host, config); -} -_.inherits(XhrConnector, ConnectionAbstract); - -/** - * Simply returns an XHR object cross browser - * @type {Function} - */ -var getXhr = _.noop; - -if (typeof XMLHttpRequest !== 'undefined') { - // rewrite the getXhr method to always return the native implementation - getXhr = function () { - return new XMLHttpRequest(); - }; -} else { - // find the first MS implementation available - getXhr = _.first(['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'], function (appName) { - /* jshint unused: false */ - try { - var test = new window.ActiveXObject(appName); - return function () { - return new window.ActiveXObject(appName); - }; - } catch (e) { - return null; - } - }); -} - -if (!getXhr) { - throw new Error('getXhr(): XMLHttpRequest not available'); -} - -XhrConnector.prototype.request = function (params, cb) { - var xhr = getXhr(); - var timeout = params.timeout ? params.timeout : 10000; - var timeoutId; - var url = this.host.makeUrl(params); - var log = this.config.log; - var async = params.async === false ? false : asyncDefault; - - if (params.auth) { - xhr.open(params.method, url, async, params.auth.user, params.auth.pass); - } else { - xhr.open(params.method, url, async); - } - - xhr.onreadystatechange = function () { - if (xhr.readyState === 4) { - clearTimeout(timeoutId); - log.trace(params.method, url, params.body, xhr.responseText, xhr.status); - var err = xhr.status ? void 0 : new ConnectionFault(xhr.statusText || 'Request failed to complete.'); - cb(err, xhr.responseText, xhr.status); - } - }; - - if (timeout !== Infinity) { - timeoutId = setTimeout(function () { - xhr.onreadystatechange = _.noop; - xhr.abort(); - cb(new TimeoutError()); - }, timeout); - } - - xhr.send(params.body || void 0); -}; - -},{"../connection":62,"../errors":68,"../utils":79}],68:[function(require,module,exports){ -var process=require("__browserify_process");var _ = require('./utils'); -var errors = module.exports; - -function ErrorAbstract(msg, constructor) { - this.message = msg; - - Error.call(this, this.message); - if (process.browser) { - this.stack = ''; - } else { - Error.captureStackTrace(this, constructor); - } -} -errors._Abstract = ErrorAbstract; -_.inherits(ErrorAbstract, Error); - -/** - * Connection Error - * @param {String} [msg] - An error message that will probably end up in a log. - */ -errors.ConnectionFault = function ConnectionFault(msg) { - ErrorAbstract.call(this, msg || 'Connection Failure', errors.ConnectionFault); -}; -_.inherits(errors.ConnectionFault, ErrorAbstract); - -/** - * No Living Connections - * @param {String} [msg] - An error message that will probably end up in a log. - */ -errors.NoConnections = function NoConnections(msg) { - ErrorAbstract.call(this, msg || 'No Living connections', errors.NoConnections); -}; -_.inherits(errors.NoConnections, ErrorAbstract); - -/** - * Generic Error - * @param {String} [msg] - An error message that will probably end up in a log. - */ -errors.Generic = function Generic(msg) { - ErrorAbstract.call(this, msg || 'Generic Error', errors.Generic); -}; -_.inherits(errors.Generic, ErrorAbstract); - -/** - * Request Timeout Error - * @param {String} [msg] - An error message that will probably end up in a log. - */ -errors.RequestTimeout = function RequestTimeout(msg) { - ErrorAbstract.call(this, msg || 'Request Timeout', errors.RequestTimeout); -}; -_.inherits(errors.RequestTimeout, ErrorAbstract); - - -/** - * Request Body could not be parsed - * @param {String} [msg] - An error message that will probably end up in a log. - */ -errors.Serialization = function Serialization(msg) { - ErrorAbstract.call(this, msg || 'Unable to parse/serialize body', errors.Serialization); -}; -_.inherits(errors.Serialization, ErrorAbstract); - - -var statusCodes = { - - /** - * Service Unavailable - * @param {String} [msg] - An error message that will probably end up in a log. - */ - 503: 'Service Unavailable', - - /** - * Internal Server Error - * @param {String} [msg] - An error message that will probably end up in a log. - */ - 500: 'Internal Server Error', - - /** - * Precondition Failed - * @param {String} [msg] - An error message that will probably end up in a log. - */ - 412: 'Precondition Failed', - - /** - * Conflict - * @param {String} [msg] - An error message that will probably end up in a log. - */ - 409: 'Conflict', - - /** - * Forbidden - * @param {String} [msg] - An error message that will probably end up in a log. - */ - 403: 'Forbidden', - - /** - * Not Found - * @param {String} [msg] - An error message that will probably end up in a log. - */ - 404: 'Not Found', - - /** - * Bad Request - * @param {String} [msg] - An error message that will probably end up in a log. - */ - 400: 'Bad Request', - - /** - * Moved Permanently - * @param {String} [msg] - An error message that will probably end up in a log. - */ - 301: 'Moved Permanently' -}; - -_.each(statusCodes, function (name, status) { - var className = _.studlyCase(name); - - function StatusCodeError(msg) { - ErrorAbstract.call(this, msg || name, errors[className]); - } - - _.inherits(StatusCodeError, ErrorAbstract); - errors[className] = StatusCodeError; - errors[status] = StatusCodeError; -}); - -},{"./utils":79,"__browserify_process":15}],69:[function(require,module,exports){ -/** - * Class to wrap URLS, formatting them and maintaining their separate details - * @type {[type]} - */ -module.exports = Host; - -var url = require('url'); -var qs = require('querystring'); -var _ = require('./utils'); - -var startsWithProtocolRE = /^([a-z]+:)?\/\//; - -// simple reference used when formatting as a url -var defaultPort = { - http: 80, - https: 443 -}; - -var urlParseFields = [ - 'protocol', 'hostname', 'pathname', 'port', 'auth', 'query' -]; - -var simplify = ['host', 'path']; - -function Host(config) { - config = config || {}; - - // defaults - this.protocol = 'http'; - this.host = 'localhost'; - this.port = 9200; - this.auth = null; - this.query = null; - - if (typeof config === 'string') { - if (!startsWithProtocolRE.test(config)) { - config = 'http://' + config; - } - config = _.pick(url.parse(config, false, true), urlParseFields); - } - - if (_.isObject(config)) { - // move hostname/portname to host/port semi-intelligently. - _.each(simplify, function (to) { - var from = to + 'name'; - if (config[from] && config[to]) { - if (config[to].indexOf(config[from]) === 0) { - config[to] = config[from]; - } - } else if (config[from]) { - config[to] = config[from]; - } - delete config[from]; - }); - } else { - config = {}; - } - - _.assign(this, config); - - // make sure the query string is parsed - if (this.query === null) { - // majority case - this.query = {}; - } else if (!_.isPlainObject(this.query)) { - this.query = qs.parse(this.query); - } - - // make sure that the port is a number - if (typeof this.port !== 'number') { - this.port = parseInt(this.port, 10); - if (isNaN(this.port)) { - this.port = 9200; - } - } - - // make sure the path starts with a leading slash - // and that empty paths convert to '/' - if (!this.path || this.path.charAt(0) !== '/') { - this.path = '/' + (this.path || ''); - } - - // strip trailing ':' on the protocol (when config comes from url.parse) - if (this.protocol.substr(-1) === ':') { - this.protocol = this.protocol.substring(0, this.protocol.length - 1); - } -} - -Host.prototype.makeUrl = function (params) { - params = params || {}; - // build the port - var port = ''; - if (this.port !== defaultPort[this.protocol]) { - // add an actual port - port = ':' + this.port; - } - - // build the path - var path = '' + (this.path || '') + (params.path || ''); - - // if path doesn't start with '/' add it. - if (path.charAt(0) !== '/') { - path = '/' + path; - } - - // build the query string - var query = ''; - if (params.query) { - // if the user passed in a query, merge it with the defaults from the host - query = qs.stringify( - _.defaults(typeof params.query === 'string' ? qs.parse(params.query) : params.query, this.query) - ); - } else if (this.query) { - // just stringify the hosts query - query = qs.stringify(this.query); - } - - return this.protocol + '://' + this.host + port + path + (query ? '?' + query : ''); -}; - -Host.prototype.toString = function () { - return this.makeUrl(); -}; - -},{"./utils":79,"querystring":8,"url":9}],70:[function(require,module,exports){ -var process=require("__browserify_process");var _ = require('./utils'); -var url = require('url'); -var EventEmitter = require('events').EventEmitter; - -/** - * Log bridge, which is an [EventEmitter](http://nodejs.org/api/events.html#events_class_events_eventemitter) - * that sends events to one or more outputs/loggers. Setup these loggers by - * specifying their config as the first argument, or by passing it to addOutput(). - * - * @class Log - * @uses Loggers.Stdio - * @constructor - * @param {string|Object|ArrayOfStrings|ArrayOfObjects} output - Either the level - * to setup a single logger, a full config object for alogger, or an array of - * config objects to use for creating log outputs. - * @param {string} output.level - One of the keys in Log.levels (error, warning, etc.) - * @param {string} output.type - The name of the logger to use for this output - */ -function Log(config) { - config = config || {}; - - var i; - var outputs; - - if (config.log) { - if (_.isArrayOfStrings(config.log)) { - outputs = [{ - levels: config.log - }]; - } else { - outputs = _.createArray(config.log, function (val) { - if (_.isPlainObject(val)) { - return val; - } - if (typeof val === 'string') { - return { - level: val - }; - } - }); - } - - if (!outputs) { - throw new TypeError('Invalid logging output config. Expected either a log level, array of log levels, ' + - 'a logger config object, or an array of logger config objects.'); - } - - for (i = 0; i < outputs.length; i++) { - this.addOutput(outputs[i]); - } - } -} -_.inherits(Log, EventEmitter); - -Log.loggers = require('./loggers'); - -Log.prototype.close = function () { - this.emit('closing'); - if (this.listenerCount()) { - console.error('Something is still listening for log events, but the logger is closing.'); - this.clearAllListeners(); - } -}; - -Log.prototype.listenerCount = function (event) { - // compatability for node < 0.10 - if (EventEmitter.listenerCount) { - return EventEmitter.listenerCount(this, event); - } else { - return this.listeners(event).length; - } -}; - -/** - * Levels observed by the loggers, ordered by rank - * - * @property levels - * @type Array - * @static - */ -Log.levels = [ - /** - * Event fired for error level log entries - * @event error - * @param {Error} error - The error object to log - */ - 'error', - /** - * Event fired for "warning" level log entries, which usually represent things - * like correctly formatted error responses from ES (400, ...) and recoverable - * errors (one node unresponsive) - * - * @event warning - * @param {String} message - A message to be logged - */ - 'warning', - /** - * Event fired for "info" level log entries, which usually describe what a - * client is doing (sniffing etc) - * - * @event info - * @param {String} message - A message to be logged - */ - 'info', - /** - * Event fired for "debug" level log entries, which will describe requests sent, - * including their url (no data, response codes, or exec times) - * - * @event debug - * @param {String} message - A message to be logged - */ - 'debug', - /** - * Event fired for "trace" level log entries, which provide detailed information - * about each request made from a client, including reponse codes, execution times, - * and a full curl command that can be copied and pasted into a terminal - * - * @event trace - * @param {String} method method, , body, responseStatus, responseBody - * @param {String} url - The url the request was made to - * @param {String} body - The body of the request - * @param {Integer} responseStatus - The status code returned from the response - * @param {String} responseBody - The body of the response - */ - 'trace' -]; - -/** - * Converts a log config value (string or array) to an array of level names which - * it represents - * - * @method parseLevels - * @static - * @private - * @param {String|ArrayOfStrings} input - Cound be a string to specify the max - * level, or an array of exact levels - * @return {Array} - - */ -Log.parseLevels = function (input) { - switch (typeof input) { - case 'string': - var i = _.indexOf(Log.levels, input); - if (i >= 0) { - return Log.levels.slice(0, i + 1); - } - /* fall through */ - case 'object': - if (_.isArray(input)) { - var valid = _.intersection(input, Log.levels); - if (valid.length === input.length) { - return valid; - } - } - /* fall through */ - default: - throw new TypeError('invalid logging level ' + input + '. Expected zero or more of these options: ' + - Log.levels.join(', ')); - } -}; - -/** - * Combine the array-like param into a simple string - * - * @method join - * @static - * @private - * @param {*} arrayish - An array like object that can be itterated by _.each - * @return {String} - The final string. - */ -Log.join = function (arrayish) { - return _.map(arrayish, function (item) { - if (_.isPlainObject(item)) { - return _.inspect(item) + '\n'; - } else { - return item.toString(); - } - }).join(' '); -}; - -/** - * Create a new logger, based on the config. - * - * @method addOutput - * @param {object} config - An object with config options for the logger. - * @param {String} [config.type=stdio] - The name of an output/logger. Options - * can be found in the `src/loggers` directory. - * @param {String|ArrayOfStrings} [config.levels=warning] - The levels to output - * to this logger, when an array is specified no levels other than the ones - * specified will be listened to. When a string is specified, that and all lower - * levels will be logged. - * @return {Logger} - */ -Log.prototype.addOutput = function (config) { - config = config || {}; - - // force "levels" key - config.levels = Log.parseLevels(config.levels || config.level || 'warning'); - delete config.level; - - var Logger = _.funcEnum(config, 'type', Log.loggers, process.browser ? 'console' : 'stdio'); - return new Logger(this, config); -}; - -/** - * Log an error - * - * @method error - * @param {Error|String} error The Error to log - * @return {Boolean} - True if any outputs accepted the message - */ -Log.prototype.error = function (e) { - if (this.listenerCount('error')) { - return this.emit('error', e instanceof Error ? e : new Error(e)); - } -}; - - -/** - * Log a warning message - * - * @method warning - * @param {*} msg* - Any amount of messages that will be joined before logged - * @return {Boolean} - True if any outputs accepted the message - */ -Log.prototype.warning = function (/* ...msg */) { - if (this.listenerCount('warning')) { - return this.emit('warning', Log.join(arguments)); - } -}; - - -/** - * Log useful info about what's going on - * - * @method info - * @param {*} msg* - Any amount of messages that will be joined before logged - * @return {Boolean} - True if any outputs accepted the message - */ -Log.prototype.info = function (/* ...msg */) { - if (this.listenerCount('info')) { - return this.emit('info', Log.join(arguments)); - } -}; - -/** - * Log a debug level message - * - * @method debug - * @param {*} msg* - Any amount of messages that will be joined before logged - * @return {Boolean} - True if any outputs accepted the message - */ -Log.prototype.debug = function (/* ...msg */) { - if (this.listenerCount('debug')) { - return this.emit('debug', Log.join(arguments) /*+ _.getStackTrace(Log.prototype.debug)*/); - } -}; - -/** - * Log a trace level message - * - * @method trace - * @param {String} method - HTTP request method - * @param {String|Object} requestUrl - URL requested. If the value is an object, - * it is expected to be the return value of Node's url.parse() - * @param {String} body - The request's body - * @param {String} responseBody - body returned from ES - * @param {String} responseStatus - HTTP status code - * @return {Boolean} - True if any outputs accepted the message - */ -Log.prototype.trace = function (method, requestUrl, body, responseBody, responseStatus) { - if (this.listenerCount('trace')) { - if (typeof requestUrl === 'string') { - requestUrl = url.parse(requestUrl, true, true); - } - requestUrl = _.defaults({ - host: 'localhost:9200', - query: _.defaults({ - pretty: true - }, requestUrl.query) - }, requestUrl); - delete requestUrl.auth; - - if (!requestUrl.pathname && requestUrl.path) { - requestUrl.pathname = requestUrl.path.split('?').shift(); - } - - requestUrl = url.format(requestUrl); - - var message = '<- ' + responseStatus + '\n' + prettyJSON(responseBody); - - /* jshint quotmark: double */ - var curlCall = "curl '" + requestUrl.replace(/'/g, "\\'") + "' -X" + method.toUpperCase(); - if (body) { - curlCall += " -d '" + prettyJSON(body) + "'"; - } - /* jshint quotmark: single */ - - return this.emit('trace', message, curlCall); - } -}; - -function prettyJSON(body) { - try { - return JSON.stringify(JSON.parse(body), null, ' ').replace(/'/g, '\\\''); - } catch (e) { - return body || ''; - } -} - -module.exports = Log; - -},{"./loggers":72,"./utils":79,"__browserify_process":15,"events":5,"url":9}],71:[function(require,module,exports){ -var _ = require('./utils'); - -/** - * Abstract class providing common functionality to loggers - * @param {[type]} log [description] - * @param {[type]} config [description] - */ -function LoggerAbstract(log, config) { - this.log = log; - this.listeningLevels = []; - - _.makeBoundMethods(this); - - // when the log closes, remove our event listeners - this.log.on('closing', this.bound.cleanUpListeners); - - this.setupListeners(config.levels); -} - -function padNumToTen(n) { - return n < 10 ? '0' + n.toString(10) : n.toString(10); -} - -/** - * Create a timestamp string used in the format function. Defers to Log.timestamp if it is defined, - * Also, feel free to override this at the logger level. - * @return {String} - Timestamp in ISO 8601 UTC - */ -LoggerAbstract.prototype.timestamp = function () { - var d = new Date(); - return d.getUTCFullYear() + '-' + - padNumToTen(d.getUTCMonth() + 1) + '-' + - padNumToTen(d.getUTCDate()) + 'T' + - padNumToTen(d.getUTCHours()) + ':' + - padNumToTen(d.getUTCMinutes()) + ':' + - padNumToTen(d.getUTCSeconds()) + 'Z'; -}; - -function indent(text, spaces) { - var space = _.repeat(' ', spaces || 2); - return text.split(/\r?\n/).map(function (line) { - return space + line; - }).join('\n'); -} - -LoggerAbstract.prototype.format = function (label, message) { - return label + ': ' + this.timestamp() + '\n' + indent(message) + '\n\n'; -}; - -LoggerAbstract.prototype.write = function () { - throw new Error('This should be overwritten by the logger'); -}; - -/** - * Clear the current event listeners and then re-listen for events based on the level specified - * - * @method setupListeners - * @private - * @param {Integer} level - The max log level that this logger should listen to - * @return {undefined} - */ -LoggerAbstract.prototype.setupListeners = function (levels) { - this.cleanUpListeners(); - - this.listeningLevels = levels; - - _.each(this.listeningLevels, function (level) { - var fnName = 'on' + _.ucfirst(level); - if (this.bound[fnName]) { - this.log.on(level, this.bound[fnName]); - } else { - throw new Error(fnName + ' is not a function'); - } - }, this); -}; - -/** - * Clear the current event listeners - * - * @method cleanUpListeners - * @private - * @return {undefined} - */ -LoggerAbstract.prototype.cleanUpListeners = _.handler(function () { - _.each(this.listeningLevels, function (level) { - this.log.removeListener(level, this.bound['on' + _.ucfirst(level)]); - }, this); -}); - -/** - * Handler for the logs "error" event - * - * @method onError - * @private - * @param {Error} e - The Error object to log - * @return {undefined} - */ -LoggerAbstract.prototype.onError = _.handler(function (e) { - this.write((e.name === 'Error' ? 'ERROR' : e.name), e.stack); -}); - -/** - * Handler for the logs "warning" event - * - * @method onWarning - * @private - * @param {String} msg - The message to be logged - * @return {undefined} - */ -LoggerAbstract.prototype.onWarning = _.handler(function (msg) { - this.write('WARNING', msg); -}); - -/** - * Handler for the logs "info" event - * - * @method onInfo - * @private - * @param {String} msg - The message to be logged - * @return {undefined} - */ -LoggerAbstract.prototype.onInfo = _.handler(function (msg) { - this.write('INFO', msg); -}); - -/** - * Handler for the logs "debug" event - * - * @method onDebug - * @private - * @param {String} msg - The message to be logged - * @return {undefined} - */ -LoggerAbstract.prototype.onDebug = _.handler(function (msg) { - this.write('DEBUG', msg); -}); - -/** - * Handler for the logs "trace" event - * - * @method onTrace - * @private - * @param {String} msg - The message to be logged - * @return {undefined} - */ -LoggerAbstract.prototype.onTrace = _.handler(function (message) { - this.write('TRACE', message); -}); - - -module.exports = LoggerAbstract; - -},{"./utils":79}],72:[function(require,module,exports){ -module.exports = { - console: require('./console') -}; - -},{"./console":73}],73:[function(require,module,exports){ -/** - * Special version of the Stream logger, which logs errors and warnings to stderr and all other - * levels to stdout. - * - * @class Loggers.Console - * @extends LoggerAbstract - * @constructor - * @param {Object} config - The configuration for the Logger - * @param {string} config.level - The highest log level for this logger to output. - * @param {Log} bridge - The object that triggers logging events, which we will record - */ - -module.exports = Console; - -var LoggerAbstract = require('../logger'); -var _ = require('../utils'); - -function Console(log, config) { - // call my super - LoggerAbstract.call(this, log, config); - - // config/state - this.color = _.has(config, 'color') ? !!config.color : true; -} -_.inherits(Console, LoggerAbstract); - -/** - * Override the LoggerAbstract's setup listeners to do a little extra setup - * - * @param {Array} levels - The levels that we should be listeneing for - */ -Console.prototype.setupListeners = function (levels) { - // since some of our functions are bound a bit differently (to the console) - // create some of the bound properties manually - this.bound.onError = this.onError; - this.bound.onWarning = this.onWarning; - this.bound.onInfo = this.onInfo; - this.bound.onDebug = this.onDebug; - this.bound.onTrace = this.onTrace; - - // call the super method - LoggerAbstract.prototype.setupListeners.call(this, levels); -}; - -/** - * Handler for the bridges "error" event - * - * @method onError - * @private - * @param {Error} e - The Error object to log - * @return {undefined} - */ -Console.prototype.onError = function (e) { - if (console.error && console.trace) { - console.error(e.name === 'Error' ? 'ERROR' : e.name, e.stack || e.message); - } else { - console.log(e.name === 'Error' ? 'ERROR' : e.name, e.stack || e.message); - } -}; - -/** - * Handler for the bridges "warning" event - * - * @method onWarning - * @private - * @param {String} msg - The message to be logged - * @return {undefined} - */ -Console.prototype.onWarning = function (msg) { - console[console.warn ? 'warn' : 'log']('WARNING', msg); -}; - -/** - * Handler for the bridges "info" event - * - * @method onInfo - * @private - * @param {String} msg - The message to be logged - * @return {undefined} - */ -Console.prototype.onInfo = function (msg) { - console[console.warn ? 'info' : 'log']('INFO', msg); -}; - -/** - * Handler for the bridges "debug" event - * - * @method onDebug - * @private - * @param {String} msg - The message to be logged - * @return {undefined} - */ -Console.prototype.onDebug = function (msg) { - console[console.debug ? 'debug' : 'log']('DEBUG', msg); -}; -/** - * Handler for the bridges "trace" event - * - * @method onTrace - * @private - * @return {undefined} - */ -Console.prototype.onTrace = function (message, curlCall) { - console.log('TRACE:\n' + curlCall + '\n' + message); -}; - -},{"../logger":71,"../utils":79}],74:[function(require,module,exports){ -module.exports = { - random: require('./random'), - roundRobin: require('./round_robin') -}; - -},{"./random":75,"./round_robin":76}],75:[function(require,module,exports){ -/** - * Selects a connection randomly - * - * @module selectors - * @type {Function} - * @param {Array} connection - The list of connections to choose from - * @return {Connection} - The selected connection - */ -module.exports = function RandomSelector(connections) { - return connections[Math.floor(Math.random() * connections.length)]; -}; - -},{}],76:[function(require,module,exports){ -/** - * Selects a connection the simplest way possible, Round Robin - * - * @module selectors - * @type {Function} - * @param {Array} connections - The list of connections that this selector needs to choose from - * @return {Connection} - The selected connection - */ -module.exports = function (connections) { - var connection = connections[0]; - connections.push(connections.shift()); - return connection; -}; - -},{}],77:[function(require,module,exports){ -/** - * Simple JSON serializer - * @type {[type]} - */ -module.exports = Json; - -var _ = require('../utils'); - -function Json() {} - -Json.prototype.serialize = function (val, replacer, spaces) { - if (val == null) { - return; - } - else if (typeof val === 'string') { - return val; - } else { - return JSON.stringify(val, replacer, spaces); - } -}; - -Json.prototype.unserialize = function (str) { - if (typeof str === 'string') { - try { - return JSON.parse(str); - } catch (e) { - return; - } - } else { - return str; - } -}; - -Json.prototype.bulkBody = function (val) { - var body = '', i; - - if (_.isArray(val)) { - for (i = 0; i < val.length; i++) { - body += this.serialize(val[i]) + '\n'; - } - } else if (typeof val === 'string') { - // make sure the string ends in a new line - body = val + (val[val.length - 1] === '\n' ? '' : '\n'); - } else { - throw new TypeError('Bulk body should either be an Array of commands/string, or a String'); - } - - return body; -}; - -},{"../utils":79}],78:[function(require,module,exports){ -/** - * Class that manages making request, called by all of the API methods. - * @type {[type]} - */ -module.exports = Transport; - -var _ = require('./utils'); -var errors = require('./errors'); -var Host = require('./host'); -var Log = require('./log'); -var when = require('when'); - -function Transport(config) { - config = config || {}; - - var LogClass; - // setup the log - switch (typeof config.log) { - case 'function': - LogClass = config.log; - break; - case 'undefined': - config.log = 'warning'; - /* fall through */ - default: - LogClass = Log; - } - - config.log = this.log = new LogClass(config); - - // overwrite the createDefer method if a new implementation is provided - if (typeof config.createDefer === 'function') { - this.createDefer = config.createDefer; - } - - // setup the connection pool - var ConnectionPool = _.funcEnum(config, 'connectionPool', Transport.connectionPools, 'main'); - this.connectionPool = new ConnectionPool(config); - - if (config.hosts) { - var hosts = _.createArray(config.hosts, function (val) { - if (_.isPlainObject(val) || _.isString(val)) { - return val; - } - }); - if (!hosts) { - throw new Error('Invalid hosts config. Expected a URL, an array of urls, a host config object, or an array of ' + - 'host config objects.'); - } - - this.connectionPool.setHosts(_.map(hosts, function (conf) { - return new Host(conf); - })); - } - - // setup the serializer - var Serializer = _.funcEnum(config, 'serializer', Transport.serializers, 'json'); - this.serializer = new Serializer(config); -} - -Transport.connectionPools = { - main: require('./connection_pool') -}; - -Transport.serializers = { - json: require('./serializers/json') -}; - -/** - * Perform a request with the client's transport - * - * @method request - * @todo async body writing - * @todo abort - * @todo access to custom headers, modifying of request in general - * @param {object} params - * @param {String} params.url - The url for the request - * @param {String} params.method - The HTTP method for the request - * @param {String} params.body - The body of the HTTP request - * @param {Function} cb - A function to call back with (error, responseBody, responseStatus) - */ -Transport.prototype.request = function (params, cb) { - - var self = this; - var remainingRetries = this.maxRetries; - var connection; // set in sendReqWithConnection - var connectionReq; // an object with an abort method, set in sendReqWithConnection - var request; // the object returned to the user, might be a deferred - - self.log.debug('starting request', params); - - if (params.body && params.method === 'GET') { - _.nextTick(respond, new TypeError('Body can not be sent with method "GET"')); - return; - } - - // serialize the body - if (params.body) { - params.body = self.serializer[params.bulkBody ? 'bulkBody' : 'serialize'](params.body); - } - - params.req = { - timeout: params.timeout, - method: params.method, - path: params.path, - query: params.query, - body: params.body, - }; - - self.connectionPool.select(sendReqWithConnection); - - function abortRequest() { - remainingRetries = 0; - connectionReq.abort(); - } - - function sendReqWithConnection(err, _connection) { - if (err) { - respond(err); - } else if (_connection) { - connection = _connection; - connectionReq = connection.request(params.req, checkRespForFailure); - } else { - self.log.warning('No living connections'); - respond(new errors.NoConnections()); - } - } - - function checkRespForFailure(err, body, status) { - if (err && remainingRetries) { - remainingRetries--; - self.log.error(err.message, '-- retrying'); - self.connectionPool.select(sendReqWithConnection); - } else { - self.log.info('Request complete'); - respond(err, body, status); - } - } - - function respond(err, body, status) { - var parsedBody; - - if (!err && body) { - parsedBody = self.serializer.unserialize(body); - if (parsedBody == null) { - err = new errors.Serialization(); - } - } - - if (!err) { - if ((status < 200 || status >= 300) - && (!params.ignore || !_.contains(params.ignore, status)) - ) { - if (errors[status]) { - err = new errors[status](parsedBody && parsedBody.error); - } else { - err = new errors.Generic('unknown error'); - } - } - } - - if (params.castExists) { - if (err && err instanceof errors.NotFound) { - parsedBody = false; - err = void 0; - } else { - parsedBody = !err; - } - } - - if (typeof cb === 'function') { - cb(err, parsedBody, status); - } else if (err) { - request.reject(err); - } else { - request.resolve({ - body: parsedBody, - status: status - }); - } - } - - // determine the API based on the presense of a callback - if (typeof cb === 'function') { - request = { - abort: abortRequest - }; - } else { - var defer = this.createDefer(); - defer.promise.abort = abortRequest; - request = defer.promise; - } - - return request; -}; - -Transport.prototype.createDefer = function () { - return when.defer(); -}; - -/** - * Ask an ES node for a list of all the nodes, add/remove nodes from the connection - * pool as appropriate - * - * @param {Function} cb - Function to call back once complete - */ -Transport.prototype.sniff = function (cb) { - var self = this; - - // make cb a function if it isn't - cb = typeof cb === 'function' ? cb : _.noop; - - this.request({ - path: '/_cluster/nodes', - method: 'GET' - }, function (err, resp) { - if (!err && resp && resp.nodes) { - var hosts = _.map(self.nodesToHostCallback(resp.nodes), function (hostConfig) { - return new Host(hostConfig); - }); - this.connectionPool.setHosts(hosts); - } - cb(err, resp); - }); -}; - -Transport.prototype.close = function () { - this.log.close(); - this.connectionPool.close(); -}; - -},{"./connection_pool":63,"./errors":68,"./host":69,"./log":70,"./serializers/json":77,"./utils":79,"when":57}],79:[function(require,module,exports){ +},{}],52:[function(require,module,exports){ var process=require("__browserify_process");var path = require('path'); var _ = require('lodash'); -var nodeUtils = require('util'); // not included in the browser build +var nodeUtils = require('util'); /** * Custom utils library, basically a modified version of [lodash](http://lodash.com/docs) + @@ -30636,23 +22901,6 @@ var nodeUtils = require('util'); // not included in the browser build var utils = _.extend({}, _, nodeUtils); _ = utils; -utils.inspect = function (thing, opts) { - if (process.browser) { - try { - return JSON.stringify(thing, null, ' ') + '\n'; - } catch (e) { - return thing ? thing.toString() : '' + thing; - } - } else { - return nodeUtils.inspect(thing, _.defaults(opts || {}, { - showHidden: true, - depth: null, - color: true - })); - } -}; - - /** * Link to [path.join](http://nodejs.org/api/path.html#path_path_join_path1_path2) * @@ -30661,32 +22909,6 @@ utils.inspect = function (thing, opts) { */ utils.joinPath = path.join; -/** - * Recursively re-key an object, applying "transform" to each key - * @param {Object} obj - The object to re-key - * @param {Function} transform - The transformation function to apply to each key - * @param {Boolean} [recursive=true] - Should this act recursively? - * @param {Object} out - used primarily for recursion, allows you to specify the object which new keys will be written to - * @return {Object} - */ -utils.reKey = function (obj, transform, recursive) { - // defaults - if (recursive === void 0) { recursive = true; } - if (typeof transform !== 'function') { throw new TypeError('invalid transform function'); } - - var out = {}; - - _.each(obj, function (prop, name) { - if (recursive && _.isPlainObject(prop)) { - out[transform(name)] = utils.reKey(prop, transform, recursive); - } else { - out[transform(name)] = prop; - } - }); - - return out; -}; - /** * Recursively merge two objects, walking into each object and concating arrays. If both to and from have a value at a * key, but the values' types don't match to's value is left unmodified. Only Array and Object values are merged - that @@ -30786,7 +23008,7 @@ function adjustWordCase(firstWordCap, otherWordsCap, sep) { words.push(word); } // add the leading underscore back to strings the had it originally - if (words.lenth && string.charAt(0) === '_') { + if (words.length && string.charAt(0) === '_') { words[0] = '_' + words[0]; } return words.join(sep); @@ -30892,36 +23114,6 @@ utils.repeat = function (what, times) { return (new Array(times + 1)).join(what); }; -/** - * Override node's util.inherits function, providing a browser safe version thanks to lodash - * - * @param constructor {Function} - the constructor that should subClass superConstructor - * @param superConstructor {Function} - The parent constructor - */ -utils.inherits = require('inherits'); - -/** - * Remove leading/trailing spaces from a string - * - * @param str {String} - Any string - * @returns {String} - */ -utils.trim = function (str) { - return typeof str === 'string' ? str.replace(/^\s+|\s+$/g, '') : ''; -}; - -utils.collectMatches = function (text, regExp) { - var matches = [], match; - while (match = regExp.exec(text)) { - matches.push(match); - if (regExp.global !== true) { - // would loop forever if not true - break; - } - } - return matches; -}; - /** * Call a function, applying the arguments object to it in an optimized way, rather than always turning it into an array * @@ -30998,22 +23190,14 @@ _.scheduled = _.handler; * ``` * * @param {Object} obj - The object to bind the methods to - * @param {Array} [methods] - The methods to bind, false values === bind all flagged with _provideBound */ -_.makeBoundMethods = function (obj, methods) { +_.makeBoundMethods = function (obj) { obj.bound = {}; - if (!methods) { - methods = []; - for (var prop in obj) { - // dearest maintainer, we want to look through the prototype - if (typeof obj[prop] === 'function' && obj[prop]._provideBound === true) { - obj.bound[prop] = _.bind(obj[prop], obj); - } + for (var prop in obj) { + // dearest maintainer, we want to look through the prototype + if (typeof obj[prop] === 'function' && obj[prop]._provideBound === true) { + obj.bound[prop] = _.bind(obj[prop], obj); } - } else { - _.each(methods, function (method) { - obj.bound[method] = _.bindKey(obj, method); - }); } }; @@ -31033,13 +23217,23 @@ _.funcEnum = function (config, name, opts, def) { case 'function': return val; case 'string': - if (opts[val]) { + if (opts.hasOwnProperty(val)) { return opts[val]; } /* falls through */ default: - throw new TypeError('Invalid ' + name + ' "' + val + '", expected a function or one of ' + - _.keys(opts).join(', ')); + var err = 'Invalid ' + name + ' "' + val + '", expected a function'; + switch (_.size(opts)) { + case 0: + break; + case 1: + err += ' or ' + _.keys(opts)[0]; + break; + default: + err += ' or one of ' + _.keys(opts).join(', '); + break; + } + throw new TypeError(err); } }; @@ -31074,9 +23268,31 @@ _.createArray = function (input, transform) { return output; }; +/** + * Takes a WritableStream, and returns the chunks that have not successfully written, returning them as a string. + * + * ONLY WORKS FOR TEXT STREAMS + * + * @param {WritableStream} stream - an instance of stream.Writable + * @return {string} - the remaining test to be written to the stream + */ +_.getUnwrittenFromStream = function (stream) { + if (stream && stream._writableState && stream._writableState.buffer) { + // flush the write buffer to disk + var writeBuffer = stream._writableState.buffer; + var out = ''; + if (writeBuffer.length) { + writeBuffer.forEach(function (buffered) { + out += buffered.chunk.toString(); + }); + } + return out; + } +}; + module.exports = utils; -},{"__browserify_process":15,"inherits":17,"lodash":50,"path":7,"util":10}],80:[function(require,module,exports){ +},{"__browserify_process":14,"lodash":48,"path":8,"util":9}],53:[function(require,module,exports){ var process=require("__browserify_process");var path = require('path'); var _ = require('../../../src/lib/utils'); @@ -31107,7 +23323,7 @@ if (process.browser) { .argv; } -},{"../../../src/lib/utils":79,"__browserify_process":15,"optimist":54,"path":7}],81:[function(require,module,exports){ +},{"../../../src/lib/utils":52,"__browserify_process":14,"optimist":false,"path":8}],54:[function(require,module,exports){ var process=require("__browserify_process");if (process.browser) { /* jshint browser: true */ var es = window.elasticsearch; @@ -31116,8 +23332,8 @@ var process=require("__browserify_process");if (process.browser) { } var argv = require('./argv'); var server = require('./server'); -var path = require('path'); -var fs = require('fs'); +// var path = require('path'); +// var fs = require('fs'); var _ = require('../../../src/lib/utils'); // current client @@ -31148,7 +23364,7 @@ module.exports = { doCreateClient(function () { client.ping(function (err) { if (err instanceof es.errors.ConnectionFault) { - externalExists = !err; + externalExists = false; create(done); } else { done(err); @@ -31191,7 +23407,7 @@ module.exports = { } }; -},{"../../../src/elasticsearch":58,"../../../src/lib/utils":79,"./argv":80,"./server":83,"__browserify_process":15,"fs":6,"path":7}],82:[function(require,module,exports){ +},{"../../../src/elasticsearch":2,"../../../src/lib/utils":52,"./argv":53,"./server":56,"__browserify_process":14}],55:[function(require,module,exports){ var __dirname="/";var path = require('path'); var async = require('async'); var jsYaml = require('js-yaml'); @@ -31226,7 +23442,7 @@ var files = _.map(require('./yaml_tests.json'), function (docs, filename) { } }); -},{"../../../src/elasticsearch":58,"../../../src/lib/utils":79,"./argv":80,"./client_manager":81,"./yaml_file":85,"./yaml_tests.json":86,"async":1,"expect.js":16,"js-yaml":18,"minimatch":51,"path":7}],83:[function(require,module,exports){ +},{"../../../src/elasticsearch":2,"../../../src/lib/utils":52,"./argv":53,"./client_manager":54,"./yaml_file":58,"./yaml_tests.json":59,"async":1,"expect.js":15,"js-yaml":16,"minimatch":49,"path":8}],56:[function(require,module,exports){ var process=require("__browserify_process");var childProc = require('child_process'); var events = require('events'); var path = require('path'); @@ -31262,7 +23478,7 @@ exports.start = function (cb) { ); server.stdout.on('data', function onProcessData(line) { - line = _.trim(line.toString()); + line = line.toString().trim(); var match; if (match = line.match(/\{inet\[\/?([^:]+):(\d+)\]\}/)) { server.__hostname = match[1]; @@ -31278,7 +23494,7 @@ exports.start = function (cb) { }); server.stderr.on('data', function (line) { - console.error(_.trim(line.toString())); + console.error(line.toString().trim()); }); server.on('close', function (code) { @@ -31293,7 +23509,7 @@ exports.start = function (cb) { }; -},{"../../../src/lib/utils":79,"./argv":80,"__browserify_process":15,"child_process":4,"events":5,"fs":6,"path":7}],84:[function(require,module,exports){ +},{"../../../src/lib/utils":52,"./argv":53,"__browserify_process":14,"child_process":5,"events":6,"fs":7,"path":8}],57:[function(require,module,exports){ var process=require("__browserify_process");/** * Class to wrap a single document from a yaml test file * @@ -31734,7 +23950,7 @@ YamlDoc.prototype = { } }; -},{"../../../src/lib/utils":79,"./client_manager":81,"__browserify_process":15,"expect.js":16}],85:[function(require,module,exports){ +},{"../../../src/lib/utils":52,"./client_manager":54,"__browserify_process":14,"expect.js":15}],58:[function(require,module,exports){ /** * Class representing a YAML file * @type {[type]} @@ -31757,7 +23973,6 @@ function YamlFile(filename, docs) { doc = new YamlDoc(doc, file); if (doc.description === 'setup') { beforeEach(/* doc */function (done) { - // console.log('setting up:', filename); async.series(_.pluck(doc._actions, 'testable'), done); }); } else { @@ -31768,7 +23983,6 @@ function YamlFile(filename, docs) { }); afterEach(/* doc */function (done) { - // console.log('clearing indices'); clientManager.get().indices.delete({ index: '*', ignore: 404 @@ -31778,7 +23992,7 @@ function YamlFile(filename, docs) { } -},{"../../../src/lib/utils":79,"./client_manager":81,"./yaml_doc":84,"async":1}],86:[function(require,module,exports){ +},{"../../../src/lib/utils":52,"./client_manager":54,"./yaml_doc":57,"async":1}],59:[function(require,module,exports){ module.exports={ "bulk/10_basic.yaml": [ { @@ -42349,5 +34563,5 @@ module.exports={ } ] } -},{}]},{},[82]) +},{}]},{},[55]) ; \ No newline at end of file diff --git a/test/integration/yaml_suite/index.js b/test/integration/yaml_suite/index.js index 72736bdfd..dbd1dff70 100644 --- a/test/integration/yaml_suite/index.js +++ b/test/integration/yaml_suite/index.js @@ -11,23 +11,27 @@ var argv = require('./argv'); var testDir = path.resolve(__dirname, './tests'); var doPattern = new Minimatch(argv.match); -// before running any tests... -before(function (done) { - // start our personal ES Server - this.timeout(null); - clientManager.create(done); -}); +describe('yaml -', function () { -before(function (done) { - // make sure ES is empty - clientManager.get().indices.delete({ - index: '*', - ignore: 404 - }, done); -}); + // before running any tests... + before(function (done) { + // start our personal ES Server + this.timeout(null); + clientManager.create(done); + }); -var files = _.map(require('./yaml_tests.json'), function (docs, filename) { - if (doPattern.match(filename)) { - return new YamlFile(filename, docs); - } -}); + before(function (done) { + // make sure ES is empty + clientManager.get().indices.delete({ + index: '*', + ignore: 404 + }, done); + }); + + var files = _.map(require('./yaml_tests.json'), function (docs, filename) { + if (doPattern.match(filename)) { + return new YamlFile(filename, docs); + } + }); + +}); \ No newline at end of file diff --git a/test/mocks/browser_http.js b/test/mocks/browser_http.js new file mode 100644 index 000000000..bcc228ecb --- /dev/null +++ b/test/mocks/browser_http.js @@ -0,0 +1,484 @@ +/* jshint browser:true */ +/* global ActiveXObject */ + +////////////// +/// Extended version of: +/// https://github.com/philikon/MockHttpRequest/ +////////////// +/* + * Mock XMLHttpRequest (see http://www.w3.org/TR/XMLHttpRequest) + * + * Written by Philipp von Weitershausen + * Released under the MIT license. + * http://www.opensource.org/licenses/mit-license.php + * + * For test interaction it exposes the following attributes: + * + * - method, url, urlParts, async, user, password + * - requestText + * + * as well as the following methods: + * + * - getRequestHeader(header) + * - setResponseHeader(header, value) + * - receive(status, data) + * - err(exception) + * - authenticate(user, password) + * + */ + +module.exports = MockHttpRequest; + +var _ = require('lodash'); + +function MockHttpRequest() { + // These are internal flags and data structures + this.error = false; + this.sent = false; + this.requestHeaders = {}; + this.responseHeaders = {}; +} + +MockHttpRequest.prototype = { + + statusReasons: { + 100: 'Continue', + 101: 'Switching Protocols', + 102: 'Processing', + 200: 'OK', + 201: 'Created', + 202: 'Accepted', + 203: 'Non-Authoritative Information', + 204: 'No Content', + 205: 'Reset Content', + 206: 'Partial Content', + 207: 'Multi-Status', + 300: 'Multiple Choices', + 301: 'Moved Permanently', + 302: 'Moved Temporarily', + 303: 'See Other', + 304: 'Not Modified', + 305: 'Use Proxy', + 307: 'Temporary Redirect', + 400: 'Bad Request', + 401: 'Unauthorized', + 402: 'Payment Required', + 403: 'Forbidden', + 404: 'Not Found', + 405: 'Method Not Allowed', + 406: 'Not Acceptable', + 407: 'Proxy Authentication Required', + 408: 'Request Time-out', + 409: 'Conflict', + 410: 'Gone', + 411: 'Length Required', + 412: 'Precondition Failed', + 413: 'Request Entity Too Large', + 414: 'Request-URI Too Large', + 415: 'Unsupported Media Type', + 416: 'Requested range not satisfiable', + 417: 'Expectation Failed', + 422: 'Unprocessable Entity', + 423: 'Locked', + 424: 'Failed Dependency', + 500: 'Internal Server Error', + 501: 'Not Implemented', + 502: 'Bad Gateway', + 503: 'Service Unavailable', + 504: 'Gateway Time-out', + 505: 'HTTP Version not supported', + 507: 'Insufficient Storage' + }, + + /*** State ***/ + + UNSENT: 0, + OPENED: 1, + HEADERS_RECEIVED: 2, + LOADING: 3, + DONE: 4, + readyState: 0, + + /*** Request ***/ + + open: function (method, url, async, user, password) { + if (typeof method !== 'string') { + throw 'INVALID_METHOD'; + } + switch (method.toUpperCase()) { + case 'CONNECT': + case 'TRACE': + case 'TRACK': + throw 'SECURITY_ERR'; + + case 'DELETE': + case 'GET': + case 'HEAD': + case 'OPTIONS': + case 'POST': + case 'PUT': + method = method.toUpperCase(); + } + this.method = method; + + if (typeof url !== 'string') { + throw 'INVALID_URL'; + } + this.url = url; + this.urlParts = this.parseUri(url); + + if (async === undefined) { + async = true; + } + this.async = async; + this.user = user; + this.password = password; + + this.readyState = this.OPENED; + this.onreadystatechange(); + }, + + setRequestHeader: function (header, value) { + header = header.toLowerCase(); + + switch (header) { + case 'accept-charset': + case 'accept-encoding': + case 'connection': + case 'content-length': + case 'cookie': + case 'cookie2': + case 'content-transfer-encoding': + case 'date': + case 'expect': + case 'host': + case 'keep-alive': + case 'referer': + case 'te': + case 'trailer': + case 'transfer-encoding': + case 'upgrade': + case 'user-agent': + case 'via': + return; + } + if ((header.substr(0, 6) === 'proxy-') || (header.substr(0, 4) === 'sec-')) { + return; + } + + // it's the first call on this header field + if (this.requestHeaders[header] === undefined) { + this.requestHeaders[header] = value; + } + else { + var prev = this.requestHeaders[header]; + this.requestHeaders[header] = prev + ', ' + value; + } + + }, + + send: function (data) { + if ((this.readyState !== this.OPENED) || this.sent) { + throw 'INVALID_STATE_ERR'; + } + if ((this.method === 'GET') || (this.method === 'HEAD')) { + data = null; + } + + //TODO set Content-Type header? + this.error = false; + this.sent = true; + this.onreadystatechange(); + + // fake send + this.requestText = data; + this.onsend(); + }, + + abort: function () { + this.responseText = null; + this.error = true; + for (var header in this.requestHeaders) { + if (this.requestHeaders.hasOwnProperty(header)) { + delete this.requestHeaders[header]; + } + } + delete this.requestText; + this.onreadystatechange(); + this.onabort(); + this.readyState = this.UNSENT; + }, + + /*** Response ***/ + + status: 0, + statusText: '', + + getResponseHeader: function (header) { + if ((this.readyState === this.UNSENT) || (this.readyState === this.OPENED) || this.error) { + return null; + } + return this.responseHeaders[header.toLowerCase()]; + }, + + getAllResponseHeaders: function () { + var r = ''; + _.each(this.responseHeaders, function (header) { + if ((header === 'set-cookie') || (header === 'set-cookie2')) { + return; + } + //TODO title case header + r += header + ': ' + this.responseHeaders[header] + '\r\n'; + }, this); + return r; + }, + + responseText: '', + responseXML: undefined, //TODO + + /*** See http://www.w3.org/TR/progress-events/ ***/ + + onload: function () { + // Instances should override this. + }, + + onprogress: function () { + // Instances should override this. + }, + + onerror: function () { + // Instances should override this. + }, + + onabort: function () { + // Instances should override this. + }, + + onreadystatechange: function () { + // Instances should override this. + }, + + /*** Properties and methods for test interaction ***/ + + onsend: function () { + // Instances should override this. + }, + + getRequestHeader: function (header) { + return this.requestHeaders[header.toLowerCase()]; + }, + + setResponseHeader: function (header, value) { + this.responseHeaders[header.toLowerCase()] = value; + }, + + makeXMLResponse: function (data) { + var xmlDoc; + // according to specs from point 3.7.5: + // '1. If the response entity body is null terminate these steps + // and return null. + // 2. If final MIME type is not null, text/xml, application/xml, + // and does not end in +xml terminate these steps and return null. + var mimetype = this.getResponseHeader('Content-Type'); + mimetype = mimetype && mimetype.split(';', 1)[0]; + if ((mimetype == null) || (mimetype === 'text/xml') || + (mimetype === 'application/xml') || + (mimetype && mimetype.substring(mimetype.length - 4) === '+xml')) { + // Attempt to produce an xml response + // and it will fail if not a good xml + try { + if (window.DOMParser) { + var parser = new DOMParser(); + xmlDoc = parser.parseFromString(data, 'text/xml'); + } else { // Internet Explorer + xmlDoc = new ActiveXObject('Microsoft.XMLDOM'); + xmlDoc.async = 'false'; + xmlDoc.loadXML(data); + } + } catch (e) { + // according to specs from point 3.7.5: + // '3. Let document be a cookie-free Document object that + // represents the result of parsing the response entity body + // into a document tree following the rules from the XML + // specifications. If this fails (unsupported character + // encoding, namespace well-formedness error etc.), terminate + // these steps return null.' + xmlDoc = null; + } + // parse errors also yield a null. + if ((xmlDoc && xmlDoc.parseError && xmlDoc.parseError.errorCode !== 0) || (xmlDoc && xmlDoc.documentElement && + xmlDoc.documentElement.nodeName !== 'parsererror') || (xmlDoc && xmlDoc.documentElement && xmlDoc.documentElement + .nodeName !== 'html' && xmlDoc.documentElement.firstChild && xmlDoc.documentElement.firstChild.nodeName === + 'body' && xmlDoc.documentElement.firstChild.firstChild && xmlDoc.documentElement.firstChild.firstChild.nodeName + === 'parsererror')) { + xmlDoc = null; + } + } else { + // mimetype is specified, but not xml-ish + xmlDoc = null; + } + return xmlDoc; + }, + + // Call this to simulate a server response + receive: function (status, data) { + if ((this.readyState !== this.OPENED) || (!this.sent)) { + // Can't respond to unopened request. + throw 'INVALID_STATE_ERR'; + } + + this.status = status; + this.statusText = status + ' ' + this.statusReasons[status]; + this.readyState = this.HEADERS_RECEIVED; + this.onprogress(); + this.onreadystatechange(); + + this.responseText = data; + this.responseXML = this.makeXMLResponse(data); + + this.readyState = this.LOADING; + this.onprogress(); + this.onreadystatechange(); + + this.readyState = this.DONE; + this.onreadystatechange(); + this.onprogress(); + this.onload(); + }, + + // Call this to simulate a request error (e.g. NETWORK_ERR) + err: function (exception) { + if ((this.readyState !== this.OPENED) || (!this.sent)) { + // Can't respond to unopened request. + throw 'INVALID_STATE_ERR'; + } + + this.responseText = null; + this.error = true; + _.each(this.requestHeaders, function (header) { + delete this.requestHeaders[header]; + }, this); + + this.readyState = this.DONE; + if (!this.async) { + throw exception; + } + this.onreadystatechange(); + this.onerror(); + }, + + // Convenience method to verify HTTP credentials + authenticate: function (user, password) { + if (this.user) { + return (user === this.user) && (password === this.password); + } + + if (this.urlParts.user) { + return ((user === this.urlParts.user) && (password === this.urlParts.password)); + } + + // Basic auth. Requires existence of the 'atob' function. + var auth = this.getRequestHeader('Authorization'); + if (auth === undefined) { + return false; + } + if (auth.substr(0, 6) !== 'Basic ') { + return false; + } + if (typeof atob !== 'function') { + return false; + } + auth = atob(auth.substr(6)); + var pieces = auth.split(':'); + var requser = pieces.shift(); + var reqpass = pieces.join(':'); + return (user === requser) && (password === reqpass); + }, + + // Parse RFC 3986 compliant URIs. + // Based on parseUri by Steven Levithan + // See http://blog.stevenlevithan.com/archives/parseuri + parseUri: function (str) { + /* jshint maxlen:false */ + var pattern = + /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/; + var key = ['source', 'protocol', 'authority', 'userInfo', 'user', + 'password', 'host', 'port', 'relative', 'path', + 'directory', 'file', 'query', 'anchor' + ]; + var querypattern = /(?:^|&)([^&=]*)=?([^&]*)/g; + + var match = pattern.exec(str); + var uri = {}; + var i = 14; + while (i--) { + uri[key[i]] = match[i] || ''; + } + + uri.queryKey = {}; + uri[key[12]].replace(querypattern, function ($0, $1, $2) { + if ($1) { + uri.queryKey[$1] = $2; + } + }); + + return uri; + } +}; + +/* + * A small mock 'server' that intercepts XMLHttpRequest calls and + * diverts them to your handler. + * + * Usage: + * + * 1. Initialize with either + * var server = new MockHttpServer(your_request_handler); + * or + * var server = new MockHttpServer(); + * server.handle = function (request) { ... }; + * + * 2. Call server.start() to start intercepting all XMLHttpRequests. + * + * 3. Do your tests. + * + * 4. Call server.stop() to tear down. + * + * 5. Profit! + */ +function MockHttpServer(handler) { + if (handler) { + this.handle = handler; + } +} +MockHttpRequest.MockHttpServer = MockHttpServer; + +MockHttpServer.prototype = { + + start: function () { + var self = this; + + function Request() { + var req = this; + req.onsend = function () { + req.sendStack = (new Error()).stack; + process.nextTick(function () { + self.handle(req); + }); + }; + MockHttpRequest.apply(this, arguments); + } + Request.prototype = MockHttpRequest.prototype; + + window.OriginalHttpRequest = window.XMLHttpRequest; + window.XMLHttpRequest = Request; + }, + + stop: function () { + window.XMLHttpRequest = window.OriginalHttpRequest; + }, + + handle: function (request) { + // Instances should override this. + } +}; \ No newline at end of file diff --git a/test/mocks/browser_server.js b/test/mocks/browser_server.js new file mode 100644 index 000000000..7c4d0db59 --- /dev/null +++ b/test/mocks/browser_server.js @@ -0,0 +1,83 @@ +var interceptors = []; +var complete = []; +var MockHttpRequest = require('./browser_http'); +var XhrServer = MockHttpRequest.MockHttpServer; +var parseUrl = MockHttpRequest.prototype.parseUri; +var _ = require('lodash'); + +var server = new XhrServer(function (request) { + var reqDetails = { + method: request.method, + host: request.urlParts.host, + path: request.urlParts.relative + }; + var response = _.find(interceptors, reqDetails); + + if (response) { + // remove of tick down the times + if (response.times === 1) { + var i = interceptors.indexOf(response); + complete.push(interceptors.splice(i, 1)); + } else { + response.times--; + } + + request.receive(response.status, response.body || void 0); + } else { + throw new Error('No known match for request: ' + JSON.stringify(reqDetails)); + } +}); + +server.start(); + +var mockNock = module.exports = function (url) { + var parsedUrl = parseUrl(url); + var req = { + method: 'GET', + host: parsedUrl.host, + times: 1 + }; + + var modifyReq = { + get: function (path) { + req.path = path; + req.method = 'GET'; + return modifyReq; + }, + port: function (path) { + req.path = path; + req.method = 'POST'; + return modifyReq; + }, + times: function (times) { + req.times = times; + return modifyReq; + }, + reply: function (status, body) { + req.status = status; + req.body = body; + switch (typeof req.body) { + case 'string': + case 'number': + break; + default: + try { + req.body = req.body && JSON.stringify(req.body); + } catch (e) { + req.body = req.body; + } + } + interceptors.push(req); + return mockNock(url); + }, + done: mockNock.done + }; + + return modifyReq; +}; + +mockNock.done = function () { + if (interceptors.length) { + throw new Error('Some interceptors were not called: ' + JSON.stringify(interceptors)); + } +}; \ No newline at end of file diff --git a/test/mocks/server.js b/test/mocks/server.js new file mode 100644 index 000000000..740fc6fae --- /dev/null +++ b/test/mocks/server.js @@ -0,0 +1,3 @@ +var nock = require('nock'); +nock.disableNetConnect(); +module.exports = nock; diff --git a/test/unit/auto_release_stub.js b/test/unit/auto_release_stub.js index 53e1fb3da..ce66cbf02 100644 --- a/test/unit/auto_release_stub.js +++ b/test/unit/auto_release_stub.js @@ -14,9 +14,7 @@ exports.make = function () { }; stubber.autoRelease = function (item) { - if (item.restore && !~log.indexOf(item)) { - log.push(item); - } + log.push(item); }; return stubber; diff --git a/test/unit/test_connection_abstract.js b/test/unit/test_connection_abstract.js index 8a3523d5f..5be45fd31 100644 --- a/test/unit/test_connection_abstract.js +++ b/test/unit/test_connection_abstract.js @@ -96,34 +96,31 @@ describe('Connection Abstract', function () { var conn = new ConnectionAbstract(host); conn.setStatus('alive'); - conn.ping = function () { + stub(conn, 'ping', function () { throw new Error('ping should not have been called'); - }; + }); conn.resuscitate(); }); it('should ping the connection after the deadTimeout, and set the status to "alive" on pong', function (done) { var conn = new ConnectionAbstract(host); - var clock = sinon.useFakeTimers('setTimeout', 'clearTimeout'); - stub.autoRelease(clock); + var clock; + stub.autoRelease(clock = sinon.useFakeTimers('setTimeout', 'clearTimeout')); // schedules the resuscitate conn.setStatus('dead'); // override the ping method to just callback without an error - conn.ping = function (cb) { - process.nextTick(function () { - cb(); - }); - }; + stub(conn, 'ping', function (cb) { + cb(); + }); // will be called after the ping calls back - conn.setStatus = function (status) { + stub(conn, 'setStatus', function (status) { status.should.eql('alive'); - clock.restore(); done(); - }; + }); // fast forward the clock clock.tick(conn.deadTimeout); @@ -131,24 +128,22 @@ describe('Connection Abstract', function () { it('should ping the connection after the deadTimeout, and set the status to "dead" on error', function (done) { var conn = new ConnectionAbstract(host); - var clock = sinon.useFakeTimers('setTimeout', 'clearTimeout'); - stub.autoRelease(clock); + var clock; + stub.autoRelease(clock = sinon.useFakeTimers('setTimeout', 'clearTimeout')); // schedules the resuscitate conn.setStatus('dead'); // override the ping method to just callback without an error - conn.ping = function (cb) { - process.nextTick(function () { - cb(new Error('server still down')); - }); - }; + stub(conn, 'ping', function (cb) { + cb(new Error('server still down')); + }); // will be called after the ping calls back - conn.setStatus = function (status) { + stub(conn, 'setStatus', function (status) { status.should.eql('dead'); done(); - }; + }); // fast forward the clock clock.tick(conn.deadTimeout); diff --git a/test/unit/test_connection_pool.js b/test/unit/test_connection_pool.js index eeb142ae7..7c8d0c577 100644 --- a/test/unit/test_connection_pool.js +++ b/test/unit/test_connection_pool.js @@ -151,12 +151,13 @@ describe('Connection Pool', function () { }; pool.select(function (err, selection) { - should(err).Error; + should(err).be.an.instanceOf(Error); done(); }); }); it('should automatically select the first dead connection when there no living connections', function (done) { + pool.setHosts([]); pool._conns.alive = []; pool._conns.dead = [1, 2, 3]; @@ -188,6 +189,10 @@ describe('Connection Pool', function () { pool._conns.dead.should.have.length(0); }); + afterEach(function () { + pool.close(); + }); + it('moves an alive connection to dead', function () { connection.setStatus('dead'); @@ -207,7 +212,7 @@ describe('Connection Pool', function () { pool._conns.dead[0].should.be.exactly(connection2); }); - it('moves a does nothing when a connection is re-alive', function () { + it('does nothing when a connection is re-alive', function () { var last = pool._conns.alive[pool._conns.alive.length - 1]; var first = pool._conns.alive[0]; diff --git a/test/unit/test_console_logger.js b/test/unit/test_console_logger.js index 50b6d5d47..7fdccd662 100644 --- a/test/unit/test_console_logger.js +++ b/test/unit/test_console_logger.js @@ -28,7 +28,7 @@ describe('Console Logger', function () { it('checks before using unique logging functions, falls back to #log()', function () { var _warning = console.warn; console.warn = null; - stub(console, 'log'); + sinon.stub(console, 'log'); var logger = makeLogger(); @@ -36,6 +36,7 @@ describe('Console Logger', function () { console.log.callCount.should.eql(1); console.warn = _warning; + console.log.restore(); }); }); diff --git a/test/unit/test_http_connector.js b/test/unit/test_http_connector.js index aa54d5ad3..e3c7c9e79 100644 --- a/test/unit/test_http_connector.js +++ b/test/unit/test_http_connector.js @@ -116,7 +116,7 @@ describe('Http Connector', function () { }); reqParams.should.include({ - path: '?user_id=123&jvm=yes' + path: '/?user_id=123&jvm=yes' }); }); @@ -353,7 +353,7 @@ describe('Http Connector', function () { it('uses TCP no delay', function (done) { var con = new HttpConnection(new Host('localhost')); stub(http.ClientRequest.prototype, 'setNoDelay'); - var server = nock('http://localhost').get('').reply(200); + var server = nock('http://localhost').get('/').reply(200); con.request({}, function (err, resp, status) { http.ClientRequest.prototype.setNoDelay.callCount.should.eql(1); @@ -366,7 +366,7 @@ describe('Http Connector', function () { it('sets the Content-Length header properly', function (done) { var con = new HttpConnection(new Host('localhost')); stub(http.ClientRequest.prototype, 'setHeader'); - var server = nock('http://localhost').get('').reply(200); + var server = nock('http://localhost').get('/').reply(200); var body = 'pasta and 𝄞'; body.length.should.eql(12); // nope diff --git a/test/unit/test_stream_logger.js b/test/unit/test_stream_logger.js index d875eb43b..7c96d283a 100644 --- a/test/unit/test_stream_logger.js +++ b/test/unit/test_stream_logger.js @@ -3,7 +3,6 @@ var StreamLogger = require('../../src/lib/loggers/stream'); var MockWritableStream = require('../mocks/writable_stream'); var MockOldWritableStream = require('../mocks/old_writable_stream'); var once = require('events').EventEmitter.prototype.once; -var sinon = require('sinon'); var stream = new MockWritableStream(); var _ = require('lodash'); var util = require('util'); diff --git a/test/unit/test_transport.js b/test/unit/test_transport.js index 8c6e75dcc..039faa4e3 100644 --- a/test/unit/test_transport.js +++ b/test/unit/test_transport.js @@ -4,14 +4,12 @@ var errors = require('../../src/lib/errors'); var when = require('when'); var sinon = require('sinon'); -var nock = require('nock'); +var nock = require('../mocks/server.js'); var should = require('should'); var _ = require('lodash'); var nodeList = require('../fixtures/short_node_list.json'); var stub = require('./auto_release_stub').make(); -nock.disableNetConnect(); - /** * Allows the tests call #request() without it doing anything past trying to select * a connection. @@ -19,10 +17,7 @@ nock.disableNetConnect(); */ function shortCircuitRequest(tran, delay) { stub(tran.connectionPool, 'select', function (cb) { - setTimeout(function () { - // call back with no error, and no connection === "NoConnections" - cb(); - }, delay); + setTimeout(cb, delay); }); } @@ -315,14 +310,13 @@ describe('Transport Class', function () { done(); }); }); - it('logs when it begins', function (done) { + it('rejects get requests with bodies', function (done) { var trans = new Transport(); stub(trans.log, 'debug'); stub(trans.connectionPool, 'select', function (cb) { // simulate "no connections" process.nextTick(cb); }); - trans.request({ body: 'JSON!!', method: 'GET' @@ -754,71 +748,90 @@ describe('Transport Class', function () { }); describe('timeout', function () { - it('uses 10 seconds for the default', function (done) { - this.timeout(5); - var clock; - stub.autoRelease(clock = sinon.useFakeTimers('setTimeout')); - + it('uses 30 seconds for the default', function () { + var clock = sinon.useFakeTimers(); var tran = new Transport({}); + var err; - stub(tran.connectionPool, 'select', function (cb) { - setTimeout(cb, 11000); + tran.request({}); + + _.size(clock.timeouts).should.eql(1); + _.each(clock.timeouts, function (timer, id) { + timer.callAt.should.eql(30000); + clearTimeout(id); }); - - tran.request({}, function (err) { - err.should.be.an.instanceOf(errors.RequestTimeout); - done(); - }); - - clock.tick(10010); + clock.restore(); }); - it('inherits the requestTimeout from the transport', function (done) { - this.timeout(5); - var clock; - stub.autoRelease(clock = sinon.useFakeTimers('setTimeout')); - + it('inherits the requestTimeout from the transport', function () { + var clock = sinon.useFakeTimers(); var tran = new Transport({ requestTimeout: 5000 }); + var err; - stub(tran.connectionPool, 'select', function (cb) { - setTimeout(cb, 11000); + tran.request({}); + + _.size(clock.timeouts).should.eql(1); + _.each(clock.timeouts, function (timer, id) { + timer.callAt.should.eql(5000); + clearTimeout(id); + }); + clock.restore(); + }); + it('clears the timeout when the request is complete', function () { + var clock = sinon.useFakeTimers('setTimeout', 'clearTimeout'); + var tran = new Transport({ + host: 'http://localhost:9200' }); - tran.request({}, function (err) { + var server = nock('http://localhost:9200') + .get('/') + .reply(200, { + i: 'am here' + }); + + tran.request({}, function (err, resp, status) { + should.not.exist(err); + resp.should.eql({ i: 'am here' }); + status.should.eql(200); + Object.keys(clock.timeouts).should.have.length(0); + clock.restore(); + }); + }); + it('timeout responds with a requestTimeout error', function (done) { + // var clock = sinon.useFakeTimers('setTimeout', 'clearTimeout'); + var tran = new Transport({ + host: 'http://localhost:9200' + }); + + var server = nock('http://localhost:9200') + .get('/') + .delay(1000) + .reply(200, { + i: 'am here' + }); + + tran.request({ + requestTimeout: 25 + }, function (err, resp, status) { err.should.be.an.instanceOf(errors.RequestTimeout); + // Object.keys(clock.timeouts).should.have.length(0); + // clock.restore(); done(); }); - - clock.tick(6000); }); [false, 0, null].forEach(function (falsy) { - it('skips the timeout when it is ' + falsy, function (done) { - this.timeout(5); - var clock; - stub.autoRelease(clock = sinon.useFakeTimers('setTimeout')); - - var tran = new Transport({ - requestTimeout: 5000 - }); - - stub(tran.connectionPool, 'select', function (cb) { - setTimeout(function () { - cb(new Error('it works')); - }, 10000); - }); + it('skips the timeout when it is ' + falsy, function () { + var clock = sinon.useFakeTimers(); + var tran = new Transport({}); + stub(tran.connectionPool, 'select', function () {}); tran.request({ requestTimeout: falsy - }, function (err) { - err.message.should.eql('it works'); - done(); - }); + }, function (_err) {}); - clock.tick(6000); - process.nextTick(function () { - clock.tick(6000); - }); + _.size(clock.timeouts).should.eql(0); + clock.restore(); }); }); }); diff --git a/test/integration/yaml_suite/reporter.js b/test/utils/jenkins-reporter.js similarity index 71% rename from test/integration/yaml_suite/reporter.js rename to test/utils/jenkins-reporter.js index b0ec13032..fd3582b77 100644 --- a/test/integration/yaml_suite/reporter.js +++ b/test/utils/jenkins-reporter.js @@ -4,20 +4,33 @@ * @param {Runner} runner * @api public */ -module.exports = EsjsReporter; +module.exports = JenkinsReporter; var Base = require('mocha/lib/reporters/base'); var _ = require('lodash'); var chalk = require('chalk'); -var clientManager = require('./client_manager'); -var makeJUnitXml = require('../../../scripts/make_j_unit_xml'); +var makeJUnitXml = require('./make_j_unit_xml'); var fs = require('fs'); var path = require('path'); +var inspect = require('util').inspect; -function EsjsReporter(runner) { +var log = (function () { + var locked = _.bind(process.stdout.write, process.stdout); + return function (str) { + if (typeof str !== 'string') { + str = inspect(str); + } + locked(str); + }; +})(); + +function JenkinsReporter(runner) { Base.call(this, runner); - clientManager.reporter = this; + var stats = this.stats; + var pass = 0; + var pending = 0; + var fail = 0; var rootSuite = { results: [], suites: [] @@ -36,7 +49,7 @@ function EsjsReporter(runner) { // suite suite = { - name: suite.title, + name: suite.fullTitle(), results: [], start: Date.now(), stdout: '', @@ -68,9 +81,17 @@ function EsjsReporter(runner) { }); runner.on('test end', function (test) { - // test - var color = chalk[test.state === 'passed' ? 'green' : 'red']; - log(color('.')); + if (test.state === 'passed') { + pass++; + log(chalk.green('.')); + } else if (test.pending) { + pending++; + log(chalk.grey('.')); + return; + } else { + fail++; + log(chalk.red('x')); + } var errMsg = void 0; @@ -98,22 +119,19 @@ function EsjsReporter(runner) { }).join('\n')); } - if (!test.pending) { - if (stack[0]) { - stack[0].results.push({ - name: test.title, - time: test.duration, - pass: test.state === 'passed', - test: test - }); - } + if (stack[0]) { + stack[0].results.push({ + name: test.title, + time: test.duration, + pass: test.state === 'passed', + test: test + }); } }); runner.on('end', function () { restoreStdio(); - var outputFilename = path.join(__dirname, '../../../test-output-node-yaml.xml'); - var xml = makeJUnitXml('node ' + process.version + ' yaml tests', { + var xml = makeJUnitXml('node ' + process.version, { stats: stats, suites: _.map(rootSuite.suites, function removeElements(suite) { var s = { @@ -131,16 +149,15 @@ function EsjsReporter(runner) { return s; }) }); - fs.writeFileSync(outputFilename, xml); - console.log('\nwrote log to', outputFilename); - }); + console.error(xml); - var log = (function () { - var locked = _.bind(process.stdout.write, process.stdout); - return function (str) { - locked(str); - }; - })(); + console.log('\n' + [ + 'tests complete in ' + (Math.round(stats.duration / 10) / 100) + ' seconds', + ' fail: ' + chalk.red(stats.failures), + ' pass: ' + chalk.green(stats.passes), + ' pending: ' + chalk.grey(stats.pending) + ].join('\n')); + }); // overload the write methods on stdout and stderr ['stdout', 'stderr'].forEach(function (name) { diff --git a/scripts/make_j_unit_xml.js b/test/utils/make_j_unit_xml.js similarity index 78% rename from scripts/make_j_unit_xml.js rename to test/utils/make_j_unit_xml.js index 9cef01f7b..c0433e6e8 100644 --- a/scripts/make_j_unit_xml.js +++ b/test/utils/make_j_unit_xml.js @@ -32,8 +32,9 @@ var _ = require('lodash'); function makeJUnitXml(runnerName, testDetails) { _.each(testDetails.suites, function serializeSuite(suiteInfo) { + var suite = suites.ele('testsuite', { - package: 'elasticsearch-js:yaml_tests', + package: 'elasticsearch-js', id: suiteCount++, name: suiteInfo.name, timestamp: moment(suiteInfo.start).toJSON(), @@ -45,13 +46,16 @@ function makeJUnitXml(runnerName, testDetails) { }); _.each(suiteInfo.results, function (testInfo) { + var section; - var parts = suiteInfo.name.replace(/\.yaml$/, '').replace(/\./g, '_').split(/\//); - var section = parts.shift(); - var behavior = parts.join('/'); + if (suiteInfo.name.match(/\/.*\.yaml$/)) { + section = suiteInfo.name.split('/').slice(0, -1).join('/'); + } else { + section = suiteInfo.name; + } var testcase = suite.ele('testcase', { - name: behavior + ' - ' + testInfo.name, + name: testInfo.name, time: (testInfo.time || 0) / 1000, classname: runnerName + '.' + section }); @@ -73,8 +77,12 @@ function makeJUnitXml(runnerName, testDetails) { _.each(suiteInfo.suites, serializeSuite); } - suite.ele('system-out', {}).cdata(suiteInfo.stdout); - suite.ele('system-err', {}).cdata(suiteInfo.stderr); + // if (suiteInfo.stdout.trim()) { + // suite.ele('system-out', {}).cdata(suiteInfo.stdout); + // } + // if (suiteInfo.stderr.trim()) { + // suite.ele('system-err', {}).cdata(suiteInfo.stderr); + // } }); return suites.toString({ pretty: true});