# Documentation generator ```bash nupp doc site -o build/docs src nupp doc markdown -o docs/api.md src nupp doc both -o build/docs ``` This site is built by it. `nupp doc` reads the parser's lossless CST and never invokes the checker or the code generator, so a documentation build costs parsing and rendering alone. Unchanged output files are left untouched. ``` nupp doc [site|markdown|both] [-o PATH] [--title TITLE] [--all] [path...] ``` The format is a positional word rather than a flag, and `md` is accepted for `markdown`. With none, the manifest's configured format is used, and `site` if it has none. Anything in first position that is not a format word is a path. `nupp doc` needs [lunamark](https://github.com/jgm/lunamark) and stops with a message if it is missing. Scintillua is optional: without it, a fence in a language it cannot load renders as escaped text. Both are ordinary [rock dependencies](build.md#rock-dependencies), so a docs target that declares them has them installed by the command that renders: ```lua docs = { kind = "docs", dependencies = { "lunamark", "scintillua" }, sources = { "src" }, } ``` ## Doc comments Two forms, and they are different. **A long comment at the very top of a file** is that file's module documentation, kept as Markdown. Only whitespace may precede it, and an ordinary `--` header does not count. ```nupp --[[ What this module is for. Prose here is rendered as Markdown. ]] ``` **A run of `---` line comments** immediately above a declaration documents it: ```nupp --- Opens a session against the account service. --- --- @param id the stable account identifier --- @return the open session --- @raises when the service refuses the connection @owned(closeSession) local function openSession(id: uint64): Session ``` Only the final adjacent run counts. An ordinary `--` comment or a blank line is a hard boundary, so a copyright header cannot become the first declaration's documentation. ### Tags ``` Tag Shape ───────────────────────── ────────────────────────────────── @param Named, by parameter @field Named, by field @typearg Named, by type parameter @return Listed, one per occurrence, in order @returns The same tag @raises Listed, one per occurrence, in order @module [text] Overrides the file's module blurb @export, @public Force a declaration public @local Keep a declaration out; --all brings it back @namespace [prefix] Document a shape's own fields as modules ``` A tag's description continues onto any following indented line. Any other `@name` is kept as a tag with its value. `@namespace` is for a shape with no file of its own to be documented from — an ambient global declared once, whose fields are the surface a reader actually reaches. On a `local name: {...}` declaration it replaces that one item with a module per field, named `prefix.field` (the enclosing module's own name, when `prefix` is omitted). A field inside one of those modules may carry `@namespace` too; it becomes a nested module instead of a value on its parent. A field written inline (`data: {...}`) documents its own fields directly; a field spelled as a name (`math: nupp.MathLibrary`) is followed to a record of that name declared in the same file. Documentation never resolves a type the way the checker does, so a field answering to neither is left out rather than guessed at. This is how the standard library's own `nupp` global — `nupp.data`, `nupp.io`, and `nupp.math` — gets pages nested under `nupp` without a file to require any of them by, since native members have none. `@raises` says what makes a function raise, one line per condition. Lua has no signature to find that out from, so it is written down. The `undocumented-raise` lint asks a documented function that calls `error` to say so; it judges only documented functions, `assert` does not count, and it does not propagate through calls, because documenting what a callee raises is a claim the checker cannot verify. Tags are read wherever a function is declared, including the typed bindings and function-typed record fields that declaration files are written with, so `local ipairs: function(t: {V}): ...` documents its arguments like any other function. ## What is public Without `--all`, an ordinary module shows its globals, its exported types, and anything marked `@export`. Private by default: - a source file whose basename starts with `_`; - any file below an `internal/` directory; - a file beginning with `@!internal`; - every module below an `init.nupp` beginning with `@!internal`; - a record method or member whose name starts with `_`. `includePrivate = true` on the docs target includes them. `@!internal` is a file-level inner annotation, not a docblock tag. Put it first in a namespace's `init.nupp` to keep that module and every descendant out of public API documentation without naming the directory `internal`: ```nupp @!internal return {} ``` It affects documentation only. The compiler still checks, builds, and resolves the modules normally. A `.d.nupp` declaration file documents in full without `--all`, because `local` there is not privacy — its bindings are the interface it describes. Mark one `@local` to keep it out. ## Markdown pages A docs target can carry handwritten pages alongside the generated API. Beyond ordinary Markdown, five things are available in a fenced block. Every ordinary `nupp` fence becomes an editable playground; the other languages stay highlighted, static code. **A caption**, which also becomes a tab label: ```` ```lua [Generated Lua] local x = 1 ``` ```` **Line numbers**, optionally starting partway into a file: ```` ```nupp:line-numbers=41 local offset = true ``` ```` The numbers sit in their own gutter, so selecting the block copies the code without them. **Code groups**, which need no JavaScript: ```` ::: code-group ```nupp [Nupp] local record Point x: number end ``` ```lua [Generated Lua] const Point = {} Point.__index = Point ``` ::: ```` **Admonitions**, whose bodies remain ordinary Lunamark Markdown: ```` ::: note Optional title Use **normal Markdown** here, including links, lists, and fenced code. ::: ```` The supported kinds are `note`, `info`, `tip`, `warning`, and `danger`. Omit the title to use the capitalized kind. Containers may nest, and a fenced code block containing `:::` does not close its admonition. **A playground**, which is also the editor rather than a picture of one. Spell it explicitly when an empty block should open on the playground's example menu: ```` ```playground local type Priority = "low" | "high" local p: Priority = "urgent" ``` ```` An ordinary `nupp` fence supplies its program the same way. The program is checked in the reader's browser, as they type, by the real compiler — see [`editors/playground`](https://github.com/nupp-lang/nupp/tree/main/editors/playground) for how that works and what it cannot do. An empty fence opens on the editor's own example menu instead of a program; a caption becomes the frame's title. Add `:static` to a `nupp` fence when it is deliberately an incomplete fragment. `:line-numbers` also keeps a Nupp fence static so its requested starting line is preserved. The block is an `