Getting Started
This page explains how to install md2form v2 and use it from the beginning.
Installation
Using npm
npm install md2formUsing Bun (recommended)
bun add md2formDevelopment Environment Setup
If you plan to develop or customize the project:
git clone <repository-url>
cd md2form
bun installFor development, Bun v1.2.18 or later is recommended.
Basic Usage
Simple Example
The most basic usage of v2’s main API parseForm:
import { parseForm, isParsedDocument } from "md2form"
const markdown = `
# Basic Form
## Question Section
### Your Name
#type short_text
#required true
`
const result = parseForm(markdown)
if (!isParsedDocument(result)) {
// If error exists, isParsedDocument returns false
console.error(result.diagnostics)
} else {
const form = result.document
console.log(form.title) // "Basic Form"
}parseForm is a synchronous function. No await is required.
ParseResult Structure
The return value of parseForm is of type ParseResult with these 3 fields:
type ParseResult = {
document: FormDocument // Parsed form definition
diagnostics: Diagnostic[] // Error, warning, and info messages
ok: boolean // In strict mode: true if no errors
}Example of checking diagnostics:
const result = parseForm(markdown)
// Display all diagnostics
result.diagnostics.forEach((d) => {
console.log(`[${d.severity}] ${d.code}: ${d.message}`)
})
// Parse result can always be obtained (partially recovered if issues exist)
console.log(result.document.title)Using Strict Mode (Recommended for CI)
When you specify strict: true, ok === false when error-level diagnostics exist:
import { parseForm, isParsedDocument } from "md2form"
const result = parseForm(markdown, { strict: true, validateSettings: true })
if (!isParsedDocument(result)) {
console.error("Form has errors:")
result.diagnostics
.filter((d) => d.severity === "error")
.forEach((d) => console.error(` ${d.code}: ${d.message}`))
process.exit(1)
}
const form = result.documentExample with Frontmatter
import { parseForm, isParsedDocument } from "md2form"
import type { FormDocument } from "md2form"
const markdown = `
---
collectEmail: true
showProgressBar: true
allowMultipleResponses: false
themeColor: "#3B82F6"
---
# Customer Survey
Please share your feedback.
## Basic Information
### Please Enter Your Name
#type short_text
#placeholder "John Doe"
#required true
### Email Address
#type email
#placeholder "example@example.com"
#required true
## Rating
### Service Satisfaction
#type rating
#scale 5
#labels "Dissatisfied","Very Satisfied"
#required true
`
const result = parseForm(markdown, { strict: true })
if (!isParsedDocument(result)) {
throw new Error("Invalid form")
}
const form: FormDocument = result.document
// Access form information
console.log(form.title) // "Customer Survey"
console.log(form.settings?.collectEmail) // true
console.log(form.settings?.themeColor) // "#3B82F6"
console.log(form.pages.length) // 2 (Basic Information, Rating)Structure of the Returned Object
The parsed form has this structure:
{
schemaVersion: 2,
title: "Customer Survey",
description: "Please share your feedback.",
settings: {
collectEmail: true,
showProgressBar: true,
allowMultipleResponses: false,
themeColor: "#3B82F6"
},
pages: [
{
title: "Basic Information",
elements: [
{
type: "short_text",
label: "Please Enter Your Name", // v2: label field
placeholder: "John Doe",
required: true
},
{
type: "email",
label: "Email Address",
placeholder: "example@example.com",
required: true
}
]
},
{
title: "Rating",
elements: [
{
type: "rating",
label: "Service Satisfaction",
scale: 5,
labels: { low: "Dissatisfied", high: "Very Satisfied" },
required: true
}
]
}
]
}v2 Changes: The question heading (
### heading) is now stored in thelabelfield in v2. In v1 it wasdescription.
Reusable Parser
When parsing multiple Markdown files with the same options, use createParser:
import { createParser } from "md2form"
// Create parser instance once
const parser = createParser({ strict: false })
// Efficiently parse multiple Markdown files
const result1 = parser.parse(markdown1)
const result2 = parser.parse(markdown2)
const result3 = parser.parse(markdown3)Running Samples
The project includes complete samples:
# Parse sample form and check results
bun run workspaceThis will:
- Parse
workspace/sample-form.md - Output results to
workspace/workspace.json - Display form structure in the console
Using Diagnostics
In v2, errors are reported as diagnostics array instead of exceptions:
import { parseForm } from "md2form"
import type { Diagnostic } from "md2form"
const result = parseForm(markdown)
// Filter by severity
const errors = result.diagnostics.filter((d) => d.severity === "error")
const warnings = result.diagnostics.filter((d) => d.severity === "warning")
const infos = result.diagnostics.filter((d) => d.severity === "info")
// Detect specific issues by diagnostic code
const missingTypes = result.diagnostics.filter((d) => d.code === "MISSING_ELEMENT_TYPE")
// Format and display diagnostics
function printDiagnostics(diagnostics: Diagnostic[]): void {
diagnostics.forEach((d) => {
const loc = d.line ? ` (line ${d.line})` : ""
console.log(`[${d.severity.toUpperCase()}] ${d.code}${loc}: ${d.message}`)
})
}Common diagnostic codes:
| Code | Severity | Description |
|---|---|---|
MISSING_FORM_TITLE | warning | # Title not found |
MISSING_ELEMENT_TYPE | warning | Question without #type specification |
UNSUPPORTED_ELEMENT_TYPE | warning | Unknown #type value |
MISSING_REQUIRED_FIELD | error | Required property (like #options) not set |
INVALID_PROPERTY_VALUE | warning | Invalid property value format |
UNKNOWN_SETTING_KEY | warning | Unknown key in frontmatter |
INVALID_SETTING_VALUE | warning | Invalid value in frontmatter |
Using Type Safety
When using TypeScript, you can safely handle data using type definitions:
import { parseForm, isParsedDocument } from "md2form"
import type { FormDocument, ShortText, NumberField } from "md2form"
const result = parseForm(markdown, { strict: true })
if (!isParsedDocument(result)) {
throw new Error("Parse failed")
}
const form: FormDocument = result.document
form.pages.forEach((page) => {
page.elements.forEach((element) => {
if (element.type === "short_text") {
const shortText = element as ShortText
console.log(shortText.placeholder) // Type-safe
}
if (element.type === "number") {
const numberField = element as NumberField
console.log(numberField.min, numberField.max) // Type-safe
}
})
})v1 Compatibility
The v1 parseMarkdownToForm continues to work in v2, but is deprecated:
// ❌ Deprecated (v1 compatible)
import { parseMarkdownToForm } from "md2form"
const form = await parseMarkdownToForm(markdown) // Cannot get diagnostics
// ✅ Recommended (v2)
import { parseForm, isParsedDocument } from "md2form"
const result = parseForm(markdown)
const form = result.documentNext Steps
After understanding the basics, check these pages for more detailed information:
- Markdown Schema - Form definition syntax and rules
- Question Types - Details of all question types
- Property Reference - Configurable properties
- Examples - Real-world usage and best practices
- API Reference - Details of functions and types
FAQ
Q: Can I use md2form with npm or yarn instead of Bun?
A: Yes, md2form works correctly with npm and yarn. However, Bun is recommended for development.
Q: Is parseForm async?
A: No, v2’s parseForm is a synchronous function. No await is needed. v1’s parseMarkdownToForm returned a Promise, but v2 changed to a synchronous API.
Q: Can I use it directly in the browser?
A: md2form is intended for Node.js/Bun environments. For browser use, use a bundler (webpack, Vite, etc.).
Q: How do I save parse results to a JSON file?
A: You can save it like this:
import { parseForm } from "md2form"
import { writeFileSync } from "fs"
const result = parseForm(markdown)
writeFileSync("form.json", JSON.stringify(result.document, null, 2))