Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide new.target to functions containing eval() #448

Open
overlookmotel opened this issue Nov 6, 2022 · 2 comments
Open

Provide new.target to functions containing eval() #448

overlookmotel opened this issue Nov 6, 2022 · 2 comments
Labels
bug Something isn't working eval Issue related to `eval`

Comments

@overlookmotel
Copy link
Owner

overlookmotel commented Nov 6, 2022

Input:

function F() {
  this.x = 1;
  return (F, Dummy) => eval('new.target');
}
function Dummy() {}
export default Reflect.construct(F, [], Dummy);

Output:

const Object$0 = Object;
export default (0, eval)(`
  "use strict";
  (_this, _arguments) => function() {
    return (F, Dummy) => eval('new.target');
  }.apply(_this, _arguments);
`)(
  Object$0.assign(
    Object$0.create(function Dummy() {}.prototype),
    { x: 1 }
  ),
  function () { return arguments; }()
);

this and arguments are made available in eval(), but new.target is not.

This is possible to implement by using Reflect.construct:

const scope = (0, eval)(`
  "use strict";
  (_arguments, _newTarget) => Reflect.construct(
    function () {
      return [
        this,
        (F, Dummy) => eval('new.target')
      ];
    },
    _arguments,
    _newTarget
  );
`)(
  function () { return arguments; }(),
  function Dummy() {}
);
scope[0].x = 1;
export default scope[1];

However, there is one major complication. this is now created inside the constructor function and needs to be returned to the "outside world" in order to have its x property added. This would be only circumstance in which objects are created in scope functions, so would need special treatment.

@overlookmotel overlookmotel added bug Something isn't working eval Issue related to `eval` labels Nov 6, 2022
@overlookmotel
Copy link
Owner Author

overlookmotel commented Jan 2, 2023

Same complication with arguments.

function () { return arguments; }() in example output could be replaced with [] as arguments is implicitly created inside the constructor function.

If that arguments object is used elsewhere, or has extra properties added, it'd also need to be passed back to the "outside world". e.g.:

Input:

function F() {
  this.x = 1;
  arguments.y = 2;
  return (F, Dummy) => eval('[new.target, arguments]');
}
function Dummy() {}
export default Reflect.construct(F, [], Dummy);

Output:

const scope = (0, eval)(`
  "use strict";
  (_arguments, _newTarget) => Reflect.construct(
    function() {
      return [
        this,
        arguments,
        (F, Dummy) => eval('[new.target, arguments]')
      ];
    },
    _arguments,
    _newTarget
  );
`)( [], function Dummy() {} );
scope[0].x = 1;
scope[1].y = 2;
export default scope[2];

Adding properties to arguments is a very uncommon case, but would still be good to cover.

@overlookmotel
Copy link
Owner Author

overlookmotel commented Jan 2, 2023

The intermediate vars _arguments and _newTarget can also be removed, so they're not visible inside eval() code with:

const scope = (0, eval)(`
  "use strict";
  (function() {
    return Reflect.construct(
      function() {
        return [
          this,
          arguments,
          (F, Dummy) => eval('[new.target, arguments]')
        ];
      },
      arguments[0],
      arguments[1]
    );
  })
`)( [], function Dummy() {} );
scope[0].x = 1;
scope[1].y = 2;
export default scope[2];

(same idea as #473)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working eval Issue related to `eval`
Projects
None yet
Development

No branches or pull requests

1 participant