dslify
Rewrites a JavaScript function or module, such that any global property access is transformed to call a member of a new dsl argument. Use dslify to interpret domain-specific languages without messing around in global scope.
Install
npm install dslify
Rewriting Functions
var dslify = require('dslify');
var fn = function() { return shout(word); };
var shouter = dslify.transform(fn);
var dsl = {
shout: function(something) {
return something + "!!";
},
word: "unicorns"
};
shouter(dsl); // unicorns!!
Sometimes you might want to operate with strings instead of JavaScript functions. For example if you are generating templates or want to send JavaScript to the client.
var dslify = require('dslify');
var input = "function(input) { return shout(input, globalValue); };";
var output = dslify.transform(input, {asString: true});
output // function(input) { return shout(input, _dsl.globalValue); };
Rewriting Modules
By rewriting an entire module in terms of another 'dsl' interpreter module, you can make slightly larger DSLs:
// abstract.js
module.exports = {
log: function(message) {
print(message);
}
};
// printer.js
module.exports = {
print: function(message) {
console.log(message + '!')
}
};
// compile.js
var dslify = require('dslify');
var abstract = require('fs').readFileSync('./abstract.js', 'utf-8');
var concrete = dslify.transformModule(abstract, './printer');
fs.writeFileSync('./concrete.js', concrete);
// then...
var concrete = require('./concrete.js');
concrete.log('jibber jabber'); // -> jibber jabber!
How?
dslify parses JavaScript using esprima, rewriting it as new JavaScript using escodegen.
Hold on, isn't this just a long-winded JavaScript 'with'?
Yes. But 'with' is leaky and dangerous, wheras dslify is like a sandbox because it rewrites access to global scope, e.g:
var dslify = require('dslify');
var dsl = {};
var withWith = function(dsl) {
with (dsl) {
y = 'leaks into global!';
}
};
var withDslify = dslify.transform(function() {
z = 'global is safe!';
});
withWith(dsl);
withDslify(dsl);
console.log(global.y); // leaks into global!
console.log(global.z); // undefined
console.log(dsl.z); // global is safe!
Isn't it hard to debug dynamically-generated functions?
Yes. And dynamically generating functions is relatively slow, compared to calling functions. Therefore consider transforming functions at build time instead of run time.
License
BSD