Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Refactoring: Split BasicBody.ts into focused modules #10

Open
Labels
bugSomething isn't working

Description

BasicBody.ts at 1,774 lines is the second largest file in the codebase. It handles multiple responsibilities that should be separated:

  1. Tree node structure and traversal
  2. Value computation and caching
  3. Formula text generation
  4. Serialization/deserialization
  5. Event handling for changes

This violates the Single Responsibility Principle and makes the code difficult to maintain.

Current Class Structure

// BasicBody.ts - 1,774 lines
class BasicBody {
 // Tree structure (~400 lines)
 parent: BasicBody | null
 children: BasicBody[]
 addChild(), removeChild(), getRoot()...
 // Value computation (~500 lines)
 getValue(), computeValue(), evaluateExpression()...
 // Text generation (~300 lines)
 getTextValue(), getCharacterValue(), formatFormula()...
 // Serialization (~250 lines)
 toJSON(), fromJSON(), clone()...
 // Event handling (~150 lines)
 onChange(), notifyParent()...
 // Utility methods (~174 lines)
 // ... various helpers
}

Proposed Architecture

Option A: Composition Pattern (Recommended)

src/data/models/
├── basic-body/
│ ├── index.ts - Re-exports for backward compatibility
│ ├── BasicBody.ts (~300 lines) - Core class with composition
│ ├── TreeOperations.ts (~200 lines) - Tree traversal mixin
│ ├── ValueComputation.ts (~250 lines) - Calculation logic
│ ├── TextGenerator.ts (~200 lines) - Formula text formatting
│ ├── Serializer.ts (~150 lines) - JSON serialization
│ └── types.ts - Shared interfaces

Option B: Inheritance Hierarchy

src/data/models/
├── AbstractNode.ts - Base tree node
├── ComputedNode.ts - Adds computation (extends AbstractNode)
├── BasicBody.ts - Full implementation (extends ComputedNode)
└── types.ts

Implementation: Option A Details

TreeOperations.ts

export class TreeOperations<T extends TreeNode> {
 getRoot(node: T): T
 getDepth(node: T): number
 traverse(node: T, callback: (n: T) => void): void
 findByPredicate(node: T, predicate: (n: T) => boolean): T | null
 getPath(node: T): T[]
 isAncestorOf(node: T, potential: T): boolean
}

ValueComputation.ts

export class ValueComputation {
 private cache: Map<string, CachedValue>
 compute(node: BasicBody, context: EvaluationContext): number
 invalidateCache(nodeId: string): void
 getCacheStats(): CacheStatistics
}

TextGenerator.ts

export class TextGenerator {
 generateText(node: BasicBody, format: TextFormat): string
 generateCharacterRepresentation(node: BasicBody): string
 formatWithPrecedence(node: BasicBody): string
}
export enum TextFormat {
 PLAIN = 'plain',
 LATEX = 'latex',
 ASCII = 'ascii'
}

Serializer.ts

export class BasicBodySerializer {
 serialize(node: BasicBody): SerializedBasicBody
 deserialize(data: SerializedBasicBody): BasicBody
 clone(node: BasicBody, deep?: boolean): BasicBody
}

Updated BasicBody.ts

import { TreeOperations } from './TreeOperations'
import { ValueComputation } from './ValueComputation'
import { TextGenerator } from './TextGenerator'
import { BasicBodySerializer } from './Serializer'
export class BasicBody {
 private static treeOps = new TreeOperations()
 private static computation = new ValueComputation()
 private static textGen = new TextGenerator()
 private static serializer = new BasicBodySerializer()
 // Delegate to specialized classes
 getRoot() { return BasicBody.treeOps.getRoot(this) }
 getValue() { return BasicBody.computation.compute(this, this.context) }
 getTextValue() { return BasicBody.textGen.generateText(this, TextFormat.PLAIN) }
 toJSON() { return BasicBody.serializer.serialize(this) }
}

Migration Strategy

  1. Create new module files without changing BasicBody
  2. Extract logic method by method with tests
  3. Update BasicBody to delegate to new classes
  4. Ensure 100% backward compatibility
  5. Deprecate direct method usage (optional)
  6. Update documentation

Backward Compatibility

The public API of BasicBody remains unchanged:

const node = new BasicBody()
node.addChild(childNode) // Still works
node.getValue() // Still works
node.getTextValue() // Still works

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

        AltStyle によって変換されたページ (->オリジナル) /