AGENTS.md - docs/
The published site is Docusaurus 3.7 (MDX v3): https://nussknacker.io/documentation. The docs/
folder is uploaded to the repo that serves it (see CONTRIBUTING/README.md), so nothing in this repo
builds the docs - a file that cannot compile is found only after the upload, when the site build fails.
Compile what you touched yourself before handing the change over.
.md files are parsed as CommonMark, where { is ordinary text. .mdx files are JSX, where every
unescaped { opens a JavaScript expression. The rules below are about .mdx only.
Curly braces in .mdx
SpEL ({#input.amount}), JSON ({"a": 1}) and SQL quantifiers ({2,}) are all over these docs and all
contain braces. MDX reads them in three ways, and only the first is loud:
| Written in prose or a table cell | What happens |
|---|---|
{#input.amount}, {"a": 1}, {2,} | build fails: Could not parse expression with acorn |
{n}, {foo} - anything shaped like one identifier | compiles, then ReferenceError: n is not defined when the page renders |
{} | compiles to nothing - the braces vanish from the page, no error at all |
Do not reflexively wrap braces in backticks to silence this. Backticks add monospace and a code meaning; when the braces are not code, or their neighbours are unstyled, that is the wrong fix. Choose by what the braces actually are:
- Fenced code block - multi-line JSON, SpEL or HOCON configuration. Braces are inert inside a fence, so nothing needs escaping. This is the right home for anything longer than a phrase.
- Inline code -
`{#input.amount}`,`A{2,}`- the braces are code the reader could type: an expression, a JSON fragment, a quantifier. Use it when a code span is also how it should look. - Backslash escape,
\{and\}- the braces belong to running prose, or to a UI label quoted verbatim, and monospace would be wrong or inconsistent. Renders a bare{. Reach for this when the neighbouring items carry no code styling: in the quantifier table incomponents/matchRecognize.mdx,(\{2,\})sits beside(+),(?)and(*), so backticking only the brace rows would look arbitrary. {"{"}- only inside JSX children, where markdown escapes do not apply.selfManaged/configuration/Overview.mdxneeds it and explains why in a comment; nothing else should.
Each escape widens a table cell by two characters - re-pad the column so the source pipes stay aligned.
Compiling a changed .mdx locally
Set the checker up once, outside the repo:
mkdir -p /tmp/mdxcheck && cd /tmp/mdxcheck && npm install @mdx-js/mdx@3 remark-frontmatter remark-gfm
cat > check.mjs <<'EOF'
import {compile} from '@mdx-js/mdx'
import remarkFrontmatter from 'remark-frontmatter'
import remarkGfm from 'remark-gfm'
import {readFileSync} from 'node:fs'
let bad = 0
for (const f of process.argv.slice(2)) {
// Docusaurus preprocesses HTML comments away; plain MDX v3 rejects them, so do the same here
const src = readFileSync(f, 'utf8').replace(/<!--[\s\S]*?-->/g, '')
try { await compile(src, {remarkPlugins: [remarkFrontmatter, remarkGfm]}) }
catch (e) { bad++; console.log(`FAIL ${f}:${e.line ?? '?'} ${e.reason ?? e.message.split('\n')[0]}`) }
}
console.log(bad ? `${bad} file(s) fail` : 'all files compile')
EOF
Then, from the repo root:
node /tmp/mdxcheck/check.mjs $(git diff --name-only HEAD -- 'docs/**/*.mdx') # changed files
node /tmp/mdxcheck/check.mjs $(find docs -name '*.mdx') # all 108, ~2s
A clean run only proves the files parse. It cannot see the second row of the table above, so also read
back any {...} you left unescaped and confirm it is a real reference to something imported in the
file, not prose that happens to look like an identifier.
Note on HTML comments: 58 .mdx files here use <!-- ... -->, which MDX v3 rejects on its own and
Docusaurus strips in a compatibility step before compiling. That is why the checker above removes them
too. Do not add new ones - write {/* ... */} - and do not "fix" the existing ones as a side errand.