Refactored the API, moving it into a single api.js file which can be

exluded from a build if desired.
This commit is contained in:
Spencer Alger
2013-10-23 06:24:02 -07:00
parent b063dfdca7
commit 01763c2c39
102 changed files with 4097 additions and 8459 deletions

View File

@ -1,63 +0,0 @@
module.exports = {
'cluster.node_hot_threads': [
'/_cluster/nodes/hotthreads',
'/_cluster/nodes/hot_threads',
'/_nodes/hot_threads',
'/_cluster/nodes/{node_id}/hotthreads',
'/_cluster/nodes/{node_id}/hot_threads',
'/_nodes/{node_id}/hot_threads'
],
'cluster.node_info': [
'/_cluster/nodes',
'/_nodes/settings',
'/_nodes/os',
'/_nodes/process',
'/_nodes/jvm',
'/_nodes/thread_pool',
'/_nodes/network',
'/_nodes/transport',
'/_nodes/http',
'/_nodes/plugin',
'/_cluster/nodes/{node_id}',
'/_nodes/{node_id}/settings',
'/_nodes/{node_id}/os',
'/_nodes/{node_id}/process',
'/_nodes/{node_id}/jvm',
'/_nodes/{node_id}/thread_pool',
'/_nodes/{node_id}/network',
'/_nodes/{node_id}/transport',
'/_nodes/{node_id}/http',
'/_nodes/{node_id}/plugin'
],
'cluster.node_shutdown': [
'/_cluster/nodes/_shutdown'
],
'cluster.node_stats': [
'/_cluster/nodes/stats',
'/_nodes/stats/{metric_family}',
'/_nodes/stats/indices/{metric}/{fields}',
'/_cluster/nodes/{node_id}/stats',
'/_nodes/{node_id}/stats/{metric_family}',
'/_nodes/{node_id}/stats/indices/{metric}/{fields}'
],
'get': [
'/{index}/{type}/{id}/_source'
],
'indices.delete_mapping': [
'/{index}/{type}/_mapping'
],
'indices.stats': [
'_stats/{metric_family}',
'/_stats/indexing',
'/_stats/indexing/{indexing_types}',
'/_stats/search/{search_groups}',
'/_stats/fielddata/{fields}',
'/{index}/_stats/{metric_family}',
'/{index}/_stats/indexing',
'/{index}/_stats/search/{search_groups}',
'/{index}/_stats/fielddata/{fields}'
],
'search': [
'/_search'
]
};

View File

@ -1,59 +0,0 @@
var _ = require('../../../src/lib/utils')
, asset = require('assert')
, path = require('path')
, fs = require('fs')
, mkdirp = require('mkdirp')
, docs = _.requireDir(module, '../../../es_api_spec/api')
, outputDir = _.joinPath(__dirname, '../../../src/api/')
, templates = require('./templates')
, notes = require('./notes')
, aliases = require('./aliases');
// completely delete the output directory
(function clean(path) {
if (fs.existsSync(path)) {
fs.readdirSync(path).forEach(function (file, index) {
var curPath = path + '/' + file;
if (fs.statSync(curPath).isDirectory()) { // recurse
clean(curPath);
} else { // delete file
fs.unlinkSync(curPath);
}
});
fs.rmdirSync(path);
}
})(outputDir);
// itterate all of the found docs
_.each(docs, function (doc) {
// and each definition within each doc (should only be one)
_.each(doc, function (def, name) {
var steps = name.split('.')
, fileName = steps.pop() + '.js'
, dirName = _.joinPath(outputDir, steps.join('/') || './');
var spec = {
name: name,
methods: _.map(def.methods, function (m) { return m.toUpperCase(); }),
docUrl: def.documentation,
urlParts: def.url.parts,
params: def.url.params,
urls: _.difference(def.url.paths, aliases[name]),
body: def.body || null,
path2lib: _.repeat('../', steps.length + 1) + 'lib/',
notes: notes[name]
};
spec.enumOptions = _.object(_.filter(_.map(_.pairs(_.extend({}, spec.params, spec.urlParts)), function (pair) {
// pair = [name, param];
if (pair[1].type === 'enum') {
return [_.camelCase(pair[0]), pair[1].options];
}
})));
mkdirp.sync(dirName);
fs.writeFileSync(_.joinPath(dirName, fileName), templates.action(spec));
});
});

