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

Greater spec compliance for class properties #4544

Merged
merged 13 commits into from Nov 15, 2016

Conversation

motiz88
Copy link
Contributor

@motiz88 motiz88 commented Sep 22, 2016

Q A
Bug fix? yes
Breaking change? possibly
New feature? no
Deprecations? no
Spec compliancy? yes
Tests added/pass? yes
Fixed tickets #4463
License MIT
  • Class property definitions are now transpiled to Object.defineProperty calls, following the latest proposed spec for instance fields and static fields.
  • Static fields are now defined even if they are not initialized. This curious difference between statics and instance fields is in the spec (see above links).
  • This now includes computed property support (Computed class properties #4500).

Oddities

In a couple of places (see commit comments), function name inference apparently kicks in on the intermediate code, e.g. turning Object.defineProperty(..., {value: function() {}}) into ... value: function value() {} ..... This may not be desired.

Future work

  • Collect consecutive definitions of the same kind into Object.defineProperties calls?

Object.defineProperty(_this, "scopedFunctionWithThis", {
enumerable: true,
writable: true,
value: function value() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

value: function value()
                ^^^^^

Kinda meaningless function name inference here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, yeah seems like we'd ideally want to implement name inference here better, though it doesn't appear to be officially in the class-properties spec text anyway: tc39/proposal-class-public-fields#48

@danez danez added the PR: Bug Fix 🐛 A type of pull request used for our changelog categories label Sep 22, 2016
console.log(_this);
});

return function value() {
Copy link
Contributor Author

@motiz88 motiz88 Sep 22, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return function value() {
                ^^^^^

Kinda meaningless function name inference here. Also, the surrounding IIFE's sole purpose is to rename the function returned from asyncToGenerator.

@codecov-io
Copy link

codecov-io commented Sep 22, 2016

Current coverage is 88.83% (diff: 100%)

No coverage report found for master at 2dc919d.

Powered by Codecov. Last update 2dc919d...71da4ad

@loganfsmyth
Copy link
Member

Commented on #4463 (comment) but duplicating over here:

I think the fact that the Node REPL disagrees with the spec doesn't necessarily make this an obvious non-breaking change. I totally agree we should land this change, but since at least according to the spec it has the potential to be a breaking change, I'd prefer if we perhaps initially landed it as an opt-in option for the class property transform or something.

As-is, this will also break transform-decorators-legacy unfortunately, so that will need to be fixed to detect both cases, I think.

@hzoo
Copy link
Member

hzoo commented Sep 22, 2016

We could do a loose mode for class properties as well? (although since it's breaking it would be the opposite atm)

@loganfsmyth
Copy link
Member

Yeah, perhaps we should go with spec: true to get this behavior?

@loganfsmyth
Copy link
Member

I think the fact that the Node REPL disagrees with the spec doesn't necessarily make this an obvious non-breaking change. I totally agree we should land this change, but since at least according to the spec it has the potential to be a breaking change, I'd prefer if we perhaps initially landed it as an opt-in option for the class property transform or something.

Nevermind, I just didn't read the spec right :P We should be good as far as Object.defineProperty goes.

I'm all for this, but I do think it will need to be opt-in unfortunately, until we bump our major version anyway.

@hzoo
Copy link
Member

hzoo commented Sep 22, 2016

@motiz88
Copy link
Contributor Author

motiz88 commented Sep 22, 2016

Alrighty. The two new behaviors in this PR (defineProperty all the properties, and statics are always defined) are now conditional upon spec: true.

@@ -1,5 +1,5 @@
/* eslint max-len: 0 */
// todo: define instead of assign

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we drop this extra newline?

loose: (ref, {key, value}) => t.expressionStatement(
t.assignmentExpression("=", t.memberExpression(ref, key), value) // TODO(motiz88): handle computed key
)
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'd be better off using babel-template for these, e.g.

import templates from 'babel-templates';

const buildPropertySpec = template(`
  Object.defineProperty(REF, KEY, {
    // configurable is false by default
    enumerable: true,
    writable: true,
    value: VALUE,
  });
`);

const buildProperty = template(`
  REF[KEY] = VALUE;
`);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And per my example, let's not call the old behavior "loose" since it's not technically "loose" mode and that might lead to confusion.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can also use template from the babel parameter - export default function ({ types: t, template }) { but it would be created inside the function

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That works too, though I think most of our plugins import it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've now implemented this change, but kept buildProperty as a "raw" AST expression due to logic surrounding computed properties I'm not sure how to efficiently pack into template form.

@@ -55,18 +79,16 @@ export default function ({ types: t }) {
for (let prop of props) {
let propNode = prop.node;
if (propNode.decorators && propNode.decorators.length > 0) continue;
if (!propNode.value) continue;

if (!state.opts.spec && !propNode.value) continue;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feels like this could use a comment to make it clear why this is done.

@motiz88
Copy link
Contributor Author

motiz88 commented Sep 26, 2016

I think this is it, as far as the requested changes go.

I'm not crazy about the names buildDefineProperty, buildPropertySpec, buildProperty, buildPropertyDefinition, though. It's late and my brain can't come up with a reasoned naming scheme for these right now, so I'll be taking ideas if anyone has them.

@motiz88
Copy link
Contributor Author

motiz88 commented Oct 16, 2016

Gave the helper functions new names, updated to latest master, everything works! 😀 Are we good to go? @loganfsmyth

@hzoo hzoo merged commit f8ddd80 into babel:master Nov 15, 2016
panagosg7 pushed a commit to panagosg7/babel that referenced this pull request Jan 17, 2017
* Desugar class properties to Object.defineProperty per spec
* Define uninitialized static class properties with value=undefined
* Make class-properties increased spec compliance opt-in (spec: true)
@hzoo hzoo mentioned this pull request Sep 12, 2017
10 tasks
@lock lock bot added the outdated A closed issue/PR that is archived due to age. Recommended to make a new issue label Oct 7, 2019
@lock lock bot locked as resolved and limited conversation to collaborators Oct 7, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
outdated A closed issue/PR that is archived due to age. Recommended to make a new issue PR: Bug Fix 🐛 A type of pull request used for our changelog categories
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants