Skip to content

Commit

Permalink
helpers-lib: augment the `function printFunctionSourceCodeContainer(f…
Browse files Browse the repository at this point in the history
…)` API to support ES6 arrow functions and extract the code content of any such function for inlining. This code will be used in jison and jison-lex to support arrow functions passed via the programmer API (a la zaach/jison-lex#23 )

Also extended the unit tests to cover various function type input scenarios.
  • Loading branch information
GerHobbelt committed Dec 25, 2017
1 parent 1c8c89d commit 736d3db
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 5 deletions.
66 changes: 61 additions & 5 deletions packages/helpers-lib/code-stringification.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,75 @@ function chkBugger(src) {
/// HELPER FUNCTION: print the function in source code form, properly indented.
/** @public */
function printFunctionSourceCode(f) {
chkBugger(f);
return String(f);
var src = String(f);
chkBugger(src);
return src;
}

/// HELPER FUNCTION: print the function **content** in source code form, properly indented.


const funcRe = /^function[\s\r\n]*[^\(]*\(([^\)]*)\)[\s\r\n]*\{([^]*?)\}$/;
const arrowFuncRe = /^\(([^\)]*)\)[\s\r\n]*=>[\s\r\n]*(?:(?:\{([^]*?)\})|(?:(([^\s\r\n\{)])[^]*?)))$/;

/// HELPER FUNCTION: print the function **content** in source code form, properly indented,
/// ergo: produce the code for inlining the function.
///
/// Also supports ES6's Arrow Functions:
///
/// ```
/// function a(x) { return x; } ==> 'return x;'
/// function (x) { return x; } ==> 'return x;'
/// (x) => { return x; } ==> 'return x;'
/// (x) => x; ==> 'return x;'
/// (x) => do(1), do(2), x; ==> 'return (do(1), do(2), x);'
///
/** @public */
function printFunctionSourceCodeContainer(f) {
chkBugger(f);
return String(f).replace(/^[\s\r\n]*function\b[^\{]+\{/, '').replace(/\}[\s\r\n]*$/, '');
var action = printFunctionSourceCode(f).trim();
var args;

// Also cope with Arrow Functions (and inline those as well?).
// See also https://github.com/zaach/jison-lex/issues/23
var m = funcRe.exec(action);
if (m) {
args = m[1].trim();
action = m[2].trim();
} else {
m = arrowFuncRe.exec(action);
if (m) {
args = m[1].trim();
if (m[4]) {
// non-bracketed version: implicit `return` statement!
//
// Q: Must we make sure we have extra braces around the return value
// to prevent JavaScript from inserting implit EOS (End Of Statement)
// markers when parsing this, when there are newlines in the code?
// A: No, we don't have to as arrow functions rvalues suffer from this
// same problem, hence the arrow function's programmer must already
// have formatted the code correctly.
action = m[3].trim();
action = 'return ' + action + ';';
} else {
action = m[2].trim();
}
} else {
var e = new Error('Cannot extract code from function');
e.subject = action;
throw e;
}
}
return {
args: args,
code: action,
};
}







export default {
printFunctionSourceCode,
printFunctionSourceCodeContainer,
Expand Down
47 changes: 47 additions & 0 deletions packages/helpers-lib/tests/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,53 @@ describe("helpers API", function () {
'PRETTY RANGE');
});

/* istanbul ignore next: test functions' code is injected and then crashes the test due to extra code coverage statements having been injected */
it("printFunctionSourceCode", function () {
function d(i) { /* mock for linters */ }

assert.strictEqual(helpers.printFunctionSourceCode(function a(x) { return x; }), "function a(x) { return x; }");
assert.strictEqual(helpers.printFunctionSourceCode(function (x) { return x; }), "function (x) { return x; }");
assert.strictEqual(helpers.printFunctionSourceCode((x) => { return x; }), "(x) => { return x; }");
assert.strictEqual(helpers.printFunctionSourceCode((x) => x), "(x) => x");
assert.strictEqual(helpers.printFunctionSourceCode((x) => (d(1), d(2), x)), "(x) => (d(1), d(2), x)");

var f1 = function a(x) { return x; };
var f2 = function (x) { return x; };
var f3 = (x) => { return x; };
var f4 = (x) => x;
var f5 = (x) => (d(1), d(2), x);

assert.strictEqual(helpers.printFunctionSourceCode(f1), "function a(x) { return x; }");
assert.strictEqual(helpers.printFunctionSourceCode(f2), "function (x) { return x; }");
assert.strictEqual(helpers.printFunctionSourceCode(f3), "(x) => { return x; }");
assert.strictEqual(helpers.printFunctionSourceCode(f4), "(x) => x");
assert.strictEqual(helpers.printFunctionSourceCode(f5), "(x) => (d(1), d(2), x)");
});

/* istanbul ignore next: test functions' code is injected and then crashes the test due to extra code coverage statements having been injected */
it("printFunctionSourceCodeContainer", function () {
function d(i) { /* mock for linters */ }
var x; /* mock */

assert.deepEqual(helpers.printFunctionSourceCodeContainer(function a(x) { return x; }), { args: "x", code: "return x;" });
assert.deepEqual(helpers.printFunctionSourceCodeContainer(function (x) { return x; }), { args: "x", code: "return x;" });
assert.deepEqual(helpers.printFunctionSourceCodeContainer((x) => { return x; }), { args: "x", code: "return x;" });
assert.deepEqual(helpers.printFunctionSourceCodeContainer((x) => x), { args: "x", code: "return x;" });
assert.deepEqual(helpers.printFunctionSourceCodeContainer((x) => (d(1), d(2), x)), { args: "x", code: "return (d(1), d(2), x);" });

var f1 = function a(x) { return x; };
var f2 = function (x) { return x; };
var f3 = (x) => { return x; };
var f4 = (x) => x;
var f5 = (x) => (d(1), d(2), x);

assert.deepEqual(helpers.printFunctionSourceCodeContainer(f1), { args: "x", code: "return x;" });
assert.deepEqual(helpers.printFunctionSourceCodeContainer(f2), { args: "x", code: "return x;" });
assert.deepEqual(helpers.printFunctionSourceCodeContainer(f3), { args: "x", code: "return x;" });
assert.deepEqual(helpers.printFunctionSourceCodeContainer(f4), { args: "x", code: "return x;" });
assert.deepEqual(helpers.printFunctionSourceCodeContainer(f5), { args: "x", code: "return (d(1), d(2), x);" });
});

it("parseCodeChunkToAST + prettyPrintAST", function () {
var rmCommonWS = helpers.rmCommonWS;

Expand Down

0 comments on commit 736d3db

Please sign in to comment.