View File

@ -1,2 +0,0 @@
// exports['cluster.node_info'] =
// '//TODO: this enpoint ***needs*** work, many of the possible urls are not supported';

View File

@ -1,74 +0,0 @@
var _ = require('<%= path2lib %>utils'),
errors = require('<%= path2lib %>errors'),
q = require('q');<%
if (_.keys(enumOptions).length) {
%>
<% _.each(enumOptions, function(options, name) {
%>
var <%= name %>Options = <%= stringify(options) %>;<%
});
}
%>
/**
* Perform an elasticsearch [<%= name %>](<%= docUrl %>) request
*
* @for Client
* @method <%= name %>
* @param {Object} params - An object with parameters used to carry out this action<% _.each(params, function(param, paramName) { %>
* @param {<%= paramType(param.type) %>} <%= paramWithDefault('params.' + paramName, param.default) %><% if (param.description) { %> - <%= param.description %><% } %><%
})
%>
*/
function do<%= _.studlyCase(name) %>(params, cb) {
if (typeof params === 'function') {
cb = params;
params = {};
} else {
params = params || {};
cb = typeof cb === 'function' ? cb : _.noop;
}
var request = {
<%= writeRequestObjectBody(6, name, body, methods) %>
},
parts = {},
query = {},
responseOpts = {};
<%
if (methods.length > 1) { %>
// figure out the method
if (params.method = _.toUpperString(params.method)) {
if (<%= _.map(methods, function (method) { return 'params.method === ' + stringify(method) }).join(' || ') %>) {
request.method = params.method;
} else {
throw new TypeError('Invalid method: should be one of <%= methods.join(', ') %>');
}
} else {<%
if (_.contains(methods, 'GET')) {
var nonGet = _.find(methods, function (m) {return m !== 'GET'; });%>
request.method = params.body ? <%= stringify(nonGet) %> : 'GET';<%
} else {%>
request.method = <%= stringify(methods[0]) %>;<%
}%>
}<%
}
%>
// find the paths's params
<%= writeParams(2, urlParts, 'parts.') %>
// build the path
<%= writeUrls(2, urls, urlParts, params) %>
// build the query string
<%= writeParams(2, params, 'query.') %>
request.path = request.path + _.makeQueryString(query);
<%= returnStatement(2, name) %>
}
module.exports = do<%= _.studlyCase(name) %>;

View File

@ -1 +0,0 @@
<%= set %> = <%= get %>;

View File

@ -1,7 +0,0 @@
if (<%= get %>.toLowerCase && (<%= get %> = <%= get %>.toLowerCase())
&& (<%= get %> === 'no' || <%= get %> === 'off')
) {
<%= set %> = false;
} else {
<%= set %> = !!<%= get %>;
}

View File

@ -1,5 +0,0 @@
if (_.isNumeric(<%= get %>) || _.isInterval(<%= get %>)) {
<%= set %> = <%= get %>;
} else {
throw new TypeError('Invalid <%= name %>: ' + <%= get %> + ' should be a number or in interval notation (an integer followed by one of Mwdhmsy).');
}

View File

@ -1,8 +0,0 @@
if (_.contains(<%= _.camelCase(name) %>Options, <%= get %>)) {
<%= set %> = <%= get %>;
} else {
throw new TypeError(
'Invalid <%= name %>: ' + <%= get %> +
' should be one of ' + <%= _.camelCase(name) %>Options.join(', ') + '.'
);
}

View File

@ -1,261 +0,0 @@
var _ = require('../../../../src/lib/utils')
, fs = require('fs')
, path = require('path')
, urlParamRE = /\{(\w+)\}/g;
/**
* Simple manager to take care of indentation
* @param {number} i - Width of the indentation
* @return {function} - Call this to add a new line to the output
*/
function lines(i) {
function l(line) {
if (line === '') {
// no indent on empty lines
l.lines.push('');
} else if (typeof line !== 'undefined') {
l.lines.push(_.repeat(' ', l.indent) + line);
}
return l;
}
l.lines = [];
l.indent = i || 0;
l.split = function (toSplit) {
_.each(_.filter(toSplit.split(/\r|\n/)), l);
return l;
};
l.in = function (line) {
l.indent += 2;
return l(line);
};
l.out = function (line) {
l.indent -= 2;
return l(line);
};
l.toString = function () {
return l.lines.join('\n');
};
return l;
}
function stringify(thing) {
return JSON.stringify(thing)
.replace('\'', '\\\'')
.replace(/\\?"/g, function (quote) {
// replace external (unescaped) double quotes with single quotes
return quote === '\\"' ? '"' : '\'';
})
// inject a space between array parts
.replace(/([^\\])','/g, '$1\', \'');
}
/**
* We'll collect the templates here
* @type {Object}
*/
var templates = {};
/**
* These keys will be available as local variables to each template
* @type {Object}
*/
var templateGlobals = {
writeParams: function (indent, params, namespace) {
var l = lines(indent);
_.each(params, function (param, name) {
if (!param.required) {
l('if (typeof params.' + name + ' !== \'undefined\') {').in();
}
l.split(templates[param.type || 'any']({
get: 'params.' + name,
set: namespace + name,
name: name
}));
if (!param.required) {
l.out();
l('}');
}
l('');
});
return l.toString();
},
writeUrls: function (indent, urls, urlParams, queryStringParams) {
var l = lines(indent);
function urlVarIsRequired(varDetails) {
varDetails = typeof varDetails === 'string' ? urlParams[varDetails] : varDetails;
return varDetails && (varDetails.required || !varDetails.default);
}
// turn a url string into an object describing the url, then sort them in decending order by how many args they have
urls = _.sortBy(urls, function (url) {
var requiredVars = _.filter(_.collectMatches(url, urlParamRE), function (match) {
return urlVarIsRequired(urlParams[match[1]]);
});
return requiredVars ? requiredVars.length * -1 : 0;
});
_.each(urls, function (url, urlIndex) {
// collect the vars from the url and replace them to form the js that will build the url
var makeL = lines(), vars = [];
makeL('request.path = \'' + url.replace(urlParamRE, function (match, varName) {
var varDetails = urlParams[varName];
varDetails.name = varName;
vars.push(varDetails);
if (urlVarIsRequired(varDetails)) {
return '\' + encodeURIComponent(parts.' + varName + ') + \'';
} else {
return '\' + encodeURIComponent(parts.' + varName + ' || ' + stringify(varDetails.default) + ') + \'';
}
}) + '\';');
makeL(_.filter(_.map(vars, function (v, i) {
if (_.has(queryStringParams, v.name)) {
// delete the param so that it's not used later on in the queryString
return 'delete params.' + v.name + ';';
}
})).join(' '));
if (vars.length || urlIndex) {
var requiredVars = _.filter(vars, urlVarIsRequired);
var condition = _.map(requiredVars, function (v) {
return 'parts.hasOwnProperty(\'' + v.name + '\')';
}).join(' && ');
l((urlIndex > 0 ? 'else ' : '') + (condition ? 'if (' + condition + ') ' : '') + '{')
.in()
.split(makeL.toString())
.out('}');
if (urlIndex === urls.length - 1 && condition) {
l('else {')
.in('throw new TypeError(\'Unable to build a path with those params. Supply at least ' +
vars.join(', ') + '\');'
)
.out('}');
}
} else {
l.split(makeL.toString());
}
});
l('');
return l.toString();
},
writeRequestObjectBody: function (indent, name, body, methods) {
var parts = [], l = lines(indent);
if (~name.indexOf('exists')) {
parts.push('ignore: _.union([404], params.ignore)');
} else {
parts.push('ignore: params.ignore');
}
if (body) {
if (_.contains(['bulk', 'msearch'], name)) {
parts.push('body: this.client.config.serializer.bulkBody(params.body || null)');
} else {
parts.push('body: params.body || null');
}
}
if (methods.length === 1) {
parts.push('method: ' + stringify(methods[0]));
}
_.each(parts, function (part, i) {
l(part + (i < parts.length - 1 ? ',' : ''));
});
return l.toString();
},
/**
* we want strings in code to use single-quotes, so this will JSON encode vars, but then
* modify them to follow our code standards.
*
* @param {*} thing - Any thing
* @return {String} - our pretty string
*/
stringify: stringify,
_: _,
paramType: function (type) {
switch (type && type.toLowerCase ? type.toLowerCase() : 'any') {
case 'time':
return 'Date|Number';
case 'any':
return '*';
case 'enum':
return 'String';
case 'list':
return 'String|ArrayOfStrings|Boolean';
default:
return type;
}
},
paramWithDefault: function (name, def) {
if (def) {
return '[' + name + '=' + def + ']';
} else {
return name;
}
},
returnStatement: function (indent, name) {
var l = lines(indent);
if (name.match(/(^|\.)exists/)) {
l('this.client.request(request, function (err, response) {')
.in('if (err instanceof errors.NotFound) {')
.in('cb(err, false);')
.out('} else {')
.in('cb(err, true);')
.out('}')
.out('});');
} else {
l('this.client.request(request, cb);');
}
return l.toString();
}
};
fs.readdirSync(path.resolve(__dirname)).forEach(function (filename) {
var name = filename.replace(/\..+$/, '');
if (name !== 'index') {
templates[name] = _.template(
fs.readFileSync(path.resolve(__dirname, filename), {
encoding: 'utf8'
}),
null,
{
imports: templateGlobals
}
);
}
});
templates.text = templates.string;
module.exports = {
action: templates.action,
urlParamRE: urlParamRE
};

