zudo-text

検索したい単語を入力

いつでも検索バーを開ける

@takazudo/mindmap-parser

Pure markdown parser and serializer for mind map tree data. Parses markdown files with type: mindmap frontmatter into structured MindMapTree objects. All operations are immutable. Zero dependencies. The parser normalizes CRLF and lone-CR input to LF so an editor can safely round-trip files from any platform.

Main Exports

import {
  parseMindMapMarkdown,
  serializeMindMapMarkdown,
  hasMindmapFrontmatter,
  addNode,
  removeNode,
  moveNode,
  updateNodeLabel,
  findNode,
  findParent,
  slugify,
  uniqueSlug,
  validateMindmapMarkdown,
  encodeMindMapLabel,
  decodeMindMapLabel,
} from "@takazudo/mindmap-parser";

import type { MindMapNode, MindMapTree } from "@takazudo/mindmap-parser";

Types

interface MindMapNode {
  id: string;        // slugified from label
  label: string;     // display text
  children: MindMapNode[];
}

interface MindMapTree {
  title: string;                          // from frontmatter or root heading
  root: MindMapNode;                      // the root node (from # heading)
  rawFrontmatter: Record<string, string>; // preserved for round-trip
}

parseMindMapMarkdown()

Parses a markdown string into a MindMapTree. The format uses YAML frontmatter for metadata, a # heading for the root node, and indented bullet lists for branches:

const tree = parseMindMapMarkdown(`---
type: mindmap
title: Project Plan
---

# Project Plan
- Research
  - User Interviews
  - Market Analysis
- Development
  - Backend
  - Frontend
`);
// tree.title === "Project Plan"
// tree.root.label === "Project Plan"
// tree.root.children.length === 2

Parsing rules:

  • The # heading becomes the root node

  • Bullet items (- ) become child nodes

  • Indentation (2 spaces per level) determines nesting depth

  • Node IDs are generated via slugify() with uniqueness guarantees

Blank lines and prose outside the tree do not become nodes. Call validateMindmapMarkdown() before setup or persistence to report malformed tree structure rather than committing it.

Multiline labels and codec safety

Labels containing a newline are stored on one physical Markdown line using the declared mindmap-label-codec: base64url-v1 frontmatter field and an unpadded base64url ~mml1~ payload. The parser decodes the label before deriving its ID; the serializer preserves internal, leading, and trailing line breaks and spaces. The same encoding protects literal marker-looking labels from being interpreted as data. Unsupported codec declarations and malformed payloads remain visible as literal text and are validation errors, rather than silently changing the tree. Manual edits should normalize line endings to LF and use canonical base64url spelling.

serializeMindMapMarkdown()

Converts a MindMapTree back to markdown. Preserves the original frontmatter for round-trip fidelity.

const markdown = serializeMindMapMarkdown(tree);
// ---
// type: mindmap
// title: Project Plan
// ---
//
// # Project Plan
// - Research
//   - User Interviews
//   - Market Analysis
// ...

hasMindmapFrontmatter()

Returns true if the markdown content has type: mindmap in its frontmatter. Used to detect mind map files.

hasMindmapFrontmatter("---\ntype: mindmap\n---\n# Root");
// true

hasMindmapFrontmatter("---\ntitle: Note\n---\n# Just a note");
// false

validateMindmapMarkdown(markdown) returns line-aware warnings and errors for missing frontmatter/root headings, skipped indentation levels, unsupported codecs, and malformed encoded labels. Setup flows should validate and preview the exact serialized candidate before writing; cancellation or a validation or write failure must leave the original source untouched.

Tree Operations

All operations are immutable — they return a new MindMapTree:

FunctionDescription
addNode(tree, parentId, label)Add a new child node to a parent
removeNode(tree, nodeId)Remove a node and its children (cannot remove root)
moveNode(tree, nodeId, newParentId, index?)Reparent a node (cannot move root or into own descendant)
updateNodeLabel(tree, nodeId, newLabel)Rename a node (regenerates its ID; updates title if root)

Examples

// Add a child under "research"
const updated = addNode(tree, "research", "Competitor Analysis");

// Remove a node
const pruned = removeNode(tree, "market-analysis");

// Move "frontend" under "research"
const moved = moveNode(tree, "frontend", "research");

// Rename a node
const renamed = updateNodeLabel(tree, "backend", "Server");

Query Functions

FunctionDescription
findNode(tree, nodeId)Find a node by ID. Returns null if not found
findParent(tree, nodeId)Find the parent of a node. Returns null if root or not found

Utilities

  • slugify(text) — convert to kebab-case slug (preserves non-ASCII characters)

  • uniqueSlug(title, existingIds) — generate unique slug with -2, -3 suffix if needed

Dependencies

None (standalone package).