mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-02-01 23:57:49 +00:00
fp docs - Split lib/doc/apply-fp-mapping into multiples files.
This commit is contained in:
committed by
John-David Dalton
parent
39735df82f
commit
6f4099c20b
@@ -1,485 +0,0 @@
|
||||
var _ = require('lodash'),
|
||||
j = require('jscodeshift'),
|
||||
recast = require('recast'),
|
||||
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'));
|
||||
|
||||
}
|
||||
|
||||
// Function copied from docdown/lib/entry that is not exported.
|
||||
function hasTag(string, tagName) {
|
||||
tagName = tagName == '*' ? '\\w+' : _.escapeRegExp(tagName);
|
||||
return RegExp('^ *\\*[\\t ]*@' + tagName + '\\b', 'm').test(string);
|
||||
}
|
||||
|
||||
function isWrapped(entry) {
|
||||
return !hasTag(entry, 'static');
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract 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 || '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return 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.
|
||||
* @param {boolean} wrapped Flag indicating whether method is wrapped. Will decrement ary if true.
|
||||
* @return {number} Ary of the function as an integer
|
||||
*/
|
||||
function getMethodAry(mapping, name, wrapped) {
|
||||
var ary = _.find(mapping.caps, function(cap) {
|
||||
return _.includes(mapping.aryMethod[cap], name) && cap;
|
||||
});
|
||||
if (_.isNumber(ary) && wrapped) {
|
||||
return ary - 1;
|
||||
}
|
||||
return ary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorder `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.
|
||||
* @param {boolean} wrapped Flag indicating whether method is wrapped. Will decrement ary if true.
|
||||
* @returns {*[]} Reordered parameters/arguments.
|
||||
*/
|
||||
function reorderParams(mapping, name, params, wrapped) {
|
||||
// Check if reordering is needed.
|
||||
if (!mapping || mapping.skipRearg[name]) {
|
||||
return params;
|
||||
}
|
||||
var reargOrder = mapping.methodRearg[name] || mapping.aryRearg[getMethodAry(mapping, name, wrapped)];
|
||||
if (!reargOrder) {
|
||||
return params;
|
||||
}
|
||||
// Reorder params.
|
||||
var newParams = [];
|
||||
reargOrder.forEach(function(newPosition, index) {
|
||||
newParams[newPosition] = params[index];
|
||||
});
|
||||
return newParams;
|
||||
}
|
||||
|
||||
var dotsRegex = /^\.\.\./;
|
||||
var parensRegex = /^\((.*)\)$/;
|
||||
var squareBracketsRegex = /^\[(.*)\]$/;
|
||||
var arrayRegex = /\[\]$/;
|
||||
|
||||
/**
|
||||
* Return `types` as '(X|Y|...)' if `types` contains multiple values, `types[0]` otherwise.
|
||||
*
|
||||
* @param {string[]} types Possible types of the parameter.
|
||||
* @return {string} `types` as a string.
|
||||
*/
|
||||
function wrapInParensIfMultiple(types) {
|
||||
if (types.length > 1) {
|
||||
return '(' + types.join('|') + ')';
|
||||
}
|
||||
return types[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform parameter type from 'X' to 'X|X[]'.
|
||||
*
|
||||
* @param {string[]} param Array whose first item is a description of the parameter type.
|
||||
* @return {string[]} `param` with the updated type.
|
||||
*/
|
||||
function singleItemOrArrayOf(type) {
|
||||
return type + '|' + type + '[]';
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 removeDotsFromTypeAndAllowMultiple(param) {
|
||||
var type = param[0];
|
||||
if (!dotsRegex.test(type)) {
|
||||
return param;
|
||||
}
|
||||
|
||||
var newType = _.chain(type)
|
||||
.replace(dotsRegex, '')
|
||||
.replace(parensRegex, '$1')
|
||||
.split('|')
|
||||
.map(function(s) {
|
||||
return s.replace(arrayRegex, '');
|
||||
})
|
||||
.uniq()
|
||||
.thru(wrapInParensIfMultiple)
|
||||
.thru(singleItemOrArrayOf)
|
||||
.value();
|
||||
|
||||
return [newType].concat(_.tail(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (!dotsRegex.test(type)) {
|
||||
return param;
|
||||
}
|
||||
|
||||
var newType = type
|
||||
.replace(dotsRegex, '')
|
||||
.replace(parensRegex, '$1');
|
||||
|
||||
return [newType].concat(_.tail(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and duplicate the parameter with a type of the form '...x'.
|
||||
*
|
||||
* @param {string} name Name of the method.
|
||||
* @param {string[]} params Description of the parameters of the method.
|
||||
* @return {string[]} Updated parameters.
|
||||
*/
|
||||
function duplicateRestArrays(name, params) {
|
||||
var indexOfRestParam = _.findIndex(params, function(param) {
|
||||
return dotsRegex.test(param[0]);
|
||||
});
|
||||
if (indexOfRestParam === -1) {
|
||||
console.log('WARNING: method `' + name + '`',
|
||||
'is capped to more arguments than its declared number of parameters,',
|
||||
'but does not have a parameter like `...x`');
|
||||
}
|
||||
// duplicates param[indexOfRestParam] at its position
|
||||
return params.slice(0, indexOfRestParam + 1)
|
||||
.concat(params.slice(indexOfRestParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the optional default value and brackets around the name of the method.
|
||||
*
|
||||
* @param {string[]} param Array whose second item is the name of the param of the form
|
||||
* 'name', '[name]' or [name=defaultValue].
|
||||
* @return {string[]} `param` with the updated name.
|
||||
*/
|
||||
function removeDefaultValue(param) {
|
||||
var paramName = param[1]
|
||||
.replace(squareBracketsRegex, '$1')
|
||||
.split('=')
|
||||
[0];
|
||||
|
||||
return [param[0], paramName, param[2]];
|
||||
}
|
||||
|
||||
function updateParamsDescription(mapping, entry, params) {
|
||||
var tmpParams;
|
||||
var name = getBaseName(entry);
|
||||
var ary = getMethodAry(mapping, name);
|
||||
|
||||
var wrapped = isWrapped(entry);
|
||||
if (wrapped) {
|
||||
// Needs one less argument when wrapped
|
||||
ary = ary - 1;
|
||||
params.shift();
|
||||
}
|
||||
|
||||
if (ary > params.length) {
|
||||
tmpParams = duplicateRestArrays(name, params)
|
||||
.map(removeDotsFromType);
|
||||
} else {
|
||||
tmpParams = params
|
||||
.map(removeDotsFromTypeAndAllowMultiple);
|
||||
}
|
||||
tmpParams = tmpParams.map(removeDefaultValue);
|
||||
return reorderParams(mapping, name, tmpParams, wrapped);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return 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);
|
||||
};
|
||||
}
|
||||
|
||||
function getDefaultValue(paramDescription) {
|
||||
var paramName = paramDescription[1];
|
||||
if (paramName[0] !== '[') {
|
||||
return null;
|
||||
}
|
||||
return paramName
|
||||
.slice(1, paramName.length - 1)
|
||||
.split('=')
|
||||
[1] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an AST node representation of `str`.
|
||||
*
|
||||
* @param {object} j JSCodeShift object.
|
||||
* @param {string} str String to convert.
|
||||
* @return {ASTObject} AST node.
|
||||
*/
|
||||
function stringToASTNode(j, str) {
|
||||
return j(str).find(j.Expression).paths()[0].value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of a parameter from its description.
|
||||
* @param {string[]} paramDescription Parameter description.
|
||||
* @return {string} name of the parameter.
|
||||
*/
|
||||
function paramName(paramDescription) {
|
||||
var paramName = paramDescription[1];
|
||||
if (paramName[0] !== '[') {
|
||||
return paramName;
|
||||
}
|
||||
return paramName
|
||||
.slice(1, paramName.length - 1)
|
||||
.split('=')
|
||||
[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a AST node representation of `object.property`.
|
||||
* If `object.property` can be evaluated (ex: [].length --> 0), the node will be simplified.
|
||||
* If `defaultValue` references another argument, it will be replaced by the value of that argument.
|
||||
*
|
||||
* @param {object} j JSCodeShift object.
|
||||
* @param {ASTObject} object Object of the member expression.
|
||||
* @param {string} property Property of the member expression.
|
||||
* @return {ASTObject} AST node.
|
||||
*/
|
||||
function memberExpressiontoASTNode(j, object, property) {
|
||||
var node = j.memberExpression(object, j.identifier(property));
|
||||
try {
|
||||
// Attempt to evaluate the value of the node to have simpler calls
|
||||
// [1, 2, 3, 4].length --> 4
|
||||
var evaluatedNode = eval(recast.print(node).code);
|
||||
return stringToASTNode(j, JSON.stringify(evaluatedNode));
|
||||
} catch (e) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a AST node representation of `defaultValue`.
|
||||
* If `defaultValue` references another argument, it will be replaced by the value of that argument.
|
||||
*
|
||||
* @param {object} j JSCodeShift object.
|
||||
* @param {string} defaultValue Value to convert.
|
||||
* @param {ASTObject[]} args Arguments given to the function.
|
||||
* @param {string[]} paramNames Name of the expected parameters.
|
||||
* @return {ASTObject} AST node representation of `defaultValue`.
|
||||
*/
|
||||
function defaultValueToASTNode(j, defaultValue, args, paramNames) {
|
||||
// var endValue = replaceValueByArgValue(j, defaultValue, args, paramNames);
|
||||
var splitDefaultValue = defaultValue.split('.');
|
||||
var indexOfReferencedParam = paramNames.indexOf(splitDefaultValue[0]);
|
||||
if (indexOfReferencedParam !== -1) {
|
||||
if (splitDefaultValue.length > 1) {
|
||||
// defaultValue is probably of the type 'someArg.length'
|
||||
// Other more complicated cases could be handled but none exist as of this writing.
|
||||
return memberExpressiontoASTNode(j, args[indexOfReferencedParam], splitDefaultValue[1]);
|
||||
}
|
||||
return args[indexOfReferencedParam];
|
||||
}
|
||||
return stringToASTNode(j, defaultValue);
|
||||
}
|
||||
|
||||
function mapRight(array, fn) {
|
||||
var res = [];
|
||||
var index = array.length;
|
||||
while (index--) {
|
||||
res = [fn(array[index], index)].concat(res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of arguments, augmented by the default value of the arguments that were ommitted.
|
||||
* The augmentation only happens when the method call is made without some of the optional arguments,
|
||||
* and when the arguments these optional arguments have become compulsory.
|
||||
* For a `function fn(a, b, c=0, d=b.length) { ... }` with an arity of 4,
|
||||
* when called with `args` [a, ['b']], returns [a, ['b'], 0, ['b'].length].
|
||||
* If possible, the value will be evaluated such that ̀`['b'].length` becomes `1`.
|
||||
*
|
||||
* @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 {ASTObject[]} args Arguments to concatenate.
|
||||
* @param {string[][]} paramsDescription Description of the expected params.
|
||||
* @return {ASTObject[]} Args along with missing arguments.
|
||||
*/
|
||||
function addMissingArguments(j, mapping, name, args, paramsDescription) {
|
||||
var ary = getMethodAry(mapping, name);
|
||||
|
||||
if (ary === undefined) {
|
||||
console.log('WARNING: method `' + name + '` is not capped');
|
||||
}
|
||||
|
||||
ary = ary || 1;
|
||||
if (ary <= args.length) {
|
||||
return args;
|
||||
}
|
||||
var paramNames = paramsDescription.map(paramName);
|
||||
var tmpArgs = _.clone(args);
|
||||
var newArgs = mapRight(_.take(paramsDescription, ary), function(paramDescription, index) {
|
||||
if (index === tmpArgs.length - 1) {
|
||||
return tmpArgs.pop();
|
||||
}
|
||||
var defaultValue = getDefaultValue(paramDescription);
|
||||
if (defaultValue !== null) {
|
||||
return defaultValueToASTNode(j, defaultValue, args, paramNames);
|
||||
}
|
||||
return tmpArgs.pop();
|
||||
});
|
||||
return newArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {ASTObject[]} args Arguments to concatenate.
|
||||
* @return {ASTObject[]} Concatenated arguments
|
||||
*/
|
||||
function concatExtraArgs(j, mapping, name, args) {
|
||||
var ary = getMethodAry(mapping, name);
|
||||
if (args.length <= ary) {
|
||||
return args;
|
||||
}
|
||||
|
||||
var concatenatedArgs = j.arrayExpression(_.takeRight(args, args.length - ary + 1));
|
||||
return _.take(args, ary - 1).concat(concatenatedArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorder the args in the example if needed, and eventually merges them when
|
||||
* the method is called with more args than the method's ary.
|
||||
*
|
||||
* @param {object} j JSCodeShift object.
|
||||
* @param {ASTObject} root AST representation of the example
|
||||
* @param {object} mapping Mapping object that defines if and how the arguments will be reordered.
|
||||
* @return {ASTObject} AST object where the arguments are reordered/merged
|
||||
*/
|
||||
function reorderMethodArgs(j, root, mapping, paramsDescription) {
|
||||
root.find(j.CallExpression, { callee: { object: {name: '_' }}})
|
||||
.replaceWith(function(callExpr, i) {
|
||||
var value = callExpr.value;
|
||||
var name = value.callee.property.name;
|
||||
var argsIncludingMissingOnes = addMissingArguments(j, mapping, name, value.arguments, paramsDescription)
|
||||
var args = concatExtraArgs(j, mapping, name, argsIncludingMissingOnes);
|
||||
return j.callExpression(
|
||||
value.callee,
|
||||
reorderParams(mapping, name, args)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function removeConsoleLogs(codeSample) {
|
||||
return codeSample
|
||||
.split('\n')
|
||||
.filter(function(line) {
|
||||
return !line.startsWith('console.log');
|
||||
})
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, paramsDescription) {
|
||||
var root = j(removeConsoleLogs(codeSample));
|
||||
try {
|
||||
reorderMethodArgs(j, root, mapping, paramsDescription);
|
||||
} catch (error) {
|
||||
console.error(codeSample);
|
||||
console.error(error.stack);
|
||||
process.exit(1);
|
||||
}
|
||||
return root.toSource();
|
||||
}
|
||||
|
||||
function getOriginalParams() {
|
||||
var prev = this._params;
|
||||
this._params = undefined;
|
||||
baseGetParams.call(this);
|
||||
var result = this._params;
|
||||
this._params = prev;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 paramsDescription = getOriginalParams.call(this);
|
||||
var resultReordered = reorderParamsInExample(mapping, result, paramsDescription);
|
||||
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);
|
||||
};
|
||||
72
lib/doc/apply-fp-mapping/common.js
Normal file
72
lib/doc/apply-fp-mapping/common.js
Normal file
@@ -0,0 +1,72 @@
|
||||
var _ = require('lodash'),
|
||||
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'));
|
||||
|
||||
}
|
||||
|
||||
// Function copied from docdown/lib/entry that is not exported.
|
||||
function hasTag(string, tagName) {
|
||||
tagName = tagName == '*' ? '\\w+' : _.escapeRegExp(tagName);
|
||||
return RegExp('^ *\\*[\\t ]*@' + tagName + '\\b', 'm').test(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return 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.
|
||||
* @param {boolean} wrapped Flag indicating whether method is wrapped. Will decrement ary if true.
|
||||
* @return {number} Ary of the function as an integer
|
||||
*/
|
||||
function getMethodAry(mapping, name, wrapped) {
|
||||
var ary = _.find(mapping.caps, function(cap) {
|
||||
return _.includes(mapping.aryMethod[cap], name) && cap;
|
||||
});
|
||||
if (_.isNumber(ary) && wrapped) {
|
||||
return ary - 1;
|
||||
}
|
||||
return ary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorder `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.
|
||||
* @param {boolean} wrapped Flag indicating whether method is wrapped. Will decrement ary if true.
|
||||
* @returns {*[]} Reordered parameters/arguments.
|
||||
*/
|
||||
function reorderParams(mapping, name, params, wrapped) {
|
||||
// Check if reordering is needed.
|
||||
if (!mapping || mapping.skipRearg[name]) {
|
||||
return params;
|
||||
}
|
||||
var reargOrder = mapping.methodRearg[name] || mapping.aryRearg[getMethodAry(mapping, name, wrapped)];
|
||||
if (!reargOrder) {
|
||||
return params;
|
||||
}
|
||||
// Reorder params.
|
||||
var newParams = [];
|
||||
reargOrder.forEach(function(newPosition, index) {
|
||||
newParams[newPosition] = params[index];
|
||||
});
|
||||
return newParams;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
baseGetParams: baseGetParams,
|
||||
getMultilineValue: getMultilineValue,
|
||||
hasTag: hasTag,
|
||||
getMethodAry: getMethodAry,
|
||||
reorderParams: reorderParams
|
||||
};
|
||||
268
lib/doc/apply-fp-mapping/example.js
Normal file
268
lib/doc/apply-fp-mapping/example.js
Normal file
@@ -0,0 +1,268 @@
|
||||
var _ = require('lodash'),
|
||||
recast = require('recast'),
|
||||
j = require('jscodeshift'),
|
||||
common = require('./common');
|
||||
|
||||
/**
|
||||
* Return the name of a parameter from its description.
|
||||
*
|
||||
* @param {string[]} paramDescription Parameter description.
|
||||
* @return {string} name of the parameter.
|
||||
*/
|
||||
function paramName(paramDescription) {
|
||||
var name = paramDescription[1];
|
||||
if (name[0] !== '[') {
|
||||
return name;
|
||||
}
|
||||
return name
|
||||
.slice(1, name.length - 1)
|
||||
.split('=')
|
||||
[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default value of the given parameter.
|
||||
*
|
||||
* @param {string[]} paramDescription Parameter description.
|
||||
* @return {string} Default value as string if found, null otherwise.
|
||||
*/
|
||||
function getDefaultValue(paramDescription) {
|
||||
var name = paramDescription[1];
|
||||
if (name[0] !== '[') {
|
||||
return null;
|
||||
}
|
||||
return name
|
||||
.slice(1, name.length - 1)
|
||||
.split('=')
|
||||
[1] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an AST node representation of `str`.
|
||||
*
|
||||
* @param {object} j JSCodeShift object.
|
||||
* @param {string} str String to convert.
|
||||
* @return {ASTObject} AST node.
|
||||
*/
|
||||
function stringToASTNode(j, str) {
|
||||
return j(str).find(j.Expression).paths()[0].value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a AST node representation of `object.property`.
|
||||
* If `object.property` can be evaluated (ex: [].length --> 0), the node will be simplified.
|
||||
* If `defaultValue` references another argument, it will be replaced by the value of that argument.
|
||||
*
|
||||
* @param {object} j JSCodeShift object.
|
||||
* @param {ASTObject} object Object of the member expression.
|
||||
* @param {string} property Property of the member expression.
|
||||
* @return {ASTObject} AST node.
|
||||
*/
|
||||
function memberExpressiontoASTNode(j, object, property) {
|
||||
var node = j.memberExpression(object, j.identifier(property));
|
||||
try {
|
||||
// Attempt to evaluate the value of the node to have simpler calls
|
||||
// [1, 2, 3, 4].length --> 4
|
||||
var evaluatedNode = eval(recast.print(node).code);
|
||||
return stringToASTNode(j, JSON.stringify(evaluatedNode));
|
||||
} catch (e) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a AST node representation of `defaultValue`.
|
||||
* If `defaultValue` references another argument, it will be replaced by the value of that argument.
|
||||
*
|
||||
* @param {object} j JSCodeShift object.
|
||||
* @param {string} defaultValue Value to convert.
|
||||
* @param {ASTObject[]} args Arguments given to the function.
|
||||
* @param {string[]} paramNames Name of the expected parameters.
|
||||
* @return {ASTObject} AST node representation of `defaultValue`.
|
||||
*/
|
||||
function defaultValueToASTNode(j, defaultValue, args, paramNames) {
|
||||
// var endValue = replaceValueByArgValue(j, defaultValue, args, paramNames);
|
||||
var splitDefaultValue = defaultValue.split('.');
|
||||
var indexOfReferencedParam = paramNames.indexOf(splitDefaultValue[0]);
|
||||
if (indexOfReferencedParam !== -1) {
|
||||
if (splitDefaultValue.length > 1) {
|
||||
// defaultValue is probably of the type 'someArg.length'
|
||||
// Other more complicated cases could be handled but none exist as of this writing.
|
||||
return memberExpressiontoASTNode(j, args[indexOfReferencedParam], splitDefaultValue[1]);
|
||||
}
|
||||
return args[indexOfReferencedParam];
|
||||
}
|
||||
return stringToASTNode(j, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as _.map, but applied in reverse order.
|
||||
*
|
||||
* @param {Array} collection The collection to iterate over.
|
||||
* @param {Function} iteratee The function invoked per iteration.
|
||||
* @return {Array} Returns the new mapped array.
|
||||
*/
|
||||
function mapRight(array, iteratee) {
|
||||
var res = [];
|
||||
var index = array.length;
|
||||
while (index--) {
|
||||
res = [iteratee(array[index], index)].concat(res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of arguments, augmented by the default value of the arguments that were ommitted.
|
||||
* The augmentation only happens when the method call is made without some of the optional arguments,
|
||||
* and when the arguments these optional arguments have become compulsory.
|
||||
* For a `function fn(a, b, c=0, d=b.length) { ... }` with an arity of 4,
|
||||
* when called with `args` [a, ['b']], returns [a, ['b'], 0, ['b'].length].
|
||||
* If possible, the value will be evaluated such that ̀`['b'].length` becomes `1`.
|
||||
*
|
||||
* @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 {ASTObject[]} args Arguments to concatenate.
|
||||
* @param {string[][]} paramsDescription Description of the expected params.
|
||||
* @return {ASTObject[]} Args along with missing arguments.
|
||||
*/
|
||||
function addMissingArguments(j, mapping, name, args, paramsDescription) {
|
||||
var ary = common.getMethodAry(mapping, name);
|
||||
|
||||
if (ary === undefined) {
|
||||
console.log('WARNING: method `' + name + '` is not capped');
|
||||
}
|
||||
|
||||
ary = ary || 1;
|
||||
if (ary <= args.length) {
|
||||
return args;
|
||||
}
|
||||
var paramNames = paramsDescription.map(paramName);
|
||||
var tmpArgs = _.clone(args);
|
||||
var newArgs = mapRight(_.take(paramsDescription, ary), function(paramDescription, index) {
|
||||
if (index === tmpArgs.length - 1) {
|
||||
return tmpArgs.pop();
|
||||
}
|
||||
var defaultValue = getDefaultValue(paramDescription);
|
||||
if (defaultValue !== null) {
|
||||
return defaultValueToASTNode(j, defaultValue, args, paramNames);
|
||||
}
|
||||
return tmpArgs.pop();
|
||||
});
|
||||
return newArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {ASTObject[]} args Arguments to concatenate.
|
||||
* @return {ASTObject[]} Concatenated arguments
|
||||
*/
|
||||
function concatExtraArgs(j, mapping, name, args) {
|
||||
var ary = common.getMethodAry(mapping, name);
|
||||
if (args.length <= ary) {
|
||||
return args;
|
||||
}
|
||||
|
||||
var concatenatedArgs = j.arrayExpression(_.takeRight(args, args.length - ary + 1));
|
||||
return _.take(args, ary - 1).concat(concatenatedArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorder the args in the example if needed, and eventually merges them when
|
||||
* the method is called with more args than the method's ary.
|
||||
*
|
||||
* @param {object} j JSCodeShift object.
|
||||
* @param {ASTObject} root AST representation of the example
|
||||
* @param {object} mapping Mapping object that defines if and how the arguments will be reordered.
|
||||
* @return {ASTObject} AST object where the arguments are reordered/merged
|
||||
*/
|
||||
function reorderMethodArgs(j, root, mapping, paramsDescription) {
|
||||
root.find(j.CallExpression, { callee: { object: {name: '_' }}})
|
||||
.replaceWith(function(callExpr, i) {
|
||||
var value = callExpr.value;
|
||||
var name = value.callee.property.name;
|
||||
var argsIncludingMissingOnes = addMissingArguments(j, mapping, name, value.arguments, paramsDescription);
|
||||
var args = concatExtraArgs(j, mapping, name, argsIncludingMissingOnes);
|
||||
return j.callExpression(
|
||||
value.callee,
|
||||
common.reorderParams(mapping, name, args)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove calls to `console.log` from `codeSample`.
|
||||
*
|
||||
* @param {string} codeSample string to remove the calls from.
|
||||
* @return {string} Updated code sample.
|
||||
*/
|
||||
function removeConsoleLogs(codeSample) {
|
||||
return codeSample
|
||||
.split('\n')
|
||||
.filter(function(line) {
|
||||
return !line.startsWith('console.log');
|
||||
})
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, paramsDescription) {
|
||||
var root = j(removeConsoleLogs(codeSample));
|
||||
try {
|
||||
reorderMethodArgs(j, root, mapping, paramsDescription);
|
||||
} catch (error) {
|
||||
console.error(codeSample);
|
||||
console.error(error.stack);
|
||||
process.exit(1);
|
||||
}
|
||||
return root.toSource();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the original, not reordered, list of parameters.
|
||||
*
|
||||
* @param {Entry} entryItem Entry whose parameters to get.
|
||||
* @return {string[][]} List of args.
|
||||
*/
|
||||
function getOriginalParams(entryItem) {
|
||||
var prev = entryItem._params;
|
||||
entryItem._params = undefined;
|
||||
common.baseGetParams.call(entryItem);
|
||||
var result = entryItem._params;
|
||||
entryItem._params = prev;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = common.getMultilineValue(this.entry, 'example');
|
||||
if (!result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
var paramsDescription = getOriginalParams(this);
|
||||
var resultReordered = reorderParamsInExample(mapping, result, paramsDescription);
|
||||
return '```' + this.lang + '\n' + resultReordered + '\n```';
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = getReorderedExample;
|
||||
11
lib/doc/apply-fp-mapping/index.js
Normal file
11
lib/doc/apply-fp-mapping/index.js
Normal file
@@ -0,0 +1,11 @@
|
||||
var Entry = require('docdown/lib/entry'),
|
||||
getReorderedParams = require('./parameters'),
|
||||
getReorderedExample = require('./example');
|
||||
|
||||
/**
|
||||
* 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);
|
||||
};
|
||||
206
lib/doc/apply-fp-mapping/parameters.js
Normal file
206
lib/doc/apply-fp-mapping/parameters.js
Normal file
@@ -0,0 +1,206 @@
|
||||
var _ = require('lodash'),
|
||||
j = require('jscodeshift'),
|
||||
Entry = require('docdown/lib/entry'),
|
||||
common = require('./common');
|
||||
|
||||
var baseGetParams = Entry.prototype.getParams;
|
||||
|
||||
var dotsRegex = /^\.\.\./;
|
||||
var parensRegex = /^\((.*)\)$/;
|
||||
var squareBracketsRegex = /^\[(.*)\]$/;
|
||||
var arrayRegex = /\[\]$/;
|
||||
|
||||
/**
|
||||
* Return whether method is wrapped.
|
||||
*
|
||||
* @param {Entry} entry Entry to look at.
|
||||
* @return {Boolean} true if the method is wrapped, false if it is static.
|
||||
*/
|
||||
function isWrapped(entry) {
|
||||
return !common.hasTag(entry, 'static');
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract 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 || '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return `types` as '(X|Y|...)' if `types` contains multiple values, `types[0]` otherwise.
|
||||
*
|
||||
* @param {string[]} types Possible types of the parameter.
|
||||
* @return {string} `types` as a string.
|
||||
*/
|
||||
function wrapInParensIfMultiple(types) {
|
||||
if (types.length > 1) {
|
||||
return '(' + types.join('|') + ')';
|
||||
}
|
||||
return types[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform parameter type from 'X' to 'X|X[]'.
|
||||
*
|
||||
* @param {string[]} param Array whose first item is a description of the parameter type.
|
||||
* @return {string[]} `param` with the updated type.
|
||||
*/
|
||||
function singleItemOrArrayOf(type) {
|
||||
return type + '|' + type + '[]';
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 removeDotsFromTypeAndAllowMultiple(param) {
|
||||
var type = param[0];
|
||||
if (!dotsRegex.test(type)) {
|
||||
return param;
|
||||
}
|
||||
|
||||
var newType = _.chain(type)
|
||||
.replace(dotsRegex, '')
|
||||
.replace(parensRegex, '$1')
|
||||
.split('|')
|
||||
.map(function(s) {
|
||||
return s.replace(arrayRegex, '');
|
||||
})
|
||||
.uniq()
|
||||
.thru(wrapInParensIfMultiple)
|
||||
.thru(singleItemOrArrayOf)
|
||||
.value();
|
||||
|
||||
return [newType].concat(_.tail(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (!dotsRegex.test(type)) {
|
||||
return param;
|
||||
}
|
||||
|
||||
var newType = type
|
||||
.replace(dotsRegex, '')
|
||||
.replace(parensRegex, '$1');
|
||||
|
||||
return [newType].concat(_.tail(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and duplicate the parameter with a type of the form '...x'.
|
||||
*
|
||||
* @param {string} name Name of the method.
|
||||
* @param {string[]} params Description of the parameters of the method.
|
||||
* @return {string[]} Updated parameters.
|
||||
*/
|
||||
function duplicateRestArrays(name, params) {
|
||||
var indexOfRestParam = _.findIndex(params, function(param) {
|
||||
return dotsRegex.test(param[0]);
|
||||
});
|
||||
if (indexOfRestParam === -1) {
|
||||
console.log('WARNING: method `' + name + '`',
|
||||
'is capped to more arguments than its declared number of parameters,',
|
||||
'but does not have a parameter like `...x`');
|
||||
}
|
||||
// duplicates param[indexOfRestParam] at its position
|
||||
return params.slice(0, indexOfRestParam + 1)
|
||||
.concat(params.slice(indexOfRestParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the optional default value and brackets around the name of the method.
|
||||
*
|
||||
* @param {string[]} param Array whose second item is the name of the param of the form
|
||||
* 'name', '[name]' or [name=defaultValue].
|
||||
* @return {string[]} `param` with the updated name.
|
||||
*/
|
||||
function removeDefaultValue(param) {
|
||||
var name = param[1]
|
||||
.replace(squareBracketsRegex, '$1')
|
||||
.split('=')
|
||||
[0];
|
||||
|
||||
return [param[0], name, param[2]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the updated list of parameters of a method described by `entry`,
|
||||
* according to changes described by `mapping`. Will, if needed:
|
||||
* - reorder the arguments
|
||||
* - remove default values and brackets around previously optional arguments
|
||||
* - remove ignored arguments
|
||||
* - duplicate rest arguments if the number of params is less than its cap
|
||||
* - de-restify arguments
|
||||
*
|
||||
* @param {object} mapping Mapping object that defines if and how the `params` will be reordered.
|
||||
* @param {Entry} entry Method to update.
|
||||
* @param {string[][]} params List of the original parameters of the method.
|
||||
* @return {string[][]} Updated list of params.
|
||||
*/
|
||||
function updateParamsDescription(mapping, entry, params) {
|
||||
var tmpParams;
|
||||
var name = getBaseName(entry);
|
||||
var ary = common.getMethodAry(mapping, name);
|
||||
|
||||
var wrapped = isWrapped(entry);
|
||||
if (wrapped) {
|
||||
// Needs one less argument when wrapped
|
||||
ary = ary - 1;
|
||||
params.shift();
|
||||
}
|
||||
|
||||
if (ary > params.length) {
|
||||
tmpParams = duplicateRestArrays(name, params)
|
||||
.map(removeDotsFromType);
|
||||
} else {
|
||||
tmpParams = params
|
||||
.map(removeDotsFromTypeAndAllowMultiple);
|
||||
}
|
||||
tmpParams = _.take(tmpParams, ary).map(removeDefaultValue);
|
||||
return common.reorderParams(mapping, name, tmpParams, wrapped);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return 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);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates `docdown` `Entry`'s prototype so that parameters/arguments are reordered according to `mapping`.
|
||||
*/
|
||||
module.exports = getReorderedParams;
|
||||
438
lib/doc/test.js
438
lib/doc/test.js
@@ -1,438 +0,0 @@
|
||||
var assert = require('assert');
|
||||
|
||||
var Entry = require('docdown/lib/entry');
|
||||
|
||||
var applyFPMapping = require('./apply-fp-mapping');
|
||||
var mapping = require('../../fp/_mapping');
|
||||
|
||||
function toSource(name, paramLines, exampleLines, attachedToPrototype) {
|
||||
var start = [
|
||||
"/**",
|
||||
" * ",
|
||||
" * Foo",
|
||||
" * "
|
||||
];
|
||||
var end = [
|
||||
" */",
|
||||
"function " + name + "(a, b, c) {",
|
||||
"",
|
||||
"}"
|
||||
];
|
||||
var staticLine = attachedToPrototype ? [] : [' * @static'];
|
||||
var params = paramLines.map(function(line) {
|
||||
return ' * @param ' + line;
|
||||
});
|
||||
var example = (exampleLines || []).map(function(line) {
|
||||
return ' * ' + line;
|
||||
});
|
||||
|
||||
return [].concat(start, staticLine, params, [' * @example'], example, end).join('\n');
|
||||
}
|
||||
|
||||
function toParams(name, lines, wrapped) {
|
||||
var start = [
|
||||
"/**",
|
||||
" * ",
|
||||
" * Foo",
|
||||
" * "
|
||||
];
|
||||
var end = [
|
||||
" * @returns Foo bar",
|
||||
" */",
|
||||
"function " + name + "(a, b, c) {",
|
||||
"",
|
||||
"}"
|
||||
];
|
||||
var staticLine = wrapped ? [] : [' * @static'];
|
||||
var params = lines.map(function(line) {
|
||||
return ' * @param ' + line;
|
||||
});
|
||||
return [].concat(start, staticLine, params, end).join('\n');
|
||||
}
|
||||
|
||||
var differenceBySource = toSource('differenceBy', [
|
||||
'{Array} array The array to inspect.',
|
||||
'{...Array} [values] The values to exclude.',
|
||||
'{Function|Object|string} [iteratee=_.identity] The iteratee invoked per element.'
|
||||
], [
|
||||
"_.differenceBy([3.1, 2.2, 1.3], [4.4, 2.5], Math.floor);",
|
||||
"// → [3.1, 1.3]",
|
||||
"",
|
||||
"// The `_.property` iteratee shorthand.",
|
||||
"_.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x');",
|
||||
"// → [{ 'x': 2 }]"
|
||||
]);
|
||||
|
||||
var setParams = [
|
||||
'{Object} object The object to modify.',
|
||||
'{Array|string} path The path of the property to set.',
|
||||
'{*} value The value to set.'
|
||||
];
|
||||
|
||||
describe('Docs FP mapping', function() {
|
||||
var oldgetParams;
|
||||
var oldgetExample;
|
||||
|
||||
before(function() {
|
||||
oldgetParams = Entry.prototype.getParams;
|
||||
oldgetExample = Entry.prototype.getExample;
|
||||
mapping.aryMethod[2].push('customFun');
|
||||
applyFPMapping(mapping);
|
||||
});
|
||||
|
||||
after(function() {
|
||||
Entry.prototype.getParams = oldgetParams;
|
||||
Entry.prototype.getExample = oldgetExample;
|
||||
});
|
||||
|
||||
describe('getExample', function() {
|
||||
it('should reorder parameters', function() {
|
||||
var entry = new Entry(differenceBySource, differenceBySource);
|
||||
|
||||
var actual = entry.getExample();
|
||||
|
||||
assert.equal(actual, [
|
||||
"```js",
|
||||
"_.differenceBy(Math.floor, [4.4, 2.5], [3.1, 2.2, 1.3]);",
|
||||
"// → [3.1, 1.3]",
|
||||
"",
|
||||
"// The `_.property` iteratee shorthand.",
|
||||
"_.differenceBy('x', [{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }]);",
|
||||
"// → [{ 'x': 2 }]",
|
||||
"```"
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
it('should reorder parameters that have a special order', function() {
|
||||
var example = toSource('set', setParams, [
|
||||
"var object = { 'a': [{ 'b': { 'c': 3 } }] };",
|
||||
"_.set(object, 'a[0].b.c', 4);",
|
||||
"_.set(object, 'x[0].y.z', 5);",
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getExample();
|
||||
|
||||
assert.equal(actual, [
|
||||
"```js",
|
||||
"var object = { 'a': [{ 'b': { 'c': 3 } }] };",
|
||||
"_.set('a[0].b.c', 4, object);",
|
||||
"_.set('x[0].y.z', 5, object);",
|
||||
"```"
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
it('should preserve comments', function() {
|
||||
var example = toSource('set', setParams, [
|
||||
"var object = { 'a': [{ 'b': { 'c': 3 } }] };",
|
||||
"_.set(object, 'a[0].b.c', 4);",
|
||||
"// => 4",
|
||||
"_.set(object, 'x[0].y.z', 5);",
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getExample();
|
||||
|
||||
assert.equal(actual, [
|
||||
"```js",
|
||||
"var object = { 'a': [{ 'b': { 'c': 3 } }] };",
|
||||
"_.set('a[0].b.c', 4, object);",
|
||||
"// => 4",
|
||||
"_.set('x[0].y.z', 5, object);",
|
||||
"```"
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
it('should remove console.logs from example', function() {
|
||||
var example = toSource('set', setParams, [
|
||||
"var object = { 'a': [{ 'b': { 'c': 3 } }] };",
|
||||
"",
|
||||
"_.set(object, 'a[0].b.c', 4);",
|
||||
"console.log(object.a[0].b.c);",
|
||||
"// => 4",
|
||||
"",
|
||||
"_.set(object, 'x[0].y.z', 5);",
|
||||
"console.log(object.x[0].y.z);",
|
||||
"// => 5"
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getExample();
|
||||
|
||||
assert.equal(actual, [
|
||||
"```js",
|
||||
"var object = { 'a': [{ 'b': { 'c': 3 } }] };",
|
||||
"",
|
||||
"_.set('a[0].b.c', 4, object);",
|
||||
"// => 4",
|
||||
"",
|
||||
"_.set('x[0].y.z', 5, object);",
|
||||
"// => 5",
|
||||
"```"
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
it('should merge extra arguments into an array', function() {
|
||||
var example = toSource('pullAt', [
|
||||
'{Array} array The array to modify.',
|
||||
'{...(number|number[])} [indexes] The indexes of elements to remove,\n' +
|
||||
' * specified individually or in arrays.'
|
||||
], [
|
||||
"var array = [5, 10, 15, 20];",
|
||||
"var evens = _.pullAt(array, 1, 3);",
|
||||
"",
|
||||
"console.log(array);",
|
||||
"// => [5, 15]",
|
||||
"",
|
||||
"console.log(evens);",
|
||||
"// => [10, 20]",
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getExample();
|
||||
|
||||
assert.equal(actual, [
|
||||
"```js",
|
||||
"var array = [5, 10, 15, 20];",
|
||||
"var evens = _.pullAt([1, 3], array);",
|
||||
"",
|
||||
"// => [5, 15]",
|
||||
"",
|
||||
"// => [10, 20]",
|
||||
"```"
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
it('should inject default values into optional arguments that became compulsory', function() {
|
||||
var example = toSource('sampleSize', [
|
||||
'{Array|Object} collection The collection to sample.',
|
||||
'{number} [n=0] The number of elements to sample.'
|
||||
], [
|
||||
"_.sampleSize([1, 2, 3]);",
|
||||
"// => [3, 1]",
|
||||
"",
|
||||
"_.sampleSize([1, 2, 3], 4);",
|
||||
"// => [2, 3, 1]"
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getExample();
|
||||
|
||||
assert.equal(actual, [
|
||||
"```js",
|
||||
"_.sampleSize(0, [1, 2, 3]);",
|
||||
"// => [3, 1]",
|
||||
"",
|
||||
"_.sampleSize(4, [1, 2, 3]);",
|
||||
"// => [2, 3, 1]",
|
||||
"```"
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
it('should inject referenced values into optional arguments that became compulsory, '
|
||||
+ 'if a parameter\'s default value references parameter (direct reference)',
|
||||
function() {
|
||||
var example = toSource('customFun', [
|
||||
'{Array} array Array',
|
||||
'{number} [foo=array] Foo'
|
||||
], [
|
||||
"_.customFun([1, 2, 3]);",
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getExample();
|
||||
|
||||
assert.equal(actual, [
|
||||
"```js",
|
||||
"_.customFun([1, 2, 3], [1, 2, 3]);",
|
||||
"```"
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
it('should inject referenced values into optional arguments that became compulsory, '
|
||||
+ 'if a parameter\'s default value references parameter (member expression)',
|
||||
function() {
|
||||
var example = toSource('fill', [
|
||||
'{Array} array The array to fill.',
|
||||
'{*} value The value to fill `array` with.',
|
||||
'{number} [start=0] The start position.',
|
||||
'{number} [end=array.length] The end position.'
|
||||
], [
|
||||
"var array = [1, 2, 3];",
|
||||
"",
|
||||
"_.fill(array, 'a');",
|
||||
"console.log(array);",
|
||||
"// => ['a', 'a', 'a']",
|
||||
"",
|
||||
"_.fill(Array(3), 2, 1);",
|
||||
"// => [undefined, 2, 2]",
|
||||
"",
|
||||
"_.fill([4, 6, 8, 10], '*');",
|
||||
"// => [*, '*', '*', *]"
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getExample();
|
||||
|
||||
assert.equal(actual, [
|
||||
"```js",
|
||||
"var array = [1, 2, 3];",
|
||||
"",
|
||||
"_.fill(0, array.length, 'a', array);",
|
||||
"// => ['a', 'a', 'a']",
|
||||
"",
|
||||
"_.fill(1, 3, 2, Array(3));",
|
||||
"// => [undefined, 2, 2]",
|
||||
"",
|
||||
"_.fill(0, 4, '*', [4, 6, 8, 10]);",
|
||||
"// => [*, '*', '*', *]",
|
||||
"```"
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
it('should inject default values in the middle of the arguments', function() {
|
||||
var example = toSource('inRange', [
|
||||
'{number} number The number to check.',
|
||||
'{number} [start=0] The start of the range.',
|
||||
'{number} end The end of the range.'
|
||||
], [
|
||||
"_.inRange(4, 8);",
|
||||
"// => true"
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getExample();
|
||||
|
||||
assert.equal(actual, [
|
||||
"```js",
|
||||
"_.inRange(8, 0, 4);",
|
||||
"// => true",
|
||||
"```"
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
it('should not use ignored params as default values', function() {
|
||||
var example = toSource('drop', [
|
||||
'{Array} array The array to query.',
|
||||
'{number} [n=1] The number of elements to drop.',
|
||||
'{Object} [guard] Enables use as an iteratee for functions like `_.map`.'
|
||||
], [
|
||||
"_.drop([1, 2, 3]);",
|
||||
"// => [2, 3]"
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getExample();
|
||||
|
||||
assert.equal(actual, [
|
||||
"```js",
|
||||
"_.drop(1, [1, 2, 3]);",
|
||||
"// => [2, 3]",
|
||||
"```"
|
||||
].join('\n'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('getParams', function() {
|
||||
it('should reorder arguments and remove default values', function() {
|
||||
var example = toParams('differenceBy', [
|
||||
'{Array} array The array to inspect.',
|
||||
'{...Array} [values] The values to exclude.',
|
||||
'{Function|Object|string} [iteratee=_.identity] The iteratee invoked per element.'
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getParams();
|
||||
|
||||
assert.deepEqual(actual, [
|
||||
['Function|Object|string', 'iteratee', 'The iteratee invoked per element. '],
|
||||
['Array|Array[]', 'values', 'The values to exclude. '],
|
||||
['Array', 'array', 'The array to inspect. ']
|
||||
]);
|
||||
});
|
||||
|
||||
it('should reorder arguments that have a special order', function() {
|
||||
var example = toParams('set', [
|
||||
'{Object} object The object to modify.',
|
||||
'{Array|string} path The path of the property to set.',
|
||||
'{*} value The value to set.'
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getParams();
|
||||
|
||||
assert.deepEqual(actual, [
|
||||
['Array|string', 'path', 'The path of the property to set. '],
|
||||
['*', 'value', 'The value to set. '],
|
||||
['Object', 'object', 'The object to modify. '],
|
||||
]);
|
||||
});
|
||||
|
||||
it('should transform rest arguments into an array', function() {
|
||||
var example = toParams('pullAt', [
|
||||
'{Array} array The array to modify.',
|
||||
'{...(number|number[])} [indexes] The indexes of elements to remove,\n' +
|
||||
' * specified individually or in arrays.'
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getParams();
|
||||
|
||||
assert.deepEqual(actual, [
|
||||
// TODO Remove this line in favor of the commented one.
|
||||
// Is linked to a docdown (https://github.com/jdalton/docdown/pull/37)
|
||||
// that does not handle parens in the arguments well
|
||||
['((number|number)|((number|number)[]', 'indexes', 'The indexes of elements to remove, specified individually or in arrays. '],
|
||||
// ['number|number[]', '[indexes]', 'The indexes of elements to remove, specified individually or in arrays. '],
|
||||
['Array', 'array', 'The array to modify. '],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should duplicate and de-restify "rest" parameters if there are less parameters than cap', function() {
|
||||
var example = toParams('intersectionWith', [
|
||||
'{...Array} [arrays] The arrays to inspect.',
|
||||
'{Function} [comparator] The comparator invoked per element.'
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getParams();
|
||||
|
||||
assert.deepEqual(actual, [
|
||||
['Function', 'comparator', 'The comparator invoked per element. '],
|
||||
['Array', 'arrays', 'The arrays to inspect. '],
|
||||
['Array', 'arrays', 'The arrays to inspect. ']
|
||||
]);
|
||||
});
|
||||
|
||||
it('should consider method to have an ary of `ary - 1` when capped and wrapped', function() {
|
||||
var wrapped = true;
|
||||
var example = toParams('flatMap', [
|
||||
'{Array} array The array to iterate over.',
|
||||
'{Function|Object|string} [iteratee=_.identity] The function invoked per iteration.'
|
||||
], wrapped);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getParams();
|
||||
|
||||
assert.deepEqual(actual, [
|
||||
['Function|Object|string', 'iteratee', 'The function invoked per iteration. ']
|
||||
]);
|
||||
});
|
||||
|
||||
it('should remove arguments ignored because of capping', function() {
|
||||
var example = toParams('includes', [
|
||||
'{Array|Object|string} collection The collection to search.',
|
||||
'{*} value The value to search for.',
|
||||
'{number} [fromIndex=0] The index to search from.'
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getParams();
|
||||
|
||||
assert.deepEqual(actual, [
|
||||
['*', 'value', 'The value to search for. '],
|
||||
['Array|Object|string', 'collection', 'The collection to search. ']
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -46,7 +46,8 @@
|
||||
"style:main": "jscs lodash.js",
|
||||
"style:perf": "jscs perf/*.js perf/**/*.js",
|
||||
"style:test": "jscs test/*.js test/**/*.js",
|
||||
"test": "npm run test:main && npm run test:fp",
|
||||
"test": "npm run test:main && npm run test:fp && npm run test:docs",
|
||||
"test:docs": "node test/test-fp-doc",
|
||||
"test:fp": "node test/test-fp",
|
||||
"test:main": "node test/test"
|
||||
}
|
||||
|
||||
508
test/test-fp-doc.js
Normal file
508
test/test-fp-doc.js
Normal file
@@ -0,0 +1,508 @@
|
||||
;(function() {
|
||||
/** Used as a safe reference for `undefined` in pre-ES5 environments. */
|
||||
var undefined;
|
||||
|
||||
/** Used as a reference to the global object. */
|
||||
var root = (typeof global == 'object' && global) || this;
|
||||
|
||||
var phantom = root.phantom,
|
||||
amd = root.define && define.amd,
|
||||
document = !phantom && root.document,
|
||||
noop = function() {},
|
||||
argv = root.process && process.argv;
|
||||
|
||||
/** Use a single "load" function. */
|
||||
var load = (!amd && typeof require == 'function')
|
||||
? require
|
||||
: noop;
|
||||
|
||||
/** The unit testing framework. */
|
||||
var QUnit = root.QUnit || (root.QUnit = (
|
||||
QUnit = load('../node_modules/qunitjs/qunit/qunit.js') || root.QUnit,
|
||||
QUnit = QUnit.QUnit || QUnit
|
||||
));
|
||||
|
||||
/** Load stable Lodash and QUnit Extras. */
|
||||
var _ = root._ || load('../lodash.js');
|
||||
if (_) {
|
||||
_ = _.runInContext(root);
|
||||
}
|
||||
var QUnitExtras = load('../node_modules/qunit-extras/qunit-extras.js');
|
||||
if (QUnitExtras) {
|
||||
QUnitExtras.runInContext(root);
|
||||
}
|
||||
|
||||
var mapping = root.mapping || load('../fp/_mapping.js'),
|
||||
applyFPMapping = load('../lib/doc/apply-fp-mapping'),
|
||||
Entry = load('docdown/lib/entry');
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
function toEntry(name, paramLines, exampleLines, attachedToPrototype) {
|
||||
var start = [
|
||||
'/**',
|
||||
' * ',
|
||||
' * Foo',
|
||||
' * '
|
||||
];
|
||||
var end = [
|
||||
' */',
|
||||
'function ' + name + '(a, b, c) {',
|
||||
'',
|
||||
'}'
|
||||
];
|
||||
var staticLine = attachedToPrototype ? [] : [' * @static'];
|
||||
var params = paramLines.map(function(line) {
|
||||
return ' * @param ' + line;
|
||||
});
|
||||
var example = (exampleLines || []).map(function(line) {
|
||||
return ' * ' + line;
|
||||
});
|
||||
|
||||
return [].concat(start, staticLine, params, [' * @example'], example, end).join('\n');
|
||||
}
|
||||
|
||||
var differenceBySource = toEntry('differenceBy', [
|
||||
'{Array} array The array to inspect.',
|
||||
'{...Array} [values] The values to exclude.',
|
||||
'{Function|Object|string} [iteratee=_.identity] The iteratee invoked per element.'
|
||||
], [
|
||||
'_.differenceBy([3.1, 2.2, 1.3], [4.4, 2.5], Math.floor);',
|
||||
'// → [3.1, 1.3]',
|
||||
'',
|
||||
'// The `_.property` iteratee shorthand.',
|
||||
"_.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x');",
|
||||
"// → [{ 'x': 2 }]"
|
||||
]);
|
||||
|
||||
var setParams = [
|
||||
'{Object} object The object to modify.',
|
||||
'{Array|string} path The path of the property to set.',
|
||||
'{*} value The value to set.'
|
||||
];
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
if (argv) {
|
||||
console.log('Running doc generation tests.');
|
||||
}
|
||||
|
||||
mapping.aryMethod[2].push('customFun');
|
||||
applyFPMapping(mapping);
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('getExample');
|
||||
|
||||
(function() {
|
||||
QUnit.test('should reorder parameters', function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var entry = new Entry(differenceBySource, differenceBySource);
|
||||
|
||||
var actual = entry.getExample();
|
||||
|
||||
assert.equal(actual, [
|
||||
'```js',
|
||||
'_.differenceBy(Math.floor, [4.4, 2.5], [3.1, 2.2, 1.3]);',
|
||||
'// → [3.1, 1.3]',
|
||||
'',
|
||||
'// The `_.property` iteratee shorthand.',
|
||||
"_.differenceBy('x', [{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }]);",
|
||||
"// → [{ 'x': 2 }]",
|
||||
'```'
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
QUnit.test('should reorder parameters that have a special order', function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var example = toEntry('set', setParams, [
|
||||
"var object = { 'a': [{ 'b': { 'c': 3 } }] };",
|
||||
"_.set(object, 'a[0].b.c', 4);",
|
||||
"_.set(object, 'x[0].y.z', 5);",
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getExample();
|
||||
|
||||
assert.equal(actual, [
|
||||
'```js',
|
||||
"var object = { 'a': [{ 'b': { 'c': 3 } }] };",
|
||||
"_.set('a[0].b.c', 4, object);",
|
||||
"_.set('x[0].y.z', 5, object);",
|
||||
'```'
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
QUnit.test('should preserve comments', function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var example = toEntry('set', setParams, [
|
||||
"var object = { 'a': [{ 'b': { 'c': 3 } }] };",
|
||||
"_.set(object, 'a[0].b.c', 4);",
|
||||
'// => 4',
|
||||
"_.set(object, 'x[0].y.z', 5);",
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getExample();
|
||||
|
||||
assert.equal(actual, [
|
||||
'```js',
|
||||
"var object = { 'a': [{ 'b': { 'c': 3 } }] };",
|
||||
"_.set('a[0].b.c', 4, object);",
|
||||
'// => 4',
|
||||
"_.set('x[0].y.z', 5, object);",
|
||||
'```'
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
QUnit.test('should remove console.logs from example', function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var example = toEntry('set', setParams, [
|
||||
"var object = { 'a': [{ 'b': { 'c': 3 } }] };",
|
||||
'',
|
||||
"_.set(object, 'a[0].b.c', 4);",
|
||||
'console.log(object.a[0].b.c);',
|
||||
'// => 4',
|
||||
'',
|
||||
"_.set(object, 'x[0].y.z', 5);",
|
||||
'console.log(object.x[0].y.z);',
|
||||
'// => 5'
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getExample();
|
||||
|
||||
assert.equal(actual, [
|
||||
'```js',
|
||||
"var object = { 'a': [{ 'b': { 'c': 3 } }] };",
|
||||
'',
|
||||
"_.set('a[0].b.c', 4, object);",
|
||||
'// => 4',
|
||||
'',
|
||||
"_.set('x[0].y.z', 5, object);",
|
||||
'// => 5',
|
||||
'```'
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
QUnit.test('should merge extra arguments into an array', function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var example = toEntry('pullAt', [
|
||||
'{Array} array The array to modify.',
|
||||
'{...(number|number[])} [indexes] The indexes of elements to remove,\n' +
|
||||
' * specified individually or in arrays.'
|
||||
], [
|
||||
'var array = [5, 10, 15, 20];',
|
||||
'var evens = _.pullAt(array, 1, 3);',
|
||||
'',
|
||||
'console.log(array);',
|
||||
'// => [5, 15]',
|
||||
'',
|
||||
'console.log(evens);',
|
||||
'// => [10, 20]'
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getExample();
|
||||
|
||||
assert.equal(actual, [
|
||||
'```js',
|
||||
'var array = [5, 10, 15, 20];',
|
||||
'var evens = _.pullAt([1, 3], array);',
|
||||
'',
|
||||
'// => [5, 15]',
|
||||
'',
|
||||
'// => [10, 20]',
|
||||
'```'
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
QUnit.test('should inject default values into optional arguments that became compulsory', function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var example = toEntry('sampleSize', [
|
||||
'{Array|Object} collection The collection to sample.',
|
||||
'{number} [n=0] The number of elements to sample.'
|
||||
], [
|
||||
'_.sampleSize([1, 2, 3]);',
|
||||
'// => [3, 1]',
|
||||
'',
|
||||
'_.sampleSize([1, 2, 3], 4);',
|
||||
'// => [2, 3, 1]'
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getExample();
|
||||
|
||||
assert.equal(actual, [
|
||||
'```js',
|
||||
'_.sampleSize(0, [1, 2, 3]);',
|
||||
'// => [3, 1]',
|
||||
'',
|
||||
'_.sampleSize(4, [1, 2, 3]);',
|
||||
'// => [2, 3, 1]',
|
||||
'```'
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
QUnit.test('should inject referenced values into optional arguments that became compulsory, ' +
|
||||
|
||||
'if a parameter\'s default value references parameter (direct reference)',
|
||||
function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var example = toEntry('customFun', [
|
||||
'{Array} array Array',
|
||||
'{number} [foo=array] Foo'
|
||||
], [
|
||||
'_.customFun([1, 2, 3]);',
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getExample();
|
||||
|
||||
assert.equal(actual, [
|
||||
'```js',
|
||||
'_.customFun([1, 2, 3], [1, 2, 3]);',
|
||||
'```'
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
QUnit.test('should inject referenced values into optional arguments that became compulsory, ' +
|
||||
'if a parameter\'s default value references parameter (member expression)',
|
||||
function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var example = toEntry('fill', [
|
||||
'{Array} array The array to fill.',
|
||||
'{*} value The value to fill `array` with.',
|
||||
'{number} [start=0] The start position.',
|
||||
'{number} [end=array.length] The end position.'
|
||||
], [
|
||||
'var array = [1, 2, 3];',
|
||||
'',
|
||||
"_.fill(array, 'a');",
|
||||
'console.log(array);',
|
||||
"// => ['a', 'a', 'a']",
|
||||
'',
|
||||
'_.fill(Array(3), 2, 1);',
|
||||
'// => [undefined, 2, 2]',
|
||||
'',
|
||||
"_.fill([4, 6, 8, 10], '*');",
|
||||
"// => [*, '*', '*', *]"
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getExample();
|
||||
|
||||
assert.equal(actual, [
|
||||
'```js',
|
||||
'var array = [1, 2, 3];',
|
||||
'',
|
||||
"_.fill(0, array.length, 'a', array);",
|
||||
"// => ['a', 'a', 'a']",
|
||||
'',
|
||||
'_.fill(1, 3, 2, Array(3));',
|
||||
'// => [undefined, 2, 2]',
|
||||
'',
|
||||
"_.fill(0, 4, '*', [4, 6, 8, 10]);",
|
||||
"// => [*, '*', '*', *]",
|
||||
'```'
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
QUnit.test('should inject default values in the middle of the arguments', function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var example = toEntry('inRange', [
|
||||
'{number} number The number to check.',
|
||||
'{number} [start=0] The start of the range.',
|
||||
'{number} end The end of the range.'
|
||||
], [
|
||||
'_.inRange(4, 8);',
|
||||
'// => true'
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getExample();
|
||||
|
||||
assert.equal(actual, [
|
||||
'```js',
|
||||
'_.inRange(8, 0, 4);',
|
||||
'// => true',
|
||||
'```'
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
QUnit.test('should not use ignored params as default values', function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var example = toEntry('drop', [
|
||||
'{Array} array The array to query.',
|
||||
'{number} [n=1] The number of elements to drop.',
|
||||
'{Object} [guard] Enables use as an iteratee for functions like `_.map`.'
|
||||
], [
|
||||
'_.drop([1, 2, 3]);',
|
||||
'// => [2, 3]'
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getExample();
|
||||
|
||||
assert.equal(actual, [
|
||||
'```js',
|
||||
'_.drop(1, [1, 2, 3]);',
|
||||
'// => [2, 3]',
|
||||
'```'
|
||||
].join('\n'));
|
||||
});
|
||||
}());
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
QUnit.module('getParams');
|
||||
|
||||
(function() {
|
||||
QUnit.test('should reorder arguments and remove default values', function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var example = toEntry('differenceBy', [
|
||||
'{Array} array The array to inspect.',
|
||||
'{...Array} [values] The values to exclude.',
|
||||
'{Function|Object|string} [iteratee=_.identity] The iteratee invoked per element.'
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getParams();
|
||||
|
||||
assert.deepEqual(actual, [
|
||||
['Function|Object|string', 'iteratee', 'The iteratee invoked per element. '],
|
||||
['Array|Array[]', 'values', 'The values to exclude. '],
|
||||
['Array', 'array', 'The array to inspect. ']
|
||||
]);
|
||||
});
|
||||
|
||||
QUnit.test('should reorder arguments that have a special order', function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var example = toEntry('set', [
|
||||
'{Object} object The object to modify.',
|
||||
'{Array|string} path The path of the property to set.',
|
||||
'{*} value The value to set.'
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getParams();
|
||||
|
||||
assert.deepEqual(actual, [
|
||||
['Array|string', 'path', 'The path of the property to set. '],
|
||||
['*', 'value', 'The value to set. '],
|
||||
['Object', 'object', 'The object to modify. '],
|
||||
]);
|
||||
});
|
||||
|
||||
QUnit.test('should transform rest arguments into an array', function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var example = toEntry('pullAt', [
|
||||
'{Array} array The array to modify.',
|
||||
'{...(number|number[])} [indexes] The indexes of elements to remove,\n' +
|
||||
' * specified individually or in arrays.'
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getParams();
|
||||
|
||||
assert.deepEqual(actual, [
|
||||
// TODO Remove this line in favor of the commented one.
|
||||
// Is linked to a docdown issue (https://github.com/jdalton/docdown/pull/37)
|
||||
// that does not handle parens in the arguments well
|
||||
['((number|number)|((number|number)[]', 'indexes', 'The indexes of elements to remove, specified individually or in arrays. '],
|
||||
// ['number|number[]', '[indexes]', 'The indexes of elements to remove, specified individually or in arrays. '],
|
||||
['Array', 'array', 'The array to modify. '],
|
||||
]);
|
||||
});
|
||||
|
||||
QUnit.test('should duplicate and de-restify "rest" parameters if there are less parameters than cap', function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var example = toEntry('intersectionWith', [
|
||||
'{...Array} [arrays] The arrays to inspect.',
|
||||
'{Function} [comparator] The comparator invoked per element.'
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getParams();
|
||||
|
||||
assert.deepEqual(actual, [
|
||||
['Function', 'comparator', 'The comparator invoked per element. '],
|
||||
['Array', 'arrays', 'The arrays to inspect. '],
|
||||
['Array', 'arrays', 'The arrays to inspect. ']
|
||||
]);
|
||||
});
|
||||
|
||||
QUnit.test('should consider method to have an ary of `ary - 1` when capped and wrapped', function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var wrapped = true;
|
||||
var example = toEntry('flatMap', [
|
||||
'{Array} array The array to iterate over.',
|
||||
'{Function|Object|string} [iteratee=_.identity] The function invoked per iteration.'
|
||||
], [], wrapped);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getParams();
|
||||
|
||||
assert.deepEqual(actual, [
|
||||
['Function|Object|string', 'iteratee', 'The function invoked per iteration. ']
|
||||
]);
|
||||
});
|
||||
|
||||
QUnit.test('should remove arguments ignored because of capping (includes)', function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var example = toEntry('includes', [
|
||||
'{Array|Object|string} collection The collection to search.',
|
||||
'{*} value The value to search for.',
|
||||
'{number} [fromIndex=0] The index to search from.'
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getParams();
|
||||
|
||||
assert.deepEqual(actual, [
|
||||
['*', 'value', 'The value to search for. '],
|
||||
['Array|Object|string', 'collection', 'The collection to search. ']
|
||||
]);
|
||||
});
|
||||
|
||||
QUnit.test('should remove arguments ignored because of capping (trim)', function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var example = toEntry('trim', [
|
||||
"{string} [string=''] The string to trim.",
|
||||
'{string} [chars=whitespace] The characters to trim.'
|
||||
]);
|
||||
var entry = new Entry(example, example);
|
||||
|
||||
var actual = entry.getParams();
|
||||
|
||||
assert.deepEqual(actual, [
|
||||
['string', 'string', 'The string to trim. ']
|
||||
]);
|
||||
});
|
||||
}());
|
||||
|
||||
QUnit.config.asyncRetries = 10;
|
||||
QUnit.config.hidepassed = true;
|
||||
|
||||
if (!document) {
|
||||
QUnit.config.noglobals = true;
|
||||
QUnit.load();
|
||||
}
|
||||
}.call(this));
|
||||
Reference in New Issue
Block a user