3.0.0 • Published 8 months ago
@contentrain/types-generator v3.0.0
@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