UNPKG

util-ex

Version:

Browser-friendly enhanced util fully compatible with standard node.js

115 lines (114 loc) 3.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.newScopedFunction = newScopedFunction; var _function = _interopRequireDefault(require("./is/string/function.js")); var _string = _interopRequireDefault(require("./is/type/string.js")); var _createFunction = require("./_create-function.js"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } /** * Creates an executable function with dynamic scope binding * * Unlike statically scoped functions, this rebinds scope variables on every execution, * allowing runtime updates to the execution environment. The function achieves this * through closure-delayed scope binding, regenerating the target function on each call. * * @example * // Basic usage * const scopedFunc = newScopedFunction( * 'add', * ['x'], * 'return x + y', * { y: 10 } // Initial scope * ); * scopedFunc(5); // Returns 15 * * // Dynamic scope update * const scope = { y: 20 }; * const updatableFunc = newScopedFunction('add', ['x'], 'return x + y', scope); * updatableFunc(5); // Returns 25 * scope.y = 100; * updatableFunc(5); // Returns 105 * * @param {string} name - Function name (for debugging and stack traces) * @param {string[]} argNames - Formal parameter names (array format) * @param {string} body - Function body code (as JavaScript string) * @param {Object} scope - Execution scope object (key-value pairs) * * @returns {Function} Executable function that: * - Accepts arguments defined in `argNames` * - Regenerates the function using current `scope` on each call * - Returns the execution result * * @see {@link newFunction} Underlying static-scope function generator * * @warning Performance note: Rebuilds function object on every call - * avoid in high-frequency scenarios * @note Scope dynamism: Always uses latest `scope` reference (pass-by-reference) * * @since 1.0.0 */ function newScopedFunction(name, argNames, body, scope) { const params = normalizeFuncParams(name, argNames, body, scope); let funcName = params.name; if (funcName === undefined) { const func = (0, _createFunction._createFunction)(params.body, params.scope); funcName = func.name; } params.createFunc = _createFunction._createFunction; const func = funcName ? (0, _createFunction._createFunction)(`function ${funcName}(...args) {return createFunc(body, scope)(...args);}`, params) : function (...args) { const func = (0, _createFunction._createFunction)(body, scope); return func(...args); }; return func; } function normalizeFuncParams(name, argNames, body, scope) { if (!(0, _function.default)(name)) { let async = ''; const vNameType = typeof name; if (vNameType === 'string') { if (name.startsWith('async ')) { name = name.substring(6); async = 'async '; } } else if (vNameType === 'object') { scope = name; name = ''; } else { name = ''; } if ((0, _string.default)(argNames)) { scope = argNames; body = argNames; argNames = []; } else if (!Array.isArray(argNames)) { argNames = []; } if (!body) { body = ''; } body = `${async}function ${name}(${argNames.join(', ')}) {\n${body}\n}`; } else { body = name; name = undefined; } return { name, body, scope }; } function getFuncName(name, argNames, body, scope) { const params = normalizeFuncParams(name, argNames, body, scope); if (params.name === undefined) { const func = (0, _createFunction._createFunction)(params.body, params.scope); params.name = func.name; } return params.name; } function newFunc(name, argNames, body, scope) { const params = normalizeFuncParams(name, argNames, body, scope); const func = (0, _createFunction._createFunction)(params.body, params.scope); return func; }