Closed
Description
First, thank you for this awesome project.
I am trying to set a property with a getter on the global object so that I can lazily retrieve the values from the host. However, I keep hitting the following error regardless of how I try (also see tests below).
You can see the first and last test works, but is not really what I want, since I want to lazily fetch the values from the host using createAsyncFunction.
TypeError: Primitive data type has no properties
at Interpreter../original-repo/interpreter.js.Interpreter.hasProperty (/redacted/node_modules/js-interpreter/lib/js-interpreter.js:4347:11)
at Interpreter../original-repo/interpreter.js.Interpreter.stepIdentifier (/redacted/node_modules/js-interpreter/lib/js-interpreter.js:5633:18)
at Interpreter../original-repo/interpreter.js.Interpreter.step (/redacted/node_modules/js-interpreter/lib/js-interpreter.js:2362:48)
at Interpreter../original-repo/interpreter.js.Interpreter.run (/redacted/node_modules/js-interpreter/lib/js-interpreter.js:2392:32)
at Object.<anonymous> (/redacted/js-executor/__tests__/JsExecutorTests.spec.ts:87:17)
at /redacted/node_modules/jest-jasmine2/build/queueRunner.js:45:12
at new Promise (<anonymous>)
at mapper (/redacted/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
at /redacted/node_modules/jest-jasmine2/build/queueRunner.js:75:41
import JSInterpreter from "js-interpreter";
describe("JsExecutorTests", () => {
// Works
it("should attach a string-valued property to globalObject", (done) => {
const nameValue = "world";
const initFunction = function (interpreter, globalObject) {
interpreter.setProperty(globalObject, "name", nameValue);
};
const code = `"Hello " + name;`;
const interpreter = new JSInterpreter(code, initFunction);
interpreter.run();
setTimeout(() => {
expect(interpreter.value).toEqual("Hello " + nameValue);
done();
}, 1000);
});
// Doesn't work: `Primitive data type has no properties` in Interpreter.prototype.hasProperty
it("should attach a property with getter to globalObject", (done) => {
const nameValue = "world";
const initFunction = function (interpreter, globalObject) {
const wrapper = function getName() {
return nameValue;
};
interpreter.setProperty(globalObject, "name", JSInterpreter.VALUE_IN_DESCRIPTOR, {
get: interpreter.createNativeFunction(wrapper),
});
};
const code = `"Hello " + name;`;
const interpreter = new JSInterpreter(code, initFunction);
interpreter.run();
setTimeout(() => {
expect(interpreter.value).toEqual("Hello " + nameValue);
done();
}, 1000);
});
// Doesn't work: `Primitive data type has no properties` in Interpreter.prototype.hasProperty
it("should attach property with an async-getter to globalObject", (done) => {
const nameValue = "world";
const initFunction = function (interpreter, globalObject) {
const wrapper = function getName(callback) {
setTimeout(() => {
callback(nameValue);
interpreter.run();
}, 0);
};
interpreter.setProperty(globalObject, "name", JSInterpreter.VALUE_IN_DESCRIPTOR, {
get: interpreter.createAsyncFunction(wrapper),
});
};
const code = `"Hello " + name;`;
const interpreter = new JSInterpreter(code, initFunction);
interpreter.run();
setTimeout(() => {
expect(interpreter.value).toEqual("Hello " + nameValue);
done();
}, 1000);
});
// Doesn't work: `Primitive data type has no properties` in Interpreter.prototype.hasProperty
it("HACKED: should attach property with an async-getter to globalObject in user-defined code", (done) => {
const nameValue = "world";
const initFunction = function (interpreter, globalObject) {
const wrapper = function getName(callback) {
setTimeout(() => {
callback(nameValue);
interpreter.run();
}, 0);
};
interpreter.setProperty(globalObject, "getName", interpreter.createAsyncFunction(wrapper));
interpreter.properties;
};
let code = `"Hello " + name;`;
// before run user code, we inject it with initialization stuff.
code =
`
Object.defineProperty(this, "name", {
get: function() { return getName(); },
});
` + code;
const interpreter = new JSInterpreter(code, initFunction);
interpreter.run();
setTimeout(() => {
expect(interpreter.value).toEqual("Hello " + nameValue);
done();
}, 1000);
});
// works, but not really what is required here because the value retrieval is not lazy.
it("HACKED: should attach value-property to globalObject in user-defined code", (done) => {
const nameValue = "world";
const initFunction = function (interpreter, globalObject) {
const wrapper = function getName(callback) {
setTimeout(() => {
callback(nameValue);
interpreter.run();
}, 0);
};
interpreter.setProperty(globalObject, "getName", interpreter.createAsyncFunction(wrapper));
interpreter.properties;
};
let code = `
"Hello " + name;
`;
// before run user code, we inject it with initialization stuff.
code =
`
window.name = getName();
` + code;
const interpreter = new JSInterpreter(code, initFunction);
interpreter.run();
setTimeout(() => {
expect(interpreter.value).toEqual("Hello " + nameValue);
done();
}, 1000);
});
});