Conversation
|
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/8074/ |
| import syntaxDecorators from "../lib"; | ||
|
|
||
| describe("legacy option", function() { | ||
| const oldSyntax = "@dec export class Foo {}"; |
There was a problem hiding this comment.
https://github.com/atlassian/jest-in-case could make those assertions nicely grouped
|
The I only implemented decorators for public methods. Since decorators transpilation is highly copuled to class fields and private properties, I think that we should have a single plugin for the three features: {
"plugins": [
["@babel/plugin-proposal-enhanced-classes", {
"decorators": true,
"fields": false,
"privateMethods": true,
}]
]
}We should then deprecate |
|
Yeah it might depend on https://github.com/zenparsing/js-classes-1.1 too. I was thinking we should make things like |
86e80fd to
430f9c0
Compare
|
After creating `@babel/plugin-proposal-enhanced-classes` with external-helpersconst Foo = babelHelpers.enhanceClass(function(
_defineClass,
_initializeClass,
_initializeInstance
) {
_defineClass(
class Foo {
constructor() {
_initializeInstance(this);
}
},
[
{
kind: "field",
key: "num",
value() {
return 2;
},
},
]
);
_initializeClass();
});`@babel/plugin-proposal-enhanced-classes` without external-helpersfunction _enhanceClass(factory) { var internalSlots = { F: null, elements: null, finishers: null }; factory(internalSlots, function defineClass(F, definitions) { var elements = definitions.map(_createElementDescriptor); elements = _coalesceClassElements(elements); internalSlots.F = F; internalSlots.elements = elements; }, function initializeClassElements() { _initializeClassElements(internalSlots); }, function initializeInsanceElements(O) { _initializeInstanceElements(O, internalSlots); }); return internalSlots.F; }
function _createElementDescriptor(def) { let descriptor; if (def.kind === "method") { descriptor = { value: def.value, writable: true, configurable: true }; } else if (def.kind === "get") { descriptor = { get: def.value, configurable: true }; } else if (def.kind === "set") { descriptor = { set: def.value, configurable: true }; } else if (def.kind === "field") { descriptor = { configurable: true, writable: true }; } var element = { kind: def.kind === "field" ? "field" : "method", key: def.key, placement: def.static ? "static" : def.kind === "field" ? "own" : "prototype", descriptor: descriptor }; if (def.decorators) element.decorators = def.decorators; if (def.kind === "field") element.initializer = def.value; return element; }
function _coalesceGetterSetter(element, other) { if (element.descriptor.get !== undefined) { other.descriptor.get = element.descriptor.get; } else { other.descriptor.set = element.descriptor.set; } }
function _coalesceClassElements(elements) { const newElements = []; for (var i = 0; i < elements.length; i++) { var element = elements[i]; var index = newElements.findIndex(function (other) { return other.kind === element.kind && other.key === element.key && other.placement === element.placement; }); if (element.kind === "method" && index !== -1) { var other = newElements[index]; if (element.decorators && element.decorators.length > 0) { if (other.decorators && other.decorators.length > 0) { throw new ReferenceError(); } other.decorators = element.decorators; } if (_isDataDescriptor(element.descriptor) || _isDataDescriptor(other.descriptor)) { other.descriptor = element.descriptor; } else { _coalesceGetterSetter(element, other); } } else { newElements.push(element); } } return newElements; }
function _isDataDescriptor(desc) { return desc !== undefined && !(desc.value === undefined && desc.writable === undefined); }
function _initializeClassElements(internalSlots) { var F = internalSlots.F; var proto = F.prototype; internalSlots.elements.forEach(function (element) { if (element.kind === "method") { var receiver = element.placement === "static" ? F : proto; _defineClassElement(receiver, element); } }); internalSlots.elements.forEach(function (element) { var placement = element.placement; if (element.kind === "field" && (placement === "static" || placement === "prototype")) { var receiver = placement === "static" ? F : proto; _defineClassElement(receiver, element); } }); }
function _initializeInstanceElements(O, internalSlots) { internalSlots.elements.forEach(function (element) { if (element.kind === "method" && element.placement === "own") { _defineClassElement(O, element); } }); internalSlots.elements.forEach(function (element) { if (element.kind === "field" && element.placement === "own") { _defineClassElement(O, element); } }); }
function _defineClassElement(receiver, element) { if (element.kind === "field") { var initializer = element.initializer; element.descriptor.value = initializer === void 0 ? void 0 : initializer.call(receiver); } Object.defineProperty(receiver, element.key, element.descriptor); }
const Foo = _enhanceClass(function(
_defineClass,
_initializeClass,
_initializeInstance
) {
_defineClass(
class Foo {
constructor() {
_initializeInstance(this);
}
},
[
{
kind: "field",
key: "num",
value() {
return 2;
},
},
]
);
_initializeClass();
});`@babel/plugin-transform-class-properties`class Foo {
constructor() {
Object.defineProperty(this, "num", {
configurable: true,
enumerable: true,
writable: true,
value: 2,
});
}
}I think that we should keep the two plugins separated, but let I haven't tested private properties yet, but I think that they will have the same problem. |
d08310a to
ceb2ddf
Compare
|
Weird CircleCI error: |
|
Thank you, I restarted it. |
|
Will @babel-bot update REPL? |
|
Yes, the link in the first comment is always updated |
|
I still need to add some tests (e.g. finishers), but this PR can be reviewed |
530f8cd to
3ec60b3
Compare
|
Next step: #7821 After that PR, I will update Babylon again to reflect the last changes (tc39/proposal-decorators#81 (comment) and tc39/proposal-decorators#69 (comment)). |
|
Things getting complicated as I see… I was interested only in simple class or function decorators especifically only as React HoC… So I have questions:
Thank you for your attention on this, I see and really appreciate — it's really hard work |
* Add decoratorsBeforeExport to the syntax plugin * Require legacy: true, like in the transform plugin
8f5a7f6 to
ba0a0c8
Compare
|
I have merged the decorators PRs here so that they can be tested together in the repl (https://babeljs.io/repl/build/8074). @langpavel Decorators will be hard to optimize, but I hope that js engines will figure out how to optimize them. |
|
I'm closing this, since now it is the same as #7976 |
EDIT by @hzoo: REPL link https://babeljs.io/repl/build/8074/ - need to turn on Stage 2
I'm working on #6107. Since that PR has become quite old (and there are different things that needs to be done) I'm not rebasing it, but I will just copy-paste the needed code.
Then I will set both me and @peey as the PR authors (I have no idea of how to do it, but I'm sure that it is possible 🤣).
TODO:
NOTE: The
legacy-transformer.jsfile contains the code that was peviously inindex.js, I didn't change it.Breaking change!
I added a new option to keep both the new and legacy decorators in the same plugin. By default, the new proposal is used but it can be disabled with the
legacy: trueoption (accepted by-syntax-and-proposal-). In thestage-0,1,2presets this option is calleddecoratorsLegacy.