Skip to content

feat: optional @effect/language-service integration for type-based diagnostics #38

@aridyckovsky

Description

@aridyckovsky

Summary

Add optional integration with @effect/language-service to provide type-based diagnostics alongside our existing regex-based pattern detection.

Context

Currently, effect-migrate uses fast regex patterns to detect legacy code (async/await, Promise, etc.). The Effect team's @effect/language-service provides more accurate type-based diagnostics (floating Effects, missing error types) using TypeScript's type checker.

Research findings:

  • Language-service can run programmatically via createProjectService (not just VS Code)
  • Provides 36+ diagnostic rules with structured output (ts.Diagnostic[])
  • Uses lightweight Nano runtime (Effect-like, but synchronous)
  • CLI command proves standalone usage: diagnostics.ts

Key distinction:

  • effect-migrate: Pre-migration detection ("what to migrate")
  • language-service: Post-migration correctness ("using Effect correctly")
  • Together: Comprehensive guidance

Proposed Design

Two-tier detection system:

  1. Fast regex patterns (default): Detect legacy patterns
  2. Type-based checks (opt-in): Deep semantic analysis

Architecture decisions:

  • Optional: Default disabled, requires typeChecks.enabled: true
  • Lazy load: Dynamic import only when enabled
  • Merged output: Results use ls/ prefix (e.g., ls/floatingEffect)
  • Dedupe: preferTypeOverPattern removes regex duplicates
  • Minimal deps: Make language-service optional peer dependency

Configuration schema:

// In effect-migrate.config.ts
export default {
  typeChecks: {
    enabled: true,  // Opt-in
    tsconfig: "./tsconfig.json",  // Auto-detect if omitted
    diagnostics: ["floatingEffect", "missingEffectError"],
    severity: { floatingEffect: "error", missingEffectError: "warning" },
    preferTypeOverPattern: true  // Dedupe conflicts
  }
}

Example output:

$ effect-migrate audit --amp-out .amp/effect-migrate
✓ Found 15 async/await patterns (regex)
✓ Found 3 floating Effects (type-based)
✓ Generated .amp/effect-migrate/index.json

Implementation Tasks

  • Add TypeChecksSchema to packages/core/src/schema/Config.ts
  • Make @effect/language-service and typescript optional peer deps in CLI
  • Create packages/cli/src/typechecks/collector.ts with dynamic import
  • Wire type-check results into audit command (merge with ls/ prefix)
  • Add deduplication logic (preferTypeOverPattern)
  • Update README and config documentation
  • Add tests with real diagnostics
  • Update AGENTS.md with integration notes

Benefits

  1. Better migration guidance: Combine syntax patterns + semantic analysis
  2. Incremental adoption: Start with patterns, add type checks later
  3. Amp-friendly: Unified results in .amp/effect-migrate/audit.json
  4. Performance: Opt-in keeps default fast path
  5. Future-proof: Leverage Effect team's diagnostic evolution

References

Out of Scope (for now)

  • Multi-tsconfig/monorepo support (simple path: one tsconfig)
  • Watch mode / incremental caching
  • Automatic code fix application (diagnostics include fixes, but won't apply them yet)
  • Promoting to first-class Rule in RuleRunner (simpler to keep separate initially)

Risks & Mitigations

Risk: Heavy TypeScript compiler startup cost
Mitigation: Opt-in, lazy import, single project service per run

Risk: Version mismatches (TS / language-service)
Mitigation: Optional peers with runtime validation + clear error messages

Risk: Duplicate/noisy findings
Mitigation: ls/ prefix, preferTypeOverPattern dedupe, severity overrides

Risk: Monorepo complexity
Mitigation: Document single-tsconfig limitation, allow explicit path

Metadata

Metadata

Assignees

No one assigned

    Labels

    amp:threadsThread URL tracking and threads.json managementeffect-tsEffect-TS patterns and usagepkg:cliIssues related to @effect-migrate/cli packagepkg:coreIssues related to @effect-migrate/core packagetype:featureNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions