diff --git a/function/#/to-string-tokens.js b/function/#/to-string-tokens.js index 4ce026a5..b35f51d4 100644 --- a/function/#/to-string-tokens.js +++ b/function/#/to-string-tokens.js @@ -1,17 +1,52 @@ "use strict"; -var validFunction = require("../valid-function"); +var isValue = require("../../object/is-value") + , esniff = require("esniff") + , validFunction = require("../valid-function"); -var re1 = /^\s*function[\0-')-\uffff]*\(([\0-(*-\uffff]*)\)\s*\{([\0-\uffff]*)\}\s*$/ - , re2 = /^\s*\(?([\0-'*-\uffff]*)\)?\s*=>\s*(\{?[\0-\uffff]*\}?)\s*$/; +var classRe = /^\s*class[\s{/}]/; module.exports = function () { - var str = String(validFunction(this)), data = str.match(re1); - if (!data) { - data = str.match(re2); - if (!data) throw new Error("Unrecognized string format"); - data[1] = data[1].trim(); - if (data[2][0] === "{") data[2] = data[2].trim().slice(1, -1); - } - return { args: data[1], body: data[2] }; + var str = String(validFunction(this)); + if (classRe.test(str)) throw new Error("Class methods are not supported"); + + var argsStartIndex + , argsEndIndex + , bodyStartIndex + , bodyEndReverseIndex = -1 + , shouldTrimArgs = false; + + esniff(str, function (emitter, accessor) { + emitter.once("trigger:(", function () { argsStartIndex = accessor.index + 1; }); + emitter.once("trigger:=", function () { + if (isValue(argsStartIndex)) return; + argsStartIndex = 0; + argsEndIndex = accessor.index; + shouldTrimArgs = true; + if (!accessor.skipCodePart("=>")) { + throw new Error("Unexpected function string: " + str); + } + accessor.skipWhitespace(); + if (!accessor.skipCodePart("{")) bodyEndReverseIndex = Infinity; + bodyStartIndex = accessor.index; + }); + emitter.on("trigger:)", function () { + if (accessor.scopeDepth) return; + argsEndIndex = accessor.index; + accessor.skipCodePart(")"); + accessor.skipWhitespace(); + if (accessor.skipCodePart("=>")) { + accessor.skipWhitespace(); + if (!accessor.skipCodePart("{")) bodyEndReverseIndex = Infinity; + } else if (!accessor.skipCodePart("{")) { + throw new Error("Unexpected function string: " + str); + } + bodyStartIndex = accessor.index; + accessor.stop(); + }); + }); + + var argsString = str.slice(argsStartIndex, argsEndIndex); + if (shouldTrimArgs) argsString = argsString.trim(); + return { args: argsString, body: str.slice(bodyStartIndex, bodyEndReverseIndex) }; }; diff --git a/package.json b/package.json index b91b917a..aa75130d 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "dependencies": { "es6-iterator": "^2.0.3", "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", "next-tick": "^1.1.0" }, "devDependencies": { diff --git a/test/function/#/to-string-tokens.js b/test/function/#/to-string-tokens.js index 79bb83b3..c7160dfb 100644 --- a/test/function/#/to-string-tokens.js +++ b/test/function/#/to-string-tokens.js @@ -10,10 +10,10 @@ module.exports = function (t, a) { a.deep(t.call(function () {}), { args: "", body: "" }); // eslint-disable-next-line no-unused-vars a.deep(t.call(function (raz) {}), { args: "raz", body: "" }); - a.deep(t.call(function () { Object(); }), { args: "", body: " Object(); " }); + a.deep(t.call(function () { return {}; }), { args: "", body: " return {}; " }); try { - eval("(() => {})"); + eval("((foo = bar) => {})"); } catch (e) { // Non ES2015 env return; @@ -23,4 +23,9 @@ module.exports = function (t, a) { a.deep(t.call(eval("((elo) => foo)")), { args: "elo", body: "foo" }); a.deep(t.call(eval("(elo => foo)")), { args: "elo", body: "foo" }); a.deep(t.call(eval("((elo, bar) => foo())")), { args: "elo, bar", body: "foo()" }); + a.deep(t.call(eval("foo=>bar")), { args: "foo", body: "bar" }); + a.deep(t.call(eval("(foo = { marko: (elo) => { someFunct(); } }) => { body(); }")), { + args: "foo = { marko: (elo) => { someFunct(); } }", + body: " body(); " + }); };