CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-ts-morph

TypeScript compiler wrapper for static analysis and code manipulation.

Pending
Overview
Eval results
Files

code-generation.mddocs/

Code Generation

Structure-based API for creating new TypeScript code elements with full type safety and intelligent formatting. The structure system provides a declarative way to generate code without manually constructing AST nodes.

Capabilities

Structure Interfaces

Base interfaces that define the shape of code elements to be generated.

enum StructureKind {
  ImportAttribute,
  CallSignature,
  Class,
  ClassStaticBlock,
  ConstructSignature,
  Constructor,
  ConstructorOverload,
  Decorator,
  Enum,
  EnumMember,
  ExportAssignment,
  ExportDeclaration,
  ExportSpecifier,
  Function,
  FunctionOverload,
  GetAccessor,
  ImportDeclaration,
  ImportSpecifier,
  IndexSignature,
  Interface,
  JsxAttribute,
  JsxSpreadAttribute,
  JsxElement,
  JsxSelfClosingElement,
  JSDoc,
  JSDocTag,
  Method,
  MethodOverload,
  MethodSignature,
  Module,
  Parameter,
  Property,
  PropertyAssignment,
  PropertySignature,
  SetAccessor,
  ShorthandPropertyAssignment,
  SourceFile,
  SpreadAssignment,
  TypeAlias,
  TypeParameter,
  VariableDeclaration,
  VariableStatement,
}

interface Structure {
  kind: StructureKind;
}

interface StatementedNodeStructure {
  statements?: (string | WriterFunction | StatementStructures)[];
}

interface JSDocableNodeStructure {
  docs?: (JSDocStructure | string)[];
}

interface DecoratableNodeStructure {
  decorators?: DecoratorStructure[];
}

Class Generation Structures

Structures for generating class-related code elements.

interface ClassDeclarationStructure extends Structure, JSDocableNodeStructure, DecoratableNodeStructure {
  kind: StructureKind.Class;
  name: string;
  extends?: string;
  implements?: string[];
  typeParameters?: TypeParameterDeclarationStructure[];
  isAbstract?: boolean;
  isExported?: boolean;
  isDefaultExport?: boolean;
  constructors?: ConstructorDeclarationStructure[];
  properties?: PropertyDeclarationStructure[];
  methods?: MethodDeclarationStructure[];
  getAccessors?: GetAccessorDeclarationStructure[];
  setAccessors?: SetAccessorDeclarationStructure[];
}

interface PropertyDeclarationStructure extends Structure, JSDocableNodeStructure, DecoratableNodeStructure {
  kind: StructureKind.Property;
  name: string;
  type?: string;
  initializer?: string | WriterFunction;
  hasQuestionToken?: boolean;
  hasExclamationToken?: boolean;
  isReadonly?: boolean;
  isStatic?: boolean;
  scope?: Scope;
}

interface MethodDeclarationStructure extends Structure, JSDocableNodeStructure, DecoratableNodeStructure {
  kind: StructureKind.Method;
  name: string;
  parameters?: ParameterDeclarationStructure[];
  returnType?: string;
  typeParameters?: TypeParameterDeclarationStructure[];
  statements?: (string | WriterFunction)[];
  isAbstract?: boolean;
  isAsync?: boolean;
  isGenerator?: boolean;
  isStatic?: boolean;
  scope?: Scope;
  overloads?: MethodDeclarationOverloadStructure[];
}

interface ConstructorDeclarationStructure extends Structure, JSDocableNodeStructure {
  kind: StructureKind.Constructor;
  parameters?: ParameterDeclarationStructure[];
  statements?: (string | WriterFunction)[];
  scope?: Scope;
  overloads?: ConstructorDeclarationOverloadStructure[];
}

enum Scope {
  Public = "public",
  Protected = "protected",
  Private = "private",
}

Function Generation Structures

interface FunctionDeclarationStructure extends Structure, JSDocableNodeStructure, StatementedNodeStructure {
  kind: StructureKind.Function;
  name: string;
  parameters?: ParameterDeclarationStructure[];
  returnType?: string;
  typeParameters?: TypeParameterDeclarationStructure[];
  isAsync?: boolean;
  isGenerator?: boolean;
  isExported?: boolean;
  isDefaultExport?: boolean;
  overloads?: FunctionDeclarationOverloadStructure[];
}

interface ParameterDeclarationStructure extends Structure, DecoratableNodeStructure {
  kind: StructureKind.Parameter;
  name: string;
  type?: string;
  initializer?: string | WriterFunction;
  hasQuestionToken?: boolean;
  isRestParameter?: boolean;
  scope?: Scope;
}

Interface Generation Structures

interface InterfaceDeclarationStructure extends Structure, JSDocableNodeStructure {
  kind: StructureKind.Interface;
  name: string;
  extends?: string[];
  typeParameters?: TypeParameterDeclarationStructure[];
  isExported?: boolean;
  isDefaultExport?: boolean;
  properties?: PropertySignatureStructure[];
  methods?: MethodSignatureStructure[];
  callSignatures?: CallSignatureDeclarationStructure[];
  constructSignatures?: ConstructSignatureDeclarationStructure[];
  indexSignatures?: IndexSignatureDeclarationStructure[];
}

interface PropertySignatureStructure extends Structure, JSDocableNodeStructure {
  kind: StructureKind.PropertySignature;
  name: string;
  type?: string;
  hasQuestionToken?: boolean;
  isReadonly?: boolean;
}

interface MethodSignatureStructure extends Structure, JSDocableNodeStructure {
  kind: StructureKind.MethodSignature;
  name: string;
  parameters?: ParameterDeclarationStructure[];
  returnType?: string;
  typeParameters?: TypeParameterDeclarationStructure[];
  hasQuestionToken?: boolean;
}

Import and Export Structures

interface ImportDeclarationStructure extends Structure {
  kind: StructureKind.ImportDeclaration;
  moduleSpecifier: string;
  defaultImport?: string;
  namespaceImport?: string;
  namedImports?: (string | ImportSpecifierStructure)[];
  isTypeOnly?: boolean;
}

interface ImportSpecifierStructure {
  name: string;
  alias?: string;
  isTypeOnly?: boolean;
}

interface ExportDeclarationStructure extends Structure {
  kind: StructureKind.ExportDeclaration;
  moduleSpecifier?: string;
  namedExports?: (string | ExportSpecifierStructure)[];
  namespaceExport?: string;
  isTypeOnly?: boolean;
}

interface ExportSpecifierStructure {
  name: string;
  alias?: string;
  isTypeOnly?: boolean;
}

Variable and Type Structures

interface VariableStatementStructure extends Structure, JSDocableNodeStructure {
  kind: StructureKind.VariableStatement;
  declarationKind: VariableDeclarationKind;
  declarations: VariableDeclarationStructure[];
  isExported?: boolean;
  isDefaultExport?: boolean;
}

interface VariableDeclarationStructure {
  name: string;
  type?: string;
  initializer?: string | WriterFunction;
}

interface TypeAliasDeclarationStructure extends Structure, JSDocableNodeStructure {
  kind: StructureKind.TypeAlias;
  name: string;
  type: string;
  typeParameters?: TypeParameterDeclarationStructure[];
  isExported?: boolean;
  isDefaultExport?: boolean;
}

interface EnumDeclarationStructure extends Structure, JSDocableNodeStructure {
  kind: StructureKind.Enum;
  name: string;
  members: EnumMemberStructure[];
  isConst?: boolean;
  isExported?: boolean;
  isDefaultExport?: boolean;
}

interface EnumMemberStructure extends Structure, JSDocableNodeStructure {
  name: string;
  value?: string | number;
}

Code Block Writer

Utility for generating formatted code with proper indentation and structure.

class CodeBlockWriter {
  /** Write text */
  write(text: string): this;
  
  /** Write a line of text */
  writeLine(text?: string): this;
  
  /** Write a new line */
  newLine(): this;
  
  /** Write spaces for current indentation level */
  indent(): this;
  
  /** Increase indentation level */
  indentBlock(): this;
  
  /** Write text within a block with increased indentation */
  inlineBlock(block: () => void): this;
  
  /** Write a code block with braces and proper indentation */
  block(block?: () => void): this;
  
  /** Conditionally write text */
  conditionalWrite(condition: boolean, text: string): this;
  
  /** Get the current indentation level */
  getIndentationLevel(): number;
  
  /** Set the indentation level */
  setIndentationLevel(indentationLevel: number): this;
  
  /** Get the generated string */
  toString(): string;
}

type WriterFunction = (writer: CodeBlockWriter) => void;

Writers Utility Class

Static utility class providing common writer functions for code generation.

class Writers {
  /** Create a writer function for object properties */
  static object(obj: { [key: string]: string | WriterFunction }): WriterFunction;
  
  /** Create a writer function for array elements */
  static array(elements: (string | WriterFunction)[]): WriterFunction;
  
  /** Create a writer function for union types */
  static unionType(types: string[]): WriterFunction;
  
  /** Create a writer function for intersection types */
  static intersectionType(types: string[]): WriterFunction;
  
  /** Create a writer function for conditional expressions */
  static conditionalExpression(condition: string, whenTrue: string, whenFalse: string): WriterFunction;
  
