import type { SysMLConstruct } from './config.js'; /** * A kind as the registry reports it. * * This shape used to live in `config.ts`, where a YAML `kinds:` block could * declare one. Kinds come from the ontology's own `part def` / `item def` * declarations now, so the shape belongs to the registry that derives it. */ export interface KindDefinition { /** Human-readable label */ label: string; /** Architecture layer this kind belongs to */ layer?: string; /** SysML v2 construct this kind maps to */ sysmlConstruct: SysMLConstruct; /** Icon identifier for the palette/diagram */ icon?: string; /** Template file for new instances */ template?: string; /** Default attributes for new instances */ defaultAttributes?: Record; } import type { ParsedDocument } from './parser-utils.js'; import type { KindDefinitionDTO } from './relationship-legality.js'; /** Entry in the KindRegistry, matching KindDefinition shape */ export interface KindRegistryEntry { /** Kind name (e.g. "Hazard") */ name: string; /** Human-readable label */ label: string; /** Architecture layer derived from directory path */ layer: string; /** SysML v2 construct type */ sysmlConstruct: SysMLConstruct; /** Supertype name if the definition specializes another */ superType?: string; /** * The rest of a multiple specialization. * * `interface def Interface specializes MemoInterface, Interfaces::Interface` * declares two, and only the first fits in `superType`. Dropping the rest * broke every check that walks the chain: when UIElement still declared * `specializes SoftwareElement, InteractionElement`, 314 well-formed * `elementTriggersAction` links were reported as malformed because the * second supertype was invisible. The grammar has always captured these * (`additionalSpecializations`); the registry simply dropped them. */ additionalSuperTypes?: string[]; /** Description extracted from SysML doc comment */ description?: string; /** Kinds that specialize this kind (reverse of superType) */ derivedBy?: string[]; /** Compliance standard (e.g. "iso-14971"), set for kinds under compliance// */ standard?: string; /** Standard clause reference (e.g. "4.5"), extracted from SysML attribute if present */ clause?: string; /** Abstract definitions (e.g. MemoPart) classify but are never instantiated */ isAbstract?: boolean; /** Namespace segments mirrored by the ontology source folders. */ namespace?: string[]; /** * Fully qualified name, e.g. `memo::ontology::assurance::safety_risk::Hazard`. * * This is the registry's real identity. `name` is a short index into it, * which resolves only while it is unambiguous — see `getCollisions`. */ qualifiedName?: string; /** Source file this definition was declared in. */ sourceFile?: string; } /** * Two definitions sharing a short name. * * Previously the second silently replaced the first in a `Map` keyed by short * name, so which one survived depended on file iteration order and the loss was * invisible. Collisions are now recorded and surfaced as load diagnostics. */ export interface KindNameCollision { shortName: string; /** Qualified names competing for the short name, in discovery order. */ qualifiedNames: string[]; /** Files declaring them, aligned with `qualifiedNames`. */ sourceFiles: string[]; } /** * Registry that discovers kinds from SysML AST Definition nodes. * Replaces config.kinds lookups in the builder. */ export declare class KindRegistry { private readonly kinds; /** * Attribute values bound by a `view def`, keyed by definition name, with the * definition's own supertype chain already merged in. * * A view usage inherits these — `view mainScreenLayout : MemoScreenLayoutView` * gets that definition's `viewKind` without restating it, and SysIDE in fact * REJECTS restating it ("Cannot override a binding feature value"). So the * definition is the only place the value can live, and consumers resolve a * usage's presentation by falling back here. * * View definitions are not registered as kinds: they classify views, not * model elements, and adding them to the kind extent would put them in the * Explorer and in kind counts where they do not belong. */ private readonly viewDefaults; private readonly viewSuperTypes; /** short name → the qualified name it currently resolves to. */ private readonly byQualifiedName; /** qualified name → declaring file, for collision diagnostics. */ private readonly sourceFiles; private readonly collisions; /** Number of registered kinds */ get size(): number; /** * Look up a kind by name. * Returns undefined if the kind is not registered. */ getKind(name: string): KindRegistryEntry | undefined; /** * Attribute values a view usage inherits from its `view def`, resolved up * the definition's specialization chain (nearest declaration wins). */ getViewDefaults(viewDefName: string | undefined): Record | undefined; /** * Convert a registry entry to a KindDefinition (for backward compat with builder). */ toKindDefinition(name: string): KindDefinition | undefined; /** * Get all registered kinds as a Record, * matching the shape of config.kinds for backward compatibility. */ toKindsRecord(): Record; /** Check if a kind is registered */ has(name: string): boolean; /** Get all kind names */ kindNames(): string[]; /** Get all entries */ entries(): KindRegistryEntry[]; /** * Return a registry augmented with project-local definitions. Definitions * that derive from a registered ontology kind inherit that kind's * placement. Other valid SysML definitions remain available under the * standard SysML area instead of being reported as undefined. The * ontology registry itself remains unchanged (it is frozen for the * lifetime of an Architect session). * * Local extension kinds inherit their ontology parent's placement while * retaining their own name and construct. This lets a project declare, * for example, `FirmwareComponent specializes SoftwareComponent` and use * FirmwareComponent everywhere the ontology accepts SoftwareComponent. */ withProjectExtensions(documents: ParsedDocument[]): KindRegistry; /** * Project the registry into serializable definitions for the web client. * Only the fields relationship legality needs — chiefly superType, which * carries the specialization chain that conformance walks. */ toDefinitionDTOs(): KindDefinitionDTO[]; /** Get compliance standard groups discovered from the ontology tree. */ getComplianceGroups(): { standard: string; kinds: KindRegistryEntry[]; }[]; /** Register a kind manually (for testing or config fallback) */ register(entry: KindRegistryEntry): void; /** * Track qualified identity alongside the short-name map. * * Short-name lookup is kept as-is so every existing caller keeps working; * what changes is that a shadowed definition is no longer lost silently. * A re-registration of the SAME qualified name is not a collision — that * happens legitimately when a registry is copied in `withProjectExtensions`. */ private recordIdentity; /** * Short names claimed by more than one qualified definition. * * Callers surface these as load diagnostics: a reference to an ambiguous * short name cannot be resolved by load order and needs qualifying. */ getCollisions(): KindNameCollision[]; /** Qualified name a short name currently resolves to. */ getQualifiedName(shortName: string): string | undefined; /** * Give a kind the placement of the kind it specializes, wherever its own * declaring path could not supply one. * * Layer, namespace and standard are derived from the declaring file's path * under `src//`. An EXTENSION declares its types in * `extensions//src/`, which matches no layer — so `RosNode`, * `CloudService` and `AadlThread` all landed in `unknown` and a project * that included one showed most of its model as unplaced. * * The placement is read from the specialization, not from any list of * names: `RosNode : SoftwareComponent` is implementation because * `SoftwareComponent` is. Resolution repeats so a chain works regardless * of source-file order (`RosContainerImage -> ContainerImage -> * DeploymentUnit`), and a kind that specializes nothing placed stays * `unknown`, which is the honest answer. * * Must be called after populateFromDocuments() is complete. */ inheritPlacementFromSuperTypes(): void; /** * Compute the derivedBy reverse-lookup for all kinds. * Must be called after populateFromDocuments() is complete. */ computeDerivedBy(): void; /** * Populate the registry from parsed SysML documents. * Walks all Definition nodes in each document's AST and registers them. */ populateFromDocuments(documents: ParsedDocument[]): void; /** Walk a package declaration and register all Definition nodes */ private walkPackage; } /** * The ontology facts a formatter or importer needs, derived from the registries. * * Consumers used to take a `MEMOConfig` and read `config.kinds` and * `config.relationshipTypes` off it, which meant a settings file could declare * a kind the ontology never defined. They take this instead: it can only be * built from what the resolved SysML declares. */ export interface OntologyView { kinds: Record; relationshipTypes: Array<{ name: string; label: string; layer: string; color: string; }>; } /** An empty view — what a caller has before any ontology is resolved. */ export declare const EMPTY_ONTOLOGY_VIEW: OntologyView; /** Build a view from populated registries. */ export declare function ontologyViewFrom(kindRegistry?: { toKindsRecord(): Record; }, relationshipRegistry?: { toRelationshipTypesArray(): OntologyView['relationshipTypes']; }): OntologyView; //# sourceMappingURL=kind-registry.d.ts.map