Skip to content

Commit

Permalink
Preserve class elements comments in class transform (#15406)
Browse files Browse the repository at this point in the history
* inherit comments in properties transform

* inherit comments in static block transform

* add classes transform test cases

* update test fixtures

* address review comments
  • Loading branch information
JLHwung committed Feb 11, 2023
1 parent 1b79436 commit 8d1486d
Show file tree
Hide file tree
Showing 51 changed files with 702 additions and 107 deletions.
282 changes: 176 additions & 106 deletions packages/babel-helper-create-class-features-plugin/src/fields.ts
Expand Up @@ -557,14 +557,17 @@ function buildPrivateFieldInitLoose(
const { id } = privateNamesMap.get(prop.node.key.id.name);
const value = prop.node.value || prop.scope.buildUndefinedNode();

return template.statement.ast`
Object.defineProperty(${ref}, ${t.cloneNode(id)}, {
// configurable is false by default
// enumerable is false by default
writable: true,
value: ${value}
});
`;
return inheritPropComments(
template.statement.ast`
Object.defineProperty(${ref}, ${t.cloneNode(id)}, {
// configurable is false by default
// enumerable is false by default
writable: true,
value: ${value}
});
`,
prop,
);
}

function buildPrivateInstanceFieldInitSpec(
Expand All @@ -578,24 +581,30 @@ function buildPrivateInstanceFieldInitSpec(

if (!process.env.BABEL_8_BREAKING) {
if (!state.availableHelper("classPrivateFieldInitSpec")) {
return template.statement.ast`${t.cloneNode(id)}.set(${ref}, {
// configurable is always false for private elements
// enumerable is always false for private elements
writable: true,
value: ${value},
})`;
return inheritPropComments(
template.statement.ast`${t.cloneNode(id)}.set(${ref}, {
// configurable is always false for private elements
// enumerable is always false for private elements
writable: true,
value: ${value},
})`,
prop,
);
}
}

const helper = state.addHelper("classPrivateFieldInitSpec");
return template.statement.ast`${helper}(
${t.thisExpression()},
${t.cloneNode(id)},
{
writable: true,
value: ${value}
},
)`;
return inheritPropComments(
template.statement.ast`${helper}(
${t.thisExpression()},
${t.cloneNode(id)},
{
writable: true,
value: ${value}
},
)`,
prop,
);
}

function buildPrivateStaticFieldInitSpec(
Expand All @@ -614,26 +623,32 @@ function buildPrivateStaticFieldInitSpec(
initAdded: true,
});

return template.statement.ast`
var ${t.cloneNode(id)} = {
// configurable is false by default
// enumerable is false by default
// writable is false by default
get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
}
`;
return inheritPropComments(
template.statement.ast`
var ${t.cloneNode(id)} = {
// configurable is false by default
// enumerable is false by default
// writable is false by default
get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
}
`,
prop,
);
}

const value = prop.node.value || prop.scope.buildUndefinedNode();
return template.statement.ast`
var ${t.cloneNode(id)} = {
// configurable is false by default
// enumerable is false by default
writable: true,
value: ${value}
};
`;
return inheritPropComments(
template.statement.ast`
var ${t.cloneNode(id)} = {
// configurable is false by default
// enumerable is false by default
writable: true,
value: ${value}
};
`,
prop,
);
}

function buildPrivateMethodInitLoose(
Expand All @@ -646,14 +661,17 @@ function buildPrivateMethodInitLoose(
if (initAdded) return;

if (methodId) {
return template.statement.ast`
return inheritPropComments(
template.statement.ast`
Object.defineProperty(${ref}, ${id}, {
// configurable is false by default
// enumerable is false by default
// writable is false by default
value: ${methodId.name}
});
`;
`,
prop,
);
}
const isAccessor = getId || setId;
if (isAccessor) {
Expand All @@ -662,15 +680,18 @@ function buildPrivateMethodInitLoose(
initAdded: true,
});

return template.statement.ast`
Object.defineProperty(${ref}, ${id}, {
// configurable is false by default
// enumerable is false by default
// writable is false by default
get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
});
`;
return inheritPropComments(
template.statement.ast`
Object.defineProperty(${ref}, ${id}, {
// configurable is false by default
// enumerable is false by default
// writable is false by default
get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
});
`,
prop,
);
}
}

Expand Down Expand Up @@ -719,24 +740,30 @@ function buildPrivateAccessorInitialization(

if (!process.env.BABEL_8_BREAKING) {
if (!state.availableHelper("classPrivateFieldInitSpec")) {
return template.statement.ast`
${id}.set(${ref}, {
get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
});
`;
return inheritPropComments(
template.statement.ast`
${id}.set(${ref}, {
get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
});
`,
prop,
);
}
}

const helper = state.addHelper("classPrivateFieldInitSpec");
return template.statement.ast`${helper}(
${t.thisExpression()},
${t.cloneNode(id)},
{
get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
},
)`;
return inheritPropComments(
template.statement.ast`${helper}(
${t.thisExpression()},
${t.cloneNode(id)},
{
get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
},
)`,
prop,
);
}

