JSPM

  • Created
  • Published
  • Downloads 1177
  • Score
    100M100P100Q104634F
  • License MIT

Compile markdown resources to TypeScript with full IDE support

Package Exports

  • @vibe-agent-toolkit/resource-compiler
  • @vibe-agent-toolkit/resource-compiler/compiler
  • @vibe-agent-toolkit/resource-compiler/language-service
  • @vibe-agent-toolkit/resource-compiler/transformer
  • @vibe-agent-toolkit/resource-compiler/utils

Readme

@vibe-agent-toolkit/resource-compiler

Compile markdown resources to TypeScript with full IDE support

Status

🚧 Under Development - Phase 1: Core Compiler (v0.2.0)

Overview

The resource compiler transforms markdown files into TypeScript modules with:

  • Type-safe imports: Import .md files directly in TypeScript
  • Fragment extraction: H2 headings become typed properties
  • IDE support: Autocomplete, go-to-definition, hover tooltips
  • Frontmatter parsing: YAML metadata becomes typed objects

Installation

npm install -D @vibe-agent-toolkit/resource-compiler

Quick Start

1. Create a Markdown File

<!-- src/prompts/system.md -->
---
title: System Prompts
version: 1.0
---

# System Prompts

## Welcome

You are a helpful AI assistant.

## Farewell

Thank you for using our system.

2. Compile to TypeScript

# Compile markdown files
npx vat-compile-resources compile src/prompts dist/prompts

# Or generate type declarations only
npx vat-compile-resources generate-types src/prompts

3. Import in TypeScript

import prompts from './prompts/system.md';

// Type-safe access to frontmatter
console.log(prompts.meta.title);        // "System Prompts"
console.log(prompts.meta.version);      // 1.0

// Access full markdown text
console.log(prompts.text);

// Access specific fragments (H2 sections)
console.log(prompts.fragments.welcome.text);
console.log(prompts.fragments.farewell.body);

// Get all fragment names (type-safe)
const names: ('welcome' | 'farewell')[] = ['welcome', 'farewell'];

Build Integration

When using the compile command, you generate JavaScript modules in a separate generated/ directory. To ensure these modules are available at runtime, you need to copy them to your build output directory.

Why Copy Generated Resources?

TypeScript's type-checker needs to resolve imports during compilation. Your source files import from the generated/ directory:

// src/agent.ts
import * as Core from '../generated/resources/core.js';

When TypeScript compiles to dist/, it only copies compiled TypeScript files - not the generated JavaScript resources. You must copy generated/ to dist/ separately.

Directory structure:

your-package/
├── resources/            # Source markdown (author these)
│   └── prompts/
│       └── core.md
├── generated/            # Generated JS/TS (from compile command)
│   └── resources/
│       └── prompts/
│           ├── core.js
│           └── core.d.ts
├── src/                  # Your TypeScript source
│   └── agent.ts
└── dist/                 # Build output
    ├── src/              # Compiled TypeScript
    │   └── agent.js
    └── generated/        # Copied resources (post-build step)
        └── resources/

Build flow:

  1. compile resources → generated/
  2. TypeScript compilation → dist/src/
  3. Copy generated/dist/generated/

Create a post-build script using the provided cross-platform utility:

// scripts/post-build.ts
import { createPostBuildScript } from '@vibe-agent-toolkit/resource-compiler/utils';

createPostBuildScript({
  generatedDir: 'generated',
  distDir: 'dist',
  verbose: true,
});

Update package.json:

{
  "scripts": {
    "generate:resources": "vat-compile-resources compile resources/ generated/resources/",
    "build": "npm run generate:resources && tsc && node scripts/post-build.js"
  }
}

Method 2: Manual Copy (Custom Logic)

For more control, use the copyResources utility directly:

// scripts/post-build.ts
import { copyResources } from '@vibe-agent-toolkit/resource-compiler/utils';

copyResources({
  sourceDir: 'generated',
  targetDir: 'dist/generated',
  verbose: true,
});

// Add custom logic here
console.log('Build complete!');

Method 3: Build Tool Integration

Integrate with your build tool (Vite, Rollup, etc.):

// vite.config.ts
import { copyResources } from '@vibe-agent-toolkit/resource-compiler/utils';

export default {
  plugins: [
    {
      name: 'copy-resources',
      closeBundle() {
        copyResources({
          sourceDir: 'generated',
          targetDir: 'dist/generated',
        });
      },
    },
  ],
};

Cross-Platform Considerations

❌ Don't use shell commands:

"build": "tsc && cp -r generated dist/"  // Unix only!

✅ Use Node.js APIs:

import { cpSync } from 'node:fs';
cpSync('generated', 'dist/generated', { recursive: true });

The provided utilities use Node's built-in cpSync() which works on Windows, macOS, and Linux.

You could generate .md.js files alongside .md files:

resources/
  ├── core.md
  ├── core.md.js      # Generated - clutters source directory
  └── core.md.d.ts    # Generated - clutters source directory

