Repository: unexpectedjs/unexpected
Pull request #387 (2017-04-17 21:59:12)

Support inspection of arrow functions
Currently they end up as `function /*...*/  { /*...*/ }` in the output.

papandreou: Argh, stupid Phantom.js. Will fix tomorrow.

Patch:
diff --git a/lib/types.js b/lib/types.js
index 59580308..76fc0ab1 100644
--- a/lib/types.js
+++ b/lib/types.js
@@ -762,15 +762,25 @@ module.exports = function (expect) {
         inspect: function (f, depth, output, inspect) {
             var source = f.toString().replace(/\r\n?|\n\r?/g, '\n');
             var name = utils.getFunctionName(f) || '';
-            var args;
+            var preamble;
             var body;
-            var asyncPrefix = '';
-            var matchSource = source.match(/^\s*(async )?function \w*?\s*\(([^\)]*)\)\s*\{([\s\S]*?( *)?)\}\s*$/);
+            var bodyIndent;
+            var matchSource = source.match(/^\s*((?:async )?\s*(?:\S+\s*=>|\([^\)]*\)\s*=>|function \w*?\s*\([^\)]*\)))([\s\S]*)$/);
             if (matchSource) {
-                asyncPrefix = matchSource[1] || '';
-                args = matchSource[2];
-                body = matchSource[3];
-                var bodyIndent = matchSource[4] || '';
+                preamble = matchSource[1];
+                body = matchSource[2];
+                var matchBodyAndIndent = body.match(/^(\s*\{)([\s\S]*?)([ ]*)\}\s*$/);
+                var openingBrace;
+                var closingBrace = '}';
+                if (matchBodyAndIndent) {
+                    openingBrace = matchBodyAndIndent[1];
+                    body = matchBodyAndIndent[2];
+                    bodyIndent = matchBodyAndIndent[3] || '';
+                    if (bodyIndent.length === 1) {
+                        closingBrace = ' }';
+                    }
+                }
+
                 // Remove leading indentation unless the function is a one-liner or it uses multiline string literals
                 if (/\n/.test(body) && !/\\\n/.test(body)) {
                     body = body.replace(new RegExp('^ {' + bodyIndent.length + '}', 'mg'), '');
@@ -784,18 +794,26 @@ module.exports = function (expect) {
                 }
                 if (/^\s*\[native code\]\s*$/.test(body)) {
                     body = ' /* native code */ ';
+                    closingBrace = '}';
                 } else if (/^\s*$/.test(body)) {
                     body = '';
                 } else if (/^\s*[^\r\n]{1,30}\s*$/.test(body) && body.indexOf('//') === -1) {
                     body = ' ' + body.trim() + ' ';
+                    closingBrace = '}';
                 } else {
                     body = body.replace(/^((?:.*\n){3}( *).*\n)[\s\S]*?\n[\s\S]*?\n((?:.*\n){3})$/, '$1$2// ... lines removed ...\n$3');
                 }
+                if (matchBodyAndIndent) {
+                    body = openingBrace + body + closingBrace;
+                } else {
+                    // Strip trailing space from arrow function body
+                    body = body.replace(/[ ]*$/, '');
+                }
             } else {
-                args = ' /*...*/ ';
-                body = ' /*...*/ ';
+                preamble = 'function ' + name + '( /*...*/ ) ';
+                body = '{ /*...*/ }';
             }
-            return output.code(asyncPrefix + 'function ' + name + '(' + args + ') {' + body + '}', 'javascript');
+            return output.code(preamble + body, 'javascript');
         }
     });
 


Test patch:
diff --git a/test/api/inspect.spec.js b/test/api/inspect.spec.js
index ec6e1407..a2745f09 100644
--- a/test/api/inspect.spec.js
+++ b/test/api/inspect.spec.js
@@ -358,7 +358,7 @@ describe('inspect', function () {
                '            var quux = \'baz\\\n' +
                '            blah\';\n' +
                '            foo = foo + quux;\n' +
-               '        }');
+               '}');
         /*eslint-enable no-multi-str*/
     });
 
diff --git a/test/types/function-type.spec.js b/test/types/function-type.spec.js
index 522fb566..18ee5b99 100644
--- a/test/types/function-type.spec.js
+++ b/test/types/function-type.spec.js
@@ -115,6 +115,30 @@ describe('function type', function () {
         // jscs:enable
     });
 
+    // We can't complete this test if the runtime doesn't support arrow functions:
+    var singleParamArrowFunction;
+    try {
+        singleParamArrowFunction = new Function('return a => a + 1;')();
+    } catch (e) {}
+
+    if (singleParamArrowFunction) {
+        it('should render a single param arrow function', function () {
+            expect(singleParamArrowFunction, 'to inspect as', 'a => a + 1');
+        });
+    }
+
+    // We can't complete this test if the runtime doesn't support arrow functions:
+    var multiParamArrowFunction;
+    try {
+        multiParamArrowFunction = new Function('return (a, b) => a + b;')();
+    } catch (e) {}
+
+    if (multiParamArrowFunction) {
+        it('should render a multi param arrow function', function () {
+            expect(multiParamArrowFunction, 'to inspect as', '(a, b) => a + b');
+        });
+    }
+
     // We can't complete this test if the runtime doesn't support the async keyword:
     var asyncFunction;
     try {