function buildPrivateInstanceMethodInitalization(
Expand All @@ -750,15 +777,21 @@ function buildPrivateInstanceMethodInitalization(

if (!process.env.BABEL_8_BREAKING) {
if (!state.availableHelper("classPrivateMethodInitSpec")) {
return template.statement.ast`${id}.add(${ref})`;
return inheritPropComments(
template.statement.ast`${id}.add(${ref})`,
prop,
);
}
}

const helper = state.addHelper("classPrivateMethodInitSpec");
return template.statement.ast`${helper}(
${t.thisExpression()},
${t.cloneNode(id)}
)`;
return inheritPropComments(
template.statement.ast`${helper}(
${t.thisExpression()},
${t.cloneNode(id)}
)`,
prop,
);
}

function buildPublicFieldInitLoose(
Expand All @@ -768,12 +801,15 @@ function buildPublicFieldInitLoose(
const { key, computed } = prop.node;
const value = prop.node.value || prop.scope.buildUndefinedNode();

return t.expressionStatement(
t.assignmentExpression(
"=",
t.memberExpression(ref, key, computed || t.isLiteral(key)),
value,
return inheritPropComments(
t.expressionStatement(
t.assignmentExpression(
"=",
t.memberExpression(ref, key, computed || t.isLiteral(key)),
value,
),
),
prop,
);
}

Expand All @@ -785,14 +821,17 @@ function buildPublicFieldInitSpec(
const { key, computed } = prop.node;
const value = prop.node.value || prop.scope.buildUndefinedNode();

return t.expressionStatement(
t.callExpression(state.addHelper("defineProperty"), [
ref,
computed || t.isLiteral(key)
? key
: t.stringLiteral((key as t.Identifier).name),
value,
]),
return inheritPropComments(
t.expressionStatement(
t.callExpression(state.addHelper("defineProperty"), [
ref,
computed || t.isLiteral(key)
? key
: t.stringLiteral((key as t.Identifier).name),
value,
]),
),
prop,
);
}

Expand All @@ -814,25 +853,31 @@ function buildPrivateStaticMethodInitLoose(
initAdded: true,
});

return template.statement.ast`
return inheritPropComments(
template.statement.ast`
Object.defineProperty(${ref}, ${id}, {
// configurable is false by default
// enumerable is false by default
// writable is false by default
get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
})
`,
prop,
);
}

return inheritPropComments(
template.statement.ast`
Object.defineProperty(${ref}, ${id}, {
// configurable is false by default
// enumerable is false by default
// writable is false by default
get: ${getId ? getId.name : prop.scope.buildUndefinedNode()},
set: ${setId ? setId.name : prop.scope.buildUndefinedNode()}
})
`;
}

return template.statement.ast`
Object.defineProperty(${ref}, ${id}, {
// configurable is false by default
// enumerable is false by default
// writable is false by default
value: ${methodId.name}
});
`;
value: ${methodId.name}
});
`,
prop,
);
}

function buildPrivateMethodDeclaration(
Expand Down Expand Up @@ -872,13 +917,16 @@ function buildPrivateMethodDeclaration(
declId = id;
}

return t.functionDeclaration(
t.cloneNode(declId),
// @ts-expect-error params for ClassMethod has TSParameterProperty
params,
body,
generator,
async,
return inheritPropComments(
t.functionDeclaration(
t.cloneNode(declId),
// @ts-expect-error params for ClassMethod has TSParameterProperty
params,
body,
generator,
async,
),
prop,
);
}

Expand Down Expand Up @@ -994,6 +1042,23 @@ function isNameOrLength({ key, computed }: t.ClassProperty) {
return false;
}

/**
* Inherit comments from class members. This is a reduced version of
* t.inheritsComments: the trailing comments are not inherited because
* for most class members except the last one, their trailing comments are
* the next sibiling's leading comments.
*
* @template T transformed class member type
* @param {T} node transformed class member
* @param {PropPath} prop class member
* @returns transformed class member type with comments inherited
*/
function inheritPropComments<T extends t.Node>(node: T, prop: PropPath) {
t.inheritLeadingComments(node, prop.node);
t.inheritInnerComments(node, prop.node);
return node;
}

export function buildFieldsInitNodes(
ref: t.Identifier,
superRef: t.Expression | undefined,
Expand Down Expand Up @@ -1056,9 +1121,14 @@ export function buildFieldsInitNodes(
// We special-case the single expression case to avoid the iife, since
// it's common.
if (blockBody.length === 1 && t.isExpressionStatement(blockBody[0])) {
staticNodes.push(blockBody[0]);
staticNodes.push(inheritPropComments(blockBody[0], prop));
} else {
staticNodes.push(template.statement.ast`(() => { ${blockBody} })()`);
staticNodes.push(
t.inheritsComments(
template.statement.ast`(() => { ${blockBody} })()`,
prop.node,
),
);
}
break;
}
Expand Down

0 comments on commit 8d1486d

Please sign in to comment.