Skip to content

generate — write

Write

Functions

writeDocs

async function writeDocs(docs: GeneratedDoc[], outputPath: string, primarySourcePath: string, isMultiSource: boolean, options: WriteDocsOptions): Promise<WriteDocsResult>
TypeScript

Use writeDocs to persist AI-generated documentation to disk, automatically choosing the right file layout based on how your source was scanned.

Call this after skrypt generate has produced your GeneratedDoc[] array — it's the final step that turns in-memory doc objects into .mdx files your documentation site can serve. It handles three distinct output strategies (by-topic grouping, multi-source, and single-source) so you don't need to branch that logic yourself.

Parameters

NameTypeRequiredDescription
docsGeneratedDoc[]YesThe documentation objects returned by the generation step. Each entry maps to one or more output files.
outputPathstringYesAbsolute or relative path to the directory where .mdx files will be written. Created automatically if it doesn't exist.
primarySourcePathstringYesPath to the root of the scanned source — used to compute relative file paths and preserve directory structure in the output.
isMultiSourcebooleanYesSet to true when docs were generated from multiple source directories. Affects how output files are namespaced to avoid collisions.
optionsWriteDocsOptionsYesControls output strategy: pass byTopic: true to group related elements into topic pages instead of mirroring source file structure.

Returns

Returns a Promise<WriteDocsResult> that resolves once all files are written. The result contains the list of files created and a manifest entry you can pass to subsequent refresh or search-index steps.

Heads up

  • outputPath is written to eagerly — existing .mdx files at conflicting paths will be overwritten without warning. Point it at a dedicated output directory, not your source tree.
  • When byTopic and isMultiSource are both true, topic grouping takes precedence and source namespacing is applied within each topic file.

Example:

import { writeFile, mkdir } from "fs/promises";
import { join } from "path";

// Inline types — do not import from autodocs
interface GeneratedDoc {
  title: string;
  slug: string;
  content: string;
  sourceFile: string;
  topic?: string;
}

interface WriteDocsOptions {
  byTopic?: boolean;
}

interface WriteDocsResult {
  filesWritten: string[];
  manifest: Record<string, string>;
}

// Minimal self-contained implementation for demonstration
async function writeDocs(
  docs: GeneratedDoc[],
  outputPath: string,
  primarySourcePath: string,
  isMultiSource: boolean,
  options: WriteDocsOptions
): Promise<WriteDocsResult> {
  await mkdir(outputPath, { recursive: true });

  const filesWritten: string[] = [];
  const manifest: Record<string, string> = {};

  for (const doc of docs) {
    const subdir = options.byTopic && doc.topic ? doc.topic : "";
    const dir = subdir ? join(outputPath, subdir) : outputPath;
    await mkdir(dir, { recursive: true });

    const filename = `${doc.slug}.mdx`;
    const filePath = join(dir, filename);
    await writeFile(filePath, doc.content, "utf-8");

    filesWritten.push(filePath);
    manifest[doc.slug] = filePath;
  }

  return { filesWritten, manifest };
}

// Realistic usage: write docs generated from a payments SDK
const generatedDocs: GeneratedDoc[] = [
  {
    title: "createCharge",
    slug: "create-charge",
    content: "# createCharge\n\nUse `createCharge` to initiate a payment...",
    sourceFile: "/projects/payments-sdk/src/charges.ts",
    topic: "payments",
  },
  {
    title: "refundCharge",
    slug: "refund-charge",
    content: "# refundCharge\n\nUse `refundCharge` to reverse a captured payment...",
    sourceFile: "/projects/payments-sdk/src/charges.ts",
    topic: "payments",
  },
  {
    title: "createCustomer",
    slug: "create-customer",
    content: "# createCustomer\n\nUse `createCustomer` to store a payer's details...",
    sourceFile: "/projects/payments-sdk/src/customers.ts",
    topic: "customers",
  },
];

async function main() {
  try {
    const result = await writeDocs(
      generatedDocs,
      "./content/docs/api",
      "/projects/payments-sdk/src",
      false,
      { byTopic: true }
    );

    console.log("Files written:", result.filesWritten);
    // Files written: [
    //   './content/docs/api/payments/create-charge.mdx',
    //   './content/docs/api/payments/refund-charge.mdx',
    //   './content/docs/api/customers/create-customer.mdx'
    // ]

    console.log("Manifest:", result.manifest);
    // Manifest: {
    //   'create-charge': './content/docs/api/payments/create-charge.mdx',
    //   'refund-charge': './content/docs/api/payments/refund-charge.mdx',
    //   'create-customer': './content/docs/api/customers/create-customer.mdx'
    // }
  } catch (err) {
    console.error("Failed to write docs:", err);
  }
}

main();
TypeScript

writeAssets

async function writeAssets(docs: GeneratedDoc[], allElements: APIElement[], outputPath: string, primarySourcePath: string, configOutputPath: string, filesWritten: number, options: WriteAssetsOptions): Promise<void>
TypeScript

Use writeAssets to finalize a documentation generation run by writing all supplementary output files — the OpenAPI spec copy, llms.txt, AGENTS.md, and the doc manifest — after your primary MDX files have been generated.

Call this as the last step in a custom generation pipeline, after you've scanned source files and generated doc content. It handles everything that isn't the per-element MDX files themselves: machine-readable indexes, AI agent context files, and the manifest that powers incremental regeneration.

