github.com/latentflip/deval
Sometimes you're doing interesting things, and you want a block of code as a multiline string.
But doing this is super annoying:
var codeString = [
"var foo = 'bar'",
"function stuff () {",
" console.log('The thing is \"10\"');"
"}"
].join('\n');
Quotes everywhere, keeping track of indentation is a pain if you want it properly formatted, no syntax highlighting.
Function code to string makes it look like this:
var codeToString = require('codeToString');
var codeString = codeToString(function () {
var foo = 'bar';
function stuff () {
console.log('The thing is "10"');
}
});
// codeString -> "var foo = 'bar';\nfunction stuff () {\n console.log('The thing is \"10\"');\n}"
It even figures out what indentation you meant and cleans that up.
If eval() takes a string representing code, and turns it into actual code, codeToString() takes actual code, and returns a string representation of it.
Basic usage.
Call codeToString() with a function containing the code you want to get back as a string.
The function wrapper will be removed.
var codeToString = require('codeToString');
var codeString = codeToString(function(){
var foo = 'bar';
function stuff () {
console.log('The thing is "10"');
}
});
// codeString will be:
// "var foo = 'bar';
// function stuff () {
// console.log('The thing is \"10\"');
// }"
Advanced usage.
Sometimes you want to interpolate strings / numbers / etc into your generated code.
You can't just use normal scoping rules, because this code won't be executed in the current scope.
So instead you can do a little templating magic.
To interpolate:
- Name some positional arguments in the function you pass to codeToString: codeToString(function (arg1, arg2) { ...
- Insert them where you want them in your code by wrapping in dollars: $arg1$
- Pass the values of those arguments as additional arguments to codeToString itself. codeToString(function (arg1, arg2) { ... }, "one", 2)
var codeString = codeToString(function (foo, bar) {
var thing = $bar$;
console.log('$foo$');
console.log(thing);
}, "hi", 5);
// codeString will be:
// "var thing = 5;
// console.log('hi');
// console.log(thing)"
Don't try to be too clever with this, and if you're passing strings, you'll want to wrap them in quotes inside the code block, as shown about for "hi" -> '$foo$'
Source Code of codeToString():
var min = function (arr) {return Math.min.apply(Math, arr);};
var REGEXES = {
functionOpening: /^function\s*\((.*)\)[^{]{/
};
module.exports = function (fn/*, interpolateArgs... */) {
var str = fn.toString();
var interpolateArgs = Array.prototype.slice.call(arguments, 1);
var argNames;
if (interpolateArgs.length) {argNames = getArgumentNames(str);}
str = removeFunctionWrapper(str);
str = dedent(str);
if (argNames && argNames.length) {str = interpolate(str, argNames, interpolateArgs);}
return str;
};
function getArgumentNames (str) {
var argStr = str.match(REGEXES.functionOpening);
return argStr[1].split(',').map(function (s) { return s.trim(); });
}
function removeFunctionWrapper (str) {
var closingBraceIdx, finalNewlineIdx, lastLine;
// remove opening function bit
str = str.replace(REGEXES.functionOpening, '');
// remove closing function brace
closingBraceIdx = str.lastIndexOf('}');
if (closingBraceIdx > 0) {str = str.slice(0, closingBraceIdx - 1);}
// If there was no code on opening wrapper line, remove it
str = str.replace(/^[^\S\n]*\n/, '');
// If there was no code on final line, remove it
finalNewlineIdx = str.lastIndexOf('\n');
lastLine = str.slice(finalNewlineIdx);
if (lastLine.trim() === '') str = str.slice(0, finalNewlineIdx);
return str;
}
// Reset indent on the code to minimum possible
function dedent (str) {
var lines = str.split('\n');
var indent = min(lines.map(function (line) {return line.match(/^\s*/)[0].length;}));
lines = lines.map(function (line) {return line.slice(indent);});
return lines.join('\n');
}
function interpolate (str, argNames, args) {
argNames.forEach(function (name, i) {
var regex = new RegExp('\\$' + name + '\\$', 'g');
str = str.replace(regex, args[i]);
});
return str;
}
Tests:
var test = require('tape');
var codeToString = require('./codeToString');
test('it serializes multiline code', function (t) {
var serialized = codeToString(function () {
console.log('hi');
console.log('there');
});
var expected = [
"console.log('hi');",
"console.log('there');"
].join('\n');
t.equal(serialized, expected);
t.end();
});
test('it serializes inline code', function (t) {
var serialized = codeToString(function () { console.log('hi'); console.log('there'); });
var expected = [
"console.log('hi'); console.log('there');"
].join('\n');
t.equal(serialized, expected);
t.end();
});
test('it even interpolates things', function (t) {
var serialized = codeToString(function (foo, bar) {
console.log('$foo$');
console.log($bar$);
}, "hi", 5);
var expected = [
"console.log('hi');",
"console.log(5);"
].join('\n');
t.equal(serialized, expected);
t.end();
});
Комментариев нет:
Отправить комментарий