// SPDX-License-Identifier: CC-BY-SA-4.0
// Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>

= K9 Pandoc Reader, Writer, and Filter
:author: Jonathan D.A. Jewell
:revdate: 2026-03-17
:toc: preamble
:icons: font

Pandoc custom reader, writer, and filter for K9 Self-Validating Component files.
Convert K9 pedigree documents to HTML, Markdown, LaTeX, PDF, DOCX, and any
other format Pandoc supports -- or convert other formats into K9 Nickel.

== Installation

=== From LuaRocks

[source,sh]
----
luarocks install pandoc-k9
----

=== Manual

Copy the Lua files into your Pandoc data directory or reference them by path:

[source,sh]
----
cp k9.lua k9-reader.lua k9-writer.lua k9-filter.lua k9.html \
   ~/.local/share/pandoc/
----

=== Requirements

* Pandoc 3.0+ with Lua support (`+lua` feature)
* Lua >= 5.1 (bundled with Pandoc)

== Files

[cols="1,1,3"]
|===
| File | Type | Description

| `k9.lua`
| Reader
| Comprehensive reader with full YAML + Nickel parsing, pedigree extraction,
  contract annotations, and security badge generation.

| `k9-reader.lua`
| Reader
| Lightweight reader for quick metadata extraction. Produces a simpler AST
  suitable for summary views.

| `k9-writer.lua`
| Writer
| Converts Pandoc AST to K9 Nickel format (`.k9.ncl`). Produces valid Nickel
  with pedigree, security, recipes, and config blocks.

| `k9-filter.lua`
| Filter
| Post-processing filter with four passes: security badge colouring, contract
  highlighting, recipe validation, and pedigree completeness checks.

| `k9.html`
| Template
| HTML5 template with security-level colour scheme, pedigree summary card,
  copy-to-clipboard, and responsive layout.
|===

== Usage Examples

=== Reading K9 files

[source,sh]
----
# K9 (YAML variant) to HTML
pandoc -f k9.lua hello.k9 -o output.html

# K9 (Nickel variant) to HTML
pandoc -f k9.lua config.k9.ncl -o output.html

# K9 to Markdown
pandoc -f k9.lua deploy.k9.ncl -t markdown

# K9 to PDF (via LaTeX)
pandoc -f k9.lua config.k9.ncl -o output.pdf

# K9 to JSON AST (for programmatic use)
pandoc -f k9.lua hello.k9 -t json
----

=== Writing K9 files

[source,sh]
----
# Markdown to K9 Nickel
pandoc input.md -t k9-writer.lua -o component.k9.ncl

# HTML to K9 Nickel
pandoc input.html -t k9-writer.lua -o config.k9.ncl

# Round-trip: K9 -> AST -> K9
pandoc -f k9.lua input.k9.ncl -t k9-writer.lua -o roundtrip.k9.ncl
----

=== Full pipeline with filter and template

[source,sh]
----
pandoc -f k9.lua input.k9.ncl \
  --lua-filter=k9-filter.lua \
  --template=k9.html \
  -o output.html
----

=== Quick extraction with the lightweight reader

[source,sh]
----
pandoc -f k9-reader.lua component.k9.ncl -o docs.html
pandoc -f k9-reader.lua component.k9.ncl -t markdown
----

== Reader Capabilities

=== Auto-Detection

The reader automatically detects:

* *Syntax* -- YAML (`.k9`) vs Nickel (`.k9.ncl`) based on content patterns
* *Security level* -- Kennel / Yard / Hunt from `trust_level` or content analysis
* *Magic number* -- `K9!` presence at file start
* *SPDX license* -- Extracted from comment headers

=== Pedigree Extraction

Every K9 document produces a structured pedigree summary containing title
(with security badge), version, description, security level, syntax format,
and license identifier.

=== YAML Content (Kennel Level)

* Top-level keys become section headers
* Key-value pairs become definition list entries
* Block scalars (`|`) are preserved
* Comments are skipped

=== Nickel Content (Yard/Hunt Level)

* `let ... = { ... } in` bindings become sections with definition lists
* Contract annotations (`| Type`) display alongside field names
* `import` statements render as import declarations
* Comment blocks become `Div` elements with `.k9-comment` class
* Multiline strings (`m%"..."%`) become code blocks
* Record nesting is handled recursively

== Pandoc Metadata

The reader sets these metadata fields (accessible via `$meta.field$` in templates):

* `k9-format` -- `"yaml"` or `"nickel"`
* `k9-security-level` -- `"Kennel"`, `"Yard"`, or `"Hunt"`
* `k9-magic` -- `true` / `false`
* `spdx-license` -- License identifier string
* `title` -- Component name
* `version` -- Component version

== Filter Capabilities

The filter (`k9-filter.lua`) provides four post-processing passes:

[cols="1,3"]
|===
| Capability | Description

| Security badge colouring
| Renders `k9-security-badge` spans as inline HTML badges.
  Kennel = green, Yard = amber, Hunt = red.

| Contract highlighting
| Renders `k9-contract` spans in monospace with type-specific colours:
  green for String, blue for Number, orange for Bool, purple for Array,
  dark blue for Record.

| Recipe validation
| Scans recipe code blocks for command references. Checks the first word of
  each line against 80+ known tools. Warns on unrecognised commands.

| Pedigree completeness
| Checks that name, version, and description are present. Warns for
  missing fields.
|===

=== Disabling Filter Features

Set metadata flags in your document front matter:

[source,yaml]
----
---
k9-validate: false
k9-diagrams: false
---
----

== CSS Classes

For HTML output, the reader emits semantic CSS classes:

* `.k9-pedigree` -- pedigree summary block
* `.k9-security-badge` -- security level badge
* `.k9-kennel` / `.k9-yard` / `.k9-hunt` -- security level variants
* `.k9-section` -- YAML section header
* `.k9-binding` -- Nickel `let` binding header
* `.k9-contract` -- Nickel type contract annotation
* `.k9-comment` -- comment block
* `.k9-source` -- raw source section
* `.k9-export` -- top-level export record

== HTML Template

The `k9.html` template provides:

* *Security-level header bar* -- gradient background adapts to trust level
* *Pedigree summary card* -- structured table showing name, version, security, license
* *Contract annotations* -- monospace styling with type-specific colours
* *Recipe blocks* -- distinct left-border styling with "Recipe" label badge
* *Copy-to-clipboard* -- JavaScript-powered copy button on code blocks
* *Responsive layout* -- fluid container, mobile-friendly grid
* *Print-friendly* -- clean monochrome, badges outlined instead of filled

== Extensions

Both the reader and filter advertise an extensions table:

[cols="1,3"]
|===
| Extension | Purpose

| `+smart`
| Typographic quotes (SmartyPants processing)

| `+includes`
| File inclusion support

| `+diagrams`
| Diagram rendering (mermaid, graphviz/dot)

| `+validate`
| Structural validation (pedigree, recipes, SPDX)
|===

== Part of the K9 Ecosystem

This Pandoc integration is part of the
https://github.com/hyperpolymath/standards/tree/main/k9-svc[K9 Self-Validating Components]
suite within the `standards` monorepo. Related tools:

* link:../bindings/[`bindings/`] -- Language bindings (Deno, Rust, Gleam, Elixir, Haskell)
* link:../actions/validate/[`actions/validate/`] -- GitHub Action for CI validation
* link:../editors/vscode/[`editors/vscode/`] -- VS Code extension
* link:../SPEC.adoc[`SPEC.adoc`] -- K9 format specification
* link:../pedigree.ncl[`pedigree.ncl`] -- Nickel contract schema
