Metadata-Version: 2.4
Name: nide
Version: 2026.7.7
Summary: A bound volume (Finnish: nide) - assemble markdown text files into gfm-plus, html, and pdf channel outputs.
Author-email: Stefan Hagen <stefan@hagen.link>
Maintainer-email: Stefan Hagen <stefan@hagen.link>
License-Expression: MIT
Project-URL: Documentation, https://codes.dilettant.life/docs/nide
Keywords: developer-tools,documentation,markdown
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: jsonschema>=4.26.0
Requires-Dist: kaava>=2026.6.20
Requires-Dist: python-jsonpath>=2.0.2
Requires-Dist: PyYAML>=6.0.3
Requires-Dist: vyyhti>=2026.6.21
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Dynamic: license-file

# nide

A bound volume (Finnish: nide) — assemble Markdown source files into gfm-plus, html, and pdf channel outputs.

Requires Python 3.11 or later.

## Install

```
pip install nide
```

## Manual

The [man page](docs/nide.1) provides the CLI reference (`man nide` after placing the file on your `MANPATH`):

```sh
mkdir -p ~/.local/share/man/man1
cp docs/nide.1 ~/.local/share/man/man1/
```

## Quickstart

Run `nide` with no arguments for a usage summary, or `nide --version` to check the installed version.
For a dedicated feature walkthrough you can follow in minutes visit [quickstart](quickstart/README.md).
A step-by-step guided build of a document pipeline is provided in the [tutorial](tutorial/README.md).

## Pipeline

Two-pass workflow:

```
nide harvest              →  build/section-*.json, build/example-*.json

nide assemble             →  build/ir.json          (Pass 1: channel-neutral IR)
nide render -t html       →  build/html.md, build/toc-mint.json
pandoc                    →  build/tmp.html
nide inject               →  build/injected.html
tidy                      →  delivery HTML

nide render -t gfm-plus   →  build/gfm-plus.md
nide render -t pdf        →  build/pdf.md
liitos                    →  delivery PDF
```

The compat one-pass form combines Pass 1 + Pass 2 into a single command
(`nide assemble -t html|gfm-plus|pdf`) for existing workflows.

## Commands

`nide` has eight subcommands.  Every name accepts any unambiguous prefix —
`nide a` = assemble, `nide r` = render, `nide ej` = eject, `nide ex` = explain, etc.

**`nide assemble`** (Pass 1) splices a list of Markdown source files into a single
channel-neutral intermediate representation (IR) and writes it to `build/ir.json`:

- Citation definition files are expanded into formatted inline citation entries.
- Glossary content is captured per source file for channel-specific rendering.
- Section headings are numbered and stored with all metadata needed by any channel.
- Cross-references (`[sec](#label)`, `[cite](#label)`, `[eg](#label)`) are resolved
  from JSON look-up tables produced by `nide harvest`.

When called with `-t CHANNEL`, `nide assemble` also runs Pass 2 immediately
(compat shortcut).

**`nide render`** (Pass 2) reads `build/ir.json` and renders one or more channels.
Accepts a comma-separated list: `nide render -t gfm-plus,html,pdf`.

- `html`: numbers headings with inline anchors; expands glossary into `<dl>` elements;
  writes `build/html.md` and `build/toc-mint.json`.
- `gfm-plus`: numbers headings with inline anchors; passes glossary through verbatim;
  writes `build/gfm-plus.md`.
- `pdf`: prepends `\phantomsection` before unnumbered section headings; replaces
  remote logo URL with the local path; writes `build/pdf.md`.

**`nide inject`** post-processes the HTML file that pandoc has produced from
nide's `build/html.md`, applying:

- Custom HTML table of contents (built from `build/toc-mint.json`).
- `<title>` element replaced with the value of `html-title` from config.
- Base and skin CSS inlined; `<link>` tags removed.
- Remote logo URL replaced with a local data URL.
- Image `src` attributes optionally replaced with base64 data URLs.

The result is written to `build/injected.html`.

**`nide harvest`** scans the Markdown sources and writes JSON look-up table (LUT)
files for section and example cross-references.  Run it before `nide assemble`
whenever source files change.

**`nide explain`** performs a dry-run walkthrough without writing any output files.
It prints config values, binder contents with exist/missing tags, channel exclusions,
auxiliary source file status, and LUT file presence.  Useful for diagnosing why an
assembly produces unexpected output.

**`nide doctor [--fix]`** scans the project layout and reports findings at ERROR or
WARN level: missing directories, binder file, source files, first-authored-section
heading, auxiliary sources, and LUT files.  With `--fix`, it creates missing
directories and runs `nide harvest` to generate absent LUT files.

