mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-02-02 08:07:50 +00:00
206 lines
6.7 KiB
JavaScript
206 lines
6.7 KiB
JavaScript
var _ = require('lodash'),
|
|
j = require('jscodeshift'),
|
|
Entry = require('docdown/lib/entry');
|
|
|
|
var baseGetParams = Entry.prototype.getParams;
|
|
|
|
// Function copied from docdown/lib/entry that is not exported.
|
|
function getMultilineValue(string, tagName) {
|
|
var prelude = tagName == 'description' ? '^ */\\*\\*(?: *\\n *\\* *)?' : ('^ *\\*[\\t ]*@' + _.escapeRegExp(tagName) + '\\b'),
|
|
postlude = '(?=\\*\\s+\\@[a-z]|\\*/)',
|
|
result = _.result(RegExp(prelude + '([\\s\\S]*?)' + postlude, 'gm').exec(string), 1, '');
|
|
|
|
return _.trim(result.replace(RegExp('(?:^|\\n)[\\t ]*\\*[\\t ]' + (tagName == 'example' ? '?' : '*'), 'g'), '\n'));
|
|
}
|
|
|
|
/**
|
|
* Extracts the entry's `name` data.
|
|
* Sub-part of Entry.prototype.getCall() that fetches the name. Using `Entry.prototype.getCall()`
|
|
* makes a call to getParams(), which itself call getBaseName --> infinite recursion.
|
|
*
|
|
* @param {Object} entry Entry whose name to extract.
|
|
* @returns {string} The entry's `name` data.
|
|
*/
|
|
function getBaseName(entry) {
|
|
var result = /\*\/\s*(?:function\s+([^(]*)|(.*?)(?=[:=,]))/.exec(entry);
|
|
if (result) {
|
|
result = (result[1] || result[2]).split('.').pop();
|
|
result = _.trim(_.trim(result), "'").split('var ').pop();
|
|
result = _.trim(result);
|
|
}
|
|
// Get the function name.
|
|
return _.result(/\*[\t ]*@name\s+(.+)/.exec(entry), 1, result || '');
|
|
}
|
|
|
|
/**
|
|
* Returns the new ary of a given function.
|
|
*
|
|
* @param {Object} mapping Mapping object that defines the arity of all functions.
|
|
* @param {String} name Name of the function associated to the call/function definition.
|
|
* @return {number} Ary of the function as an integer
|
|
*/
|
|
function getMethodAry(mapping, name) {
|
|
var ary = _.reduce(mapping.aryMethod, function(res, value, key) {
|
|
if (res) {
|
|
return res;
|
|
}
|
|
return _.includes(value, name) && key;
|
|
}, '');
|
|
return _.parseInt(ary);
|
|
}
|
|
|
|
/**
|
|
* Reorders `params` for a given function definition/call.
|
|
*
|
|
* @param {Object} mapping Mapping object that defines if and how the `params` will be reordered.
|
|
* @param {String} name Name of the function associated to the call/function definition.
|
|
* @param {*[]} params Parameters/arguments to reorder.
|
|
* @returns {*[]} Reordered parameters/arguments.
|
|
*/
|
|
function reorderParams(mapping, name, params) {
|
|
// Check if reordering is needed.
|
|
if (!mapping || mapping.skipRearg[name]) {
|
|
return params;
|
|
}
|
|
var reargOrder = mapping.methodRearg[name] || mapping.aryRearg[params.length];
|
|
if (!reargOrder) {
|
|
return params;
|
|
}
|
|
// Reorder params.
|
|
var newParams = [];
|
|
reargOrder.forEach(function(newPosition, index) {
|
|
newParams[newPosition] = params[index];
|
|
});
|
|
return newParams;
|
|
}
|
|
|
|
var dotsRegex = /^\.\.\./;
|
|
var parensRegex = /^\((.*)\)$/;
|
|
var arrayRegex = /\[\]$/;
|
|
|
|
/**
|
|
* Replace parameter type from something like `...number` to `number|number[]`.
|
|
*
|
|
* @param {string[]} param Array whose first item is a description of the parameter type.
|
|
* @return {string[]} `param` with the updated type.
|
|
*/
|
|
function removeDotsFromType(param) {
|
|
var type = param[0];
|
|
if (!type.startsWith('...')) {
|
|
return param;
|
|
}
|
|
|
|
var newType = _.chain(type)
|
|
.replace(dotsRegex, '')
|
|
.replace(parensRegex, '$1')
|
|
.split('|')
|
|
.map(function(s) {
|
|
return s.replace(arrayRegex, '');
|
|
})
|
|
.uniq()
|
|
.thru(function(array) {
|
|
if (array.length > 1) {
|
|
return '(' + array.join('|') + ')';
|
|
}
|
|
return array;
|
|
})
|
|
.thru(function(subtypes) {
|
|
return subtypes + '|' + subtypes + '[]';
|
|
})
|
|
.value();
|
|
|
|
return [newType].concat(_.tail(param));
|
|
}
|
|
|
|
function updateParamsDescription(mapping, entry, params) {
|
|
var paramsWithoutDots = params.map(removeDotsFromType);
|
|
return reorderParams(mapping, getBaseName(entry), paramsWithoutDots);
|
|
}
|
|
|
|
/**
|
|
* Returns a function that extracts the entry's `param` data, reordered according to `mapping`.
|
|
*
|
|
* @param {Object} mapping Mapping object that defines if and how the `params` will be reordered.
|
|
* @returns {Function} Function that returns the entry's `param` data.
|
|
*/
|
|
function getReorderedParams(mapping) {
|
|
return function(index) {
|
|
if (!this._params) {
|
|
// Call baseGetParams in order to compute `this._params`.
|
|
baseGetParams.call(this);
|
|
// Reorder params according to the `mapping`.
|
|
this._params = updateParamsDescription(mapping, this.entry, this._params);
|
|
}
|
|
return baseGetParams.call(this, index);
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Concatenate arguments into an array of arguments.
|
|
* For a `function fn(a, b, ...args) { ... }` with an arity of 3,
|
|
* when called with `args` [a, b, c, d, e, f], returns [a, b, [c, d, e, f]].
|
|
*
|
|
* @param {object} j JSCodeShift object.
|
|
* @param {Object} mapping Mapping object that defines if and how the arguments will be reordered.
|
|
* @param {String} name Name of the function associated to the call/function definition.
|
|
* @param {ASTobjects[]} Arguments to concatenate.
|
|
* @return {ASTobjects[]} Concatenated arguments
|
|
*/
|
|
function concatExtraArgs(j, mapping, name, args) {
|
|
var ary = getMethodAry(mapping, name);
|
|
if (ary === args.length) {
|
|
return args;
|
|
}
|
|
return _.take(args, ary - 1).concat(
|
|
j.arrayExpression(_.takeRight(args, args.length - ary + 1))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Updates a code sample so that the arguments in the call are reordered according to `mapping`.
|
|
*
|
|
* @param {Object} mapping Mapping object that defines if and how the arguments will be reordered.
|
|
* @param {string} codeSample Code sample to update.
|
|
* @returns {string} Updated code sample.
|
|
*/
|
|
function reorderParamsInExample(mapping, codeSample) {
|
|
return j(codeSample)
|
|
.find(j.CallExpression, { callee: { object: {name: '_' }}})
|
|
.replaceWith(function(callExpr) {
|
|
var value = callExpr.value;
|
|
var name = value.callee.property.name;
|
|
var args = concatExtraArgs(j, mapping, name, value.arguments);
|
|
return j.callExpression(
|
|
value.callee,
|
|
reorderParams(mapping, name, args)
|
|
);
|
|
})
|
|
.toSource();
|
|
}
|
|
|
|
/**
|
|
* Returns a function that extracts the entry's `example` data,
|
|
* where function call arguments are reordered according to `mapping`.
|
|
*
|
|
* @param {Object} mapping Mapping object that defines if and how the `params` will be reordered.
|
|
* @returns {Function} Function that returns the entry's `example` data.
|
|
*/
|
|
function getReorderedExample(mapping) {
|
|
return function() {
|
|
var result = getMultilineValue(this.entry, 'example');
|
|
if (!result) {
|
|
return result;
|
|
}
|
|
var resultReordered = reorderParamsInExample(mapping, result);
|
|
return '```' + this.lang + '\n' + resultReordered + '\n```';
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Updates `docdown` `Entry`'s prototype so that parameters/arguments are reordered according to `mapping`.
|
|
*/
|
|
module.exports = function applyFPMapping(mapping) {
|
|
Entry.prototype.getParams = getReorderedParams(mapping);
|
|
Entry.prototype.getExample = getReorderedExample(mapping);
|
|
};
|