import type { InstalledPlugin } from './plugins/compile.js'; import type { Finding } from './types.js'; export interface NamedView { /** the filename slug — the ONLY name a reference resolves */ id: string; /** the library path the view came from (what Finding.file names) */ file: string; /** the raw view mapping. NEVER mutated and NEVER id-stamped: one registry * serves many evaluations, so every consumer clones before touching. */ spec: any; /** statically detected bare shared-state spellings (a stat-row with no * indicators/preset, a coverage or reverse-gap with no bind) — those read * the HOST dashboard's pack/indicator state, so a host without it cannot * give this view its numbers. Tooling metadata; no finding at load. */ dashboardBound: boolean; } export interface ViewRegistry { get(name: string): NamedView | undefined; has(name: string): boolean; names(): string[]; sourceOf(name: string): string; /** declared ids that LOST to their filename, mapped to the winning slug — * kept so view-missing can route a reference-to-the-loser toward the name * that actually resolves. A bare list would let suggest() parrot the * failed name back at the author ("no view \"beta\" — did you mean * \"beta\"?"), which tells them nothing; the owner is the answer. */ aliases(): Map; } /** * Load a view library from (path → yaml text). NEVER throws: a bad file is a * `view-file-invalid` warning and a skip, and the rest of the library loads — * one broken experiment in views/ must not take down every dashboard that * never referenced it. */ export declare function buildViewRegistry(files: Map, findings: Finding[]): ViewRegistry; /** Is this `views:` entry a REFERENCE (bare string, or the explicit * `{view: }` form) rather than an inline view? */ export declare function isViewRef(entry: any): boolean; /** The body keys a record view carries beside `kind`/`label`. Shared by the * normalizer here and evalRecordView's validation so the two lists can never * drift. */ export declare const RECORD_VIEW_KEYS: readonly ["block", "title", "subtitle", "body", "properties", "sections", "subject"]; /** Is this raw view spec a record view? The `kind:` key is the declaration — * never inferred from shape, exactly as `tier:` is declared on a block. */ export declare function isRecordViewSpec(spec: any): boolean; /** A record view spec → the one `record` widget that IS its body. `label` is * deliberately left off the widget: the view's label is the page heading the * surface already prints, and doubling it as a widget heading would print it * twice. */ export declare function recordWidgetOf(spec: any): any; /** The body keys a mentions view carries beside `kind`/`label`. `where` is a * dashboard query over MENTION_QUERY_FIELDS (core/mentions.ts); `of: subject` * narrows to the OPEN RECORD's own mentions and is legal only where a record * supplies a subject — a record view's sections (§5 PR9 item 2). */ export declare const MENTIONS_VIEW_KEYS: readonly ["where", "of"]; /** Is this raw view spec a mentions view? Declared by `kind:`, exactly as * record views (and `tier:` on blocks) are — never inferred from shape. */ export declare function isMentionsViewSpec(spec: any): boolean; /** A mentions view spec → the one `mentions` widget that IS its body — * recordWidgetOf's shape rule, label left to the surface. EVERY body key * rides except the view's own chrome (`kind` the declaration, `label` the * page heading, `id` the resolver's stamp): the widget evaluator warns on * what it does not accept, and a stripped copy here would make a typo'd key * the one silent mistake in the family. */ export declare function mentionsWidgetOf(spec: any): any; /** The GENERIC record view for a block — what a `#/r/` address opens when no * authored record view names the block: title from the first column, * everything else a property, no sections (evalRecordView applies exactly * these defaults to the empty spec). Exported as the one place the fallback * shape is spelled, so a host minting a record page and the evaluator's * defaults cannot disagree. */ export declare function recordViewFor(block: string, label?: string): any; /** view name (dj/comments) → the view spec it resolves to: a one-widget view * wrapping the plugin's widget kind, evaluated by the ONE widget pipeline — * no second resolution path. */ export declare function engineViews(installed: readonly InstalledPlugin[]): Map; /** WHY a name failed to resolve, worded once for BOTH resolution points (§7: * every view-* finding fires identically from the top-level resolver here * and from compose.ts's placement path — two message builders would drift * the day one gains a hint). Returns the head of the message; each caller * appends its own degradation tail (a stub page vs an unresolved slot), * because the degradation genuinely differs. */ export declare function describeMissingView(name: string, reg: ViewRegistry, installed?: ReadonlyMap): string; /** * Resolve every reference in a dashboard's composed `views:` list, in place — * list position preserved, so navigation and payload ordering never move. * * Returns THE SAME ARRAY OBJECT when there is nothing to do (no references, * nothing dropped): the byte-identity guarantee a pre-t1 dashboard rides * through this function on. The registry is never mutated — every resolution * is a deep clone with the id stamped ON THE CLONE (which is what satisfies * evaluateDashboard's `a view needs an id` check for canonical id-less files). * * `sources` is the per-entry include-fragment path (null for inline entries), * threaded from composeViews so the R6 same-file exemption can compare paths: * a fragment include that IS the library file plays both roles legitimately. */ export declare function resolveViews(rawViews: any[], reg: ViewRegistry, findings: Finding[], sources?: readonly (string | null)[], engine?: ReadonlyMap): { views: any[]; unresolved: Set; };