-
Notifications
You must be signed in to change notification settings - Fork 107
Open
Labels
bugSomething isn't workingSomething 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:
- Tree node structure and traversal
- Value computation and caching
- Formula text generation
- Serialization/deserialization
- 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
- Create new module files without changing BasicBody
- Extract logic method by method with tests
- Update BasicBody to delegate to new classes
- Ensure 100% backward compatibility
- Deprecate direct method usage (optional)
- 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 worksMetadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working