Quickstart

Get started with datamark in under 5 minutes. Parse your first Markdown document into a typed object.

Parse your first Markdown document into a typed object in three steps. About 5 minutes.

Install

npm install datamark

For validation, also install your schema library of choice:

npm install zod

Write your first format

Create a file that describes how your Markdown is structured:

import { datamark } from "datamark";
import { findAll, inlineText, textContent, isCodeBlock } from "datamark/parse";
import { frontmatter, heading, paragraph, codeBlock } from "datamark/stringify";
import * as z from "zod";

const PlanFrontmatterSchema = z.object({ id: z.string() });

const PlanSchema = z.object({
  id: z.string(),
  title: z.string(),
  steps: z.array(
    z.object({
      description: z.string(),
      scripts: z.array(z.string()),
    })
  ),
});

const PlanFormat = datamark({
  frontmatterSchema: PlanFrontmatterSchema,
  schema: PlanSchema,

  parse(doc) {
    const id = doc.frontmatter.id;
    const titleSection = doc.root.children.find((n) => n.type === "section") as any;
    const title = titleSection ? inlineText(titleSection.heading.children) : "";

    const steps = titleSection
      ? (titleSection.children.filter((n: any) => n.type === "section") as any[]).map(
          (section) => {
            const scripts = findAll(section, (n) => isCodeBlock(n, "javascript")).map(
              (n: any) => n.value
            );
            const description = textContent(section).trim();
            return { description, scripts };
          }
        )
      : [];

    return { id, title, steps };
  },

  stringify(data) {
    let md = frontmatter({ id: data.id }) + heading(data.title) + "\n\n";
    for (const step of data.steps) {
      md += heading("Step", 2) + "\n\n" + paragraph(step.description) + "\n\n";
      for (const script of step.scripts) {
        md += codeBlock(script, "javascript") + "\n\n";
      }
    }
    return md;
  },
});

const planMarkdown = `---
id: plan-001
---
# Q3 Roadmap

## Step

Set up the project.

\`\`\`javascript
npm init -y
\`\`\`

## Step

Implement the core features.`;
const result = PlanFormat.parse(planMarkdown);
console.log(result.id);     // "plan-001"
console.log(result.title);  // "Q3 Roadmap"
console.log(result.steps[0].description); // "Set up the project."

Parse a document

import { PlanFormat } from "./plan-format";

const markdown = `---
id: plan-001
---
# Q3 Roadmap

## Set up project scaffolding

Install dependencies.

\`\`\`javascript
npm init -y
\`\`\`

## Implement core features

Build the main functionality.
`;

const result = PlanFormat.parse(markdown);
console.log(result);
// {
//   id: "plan-001",
//   title: "Q3 Roadmap",
//   steps: [
//     { title: "Set up project scaffolding", description: "Install dependencies.", scripts: ["npm init -y"] },
//     { title: "Implement core features", description: "Build the main functionality.", scripts: [] },
//   ],
// }

What happened?

  1. parse turned the raw Markdown string into a typed AST with a section tree.
  2. Your parse function traversed the AST using utility functions like findAll, textContent, and isCodeBlock.
  3. The section tree made it easy to iterate over H2-delimited sections.
  4. The final return value was validated against your Zod schema.

Where to go next

GoalLink
Understand how it worksThe AST
Learn about the format systemFormat SDK
Look up core functionsParse SDK
See more examplesExamples

On this page