Get the FREE Ultimate OpenClaw Setup Guide →

smol-toml

Scanned
npx machina-cli add skill nklisch/skilltap/smol-toml --openclaw
Files (1)
SKILL.md
6.1 KB

smol-toml — TOML Parser Reference

Small, zero-dependency, TOML v1.0.0 spec-compliant parser and serializer. Works in Bun, Node, Deno, and browsers (ESM only).

Install: bun add smol-toml

Import: import { parse, stringify, TomlError, TomlDate } from "smol-toml"

parse(toml: string): Record<string, TomlPrimitive>

Parses a TOML string into a JavaScript object.

import { parse } from "smol-toml"

const config = parse(`
[defaults]
also = ["claude-code"]
yes = false
scope = ""

[security]
scan = "static"
on_warn = "prompt"
threshold = 5

[[taps]]
name = "home"
url = "https://gitea.example.com/nathan/my-skills-tap"
`)

config.defaults.also       // ["claude-code"]
config.security.threshold  // 5
config.taps                // [{ name: "home", url: "https://..." }]

Type mapping (TOML → JavaScript)

TOMLJavaScriptNotes
StringstringAll four string types (basic, literal, multiline)
Integernumber or bigintbigint if outside safe integer range
FloatnumberIncludes Infinity, -Infinity, NaN
Booleanboolean
Offset Date-TimeTomlDatee.g. 1979-05-27T07:32:00Z
Local Date-TimeTomlDatee.g. 1979-05-27T07:32:00
Local DateTomlDatee.g. 1979-05-27
Local TimeTomlDatee.g. 07:32:00
ArrayArrayMust be homogeneous per TOML spec
TableRecord<string, TomlPrimitive>Plain object
Inline TableRecord<string, TomlPrimitive>Same as table after parsing
Array of Tables ([[...]])Array<Record<string, TomlPrimitive>>Array of objects

TomlPrimitive type

type TomlPrimitive =
  | string
  | number
  | bigint
  | boolean
  | TomlDate
  | TomlPrimitive[]
  | { [key: string]: TomlPrimitive }

stringify(obj: Record<string, TomlPrimitive>): string

Serializes a JavaScript object to a TOML string.

import { stringify } from "smol-toml"

const toml = stringify({
  defaults: {
    also: ["claude-code", "cursor"],
    yes: false,
    scope: "",
  },
  security: {
    scan: "static",
    on_warn: "prompt",
    require_scan: false,
    agent: "",
    threshold: 5,
    max_size: 51200,
    ollama_model: "",
  },
  "agent-mode": {
    enabled: false,
    scope: "project",
  },
  taps: [],
})

What stringify handles

  • Strings → properly escaped basic strings
  • Numbers → integers or floats
  • bigint → TOML integers
  • Booleans → true/false
  • Date objects → TOML date-time
  • TomlDate → preserves original format (local vs offset)
  • Arrays of primitives → TOML arrays [1, 2, 3]
  • Arrays of objects → array of tables [[section]]
  • Nested objects → TOML table sections [parent.child]

What stringify throws on

  • undefined values
  • null values
  • Functions, symbols
  • Mixed arrays (primitives + objects together)
  • Circular references

TomlError

Custom error thrown on parse failure. Has line/column info for diagnostics.

import { parse, TomlError } from "smol-toml"

try {
  parse(raw)
} catch (e) {
  if (e instanceof TomlError) {
    console.error(`TOML error at line ${e.line}, col ${e.column}:`)
    console.error(e.codeblock)  // Visual pointer to error location
    // e.message — human-readable description
  }
}

Properties:

PropertyTypeDescription
linenumberLine number (1-indexed)
columnnumberColumn number (1-indexed)
codeblockstringFormatted snippet with ^ pointer
messagestringError description

TomlDate

Represents TOML date/time values. Preserves which of the four TOML date types was used.

import { TomlDate } from "smol-toml"

