UNPKG

react-editable-json-tree

Version:
174 lines (156 loc) 5.95 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.functionToString = undefined; var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray'); var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /* * Author: Alexandre Havrileck (Oxyno-zeta) * Date: 22/10/16 * Licence: See Readme */ /* ************************************* */ /* ******** IMPORTS ******** */ /* ************************************* */ /* ************************************* */ /* ******** VARIABLES ******** */ /* ************************************* */ var basicFunctionPattern = new RegExp( // eslint-disable-next-line prefer-template '' + /^function/.source + / *([$_a-zA-Z][$\w]*)?/.source // name + / *\([ \n]*([$_a-zA-Z][$\w]*(?:[ \n]*,[ \n]*[$_a-zA-Z][$\w]*)*)*?,?[ \n]*\)/.source // params + /[ \n]*{\n*(.*?)\n? *}$/.source, // body 's'); /* ************************************* */ /* ******** PRIVATE FUNCTIONS ******** */ /* ************************************* */ /** * Try to regex match a string as a javascript function. * @param functionString {string} string to match * @param splitParams {boolean} whether to split parameters into an array * @returns {{name: string, params: string | string[], body: string} | null} */ function matchFunction(functionString) { var splitParams = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; var match = basicFunctionPattern.exec(functionString); if (match === null) return null; return { name: match[1], params: splitParams ? commaSplit(match[2]) : match[2], body: match[3] }; } /** * Split comma separated strings and trim surrounding whitespace. * @param string {string | undefined} a string of comma-separated strings * @returns {string[]} an array of elements that were separated by commas with * surrounding whitespace trimmed. May be empty. */ function commaSplit(string) { if (!string) return []; return string.split(',').map(function (x) { return x.trim(); }); } /** * Try creating an anonymous function from a string, or return null if it's * not a valid function definition. * Note that this is not a completely safe, there are still security flaws, * but it is safer than using `exec`. * @param functionString {string} string to try to parse as a function * definition * @returns {Function | null} an anonymous function if the string is a valid * function definition, else null */ function createFunction(functionString) { /* This is not an exhaustive check by any means * For instance, function names may have a wide variety of * unicode characters and still be valid... oh well! * * TEST CASES: * * // Should match (single-line): * function() {} * function () {} * function myFunc(){} * function myFunc(arg1){} * function(arg1,arg2, arg3, arg4) {} * function myFunc(arg1, arg2, arg3){} * function myFunc(arg1, arg2, arg3){console.log('something');} * function myFunc(arg1,){} * function myFunc(arg1, ){} * function myFunc(arg1) {if (true) {var moreCurlyBraces = 1;}} * * // Should match (multi-line): * function myFunc(arg1, arg2, arg3) { * console.log('something'); * } * * function myFunc() { * console.log('test'); * if (true) { * console.log('test2'); * } * } * * // Should not match (single-line): * anotherFunction() * function myFunc {} * function myFunc()); (anotherFunction() * function myFunc(){}, anotherFunction() */ var match = matchFunction(functionString, true); if (!match) return null; // Here's the security flaw. We want this functionality for supporting // JSONP, so we've opted for the best attempt at maintaining some amount // of security. This should be a little better than eval because it // shouldn't automatically execute code, just create a function which can // be called later. // eslint-disable-next-line no-new-func var func = new (Function.prototype.bind.apply(Function, [null].concat((0, _toConsumableArray3.default)(match.params), [match.body || ''])))(); func.displayName = match.name; return func; } /* ************************************* */ /* ******** PUBLIC FUNCTIONS ******** */ /* ************************************* */ /** * Parse a string into either a function or a JSON element. * @param string {string} string to parse * @param allowFunctionEvaluation {boolean} whether to parse strings that * are function definitions as Javascript * @returns {Function | Object | Array | null | boolean | number | string} */ function parse(string, allowFunctionEvaluation) { // Try parsing (and sanitizing) a function if (allowFunctionEvaluation) { var func = createFunction(string); if (func !== null) return func; } try { return JSON.parse(string); } catch (e) { return string; } } /** * A different implementation of Function.prototype.toString which tries to get * a function name using displayName when name is "anonymous". * @param func {Function} function to transform into a string * @returns {string} a string representing the function */ function functionToString(func) { var pattern = /^function anonymous/; var funcStr = func.toString(); if (pattern.test(funcStr) && func.displayName) { return func.toString().replace(pattern, 'function ' + func.displayName); } return funcStr; } /* ************************************* */ /* ******** EXPORTS ******** */ /* ************************************* */ exports.default = parse; exports.functionToString = functionToString;