util-ex
Version:
Browser-friendly enhanced util fully compatible with standard node.js
157 lines (153 loc) • 6.37 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
exports.newFunction = newFunction;
var _createFunction = _interopRequireDefault(require("./_create-function.js"));
var _function = _interopRequireDefault(require("./is/string/function.js"));
var _arrowFunction = _interopRequireDefault(require("./is/string/arrow-function.js"));
var _identifier = _interopRequireDefault(require("./is/string/identifier.js"));
var _string = _interopRequireDefault(require("./is/type/string.js"));
var _array = _interopRequireDefault(require("./is/type/array.js"));
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
/*
* Usage:
* var fn = newFunction('yourFuncName', ['arg1', 'arg2'], 'return log(arg1+arg2);', {log:console.log});
*
* newFunction('function abc(){}');
* newFunction('function abc(){}', {log:console.log})
* newFunction('function abc(){}', ['log'], [console.log])
*
* // Expression support:
* newFunction('a + b', {a:1, b:2})
* newFunction('a + b', 'add', {a:1, b:2})
*
* fn.toString() is :
* "function yourFuncName(arg1, arg2) {
* return log(arg1+arg2);
* }"
*/
function _parseExpression(expression, name, scope, values) {
if ((0, _string.default)(name) && (0, _identifier.default)(name, {
allowAsync: true
})) {
// newFunction(expression, name, scope, values)
} else {
// newFunction(expression, scope, values)
values = scope;
scope = name;
name = 'anonymous';
}
let async = '';
if (expression.includes('await') || expression.trim().startsWith('async ')) {
async = 'async ';
if (expression.trim().startsWith('async ')) {
expression = expression.trim().substring(6);
}
}
const body = expression.includes('return ') ? expression : `return ${expression}`;
const funcStr = `${async}function ${name}(){${body}}`;
return (0, _createFunction.default)(funcStr, scope, values);
}
/**
* Creates a new function with the given name, arguments, body, scope and values.
*
* * If the first argument is an **expression** (not a valid identifier and not a full function string):
* `newFunction(expression, [name], [scope], [values])`
* - The expression is automatically wrapped in a function and prefixed with `return` if needed.
* - If the second argument is a valid identifier, it's used as the function name.
*
* * If only one argument is provided and it is a **function string**, returns a new function with the same code.
* * If only one argument is provided and it is an **identifier**, returns a new empty function with that name.
* * If multiple arguments are provided in the traditional way:
* `newFunction(name, aArgs, body, [scope], [values])`
*
* @param {string|Function} name The name of the function, the function itself, or an expression.
* @param {string[]|string|object} [aArgs] An array of argument names, or the function name (if first arg is expression), or scope.
* @param {string|object} [body] The body of the function, or scope (if first arg is expression).
* @param {object|any[]} [scope] The scope for the function, or values (if first arg is expression).
* @param {any[]} [values] The values to apply to the scope.
* @returns {Function} A new function with the given name, arguments, body, scope and values.
* @example
* // Expression support (New!)
* var add = newFunction('a + b', {a: 1, b: 2});
* add(); // 3
* var namedAdd = newFunction('a + b', 'add', {a: 1, b: 2});
* namedAdd.name; // 'add'
* var asyncAdd = newFunction('await Promise.resolve(a + b)', {a: 1, b: 2});
*
* // Traditional usage
* var add1 = newFunction(`function add(a,b) {return a+b}`);
* var add = newFunction('add', ['a', 'b'], 'return a + b;');
* var result = add(1, 2); // result is 3
* var greet = newFunction('greet', ['name'], 'console.log("Hello, " + name + "!");');
* greet('John'); // Output: Hello, John!
* const sleep = newFunction('sleep', ['ms'], 'return new Promise(resolve => setTimeout(resolve, ms));');
* const wait1Second = newFunction('async wait1Second', [], `await sleep(1000);`, {sleep});
* await wait1Second()
*/
function newFunction(name, aArgs, body, scope, values) {
if (typeof name === 'function') {
name = name.toString();
}
const asyncMatch = name.match(/^(async\s+)(.*)$/);
if ((0, _string.default)(name) && !(0, _function.default)(name) && !(0, _arrowFunction.default)(name) && !(0, _string.default)(body)) {
const expression = name;
let exprName = aArgs;
let exprScope = body;
let exprValues = scope;
if (!((0, _string.default)(exprName) && (0, _identifier.default)(exprName, {
allowAsync: true
}))) {
exprValues = exprScope;
exprScope = exprName;
exprName = 'anonymous';
}
const exprIsIdentifier = (0, _identifier.default)(expression, {
allowAsync: true
});
let maybeIdentifierExpr = exprScope && exprIsIdentifier;
if (maybeIdentifierExpr) {
const identifier = asyncMatch ? asyncMatch[2] : expression;
maybeIdentifierExpr = (0, _array.default)(exprScope) ? exprScope.indexOf(identifier) >= 0 : exprScope.hasOwnProperty(identifier);
}
if (maybeIdentifierExpr || !exprIsIdentifier) return _parseExpression(expression, exprName, exprScope, exprValues);
}
if (arguments.length === 1) {
if ((0, _function.default)(name) || (0, _arrowFunction.default)(name)) {
return (0, _createFunction.default)(name);
}
let async = '';
if (asyncMatch) {
async = 'async ';
name = asyncMatch[2];
}
name = `${async}function ${name}(){}`;
return (0, _createFunction.default)(name);
}
if ((0, _function.default)(name) || (0, _arrowFunction.default)(name)) {
scope = aArgs;
values = body;
} else {
if ((0, _string.default)(aArgs)) {
values = scope;
scope = body;
body = aArgs;
aArgs = [];
} else if (aArgs == null) {
aArgs = [];
}
let async = '';
const asyncMatch = name.match(/^(async\s+)(.*)$/);
if (asyncMatch) {
async = 'async ';
name = asyncMatch[2];
}
name = `${async}function ${name}(${aArgs.join(', ')}) {\n${body}\n}`;
}
return (0, _createFunction.default)(name, scope, values);
}
;
// Function(scope, 'return ' + name + ';').apply null, values
var _default = exports.default = newFunction;