Skip to main content

dmc/cli/
init.rs

1use std::path::PathBuf;
2
3use dmc_diagnostic::{Code, DiagResult};
4use duck_diagnostic::{Diagnostic, diag};
5#[derive(clap::Args)]
6pub struct InitCmd {
7  #[arg(long, default_value = "dmc.toml")]
8  pub path: PathBuf,
9}
10
11impl InitCmd {
12  pub fn run(self) -> DiagResult<Diagnostic<Code>> {
13    if self.path.exists() {
14      return Err(diag!(Code::ConfigExists, format!("refusing to overwrite existing {}", self.path.display())));
15    }
16
17    std::fs::write(&self.path, DEFAULT_CONFIG).map_err(|e| {
18      diag!(
19        Code::Custom { code: String::from("N001"), severity: duck_diagnostic::Severity::Note },
20        format!("write error: {}", e.to_string())
21      )
22    })?;
23
24    Ok(diag!(
25      Code::Custom { code: String::from("N001"), severity: duck_diagnostic::Severity::Note },
26      format!("wrote {}", self.path.display())
27    ))
28  }
29}
30
31const DEFAULT_CONFIG: &str = r#"# dmc.toml - Rust MDX compiler config.
32# Every option below is commented at its default; uncomment + change to override.
33
34# --- Engine ---------------------------------------------------------------
35# Project root used to resolve relative paths in collection patterns.
36# root = "."
37
38# Where compiled JSON indexes are written. One file per collection: <output_dir>/<name>.json
39output_dir = ".dmc"
40
41# Optional: name + format of the aggregated index file (when multiple collections).
42# output_name   = "index"
43# output_format = "esm"   # "esm" | "json"
44
45# Wipe output_dir before each build (also enabled by `--clean` flag).
46# clean = false
47
48# Abort on the first frontmatter validation failure (also enabled by `--strict` flag).
49# strict = false
50
51# Include rendered HTML in the per-record output (alongside `body`/`content`).
52# Sidecar always emits HTML when JS plugins are configured; this is for the
53# native render path.
54# include_html = false
55
56# --- Compile (markdown / mdx) ---------------------------------------------
57# GitHub-Flavored Markdown extensions: tables, strikethrough, autolinks, task lists.
58# markdown_gfm = true
59
60# Native HTML emit on (auto-disabled for files that go through the sidecar).
61# emit_html = true
62
63# Native MDX body emit on.
64# emit_body = true
65
66# Run a JS minifier on the emitted MDX body (requires sidecar).
67# mdx_minify = false
68
69# MDX output format: "module" wraps body as an ES module with the imports
70# rolled in; "function-body" returns just the function body string.
71# mdx_output_format = "function-body"
72
73# --- JS plugin pipelines (run via the Node sidecar) -----------------------
74# Each entry is either "package-name" or ["package-name", { ...options }].
75# Plugins resolve from the project's node_modules first, then sidecar's.
76#
77# Example:
78#   markdown_remark_plugins = [
79#     "remark-gfm",
80#     ["remark-toc", { tight = true }],
81#   ]
82#   markdown_rehype_plugins = [
83#     ["rehype-pretty-code", { theme = "github-dark" }],
84#   ]
85#
86# markdown_remark_plugins = []
87# markdown_rehype_plugins = []
88# mdx_remark_plugins      = []
89# mdx_rehype_plugins      = []
90
91# --- Asset handling -------------------------------------------------------
92# Copy files referenced by relative `![](...)` / `<a href="...">` into the
93# output bundle. Requires both `output_assets` and `output_base` set.
94# copy_linked_files = false
95# output_assets     = "static"
96# output_base       = "/"
97
98# --- Sidecar tuning (env-only, listed for reference) ----------------------
99# DMC_SIDECAR_POOL_SIZE  -> number of long-lived `node` processes (default min(cores, 4))
100# dmc_SIDECAR            -> override path to dmc-sidecar/index.mjs
101
102# --- Collections ----------------------------------------------------------
103# Each collection globs files under `base_dir` matching `pattern`, compiles
104# them, validates frontmatter against `schema` (optional), and writes
105# `<output_dir>/<name>.json`. The schema doubles as a TypeScript source --
106# `index.d.ts` ships a typed interface derived from it.
107[[collections]]
108name     = "docs"
109pattern  = "docs/**/*.{md,mdx}"
110base_dir = "."
111# single = false        # if true, expect exactly one match; emit a single object instead of an array
112
113# Frontmatter schema. dmc-schema descriptor (each node has `kind`):
114# string | number | boolean | array (with `item`) | object (with `fields`,
115# optional `passthrough`) | enum (with `variants`) | literal | union |
116# nullable | optional | default | record | tuple | intersection |
117# discriminatedUnion | isodate | path | slug | unique | file | image |
118# markdown | mdx | raw | toc | metadata | excerpt | coerce.{string,number,boolean,date}
119# Wrap a field in `{ kind = "optional", inner = { ... } }` to make it optional.
120schema = { kind = "object", fields = { title = { kind = "string" }, description = { kind = "optional", inner = { kind = "string" } }, date = { kind = "optional", inner = { kind = "isodate" } }, draft = { kind = "optional", inner = { kind = "boolean" } }, tags = { kind = "optional", inner = { kind = "array", item = { kind = "string" } } }, author = { kind = "optional", inner = { kind = "object", fields = { name = { kind = "string" }, url = { kind = "optional", inner = { kind = "string" } } } } } } }
121"#;