I have JavaScript REPL I've asked before How to create JavaScript REPL that will work with let and const?. I was able to solve my issue with VM Node module that is builtin into browserify and node-falafel (JS AST transformer).
The REPL works fine, but I have problem when evaluating:
document.querySelectorAll('div');
The VM return empty NodeList. But if I call jQuery $('div') I get all divs from the page.
Relevant part of the code:
// before script tags:
var window_names = Object.getOwnPropertyNames(window);
function globals() {
return Object.fromEntries(window_names.map(name => {
const value = window[name];
return [name, value];
}));
}
const context = {
__$$__: {},
...globals(), // the same is with window here
$,
console: {
log(...args) {
console.log(...args);
term.echo(args.map(repr).join(' '));
}
}
};
function unset(context, name) {
delete context[name];
}
// main interpreter funtion
function exec(code, ctx = context) {
ctx = {...ctx};
code = patch(code, ctx)
return vm.runInNewContext(code, ctx);
}
function is_scoped(name, context) {
return name in context.__$$__;
}
function patch(code, context) {
let patching = [];
let result = falafel(code, function(node) {
if (node.type == 'VariableDeclaration') {
node.declarations.forEach(declaration => {
const name = declaration.id.name;
if (is_scoped(name, context)) {
unset(context, name);
}
patching.push(`__$$__.${name} = ${name}`);
});
} else if (node.type === 'Identifier' &&
is_scoped(node.name, context) &&
node.parent.type !== 'VariableDeclarator') {
const name = node.name;
node.update(`__$$__.${name}`);
}
});
result = result.toString();
if (patching.length) {
result += ';' + patching.join(';');
}
return result;
}
Anyone know why document.querySelector doesn't work in vm.runInNewContext?
Just to be sure I was testing using document out of context:
var x = document
x.querySelectorAll('div');
but of course document is not a function so it doesn't have its own context as window object. Then why it doesn't work?