const d = new TomlDate("1979-05-27T07:32:00Z")
d.isDateTime()       // true (Offset Date-Time)
d.isLocalDateTime()  // false
d.isLocalDate()      // false
d.isLocalTime()      // false
d.toDate()           // JavaScript Date object
d.toString()         // "1979-05-27T07:32:00Z"

// Local types preserve their format through stringify round-trips
const lt = new TomlDate("07:32:00")
lt.isLocalTime()     // true
lt.toString()        // "07:32:00"

Pattern: skilltap Config Read/Write

import { parse, stringify, TomlError } from "smol-toml"
import { readFile, writeFile } from "node:fs/promises"
import { ConfigSchema } from "./schemas/config"
import type { Result } from "./types"

export async function loadConfig(path: string): Result<Config> {
  let raw: string
  try {
    raw = await readFile(path, "utf-8")
  } catch {
    // File doesn't exist — create default
    return { ok: true, value: ConfigSchema.parse({}) }
  }

  let parsed: Record<string, unknown>
  try {
    parsed = parse(raw)
  } catch (e) {
    if (e instanceof TomlError) {
      return {
        ok: false,
        error: new UserError(
          `Invalid config.toml at line ${e.line}: ${e.message}`
        ),
      }
    }
    throw e
  }

  const result = ConfigSchema.safeParse(parsed)
  if (!result.success) {
    return {
      ok: false,
      error: new UserError(`Config validation failed: ${result.error.message}`),
    }
  }
  return { ok: true, value: result.data }
}

export async function saveConfig(path: string, config: Config): Promise<void> {
  const toml = stringify(config)
  await writeFile(path, toml, "utf-8")
}

Limitations

  • No comment preservation: Comments are lost during parse → stringify round-trips
  • No format preservation: Original whitespace, key ordering, and inline-vs-standard table choices are not preserved
  • No streaming: Entire document must be a string
  • ESM only: No CommonJS export
  • TOML v1.0.0 only: No TOML 1.1 draft features
  • Inline tables: Must be single-line per TOML v1.0 spec (smol-toml enforces this)
  • Duplicate keys: Throws TomlError (per spec)

Source

git clone https://github.com/nklisch/skilltap/blob/main/.agents/skills/smol-toml/SKILL.mdView on GitHub

Overview

smol-toml is a tiny, spec-compliant TOML v1.0.0 parser and serializer with zero dependencies. It works in Bun, Node, Deno, and browsers (ESM only) and exposes parse, stringify, TomlError, and TomlDate to handle config.toml data in JavaScript projects.

How This Skill Works

It parses a TOML string into a JavaScript object using a defined TomlPrimitive type mapping, returning a Record<string, TomlPrimitive>. stringify performs the reverse, turning a JavaScript object into a TOML string, including support for TomlDate and arrays of tables. TomlError provides diagnostics on parse failures with line/column and a codeblock pointer.

When to Use It

  • Reading a config.toml file at startup to configure an app
  • Writing updated configuration back to disk after runtime changes
  • Working with repeated sections using arrays of tables ([[taps]])
  • Diagnosing parse errors during config loading with line/column info
  • Using in Bun, Node, Deno, or browser environments via ES module imports

Quick Start

  1. Step 1: bun add smol-toml
  2. Step 2: import { parse, stringify } from 'smol-toml'
  3. Step 3: Use parse(tomlString) to read or stringify(obj) to write TOML

Best Practices

  • Use parse for consuming TOML input and stringify for persisting a JS object to TOML
  • Leverage TomlDate to preserve TOML date/time semantics (Offset, Local variants)
  • Ensure arrays are homogeneous (per TOML rules) to avoid mixed-type arrays
  • Catch parse failures with TomlError and inspect line, column, and codeblock
  • Avoid undefined or null values when passing objects to stringify

Example Use Cases

  • Parse a config.toml with [defaults] and [[taps]] to access config.defaults.also and config.taps
  • Serialize a JS config object to TOML including TomlDate values and nested tables
  • Parse date/time values and observe TomlDate types for local vs offset times
  • Handle an array of tables (taps) to model repeatable sections in config
  • Catch and inspect TomlError to pinpoint syntax issues with line/column and codeblock

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers