Skip to content

Commit d24e2a7

Browse files
authored
feat: ClassDeclarationStructure - support static blocks (#1520)
1 parent ca77636 commit d24e2a7

File tree

11 files changed

+66
-0
lines changed

11 files changed

+66
-0
lines changed

deno/ts_morph.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10309,6 +10309,7 @@ export interface ClassLikeDeclarationBaseStructure extends NameableNodeStructure
1030910309
interface ClassLikeDeclarationBaseSpecificStructure {
1031010310
extends?: string | WriterFunction;
1031110311
ctors?: OptionalKind<ConstructorDeclarationStructure>[];
10312+
staticBlocks?: OptionalKind<ClassStaticBlockDeclarationStructure>[];
1031210313
properties?: OptionalKind<PropertyDeclarationStructure>[];
1031310314
getAccessors?: OptionalKind<GetAccessorDeclarationStructure>[];
1031410315
setAccessors?: OptionalKind<SetAccessorDeclarationStructure>[];

deno/ts_morph.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6521,6 +6521,7 @@ class ClassDeclarationStructurePrinter extends NodePrinter {
65216521
this.#printHeader(writer, structure);
65226522
writer.inlineBlock(() => {
65236523
this.factory.forPropertyDeclaration().printTexts(writer, structure.properties);
6524+
this.#printStaticBlocks(writer, structure);
65246525
this.#printCtors(writer, structure, isAmbient);
65256526
this.#printGetAndSet(writer, structure, isAmbient);
65266527
if (!ArrayUtils.isNullOrEmpty(structure.methods)) {
@@ -6559,6 +6560,14 @@ class ClassDeclarationStructurePrinter extends NodePrinter {
65596560
this.factory.forConstructorDeclaration({ isAmbient }).printText(writer, ctor);
65606561
}
65616562
}
6563+
#printStaticBlocks(writer, structure) {
6564+
if (ArrayUtils.isNullOrEmpty(structure.staticBlocks))
6565+
return;
6566+
for (const block of structure.staticBlocks) {
6567+
this.#conditionalSeparator(writer, false);
6568+
this.factory.forClassStaticBlockDeclaration().printText(writer, block);
6569+
}
6570+
}
65626571
#printGetAndSet(writer, structure, isAmbient) {
65636572
if (structure.getAccessors == null && structure.setAccessors == null)
65646573
return;
@@ -7235,6 +7244,7 @@ function forClassLikeDeclarationBase(structure, callback) {
72357244
|| forTypeParameteredNode(structure, callback)
72367245
|| forJSDocableNode(structure, callback)
72377246
|| forAll(structure.ctors, callback, StructureKind.Constructor)
7247+
|| forAll(structure.staticBlocks, callback, StructureKind.ClassStaticBlock)
72387248
|| forAll(structure.properties, callback, StructureKind.Property)
72397249
|| forAll(structure.getAccessors, callback, StructureKind.GetAccessor)
72407250
|| forAll(structure.setAccessors, callback, StructureKind.SetAccessor)
@@ -14655,6 +14665,10 @@ class ClassDeclaration extends ClassDeclarationBase {
1465514665
this.getConstructors().forEach(c => c.remove());
1465614666
this.addConstructors(structure.ctors);
1465714667
}
14668+
if (structure.staticBlocks != null) {
14669+
this.getStaticBlocks().forEach(c => c.remove());
14670+
this.addStaticBlocks(structure.staticBlocks);
14671+
}
1465814672
if (structure.properties != null) {
1465914673
this.getProperties().forEach(p => p.remove());
1466014674
this.addProperties(structure.properties);
@@ -14679,6 +14693,7 @@ class ClassDeclaration extends ClassDeclarationBase {
1467914693
return callBaseGetStructure(ClassDeclarationBase.prototype, this, {
1468014694
kind: StructureKind.Class,
1468114695
ctors: this.getConstructors().filter(ctor => isAmbient || !ctor.isOverload()).map(ctor => ctor.getStructure()),
14696+
staticBlocks: this.getStaticBlocks().map(ctor => ctor.getStructure()),
1468214697
methods: this.getMethods().filter(method => isAmbient || !method.isOverload()).map(method => method.getStructure()),
1468314698
properties: this.getProperties().map(property => property.getStructure()),
1468414699
extends: getExtends ? getExtends.getText() : undefined,

packages/ts-morph/lib/ts-morph.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10309,6 +10309,7 @@ export interface ClassLikeDeclarationBaseStructure extends NameableNodeStructure
1030910309
interface ClassLikeDeclarationBaseSpecificStructure {
1031010310
extends?: string | WriterFunction;
1031110311
ctors?: OptionalKind<ConstructorDeclarationStructure>[];
10312+
staticBlocks?: OptionalKind<ClassStaticBlockDeclarationStructure>[];
1031210313
properties?: OptionalKind<PropertyDeclarationStructure>[];
1031310314
getAccessors?: OptionalKind<GetAccessorDeclarationStructure>[];
1031410315
setAccessors?: OptionalKind<SetAccessorDeclarationStructure>[];

packages/ts-morph/src/compiler/ast/class/ClassDeclaration.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
ClassDeclarationSpecificStructure,
44
ClassDeclarationStructure,
55
ClassLikeDeclarationBaseSpecificStructure,
6+
ClassStaticBlockDeclarationStructure,
67
ConstructorDeclarationStructure,
78
InterfaceDeclarationStructure,
89
JSDocStructure,
@@ -48,6 +49,10 @@ export class ClassDeclaration extends ClassDeclarationBase<ts.ClassDeclaration>
4849
this.getConstructors().forEach(c => c.remove());
4950
this.addConstructors(structure.ctors);
5051
}
52+
if (structure.staticBlocks != null) {
53+
this.getStaticBlocks().forEach(c => c.remove());
54+
this.addStaticBlocks(structure.staticBlocks);
55+
}
5156
if (structure.properties != null) {
5257
this.getProperties().forEach(p => p.remove());
5358
this.addProperties(structure.properties);
@@ -77,6 +82,7 @@ export class ClassDeclaration extends ClassDeclarationBase<ts.ClassDeclaration>
7782
return callBaseGetStructure<ClassDeclarationSpecificStructure & ClassLikeDeclarationBaseSpecificStructure>(ClassDeclarationBase.prototype, this, {
7883
kind: StructureKind.Class,
7984
ctors: this.getConstructors().filter(ctor => isAmbient || !ctor.isOverload()).map(ctor => ctor.getStructure() as ConstructorDeclarationStructure),
85+
staticBlocks: this.getStaticBlocks().map(ctor => ctor.getStructure() as ClassStaticBlockDeclarationStructure),
8086
methods: this.getMethods().filter(method => isAmbient || !method.isOverload()).map(method => method.getStructure() as MethodDeclarationStructure),
8187
properties: this.getProperties().map(property => property.getStructure()),
8288
extends: getExtends ? getExtends.getText() : undefined,

packages/ts-morph/src/structurePrinters/class/ClassDeclarationStructurePrinter.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export class ClassDeclarationStructurePrinter extends NodePrinter<OptionalKind<C
2727

2828
writer.inlineBlock(() => {
2929
this.factory.forPropertyDeclaration().printTexts(writer, structure.properties);
30+
this.#printStaticBlocks(writer, structure);
3031
this.#printCtors(writer, structure, isAmbient);
3132
this.#printGetAndSet(writer, structure, isAmbient);
3233

@@ -74,6 +75,16 @@ export class ClassDeclarationStructurePrinter extends NodePrinter<OptionalKind<C
7475
}
7576
}
7677

78+
#printStaticBlocks(writer: CodeBlockWriter, structure: OptionalKind<ClassDeclarationStructure>) {
79+
if (ArrayUtils.isNullOrEmpty(structure.staticBlocks))
80+
return;
81+
82+
for (const block of structure.staticBlocks) {
83+
this.#conditionalSeparator(writer, /* is ambient */ false);
84+
this.factory.forClassStaticBlockDeclaration().printText(writer, block);
85+
}
86+
}
87+
7788
#printGetAndSet(writer: CodeBlockWriter, structure: OptionalKind<ClassDeclarationStructure>, isAmbient: boolean) {
7889
if (structure.getAccessors == null && structure.setAccessors == null)
7990
return;

packages/ts-morph/src/structures/class/base/ClassLikeDeclarationBaseStructure.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
TypeParameteredNodeStructure,
99
} from "../../base";
1010
import { OptionalKind } from "../../types";
11+
import { ClassStaticBlockDeclarationStructure } from "../ClassStaticBlockDeclarationStructure";
1112
import { ConstructorDeclarationStructure } from "../ConstructorDeclarationStructure";
1213
import { GetAccessorDeclarationStructure } from "../GetAccessorDeclarationStructure";
1314
import { MethodDeclarationStructure } from "../MethodDeclarationStructure";
@@ -29,6 +30,7 @@ export interface ClassLikeDeclarationBaseStructure
2930
export interface ClassLikeDeclarationBaseSpecificStructure {
3031
extends?: string | WriterFunction;
3132
ctors?: OptionalKind<ConstructorDeclarationStructure>[];
33+
staticBlocks?: OptionalKind<ClassStaticBlockDeclarationStructure>[];
3234
properties?: OptionalKind<PropertyDeclarationStructure>[];
3335
getAccessors?: OptionalKind<GetAccessorDeclarationStructure>[];
3436
setAccessors?: OptionalKind<SetAccessorDeclarationStructure>[];

packages/ts-morph/src/structures/utils/forEachStructureChild.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ function forClassLikeDeclarationBase<TStructure>(structure: ClassLikeDeclaration
145145
|| forTypeParameteredNode(structure, callback)
146146
|| forJSDocableNode(structure, callback)
147147
|| forAll(structure.ctors, callback, StructureKind.Constructor)
148+
|| forAll(structure.staticBlocks, callback, StructureKind.ClassStaticBlock)
148149
|| forAll(structure.properties, callback, StructureKind.Property)
149150
|| forAll(structure.getAccessors, callback, StructureKind.GetAccessor)
150151
|| forAll(structure.setAccessors, callback, StructureKind.SetAccessor)

packages/ts-morph/src/tests/compiler/ast/class/classDeclarationTests.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ class Identifier extends Other {
7070
constructor() {
7171
}
7272
73+
static {
74+
test;
75+
}
76+
7377
p;
7478
7579
get g() {
@@ -85,6 +89,7 @@ class Identifier extends Other {
8589
const structure: OptionalKindAndTrivia<MakeRequired<ClassDeclarationSpecificStructure & ClassLikeDeclarationBaseSpecificStructure>> = {
8690
extends: "Other",
8791
ctors: [{}],
92+
staticBlocks: [{ statements: ["test;"]}],
8893
properties: [{ name: "p" }],
8994
getAccessors: [{ name: "g" }],
9095
setAccessors: [{ name: "s", parameters: [{ name: "value", type: "string" }] }],
@@ -110,6 +115,7 @@ class Identifier {
110115
const structure: OptionalKindAndTrivia<MakeRequired<ClassDeclarationSpecificStructure & ClassLikeDeclarationBaseSpecificStructure>> = {
111116
extends: undefined,
112117
ctors: [],
118+
staticBlocks: [],
113119
properties: [],
114120
getAccessors: [],
115121
setAccessors: [],
@@ -130,6 +136,7 @@ class Identifier {
130136
doTest("class Identifier {}", {
131137
kind: StructureKind.Class,
132138
ctors: [],
139+
staticBlocks: [],
133140
decorators: [],
134141
docs: [],
135142
extends: undefined,
@@ -152,6 +159,7 @@ class Identifier {
152159
/** Test */
153160
@dec export default abstract class Identifier<T> extends Base implements IBase {
154161
constructor() {}
162+
static {}
155163
method() {}
156164
prop: string;
157165
get getAccessor() {}
@@ -161,6 +169,7 @@ class Identifier {
161169
doTest(code, {
162170
kind: StructureKind.Class,
163171
ctors: [{ statements: [], overloads: [] }],
172+
staticBlocks: [{}],
164173
decorators: [{ name: "dec" }],
165174
docs: [{ description: "Test" }],
166175
extends: "Base",
@@ -193,6 +202,7 @@ declare class Identifier {
193202
doTest(code, {
194203
kind: StructureKind.Class,
195204
ctors: [{ returnType: "string" }, { returnType: "number" }],
205+
staticBlocks: [],
196206
decorators: [],
197207
docs: [],
198208
extends: undefined,

packages/ts-morph/src/tests/compiler/ast/statement/statementedNode/classTests.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ describe("StatementedNode", () => {
6363
const structure: OptionalKindAndTrivia<MakeRequired<ClassDeclarationStructure>> = {
6464
name: "C",
6565
ctors: [{}, {}],
66+
staticBlocks: [{}],
6667
decorators: [{ name: "D" }],
6768
docs: [{ description: "Test" }],
6869
extends: "Base",
@@ -79,6 +80,7 @@ describe("StatementedNode", () => {
7980
};
8081
const expectedText = "/** Test */\n@D\nexport default abstract class C<T> extends Base implements IBase, IBase2 {\n"
8182
+ " p: number;\n\n"
83+
+ " static {\n }\n\n"
8284
+ " constructor() {\n }\n\n"
8385
+ " constructor() {\n }\n\n"
8486
+ " get g() {\n }\n\n set g() {\n }\n\n get s() {\n }\n\n set s() {\n }\n\n"

packages/ts-morph/src/tests/compiler/testHelpers/fillStructureWithDefaults.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ModuleDeclarationKind, VariableDeclarationKind } from "../../../compile
22
import {
33
CallSignatureDeclarationStructure,
44
ClassDeclarationStructure,
5+
ClassStaticBlockDeclarationStructure,
56
ConstructorDeclarationOverloadStructure,
67
ConstructorDeclarationStructure,
78
ConstructSignatureDeclarationStructure,
@@ -96,6 +97,7 @@ export namespace fillStructures {
9697
setIfNull(structure, "isDefaultExport", false);
9798
setIfNull(structure, "isExported", false);
9899
setIfNull(structure, "ctors", []);
100+
setIfNull(structure, "staticBlocks", []);
99101
setIfNull(structure, "decorators", []);
100102
setIfNull(structure, "docs", []);
101103
setIfNull(structure, "extends", undefined);
@@ -110,6 +112,7 @@ export namespace fillStructures {
110112
fill(structure.decorators!, decorator);
111113
fill(structure.typeParameters!, typeParameter);
112114
fill(structure.ctors!, constructorDeclaration);
115+
fill(structure.staticBlocks!, classStaticBlock);
113116
fill(structure.methods!, method);
114117
fill(structure.properties!, property);
115118
fill(structure.getAccessors!, getAccessor);
@@ -119,6 +122,13 @@ export namespace fillStructures {
119122
return structure as ClassDeclarationStructure;
120123
}
121124

125+
export function classStaticBlock(structure: OptionalKind<ClassStaticBlockDeclarationStructure>): ClassStaticBlockDeclarationStructure {
126+
setIfNull(structure, "statements", []);
127+
setIfNull(structure, "docs", []);
128+
setIfNull(structure, "kind", StructureKind.ClassStaticBlock);
129+
return structure as ClassStaticBlockDeclarationStructure;
130+
}
131+
122132
export function constructorDeclaration(structure: OptionalKind<ConstructorDeclarationStructure>): ConstructorDeclarationStructure {
123133
constructorBase(structure);
124134
setIfNull(structure, "statements", undefined);

packages/ts-morph/src/tests/structurePrinters/class/classDeclarationStructurePrinterTests.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ describe("ClassDeclarationStructurePrinter", () => {
3737
name: "pProtected",
3838
}],
3939
ctors: [{}],
40+
staticBlocks: [{
41+
statements: ["test;"],
42+
}],
4043
methods: [{
4144
scope: Scope.Private,
4245
name: "m1",
@@ -59,6 +62,10 @@ describe("ClassDeclarationStructurePrinter", () => {
5962
private pPrivate;
6063
protected pProtected;
6164
65+
static {
66+
test;
67+
}
68+
6269
constructor() {
6370
}
6471

0 commit comments

Comments
 (0)