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

Set function name for decorated private non-field elements #16144

Merged
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile.js

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion Makefile.source.mjs
Expand Up @@ -450,12 +450,14 @@ target["bootstrap-flow"] = function () {

target["new-version-checklist"] = function () {
// eslint-disable-next-line no-constant-condition
if (0) {
if (1) {
console.log(
`
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!! !!!!!!
- packages/babel-helpers/src/helpers/setFunctionName.ts
Bump minVersion
!!!!!! Write any important message here, and change the !!!!!!
!!!!!! if (0) above to if (1) !!!!!!
!!!!!! !!!!!!
Expand Down
12 changes: 8 additions & 4 deletions packages/babel-helpers/src/helpers-generated.ts

Large diffs are not rendered by default.

12 changes: 11 additions & 1 deletion packages/babel-helpers/src/helpers/applyDecs.js
@@ -1,5 +1,6 @@
/* @minVersion 7.17.8 */

import setFunctionName from "setFunctionName";
import toPropertyKey from "toPropertyKey";
/**
* NOTE: This is an old version of the helper, used for 2021-12 decorators.
Expand Down Expand Up @@ -316,27 +317,36 @@ function old_applyMemberDec(
) {
var decs = decInfo[0];

var desc, initializer, value;
var desc, initializer, prefix, value;

if (isPrivate) {
if (kind === 0 /* FIELD */ || kind === 1 /* ACCESSOR */) {
desc = {
get: decInfo[3],
set: decInfo[4],
};
prefix = "get";
} else if (kind === 3 /* GETTER */) {
desc = {
get: decInfo[3],
};
prefix = "get";
} else if (kind === 4 /* SETTER */) {
desc = {
set: decInfo[3],
};
prefix = "set";
} else {
desc = {
value: decInfo[3],
};
}
if (kind !== 0 /* FIELD */) {
if (kind === 1 /* ACCESSOR */) {
setFunctionName(decInfo[4], "#" + name, "set");
}
setFunctionName(decInfo[3], "#" + name, prefix);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The TS emits dedicated setFunctionName call here:

// input
class C {
  @dec static accessor #f = 1
}

// output
let C = (() => {
    var _a, _C_f_accessor_storage, _C_f_get, _C_f_set;
    let _staticExtraInitializers = [];
    let _static_private_f_decorators;
    let _static_private_f_initializers = [];
    let _static_private_f_descriptor;
    return _a = class C {
        },
        _C_f_get = function _C_f_get() { return _static_private_f_descriptor.get.call(this); },
        _C_f_set = function _C_f_set(value) { return _static_private_f_descriptor.set.call(this, value); },
        (() => {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
            _static_private_f_decorators = [dec];
            /* ⬇️⬇️⬇️ __setFunctionName call here ⬇️⬇️⬇️ */
            __esDecorate(_a, _static_private_f_descriptor = { get: __setFunctionName(function () { return __classPrivateFieldGet(_a, _a, "f", _C_f_accessor_storage); }, "#f", "get"), set: __setFunctionName(function (value) { __classPrivateFieldSet(_a, _a, value, "f", _C_f_accessor_storage); }, "#f", "set") }, _static_private_f_decorators, { kind: "accessor", name: "#f", static: true, private: true, access: { has: obj => __classPrivateFieldIn(_a, obj), get: obj => __classPrivateFieldGet(obj, _a, "a", _C_f_get), set: (obj, value) => { __classPrivateFieldSet(obj, _a, value, "a", _C_f_set); } }, metadata: _metadata }, _static_private_f_initializers, _staticExtraInitializers);
            if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
            __runInitializers(_a, _staticExtraInitializers);
        })(),
        _C_f_accessor_storage = { value: __runInitializers(_a, _static_private_f_initializers, 1) },
        _a;
})();

Here we merge the setFunctionName call with the applyMemberDecs to optimize the output size.

} else if (kind !== 0 /* FIELD */) {
desc = Object.getOwnPropertyDescriptor(base, name);
}
Expand Down
12 changes: 11 additions & 1 deletion packages/babel-helpers/src/helpers/applyDecs2203R.js
@@ -1,5 +1,6 @@
/* @minVersion 7.20.0 */

import setFunctionName from "setFunctionName";
import toPropertyKey from "toPropertyKey";

/**
Expand Down Expand Up @@ -174,27 +175,36 @@ function applyDecs2203RFactory() {
) {
var decs = decInfo[0];

var desc, init, value;
var desc, init, prefix, value;

if (isPrivate) {
if (kind === 0 /* FIELD */ || kind === 1 /* ACCESSOR */) {
desc = {
get: decInfo[3],
set: decInfo[4],
};
prefix = "get";
} else if (kind === 3 /* GETTER */) {
desc = {
get: decInfo[3],
};
prefix = "get";
} else if (kind === 4 /* SETTER */) {
desc = {
set: decInfo[3],
};
prefix = "set";
} else {
desc = {
value: decInfo[3],
};
}
if (kind !== 0 /* FIELD */) {
if (kind === 1 /* ACCESSOR */) {
setFunctionName(decInfo[4], "#" + name, "set");
}
setFunctionName(decInfo[3], "#" + name, prefix);
}
} else if (kind !== 0 /* FIELD */) {
desc = Object.getOwnPropertyDescriptor(base, name);
}
Expand Down
12 changes: 11 additions & 1 deletion packages/babel-helpers/src/helpers/applyDecs2301.js
@@ -1,6 +1,7 @@
/* @minVersion 7.21.0 */

import checkInRHS from "checkInRHS";
import setFunctionName from "setFunctionName";
import toPropertyKey from "toPropertyKey";

/**
Expand Down Expand Up @@ -218,29 +219,38 @@ function applyDecs2301Factory() {
) {
var decs = decInfo[0];

var desc, init, value;
var desc, init, prefix, value;

if (isPrivate) {
if (kind === 0 /* FIELD */ || kind === 1 /* ACCESSOR */) {
desc = {
get: curryThis1(decInfo[3]),
set: curryThis2(decInfo[4]),
};
prefix = "get";
} else {
if (kind === 3 /* GETTER */) {
desc = {
get: decInfo[3],
};
prefix = "get";
} else if (kind === 4 /* SETTER */) {
desc = {
set: decInfo[3],
};
prefix = "set";
} else {
desc = {
value: decInfo[3],
};
}
}
if (kind !== 0 /* FIELD */) {
if (kind === 1 /* ACCESSOR */) {
setFunctionName(desc.set, "#" + name, "set");
}
setFunctionName(desc[prefix || "value"], "#" + name, prefix);
}
} else if (kind !== 0 /* FIELD */) {
desc = Object.getOwnPropertyDescriptor(base, name);
}
Expand Down
16 changes: 15 additions & 1 deletion packages/babel-helpers/src/helpers/applyDecs2305.ts
Expand Up @@ -3,6 +3,8 @@
// @ts-expect-error helper
import checkInRHS from "checkInRHS";
// @ts-expect-error helper
import setFunctionName from "setFunctionName";
// @ts-expect-error helper
import toPropertyKey from "toPropertyKey";

/**
Expand Down Expand Up @@ -205,7 +207,10 @@ function applyMemberDec(
decs = [decs];
}

var desc: PropertyDescriptor, init, value: any;
var desc: PropertyDescriptor,
init,
prefix: "get" | "set" | undefined,
value: any;

if (isPrivate) {
if (kind === PROP_KIND.FIELD || kind === PROP_KIND.ACCESSOR) {
Expand All @@ -217,21 +222,30 @@ function applyMemberDec(
decInfo[4](this, value);
},
};
prefix = "get";
} else {
if (kind === PROP_KIND.GETTER) {
desc = {
get: decVal,
};
prefix = "get";
} else if (kind === PROP_KIND.SETTER) {
desc = {
set: decVal,
};
prefix = "set";
} else {
desc = {
value: decVal,
};
}
}
if (kind !== PROP_KIND.FIELD) {
if (kind === PROP_KIND.ACCESSOR) {
setFunctionName(desc.set, "#" + name, "set");
}
setFunctionName(desc[prefix || "value"], "#" + name, prefix);
}
} else if (kind !== PROP_KIND.FIELD) {
desc = Object.getOwnPropertyDescriptor(base, name);
}
Expand Down
22 changes: 22 additions & 0 deletions packages/babel-helpers/src/helpers/setFunctionName.ts
@@ -0,0 +1,22 @@
/* @minVersion 7.23.5 */

// https://tc39.es/ecma262/#sec-setfunctionname
export default function setFunctionName(
Copy link
Member

Choose a reason for hiding this comment

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

Given that the various decorators helpers are exclusive (and everything except for legacy and 2023-05) will be dropped in Babel 8, could we just inline the helper instead?

Or maybe we could even just fix this in 2023-05.

Copy link
Contributor Author

@JLHwung JLHwung Nov 30, 2023

Choose a reason for hiding this comment

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

The helper is isolated because we will eventually emit setFunctionName when transforming the decorated anonymous class expression (Part 1 of #16117). For example

// input.js
function dec(target, context) {
  // print '[Symbol.iterator]'
  console.log(target.name);
}
class Dummy {
  [Symbol.iterator] = @dec class {}
}

to

// output.js
function dec(_, context) {
  // print '[Symbol.iterator]'
  console.log(context.name);
}
var computedKey = Symbol.iterator;
class Dummy {
  [computedKey] = (setFunctionName(class {
    static {
      [_decorated_class, _initClass] = _applyDecs(this, [], [dec]).c;
    }
    static {
      _initClass();
    }
  }, computedKey), _decorated_class);
}

In this example we will also pass a symbol, which is also a valid property key, to the setFunctionName helper.

Currently we have not implemented such transform yet. It was addressed in #15122 but I will open new PR to do so.

fn: Function,
name: symbol | string,
Copy link
Member

Choose a reason for hiding this comment

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

In which case we are passing a symbol name to this helper?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

prefix?: string,
) {
if (typeof name === "symbol") {
name = name.description;
name = name ? "[" + name + "]" : "";
}
// In some older browsers .name was non-configurable, here we catch any
// errors thrown by defineProperty.
try {
Object.defineProperty(fn, "name", {
configurable: true,
value: prefix ? prefix + " " + name : name,
});
} catch (_) {}
return fn;
}
Expand Up @@ -3,6 +3,8 @@ function dec({ get, set }, context) {
this[context.name + 'Context'] = context;
});

expect(get.name).toEqual("get " + context.name);
expect(set.name).toEqual("set " + context.name);
return {
get() {
return get.call(this) + 1;
Expand Down
Expand Up @@ -3,6 +3,8 @@ function dec({ get, set }, context) {
this[context.name + 'Context'] = context;
});

expect(get.name).toEqual("get " + context.name);
expect(set.name).toEqual("set " + context.name);
return {
get() {
return get.call(this) + 1;
Expand Down
Expand Up @@ -3,6 +3,8 @@ function dec({ get, set }, context) {
this[context.name + 'Context'] = context;
});

expect(get.name).toEqual("get " + context.name);
expect(set.name).toEqual("set " + context.name);
return {
get() {
return get.call(this) + 1;
Expand Down
Expand Up @@ -3,6 +3,8 @@ function dec({ get, set }, context) {
this[context.name + 'Context'] = context;
});

expect(get.name).toEqual("get " + context.name);
expect(set.name).toEqual("set " + context.name);
return {
get() {
return get.call(this) + 1;
Expand Down
Expand Up @@ -3,6 +3,7 @@ function dec(get, context) {
this[context.name + 'Context'] = context;
});

expect(get.name).toEqual("get " + context.name);
return function () {
return get.call(this) + 1;
}
Expand Down
Expand Up @@ -3,6 +3,7 @@ function dec(get, context) {
this[context.name + 'Context'] = context;
});

expect(get.name).toEqual("get " + context.name);
return function () {
return get.call(this) + 1;
}
Expand Down
Expand Up @@ -3,6 +3,7 @@ function dec(get, context) {
this[context.name + 'Context'] = context;
});

expect(get.name).toEqual("get " + context.name);
return function () {
return get.call(this) + 1;
}
Expand Down
Expand Up @@ -3,6 +3,7 @@ function dec(get, context) {
this[context.name + 'Context'] = context;
});

expect(get.name).toEqual("get " + context.name);
return function () {
return get.call(this) + 1;
}
Expand Down
Expand Up @@ -3,6 +3,7 @@ function dec(fn, context) {
this[context.name + 'Context'] = context;
});

expect(fn.name).toEqual(context.name);
return function () {
return fn.call(this) + 1;
}
Expand Down
@@ -1,4 +1,5 @@
function dec(fn, context) {
expect(fn.name).toEqual(context.name);
return function () {
return fn.call(this) + 1;
}
Expand Down
Expand Up @@ -3,6 +3,7 @@ function dec(fn, context) {
this[context.name + 'Context'] = context;
});

expect(fn.name).toEqual(context.name);
return function () {
return fn.call(this) + 1;
}
Expand Down
@@ -1,4 +1,5 @@
function dec(fn, context) {
expect(fn.name).toEqual(context.name);
return function () {
return fn.call(this) + 1;
}
Expand Down
Expand Up @@ -3,6 +3,7 @@ function dec(fn, context) {
this[context.name + 'Context'] = context;
});

expect(fn.name).toEqual(context.name);
return function () {
return fn.call(this) + 1;
}
Expand Down
@@ -1,4 +1,5 @@
function dec(fn, context) {
expect(fn.name).toEqual(context.name);
return function () {
return fn.call(this) + 1;
}
Expand Down
Expand Up @@ -3,6 +3,7 @@ function dec(fn, context) {
this[context.name + 'Context'] = context;
});

expect(fn.name).toEqual(context.name);
return function () {
return fn.call(this) + 1;
}
Expand Down
@@ -1,4 +1,5 @@
function dec(fn, context) {
expect(fn.name).toEqual(context.name);
return function () {
return fn.call(this) + 1;
}
Expand Down
Expand Up @@ -3,6 +3,7 @@ function dec(set, context) {
this[context.name + 'Context'] = context;
});

expect(set.name).toEqual("set " + context.name);
return function (v) {
return set.call(this, v + 1);
}
Expand Down
Expand Up @@ -3,6 +3,7 @@ function dec(set, context) {
this[context.name + 'Context'] = context;
});

expect(set.name).toEqual("set " + context.name);
return function (v) {
return set.call(this, v + 1);
}
Expand Down
Expand Up @@ -3,6 +3,7 @@ function dec(set, context) {
this[context.name + 'Context'] = context;
});

expect(set.name).toEqual("set " + context.name);
return function (v) {
return set.call(this, v + 1);
}
Expand Down
Expand Up @@ -3,6 +3,7 @@ function dec(set, context) {
this[context.name + 'Context'] = context;
});

expect(set.name).toEqual("set " + context.name);
return function (v) {
return set.call(this, v + 1);
}
Expand Down
Expand Up @@ -3,6 +3,8 @@ function dec({ get, set }, context) {
this[context.name + 'Context'] = context;
});

expect(get.name).toEqual("get " + context.name);
expect(set.name).toEqual("set " + context.name);
return {
get() {
return get.call(this) + 1;
Expand Down