**`nide eject`** emits a fully-commented `nide.yaml` template to stdout.
Use `-o PATH` to write it to a file; add `-f` to overwrite an existing file.

**`nide version`** (also `-V` / `--version`) prints the installed version and exits.

Three output channels are supported:

| Channel    | Output (`nide render`)                          | Intended consumer      |
|:-----------|:------------------------------------------------|:-----------------------|
| `html`     | `build/html.md` + `build/toc-mint.json`         | pandoc → `nide inject` |
| `gfm-plus` | `build/gfm-plus.md`                             | direct delivery        |
| `pdf`      | `build/pdf.md`                                  | `liitos`               |

IR output (`nide assemble`): `build/ir.json`.

## Configuration

All settings are read from `etc/nide.yaml` (override with `-c`).
Every key is optional; the built-in defaults are listed below.

### Assembly keys

```yaml
binder: bind.txt
binder-ignores:
  gfm-plus: []
  html: []
  pdf: []
build-path: build
citation-skip-prefixes:
- '#'
citation-sources: []
cite-cosmetics-template: '**\[**<span id="$label$" class="anchor"></span>**$code$\]** $text$'
delete-when:
- contains: '<mark title="Ephemeral region marking">'
  delete:
  - '<mark title="Ephemeral region marking">'
  - '</mark>'
etc-path: etc
first-authored-section: '# Scope'
glossary-sources: []
html-title: No Title Given
logo-local-path: images/OASISLogo-v3.0.png
logo-url: https://docs.oasis-open.org/templates/OASISLogo-v3.0.png
sec-no-toc-postfix: '{.unnumbered .unlisted}'
section-display-to-label-db: section-display-to-label.json
section-display-to-text-db: section-display-to-text.json
section-label-to-display-db: section-label-to-display.json
section-reference-style: number
source-path: src
toc-template:
- '$sec_cnt_disp$ [$text$](#$label$)  '
- "\t$sec_cnt_disp$ [$text$](#$label$)  "
- "\t\t$sec_cnt_disp$ [$text$](#$label$)  "
- "\t\t\t$sec_cnt_disp$ [$text$](#$label$)  "
- "\t\t\t\t$sec_cnt_disp$ [$text$](#$label$)  "
tok-sec: "<a id='$thing$'></a>"
track-examples: false
```

The `section-*-db` files are look-up tables produced by `nide harvest` and must
be present before running `nide assemble` with cross-references.

### Output path keys

```yaml
output-paths:
  ir: build/ir.json
  gfm-plus: build/gfm-plus.md
  html: build/html.md
  pdf: build/pdf.md
```

### Inject keys

HTML post-processing settings live under the `html-inject:` block:

```yaml
html-inject:
  css-base: ''              # path to base CSS file (empty = skip)
  css-skin: ''              # path to skin CSS file
  images: false             # inline local images as base64 data URLs
  images-path: build/data-url
  intro-trigger: ''         # HTML trigger for TOC end; both triggers required
  logo-data-url: ''         # path to logo data URL .txt file (empty = skip)
  logo-remote-url: ''       # remote logo URL to replace
  toc-trigger: '<h1 id="table-of-contents'
```

Both `toc-trigger` and `intro-trigger` must be non-empty for TOC replacement to
occur.  The trigger values are pandoc-generated HTML id attributes and depend on
the heading text.

## Options

### Global options

```
nide [-V|--version]
nide version
```

| Option              | Description                                             |
|:--------------------|:--------------------------------------------------------|
| `-V`, `--version`   | Print version string and exit                           |
| `version`           | Subcommand alias for `--version`                        |

Subcommand names accept any unambiguous prefix: `nide a` = assemble,
`nide r` = render, `nide ej` = eject, `nide ex` = explain, `nide v` = version, etc.

### `nide assemble`

```
nide assemble [-d|--debug] [-c PATH|--config PATH] [-t CHANNEL|--target CHANNEL]
```

| Option       | Default         | Description                                                       |
|:-------------|:----------------|:------------------------------------------------------------------|
| `-t CHANNEL` | (IR only)       | Compat: build IR + render `CHANNEL` in one step (`gfm-plus`, `html`, `pdf`) |
| `-c PATH`    | `etc/nide.yaml` | Path to the assembly configuration file                           |
| `-d`         | off             | Debug mode: write per-stage snapshot files                        |

Without `-t`, writes only the channel-neutral IR to `build/ir.json`.

### `nide render`

