import { type Aspect, type RelationshipKind } from './profile.js'; import { type CoreConceptKindId } from './relationship-matrix.js'; export interface WorkspaceSource { readonly path: string; readonly source: string; } export interface Diagnostic { readonly severity: 'error'; readonly code: string; readonly message: string; readonly path: string; readonly pointer: string; readonly line: number; readonly column: number; /** * The subjects this diagnostic is about, most relevant first, when its * pointer names one. A consumer that draws the model - a canvas badging the * element a rule refused - needs the subject, not the byte offset, and the * rules already knew it: YM404 interpolates both endpoint ids into its own * message. * * Absence is meaningful and is not the same as "not yet populated". These * are derived in one place from the pointer, so every diagnostic that names * a concept or a relationship carries them, and the ones that stay empty are * exactly the ones that belong to no subject: a YAML parse failure, a * whole-document schema violation, a projection's own definition, a * manifest. A consumer can therefore treat an empty list as "this belongs * somewhere other than the canvas" rather than as missing data. */ readonly subjects?: readonly string[]; } /** * One slot of a pattern, as a CONSUMER reads it (#473 phase 4, ADR 0146). * * The resolved shape rather than the authored one: `kindIdentity` is qualified * and `kindMatching` is explicit, so a caller deciding what a slot admits does * not have to re-resolve the document it came from. */ export interface PatternSlotShape { readonly name: string; readonly kindIdentity: string; readonly required: boolean; readonly kindMatching: 'exact' | 'descendants'; } /** A wire the pattern declares, `self` naming the instance. */ export interface PatternWireShape { readonly from: string; readonly to: string; readonly kindIdentity: string; } /** Where a macro edge of one kind leaves and arrives (ADR 0124). */ export interface PatternPortShape { readonly kindIdentity: string; readonly out: string; readonly in: string; } /** * A pattern as the workspace resolved it. * * The pattern DOCUMENT has had a JSON schema since ADR 0123 and never a public * TypeScript type, so a host that wanted to offer patterns had to re-read the * YAML or guess. Slots come as an ordered array rather than a map because the * order a pattern DECLARES them is the order a form should ask for them, and a * map's iteration order is not something a consumer should have to trust. */ export interface PatternShape { readonly kindIdentity: string; /** * The PATH of the pattern document that declared it, not that document's id. * It is the same string a duplicate-declaration diagnostic names, so a host * grouping patterns by document groups them by the thing a reader can open. */ readonly declaredBy: string; readonly slots: readonly PatternSlotShape[]; readonly wiring: readonly PatternWireShape[]; readonly ports: readonly PatternPortShape[]; } export interface GraphSource { readonly document: string; readonly path: string; readonly pointer: string; readonly line: number; readonly column: number; } export interface GraphClaim { readonly id: string; readonly subject: string; readonly predicate: string; readonly object: { readonly ref: string; } | { readonly value: string; }; readonly origin: 'declared'; readonly source: GraphSource; } export interface SemanticGraph { readonly format: 'yarramate/graph/v2'; readonly profiles: readonly string[]; readonly documents: ReadonlyArray<{ readonly id: string; readonly source: string; }>; readonly subjects: ReadonlyArray<{ readonly id: string; readonly type: 'concept' | 'relationship'; }>; readonly claims: readonly GraphClaim[]; } export interface RelationshipEndpointAspects { readonly source: readonly Aspect[]; readonly target: readonly Aspect[]; } export interface ResolvedProfileContext { readonly conceptKindLineages: ReadonlyMap; readonly relationshipKindLineages: ReadonlyMap; readonly conceptKindLayers: ReadonlyMap; readonly conceptKindAspects: ReadonlyMap; readonly relationshipKindEndpointAspects: ReadonlyMap; /** Kind identity -> the core kind it resolves to through lineage. */ readonly conceptKindCoreAncestors: ReadonlyMap; readonly relationshipKindCoreAncestors: ReadonlyMap; /** * The core relationship kinds a pattern PORTS for a concept kind (#268 * phase 3, ADR 0124), keyed by kind identity. Only kinds that have a * pattern with ports appear. * * A macro edge needs both ends to port its kind, so a consumer offering a * palette between two instances intersects the two sets. Two raw groupings * permit ten of the eleven kinds, which is no narrowing at all; the ports * are what restore the guidance the relationship table gives everywhere * else. */ readonly patternPortKinds: ReadonlyMap; /** * Every pattern the workspace resolved, in kind order (#473 phase 4). * * Optional for the reason `patternMemberships` is: this shape is published * and a required addition is free for readers and a break for CONSTRUCTORS. * Read it as `?? []`. Absent, a host offers no patterns rather than offering * an empty list of them. */ readonly patterns?: readonly PatternShape[]; /** * Kind identity -> the display name its PROFILE authored (#473 phase 4). * * Only profile-declared kinds appear: a core kind's name is the vocabulary's * own and a consumer already has it. Optional for the reason `patterns` is, * and read as `?? new Map()`. */ readonly conceptKindNames?: ReadonlyMap; /** * The core relationship kinds the ArchiMate table permits between two * concept kind identities, resolved through lineage; undefined when either * identity is unknown. An extension relationship kind's own narrowing is * not applied here: read `relationshipKindEndpointAspects` for that. */ readonly permittedRelationshipKinds: (fromKindIdentity: string, toKindIdentity: string) => ReadonlySet | undefined; } /** * One slot of one pattern instance, and the subject bound into it * (ADR 0131). Compile CONTEXT, not graph content: `parts` binds existing * subjects (#268), the binding is consumed during expansion, and the graph * stays indistinguishable from a hand-authored one — so the compile result * is the only place this fact survives. `pattern` is the kind identity * (`yarrasys/api-led@1.0#api`), the naming ADR 0129 chose: identity that * travels, never a document path. */ export interface PatternMembership { readonly member: string; readonly slot: string; readonly instance: string; readonly pattern: string; /** * How the pattern's WIRING relates this slot to the instance (#473). * * - `owned` — a wire runs `self -> slot`. The instance holds the member out: * it is a part, and a view that folds instances may draw it inside. * - `context` — a wire runs `slot -> self`. The member acts on the instance * rather than belonging to it: the upstream API it calls, the plane it runs * on. Folding these would swallow half the landscape into whichever box * happened to name it. * - `unwired` — the pattern declares the slot and wires nothing through it. * Still a part; nothing about containment changes. * * A slot with wires in BOTH directions is `owned`: the instance holding * something out is the stronger statement, and it is what a reader means by * the box. * * Optional, so no existing reader breaks. `yarramate/graph/v2` is unchanged: * this is compile CONTEXT like the rest of membership (ADR 0131), never a * claim an author could have written. */ readonly wiring?: 'owned' | 'context' | 'unwired'; } /** * One slot of one pattern instance that nothing is bound into (#447): the * shape of a question a pattern already knows to ask. The mirror of * {@link PatternMembership}, and it has to be a second array rather than a * widening of that one, because a vacancy has no `member` and making that * field optional would break every reader. * * `required` is here because a vacancy on a SUCCESSFUL compile can be a * required slot after all. The first draft of this shape left the field out, * reasoning that a required slot left unbound is `YM416` and so never reaches * a result. That is true only of an instance that declares `parts`: a concept * whose kind has a pattern but which declares no parts at all is not a * `PatternInstance`, never reaches YM416, and compiles clean with every slot * vacant. So the flag is load-bearing rather than permanently `false`, and it * is the difference between "you have not decided this yet" and "this model * does not stand up without it". */ export interface PatternVacancy { readonly instance: string; readonly pattern: string; readonly slot: string; readonly slotKind: string; /** The pattern declares this part `required` (ADR 0123). */ readonly required: boolean; } export type CompilationResult = { readonly ok: true; readonly graph: SemanticGraph; /** * Optional in the type although the compiler always emits it: this * shape is published, and a required addition is free for readers * and a break for constructors. Read it as `?? []` — and thread it * to `evaluateCatalogue`, or `fills-pattern-slot` never fires. */ readonly patternMemberships?: readonly PatternMembership[]; /** Same rule as `patternMemberships`, for the same reason (#447). */ readonly patternVacancies?: readonly PatternVacancy[]; } | { readonly ok: false; readonly diagnostics: readonly Diagnostic[]; }; export type ContextualCompilationResult = { readonly ok: true; readonly graph: SemanticGraph; readonly profileContext: ResolvedProfileContext; readonly patternMemberships?: readonly PatternMembership[]; readonly patternVacancies?: readonly PatternVacancy[]; } | { readonly ok: false; readonly diagnostics: readonly Diagnostic[]; }; /** * One parsed workspace source, retained by a {@link CompilationCache}. Hold it * and hand it back; never construct one. `value` is the composed YAML of * `source` and nothing else, so an entry is a pure function of its text. */ export interface ParsedWorkspaceSource { readonly source: string; readonly kind: 'profile' | 'document' | 'pattern'; readonly value: unknown; readonly schemaDiagnostics: readonly Diagnostic[]; /** * Line/column already resolved for this text, keyed by YAML path. An * internal memo of the compiler, filled as positions are asked for; a * consumer that mutates it corrupts the `source` of later claims. */ readonly positions: Map; } /** * Opaque parse cache returned by {@link compileWorkspaceIncremental} and * accepted by its next call. Reuse is decided by exact source-text equality, * not by a caller-declared change set and not by a digest, so a stale cache * cannot change the compiled output - it can only fail to save work. */ export interface CompilationCache { readonly sources: ReadonlyMap; } export type IncrementalCompilationResult = ({ readonly ok: true; readonly graph: SemanticGraph; readonly profileContext: ResolvedProfileContext; } | { readonly ok: false; readonly diagnostics: readonly Diagnostic[]; }) & { /** False when every source had to be parsed, e.g. the first call. */ readonly incremental: boolean; readonly cache: CompilationCache; }; /** * A succession entry: a bare predecessor id, or one with the respect in which * it was superseded. * * The scope is load-bearing rather than decorative. A model claimed that Zoekt * superseded the Elasticsearch indexer, unqualified, while the source it was * built from says Zoekt "handles only code search and does not replace * Elasticsearch". The prose carried the qualifier and the field could not, and * `ask --compare` reads the field, so the declared target architecture became * the deletion of a component that is not being deleted (ADR 0109). */ export type NativeSuccession = string | { readonly subject: string; readonly inRespectOf: string; }; export declare const successionSubject: (entry: NativeSuccession) => string; export declare const successionScope: (entry: NativeSuccession) => string | undefined; export { ATTESTATION_PREDICATE_PREFIX, attestationClaimValue, parseAttestationClaimValue, parseConstraintExpectsValue, type AttestationClaimParts, type ConstraintExpectsParts, } from './graph-claims.js'; interface ResolvedPosition { readonly line: number; readonly col: number; } export declare const withDiagnosticSubjects: (diagnostics: readonly Diagnostic[], sources: readonly WorkspaceSource[]) => readonly Diagnostic[]; export declare function compileWorkspace(sources: readonly WorkspaceSource[]): CompilationResult; export declare const compileWorkspaceWithProfileContext: (sources: readonly WorkspaceSource[]) => ContextualCompilationResult; /** * Compiles the whole workspace, reusing the YAML parse of every source whose * text is unchanged since `previous`. The compiled output is byte-identical to * {@link compileWorkspaceWithProfileContext} for the same sources: the cache * holds parse results only, and every cross-document decision is re-derived. * * Hold the returned `cache` and pass it to the next call. It retains one * composed value per current source and drops sources that left the workspace. */ export declare const compileWorkspaceIncremental: (sources: readonly WorkspaceSource[], previous?: CompilationCache) => IncrementalCompilationResult;