UNPKG

js2flowchart

Version:

> Why? While I've been working on [Under-the-hood-ReactJS](https://github.com/Bogdan-Lyashenko/Under-the-hood-ReactJS) I spent enormous amount of time on creating schemes. Each change in code or flowchart affects all entire scheme instantly, forcing you t

234 lines (227 loc) 9.49 kB
import generate from '@babel/generator'; import { TOKEN_TYPES, CLASS_FUNCTION_KINDS } from 'shared/constants'; export var idleConverter = function idleConverter(path) { return generate(path.node).code; }; export var identifierConverter = function identifierConverter(path) { if (path.parent.type === TOKEN_TYPES.SPREAD_PROPERTY) { return '...' + idleConverter(path); } return idleConverter(path); }; /* function */ export var functionConverter = function functionConverter(path) { var node = path.node, paramsCode = getFunctionParametersCode(node.params); var name = ''; if (node.id) { name = getAnonymousFunctionName(path) + 'function ' + node.id.name + paramsCode; } else if (node.type === TOKEN_TYPES.ARROW_FUNCTION_EXPRESSION) { name = getAnonymousFunctionName(path) + paramsCode + ' =>'; } else if (node.type === TOKEN_TYPES.CLASS_METHOD || node.type === TOKEN_TYPES.OBJECT_METHOD) { name = node.kind === CLASS_FUNCTION_KINDS.CONSTRUCTOR ? 'constructor' + paramsCode : node.key.name + paramsCode; } else { name = getAnonymousFunctionName(path) + 'function' + paramsCode; } return { name: name, pathParentType: path.parent.type }; }; export var getAnonymousFunctionName = function getAnonymousFunctionName(path) { var parent = path.parent; if (!parent || parent.type !== TOKEN_TYPES.VARIABLE_DECLARATOR && parent.type !== TOKEN_TYPES.ASSIGNMENT_EXPRESSION && parent.type !== TOKEN_TYPES.OBJECT_PROPERTY) { return ''; } if (parent.left) { return generate(parent.left).code + ' = '; } var parentId = parent.id; return parentId ? parentId.name + ' = ' : ''; }; export var getFunctionParametersCode = function getFunctionParametersCode(params) { return "(".concat(params.map(function (p) { if (p.name) { return p.name; } return generate(p).code; }).join(', '), ")"); }; export var returnConverter = function returnConverter(path) { var node = path.node; if (node.argument && ([TOKEN_TYPES.CONDITIONAL_EXPRESSION, TOKEN_TYPES.OBJECT_EXPRESSION].includes(node.argument.type) || isFunctionType(node.argument.type))) { return 'return'; } return path.node.argument ? "return ".concat(generate(path.node.argument).code) : 'return'; }; /* end function */ /* loop */ export var loopConverter = function loopConverter(_ref) { var node = _ref.node; if (node.test) { return generate(node.test).code; } if (node.left && node.right) { var innerPart = node.type === TOKEN_TYPES.FOR_OF_STATEMENT ? 'of' : 'in'; var leftPart = node.left.type === TOKEN_TYPES.VARIABLE_DECLARATION ? getVariableDeclarations(node.left.declarations) : generate(node.left).code; return "".concat(leftPart, " ").concat(innerPart, " ").concat(generate(node.right).code); } }; export var continueConverter = function continueConverter(path) { return path.node.label ? "continue ".concat(generate(path.node.label).code) : 'continue'; }; /* end loop */ export var conditionalConverter = function conditionalConverter(path) { return "(".concat(generate(path.node.test).code, ")"); }; /* try-catch */ export var tryConverter = function tryConverter(path) { return "try"; }; export var catchConverter = function catchConverter(path) { return path.node.param ? "catch (".concat(generate(path.node.param).code, ")") : '*catchConverter*'; }; export var finallyConverter = function finallyConverter(path) { //TODO: fix `finally`, not implemented yet because it presents only as a part of parent, //there is no `finally` visitor as it exist for `catch` //seems like to do that each try-catch block should be handled in a different way return '*finallyConverter*'; }; /* end try-catch */ /* switch-case */ export var switchStatementConverter = function switchStatementConverter(path) { return "switch (".concat(generate(path.node.discriminant).code, ")"); }; export var caseConverter = function caseConverter(path) { return path.node.test ? "case ".concat(generate(path.node.test).code, ":") : 'default:'; }; export var breakConverter = function breakConverter(path) { return path.node.label ? "break ".concat(generate(path.node.label).code, ":") : 'break'; }; /* end switch - case */ export var withStatementConverter = function withStatementConverter(path) { return "with (".concat(generate(path.node.object).code, ")"); }; export var programConverter = function programConverter(path) { return "".concat(path.node.type, ": source ").concat(path.node.sourceType); }; export var throwStatementConverter = function throwStatementConverter(path) { return "throw ".concat(generate(path.node.argument).code); }; export var debuggerConverter = function debuggerConverter(path) { return "debugger"; }; export var getVariableDeclarations = function getVariableDeclarations(variables) { return variables.map(function (v) { return variableDeclaratorConverter({ node: v }); }).join(', '); }; export var variableDeclaratorConverter = function variableDeclaratorConverter(path) { var node = path.node, parentKind = path.parent && path.parent.kind || ''; if (node.init && (isNodeContainsFunc(node.init) || node.init.type === TOKEN_TYPES.CONDITIONAL_EXPRESSION)) { return "".concat(parentKind, " ").concat(node.id.name, " = "); } var variableName = ''; if (node.id.type === TOKEN_TYPES.OBJECT_PATTERN) { variableName = '{...}'; } else if (node.id.type === TOKEN_TYPES.ARRAY_PATTERN) { variableName = '[...]'; } else { variableName = node.id.name; } if (node.init && [TOKEN_TYPES.CALL_EXPRESSION, TOKEN_TYPES.NEW_EXPRESSION].includes(node.init.type)) { return "".concat(parentKind, " ").concat(variableName, " = ") + callExpressionConverter({ node: node.init }); } if (node.init && node.init.type === TOKEN_TYPES.OBJECT_EXPRESSION) { return "".concat(parentKind, " ").concat(variableName, " = ").concat(objectExpressionConverter()); } if (node.id && node.id.type === TOKEN_TYPES.OBJECT_PATTERN) { return "".concat(parentKind, " {...} = ").concat(node.init.name); } if (node.id && node.id.type === TOKEN_TYPES.ARRAY_PATTERN) { return "".concat(parentKind, " [...] = ").concat(node.init.name); } return parentKind + ' ' + generate(node).code; }; export var assignmentExpressionConverter = function assignmentExpressionConverter(_ref2) { var node = _ref2.node; if (isNodeContainsFunc(node.right) || node.right.type === TOKEN_TYPES.CONDITIONAL_EXPRESSION) { return "".concat(getLeftAssignmentName(node.left), " ").concat(node.operator, " "); } if (node.right.type === TOKEN_TYPES.OBJECT_EXPRESSION) { return "".concat(getLeftAssignmentName(node.left), " ").concat(node.operator, " ").concat(objectExpressionConverter()); } if ([TOKEN_TYPES.CALL_EXPRESSION, TOKEN_TYPES.NEW_EXPRESSION].includes(node.right.type)) { return "".concat(getLeftAssignmentName(node.left), " ").concat(node.operator, " ").concat(callExpressionConverter({ node: node.right })); } return generate(node).code; }; var getLeftAssignmentName = function getLeftAssignmentName(node) { if (node.name) { return node.name; } return generate(node).code; }; export var callExpressionConverter = function callExpressionConverter(_ref3) { var node = _ref3.node; var argumentsCode = ''; if (node.arguments && node.arguments.length) { argumentsCode = node.arguments.map(getArgumentName).join(', '); } var callee = node.callee; if (callee.type === TOKEN_TYPES.MEMBER_EXPRESSION && callee.object.type === TOKEN_TYPES.CALL_EXPRESSION) { return { name: ".".concat(callee.property.name, "(").concat(argumentsCode, ")"), chain: true }; } else if (argumentsCode) { return "".concat(generate(node.callee).code, "(").concat(argumentsCode, ")"); } return generate(node).code; }; var getArgumentName = function getArgumentName(argument) { if (isNodeContainsFunc(argument)) return '*()'; if (argument.type === TOKEN_TYPES.OBJECT_EXPRESSION) return objectExpressionConverter(); if (argument.name) return argument.name; if (argument.value) return argument.type === TOKEN_TYPES.STRING_LITERAL ? "'".concat(argument.value, "'") : argument.value; return generate(argument).code; }; export var objectExpressionConverter = function objectExpressionConverter(path) { var name = '{*}'; if (path) return { name: name, pathParentType: path.parent.type }; return name; }; export var objectPropertyConverter = function objectPropertyConverter(path) { var node = path.node; if (node.value && isFunctionType(node.value.type)) { return node.key.name + ': '; } if (node.value && node.value.type === TOKEN_TYPES.OBJECT_EXPRESSION) { return node.key.name + ': ' + objectExpressionConverter(); } return generate(node).code; }; var getFirstCallee = function getFirstCallee(callee) { if (!callee) return callee; if (callee.type === TOKEN_TYPES.MEMBER_EXPRESSION && callee.object.type === TOKEN_TYPES.CALL_EXPRESSION) { return getFirstCallee(callee.object); } return callee; }; export var isFunctionType = function isFunctionType(type) { return [TOKEN_TYPES.FUNCTION_EXPRESSION, TOKEN_TYPES.FUNCTION, TOKEN_TYPES.ARROW_FUNCTION_EXPRESSION, TOKEN_TYPES.FUNCTION_DECLARATION].includes(type); }; export var isNodeContainsFunc = function isNodeContainsFunc(node) { var functions = [TOKEN_TYPES.ARROW_FUNCTION_EXPRESSION, TOKEN_TYPES.FUNCTION_EXPRESSION]; return node && functions.indexOf(node.type) !== -1; };