Why we don't recommend this:

  • ❌ Clutters your clean markdown directory with generated files
  • ❌ Makes .gitignore patterns more complex
  • ❌ Harder to clean generated files

Use a separate generated/ directory instead - it keeps source files clean and makes the build process explicit.

Documentation

CLI Commands

compile - Compile Markdown to JavaScript/TypeScript

Compiles markdown files to JavaScript modules and TypeScript declarations.

npx vat-compile-resources compile <input> <output> [options]

Arguments:

  • <input> - Input directory containing markdown files
  • <output> - Output directory for compiled files

Options:

  • -p, --pattern <pattern> - Glob pattern for markdown files (default: **/*.md)
  • -v, --verbose - Enable verbose logging
  • -w, --watch - Watch mode for automatic recompilation

Example:

# Compile all markdown files
npx vat-compile-resources compile src/prompts dist/prompts

# Compile with custom pattern
npx vat-compile-resources compile src docs --pattern "guides/**/*.md"

# Watch mode
npx vat-compile-resources compile src dist --watch

generate-types - Generate .md.d.ts Declaration Files

Generates TypeScript declaration files (.md.d.ts) alongside markdown files for use with the TypeScript transformer.

npx vat-compile-resources generate-types <input> [options]

Arguments:

  • <input> - Input directory containing markdown files

Options:

  • -p, --pattern <pattern> - Glob pattern for markdown files (default: **/*.md)
  • -v, --verbose - Enable verbose logging

Example:

# Generate declarations for all markdown files
npx vat-compile-resources generate-types src/prompts

# Generate with custom pattern
npx vat-compile-resources generate-types docs --pattern "**/*.md"

TypeScript Transformer

The TypeScript transformer enables direct .md imports in TypeScript without pre-compilation.

Setup with ts-patch

  1. Install dependencies:
npm install -D @vibe-agent-toolkit/resource-compiler ts-patch typescript
  1. Update tsconfig.json:
{
  "compilerOptions": {
    "plugins": [
      {
        "transform": "@vibe-agent-toolkit/resource-compiler/transformer"
      }
    ]
  }
}
  1. Patch TypeScript:
npx ts-patch install
  1. Generate type declarations:
npx vat-compile-resources generate-types src/
  1. Import markdown files:
import prompts from './prompts/system.md';

console.log(prompts.text);
console.log(prompts.fragments.welcome.text);

How It Works

  1. Generate Declarations: generate-types creates .md.d.ts files alongside your markdown files
  2. Transform Imports: The transformer detects .md imports and inlines the compiled resource
  3. Type Safety: TypeScript uses .md.d.ts files to provide autocomplete and type checking

Import Styles

The transformer supports all TypeScript import styles:

// Default import
import doc from './doc.md';

// Namespace import
import * as doc from './doc.md';

// Named imports
import { text, fragments, meta } from './doc.md';

API Reference

Exported Types

// From compiled markdown
export interface Fragment {
  readonly header: string;  // H2 heading with ##
  readonly body: string;    // Content below heading
  readonly text: string;    // header + body
}

export const meta: Record<string, unknown>;  // Frontmatter
export const text: string;                   // Full markdown text
export const fragments: Record<string, Fragment>;  // H2 sections
export type FragmentName = keyof typeof fragments;

Compiler API

import { compileMarkdownResources } from '@vibe-agent-toolkit/resource-compiler/compiler';

const results = await compileMarkdownResources({
  inputDir: 'src/prompts',
  outputDir: 'dist/prompts',
  pattern: '**/*.md',
  verbose: true,
});

// Each result contains:
interface CompileResult {
  sourcePath: string;
  jsPath: string;
  dtsPath: string;
  success: boolean;
  error?: string;
}

Transformer API

import { createTransformer } from '@vibe-agent-toolkit/resource-compiler/transformer';
import ts from 'typescript';

const transformer = createTransformer({
  verbose: true,
});

// Use with TypeScript compiler API
const result = program.emit(
  undefined,
  undefined,
  undefined,
  undefined,
  { before: [transformer] }
);

Build Utilities API

import { copyResources, createPostBuildScript } from '@vibe-agent-toolkit/resource-compiler/utils';

// Copy resources with options
copyResources({
  sourceDir: 'generated',
  targetDir: 'dist/generated',
  verbose: true,
});

// Create a complete post-build script
createPostBuildScript({
  generatedDir: 'generated',
  distDir: 'dist',
  verbose: true,
});

Options:

interface CopyResourcesOptions {
  sourceDir: string;   // Source directory with generated files
  targetDir: string;   // Target directory in dist
  verbose?: boolean;   // Enable logging (default: false)
}

Throws:

  • Error if source directory doesn't exist
  • Error if copy operation fails

Language Service Plugin

Coming soon - TypeScript language service plugin for enhanced IDE support.

Development

See the implementation plan for development details.

License

MIT