```
nide render -t CHANNEL[,CHANNEL…] [-c PATH|--config PATH] [-d|--debug]
```

| Option            | Default         | Description                                        |
|:------------------|:----------------|:---------------------------------------------------|
| `-t CHANNEL[,…]`  | (required)      | Channels to render: `gfm-plus`, `html`, `pdf`; CSV |
| `-c PATH`         | `etc/nide.yaml` | Path to the assembly configuration file            |
| `-d`              | off             | Enable debug-level logging                         |

Reads `build/ir.json` (or the path in `output-paths.ir`).  Run `nide assemble` first.

### `nide inject`

```
nide inject [-c PATH|--config PATH]
```

| Option    | Default         | Description                             |
|:----------|:----------------|:----------------------------------------|
| `-c PATH` | `etc/nide.yaml` | Path to the assembly configuration file |

### `nide harvest`

```
nide harvest [-c PATH|--config PATH]
```

| Option    | Default         | Description                             |
|:----------|:----------------|:----------------------------------------|
| `-c PATH` | `etc/nide.yaml` | Path to the assembly configuration file |

### `nide explain`

```
nide explain [-c PATH|--config PATH] [-t CHANNEL|--target CHANNEL]
```

| Option       | Default         | Description                                      |
|:-------------|:----------------|:-------------------------------------------------|
| `-c PATH`    | `etc/nide.yaml` | Path to the assembly configuration file          |
| `-t CHANNEL` | (all channels)  | Limit channel-exclusion display to one channel   |

### `nide doctor`

```
nide doctor [-c PATH|--config PATH] [--fix]
```

| Option    | Default         | Description                                            |
|:----------|:----------------|:-------------------------------------------------------|
| `-c PATH` | `etc/nide.yaml` | Path to the assembly configuration file                |
| `--fix`   | off             | Create missing directories and run `nide harvest`      |

Exit code is 1 if any ERROR-level check fails; 0 otherwise (warnings alone → 0).

### `nide eject`

```
nide eject [-o PATH|--output PATH] [-f|--force]
```

| Option       | Default | Description                                   |
|:-------------|:--------|:----------------------------------------------|
| `-o PATH`    | stdout  | Write the template to `PATH` instead of stdout |
| `-f`         | off     | Overwrite `PATH` if it already exists          |

### Environment

| Variable       | Effect                                                              |
|:---------------|:--------------------------------------------------------------------|
| `NIDE_CONFIG`  | Default config path when `-c` is not given (all subcommands)        |
| `NIDE_DEBUG`   | Enable debug output; equivalent to `-d` (assemble and render modes) |
| `DUMP_LUT`     | Write back section LUT files to `etc-path` after assembly           |

## Dependencies

- [jsonschema](https://pypi.org/project/jsonschema/) — JSON Schema validation
- [kaava](https://pypi.org/project/kaava/) — typed configuration from YAML
- [python-jsonpath](https://pypi.org/project/python-jsonpath/) — JSONPath expression scanning
- [PyYAML](https://pypi.org/project/PyYAML/) — YAML parsing
- [vyyhti](https://pypi.org/project/vyyhti/) — Markdown embedding scanner

## Design and requirements

| Document                            | Identifier  | File                                            |
|:------------------------------------|:------------|:------------------------------------------------|
| Software Requirements Specification | KOO-SRS-001 | [requirements/srs/](requirements/srs/README.md) |
| Software Design Description         | KOO-SDD-001 | [design/sdd/](design/sdd/README.md)             |

Both documents follow the MIL-STD-498 DID structure and are rendered into
the documentation site alongside the quickstart and tutorial.

## Bug Tracker

Any feature requests or bug reports shall go to the [todos of nide](https://todo.sr.ht/~sthagen/nide).

## Primary Source repository

The main source of `nide` is on a mountain in Central Switzerland under
configuration control ([fossil](https://fossil-scm.org/)).

## Contributions

If you like to share small changes under the repositories license please kindly
do so by sending a patchset.
You can send such a patchset per email using [git send-email](https://git-send-email.io).

## Support

Please kindly submit issues at https://todo.sr.ht/~sthagen/nide or write plain
text email to ~sthagen/nide@lists.sr.ht to support.
Thanks.

## Changes

See `docs/changes.md` for the release history.

## Coverage

The test suite maintains high branch coverage (≥99%).
The HTML report (if generated) is in `site/coverage/`.

## SBOM

Runtime dependency information is published in `docs/sbom/` in SPDX 3.0 (JSON-LD)
and CycloneDX 1.6 (JSON) formats.
See `docs/sbom/README.md` for the component inventory and validation guide.
