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

feat: ClassDeclarationStructure - support static blocks #1520

Merged
merged 1 commit into from
Mar 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions deno/ts_morph.d.ts
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Loading