import type { MemoElement, MemoModelDTO, MemoRelationship } from './semantic.js'; /** Declared multiplicity on a connection end, e.g. `[0..1]`, `[1]`, `[*]`. */ export interface MultiplicityDTO { /** Lower bound (0 when unbounded-only, e.g. `[*]`). */ lower: number; /** Upper bound; null means unbounded (`*`). */ upper: number | null; } /** One end of a relationship definition. */ export interface RelationshipEndDTO { /** End name as declared in SysML, e.g. "control", "requiredElement". */ name: string; /** Declared end type (a kind name). Undefined ends accept any kind. */ type?: string; /** Declared multiplicity, when the ontology states one. */ multiplicity?: MultiplicityDTO; } /** * Serializable projection of one RelationshipRegistry entry — the wire format * the web client uses to reason about legality without a parser. */ export interface RelationshipDefinitionDTO { /** Normalized camelCase name used on MemoRelationship.type, e.g. "satisfiedBy". */ name: string; /** PascalCase SysML name of the `connection def`, e.g. "SatisfiedBy". */ sysmlName: string; /** Human-readable label, e.g. "Satisfied By". */ label: string; /** Doc comment from the connection definition, when present. */ description?: string; /** Architecture layer the connection definition lives in. */ layer: string; /** Abstract definitions are not directly instantiable. */ isAbstract?: boolean; /** * Whether an element may be related to itself by this relation, from the * ontology's `isReflexive` attribute. Undefined means the ontology is * silent, and self-links are refused — see SELF_LINK_ALLOWED_BY_DEFAULT. */ isReflexive?: boolean; /** * Whether the same ordered pair may carry more than one link of this type, * from the ontology's `isUnique` attribute. Undefined means the ontology is * silent, and repeats are refused — see DUPLICATES_ALLOWED_BY_DEFAULT. */ isUnique?: boolean; /** * The SysML v2 keyword that writes this relation natively — `satisfy`, * `verify`, `allocate` — when the language already provides one. Set means * the relation is a usage, not a `connection def` instance, and must not be * serialized as `connection : X connect a to b`. */ nativeKeyword?: string; /** First declared end — the source/from end. */ sourceEnd: RelationshipEndDTO; /** Second declared end — the target/to end. */ targetEnd: RelationshipEndDTO; } /** Serializable projection of one KindRegistry entry. */ export interface KindDefinitionDTO { name: string; label: string; layer: string; /** SysML v2 construct, e.g. "part def". */ construct: string; /** Direct supertype, the basis for transitive conformance. */ superType?: string; /** The rest of a multiple specialization — see KindRegistryEntry. */ additionalSuperTypes?: string[]; isAbstract?: boolean; /** * Ontology namespace segments derived from the source tree. * Example: ["assurance", "safety_risk", "analysis"]. */ namespace?: string[]; } /** Both ontology registries in serializable form, as shipped to the client. */ export interface OntologyRegistriesDTO { relationships: RelationshipDefinitionDTO[]; kinds: KindDefinitionDTO[]; } /** Direction of a relationship relative to the selected element. */ export type RelationshipDirection = 'outgoing' | 'incoming'; /** A request to create one model relationship. */ export interface RelationshipCreateRequest { /** Correlates the response with the pending UI row. */ requestId: string; /** Relationship type — camelCase name or PascalCase sysmlName. */ type: string; /** Element occupying the relationship's source end. */ sourceId: string; /** Element occupying the relationship's target end. */ targetId: string; /** Direction the user chose, relative to the element they had selected. */ direction: RelationshipDirection; /** Element the user had selected when they opened the dialog. */ selectedElementId?: string; /** Requested owning package or project-relative file, when the user picked one. */ owningFile?: string; /** Diagram the request was invoked from, when invoked from a diagram. */ diagramId?: string; /** Optional item or information flow transported by the connector. */ flowItem?: string; /** Guard expression, for notations that take one (a guarded succession). */ guard?: string; /** * IR identity of the source element, from the revision the caller drew * against. Checked before anything is written; a stale one is refused * rather than resolved by name. See `model/ir-identity.ts`. */ sourceIdentity?: string; /** IR identity of the target element, checked the same way. */ targetIdentity?: string; } /** A request to delete one model relationship. */ export interface RelationshipDeleteRequest { requestId: string; /** Stable relationship ID (the connection usage name). */ relationshipId: string; /** Source file the caller believes owns it — checked against the model. */ sourceFile?: string; } /** Move one or both endpoints of an existing relationship declaration. */ export interface RelationshipUpdateRequest { requestId: string; relationshipId: string; sourceId: string; targetId: string; diagramId?: string; sourceIdentity?: string; targetIdentity?: string; } /** Machine-readable codes so callers can branch without matching on prose. */ export type RelationshipDiagnosticCode = 'REL-001' | 'REL-002' | 'REL-003' | 'REL-004' | 'REL-005' | 'REL-006' | 'REL-007' | 'REL-008' | 'REL-009' | 'REL-010'; /** One actionable validation failure. */ export interface RelationshipDiagnostic { code: RelationshipDiagnosticCode; message: string; /** 'error' blocks the mutation; 'warning' is advisory (view-profile fit). */ severity: 'error' | 'warning'; } /** Outcome of validating a mutation request. */ export interface RelationshipValidationResult { /** True when no error-severity diagnostic was raised. */ valid: boolean; diagnostics: RelationshipDiagnostic[]; /** Normalized camelCase relationship type, when the type resolved. */ normalizedType?: string; /** The resolved definition, when the type resolved. */ definition?: RelationshipDefinitionDTO; } /** How an undeclared `isReflexive` is read. */ export declare const SELF_LINK_ALLOWED_BY_DEFAULT = false; /** How an undeclared `isUnique` is read (unique ⇒ duplicates refused). */ export declare const DUPLICATES_ALLOWED_BY_DEFAULT = false; /** Whether this relation permits an element to be related to itself. */ export declare function allowsSelfLink(definition: RelationshipDefinitionDTO): boolean; /** Whether this relation permits the same ordered pair to be linked twice. */ export declare function allowsDuplicates(definition: RelationshipDefinitionDTO): boolean; /** * How constrained a relation is, as the number of ends it types (0–2). * * Read off the ontology rather than a curated list: a relation that types both * ends says the most about what it connects, and one that types neither can * join anything. Callers order by this so precise relations are offered ahead * of general ones. */ export declare function relationshipSpecificity(definition: RelationshipDefinitionDTO): number; /** * True for a relation that can join any two elements because it types neither * end — MemoLink and anything else declared the same way. These are the * fallback when no specific relation carries the meaning, so they are offered * last rather than suppressed. */ export declare function isUniversalRelationship(definition: RelationshipDefinitionDTO): boolean; /** Index kind definitions by name for O(1) supertype walks. */ export declare function indexKinds(kinds: KindDefinitionDTO[]): Map; /** * Resolve a relationship definition by camelCase name or PascalCase sysmlName. * Callers may hold either form (the model uses camelCase, SysML source uses * PascalCase), so both resolve to the same definition. */ export declare function findRelationshipDefinition(type: string, registries: OntologyRegistriesDTO): RelationshipDefinitionDTO | undefined; /** * True when `actualKind` may occupy an end declared as `expectedKind`. * * Conformance is transitive over the kind specialization chain, so * HardwareAssembly :> ArchitectureElement :> MemoPart conforms to all three. * An undefined or empty expected type accepts any kind (untyped end). */ export declare function kindConformsTo(actualKind: string, expectedKind: string | undefined, kindRegistry: Map | KindDefinitionDTO[]): boolean; /** * Which ends of `definition` the element may occupy. * * 'outgoing' means the element can sit on the source end (element → other); * 'incoming' means it can sit on the target end (other → element). An element * whose kind conforms to both ends legally supports both directions. */ export declare function legalRelationshipDirections(selectedElement: Pick, definition: RelationshipDefinitionDTO, registries: OntologyRegistriesDTO): RelationshipDirection[]; /** * Every relationship type the element can participate in, with the directions * it may take. This is what the Properties panel lists under Add Relationship * before the user has picked an opposite endpoint. */ export declare function legalRelationshipsForElement(selectedElement: Pick, registries: OntologyRegistriesDTO): Array<{ definition: RelationshipDefinitionDTO; directions: RelationshipDirection[]; }>; /** One legal (type, direction) pair between two concrete elements. */ export interface LegalRelationshipOption { definition: RelationshipDefinitionDTO; /** Direction relative to `sourceElement` — the first argument. */ direction: RelationshipDirection; /** Element that ends up on the source end for this option. */ sourceId: string; /** Element that ends up on the target end for this option. */ targetId: string; } /** * All relationship types legal between two specific elements, in both * directions. Backs the target-first workflow: pick any element, then see only * the links that could actually connect the two. * * `direction` is stated relative to `sourceElement`, so an 'incoming' option * means sourceElement occupies the target end. */ export declare function legalRelationshipTypes(sourceElement: Pick, targetElement: Pick, registries: OntologyRegistriesDTO): LegalRelationshipOption[]; /** Filters applied to the opposite-endpoint search. */ export interface TargetFilter { /** Free text matched against element name, id and shortId. */ query?: string; kind?: string; layer?: string; package?: string; } /** One candidate for the opposite endpoint, carrying its grouping keys. */ export interface RelationshipTargetCandidate { element: MemoElement; kind: string; layer: string; package?: string; } /** * Every element in the loaded model that may legally occupy the opposite end. * * Searches the complete model — not only what the active diagram shows — and * excludes the selected element itself, since self-relationships are prohibited. */ export declare function compatibleRelationshipTargets(selectedElement: Pick, definition: RelationshipDefinitionDTO, direction: RelationshipDirection, model: Pick, registries: OntologyRegistriesDTO, filter?: TargetFilter): RelationshipTargetCandidate[]; /** Group candidates by kind within layer, for the picker's section headers. */ export declare function groupTargetsByKindAndLayer(candidates: RelationshipTargetCandidate[]): Array<{ layer: string; kind: string; elements: MemoElement[]; }>; /** View profile the relationship would have to satisfy to be drawn. */ export interface ViewProfileContext { diagramId: string; /** Relationship types the view permits. Empty/undefined means unrestricted. */ permittedRelationshipTypes?: string[]; /** Elements the view selects. Empty/undefined means unrestricted. */ elementIds?: string[]; } /** Everything validation needs beyond the model and registries. */ export interface RelationshipMutationContext { /** Profile of the diagram the request came from, when there was one. */ viewProfile?: ViewProfileContext; /** False when the project has no writable package able to own the link. */ hasWritableOwner?: boolean; } /** * The complete legality check for a create request. The client runs this to * shape the UI; the server runs the identical function again before touching a * file, so a stale or hand-crafted request cannot bypass the ontology. */ export declare function validateRelationshipMutation(request: RelationshipCreateRequest, model: Pick, registries: OntologyRegistriesDTO, context?: RelationshipMutationContext): RelationshipValidationResult; /** Validate a delete request against the loaded model. */ export declare function validateRelationshipDeletion(request: RelationshipDeleteRequest, model: Pick): { valid: boolean; diagnostics: RelationshipDiagnostic[]; relationship?: MemoRelationship; }; /** * Plain-language preview of a pending relationship, e.g. * "Infusion Controller — satisfies → Software Requirement SR-104". * Shared so the Properties panel and the diagram picker word it identically. */ export declare function describeRelationship(definition: RelationshipDefinitionDTO, source: Pick | undefined, target: Pick | undefined, options?: { sourceId?: string; targetId?: string; }): string; /** * Whether an existing relationship should be drawn in a given view: both * endpoints selected by the view, and the type permitted by its profile. */ export declare function isRelationshipVisibleInView(relationship: Pick, profile: ViewProfileContext): boolean; //# sourceMappingURL=relationship-legality.d.ts.map