writeAssets coordinates several output concerns in one call: it copies any OpenAPI spec found at the source path, builds an llms.txt summary of your API surface for LLM consumption, generates an AGENTS.md file describing the codebase for AI coding agents, and writes a manifest used by skrypt generate to skip unchanged files on future runs.

NameTypeRequiredDescription
docsGeneratedDoc[]YesThe generated documentation objects produced earlier in the pipeline — used to build the manifest and llms.txt index.
allElementsAPIElement[]YesEvery API element scanned from source, including those that may not have generated docs — ensures the manifest and agent files reflect the full API surface.
outputPathstringYesAbsolute or relative path to the directory where all asset files will be written. Must already exist or be creatable.
primarySourcePathstringYesPath to the root of the scanned source — used to locate the OpenAPI spec and compute relative paths in the manifest.
configOutputPathstringYesPath to the config file written during skrypt init — embedded in the manifest so incremental runs can find it.
filesWrittennumberYesCount of MDX files written before this call — included in the manifest summary so you can audit what changed between runs.
optionsWriteAssetsOptionsYesControls optional behaviors: whether to generate llms.txt, AGENTS.md, topic grouping, and multi-language example output.

Returns Promise<void>. This function writes directly to disk and has no return value — check your outputPath directory for the generated files after it resolves.

Heads up:

  • filesWritten should reflect only the MDX doc files written before this call, not the assets this function writes itself — passing the wrong count will produce a misleading manifest diff on the next incremental run.
  • If outputPath doesn't exist, writeAssets will attempt to create it. If the path is invalid or write permissions are missing, it will throw a filesystem error with no cleanup of partial writes.

Example:

import { promises as fs } from 'fs'
import path from 'path'

// Inline types — do not import from autodocs
interface GeneratedDoc {
  elementName: string
  filePath: string
  content: string
  topic?: string
}

interface APIElement {
  name: string
  kind: 'function' | 'class' | 'interface' | 'type'
  filePath: string
  signature: string
}

interface WriteAssetsOptions {
  generateLlmsTxt?: boolean
  generateAgentsMd?: boolean
  byTopic?: boolean
  multiLang?: boolean
}

// Minimal self-contained mock of writeAssets
async function writeAssets(
  docs: GeneratedDoc[],
  allElements: APIElement[],
  outputPath: string,
  primarySourcePath: string,
  configOutputPath: string,
  filesWritten: number,
  options: WriteAssetsOptions
): Promise<void> {
  await fs.mkdir(outputPath, { recursive: true })

  // Write llms.txt — a plain-text index of the API surface for LLM consumption
  if (options.generateLlmsTxt) {
    const lines = [
      '# API Surface',
      `Generated from: ${primarySourcePath}`,
      '',
      ...allElements.map(el => `${el.kind} ${el.name}: ${el.signature}`)
    ]
    await fs.writeFile(path.join(outputPath, 'llms.txt'), lines.join('\n'))
  }

  // Write AGENTS.md — codebase context for AI coding agents
  if (options.generateAgentsMd) {
    const agentsMd = [
      '# AGENTS.md',
      '',
      `This codebase exposes ${allElements.length} public API elements.`,
      `Documentation lives in: ${outputPath}`,
      `Config: ${configOutputPath}`,
    ].join('\n')
    await fs.writeFile(path.join(outputPath, 'AGENTS.md'), agentsMd)
  }

  // Write manifest for incremental regeneration
  const manifest = {
    generatedAt: new Date().toISOString(),
    sourcePath: primarySourcePath,
    configPath: configOutputPath,
    filesWritten,
    totalElements: allElements.length,
    docs: docs.map(d => ({ name: d.elementName, file: d.filePath }))
  }
  await fs.writeFile(
    path.join(outputPath, 'manifest.json'),
    JSON.stringify(manifest, null, 2)
  )
}

// --- Usage ---
const generatedDocs: GeneratedDoc[] = [
  { elementName: 'createUser', filePath: 'src/users.ts', content: '# createUser\n...', topic: 'Users' },
  { elementName: 'deleteUser', filePath: 'src/users.ts', content: '# deleteUser\n...', topic: 'Users' },
]

const apiElements: APIElement[] = [
  { name: 'createUser', kind: 'function', filePath: 'src/users.ts', signature: 'createUser(email: string): Promise<User>' },
  { name: 'deleteUser', kind: 'function', filePath: 'src/users.ts', signature: 'deleteUser(id: string): Promise<void>' },
]

const options: WriteAssetsOptions = {
  generateLlmsTxt: true,
  generateAgentsMd: true,
  byTopic: false,
  multiLang: false,
}

;(async () => {
  try {
    await writeAssets(
      generatedDocs,
      apiElements,
      './docs/output',
      './src',
      './skrypt.config.json',
      2,       // 2 MDX files were written before this call
      options
    )

    const manifest = JSON.parse(
      await fs.readFile('./docs/output/manifest.json', 'utf-8') as string
    )

    console.log('Assets written successfully')
    console.log(`Manifest: ${manifest.filesWritten} files, ${manifest.totalElements} elements, generated at ${manifest.generatedAt}`)
    // → Assets written successfully
    // → Manifest: 2 files, 2 elements, generated at 2024-11-15T10:23:41.000Z
  } catch (err) {
    console.error('Failed to write assets:', err)
    process.exit(1)
  }
})()
TypeScript
Was this helpful?