{
  "type": "module",
  "source": "doc/api/creating-generators.md",
  "modules": [
    {
      "textRaw": "Creating Generators",
      "name": "creating_generators",
      "type": "module",
      "desc": "<p>This guide explains how to create new documentation generators for <code>@doc-kit/core</code>.</p>",
      "modules": [
        {
          "textRaw": "Generator Concepts",
          "name": "generator_concepts",
          "type": "module",
          "desc": "<p>Generators in <code>doc-kit</code> transform API documentation through a pipeline. Each generator:</p>\n<ol>\n<li><strong>Takes input</strong> from a previous generator or raw files</li>\n<li><strong>Processes the data</strong> into a different format</li>\n<li><strong>Yields output</strong> for the next generator or final output</li>\n</ol>",
          "modules": [
            {
              "textRaw": "Generator Pipeline",
              "name": "generator_pipeline",
              "type": "module",
              "desc": "<pre><code class=\"language-text\">Raw Markdown Files\n    ↓\n  [ast] - Parse to MDAST\n    ↓\n  [metadata] - Extract structured metadata\n    ↓\n  [jsx-ast] - Convert to JSX AST\n    ↓\n  [html] - Generate HTML/CSS/JS bundles\n</code></pre>\n<p>Each generator declares its dependency using the <code>dependsOn</code> field, allowing automatic pipeline construction. Each stage is documented alongside the rest of the <a href=\"./generators.html#pipeline-stages\">generators</a>.</p>",
              "displayName": "Generator Pipeline"
            }
          ],
          "displayName": "Generator Concepts"
        },
        {
          "textRaw": "Generator Structure",
          "name": "generator_structure",
          "type": "module",
          "desc": "<p>A generator is defined as a module exporting an object conforming to the <code>GeneratorMetadata</code> interface.</p>",
          "displayName": "Generator Structure"
        },
        {
          "textRaw": "Creating a Basic Generator",
          "name": "creating_a_basic_generator",
          "type": "module",
          "modules": [
            {
              "textRaw": "Step 1: Create the Generator Files",
              "name": "step_1:_create_the_generator_files",
              "type": "module",
              "desc": "<p>Create a new directory in your project:</p>\n<pre><code class=\"language-text\">/\n├── index.mjs         # Generator metadata (required)\n├── generate.mjs      # Generator implementation (required)\n├── constants.mjs     # Constants (optional)\n├── types.d.ts        # TypeScript types (required)\n└── utils/            # Utility functions (optional)\n    └── formatter.mjs\n</code></pre>",
              "displayName": "Step 1: Create the Generator Files"
            },
            {
              "textRaw": "Step 2: Define Types",
              "name": "step_2:_define_types",
              "type": "module",
              "desc": "<p>Create a <code>types.d.ts</code> file containing a <code>Generator</code> export. Use this when typing your generator.</p>\n<pre><code class=\"language-typescript\">export type Generator = GeneratorMetadata&#x3C;\n  {\n    // If your generator supports a custom configuration,\n    // define it here\n    myCustomOption: string;\n  },\n  Generate&#x3C;InputToMyGenerator, Promise&#x3C;OutputOfMyGenerator>>,\n  // If your generator supports parallel processing:\n  ProcessChunk&#x3C;\n    InputToMyParallelProcessor,\n    OutputOfMyParallelProcessor,\n    DependenciesOfMyParallelProcessor\n  >\n>;\n</code></pre>",
              "displayName": "Step 2: Define Types"
            },
            {
              "textRaw": "Step 3: Define Generator Metadata",
              "name": "step_3:_define_generator_metadata",
              "type": "module",
              "desc": "<p>A generator module's default export is a plain object with its metadata and\nimplementation. Create it in <code>index.mjs</code>:</p>\n<pre><code class=\"language-mjs\">import { generate } from './generate.mjs';\n\n/**\n * Generates output in MyFormat.\n *\n * @type {import('./types').Generator}\n */\nexport default {\n  name: 'my-format',\n\n  description: 'Generates documentation in MyFormat',\n\n  // This generator depends on the metadata generator. Dependencies are\n  // declared as import specifiers, so they can live in any package.\n  dependsOn: '@doc-kit/core/metadata',\n\n  defaultConfiguration: {\n    // If your generator supports a custom configuration, define the defaults here\n    myCustomOption: 'myDefaultValue',\n\n    // All generators support options in the GlobalConfiguration object\n    // To override the defaults, they can be specified here\n    ref: 'overriddenRef',\n  },\n\n  generate,\n};\n</code></pre>",
              "displayName": "Step 3: Define Generator Metadata"
            },
            {
              "textRaw": "Step 4: Implement the Generator Logic",
              "name": "step_4:_implement_the_generator_logic",
              "type": "module",
              "desc": "<p>Create the generator implementation in <code>generate.mjs</code>:</p>\n<pre><code class=\"language-mjs\">import { writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport getConfig from '../../utils/configuration/index.mjs';\n\n/**\n * Main generation function\n *\n * @type {import('./types').Generator['generate']}\n */\nexport async function generate(input, worker) {\n  const config = getConfig('my-format');\n\n  // Transform input to your format\n  const result = transformToMyFormat(input, config.version);\n\n  // Write to file if output directory specified\n  if (config.output) {\n    await writeFile(\n      join(config.output, 'documentation.myformat'),\n      result,\n      'utf-8'\n    );\n  }\n\n  return result;\n}\n\n/**\n * Transform metadata entries to MyFormat\n * @param {Array&#x3C;MetadataEntry>} entries\n * @param {import('semver').SemVer} version\n * @returns {string}\n */\nfunction transformToMyFormat(entries, version) {\n  // Your transformation logic here\n  return entries\n    .map(entry => `${entry.api}: ${entry.heading.data.name}`)\n    .join('\\n');\n}\n</code></pre>",
              "displayName": "Step 4: Implement the Generator Logic"
            },
            {
              "textRaw": "Step 5: Make the Generator Loadable",
              "name": "step_5:_make_the_generator_loadable",
              "type": "module",
              "desc": "<p>Generators are loaded dynamically by import specifier. Anything that resolves\nto a module whose default export is a generator works as a <code>--target</code>:</p>\n<pre><code class=\"language-bash\"># A package (subpath) export\nnpx @doc-kit/cli generate -t @my-scope/my-package/my-format ...\n\n# A local file\nnpx @doc-kit/cli generate -t ./generators/my-format/index.mjs ...\n</code></pre>\n<p>Built-in generators additionally get a shorthand alias in\n<code>packages/core/src/generators/index.mjs</code>, which maps the name users type to\nthe import specifier it resolves to:</p>\n<pre><code class=\"language-mjs\">export const publicGenerators = {\n  'json-simple': '@doc-kit/core/json-simple',\n  'my-format': '@doc-kit/core/my-format', // Add this\n  // ... other generators\n};\n</code></pre>\n<p>If the generator lives in this repository, also add a matching subpath to the\n<code>exports</code> map of its package's <code>package.json</code>.</p>",
              "displayName": "Step 5: Make the Generator Loadable"
            }
          ],
          "displayName": "Creating a Basic Generator"
        },
        {
          "textRaw": "Parallel Processing with Workers",
          "name": "parallel_processing_with_workers",
          "type": "module",
          "desc": "<p>For generators processing large datasets, implement parallel processing using worker threads.</p>",
          "modules": [
            {
              "textRaw": "Implementing Worker-Based Processing",
              "name": "implementing_worker-based_processing",
              "type": "module",
              "desc": "<p>First, define the generator metadata in <code>index.mjs</code>:</p>\n<pre><code class=\"language-mjs\">import { generate, processChunk } from './generate.mjs';\n\n/**\n * @type {import('./types').Generator}\n */\nexport default {\n  name: 'parallel-generator',\n\n  description: 'Processes data in parallel',\n\n  dependsOn: '@doc-kit/core/metadata',\n\n  // Indicates this generator has a processChunk implementation\n  hasParallelProcessor: true,\n\n  generate,\n  processChunk,\n};\n</code></pre>\n<p>Then, implement both <code>processChunk</code> and <code>generate</code> in <code>generate.mjs</code>:</p>\n<pre><code class=\"language-mjs\">import getConfig from '../../utils/configuration/index.mjs';\n\n/**\n * Process a chunk of items in a worker thread.\n * This function runs in isolated worker threads.\n *\n * @type {import('./types').Generator['processChunk']}\n */\nexport async function processChunk(fullInput, itemIndices, deps) {\n  const results = [];\n\n  // Process only the items at specified indices\n  for (const idx of itemIndices) {\n    const item = fullInput[idx];\n    const result = await processItem(item, deps);\n    results.push(result);\n  }\n\n  return results;\n}\n\n/**\n * Main generation function that orchestrates worker threads\n *\n * @type {import('./types').Generator['generate']}\n */\nexport async function* generate(input, worker) {\n  // Configuration for this generator is based on its name\n  const config = getConfig('my-format');\n\n  // Prepare serializable dependencies\n  const deps = {\n    version: config.version,\n    // ...other config\n  };\n\n  // Stream chunks as they complete\n  for await (const chunkResult of worker.stream(input, deps)) {\n    // Process chunk result if needed\n    yield chunkResult;\n  }\n}\n</code></pre>",
              "displayName": "Implementing Worker-Based Processing"
            },
            {
              "textRaw": "Key Points for Worker Processing",
              "name": "key_points_for_worker_processing",
              "type": "module",
              "desc": "<ol>\n<li><strong><code>processChunk</code> executes in worker threads</strong> - No access to main thread state</li>\n<li><strong>Only serializable data</strong> can be passed to workers (no functions, classes, etc.)</li>\n<li><strong><code>fullInput</code> and <code>itemIndices</code></strong> - Workers receive full input but only process specified indices</li>\n<li><strong><code>deps</code> must be serializable</strong> - Pass only JSON-compatible data</li>\n</ol>",
              "displayName": "Key Points for Worker Processing"
            },
            {
              "textRaw": "When to Use Workers",
              "name": "when_to_use_workers",
              "type": "module",
              "desc": "<p>Use parallel processing when:</p>\n<ul>\n<li>Processing many independent items (files, modules, entries)</li>\n<li>Each item takes significant time to process</li>\n<li>Operations are CPU-intensive</li>\n</ul>\n<p>Don't use workers when:</p>\n<ul>\n<li>Items have dependencies on each other</li>\n<li>Output must be in specific order</li>\n<li>Operation is I/O bound rather than CPU bound</li>\n</ul>",
              "displayName": "When to Use Workers"
            }
          ],
          "displayName": "Parallel Processing with Workers"
        },
        {
          "textRaw": "Streaming Results",
          "name": "streaming_results",
          "type": "module",
          "desc": "<p>Generators can yield results as they're produced using async generators.</p>\n<p>Define the generator metadata in <code>index.mjs</code>:</p>\n<pre><code class=\"language-mjs\">import { generate, processChunk } from './generate.mjs';\n\n/**\n * @type {import('./types').Generator}\n */\nexport default {\n  name: 'streaming-generator',\n\n  description: 'Streams results as they are ready',\n\n  dependsOn: '@doc-kit/core/metadata',\n\n  hasParallelProcessor: true,\n\n  generate,\n  processChunk,\n};\n</code></pre>\n<p>Implement the generator in <code>generate.mjs</code>:</p>\n<pre><code class=\"language-mjs\">/**\n * Process a chunk of data\n *\n * @type {import('./types').Generator['processChunk']}\n */\nexport async function processChunk(fullInput, itemIndices, deps) {\n  // Process chunk\n  return results;\n}\n\n/**\n * Generator function that yields results incrementally\n *\n * @type {import('./types').Generator['generate']}\n */\nexport async function* generate(input, worker) {\n  // Stream results as workers complete chunks\n  for await (const chunkResult of worker.stream(input, {})) {\n    // Yield immediately - downstream can start processing\n    yield chunkResult;\n  }\n}\n</code></pre>",
          "modules": [
            {
              "textRaw": "Benefits of Streaming",
              "name": "benefits_of_streaming",
              "type": "module",
              "desc": "<ul>\n<li><strong>Reduced memory usage</strong> - Process data in chunks</li>\n<li><strong>Earlier downstream starts</strong> - Next generator can begin before this one finishes</li>\n<li><strong>Better parallelism</strong> - Multiple generators can work simultaneously</li>\n</ul>",
              "displayName": "Benefits of Streaming"
            },
            {
              "textRaw": "Non-Streaming Generators",
              "name": "non-streaming_generators",
              "type": "module",
              "desc": "<p>Some generators must collect all input before processing.</p>\n<p>Generator metadata in <code>index.mjs</code>:</p>\n<pre><code class=\"language-mjs\">import { generate } from './generate.mjs';\n\n/**\n * @type {import('./types').Generator}\n */\nexport default {\n  name: 'batch-generator',\n\n  description: 'Requires all input at once',\n\n  dependsOn: '@doc-kit/generator-react/jsx-ast',\n\n  generate,\n};\n</code></pre>\n<p>Implementation in <code>generate.mjs</code>:</p>\n<pre><code class=\"language-mjs\">/**\n * Non-streaming - returns Promise instead of AsyncGenerator\n *\n * @type {import('./types').Generator['generate']}\n */\nexport async function generate(input, worker) {\n  // Collect all input (if dependency is streaming, this waits for completion)\n  const allData = await collectAll(input);\n\n  // Process everything together\n  const result = processBatch(allData);\n\n  return result;\n}\n</code></pre>\n<p>Use non-streaming when:</p>\n<ul>\n<li>You need all data to make decisions (e.g., code splitting, global analysis)</li>\n<li>Output format requires complete dataset</li>\n<li>Cross-references between items need resolution</li>\n</ul>",
              "displayName": "Non-Streaming Generators"
            }
          ],
          "displayName": "Streaming Results"
        },
        {
          "textRaw": "Generator Dependencies",
          "name": "generator_dependencies",
          "type": "module",
          "modules": [
            {
              "textRaw": "Declaring Dependencies",
              "name": "declaring_dependencies",
              "type": "module",
              "desc": "<p>In <code>index.mjs</code>:</p>\n<pre><code class=\"language-mjs\">import { generate } from './generate.mjs';\n\nexport default {\n  name: 'my-generator',\n\n  // This generator requires the metadata generator's output. The dependency\n  // is an import specifier, so it may point at any installed package.\n  dependsOn: '@doc-kit/core/metadata',\n\n  // ... other metadata\n\n  generate,\n};\n</code></pre>\n<p>In <code>generate.mjs</code>:</p>\n<pre><code class=\"language-mjs\">export async function generate(input, worker) {\n  // input contains the output from 'metadata' generator\n}\n</code></pre>",
              "displayName": "Declaring Dependencies"
            }
          ],
          "displayName": "Generator Dependencies"
        },
        {
          "textRaw": "File Output",
          "name": "file_output",
          "type": "module",
          "modules": [
            {
              "textRaw": "Writing Output Files",
              "name": "writing_output_files",
              "type": "module",
              "desc": "<p>In <code>generate.mjs</code>:</p>\n<pre><code class=\"language-mjs\">import { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport getConfig from '../../utils/configuration/index.mjs';\n\nexport async function generate(input, worker) {\n  const config = getConfig('my-format');\n\n  if (!config.output) {\n    // Return data without writing\n    return result;\n  }\n\n  // Ensure directory exists\n  await mkdir(config.output, { recursive: true });\n\n  // Write single file\n  await writeFile(join(config.output, 'output.txt'), content, 'utf-8');\n\n  // Write multiple files\n  for (const item of items) {\n    await writeFile(\n      join(config.output, `${item.name}.txt`),\n      item.content,\n      'utf-8'\n    );\n  }\n\n  return result;\n}\n</code></pre>",
              "displayName": "Writing Output Files"
            },
            {
              "textRaw": "Copying Assets",
              "name": "copying_assets",
              "type": "module",
              "desc": "<pre><code class=\"language-mjs\">import { cp } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport getConfig from '../../utils/configuration/index.mjs';\n\nexport async function generate(input, worker) {\n  const config = getConfig('my-format');\n\n  if (config.output) {\n    // Copy asset directory\n    await cp(\n      new URL('./assets', import.meta.url),\n      join(config.output, 'assets'),\n      { recursive: true }\n    );\n  }\n\n  return result;\n}\n</code></pre>",
              "displayName": "Copying Assets"
            }
          ],
          "displayName": "File Output"
        }
      ],
      "displayName": "Creating Generators"
    }
  ]
}