3.0.0 • Published 8 months ago

@contentrain/types-generator v3.0.0

Weekly downloads
-
License
MIT
Repository
github
Last release
8 months ago

@contentrain/types-generator

A tool for automatically generating TypeScript type definitions for Contentrain CMS. This package provides type safety for your Contentrain content models.

Features

  • 🚀 Automatic type generation from model schemas
  • 🔄 Automatic relation type mapping with validation
  • 📦 Full TypeScript support with generics
  • 🎯 CLI tool with debug mode
  • 💪 Comprehensive test coverage
  • 🔍 Watch mode with debounce
  • 🛠️ Custom type transformers
  • 🔧 CI/CD integration
  • 📝 Multiple config file support
  • 🌍 Multi-language support

Installation

# Using npm
npm install -D @contentrain/types-generator

# Using yarn
yarn add -D @contentrain/types-generator

# Using pnpm
pnpm add -D @contentrain/types-generator

CLI Usage

# Basic usage
contentrain-generate

# With custom config file
contentrain-generate --config contentrain.config.js

# With custom directories
contentrain-generate --models ./models --output ./types

# Watch mode with debug output
contentrain-generate --watch --debug

# Help
contentrain-generate --help

Configuration

The generator supports multiple configuration file locations:

  • contentrain-config.json
  • .contentrain/config.json
  • .config/contentrain.json

Example configuration:

{
  // Required: Directory paths
  "modelsDir": "./models",
  "outputDir": "./types",
  "contentDir": "./content",

  // Optional: Type generation options
  "options": {
    // Relation type generation
    "generateRelationTypes": true,
    "includeBaseTypes": true,

    // Type mappings
    "typeMapping": {
      "string[]": "Array<string>",
      "number[]": "Array<number>",
      "date": "Date",
      "media": "MediaFile"
    },

    // Custom type transformers
    "transformers": {
      "date": {
        "type": "Date",
        "imports": ["import { parseISO } from 'date-fns'"],
        "transform": "parseISO"
      },
      "json": {
        "type": "Record<string, any>",
        "transform": "JSON.parse"
      }
    },

    // Output configuration
    "output": {
      "prettier": true,
      "declaration": true,
      "banner": "/* Generated by Contentrain */"
    }
  },

  // Watch mode configuration
  "watch": {
    "enabled": true,
    "debounce": 1000,
    "ignore": ["**/node_modules/**"]
  }
}

Model Schema Example

// models/posts.json
[
  {
    "fieldId": "title",
    "fieldType": "string",
    "componentId": "single-line-text",
    "validations": {
      "required-field": { "value": true }
    }
  },
  {
    "fieldId": "content",
    "fieldType": "string",
    "componentId": "rich-text"
  },
  {
    "fieldId": "author",
    "fieldType": "relation",
    "componentId": "one-to-one",
    "options": {
      "reference": {
        "form": {
          "reference": {
            "value": "authors"
          }
        }
      }
    }
  },
  {
    "fieldId": "categories",
    "fieldType": "relation",
    "componentId": "one-to-many",
    "options": {
      "reference": {
        "form": {
          "reference": {
            "value": "categories"
          }
        }
      }
    }
  }
]

Generated Types Example

// Generated contentrain.d.ts
import type { BaseContentrainType, QueryConfig } from '@contentrain/query';

export interface IPost extends BaseContentrainType {
  title: string;
  content?: string;
  author: string;
  categories: string[];
  _relations?: {
    author: IAuthor;
    categories: ICategory[];
  }
}

export interface IPostQuery extends QueryConfig<
  IPost,
  'en' | 'tr',
  {
    author: IAuthor;
    categories: ICategory;
  }
> {}

Programmatic Usage

import { ContentrainTypesGenerator } from '@contentrain/types-generator';

// Basic usage
const generator = new ContentrainTypesGenerator({
  modelsDir: './models',
  outputDir: './types',
  contentDir: './content'
});

// Generate types
generator.generate();

// With error handling
try {
  const generator = new ContentrainTypesGenerator({
    modelsDir: './models',
    outputDir: './types',
    contentDir: './content'
  });

  generator.generate();
} catch (error) {
  if (error instanceof Error) {
    console.error('Generation failed:', {
      message: error.message,
      cause: error.cause
    });
  }
}

Custom Type Transformers

// Custom date transformer
const dateTransformer = {
  name: 'date',
  match: (field) => field.fieldType === 'date',
  transform: (field) => ({
    type: 'Date',
    imports: ['import { parseISO } from "date-fns"'],
    transform: (value) => `parseISO(${value})`
  })
};

// Custom media transformer
const mediaTransformer = {
  name: 'media',
  match: (field) => field.fieldType === 'media',
  transform: (field) => ({
    type: 'MediaFile',
    imports: ['import type { MediaFile } from "./types"'],
  })
};

// Apply transformers
const generator = new ContentrainTypesGenerator({
  // ... other options
  options: {
    transformers: [dateTransformer, mediaTransformer]
  }
});

Testing

The package includes comprehensive tests. To run them:

# Run tests in watch mode
pnpm test

# Run tests once
pnpm test:run

Example test:

import { ContentrainTypesGenerator } from '@contentrain/types-generator';

describe('Type Generation', () => {
  const generator = new ContentrainTypesGenerator({
    modelsDir: './test/fixtures/models',
    outputDir: './test/output',
    contentDir: './test/fixtures/content'
  });

  it('should generate correct types for models', () => {
    generator.generate();

    const output = fs.readFileSync(
      './test/output/contentrain.d.ts',
      'utf-8'
    );

    expect(output).toContain('export interface IPost');
    expect(output).toContain('_relations?: {');
  });
});

Error Handling

The generator provides detailed error messages for common scenarios:

try {
  generator.generate();
} catch (error) {
  if (error.message.includes('Model directory not found')) {
    // Handle missing directory
  } else if (error.message.includes('Invalid model')) {
    // Handle invalid model schema
  } else if (error.message.includes('Failed to read metadata')) {
    // Handle metadata issues
  }
}

CI/CD Integration

GitHub Actions

name: Generate Types

on:
  push:
    paths:
      - 'models/**'
      - 'content/**'

jobs:
  generate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: '16'

      - name: Install dependencies
        run: pnpm install

      - name: Generate types
        run: pnpm contentrain-generate

      - name: Commit changes
        uses: stefanzweifel/git-auto-commit-action@v4
        with:
          commit_message: "chore: update generated types"

GitLab CI

generate-types:
  script:
    - pnpm install
    - pnpm contentrain-generate
  only:
    changes:
      - models/**/*
      - content/**/*
  artifacts:
    paths:
      - types/

API Reference

CLI Options

Options:
  -m, --models <path>   Path to models directory
  -o, --output <path>   Path to output directory
  -c, --content <path>  Path to content directory
  -d, --debug          Enable debug mode
  --watch              Enable watch mode
  -h, --help           Display help
  -v, --version        Display version

Generator Options

interface GeneratorConfig {
  // Required paths
  modelsDir: string;
  outputDir: string;
  contentDir: string;

  // Optional configurations
  options?: {
    generateRelationTypes?: boolean;
    includeBaseTypes?: boolean;
    typeMapping?: Record<string, string>;
    transformers?: TypeTransformer[];
    output?: {
      prettier?: boolean;
      declaration?: boolean;
      banner?: string;
    };
  };

  // Watch mode options
  watch?: {
    enabled?: boolean;
    debounce?: number;
    ignore?: string[];
  };
}

interface TypeTransformer {
  name: string;
  match: (field: FieldMetadata) => boolean;
  transform: (field: FieldMetadata) => {
    type: string;
    imports?: string[];
    transform?: string | ((value: string) => string);
  };
}

License

MIT