Skip to content

Latest commit

 

History

History
753 lines (578 loc) · 27.4 KB

File metadata and controls

753 lines (578 loc) · 27.4 KB

TaskPaper macOS Application - Architecture Analysis

Analysis Date: November 2025
Project: TaskPaper (Shared Source)
License: Proprietary with shared source for license owners
Main Branch: main


Executive Summary

TaskPaper is a sophisticated macOS outlining application with a unique hybrid architecture combining JavaScript for business logic with Swift/AppKit for UI presentation. Developed from 2007-2018 with maintenance continuing for macOS updates, the codebase represents a mature, well-polished application built on pre-modern macOS technologies.

Key Architectural Characteristics:

  • Hybrid JavaScript/Swift Architecture: JavaScript (via JavaScriptCore) handles the model layer while Swift/AppKit manages UI
  • Pure AppKit Implementation: No SwiftUI or Combine usage; built on NSTextView and related text system classes
  • Custom Text Engine: Deeply customized NSTextStorage/NSLayoutManager for outline rendering
  • LESS-based Styling: Dynamic stylesheet system using LESS CSS preprocessor
  • Multi-target Build: Supports Direct, App Store, and Setapp distribution channels

Technology Snapshot:

  • Swift 5.0
  • macOS 11.0+ deployment target
  • AppKit (no SwiftUI)
  • JavaScriptCore bridge
  • Carthage dependency management

1. Project Structure & Organization

1.1 Directory Hierarchy

TaskPaper/
├── BirchOutline/                    # Model layer (JavaScript + Swift wrapper)
│   ├── birch-outline.js/           # JavaScript outline model, query language, undo
│   └── BirchOutline.swift/         # Swift/JavaScriptCore bridge
├── BirchEditor/                     # View model & view layer
│   ├── birch-editor.js/            # JavaScript editor state, selection, styling
│   └── BirchEditor.swift/          # AppKit-based editor UI (~10,900 LOC)
├── TaskPaper/                       # TaskPaper-specific customizations (~300 LOC)
│   ├── TaskPaperAppDelegate.swift
│   ├── TaskPaperDocument.swift
│   ├── base-stylesheet.less        # Default styling
│   └── Resources/
├── TaskPaperTests/                  # Test suite
├── Carthage/                        # External dependencies
└── TaskPaper.xcodeproj             # Main Xcode project

File References:

  • Main project: TaskPaper.xcodeproj/project.pbxproj
  • Build configuration: Lines showing MACOSX_DEPLOYMENT_TARGET = 11.0/11.5, SWIFT_VERSION = 5.0

1.2 Module Dependencies

The architecture follows a clear layered dependency hierarchy:

TaskPaper (Application Layer)
    ↓
BirchEditor.swift (View + ViewModel Layer)
    ↓
BirchOutline.swift (Model Bridge)
    ↓
birch-editor.js ← birch-outline.js (JavaScript Core)

Key Design Intent (from README.md):

"TaskPaper specific customization to BirchEditor.swift. The intention was that there might be other apps that build off BirchEditor.swift."

This demonstrates a framework-oriented design where BirchEditor.swift is intended as reusable infrastructure.

1.3 Build Configuration

Dependencies (Cartfile):

github "sparkle-project/Sparkle" ~> 1.2
github "PaddleHQ/Mac-Framework-V4"

Build Targets:

  1. TaskPaper-Direct: Standalone with Paddle licensing and Sparkle updates
  2. TaskPaper-AppStore: Mac App Store distribution
  3. TaskPaper-Setapp: Setapp subscription platform

JavaScript Build Process (from README.md):

  • Requires Node.js v11.15.0 (legacy requirement)
  • Uses webpack for bundling
  • npm link connects birch-outline and birch-editor during development
  • Compiled JavaScript bundled into app at build time

2. Core Architecture & Design Patterns

2.1 Architectural Pattern: Hybrid JavaScript/Swift MVC

TaskPaper employs a unique hybrid architecture where:

JavaScript Layer (Model + ViewModel):

  • birch-outline.js: Core outline data structure, attributed strings, query language, undo management
  • birch-editor.js: Editor state, selection tracking, visible line calculations, style computations

Swift Layer (View + Controller):

  • BirchOutline.swift: JavaScriptCore bridge providing Swift-friendly API
  • BirchEditor.swift: AppKit UI implementation with custom text system
  • TaskPaper: Application-specific behavior

Bridge Mechanism:

// BirchOutline/BirchOutline.swift/Common/Sources/BirchOutline.swift
open class BirchOutline {
    static var _sharedContext: BirchScriptContext!
    
    public static var sharedContext: BirchScriptContext {
        // Singleton JSContext for JavaScript execution
    }
}

2.2 Data Flow & State Management

Document-Based Architecture:

// TaskPaper/TaskPaperDocument.swift
class TaskPaperDocument: OutlineDocument {
    override var outlineRuntimeType: String {
        return "com.taskpaper.text"
    }
}

State Synchronization: The architecture maintains bidirectional sync between JavaScript model and NSTextStorage:

// BirchEditor/BirchEditor.swift/BirchEditor/OutlineEditorTextStorage.swift:70-85
override open func replaceCharacters(in range: NSRange, with str: String) {
    let updatingFromJS = isUpdatingFromJS
    if !updatingFromJS {
        // Update JavaScript model
        _ = outlineEditor?.jsOutlineEditor.invokeMethod(
            "replaceRangeWithString", 
            withArguments: [range.location, range.length, str, true]
        )
    }
}

This creates a carefully coordinated two-way data flow to prevent infinite update loops.

2.3 Text System Architecture

TaskPaper uses a deeply customized NSTextView text system:

Core Components:

  1. OutlineEditorTextStorage (BirchEditor/BirchEditor.swift/BirchEditor/OutlineEditorTextStorage.swift)

    • Custom NSTextStorage subclass
    • Syncs with JavaScript item buffer
    • Manages outline-specific attributes
  2. OutlineEditorLayoutManager (BirchEditor/BirchEditor.swift/BirchEditor/OutlineEditorLayoutManager.swift)

    • Custom layout for outline items
    • Handle (disclosure triangle) positioning
    • Guide line rendering
  3. OutlineEditorTextContainer (BirchEditor/BirchEditor.swift/BirchEditor/OutlineEditorTextContainer.swift)

    • Custom text container for outline-specific layout
  4. OutlineEditorView (BirchEditor/BirchEditor.swift/BirchEditor/OutlineEditorView.swift)

    • Custom NSTextView subclass
    • Handles outline-specific editing behaviors

Text System Setup (OutlineEditorViewController.swift:42-70):

open var outlineEditor: OutlineEditorType? {
    didSet {
        if let textStorage = outlineEditor?.textStorage {
            let textContainer = OutlineEditorTextContainer()
            let layoutManager = OutlineEditorLayoutManager(outlineEditor: outlineEditor!)
            
            textContainer.replaceLayoutManager(layoutManager)
            layoutManager.replaceTextStorage(textStorage)
            outlineEditorView.replaceTextContainer(textContainer)
        }
    }
}

2.4 Styling System

LESS-Based Dynamic Styling:

TaskPaper uses LESS CSS for theme definitions, compiled at runtime in JavaScript:

Base Stylesheet (TaskPaper/base-stylesheet.less):

@appearance: $APPEARANCE; // dark or light
@user-font-size: $USER_FONT_SIZE;
@tint-color: $CONTROL_ACCENT_COLOR;

editor {
    color: @text-color;
    font-size: @user-font-size;
    background-color: @background-color;
}

Runtime Compilation (BirchEditor/BirchEditor.swift/BirchEditor/StyleSheet.swift:65-75):

  • Processes LESS with runtime variable substitution
  • Supports light/dark appearance modes (macOS 10.14+)
  • User-customizable via .less files in Application Support

Computed Styles: Compiled styles are converted to native Cocoa attributes via ComputedStyle class.


3. UI Implementation

3.1 Technology: Pure AppKit

No SwiftUI Usage: Grep analysis confirms zero SwiftUI imports or property wrappers (@State, @ObservedObject, etc.)

UI Framework Breakdown:

  • Primary: AppKit (NSViewController, NSTextView, NSSplitView)
  • Storyboards: 13 .storyboard/.xib files for interface layout
  • Custom Views: Extensive NSView/NSControl subclasses

3.2 View Controller Hierarchy

Main View Controllers:

  1. OutlineEditorWindowController (BirchEditor/BirchEditor.swift/BirchEditor/OutlineEditorWindowController.swift)

    • Root window controller
    • Manages document window lifecycle
  2. OutlineEditorSplitViewController (BirchEditor/BirchEditor.swift/BirchEditor/OutlineEditorSplitViewController.swift)

    • Three-pane split view (sidebar, editor, searchbar)
  3. OutlineEditorViewController (BirchEditor/BirchEditor.swift/BirchEditor/OutlineEditorViewController.swift)

    • Main editor view controller
    • ~100 lines core implementation
    • Manages OutlineEditorView (NSTextView subclass)
  4. OutlineSidebarViewController (BirchEditor/BirchEditor.swift/BirchEditor/OutlineSidebarViewController.swift)

    • Sidebar for searches and tags
    • NSOutlineView-based
  5. SearchBarViewController (BirchEditor/BirchEditor.swift/BirchEditor/SearchBarViewController.swift)

    • Search/filter UI

Grep Results: 9 NSViewController subclasses identified in BirchEditor layer

3.3 Custom UI Components

Palette Windows:

  • ChoicePaletteViewController: Command palette-style picker
  • DatePickerViewController: Date tag insertion UI
  • PaletteWindow: Custom NSPanel subclass for floating palettes

Custom Views:

  • OutlineEditorView: Custom NSTextView with outline-specific behavior
  • OutlineSidebarView: Outline view for searches/tags
  • SearchBarSearchField: Custom NSSearchField

3.4 AppKit Customization Techniques

Method Swizzling (10 files use Objective-C runtime manipulation):

// BirchEditor/BirchEditor.swift/BirchEditor/JGMethodSwizzler.m
// Used to patch NSTextView, NSWindow, NSTextStorage behaviors

Performance Hacks:

  • NSTextView-AccessibilityPerformanceHacks.m: Disables expensive accessibility features
  • NSTextStorage-Performance.m: Optimizes text storage operations
  • NSMutableAttributedString-Performance.m: Attribute manipulation optimizations

This is a red flag for modernization: Method swizzling is fragile and may break with macOS updates.


4. File Format & Persistence

4.1 TaskPaper File Format

Format: Plain text (.taskpaper extension)

Example (TaskPaper/Welcome.txt):

Welcome:
	- TaskPaper knows about projects, tasks, notes, and tags.
To Create Items:
	- To create a task, type a dash followed by a space.
	- To create a project, type a line ending with a colon.
	- To create a tag, type '@' followed by the tag's name.

Grammar:

  • Projects: Lines ending with :
  • Tasks: Lines starting with -
  • Tags: @tagname or @tagname(value)
  • Notes: Plain text lines
  • Indentation: Tab-based hierarchy

4.2 Serialization & Parsing

JavaScript Parser (BirchOutline/birch-outline.js/src/item-path-parser.js):

  • PEG.js-based parser for query language
  • Item path expressions for filtering/searching

Document Loading (BirchEditor/BirchEditor.swift/BirchEditor/OutlineDocument.swift:30-45):

override open func read(from data: Data, ofType typeName: String) throws {
    // Deserialize plain text into outline model
    if let string = String(data: data, encoding: .utf8) {
        outline.reloadSerialization(string)
    }
}

Autosave: Uses NSDocument's autosavesInPlace (enabled)

4.3 Undo Management

Undo handled in JavaScript layer:

  • birch-outline.js manages undo stack
  • Synced to Cocoa undo manager via bridge
  • Change tracking for autosave triggers

5. Comparison with Modern macOS Development

5.1 Technology Gap Analysis

