Skip to content

docs: add migration guide for creating custom presets #37

@aridyckovsky

Description

@aridyckovsky

Summary

Create comprehensive documentation for users who want to create custom migration presets for their organization or specific migration scenarios.

Motivation

With first-class preset support now available (feat: implement first-class preset support), users need guidance on:

  • When to create a custom preset vs using @effect-migrate/preset-basic
  • How to structure a preset package
  • How to write effective pattern and boundary rules
  • How to distribute presets (npm, monorepo, local)
  • Best practices for rule organization

Proposed Content

Location

Create docs/guides/creating-custom-presets.md

Outline

# Creating Custom Presets

## When to Create a Custom Preset

- Organization-specific patterns
- Framework-specific migrations (React, Express, etc.)
- Domain-specific rules (finance, healthcare)
- Private/proprietary migration patterns

## Preset Structure

### Package Setup
- package.json configuration
- TypeScript setup
- Exports and entry point

### Preset Object
```typescript
import type { Preset } from '@effect-migrate/core'

export const myPreset: Preset = {
  rules: [...],
  defaults: {
    paths: { exclude: [...] },
    report: { failOn: ['error'] }
  }
}

Writing Rules

Pattern Rules

  • When to use pattern rules
  • Regex best practices
  • Avoiding false positives

Boundary Rules

  • Architectural constraints
  • Import restrictions
  • Layer boundaries

Custom Rule Implementations

  • Using ctx.listFiles
  • Using ctx.readFile
  • Using ctx.getImportIndex

Testing Your Preset

Unit Tests

  • Testing individual rules
  • Mock context setup
  • Fixture files

Integration Tests

  • Testing with real codebases
  • CI/CD integration

Publishing

NPM Package

  • Naming conventions (@org/preset-name)
  • Versioning
  • README requirements

Monorepo Distribution

  • Workspace packages
  • Local presets

Private Presets

  • Internal npm registry
  • Git dependencies

Examples

Example 1: React Migration Preset

  • Detect class components
  • Find deprecated lifecycle methods
  • Suggest hooks patterns

Example 2: Express to Fastify Preset

  • Detect Express middleware patterns
  • Flag incompatible APIs
  • Suggest Fastify equivalents

Best Practices

  • Keep rules focused and specific
  • Provide actionable error messages
  • Link to documentation
  • Use negativePattern to reduce false positives
  • Test extensively with real code

Reference

  • @effect-migrate/preset-basic source code
  • Core API documentation
  • Rule interface reference

## Documentation Locations

1. **Main guide:** `docs/guides/creating-custom-presets.md`
2. **README update:** Add link to guide in root README.md
3. **preset-basic README:** Add "Creating Custom Presets" section
4. **AGENTS.md:** Add reference for AI agents

## Examples to Include

### Minimal Preset

```typescript
// my-preset/src/index.ts
import { makePatternRule, type Preset } from '@effect-migrate/core'

const noOldPattern = makePatternRule({
  id: 'no-old-pattern',
  files: ['**/*.ts'],
  pattern: /oldFunction\(/g,
  message: 'Use newFunction instead of oldFunction',
  severity: 'warning',
  docsUrl: 'https://docs.example.com/migration'
})

export const myPreset: Preset = {
  rules: [noOldPattern],
  defaults: {
    paths: { exclude: ['node_modules/**'] }
  }
}

React Preset Example

// preset-react/src/index.ts
import { makePatternRule, type Preset } from '@effect-migrate/core'

const noClassComponents = makePatternRule({
  id: 'no-class-components',
  files: ['**/*.tsx'],
  pattern: /class\s+\w+\s+extends\s+React\.Component/g,
  message: 'Migrate class component to function component with hooks',
  severity: 'warning',
  docsUrl: 'https://react.dev/reference/react/Component#alternatives'
})

const noComponentWillMount = makePatternRule({
  id: 'no-component-will-mount',
  files: ['**/*.tsx'],
  pattern: /componentWillMount\s*\(/g,
  message: 'componentWillMount is deprecated, use useEffect',
  severity: 'error',
  docsUrl: 'https://react.dev/reference/react/Component#componentwillmount'
})

export const reactPreset: Preset = {
  rules: [noClassComponents, noComponentWillMount],
  defaults: {
    paths: {
      exclude: ['node_modules/**', '*.test.tsx']
    }
  }
}

Acceptance Criteria

  • Guide written with examples
  • Code examples tested and verified
  • Screenshots/diagrams if helpful
  • Links to relevant API docs
  • Referenced in root README
  • Referenced in preset-basic README
  • Mentioned in AGENTS.md

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions