137 lines
3.9 KiB
JavaScript
Executable File
137 lines
3.9 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
'use strict';
|
|
|
|
const splitSkip = require('split-skip');
|
|
const unpackString = require('unpack-string');
|
|
|
|
const isArrayLike = p => p.match(/^\[+/) || null;
|
|
const isObjectLike = p => p.match(/^{+/) || null;
|
|
const matchObjectProperty = p => p.match(/^([^{]+):(.*)/) || null;
|
|
|
|
const getParametersStringfied = fn => {
|
|
let fnString = fn.constructor === String ? fn.replace(/\s/g, '') : fn.toString().replace(/\s/g, '');
|
|
|
|
// Is an Arrow function with only one argument defined without parenthesis
|
|
if (!fnString.match(/^function/) && !fnString.match(/^\(/)) {
|
|
let matchArrowWithoutParenthesis = fnString.match(/^(.*?)=>/);
|
|
return matchArrowWithoutParenthesis ? matchArrowWithoutParenthesis[1] : null;
|
|
}
|
|
|
|
return unpackString(fnString);
|
|
}
|
|
|
|
function splitSkipBrackets(string, delimiter) {
|
|
return splitSkip(string, delimiter, (state, char, i) => {
|
|
|
|
if ('{[('.indexOf(char) >= 0) {
|
|
state.skip += 1;
|
|
}
|
|
|
|
if ('}])'.indexOf(char) >= 0) {
|
|
state.skip -= 1;
|
|
}
|
|
|
|
return state;
|
|
});
|
|
}
|
|
|
|
function getParametersArray(paramsString) {
|
|
return splitSkipBrackets(paramsString, ',');
|
|
}
|
|
|
|
function inspectDestructuringParameters(param, list = []) {
|
|
param = param.trim();
|
|
|
|
const unpackedArray = getParametersArray(unpackString(param));
|
|
|
|
if (isArrayLike(param)) {
|
|
unpackedArray.forEach(param => inspectDestructuringParameters(param, list));
|
|
} else if (isObjectLike(param)) {
|
|
unpackedArray.forEach(param => {
|
|
let objectProperty = matchObjectProperty(param);
|
|
if (objectProperty) {
|
|
param = objectProperty[2];
|
|
inspectDestructuringParameters(param, list);
|
|
} else {
|
|
inspectDestructuringParameters(param, list);
|
|
}
|
|
});
|
|
} else {
|
|
const [ name, defaultValue ] = splitSkipBrackets(param, '=');
|
|
list.push([ name, defaultValue ]);
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
function getParametersInfo(paramsArray) {
|
|
let names = [];
|
|
let expected = [];
|
|
let defaultValues = {};
|
|
|
|
paramsArray.forEach((param) => {
|
|
let [ paramDefinition, defaultValue ] = splitSkipBrackets(param, '=');
|
|
|
|
expected.push(paramDefinition);
|
|
if (defaultValue) {
|
|
defaultValues[paramDefinition] = defaultValue;
|
|
}
|
|
|
|
if (isArrayLike(paramDefinition) || isObjectLike(paramDefinition)) {
|
|
inspectDestructuringParameters(paramDefinition)
|
|
.forEach(([paramName, defaultValue]) => {
|
|
names.push(paramName);
|
|
if(defaultValue){
|
|
defaultValues[paramName] = defaultValue;
|
|
}
|
|
});
|
|
} else {
|
|
names.push(paramDefinition);
|
|
}
|
|
|
|
});
|
|
|
|
return { parameters: { expected, defaultValues, names } };
|
|
}
|
|
|
|
function getSignatureFromParametersArray(name, paramsArray) {
|
|
return `${name}(${paramsArray.map(v => v.replace(/^([^=]*)=/, `$1 = `)).join(', ')});`
|
|
}
|
|
|
|
function getNameFromSourceCode(fn) {
|
|
let fnString = fn.constructor === String ? fn.replace(/(\r\n|\r|\n)/g, '') : fn.toString().replace(/(\r\n|\r|\n)/g, '');
|
|
fnString = fnString.replace(/function\(/g, '');
|
|
fnString = fnString.replace(/^const|let|var/, '');
|
|
|
|
let pattern = /([^ (]*)\(/;
|
|
let match = fnString.match(/([^ (]*)\(/);
|
|
if(!match){
|
|
match = fnString.match(/([^ (]*)\s?=/);
|
|
}
|
|
if(match){
|
|
return match[1].trim();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Inspects a function and returns informations about it
|
|
* @param {Function|String} fn - Function to be inspected
|
|
* @param {String} name - Name of the function to be used at the result set (it will supersed the one found during the inspection)
|
|
* @return {Object} Returns and object with fn, name, parameters, parameters, signature
|
|
*/
|
|
function inspectFunction(fn, name) {
|
|
name = name || fn.name || getNameFromSourceCode(fn) || '';
|
|
const parametersDefinitions = getParametersArray(getParametersStringfied(fn));
|
|
const { parameters } = getParametersInfo(parametersDefinitions);
|
|
const signature = getSignatureFromParametersArray(name, parametersDefinitions);
|
|
parameters.definitions = parametersDefinitions;
|
|
|
|
return {
|
|
fn: fn.constructor === Function ? fn : null,
|
|
name,
|
|
parameters,
|
|
signature
|
|
}
|
|
}
|
|
|
|
module.exports = inspectFunction; |