components_rs/components/types.rs
1//! Core data types produced by the component extractor.
2//!
3//! All four main types carry an `iri_span: Range<usize>` — the byte range of the `@id` value
4//! in the source file. Combine it with the `source_file` field (on [`CjsModule`] and
5//! [`ConfigInstance`]) or with `module_iri → CjsModule.source_file` (for [`CjsComponent`] and
6//! [`CjsParameter`]) to build an LSP `Location` for goto-definition responses.
7//!
8//! Spans use `0..0` as a sentinel when the source byte range could not be determined (e.g.,
9//! because the file failed to parse or because the node was synthesised during merging).
10
11use std::ops::Range;
12
13use rdf_parsers::jsonld::convert::JsonLdVal;
14
15pub const PREFIX_OO: &str =
16 "https://linkedsoftwaredependencies.org/vocabularies/object-oriented#";
17pub const PREFIX_OM: &str =
18 "https://linkedsoftwaredependencies.org/vocabularies/object-mapping#";
19pub const PREFIX_RDF: &str = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
20pub const PREFIX_RDFS: &str = "http://www.w3.org/2000/01/rdf-schema#";
21pub const PREFIX_XSD: &str = "http://www.w3.org/2001/XMLSchema#";
22pub const PREFIX_DOAP: &str = "http://usefulinc.com/ns/doap#";
23pub const PREFIX_OWL: &str = "http://www.w3.org/2002/07/owl#";
24
25// Well-known OO IRIs
26pub const IRI_MODULE: &str =
27 "https://linkedsoftwaredependencies.org/vocabularies/object-oriented#Module";
28pub const IRI_CLASS: &str =
29 "https://linkedsoftwaredependencies.org/vocabularies/object-oriented#Class";
30pub const IRI_ABSTRACT_CLASS: &str =
31 "https://linkedsoftwaredependencies.org/vocabularies/object-oriented#AbstractClass";
32pub const IRI_COMPONENT_INSTANCE: &str =
33 "https://linkedsoftwaredependencies.org/vocabularies/object-oriented#ComponentInstance";
34pub const IRI_COMPONENT: &str =
35 "https://linkedsoftwaredependencies.org/vocabularies/object-oriented#component";
36pub const IRI_COMPONENT_PATH: &str =
37 "https://linkedsoftwaredependencies.org/vocabularies/object-oriented#componentPath";
38pub const IRI_PARAMETER: &str =
39 "https://linkedsoftwaredependencies.org/vocabularies/object-oriented#parameter";
40pub const IRI_CONSTRUCTOR_ARGUMENTS: &str =
41 "https://linkedsoftwaredependencies.org/vocabularies/object-oriented#constructorArguments";
42
43pub const IRI_DOAP_NAME: &str = "http://usefulinc.com/ns/doap#name";
44pub const IRI_RDFS_SUBCLASS_OF: &str = "http://www.w3.org/2000/01/rdf-schema#subClassOf";
45pub const IRI_RDFS_SEE_ALSO: &str = "http://www.w3.org/2000/01/rdf-schema#seeAlso";
46pub const IRI_RDFS_RANGE: &str = "http://www.w3.org/2000/01/rdf-schema#range";
47pub const IRI_RDFS_COMMENT: &str = "http://www.w3.org/2000/01/rdf-schema#comment";
48
49/// Whether a component is a concrete class, an abstract class, or a singleton instance.
50///
51/// Used by LSP completion to decide what hover/detail info to show:
52/// - `Class` → instantiable, show constructor parameters
53/// - `AbstractClass` → not directly instantiable, show as base type in completions
54/// - `Instance` → pre-built singleton, no constructor parameters needed
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub enum ComponentType {
57 Class,
58 AbstractClass,
59 Instance,
60}
61
62impl ComponentType {
63 pub fn from_type_iris(types: &[String]) -> Option<Self> {
64 for t in types {
65 match t.as_str() {
66 IRI_CLASS => return Some(ComponentType::Class),
67 IRI_ABSTRACT_CLASS => return Some(ComponentType::AbstractClass),
68 IRI_COMPONENT_INSTANCE => return Some(ComponentType::Instance),
69 _ => {}
70 }
71 }
72 None
73 }
74}
75
76impl std::fmt::Display for ComponentType {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 match self {
79 ComponentType::Class => write!(f, "Class"),
80 ComponentType::AbstractClass => write!(f, "AbstractClass"),
81 ComponentType::Instance => write!(f, "Instance"),
82 }
83 }
84}
85
86/// A CJS module — the top-level container declared in a `components.jsonld` file.
87///
88/// Each npm package with `lsd:module` exposes exactly one module. The module
89/// groups all its component classes and is the entry point for import-path
90/// resolution. Use `source_file` + `iri_span` for goto-definition on module IRIs
91/// that appear in config `@context` entries.
92#[derive(Debug, Clone)]
93pub struct CjsModule {
94 /// Full expanded IRI of this module (e.g. `https://…/MyPackage`).
95 pub iri: String,
96 /// npm package name used in `require()` calls (from `doap:name`).
97 pub require_name: Option<String>,
98 /// All component classes declared in this module.
99 pub components: Vec<CjsComponent>,
100 /// Absolute path to the `components.jsonld` file that defines this module.
101 pub source_file: String,
102 /// Byte range of the `@id` value for this module in `source_file`.
103 /// Use this for LSP goto-definition when the cursor is on a module IRI.
104 pub iri_span: Range<usize>,
105}
106
107/// A CJS component — a class, abstract class, or singleton instance declared
108/// inside a module.
109///
110/// Returned by [`ComponentRegistry`] and used for:
111/// - **Autocompletion** of `@type` values in config files (all variants)
112/// - **Hover documentation** — `comment` provides the description
113/// - **Goto-definition** — `source_file` + `iri_span` points to the `@id`
114/// in the file where this component is defined (may differ from the module's
115/// entry-point file when components are split across imported sub-files)
116/// - **Parameter completion** — `parameters` drives key completion inside
117/// config instance objects
118#[derive(Debug, Clone)]
119pub struct CjsComponent {
120 /// Fully expanded IRI identifying this component.
121 pub iri: String,
122 pub component_type: ComponentType,
123 /// The JavaScript export name to require (from `oo:componentPath`).
124 pub require_element: Option<String>,
125 /// Human-readable description from `rdfs:comment` — shown in hover cards.
126 pub comment: Option<String>,
127 /// Constructor parameters for this component (own + inherited via `finalize`).
128 pub parameters: Vec<CjsParameter>,
129 /// IRIs of parent classes (from `rdfs:subClassOf`). Populated so the LSP
130 /// can show the full inheritance chain and resolve inherited parameters.
131 pub extends: Vec<String>,
132 /// Raw constructor arguments descriptor (kept for completeness).
133 pub constructor_arguments: Option<JsonLdVal>,
134 /// IRI of the module that declares this component.
135 pub module_iri: Option<String>,
136 /// Absolute path to the file where this component's `@id` is defined.
137 /// This is the correct target for goto-definition; it may differ from
138 /// `CjsModule::source_file` when the module imports component sub-files.
139 pub source_file: String,
140 /// Byte range of the `@id` value for this component in `source_file`.
141 pub iri_span: Range<usize>,
142}
143
144/// A single named parameter on a CJS component.
145///
146/// Used for:
147/// - **Key completion** inside config instance objects (the parameter IRI,
148/// compacted via the active context, is the JSON key)
149/// - **Type-aware value completion** — `range` restricts accepted value types
150/// - **Goto-definition** on a config parameter key — `source_file` + `iri_span`
151/// point to the `@id` in the component definition file
152#[derive(Debug, Clone)]
153pub struct CjsParameter {
154 /// Fully expanded parameter IRI (the JSON key in a config file after expansion).
155 pub iri: String,
156 /// Accepted value type IRI (from `rdfs:range`), e.g. `xsd:string`.
157 pub range: Option<String>,
158 /// Human-readable description from `rdfs:comment`.
159 pub comment: Option<String>,
160 /// Whether this parameter must be provided in every config instance.
161 pub required: bool,
162 /// Whether the value is lazily resolved at runtime.
163 pub lazy: bool,
164 /// Whether only a single value is allowed (no array).
165 pub unique: bool,
166 /// Default value used when the parameter is omitted.
167 pub default_value: Option<JsonLdVal>,
168 /// Absolute path to the file where this parameter's `@id` is defined.
169 pub source_file: String,
170 /// Byte range of the `@id` value for this parameter in `source_file`.
171 pub iri_span: Range<usize>,
172}
173
174/// A concrete configuration instance — a pre-wired instantiation of a component
175/// with specific parameter values, declared in a `config/*.jsonld` file.
176///
177/// Config instances are the primary subject of config files. The LSP uses them
178/// to validate that all required parameters are present and that value types
179/// match the `CjsParameter.range` constraints. `source_file` + `iri_span`
180/// support goto-definition when the instance IRI is referenced elsewhere.
181#[derive(Debug, Clone)]
182pub struct ConfigInstance {
183 /// IRI of this config instance.
184 pub iri: String,
185 /// IRI of the component class this instance instantiates (`@type` value).
186 pub component_type_iri: String,
187 /// Parameter values keyed by their fully expanded parameter IRI.
188 pub parameters: std::collections::HashMap<String, JsonLdVal>,
189 /// Absolute path to the config file containing this instance.
190 pub source_file: String,
191 /// Byte range of the `@id` value for this instance in `source_file`.
192 pub iri_span: Range<usize>,
193}