diff --git a/.gitignore b/.gitignore index b9a94e374..bf1530c03 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ dist -docs npm-debug.log node_modules scripts/scratch* @@ -14,4 +13,5 @@ test/integration/yaml_suite/yaml_tests.json junit-*.xml test.log elasticsearch*.log -coverage.html \ No newline at end of file +coverage.html +.snapshots \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index a713b0560..08778435c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "src/rest-api-spec"] - path = src/rest-api-spec - url = git://github.com/elasticsearch/elasticsearch-rest-api-spec.git +[submodule "src/elasticsearch"] + path = src/elasticsearch + url = https://github.com/elasticsearch/elasticsearch.git diff --git a/.travis.yml b/.travis.yml index e2d1804c1..6941e66bb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,24 @@ language: node_js -node_js: - - "0.10" - - "0.8" -services: - - elasticsearch -before_script: - - npm install -g grunt-cli -script: - - grunt travis \ No newline at end of file +node_js: false +matrix: + include: + - node_js: "0.8" + env: ES_BRANCH=master + - node_js: "0.10" + env: ES_BRANCH=master COVERAGE=true + - node_js: "0.10" + env: ES_BRANCH=0.90 NO_UNIT=true + - node_js: "0.10" + env: ES_RELEASE=0.90.9 ES_BRANCH=0.90 NO_UNIT=true + - node_js: "0.10" + env: ES_RELEASE=0.90.8 ES_BRANCH=0.90 NO_UNIT=true + + exclude: + - node_js: false + +script: ./scripts/travis.sh +email: + recipients: + - spencer.alger@elasticsearch.com + on_success: change + on_failure: always \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 55f977239..c107e7cb9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,27 +12,11 @@ The process for contributing to any of the Elasticsearch repositories is similar 2. When you're ready to run the tests - Call `npm test` which executes `scripts/run_tests.js`. - - ```sh - $ node scripts/run_tests.js --help - - Runner for the Elasticsearch.js Unit and Integration tests in both node and the browser. - Specify --no-{{flag}} to negate it. - - Options: - --server [true] - --browser [true] - --unit [true] - --integration [false] - --port [9200] - --host ["localhost"] hostname for elasticsearch instance used in integration tests - --check-upstream [false] check for remote updates to the yaml test suite - ``` + Integration and unit tests can be run by simply calling `npm test` or `grunt test`, but the integration tests require a running instance of elasticsearch and ***WILL WIPE ALL DATA FROM ELASTICSEARCH***. If you only want to run the unit tests, run `grunt unit_test` instead. Travis and Jenkins run the integration tests so your changes can be verified before they are merged. 3. Submit a pull request - Push your local changes to your forked copy of the repository and submit a pull request. In the pull request, describe what your changes do and be sure to link to any conversations regarding this implementation, eg "Closes #123". + Push your local changes a forked copy of the repository and submit a pull request. In the pull request, describe what your changes do and be sure to link to any conversations regarding this implementation, eg "Closes #123". 4. Sign the CLA diff --git a/README.md b/README.md index 05b2ca73b..f004a09a2 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,64 @@ We also provide builds of the elasticsearch.js client for use in the browser. If - [Extending Core Components](http://elasticsearch.github.io/elasticsearch-js/index.html#extending) - [Logging](http://elasticsearch.github.io/elasticsearch-js/index.html#logging) +## Examples + +Create a client instance +```js +var elasticsearch = require('elasticsearch'); +var client = new elasticsearch.Client({ + host: 'localhost:9200', + log: 'trace' +}); +``` + +Send a HEAD request to "/?hello=elasticsearch" and allow up to 1 second for it to complete. +```js +client.ping({ + requestTimeout: 1000, + // undocumented params are appended to the query string + hello: "elasticsearch!" +}, function (error) { + if (error) { + console.trace('elasticsearch cluster is down!'); + } else { + console.log('All is well'); + } +}); +``` + +Skip the callback to get a promise back +```js +client.search({ + q: 'pants' +}).then(function (body) { + var hits = body.hits.hits; +}, function (error) { + console.trace(error.message); +}); +``` + +Find tweets that have "elasticsearch" in their body field +```js +client.search({ + index: 'twitter', + type: 'tweets', + body: { + query: { + match: { + body: 'elasticsearch' + } + } + } +}).then(function (resp) { + var hits = resp.hits.hits; +}, function (err) { + console.trace(err.message); +}); +``` + +~~More examples and detailed information about each method are available [here](http://www.elasticsearch.org/guide/en/elasticsearch/client/javascript-api/master/index.html)~~ + ## License This software is licensed under the Apache 2 license, quoted below. diff --git a/docs/README.asciidoc b/docs/README.asciidoc new file mode 100644 index 000000000..b638643cd --- /dev/null +++ b/docs/README.asciidoc @@ -0,0 +1 @@ += These files are used to build http://www.elasticsearch.org/guide/en/elasticsearch/client/javascript-api/current/index.html \ No newline at end of file diff --git a/docs/_descriptions/bulk.asciidoc b/docs/_descriptions/bulk.asciidoc new file mode 100644 index 000000000..20c10fa12 --- /dev/null +++ b/docs/_descriptions/bulk.asciidoc @@ -0,0 +1 @@ +Perform many index/delete operations in a single API call. \ No newline at end of file diff --git a/docs/_descriptions/clearScroll.asciidoc b/docs/_descriptions/clearScroll.asciidoc new file mode 100644 index 000000000..c9fabf9a4 --- /dev/null +++ b/docs/_descriptions/clearScroll.asciidoc @@ -0,0 +1 @@ +Clear the scroll request created by specifying the scroll parameter to search. \ No newline at end of file diff --git a/docs/_descriptions/cluster.getSettings.asciidoc b/docs/_descriptions/cluster.getSettings.asciidoc new file mode 100644 index 000000000..e473cd92f --- /dev/null +++ b/docs/_descriptions/cluster.getSettings.asciidoc @@ -0,0 +1 @@ +Get cluster settings (previously set with `putSettings()`) \ No newline at end of file diff --git a/docs/_descriptions/cluster.health.asciidoc b/docs/_descriptions/cluster.health.asciidoc new file mode 100644 index 000000000..769634bec --- /dev/null +++ b/docs/_descriptions/cluster.health.asciidoc @@ -0,0 +1 @@ +Get a very simple status on the health of the cluster. \ No newline at end of file diff --git a/docs/_descriptions/cluster.nodeHotThreads.asciidoc b/docs/_descriptions/cluster.nodeHotThreads.asciidoc new file mode 100644 index 000000000..6bd937190 --- /dev/null +++ b/docs/_descriptions/cluster.nodeHotThreads.asciidoc @@ -0,0 +1,3 @@ +Returns information about the hottest threads in the cluster or on a specific node as a String. The information is returned as text, and allows you to understand what are currently the most taxing operations happening in the cluster, for debugging or monitoring purposes. + +WARNING: This endpoint returns plain text \ No newline at end of file diff --git a/docs/_descriptions/cluster.nodeInfo.asciidoc b/docs/_descriptions/cluster.nodeInfo.asciidoc new file mode 100644 index 000000000..aeb37a835 --- /dev/null +++ b/docs/_descriptions/cluster.nodeInfo.asciidoc @@ -0,0 +1 @@ +Retrieve one or more (or all) of the cluster nodes' information. \ No newline at end of file diff --git a/docs/_descriptions/cluster.nodeShutdown.asciidoc b/docs/_descriptions/cluster.nodeShutdown.asciidoc new file mode 100644 index 000000000..c4663f50f --- /dev/null +++ b/docs/_descriptions/cluster.nodeShutdown.asciidoc @@ -0,0 +1 @@ +Shutdown one or more (or all) nodes in the cluster. \ No newline at end of file diff --git a/docs/_descriptions/cluster.nodeStats.asciidoc b/docs/_descriptions/cluster.nodeStats.asciidoc new file mode 100644 index 000000000..beb4cd569 --- /dev/null +++ b/docs/_descriptions/cluster.nodeStats.asciidoc @@ -0,0 +1 @@ +Retrieve one or more (or all) of the cluster nodes statistics. \ No newline at end of file diff --git a/docs/_descriptions/cluster.putSettings.asciidoc b/docs/_descriptions/cluster.putSettings.asciidoc new file mode 100644 index 000000000..8249a162f --- /dev/null +++ b/docs/_descriptions/cluster.putSettings.asciidoc @@ -0,0 +1 @@ +Update cluster wide specific settings. \ No newline at end of file diff --git a/docs/_descriptions/cluster.reroute.asciidoc b/docs/_descriptions/cluster.reroute.asciidoc new file mode 100644 index 000000000..624861283 --- /dev/null +++ b/docs/_descriptions/cluster.reroute.asciidoc @@ -0,0 +1 @@ +Explicitly execute a cluster reroute allocation command including specific commands. \ No newline at end of file diff --git a/docs/_descriptions/cluster.state.asciidoc b/docs/_descriptions/cluster.state.asciidoc new file mode 100644 index 000000000..d3784956a --- /dev/null +++ b/docs/_descriptions/cluster.state.asciidoc @@ -0,0 +1 @@ +Get comprehensive details about the state of the whole cluster (indices settings, allocations, etc). \ No newline at end of file diff --git a/docs/_descriptions/count.asciidoc b/docs/_descriptions/count.asciidoc new file mode 100644 index 000000000..914366fd1 --- /dev/null +++ b/docs/_descriptions/count.asciidoc @@ -0,0 +1 @@ +Get the number of documents for the cluster, index, type, or a query. \ No newline at end of file diff --git a/docs/_descriptions/create.asciidoc b/docs/_descriptions/create.asciidoc new file mode 100644 index 000000000..a0dda34ae --- /dev/null +++ b/docs/_descriptions/create.asciidoc @@ -0,0 +1 @@ +Adds a typed JSON document in a specific index, making it searchable. If a document with the same `index`, `type`, and `id` already exists, an error will occur. \ No newline at end of file diff --git a/docs/_descriptions/delete.asciidoc b/docs/_descriptions/delete.asciidoc new file mode 100644 index 000000000..2365c860d --- /dev/null +++ b/docs/_descriptions/delete.asciidoc @@ -0,0 +1 @@ +Delete a typed JSON document from a specific index based on its id. \ No newline at end of file diff --git a/docs/_descriptions/deleteByQuery.asciidoc b/docs/_descriptions/deleteByQuery.asciidoc new file mode 100644 index 000000000..e69e6ee53 --- /dev/null +++ b/docs/_descriptions/deleteByQuery.asciidoc @@ -0,0 +1 @@ +Delete documents from one or more indices and one or more types based on a query. \ No newline at end of file diff --git a/docs/_descriptions/exists.asciidoc b/docs/_descriptions/exists.asciidoc new file mode 100644 index 000000000..82df1be9f --- /dev/null +++ b/docs/_descriptions/exists.asciidoc @@ -0,0 +1 @@ +Returns a boolean indicating whether or not a given document exists. \ No newline at end of file diff --git a/docs/_descriptions/explain.asciidoc b/docs/_descriptions/explain.asciidoc new file mode 100644 index 000000000..7b16e6346 --- /dev/null +++ b/docs/_descriptions/explain.asciidoc @@ -0,0 +1 @@ +Provides details about a specific document's score in relation to a specific query. It will also tell you if the document matches the specified query. Also check out http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-percolate.html[percolaters]. \ No newline at end of file diff --git a/docs/_descriptions/get.asciidoc b/docs/_descriptions/get.asciidoc new file mode 100644 index 000000000..154136448 --- /dev/null +++ b/docs/_descriptions/get.asciidoc @@ -0,0 +1 @@ +Get a typed JSON document from the index based on its id. \ No newline at end of file diff --git a/docs/_descriptions/getSource.asciidoc b/docs/_descriptions/getSource.asciidoc new file mode 100644 index 000000000..bfbf79e47 --- /dev/null +++ b/docs/_descriptions/getSource.asciidoc @@ -0,0 +1 @@ +Get the source of a document by it's index, type and id. \ No newline at end of file diff --git a/docs/_descriptions/index.asciidoc b/docs/_descriptions/index.asciidoc new file mode 100644 index 000000000..715fd2de2 --- /dev/null +++ b/docs/_descriptions/index.asciidoc @@ -0,0 +1,5 @@ +Stores a typed JSON document in an index, making it searchable. When the `id` param is not set, a unique id will be auto-generated. When you specify an `id` either a new document will be created, or an existing document will be updated. To enforce "put-if-absent" behavior set the `opType` to `"create"` or use the `create()` method. + +Optimistic concurrency control is performed, when the `version` argument is specified. By default, no version checks are performed. + +By default, the document will be available for `get()` actions immediately, but will only be available for searching after an index refresh (which can happen automatically or manually). See <>. diff --git a/docs/_descriptions/indices.analyze.asciidoc b/docs/_descriptions/indices.analyze.asciidoc new file mode 100644 index 000000000..7787e4449 --- /dev/null +++ b/docs/_descriptions/indices.analyze.asciidoc @@ -0,0 +1 @@ +Perform the analysis process on a text and return the tokens breakdown of the text. \ No newline at end of file diff --git a/docs/_descriptions/indices.clearCache.asciidoc b/docs/_descriptions/indices.clearCache.asciidoc new file mode 100644 index 000000000..8163eb99c --- /dev/null +++ b/docs/_descriptions/indices.clearCache.asciidoc @@ -0,0 +1 @@ +Clear either all caches or specific cached associated with one ore more indices. \ No newline at end of file diff --git a/docs/_descriptions/indices.close.asciidoc b/docs/_descriptions/indices.close.asciidoc new file mode 100644 index 000000000..6b5d227b1 --- /dev/null +++ b/docs/_descriptions/indices.close.asciidoc @@ -0,0 +1 @@ +Close an index to remove it's overhead from the cluster. Closed index is blocked for read/write operations. \ No newline at end of file diff --git a/docs/_descriptions/indices.create.asciidoc b/docs/_descriptions/indices.create.asciidoc new file mode 100644 index 000000000..7db40031d --- /dev/null +++ b/docs/_descriptions/indices.create.asciidoc @@ -0,0 +1 @@ +Create an index in Elasticsearch. \ No newline at end of file diff --git a/docs/_descriptions/indices.delete.asciidoc b/docs/_descriptions/indices.delete.asciidoc new file mode 100644 index 000000000..f0906c760 --- /dev/null +++ b/docs/_descriptions/indices.delete.asciidoc @@ -0,0 +1 @@ +Delete an index in Elasticsearch \ No newline at end of file diff --git a/docs/_descriptions/indices.deleteAlias.asciidoc b/docs/_descriptions/indices.deleteAlias.asciidoc new file mode 100644 index 000000000..d752aea1d --- /dev/null +++ b/docs/_descriptions/indices.deleteAlias.asciidoc @@ -0,0 +1 @@ +Delete a specific alias. \ No newline at end of file diff --git a/docs/_descriptions/indices.deleteMapping.asciidoc b/docs/_descriptions/indices.deleteMapping.asciidoc new file mode 100644 index 000000000..ba0c41738 --- /dev/null +++ b/docs/_descriptions/indices.deleteMapping.asciidoc @@ -0,0 +1 @@ +Delete a mapping (type definition) along with its data. \ No newline at end of file diff --git a/docs/_descriptions/indices.deleteTemplate.asciidoc b/docs/_descriptions/indices.deleteTemplate.asciidoc new file mode 100644 index 000000000..4b4db6664 --- /dev/null +++ b/docs/_descriptions/indices.deleteTemplate.asciidoc @@ -0,0 +1 @@ +Delete an index template by its name. \ No newline at end of file diff --git a/docs/_descriptions/indices.deleteWarmer.asciidoc b/docs/_descriptions/indices.deleteWarmer.asciidoc new file mode 100644 index 000000000..a4a2717d9 --- /dev/null +++ b/docs/_descriptions/indices.deleteWarmer.asciidoc @@ -0,0 +1 @@ +Delete an index warmer. \ No newline at end of file diff --git a/docs/_descriptions/indices.exists.asciidoc b/docs/_descriptions/indices.exists.asciidoc new file mode 100644 index 000000000..419f35459 --- /dev/null +++ b/docs/_descriptions/indices.exists.asciidoc @@ -0,0 +1 @@ +Return a boolean indicating whether given index exists. \ No newline at end of file diff --git a/docs/_descriptions/indices.existsAlias.asciidoc b/docs/_descriptions/indices.existsAlias.asciidoc new file mode 100644 index 000000000..f6a0d43e1 --- /dev/null +++ b/docs/_descriptions/indices.existsAlias.asciidoc @@ -0,0 +1 @@ +Return a boolean indicating whether given alias exists. \ No newline at end of file diff --git a/docs/_descriptions/indices.existsType.asciidoc b/docs/_descriptions/indices.existsType.asciidoc new file mode 100644 index 000000000..04d06d2eb --- /dev/null +++ b/docs/_descriptions/indices.existsType.asciidoc @@ -0,0 +1 @@ +Check if a type/types exists in an index/indices. \ No newline at end of file diff --git a/docs/_descriptions/indices.flush.asciidoc b/docs/_descriptions/indices.flush.asciidoc new file mode 100644 index 000000000..cbeaa5865 --- /dev/null +++ b/docs/_descriptions/indices.flush.asciidoc @@ -0,0 +1 @@ +Explicitly flush one or more indices. \ No newline at end of file diff --git a/docs/_descriptions/indices.getAlias.asciidoc b/docs/_descriptions/indices.getAlias.asciidoc new file mode 100644 index 000000000..f8b403878 --- /dev/null +++ b/docs/_descriptions/indices.getAlias.asciidoc @@ -0,0 +1 @@ +Retrieve a specified alias. \ No newline at end of file diff --git a/docs/_descriptions/indices.getAliases.asciidoc b/docs/_descriptions/indices.getAliases.asciidoc new file mode 100644 index 000000000..a540052f0 --- /dev/null +++ b/docs/_descriptions/indices.getAliases.asciidoc @@ -0,0 +1 @@ +Retrieve specified aliases \ No newline at end of file diff --git a/docs/_descriptions/indices.getFieldMapping.asciidoc b/docs/_descriptions/indices.getFieldMapping.asciidoc new file mode 100644 index 000000000..2018262d8 --- /dev/null +++ b/docs/_descriptions/indices.getFieldMapping.asciidoc @@ -0,0 +1 @@ +Retrieve mapping definition of a specific field. \ No newline at end of file diff --git a/docs/_descriptions/indices.getMapping.asciidoc b/docs/_descriptions/indices.getMapping.asciidoc new file mode 100644 index 000000000..d7d617fc5 --- /dev/null +++ b/docs/_descriptions/indices.getMapping.asciidoc @@ -0,0 +1 @@ +Retrieve mapping definition of index or index/type. \ No newline at end of file diff --git a/docs/_descriptions/indices.getSettings.asciidoc b/docs/_descriptions/indices.getSettings.asciidoc new file mode 100644 index 000000000..ce2bbf7eb --- /dev/null +++ b/docs/_descriptions/indices.getSettings.asciidoc @@ -0,0 +1 @@ +Retrieve settings for one or more (or all) indices. \ No newline at end of file diff --git a/docs/_descriptions/indices.getTemplate.asciidoc b/docs/_descriptions/indices.getTemplate.asciidoc new file mode 100644 index 000000000..699bdfb7f --- /dev/null +++ b/docs/_descriptions/indices.getTemplate.asciidoc @@ -0,0 +1 @@ +Retrieve an index template by its name. \ No newline at end of file diff --git a/docs/_descriptions/indices.getWarmer.asciidoc b/docs/_descriptions/indices.getWarmer.asciidoc new file mode 100644 index 000000000..db2f058ab --- /dev/null +++ b/docs/_descriptions/indices.getWarmer.asciidoc @@ -0,0 +1 @@ +Retreieve an index warmer. \ No newline at end of file diff --git a/docs/_descriptions/indices.open.asciidoc b/docs/_descriptions/indices.open.asciidoc new file mode 100644 index 000000000..d680235d8 --- /dev/null +++ b/docs/_descriptions/indices.open.asciidoc @@ -0,0 +1 @@ +Open a closed index, making it available for search. \ No newline at end of file diff --git a/docs/_descriptions/indices.optimize.asciidoc b/docs/_descriptions/indices.optimize.asciidoc new file mode 100644 index 000000000..42c7f063f --- /dev/null +++ b/docs/_descriptions/indices.optimize.asciidoc @@ -0,0 +1 @@ +Explicitly optimize one or more indices. \ No newline at end of file diff --git a/docs/_descriptions/indices.putAlias.asciidoc b/docs/_descriptions/indices.putAlias.asciidoc new file mode 100644 index 000000000..de8069393 --- /dev/null +++ b/docs/_descriptions/indices.putAlias.asciidoc @@ -0,0 +1 @@ +Create an alias for a specific index/indices. \ No newline at end of file diff --git a/docs/_descriptions/indices.putMapping.asciidoc b/docs/_descriptions/indices.putMapping.asciidoc new file mode 100644 index 000000000..e239db1e2 --- /dev/null +++ b/docs/_descriptions/indices.putMapping.asciidoc @@ -0,0 +1 @@ +Register specific mapping definition for a specific type. \ No newline at end of file diff --git a/docs/_descriptions/indices.putSettings.asciidoc b/docs/_descriptions/indices.putSettings.asciidoc new file mode 100644 index 000000000..7fd4847d9 --- /dev/null +++ b/docs/_descriptions/indices.putSettings.asciidoc @@ -0,0 +1 @@ +Change specific index level settings in real time. \ No newline at end of file diff --git a/docs/_descriptions/indices.putTemplate.asciidoc b/docs/_descriptions/indices.putTemplate.asciidoc new file mode 100644 index 000000000..c1fde1a03 --- /dev/null +++ b/docs/_descriptions/indices.putTemplate.asciidoc @@ -0,0 +1 @@ +Create an index template that will automatically be applied to new indices created. \ No newline at end of file diff --git a/docs/_descriptions/indices.putWarmer.asciidoc b/docs/_descriptions/indices.putWarmer.asciidoc new file mode 100644 index 000000000..d0a40246b --- /dev/null +++ b/docs/_descriptions/indices.putWarmer.asciidoc @@ -0,0 +1 @@ +Create an index warmer to run registered search requests to warm up the index before it is available for search. \ No newline at end of file diff --git a/docs/_descriptions/indices.refresh.asciidoc b/docs/_descriptions/indices.refresh.asciidoc new file mode 100644 index 000000000..8d6652012 --- /dev/null +++ b/docs/_descriptions/indices.refresh.asciidoc @@ -0,0 +1 @@ +Explicitly refresh one or more index, making all operations performed since the last refresh available for search. \ No newline at end of file diff --git a/docs/_descriptions/indices.segments.asciidoc b/docs/_descriptions/indices.segments.asciidoc new file mode 100644 index 000000000..b03289ec4 --- /dev/null +++ b/docs/_descriptions/indices.segments.asciidoc @@ -0,0 +1 @@ +Retrieve low level segments information that a Lucene index (shard level) is built with. \ No newline at end of file diff --git a/docs/_descriptions/indices.snapshotIndex.asciidoc b/docs/_descriptions/indices.snapshotIndex.asciidoc new file mode 100644 index 000000000..074181eb0 --- /dev/null +++ b/docs/_descriptions/indices.snapshotIndex.asciidoc @@ -0,0 +1 @@ +Initiate a snapshot through the gateway of one or more indices. \ No newline at end of file diff --git a/docs/_descriptions/indices.stats.asciidoc b/docs/_descriptions/indices.stats.asciidoc new file mode 100644 index 000000000..e1f936af2 --- /dev/null +++ b/docs/_descriptions/indices.stats.asciidoc @@ -0,0 +1 @@ +Retrieve statistics on different operations happening on an index. \ No newline at end of file diff --git a/docs/_descriptions/indices.status.asciidoc b/docs/_descriptions/indices.status.asciidoc new file mode 100644 index 000000000..b20d803ff --- /dev/null +++ b/docs/_descriptions/indices.status.asciidoc @@ -0,0 +1 @@ +Get a comprehensive status information of one or more indices. \ No newline at end of file diff --git a/docs/_descriptions/indices.updateAliases.asciidoc b/docs/_descriptions/indices.updateAliases.asciidoc new file mode 100644 index 000000000..663cb9ce8 --- /dev/null +++ b/docs/_descriptions/indices.updateAliases.asciidoc @@ -0,0 +1 @@ +Update specified aliases. \ No newline at end of file diff --git a/docs/_descriptions/indices.validateQuery.asciidoc b/docs/_descriptions/indices.validateQuery.asciidoc new file mode 100644 index 000000000..b61a37a6b --- /dev/null +++ b/docs/_descriptions/indices.validateQuery.asciidoc @@ -0,0 +1 @@ +Validate a potentially expensive query without executing it. \ No newline at end of file diff --git a/docs/_descriptions/info.asciidoc b/docs/_descriptions/info.asciidoc new file mode 100644 index 000000000..3519d3de5 --- /dev/null +++ b/docs/_descriptions/info.asciidoc @@ -0,0 +1 @@ +Get basic info from the current cluster. \ No newline at end of file diff --git a/docs/_descriptions/mget.asciidoc b/docs/_descriptions/mget.asciidoc new file mode 100644 index 000000000..563f18e9a --- /dev/null +++ b/docs/_descriptions/mget.asciidoc @@ -0,0 +1 @@ +Get multiple documents based on an index, type (optional) and ids. The body required by mget can take two forms: an array of document locations, or an array of document ids. \ No newline at end of file diff --git a/docs/_descriptions/mlt.asciidoc b/docs/_descriptions/mlt.asciidoc new file mode 100644 index 000000000..dcd92c680 --- /dev/null +++ b/docs/_descriptions/mlt.asciidoc @@ -0,0 +1 @@ +(more like this) Gets more documents that are “like” the document specified using `index`, `type`, and `id`. \ No newline at end of file diff --git a/docs/_descriptions/msearch.asciidoc b/docs/_descriptions/msearch.asciidoc new file mode 100644 index 000000000..5080a464f --- /dev/null +++ b/docs/_descriptions/msearch.asciidoc @@ -0,0 +1 @@ +Execute several search requests within the same request. \ No newline at end of file diff --git a/docs/_descriptions/percolate.asciidoc b/docs/_descriptions/percolate.asciidoc new file mode 100644 index 000000000..7c9c4baa9 --- /dev/null +++ b/docs/_descriptions/percolate.asciidoc @@ -0,0 +1 @@ +Match a document against registered percolator queries. \ No newline at end of file diff --git a/docs/_descriptions/scroll.asciidoc b/docs/_descriptions/scroll.asciidoc new file mode 100644 index 000000000..1737b11e2 --- /dev/null +++ b/docs/_descriptions/scroll.asciidoc @@ -0,0 +1 @@ +Scroll a search request (retrieve the next set of results) after specifying the scroll parameter in a `search()` call. \ No newline at end of file diff --git a/docs/_descriptions/search.asciidoc b/docs/_descriptions/search.asciidoc new file mode 100644 index 000000000..c715b113d --- /dev/null +++ b/docs/_descriptions/search.asciidoc @@ -0,0 +1,4 @@ +Return documents matching a query, aggregations/facets, highlighted snippets, suggestions, and more. Write your queries as either http://www.elasticsearch.org/guide/reference/api/search/uri-request/[simple query strings] in the `q` parameter, or by specifying a http://www.elasticsearch.org/guide/reference/api/search/request-body/[full request definition] using the http://www.elasticsearch.org/guide/reference/query-dsl/[Elasticsearch Query DSL] in the `body` parameter. + +TIP: https://github.com/fullscale/elastic.js[elastic.js] can be used to make building query bodies easier. + diff --git a/docs/_descriptions/suggest.asciidoc b/docs/_descriptions/suggest.asciidoc new file mode 100644 index 000000000..61ef045bd --- /dev/null +++ b/docs/_descriptions/suggest.asciidoc @@ -0,0 +1 @@ +The suggest feature suggests similar looking terms based on a provided text by using a specific suggester. \ No newline at end of file diff --git a/docs/_descriptions/update.asciidoc b/docs/_descriptions/update.asciidoc new file mode 100644 index 000000000..44a08a8d6 --- /dev/null +++ b/docs/_descriptions/update.asciidoc @@ -0,0 +1,4 @@ +Update parts of a document. The required body parameter can contain one of two things: + + * a partial document, which will be merged with the existing one. + * a `script` which will update the document content \ No newline at end of file diff --git a/docs/_examples/bulk.asciidoc b/docs/_examples/bulk.asciidoc new file mode 100644 index 000000000..786b273b6 --- /dev/null +++ b/docs/_examples/bulk.asciidoc @@ -0,0 +1,21 @@ +.Perform three operations in a single request +[source,js] +--------- +client.bulk({ + body: [ + // action description + { index: { _index: 'myindex', _type: 'mytype', _id: 1 } }, + // the document to index + { title: 'foo' }, + // action description + { update: { _index: 'myindex', _type: 'mytype', _id: 2 } }, + // the document to update + { doc: { title: 'foo' } }, + // action description + { delete: { _index: 'myindex', _type: 'mytype', _id: 3 } }, + // no document needed for this delete + ] +}, function (err, resp) { + // ... +}); +--------- \ No newline at end of file diff --git a/docs/_examples/cluster.nodeHotThreads.asciidoc b/docs/_examples/cluster.nodeHotThreads.asciidoc new file mode 100644 index 000000000..38d9c3410 --- /dev/null +++ b/docs/_examples/cluster.nodeHotThreads.asciidoc @@ -0,0 +1,11 @@ +.Return 10 hottest threads +[source,js] +--------- +client.cluster.nodeHotThreads({ + threads: 10 + nodeId: 'mymisbehavingnode', + maxRetries: 10 +}, function (error, response) { + console.log(response); +}) +--------- \ No newline at end of file diff --git a/docs/_examples/cluster.nodeInfo.asciidoc b/docs/_examples/cluster.nodeInfo.asciidoc new file mode 100644 index 000000000..027085a4c --- /dev/null +++ b/docs/_examples/cluster.nodeInfo.asciidoc @@ -0,0 +1,10 @@ +.Return information about JVM +[source,js] +--------- +client.cluster.nodeInfo({ jvm: true }) + .then(function (response) { + // enjoy your sweet info! + }, function (error) { + // scream! + }) +--------- \ No newline at end of file diff --git a/docs/_examples/count.asciidoc b/docs/_examples/count.asciidoc new file mode 100644 index 000000000..d1dc1f19d --- /dev/null +++ b/docs/_examples/count.asciidoc @@ -0,0 +1,37 @@ +.Get the number of all documents in the cluster +[source,js] +--------- +client.count(function (error, response, status) { + // check for and handle error + var count = response.count; +}); +--------- + +.Get the number of documents in an index +[source,js] +--------- +client.count({ + index: 'index_name' +}, function (error, response) { + // ... +}); +--------- + +.Get the number of documents matching a query +[source,js] +--------- +client.count( + index: 'index_name', + body: { + filtered: { + filter: { + terms: { + foo: ['bar'] + } + } + } + } +}, function (err, response) { + // ... +}); +--------- \ No newline at end of file diff --git a/docs/_examples/create.asciidoc b/docs/_examples/create.asciidoc new file mode 100644 index 000000000..119c0c0df --- /dev/null +++ b/docs/_examples/create.asciidoc @@ -0,0 +1,18 @@ +.Create a document +[source,js] +--------- +client.create({ + index: 'myindex', + type: 'mytype', + id: '1', + body: { + title: 'Test 1', + tags: ['y', 'z'], + published: true, + published_at: '2013-01-01', + counter: 1 + } +}, function (error, response) { + // ... +}); +--------- \ No newline at end of file diff --git a/docs/_examples/delete.asciidoc b/docs/_examples/delete.asciidoc new file mode 100644 index 000000000..50d5672e5 --- /dev/null +++ b/docs/_examples/delete.asciidoc @@ -0,0 +1,11 @@ +.Delete the document `/myindex/mytype/1` +[source,js] +--------- +client.delete({ + index: 'myindex', + type: 'mytype', + id: '1' +}, function (error, response) { + // ... +}); +--------- \ No newline at end of file diff --git a/docs/_examples/deleteByQuery.asciidoc b/docs/_examples/deleteByQuery.asciidoc new file mode 100644 index 000000000..476212705 --- /dev/null +++ b/docs/_examples/deleteByQuery.asciidoc @@ -0,0 +1,23 @@ +.Deleting documents with a simple query +[source,js] +--------- +client.deleteByQuery({ + index: 'myindex', + q: 'test' +}, function (error, response) { + // ... +}); +--------- + +.Deleting documents using the Query DSL +[source,js] +--------- +client.delete_by_query({ + index: 'posts', + body: { + term: { published: false } + } +}, function (error, response) { + // ... +}); +--------- \ No newline at end of file diff --git a/docs/_examples/exists.asciidoc b/docs/_examples/exists.asciidoc new file mode 100644 index 000000000..6e5577844 --- /dev/null +++ b/docs/_examples/exists.asciidoc @@ -0,0 +1,15 @@ +.Check that the document `/myindex/mytype/1` exits +[source,js] +--------- +client.exists({ + index: 'myindex', + type: 'mytype', + id: 1 +}, function (error, exists) { + if (exists === true) { + // ... + } else { + // ... + } +}); +--------- \ No newline at end of file diff --git a/docs/_examples/explain.asciidoc b/docs/_examples/explain.asciidoc new file mode 100644 index 000000000..a82b87808 --- /dev/null +++ b/docs/_examples/explain.asciidoc @@ -0,0 +1,32 @@ +.See how a document is scored against a simple query +[source,js] +--------- +client.explain({ + // the document to test + index: 'myindex', + type: 'mytype', + id: '1', + + // the query to score it against + q: 'field:value' +}, function (error, response) { + // ... +}); +--------- + +.See how a document is scored against a query written in the Query DSL +[source,js] +--------- +client.explain({ + index: 'myindex', + type: 'mytype', + id: '1', + body: { + query: { + match: { title: 'test' } + } + } +}, function (error, response) { + // ... +}); +--------- \ No newline at end of file diff --git a/docs/_examples/get.asciidoc b/docs/_examples/get.asciidoc new file mode 100644 index 000000000..a0bb4cc37 --- /dev/null +++ b/docs/_examples/get.asciidoc @@ -0,0 +1,11 @@ +.Get `/myindex/mytype/1` +[source,js] +--------- +client.get({ + index: 'myindex', + type: 'mytype', + id: 1 +}, function (error, response) { + // ... +}); +--------- \ No newline at end of file diff --git a/docs/_examples/index.asciidoc b/docs/_examples/index.asciidoc new file mode 100644 index 000000000..028975e12 --- /dev/null +++ b/docs/_examples/index.asciidoc @@ -0,0 +1,16 @@ +.Create or update a document +[source,js] +--------- +client.index({ + index: 'myindex', + type: 'mytype', + id: '1', + body: { + title: 'Test 1', + tags: ['y', 'z'], + published: true, + } +}, function (error response) { + +}); +--------- \ No newline at end of file diff --git a/docs/_examples/mget.asciidoc b/docs/_examples/mget.asciidoc new file mode 100644 index 000000000..964d4bba2 --- /dev/null +++ b/docs/_examples/mget.asciidoc @@ -0,0 +1,29 @@ +.An array of doc locations. Useful for getting documents from different indices. +[source,js] +--------- +client.mget({ + body: { + docs: [ + { _index: 'indexA', _type: 'typeA', _id: '1' }, + { _index: 'indexB', _type: 'typeB', _id: '1' }, + { _index: 'indexC', _type: 'typeC', _id: '1' } + ] + } +}, function(error, response){ + // ... +}); +--------- + +.An array of ids. You must also specify the `index` and `type` that apply to all of the ids. +[source,js] +--------- +client.mget({ + index: 'myindex', + type: 'mytype', + body: { + ids: [1, 2, 3] + } +}, function(error, response){ + // ... +}); +--------- \ No newline at end of file diff --git a/docs/_examples/mlt.asciidoc b/docs/_examples/mlt.asciidoc new file mode 100644 index 000000000..f26cf5b68 --- /dev/null +++ b/docs/_examples/mlt.asciidoc @@ -0,0 +1,12 @@ +.Search for similar documents using the `title` property of document `myindex/mytype/1` +[source,js] +--------- +client.mlt({ + index: 'myindex', + type: 'mytype', + id: 1, + mlt_fields: 'title' +}, function (errors, response) { + // ... +}); +--------- \ No newline at end of file diff --git a/docs/_examples/msearch.asciidoc b/docs/_examples/msearch.asciidoc new file mode 100644 index 000000000..52a7bab9b --- /dev/null +++ b/docs/_examples/msearch.asciidoc @@ -0,0 +1,15 @@ +.Perform multiple different searches, the body is made up of meta/data pairs +[source,js] +--------- +client.msearch({ + body: [ + // match all query, on all indices and types + {} + { query: { match_all: {} } }, + + // query_string query, on index/mytype + { index: 'myindex', type: 'mytype' }, + { query: { query_string: { query: '"Test 1"' } } } + ] +}); +--------- \ No newline at end of file diff --git a/docs/_examples/percolate.asciidoc b/docs/_examples/percolate.asciidoc new file mode 100644 index 000000000..82ddae7bd --- /dev/null +++ b/docs/_examples/percolate.asciidoc @@ -0,0 +1,69 @@ +.First, Register queries named “alert-1” and “alert-2” for the “myindex” index +[source,js] +--------- +client.index({ + index: '_percolator', + type: 'myindex', + id: 'alert-1', + body: { + // This query will be run against documents sent to percolate + query: { + query_string: { + query: 'foo' + } + } + } +}, function (error, response) { + // ... +}); + +client.index({ + index: '_percolator', + type: 'myindex', + id: 'alert-2', + body: { + // This query will also be run against documents sent to percolate + query: { + query_string: { + query: 'bar' + } + } + } +}, function (error, response) { + // ... +}); +--------- + +.Then you can send documents to learn which query `_percolator` queries they match +[source,js] +--------- +client.percolate({ + index: 'myindex', + body: { + doc: { + title: "Foo" + } + } +}, function (error, response) { + // response would equal + // { + // ok:true, + // matches: [ "alert-1" ] + // } +}); + +client.percolate({ + index: 'myindex', + body: { + doc: { + title: "Foo Bar" + } + } +}, function (error, response) { + // response would equal + // { + // ok:true, + // matches: [ "alert-1", "alert-2" ] + // } +}); +--------- \ No newline at end of file diff --git a/docs/_examples/scroll.asciidoc b/docs/_examples/scroll.asciidoc new file mode 100644 index 000000000..afc332936 --- /dev/null +++ b/docs/_examples/scroll.asciidoc @@ -0,0 +1,29 @@ +.Collect every title in the index that contains the word "test" +[source,js] +--------- +var allTitles = []; + +// first we do a search, and specify a scroll timeout +client.search({ + index: 'myindex', + // Set to 30 seconds because we are calling right back + scroll: '30s', + fields: ['title'], + q: 'title:test' +}, function getMoreUntilDone(error, response) { + // collect the title from each response + response.hits.hists.forEach(function (hit) { + allTitles.push(hit.fields.title); + }); + + if (response.hits.total !== allTitles.length) { + // now we can call scroll over and over + client.scroll({ + scrollId: response._scroll_id, + scroll: '30s' + }, getMoreUntilDone); + } else { + console.log('every "test" title', allTitles); + } +}); +--------- \ No newline at end of file diff --git a/docs/_examples/search.asciidoc b/docs/_examples/search.asciidoc new file mode 100644 index 000000000..e7adc9d07 --- /dev/null +++ b/docs/_examples/search.asciidoc @@ -0,0 +1,34 @@ +.Search with a simple query string query +[source,js] +--------- +client.search({ + index: 'myindex', + q: 'title:test' +}, function (error, response) { + // ... +}); +--------- + +.Passing a full request definition in the Elasticsearch's Query DSL as a `Hash` +[source,js] +--------- +client.search({ + index: 'myindex', + body: { + query: { + match: { + title: 'test' + } + }, + facets: { + tags: { + terms: { + field: 'tags' + } + } + } + } +}, function (error, response) { + // ... +}): +--------- \ No newline at end of file diff --git a/docs/_examples/suggest.asciidoc b/docs/_examples/suggest.asciidoc new file mode 100644 index 000000000..28789494c --- /dev/null +++ b/docs/_examples/suggest.asciidoc @@ -0,0 +1,34 @@ +.Return query terms suggestions (“auto-correction”) +[source,js] +--------- +client.suggest({ +index: 'myindex', +body: { + mysuggester: { + text: 'tset', + term: { + field: 'title' + } + } +} +}, function (error, response) { +// response will be formatted like so: +// +// { +// ... +// mysuggester: [ +// { +// text: "tset", +// ... +// options: [ +// { +// text: "test", +// score: 0.75, +// freq: 5 +// } +// ] +// } +// ] +// } +}); +--------- \ No newline at end of file diff --git a/docs/_examples/update.asciidoc b/docs/_examples/update.asciidoc new file mode 100644 index 000000000..7e15ff0de --- /dev/null +++ b/docs/_examples/update.asciidoc @@ -0,0 +1,69 @@ +.Update document title using partial document +[source,js] +--------- +client.update({ + index: 'myindex', + type: 'mytype', + id: '1', + body: { + // put the partial document under the `doc` key + doc: { + title: 'Updated' + } + } +}, function (error, response) { + // ... +}) +--------- + +.Add a tag to document `tags` property using a `script` +[source,js] +--------- +client.update({ + index: 'myindex', + type: 'mytype', + id: '1', + body: { + script: 'ctx._source.tags += tag', + params: { tag: 'some new tag' } + } +}, function (error, response) { + // ... +}); +--------- + +.Increment a document counter by 1 or initialize it, when the document does not exist +[source,js] +--------- +client.update({ + index: 'myindex', + type: 'mytype', + id: '666', + body: { + script: 'ctx._source.counter += 1', + upsert: { + counter: 1 + } + } +}, function (error, response) { + // ... +}) +--------- + +.Delete a document if it's tagged “to-delete” +[source,js] +--------- +client.update({ + index: 'myindex', + type: 'mytype', + id: '1', + body: { + script: 'ctx._source.tags.contains(tag) ? ctx.op = "delete" : ctx.op = "none"', + params: { + tag: 'to-delete' + } + } +}, function (error, response) { + // ... +}); +--------- \ No newline at end of file diff --git a/docs/about.asciidoc b/docs/about.asciidoc new file mode 100644 index 000000000..f3f1fca93 --- /dev/null +++ b/docs/about.asciidoc @@ -0,0 +1,59 @@ +[[about]] +== About +=== Features + * One-to-one mapping with REST API + * Configurable, automatic discovery of cluster nodes + * Persistent, Keep-Alive connections + * Intelligent handling of node/connection failure + * Load balancing (with plug-able selection strategy) across all available nodes. + * Works great in node, as well as modern browsers (many thanks to https://github com/substack/node-browserify[browserify]!!). + * Generalized, plug-able, and highly configurable architecture. You can change anything! See <> + +=== Install in Node + +[source,shell] +-------- +npm install --save elasticsearch +-------- + +=== Browser Builds + +To download a build of elasticsearch.js which functions well within modern browsers, use the links +below. These versions of the client are currently ***experimental***. They will break from time to time +and should probably not be used on public-facing websites (it's a whopping 150kb of code). + + * v1.1.0 [https://download.elasticsearch.org/elasticsearch/elasticsearch-js/elasticsearch-js-1.1.0.zip[zip]] [https://download.elasticsearch.org/elasticsearch/elasticsearch-js/elasticsearch-js-1.1.0.tar.gz[tarball]] + * master [https://download.elasticsearch.org/elasticsearch/elasticsearch-js/elasticsearch-js-master.zip[zip]] [https://download.elasticsearch.org/elasticsearch/elasticsearch-js/elasticsearch-js-master.tar.gz[tarball]] + +WARNING: The entire API is compatible with IE 10+, Chrome, Firefox, Safari, and Opera. The majority of the API will +also work in IE 8 & 9, but those browsers limit cross domain requests to just GET and POST. IE versions +before 8 do not support cross-domain requests nativly. + +==== Angular Build (elasticsearch.angular.js) + * Registers the elasticsearch object as a factory `esFactory` + * Uses Angular's `$http` service + * Returns promises using Angular's `$q` service to properly trigger digest cycles within Angular + +.Create a client instance and register it as a service +[source,js] +------------------- +module.service('es', function (esFactory) { + return esFactory({ + host: 'localhost:9200', + // ... + }); +}); +------------------- + +==== jQuery Build (elasticsearch.jquery.js) + * Uses jQuery's `.ajax()` functionality + * Returns jQuery "promises" + * Registers the module at `jQuery.es` + +.Create a client with the jQuery build +[source,js] +------------------- +var client = new $.es.Client({ + hosts: 'localhost:9200' +}); +------------------- \ No newline at end of file diff --git a/docs/api_conventions.asciidoc b/docs/api_conventions.asciidoc new file mode 100755 index 000000000..bf982c293 --- /dev/null +++ b/docs/api_conventions.asciidoc @@ -0,0 +1,27 @@ +[[api-conventions]] +== API Conventions +=== Generic Parameters +By default, all api methods accept the following parameters. They are omitted from the param lists of each method, just because. + +[horizontal] +`method`:: ++ +`String` -- The HTTP method to use for this request. All of the API methods have their own default. + +`body`:: +`String, Anything` -- The body to send along with this request. If the body is a string it will be passed along as is, otherwise it is passed to the serializer and converted to either JSON or a newline seperated list of JSON objects based on the API method. ++ +NOTE: the https://github.com/fullscale/elastic.js[elastic.js] library can be used to make building request bodies simpler. + +`ignore`:: ++ +`Number, Number[]` -- HTTP status codes which should not be considered errors for this request. + +=== Config values you can override per request + * `requestTimeout` -- <> + * `maxRetries` -- <> + +=== Callbacks or Promises +When a callback is passed to any of the API methods, it will be called with `(err, response, status)`. If you prefer to use promises, don't pass a callback and a promise will be returned. The promise will either be resolved with the response body, or rejected with the error that occured (including any 300+ response for non "exists" methods). + +Both styles of calling the API will return an object (either a promise or just a plain object) which has an `abort()` method. Calling that abort method ends the HTTP request, but it will not end the work Elasticsearch is doing. diff --git a/docs/api_methods.asciidoc b/docs/api_methods.asciidoc new file mode 100644 index 000000000..2187d4d14 --- /dev/null +++ b/docs/api_methods.asciidoc @@ -0,0 +1,2618 @@ +[[api-reference]] +== API Method Reference + + +[[api-bulk]] +=== `bulk` + +[source,js] +-------- +client.bulk([params, [callback]]) +-------- + +Perform many index/delete operations in a single API call. + +The default method is `POST` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/bulk/[the elasticsearch docs] for more about this method. + +.Perform three operations in a single request +[source,js] +--------- +client.bulk({ + body: [ + // action description + { index: { _index: 'myindex', _type: 'mytype', _id: 1 } }, + // the document to index + { title: 'foo' }, + // action description + { update: { _index: 'myindex', _type: 'mytype', _id: 2 } }, + // the document to update + { doc: { title: 'foo' } }, + // action description + { delete: { _index: 'myindex', _type: 'mytype', _id: 3 } }, + // no document needed for this delete + ] +}, function (err, resp) { + // ... +}); +--------- + + +==== Params + +[horizontal] +`consistency`:: +`String` -- Explicit write consistency setting for the operation +`refresh`:: +`Boolean` -- Refresh the index after performing the operation +`[replication=sync]`:: +`String` -- Explicitely set the replication type +`type`:: +`String` -- Default document type for items which don't provide one +`timeout`:: +`Date, Number` -- Explicit operation timeout +`index`:: +`String` -- Default index for items which don't provide one + +[[api-clearscroll]] +=== `clearScroll` + +[source,js] +-------- +client.clearScroll([params, [callback]]) +-------- + +Clear the scroll request created by specifying the scroll parameter to search. + +The default method is `DELETE` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/search/scroll/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`scrollId`:: +`String, String[], Boolean` -- A comma-separated list of scroll IDs to clear + +[[api-cluster-getsettings]] +=== `cluster.getSettings` + +[source,js] +-------- +client.cluster.getSettings([params, [callback]]) +-------- + +Get cluster settings (previously set with `putSettings()`) + +The default method is `GET` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/admin-cluster-update-settings/[the elasticsearch docs] for more about this method. + +// no examples + + + +[[api-cluster-health]] +=== `cluster.health` + +[source,js] +-------- +client.cluster.health([params, [callback]]) +-------- + +Get a very simple status on the health of the cluster. + +The default method is `GET` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/admin-cluster-health/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`[level=cluster]`:: +`String` -- Specify the level of detail for returned information +`local`:: +`Boolean` -- Return local information, do not retrieve the state from master node (default: false) +`masterTimeout`:: +`Date, Number` -- Explicit operation timeout for connection to master node +`timeout`:: +`Date, Number` -- Explicit operation timeout +`waitForActiveShards`:: +`Number` -- Wait until the specified number of shards is active +`waitForNodes`:: +`String` -- Wait until the specified number of nodes is available +`waitForRelocatingShards`:: +`Number` -- Wait until the specified number of relocating shards is finished +`waitForStatus`:: +`String` -- Wait until cluster is in a specific state +`index`:: +`String` -- Limit the information returned to a specific index + +[[api-cluster-nodehotthreads]] +=== `cluster.nodeHotThreads` + +[source,js] +-------- +client.cluster.nodeHotThreads([params, [callback]]) +-------- + +Returns information about the hottest threads in the cluster or on a specific node as a String. The information is returned as text, and allows you to understand what are currently the most taxing operations happening in the cluster, for debugging or monitoring purposes. + +WARNING: This endpoint returns plain text + +The default method is `GET` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-cluster-nodes-hot-threads/[the elasticsearch docs] for more about this method. + +.Return 10 hottest threads +[source,js] +--------- +client.cluster.nodeHotThreads({ + threads: 10 + nodeId: 'mymisbehavingnode', + maxRetries: 10 +}, function (error, response) { + console.log(response); +}) +--------- + + +==== Params + +[horizontal] +`interval`:: +`Date, Number` -- The interval for the second sampling of threads +`snapshots`:: +`Number` -- Number of samples of thread stacktrace (default: 10) +`threads`:: +`Number` -- Specify the number of threads to provide information for (default: 3) +`type`:: +`String` -- The type to sample (default: cpu) +`nodeId`:: +`String, String[], Boolean` -- 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-nodeinfo]] +=== `cluster.nodeInfo` + +[source,js] +-------- +client.cluster.nodeInfo([params, [callback]]) +-------- + +Retrieve one or more (or all) of the cluster nodes' information. + +The default method is `GET` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/admin-cluster-nodes-info/[the elasticsearch docs] for more about this method. + +.Return information about JVM +[source,js] +--------- +client.cluster.nodeInfo({ jvm: true }) + .then(function (response) { + // enjoy your sweet info! + }, function (error) { + // scream! + }) +--------- + + +==== Params + +[horizontal] +`all`:: +`Boolean` -- Return all available information +`clear`:: +`Boolean` -- Reset the default settings +`http`:: +`Boolean` -- Return information about HTTP +`jvm`:: +`Boolean` -- Return information about the JVM +`network`:: +`Boolean` -- Return information about network +`os`:: +`Boolean` -- Return information about the operating system +`plugin`:: +`Boolean` -- Return information about plugins +`process`:: +`Boolean` -- Return information about the Elasticsearch process +`settings`:: +`Boolean` -- Return information about node settings +`threadPool`:: +`Boolean` -- Return information about the thread pool +`timeout`:: +`Date, Number` -- Explicit operation timeout +`transport`:: +`Boolean` -- Return information about transport +`nodeId`:: +`String, String[], Boolean` -- 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-nodeshutdown]] +=== `cluster.nodeShutdown` + +[source,js] +-------- +client.cluster.nodeShutdown([params, [callback]]) +-------- + +Shutdown one or more (or all) nodes in the cluster. + +The default method is `POST` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/admin-cluster-nodes-shutdown/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`delay`:: +`Date, Number` -- Set the delay for the operation (default: 1s) +`exit`:: +`Boolean` -- Exit the JVM as well (default: true) +`nodeId`:: +`String, String[], Boolean` -- 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-nodestats]] +=== `cluster.nodeStats` + +[source,js] +-------- +client.cluster.nodeStats([params, [callback]]) +-------- + +Retrieve one or more (or all) of the cluster nodes statistics. + +The default method is `GET` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/admin-cluster-nodes-stats/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`all`:: +`Boolean` -- Return all available information +`clear`:: +`Boolean` -- Reset the default level of detail +`fields`:: +`String, String[], Boolean` -- A comma-separated list of fields to return detailed information for, when returning the `indices` metric family (supports wildcards) +`fs`:: +`Boolean` -- Return information about the filesystem +`http`:: +`Boolean` -- Return information about HTTP +`indices`:: +`Boolean` -- Return information about indices +`jvm`:: +`Boolean` -- Return information about the JVM +`network`:: +`Boolean` -- Return information about network +`os`:: +`Boolean` -- Return information about the operating system +`process`:: +`Boolean` -- Return information about the Elasticsearch process +`threadPool`:: +`Boolean` -- Return information about the thread pool +`transport`:: +`Boolean` -- Return information about transport +`metricFamily`:: +`String` -- Limit the information returned to a certain metric family +`metric`:: +`String` -- Limit the information returned for `indices` family to a specific metric +`nodeId`:: +`String, String[], Boolean` -- 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-putsettings]] +=== `cluster.putSettings` + +[source,js] +-------- +client.cluster.putSettings([params, [callback]]) +-------- + +Update cluster wide specific settings. + +The default method is `PUT` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/admin-cluster-update-settings/[the elasticsearch docs] for more about this method. + +// no examples + + + +[[api-cluster-reroute]] +=== `cluster.reroute` + +[source,js] +-------- +client.cluster.reroute([params, [callback]]) +-------- + +Explicitly execute a cluster reroute allocation command including specific commands. + +The default method is `POST` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/admin-cluster-reroute/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`dryRun`:: +`Boolean` -- Simulate the operation only and return the resulting state +`filterMetadata`:: +`Boolean` -- Don't return cluster state metadata (default: false) + +[[api-cluster-state]] +=== `cluster.state` + +[source,js] +-------- +client.cluster.state([params, [callback]]) +-------- + +Get comprehensive details about the state of the whole cluster (indices settings, allocations, etc). + +The default method is `GET` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/admin-cluster-state/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`filterBlocks`:: +`Boolean` -- Do not return information about blocks +`filterIndexTemplates`:: +`Boolean` -- Do not return information about index templates +`filterIndices`:: +`String, String[], Boolean` -- Limit returned metadata information to specific indices +`filterMetadata`:: +`Boolean` -- Do not return information about indices metadata +`filterNodes`:: +`Boolean` -- Do not return information about nodes +`filterRoutingTable`:: +`Boolean` -- Do not return information about shard allocation (`routing_table` and `routing_nodes`) +`local`:: +`Boolean` -- Return local information, do not retrieve the state from master node (default: false) +`masterTimeout`:: +`Date, Number` -- Specify timeout for connection to master + +[[api-count]] +=== `count` + +[source,js] +-------- +client.count([params, [callback]]) +-------- + +Get the number of documents for the cluster, index, type, or a query. + +The default method is `POST` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/count/[the elasticsearch docs] for more about this method. + +.Get the number of all documents in the cluster +[source,js] +--------- +client.count(function (error, response, status) { + // check for and handle error + var count = response.count; +}); +--------- + +.Get the number of documents in an index +[source,js] +--------- +client.count({ + index: 'index_name' +}, function (error, response) { + // ... +}); +--------- + +.Get the number of documents matching a query +[source,js] +--------- +client.count( + index: 'index_name', + body: { + filtered: { + filter: { + terms: { + foo: ['bar'] + } + } + } + } +}, function (err, response) { + // ... +}); +--------- + + +==== Params + +[horizontal] +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`minScore`:: +`Number` -- Include only documents with a specific `_score` value in the result +`preference`:: +`String` -- Specify the node or shard the operation should be performed on (default: random) +`routing`:: +`String` -- Specific routing value +`source`:: +`String` -- The URL-encoded query definition (instead of using the request body) +`index`:: +`String, String[], Boolean` -- A comma-separated list of indices to restrict the results +`type`:: +`String, String[], Boolean` -- A comma-separated list of types to restrict the results + +[[api-create]] +=== `create` + +[source,js] +-------- +client.create([params, [callback]]) +-------- + +Adds a typed JSON document in a specific index, making it searchable. If a document with the same `index`, `type`, and `id` already exists, an error will occur. + +The default method is `POST` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/index_/[the elasticsearch docs] for more about this method. + +.Create a document +[source,js] +--------- +client.create({ + index: 'myindex', + type: 'mytype', + id: '1', + body: { + title: 'Test 1', + tags: ['y', 'z'], + published: true, + published_at: '2013-01-01', + counter: 1 + } +}, function (error, response) { + // ... +}); +--------- + + +==== Params + +[horizontal] +`consistency`:: +`String` -- Explicit write consistency setting for the operation +`id`:: +`String` -- Document ID +`parent`:: +`String` -- ID of the parent document +`percolate`:: +`String` -- Percolator queries to execute while indexing the document +`refresh`:: +`Boolean` -- Refresh the index after performing the operation +`[replication=sync]`:: +`String` -- Specific replication type +`routing`:: +`String` -- Specific routing value +`timeout`:: +`Date, Number` -- Explicit operation timeout +`timestamp`:: +`Date, Number` -- Explicit timestamp for the document +`ttl`:: +`Duration` -- Expiration time for the document +`version`:: +`Number` -- Explicit version number for concurrency control +`versionType`:: +`String` -- Specific version type +`index`:: +`String` -- The name of the index +`type`:: +`String` -- The type of the document + +[[api-delete]] +=== `delete` + +[source,js] +-------- +client.delete([params, [callback]]) +-------- + +Delete a typed JSON document from a specific index based on its id. + +The default method is `DELETE` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/delete/[the elasticsearch docs] for more about this method. + +.Delete the document `/myindex/mytype/1` +[source,js] +--------- +client.delete({ + index: 'myindex', + type: 'mytype', + id: '1' +}, function (error, response) { + // ... +}); +--------- + + +==== Params + +[horizontal] +`consistency`:: +`String` -- Specific write consistency setting for the operation +`parent`:: +`String` -- ID of parent document +`refresh`:: +`Boolean` -- Refresh the index after performing the operation +`[replication=sync]`:: +`String` -- Specific replication type +`routing`:: +`String` -- Specific routing value +`timeout`:: +`Date, Number` -- Explicit operation timeout +`version`:: +`Number` -- Explicit version number for concurrency control +`versionType`:: +`String` -- Specific version type +`id`:: +`String` -- The document ID +`index`:: +`String` -- The name of the index +`type`:: +`String` -- The type of the document + +[[api-deletebyquery]] +=== `deleteByQuery` + +[source,js] +-------- +client.deleteByQuery([params, [callback]]) +-------- + +Delete documents from one or more indices and one or more types based on a query. + +The default method is `DELETE` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/delete-by-query/[the elasticsearch docs] for more about this method. + +.Deleting documents with a simple query +[source,js] +--------- +client.deleteByQuery({ + index: 'myindex', + q: 'test' +}, function (error, response) { + // ... +}); +--------- + +.Deleting documents using the Query DSL +[source,js] +--------- +client.delete_by_query({ + index: 'posts', + body: { + term: { published: false } + } +}, function (error, response) { + // ... +}); +--------- + + +==== Params + +[horizontal] +`analyzer`:: +`String` -- The analyzer to use for the query string +`consistency`:: +`String` -- Specific write consistency setting for the operation +`[defaultOperator=OR]`:: +`String` -- The default operator for query string query (AND or OR) +`df`:: +`String` -- The field to use as default where no field prefix is given in the query string +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`[replication=sync]`:: +`String` -- Specific replication type +`q`:: +`String` -- Query in the Lucene query string syntax +`routing`:: +`String` -- Specific routing value +`source`:: +`String` -- The URL-encoded query definition (instead of using the request body) +`timeout`:: +`Date, Number` -- Explicit operation timeout +`index`:: +`String, String[], Boolean` -- A comma-separated list of indices to restrict the operation; use `_all` to perform the operation on all indices +`type`:: +`String, String[], Boolean` -- A comma-separated list of types to restrict the operation + +[[api-exists]] +=== `exists` + +[source,js] +-------- +client.exists([params, [callback]]) +-------- + +Returns a boolean indicating whether or not a given document exists. + +The default method is `HEAD` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/get/[the elasticsearch docs] for more about this method. + +.Check that the document `/myindex/mytype/1` exits +[source,js] +--------- +client.exists({ + index: 'myindex', + type: 'mytype', + id: 1 +}, function (error, exists) { + if (exists === true) { + // ... + } else { + // ... + } +}); +--------- + + +==== Params + +[horizontal] +`parent`:: +`String` -- The ID of the parent document +`preference`:: +`String` -- Specify the node or shard the operation should be performed on (default: random) +`realtime`:: +`Boolean` -- Specify whether to perform the operation in realtime or search mode +`refresh`:: +`Boolean` -- Refresh the shard containing the document before performing the operation +`routing`:: +`String` -- Specific routing value +`id`:: +`String` -- The document ID +`index`:: +`String` -- The name of the index +`[type=_all]`:: +`String` -- The type of the document (use `_all` to fetch the first document matching the ID across all types) + +[[api-explain]] +=== `explain` + +[source,js] +-------- +client.explain([params, [callback]]) +-------- + +Provides details about a specific document's score in relation to a specific query. It will also tell you if the document matches the specified query. Also check out http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-percolate.html[percolaters]. + +The default method is `POST` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/explain/[the elasticsearch docs] for more about this method. + +.See how a document is scored against a simple query +[source,js] +--------- +client.explain({ + // the document to test + index: 'myindex', + type: 'mytype', + id: '1', + + // the query to score it against + q: 'field:value' +}, function (error, response) { + // ... +}); +--------- + +.See how a document is scored against a query written in the Query DSL +[source,js] +--------- +client.explain({ + index: 'myindex', + type: 'mytype', + id: '1', + body: { + query: { + match: { title: 'test' } + } + } +}, function (error, response) { + // ... +}); +--------- + + +==== Params + +[horizontal] +`analyzeWildcard`:: +`Boolean` -- Specify whether wildcards and prefix queries in the query string query should be analyzed (default: false) +`analyzer`:: +`String` -- The analyzer for the query string query +`[defaultOperator=OR]`:: +`String` -- The default operator for query string query (AND or OR) +`df`:: +`String` -- The default field for query string query (default: _all) +`fields`:: +`String, String[], Boolean` -- A comma-separated list of fields to return in the response +`lenient`:: +`Boolean` -- Specify whether format-based query failures (such as providing text to a numeric field) should be ignored +`lowercaseExpandedTerms`:: +`Boolean` -- Specify whether query terms should be lowercased +`parent`:: +`String` -- The ID of the parent document +`preference`:: +`String` -- Specify the node or shard the operation should be performed on (default: random) +`q`:: +`String` -- Query in the Lucene query string syntax +`routing`:: +`String` -- Specific routing value +`source`:: +`String` -- The URL-encoded query definition (instead of using the request body) +`_source`:: +`String, String[], Boolean` -- True or false to return the _source field or not, or a list of fields to return +`_sourceExclude`:: +`String, String[], Boolean` -- A list of fields to exclude from the returned _source field +`_sourceInclude`:: +`String, String[], Boolean` -- A list of fields to extract and return from the _source field +`id`:: +`String` -- The document ID +`index`:: +`String` -- The name of the index +`type`:: +`String` -- The type of the document + +[[api-get]] +=== `get` + +[source,js] +-------- +client.get([params, [callback]]) +-------- + +Get a typed JSON document from the index based on its id. + +The default method is `GET` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/get/[the elasticsearch docs] for more about this method. + +.Get `/myindex/mytype/1` +[source,js] +--------- +client.get({ + index: 'myindex', + type: 'mytype', + id: 1 +}, function (error, response) { + // ... +}); +--------- + + +==== Params + +[horizontal] +`fields`:: +`String, String[], Boolean` -- A comma-separated list of fields to return in the response +`parent`:: +`String` -- The ID of the parent document +`preference`:: +`String` -- Specify the node or shard the operation should be performed on (default: random) +`realtime`:: +`Boolean` -- Specify whether to perform the operation in realtime or search mode +`refresh`:: +`Boolean` -- Refresh the shard containing the document before performing the operation +`routing`:: +`String` -- Specific routing value +`_source`:: +`String, String[], Boolean` -- True or false to return the _source field or not, or a list of fields to return +`_sourceExclude`:: +`String, String[], Boolean` -- A list of fields to exclude from the returned _source field +`_sourceInclude`:: +`String, String[], Boolean` -- A list of fields to extract and return from the _source field +`id`:: +`String` -- The document ID +`index`:: +`String` -- The name of the index +`[type=_all]`:: +`String` -- The type of the document (use `_all` to fetch the first document matching the ID across all types) + +[[api-getsource]] +=== `getSource` + +[source,js] +-------- +client.getSource([params, [callback]]) +-------- + +Get the source of a document by it's index, type and id. + +The default method is `GET` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/get/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`exclude`:: +`String, String[], Boolean` -- A list of fields to exclude from the returned _source field +`include`:: +`String, String[], Boolean` -- A list of fields to extract and return from the _source field +`parent`:: +`String` -- The ID of the parent document +`preference`:: +`String` -- Specify the node or shard the operation should be performed on (default: random) +`realtime`:: +`Boolean` -- Specify whether to perform the operation in realtime or search mode +`refresh`:: +`Boolean` -- Refresh the shard containing the document before performing the operation +`routing`:: +`String` -- Specific routing value +`id`:: +`String` -- The document ID +`index`:: +`String` -- The name of the index +`[type=_all]`:: +`String` -- The type of the document; use `_all` to fetch the first document matching the ID across all types + +[[api-index]] +=== `index` + +[source,js] +-------- +client.index([params, [callback]]) +-------- + +Stores a typed JSON document in an index, making it searchable. When the `id` param is not set, a unique id will be auto-generated. When you specify an `id` either a new document will be created, or an existing document will be updated. To enforce "put-if-absent" behavior set the `opType` to `"create"` or use the `create()` method. + +Optimistic concurrency control is performed, when the `version` argument is specified. By default, no version checks are performed. + +By default, the document will be available for `get()` actions immediately, but will only be available for searching after an index refresh (which can happen automatically or manually). See <>. + + +The default method is `POST` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/index_/[the elasticsearch docs] for more about this method. + +.Create or update a document +[source,js] +--------- +client.index({ + index: 'myindex', + type: 'mytype', + id: '1', + body: { + title: 'Test 1', + tags: ['y', 'z'], + published: true, + } +}, function (error response) { + +}); +--------- + + +==== Params + +[horizontal] +`consistency`:: +`String` -- Explicit write consistency setting for the operation +`[opType=index]`:: +`String` -- Explicit operation type +`parent`:: +`String` -- ID of the parent document +`percolate`:: +`String` -- Percolator queries to execute while indexing the document +`refresh`:: +`Boolean` -- Refresh the index after performing the operation +`[replication=sync]`:: +`String` -- Specific replication type +`routing`:: +`String` -- Specific routing value +`timeout`:: +`Date, Number` -- Explicit operation timeout +`timestamp`:: +`Date, Number` -- Explicit timestamp for the document +`ttl`:: +`Duration` -- Expiration time for the document +`version`:: +`Number` -- Explicit version number for concurrency control +`versionType`:: +`String` -- Specific version type +`id`:: +`String` -- Document ID +`index`:: +`String` -- The name of the index +`type`:: +`String` -- The type of the document + +[[api-indices-analyze]] +=== `indices.analyze` + +[source,js] +-------- +client.indices.analyze([params, [callback]]) +-------- + +Perform the analysis process on a text and return the tokens breakdown of the text. + +The default method is `POST` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-analyze/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`analyzer`:: +`String` -- The name of the analyzer to use +`field`:: +`String` -- Use the analyzer configured for this field (instead of passing the analyzer name) +`filters`:: +`String, String[], Boolean` -- A comma-separated list of filters to use for the analysis +`index`:: +`String` -- The name of the index to scope the operation +`preferLocal`:: +`Boolean` -- With `true`, specify that a local shard should be used if available, with `false`, use a random shard (default: true) +`text`:: +`String` -- The text on which the analysis should be performed (when request body is not used) +`tokenizer`:: +`String` -- The name of the tokenizer to use for the analysis +`[format=detailed]`:: +`String` -- Format of the output + +[[api-indices-clearcache]] +=== `indices.clearCache` + +[source,js] +-------- +client.indices.clearCache([params, [callback]]) +-------- + +Clear either all caches or specific cached associated with one ore more indices. + +The default method is `POST` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-clearcache/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`fieldData`:: +`Boolean` -- Clear field data +`fielddata`:: +`Boolean` -- Clear field data +`fields`:: +`String, String[], Boolean` -- A comma-separated list of fields to clear when using the `field_data` parameter (default: all) +`filter`:: +`Boolean` -- Clear filter caches +`filterCache`:: +`Boolean` -- Clear filter caches +`filterKeys`:: +`Boolean` -- A comma-separated list of keys to clear when using the `filter_cache` parameter (default: all) +`id`:: +`Boolean` -- Clear ID caches for parent/child +`idCache`:: +`Boolean` -- Clear ID caches for parent/child +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`index`:: +`String, String[], Boolean` -- A comma-separated list of index name to limit the operation +`recycler`:: +`Boolean` -- Clear the recycler cache + +[[api-indices-close]] +=== `indices.close` + +[source,js] +-------- +client.indices.close([params, [callback]]) +-------- + +Close an index to remove it's overhead from the cluster. Closed index is blocked for read/write operations. + +The default method is `POST` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-open-close/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`timeout`:: +`Date, Number` -- Explicit operation timeout +`masterTimeout`:: +`Date, Number` -- Specify timeout for connection to master +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`index`:: +`String` -- The name of the index + +[[api-indices-create]] +=== `indices.create` + +[source,js] +-------- +client.indices.create([params, [callback]]) +-------- + +Create an index in Elasticsearch. + +The default method is `POST` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-create-index/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`timeout`:: +`Date, Number` -- Explicit operation timeout +`masterTimeout`:: +`Date, Number` -- Specify timeout for connection to master +`index`:: +`String` -- The name of the index + +[[api-indices-delete]] +=== `indices.delete` + +[source,js] +-------- +client.indices.delete([params, [callback]]) +-------- + +Delete an index in Elasticsearch + +The default method is `DELETE` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-delete-index/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`timeout`:: +`Date, Number` -- Explicit operation timeout +`masterTimeout`:: +`Date, Number` -- Specify timeout for connection to master +`index`:: +`String, String[], Boolean` -- A comma-separated list of indices to delete; use `_all` or empty string to delete all indices + +[[api-indices-deletealias]] +=== `indices.deleteAlias` + +[source,js] +-------- +client.indices.deleteAlias([params, [callback]]) +-------- + +Delete a specific alias. + +The default method is `DELETE` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`timeout`:: +`Date, Number` -- Explicit timestamp for the document +`masterTimeout`:: +`Date, Number` -- Specify timeout for connection to master +`index`:: +`String` -- The name of the index with an alias +`name`:: +`String` -- The name of the alias to be deleted + +[[api-indices-deletemapping]] +=== `indices.deleteMapping` + +[source,js] +-------- +client.indices.deleteMapping([params, [callback]]) +-------- + +Delete a mapping (type definition) along with its data. + +The default method is `DELETE` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-delete-mapping/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`masterTimeout`:: +`Date, Number` -- Specify timeout for connection to master +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names; use `_all` for all indices +`type`:: +`String` -- The name of the document type to delete + +[[api-indices-deletetemplate]] +=== `indices.deleteTemplate` + +[source,js] +-------- +client.indices.deleteTemplate([params, [callback]]) +-------- + +Delete an index template by its name. + +The default method is `DELETE` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-templates/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`timeout`:: +`Date, Number` -- Explicit operation timeout +`masterTimeout`:: +`Date, Number` -- Specify timeout for connection to master +`name`:: +`String` -- The name of the template + +[[api-indices-deletewarmer]] +=== `indices.deleteWarmer` + +[source,js] +-------- +client.indices.deleteWarmer([params, [callback]]) +-------- + +Delete an index warmer. + +The default method is `DELETE` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-warmers/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`masterTimeout`:: +`Date, Number` -- Specify timeout for connection to master +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names to register warmer for; use `_all` or empty string to perform the operation on all indices +`name`:: +`String` -- The name of the warmer (supports wildcards); leave empty to delete all warmers +`type`:: +`String, String[], Boolean` -- 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-exists]] +=== `indices.exists` + +[source,js] +-------- +client.indices.exists([params, [callback]]) +-------- + +Return a boolean indicating whether given index exists. + +The default method is `HEAD` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-indices-exists/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`index`:: +`String, String[], Boolean` -- A comma-separated list of indices to check + +[[api-indices-existsalias]] +=== `indices.existsAlias` + +[source,js] +-------- +client.indices.existsAlias([params, [callback]]) +-------- + +Return a boolean indicating whether given alias exists. + +The default method is `HEAD` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open,closed]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names to filter aliases +`name`:: +`String, String[], Boolean` -- A comma-separated list of alias names to return + +[[api-indices-existstype]] +=== `indices.existsType` + +[source,js] +-------- +client.indices.existsType([params, [callback]]) +-------- + +Check if a type/types exists in an index/indices. + +The default method is `HEAD` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-types-exists/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names; use `_all` to check the types across all indices +`type`:: +`String, String[], Boolean` -- A comma-separated list of document types to check + +[[api-indices-flush]] +=== `indices.flush` + +[source,js] +-------- +client.indices.flush([params, [callback]]) +-------- + +Explicitly flush one or more indices. + +The default method is `POST` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-flush/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`force`:: +`Boolean` -- Whether a flush should be forced even if it is not necessarily needed ie. if no changes will be committed to the index. This is useful if transaction log IDs should be incremented even if no uncommitted changes are present. (This setting can be considered as internal) +`full`:: +`Boolean` -- If set to true a new index writer is created and settings that have been changed related to the index writer will be refreshed. Note: if a full flush is required for a setting to take effect this will be part of the settings update process and it not required to be executed by the user. (This setting can be considered as internal) +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`refresh`:: +`Boolean` -- Refresh the index after performing the operation +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names; use `_all` or empty string for all indices + +[[api-indices-getalias]] +=== `indices.getAlias` + +[source,js] +-------- +client.indices.getAlias([params, [callback]]) +-------- + +Retrieve a specified alias. + +The default method is `GET` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names to filter aliases +`name`:: +`String, String[], Boolean` -- A comma-separated list of alias names to return + +[[api-indices-getaliases]] +=== `indices.getAliases` + +[source,js] +-------- +client.indices.getAliases([params, [callback]]) +-------- + +Retrieve specified aliases + +The default method is `GET` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`timeout`:: +`Date, Number` -- Explicit operation timeout +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names to filter aliases + +[[api-indices-getfieldmapping]] +=== `indices.getFieldMapping` + +[source,js] +-------- +client.indices.getFieldMapping([params, [callback]]) +-------- + +Retrieve mapping definition of a specific field. + +The default method is `GET` and the usual <> apply. See http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-get-field-mapping.html[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`includeDefaults`:: +`Boolean` -- Whether the default mapping values should be returned as well +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names +`type`:: +`String, String[], Boolean` -- A comma-separated list of document types +`field`:: +`String, String[], Boolean` -- A comma-separated list of fields + +[[api-indices-getmapping]] +=== `indices.getMapping` + +[source,js] +-------- +client.indices.getMapping([params, [callback]]) +-------- + +Retrieve mapping definition of index or index/type. + +The default method is `GET` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-get-mapping/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names +`type`:: +`String, String[], Boolean` -- A comma-separated list of document types + +[[api-indices-getsettings]] +=== `indices.getSettings` + +[source,js] +-------- +client.indices.getSettings([params, [callback]]) +-------- + +Retrieve settings for one or more (or all) indices. + +The default method is `GET` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-get-settings/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices + +[[api-indices-gettemplate]] +=== `indices.getTemplate` + +[source,js] +-------- +client.indices.getTemplate([params, [callback]]) +-------- + +Retrieve an index template by its name. + +The default method is `GET` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-templates/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`name`:: +`String` -- The name of the template + +[[api-indices-getwarmer]] +=== `indices.getWarmer` + +[source,js] +-------- +client.indices.getWarmer([params, [callback]]) +-------- + +Retreieve an index warmer. + +The default method is `GET` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-warmers/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names to restrict the operation; use `_all` to perform the operation on all indices +`name`:: +`String` -- The name of the warmer (supports wildcards); leave empty to get all warmers +`type`:: +`String, String[], Boolean` -- A comma-separated list of document types to restrict the operation; leave empty to perform the operation on all types + +[[api-indices-open]] +=== `indices.open` + +[source,js] +-------- +client.indices.open([params, [callback]]) +-------- + +Open a closed index, making it available for search. + +The default method is `POST` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-open-close/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`timeout`:: +`Date, Number` -- Explicit operation timeout +`masterTimeout`:: +`Date, Number` -- Specify timeout for connection to master +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=closed]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`index`:: +`String` -- The name of the index + +[[api-indices-optimize]] +=== `indices.optimize` + +[source,js] +-------- +client.indices.optimize([params, [callback]]) +-------- + +Explicitly optimize one or more indices. + +The default method is `POST` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-optimize/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`flush`:: +`Boolean` -- Specify whether the index should be flushed after performing the operation (default: true) +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`maxNumSegments`:: +`Number` -- The number of segments the index should be merged into (default: dynamic) +`onlyExpungeDeletes`:: +`Boolean` -- Specify whether the operation should only expunge deleted documents +`operationThreading`:: +`Anything` -- TODO: ? +`refresh`:: +`Boolean` -- Specify whether the index should be refreshed after performing the operation (default: true) +`waitForMerge`:: +`Boolean` -- Specify whether the request should block until the merge process is finished (default: true) +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices + +[[api-indices-putalias]] +=== `indices.putAlias` + +[source,js] +-------- +client.indices.putAlias([params, [callback]]) +-------- + +Create an alias for a specific index/indices. + +The default method is `PUT` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`timeout`:: +`Date, Number` -- Explicit timestamp for the document +`masterTimeout`:: +`Date, Number` -- Specify timeout for connection to master +`index`:: +`String` -- The name of the index with an alias +`name`:: +`String` -- The name of the alias to be created or updated + +[[api-indices-putmapping]] +=== `indices.putMapping` + +[source,js] +-------- +client.indices.putMapping([params, [callback]]) +-------- + +Register specific mapping definition for a specific type. + +The default method is `PUT` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-put-mapping/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`ignoreConflicts`:: +`Boolean` -- Specify whether to ignore conflicts while updating the mapping (default: false) +`timeout`:: +`Date, Number` -- Explicit operation timeout +`masterTimeout`:: +`Date, Number` -- Specify timeout for connection to master +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names; use `_all` to perform the operation on all indices +`type`:: +`String` -- The name of the document type + +[[api-indices-putsettings]] +=== `indices.putSettings` + +[source,js] +-------- +client.indices.putSettings([params, [callback]]) +-------- + +Change specific index level settings in real time. + +The default method is `PUT` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-update-settings/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`masterTimeout`:: +`Date, Number` -- Specify timeout for connection to master +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices + +[[api-indices-puttemplate]] +=== `indices.putTemplate` + +[source,js] +-------- +client.indices.putTemplate([params, [callback]]) +-------- + +Create an index template that will automatically be applied to new indices created. + +The default method is `PUT` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-templates/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`order`:: +`Number` -- The order for this template when merging multiple matching ones (higher numbers are merged later, overriding the lower numbers) +`timeout`:: +`Date, Number` -- Explicit operation timeout +`masterTimeout`:: +`Date, Number` -- Specify timeout for connection to master +`name`:: +`String` -- The name of the template + +[[api-indices-putwarmer]] +=== `indices.putWarmer` + +[source,js] +-------- +client.indices.putWarmer([params, [callback]]) +-------- + +Create an index warmer to run registered search requests to warm up the index before it is available for search. + +The default method is `PUT` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-warmers/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`masterTimeout`:: +`Date, Number` -- Specify timeout for connection to master +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) in the search request to warm +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices in the search request to warm. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both, in the search request to warm. +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names to register the warmer for; use `_all` or empty string to perform the operation on all indices +`name`:: +`String` -- The name of the warmer +`type`:: +`String, String[], Boolean` -- A comma-separated list of document types to register the warmer for; leave empty to perform the operation on all types + +[[api-indices-refresh]] +=== `indices.refresh` + +[source,js] +-------- +client.indices.refresh([params, [callback]]) +-------- + +Explicitly refresh one or more index, making all operations performed since the last refresh available for search. + +The default method is `POST` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-refresh/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`operationThreading`:: +`Anything` -- TODO: ? +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices + +[[api-indices-segments]] +=== `indices.segments` + +[source,js] +-------- +client.indices.segments([params, [callback]]) +-------- + +Retrieve low level segments information that a Lucene index (shard level) is built with. + +The default method is `GET` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/admin-indices-segments/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`operationThreading`:: +`Anything` -- TODO: ? +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices + +[[api-indices-snapshotindex]] +=== `indices.snapshotIndex` + +[source,js] +-------- +client.indices.snapshotIndex([params, [callback]]) +-------- + +Initiate a snapshot through the gateway of one or more indices. + +The default method is `POST` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-gateway-snapshot/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names; use `_all` or empty string for all indices + +[[api-indices-stats]] +=== `indices.stats` + +[source,js] +-------- +client.indices.stats([params, [callback]]) +-------- + +Retrieve statistics on different operations happening on an index. + +The default method is `GET` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/admin-indices-stats/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`all`:: +`Boolean` -- Return all available information +`clear`:: +`Boolean` -- Reset the default level of detail +`completion`:: +`Boolean` -- Return information about completion suggester stats +`completionFields`:: +`String, String[], Boolean` -- A comma-separated list of fields for `completion` metric (supports wildcards) +`docs`:: +`Boolean` -- Return information about indexed and deleted documents +`fielddata`:: +`Boolean` -- Return information about field data +`fielddataFields`:: +`String, String[], Boolean` -- A comma-separated list of fields for `fielddata` metric (supports wildcards) +`fields`:: +`String, String[], Boolean` -- A comma-separated list of fields to return detailed information for, when returning the `search` statistics +`filterCache`:: +`Boolean` -- Return information about filter cache +`flush`:: +`Boolean` -- Return information about flush operations +`get`:: +`Boolean` -- Return information about get operations +`groups`:: +`Boolean` -- A comma-separated list of search groups for `search` statistics +`idCache`:: +`Boolean` -- Return information about ID cache +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`indexing`:: +`Boolean` -- Return information about indexing operations +`merge`:: +`Boolean` -- Return information about merge operations +`refresh`:: +`Boolean` -- Return information about refresh operations +`search`:: +`Boolean` -- Return information about search operations; use the `groups` parameter to include information for specific search groups +`store`:: +`Boolean` -- Return information about the size of the index +`warmer`:: +`Boolean` -- Return information about warmers +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices +`indexingTypes`:: +`String, String[], Boolean` -- A comma-separated list of document types to include in the `indexing` statistics +`metricFamily`:: +`String` -- Limit the information returned to a specific metric +`searchGroups`:: +`String, String[], Boolean` -- A comma-separated list of search groups to include in the `search` statistics + +[[api-indices-status]] +=== `indices.status` + +[source,js] +-------- +client.indices.status([params, [callback]]) +-------- + +Get a comprehensive status information of one or more indices. + +The default method is `GET` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/admin-indices-status/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`operationThreading`:: +`Anything` -- TODO: ? +`recovery`:: +`Boolean` -- Return information about shard recovery +`snapshot`:: +`Boolean` -- TODO: ? +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names; use `_all` or empty string to perform the operation on all indices + +[[api-indices-updatealiases]] +=== `indices.updateAliases` + +[source,js] +-------- +client.indices.updateAliases([params, [callback]]) +-------- + +Update specified aliases. + +The default method is `POST` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/admin-indices-aliases/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`timeout`:: +`Date, Number` -- Request timeout +`masterTimeout`:: +`Date, Number` -- Specify timeout for connection to master +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names to filter aliases + +[[api-indices-validatequery]] +=== `indices.validateQuery` + +[source,js] +-------- +client.indices.validateQuery([params, [callback]]) +-------- + +Validate a potentially expensive query without executing it. + +The default method is `POST` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/validate/[the elasticsearch docs] for more about this method. + +// no examples + + +==== Params + +[horizontal] +`explain`:: +`Boolean` -- Return detailed information about the error +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`operationThreading`:: +`Anything` -- TODO: ? +`source`:: +`String` -- The URL-encoded query definition (instead of using the request body) +`q`:: +`String` -- Query in the Lucene query string syntax +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names to restrict the operation; use `_all` or empty string to perform the operation on all indices +`type`:: +`String, String[], Boolean` -- A comma-separated list of document types to restrict the operation; leave empty to perform the operation on all types + +[[api-info]] +=== `info` + +[source,js] +-------- +client.info([params, [callback]]) +-------- + +Get basic info from the current cluster. + +The default method is `GET` and the usual <> apply. See http://elasticsearch.org/guide/[the elasticsearch docs] for more about this method. + +// no examples + + + +[[api-mget]] +=== `mget` + +[source,js] +-------- +client.mget([params, [callback]]) +-------- + +Get multiple documents based on an index, type (optional) and ids. The body required by mget can take two forms: an array of document locations, or an array of document ids. + +The default method is `POST` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/multi-get/[the elasticsearch docs] for more about this method. + +.An array of doc locations. Useful for getting documents from different indices. +[source,js] +--------- +client.mget({ + body: { + docs: [ + { _index: 'indexA', _type: 'typeA', _id: '1' }, + { _index: 'indexB', _type: 'typeB', _id: '1' }, + { _index: 'indexC', _type: 'typeC', _id: '1' } + ] + } +}, function(error, response){ + // ... +}); +--------- + +.An array of ids. You must also specify the `index` and `type` that apply to all of the ids. +[source,js] +--------- +client.mget({ + index: 'myindex', + type: 'mytype', + body: { + ids: [1, 2, 3] + } +}, function(error, response){ + // ... +}); +--------- + + +==== Params + +[horizontal] +`fields`:: +`String, String[], Boolean` -- A comma-separated list of fields to return in the response +`preference`:: +`String` -- Specify the node or shard the operation should be performed on (default: random) +`realtime`:: +`Boolean` -- Specify whether to perform the operation in realtime or search mode +`refresh`:: +`Boolean` -- Refresh the shard containing the document before performing the operation +`_source`:: +`String, String[], Boolean` -- True or false to return the _source field or not, or a list of fields to return +`_sourceExclude`:: +`String, String[], Boolean` -- A list of fields to exclude from the returned _source field +`_sourceInclude`:: +`String, String[], Boolean` -- A list of fields to extract and return from the _source field +`index`:: +`String` -- The name of the index +`type`:: +`String` -- The type of the document + +[[api-mlt]] +=== `mlt` + +[source,js] +-------- +client.mlt([params, [callback]]) +-------- + +(more like this) Gets more documents that are “like” the document specified using `index`, `type`, and `id`. + +The default method is `POST` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/more-like-this/[the elasticsearch docs] for more about this method. + +.Search for similar documents using the `title` property of document `myindex/mytype/1` +[source,js] +--------- +client.mlt({ + index: 'myindex', + type: 'mytype', + id: 1, + mlt_fields: 'title' +}, function (errors, response) { + // ... +}); +--------- + + +==== Params + +[horizontal] +`boostTerms`:: +`Number` -- The boost factor +`maxDocFreq`:: +`Number` -- The word occurrence frequency as count: words with higher occurrence in the corpus will be ignored +`maxQueryTerms`:: +`Number` -- The maximum query terms to be included in the generated query +`maxWordLen`:: +`Number` -- The minimum length of the word: longer words will be ignored +`minDocFreq`:: +`Number` -- The word occurrence frequency as count: words with lower occurrence in the corpus will be ignored +`minTermFreq`:: +`Number` -- The term frequency as percent: terms with lower occurence in the source document will be ignored +`minWordLen`:: +`Number` -- The minimum length of the word: shorter words will be ignored +`mltFields`:: +`String, String[], Boolean` -- Specific fields to perform the query against +`percentTermsToMatch`:: +`Number` -- How many terms have to match in order to consider the document a match (default: 0.3) +`routing`:: +`String` -- Specific routing value +`searchFrom`:: +`Number` -- The offset from which to return results +`searchIndices`:: +`String, String[], Boolean` -- A comma-separated list of indices to perform the query against (default: the index containing the document) +`searchQueryHint`:: +`String` -- The search query hint +`searchScroll`:: +`String` -- A scroll search request definition +`searchSize`:: +`Number` -- The number of documents to return (default: 10) +`searchSource`:: +`String` -- A specific search request definition (instead of using the request body) +`searchType`:: +`String` -- Specific search type (eg. `dfs_then_fetch`, `count`, etc) +`searchTypes`:: +`String, String[], Boolean` -- A comma-separated list of types to perform the query against (default: the same type as the document) +`stopWords`:: +`String, String[], Boolean` -- A list of stop words to be ignored +`id`:: +`String` -- The document ID +`index`:: +`String` -- The name of the index +`type`:: +`String` -- The type of the document (use `_all` to fetch the first document matching the ID across all types) + +[[api-msearch]] +=== `msearch` + +[source,js] +-------- +client.msearch([params, [callback]]) +-------- + +Execute several search requests within the same request. + +The default method is `POST` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/multi-search/[the elasticsearch docs] for more about this method. + +.Perform multiple different searches, the body is made up of meta/data pairs +[source,js] +--------- +client.msearch({ + body: [ + // match all query, on all indices and types + {} + { query: { match_all: {} } }, + + // query_string query, on index/mytype + { index: 'myindex', type: 'mytype' }, + { query: { query_string: { query: '"Test 1"' } } } + ] +}); +--------- + + +==== Params + +[horizontal] +`searchType`:: +`String` -- Search operation type +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names to use as default +`type`:: +`String, String[], Boolean` -- A comma-separated list of document types to use as default + +[[api-percolate]] +=== `percolate` + +[source,js] +-------- +client.percolate([params, [callback]]) +-------- + +Match a document against registered percolator queries. + +The default method is `POST` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/percolate/[the elasticsearch docs] for more about this method. + +.First, Register queries named “alert-1” and “alert-2” for the “myindex” index +[source,js] +--------- +client.index({ + index: '_percolator', + type: 'myindex', + id: 'alert-1', + body: { + // This query will be run against documents sent to percolate + query: { + query_string: { + query: 'foo' + } + } + } +}, function (error, response) { + // ... +}); + +client.index({ + index: '_percolator', + type: 'myindex', + id: 'alert-2', + body: { + // This query will also be run against documents sent to percolate + query: { + query_string: { + query: 'bar' + } + } + } +}, function (error, response) { + // ... +}); +--------- + +.Then you can send documents to learn which query `_percolator` queries they match +[source,js] +--------- +client.percolate({ + index: 'myindex', + body: { + doc: { + title: "Foo" + } + } +}, function (error, response) { + // response would equal + // { + // ok:true, + // matches: [ "alert-1" ] + // } +}); + +client.percolate({ + index: 'myindex', + body: { + doc: { + title: "Foo Bar" + } + } +}, function (error, response) { + // response would equal + // { + // ok:true, + // matches: [ "alert-1", "alert-2" ] + // } +}); +--------- + + +==== Params + +[horizontal] +`preferLocal`:: +`Boolean` -- With `true`, specify that a local shard should be used if available, with `false`, use a random shard (default: true) +`index`:: +`String` -- The name of the index with a registered percolator query +`type`:: +`String` -- The document type + +[[api-scroll]] +=== `scroll` + +[source,js] +-------- +client.scroll([params, [callback]]) +-------- + +Scroll a search request (retrieve the next set of results) after specifying the scroll parameter in a `search()` call. + +The default method is `POST` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/search/scroll/[the elasticsearch docs] for more about this method. + +.Collect every title in the index that contains the word "test" +[source,js] +--------- +var allTitles = []; + +// first we do a search, and specify a scroll timeout +client.search({ + index: 'myindex', + // Set to 30 seconds because we are calling right back + scroll: '30s', + fields: ['title'], + q: 'title:test' +}, function getMoreUntilDone(error, response) { + // collect the title from each response + response.hits.hists.forEach(function (hit) { + allTitles.push(hit.fields.title); + }); + + if (response.hits.total !== allTitles.length) { + // now we can call scroll over and over + client.scroll({ + scrollId: response._scroll_id, + scroll: '30s' + }, getMoreUntilDone); + } else { + console.log('every "test" title', allTitles); + } +}); +--------- + + +==== Params + +[horizontal] +`scroll`:: +`Duration` -- Specify how long a consistent view of the index should be maintained for scrolled search +`scrollId`:: +`String` -- The scroll ID + +[[api-search]] +=== `search` + +[source,js] +-------- +client.search([params, [callback]]) +-------- + +Return documents matching a query, aggregations/facets, highlighted snippets, suggestions, and more. Write your queries as either http://www.elasticsearch.org/guide/reference/api/search/uri-request/[simple query strings] in the `q` parameter, or by specifying a http://www.elasticsearch.org/guide/reference/api/search/request-body/[full request definition] using the http://www.elasticsearch.org/guide/reference/query-dsl/[Elasticsearch Query DSL] in the `body` parameter. + +TIP: https://github.com/fullscale/elastic.js[elastic.js] can be used to make building query bodies easier. + + + +The default method is `POST` and the usual <> apply. See http://www.elasticsearch.org/guide/reference/api/search/[the elasticsearch docs] for more about this method. + +.Search with a simple query string query +[source,js] +--------- +client.search({ + index: 'myindex', + q: 'title:test' +}, function (error, response) { + // ... +}); +--------- + +.Passing a full request definition in the Elasticsearch's Query DSL as a `Hash` +[source,js] +--------- +client.search({ + index: 'myindex', + body: { + query: { + match: { + title: 'test' + } + }, + facets: { + tags: { + terms: { + field: 'tags' + } + } + } + } +}, function (error, response) { + // ... +}): +--------- + + +==== Params + +[horizontal] +`analyzer`:: +`String` -- The analyzer to use for the query string +`analyzeWildcard`:: +`Boolean` -- Specify whether wildcard and prefix queries should be analyzed (default: false) +`[defaultOperator=OR]`:: +`String` -- The default operator for query string query (AND or OR) +`df`:: +`String` -- The field to use as default where no field prefix is given in the query string +`explain`:: +`Boolean` -- Specify whether to return detailed information about score computation as part of a hit +`fields`:: +`String, String[], Boolean` -- A comma-separated list of fields to return as part of a hit +`from`:: +`Number` -- Starting offset (default: 0) +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`indicesBoost`:: +`String, String[], Boolean` -- Comma-separated list of index boosts +`lenient`:: +`Boolean` -- Specify whether format-based query failures (such as providing text to a numeric field) should be ignored +`lowercaseExpandedTerms`:: +`Boolean` -- Specify whether query terms should be lowercased +`preference`:: +`String` -- Specify the node or shard the operation should be performed on (default: random) +`q`:: +`String` -- Query in the Lucene query string syntax +`routing`:: +`String, String[], Boolean` -- A comma-separated list of specific routing values +`scroll`:: +`Duration` -- Specify how long a consistent view of the index should be maintained for scrolled search +`searchType`:: +`String` -- Search operation type +`size`:: +`Number` -- Number of hits to return (default: 10) +`sort`:: +`String, String[], Boolean` -- A comma-separated list of : pairs +`source`:: +`String` -- The URL-encoded request definition using the Query DSL (instead of using request body) +`_source`:: +`String, String[], Boolean` -- True or false to return the _source field or not, or a list of fields to return +`_sourceExclude`:: +`String, String[], Boolean` -- A list of fields to exclude from the returned _source field +`_sourceInclude`:: +`String, String[], Boolean` -- A list of fields to extract and return from the _source field +`stats`:: +`String, String[], Boolean` -- Specific 'tag' of the request for logging and statistical purposes +`suggestField`:: +`String` -- Specify which field to use for suggestions +`[suggestMode=missing]`:: +`String` -- Specify suggest mode +`suggestSize`:: +`Number` -- How many suggestions to return in response +`suggestText`:: +`Text` -- The source text for which the suggestions should be returned +`timeout`:: +`Date, Number` -- Explicit operation timeout +`version`:: +`Boolean` -- Specify whether to return document version as part of a hit +`[index=_all]`:: +`String, String[], Boolean` -- A comma-separated list of index names to search; use `_all` or empty string to perform the operation on all indices +`type`:: +`String, String[], Boolean` -- A comma-separated list of document types to search; leave empty to perform the operation on all types + +[[api-suggest]] +=== `suggest` + +[source,js] +-------- +client.suggest([params, [callback]]) +-------- + +The suggest feature suggests similar looking terms based on a provided text by using a specific suggester. + +The default method is `POST` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/search/suggest/[the elasticsearch docs] for more about this method. + +.Return query terms suggestions (“auto-correction”) +[source,js] +--------- +client.suggest({ +index: 'myindex', +body: { + mysuggester: { + text: 'tset', + term: { + field: 'title' + } + } +} +}, function (error, response) { +// response will be formatted like so: +// +// { +// ... +// mysuggester: [ +// { +// text: "tset", +// ... +// options: [ +// { +// text: "test", +// score: 0.75, +// freq: 5 +// } +// ] +// } +// ] +// } +}); +--------- + + +==== Params + +[horizontal] +`ignoreUnavailable`:: +`Boolean` -- Whether specified concrete indices should be ignored when unavailable (missing or closed) +`allowNoIndices`:: +`Boolean` -- Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) +`[expandWildcards=open]`:: +`String` -- Whether to expand wildcard expression to concrete indices that are open, closed or both. +`preference`:: +`String` -- Specify the node or shard the operation should be performed on (default: random) +`routing`:: +`String` -- Specific routing value +`source`:: +`String` -- The URL-encoded request definition (instead of using request body) +`index`:: +`String, String[], Boolean` -- A comma-separated list of index names to restrict the operation; use `_all` or empty string to perform the operation on all indices + +[[api-update]] +=== `update` + +[source,js] +-------- +client.update([params, [callback]]) +-------- + +Update parts of a document. The required body parameter can contain one of two things: + + * a partial document, which will be merged with the existing one. + * a `script` which will update the document content + +The default method is `POST` and the usual <> apply. See http://elasticsearch.org/guide/reference/api/update/[the elasticsearch docs] for more about this method. + +.Update document title using partial document +[source,js] +--------- +client.update({ + index: 'myindex', + type: 'mytype', + id: '1', + body: { + // put the partial document under the `doc` key + doc: { + title: 'Updated' + } + } +}, function (error, response) { + // ... +}) +--------- + +.Add a tag to document `tags` property using a `script` +[source,js] +--------- +client.update({ + index: 'myindex', + type: 'mytype', + id: '1', + body: { + script: 'ctx._source.tags += tag', + params: { tag: 'some new tag' } + } +}, function (error, response) { + // ... +}); +--------- + +.Increment a document counter by 1 or initialize it, when the document does not exist +[source,js] +--------- +client.update({ + index: 'myindex', + type: 'mytype', + id: '666', + body: { + script: 'ctx._source.counter += 1', + upsert: { + counter: 1 + } + } +}, function (error, response) { + // ... +}) +--------- + +.Delete a document if it's tagged “to-delete” +[source,js] +--------- +client.update({ + index: 'myindex', + type: 'mytype', + id: '1', + body: { + script: 'ctx._source.tags.contains(tag) ? ctx.op = "delete" : ctx.op = "none"', + params: { + tag: 'to-delete' + } + } +}, function (error, response) { + // ... +}); +--------- + + +==== Params + +[horizontal] +`consistency`:: +`String` -- Explicit write consistency setting for the operation +`fields`:: +`String, String[], Boolean` -- A comma-separated list of fields to return in the response +`lang`:: +`String` -- The script language (default: mvel) +`parent`:: +`String` -- ID of the parent document +`percolate`:: +`String` -- Perform percolation during the operation; use specific registered query name, attribute, or wildcard +`refresh`:: +`Boolean` -- Refresh the index after performing the operation +`[replication=sync]`:: +`String` -- Specific replication type +`retryOnConflict`:: +`Number` -- Specify how many times should the operation be retried when a conflict occurs (default: 0) +`routing`:: +`String` -- Specific routing value +`script`:: +`Anything` -- The URL-encoded script definition (instead of using request body) +`timeout`:: +`Date, Number` -- Explicit operation timeout +`timestamp`:: +`Date, Number` -- Explicit timestamp for the document +`ttl`:: +`Duration` -- Expiration time for the document +`version`:: +`Number` -- Explicit version number for concurrency control +`versionType`:: +`String` -- Specific version type +`id`:: +`String` -- Document ID +`index`:: +`String` -- The name of the index +`type`:: +`String` -- The type of the document diff --git a/docs/configuration.asciidoc b/docs/configuration.asciidoc new file mode 100644 index 000000000..2bcf89797 --- /dev/null +++ b/docs/configuration.asciidoc @@ -0,0 +1,246 @@ +[[configuration]] +== Configuration + +The `Client` constructor accepts a single object as it's argument, and the following keys can be used to configure that client instance. + +[source,js] +------ +var elasticsearch = require('elasticsearch'); +var client = new elasticsearch.Client({ + ... +}); +------ + +=== Config options +[horizontal] +`host or hosts`[[config-hosts]]:: +`String, String[], Object[]` -- Specify the hosts that this client will connect to. If sniffing is enabled, or you call `client.sniff()`, this list will be used as seeds to discover the rest of your cluster. + +Default::: ++ +[source,js] +------ +'http://localhost:9200' +------ + + + +`log`[[config-log]]:: `String, String[], Object, Object[], Constructor` -- Unless a constructor is specified, this sets the output settings for the bundled logger. See the section on configuring-logging[logging] for more information. + +Default in Node::: ++ +[source,js] +----- +[{ + type: 'stdio', + levels: ['error', 'warning'] +}] +----- + + + +`connectionClass`[[config-connectionClass]]:: `String, Constructor` -- Defines the class that will be used to create connections to store in the connection pool. If you are looking to implement additional protocols you should probably start by writing a Connection class that extends the ConnectionAbstract. + +Defaults::: + * Node: `"http"` + * Browser Build: `"xhr"` + * Angular Build: `"angular"` + * jQuery Build: `"jquery"` + + + +`selector`:: `String, Function` -- This function will be used to select a connection from the ConnectionPool. It should received a single argument, the list of "active" connections, and return the connection to use. Use this selector to implement special logic for your client such as preferring nodes in a certain rack or data-center. ++ +To make this function asynchronous, accept a second argument which will be the callback to use. The callback should be called Node-style with a possible error like: `cb(err, selectedConnection)`. + +Default::: `"roundRobin"` + +Options::: + * `"roundRobin"` + * `"random"` + + + + +`sniffOnStart`:: `Boolean` -- Should the client attempt to detect the rest of the cluster when it is first instantiated? + +Default::: `false` + + + + + +`sniffInterval`:: `Number, false` -- Every `n` milliseconds, perform a sniff operation and make sure our list of nodes is complete. + +Default::: `false` + + + + + +`sniffOnConnectionFault`:: `Boolean` -- Should the client immediately sniff for a more current list of nodes when a connection dies? + +Default::: `false` + + + + +`maxRetries`[[config-max-retries]]:: `Integer` -- How many times should the client try to connect to other nodes before returning a <> error. + +Default::: `3` + + + + + +`requestTimeout`[[config-request-timeout]]:: `Number` -- Milliseconds before an HTTP request will be aborted and retried. This can also be set per request. + +Default::: `30000` + + + + + +`deadTimeout`:: `Number` -- Milliseconds that a dead connection will wait before attempting to revive itself. + +Default::: `30000` + + + + + +`maxSockets`:: `Number` -- Number of sockets each connection should keep to it's corresponding node. This will also be the maximum number of concurrent requests that could be made to that node. These sockets are currently kept alive using https://github.com/TBEDP/agentkeepalive[agentkeepalive]. + +Default::: `10` + + + + +`maxKeepAliveTime`:: `Number, false` -- Milliseconds of inactivity before the socket is destroyed + +Default::: `60000` + + + + +`defer`:: `Function` -- Override the way that the client creates promises. If you would rather use any other promise library this is how you'd do that. Elasticsearch.js expects that the defer object has a `promise` property (which will be returned to promise consumers), as well as `resolve` and `reject` methods. + +Default::: ++ +[source,js] +----- +function () { + return when.defer(); +} +----- + + + +`nodesToHostCallback`:: `Function` - This function will receive the list of nodes returned from the `_cluster/nodes` API during a sniff operation. The function should return an array of objects which match the <>. + +Default::: +see https://github.com/elasticsearch/elasticsearch-js/blob/master/src/lib/nodes_to_host.js[nodes_to_host.js] + + + +=== Examples + +Connect to just a single seed node, and use sniffing to find the rest of the cluster. + +[source,js] +----- +var client = new elasticsearch.Client({ + host: 'localhost:9200', + sniffOnStart: true, + sniffInterval: 60000, +}); +----- + +Specify a couple of hosts which use basic auth. + +[source,js] +----- +var client = new elasticsearch.Client({ + hosts: [ + 'https://user:pass@box1.server.org:9200', + 'https://user:pass@box2.server.org:9200' + ] +}); +----- + +Use host objects to define extra properties, and a selector that uses those properties to pick a node. + +[source,js] +----- +var client = new elasticsearch.Client({ + hosts: [ + { + protocol: 'https', + host: 'box1.server.org', + port: 56394, + country: 'EU', + weight: 10 + }, + { + protocol: 'https', + host: 'box2.server.org', + port: 56394, + country: 'US', + weight: 50 + } + ], + selector: function (hosts) { + var myCountry = process.env.COUNTRY; + // first try to find a node that is in the same country + var selection = _.find(nodes, function (node) { + return node.host.country === myCountry; + }); + + if (!selection) { + // choose the node with the smallest weight. + selection = _(nodes).sortBy(function (node) { + return node.host.weight; + }).first(); + } + + return selection; + } +}); +----- + +.Use a custom nodesToHostCallback that will direct all of the requests to a proxy and select the node via a query string param. +[source,js] +----- +var client = new elasticsearch.Client({ + nodesToHostCallback: function (nodes) { + /* + * The nodes object will look something like this + * { + * "y-YWd-LITrWXWoCi4r2GlQ": { + * name: "Supremor", + * transport_address: "inet[/192.168.1.15:9300]", + * hostname: "Small-ESBox.infra", + * version: "1.0.0", + * http_address: "inet[/192.168.1.15:9200]", + * attributes: { + * custom: "attribute" + * } + * }, + * ... + * } + */ + + return _.transform(nodes, function (nodeList, node, id) { + var port = node.http_address.match(/:(\d+)/)[1]; + nodeList.push({ + host: 'esproxy.example.com', + port: 80, + query: { + nodeHostname: node.hostname, + nodePort: port + } + }); + }, []); + } +}) +----- \ No newline at end of file diff --git a/docs/development.asciidoc b/docs/development.asciidoc new file mode 100644 index 000000000..f22ef7e5d --- /dev/null +++ b/docs/development.asciidoc @@ -0,0 +1,3 @@ +[[contributing]] +== Development/Contributing +Contributions are awesome, but please read https://github.com/elasticsearch/elasticsearch-js/blob/master/CONTRIBUTING.md before submitting a pull request. \ No newline at end of file diff --git a/docs/errors.asciidoc b/docs/errors.asciidoc new file mode 100644 index 000000000..3647db639 --- /dev/null +++ b/docs/errors.asciidoc @@ -0,0 +1,18 @@ +[[errors]] +== Error Reference +These are the standard Error types which may be passed back from the client. To access the constructors is provided via `require('elasticsearch').errors`. + +[horizontal] +[[connection-fault]] +`ConnectionFault`:: The connection was unable to initiate or complete a request with the Elasticsearch node. +`NoConnections`:: All of the connections in the ConnectionPool are dead. +`RequestTimeout`:: The request timed-out. +`Serialization`:: The response received from Elasticsearch could not be deserilaized. +`503` or `ServiceUnavailable`:: Elasticsearch responded with a 503 status. +`500` or `InternalServerError`:: Elasticsearch responded with a 500 status. +`412` or `PreconditionFailed`:: Elasticsearch responded with a 412 status. +`409` or `Conflict`:: Elasticsearch responded with a 409 status. +`403` or `Forbidden`:: Elasticsearch responded with a 403 status. +`404` or `NotFound`:: Elasticsearch responded with a 404 status. +`400` or `BadRequest`:: Elasticsearch responded with a 400 status. +`Generic`:: Elasticsearch responded with a status that does not map to it's own error type. \ No newline at end of file diff --git a/docs/extending_core_components.asciidoc b/docs/extending_core_components.asciidoc new file mode 100644 index 000000000..5851a64bc --- /dev/null +++ b/docs/extending_core_components.asciidoc @@ -0,0 +1,17 @@ +[[extending_core_components]] +== Extending Core Components +We decided to make this client low-level, and as such we probably have not implemented all the features you are looking for. For this reason, we made extending or even replacing the core components simple. + +=== Connection +Coming Soon + +=== ConnectionPool +Coming Soon + +=== Log +see <>. + +=== Client/API +The Client's only real purpose (as you may be able to tell from client.js) is to hold the API methods, set a few default values, and instantiate the transport. The transport is where all the networking, retry, and cluster discovery takes place and including it in your client is as simple as `transport = new es.Transport({});`. This way, you can benefit from the core features of our client. + +NOTE: In the near future the entire transport level will be abstracted into a separate module, as well as the API. diff --git a/docs/index.asciidoc b/docs/index.asciidoc new file mode 100644 index 000000000..bafe028da --- /dev/null +++ b/docs/index.asciidoc @@ -0,0 +1,19 @@ += elasticsearch.js + +include::about.asciidoc[] + +include::quick_start.asciidoc[] + +include::api_conventions.asciidoc[] + +include::api_methods.asciidoc[] + +include::configuration.asciidoc[] + +include::extending_core_components.asciidoc[] + +include::logging.asciidoc[] + +include::development.asciidoc[] + +include::errors.asciidoc[] \ No newline at end of file diff --git a/docs/logging.asciidoc b/docs/logging.asciidoc new file mode 100644 index 000000000..b37afe2b1 --- /dev/null +++ b/docs/logging.asciidoc @@ -0,0 +1,141 @@ +[[logging]] +== setup logging +Every application needs to have some solution for logging, and there isn't a standard in JavaScript, so instead of forcing you to rely on a specific logging module we created a bare bones logging solution and <> will show you how to configure it. That said, our implementation of logging is very minimal and ***it is highly recommended that you use something like https://github.com/trentm/node-bunyan[Bunyan] once you move to production***. + +=== Using A Library +When the client receives a function for the `log:` config value, it expects that the function is a constructor for a custom log class. This is the simplest way to integrate other logging libraries into the elasticsearch client at this time. The contract for this Log class is pretty straight-forward. See https://github.com/elasticsearch/elasticsearch-js/blob/master/src/lib/log.js[our implementation] for additional details. + +==== `new Constructor(config)` + * `config` -- The object that was passed to the client constructor, use to determine the log level. + +==== `error(error)` + * error -- `Error` The error that occurred + +==== `warning(message)` + * message -- `String` The message to be logged + +==== `info(message)` + * message -- `String` The message to be logged + +==== `debug(message)` + * message -- `String` The message to be logged + +==== `trace(httpMethod, requestUrl, requestBody, responseBody, responseStatus)` + +Called after every HTTP request. + + * httpMethod -- `String` The request's HTTP method + * requestUrl -- `Object, String` Depending on the connector in use, this will either be a url string or the object passed to node's http.request. + * requestBody -- `String, false-y` The body of the http request, if the body is false-y no body was sent + * responseStatus -- `Integrer, false-y` The HTTP response status + +=== Bunyan Example +In the future we may add loggers for some of the more common libraries, but for now this is an exercise for the user. Here is a hint to get you started implementing a https://github.com/trentm/node-bunyan[Bunyan] log class. Be sure to check out the Bunyan repo for more info about setting things up. + +.in log_to_bunyan.js +[source,js] +---------------- +module.exports = LogToBunyan; + +var bunyan = require('bunyan'); + +function LogToBunyan(config) { + // config is the object passed to the client constructor. + var bun = bunyan.createLogger({name: 'mylogger'}); + this.error = bun.error.bind(bun); + this.warning = bun.warn.bind(bun); + this.info = bun.info.bind(bun); + this.debug = bun.debug.bind(bun); + this.trace = function (method, requestUrl, body, responseBody, responseStatus) { + bun.trace({ + method: method, + requestUrl: requestUrl, + body: body, + responseBody: responseBody, + responseStatus: responseStatus + }); + }; + this.close = function () { /* bunyan's loggers do not need to be closed */ }; +} +---------------- + +.in model.js +[source,js] +---------------- +var elasticsearch = require('elasticsearch'); +var LogClass = require('./log_to_bunyan'); +// now just pass the log class to the client constructor using the "log" config option. +var client = new elasticsearch.Client({ log: LogClass }); +---------------- + +[[logging-customization]] +== Using the default loggers + +By default, the client creates a `"warning"` level, Console or Stdio logger. To change this, specify the client's `log:` config value to either an array of logger config's, a single logger config, a log level, an array of log levels, or a constructor for your own logger. That's a lot of options, so here is an example of each. + +.Change the logging level to trace, so we get every log message +[source,js] +---------------- +var client = new elasticsearch.Client({ log: 'trace' }); +---------------- + +.Change the logging level, only listen for error and trace messages +[source,js] +---------------- +var client = new elasticsearch.Client({ log: ['error', 'trace'] }); +---------------- + +.Log every message to a file +[source,js] +---------------- +var client = new elasticsearch.Client({ + log: { + type: 'file', + level: 'trace', + path: '/var/log/elasticsearch.log' + } +}); +---------------- + +.Log everything to a file and errors to a socket +[source,js] +---------------- +var client = new elasticsearch.Client({ + log: [ + { + type: 'stream', + level: 'error', + // config option specific to stream type loggers + stream: mySocket + }, + { + type: 'file', + level: 'trace', + // config options specific to file type loggers + path: '/var/log/elasticsearch.log' + } + ] +}); +---------------- + +=== Logger Types +==== "stdio" +The default logger for in Node, writes log messages for "info", "debug", and "trace" to stdout and "error" and "warning" to stderr. + +===== Options + * `[color=false]` -- `Boolean` Write with a bit of flair. The default value is intelligently chosen by https://github.com/sindresorhus/chalk[chalk] based on the details of your environment. + +==== "file" +Append the log messages to a file. + +===== Options + * `[path="elasticsearch.log"]` -- `String` Location of the file. It is created if it does not exists + +==== "stream" +Send log messages to a WriteableStream + +===== Options + * `stream` -- `WriteableStream` The object to write to. + +==== "console" +Default logger for the browser build, logs to the console when one exists. \ No newline at end of file diff --git a/docs/quick_start.asciidoc b/docs/quick_start.asciidoc new file mode 100644 index 000000000..36c2041ec --- /dev/null +++ b/docs/quick_start.asciidoc @@ -0,0 +1,161 @@ +[[quick-start]] +== Quick Start + +=== Creating a client +Start using Elasticsearch.js by creating an instance of the `elasticsearch.Client` class. The constructor accepts a config object/hash where you can define defaults values, or even entire classes, for the client to use. For a full list of config options check out the the <>. + +[source,js] +----------------- +var elasticsearch = require('elasticsearch'); +var client = new elasticsearch.Client({ + host: 'localhost:9200', + log: 'trace' +}); +----------------- + +=== Say hello to Elasticsearch + +Almost all of the methods on the client accept two arguments: + + * `params` - an optional object/hash of parameters <>. + * `callback` - an optional function that will be called with the final result of the method. When omitted, a https://github.com/cujojs/when/blob/master/docs/api.md#promise[promise] is returned. api-conventions-cb[More info here]. + +==== Ping the cluster + +.Send a HEAD request to "/?hello=elasticsearch" and allow up to 1 second for it to complete. +[source,js] +----------------- +client.ping({ + requestTimeout: 1000, + // undocumented params are appended to the query string + hello: "elasticsearch!" +}, function (error) { + if (error) { + console.error('elasticsearch cluster is down!'); + } else { + console.log('All is well'); + } +}); +----------------- + +==== Use Promises + +.Skip the callback to get a promise back +[source,js] +----------------- +client.search({ + q: 'pants' +}).then(function (body) { + var hits = body.hits.hits; +}, function (error) { + console.trace(error.message); +}); +----------------- + +==== Allow 404 responses + +.Prevent 404 responses from being considered errors by telling the client to ignore them. +[source,js] +----------------- +client.indices.delete({ + index: 'test_index', + ignore: [404] +}).then(function (body) { + // since we told the client to ignore 404 errors, the + // promise is resolved even if the index does not exist + console.log('index was deleted or never existed'); +}, function (error) { + // oh no! +}); +----------------- + +=== Searching for documents +A very common use-case for elasticsearch is to sort through through large collections of documents in order to find ones that are relavent to a query. In most cases you will use the client's `search()` method to accomplish this. + +==== Elasticsearch Query DSL + +For many searches you will want to define a search document that tells elasticsearch exactly how to find the documents you are looking for. To do this you will use the http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl.html[elasticsearch query DSL]. If you are not familiary with Elasticsearch's query DSL is it recommended that you research the topic at elasticsearch.org or watch/read one of these introductions: + + * https://www.youtube.com/watch?v=52G5ZzE0XpY#t=1471[Clinton Gormley "Getting down and dirty with Elasticsearch"] + * http://okfnlabs.org/blog/2013/07/01/elasticsearch-query-tutorial.html#query-dsl-overview[Querying Elasticsearch - A Tutorial and Guide] + * http://exploringelasticsearch.com/book/searching-data/the-query-dsl-and-the-search-api.html[The Query DSL and the Search API - Searching Data - Exploring Elasticsearch] + +Now for some examples using the Query DSL. + +===== Simple match query + +.Find tweets that have "elasticsearch" in their body field +[source,js] +----------------- +client.search({ + index: 'twitter', + type: 'tweets', + body: { + query: { + match: { + body: 'elasticsearch' + } + } + } +}).then(function (resp) { + var hits = resp.hits.hits; +}, function (err) { + console.trace(err.message); +}); +----------------- + +===== More complex filtered query + +To power a search form on a public site, you might want to allow the user to specify some text but also limit the documents returned by a few criteria. This is a good use-case for a filtered query. + +NOTE: In this example, `request` and `response` are http://expressjs.com/api.html#request[Express] request and response objects. + +[source,js] +----------------- +var pageNum = request.param('page', 0); +var perPage = request.param('per_page', 15); +var userQuery = request.param('search_query'); +var userId = request.session.userId; + +client.search({ + index: 'posts', + from: (pageNum - 1) * perPage, + size: perPage, + body: { + filtered: { + query: { + match: { + // match the query agains all of + // the fields in the posts index + _all: userQuery + } + }, + filter: { + // only return documents that are + // public or owned by the current user + or: [ + { + term: { privacy: "public" } + }, + { + term: { owner: userId } + } + ] + } + } + } +}, function (error, response) { + if (err) { + // handle error + return; + } + + response.render('search_results', { + results: response.hits.hits, + page: pageNum, + pages: Math.ceil(response.hists.total / perPage) + }) +}); +----------------- + +You can find a lot more information about filters http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-filters.html[here] \ No newline at end of file diff --git a/docs/transport.asciidoc b/docs/transport.asciidoc new file mode 100644 index 000000000..8901ef251 --- /dev/null +++ b/docs/transport.asciidoc @@ -0,0 +1,24 @@ +[[transport-reference]] +== Transport + +=== request(params, [callback]) + +==== Params +[horizontal] +`path`:: +`String` -- The path/endpoint for the request + +`query`:: +`Object` -- The query string params + +`path`:: +`Object` -- The query string params + +`ignore`:: +`Number, Number[]` -- HTTP status codes which should not be treated as errors + +`requestTimeout`:: +`Number` -- Milliseconds this request has to complete. The default can be set using the client's `requestTimeout:` config parameter. + +`method`:: +`String` -- The HTTP method to use for this request. All of the API methods have their own default. \ No newline at end of file diff --git a/grunt/config/run.js b/grunt/config/run.js index f11988b43..5ca144e89 100644 --- a/grunt/config/run.js +++ b/grunt/config/run.js @@ -1,20 +1,35 @@ module.exports = { generate: { - exec: 'node scripts/generate' + exec: 'node ./scripts/generate/index.js', + options: { + passArgs: [ + 'verbose', + 'es_branch' + ] + } + }, + generate_yaml_tests: { + exec: 'node ./scripts/generate/index.js --no-api', + options: { + passArgs: [ + 'verbose', + 'es_branch' + ] + } + }, + browser_integration_tests: { + exec: 'node ./scripts/run_browser_integration_suite', + options: { + passArgs: [ + 'browsers' + ] + } }, browser_unit_tests: { exec: './node_modules/.bin/testling .', options: { - cwd: '.' - } - }, - browser_integration_tests: { - exec: 'node scripts/run_tests --integration --no-server', - options: { - cwd: '.', passArgs: [ - 'port', - 'host' + 'x' ] } } diff --git a/grunt/tasks.js b/grunt/tasks.js index 5d048f66d..9e28c9842 100644 --- a/grunt/tasks.js +++ b/grunt/tasks.js @@ -5,17 +5,18 @@ module.exports = function (grunt) { 'test' ]); - grunt.registerTask('generate', [ - 'run:generate' - ]); - grunt.registerTask('test', [ 'jshint', 'mochacov:unit', - 'generate', + 'run:generate', 'mochacov:integration', ]); + grunt.registerTask('unit_test', [ + 'jshint', + 'mochacov:unit' + ]); + grunt.registerTask('coverage', [ 'mochacov:make_coverage_html', 'open:coverage' diff --git a/scripts/generate/index.js b/scripts/generate/index.js index 348037656..2907dcb71 100644 --- a/scripts/generate/index.js +++ b/scripts/generate/index.js @@ -19,6 +19,11 @@ var argv = require('optimist') tests: { default: true, boolean: true + }, + es_branch: { + default: 'master', + string: true, + alias: 'b' } }); @@ -34,39 +39,58 @@ 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 && git submodule foreach git pull origin master', - 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); +var branch = argv.es_branch; +// branch can be prefixed with = or suffixed with _nightly +if (branch.indexOf) { + ['='].forEach(function removePrefix(pref) { + if (branch.indexOf(pref) === 0) { + branch = branch.substring(pref.length); } + }); - if (stderr) { - console.error(stderr); + ['_nightly'].forEach(function removeSuffix(suf) { + if (branch.indexOf(suf) === branch.length - suf.length) { + branch = branch.substr(0, branch.length - suf.length); } - done(); }); } -updateSubmodules(function (err) { +var stdio = [ + 'ignore', + argv.verbose ? process.stdout : 'ignore', + process.stderr +]; + +async.series([ + function (done) { + cp.spawn('git', ['submodule', 'update', '--init'], { + stdio: stdio + }).on('exit', function (status) { + done(status ? new Error('Unable to init submodules.') : void 0); + }); + }, + function (done) { + // checkout branch and clean it + cp.spawn('git', ['submodule', 'foreach', 'git fetch origin master && git checkout origin/' + branch + ' && git clean -f'], { + stdio: stdio + }).on('exit', function (status) { + done(status ? new Error('Unable to checkout ' + branch) : void 0); + }); + }, + function (done) { + var tasks = []; + + if (argv.api) { + tasks.push(require('./js_api')); + } + if (argv.tests) { + tasks.push(require('./yaml_tests')); + } + + async.parallel(tasks, done); + } +], 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 index 6643cf61f..ed6926643 100644 --- a/scripts/generate/js_api.js +++ b/scripts/generate/js_api.js @@ -24,12 +24,11 @@ module.exports = function (done) { writeApiFile, ensureDocsDir, formatDocVars, - writeMethodList, writeMethodDocs ], done); function readSpecFiles(done) { - var apiDir = '../../src/rest-api-spec/api/'; + var apiDir = '../../src/elasticsearch/rest-api-spec/api/'; files = fs.readdirSync(apiDir).map(function (filename) { return require(apiDir + filename); }); @@ -101,17 +100,9 @@ module.exports = function (done) { done(); } - function writeMethodList(done) { - fs.writeFile( - '../../docs/_method_list.jade', - templates.apiMethodList(docVars), - done - ); - } - function writeMethodDocs(done) { fs.writeFile( - '../../docs/_methods.jade', + '../../docs/api_methods.asciidoc', templates.apiMethods(docVars), done ); diff --git a/scripts/generate/templates/api_method_list.tmpl b/scripts/generate/templates/api_method_list.tmpl deleted file mode 100644 index a304f70e5..000000000 --- a/scripts/generate/templates/api_method_list.tmpl +++ /dev/null @@ -1,32 +0,0 @@ -<% -function esc(str) { - return str.replace(/\|/g, '|'); -} - -var topActions = []; -var names = {}; - -_.each(actions, function (action) { - if (action.name.indexOf('.') > -1) { - var space = _.studlyCase(action.name.split('.').slice(0, -1).join('.')); - if (!names[space]) { - names[space] = []; - } - names[space].push(action); - } else { - topActions.push(action); - } -}); %> - -ul<% -_.each(topActions, function (action) {%> - li: a(href="api.html#<%= action.name.toLowerCase().replace(/[^\w]+/g, '-') %>") <%= action.name %><% -}); -_.each(Object.keys(names).sort(), function (namespace) {%> - h3 <%= namespace %> - ul<% - _.each(names[namespace], function (action) {%> - li: a(href="api.html#<%= action.name.toLowerCase().replace(/[^\w]+/g, '-') %>") <%= action.name.replace(/^.*\./, '') %><% - }) -}) -%> diff --git a/scripts/generate/templates/api_methods.tmpl b/scripts/generate/templates/api_methods.tmpl index 1385c85b5..3477637bd 100644 --- a/scripts/generate/templates/api_methods.tmpl +++ b/scripts/generate/templates/api_methods.tmpl @@ -1,27 +1,35 @@ +[[api-reference]] +== API Method Reference <% _.each(actions, function (action) { -var actionId = action.name.toLowerCase().replace(/[^\w]+/g, '-'); +var actionId = 'api-' + action.name.toLowerCase().replace(/[^\w]+/g, '-'); %> -h2#<%= actionId %>.fn <%= action.name %>(params, [callback]) -include _descriptions/<%= action.name %>.jade -p. - The default method is <%= action.spec.method || 'GET' %> and - the usual params and return values apply. - See <%= action.docUrl %> for more about this method. -include _examples/<%= action.name %>.jade +[[<%= actionId %>]] +=== `<%= action.name %>` + +[source,js] +-------- +client.<%= action.name %>([params, [callback]]) +-------- + +<%= description(action.name) %> + +The default method is `<%= action.spec.method || 'GET' %>` and the usual <> apply. See <%= action.docUrl %>[the elasticsearch docs] for more about this method. + +<%= examples(action.name) %> + <% if (_.size(action.allParams)) { %> -h3 Params -dl.params.api -<% _.each(action.allParams, function (param, paramName) { %> - dt: dfn: code <%= paramWithDefault(paramName, param.default) %> - dd. - <%= paramType(param.type) %> -<%= indent(param.description || '', 4) %><% -}); %> -<% } +==== Params -}); +[horizontal]<% +_.each(action.allParams, function (param, paramName) { %> +`<%= paramWithDefault(paramName, param.default) %>`:: +`<%= paramType(param.type) %>` -- <%= joinParagraphs(param.description || '', 4) %><% + + }); // endeach +} // endif + +}); // endeach %> diff --git a/scripts/generate/templates/index.js b/scripts/generate/templates/index.js index f1ba48c40..550b2a1dc 100644 --- a/scripts/generate/templates/index.js +++ b/scripts/generate/templates/index.js @@ -49,6 +49,34 @@ var templateGlobals = { }).join('\n'); }, + joinParagraphs: function (block) { + return block.split('\n\n').join('\n+\n'); + }, + + description: function (action) { + try { + return fs.readFileSync(path.join(__dirname, '../../../docs/_descriptions/' + action + '.asciidoc')); + } catch (e) { + if (~e.message.indexOf('ENOENT')) { + return '// no description'; + } else { + throw e; + } + } + }, + + examples: function (action) { + try { + return fs.readFileSync(path.join(__dirname, '../../../docs/_examples/' + action + '.asciidoc')); + } catch (e) { + if (~e.message.indexOf('ENOENT')) { + return '// no examples'; + } else { + throw e; + } + } + }, + paramType: function (type) { switch (type && type.toLowerCase ? type.toLowerCase() : 'any') { case 'time': diff --git a/scripts/generate/yaml_tests.js b/scripts/generate/yaml_tests.js index 9ac0bc8f6..c065d78b2 100644 --- a/scripts/generate/yaml_tests.js +++ b/scripts/generate/yaml_tests.js @@ -16,7 +16,7 @@ module.exports = function (done) { ], done); function readYamlTests(done) { - var testDir = path.join(__dirname, '../../src/rest-api-spec/test/'); + var testDir = path.join(__dirname, '../../src/elasticsearch/rest-api-spec/test/'); function readDirectories(dir) { fs.readdirSync(dir).forEach(function (filename) { diff --git a/scripts/jenkins.sh b/scripts/jenkins.sh index 770e4fb44..866c1524c 100755 --- a/scripts/jenkins.sh +++ b/scripts/jenkins.sh @@ -1,10 +1,15 @@ -#!/bin/bash - -# generate the latest version of the yaml-tests -node scripts/generate/ --no-api 2>&1 > /dev/null +#!/usr/bin/env bash export VERBOSE="true" +if [ -x $ES_V ]; then + echo "missing ES_V environment var" + exit 1 +fi + +# generate the latest version of the yaml-tests +node scripts/generate --es_branch="=$ES_V" --no-api + # unit tests ./node_modules/.bin/mocha test/unit/test_*.js \ --require should \ diff --git a/scripts/rest_spec_updated.js b/scripts/rest_spec_updated.js deleted file mode 100644 index 0f615f662..000000000 --- a/scripts/rest_spec_updated.js +++ /dev/null @@ -1,70 +0,0 @@ -var https = require('https'); -var request = { - hostname: 'api.github.com', - path: '/repos/elasticsearch/elasticsearch-rest-api-spec/commits/HEAD', - headers: { - 'User-Agent': 'spenceralger' - } -}; -var fs = require('fs'); - -var lastRestSpecUpdateFile = __dirname + '/last_rest_spec_update.sha'; -var lastRestSpecUpdate; -var updated; - -if (fs.existsSync(lastRestSpecUpdateFile)) { - lastRestSpecUpdate = fs.readFileSync(lastRestSpecUpdateFile, 'utf8'); -} - -var req = https.get(request, function (incoming) { - if (incoming.statusCode !== 200) { - req.abort(); - console.error('request for last commit failed', incoming.statusCode, incoming.headers); - return; - } - - var body = ''; - - incoming.on('data', onData); - incoming.on('end', onEnd); - - function onData(chunk) { - body += chunk; - } - - function onEnd() { - incoming.removeListener('data', onData); - incoming.removeListener('end', onEnd); - var _req = req; - req = null; - - var resp; - try { - resp = JSON.parse(body); - } catch (e) { - console.log('unable to parse response from github'); - _req.emit('ready'); - return; - } - - if (lastRestSpecUpdate === resp.sha) { - updated = false; - } else { - updated = true; - fs.writeFileSync(lastRestSpecUpdateFile, resp.sha); - } - _req.emit('ready'); - } -}); - -module.exports = function (cb) { - function done() { - cb(null, updated); - } - - if (req) { - req.on('ready', done); - } else { - process.nextTick(done); - } -}; diff --git a/scripts/run_tests.js b/scripts/run_tests.js deleted file mode 100644 index b6d4c7711..000000000 --- a/scripts/run_tests.js +++ /dev/null @@ -1,143 +0,0 @@ -var async = require('async'); -var cp = require('child_process'); -var chalk = require('chalk'); -var argv = require('optimist') - .usage([ - 'Runner for the Elasticsearch.js unit and integration tests in both node and the browser.', - 'To negate a flag you can use --no-{{flag}}.', - '', - 'Examples:', - '', - '# Before a commit (unit tests in Node & Phantom + integration in Chrome & Firefox):', - 'npm test --unit --integration --browsers=chrome,firefox', - '', - '# After a change in the rest-spec:', - 'npm test --no-unit --integration --browsers=chrome,firefox --check-upstream', - '', - '# During dev (just Node unit tests):', - 'npm test --no-browsers', - '' - ].join('\n')) - .options({ - server: { - default: true, - alias: 's' - }, - unit: { - default: false, - alias: 'u' - }, - integration: { - default: false, - alias: 'i' - }, - host: { - default: 'localhost', - description: 'hostname for elasticsearch instance used in integration tests' - }, - port: { - default: 9200, - alias: 'p' - }, - browsers: { - default: '*', - alias: 'b' - }, - 'check-upstream': { - default: false, - description: 'check for remote updates to the yaml test suite' - } - }); - -if (process.argv.indexOf('help') + process.argv.indexOf('--help') + process.argv.indexOf('-h') !== -3) { - argv.showHelp(); - process.exit(1); -} - -if (process.env.npm_config_argv) { - // when called by NPM - argv = argv.parse([].concat(process.argv).concat(JSON.parse(process.env.npm_config_argv).original)); -} else { - // when called directly - argv = argv.argv; -} - -var commands = []; -var command; - -if (argv['check-upstream']) { - command = ['node', 'scripts/generate']; - if (argv.force) { - command.push('--force'); - } - commands.push(command); -} - -if (argv.unit) { - if (argv.server) { - commands.push(['./node_modules/.bin/mocha', 'test/unit/test_*.js']); - } - if (argv.browsers) { - commands.push(['./node_modules/.bin/testling', '.']); - } -} - -if (argv.integration) { - if (argv.server) { - commands.push([ - './node_modules/.bin/mocha', - 'test/integration/yaml_suite/index.js', - // '-b', - '--host', argv.host, - '--port', argv.port - ].filter(Boolean)); - } - if (argv.browsers) { - commands.push([ - 'node', - 'scripts/run_browser_integration_suite/index.js', - '--browsers', - argv.browsers - ]); - } -} - -var proc = null; -process.on('exit', function () { - if (proc && proc.kill) { - proc.kill(); - } -}); - -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' - }); - - proc.on('error', function (err) { - proc.removeAllListeners(); - done(err); - }); - - proc.on('exit', function (status) { - proc.removeAllListeners(); - done(status ? new Error(command + ' exited with status ' + status) : void 0); - }); - }, function (err) { - if (err) { - console.log(chalk.red('\n\n⚑⚑⚑︎ Error! ⚑⚑⚑')); - console.error(err.message); - process.exit(1); - } else { - console.log(chalk.green('\n\n✔︎ looks good\n\n')); - process.exit(0); - } - }); -} else { - console.log('Arguments resulted in no tests to run.'); - console.log('Try combining test types with environments'); -} diff --git a/scripts/sync_examples.js b/scripts/sync_examples.js new file mode 100644 index 000000000..ff632ff90 --- /dev/null +++ b/scripts/sync_examples.js @@ -0,0 +1,72 @@ +var async = require('async'); +var fs = require('fs'); +var S = require('string'); + +var restSpecDir = './src/elasticsearch/rest-api-spec/api/'; + +function fileExists(path, done) { + fs.stat(path, function (err, stats) { + var exists; + + if (err) { + if (err.message.match(/enoent/i)) { + err = void 0; + exists = false; + } + } else if (stats.isFile()) { + exists = true; + } else { + err = new Error('weird stats: ' + JSON.stringify(stats)); + } + + done(err, exists); + }); +} + +fs.readdir(restSpecDir, function (err, files) { + if (err) { + throw err; + } + + async.forEachSeries(files, function (fileName, done) { + var apiName = S(fileName.replace(/\.json$/, '')).camelize().s; + var filePath = './docs/_descriptions/' + apiName; + var jadeFileExists; + var asciiFileExists; + + async.series([ + function (done) { + fileExists(filePath + '.jade', function (err, exists) { + jadeFileExists = exists; + done(err); + }); + }, + function (done) { + fileExists(filePath + '.asciidoc', function (err, exists) { + asciiFileExists = exists; + done(err); + }); + }, + function (done) { + if (jadeFileExists && !asciiFileExists) { + console.log(apiName, 'jade, no ascii'); + fs.rename(filePath + '.jade', filePath + '.asciidoc', done); + } + else if (!jadeFileExists && !asciiFileExists) { + console.log(apiName, 'no jade, no ascii'); + fs.writeFile(filePath + '.asciidoc', '', done); + } + else if (jadeFileExists) { + console.log(apiName, 'jade'); + fs.unlink(filePath + '.jade', done); + } + } + ], done); + }, function done(err) { + if (err) { + throw err; + } else { + console.log('done'); + } + }); +}); \ No newline at end of file diff --git a/scripts/travis.sh b/scripts/travis.sh new file mode 100755 index 000000000..2c568027d --- /dev/null +++ b/scripts/travis.sh @@ -0,0 +1,110 @@ +#!/usr/bin/env bash + +if [ -z $ES_BRANCH ]; then + echo "Missing ES_BRANCH environment var" + exit 1 +fi + +ROOT="$PWD" +ES_SUBMODULE="$ROOT/src/elasticsearch" +SNAPSHOTS="$ROOT/.snapshots" +ES_VERSION="${ES_BRANCH}_nightly" +ES_URL="http://s3-us-west-2.amazonaws.com/build.elasticsearch.org/origin/$ES_BRANCH/nightly/JDK6/elasticsearch-latest-SNAPSHOT.zip" + +if [ ! -z $ES_RELEASE ]; then + ES_VERSION="v${ES_RELEASE}" + ES_URL="https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-${ES_RELEASE}.zip" +fi + +ES_DIR="$SNAPSHOTS/$ES_VERSION" +ES_BIN="$ES_DIR/bin/elasticsearch" + +function fold { + if [ $TRAVIS = "true" ]; then + echo -e "travis_fold:$1" + fi +} + +function check { + RESULT=$1 + if [ "$RESULT" -gt "0" ]; then + echo "non-zero exit code: $RESULT" + exit $RESULT + fi +} + +fold "start:setup_es" + echo "Setting up elasticsearch" + + echo "Killing existsing java processes" + killall java 2>/dev/null + + if [ ! -d "$SNAPSHOTS" ]; then + mkdir $SNAPSHOTS + fi + + cd $SNAPSHOTS + + if [ ! -d "$ES_DIR" ]; then + echo "Downloading Elasticsearch $ES_VERSION to $ES_DIR" + + + curl -O $ES_URL \ + && unzip elasticsearch-*.zip + check $? + + rm elasticsearch-*.zip + check $? + + mv elasticsearch-*/ $ES_DIR + check $? + fi + + cd $ROOT + + if [ ! -x "$ES_BIN" ]; then + echo "Unable to find elasticsearch executable" + exit 1 + fi + + if [ "$ES_BRANCH" = "0.90" ]; then + echo "Starting Elasticsearch $ES_VERSION" + $ES_BIN \ + -Des.network.host=localhost \ + -Des.discovery.zen.ping.multicast.enabled=false \ + -Des.discovery.zen.ping_timeout=1 + check $? + else + echo "Starting Elasticsearch $ES_VERSION as a deamon" + $ES_BIN -d \ + -Des.network.host=localhost \ + -Des.discovery.zen.ping.multicast.enabled=false \ + -Des.discovery.zen.ping_timeout=1 + check $? + fi +fold "end:setup_es" + + +if [ ! -x "`which grunt`" ]; then + fold "start:install_grunt" + echo "installing grunt-cli" + npm install -g grunt-cli + check $? + fold "end:install_grunt" +fi + +if [ -z "$NO_UNIT" ]; then + grunt jshint mochacov:unit + check $? +fi + +if [ -z "$NO_INTEGRATION" ]; then + grunt --es_branch="=$ES_BRANCH" run:generate_yaml_tests mochacov:integration + check $? +fi + +if [ -n "$COVERAGE" ]; then + grunt mochacov:ship_coverage +fi + +killall java 2>/dev/null \ No newline at end of file diff --git a/src/elasticsearch b/src/elasticsearch new file mode 160000 index 000000000..3cffe334b --- /dev/null +++ b/src/elasticsearch @@ -0,0 +1 @@ +Subproject commit 3cffe334ba6c2be9434c962c6944e74cf31df014 diff --git a/src/lib/api.js b/src/lib/api.js index 16e276975..a3f834c0f 100644 --- a/src/lib/api.js +++ b/src/lib/api.js @@ -497,7 +497,9 @@ api.cluster.prototype.state = ca({ * 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 {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @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 @@ -507,14 +509,22 @@ api.cluster.prototype.state = ca({ */ api.count = ca({ params: { - ignoreIndices: { + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { type: 'enum', - 'default': 'none', + 'default': 'open', options: [ - 'none', - 'missing' + 'open', + 'closed' ], - name: 'ignore_indices' + name: 'expand_wildcards' }, minScore: { type: 'number', @@ -641,7 +651,9 @@ api['delete'] = ca({ * @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 {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @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 @@ -675,14 +687,22 @@ api.deleteByQuery = ca({ df: { type: 'string' }, - ignoreIndices: { + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { type: 'enum', - 'default': 'none', + 'default': 'open', options: [ - 'none', - 'missing' + 'open', + 'closed' ], - name: 'ignore_indices' + name: 'expand_wildcards' }, replication: { type: 'enum', @@ -1197,7 +1217,9 @@ api.indices.prototype.analyze = ca({ * @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 {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @param {String, String[], Boolean} params.index - A comma-separated list of index name to limit the operation * @param {Boolean} params.recycler - Clear the recycler cache */ @@ -1231,14 +1253,22 @@ api.indices.prototype.clearCache = ca({ type: 'boolean', name: 'id_cache' }, - ignoreIndices: { + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { type: 'enum', - 'default': 'none', + 'default': 'open', options: [ - 'none', - 'missing' + 'open', + 'closed' ], - name: 'ignore_indices' + name: 'expand_wildcards' }, index: { type: 'list' @@ -1269,6 +1299,9 @@ api.indices.prototype.clearCache = ca({ * @param {Object} params - An object with parameters used to carry out this action * @param {Date, Number} params.timeout - Explicit operation timeout * @param {Date, Number} params.masterTimeout - Specify timeout for connection to master + * @param {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @param {String} params.index - The name of the index */ api.indices.prototype.close = ca({ @@ -1279,6 +1312,23 @@ api.indices.prototype.close = ca({ masterTimeout: { type: 'time', name: 'master_timeout' + }, + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { + type: 'enum', + 'default': 'open', + options: [ + 'open', + 'closed' + ], + name: 'expand_wildcards' } }, url: { @@ -1509,9 +1559,31 @@ api.indices.prototype.deleteWarmer = ca({ * 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 {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @param {String, String[], Boolean} params.index - A comma-separated list of indices to check */ api.indices.prototype.exists = ca({ + params: { + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { + type: 'enum', + 'default': 'open', + options: [ + 'open', + 'closed' + ], + name: 'expand_wildcards' + } + }, url: { fmt: '/<%=index%>', req: { @@ -1529,20 +1601,33 @@ api.indices.prototype.exists = ca({ * 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 {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open,closed] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @param {String, String[], Boolean} params.index - A comma-separated list of index names to filter aliases * @param {String, String[], Boolean} params.name - A comma-separated list of alias names to return */ api.indices.prototype.existsAlias = ca({ params: { - ignoreIndices: { + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { type: 'enum', - 'default': 'none', - options: [ - 'none', - 'missing' + 'default': [ + 'open', + 'closed' ], - name: 'ignore_indices' + options: [ + 'open', + 'closed' + ], + name: 'expand_wildcards' } }, urls: [ @@ -1564,6 +1649,14 @@ api.indices.prototype.existsAlias = ca({ type: 'list' } } + }, + { + fmt: '/<%=index%>/_alias', + req: { + index: { + type: 'list' + } + } } ], castExists: true, @@ -1574,20 +1667,30 @@ api.indices.prototype.existsAlias = ca({ * 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 {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @param {String, String[], Boolean} params.index - A comma-separated list of index names; use `_all` to check the types across all indices * @param {String, String[], Boolean} params.type - A comma-separated list of document types to check */ api.indices.prototype.existsType = ca({ params: { - ignoreIndices: { + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { type: 'enum', - 'default': 'none', + 'default': 'open', options: [ - 'none', - 'missing' + 'open', + 'closed' ], - name: 'ignore_indices' + name: 'expand_wildcards' } }, url: { @@ -1610,9 +1713,11 @@ api.indices.prototype.existsType = ca({ * 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.force - Whether a flush should be forced even if it is not necessarily needed ie. if no changes will be committed to the index. This is useful if transaction log IDs should be incremented even if no uncommitted changes are present. (This setting can be considered as internal) + * @param {Boolean} params.full - If set to true a new index writer is created and settings that have been changed related to the index writer will be refreshed. Note: if a full flush is required for a setting to take effect this will be part of the settings update process and it not required to be executed by the user. (This setting can be considered as internal) + * @param {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @param {Boolean} params.refresh - Refresh the index after performing the operation * @param {String, String[], Boolean} params.index - A comma-separated list of index names; use `_all` or empty string for all indices */ @@ -1624,14 +1729,22 @@ api.indices.prototype.flush = ca({ full: { type: 'boolean' }, - ignoreIndices: { + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { type: 'enum', - 'default': 'none', + 'default': 'open', options: [ - 'none', - 'missing' + 'open', + 'closed' ], - name: 'ignore_indices' + name: 'expand_wildcards' }, refresh: { type: 'boolean' @@ -1657,20 +1770,30 @@ api.indices.prototype.flush = ca({ * 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 {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @param {String, String[], Boolean} params.index - A comma-separated list of index names to filter aliases * @param {String, String[], Boolean} params.name - A comma-separated list of alias names to return */ api.indices.prototype.getAlias = ca({ params: { - ignoreIndices: { + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { type: 'enum', - 'default': 'none', + 'default': 'open', options: [ - 'none', - 'missing' + 'open', + 'closed' ], - name: 'ignore_indices' + name: 'expand_wildcards' } }, urls: [ @@ -1692,6 +1815,14 @@ api.indices.prototype.getAlias = ca({ type: 'list' } } + }, + { + fmt: '/<%=index%>/_alias', + req: { + index: { + type: 'list' + } + } } ] }); @@ -1729,6 +1860,9 @@ api.indices.prototype.getAliases = ca({ * * @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 {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @param {String, String[], Boolean} params.index - A comma-separated list of index names * @param {String, String[], Boolean} params.type - A comma-separated list of document types * @param {String, String[], Boolean} params.field - A comma-separated list of fields @@ -1738,6 +1872,23 @@ api.indices.prototype.getFieldMapping = ca({ includeDefaults: { type: 'boolean', name: 'include_defaults' + }, + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { + type: 'enum', + 'default': 'open', + options: [ + 'open', + 'closed' + ], + name: 'expand_wildcards' } }, urls: [ @@ -1781,10 +1932,32 @@ api.indices.prototype.getFieldMapping = ca({ * 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 {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @param {String, String[], Boolean} params.index - A comma-separated list of index names * @param {String, String[], Boolean} params.type - A comma-separated list of document types */ api.indices.prototype.getMapping = ca({ + params: { + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { + type: 'enum', + 'default': 'open', + options: [ + 'open', + 'closed' + ], + name: 'expand_wildcards' + } + }, urls: [ { fmt: '/<%=index%>/<%=type%>/_mapping', @@ -1859,11 +2032,33 @@ api.indices.prototype.getTemplate = ca({ * 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 {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @param {String, String[], 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, String[], 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({ + params: { + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { + type: 'enum', + 'default': 'open', + options: [ + 'open', + 'closed' + ], + name: 'expand_wildcards' + } + }, urls: [ { fmt: '/<%=index%>/<%=type%>/_warmer/<%=name%>', @@ -1907,6 +2102,9 @@ api.indices.prototype.getWarmer = ca({ * @param {Object} params - An object with parameters used to carry out this action * @param {Date, Number} params.timeout - Explicit operation timeout * @param {Date, Number} params.masterTimeout - Specify timeout for connection to master + * @param {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=closed] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @param {String} params.index - The name of the index */ api.indices.prototype.open = ca({ @@ -1917,6 +2115,23 @@ api.indices.prototype.open = ca({ masterTimeout: { type: 'time', name: 'master_timeout' + }, + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { + type: 'enum', + 'default': 'closed', + options: [ + 'open', + 'closed' + ], + name: 'expand_wildcards' } }, url: { @@ -1936,7 +2151,9 @@ api.indices.prototype.open = ca({ * * @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 {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @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 {Anything} params.operationThreading - TODO: ? @@ -1949,14 +2166,22 @@ api.indices.prototype.optimize = ca({ flush: { type: 'boolean' }, - ignoreIndices: { + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { type: 'enum', - 'default': 'none', + 'default': 'open', options: [ - 'none', - 'missing' + 'open', + 'closed' ], - name: 'ignore_indices' + name: 'expand_wildcards' }, maxNumSegments: { type: 'number', @@ -2054,6 +2279,9 @@ api.indices.prototype.putAlias = ca({ * @param {Boolean} params.ignoreConflicts - Specify whether to ignore conflicts while updating the mapping (default: false) * @param {Date, Number} params.timeout - Explicit operation timeout * @param {Date, Number} params.masterTimeout - Specify timeout for connection to master + * @param {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @param {String, String[], 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 */ @@ -2069,6 +2297,23 @@ api.indices.prototype.putMapping = ca({ masterTimeout: { type: 'time', name: 'master_timeout' + }, + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { + type: 'enum', + 'default': 'open', + options: [ + 'open', + 'closed' + ], + name: 'expand_wildcards' } }, url: { @@ -2091,6 +2336,9 @@ api.indices.prototype.putMapping = ca({ * * @param {Object} params - An object with parameters used to carry out this action * @param {Date, Number} params.masterTimeout - Specify timeout for connection to master + * @param {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @param {String, String[], 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({ @@ -2098,6 +2346,23 @@ api.indices.prototype.putSettings = ca({ masterTimeout: { type: 'time', name: 'master_timeout' + }, + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { + type: 'enum', + 'default': 'open', + options: [ + 'open', + 'closed' + ], + name: 'expand_wildcards' } }, urls: [ @@ -2155,6 +2420,9 @@ api.indices.prototype.putTemplate = ca({ * * @param {Object} params - An object with parameters used to carry out this action * @param {Date, Number} params.masterTimeout - Specify timeout for connection to master + * @param {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) in the search request to warm + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices in the search request to warm. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open] - Whether to expand wildcard expression to concrete indices that are open, closed or both, in the search request to warm. * @param {String, String[], 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, String[], Boolean} params.type - A comma-separated list of document types to register the warmer for; leave empty to perform the operation on all types @@ -2164,6 +2432,23 @@ api.indices.prototype.putWarmer = ca({ masterTimeout: { type: 'time', name: 'master_timeout' + }, + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { + type: 'enum', + 'default': 'open', + options: [ + 'open', + 'closed' + ], + name: 'expand_wildcards' } }, urls: [ @@ -2200,20 +2485,30 @@ api.indices.prototype.putWarmer = ca({ * 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 {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @param {Anything} params.operationThreading - TODO: ? * @param {String, String[], 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: { + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { type: 'enum', - 'default': 'none', + 'default': 'open', options: [ - 'none', - 'missing' + 'open', + 'closed' ], - name: 'ignore_indices' + name: 'expand_wildcards' }, operationThreading: { name: 'operation_threading' @@ -2239,20 +2534,30 @@ api.indices.prototype.refresh = ca({ * 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 {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @param {Anything} params.operationThreading - TODO: ? * @param {String, String[], 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: { + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { type: 'enum', - 'default': 'none', + 'default': 'open', options: [ - 'none', - 'missing' + 'open', + 'closed' ], - name: 'ignore_indices' + name: 'expand_wildcards' }, operationThreading: { name: 'operation_threading' @@ -2277,19 +2582,29 @@ api.indices.prototype.segments = ca({ * 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 {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @param {String, String[], 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: { + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { type: 'enum', - 'default': 'none', + 'default': 'open', options: [ - 'none', - 'missing' + 'open', + 'closed' ], - name: 'ignore_indices' + name: 'expand_wildcards' } }, urls: [ @@ -2325,7 +2640,9 @@ api.indices.prototype.snapshotIndex = ca({ * @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.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @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 @@ -2382,14 +2699,22 @@ api.indices.prototype.stats = ca({ type: 'boolean', name: 'id_cache' }, - ignoreIndices: { + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { type: 'enum', - 'default': 'none', + 'default': 'open', options: [ - 'none', - 'missing' + 'open', + 'closed' ], - name: 'ignore_indices' + name: 'expand_wildcards' }, indexing: { type: 'boolean' @@ -2429,7 +2754,9 @@ api.indices.prototype.stats = ca({ * 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 {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @param {Anything} params.operationThreading - TODO: ? * @param {Boolean} params.recovery - Return information about shard recovery * @param {Boolean} params.snapshot - TODO: ? @@ -2437,14 +2764,22 @@ api.indices.prototype.stats = ca({ */ api.indices.prototype.status = ca({ params: { - ignoreIndices: { + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { type: 'enum', - 'default': 'none', + 'default': 'open', options: [ - 'none', - 'missing' + 'open', + 'closed' ], - name: 'ignore_indices' + name: 'expand_wildcards' }, operationThreading: { name: 'operation_threading' @@ -2500,7 +2835,9 @@ api.indices.prototype.updateAliases = ca({ * * @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 {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @param {Anything} 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 @@ -2512,14 +2849,22 @@ api.indices.prototype.validateQuery = ca({ explain: { type: 'boolean' }, - ignoreIndices: { + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { type: 'enum', - 'default': 'none', + 'default': 'open', options: [ - 'none', - 'missing' + 'open', + 'closed' ], - name: 'ignore_indices' + name: 'expand_wildcards' }, operationThreading: { name: 'operation_threading' @@ -2884,7 +3229,9 @@ api.scroll = ca({ * @param {Boolean} params.explain - Specify whether to return detailed information about score computation as part of a hit * @param {String, String[], 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 {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @param {String, String[], 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 @@ -2939,14 +3286,22 @@ api.search = ca({ from: { type: 'number' }, - ignoreIndices: { + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { type: 'enum', - 'default': 'none', + 'default': 'open', options: [ - 'none', - 'missing' + 'open', + 'closed' ], - name: 'ignore_indices' + name: 'expand_wildcards' }, indicesBoost: { type: 'list', @@ -3067,7 +3422,9 @@ api.search = ca({ * 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 {Boolean} params.ignoreUnavailable - Whether specified concrete indices should be ignored when unavailable (missing or closed) + * @param {Boolean} params.allowNoIndices - Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified) + * @param {String} [params.expandWildcards=open] - Whether to expand wildcard expression to concrete indices that are open, closed or both. * @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) @@ -3075,14 +3432,22 @@ api.search = ca({ */ api.suggest = ca({ params: { - ignoreIndices: { + ignoreUnavailable: { + type: 'boolean', + name: 'ignore_unavailable' + }, + allowNoIndices: { + type: 'boolean', + name: 'allow_no_indices' + }, + expandWildcards: { type: 'enum', - 'default': 'none', + 'default': 'open', options: [ - 'none', - 'missing' + 'open', + 'closed' ], - name: 'ignore_indices' + name: 'expand_wildcards' }, preference: { type: 'string' diff --git a/src/rest-api-spec b/src/rest-api-spec deleted file mode 160000 index b3ab72486..000000000 --- a/src/rest-api-spec +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b3ab72486fae1b5c5a5397356a3e113bf72eb6d5 diff --git a/test/integration/yaml_suite/client_manager.js b/test/integration/yaml_suite/client_manager.js index d60ff7c56..b30188ad0 100644 --- a/test/integration/yaml_suite/client_manager.js +++ b/test/integration/yaml_suite/client_manager.js @@ -24,41 +24,51 @@ var esServer = null; module.exports = { create: function create(cb) { - if (argv.createServer || externalExists === false) { - if (!esServer) { - server.start(function (err, _server) { - esServer = _server; - if (err) { - done(err); - } else { - doCreateClient(done); - } - }); - } else { - doCreateClient(done); - } - } else if (externalExists === void 0) { - doCreateClient(function () { + // create a client and ping the server for up to 15 seconds + doCreateClient({ + logConfig: null + }, function () { + var attemptsRemaining = 30; + var timeout = 500; + + (function ping() { client.ping({ - requestTimeout: 1000 + maxRetries: 0, + requestTimeout: 100 }, function (err) { - if (err instanceof es.errors.ConnectionFault) { - externalExists = false; - create(done); + if (err && --attemptsRemaining) { + setTimeout(ping, timeout); + } else if (err) { + cb(new Error('unable to establish contact with ES')); } else { - done(err); + // create a new client + doCreateClient(function () { + cb(void 0, client); + }); } }); - }); - } else { - doCreateClient(done); - } + }()); + }); - function done(err) { - cb(err, client); - } + function doCreateClient(options, cb) { + if (typeof options === 'function') { + cb = options, options = {}; + } + + var logConfig = _.has(options, 'logConfig') + ? options.logConfig + : { + type: BROWSER + ? 'console' + : VERBOSE + ? 'tracer' + : 'stdio', + level: VERBOSE + ? 'trace' + : 'warning', + path: VERBOSE ? undefined : false + }; - function doCreateClient(cb) { // close existing client if (client) { client.close(); @@ -71,17 +81,7 @@ module.exports = { port: esServer ? esServer.__port : argv.port } ], - log: { - type: BROWSER - ? 'console' - : VERBOSE - ? 'tracer' - : 'stdio', - level: VERBOSE - ? 'trace' - : 'warning', - path: VERBOSE ? undefined : false - } + log: logConfig }); _.nextTick(cb); diff --git a/test/unit_tests.html b/test/unit_tests.html new file mode 100644 index 000000000..3b4cc1547 --- /dev/null +++ b/test/unit_tests.html @@ -0,0 +1,22 @@ + + + + Mocha Tests + + + +
+ + + + + + + + + + \ No newline at end of file diff --git a/test/utils/mocha.js b/test/utils/mocha.js new file mode 100644 index 000000000..9b7c1fa56 --- /dev/null +++ b/test/utils/mocha.js @@ -0,0 +1,5598 @@ +;(function(){ + +// CommonJS require() + +function require(p){ + var path = require.resolve(p) + , mod = require.modules[path]; + if (!mod) throw new Error('failed to require "' + p + '"'); + if (!mod.exports) { + mod.exports = {}; + mod.call(mod.exports, mod, mod.exports, require.relative(path)); + } + return mod.exports; + } + +require.modules = {}; + +require.resolve = function (path){ + var orig = path + , reg = path + '.js' + , index = path + '/index.js'; + return require.modules[reg] && reg + || require.modules[index] && index + || orig; + }; + +require.register = function (path, fn){ + require.modules[path] = fn; + }; + +require.relative = function (parent) { + return function(p){ + if ('.' != p.charAt(0)) return require(p); + + var path = parent.split('/') + , segs = p.split('/'); + path.pop(); + + for (var i = 0; i < segs.length; i++) { + var seg = segs[i]; + if ('..' == seg) path.pop(); + else if ('.' != seg) path.push(seg); + } + + return require(path.join('/')); + }; + }; + + +require.register("browser/debug.js", function(module, exports, require){ + +module.exports = function(type){ + return function(){ + } +}; + +}); // module: browser/debug.js + +require.register("browser/diff.js", function(module, exports, require){ +/* See LICENSE file for terms of use */ + +/* + * Text diff implementation. + * + * This library supports the following APIS: + * JsDiff.diffChars: Character by character diff + * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace + * JsDiff.diffLines: Line based diff + * + * JsDiff.diffCss: Diff targeted at CSS content + * + * These methods are based on the implementation proposed in + * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986). + * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927 + */ +var JsDiff = (function() { + /*jshint maxparams: 5*/ + function clonePath(path) { + return { newPos: path.newPos, components: path.components.slice(0) }; + } + function removeEmpty(array) { + var ret = []; + for (var i = 0; i < array.length; i++) { + if (array[i]) { + ret.push(array[i]); + } + } + return ret; + } + function escapeHTML(s) { + var n = s; + n = n.replace(/&/g, '&'); + n = n.replace(//g, '>'); + n = n.replace(/"/g, '"'); + + return n; + } + + var Diff = function(ignoreWhitespace) { + this.ignoreWhitespace = ignoreWhitespace; + }; + Diff.prototype = { + diff: function(oldString, newString) { + // Handle the identity case (this is due to unrolling editLength == 0 + if (newString === oldString) { + return [{ value: newString }]; + } + if (!newString) { + return [{ value: oldString, removed: true }]; + } + if (!oldString) { + return [{ value: newString, added: true }]; + } + + newString = this.tokenize(newString); + oldString = this.tokenize(oldString); + + var newLen = newString.length, oldLen = oldString.length; + var maxEditLength = newLen + oldLen; + var bestPath = [{ newPos: -1, components: [] }]; + + // Seed editLength = 0 + var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0); + if (bestPath[0].newPos+1 >= newLen && oldPos+1 >= oldLen) { + return bestPath[0].components; + } + + for (var editLength = 1; editLength <= maxEditLength; editLength++) { + for (var diagonalPath = -1*editLength; diagonalPath <= editLength; diagonalPath+=2) { + var basePath; + var addPath = bestPath[diagonalPath-1], + removePath = bestPath[diagonalPath+1]; + oldPos = (removePath ? removePath.newPos : 0) - diagonalPath; + if (addPath) { + // No one else is going to attempt to use this value, clear it + bestPath[diagonalPath-1] = undefined; + } + + var canAdd = addPath && addPath.newPos+1 < newLen; + var canRemove = removePath && 0 <= oldPos && oldPos < oldLen; + if (!canAdd && !canRemove) { + bestPath[diagonalPath] = undefined; + continue; + } + + // Select the diagonal that we want to branch from. We select the prior + // path whose position in the new string is the farthest from the origin + // and does not pass the bounds of the diff graph + if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) { + basePath = clonePath(removePath); + this.pushComponent(basePath.components, oldString[oldPos], undefined, true); + } else { + basePath = clonePath(addPath); + basePath.newPos++; + this.pushComponent(basePath.components, newString[basePath.newPos], true, undefined); + } + + var oldPos = this.extractCommon(basePath, newString, oldString, diagonalPath); + + if (basePath.newPos+1 >= newLen && oldPos+1 >= oldLen) { + return basePath.components; + } else { + bestPath[diagonalPath] = basePath; + } + } + } + }, + + pushComponent: function(components, value, added, removed) { + var last = components[components.length-1]; + if (last && last.added === added && last.removed === removed) { + // We need to clone here as the component clone operation is just + // as shallow array clone + components[components.length-1] = + {value: this.join(last.value, value), added: added, removed: removed }; + } else { + components.push({value: value, added: added, removed: removed }); + } + }, + extractCommon: function(basePath, newString, oldString, diagonalPath) { + var newLen = newString.length, + oldLen = oldString.length, + newPos = basePath.newPos, + oldPos = newPos - diagonalPath; + while (newPos+1 < newLen && oldPos+1 < oldLen && this.equals(newString[newPos+1], oldString[oldPos+1])) { + newPos++; + oldPos++; + + this.pushComponent(basePath.components, newString[newPos], undefined, undefined); + } + basePath.newPos = newPos; + return oldPos; + }, + + equals: function(left, right) { + var reWhitespace = /\S/; + if (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)) { + return true; + } else { + return left === right; + } + }, + join: function(left, right) { + return left + right; + }, + tokenize: function(value) { + return value; + } + }; + + var CharDiff = new Diff(); + + var WordDiff = new Diff(true); + var WordWithSpaceDiff = new Diff(); + WordDiff.tokenize = WordWithSpaceDiff.tokenize = function(value) { + return removeEmpty(value.split(/(\s+|\b)/)); + }; + + var CssDiff = new Diff(true); + CssDiff.tokenize = function(value) { + return removeEmpty(value.split(/([{}:;,]|\s+)/)); + }; + + var LineDiff = new Diff(); + LineDiff.tokenize = function(value) { + return value.split(/^/m); + }; + + return { + Diff: Diff, + + diffChars: function(oldStr, newStr) { return CharDiff.diff(oldStr, newStr); }, + diffWords: function(oldStr, newStr) { return WordDiff.diff(oldStr, newStr); }, + diffWordsWithSpace: function(oldStr, newStr) { return WordWithSpaceDiff.diff(oldStr, newStr); }, + diffLines: function(oldStr, newStr) { return LineDiff.diff(oldStr, newStr); }, + + diffCss: function(oldStr, newStr) { return CssDiff.diff(oldStr, newStr); }, + + createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) { + var ret = []; + + ret.push('Index: ' + fileName); + ret.push('==================================================================='); + ret.push('--- ' + fileName + (typeof oldHeader === 'undefined' ? '' : '\t' + oldHeader)); + ret.push('+++ ' + fileName + (typeof newHeader === 'undefined' ? '' : '\t' + newHeader)); + + var diff = LineDiff.diff(oldStr, newStr); + if (!diff[diff.length-1].value) { + diff.pop(); // Remove trailing newline add + } + diff.push({value: '', lines: []}); // Append an empty value to make cleanup easier + + function contextLines(lines) { + return lines.map(function(entry) { return ' ' + entry; }); + } + function eofNL(curRange, i, current) { + var last = diff[diff.length-2], + isLast = i === diff.length-2, + isLastOfType = i === diff.length-3 && (current.added !== last.added || current.removed !== last.removed); + + // Figure out if this is the last line for the given file and missing NL + if (!/\n$/.test(current.value) && (isLast || isLastOfType)) { + curRange.push('\\ No newline at end of file'); + } + } + + var oldRangeStart = 0, newRangeStart = 0, curRange = [], + oldLine = 1, newLine = 1; + for (var i = 0; i < diff.length; i++) { + var current = diff[i], + lines = current.lines || current.value.replace(/\n$/, '').split('\n'); + current.lines = lines; + + if (current.added || current.removed) { + if (!oldRangeStart) { + var prev = diff[i-1]; + oldRangeStart = oldLine; + newRangeStart = newLine; + + if (prev) { + curRange = contextLines(prev.lines.slice(-4)); + oldRangeStart -= curRange.length; + newRangeStart -= curRange.length; + } + } + curRange.push.apply(curRange, lines.map(function(entry) { return (current.added?'+':'-') + entry; })); + eofNL(curRange, i, current); + + if (current.added) { + newLine += lines.length; + } else { + oldLine += lines.length; + } + } else { + if (oldRangeStart) { + // Close out any changes that have been output (or join overlapping) + if (lines.length <= 8 && i < diff.length-2) { + // Overlapping + curRange.push.apply(curRange, contextLines(lines)); + } else { + // end the range and output + var contextSize = Math.min(lines.length, 4); + ret.push( + '@@ -' + oldRangeStart + ',' + (oldLine-oldRangeStart+contextSize) + + ' +' + newRangeStart + ',' + (newLine-newRangeStart+contextSize) + + ' @@'); + ret.push.apply(ret, curRange); + ret.push.apply(ret, contextLines(lines.slice(0, contextSize))); + if (lines.length <= 4) { + eofNL(ret, i, current); + } + + oldRangeStart = 0; newRangeStart = 0; curRange = []; + } + } + oldLine += lines.length; + newLine += lines.length; + } + } + + return ret.join('\n') + '\n'; + }, + + applyPatch: function(oldStr, uniDiff) { + var diffstr = uniDiff.split('\n'); + var diff = []; + var remEOFNL = false, + addEOFNL = false; + + for (var i = (diffstr[0][0]==='I'?4:0); i < diffstr.length; i++) { + if(diffstr[i][0] === '@') { + var meh = diffstr[i].split(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/); + diff.unshift({ + start:meh[3], + oldlength:meh[2], + oldlines:[], + newlength:meh[4], + newlines:[] + }); + } else if(diffstr[i][0] === '+') { + diff[0].newlines.push(diffstr[i].substr(1)); + } else if(diffstr[i][0] === '-') { + diff[0].oldlines.push(diffstr[i].substr(1)); + } else if(diffstr[i][0] === ' ') { + diff[0].newlines.push(diffstr[i].substr(1)); + diff[0].oldlines.push(diffstr[i].substr(1)); + } else if(diffstr[i][0] === '\\') { + if (diffstr[i-1][0] === '+') { + remEOFNL = true; + } else if(diffstr[i-1][0] === '-') { + addEOFNL = true; + } + } + } + + var str = oldStr.split('\n'); + for (var i = diff.length - 1; i >= 0; i--) { + var d = diff[i]; + for (var j = 0; j < d.oldlength; j++) { + if(str[d.start-1+j] !== d.oldlines[j]) { + return false; + } + } + Array.prototype.splice.apply(str,[d.start-1,+d.oldlength].concat(d.newlines)); + } + + if (remEOFNL) { + while (!str[str.length-1]) { + str.pop(); + } + } else if (addEOFNL) { + str.push(''); + } + return str.join('\n'); + }, + + convertChangesToXML: function(changes){ + var ret = []; + for ( var i = 0; i < changes.length; i++) { + var change = changes[i]; + if (change.added) { + ret.push(''); + } else if (change.removed) { + ret.push(''); + } + + ret.push(escapeHTML(change.value)); + + if (change.added) { + ret.push(''); + } else if (change.removed) { + ret.push(''); + } + } + return ret.join(''); + }, + + // See: http://code.google.com/p/google-diff-match-patch/wiki/API + convertChangesToDMP: function(changes){ + var ret = [], change; + for ( var i = 0; i < changes.length; i++) { + change = changes[i]; + ret.push([(change.added ? 1 : change.removed ? -1 : 0), change.value]); + } + return ret; + } + }; +})(); + +if (typeof module !== 'undefined') { + module.exports = JsDiff; +} + +}); // module: browser/diff.js + +require.register("browser/events.js", function(module, exports, require){ + +/** + * Module exports. + */ + +exports.EventEmitter = EventEmitter; + +/** + * Check if `obj` is an array. + */ + +function isArray(obj) { + return '[object Array]' == {}.toString.call(obj); +} + +/** + * Event emitter constructor. + * + * @api public + */ + +function EventEmitter(){}; + +/** + * Adds a listener. + * + * @api public + */ + +EventEmitter.prototype.on = function (name, fn) { + if (!this.$events) { + this.$events = {}; + } + + if (!this.$events[name]) { + this.$events[name] = fn; + } else if (isArray(this.$events[name])) { + this.$events[name].push(fn); + } else { + this.$events[name] = [this.$events[name], fn]; + } + + return this; +}; + +EventEmitter.prototype.addListener = EventEmitter.prototype.on; + +/** + * Adds a volatile listener. + * + * @api public + */ + +EventEmitter.prototype.once = function (name, fn) { + var self = this; + + function on () { + self.removeListener(name, on); + fn.apply(this, arguments); + }; + + on.listener = fn; + this.on(name, on); + + return this; +}; + +/** + * Removes a listener. + * + * @api public + */ + +EventEmitter.prototype.removeListener = function (name, fn) { + if (this.$events && this.$events[name]) { + var list = this.$events[name]; + + if (isArray(list)) { + var pos = -1; + + for (var i = 0, l = list.length; i < l; i++) { + if (list[i] === fn || (list[i].listener && list[i].listener === fn)) { + pos = i; + break; + } + } + + if (pos < 0) { + return this; + } + + list.splice(pos, 1); + + if (!list.length) { + delete this.$events[name]; + } + } else if (list === fn || (list.listener && list.listener === fn)) { + delete this.$events[name]; + } + } + + return this; +}; + +/** + * Removes all listeners for an event. + * + * @api public + */ + +EventEmitter.prototype.removeAllListeners = function (name) { + if (name === undefined) { + this.$events = {}; + return this; + } + + if (this.$events && this.$events[name]) { + this.$events[name] = null; + } + + return this; +}; + +/** + * Gets all listeners for a certain event. + * + * @api public + */ + +EventEmitter.prototype.listeners = function (name) { + if (!this.$events) { + this.$events = {}; + } + + if (!this.$events[name]) { + this.$events[name] = []; + } + + if (!isArray(this.$events[name])) { + this.$events[name] = [this.$events[name]]; + } + + return this.$events[name]; +}; + +/** + * Emits an event. + * + * @api public + */ + +EventEmitter.prototype.emit = function (name) { + if (!this.$events) { + return false; + } + + var handler = this.$events[name]; + + if (!handler) { + return false; + } + + var args = [].slice.call(arguments, 1); + + if ('function' == typeof handler) { + handler.apply(this, args); + } else if (isArray(handler)) { + var listeners = handler.slice(); + + for (var i = 0, l = listeners.length; i < l; i++) { + listeners[i].apply(this, args); + } + } else { + return false; + } + + return true; +}; +}); // module: browser/events.js + +require.register("browser/fs.js", function(module, exports, require){ + +}); // module: browser/fs.js + +require.register("browser/path.js", function(module, exports, require){ + +}); // module: browser/path.js + +require.register("browser/progress.js", function(module, exports, require){ + +/** + * Expose `Progress`. + */ + +module.exports = Progress; + +/** + * Initialize a new `Progress` indicator. + */ + +function Progress() { + this.percent = 0; + this.size(0); + this.fontSize(11); + this.font('helvetica, arial, sans-serif'); +} + +/** + * Set progress size to `n`. + * + * @param {Number} n + * @return {Progress} for chaining + * @api public + */ + +Progress.prototype.size = function(n){ + this._size = n; + return this; +}; + +/** + * Set text to `str`. + * + * @param {String} str + * @return {Progress} for chaining + * @api public + */ + +Progress.prototype.text = function(str){ + this._text = str; + return this; +}; + +/** + * Set font size to `n`. + * + * @param {Number} n + * @return {Progress} for chaining + * @api public + */ + +Progress.prototype.fontSize = function(n){ + this._fontSize = n; + return this; +}; + +/** + * Set font `family`. + * + * @param {String} family + * @return {Progress} for chaining + */ + +Progress.prototype.font = function(family){ + this._font = family; + return this; +}; + +/** + * Update percentage to `n`. + * + * @param {Number} n + * @return {Progress} for chaining + */ + +Progress.prototype.update = function(n){ + this.percent = n; + return this; +}; + +/** + * Draw on `ctx`. + * + * @param {CanvasRenderingContext2d} ctx + * @return {Progress} for chaining + */ + +Progress.prototype.draw = function(ctx){ + var percent = Math.min(this.percent, 100) + , size = this._size + , half = size / 2 + , x = half + , y = half + , rad = half - 1 + , fontSize = this._fontSize; + + ctx.font = fontSize + 'px ' + this._font; + + var angle = Math.PI * 2 * (percent / 100); + ctx.clearRect(0, 0, size, size); + + // outer circle + ctx.strokeStyle = '#9f9f9f'; + ctx.beginPath(); + ctx.arc(x, y, rad, 0, angle, false); + ctx.stroke(); + + // inner circle + ctx.strokeStyle = '#eee'; + ctx.beginPath(); + ctx.arc(x, y, rad - 1, 0, angle, true); + ctx.stroke(); + + // text + var text = this._text || (percent | 0) + '%' + , w = ctx.measureText(text).width; + + ctx.fillText( + text + , x - w / 2 + 1 + , y + fontSize / 2 - 1); + + return this; +}; + +}); // module: browser/progress.js + +require.register("browser/tty.js", function(module, exports, require){ + +exports.isatty = function(){ + return true; +}; + +exports.getWindowSize = function(){ + if ('innerHeight' in global) { + return [global.innerHeight, global.innerWidth]; + } else { + // In a Web Worker, the DOM Window is not available. + return [640, 480]; + } +}; + +}); // module: browser/tty.js + +require.register("context.js", function(module, exports, require){ + +/** + * Expose `Context`. + */ + +module.exports = Context; + +/** + * Initialize a new `Context`. + * + * @api private + */ + +function Context(){} + +/** + * Set or get the context `Runnable` to `runnable`. + * + * @param {Runnable} runnable + * @return {Context} + * @api private + */ + +Context.prototype.runnable = function(runnable){ + if (0 == arguments.length) return this._runnable; + this.test = this._runnable = runnable; + return this; +}; + +/** + * Set test timeout `ms`. + * + * @param {Number} ms + * @return {Context} self + * @api private + */ + +Context.prototype.timeout = function(ms){ + this.runnable().timeout(ms); + return this; +}; + +/** + * Set test slowness threshold `ms`. + * + * @param {Number} ms + * @return {Context} self + * @api private + */ + +Context.prototype.slow = function(ms){ + this.runnable().slow(ms); + return this; +}; + +/** + * Inspect the context void of `._runnable`. + * + * @return {String} + * @api private + */ + +Context.prototype.inspect = function(){ + return JSON.stringify(this, function(key, val){ + if ('_runnable' == key) return; + if ('test' == key) return; + return val; + }, 2); +}; + +}); // module: context.js + +require.register("hook.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Runnable = require('./runnable'); + +/** + * Expose `Hook`. + */ + +module.exports = Hook; + +/** + * Initialize a new `Hook` with the given `title` and callback `fn`. + * + * @param {String} title + * @param {Function} fn + * @api private + */ + +function Hook(title, fn) { + Runnable.call(this, title, fn); + this.type = 'hook'; +} + +/** + * Inherit from `Runnable.prototype`. + */ + +function F(){}; +F.prototype = Runnable.prototype; +Hook.prototype = new F; +Hook.prototype.constructor = Hook; + + +/** + * Get or set the test `err`. + * + * @param {Error} err + * @return {Error} + * @api public + */ + +Hook.prototype.error = function(err){ + if (0 == arguments.length) { + var err = this._error; + this._error = null; + return err; + } + + this._error = err; +}; + +}); // module: hook.js + +require.register("interfaces/bdd.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test') + , utils = require('../utils'); + +/** + * BDD-style interface: + * + * describe('Array', function(){ + * describe('#indexOf()', function(){ + * it('should return -1 when not present', function(){ + * + * }); + * + * it('should return the index when present', function(){ + * + * }); + * }); + * }); + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('pre-require', function(context, file, mocha){ + + /** + * Execute before running tests. + */ + + context.before = function(fn){ + suites[0].beforeAll(fn); + }; + + /** + * Execute after running tests. + */ + + context.after = function(fn){ + suites[0].afterAll(fn); + }; + + /** + * Execute before each test case. + */ + + context.beforeEach = function(fn){ + suites[0].beforeEach(fn); + }; + + /** + * Execute after each test case. + */ + + context.afterEach = function(fn){ + suites[0].afterEach(fn); + }; + + /** + * Describe a "suite" with the given `title` + * and callback `fn` containing nested suites + * and/or tests. + */ + + context.describe = context.context = function(title, fn){ + var suite = Suite.create(suites[0], title); + suites.unshift(suite); + fn.call(suite); + suites.shift(); + return suite; + }; + + /** + * Pending describe. + */ + + context.xdescribe = + context.xcontext = + context.describe.skip = function(title, fn){ + var suite = Suite.create(suites[0], title); + suite.pending = true; + suites.unshift(suite); + fn.call(suite); + suites.shift(); + }; + + /** + * Exclusive suite. + */ + + context.describe.only = function(title, fn){ + var suite = context.describe(title, fn); + mocha.grep(suite.fullTitle()); + return suite; + }; + + /** + * Describe a specification or test-case + * with the given `title` and callback `fn` + * acting as a thunk. + */ + + context.it = context.specify = function(title, fn){ + var suite = suites[0]; + if (suite.pending) var fn = null; + var test = new Test(title, fn); + suite.addTest(test); + return test; + }; + + /** + * Exclusive test-case. + */ + + context.it.only = function(title, fn){ + var test = context.it(title, fn); + var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$'; + mocha.grep(new RegExp(reString)); + return test; + }; + + /** + * Pending test case. + */ + + context.xit = + context.xspecify = + context.it.skip = function(title){ + context.it(title); + }; + }); +}; + +}); // module: interfaces/bdd.js + +require.register("interfaces/exports.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test'); + +/** + * TDD-style interface: + * + * exports.Array = { + * '#indexOf()': { + * 'should return -1 when the value is not present': function(){ + * + * }, + * + * 'should return the correct index when the value is present': function(){ + * + * } + * } + * }; + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('require', visit); + + function visit(obj) { + var suite; + for (var key in obj) { + if ('function' == typeof obj[key]) { + var fn = obj[key]; + switch (key) { + case 'before': + suites[0].beforeAll(fn); + break; + case 'after': + suites[0].afterAll(fn); + break; + case 'beforeEach': + suites[0].beforeEach(fn); + break; + case 'afterEach': + suites[0].afterEach(fn); + break; + default: + suites[0].addTest(new Test(key, fn)); + } + } else { + var suite = Suite.create(suites[0], key); + suites.unshift(suite); + visit(obj[key]); + suites.shift(); + } + } + } +}; + +}); // module: interfaces/exports.js + +require.register("interfaces/index.js", function(module, exports, require){ + +exports.bdd = require('./bdd'); +exports.tdd = require('./tdd'); +exports.qunit = require('./qunit'); +exports.exports = require('./exports'); + +}); // module: interfaces/index.js + +require.register("interfaces/qunit.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test') + , utils = require('../utils'); + +/** + * QUnit-style interface: + * + * suite('Array'); + * + * test('#length', function(){ + * var arr = [1,2,3]; + * ok(arr.length == 3); + * }); + * + * test('#indexOf()', function(){ + * var arr = [1,2,3]; + * ok(arr.indexOf(1) == 0); + * ok(arr.indexOf(2) == 1); + * ok(arr.indexOf(3) == 2); + * }); + * + * suite('String'); + * + * test('#length', function(){ + * ok('foo'.length == 3); + * }); + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('pre-require', function(context, file, mocha){ + + /** + * Execute before running tests. + */ + + context.before = function(fn){ + suites[0].beforeAll(fn); + }; + + /** + * Execute after running tests. + */ + + context.after = function(fn){ + suites[0].afterAll(fn); + }; + + /** + * Execute before each test case. + */ + + context.beforeEach = function(fn){ + suites[0].beforeEach(fn); + }; + + /** + * Execute after each test case. + */ + + context.afterEach = function(fn){ + suites[0].afterEach(fn); + }; + + /** + * Describe a "suite" with the given `title`. + */ + + context.suite = function(title){ + if (suites.length > 1) suites.shift(); + var suite = Suite.create(suites[0], title); + suites.unshift(suite); + return suite; + }; + + /** + * Exclusive test-case. + */ + + context.suite.only = function(title, fn){ + var suite = context.suite(title, fn); + mocha.grep(suite.fullTitle()); + }; + + /** + * Describe a specification or test-case + * with the given `title` and callback `fn` + * acting as a thunk. + */ + + context.test = function(title, fn){ + var test = new Test(title, fn); + suites[0].addTest(test); + return test; + }; + + /** + * Exclusive test-case. + */ + + context.test.only = function(title, fn){ + var test = context.test(title, fn); + var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$'; + mocha.grep(new RegExp(reString)); + }; + + /** + * Pending test case. + */ + + context.test.skip = function(title){ + context.test(title); + }; + }); +}; + +}); // module: interfaces/qunit.js + +require.register("interfaces/tdd.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test') + , utils = require('../utils');; + +/** + * TDD-style interface: + * + * suite('Array', function(){ + * suite('#indexOf()', function(){ + * suiteSetup(function(){ + * + * }); + * + * test('should return -1 when not present', function(){ + * + * }); + * + * test('should return the index when present', function(){ + * + * }); + * + * suiteTeardown(function(){ + * + * }); + * }); + * }); + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('pre-require', function(context, file, mocha){ + + /** + * Execute before each test case. + */ + + context.setup = function(fn){ + suites[0].beforeEach(fn); + }; + + /** + * Execute after each test case. + */ + + context.teardown = function(fn){ + suites[0].afterEach(fn); + }; + + /** + * Execute before the suite. + */ + + context.suiteSetup = function(fn){ + suites[0].beforeAll(fn); + }; + + /** + * Execute after the suite. + */ + + context.suiteTeardown = function(fn){ + suites[0].afterAll(fn); + }; + + /** + * Describe a "suite" with the given `title` + * and callback `fn` containing nested suites + * and/or tests. + */ + + context.suite = function(title, fn){ + var suite = Suite.create(suites[0], title); + suites.unshift(suite); + fn.call(suite); + suites.shift(); + return suite; + }; + + /** + * Pending suite. + */ + context.suite.skip = function(title, fn) { + var suite = Suite.create(suites[0], title); + suite.pending = true; + suites.unshift(suite); + fn.call(suite); + suites.shift(); + }; + + /** + * Exclusive test-case. + */ + + context.suite.only = function(title, fn){ + var suite = context.suite(title, fn); + mocha.grep(suite.fullTitle()); + }; + + /** + * Describe a specification or test-case + * with the given `title` and callback `fn` + * acting as a thunk. + */ + + context.test = function(title, fn){ + var suite = suites[0]; + if (suite.pending) var fn = null; + var test = new Test(title, fn); + suite.addTest(test); + return test; + }; + + /** + * Exclusive test-case. + */ + + context.test.only = function(title, fn){ + var test = context.test(title, fn); + var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$'; + mocha.grep(new RegExp(reString)); + }; + + /** + * Pending test case. + */ + + context.test.skip = function(title){ + context.test(title); + }; + }); +}; + +}); // module: interfaces/tdd.js + +require.register("mocha.js", function(module, exports, require){ +/*! + * mocha + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var path = require('browser/path') + , utils = require('./utils'); + +/** + * Expose `Mocha`. + */ + +exports = module.exports = Mocha; + +/** + * Expose internals. + */ + +exports.utils = utils; +exports.interfaces = require('./interfaces'); +exports.reporters = require('./reporters'); +exports.Runnable = require('./runnable'); +exports.Context = require('./context'); +exports.Runner = require('./runner'); +exports.Suite = require('./suite'); +exports.Hook = require('./hook'); +exports.Test = require('./test'); + +/** + * Return image `name` path. + * + * @param {String} name + * @return {String} + * @api private + */ + +function image(name) { + return __dirname + '/../images/' + name + '.png'; +} + +/** + * Setup mocha with `options`. + * + * Options: + * + * - `ui` name "bdd", "tdd", "exports" etc + * - `reporter` reporter instance, defaults to `mocha.reporters.Dot` + * - `globals` array of accepted globals + * - `timeout` timeout in milliseconds + * - `bail` bail on the first test failure + * - `slow` milliseconds to wait before considering a test slow + * - `ignoreLeaks` ignore global leaks + * - `grep` string or regexp to filter tests with + * + * @param {Object} options + * @api public + */ + +function Mocha(options) { + options = options || {}; + this.files = []; + this.options = options; + this.grep(options.grep); + this.suite = new exports.Suite('', new exports.Context); + this.ui(options.ui); + this.bail(options.bail); + this.reporter(options.reporter); + if (null != options.timeout) this.timeout(options.timeout); + this.useColors(options.useColors) + if (options.slow) this.slow(options.slow); +} + +/** + * Enable or disable bailing on the first failure. + * + * @param {Boolean} [bail] + * @api public + */ + +Mocha.prototype.bail = function(bail){ + if (0 == arguments.length) bail = true; + this.suite.bail(bail); + return this; +}; + +/** + * Add test `file`. + * + * @param {String} file + * @api public + */ + +Mocha.prototype.addFile = function(file){ + this.files.push(file); + return this; +}; + +/** + * Set reporter to `reporter`, defaults to "dot". + * + * @param {String|Function} reporter name or constructor + * @api public + */ + +Mocha.prototype.reporter = function(reporter){ + if ('function' == typeof reporter) { + this._reporter = reporter; + } else { + reporter = reporter || 'dot'; + var _reporter; + try { _reporter = require('./reporters/' + reporter); } catch (err) {}; + if (!_reporter) try { _reporter = require(reporter); } catch (err) {}; + if (!_reporter && reporter === 'teamcity') + console.warn('The Teamcity reporter was moved to a package named ' + + 'mocha-teamcity-reporter ' + + '(https://npmjs.org/package/mocha-teamcity-reporter).'); + if (!_reporter) throw new Error('invalid reporter "' + reporter + '"'); + this._reporter = _reporter; + } + return this; +}; + +/** + * Set test UI `name`, defaults to "bdd". + * + * @param {String} bdd + * @api public + */ + +Mocha.prototype.ui = function(name){ + name = name || 'bdd'; + this._ui = exports.interfaces[name]; + if (!this._ui) try { this._ui = require(name); } catch (err) {}; + if (!this._ui) throw new Error('invalid interface "' + name + '"'); + this._ui = this._ui(this.suite); + return this; +}; + +/** + * Load registered files. + * + * @api private + */ + +Mocha.prototype.loadFiles = function(fn){ + var self = this; + var suite = this.suite; + var pending = this.files.length; + this.files.forEach(function(file){ + file = path.resolve(file); + suite.emit('pre-require', global, file, self); + suite.emit('require', require(file), file, self); + suite.emit('post-require', global, file, self); + --pending || (fn && fn()); + }); +}; + +/** + * Enable growl support. + * + * @api private + */ + +Mocha.prototype._growl = function(runner, reporter) { + var notify = require('growl'); + + runner.on('end', function(){ + var stats = reporter.stats; + if (stats.failures) { + var msg = stats.failures + ' of ' + runner.total + ' tests failed'; + notify(msg, { name: 'mocha', title: 'Failed', image: image('error') }); + } else { + notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', { + name: 'mocha' + , title: 'Passed' + , image: image('ok') + }); + } + }); +}; + +/** + * Add regexp to grep, if `re` is a string it is escaped. + * + * @param {RegExp|String} re + * @return {Mocha} + * @api public + */ + +Mocha.prototype.grep = function(re){ + this.options.grep = 'string' == typeof re + ? new RegExp(utils.escapeRegexp(re)) + : re; + return this; +}; + +/** + * Invert `.grep()` matches. + * + * @return {Mocha} + * @api public + */ + +Mocha.prototype.invert = function(){ + this.options.invert = true; + return this; +}; + +/** + * Ignore global leaks. + * + * @param {Boolean} ignore + * @return {Mocha} + * @api public + */ + +Mocha.prototype.ignoreLeaks = function(ignore){ + this.options.ignoreLeaks = !!ignore; + return this; +}; + +/** + * Enable global leak checking. + * + * @return {Mocha} + * @api public + */ + +Mocha.prototype.checkLeaks = function(){ + this.options.ignoreLeaks = false; + return this; +}; + +/** + * Enable growl support. + * + * @return {Mocha} + * @api public + */ + +Mocha.prototype.growl = function(){ + this.options.growl = true; + return this; +}; + +/** + * Ignore `globals` array or string. + * + * @param {Array|String} globals + * @return {Mocha} + * @api public + */ + +Mocha.prototype.globals = function(globals){ + this.options.globals = (this.options.globals || []).concat(globals); + return this; +}; + +/** + * Emit color output. + * + * @param {Boolean} colors + * @return {Mocha} + * @api public + */ + +Mocha.prototype.useColors = function(colors){ + this.options.useColors = arguments.length && colors != undefined + ? colors + : true; + return this; +}; + +/** + * Set the timeout in milliseconds. + * + * @param {Number} timeout + * @return {Mocha} + * @api public + */ + +Mocha.prototype.timeout = function(timeout){ + this.suite.timeout(timeout); + return this; +}; + +/** + * Set slowness threshold in milliseconds. + * + * @param {Number} slow + * @return {Mocha} + * @api public + */ + +Mocha.prototype.slow = function(slow){ + this.suite.slow(slow); + return this; +}; + +/** + * Makes all tests async (accepting a callback) + * + * @return {Mocha} + * @api public + */ + +Mocha.prototype.asyncOnly = function(){ + this.options.asyncOnly = true; + return this; +}; + +/** + * Run tests and invoke `fn()` when complete. + * + * @param {Function} fn + * @return {Runner} + * @api public + */ + +Mocha.prototype.run = function(fn){ + if (this.files.length) this.loadFiles(); + var suite = this.suite; + var options = this.options; + var runner = new exports.Runner(suite); + var reporter = new this._reporter(runner); + runner.ignoreLeaks = false !== options.ignoreLeaks; + runner.asyncOnly = options.asyncOnly; + if (options.grep) runner.grep(options.grep, options.invert); + if (options.globals) runner.globals(options.globals); + if (options.growl) this._growl(runner, reporter); + exports.reporters.Base.useColors = options.useColors; + return runner.run(fn); +}; + +}); // module: mocha.js + +require.register("ms.js", function(module, exports, require){ +/** + * Helpers. + */ + +var s = 1000; +var m = s * 60; +var h = m * 60; +var d = h * 24; +var y = d * 365.25; + +/** + * Parse or format the given `val`. + * + * Options: + * + * - `long` verbose formatting [false] + * + * @param {String|Number} val + * @param {Object} options + * @return {String|Number} + * @api public + */ + +module.exports = function(val, options){ + options = options || {}; + if ('string' == typeof val) return parse(val); + return options.long + ? long(val) + : short(val); +}; + +/** + * Parse the given `str` and return milliseconds. + * + * @param {String} str + * @return {Number} + * @api private + */ + +function parse(str) { + var match = /^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str); + if (!match) return; + var n = parseFloat(match[1]); + var type = (match[2] || 'ms').toLowerCase(); + switch (type) { + case 'years': + case 'year': + case 'y': + return n * y; + case 'days': + case 'day': + case 'd': + return n * d; + case 'hours': + case 'hour': + case 'h': + return n * h; + case 'minutes': + case 'minute': + case 'm': + return n * m; + case 'seconds': + case 'second': + case 's': + return n * s; + case 'ms': + return n; + } +} + +/** + * Short format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function short(ms) { + if (ms >= d) return Math.round(ms / d) + 'd'; + if (ms >= h) return Math.round(ms / h) + 'h'; + if (ms >= m) return Math.round(ms / m) + 'm'; + if (ms >= s) return Math.round(ms / s) + 's'; + return ms + 'ms'; +} + +/** + * Long format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function long(ms) { + return plural(ms, d, 'day') + || plural(ms, h, 'hour') + || plural(ms, m, 'minute') + || plural(ms, s, 'second') + || ms + ' ms'; +} + +/** + * Pluralization helper. + */ + +function plural(ms, n, name) { + if (ms < n) return; + if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name; + return Math.ceil(ms / n) + ' ' + name + 's'; +} + +}); // module: ms.js + +require.register("reporters/base.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var tty = require('browser/tty') + , diff = require('browser/diff') + , ms = require('../ms'); + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Check if both stdio streams are associated with a tty. + */ + +var isatty = tty.isatty(1) && tty.isatty(2); + +/** + * Expose `Base`. + */ + +exports = module.exports = Base; + +/** + * Enable coloring by default. + */ + +exports.useColors = isatty || (process.env.MOCHA_COLORS !== undefined); + +/** + * Inline diffs instead of +/- + */ + +exports.inlineDiffs = false; + +/** + * Default color map. + */ + +exports.colors = { + 'pass': 90 + , 'fail': 31 + , 'bright pass': 92 + , 'bright fail': 91 + , 'bright yellow': 93 + , 'pending': 36 + , 'suite': 0 + , 'error title': 0 + , 'error message': 31 + , 'error stack': 90 + , 'checkmark': 32 + , 'fast': 90 + , 'medium': 33 + , 'slow': 31 + , 'green': 32 + , 'light': 90 + , 'diff gutter': 90 + , 'diff added': 42 + , 'diff removed': 41 +}; + +/** + * Default symbol map. + */ + +exports.symbols = { + ok: '✓', + err: '✖', + dot: '․' +}; + +// With node.js on Windows: use symbols available in terminal default fonts +if ('win32' == process.platform) { + exports.symbols.ok = '\u221A'; + exports.symbols.err = '\u00D7'; + exports.symbols.dot = '.'; +} + +/** + * Color `str` with the given `type`, + * allowing colors to be disabled, + * as well as user-defined color + * schemes. + * + * @param {String} type + * @param {String} str + * @return {String} + * @api private + */ + +var color = exports.color = function(type, str) { + if (!exports.useColors) return str; + return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m'; +}; + +/** + * Expose term window size, with some + * defaults for when stderr is not a tty. + */ + +exports.window = { + width: isatty + ? process.stdout.getWindowSize + ? process.stdout.getWindowSize(1)[0] + : tty.getWindowSize()[1] + : 75 +}; + +/** + * Expose some basic cursor interactions + * that are common among reporters. + */ + +exports.cursor = { + hide: function(){ + isatty && process.stdout.write('\u001b[?25l'); + }, + + show: function(){ + isatty && process.stdout.write('\u001b[?25h'); + }, + + deleteLine: function(){ + isatty && process.stdout.write('\u001b[2K'); + }, + + beginningOfLine: function(){ + isatty && process.stdout.write('\u001b[0G'); + }, + + CR: function(){ + if (isatty) { + exports.cursor.deleteLine(); + exports.cursor.beginningOfLine(); + } else { + process.stdout.write('\n'); + } + } +}; + +/** + * Outut the given `failures` as a list. + * + * @param {Array} failures + * @api public + */ + +exports.list = function(failures){ + console.error(); + failures.forEach(function(test, i){ + // format + var fmt = color('error title', ' %s) %s:\n') + + color('error message', ' %s') + + color('error stack', '\n%s\n'); + + // msg + var err = test.err + , message = err.message || '' + , stack = err.stack || message + , index = stack.indexOf(message) + message.length + , msg = stack.slice(0, index) + , actual = err.actual + , expected = err.expected + , escape = true; + + // uncaught + if (err.uncaught) { + msg = 'Uncaught ' + msg; + } + + // explicitly show diff + if (err.showDiff && sameType(actual, expected)) { + escape = false; + err.actual = actual = stringify(actual); + err.expected = expected = stringify(expected); + } + + // actual / expected diff + if ('string' == typeof actual && 'string' == typeof expected) { + fmt = color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n'); + var match = message.match(/^([^:]+): expected/); + msg = match ? '\n ' + color('error message', match[1]) : ''; + + if (exports.inlineDiffs) { + msg += inlineDiff(err, escape); + } else { + msg += unifiedDiff(err, escape); + } + } + + // indent stack trace without msg + stack = stack.slice(index ? index + 1 : index) + .replace(/^/gm, ' '); + + console.error(fmt, (i + 1), test.fullTitle(), msg, stack); + }); +}; + +/** + * Initialize a new `Base` reporter. + * + * All other reporters generally + * inherit from this reporter, providing + * stats such as test duration, number + * of tests passed / failed etc. + * + * @param {Runner} runner + * @api public + */ + +function Base(runner) { + var self = this + , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 } + , failures = this.failures = []; + + if (!runner) return; + this.runner = runner; + + runner.stats = stats; + + runner.on('start', function(){ + stats.start = new Date; + }); + + runner.on('suite', function(suite){ + stats.suites = stats.suites || 0; + suite.root || stats.suites++; + }); + + runner.on('test end', function(test){ + stats.tests = stats.tests || 0; + stats.tests++; + }); + + runner.on('pass', function(test){ + stats.passes = stats.passes || 0; + + var medium = test.slow() / 2; + test.speed = test.duration > test.slow() + ? 'slow' + : test.duration > medium + ? 'medium' + : 'fast'; + + stats.passes++; + }); + + runner.on('fail', function(test, err){ + stats.failures = stats.failures || 0; + stats.failures++; + test.err = err; + failures.push(test); + }); + + runner.on('end', function(){ + stats.end = new Date; + stats.duration = new Date - stats.start; + }); + + runner.on('pending', function(){ + stats.pending++; + }); +} + +/** + * Output common epilogue used by many of + * the bundled reporters. + * + * @api public + */ + +Base.prototype.epilogue = function(){ + var stats = this.stats; + var tests; + var fmt; + + console.log(); + + // passes + fmt = color('bright pass', ' ') + + color('green', ' %d passing') + + color('light', ' (%s)'); + + console.log(fmt, + stats.passes || 0, + ms(stats.duration)); + + // pending + if (stats.pending) { + fmt = color('pending', ' ') + + color('pending', ' %d pending'); + + console.log(fmt, stats.pending); + } + + // failures + if (stats.failures) { + fmt = color('fail', ' %d failing'); + + console.error(fmt, + stats.failures); + + Base.list(this.failures); + console.error(); + } + + console.log(); +}; + +/** + * Pad the given `str` to `len`. + * + * @param {String} str + * @param {String} len + * @return {String} + * @api private + */ + +function pad(str, len) { + str = String(str); + return Array(len - str.length + 1).join(' ') + str; +} + + +/** + * Returns an inline diff between 2 strings with coloured ANSI output + * + * @param {Error} Error with actual/expected + * @return {String} Diff + * @api private + */ + +function inlineDiff(err, escape) { + var msg = errorDiff(err, 'WordsWithSpace', escape); + + // linenos + var lines = msg.split('\n'); + if (lines.length > 4) { + var width = String(lines.length).length; + msg = lines.map(function(str, i){ + return pad(++i, width) + ' |' + ' ' + str; + }).join('\n'); + } + + // legend + msg = '\n' + + color('diff removed', 'actual') + + ' ' + + color('diff added', 'expected') + + '\n\n' + + msg + + '\n'; + + // indent + msg = msg.replace(/^/gm, ' '); + return msg; +} + +/** + * Returns a unified diff between 2 strings + * + * @param {Error} Error with actual/expected + * @return {String} Diff + * @api private + */ + +function unifiedDiff(err, escape) { + var indent = ' '; + function cleanUp(line) { + if (escape) { + line = escapeInvisibles(line); + } + if (line[0] === '+') return indent + colorLines('diff added', line); + if (line[0] === '-') return indent + colorLines('diff removed', line); + if (line.match(/\@\@/)) return null; + if (line.match(/\\ No newline/)) return null; + else return indent + line; + } + function notBlank(line) { + return line != null; + } + msg = diff.createPatch('string', err.actual, err.expected); + var lines = msg.split('\n').splice(4); + return '\n ' + + colorLines('diff added', '+ expected') + ' ' + + colorLines('diff removed', '- actual') + + '\n\n' + + lines.map(cleanUp).filter(notBlank).join('\n'); +} + +/** + * Return a character diff for `err`. + * + * @param {Error} err + * @return {String} + * @api private + */ + +function errorDiff(err, type, escape) { + var actual = escape ? escapeInvisibles(err.actual) : err.actual; + var expected = escape ? escapeInvisibles(err.expected) : err.expected; + return diff['diff' + type](actual, expected).map(function(str){ + if (str.added) return colorLines('diff added', str.value); + if (str.removed) return colorLines('diff removed', str.value); + return str.value; + }).join(''); +} + +/** + * Returns a string with all invisible characters in plain text + * + * @param {String} line + * @return {String} + * @api private + */ +function escapeInvisibles(line) { + return line.replace(/\t/g, '') + .replace(/\r/g, '') + .replace(/\n/g, '\n'); +} + +/** + * Color lines for `str`, using the color `name`. + * + * @param {String} name + * @param {String} str + * @return {String} + * @api private + */ + +function colorLines(name, str) { + return str.split('\n').map(function(str){ + return color(name, str); + }).join('\n'); +} + +/** + * Stringify `obj`. + * + * @param {Mixed} obj + * @return {String} + * @api private + */ + +function stringify(obj) { + if (obj instanceof RegExp) return obj.toString(); + return JSON.stringify(obj, null, 2); +} + +/** + * Check that a / b have the same type. + * + * @param {Object} a + * @param {Object} b + * @return {Boolean} + * @api private + */ + +function sameType(a, b) { + a = Object.prototype.toString.call(a); + b = Object.prototype.toString.call(b); + return a == b; +} + + + +}); // module: reporters/base.js + +require.register("reporters/doc.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils'); + +/** + * Expose `Doc`. + */ + +exports = module.exports = Doc; + +/** + * Initialize a new `Doc` reporter. + * + * @param {Runner} runner + * @api public + */ + +function Doc(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , total = runner.total + , indents = 2; + + function indent() { + return Array(indents).join(' '); + } + + runner.on('suite', function(suite){ + if (suite.root) return; + ++indents; + console.log('%s
', indent()); + ++indents; + console.log('%s

%s

', indent(), utils.escape(suite.title)); + console.log('%s
', indent()); + }); + + runner.on('suite end', function(suite){ + if (suite.root) return; + console.log('%s
', indent()); + --indents; + console.log('%s
', indent()); + --indents; + }); + + runner.on('pass', function(test){ + console.log('%s
%s
', indent(), utils.escape(test.title)); + var code = utils.escape(utils.clean(test.fn.toString())); + console.log('%s
%s
', indent(), code); + }); +} + +}); // module: reporters/doc.js + +require.register("reporters/dot.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , color = Base.color; + +/** + * Expose `Dot`. + */ + +exports = module.exports = Dot; + +/** + * Initialize a new `Dot` matrix test reporter. + * + * @param {Runner} runner + * @api public + */ + +function Dot(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , width = Base.window.width * .75 | 0 + , n = 0; + + runner.on('start', function(){ + process.stdout.write('\n '); + }); + + runner.on('pending', function(test){ + process.stdout.write(color('pending', Base.symbols.dot)); + }); + + runner.on('pass', function(test){ + if (++n % width == 0) process.stdout.write('\n '); + if ('slow' == test.speed) { + process.stdout.write(color('bright yellow', Base.symbols.dot)); + } else { + process.stdout.write(color(test.speed, Base.symbols.dot)); + } + }); + + runner.on('fail', function(test, err){ + if (++n % width == 0) process.stdout.write('\n '); + process.stdout.write(color('fail', Base.symbols.dot)); + }); + + runner.on('end', function(){ + console.log(); + self.epilogue(); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +Dot.prototype = new F; +Dot.prototype.constructor = Dot; + +}); // module: reporters/dot.js + +require.register("reporters/html-cov.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var JSONCov = require('./json-cov') + , fs = require('browser/fs'); + +/** + * Expose `HTMLCov`. + */ + +exports = module.exports = HTMLCov; + +/** + * Initialize a new `JsCoverage` reporter. + * + * @param {Runner} runner + * @api public + */ + +function HTMLCov(runner) { + var jade = require('jade') + , file = __dirname + '/templates/coverage.jade' + , str = fs.readFileSync(file, 'utf8') + , fn = jade.compile(str, { filename: file }) + , self = this; + + JSONCov.call(this, runner, false); + + runner.on('end', function(){ + process.stdout.write(fn({ + cov: self.cov + , coverageClass: coverageClass + })); + }); +} + +/** + * Return coverage class for `n`. + * + * @return {String} + * @api private + */ + +function coverageClass(n) { + if (n >= 75) return 'high'; + if (n >= 50) return 'medium'; + if (n >= 25) return 'low'; + return 'terrible'; +} +}); // module: reporters/html-cov.js + +require.register("reporters/html.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils') + , Progress = require('../browser/progress') + , escape = utils.escape; + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Expose `HTML`. + */ + +exports = module.exports = HTML; + +/** + * Stats template. + */ + +var statsTemplate = ''; + +/** + * Initialize a new `HTML` reporter. + * + * @param {Runner} runner + * @api public + */ + +function HTML(runner, root) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , total = runner.total + , stat = fragment(statsTemplate) + , items = stat.getElementsByTagName('li') + , passes = items[1].getElementsByTagName('em')[0] + , passesLink = items[1].getElementsByTagName('a')[0] + , failures = items[2].getElementsByTagName('em')[0] + , failuresLink = items[2].getElementsByTagName('a')[0] + , duration = items[3].getElementsByTagName('em')[0] + , canvas = stat.getElementsByTagName('canvas')[0] + , report = fragment('
    ') + , stack = [report] + , progress + , ctx + + root = root || document.getElementById('mocha'); + + if (canvas.getContext) { + var ratio = window.devicePixelRatio || 1; + canvas.style.width = canvas.width; + canvas.style.height = canvas.height; + canvas.width *= ratio; + canvas.height *= ratio; + ctx = canvas.getContext('2d'); + ctx.scale(ratio, ratio); + progress = new Progress; + } + + if (!root) return error('#mocha div missing, add it to your document'); + + // pass toggle + on(passesLink, 'click', function(){ + unhide(); + var name = /pass/.test(report.className) ? '' : ' pass'; + report.className = report.className.replace(/fail|pass/g, '') + name; + if (report.className.trim()) hideSuitesWithout('test pass'); + }); + + // failure toggle + on(failuresLink, 'click', function(){ + unhide(); + var name = /fail/.test(report.className) ? '' : ' fail'; + report.className = report.className.replace(/fail|pass/g, '') + name; + if (report.className.trim()) hideSuitesWithout('test fail'); + }); + + root.appendChild(stat); + root.appendChild(report); + + if (progress) progress.size(40); + + runner.on('suite', function(suite){ + if (suite.root) return; + + // suite + var url = self.suiteURL(suite); + var el = fragment('
  • %s

  • ', url, escape(suite.title)); + + // container + stack[0].appendChild(el); + stack.unshift(document.createElement('ul')); + el.appendChild(stack[0]); + }); + + runner.on('suite end', function(suite){ + if (suite.root) return; + stack.shift(); + }); + + runner.on('fail', function(test, err){ + if ('hook' == test.type) runner.emit('test end', test); + }); + + runner.on('test end', function(test){ + // TODO: add to stats + var percent = stats.tests / this.total * 100 | 0; + if (progress) progress.update(percent).draw(ctx); + + // update stats + var ms = new Date - stats.start; + text(passes, stats.passes); + text(failures, stats.failures); + text(duration, (ms / 1000).toFixed(2)); + + // test + if ('passed' == test.state) { + var url = self.testURL(test); + var el = fragment('
  • %e%ems

  • ', test.speed, test.title, test.duration, url); + } else if (test.pending) { + var el = fragment('
  • %e

  • ', test.title); + } else { + var el = fragment('
  • %e

  • ', test.title, encodeURIComponent(test.fullTitle())); + var str = test.err.stack || test.err.toString(); + + // FF / Opera do not add the message + if (!~str.indexOf(test.err.message)) { + str = test.err.message + '\n' + str; + } + + // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we + // check for the result of the stringifying. + if ('[object Error]' == str) str = test.err.message; + + // Safari doesn't give you a stack. Let's at least provide a source line. + if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined) { + str += "\n(" + test.err.sourceURL + ":" + test.err.line + ")"; + } + + el.appendChild(fragment('
    %e
    ', str)); + } + + // toggle code + // TODO: defer + if (!test.pending) { + var h2 = el.getElementsByTagName('h2')[0]; + + on(h2, 'click', function(){ + pre.style.display = 'none' == pre.style.display + ? 'block' + : 'none'; + }); + + var pre = fragment('
    %e
    ', utils.clean(test.fn.toString())); + el.appendChild(pre); + pre.style.display = 'none'; + } + + // Don't call .appendChild if #mocha-report was already .shift()'ed off the stack. + if (stack[0]) stack[0].appendChild(el); + }); +} + +/** + * Provide suite URL + * + * @param {Object} [suite] + */ + +HTML.prototype.suiteURL = function(suite){ + return '?grep=' + encodeURIComponent(suite.fullTitle()); +}; + +/** + * Provide test URL + * + * @param {Object} [test] + */ + +HTML.prototype.testURL = function(test){ + return '?grep=' + encodeURIComponent(test.fullTitle()); +}; + +/** + * Display error `msg`. + */ + +function error(msg) { + document.body.appendChild(fragment('
    %s
    ', msg)); +} + +/** + * Return a DOM fragment from `html`. + */ + +function fragment(html) { + var args = arguments + , div = document.createElement('div') + , i = 1; + + div.innerHTML = html.replace(/%([se])/g, function(_, type){ + switch (type) { + case 's': return String(args[i++]); + case 'e': return escape(args[i++]); + } + }); + + return div.firstChild; +} + +/** + * Check for suites that do not have elements + * with `classname`, and hide them. + */ + +function hideSuitesWithout(classname) { + var suites = document.getElementsByClassName('suite'); + for (var i = 0; i < suites.length; i++) { + var els = suites[i].getElementsByClassName(classname); + if (0 == els.length) suites[i].className += ' hidden'; + } +} + +/** + * Unhide .hidden suites. + */ + +function unhide() { + var els = document.getElementsByClassName('suite hidden'); + for (var i = 0; i < els.length; ++i) { + els[i].className = els[i].className.replace('suite hidden', 'suite'); + } +} + +/** + * Set `el` text to `str`. + */ + +function text(el, str) { + if (el.textContent) { + el.textContent = str; + } else { + el.innerText = str; + } +} + +/** + * Listen on `event` with callback `fn`. + */ + +function on(el, event, fn) { + if (el.addEventListener) { + el.addEventListener(event, fn, false); + } else { + el.attachEvent('on' + event, fn); + } +} + +}); // module: reporters/html.js + +require.register("reporters/index.js", function(module, exports, require){ + +exports.Base = require('./base'); +exports.Dot = require('./dot'); +exports.Doc = require('./doc'); +exports.TAP = require('./tap'); +exports.JSON = require('./json'); +exports.HTML = require('./html'); +exports.List = require('./list'); +exports.Min = require('./min'); +exports.Spec = require('./spec'); +exports.Nyan = require('./nyan'); +exports.XUnit = require('./xunit'); +exports.Markdown = require('./markdown'); +exports.Progress = require('./progress'); +exports.Landing = require('./landing'); +exports.JSONCov = require('./json-cov'); +exports.HTMLCov = require('./html-cov'); +exports.JSONStream = require('./json-stream'); + +}); // module: reporters/index.js + +require.register("reporters/json-cov.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base'); + +/** + * Expose `JSONCov`. + */ + +exports = module.exports = JSONCov; + +/** + * Initialize a new `JsCoverage` reporter. + * + * @param {Runner} runner + * @param {Boolean} output + * @api public + */ + +function JSONCov(runner, output) { + var self = this + , output = 1 == arguments.length ? true : output; + + Base.call(this, runner); + + var tests = [] + , failures = [] + , passes = []; + + runner.on('test end', function(test){ + tests.push(test); + }); + + runner.on('pass', function(test){ + passes.push(test); + }); + + runner.on('fail', function(test){ + failures.push(test); + }); + + runner.on('end', function(){ + var cov = global._$jscoverage || {}; + var result = self.cov = map(cov); + result.stats = self.stats; + result.tests = tests.map(clean); + result.failures = failures.map(clean); + result.passes = passes.map(clean); + if (!output) return; + process.stdout.write(JSON.stringify(result, null, 2 )); + }); +} + +/** + * Map jscoverage data to a JSON structure + * suitable for reporting. + * + * @param {Object} cov + * @return {Object} + * @api private + */ + +function map(cov) { + var ret = { + instrumentation: 'node-jscoverage' + , sloc: 0 + , hits: 0 + , misses: 0 + , coverage: 0 + , files: [] + }; + + for (var filename in cov) { + var data = coverage(filename, cov[filename]); + ret.files.push(data); + ret.hits += data.hits; + ret.misses += data.misses; + ret.sloc += data.sloc; + } + + ret.files.sort(function(a, b) { + return a.filename.localeCompare(b.filename); + }); + + if (ret.sloc > 0) { + ret.coverage = (ret.hits / ret.sloc) * 100; + } + + return ret; +}; + +/** + * Map jscoverage data for a single source file + * to a JSON structure suitable for reporting. + * + * @param {String} filename name of the source file + * @param {Object} data jscoverage coverage data + * @return {Object} + * @api private + */ + +function coverage(filename, data) { + var ret = { + filename: filename, + coverage: 0, + hits: 0, + misses: 0, + sloc: 0, + source: {} + }; + + data.source.forEach(function(line, num){ + num++; + + if (data[num] === 0) { + ret.misses++; + ret.sloc++; + } else if (data[num] !== undefined) { + ret.hits++; + ret.sloc++; + } + + ret.source[num] = { + source: line + , coverage: data[num] === undefined + ? '' + : data[num] + }; + }); + + ret.coverage = ret.hits / ret.sloc * 100; + + return ret; +} + +/** + * Return a plain-object representation of `test` + * free of cyclic properties etc. + * + * @param {Object} test + * @return {Object} + * @api private + */ + +function clean(test) { + return { + title: test.title + , fullTitle: test.fullTitle() + , duration: test.duration + } +} + +}); // module: reporters/json-cov.js + +require.register("reporters/json-stream.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , color = Base.color; + +/** + * Expose `List`. + */ + +exports = module.exports = List; + +/** + * Initialize a new `List` test reporter. + * + * @param {Runner} runner + * @api public + */ + +function List(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , total = runner.total; + + runner.on('start', function(){ + console.log(JSON.stringify(['start', { total: total }])); + }); + + runner.on('pass', function(test){ + console.log(JSON.stringify(['pass', clean(test)])); + }); + + runner.on('fail', function(test, err){ + console.log(JSON.stringify(['fail', clean(test)])); + }); + + runner.on('end', function(){ + process.stdout.write(JSON.stringify(['end', self.stats])); + }); +} + +/** + * Return a plain-object representation of `test` + * free of cyclic properties etc. + * + * @param {Object} test + * @return {Object} + * @api private + */ + +function clean(test) { + return { + title: test.title + , fullTitle: test.fullTitle() + , duration: test.duration + } +} +}); // module: reporters/json-stream.js + +require.register("reporters/json.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `JSON`. + */ + +exports = module.exports = JSONReporter; + +/** + * Initialize a new `JSON` reporter. + * + * @param {Runner} runner + * @api public + */ + +function JSONReporter(runner) { + var self = this; + Base.call(this, runner); + + var tests = [] + , failures = [] + , passes = []; + + runner.on('test end', function(test){ + tests.push(test); + }); + + runner.on('pass', function(test){ + passes.push(test); + }); + + runner.on('fail', function(test){ + failures.push(test); + }); + + runner.on('end', function(){ + var obj = { + stats: self.stats + , tests: tests.map(clean) + , failures: failures.map(clean) + , passes: passes.map(clean) + }; + + process.stdout.write(JSON.stringify(obj, null, 2)); + }); +} + +/** + * Return a plain-object representation of `test` + * free of cyclic properties etc. + * + * @param {Object} test + * @return {Object} + * @api private + */ + +function clean(test) { + return { + title: test.title + , fullTitle: test.fullTitle() + , duration: test.duration + } +} +}); // module: reporters/json.js + +require.register("reporters/landing.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `Landing`. + */ + +exports = module.exports = Landing; + +/** + * Airplane color. + */ + +Base.colors.plane = 0; + +/** + * Airplane crash color. + */ + +Base.colors['plane crash'] = 31; + +/** + * Runway color. + */ + +Base.colors.runway = 90; + +/** + * Initialize a new `Landing` reporter. + * + * @param {Runner} runner + * @api public + */ + +function Landing(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , width = Base.window.width * .75 | 0 + , total = runner.total + , stream = process.stdout + , plane = color('plane', '✈') + , crashed = -1 + , n = 0; + + function runway() { + var buf = Array(width).join('-'); + return ' ' + color('runway', buf); + } + + runner.on('start', function(){ + stream.write('\n '); + cursor.hide(); + }); + + runner.on('test end', function(test){ + // check if the plane crashed + var col = -1 == crashed + ? width * ++n / total | 0 + : crashed; + + // show the crash + if ('failed' == test.state) { + plane = color('plane crash', '✈'); + crashed = col; + } + + // render landing strip + stream.write('\u001b[4F\n\n'); + stream.write(runway()); + stream.write('\n '); + stream.write(color('runway', Array(col).join('⋅'))); + stream.write(plane) + stream.write(color('runway', Array(width - col).join('⋅') + '\n')); + stream.write(runway()); + stream.write('\u001b[0m'); + }); + + runner.on('end', function(){ + cursor.show(); + console.log(); + self.epilogue(); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +Landing.prototype = new F; +Landing.prototype.constructor = Landing; + +}); // module: reporters/landing.js + +require.register("reporters/list.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `List`. + */ + +exports = module.exports = List; + +/** + * Initialize a new `List` test reporter. + * + * @param {Runner} runner + * @api public + */ + +function List(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , n = 0; + + runner.on('start', function(){ + console.log(); + }); + + runner.on('test', function(test){ + process.stdout.write(color('pass', ' ' + test.fullTitle() + ': ')); + }); + + runner.on('pending', function(test){ + var fmt = color('checkmark', ' -') + + color('pending', ' %s'); + console.log(fmt, test.fullTitle()); + }); + + runner.on('pass', function(test){ + var fmt = color('checkmark', ' '+Base.symbols.dot) + + color('pass', ' %s: ') + + color(test.speed, '%dms'); + cursor.CR(); + console.log(fmt, test.fullTitle(), test.duration); + }); + + runner.on('fail', function(test, err){ + cursor.CR(); + console.log(color('fail', ' %d) %s'), ++n, test.fullTitle()); + }); + + runner.on('end', self.epilogue.bind(self)); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +List.prototype = new F; +List.prototype.constructor = List; + + +}); // module: reporters/list.js + +require.register("reporters/markdown.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils'); + +/** + * Expose `Markdown`. + */ + +exports = module.exports = Markdown; + +/** + * Initialize a new `Markdown` reporter. + * + * @param {Runner} runner + * @api public + */ + +function Markdown(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , level = 0 + , buf = ''; + + function title(str) { + return Array(level).join('#') + ' ' + str; + } + + function indent() { + return Array(level).join(' '); + } + + function mapTOC(suite, obj) { + var ret = obj; + obj = obj[suite.title] = obj[suite.title] || { suite: suite }; + suite.suites.forEach(function(suite){ + mapTOC(suite, obj); + }); + return ret; + } + + function stringifyTOC(obj, level) { + ++level; + var buf = ''; + var link; + for (var key in obj) { + if ('suite' == key) continue; + if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n'; + if (key) buf += Array(level).join(' ') + link; + buf += stringifyTOC(obj[key], level); + } + --level; + return buf; + } + + function generateTOC(suite) { + var obj = mapTOC(suite, {}); + return stringifyTOC(obj, 0); + } + + generateTOC(runner.suite); + + runner.on('suite', function(suite){ + ++level; + var slug = utils.slug(suite.fullTitle()); + buf += '' + '\n'; + buf += title(suite.title) + '\n'; + }); + + runner.on('suite end', function(suite){ + --level; + }); + + runner.on('pass', function(test){ + var code = utils.clean(test.fn.toString()); + buf += test.title + '.\n'; + buf += '\n```js\n'; + buf += code + '\n'; + buf += '```\n\n'; + }); + + runner.on('end', function(){ + process.stdout.write('# TOC\n'); + process.stdout.write(generateTOC(runner.suite)); + process.stdout.write(buf); + }); +} +}); // module: reporters/markdown.js + +require.register("reporters/min.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base'); + +/** + * Expose `Min`. + */ + +exports = module.exports = Min; + +/** + * Initialize a new `Min` minimal test reporter (best used with --watch). + * + * @param {Runner} runner + * @api public + */ + +function Min(runner) { + Base.call(this, runner); + + runner.on('start', function(){ + // clear screen + process.stdout.write('\u001b[2J'); + // set cursor position + process.stdout.write('\u001b[1;3H'); + }); + + runner.on('end', this.epilogue.bind(this)); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +Min.prototype = new F; +Min.prototype.constructor = Min; + + +}); // module: reporters/min.js + +require.register("reporters/nyan.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Base = require('./base') + , color = Base.color; + +/** + * Expose `Dot`. + */ + +exports = module.exports = NyanCat; + +/** + * Initialize a new `Dot` matrix test reporter. + * + * @param {Runner} runner + * @api public + */ + +function NyanCat(runner) { + Base.call(this, runner); + var self = this + , stats = this.stats + , width = Base.window.width * .75 | 0 + , rainbowColors = this.rainbowColors = self.generateColors() + , colorIndex = this.colorIndex = 0 + , numerOfLines = this.numberOfLines = 4 + , trajectories = this.trajectories = [[], [], [], []] + , nyanCatWidth = this.nyanCatWidth = 11 + , trajectoryWidthMax = this.trajectoryWidthMax = (width - nyanCatWidth) + , scoreboardWidth = this.scoreboardWidth = 5 + , tick = this.tick = 0 + , n = 0; + + runner.on('start', function(){ + Base.cursor.hide(); + self.draw(); + }); + + runner.on('pending', function(test){ + self.draw(); + }); + + runner.on('pass', function(test){ + self.draw(); + }); + + runner.on('fail', function(test, err){ + self.draw(); + }); + + runner.on('end', function(){ + Base.cursor.show(); + for (var i = 0; i < self.numberOfLines; i++) write('\n'); + self.epilogue(); + }); +} + +/** + * Draw the nyan cat + * + * @api private + */ + +NyanCat.prototype.draw = function(){ + this.appendRainbow(); + this.drawScoreboard(); + this.drawRainbow(); + this.drawNyanCat(); + this.tick = !this.tick; +}; + +/** + * Draw the "scoreboard" showing the number + * of passes, failures and pending tests. + * + * @api private + */ + +NyanCat.prototype.drawScoreboard = function(){ + var stats = this.stats; + var colors = Base.colors; + + function draw(color, n) { + write(' '); + write('\u001b[' + color + 'm' + n + '\u001b[0m'); + write('\n'); + } + + draw(colors.green, stats.passes); + draw(colors.fail, stats.failures); + draw(colors.pending, stats.pending); + write('\n'); + + this.cursorUp(this.numberOfLines); +}; + +/** + * Append the rainbow. + * + * @api private + */ + +NyanCat.prototype.appendRainbow = function(){ + var segment = this.tick ? '_' : '-'; + var rainbowified = this.rainbowify(segment); + + for (var index = 0; index < this.numberOfLines; index++) { + var trajectory = this.trajectories[index]; + if (trajectory.length >= this.trajectoryWidthMax) trajectory.shift(); + trajectory.push(rainbowified); + } +}; + +/** + * Draw the rainbow. + * + * @api private + */ + +NyanCat.prototype.drawRainbow = function(){ + var self = this; + + this.trajectories.forEach(function(line, index) { + write('\u001b[' + self.scoreboardWidth + 'C'); + write(line.join('')); + write('\n'); + }); + + this.cursorUp(this.numberOfLines); +}; + +/** + * Draw the nyan cat + * + * @api private + */ + +NyanCat.prototype.drawNyanCat = function() { + var self = this; + var startWidth = this.scoreboardWidth + this.trajectories[0].length; + var color = '\u001b[' + startWidth + 'C'; + var padding = ''; + + write(color); + write('_,------,'); + write('\n'); + + write(color); + padding = self.tick ? ' ' : ' '; + write('_|' + padding + '/\\_/\\ '); + write('\n'); + + write(color); + padding = self.tick ? '_' : '__'; + var tail = self.tick ? '~' : '^'; + var face; + write(tail + '|' + padding + this.face() + ' '); + write('\n'); + + write(color); + padding = self.tick ? ' ' : ' '; + write(padding + '"" "" '); + write('\n'); + + this.cursorUp(this.numberOfLines); +}; + +/** + * Draw nyan cat face. + * + * @return {String} + * @api private + */ + +NyanCat.prototype.face = function() { + var stats = this.stats; + if (stats.failures) { + return '( x .x)'; + } else if (stats.pending) { + return '( o .o)'; + } else if(stats.passes) { + return '( ^ .^)'; + } else { + return '( - .-)'; + } +} + +/** + * Move cursor up `n`. + * + * @param {Number} n + * @api private + */ + +NyanCat.prototype.cursorUp = function(n) { + write('\u001b[' + n + 'A'); +}; + +/** + * Move cursor down `n`. + * + * @param {Number} n + * @api private + */ + +NyanCat.prototype.cursorDown = function(n) { + write('\u001b[' + n + 'B'); +}; + +/** + * Generate rainbow colors. + * + * @return {Array} + * @api private + */ + +NyanCat.prototype.generateColors = function(){ + var colors = []; + + for (var i = 0; i < (6 * 7); i++) { + var pi3 = Math.floor(Math.PI / 3); + var n = (i * (1.0 / 6)); + var r = Math.floor(3 * Math.sin(n) + 3); + var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3); + var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3); + colors.push(36 * r + 6 * g + b + 16); + } + + return colors; +}; + +/** + * Apply rainbow to the given `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +NyanCat.prototype.rainbowify = function(str){ + var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length]; + this.colorIndex += 1; + return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m'; +}; + +/** + * Stdout helper. + */ + +function write(string) { + process.stdout.write(string); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +NyanCat.prototype = new F; +NyanCat.prototype.constructor = NyanCat; + + +}); // module: reporters/nyan.js + +require.register("reporters/progress.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `Progress`. + */ + +exports = module.exports = Progress; + +/** + * General progress bar color. + */ + +Base.colors.progress = 90; + +/** + * Initialize a new `Progress` bar test reporter. + * + * @param {Runner} runner + * @param {Object} options + * @api public + */ + +function Progress(runner, options) { + Base.call(this, runner); + + var self = this + , options = options || {} + , stats = this.stats + , width = Base.window.width * .50 | 0 + , total = runner.total + , complete = 0 + , max = Math.max; + + // default chars + options.open = options.open || '['; + options.complete = options.complete || '▬'; + options.incomplete = options.incomplete || Base.symbols.dot; + options.close = options.close || ']'; + options.verbose = false; + + // tests started + runner.on('start', function(){ + console.log(); + cursor.hide(); + }); + + // tests complete + runner.on('test end', function(){ + complete++; + var incomplete = total - complete + , percent = complete / total + , n = width * percent | 0 + , i = width - n; + + cursor.CR(); + process.stdout.write('\u001b[J'); + process.stdout.write(color('progress', ' ' + options.open)); + process.stdout.write(Array(n).join(options.complete)); + process.stdout.write(Array(i).join(options.incomplete)); + process.stdout.write(color('progress', options.close)); + if (options.verbose) { + process.stdout.write(color('progress', ' ' + complete + ' of ' + total)); + } + }); + + // tests are complete, output some stats + // and the failures if any + runner.on('end', function(){ + cursor.show(); + console.log(); + self.epilogue(); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +Progress.prototype = new F; +Progress.prototype.constructor = Progress; + + +}); // module: reporters/progress.js + +require.register("reporters/spec.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `Spec`. + */ + +exports = module.exports = Spec; + +/** + * Initialize a new `Spec` test reporter. + * + * @param {Runner} runner + * @api public + */ + +function Spec(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , indents = 0 + , n = 0; + + function indent() { + return Array(indents).join(' ') + } + + runner.on('start', function(){ + console.log(); + }); + + runner.on('suite', function(suite){ + ++indents; + console.log(color('suite', '%s%s'), indent(), suite.title); + }); + + runner.on('suite end', function(suite){ + --indents; + if (1 == indents) console.log(); + }); + + runner.on('test', function(test){ + process.stdout.write(indent() + color('pass', ' ◦ ' + test.title + ': ')); + }); + + runner.on('pending', function(test){ + var fmt = indent() + color('pending', ' - %s'); + console.log(fmt, test.title); + }); + + runner.on('pass', function(test){ + if ('fast' == test.speed) { + var fmt = indent() + + color('checkmark', ' ' + Base.symbols.ok) + + color('pass', ' %s '); + cursor.CR(); + console.log(fmt, test.title); + } else { + var fmt = indent() + + color('checkmark', ' ' + Base.symbols.ok) + + color('pass', ' %s ') + + color(test.speed, '(%dms)'); + cursor.CR(); + console.log(fmt, test.title, test.duration); + } + }); + + runner.on('fail', function(test, err){ + cursor.CR(); + console.log(indent() + color('fail', ' %d) %s'), ++n, test.title); + }); + + runner.on('end', self.epilogue.bind(self)); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +Spec.prototype = new F; +Spec.prototype.constructor = Spec; + + +}); // module: reporters/spec.js + +require.register("reporters/tap.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `TAP`. + */ + +exports = module.exports = TAP; + +/** + * Initialize a new `TAP` reporter. + * + * @param {Runner} runner + * @api public + */ + +function TAP(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , n = 1 + , passes = 0 + , failures = 0; + + runner.on('start', function(){ + var total = runner.grepTotal(runner.suite); + console.log('%d..%d', 1, total); + }); + + runner.on('test end', function(){ + ++n; + }); + + runner.on('pending', function(test){ + console.log('ok %d %s # SKIP -', n, title(test)); + }); + + runner.on('pass', function(test){ + passes++; + console.log('ok %d %s', n, title(test)); + }); + + runner.on('fail', function(test, err){ + failures++; + console.log('not ok %d %s', n, title(test)); + if (err.stack) console.log(err.stack.replace(/^/gm, ' ')); + }); + + runner.on('end', function(){ + console.log('# tests ' + (passes + failures)); + console.log('# pass ' + passes); + console.log('# fail ' + failures); + }); +} + +/** + * Return a TAP-safe title of `test` + * + * @param {Object} test + * @return {String} + * @api private + */ + +function title(test) { + return test.fullTitle().replace(/#/g, ''); +} + +}); // module: reporters/tap.js + +require.register("reporters/xunit.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils') + , escape = utils.escape; + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Expose `XUnit`. + */ + +exports = module.exports = XUnit; + +/** + * Initialize a new `XUnit` reporter. + * + * @param {Runner} runner + * @api public + */ + +function XUnit(runner) { + Base.call(this, runner); + var stats = this.stats + , tests = [] + , self = this; + + runner.on('pass', function(test){ + tests.push(test); + }); + + runner.on('fail', function(test){ + tests.push(test); + }); + + runner.on('end', function(){ + console.log(tag('testsuite', { + name: 'Mocha Tests' + , tests: stats.tests + , failures: stats.failures + , errors: stats.failures + , skipped: stats.tests - stats.failures - stats.passes + , timestamp: (new Date).toUTCString() + , time: (stats.duration / 1000) || 0 + }, false)); + + tests.forEach(test); + console.log(''); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +XUnit.prototype = new F; +XUnit.prototype.constructor = XUnit; + + +/** + * Output tag for the given `test.` + */ + +function test(test) { + var attrs = { + classname: test.parent.fullTitle() + , name: test.title + , time: test.duration / 1000 + }; + + if ('failed' == test.state) { + var err = test.err; + attrs.message = escape(err.message); + console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack)))); + } else if (test.pending) { + console.log(tag('testcase', attrs, false, tag('skipped', {}, true))); + } else { + console.log(tag('testcase', attrs, true) ); + } +} + +/** + * HTML tag helper. + */ + +function tag(name, attrs, close, content) { + var end = close ? '/>' : '>' + , pairs = [] + , tag; + + for (var key in attrs) { + pairs.push(key + '="' + escape(attrs[key]) + '"'); + } + + tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end; + if (content) tag += content + ''; +} + +}); // module: reporters/xunit.js + +require.register("runnable.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var EventEmitter = require('browser/events').EventEmitter + , debug = require('browser/debug')('mocha:runnable') + , milliseconds = require('./ms'); + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Object#toString(). + */ + +var toString = Object.prototype.toString; + +/** + * Expose `Runnable`. + */ + +module.exports = Runnable; + +/** + * Initialize a new `Runnable` with the given `title` and callback `fn`. + * + * @param {String} title + * @param {Function} fn + * @api private + */ + +function Runnable(title, fn) { + this.title = title; + this.fn = fn; + this.async = fn && fn.length; + this.sync = ! this.async; + this._timeout = 2000; + this._slow = 75; + this.timedOut = false; +} + +/** + * Inherit from `EventEmitter.prototype`. + */ + +function F(){}; +F.prototype = EventEmitter.prototype; +Runnable.prototype = new F; +Runnable.prototype.constructor = Runnable; + + +/** + * Set & get timeout `ms`. + * + * @param {Number|String} ms + * @return {Runnable|Number} ms or self + * @api private + */ + +Runnable.prototype.timeout = function(ms){ + if (0 == arguments.length) return this._timeout; + if ('string' == typeof ms) ms = milliseconds(ms); + debug('timeout %d', ms); + this._timeout = ms; + if (this.timer) this.resetTimeout(); + return this; +}; + +/** + * Set & get slow `ms`. + * + * @param {Number|String} ms + * @return {Runnable|Number} ms or self + * @api private + */ + +Runnable.prototype.slow = function(ms){ + if (0 === arguments.length) return this._slow; + if ('string' == typeof ms) ms = milliseconds(ms); + debug('timeout %d', ms); + this._slow = ms; + return this; +}; + +/** + * Return the full title generated by recursively + * concatenating the parent's full title. + * + * @return {String} + * @api public + */ + +Runnable.prototype.fullTitle = function(){ + return this.parent.fullTitle() + ' ' + this.title; +}; + +/** + * Clear the timeout. + * + * @api private + */ + +Runnable.prototype.clearTimeout = function(){ + clearTimeout(this.timer); +}; + +/** + * Inspect the runnable void of private properties. + * + * @return {String} + * @api private + */ + +Runnable.prototype.inspect = function(){ + return JSON.stringify(this, function(key, val){ + if ('_' == key[0]) return; + if ('parent' == key) return '#'; + if ('ctx' == key) return '#'; + return val; + }, 2); +}; + +/** + * Reset the timeout. + * + * @api private + */ + +Runnable.prototype.resetTimeout = function(){ + var self = this; + var ms = this.timeout() || 1e9; + + this.clearTimeout(); + this.timer = setTimeout(function(){ + self.callback(new Error('timeout of ' + ms + 'ms exceeded')); + self.timedOut = true; + }, ms); +}; + +/** + * Run the test and invoke `fn(err)`. + * + * @param {Function} fn + * @api private + */ + +Runnable.prototype.run = function(fn){ + var self = this + , ms = this.timeout() + , start = new Date + , ctx = this.ctx + , finished + , emitted; + + if (ctx) ctx.runnable(this); + + // timeout + if (this.async) { + if (ms) { + this.timer = setTimeout(function(){ + done(new Error('timeout of ' + ms + 'ms exceeded')); + self.timedOut = true; + }, ms); + } + } + + // called multiple times + function multiple(err) { + if (emitted) return; + emitted = true; + self.emit('error', err || new Error('done() called multiple times')); + } + + // finished + function done(err) { + if (self.timedOut) return; + if (finished) return multiple(err); + self.clearTimeout(); + self.duration = new Date - start; + finished = true; + fn(err); + } + + // for .resetTimeout() + this.callback = done; + + // async + if (this.async) { + try { + this.fn.call(ctx, function(err){ + if (err instanceof Error || toString.call(err) === "[object Error]") return done(err); + if (null != err) return done(new Error('done() invoked with non-Error: ' + err)); + done(); + }); + } catch (err) { + done(err); + } + return; + } + + if (this.asyncOnly) { + return done(new Error('--async-only option in use without declaring `done()`')); + } + + // sync + try { + if (!this.pending) this.fn.call(ctx); + this.duration = new Date - start; + fn(); + } catch (err) { + fn(err); + } +}; + +}); // module: runnable.js + +require.register("runner.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var EventEmitter = require('browser/events').EventEmitter + , debug = require('browser/debug')('mocha:runner') + , Test = require('./test') + , utils = require('./utils') + , filter = utils.filter + , keys = utils.keys; + +/** + * Non-enumerable globals. + */ + +var globals = [ + 'setTimeout', + 'clearTimeout', + 'setInterval', + 'clearInterval', + 'XMLHttpRequest', + 'Date' +]; + +/** + * Expose `Runner`. + */ + +module.exports = Runner; + +/** + * Initialize a `Runner` for the given `suite`. + * + * Events: + * + * - `start` execution started + * - `end` execution complete + * - `suite` (suite) test suite execution started + * - `suite end` (suite) all tests (and sub-suites) have finished + * - `test` (test) test execution started + * - `test end` (test) test completed + * - `hook` (hook) hook execution started + * - `hook end` (hook) hook complete + * - `pass` (test) test passed + * - `fail` (test, err) test failed + * - `pending` (test) test pending + * + * @api public + */ + +function Runner(suite) { + var self = this; + this._globals = []; + this.suite = suite; + this.total = suite.total(); + this.failures = 0; + this.on('test end', function(test){ self.checkGlobals(test); }); + this.on('hook end', function(hook){ self.checkGlobals(hook); }); + this.grep(/.*/); + this.globals(this.globalProps().concat(['errno'])); +} + +/** + * Wrapper for setImmediate, process.nextTick, or browser polyfill. + * + * @param {Function} fn + * @api private + */ + +Runner.immediately = global.setImmediate || process.nextTick; + +/** + * Inherit from `EventEmitter.prototype`. + */ + +function F(){}; +F.prototype = EventEmitter.prototype; +Runner.prototype = new F; +Runner.prototype.constructor = Runner; + + +/** + * Run tests with full titles matching `re`. Updates runner.total + * with number of tests matched. + * + * @param {RegExp} re + * @param {Boolean} invert + * @return {Runner} for chaining + * @api public + */ + +Runner.prototype.grep = function(re, invert){ + debug('grep %s', re); + this._grep = re; + this._invert = invert; + this.total = this.grepTotal(this.suite); + return this; +}; + +/** + * Returns the number of tests matching the grep search for the + * given suite. + * + * @param {Suite} suite + * @return {Number} + * @api public + */ + +Runner.prototype.grepTotal = function(suite) { + var self = this; + var total = 0; + + suite.eachTest(function(test){ + var match = self._grep.test(test.fullTitle()); + if (self._invert) match = !match; + if (match) total++; + }); + + return total; +}; + +/** + * Return a list of global properties. + * + * @return {Array} + * @api private + */ + +Runner.prototype.globalProps = function() { + var props = utils.keys(global); + + // non-enumerables + for (var i = 0; i < globals.length; ++i) { + if (~utils.indexOf(props, globals[i])) continue; + props.push(globals[i]); + } + + return props; +}; + +/** + * Allow the given `arr` of globals. + * + * @param {Array} arr + * @return {Runner} for chaining + * @api public + */ + +Runner.prototype.globals = function(arr){ + if (0 == arguments.length) return this._globals; + debug('globals %j', arr); + utils.forEach(arr, function(arr){ + this._globals.push(arr); + }, this); + return this; +}; + +/** + * Check for global variable leaks. + * + * @api private + */ + +Runner.prototype.checkGlobals = function(test){ + if (this.ignoreLeaks) return; + var ok = this._globals; + var globals = this.globalProps(); + var isNode = process.kill; + var leaks; + + // check length - 2 ('errno' and 'location' globals) + if (isNode && 1 == ok.length - globals.length) return; + else if (2 == ok.length - globals.length) return; + + if(this.prevGlobalsLength == globals.length) return; + this.prevGlobalsLength = globals.length; + + leaks = filterLeaks(ok, globals); + this._globals = this._globals.concat(leaks); + + if (leaks.length > 1) { + this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + '')); + } else if (leaks.length) { + this.fail(test, new Error('global leak detected: ' + leaks[0])); + } +}; + +/** + * Fail the given `test`. + * + * @param {Test} test + * @param {Error} err + * @api private + */ + +Runner.prototype.fail = function(test, err){ + ++this.failures; + test.state = 'failed'; + + if ('string' == typeof err) { + err = new Error('the string "' + err + '" was thrown, throw an Error :)'); + } + + this.emit('fail', test, err); +}; + +/** + * Fail the given `hook` with `err`. + * + * Hook failures (currently) hard-end due + * to that fact that a failing hook will + * surely cause subsequent tests to fail, + * causing jumbled reporting. + * + * @param {Hook} hook + * @param {Error} err + * @api private + */ + +Runner.prototype.failHook = function(hook, err){ + this.fail(hook, err); + this.emit('end'); +}; + +/** + * Run hook `name` callbacks and then invoke `fn()`. + * + * @param {String} name + * @param {Function} function + * @api private + */ + +Runner.prototype.hook = function(name, fn){ + var suite = this.suite + , hooks = suite['_' + name] + , self = this + , timer; + + function next(i) { + var hook = hooks[i]; + if (!hook) return fn(); + if (self.failures && suite.bail()) return fn(); + self.currentRunnable = hook; + + hook.ctx.currentTest = self.test; + + self.emit('hook', hook); + + hook.on('error', function(err){ + self.failHook(hook, err); + }); + + hook.run(function(err){ + hook.removeAllListeners('error'); + var testError = hook.error(); + if (testError) self.fail(self.test, testError); + if (err) return self.failHook(hook, err); + self.emit('hook end', hook); + delete hook.ctx.currentTest; + next(++i); + }); + } + + Runner.immediately(function(){ + next(0); + }); +}; + +/** + * Run hook `name` for the given array of `suites` + * in order, and callback `fn(err)`. + * + * @param {String} name + * @param {Array} suites + * @param {Function} fn + * @api private + */ + +Runner.prototype.hooks = function(name, suites, fn){ + var self = this + , orig = this.suite; + + function next(suite) { + self.suite = suite; + + if (!suite) { + self.suite = orig; + return fn(); + } + + self.hook(name, function(err){ + if (err) { + self.suite = orig; + return fn(err); + } + + next(suites.pop()); + }); + } + + next(suites.pop()); +}; + +/** + * Run hooks from the top level down. + * + * @param {String} name + * @param {Function} fn + * @api private + */ + +Runner.prototype.hookUp = function(name, fn){ + var suites = [this.suite].concat(this.parents()).reverse(); + this.hooks(name, suites, fn); +}; + +/** + * Run hooks from the bottom up. + * + * @param {String} name + * @param {Function} fn + * @api private + */ + +Runner.prototype.hookDown = function(name, fn){ + var suites = [this.suite].concat(this.parents()); + this.hooks(name, suites, fn); +}; + +/** + * Return an array of parent Suites from + * closest to furthest. + * + * @return {Array} + * @api private + */ + +Runner.prototype.parents = function(){ + var suite = this.suite + , suites = []; + while (suite = suite.parent) suites.push(suite); + return suites; +}; + +/** + * Run the current test and callback `fn(err)`. + * + * @param {Function} fn + * @api private + */ + +Runner.prototype.runTest = function(fn){ + var test = this.test + , self = this; + + if (this.asyncOnly) test.asyncOnly = true; + + try { + test.on('error', function(err){ + self.fail(test, err); + }); + test.run(fn); + } catch (err) { + fn(err); + } +}; + +/** + * Run tests in the given `suite` and invoke + * the callback `fn()` when complete. + * + * @param {Suite} suite + * @param {Function} fn + * @api private + */ + +Runner.prototype.runTests = function(suite, fn){ + var self = this + , tests = suite.tests.slice() + , test; + + function next(err) { + // if we bail after first err + if (self.failures && suite._bail) return fn(); + + // next test + test = tests.shift(); + + // all done + if (!test) return fn(); + + // grep + var match = self._grep.test(test.fullTitle()); + if (self._invert) match = !match; + if (!match) return next(); + + // pending + if (test.pending) { + self.emit('pending', test); + self.emit('test end', test); + return next(); + } + + // execute test and hook(s) + self.emit('test', self.test = test); + self.hookDown('beforeEach', function(){ + self.currentRunnable = self.test; + self.runTest(function(err){ + test = self.test; + + if (err) { + self.fail(test, err); + self.emit('test end', test); + return self.hookUp('afterEach', next); + } + + test.state = 'passed'; + self.emit('pass', test); + self.emit('test end', test); + self.hookUp('afterEach', next); + }); + }); + } + + this.next = next; + next(); +}; + +/** + * Run the given `suite` and invoke the + * callback `fn()` when complete. + * + * @param {Suite} suite + * @param {Function} fn + * @api private + */ + +Runner.prototype.runSuite = function(suite, fn){ + var total = this.grepTotal(suite) + , self = this + , i = 0; + + debug('run suite %s', suite.fullTitle()); + + if (!total) return fn(); + + this.emit('suite', this.suite = suite); + + function next() { + var curr = suite.suites[i++]; + if (!curr) return done(); + self.runSuite(curr, next); + } + + function done() { + self.suite = suite; + self.hook('afterAll', function(){ + self.emit('suite end', suite); + fn(); + }); + } + + this.hook('beforeAll', function(){ + self.runTests(suite, next); + }); +}; + +/** + * Handle uncaught exceptions. + * + * @param {Error} err + * @api private + */ + +Runner.prototype.uncaught = function(err){ + debug('uncaught exception %s', err.message); + var runnable = this.currentRunnable; + if (!runnable || 'failed' == runnable.state) return; + runnable.clearTimeout(); + err.uncaught = true; + this.fail(runnable, err); + + // recover from test + if ('test' == runnable.type) { + this.emit('test end', runnable); + this.hookUp('afterEach', this.next); + return; + } + + // bail on hooks + this.emit('end'); +}; + +/** + * Run the root suite and invoke `fn(failures)` + * on completion. + * + * @param {Function} fn + * @return {Runner} for chaining + * @api public + */ + +Runner.prototype.run = function(fn){ + var self = this + , fn = fn || function(){}; + + function uncaught(err){ + self.uncaught(err); + } + + debug('start'); + + // callback + this.on('end', function(){ + debug('end'); + process.removeListener('uncaughtException', uncaught); + fn(self.failures); + }); + + // run suites + this.emit('start'); + this.runSuite(this.suite, function(){ + debug('finished running'); + self.emit('end'); + }); + + // uncaught exception + process.on('uncaughtException', uncaught); + + return this; +}; + +/** + * Filter leaks with the given globals flagged as `ok`. + * + * @param {Array} ok + * @param {Array} globals + * @return {Array} + * @api private + */ + +function filterLeaks(ok, globals) { + return filter(globals, function(key){ + // Firefox and Chrome exposes iframes as index inside the window object + if (/^d+/.test(key)) return false; + + // in firefox + // if runner runs in an iframe, this iframe's window.getInterface method not init at first + // it is assigned in some seconds + if (global.navigator && /^getInterface/.test(key)) return false; + + // an iframe could be approached by window[iframeIndex] + // in ie6,7,8 and opera, iframeIndex is enumerable, this could cause leak + if (global.navigator && /^\d+/.test(key)) return false; + + // Opera and IE expose global variables for HTML element IDs (issue #243) + if (/^mocha-/.test(key)) return false; + + var matched = filter(ok, function(ok){ + if (~ok.indexOf('*')) return 0 == key.indexOf(ok.split('*')[0]); + return key == ok; + }); + return matched.length == 0 && (!global.navigator || 'onerror' !== key); + }); +} + +}); // module: runner.js + +require.register("suite.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var EventEmitter = require('browser/events').EventEmitter + , debug = require('browser/debug')('mocha:suite') + , milliseconds = require('./ms') + , utils = require('./utils') + , Hook = require('./hook'); + +/** + * Expose `Suite`. + */ + +exports = module.exports = Suite; + +/** + * Create a new `Suite` with the given `title` + * and parent `Suite`. When a suite with the + * same title is already present, that suite + * is returned to provide nicer reporter + * and more flexible meta-testing. + * + * @param {Suite} parent + * @param {String} title + * @return {Suite} + * @api public + */ + +exports.create = function(parent, title){ + var suite = new Suite(title, parent.ctx); + suite.parent = parent; + if (parent.pending) suite.pending = true; + title = suite.fullTitle(); + parent.addSuite(suite); + return suite; +}; + +/** + * Initialize a new `Suite` with the given + * `title` and `ctx`. + * + * @param {String} title + * @param {Context} ctx + * @api private + */ + +function Suite(title, ctx) { + this.title = title; + this.ctx = ctx; + this.suites = []; + this.tests = []; + this.pending = false; + this._beforeEach = []; + this._beforeAll = []; + this._afterEach = []; + this._afterAll = []; + this.root = !title; + this._timeout = 2000; + this._slow = 75; + this._bail = false; +} + +/** + * Inherit from `EventEmitter.prototype`. + */ + +function F(){}; +F.prototype = EventEmitter.prototype; +Suite.prototype = new F; +Suite.prototype.constructor = Suite; + + +/** + * Return a clone of this `Suite`. + * + * @return {Suite} + * @api private + */ + +Suite.prototype.clone = function(){ + var suite = new Suite(this.title); + debug('clone'); + suite.ctx = this.ctx; + suite.timeout(this.timeout()); + suite.slow(this.slow()); + suite.bail(this.bail()); + return suite; +}; + +/** + * Set timeout `ms` or short-hand such as "2s". + * + * @param {Number|String} ms + * @return {Suite|Number} for chaining + * @api private + */ + +Suite.prototype.timeout = function(ms){ + if (0 == arguments.length) return this._timeout; + if ('string' == typeof ms) ms = milliseconds(ms); + debug('timeout %d', ms); + this._timeout = parseInt(ms, 10); + return this; +}; + +/** + * Set slow `ms` or short-hand such as "2s". + * + * @param {Number|String} ms + * @return {Suite|Number} for chaining + * @api private + */ + +Suite.prototype.slow = function(ms){ + if (0 === arguments.length) return this._slow; + if ('string' == typeof ms) ms = milliseconds(ms); + debug('slow %d', ms); + this._slow = ms; + return this; +}; + +/** + * Sets whether to bail after first error. + * + * @parma {Boolean} bail + * @return {Suite|Number} for chaining + * @api private + */ + +Suite.prototype.bail = function(bail){ + if (0 == arguments.length) return this._bail; + debug('bail %s', bail); + this._bail = bail; + return this; +}; + +/** + * Run `fn(test[, done])` before running tests. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.beforeAll = function(fn){ + if (this.pending) return this; + var hook = new Hook('"before all" hook', fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.slow(this.slow()); + hook.ctx = this.ctx; + this._beforeAll.push(hook); + this.emit('beforeAll', hook); + return this; +}; + +/** + * Run `fn(test[, done])` after running tests. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.afterAll = function(fn){ + if (this.pending) return this; + var hook = new Hook('"after all" hook', fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.slow(this.slow()); + hook.ctx = this.ctx; + this._afterAll.push(hook); + this.emit('afterAll', hook); + return this; +}; + +/** + * Run `fn(test[, done])` before each test case. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.beforeEach = function(fn){ + if (this.pending) return this; + var hook = new Hook('"before each" hook', fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.slow(this.slow()); + hook.ctx = this.ctx; + this._beforeEach.push(hook); + this.emit('beforeEach', hook); + return this; +}; + +/** + * Run `fn(test[, done])` after each test case. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.afterEach = function(fn){ + if (this.pending) return this; + var hook = new Hook('"after each" hook', fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.slow(this.slow()); + hook.ctx = this.ctx; + this._afterEach.push(hook); + this.emit('afterEach', hook); + return this; +}; + +/** + * Add a test `suite`. + * + * @param {Suite} suite + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.addSuite = function(suite){ + suite.parent = this; + suite.timeout(this.timeout()); + suite.slow(this.slow()); + suite.bail(this.bail()); + this.suites.push(suite); + this.emit('suite', suite); + return this; +}; + +/** + * Add a `test` to this suite. + * + * @param {Test} test + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.addTest = function(test){ + test.parent = this; + test.timeout(this.timeout()); + test.slow(this.slow()); + test.ctx = this.ctx; + this.tests.push(test); + this.emit('test', test); + return this; +}; + +/** + * Return the full title generated by recursively + * concatenating the parent's full title. + * + * @return {String} + * @api public + */ + +Suite.prototype.fullTitle = function(){ + if (this.parent) { + var full = this.parent.fullTitle(); + if (full) return full + ' ' + this.title; + } + return this.title; +}; + +/** + * Return the total number of tests. + * + * @return {Number} + * @api public + */ + +Suite.prototype.total = function(){ + return utils.reduce(this.suites, function(sum, suite){ + return sum + suite.total(); + }, 0) + this.tests.length; +}; + +/** + * Iterates through each suite recursively to find + * all tests. Applies a function in the format + * `fn(test)`. + * + * @param {Function} fn + * @return {Suite} + * @api private + */ + +Suite.prototype.eachTest = function(fn){ + utils.forEach(this.tests, fn); + utils.forEach(this.suites, function(suite){ + suite.eachTest(fn); + }); + return this; +}; + +}); // module: suite.js + +require.register("test.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Runnable = require('./runnable'); + +/** + * Expose `Test`. + */ + +module.exports = Test; + +/** + * Initialize a new `Test` with the given `title` and callback `fn`. + * + * @param {String} title + * @param {Function} fn + * @api private + */ + +function Test(title, fn) { + Runnable.call(this, title, fn); + this.pending = !fn; + this.type = 'test'; +} + +/** + * Inherit from `Runnable.prototype`. + */ + +function F(){}; +F.prototype = Runnable.prototype; +Test.prototype = new F; +Test.prototype.constructor = Test; + + +}); // module: test.js + +require.register("utils.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var fs = require('browser/fs') + , path = require('browser/path') + , join = path.join + , debug = require('browser/debug')('mocha:watch'); + +/** + * Ignored directories. + */ + +var ignore = ['node_modules', '.git']; + +/** + * Escape special characters in the given string of html. + * + * @param {String} html + * @return {String} + * @api private + */ + +exports.escape = function(html){ + return String(html) + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(//g, '>'); +}; + +/** + * Array#forEach (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @param {Object} scope + * @api private + */ + +exports.forEach = function(arr, fn, scope){ + for (var i = 0, l = arr.length; i < l; i++) + fn.call(scope, arr[i], i); +}; + +/** + * Array#indexOf (<=IE8) + * + * @parma {Array} arr + * @param {Object} obj to find index of + * @param {Number} start + * @api private + */ + +exports.indexOf = function(arr, obj, start){ + for (var i = start || 0, l = arr.length; i < l; i++) { + if (arr[i] === obj) + return i; + } + return -1; +}; + +/** + * Array#reduce (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @param {Object} initial value + * @api private + */ + +exports.reduce = function(arr, fn, val){ + var rval = val; + + for (var i = 0, l = arr.length; i < l; i++) { + rval = fn(rval, arr[i], i, arr); + } + + return rval; +}; + +/** + * Array#filter (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @api private + */ + +exports.filter = function(arr, fn){ + var ret = []; + + for (var i = 0, l = arr.length; i < l; i++) { + var val = arr[i]; + if (fn(val, i, arr)) ret.push(val); + } + + return ret; +}; + +/** + * Object.keys (<=IE8) + * + * @param {Object} obj + * @return {Array} keys + * @api private + */ + +exports.keys = Object.keys || function(obj) { + var keys = [] + , has = Object.prototype.hasOwnProperty // for `window` on <=IE8 + + for (var key in obj) { + if (has.call(obj, key)) { + keys.push(key); + } + } + + return keys; +}; + +/** + * Watch the given `files` for changes + * and invoke `fn(file)` on modification. + * + * @param {Array} files + * @param {Function} fn + * @api private + */ + +exports.watch = function(files, fn){ + var options = { interval: 100 }; + files.forEach(function(file){ + debug('file %s', file); + fs.watchFile(file, options, function(curr, prev){ + if (prev.mtime < curr.mtime) fn(file); + }); + }); +}; + +/** + * Ignored files. + */ + +function ignored(path){ + return !~ignore.indexOf(path); +} + +/** + * Lookup files in the given `dir`. + * + * @return {Array} + * @api private + */ + +exports.files = function(dir, ret){ + ret = ret || []; + + fs.readdirSync(dir) + .filter(ignored) + .forEach(function(path){ + path = join(dir, path); + if (fs.statSync(path).isDirectory()) { + exports.files(path, ret); + } else if (path.match(/\.(js|coffee|litcoffee|coffee.md)$/)) { + ret.push(path); + } + }); + + return ret; +}; + +/** + * Compute a slug from the given `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +exports.slug = function(str){ + return str + .toLowerCase() + .replace(/ +/g, '-') + .replace(/[^-\w]/g, ''); +}; + +/** + * Strip the function definition from `str`, + * and re-indent for pre whitespace. + */ + +exports.clean = function(str) { + str = str + .replace(/^function *\(.*\) *{/, '') + .replace(/\s+\}$/, ''); + + var whitespace = str.match(/^\n?(\s*)/)[1] + , re = new RegExp('^' + whitespace, 'gm'); + + str = str.replace(re, ''); + + return exports.trim(str); +}; + +/** + * Escape regular expression characters in `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +exports.escapeRegexp = function(str){ + return str.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&"); +}; + +/** + * Trim the given `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +exports.trim = function(str){ + return str.replace(/^\s+|\s+$/g, ''); +}; + +/** + * Parse the given `qs`. + * + * @param {String} qs + * @return {Object} + * @api private + */ + +exports.parseQuery = function(qs){ + return exports.reduce(qs.replace('?', '').split('&'), function(obj, pair){ + var i = pair.indexOf('=') + , key = pair.slice(0, i) + , val = pair.slice(++i); + + obj[key] = decodeURIComponent(val); + return obj; + }, {}); +}; + +/** + * Highlight the given string of `js`. + * + * @param {String} js + * @return {String} + * @api private + */ + +function highlight(js) { + return js + .replace(//g, '>') + .replace(/\/\/(.*)/gm, '//$1') + .replace(/('.*?')/gm, '$1') + .replace(/(\d+\.\d+)/gm, '$1') + .replace(/(\d+)/gm, '$1') + .replace(/\bnew *(\w+)/gm, 'new $1') + .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '$1') +} + +/** + * Highlight the contents of tag `name`. + * + * @param {String} name + * @api private + */ + +exports.highlightTags = function(name) { + var code = document.getElementsByTagName(name); + for (var i = 0, len = code.length; i < len; ++i) { + code[i].innerHTML = highlight(code[i].innerHTML); + } +}; + +}); // module: utils.js +// The global object is "self" in Web Workers. +global = (function() { return this; })(); + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date; +var setTimeout = global.setTimeout; +var setInterval = global.setInterval; +var clearTimeout = global.clearTimeout; +var clearInterval = global.clearInterval; + +/** + * Node shims. + * + * These are meant only to allow + * mocha.js to run untouched, not + * to allow running node code in + * the browser. + */ + +var process = {}; +process.exit = function(status){}; +process.stdout = {}; + +/** + * Remove uncaughtException listener. + */ + +process.removeListener = function(e){ + if ('uncaughtException' == e) { + global.onerror = function() {}; + } +}; + +/** + * Implements uncaughtException listener. + */ + +process.on = function(e, fn){ + if ('uncaughtException' == e) { + global.onerror = function(err, url, line){ + fn(new Error(err + ' (' + url + ':' + line + ')')); + }; + } +}; + +/** + * Expose mocha. + */ + +var Mocha = global.Mocha = require('mocha'), + mocha = global.mocha = new Mocha({ reporter: 'html' }); + +var immediateQueue = [] + , immediateTimeout; + +function timeslice() { + var immediateStart = new Date().getTime(); + while (immediateQueue.length && (new Date().getTime() - immediateStart) < 100) { + immediateQueue.shift()(); + } + if (immediateQueue.length) { + immediateTimeout = setTimeout(timeslice, 0); + } else { + immediateTimeout = null; + } +} + +/** + * High-performance override of Runner.immediately. + */ + +Mocha.Runner.immediately = function(callback) { + immediateQueue.push(callback); + if (!immediateTimeout) { + immediateTimeout = setTimeout(timeslice, 0); + } +}; + +/** + * Override ui to ensure that the ui functions are initialized. + * Normally this would happen in Mocha.prototype.loadFiles. + */ + +mocha.ui = function(ui){ + Mocha.prototype.ui.call(this, ui); + this.suite.emit('pre-require', global, null, this); + return this; +}; + +/** + * Setup mocha with the given setting options. + */ + +mocha.setup = function(opts){ + if ('string' == typeof opts) opts = { ui: opts }; + for (var opt in opts) this[opt](opts[opt]); + return this; +}; + +/** + * Run mocha, returning the Runner. + */ + +mocha.run = function(fn){ + var options = mocha.options; + mocha.globals('location'); + + var query = Mocha.utils.parseQuery(global.location.search || ''); + if (query.grep) mocha.grep(query.grep); + if (query.invert) mocha.invert(); + + return Mocha.prototype.run.call(mocha, function(){ + // The DOM Document is not available in Web Workers. + if (global.document) { + Mocha.utils.highlightTags('code'); + } + if (fn) fn(); + }); +}; + +/** + * Expose the process shim. + */ + +Mocha.process = process; +})(); \ No newline at end of file