Aspect TaskPaper (Current) Modern Practice (2025) Gap
UI Framework AppKit (NSViewController) SwiftUI 4+ with AppKit interop Major
Concurrency GCD, callbacks Swift Concurrency (async/await, actors) Significant
Reactive Custom KVO, notifications Combine, Swift Observation Significant
Language Swift 5.0 Swift 6 (strict concurrency) Moderate
Deployment macOS 11.0 macOS 13.0+ typical Moderate
Dependencies Carthage Swift Package Manager Minor
Text Editing Custom NSTextView TextKit 2 (macOS 12+) Moderate

5.2 Outdated Patterns

1. JavaScript Bridge Architecture

  • Current: JavaScriptCore bridge for model layer
  • Modern: Pure Swift with Codable, structured concurrency
  • Issue: Performance overhead, debugging complexity, two language maintenance burden

2. Method Swizzling

  • Current: 10+ files use runtime method replacement
  • Modern: Subclassing, delegation, or SwiftUI composition
  • Issue: Fragile, breaks with OS updates, hard to debug

3. Callbacks & Delegates

// BirchEditor/BirchEditor.swift/BirchEditor/delay.swift
// Uses GCD-based delayed callbacks
func delay(_ delay: Double, closure: @escaping () -> Void) {
    DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
        closure()
    }
}
  • Modern: Task.sleep() with async/await

4. No Async/Await

  • Limited usage found (only in RemindersStore.swift for EventKit)
  • Most async operations use completion handlers

5. No Combine or Swift Observation

  • Custom observer pattern implementations
  • Manual KVO setup

6. Old Build System

  • Carthage (deprecated by many projects)
  • Legacy Node.js v11.15.0 requirement
  • Modern: Swift Package Manager, modern Node LTS

5.3 Modern Features Not Utilized

Available but Unused:

  1. TextKit 2 (macOS 12+): More efficient text layout
  2. Swift Concurrency: async/await, actors, @MainActor
  3. Swift 6: Data-race safety, strict concurrency checking
  4. NSTextLayoutManager: Modern replacement for NSLayoutManager
  5. Observation framework: Swift 5.9+ property observation
  6. Swift Package Manager: Modern dependency management

6. Code Quality Assessment

6.1 Codebase Metrics

Size:

  • BirchEditor.swift: ~10,900 lines of Swift
  • TaskPaper layer: ~300 lines of Swift
  • JavaScript: Substantial (birch-outline.js + birch-editor.js)

Code Organization: ★★★★☆ (4/5)

  • Clear separation of concerns (Model/ViewModel/View)
  • Well-structured file organization
  • Logical grouping of related functionality

6.2 Maintainability

Strengths:

  1. Modular Architecture: Clean separation between BirchOutline, BirchEditor, TaskPaper
  2. Extensive Documentation: README explains build process and architecture
  3. Consistent Naming: Swift naming conventions followed
  4. Extension Pattern: Features logically separated (e.g., OutlineEditorViewController-Actions.swift)

Weaknesses:

  1. Method Swizzling: Makes behavior unpredictable and fragile
  2. JavaScript Bridge: Adds complexity, debugging difficulty
  3. Legacy Dependencies: Old Node.js, Carthage instead of SPM
  4. Limited Comments: Code documentation sparse in implementation files
  5. Tight Coupling: Text system components heavily interdependent

Maintainability Score: ★★★☆☆ (3/5)

  • Well-organized but complex architecture
  • Fragile AppKit customizations
  • Two-language maintenance burden

6.3 Testability

Test Coverage: ★★☆☆☆ (2/5)

Existing Tests:

  • TaskPaperTests/TaskPaperTests.swift (minimal)
  • BirchEditorTests/ (basic outline editor tests)
  • BirchOutlineTests/ (JavaScript model tests)

Testability Issues:

  1. Heavy use of singletons (BirchOutline.sharedContext)
  2. Tight coupling to AppKit (hard to unit test)
  3. JavaScript bridge complicates mocking
  4. Limited dependency injection
  5. No apparent protocol-oriented design for testing

Improvement Needed: Add comprehensive unit tests, integration tests, and UI tests

6.4 Performance Characteristics

Optimizations Present:

  1. Performance-specific Objective-C categories for NSTextStorage, NSTextView
  2. Custom accessibility hacks to avoid expensive operations
  3. Debouncer class for throttling updates
  4. Incremental text storage updates

Potential Issues:

  1. JavaScript bridge overhead for every model operation
  2. Two-way sync between JavaScript and NSTextStorage could cause performance bottlenecks
  3. Method swizzling may have unexpected performance impacts

6.5 Adherence to Apple HIG

Human Interface Guidelines Compliance: ★★★★☆ (4/5)

Strengths:

  1. Standard Document Model: Uses NSDocument correctly
  2. Native Controls: Uses standard AppKit controls
  3. Keyboard Shortcuts: Extensive keyboard support
  4. Dark Mode: Supports macOS dark mode (10.14+)
  5. Accessibility: Maintains accessibility (though with performance hacks)

Areas for Improvement:

  1. Window Tabbing: Uses swizzling for tab bar customization (NSWindowTabbedBase.m)
  2. Touch Bar: No evidence of Touch Bar support
  3. Continuity: No apparent Handoff or iCloud sync features
  4. Localization: Limited localization (es.lproj present but minimal)

7. Modernization Recommendations

7.1 Priority 1: High-Impact, Lower Risk

1. Migrate to Swift Package Manager

  • Why: Carthage is deprecated, SPM is Apple's standard
  • Impact: Easier dependency management, better Xcode integration
  • Risk: Low (straightforward migration)
  • Files: Cartfile → Package.swift
  • Effort: 1-2 days

2. Update to Swift 6 (Non-Strict Mode)

  • Why: Access to newer language features, preparation for concurrency safety
  • Impact: Better type safety, modern syntax
  • Risk: Low (backward compatible)
  • Files: Project build settings
  • Effort: 2-3 days + testing

3. Adopt Async/Await for Asynchronous Operations

  • Why: Clearer async code, better error handling
  • Impact: More readable, less callback hell
  • Risk: Medium (requires iOS 15+/macOS 12+)
  • Files: delay.swift, RemindersStore.swift, networking code
  • Effort: 1-2 weeks

4. Modernize Node.js Build Process

  • Why: Node.js v11.15.0 is ancient and unsupported
  • Impact: Security, modern tooling
  • Risk: Low (update package.json)
  • Files: BirchOutline/birch-outline.js, BirchEditor/birch-editor.js
  • Effort: 2-3 days

7.2 Priority 2: Medium-Impact, Medium Risk

5. Eliminate Method Swizzling

  • Why: Fragile, breaks with OS updates
  • Impact: More stable, future-proof
  • Risk: High (requires architectural changes)
  • Files: JGMethodSwizzler.m, NSWindowTabbedBase.m, NSTextView-*.m
  • Approach: Replace with subclassing, composition, or accept default behaviors
  • Effort: 3-4 weeks

6. Introduce Protocol-Oriented Design for Testability

  • Why: Enable unit testing, reduce coupling
  • Impact: Better test coverage, more maintainable
  • Risk: Medium (refactoring required)
  • Approach: Extract protocols from key classes
  • Effort: 2-3 weeks

7. Migrate to TextKit 2

  • Why: Better performance, modern text handling
  • Impact: Faster rendering, less custom code
  • Risk: High (requires macOS 12+, significant rewrite)
  • Files: OutlineEditorTextStorage.swift, OutlineEditorLayoutManager.swift
  • Effort: 4-6 weeks

7.3 Priority 3: High-Impact, High Risk

8. Gradual SwiftUI Adoption

  • Why: Modern UI framework, declarative syntax
  • Impact: Easier UI development, better platform integration
  • Risk: Very High (major architectural change)
  • Approach: Start with preferences, palettes; keep editor in AppKit initially
  • Files: PreferencesWindowController.swift, ChoicePaletteViewController.swift
  • Effort: 8-12 weeks (incremental)

