Skip to content

Commit

Permalink
feat: ClassDeclarationStructure - support static blocks (#1520)
Browse files Browse the repository at this point in the history
  • Loading branch information
dsherret committed Mar 10, 2024
1 parent ca77636 commit d24e2a7
Show file tree
Hide file tree
Showing 11 changed files with 66 additions and 0 deletions.
1 change: 1 addition & 0 deletions deno/ts_morph.d.ts
Expand Up @@ -10309,6 +10309,7 @@ export interface ClassLikeDeclarationBaseStructure extends NameableNodeStructure
interface ClassLikeDeclarationBaseSpecificStructure {
extends?: string | WriterFunction;
ctors?: OptionalKind<ConstructorDeclarationStructure>[];
staticBlocks?: OptionalKind<ClassStaticBlockDeclarationStructure>[];
properties?: OptionalKind<PropertyDeclarationStructure>[];
getAccessors?: OptionalKind<GetAccessorDeclarationStructure>[];
setAccessors?: OptionalKind<SetAccessorDeclarationStructure>[];
Expand Down
15 changes: 15 additions & 0 deletions deno/ts_morph.js
Expand Up @@ -6521,6 +6521,7 @@ class ClassDeclarationStructurePrinter extends NodePrinter {
this.#printHeader(writer, structure);
writer.inlineBlock(() => {
this.factory.forPropertyDeclaration().printTexts(writer, structure.properties);
this.#printStaticBlocks(writer, structure);
this.#printCtors(writer, structure, isAmbient);
this.#printGetAndSet(writer, structure, isAmbient);
if (!ArrayUtils.isNullOrEmpty(structure.methods)) {
Expand Down Expand Up @@ -6559,6 +6560,14 @@ class ClassDeclarationStructurePrinter extends NodePrinter {
this.factory.forConstructorDeclaration({ isAmbient }).printText(writer, ctor);
}
}
#printStaticBlocks(writer, structure) {
if (ArrayUtils.isNullOrEmpty(structure.staticBlocks))
return;
for (const block of structure.staticBlocks) {
this.#conditionalSeparator(writer, false);
this.factory.forClassStaticBlockDeclaration().printText(writer, block);
}
}
#printGetAndSet(writer, structure, isAmbient) {
if (structure.getAccessors == null && structure.setAccessors == null)
return;
Expand Down Expand Up @@ -7235,6 +7244,7 @@ function forClassLikeDeclarationBase(structure, callback) {
|| forTypeParameteredNode(structure, callback)
|| forJSDocableNode(structure, callback)
|| forAll(structure.ctors, callback, StructureKind.Constructor)
|| forAll(structure.staticBlocks, callback, StructureKind.ClassStaticBlock)
|| forAll(structure.properties, callback, StructureKind.Property)
|| forAll(structure.getAccessors, callback, StructureKind.GetAccessor)
|| forAll(structure.setAccessors, callback, StructureKind.SetAccessor)
Expand Down Expand Up @@ -14655,6 +14665,10 @@ class ClassDeclaration extends ClassDeclarationBase {
this.getConstructors().forEach(c => c.remove());
this.addConstructors(structure.ctors);
}
if (structure.staticBlocks != null) {
this.getStaticBlocks().forEach(c => c.remove());
this.addStaticBlocks(structure.staticBlocks);
}
if (structure.properties != null) {
this.getProperties().forEach(p => p.remove());
this.addProperties(structure.properties);
Expand All @@ -14679,6 +14693,7 @@ class ClassDeclaration extends ClassDeclarationBase {
return callBaseGetStructure(ClassDeclarationBase.prototype, this, {
kind: StructureKind.Class,
ctors: this.getConstructors().filter(ctor => isAmbient || !ctor.isOverload()).map(ctor => ctor.getStructure()),
staticBlocks: this.getStaticBlocks().map(ctor => ctor.getStructure()),
methods: this.getMethods().filter(method => isAmbient || !method.isOverload()).map(method => method.getStructure()),
properties: this.getProperties().map(property => property.getStructure()),
extends: getExtends ? getExtends.getText() : undefined,
Expand Down
1 change: 1 addition & 0 deletions packages/ts-morph/lib/ts-morph.d.ts
Expand Up @@ -10309,6 +10309,7 @@ export interface ClassLikeDeclarationBaseStructure extends NameableNodeStructure
interface ClassLikeDeclarationBaseSpecificStructure {
extends?: string | WriterFunction;
ctors?: OptionalKind<ConstructorDeclarationStructure>[];
staticBlocks?: OptionalKind<ClassStaticBlockDeclarationStructure>[];
properties?: OptionalKind<PropertyDeclarationStructure>[];
getAccessors?: OptionalKind<GetAccessorDeclarationStructure>[];
setAccessors?: OptionalKind<SetAccessorDeclarationStructure>[];
Expand Down
6 changes: 6 additions & 0 deletions packages/ts-morph/src/compiler/ast/class/ClassDeclaration.ts
Expand Up @@ -3,6 +3,7 @@ import {
ClassDeclarationSpecificStructure,
ClassDeclarationStructure,
ClassLikeDeclarationBaseSpecificStructure,
ClassStaticBlockDeclarationStructure,
ConstructorDeclarationStructure,
InterfaceDeclarationStructure,
JSDocStructure,
Expand Down Expand Up @@ -48,6 +49,10 @@ export class ClassDeclaration extends ClassDeclarationBase<ts.ClassDeclaration>
this.getConstructors().forEach(c => c.remove());
this.addConstructors(structure.ctors);
}
if (structure.staticBlocks != null) {
this.getStaticBlocks().forEach(c => c.remove());
this.addStaticBlocks(structure.staticBlocks);
}
if (structure.properties != null) {
this.getProperties().forEach(p => p.remove());
this.addProperties(structure.properties);
Expand Down Expand Up @@ -77,6 +82,7 @@ export class ClassDeclaration extends ClassDeclarationBase<ts.ClassDeclaration>
return callBaseGetStructure<ClassDeclarationSpecificStructure & ClassLikeDeclarationBaseSpecificStructure>(ClassDeclarationBase.prototype, this, {
kind: StructureKind.Class,
ctors: this.getConstructors().filter(ctor => isAmbient || !ctor.isOverload()).map(ctor => ctor.getStructure() as ConstructorDeclarationStructure),
staticBlocks: this.getStaticBlocks().map(ctor => ctor.getStructure() as ClassStaticBlockDeclarationStructure),
methods: this.getMethods().filter(method => isAmbient || !method.isOverload()).map(method => method.getStructure() as MethodDeclarationStructure),
properties: this.getProperties().map(property => property.getStructure()),
extends: getExtends ? getExtends.getText() : undefined,
Expand Down
Expand Up @@ -27,6 +27,7 @@ export class ClassDeclarationStructurePrinter extends NodePrinter<OptionalKind<C

writer.inlineBlock(() => {
this.factory.forPropertyDeclaration().printTexts(writer, structure.properties);
this.#printStaticBlocks(writer, structure);
this.#printCtors(writer, structure, isAmbient);
this.#printGetAndSet(writer, structure, isAmbient);

Expand Down Expand Up @@ -74,6 +75,16 @@ export class ClassDeclarationStructurePrinter extends NodePrinter<OptionalKind<C
}
}

#printStaticBlocks(writer: CodeBlockWriter, structure: OptionalKind<ClassDeclarationStructure>) {
if (ArrayUtils.isNullOrEmpty(structure.staticBlocks))
return;

for (const block of structure.staticBlocks) {
this.#conditionalSeparator(writer, /* is ambient */ false);
this.factory.forClassStaticBlockDeclaration().printText(writer, block);
}
}

#printGetAndSet(writer: CodeBlockWriter, structure: OptionalKind<ClassDeclarationStructure>, isAmbient: boolean) {
if (structure.getAccessors == null && structure.setAccessors == null)
return;
Expand Down
Expand Up @@ -8,6 +8,7 @@ import {
TypeParameteredNodeStructure,
} from "../../base";
import { OptionalKind } from "../../types";
import { ClassStaticBlockDeclarationStructure } from "../ClassStaticBlockDeclarationStructure";
import { ConstructorDeclarationStructure } from "../ConstructorDeclarationStructure";
import { GetAccessorDeclarationStructure } from "../GetAccessorDeclarationStructure";
import { MethodDeclarationStructure } from "../MethodDeclarationStructure";
Expand All @@ -29,6 +30,7 @@ export interface ClassLikeDeclarationBaseStructure
export interface ClassLikeDeclarationBaseSpecificStructure {
extends?: string | WriterFunction;
ctors?: OptionalKind<ConstructorDeclarationStructure>[];
staticBlocks?: OptionalKind<ClassStaticBlockDeclarationStructure>[];
properties?: OptionalKind<PropertyDeclarationStructure>[];
getAccessors?: OptionalKind<GetAccessorDeclarationStructure>[];
setAccessors?: OptionalKind<SetAccessorDeclarationStructure>[];
Expand Down
Expand Up @@ -145,6 +145,7 @@ function forClassLikeDeclarationBase<TStructure>(structure: ClassLikeDeclaration
|| forTypeParameteredNode(structure, callback)
|| forJSDocableNode(structure, callback)
|| forAll(structure.ctors, callback, StructureKind.Constructor)
|| forAll(structure.staticBlocks, callback, StructureKind.ClassStaticBlock)
|| forAll(structure.properties, callback, StructureKind.Property)
|| forAll(structure.getAccessors, callback, StructureKind.GetAccessor)
|| forAll(structure.setAccessors, callback, StructureKind.SetAccessor)
Expand Down
Expand Up @@ -70,6 +70,10 @@ class Identifier extends Other {
constructor() {
}
static {
test;
}
p;
get g() {
Expand All @@ -85,6 +89,7 @@ class Identifier extends Other {
const structure: OptionalKindAndTrivia<MakeRequired<ClassDeclarationSpecificStructure & ClassLikeDeclarationBaseSpecificStructure>> = {
extends: "Other",
ctors: [{}],
staticBlocks: [{ statements: ["test;"]}],
properties: [{ name: "p" }],
getAccessors: [{ name: "g" }],
setAccessors: [{ name: "s", parameters: [{ name: "value", type: "string" }] }],
Expand All @@ -110,6 +115,7 @@ class Identifier {
const structure: OptionalKindAndTrivia<MakeRequired<ClassDeclarationSpecificStructure & ClassLikeDeclarationBaseSpecificStructure>> = {
extends: undefined,
ctors: [],
staticBlocks: [],
properties: [],
getAccessors: [],
setAccessors: [],
Expand All @@ -130,6 +136,7 @@ class Identifier {
doTest("class Identifier {}", {
kind: StructureKind.Class,
ctors: [],
staticBlocks: [],
decorators: [],
docs: [],
extends: undefined,
Expand All @@ -152,6 +159,7 @@ class Identifier {
/** Test */
@dec export default abstract class Identifier<T> extends Base implements IBase {
constructor() {}
static {}
method() {}
prop: string;
get getAccessor() {}
Expand All @@ -161,6 +169,7 @@ class Identifier {
doTest(code, {
kind: StructureKind.Class,
ctors: [{ statements: [], overloads: [] }],
staticBlocks: [{}],
decorators: [{ name: "dec" }],
docs: [{ description: "Test" }],
extends: "Base",
Expand Down Expand Up @@ -193,6 +202,7 @@ declare class Identifier {
doTest(code, {
kind: StructureKind.Class,
ctors: [{ returnType: "string" }, { returnType: "number" }],
staticBlocks: [],
decorators: [],
docs: [],
extends: undefined,
Expand Down
Expand Up @@ -63,6 +63,7 @@ describe("StatementedNode", () => {
const structure: OptionalKindAndTrivia<MakeRequired<ClassDeclarationStructure>> = {
name: "C",
ctors: [{}, {}],
staticBlocks: [{}],
decorators: [{ name: "D" }],
docs: [{ description: "Test" }],
extends: "Base",
Expand All @@ -79,6 +80,7 @@ describe("StatementedNode", () => {
};
const expectedText = "/** Test */\n@D\nexport default abstract class C<T> extends Base implements IBase, IBase2 {\n"
+ " p: number;\n\n"
+ " static {\n }\n\n"
+ " constructor() {\n }\n\n"
+ " constructor() {\n }\n\n"
+ " get g() {\n }\n\n set g() {\n }\n\n get s() {\n }\n\n set s() {\n }\n\n"
Expand Down
Expand Up @@ -2,6 +2,7 @@ import { ModuleDeclarationKind, VariableDeclarationKind } from "../../../compile
import {
CallSignatureDeclarationStructure,
ClassDeclarationStructure,
ClassStaticBlockDeclarationStructure,
ConstructorDeclarationOverloadStructure,
ConstructorDeclarationStructure,
ConstructSignatureDeclarationStructure,
Expand Down Expand Up @@ -96,6 +97,7 @@ export namespace fillStructures {
setIfNull(structure, "isDefaultExport", false);
setIfNull(structure, "isExported", false);
setIfNull(structure, "ctors", []);
setIfNull(structure, "staticBlocks", []);
setIfNull(structure, "decorators", []);
setIfNull(structure, "docs", []);
setIfNull(structure, "extends", undefined);
Expand All @@ -110,6 +112,7 @@ export namespace fillStructures {
fill(structure.decorators!, decorator);
fill(structure.typeParameters!, typeParameter);
fill(structure.ctors!, constructorDeclaration);
fill(structure.staticBlocks!, classStaticBlock);
fill(structure.methods!, method);
fill(structure.properties!, property);
fill(structure.getAccessors!, getAccessor);
Expand All @@ -119,6 +122,13 @@ export namespace fillStructures {
return structure as ClassDeclarationStructure;
}

export function classStaticBlock(structure: OptionalKind<ClassStaticBlockDeclarationStructure>): ClassStaticBlockDeclarationStructure {
setIfNull(structure, "statements", []);
setIfNull(structure, "docs", []);
setIfNull(structure, "kind", StructureKind.ClassStaticBlock);
return structure as ClassStaticBlockDeclarationStructure;
}

export function constructorDeclaration(structure: OptionalKind<ConstructorDeclarationStructure>): ConstructorDeclarationStructure {
constructorBase(structure);
setIfNull(structure, "statements", undefined);
Expand Down
Expand Up @@ -37,6 +37,9 @@ describe("ClassDeclarationStructurePrinter", () => {
name: "pProtected",
}],
ctors: [{}],
staticBlocks: [{
statements: ["test;"],
}],
methods: [{
scope: Scope.Private,
name: "m1",
Expand All @@ -59,6 +62,10 @@ describe("ClassDeclarationStructurePrinter", () => {
private pPrivate;
protected pProtected;
static {
test;
}
constructor() {
}
Expand Down

0 comments on commit d24e2a7

Please sign in to comment.