Skip to content

Cannot define a property with a getter on the globalObject #192

Closed
@atifsyedali

Description

@atifsyedali

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);
  });
});

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions