UNPKG

parse-function

Version:

Parse a function into an object using espree, acorn or babylon parsers. Extensible through Smart Plugins

181 lines (145 loc) 4.62 kB
import { parseExpression } from '@babel/parser'; const arrify = value => { if (value === null || value === undefined) { return []; } if (Array.isArray(value)) { return value; } if (typeof value === 'string') { return [value]; } if (typeof value[Symbol.iterator] === 'function') { return [...value]; } return [value]; }; var arrify_1 = arrify; const utils = {}; utils.arrayify = arrify_1; utils.setDefaults = function setDefaults(code) { const result = { name: null, body: '', args: [], params: '' }; if (typeof code === 'function') { code = code.toString('utf8'); } if (typeof code !== 'string') { code = ''; } return utils.setHiddenDefaults(result, code || ''); }; utils.setHiddenDefaults = function setHiddenDefaults(result, code) { result.defaults = {}; result.value = code; result.isValid = code.length > 0; result.isArrow = false; result.isAsync = false; result.isNamed = false; result.isAnonymous = false; result.isGenerator = false; result.isExpression = false; return result; }; utils.getNode = function getNode(result, opts) { if (typeof opts.parse === 'function') { result.value = `(${result.value})`; const ast = opts.parse(result.value, opts); const body = ast.program && ast.program.body || ast.body; return body[0].expression; } return parseExpression(result.value, opts); }; const body = (() => (node, result) => { result.body = result.value.slice(node.body.start, node.body.end); const openCurly = result.body.charCodeAt(0) === 123; const closeCurly = result.body.charCodeAt(result.body.length - 1) === 125; if (openCurly && closeCurly) { result.body = result.body.slice(1, -1); } return result; }); const props = (() => (node, result) => { result.isArrow = node.type.startsWith('Arrow'); result.isAsync = node.async || false; result.isGenerator = node.generator || false; result.isExpression = node.expression || false; result.isAnonymous = node.id === null; result.isNamed = !result.isAnonymous; result.name = result.isAnonymous ? null : node.id.name; return result; }); const params = (() => (node, result) => { node.params.forEach(param => { const defaultArgsName = param.type === 'AssignmentPattern' && param.left && param.left.name; const restArgName = param.type === 'RestElement' && param.argument && param.argument.name; const name = param.name || defaultArgsName || restArgName; result.args.push(name); if (param.right && param.right.type === 'SequenceExpression') { const lastExpression = param.right.expressions.pop(); result.defaults[name] = result.value.slice(lastExpression.start, lastExpression.end); } else { result.defaults[name] = param.right ? result.value.slice(param.right.start, param.right.end) : undefined; } }); result.params = result.args.join(', '); return result; }); const initial = (app => (node, result) => { const isFn = node.type.endsWith('FunctionExpression'); const isMethod = node.type === 'ObjectExpression'; if (!isFn && !isMethod) { return; } node = isMethod ? node.properties[0] : node; node.id = isMethod ? node.key : node.id; if (node.type === 'Property') { const id = node.key; node = node.value; node.id = id; } result = props()(node, result); result = params()(node, result); result = body()(node, result); return result; }); function parseFunction(opts = {}) { const plugins = []; const app = { parse(code, options) { const result = utils.setDefaults(code); if (!result.isValid) { return result; } const mergedOptions = { ...opts, ...options }; const isFunction = result.value.startsWith('function'); const isAsyncFn = result.value.startsWith('async function'); const isAsync = result.value.startsWith('async'); const isArrow = result.value.includes('=>'); const isAsyncArrow = isAsync && isArrow; const isMethod = /^\*?.+\([\s\S\w\W]*\)\s*\{/i.test(result.value); if (!(isFunction || isAsyncFn || isAsyncArrow) && isMethod) { result.value = `{ ${result.value} }`; } const node = utils.getNode(result, mergedOptions); return plugins.reduce((res, fn) => fn(node, res) || res, result); }, use(fn) { const ret = fn(app); if (typeof ret === 'function') { plugins.push(ret); } return app; }, define: utils.define }; app.use(initial); return app; } export default parseFunction; //# sourceMappingURL=index.js.map