Skip to content

Commit

Permalink
[Babel 8] Create TSAbstract{Method,Property}Definition (#17014)
Browse files Browse the repository at this point in the history
* add abstract class property / private tests

* breaking: create TSAbstract{Method,Property}Definition

* update test fixtures

* move logic to estree plugin
  • Loading branch information
JLHwung authored Dec 11, 2024
1 parent 8b6fb94 commit 40d37cb
Show file tree
Hide file tree
Showing 28 changed files with 612 additions and 27 deletions.
54 changes: 45 additions & 9 deletions packages/babel-parser/src/plugins/estree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ export default (superClass: typeof Parser) =>
allowDirectSuper: boolean,
type: T["type"],
inClassScope: boolean = false,
): N.EstreeMethodDefinition {
): N.EstreeMethodDefinition | N.EstreeTSAbstractMethodDefinition {
let funcNode = this.startNode<N.MethodLike>();
funcNode.kind = node.kind; // provide kind, so super method correctly sets state
funcNode = super.parseMethod(
Expand All @@ -301,6 +301,22 @@ export default (superClass: typeof Parser) =>
if (type === "ClassPrivateMethod") {
node.computed = false;
}
if (
process.env.BABEL_8_BREAKING &&
// @ts-expect-error todo(flow->ts) property not defined for all types in union
node.abstract &&
this.hasPlugin("typescript")
) {
if (!funcNode.body) {
(funcNode as unknown as N.EstreeTSEmptyBodyFunctionExpression).type =
"TSEmptyBodyFunctionExpression";
}
return this.finishNode(
// @ts-expect-error cast methods to estree types
node as Undone<N.EstreeTSAbstractMethodDefinition>,
"TSAbstractMethodDefinition",
);
}
return this.finishNode(
// @ts-expect-error cast methods to estree types
node as Undone<N.EstreeMethodDefinition>,
Expand All @@ -314,26 +330,46 @@ export default (superClass: typeof Parser) =>
}

parseClassProperty(...args: [N.ClassProperty]): any {
const propertyNode = super.parseClassProperty(...args) as any;
const propertyNode = super.parseClassProperty(...args);
if (!process.env.BABEL_8_BREAKING) {
if (!this.getPluginOption("estree", "classFeatures")) {
return propertyNode as N.EstreePropertyDefinition;
return propertyNode as unknown as N.EstreePropertyDefinition;
}
}
propertyNode.type = "PropertyDefinition";
return propertyNode as N.EstreePropertyDefinition;
if (
process.env.BABEL_8_BREAKING &&
propertyNode.abstract &&
this.hasPlugin("typescript")
) {
(propertyNode as unknown as N.EstreeTSAbstractPropertyDefinition).type =
"TSAbstractPropertyDefinition";
} else {
(propertyNode as unknown as N.EstreePropertyDefinition).type =
"PropertyDefinition";
}
return propertyNode;
}

parseClassPrivateProperty(...args: [N.ClassPrivateProperty]): any {
const propertyNode = super.parseClassPrivateProperty(...args) as any;
const propertyNode = super.parseClassPrivateProperty(...args);
if (!process.env.BABEL_8_BREAKING) {
if (!this.getPluginOption("estree", "classFeatures")) {
return propertyNode as N.EstreePropertyDefinition;
return propertyNode as unknown as N.EstreePropertyDefinition;
}
}
propertyNode.type = "PropertyDefinition";
if (
process.env.BABEL_8_BREAKING &&
propertyNode.abstract &&
this.hasPlugin("typescript")
) {
(propertyNode as unknown as N.EstreeTSAbstractPropertyDefinition).type =
"TSAbstractPropertyDefinition";
} else {
(propertyNode as unknown as N.EstreePropertyDefinition).type =
"PropertyDefinition";
}
propertyNode.computed = false;
return propertyNode as N.EstreePropertyDefinition;
return propertyNode;
}

parseObjectMethod(
Expand Down
2 changes: 1 addition & 1 deletion packages/babel-parser/src/plugins/flow/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2550,7 +2550,7 @@ export default (superClass: typeof Parser) =>
}
// estree support
} else if (
// @ts-expect-error TS does not know about the face that estree can replace ClassMethod with MethodDefinition
// @ts-expect-error TS does not know about the fact that estree can replace ClassMethod with MethodDefinition
method.type === "MethodDefinition" &&
isConstructor &&
// @ts-expect-error estree
Expand Down
12 changes: 5 additions & 7 deletions packages/babel-parser/src/plugins/typescript/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3272,15 +3272,12 @@ export default (superClass: ClassWithMixin<typeof Parser, IJSXParserMixin>) =>
parseClassPrivateProperty(
node: N.ClassPrivateProperty,
): N.ClassPrivateProperty {
// @ts-expect-error abstract may not index node
if (node.abstract) {
this.raise(TSErrors.PrivateElementHasAbstract, node);
}

// @ts-expect-error accessibility may not index node
if (node.accessibility) {
this.raise(TSErrors.PrivateElementHasAccessibility, node, {
// @ts-expect-error refine typings
modifier: node.accessibility,
});
}
Expand Down Expand Up @@ -4024,11 +4021,12 @@ export default (superClass: ClassWithMixin<typeof Parser, IJSXParserMixin>) =>
);
// @ts-expect-error todo(flow->ts) property not defined for all types in union
if (method.abstract) {
const hasBody = this.hasPlugin("estree")
const hasEstreePlugin = this.hasPlugin("estree");
const methodFn = hasEstreePlugin
? // @ts-expect-error estree typings
!!method.value.body
: !!method.body;
if (hasBody) {
method.value
: method;
if (methodFn.body) {
const { key } = method;
this.raise(TSErrors.AbstractMethodHasImplementation, method, {
methodName:
Expand Down
38 changes: 33 additions & 5 deletions packages/babel-parser/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,9 @@ export interface ClassPrivateProperty extends NodeBase {
definite?: true;
readonly?: true;
override?: true;
// For error recovery
abstract?: null;
accessibility?: null;
// Flow only
variance?: FlowVariance | null;
}
Expand Down Expand Up @@ -1378,14 +1381,17 @@ export interface EstreeProperty extends NodeBase {
variance?: FlowVariance | null;
}

export interface EstreeMethodDefinition extends NodeBase {
type: "MethodDefinition";
interface EstreeMethodDefinitionBase extends NodeBase {
static: boolean;
key: Expression;
computed: boolean;
value: FunctionExpression;
decorators: Decorator[];
kind?: "get" | "set" | "method";
}

export interface EstreeMethodDefinition extends EstreeMethodDefinitionBase {
type: "MethodDefinition";
value: FunctionExpression;
variance?: FlowVariance | null;
}

Expand All @@ -1404,11 +1410,14 @@ export interface EstreePrivateIdentifier extends NodeBase {
name: string;
}

export interface EstreePropertyDefinition extends NodeBase {
type: "PropertyDefinition";
interface EstreePropertyDefinitionBase extends NodeBase {
static: boolean;
key: Expression | EstreePrivateIdentifier;
computed: boolean;
}

export interface EstreePropertyDefinition extends EstreePropertyDefinitionBase {
type: "PropertyDefinition";
value: Expression;
}

Expand Down Expand Up @@ -1539,6 +1548,22 @@ export interface TsIndexSignature
// Note: parameters.length must be 1.
}

export interface EstreeTSEmptyBodyFunctionExpression extends NodeBase {
type: "TSEmptyBodyFunctionExpression";
}

export interface EstreeTSAbstractMethodDefinition
extends EstreeMethodDefinitionBase {
type: "TSAbstractMethodDefinition";
value: EstreeTSEmptyBodyFunctionExpression;
}

export interface EstreeTSAbstractPropertyDefinition
extends EstreePropertyDefinitionBase {
type: "TSAbstractPropertyDefinition";
value: null;
}

// ================
// TypeScript types
// ================
Expand Down Expand Up @@ -1932,6 +1957,9 @@ export type Node =
| EstreePrivateIdentifier
| EstreeProperty
| EstreePropertyDefinition
| EstreeTSAbstractMethodDefinition
| EstreeTSAbstractPropertyDefinition
| EstreeTSEmptyBodyFunctionExpression
| ExportAllDeclaration
| ExportDefaultDeclaration
| ExportDefaultSpecifier
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"plugins": [
"typescript",
"estree"
],
"BABEL_8_BREAKING": false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{
"type": "File",
"start":0,"end":73,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"program": {
"type": "Program",
"start":0,"end":73,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ClassDeclaration",
"start":0,"end":73,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"abstract": true,
"id": {
"type": "Identifier",
"start":15,"end":30,"loc":{"start":{"line":1,"column":15},"end":{"line":1,"column":30},"identifierName":"TSAbstractClass"},
"name": "TSAbstractClass"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start":31,"end":73,"loc":{"start":{"line":1,"column":31},"end":{"line":3,"column":1}},
"body": [
{
"type": "MethodDefinition",
"start":35,"end":71,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":38}},
"abstract": true,
"static": false,
"key": {
"type": "Identifier",
"start":44,"end":47,"loc":{"start":{"line":2,"column":11},"end":{"line":2,"column":14},"identifierName":"foo"},
"name": "foo"
},
"computed": false,
"kind": "method",
"value": {
"type": "FunctionExpression",
"start":47,"end":71,"loc":{"start":{"line":2,"column":14},"end":{"line":2,"column":38}},
"id": null,
"generator": false,
"async": false,
"expression": false,
"params": [
{
"type": "Identifier",
"start":48,"end":60,"loc":{"start":{"line":2,"column":15},"end":{"line":2,"column":27},"identifierName":"name"},
"name": "name",
"typeAnnotation": {
"type": "TSTypeAnnotation",
"start":52,"end":60,"loc":{"start":{"line":2,"column":19},"end":{"line":2,"column":27}},
"typeAnnotation": {
"type": "TSStringKeyword",
"start":54,"end":60,"loc":{"start":{"line":2,"column":21},"end":{"line":2,"column":27}}
}
}
}
],
"returnType": {
"type": "TSTypeAnnotation",
"start":61,"end":70,"loc":{"start":{"line":2,"column":28},"end":{"line":2,"column":37}},
"typeAnnotation": {
"type": "TSBooleanKeyword",
"start":63,"end":70,"loc":{"start":{"line":2,"column":30},"end":{"line":2,"column":37}}
}
}
}
}
]
}
}
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
abstract class TSAbstractClass {
abstract foo(name: string): boolean;
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
{
"plugins": ["typescript", "estree"]
}
"plugins": [
"typescript",
"estree"
],
"BABEL_8_BREAKING": true
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"start":31,"end":73,"loc":{"start":{"line":1,"column":31},"end":{"line":3,"column":1}},
"body": [
{
"type": "MethodDefinition",
"type": "TSAbstractMethodDefinition",
"start":35,"end":71,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":38}},
"abstract": true,
"static": false,
Expand All @@ -34,7 +34,7 @@
"computed": false,
"kind": "method",
"value": {
"type": "FunctionExpression",
"type": "TSEmptyBodyFunctionExpression",
"start":47,"end":71,"loc":{"start":{"line":2,"column":14},"end":{"line":2,"column":38}},
"id": null,
"generator": false,
Expand Down Expand Up @@ -70,4 +70,4 @@
}
]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
abstract class TSAbstractClass {
abstract #foo(name: string): boolean;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"plugins": [
"typescript",
"estree"
],
"BABEL_8_BREAKING": false
}
Loading

0 comments on commit 40d37cb

Please sign in to comment.