GithubHelp home page GithubHelp logo

Comments (9)

benjamn avatar benjamn commented on April 27, 2024

Unfortunately it doesn't seem possible to change the .constructor property of a function or the .name property of a constructor, so we might be out of luck here. Where have you seen this test in the wild?

from regenerator.

TooTallNate avatar TooTallNate commented on April 27, 2024

Unfortunately it doesn't seem possible to change the .constructor property of a function or the .name property of a constructor, so we might be out of luck here.

While we can't update name on a function, we can luckily definitely set the constructor on a function object. To wit:

$ node
> function test () {}

// original constructor is Function
> test.constructor
[Function: Function]

// create a polyfill faux GeneratorFunction constructor
> function GeneratorFunction () {}

// set constructor to polyfill
> test.constructor = GeneratorFunction
[Function: GeneratorFunction]

// test.constructor.name is now the expected value, and will pass isGeneratorFunction()
> test.constructor.name
'GeneratorFunction'

Where have you seen this test in the wild?

The generator flow control library co: https://github.com/visionmedia/co/blob/c247a120e34c147b28119c732e550836e3477660/index.js#L201-L211

You can see above that the same technique is used to detect Generator instances, and that works great with regenerator at the moment. The fact that the isGeneratorFunction is failing is causing 4 of the co tests to fail, whereas they pass using the --harmony_generators flag in node.

from regenerator.

TooTallNate avatar TooTallNate commented on April 27, 2024

That said, my proposal (and I know the extra boilerplate here kinda sucks), is to wrap the function in an immediately invoked function, so that we can have a closure around the transpiled function, and then set the constructor property before returning.

So some ES6 code like this:

co(function *() {
})();

Would turn into this (extra whitespace added for readability):

co( (function() {
  var fg = function() {
    return wrapGenerator(function($ctx) {
      while (1) switch ($ctx.next) {
      case 0:
        return $ctx.stop();
      }
    }, this);
  };

  // here's the crucial part: we overwrite the original `constructor` property with
  // one defined in the runtime, perhaps exposed as `wrapGenerator.GeneratorFunction`…
  fg.constructor = wrapGenerator.GeneratorFunction;

  return fg;
})() )();

Thoughts?

edit: fixed syntax errors in example output

from regenerator.

benjamn avatar benjamn commented on April 27, 2024

I agree that the boilerplate is less than ideal, but I also think it would be worth it.

The part I'm struggling with right now is what to do about named function declarations. Right now, their behavior is pretty simple because a generator function declaration just becomes a normal function declaration with the same name. That seems more tricky when the function is created inside a closure, because you'd have to assign the function to a variable of the same name in the outer scope before any other statements, in case those earlier statements refer to the declared function by name.

I'm going to keep thinking about it. Maybe there's a way to implement isGeneratorFunction that's easier to cooperate with, and we could persuade @visionmedia to adopt that instead.

from regenerator.

TooTallNate avatar TooTallNate commented on April 27, 2024

I have come up with a hacky, regenerator-aware isGeneratorFunction(), but I can almost promise that TJ would never merge it upstream ;) Essentially it's toString()ing the argument and checking the function source for the "wrapGenerator" function.

function isGeneratorFunction(obj) {
  // the "function" typeof test is required to filter out false-positives from
  // the toString() hack below, when obj is an Array
  if ('function' != typeof obj) return false;

  // "offically" sanctioned check...
  if (obj.constructor && 'GeneratorFunction' == obj.constructor.name) return true;

  // hacky check for facebook/regenerator
  if ((String(obj).indexOf('wrapGenerator(') != -1) return true;

  return false;
}

This makes the co test cases pass 100% for me using node v0.10.21 which is using regenerator under the hood.

from regenerator.

benjamn avatar benjamn commented on April 27, 2024

What if the runtime added

Function.prototype.markGenerator = function() {
  this.constructor = GeneratorFunction;
  return this;
};

And then generator function expressions like function *gen() {} became the expression function gen() { ... }.markGenerator() and function declarations of the same form became

gen.markGenerator(); // At beginning of scope where gen is defined.
...
function gen() { ... }

That saves some boilerplate, at least (and we could use an even shorter name than markGenerator).

from regenerator.

TooTallNate avatar TooTallNate commented on April 27, 2024

If that's possible then I think it would be awesome!

I'd recommend prefixing the name of the function though, since augmenting the Function.prototype could upset some people. Perhaps _regenMark() or something less likely to ever collide.

I would love to see this happen!

from regenerator.

Raynos avatar Raynos commented on April 27, 2024

Please don't add stuff to Function.prototype for making generated code pretty. Just use wrapGenerator.markGenerator(gen)

// function declarations
wrapGenerator.markGenerator(gen); // At beginning of scope where gen is defined.
...
function gen() { ... }

// function expressions
wrapGenerator.markGenerator(function gen() { ... })

from regenerator.

TooTallNate avatar TooTallNate commented on April 27, 2024

@Raynos +1

from regenerator.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.