@judo/model-loader
v0.1.1
Published
Model loading and registry services for JUDO UI Runtime
Readme
@judo/model-loader
Model loading and registry services for JUDO UI Runtime
Purpose
Provides three model-loading strategies (embedded XML, filesystem, HTTP), a central model registry with full cross-reference resolution, and tree-navigation utilities. Bridges raw parsed models into a fully resolved, queryable runtime registry.
Architecture Layer
Layer 1 (Foundation) — sits between model-parser and all higher-level packages that need resolved model access.
Dependencies
@judo/model-api— TypeScript type definitions (dependency + peer)@judo/model-parser— XML parsing (dependency + peer)axios— HTTP client (peer dependency)
Entry Points
| Export | File | Purpose |
| --------------- | ---------------- | ------------------------------------------------------------- |
| "." (default) | src/index.ts | Full entry — includes all loaders (Node + browser) |
| "." (browser) | src/browser.ts | Browser-only entry — excludes FileModelLoader (Node.js API) |
File Structure
src/
├── index.ts # Main barrel export
├── browser.ts # Browser-safe re-exports (no Node APIs)
├── errors.ts # Custom error classes
├── loaders/
│ ├── index.ts
│ ├── embedded-loader.ts # XML-from-string loader
│ ├── file-loader.ts # Filesystem loader (Node only)
│ └── http-loader.ts # HTTP/axios loader
└── registry/
├── index.ts
├── cross-reference.ts # Reference string parsing/building
├── instance-resolver.ts # Deep reference resolution + eContainer
└── model-registry.ts # Central registry (implements ModelRegistryService)Exports Summary
Loaders (implement ModelLoaderService)
| Class | Description |
| --------------------- | -------------------------------------------------------------------------------------------------------------- |
| EmbeddedModelLoader | Loads a model from a pre-imported XML string (bundled at build time). |
| FileModelLoader | Loads a model from a filesystem path using node:fs/promises. Node.js only — excluded from browser entry. |
| HttpModelLoader | Fetches XML from a URL via axios, parses to Application[]. |
All three implement the ModelLoaderService interface (from @judo/model-api) with a single load() method returning Promise<Application[]>.
Model Registry — ModelRegistry
Central model registry implementing ModelRegistryService. Key methods:
| Method | Description |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------- |
| registerModel(apps) | Registers parsed applications, triggers reference resolution, builds the element index, and notifies subscribers. |
| getApplications() | Returns all registered applications. |
| getApplication(name) | Returns a specific app by name; throws ModelNotFoundError if not found. |
| getActiveApplication() | Returns the currently active application; throws NoActiveApplicationError if none set. |
| setActiveApplication(name) | Sets the active application, invalidates snapshot cache, notifies subscribers. |
| resolveById(id) | Resolves any element by xmi:id (generic <T>). |
| resolveClassType(ref) | Resolves a ClassType by reference (with type guard). |
| resolveRelationType(ref) | Resolves a RelationType by reference (with type guard). |
| resolveAttributeType(ref) | Resolves an AttributeType by reference (with type guard). |
| resolveOperationType(ref) | Resolves an OperationType by reference (with type guard). |
| resolveDataType(ref) | Resolves a DataType by reference. |
| resolvePageDefinition(ref) | Resolves a PageDefinition by reference. |
| resolvePageContainer(ref) | Resolves a PageContainer by reference. |
| resolveActionDefinition(ref) | Resolves an ActionDefinition by reference. |
| resolveNavigationItem(ref) | Resolves a NavigationItem by xmi:id. |
| resolveVisualElement(ref) | Resolves a VisualElement by xmi:id or sourceId. |
| subscribe(callback) | Subscribes to registry changes (returns unsubscribe function). For useSyncExternalStore. |
| getSnapshot() | Returns a cached RegistrySnapshot — only creates new when invalidated. |
Cross-Reference Utilities
| Export | Kind | Description |
| ------------------------------------------ | --------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| ParsedReference | interface | Parsed form of a reference string: { namespace?, actorName?, elementId, elementType? }. |
| parseReference(ref) | function | Parses a reference string into ParsedReference. Handles namespaced (ns::Name), standard (Actor/(esm/_id)/Type), and direct ID formats. |
| buildReference(actor, id, type) | function | Builds a reference string from actor name, element ID, and type. |
| isNamespacedReference(ref) | function | Checks if a reference uses the :: namespace syntax. |
| isCrossActorReference(ref, currentActor) | function | Checks if a reference points to a different actor. |
Instance Resolver & Tree Navigation
| Export | Kind | Description |
| ---------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------- |
| ReferenceMapping | interface | Maps a property name to the target type of element it references. |
| REFERENCE_MAPPINGS | constant | Complete array of all known reference property mappings (49 entries). |
| REFERENCE_PROPERTIES | constant | Derived Set of all property names for fast O(1) lookup (48 unique names). |
| InstanceReferenceResolver | class | Core resolver: indexes by xmi:id/sourceId, sets eContainer, resolves string refs to object instances. |
| getContainer(element) | function | Returns the eContainer of a ModelElement, typed via generic <T>. |
| getAncestors(element) | function | Walks up the eContainer chain and returns all ancestors as an array. |
| findAncestor(element, predicate) | function | Finds the nearest ancestor matching a type-guard predicate. |
| isApplication(element) | type guard | Checks if element is an Application (by presence of pages property). |
| isPageDefinition(element) | type guard | Checks if element is a PageDefinition (by presence of container property). |
| isPageContainer(element) | type guard | Checks if element is a PageContainer (by @type discriminator). |
Error Classes
| Class | Description |
| -------------------------- | ---------------------------------------------------------------------------------------------- |
| ModelLoadError | Thrown when model loading fails (file read, HTTP fetch, parse). Properties: source, cause. |
| ModelNotFoundError | Thrown when an application/actor is not found in the registry. Property: actorName. |
| NoActiveApplicationError | Thrown when accessing the active application before one is set. |
| ReferenceResolutionError | Thrown when reference resolution fails. Properties: reference, referenceType. |
Key Patterns
- Strategy pattern (loaders): Three
ModelLoaderServiceimplementations sharing a common interface. Browser entry excludesFileModelLoader. - Single-pass index + deferred resolution:
InstanceReferenceResolverindexes the full tree once, then resolves all string references against the complete index in a second sweep. eContainernavigation: Every child gets aneContainerback-pointer during resolution, enabling upward tree traversal viagetContainer,getAncestors, andfindAncestor.- Dual indexing: Elements indexed by both
xmi:idandsourceId, allowing resolution by either key. - Snapshot caching for React:
ModelRegistrycaches the snapshot object and only creates new ones when invalidated, ensuring referential equality foruseSyncExternalStore. - Graceful degradation: Unresolvable references (e.g., external) are silently kept as strings.
- Type-guarded resolution: Methods like
resolveClassType,resolveRelationType,resolveAttributeType,resolveOperationTypeperform type checks before returning. - Error hierarchy: Four domain-specific error classes with structured properties for programmatic error handling.
