Skip to content

Commit 60352f6

Browse files
feat: add CLI package with AJV-based JSON Schema validation (#4)
* feat: add CLI package with AJV-based JSON Schema validation - Add AJV (Another JSON Validator) for JSON Schema validation - Make Zod optional peer dependency for backward compatibility - Create CLI package with build and validate commands - Add config file auto-discovery (.markdown-di.json) - Support both named schema references and inline JSON Schema objects - Maintain dual validation path: AJV (primary) and Zod (fallback) Core changes: - packages/core/src/ajv-schema.ts: AJV validator implementation - packages/core/src/config-loader.ts: Config discovery and loading - packages/core/src/index.ts: Integrated AJV validation - packages/core/package.json: Added AJV dependencies, made Zod optional CLI package: - packages/cli/src/index.ts: Commander.js setup - packages/cli/src/commands/build.ts: Build command with schema validation - packages/cli/src/commands/validate.ts: Validate command - packages/cli/package.json: CLI dependencies and scripts Testing: - Validated single file processing - Validated batch directory processing - Validated error reporting for invalid schemas - Validated config auto-discovery and explicit config path 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: remove incorrect deprecation warnings from Zod methods Zod is still fully supported as an optional peer dependency. The methods registerSchema(), registerSchemas(), and getSchema() remain valid for programmatic usage with Zod schemas. * docs: update README with CLI usage and JSON Schema documentation - Add CLI installation and usage instructions - Document JSON Schema support alongside Zod - Add CLI Reference section with commands, options, and examples - Update API Reference with new JSON Schema methods - Clarify that JSON Schema is recommended for CLI, Zod for programmatic API - Add CI/CD integration examples * fix: update test for new schema error message format Update integration test and snapshot to reflect the new error message format from AJV-based validation: "Schema not found. No schemas registered." instead of "Schema not found in registry. Register it with registerSchema() first." 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 5329dd2 commit 60352f6

File tree

13 files changed

+944
-87
lines changed

13 files changed

+944
-87
lines changed

README.md

Lines changed: 302 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# markdown-di
22

3-
**Type-safe Mustache templating for markdown with Zod schema validation.**
3+
**Type-safe Mustache templating for markdown with schema validation.**
44

5-
Build reliable documentation and content systems with frontmatter schemas that catch errors at build time.
5+
Build reliable documentation and content systems with frontmatter schemas that catch errors at build time. Use the CLI for quick validation or the programmatic API for advanced workflows.
66

77
## The Problem
88

@@ -74,7 +74,8 @@ docs/getting-started.md:
7474

7575
## Features
7676

77-
-**Zod schema validation** - Type-safe frontmatter at build time
77+
-**Schema validation** - JSON Schema (CLI) or Zod (programmatic API)
78+
-**CLI tool** - Validate and build markdown files from the command line
7879
-**Mustache templating** - Variables, loops, conditionals
7980
-**File injection** - Include external files with `{{partials.xxx}}`
8081
-**Glob patterns** - `guides/*.md` expands to multiple files
@@ -85,13 +86,85 @@ docs/getting-started.md:
8586

8687
## Installation
8788

89+
### CLI (Recommended for most users)
90+
91+
```bash
92+
npm install -g @markdown-di/cli
93+
# or use npx
94+
npx @markdown-di/cli validate docs/
95+
```
96+
97+
### Programmatic API
98+
8899
```bash
89100
npm install @markdown-di/core
90101
```
91102

92103
## Quick Start
93104

94-
### Batch Processing (Recommended)
105+
### CLI Usage (Recommended)
106+
107+
The CLI is the easiest way to get started. It uses JSON Schema for validation.
108+
109+
#### 1. Create a config file
110+
111+
Create `.markdown-di.json` in your project root:
112+
113+
```json
114+
{
115+
"schemas": {
116+
"blog-post": {
117+
"type": "object",
118+
"required": ["author", "publishedAt", "tags"],
119+
"properties": {
120+
"author": { "type": "string" },
121+
"publishedAt": { "type": "string", "format": "date" },
122+
"tags": {
123+
"type": "array",
124+
"items": { "type": "string" }
125+
}
126+
}
127+
}
128+
}
129+
}
130+
```
131+
132+
#### 2. Write markdown with frontmatter
133+
134+
```markdown
135+
---
136+
schema: blog-post
137+
name: Getting Started
138+
author: Jane Doe
139+
publishedAt: 2024-01-15
140+
tags: [tutorial, beginners]
141+
---
142+
143+
# {{name}}
144+
145+
By {{author}}
146+
```
147+
148+
#### 3. Validate or build
149+
150+
```bash
151+
# Validate files (no output)
152+
markdown-di validate docs/
153+
154+
# Build with processed output
155+
markdown-di build docs/ --output dist/
156+
157+
# Use explicit config path
158+
markdown-di validate docs/ --config path/to/.markdown-di.json
159+
```
160+
161+
The CLI will:
162+
- Auto-discover `.markdown-di.json` by walking up directories
163+
- Validate all frontmatter against your schemas
164+
- Report errors with exact locations
165+
- Process Mustache templates and inject partials
166+
167+
### Programmatic API - Batch Processing
95168

96169
Process multiple markdown files with a simple API:
97170

@@ -417,7 +490,75 @@ All nested partials have access to the parent document's variables (`author`, `t
417490

418491
## Schema Validation
419492

420-
### Registering Custom Schemas
493+
### JSON Schema (CLI & Programmatic)
494+
495+
JSON Schema is the recommended format for most users. It's a W3C standard that's widely supported and portable.
496+
497+
#### Using with CLI
498+
499+
Create a `.markdown-di.json` config file:
500+
501+
```json
502+
{
503+
"schemas": {
504+
"blog-post": {
505+
"type": "object",
506+
"required": ["author", "date"],
507+
"properties": {
508+
"author": { "type": "string", "minLength": 1 },
509+
"date": { "type": "string", "format": "date" },
510+
"tags": {
511+
"type": "array",
512+
"items": { "type": "string" }
513+
}
514+
}
515+
}
516+
}
517+
}
518+
```
519+
520+
Then run the CLI:
521+
522+
```bash
523+
markdown-di validate docs/
524+
markdown-di build docs/ --output dist/
525+
```
526+
527+
#### Using Programmatically (JSON Schema)
528+
529+
```typescript
530+
import { MarkdownDI } from '@markdown-di/core';
531+
532+
const mdi = new MarkdownDI();
533+
534+
// Load schemas from config file (auto-discovery)
535+
mdi.loadConfigSchemas();
536+
537+
// Or load from explicit path
538+
mdi.loadConfigSchemas('./my-config.json');
539+
540+
// Or register schemas directly
541+
mdi.registerJsonSchema('blog-post', {
542+
type: 'object',
543+
required: ['author', 'date'],
544+
properties: {
545+
author: { type: 'string' },
546+
date: { type: 'string', format: 'date' }
547+
}
548+
});
549+
550+
// Register multiple schemas
551+
mdi.registerJsonSchemas({
552+
'blog-post': { /* schema */ },
553+
'api-doc': { /* schema */ }
554+
});
555+
```
556+
557+
### Zod Schemas (Programmatic Only)
558+
559+
For TypeScript projects that want strong type inference, you can use Zod schemas programmatically:
560+
561+
#### Registering Zod Schemas
421562

422563
Register schemas once, then reference them in frontmatter:
423564

@@ -566,6 +707,115 @@ output-frontmatter:
566707
- Remove draft/workflow fields from production documents
567708
- Keep sensitive information in source but not in output
568709

710+
## CLI Reference
711+
712+
The `@markdown-di/cli` package provides command-line tools for validation and building.
713+
714+
### Installation
715+
716+
```bash
717+
# Global installation
718+
npm install -g @markdown-di/cli
719+
720+
# Or use with npx
721+
npx @markdown-di/cli validate docs/
722+
```
723+
724+
### Commands
725+
726+
#### `validate <input>`
727+
728+
Validate markdown files without writing output. Perfect for CI/CD pipelines.
729+
730+
```bash
731+
# Validate single file
732+
markdown-di validate docs/post.md
733+
734+
# Validate directory
735+
markdown-di validate docs/
736+
737+
# Validate with glob pattern
738+
markdown-di validate "docs/**/*.md"
739+
740+
# Use explicit config
741+
markdown-di validate docs/ --config path/to/.markdown-di.json
742+
```
743+
744+
**Options:**
745+
- `-c, --config <path>` - Path to config file (overrides auto-discovery)
746+
747+
**Exit codes:**
748+
- `0` - All files valid
749+
- `1` - Validation errors found
750+
751+
#### `build <input>`
752+
753+
Build markdown files with dependency injection and optional output directory.
754+
755+
```bash
756+
# Build single file to output directory
757+
markdown-di build docs/post.md --output dist/
758+
759+
# Build entire directory
760+
markdown-di build docs/ --output dist/
761+
762+
# Build in-place (overwrites source files)
763+
markdown-di build docs/
764+
765+
# Use explicit config
766+
markdown-di build docs/ --output dist/ --config .markdown-di.json
767+
```
768+
769+
**Options:**
770+
- `-o, --output <dir>` - Output directory for processed files
771+
- `-c, --config <path>` - Path to config file (overrides auto-discovery)
772+
- `-w, --watch` - Watch mode (not yet implemented)
773+
774+
### Config File
775+
776+
The CLI looks for config files in this order:
777+
1. Path specified with `--config` flag
778+
2. `.markdown-di.json` (auto-discovered by walking up directories)
779+
3. `.markdown-di.schemas.json`
780+
4. `markdown-di.config.json`
781+
782+
**Config format:**
783+
784+
```json
785+
{
786+
"schemas": {
787+
"schema-name": {
788+
"type": "object",
789+
"required": ["field1"],
790+
"properties": {
791+
"field1": { "type": "string" },
792+
"field2": { "type": "number" }
793+
}
794+
}
795+
}
796+
}
797+
```
798+
799+
The config file uses standard [JSON Schema](https://json-schema.org/) format with support for:
800+
- Type validation (`string`, `number`, `boolean`, `array`, `object`, `null`)
801+
- Format validation (`date`, `date-time`, `email`, `uri`, `uuid`, etc.)
802+
- Array items validation
803+
- Nested objects
804+
- Required fields
805+
- Min/max constraints
806+
807+
### CI/CD Integration
808+
809+
Use the validate command in your CI pipeline:
810+
811+
```yaml
812+
# GitHub Actions example
813+
- name: Validate markdown
814+
run: npx @markdown-di/cli validate docs/
815+
816+
# Will exit with code 1 if validation fails
817+
```
818+
569819
## API Reference
570820

571821
### `BatchProcessor`
@@ -686,20 +936,65 @@ const result = await mdi.validate({
686936
// Returns errors but doesn't inject partials
687937
```
688938

939+
#### `loadConfigSchemas(configPath?: string, startDir?: string): void`
940+
941+
Load JSON Schema from config file (recommended for CLI usage):
942+
943+
```typescript
944+
// Auto-discover .markdown-di.json
945+
mdi.loadConfigSchemas();
946+
947+
// Explicit path
948+
mdi.loadConfigSchemas('./custom-config.json');
949+
950+
// Start search from specific directory
951+
mdi.loadConfigSchemas(undefined, './docs');
952+
```
953+
954+
#### `registerJsonSchema(name: string, jsonSchema: any): void`
955+
956+
Register a single JSON Schema:
957+
958+
```typescript
959+
mdi.registerJsonSchema('blog-post', {
960+
type: 'object',
961+
required: ['author', 'date'],
962+
properties: {
963+
author: { type: 'string' },
964+
date: { type: 'string', format: 'date' }
965+
}
966+
});
967+
```
968+
969+
#### `registerJsonSchemas(schemas: Record<string, any>): void`
970+
971+
Register multiple JSON Schemas:
972+
973+
```typescript
974+
mdi.registerJsonSchemas({
975+
'blog-post': { /* JSON Schema */ },
976+
'api-doc': { /* JSON Schema */ }
977+
});
978+
```
979+
689980
#### `registerSchema(name: string, schema: z.ZodSchema): void`
690981

691-
Register a named schema:
982+
Register a Zod schema (programmatic API only):
692983

693984
```typescript
985+
import { z } from '@markdown-di/core';
986+
694987
mdi.registerSchema('blog-post', z.object({
695988
author: z.string(),
696989
tags: z.array(z.string())
697990
}));
698991
```
699992

993+
**Note:** Requires Zod as a peer dependency (`npm install zod`).
994+
700995
#### `registerSchemas(schemas: Record<string, z.ZodSchema>): void`
701996

702-
Register multiple schemas:
997+
Register multiple Zod schemas:
703998

704999
```typescript
7051000
mdi.registerSchemas({

0 commit comments

Comments
 (0)