npm package: @genzai/templates
Description: Directory-based project templates for Genzai
Latest version: 0.1.8

# @genzai/templates

Directory-based project templates for Genzai.

## Overview

`@genzai/templates` provides a simple way to create code generators from directory structures. It walks template directories, executes `.gen.ts` generator files, and copies static files, returning a standard `Generator` that works seamlessly with Genzai's `generate()` function.

## Installation

```bash
npm install @genzai/templates @genzai/core tsx
```

Note: `tsx` is required as a peer dependency to load TypeScript generator files at runtime.

## Usage

### Basic Example

```typescript
import { generate } from "@genzai/core";
import { template } from "@genzai/templates";

// Create a generator that uses template
const myAppGenerator = async (ctx) => template("./templates/my-app", ctx);

// Use it like any other generator
await generate(myAppGenerator, "./output", {
  projectName: "my-app",
  apiUrl: "https://api.example.com",
});
```

### Template Directory Structure

A template directory can contain:
- **Static files**: Copied as-is to the output
- **`.gen.ts` files**: TypeScript files that export Generators
- **Directories**: Recursively processed

Example structure:

```
templates/my-app/
  .genzai.json            # Optional config for regeneration strategies
  src/
    index.ts              # Static - copied as-is
    config.gen.ts         # Dynamic - executes generator
    components/
      Button.tsx          # Static
  package.json.gen.ts     # Dynamic
  README.md               # Static
  .gitignore              # Static
```

### Configuring Regeneration Strategies

For static files that can't contain JSDoc markers (JSON, markdown, etc.), use a `.genzai.json` config file in the template root:

```json
{
  "files": {
    "package.json": { "regenerationStrategy": "preserve-edits" },
    "src/**/*.ts": { "regenerationStrategy": "overwrite" }
  },
  "default": { "regenerationStrategy": "overwrite" }
}
```

**Pattern matching:**
- Exact paths: `"package.json"`
- Glob patterns: `"src/**/*.ts"` (matches any `.ts` file in `src/`)
- `*` matches any characters except `/`
- `**` matches any characters including `/`

The config sets `meta.regenerationStrategy` on static file nodes, which is then used by `regenerationStrategyMiddleware` from `@genzai/core`.

### Creating Generator Files (.gen.ts)

Generator files must export a default Generator function that returns an array of nodes:

```typescript
// package.json.gen.ts
import { file } from "@genzai/core";

interface Context {
  projectName: string;
  dependencies: Record<string, string>;
}

export default (ctx: Context) => [
  file("package.json", () =>
    JSON.stringify(
      {
        name: ctx.projectName,
        version: "1.0.0",
        dependencies: ctx.dependencies,
      },
      null,
      2
    )
  ),
];
```

### Composing with Other Generators

Templates can be composed with other Genzai generators:

```typescript
import { generate, folder, file } from "@genzai/core";
import { template } from "@genzai/templates";

const myGenerator = async (ctx) => [
  folder("project", [
    ...(await template("./templates/base", ctx)),  // Load from directory
    file("custom.ts", () => "// custom"),          // Add extra file
  ]),
];

await generate(myGenerator, "./output", context);
```

### With Middleware

Templates work seamlessly with Genzai middleware:

```typescript
import { generate, defaultMiddleware } from "@genzai/core";
import { template } from "@genzai/templates";
import { prettierMiddleware } from "@genzai/prettier";
import { slotMiddleware } from "@genzai/slots";

const myAppGenerator = async (ctx) => template("./templates/my-app", ctx);

await generate(
  myAppGenerator,
  "./output",
  context,
  {
    middlewares: [...defaultMiddleware, slotMiddleware, prettierMiddleware],
  }
);
```

## API

### `template(templatePath, context)`

Loads a template directory and returns nodes.

**Parameters:**
- `templatePath` (string): Path to template directory (absolute or relative)
- `context` (C): Context object to pass to `.gen.ts` generators

**Returns:**
- `Promise<Node[]>`: A promise that resolves to an array of nodes

**Throws:**
- Error if path is empty or not a string
- Error if path doesn't exist or isn't a directory
- Error if `.gen.ts` files don't export valid Generators

**Example:**

```typescript
const myGenerator = async (ctx) => template("./templates/my-app", ctx);
await generate(myGenerator, "./output", context);
```

## How It Works

1. **Directory Walking**: Recursively walks the template directory
2. **File Processing**:
   - `.gen.ts` files: Dynamically loaded with `tsx` and executed as async Generators with the provided context
   - Directories: Recursively processed as folders
   - Other files: Copied as-is using lazy content loading
3. **Output**: Returns an array of nodes that can be used in any generator

## Error Handling

The package provides comprehensive validation and error messages:

- Template path validation (exists, is directory, readable)
- Generator file validation (valid TypeScript, exports default function)
- File system error handling with context
- Detailed error messages with file paths

## License

MIT