import { execFileSync } from "node:child_process";
import { mkdir, readFile, rm, writeFile, copyFile } from "node:fs/promises";
import path from "node:path";
import process from "node:process";
const root = process.cwd();
const wryRoot = path.resolve(process.env.WRY_REPO_PATH ?? path.join(root, "..", "wry"));
const specDir = path.join(wryRoot, "crates", "toml-spec", "spec");
const schemaPath = path.join(specDir, "spec.generated.json");
const docsDir = path.join(root, "src", "content", "docs");
const referenceDir = path.join(docsDir, "reference");
const typesDir = path.join(referenceDir, "types");
const publicSpecDir = path.join(root, "public", "spec");
const copiedSpecs = ["spec.generated.json", "spec.generated.md", "spec.yaml"];
function frontmatter({ title, description }) {
return [
"---",
`title: ${JSON.stringify(title)}`,
description ? `description: ${JSON.stringify(description)}` : undefined,
"---",
""
]
.filter(Boolean)
.join("\n");
}
function slugify(name) {
return name
.replace(/([a-z0-9])([A-Z])/g, "$1-$2")
.replace(/[^A-Za-z0-9]+/g, "-")
.replace(/^-|-$/g, "")
.toLowerCase();
}
function trimDescription(description) {
return typeof description === "string" ? description.trim() : "";
}
function escapePipe(value) {
return String(value).replaceAll("|", "\\|").replaceAll("\n", "
");
}
function inlineCode(value) {
return `\`${String(value).replaceAll("`", "\\`")}\``;
}
function refName(ref) {
const prefix = "#/$defs/";
return typeof ref === "string" && ref.startsWith(prefix) ? ref.slice(prefix.length) : null;
}
function linkRef(ref) {
const name = refName(ref);
if (!name) {
return inlineCode(ref);
}
return `[${name}](/reference/types/${slugify(name)}/)`;
}
function schemaType(schema) {
if (!schema || typeof schema !== "object") {
return "unknown";
}
if (schema.$ref) {
return linkRef(schema.$ref);
}
if (schema.const !== undefined) {
return `constant ${inlineCode(schema.const)}`;
}
if (Array.isArray(schema.enum)) {
return "enum";
}
if (schema.type === "array") {
return `array of ${schemaType(schema.items)}`;
}
if (schema.type) {
return Array.isArray(schema.type) ? schema.type.map(inlineCode).join(" or ") : inlineCode(schema.type);
}
if (schema.anyOf) {
return "one of several forms";
}
if (schema.oneOf) {
return "one of several forms";
}
if (schema.allOf) {
return "combination";
}
if (schema.properties) {
return inlineCode("object");
}
return "unspecified";
}
function describeConstraints(schema) {
const rows = [];
if (schema.pattern) rows.push(["Pattern", inlineCode(schema.pattern)]);
if (schema.minimum !== undefined) rows.push(["Minimum", inlineCode(schema.minimum)]);
if (schema.maximum !== undefined) rows.push(["Maximum", inlineCode(schema.maximum)]);
if (schema.exclusiveMinimum !== undefined) rows.push(["Exclusive minimum", inlineCode(schema.exclusiveMinimum)]);
if (schema.exclusiveMaximum !== undefined) rows.push(["Exclusive maximum", inlineCode(schema.exclusiveMaximum)]);
if (schema.minLength !== undefined) rows.push(["Minimum length", inlineCode(schema.minLength)]);
if (schema.maxLength !== undefined) rows.push(["Maximum length", inlineCode(schema.maxLength)]);
if (schema.minItems !== undefined) rows.push(["Minimum items", inlineCode(schema.minItems)]);
if (schema.maxItems !== undefined) rows.push(["Maximum items", inlineCode(schema.maxItems)]);
return rows;
}
function heading(level, text) {
return `${"#".repeat(Math.min(level, 6))} ${text}`;
}
function variantLabel(schema, index) {
const tag = schema?.properties?.type?.const;
if (tag !== undefined) {
return `${inlineCode(`type = "${tag}"`)}`;
}
if (schema?.const !== undefined) {
return inlineCode(schema.const);
}
if (schema?.$ref) {
return linkRef(schema.$ref);
}
if (schema?.type === "array") {
return "array";
}
if (schema?.type) {
return Array.isArray(schema.type) ? schema.type.join(" or ") : schema.type;
}
return `form ${index + 1}`;
}
function renderSchema(schema, level = 2, seen = new Set()) {
if (!schema || typeof schema !== "object") {
return "";
}
const out = [];
const description = trimDescription(schema.description);
if (description) {
out.push(description, "");
}
const constraints = describeConstraints(schema);
if (schema.$ref || schema.type || schema.const !== undefined || constraints.length || Array.isArray(schema.enum)) {
out.push('
${inlineCode(name)} ${required.has(name) ? "(required)" : "(optional)"}
`); out.push(`Type: ${schemaType(property)}
`); const propertyDescription = trimDescription(property.description); if (propertyDescription) { out.push("", propertyDescription); } const propertyConstraints = describeConstraints(property); if (propertyConstraints.length) { out.push("", "| Constraint | Value |", "| --- | --- |"); for (const [label, value] of propertyConstraints) { out.push(`| ${escapePipe(label)} | ${escapePipe(value)} |`); } } if (property.items?.$ref) { out.push("", `Each item should be ${linkRef(property.items.$ref)}.`); } if ((property.anyOf || property.oneOf || property.properties) && !property.$ref) { out.push("", renderSchema(property, level + 1, seen)); } out.push("