  /** Create a writer function for assertions */
  static assertion(type: string, expr: string): WriterFunction;
}

type WriterFunctionOrValue = string | WriterFunction;

Usage Examples:

import { Project, StructureKind, Scope, VariableDeclarationKind } from "ts-morph";

const project = new Project();
const sourceFile = project.createSourceFile("generated.ts", "");

// Generate a class
const classDeclaration = sourceFile.addClass({
  kind: StructureKind.Class,
  name: "UserService",
  isExported: true,
  properties: [
    {
      kind: StructureKind.Property,
      name: "users",
      type: "User[]",
      scope: Scope.Private,
      initializer: "[]",
    },
  ],
  constructors: [
    {
      kind: StructureKind.Constructor,
      parameters: [
        {
          kind: StructureKind.Parameter,
          name: "apiClient",
          type: "ApiClient",
          scope: Scope.Private,
        },
      ],
      statements: ["// Constructor implementation"],
    },
  ],
  methods: [
    {
      kind: StructureKind.Method,
      name: "getUsers",
      returnType: "Promise<User[]>",
      isAsync: true,
      statements: [
        "const response = await this.apiClient.get('/users');",
        "return response.data;",
      ],
    },
    {
      kind: StructureKind.Method,
      name: "createUser",
      parameters: [
        {
          kind: StructureKind.Parameter,
          name: "userData",
          type: "CreateUserData",
        },
      ],
      returnType: "Promise<User>",
      isAsync: true,
      statements: [
        "const response = await this.apiClient.post('/users', userData);",
        "return response.data;",
      ],
    },
  ],
});

// Generate an interface
sourceFile.addInterface({
  kind: StructureKind.Interface,
  name: "User",
  isExported: true,
  properties: [
    {
      kind: StructureKind.PropertySignature,
      name: "id",
      type: "string",
    },
    {
      kind: StructureKind.PropertySignature,
      name: "name",
      type: "string",
    },
    {
      kind: StructureKind.PropertySignature,
      name: "email",
      type: "string",
    },
    {
      kind: StructureKind.PropertySignature,
      name: "age",
      type: "number",
      hasQuestionToken: true,
    },
  ],
});

// Generate a type alias
sourceFile.addTypeAlias({
  kind: StructureKind.TypeAlias,
  name: "CreateUserData",
  type: "Omit<User, 'id'>",
  isExported: true,
});

// Generate imports
sourceFile.addImportDeclaration({
  kind: StructureKind.ImportDeclaration,
  moduleSpecifier: "./api-client",
  namedImports: ["ApiClient"],
});

// Generate an enum
sourceFile.addEnum({
  kind: StructureKind.Enum,
  name: "UserRole",
  isExported: true,
  members: [
    { name: "Admin", value: "'admin'" },
    { name: "User", value: "'user'" },
    { name: "Guest", value: "'guest'" },
  ],
});

// Generate variables
sourceFile.addVariableStatement({
  kind: StructureKind.VariableStatement,
  declarationKind: VariableDeclarationKind.Const,
  isExported: true,
  declarations: [
    {
      name: "DEFAULT_USER_ROLE",
      type: "UserRole",
      initializer: "UserRole.User",
    },
  ],
});

console.log(sourceFile.getFullText());

Advanced Code Generation with Writers:

import { Project, Writers } from "ts-morph";

const project = new Project();
const sourceFile = project.createSourceFile("complex.ts", "");

// Using writer functions for complex code generation
sourceFile.addFunction({
  name: "createValidator",
  returnType: "ValidationFunction",
  isExported: true,
  parameters: [
    {
      name: "schema",
      type: "ValidationSchema",
    },
  ],
  statements: [
    (writer) => {
      writer.writeLine("return (data: any) => {");
      writer.indent().writeLine("const errors: string[] = [];");
      writer.newLine();
      writer.writeLine("// Validation logic here");
      writer.newLine();
      writer.writeLine("return {");
      writer.indent().writeLine("isValid: errors.length === 0,");
      writer.writeLine("errors");
      writer.outdent().writeLine("};");
      writer.outdent().writeLine("};");
    },
  ],
});

// Using Writers utility methods
sourceFile.addTypeAlias({
  name: "ComplexType",
  type: Writers.unionType([
    "string",
    "number",
    Writers.object({
      name: "string",
      age: "number",
    }).toString(),
  ]).toString(),
  isExported: true,
});

Install with Tessl CLI

npx tessl i tessl/npm-ts-morph

docs

ast-nodes.md

code-generation.md

file-system.md

index.md

project-management.md

type-system.md

tile.json