diff --git a/lib/doc/apply-fp-mapping.js b/lib/doc/apply-fp-mapping.js index 1f26088ce..ede0d239f 100644 --- a/lib/doc/apply-fp-mapping.js +++ b/lib/doc/apply-fp-mapping.js @@ -32,6 +32,23 @@ function getBaseName(entry) { 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. * @@ -57,6 +74,49 @@ function reorderParams(mapping, name, params) { 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`. * @@ -69,12 +129,33 @@ function getReorderedParams(mapping) { // Call baseGetParams in order to compute `this._params`. baseGetParams.call(this); // Reorder params according to the `mapping`. - this._params = reorderParams(mapping, getBaseName(this.entry), this._params); + 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`. * @@ -87,9 +168,11 @@ function reorderParamsInExample(mapping, 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, value.callee.property.name, value.arguments) + reorderParams(mapping, name, args) ); }) .toSource();