swagger-tools/docs/tasks/typescript-options-task.md
rimskij a4fc2df4ea feat: add TypeScript generation options to generate-types tool
Add configurable options for customizing TypeScript output:
- enumAsUnion/enumAsEnum: control enum generation style
- interfacePrefix/interfaceSuffix: naming conventions for interfaces
- indentation: 2 spaces, 4 spaces, or tab

Includes validation for mutually exclusive options and valid
TypeScript identifier prefixes/suffixes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 15:42:39 +01:00

4.7 KiB

Task: TypeScript Generation Options

  • Analysis: docs/analysis/feature-enhancements-analysis.md
  • Branch: feature/typescript-options (from dev)

Priority

NORMAL

Objective

Add configurable options to the generate-types tool for customizing TypeScript output format, including enum style, interface naming conventions, and indentation preferences.

Definition of Done

  • Code implemented per specification
  • TypeScript compilation CLEAN
  • Lint checks PASSED (no lint script in project)
  • ALL tests passing
  • Manual verification with petstore spec
  • PROOF PROVIDED (before/after output samples)

Scope

IN SCOPE

  • enumAsUnion option (default true) - generate enums as union types
  • enumAsEnum option - generate enums as TypeScript enums
  • interfacePrefix option - prefix for interface names (e.g., "I")
  • interfaceSuffix option - suffix for interface names (e.g., "Type")
  • indentation option - 2 spaces, 4 spaces, or tab
  • Validation of mutually exclusive options

OUT OF SCOPE

  • readonlyProperties option (future enhancement)
  • exportDefault option (future enhancement)
  • includeRefs option (future enhancement)
  • allOptional / allRequired options (future enhancement)

Sub-Tasks

Phase 1: Options Interface and Schema

1.1 Add TypeScriptOptions interface to types.ts

  • Details: Define interface with all option properties as optional
  • Files: src/lib/types.ts
  • Testing: TypeScript compilation

1.2 Update generate tool schema with options parameter

  • Details: Add nested options object to Zod schema
  • Files: src/tools/generate.ts
  • Testing: Parse spec with invalid options should fail

Phase 2: Enum Generation Modes

2.1 Implement enumAsEnum generation

  • Details: Convert type X = 'a' | 'b' to enum X { A = 'a', B = 'b' }
  • Files: src/tools/generate.ts
  • Testing: Generate with enumAsEnum=true

2.2 Add mutual exclusion validation

  • Details: Error if both enumAsUnion and enumAsEnum are true
  • Files: src/tools/generate.ts
  • Testing: Should reject invalid combination

Phase 3: Interface Naming

3.1 Implement prefix/suffix application

  • Details: Apply prefix/suffix to interface names during generation
  • Files: src/tools/generate.ts
  • Testing: interfacePrefix='I' produces interface IPet

3.2 Handle sanitized names with prefix/suffix

  • Details: Ensure prefix/suffix works with .NET sanitized names
  • Files: src/tools/generate.ts
  • Testing: Namespace.Type with prefix='I' produces IType

Phase 4: Indentation Options

4.1 Implement indentation configuration

  • Details: Support '2', '4', 'tab' options for generated code
  • Files: src/tools/generate.ts
  • Testing: Generate with each option, verify output

Files to Modify

  • src/lib/types.ts: Add TypeScriptOptions interface
  • src/tools/generate.ts: Update schema, implement option handling in schemaToType() and generateTypes()

Risks & Mitigations

Risk Impact Mitigation
Invalid option combinations LOW Validate at handler entry, return clear error
Breaking existing behavior LOW All options optional with current defaults
Enum PascalCase conversion edge cases MEDIUM Use robust capitalizeFirst function

Testing Strategy

  • Build: npm run build - must pass
  • Manual: Test with petstore spec using various option combinations
  • Verification commands:
    # Default (current behavior)
    echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"generate-types","arguments":{"path":"https://petstore.swagger.io/v2/swagger.json","schemas":["Pet"]}}}' | node dist/index.js
    
    # With enumAsEnum
    echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"generate-types","arguments":{"path":"https://petstore.swagger.io/v2/swagger.json","schemas":["Pet"],"options":{"enumAsEnum":true}}}}' | node dist/index.js
    
    # With prefix
    echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"generate-types","arguments":{"path":"https://petstore.swagger.io/v2/swagger.json","schemas":["Pet"],"options":{"interfacePrefix":"I"}}}}' | node dist/index.js
    

Implementation Notes

Enum to TypeScript Enum Conversion

// Input: enum values ['available', 'pending', 'sold']
// Output:
export enum PetStatus {
  Available = 'available',
  Pending = 'pending',
  Sold = 'sold'
}

Use PascalCase for enum member names:

function toPascalCase(value: string): string {
  return value.replace(/(?:^|[_-])(\w)/g, (_, c) => c.toUpperCase());
}

Indentation Implementation

const INDENT = {
  '2': '  ',
  '4': '    ',
  'tab': '\t'
};
const indent = INDENT[options.indentation ?? '2'];