[@layout]: ../docs.layout.md

# Generate Sources

Use `@pathmx/generate` to turn JSON or CSV records into ordinary Markdown
Sources with Knap templates.

Generated Sources work with PathMX's existing queries, links, layouts, and editing.

```sh
bun run pmx plugins add generate
```

---

## Generate from arguments

Put your records in `data/artists.json`:

```json
[
  {
    "slug": "ada-clay",
    "title": "Ada Clay",
    "category": "Ceramics",
    "booth": "A12"
  },
  { "slug": "rowan-paper", "title": "Rowan Paper", "category": "Printmaking" }
]
```

Create `templates/artist.knap.md` beside your Paths directory:

```md
---
{{ category | yaml_property:"category" }}
---

# {{ title | escape_md }}

{{ category | escape_md }}

{% if booth %}Visit booth {{ booth | escape_md }}.{% endif %}
```

Preview the resulting files:

```sh
bun run pmx generate \
  --template templates/artist.knap.md \
  --data data/artists.json \
  --output 'paths/artists/{{ slug }}.artist.md' \
  --dry-run
```

Each record supplies the variables for both the template and the output path.
This example creates `paths/artists/ada-clay.artist.md` and
`paths/artists/rowan-paper.artist.md`. Ada's page includes the booth line;
Rowan's omits it. Remove `--dry-run` to create the files.

Quote output patterns so your shell passes them unchanged. Outputs must be
visible `.md` files inside the selected Paths directory. Templates and input
data may live elsewhere. Keep templates outside Paths when they are authoring
inputs rather than pages you want PathMX to index.

---

## Save a recipe in a Source

Save the same request in `paths/artists.recipe.md`:

```md
---
generate:
  template: ../templates/artist.knap.md
  data: ../data/artists.json
  output: "./artists/{{ slug }}.artist.md"
---

# Generate artist pages

Create one artist Source per record in the gallery export.
Review replacements before overwriting hand-edited pages.
```

Run it with:

```sh
bun run pmx generate paths/artists.recipe.md --dry-run
```

The recipe is a Source in the selected Paths directory. Its type is your choice:
`.recipe.md`, `.import.md`, or another filename works. The plugin validates the
`generate` declaration's shape; `pmx lint` reports malformed declarations.
`template`, `data`, and `output` are required nonempty strings. Optional
`dataFormat` is `json` or `csv`. Other declaration fields are rejected.

Arguments override the corresponding saved fields. Paths in the declaration
resolve beside the recipe Source; paths supplied as arguments resolve from the
working directory. The recipe filename itself is also working-directory-relative.

```sh
bun run pmx generate paths/artists.recipe.md --data data/updated-artists.csv --dry-run
```

---

## Data and templates

JSON input accepts one object or an array of objects. CSV uses the first row
for column names and retains all values as strings. Quoted commas, embedded
newlines, and UTF-8 BOMs are supported. Empty batches, inconsistent CSV rows,
and empty or duplicate column names are errors.

The data filename selects CSV for `.csv`; other filenames default to JSON.
Use `--data-format csv` or `--data-format json` to override that choice.
Piped input defaults to JSON:

```sh
cat data/artists.json | bun run pmx generate \
  --template templates/artist.knap.md --data - \
  --output 'paths/artists/{{ slug }}.artist.md' --dry-run
```

Use `--data - --data-format csv` for piped CSV. A recipe can also declare
`data: '-'` and `dataFormat: csv`.

Templates use [Knap syntax](https://knap.md/). Variables come directly from each
record; PathMX's live `$` bindings and implicit `source` scope are not supplied.
Knap evaluates its tokens throughout the template, including code fences.
Use `escape_md` for literal text and `yaml_property` for metadata. Raw values
can deliberately emit Markdown and HTML. Source generation does not automatically
escape every value or sanitize authored markup.

---

## Preview and replace

`--dry-run` renders the entire batch, validates proposed Source changes, and
prints file diffs without committing them. Templates report errors with their
filename, line, column, and input record. `--json` returns a structured report
with file paths, statuses, warnings, and preview diffs.

Existing files with identical content are unchanged. Replacing different
content requires `--overwrite`, including during a preview:

```sh
bun run pmx generate paths/artists.recipe.md --overwrite --dry-run
bun run pmx generate paths/artists.recipe.md --overwrite
```

Replacement writes the entire generated Source. Keep manual additions in the
template or input data if they should survive later replacements. The command
does not merge content, synchronize remote data, or delete stale outputs.

Duplicate destinations, paths outside Paths, symbolic-link destinations, and
outputs that replace the recipe, template, or data input are rejected. Rendering
and validation finish before any generated Source is committed. Writes use
PathMX's existing Source transaction lifecycle, so watching servers see ordinary
Source changes.