View File

@ -1,14 +0,0 @@
switch (typeof <%= get %>) {
case 'string':
<%= set %> = <%= get %>;
break;
case 'object':
if (_.isArray(<%= get %>)) {
<%= set %> = <%= get %>.join(',');
} else {
throw new TypeError('Invalid <%= name %>: ' + <%= get %> + ' should be a comma seperated list, array, or boolean.');
}
break;
default:
<%= set %> = !!<%= get %>;
}

View File

@ -1,5 +0,0 @@
if (_.isNumeric(<%= get %>)) {
<%= set %> = <%= get %> * 1;
} else {
throw new TypeError('Invalid <%= name %>: ' + <%= get %> + ' should be a number.');
}

View File

@ -1,5 +0,0 @@
if (typeof <%= get %> !== 'object' && <%= get %>) {
<%= set %> = '' + <%= get %>;
} else {
throw new TypeError('Invalid <%= name %>: ' + <%= get %> + ' should be a string.');
}

View File

@ -1,7 +0,0 @@
if (<%= get %> instanceof Date) {
<%= set %> = <%= get %>.getTime();
} else if (_.isNumeric(<%= get %>)) {
<%= set %> = <%= get %>;
} else {
throw new TypeError('Invalid <%= name %>: ' + <%= get %> + ' should be be some sort of time.');
}

View File

@ -87,7 +87,7 @@ exports.make = function (startingMoment, endingMoment) {
'apache': 4
});
return _.map(sets, function (set, name) {
return _.bindKey(set, 'get');
});
return _.transform(sets, function (note, set, name) {
note[name] = _.bindKey(set, 'get');
}, {});
};