9. Replace JavaScript Bridge with Pure Swift

  • Why: Eliminate two-language complexity, better performance
  • Impact: Simplified architecture, easier debugging
  • Risk: Very High (complete rewrite of model layer)
  • Approach: Rewrite birch-outline.js logic in Swift
  • Files: Entire BirchOutline layer
  • Effort: 12-16 weeks (major project)

10. Adopt Combine for Reactive Bindings

  • Why: Modern reactive programming, SwiftUI integration
  • Impact: Cleaner data flow, less manual observation
  • Risk: Medium (requires iOS 13+/macOS 10.15+)
  • Files: Observer patterns, KVO usage throughout
  • Effort: 4-6 weeks

7.4 Incremental Modernization Roadmap

Phase 1 (1-2 months): Foundation

  • Migrate to SPM
  • Update to Swift 6 (compatibility mode)
  • Modernize Node.js toolchain
  • Add comprehensive test suite

Phase 2 (2-3 months): Async & Safety

  • Adopt async/await throughout
  • Introduce protocol-oriented design
  • Eliminate critical method swizzling

Phase 3 (3-6 months): UI Modernization

  • Migrate preferences to SwiftUI
  • Adopt TextKit 2 for text rendering
  • Add Touch Bar support

Phase 4 (6-12 months): Deep Architecture

  • Consider JavaScript bridge alternatives
  • Evaluate full SwiftUI editor (long-term)
  • Implement Combine where beneficial

8. Pull Request Opportunities

Based on the shared-source license and contribution guidelines from README.md:

"Do submit pull requests if you would like your changes potentially included in the official TaskPaper release."

8.1 Low-Hanging Fruit PRs

PR #1: Migrate to Swift Package Manager

  • Description: Replace Carthage with SPM for dependency management
  • Files: Add Package.swift, remove Cartfile, update project settings
  • Benefits: Modern dependency management, better Xcode integration
  • Risk: Low

PR #2: Update Node.js Requirement

  • Description: Modernize JavaScript build to use Node.js LTS (v20+)
  • Files: package.json in birch-outline.js and birch-editor.js, README.md
  • Benefits: Security updates, modern tooling
  • Risk: Low

PR #3: Add Swift Concurrency to RemindersStore

  • Description: Fully convert RemindersStore.swift to async/await
  • Files: BirchEditor/BirchEditor.swift/BirchEditor/RemindersStore.swift
  • Benefits: Cleaner async code, better error handling
  • Risk: Low (isolated component)

PR #4: Comprehensive Test Suite

  • Description: Add unit tests for core outline operations
  • Files: New test files in TaskPaperTests/
  • Benefits: Better reliability, regression prevention
  • Risk: Very Low

8.2 Medium-Complexity PRs

PR #5: Extract Protocols for Core Types

  • Description: Introduce protocols for OutlineEditor, StyleSheet, OutlineDocument
  • Files: New protocol files, refactor concrete types
  • Benefits: Better testability, reduced coupling
  • Risk: Medium

PR #6: Replace delay() with Task.sleep()

  • Description: Use Swift concurrency for delayed operations
  • Files: delay.swift, call sites throughout codebase
  • Benefits: Modern concurrency patterns
  • Risk: Medium (requires async context)

PR #7: Localization Infrastructure

  • Description: Improve localization support, add more languages
  • Files: .strings files, localization infrastructure
  • Benefits: Broader user base
  • Risk: Medium

8.3 Advanced PRs (Discuss First)

PR #8: Eliminate NSTextView Swizzling

  • Description: Remove method swizzling from NSTextView customizations
  • Files: NSTextView-AccessibilityPerformanceHacks.m, JGMethodSwizzler.m
  • Benefits: More stable, future-proof
  • Risk: High (may change behavior)
  • Note: Discuss approach with maintainer first

PR #9: TextKit 2 Migration (Proof of Concept)

  • Description: Experimental TextKit 2 implementation
  • Files: New NSTextLayoutManager-based classes
  • Benefits: Modern text system, better performance
  • Risk: Very High
  • Note: Would require macOS 12+ minimum version bump

8.4 Contributing Guidelines

Per README.md restrictions:

  • ✅ DO modify for your own use
  • ❌ DO NOT change or disable licensing code (check before submitting PRs)
  • ❌ DO NOT redistribute binaries without permission
  • ✅ DO submit pull requests for potential inclusion

Before Submitting:

  1. Contact jesse@hogbaysoftware.com for non-standard contributions
  2. Ensure no licensing code is affected
  3. Test thoroughly across supported macOS versions
  4. Include tests for new functionality
  5. Follow existing code style and conventions

9. Conclusion

9.1 Architectural Strengths

  1. Clean Separation of Concerns: Model/ViewModel/View clearly delineated
  2. Reusable Framework Design: BirchEditor.swift designed for multiple apps
  3. Sophisticated Text System: Custom NSTextView implementation handles complex outline rendering
  4. Dynamic Styling: LESS-based theming enables user customization
  5. Well-Polished: Mature codebase with attention to detail

9.2 Key Challenges

  1. Two-Language Complexity: JavaScript + Swift maintenance burden
  2. Legacy Technologies: Swift 5.0, old Node.js, Carthage, method swizzling
  3. Limited Test Coverage: Insufficient automated testing
  4. AppKit Lock-in: No modern SwiftUI adoption
  5. Modernization Risk: Deep customizations make updates risky

9.3 Strategic Recommendations

For Individual Contributors:

  • Start with low-risk PRs (SPM migration, tests, async/await adoption)
  • Focus on improving testability and modernizing build infrastructure
  • Respect licensing code boundaries

For Long-Term Modernization:

  • Incrementally reduce JavaScript bridge dependency
  • Gradually introduce SwiftUI for new UI components
  • Plan TextKit 2 migration as multi-phase project
  • Eliminate method swizzling through careful refactoring

For Current Maintenance:

  • Keep pace with macOS releases (already doing well)
  • Update dependencies regularly
  • Improve test coverage before major refactoring
  • Document architectural decisions

9.4 Final Assessment

TaskPaper represents a well-architected mature application built on pre-modern macOS technologies. The hybrid JavaScript/Swift architecture was forward-thinking for its time but now presents maintenance challenges. The codebase would benefit significantly from incremental modernization, starting with dependency management, build tooling, and test coverage, before tackling deeper architectural changes.

Overall Code Quality: ★★★★☆ (4/5) Modernization Priority: ★★★★☆ (High) Contribution Friendliness: ★★★☆☆ (Moderate - complex architecture but clear guidelines)


Appendix: Key File References

Core Architecture Files

  • BirchOutline/BirchOutline.swift/Common/Sources/BirchOutline.swift - JavaScript bridge entry point
  • BirchEditor/BirchEditor.swift/BirchEditor/BirchEditor.swift - Main editor framework
  • TaskPaper/TaskPaperAppDelegate.swift - Application entry point
  • TaskPaper/TaskPaperDocument.swift - Document model

UI Layer

  • BirchEditor/BirchEditor.swift/BirchEditor/OutlineEditorViewController.swift - Main editor view controller
  • BirchEditor/BirchEditor.swift/BirchEditor/OutlineEditorView.swift - Custom NSTextView
  • BirchEditor/BirchEditor.swift/BirchEditor/OutlineEditorTextStorage.swift - Text storage sync

Styling

  • TaskPaper/base-stylesheet.less - Base theme definition
  • BirchEditor/BirchEditor.swift/BirchEditor/StyleSheet.swift - Style compilation

Build & Configuration

  • TaskPaper.xcodeproj/project.pbxproj - Xcode project configuration
  • Cartfile - Dependency declarations
  • BirchOutline/birch-outline.js/package.json - JavaScript model package
  • BirchEditor/birch-editor.js/package.json - JavaScript editor package

Performance Customizations

  • BirchEditor/BirchEditor.swift/BirchEditor/NSTextView-AccessibilityPerformanceHacks.m
  • BirchEditor/BirchEditor.swift/BirchEditor/NSTextStorage-Performance.m
  • BirchEditor/BirchEditor.swift/BirchEditor/JGMethodSwizzler.m

Document Version: 1.0
Author: Automated Architecture Analysis
Last Updated: November 2025