Skip to content

Documentation toolchain ​

How the documentation under docs/ is produced, and which parts of it you may edit by hand.

This covers the documentation toolchain only. For the general development loop (lint, static analysis, tests, and what to run before a pull request) see CONTRIBUTING.md.

Generated pages: do not edit ​

These pages are written by composer docs:gen. Editing them directly is wasted work: the next docs:gen overwrites your changes, and so does composer docs:build, which runs docs:gen first.

PageBuilt from
reference/annotations.mdsrc/Annotations/ docblocks + snippets/preamble_annotations.md
reference/attributes.mdsrc/Attributes/ docblocks + snippets/preamble_attributes.md
reference/spec-attributes.mdsrc/Spec/ docblocks + snippets/preamble_spec-attributes.md
reference/processors.mdsrc/Processors/ docblocks + snippets/preamble_processors.md + prose in ProcessorGenerator
reference/augmenters.mdsrc/Augmenter/ docblocks + snippets/preamble_augmenters.md + prose in AugmenterGenerator
reference/extension-points.mddocblocks of the default translators and resolvers + snippets/preamble_extension-points.md
reference/mergers.mdsrc/Merge/ docblocks + snippets/preamble_mergers.md
guide/examples.mdexample sources + the per-example docs/examples/specs/*/Readme.md

To change one of these, change its source and re-run composer docs:gen.

Note that some prose lives inside the generators rather than in any markdown file. The -c and -D explanations in the "Configuration" sections are string literals in tools/src/Docs/Reference/{Augmenter,Processor}Generator.php.

Every generator renders through tools/src/Docs/Sections/. Renderer builds only the page frame: preamble, headers, and the example blocks. Parameters render as a definition list. A description is prose with its own paragraph breaks and a type arrives HTML-escaped, so both need markup that reaches the page without the markdown parser reading it again.

Everything else under docs/ is hand-written, including the top-level docs/examples/Readme.md, since only the per-example ones feed the generated page.

docs:gen is a drift check ​

The generators are deterministic, and committed output is expected to match its source. So:

shell
composer docs:gen && git status --porcelain docs/

Any output means the committed pages have drifted, and the regenerated version is the correct one. Worth running before opening a pull request.

Run it with an otherwise-clean tree, or scope the git status to the generated pages. docs/reference/ holds hand-written ones too, so a directory-wide check reports your own edits as drift.

Commands ​

CommandNotes
composer docs:genregenerate the pages listed above
composer docs:buildruns docs:gen, then builds the static site
composer docs:devlocal preview, long-running. It prints its URL on startup and does not return

What counts as a documented config setting ​

reference/augmenters.md and reference/processors.md list the options accepted by -c name.option=value. A setting qualifies when it is a constructor parameter that is not object typed:

  • constructor parameters are the public configuration contract, by convention
  • object typed parameters (factories, resolvers, the generator) are collaborators, not settings, and cannot be expressed as a CLI value

This is implemented once, in DocGenerator::configurableParameters(), and mirrors what Utils\Pipeline::getConfig() reports at runtime. The two are aligned by hand rather than by construction. If you change one, check the other. The check is that ./bin/openapi --mode spec -D src lists exactly the settings the reference page documents.

CLI behavior worth knowing ​

  • -D / --defaults prints the resolved default config, but still requires the paths argument: ./bin/openapi --mode spec -D src, not ./bin/openapi --mode spec -D.
  • --version sets the target OpenAPI version, not the tool version.
  • Help output is standard Symfony Console format, from ./bin/openapi -h.
  • Unknown -c keys are reported as warnings in spec mode, via Pipeline::configure(). In classic mode they are silently ignored, because configuration is routed through Generator::setConfig() instead. A typo in a classic -c key fails invisibly.