From 336b4f6b25ccf2bb945d4c7e03c1e6b70c231686 Mon Sep 17 00:00:00 2001 From: Gautier DI FOLCO Date: Sun, 7 Jun 2026 22:20:43 +0200 Subject: [PATCH] Decoupling the Haddock Declaration AST from GHC --- ...0000-decoupling-haddock-declaration-ast.md | 443 +++++ .../schema.json | 1640 +++++++++++++++++ 2 files changed, 2083 insertions(+) create mode 100644 proposals/decoupling-haddock-declaration-ast/0000-decoupling-haddock-declaration-ast.md create mode 100644 proposals/decoupling-haddock-declaration-ast/schema.json diff --git a/proposals/decoupling-haddock-declaration-ast/0000-decoupling-haddock-declaration-ast.md b/proposals/decoupling-haddock-declaration-ast/0000-decoupling-haddock-declaration-ast.md new file mode 100644 index 0000000..0d05331 --- /dev/null +++ b/proposals/decoupling-haddock-declaration-ast/0000-decoupling-haddock-declaration-ast.md @@ -0,0 +1,443 @@ +# RFC - Decoupling the Haddock Declaration AST from GHC + +## Abstract + +Haddock reuses GHC's full `HsDecl`/`HsType` AST to represent and render +documentation declarations. An audit of Haddock's three rendering backends +(HTML, LaTeX, Hoogle) shows that only a small, well-defined subset is ever +reached: 3 HsDecl constructors (out of ~11), 4 `TyClDecl` shapes, ~20 `HsType` +constructors, and a handful of supporting types. The rest is never rendered. + +This proposal defines a standalone, serializable "Haddock Declaration AST" +that captures exactly this subset, in a new `haddock-ast` package with no GHC +dependency. Combined with the already GHC-free `DocH` documentation AST from +`haddock-library`, the two form a complete intermediate representation (IR) +for Haskell documentation, backed by JSON and described by a JSON Schema. + +The implementation covers: (1) auditing and documenting the exact GHC AST +subset Haddock consumes, (2) defining the Haddock Declaration AST as new +Haskell types, (3) implementing JSON serialization and deserialization, +(4) integrating the IR as a replacement for the existing `--json` flag and as +a new `--read-ir` / `--emit-ir` pipeline so that rendering can proceed without +GHC. + +## Background + +### How Haddock works today + +Haddock's pipeline has five stages: + +1. **Parse**: GHC's parser reads Haskell source and produces a `RenamedSource` + AST indexed by `GhcRn`. +2. **Extract**: `haddock-api` extracts documentation comments, export items, + instances, and fixities from the typechecked module, building an + `Interface` value. +3. **Synify**: For exported entities, GHC's internal `TyThing` values are + converted back to `HsDecl GhcRn` via `Haddock.Convert` (the "synify" + process). This step is necessary because GHC's Core types are not + source-level syntax. The `synifyType` function pattern-matches on every + constructor of `Type` from `GHC.Core.TyCo.Rep` and reconstructs the + corresponding `HsType GhcRn`. +4. **Rename**: All GHC `Name`s are replaced with `DocName` (a `Name` plus + cross-reference info) using the `DocNameI` pass. `DocNameI` is a fake GHC + pass (analogous to `GhcPs` or `GhcRn`) that maps the `IdP` type family to + `DocName` instead of `Name`. This requires approximately 113 type family + instances: 28 mapped to `DataConCantHappen`, 67 to `NoExtField`, 15 to + `EpAnn NoEpAnns`, plus custom mappings for `XXType`, `XExportDecl`, and + others. +5. **Render**: The backends (HTML, LaTeX, Hoogle) pattern-match on the + resulting `HsDecl DocNameI` and `HsType DocNameI` trees to produce output. + +Steps 1-4 require GHC. Step 5 (rendering) does not inherently require GHC, +but because it operates on GHC AST types, it currently depends on the `ghc` +package. + +### haddock-library vs haddock-api + +`haddock-library` is GHC-free. It defines: + +- `DocH mod id`: the documentation markup AST (28 constructors), parametrized + by two type variables so it is independent of any name representation. +- Parser: converts Haddock comments to `DocH`. +- Markup: a catamorphism (`DocMarkupH`) for rendering `DocH`. + +`haddock-api` is where the coupling lives. It defines: + +- `DocName` and `DocNameI` (bridging GHC `Name`s to cross-referenced names). +- `Interface` and `InstalledInterface` (the module-level documentation + structure, containing `Module`, `DynFlags`, `ClsInst`, and + `[ExportItem GhcRn]`). +- `ExportItem`, `ExportD`, `InstHead` (combining declarations with docs). +- `Convert.hs`: `TyThing` to `HsDecl GhcRn` synification (1172 lines). +- All rendering backends. + +### The DocNameI pass + +To reuse GHC's AST types with Haddock's own name resolution, Haddock defines +`DocNameI` as a fake GHC "pass". It maps `IdP` to `DocName` and requires type +family instances for every extension point in the GHC AST. Any change to GHC's +AST extension points requires updating these instances. This is the main +maintenance burden of the GHC-Haddock coupling. + +### Current serialization + +Haddock has two existing serialization paths: + +1. **Binary** (`.haddock` files): Uses `GHC.Utils.Binary`. Serializes + `InstalledInterface` (which includes `DocMap`, `ArgMap`, fixities, + warnings, `DocOption`, but not the declaration AST). Requires `NameCache` + from GHC to deserialize. Version-controlled with a magic number + (`binaryInterfaceVersion = 46` for GHC 9.11-9.13). + +2. **JSON** (`--json` flag): Serializes `InstalledInterface` to GHC's internal + `JsonDoc` format. Names become strings via `nameStableString`. The output + is lossy: no declaration AST, no instances with types, module link labels + discarded. + +Neither format supports rendering without GHC. The binary format needs +`NameCache`, and the JSON format drops declarations entirely. + +## Problem Statement + +Haddock's reuse of GHC's AST creates three problems. + +1. **Version lock-in.** Haddock must track GHC's AST changes. The `DocNameI` + pass (~113 type family instances) must be updated whenever GHC's extension + points change. The binary serialization format is tied to GHC's `Binary` + instances and `NameCache`. + +2. **GHC is required to render.** Even though rendering is a presentation + concern, all three backends import from the `ghc` package because they + pattern-match on `HsDecl`/`HsType` constructors. + +3. **No external tooling can consume documentation.** Hackage, Hoogle, + haskell-language-server, and other tools must either use `haddock-api` + (pulling in GHC) or parse rendered HTML. + +The requirements for a solution: + +- The IR must capture everything Haddock's backends need to render + documentation for a module. +- The IR must be serializable to JSON, described by a JSON Schema, and + versioned. +- The IR must not require any GHC type or GHC package to deserialize. +- Backward compatibility: newer Haddock versions should read IR from older + versions. + +## Prior Art and Related Efforts + +### Original Haddock IR proposal (HF tech-proposals PR #44) + +"Maximally decoupling Haddock and GHC" proposed a serializable IR plus +refactoring Haddock into GHC-specific and GHC-agnostic packages. It was +discussed in TWG meetings from November 2022 through October 2023. A HSoC +student worked on it under Laurent R. de Cotret's mentorship. The scope +proved too large: it included creating `haddock-backends`, moving +GHC-agnostic code to `haddock-library`, and having GHC emit the IR. The +proposal was never merged. In October 2023, the Haddock-specific work was +explicitly moved to "Future Work." + +This proposal reduces scope to the core deliverable: defining and serializing +the AST subset. + +### proto-docser-hs + +A prototype that serializes the entire GHC `RenamedSource` AST to JSON using +`aeson` `Generic`-derived `ToJSON` instances (~150 GHC AST types, 994 lines). +It demonstrated that brute-force serialization is possible but has critical +limitations: + +- `Type` (GHC Core), `Var`, and `ThModFinalizers` cannot be meaningfully + serialized. They are serialized as placeholder strings, losing all + information. +- `Name` is serialized lossily (occurrence name + unique + source span), + losing `NameSort` and other internals. +- The output is tightly coupled to GHC's internal type structure and would + break across GHC versions. +- The output is large: the entire renamed AST is serialized, including parts + that Haddock never uses (expressions, patterns, bindings, splice + declarations, etc.). + +Our approach differs: we define a minimal AST containing only what Haddock +needs. This is smaller, stable across GHC versions, and includes only +serializable types. + +### rustdoc JSON (Rust RFC 2963) + +The Rust community added JSON output to `rustdoc`. Before 2020, `rustdoc` +parsed and rendered HTML in one step. The JSON output decoupled these, +enabling `rust-analyzer` and other tools to consume Rust documentation +without the compiler. Our approach follows the same pattern. + +### Pandoc types + +Pandoc defines its document AST in a separate package (`pandoc-types`), +backed by JSON serialization. Third-party tools can read, transform, and +write Pandoc documents without depending on Pandoc itself. The +`haddock-library` `DocH` type already follows this pattern for documentation +markup. We extend it to declaration types. + +### GHC JSON diagnostic dump (HF proposal #050) + +Gained acceptance for a versioned JSON output of GHC diagnostics, described +by a JSON Schema, with top-level `version` and `ghcVersion` fields. We follow +the same conventions. + +## Technical Content + +### Step 1: Audit of the GHC AST subset + +An audit of Haddock's three backends reveals exactly which GHC AST +constructors are used. + +#### `HsDecl` constructors used by backends + +| Constructor | HTML | LaTeX | Hoogle | Notes | +|---|---|---|---|---| +| `TyClD` (`FamDecl`) | yes | yes | yes | Type/data families | +| `TyClD` (`DataDecl`) | yes | yes | yes | Data/newtype | +| `TyClD` (`SynDecl`) | yes | yes | yes | Type synonyms | +| `TyClD` (`ClassDecl`) | yes | yes | yes | Type classes | +| `SigD` (`TypeSig`) | yes | yes | yes | Function signatures | +| `SigD` (`PatSynSig`) | yes | yes | yes | Pattern synonyms | +| `SigD` (`ClassOpSig`) | yes | yes | -- | Class methods | +| `SigD` (`MinimalSig`) | yes | -- | -- | Minimal complete def | +| `ForD` (`ForeignImport`) | yes | yes | yes | FFI imports | +| `ForD` (`ForeignExport`) | -- | -- | yes | FFI exports | +| `InstD` | consumed, no output | same | -- | Filtered out | +| `DerivD` | consumed, no output | same | -- | Filtered out | +| `ValD`, `SpliceD`, `RuleD`, `AnnD`, `WarningD`, `DefD`, `DocD` | never | never | never | Not used | + +This gives 3 productive `HsDecl` constructors: `TyClD`, `SigD`, `ForD`. + +#### `HsType` constructors used by all three backends + +`HsForAllTy`, `HsQualTy`, `HsFunTy`, `HsTyVar`, `HsStarTy`, `HsAppTy`, +`HsAppKindTy`, `HsListTy`, `HsIParamTy`, `HsTupleTy`, `HsSumTy`, `HsOpTy`, +`HsParTy`, `HsKindSig`, `HsExplicitListTy`, `HsExplicitTupleTy`, +`HsTyLit` (`HsNumTy`, `HsStrTy`, `HsCharTy`), `HsWildCardTy`, `HsDocTy` +(stripped, annotation discarded), `HsBangTy`, `HsRecTy`. + +Not used: `HsSpliceTy` (dead code in the backends), `HsCoreTy` (produces an +error in the backends). + +#### `TyClDecl` constructors + +All 4: `FamDecl`, `DataDecl`, `SynDecl`, `ClassDecl`. + +#### Sig constructors + +5: `TypeSig`, `PatSynSig`, `ClassOpSig`, `MinimalSig`, `FixSig`. + +#### Other types + +`ConDecl` (H98 and GADT), `FamilyDecl`, `FamilyInfo`, `FamilyResultSig`, +`HsDataDefn`, `HsSigType`, `HsForAllTelescope`, `HsTyVarBndr`, `HsBndrVar`, +`HsBndrKind`, `HsBndrVis`, `HsTypeArg`, `HsMultAnn`, `FunDep`, +`InjectivityAnn`, `Fixity`, `BooleanFormula`, `ForeignDecl`. + +Names: `Name`, `Module`, `ModuleName`, `OccName`. + +#### What the renaming discards + +The `GhcRn` -> `DocNameI` renaming explicitly discards: `tcdMeths` (class +default methods), `tcdDocs` (class docs), `dd_derivs` (deriving clauses), +`cid_binds` (instance bindings), `cid_sigs` (instance signatures), and `HsDoc` +identifiers (cleared to `[]`). None of this discarded data is used by any +backend. + +### Step 2: Define the Haddock Declaration AST + +We create a new package `haddock-ast` with no GHC dependency. It defines +Haskell types mirroring only the needed subset. + +The types are not parametrized by a pass index. In the serialized form, names +are plain structured data (`{package, module, occurrence}`) rather than GHC +`Name` values. The types can be instantiated with either GHC names (for the +conversion layer in `haddock-api`) or plain strings (for deserialization). + +Top-level structure: + +``` +HaddockPackage + version :: String + ghcVersion :: String + package :: Maybe PackageInfo + linkEnv :: Map NameRef ModuleRef + modules :: [HaddockModule] + +HaddockModule + module :: ModuleRef + isSignature :: Bool + description :: Maybe Documentation + info :: HaddockModInfo + exports :: [HaddockExport] + exportedNames :: [NameRef] + visibleNames :: [NameRef] + instances :: [DocInstance] + fixities :: [(NameRef, Fixity)] + warnings :: [(NameRef, Doc)] + options :: [DocOption] +``` + +Exports: + +``` +HaddockExport + = ExportDecl HaddockDecl DocForDecl [DocInstance] [(NameRef, Fixity)] + | ExportNoDecl NameRef [NameRef] (Maybe DocForDecl) + | ExportGroup Int String (Maybe Doc) + | ExportDoc MDoc + | ExportModule ModuleRef +``` + +Declarations: + +``` +HaddockDecl + = HaddockTyCl HaddockTyClDecl + | HaddockSig HaddockSigDecl + | HaddockFor HaddockForeignDecl +``` + +No `InstD` or `DerivD`: both are consumed by the pipeline but produce no +output in any backend. + +`HaddockTyClDecl` has 4 variants (`FamDecl`, `DataDecl`, `SynDecl`, +`ClassDecl`) with fields matching what the backends access. `HaddockType` +has ~20 constructors matching the audit. `HaddockConDecl` has H98 and GADT +variants. + +Key design decisions: + +- **No extension points.** Unlike GHC's "trees that grow," the Haddock + Declaration AST has no type family hooks. Extension is handled by versioning + the JSON schema. +- **Names as data, not references.** In the serialized form, names are + `{package, module, occurrence}` rather than GHC `Unique`-based identifiers. + This enables cross-version compatibility. +- **Documentation reuse.** The `DocH` type from `haddock-library` is reused + as-is for documentation content. `haddock-ast` depends on + `haddock-library`. + +### Step 3: JSON serialization and schema + +We implement `ToJSON`/`FromJSON` instances for all types in `haddock-ast`, +using the tagged union pattern: each AST node is a JSON object with a `"tag"` +field and constructor-specific fields. + +Example type signature: + +```json +{ + "tag": "HsFunTy", + "multiplicity": "Unannotated", + "arg": { "tag": "HsTyVar", "promoted": false, "name": { "package": "base", "module": "GHC.Base", "occurrence": "Int" } }, + "result": { "tag": "HsTyVar", "promoted": false, "name": { "package": "base", "module": "GHC.Base", "occurrence": "Bool" } } +} +``` + +Names are structured objects, not strings: + +```json +{ "package": "base", "module": "Data.List", "occurrence": "map" } +``` + +The existing `Interface/Json.hs` in `haddock-api` already serializes `DocH` +using this tagged union pattern (the `jsonDoc` function). We reuse and extend +this approach. + +The JSON Schema is provided alongside this proposal as `schema.json`. It +defines the complete structure and can be used by tools in any language to +validate and parse the output. The schema follows the same conventions as the +GHC JSON diagnostic dump (proposal #050): top-level `version` and `ghcVersion` +fields, semantic versioning, `additionalProperties: false` for forward +compatibility. + +### Step 4: Integration into Haddock + +Two conversion functions are added to `haddock-api`: + +- **`GHC AST -> HaddockDecl`**: implemented in `haddock-api`, where GHC is + available. This replaces the current `DocNameI` renaming with a conversion + to the standalone AST. The conversion function takes an `Interface` (which + contains `[ExportItem GhcRn]`) and produces a `[HaddockExport]`. +- **`HaddockDecl -> rendering`**: the backends are refactored to + pattern-match on `HaddockDecl`/`HaddockType` instead of + `HsDecl GhcRn`/`HsType GhcRn`. + +The existing pipeline (GHC parse -> synify -> rename -> render) remains +operational. The new pipeline runs in parallel: + +- **Emit**: GHC parse -> synify -> convert to `HaddockDecl` -> serialize to + JSON. Invoked by `--emit-ir` (replaces `--json`). +- **Read**: deserialize JSON to `HaddockDecl` -> render. Invoked by + `--read-ir`. No GHC involved. + +The `--json` flag is replaced by `--emit-ir`. The old behavior (lossy JSON +output without declarations) is superseded by the complete IR output. + +### Benefits + +- Haddock rendering becomes GHC-free when using `--read-ir`. +- The IR format is versioned and backward-compatible. +- Tools can consume Haskell documentation in any programming language. +- Hackage can store IR at upload time and re-render with any Haddock version, + solving the frozen documentation problem. +- The `haddock-ast` package is stable: it only changes when Haddock's + rendering needs change, not when GHC's internal AST changes. +- The `DocNameI` pass and its ~113 type family instances can eventually be + removed, reducing maintenance burden. + +### Drawbacks and risks + +- The `haddock-ast` package is a new type to maintain alongside GHC's AST. + Every change to Haddock's rendering must be reflected in the AST. The risk + is mitigated because the AST is small (3 decl constructors, ~20 type + constructors) and well-defined by the audit. +- The conversion from GHC AST to `haddock-ast` must track GHC version changes. + This is no worse than the current situation (the `DocNameI` instances also + track GHC), but is now concentrated in one conversion function rather than + spread across ~113 type family instances. +- The JSON output will be larger than the current binary format. This is + acceptable for an IR intended for tooling consumption, not for distribution. + The binary `.haddock` format continues to exist for Haddock's internal + package reading. +- The Hoogle backend currently relies on GHC's `Outputable` class for + rendering types. It will need its own type pretty-printer when using the + standalone AST. This is additional work but straightforward: the HTML and + LaTeX backends already do their own pretty-printing rather than using + `Outputable`. + +## Stakeholders + +- **Haddock maintainers**: the proposal changes the internal AST + representation and backend interface. +- **Hackage maintainers**: the IR enables re-rendering documentation without + GHC, addressing the frozen documentation problem. Hackage is the primary + consumer of the `--emit-ir` output. +- **Hoogle**: the IR provides structured documentation data without requiring + GHC or `haddock-api`. +- **haskell-language-server**: the IR can be consumed to show documentation + without running GHC's full pipeline. +- **GHC developers**: the proposal reduces the coupling surface between GHC + and Haddock, making GHC's AST changes less likely to break Haddock. +- **Tool authors in other languages**: a JSON-based IR enables documentation + tooling outside the Haskell ecosystem (e.g., `haskell-spotlight`, a + TypeScript VS Code extension). + +## Success + +Success criteria: + +1. The `haddock-ast` package is defined as a standalone Haskell package with no + GHC dependency, containing `HaddockDecl`, `HaddockType`, `HaddockExport`, + and all supporting types. +2. `ToJSON` and `FromJSON` instances are implemented for all types. JSON + serialization and deserialization round-trip correctly for all constructors. +3. The `--emit-ir` flag produces valid JSON matching the schema for any + compilable Haskell package. +4. The `--read-ir` flag produces identical HTML output to the existing + pipeline for the `html-test` test suite in the Haddock repository. +5. The JSON Schema validates against example outputs from the `html-test` + suite. diff --git a/proposals/decoupling-haddock-declaration-ast/schema.json b/proposals/decoupling-haddock-declaration-ast/schema.json new file mode 100644 index 0000000..5fdb7b8 --- /dev/null +++ b/proposals/decoupling-haddock-declaration-ast/schema.json @@ -0,0 +1,1640 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Haddock IR", + "description": "Intermediate representation of Haskell documentation, decoupled from GHC", + "type": "object", + "properties": { + "version": { + "description": "Schema version of the IR (semver)", + "type": "string" + }, + "ghcVersion": { + "description": "GHC version that produced this IR", + "type": "string" + }, + "package": { + "$ref": "#/$defs/packageInfo" + }, + "linkEnv": { + "description": "Map from qualified name to its preferred link-destination module", + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/moduleRef" + } + }, + "modules": { + "type": "array", + "items": { + "$ref": "#/$defs/haddockModule" + } + } + }, + "required": ["version", "ghcVersion", "modules"], + "additionalProperties": false, + + "$defs": { + + "packageInfo": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "version": { "type": "string" } + }, + "required": ["name", "version"], + "additionalProperties": false + }, + + "moduleRef": { + "type": "object", + "properties": { + "package": { "type": "string" }, + "module": { "type": "string" } + }, + "required": ["package", "module"], + "additionalProperties": false + }, + + "nameRef": { + "description": "A fully-qualified name", + "type": "object", + "properties": { + "package": { "type": "string" }, + "module": { "type": "string" }, + "occurrence": { "type": "string" } + }, + "required": ["package", "module", "occurrence"], + "additionalProperties": false + }, + + "wrapName": { + "description": "A name with rendering decoration", + "oneOf": [ + { + "type": "object", + "properties": { + "tag": { "const": "Unadorned" }, + "name": { "$ref": "#/$defs/nameRef" } + }, + "required": ["tag", "name"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "Parenthesized" }, + "name": { "$ref": "#/$defs/nameRef" } + }, + "required": ["tag", "name"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "Backticked" }, + "name": { "$ref": "#/$defs/nameRef" } + }, + "required": ["tag", "name"], + "additionalProperties": false + } + ] + }, + + "haddockModule": { + "type": "object", + "properties": { + "module": { "$ref": "#/$defs/moduleRef" }, + "isSignature": { "type": "boolean" }, + "description": { + "description": "Module-level documentation", + "$ref": "#/$defs/documentation" + }, + "info": { "$ref": "#/$defs/haddockModInfo" }, + "exports": { + "type": "array", + "items": { "$ref": "#/$defs/haddockExport" } + }, + "exportedNames": { + "type": "array", + "items": { "$ref": "#/$defs/nameRef" } + }, + "visibleNames": { + "type": "array", + "items": { "$ref": "#/$defs/nameRef" } + }, + "instances": { + "type": "array", + "items": { "$ref": "#/$defs/docInstance" } + }, + "fixities": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "$ref": "#/$defs/nameRef" }, + "fixity": { "$ref": "#/$defs/fixity" } + }, + "required": ["name", "fixity"], + "additionalProperties": false + } + }, + "warnings": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "$ref": "#/$defs/nameRef" }, + "doc": { "$ref": "#/$defs/doc" } + }, + "required": ["name", "doc"], + "additionalProperties": false + } + }, + "options": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "Hide", + "Prune", + "IgnoreExports", + "NotHome", + "ShowExtensions", + "PrintRuntimeRep" + ] + } + } + }, + "required": ["module", "isSignature", "exports"], + "additionalProperties": false + }, + + "haddockModInfo": { + "type": "object", + "properties": { + "description": { "$ref": "#/$defs/doc" }, + "language": { "type": ["string", "null"] }, + "extensions": { + "type": "array", + "items": { "type": "string" } + } + }, + "additionalProperties": false + }, + + "haddockExport": { + "oneOf": [ + { + "type": "object", + "description": "An exported declaration with documentation, instances, and fixities", + "properties": { + "tag": { "const": "ExportDecl" }, + "decl": { "$ref": "#/$defs/haddockDecl" }, + "doc": { "$ref": "#/$defs/docForDecl" }, + "subDocs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "$ref": "#/$defs/nameRef" }, + "doc": { "$ref": "#/$defs/docForDecl" } + }, + "required": ["name", "doc"], + "additionalProperties": false + } + }, + "instances": { + "type": "array", + "items": { "$ref": "#/$defs/docInstance" } + }, + "fixities": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { "$ref": "#/$defs/nameRef" }, + "fixity": { "$ref": "#/$defs/fixity" } + }, + "required": ["name", "fixity"], + "additionalProperties": false + } + }, + "splice": { "type": "boolean" } + }, + "required": ["tag", "decl"], + "additionalProperties": false + }, + { + "type": "object", + "description": "An exported name without a corresponding declaration", + "properties": { + "tag": { "const": "ExportNoDecl" }, + "name": { "$ref": "#/$defs/nameRef" }, + "subnames": { + "type": "array", + "items": { "$ref": "#/$defs/nameRef" } + }, + "doc": { "$ref": "#/$defs/docForDecl" } + }, + "required": ["tag", "name"], + "additionalProperties": false + }, + { + "type": "object", + "description": "A section heading", + "properties": { + "tag": { "const": "ExportGroup" }, + "level": { "type": "integer" }, + "title": { "type": "string" }, + "doc": { "$ref": "#/$defs/doc" } + }, + "required": ["tag", "level", "title"], + "additionalProperties": false + }, + { + "type": "object", + "description": "Standalone documentation", + "properties": { + "tag": { "const": "ExportDoc" }, + "doc": { "$ref": "#/$defs/mDoc" } + }, + "required": ["tag", "doc"], + "additionalProperties": false + }, + { + "type": "object", + "description": "A module re-export", + "properties": { + "tag": { "const": "ExportModule" }, + "module": { "$ref": "#/$defs/moduleRef" } + }, + "required": ["tag", "module"], + "additionalProperties": false + } + ] + }, + + "haddockDecl": { + "oneOf": [ + { + "type": "object", + "description": "Type/class/family declaration", + "properties": { + "tag": { "const": "TyClD" }, + "decl": { "$ref": "#/$defs/tyClDecl" } + }, + "required": ["tag", "decl"], + "additionalProperties": false + }, + { + "type": "object", + "description": "Signature declaration", + "properties": { + "tag": { "const": "SigD" }, + "sig": { "$ref": "#/$defs/sigDecl" } + }, + "required": ["tag", "sig"], + "additionalProperties": false + }, + { + "type": "object", + "description": "Foreign declaration", + "properties": { + "tag": { "const": "ForD" }, + "decl": { "$ref": "#/$defs/foreignDecl" } + }, + "required": ["tag", "decl"], + "additionalProperties": false + } + ] + }, + + "tyClDecl": { + "oneOf": [ + { + "type": "object", + "description": "Type or data family", + "properties": { + "tag": { "const": "FamDecl" }, + "decl": { "$ref": "#/$defs/familyDecl" } + }, + "required": ["tag", "decl"], + "additionalProperties": false + }, + { + "type": "object", + "description": "Type synonym", + "properties": { + "tag": { "const": "SynDecl" }, + "name": { "$ref": "#/$defs/nameRef" }, + "tyVars": { + "type": "array", + "items": { "$ref": "#/$defs/tyVarBndr" } + }, + "fixity": { "$ref": "#/$defs/fixity" }, + "rhs": { "$ref": "#/$defs/hsType" } + }, + "required": ["tag", "name", "tyVars", "rhs"], + "additionalProperties": false + }, + { + "type": "object", + "description": "Data or newtype", + "properties": { + "tag": { "const": "DataDecl" }, + "name": { "$ref": "#/$defs/nameRef" }, + "tyVars": { + "type": "array", + "items": { "$ref": "#/$defs/tyVarBndr" } + }, + "fixity": { "$ref": "#/$defs/fixity" }, + "context": { + "type": "array", + "items": { "$ref": "#/$defs/hsType" } + }, + "kindSig": { + "oneOf": [ + { "$ref": "#/$defs/hsType" }, + { "type": "null" } + ] + }, + "constructors": { + "type": "array", + "items": { "$ref": "#/$defs/conDecl" } + }, + "isNewType": { "type": "boolean" } + }, + "required": ["tag", "name", "tyVars", "constructors", "isNewType"], + "additionalProperties": false + }, + { + "type": "object", + "description": "Type class", + "properties": { + "tag": { "const": "ClassDecl" }, + "context": { + "type": "array", + "items": { "$ref": "#/$defs/hsType" } + }, + "name": { "$ref": "#/$defs/nameRef" }, + "tyVars": { + "type": "array", + "items": { "$ref": "#/$defs/tyVarBndr" } + }, + "fundeps": { + "type": "array", + "items": { + "type": "object", + "properties": { + "lhs": { + "type": "array", + "items": { "$ref": "#/$defs/nameRef" } + }, + "rhs": { + "type": "array", + "items": { "$ref": "#/$defs/nameRef" } + } + }, + "required": ["lhs", "rhs"], + "additionalProperties": false + } + }, + "sigs": { + "type": "array", + "items": { "$ref": "#/$defs/sigDecl" } + }, + "associatedTypes": { + "type": "array", + "items": { "$ref": "#/$defs/familyDecl" } + }, + "associatedTypeDefaults": { + "type": "array", + "items": { "$ref": "#/$defs/tyFamInstEqn" } + }, + "minimalComplete": { + "oneOf": [ + { "$ref": "#/$defs/booleanFormula" }, + { "type": "null" } + ] + }, + "fixity": { "$ref": "#/$defs/fixity" } + }, + "required": ["tag", "name", "tyVars"], + "additionalProperties": false + } + ] + }, + + "familyDecl": { + "type": "object", + "properties": { + "info": { + "type": "string", + "enum": ["OpenTypeFamily", "ClosedTypeFamily", "DataFamily"] + }, + "name": { "$ref": "#/$defs/nameRef" }, + "tyVars": { + "type": "array", + "items": { "$ref": "#/$defs/tyVarBndr" } + }, + "resultSig": { + "oneOf": [ + { "type": "string", "const": "NoSig" }, + { + "type": "object", + "properties": { + "tag": { "const": "KindSig" }, + "kind": { "$ref": "#/$defs/hsType" } + }, + "required": ["tag", "kind"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "TyVarSig" }, + "bndr": { "$ref": "#/$defs/tyVarBndr" } + }, + "required": ["tag", "bndr"], + "additionalProperties": false + } + ] + }, + "injectivityAnn": { + "oneOf": [ + { + "type": "object", + "properties": { + "lhs": { "$ref": "#/$defs/nameRef" }, + "rhs": { + "type": "array", + "items": { "$ref": "#/$defs/nameRef" } + } + }, + "required": ["lhs", "rhs"], + "additionalProperties": false + }, + { "type": "null" } + ] + }, + "equations": { + "description": "For closed type families only", + "type": ["array", "null"], + "items": { "$ref": "#/$defs/tyFamInstEqn" } + } + }, + "required": ["info", "name"], + "additionalProperties": false + }, + + "sigDecl": { + "oneOf": [ + { + "type": "object", + "description": "Function type signature", + "properties": { + "tag": { "const": "TypeSig" }, + "names": { + "type": "array", + "items": { "$ref": "#/$defs/nameRef" } + }, + "type": { "$ref": "#/$defs/hsSigType" } + }, + "required": ["tag", "names", "type"], + "additionalProperties": false + }, + { + "type": "object", + "description": "Pattern synonym signature", + "properties": { + "tag": { "const": "PatSynSig" }, + "names": { + "type": "array", + "items": { "$ref": "#/$defs/nameRef" } + }, + "type": { "$ref": "#/$defs/hsSigType" } + }, + "required": ["tag", "names", "type"], + "additionalProperties": false + }, + { + "type": "object", + "description": "Class method signature", + "properties": { + "tag": { "const": "ClassOpSig" }, + "isDefault": { "type": "boolean" }, + "names": { + "type": "array", + "items": { "$ref": "#/$defs/nameRef" } + }, + "type": { "$ref": "#/$defs/hsSigType" } + }, + "required": ["tag", "isDefault", "names", "type"], + "additionalProperties": false + }, + { + "type": "object", + "description": "Minimal complete definition", + "properties": { + "tag": { "const": "MinimalSig" }, + "formula": { "$ref": "#/$defs/booleanFormula" } + }, + "required": ["tag", "formula"], + "additionalProperties": false + }, + { + "type": "object", + "description": "Fixity declaration", + "properties": { + "tag": { "const": "FixSig" }, + "name": { "$ref": "#/$defs/nameRef" }, + "fixity": { "$ref": "#/$defs/fixity" } + }, + "required": ["tag", "name", "fixity"], + "additionalProperties": false + } + ] + }, + + "foreignDecl": { + "oneOf": [ + { + "type": "object", + "description": "Foreign import", + "properties": { + "tag": { "const": "ForeignImport" }, + "name": { "$ref": "#/$defs/nameRef" }, + "type": { "$ref": "#/$defs/hsSigType" } + }, + "required": ["tag", "name", "type"], + "additionalProperties": false + }, + { + "type": "object", + "description": "Foreign export", + "properties": { + "tag": { "const": "ForeignExport" }, + "name": { "$ref": "#/$defs/nameRef" }, + "type": { "$ref": "#/$defs/hsSigType" } + }, + "required": ["tag", "name", "type"], + "additionalProperties": false + } + ] + }, + + "conDecl": { + "oneOf": [ + { + "type": "object", + "description": "Haskell 98 constructor", + "properties": { + "tag": { "const": "ConDeclH98" }, + "name": { "$ref": "#/$defs/nameRef" }, + "forall": { "type": "boolean" }, + "tyVars": { + "type": "array", + "items": { "$ref": "#/$defs/tyVarBndr" } + }, + "context": { + "type": "array", + "items": { "$ref": "#/$defs/hsType" } + }, + "details": { "$ref": "#/$defs/conDeclH98Details" }, + "doc": { + "oneOf": [ + { "$ref": "#/$defs/mDoc" }, + { "type": "null" } + ] + } + }, + "required": ["tag", "name", "forall", "details"], + "additionalProperties": false + }, + { + "type": "object", + "description": "GADT constructor", + "properties": { + "tag": { "const": "ConDeclGADT" }, + "names": { + "type": "array", + "items": { "$ref": "#/$defs/nameRef" } + }, + "tyVars": { + "type": "array", + "items": { "$ref": "#/$defs/tyVarBndr" } + }, + "context": { + "type": "array", + "items": { "$ref": "#/$defs/hsType" } + }, + "details": { "$ref": "#/$defs/conDeclGADTDetails" }, + "resultType": { "$ref": "#/$defs/hsType" }, + "doc": { + "oneOf": [ + { "$ref": "#/$defs/mDoc" }, + { "type": "null" } + ] + } + }, + "required": ["tag", "names", "details", "resultType"], + "additionalProperties": false + } + ] + }, + + "conDeclH98Details": { + "oneOf": [ + { + "type": "object", + "description": "Prefix constructor", + "properties": { + "tag": { "const": "PrefixCon" }, + "args": { + "type": "array", + "items": { + "type": "object", + "properties": { + "argType": { "$ref": "#/$defs/hsType" }, + "strictness": { + "type": ["string", "null"], + "enum": ["SrcStrict", "SrcLazy", null] + } + }, + "required": ["argType"], + "additionalProperties": false + } + } + }, + "required": ["tag", "args"], + "additionalProperties": false + }, + { + "type": "object", + "description": "Record constructor", + "properties": { + "tag": { "const": "RecCon" }, + "fields": { + "type": "array", + "items": { "$ref": "#/$defs/conDeclField" } + } + }, + "required": ["tag", "fields"], + "additionalProperties": false + }, + { + "type": "object", + "description": "Infix constructor", + "properties": { + "tag": { "const": "InfixCon" }, + "leftArg": { "$ref": "#/$defs/hsType" }, + "rightArg": { "$ref": "#/$defs/hsType" } + }, + "required": ["tag", "leftArg", "rightArg"], + "additionalProperties": false + } + ] + }, + + "conDeclGADTDetails": { + "oneOf": [ + { + "type": "object", + "description": "GADT prefix constructor", + "properties": { + "tag": { "const": "PrefixConGADT" }, + "args": { + "type": "array", + "items": { + "type": "object", + "properties": { + "argType": { "$ref": "#/$defs/hsType" }, + "strictness": { + "type": ["string", "null"], + "enum": ["SrcStrict", "SrcLazy", null] + } + }, + "required": ["argType"], + "additionalProperties": false + } + } + }, + "required": ["tag", "args"], + "additionalProperties": false + }, + { + "type": "object", + "description": "GADT record constructor", + "properties": { + "tag": { "const": "RecConGADT" }, + "fields": { + "type": "array", + "items": { "$ref": "#/$defs/conDeclField" } + } + }, + "required": ["tag", "fields"], + "additionalProperties": false + } + ] + }, + + "conDeclField": { + "type": "object", + "description": "A record field", + "properties": { + "names": { + "type": "array", + "items": { "$ref": "#/$defs/nameRef" } + }, + "type": { "$ref": "#/$defs/hsType" }, + "doc": { + "oneOf": [ + { "$ref": "#/$defs/mDoc" }, + { "type": "null" } + ] + }, + "strictness": { + "type": ["string", "null"], + "enum": ["SrcStrict", "SrcLazy", null] + } + }, + "required": ["names", "type"], + "additionalProperties": false + }, + + "hsSigType": { + "type": "object", + "description": "A type with outer type variable binders", + "properties": { + "tyVars": { + "type": "array", + "items": { "$ref": "#/$defs/tyVarBndr" } + }, + "body": { "$ref": "#/$defs/hsType" } + }, + "required": ["tyVars", "body"], + "additionalProperties": false + }, + + "hsType": { + "oneOf": [ + { + "type": "object", + "properties": { + "tag": { "const": "HsForAllTy" }, + "tele": { "$ref": "#/$defs/hsForAllTelescope" }, + "body": { "$ref": "#/$defs/hsType" } + }, + "required": ["tag", "tele", "body"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "HsQualTy" }, + "context": { + "type": "array", + "items": { "$ref": "#/$defs/hsType" } + }, + "body": { "$ref": "#/$defs/hsType" } + }, + "required": ["tag", "body"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "HsFunTy" }, + "multiplicity": { + "type": "string", + "enum": ["Unannotated", "Linear", "One", "Many"] + }, + "arg": { "$ref": "#/$defs/hsType" }, + "result": { "$ref": "#/$defs/hsType" } + }, + "required": ["tag", "multiplicity", "arg", "result"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "HsTyVar" }, + "promoted": { "type": "boolean" }, + "name": { "$ref": "#/$defs/nameRef" } + }, + "required": ["tag", "promoted", "name"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "HsAppTy" }, + "fun": { "$ref": "#/$defs/hsType" }, + "arg": { "$ref": "#/$defs/hsType" } + }, + "required": ["tag", "fun", "arg"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "HsAppKindTy" }, + "fun": { "$ref": "#/$defs/hsType" }, + "kind": { "$ref": "#/$defs/hsType" } + }, + "required": ["tag", "fun", "kind"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "HsOpTy" }, + "promoted": { "type": "boolean" }, + "left": { "$ref": "#/$defs/hsType" }, + "operator": { "$ref": "#/$defs/nameRef" }, + "right": { "$ref": "#/$defs/hsType" } + }, + "required": ["tag", "promoted", "left", "operator", "right"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "HsParTy" }, + "inner": { "$ref": "#/$defs/hsType" } + }, + "required": ["tag", "inner"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "HsKindSig" }, + "type": { "$ref": "#/$defs/hsType" }, + "kind": { "$ref": "#/$defs/hsType" } + }, + "required": ["tag", "type", "kind"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "HsListTy" }, + "inner": { "$ref": "#/$defs/hsType" } + }, + "required": ["tag", "inner"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "HsTupleTy" }, + "sort": { + "type": "string", + "enum": ["Boxed", "Unboxed"] + }, + "elements": { + "type": "array", + "items": { "$ref": "#/$defs/hsType" } + } + }, + "required": ["tag", "sort", "elements"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "HsSumTy" }, + "elements": { + "type": "array", + "items": { "$ref": "#/$defs/hsType" } + } + }, + "required": ["tag", "elements"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "HsIParamTy" }, + "name": { "type": "string" }, + "type": { "$ref": "#/$defs/hsType" } + }, + "required": ["tag", "name", "type"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "HsExplicitListTy" }, + "promoted": { "type": "boolean" }, + "elements": { + "type": "array", + "items": { "$ref": "#/$defs/hsType" } + } + }, + "required": ["tag", "promoted", "elements"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "HsExplicitTupleTy" }, + "promoted": { "type": "boolean" }, + "elements": { + "type": "array", + "items": { "$ref": "#/$defs/hsType" } + } + }, + "required": ["tag", "promoted", "elements"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "HsTyLit" }, + "lit": { "$ref": "#/$defs/hsTyLit" } + }, + "required": ["tag", "lit"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "HsWildCardTy" } + }, + "required": ["tag"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "HsStarTy" }, + "isUnicode": { "type": "boolean" } + }, + "required": ["tag", "isUnicode"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "HsBangTy" }, + "strictness": { + "type": "string", + "enum": ["SrcStrict", "SrcLazy"] + }, + "inner": { "$ref": "#/$defs/hsType" } + }, + "required": ["tag", "strictness", "inner"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "HsRecTy" }, + "fields": { + "type": "array", + "items": { "$ref": "#/$defs/conDeclField" } + } + }, + "required": ["tag", "fields"], + "additionalProperties": false + } + ] + }, + + "hsForAllTelescope": { + "oneOf": [ + { + "type": "object", + "description": "Visible forall (type-level, @->@)", + "properties": { + "tag": { "const": "HsForAllVis" }, + "binders": { + "type": "array", + "items": { "$ref": "#/$defs/tyVarBndr" } + } + }, + "required": ["tag", "binders"], + "additionalProperties": false + }, + { + "type": "object", + "description": "Invisible forall (term-level, @.@)", + "properties": { + "tag": { "const": "HsForAllInvis" }, + "binders": { + "type": "array", + "items": { "$ref": "#/$defs/tyVarBndr" } + } + }, + "required": ["tag", "binders"], + "additionalProperties": false + } + ] + }, + + "tyVarBndr": { + "type": "object", + "description": "A type variable binder", + "properties": { + "name": { "$ref": "#/$defs/nameRef" }, + "visibility": { + "type": "string", + "enum": ["Required", "Inferred", "Specified"] + }, + "kind": { + "oneOf": [ + { "$ref": "#/$defs/hsType" }, + { "type": "null" } + ] + } + }, + "required": ["name", "visibility"], + "additionalProperties": false + }, + + "hsTyLit": { + "oneOf": [ + { + "type": "object", + "properties": { + "tag": { "const": "HsNumTy" }, + "value": { "type": "integer" } + }, + "required": ["tag", "value"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "HsStrTy" }, + "value": { "type": "string" } + }, + "required": ["tag", "value"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "HsCharTy" }, + "value": { "type": "string" } + }, + "required": ["tag", "value"], + "additionalProperties": false + } + ] + }, + + "tyFamInstEqn": { + "type": "object", + "description": "A type family instance equation", + "properties": { + "tyCon": { "$ref": "#/$defs/nameRef" }, + "patterns": { + "type": "array", + "items": { "$ref": "#/$defs/hsType" } + }, + "rhs": { "$ref": "#/$defs/hsType" } + }, + "required": ["tyCon", "patterns", "rhs"], + "additionalProperties": false + }, + + "booleanFormula": { + "description": "A boolean formula for minimal complete definitions", + "oneOf": [ + { + "type": "object", + "properties": { + "tag": { "const": "Var" }, + "name": { "$ref": "#/$defs/nameRef" } + }, + "required": ["tag", "name"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "And" }, + "formulas": { + "type": "array", + "items": { "$ref": "#/$defs/booleanFormula" } + } + }, + "required": ["tag", "formulas"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "Or" }, + "formulas": { + "type": "array", + "items": { "$ref": "#/$defs/booleanFormula" } + } + }, + "required": ["tag", "formulas"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "Parens" }, + "formula": { "$ref": "#/$defs/booleanFormula" } + }, + "required": ["tag", "formula"], + "additionalProperties": false + } + ] + }, + + "fixity": { + "type": "object", + "properties": { + "precedence": { "type": "integer" }, + "direction": { + "type": "string", + "enum": ["InfixL", "InfixR", "InfixN"] + } + }, + "required": ["precedence", "direction"], + "additionalProperties": false + }, + + "docInstance": { + "type": "object", + "description": "A documented instance", + "properties": { + "instanceType": { "$ref": "#/$defs/instHead" }, + "doc": { + "oneOf": [ + { "$ref": "#/$defs/mDoc" }, + { "type": "null" } + ] + }, + "module": { + "oneOf": [ + { "$ref": "#/$defs/moduleRef" }, + { "type": "null" } + ] + }, + "isOrphan": { "type": "boolean" } + }, + "required": ["instanceType"], + "additionalProperties": false + }, + + "instHead": { + "type": "object", + "properties": { + "className": { "$ref": "#/$defs/nameRef" }, + "types": { + "type": "array", + "items": { "$ref": "#/$defs/hsType" } + }, + "instanceType": { + "oneOf": [ + { + "type": "object", + "description": "Class instance", + "properties": { + "tag": { "const": "ClassInst" }, + "context": { + "type": "array", + "items": { "$ref": "#/$defs/hsType" } + }, + "tyVars": { + "type": "array", + "items": { "$ref": "#/$defs/tyVarBndr" } + }, + "sigs": { + "type": "array", + "items": { "$ref": "#/$defs/sigDecl" } + }, + "associatedTypes": { + "type": "array", + "items": { "$ref": "#/$defs/familyDecl" } + } + }, + "required": ["tag"], + "additionalProperties": false + }, + { + "type": "object", + "description": "Type family instance", + "properties": { + "tag": { "const": "TypeInst" }, + "rhs": { + "oneOf": [ + { "$ref": "#/$defs/hsType" }, + { "type": "null" } + ] + } + }, + "required": ["tag"], + "additionalProperties": false + }, + { + "type": "object", + "description": "Data family instance", + "properties": { + "tag": { "const": "DataInst" }, + "constructors": { + "type": "array", + "items": { "$ref": "#/$defs/conDecl" } + } + }, + "required": ["tag"], + "additionalProperties": false + } + ] + } + }, + "required": ["className", "types", "instanceType"], + "additionalProperties": false + }, + + "documentation": { + "description": "Module-level documentation (body and optional warning)", + "type": "object", + "properties": { + "body": { + "oneOf": [ + { "$ref": "#/$defs/mDoc" }, + { "type": "null" } + ] + }, + "warning": { + "oneOf": [ + { "$ref": "#/$defs/doc" }, + { "type": "null" } + ] + } + }, + "additionalProperties": false + }, + + "docForDecl": { + "description": "Documentation for a declaration (body and argument docs)", + "type": "object", + "properties": { + "body": { + "oneOf": [ + { "$ref": "#/$defs/mDoc" }, + { "type": "null" } + ] + }, + "arguments": { + "type": "array", + "items": { + "oneOf": [ + { "$ref": "#/$defs/mDoc" }, + { "type": "null" } + ] + } + } + }, + "additionalProperties": false + }, + + "mDoc": { + "description": "A documentation tree with metadata (@since annotation)", + "type": "object", + "properties": { + "meta": { + "type": "object", + "properties": { + "version": { + "oneOf": [ + { + "type": "object", + "properties": { + "since": { "type": "string" } + }, + "required": ["since"], + "additionalProperties": false + }, + { "type": "null" } + ] + } + }, + "additionalProperties": false + }, + "doc": { "$ref": "#/$defs/doc" } + }, + "required": ["meta", "doc"], + "additionalProperties": false + }, + + "doc": { + "description": "A Haddock DocH documentation markup tree", + "oneOf": [ + { + "type": "object", + "properties": { + "tag": { "const": "DocEmpty" } + }, + "required": ["tag"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "DocAppend" }, + "first": { "$ref": "#/$defs/doc" }, + "second": { "$ref": "#/$defs/doc" } + }, + "required": ["tag", "first", "second"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "DocString" }, + "string": { "type": "string" } + }, + "required": ["tag", "string"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "DocParagraph" }, + "document": { "$ref": "#/$defs/doc" } + }, + "required": ["tag", "document"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "DocIdentifier" }, + "name": { "$ref": "#/$defs/wrapName" } + }, + "required": ["tag", "name"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "DocIdentifierUnchecked" }, + "modName": { + "type": "object", + "properties": { + "moduleName": { "type": "string" }, + "occName": { "type": "string" } + }, + "required": ["moduleName", "occName"], + "additionalProperties": false + } + }, + "required": ["tag", "modName"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "DocModule" }, + "name": { "type": "string" }, + "label": { + "oneOf": [ + { "$ref": "#/$defs/doc" }, + { "type": "null" } + ] + } + }, + "required": ["tag", "name"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "DocWarning" }, + "document": { "$ref": "#/$defs/doc" } + }, + "required": ["tag", "document"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "DocEmphasis" }, + "document": { "$ref": "#/$defs/doc" } + }, + "required": ["tag", "document"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "DocBold" }, + "document": { "$ref": "#/$defs/doc" } + }, + "required": ["tag", "document"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "DocMonospaced" }, + "document": { "$ref": "#/$defs/doc" } + }, + "required": ["tag", "document"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "DocUnorderedList" }, + "documents": { + "type": "array", + "items": { "$ref": "#/$defs/doc" } + } + }, + "required": ["tag", "documents"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "DocOrderedList" }, + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "seq": { "type": "integer" }, + "document": { "$ref": "#/$defs/doc" } + }, + "required": ["seq", "document"], + "additionalProperties": false + } + } + }, + "required": ["tag", "items"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "DocDefList" }, + "definitions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "term": { "$ref": "#/$defs/doc" }, + "definition": { "$ref": "#/$defs/doc" } + }, + "required": ["term", "definition"], + "additionalProperties": false + } + } + }, + "required": ["tag", "definitions"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "DocCodeBlock" }, + "document": { "$ref": "#/$defs/doc" } + }, + "required": ["tag", "document"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "DocHyperlink" }, + "url": { "type": "string" }, + "label": { + "oneOf": [ + { "$ref": "#/$defs/doc" }, + { "type": "null" } + ] + } + }, + "required": ["tag", "url"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "DocPic" }, + "url": { "type": "string" }, + "title": { + "oneOf": [ + { "type": "string" }, + { "type": "null" } + ] + } + }, + "required": ["tag", "url"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "DocMathInline" }, + "string": { "type": "string" } + }, + "required": ["tag", "string"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "DocMathDisplay" }, + "string": { "type": "string" } + }, + "required": ["tag", "string"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "DocAName" }, + "string": { "type": "string" } + }, + "required": ["tag", "string"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "DocProperty" }, + "string": { "type": "string" } + }, + "required": ["tag", "string"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "DocExamples" }, + "examples": { + "type": "array", + "items": { + "type": "object", + "properties": { + "expression": { "type": "string" }, + "result": { + "type": "array", + "items": { "type": "string" } + } + }, + "required": ["expression", "result"], + "additionalProperties": false + } + } + }, + "required": ["tag", "examples"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "DocHeader" }, + "level": { "type": "integer" }, + "title": { "$ref": "#/$defs/doc" } + }, + "required": ["tag", "level", "title"], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tag": { "const": "DocTable" }, + "headerRows": { + "type": "array", + "items": { "$ref": "#/$defs/tableRow" } + }, + "bodyRows": { + "type": "array", + "items": { "$ref": "#/$defs/tableRow" } + } + }, + "required": ["tag", "headerRows", "bodyRows"], + "additionalProperties": false + } + ] + }, + + "tableRow": { + "type": "array", + "items": { "$ref": "#/$defs/tableCell" } + }, + + "tableCell": { + "type": "object", + "properties": { + "colspan": { "type": "integer" }, + "rowspan": { "type": "integer" }, + "contents": { "$ref": "#/$defs/doc" } + }, + "required": ["colspan", "rowspan", "contents"], + "additionalProperties": false + } + } +}