# @memberjunction/doc-utils
A TypeScript library for dynamically retrieving, parsing, and caching MemberJunction library documentation from the official documentation website. Designed to support AI models, code generation tools, and other documentation-driven features that need structured access to MJ library metadata.
## Overview
The `@memberjunction/doc-utils` package provides a singleton `DocumentationEngine` that loads library and library item metadata from the MemberJunction entity system, then fetches the corresponding HTML documentation pages from the official MJ documentation site ([https://memberjunction.github.io/MJ/](https://memberjunction.github.io/MJ/)). Parsed content is cached in memory for efficient repeated access.
This package is particularly useful for:
- Feeding structured library documentation to AI models for context-aware code generation
- Building developer tools that reference MJ API documentation
- Providing searchable documentation indexes for MJ packages and their exported items
## Architecture
```mermaid
graph TB
subgraph DocUtils["DocUtils Package"]
DE["DocumentationEngine
(Singleton)"]
LEE["MJLibraryEntityExtended"]
LIEE["MJLibraryItemEntityExtended"]
end
subgraph MJCore["@memberjunction/core"]
BE["BaseEngine"]
BEnt["BaseEntity"]
end
subgraph CoreEntities["@memberjunction/core-entities"]
LE["LibraryEntity"]
LIE["LibraryItemEntity"]
end
subgraph External["External Services"]
DB[("MJ Database
Libraries &
Library Items")]
DOCS["MJ Docs Site
memberjunction.github.io"]
end
DE -->|extends| BE
LEE -->|extends| LE
LIEE -->|extends| LIE
LE -->|extends| BEnt
LIE -->|extends| BEnt
DE -->|loads metadata| DB
DE -->|fetches HTML| DOCS
DE -->|manages| LEE
DE -->|manages| LIEE
LEE -->|contains| LIEE
style DE fill:#2d6a9f,stroke:#1a4971,color:#fff
style LEE fill:#2d8659,stroke:#1a5c3a,color:#fff
style LIEE fill:#2d8659,stroke:#1a5c3a,color:#fff
style BE fill:#7c5295,stroke:#563a6b,color:#fff
style BEnt fill:#7c5295,stroke:#563a6b,color:#fff
style LE fill:#7c5295,stroke:#563a6b,color:#fff
style LIE fill:#7c5295,stroke:#563a6b,color:#fff
style DB fill:#b8762f,stroke:#8a5722,color:#fff
style DOCS fill:#b8762f,stroke:#8a5722,color:#fff
```
## Data Flow
The engine follows a two-phase loading process: first it loads entity metadata from the database, then it fetches and parses HTML documentation for each library item.
```mermaid
sequenceDiagram
participant App as Application
participant DE as DocumentationEngine
participant DB as MJ Database
participant Site as Docs Website
App->>DE: Config(forceRefresh, contextUser)
DE->>DB: Load Libraries (entity metadata)
DB-->>DE: MJLibraryEntityExtended[]
DE->>DB: Load Library Items (entity metadata)
DB-->>DE: MJLibraryItemEntityExtended[]
Note over DE: AdditionalLoading phase
loop For each Library
loop For each Item in Library
DE->>DE: Build URL from library name + item type
DE->>Site: GET /{type}/{sanitized_name}.{ItemName}.html
Site-->>DE: HTML response
DE->>DE: Parse HTML via JSDOM (extract div.col-content)
DE->>DE: Cache HTMLContent and URL on item
end
end
DE-->>App: Config complete, data cached
App->>DE: Access Libraries / LibraryItems
DE-->>App: Cached entity data with HTML content
```
## Class Hierarchy
```mermaid
classDiagram
class BaseEngine {
<>
+Load(configs, provider, forceRefresh, contextUser)
#AdditionalLoading(contextUser)*
}
class DocumentationEngine {
+Instance$ DocumentationEngine
+Libraries MJLibraryEntityExtended[]
+LibraryItems MJLibraryItemEntityExtended[]
+Config(forceRefresh, contextUser, provider)
#AdditionalLoading(contextUser)
#GetContent(url, rootSelector) string
#fetchDocumentation(url) string
#parseDocumentation(html, rootSelector) string
}
class BaseEntity {
<>
+Get(fieldName)
+Set(fieldName, value)
+Save()
}
class LibraryEntity {
+ID string
+Name string
+Description string?
+Status "Active" | "Disabled" | "Pending"
+TypeDefinitions string?
+SampleCode string?
}
class MJLibraryEntityExtended {
+Items MJLibraryItemEntityExtended[]
}
class LibraryItemEntity {
+ID string
+Name string
+LibraryID string
+Type "Class"|"Function"|"Interface"|"Module"|"Type"|"Variable"
+Library string
}
class MJLibraryItemEntityExtended {
+URL string
+HTMLContent string
+TypeURLSegment string
}
BaseEngine <|-- DocumentationEngine
BaseEntity <|-- LibraryEntity
BaseEntity <|-- LibraryItemEntity
LibraryEntity <|-- MJLibraryEntityExtended
LibraryItemEntity <|-- MJLibraryItemEntityExtended
DocumentationEngine o-- MJLibraryEntityExtended
DocumentationEngine o-- MJLibraryItemEntityExtended
MJLibraryEntityExtended o-- MJLibraryItemEntityExtended
style DocumentationEngine fill:#2d6a9f,stroke:#1a4971,color:#fff
style MJLibraryEntityExtended fill:#2d8659,stroke:#1a5c3a,color:#fff
style MJLibraryItemEntityExtended fill:#2d8659,stroke:#1a5c3a,color:#fff
style BaseEngine fill:#7c5295,stroke:#563a6b,color:#fff
style BaseEntity fill:#7c5295,stroke:#563a6b,color:#fff
style LibraryEntity fill:#7c5295,stroke:#563a6b,color:#fff
style LibraryItemEntity fill:#7c5295,stroke:#563a6b,color:#fff
```
## Installation
```bash
npm install @memberjunction/doc-utils
```
## Dependencies
**MemberJunction packages:**
| Package | Purpose |
|---------|---------|
| `@memberjunction/core` | Base engine class, metadata provider, user context |
| `@memberjunction/core-entities` | `LibraryEntity` and `LibraryItemEntity` base classes |
| `@memberjunction/global` | `@RegisterClass` decorator for entity registration |
**External packages:**
| Package | Purpose |
|---------|---------|
| `axios` | HTTP requests to the documentation website |
| `jsdom` | HTML parsing and DOM manipulation for content extraction |
## Usage
### Initializing the Engine
The `DocumentationEngine` uses the singleton pattern. Call `Config()` once to load metadata and documentation content before accessing data.
```typescript
import { DocumentationEngine } from '@memberjunction/doc-utils';
import { UserInfo } from '@memberjunction/core';
// Get the singleton instance
const docEngine = DocumentationEngine.Instance;
// Server-side: pass contextUser for proper data isolation
const contextUser: UserInfo = /* from your authentication context */;
await docEngine.Config(false, contextUser);
// Client-side: contextUser is optional
await docEngine.Config();
```
### Accessing Libraries and Items
After configuration, libraries and their items are available through cached properties.
```typescript
const docEngine = DocumentationEngine.Instance;
// Get all libraries
const libraries = docEngine.Libraries;
console.log(`Loaded ${libraries.length} libraries`);
// Find a specific library
const coreLib = libraries.find(lib => lib.Name === '@memberjunction/core');
if (coreLib) {
console.log(`${coreLib.Name} (${coreLib.Status})`);
console.log(`Items: ${coreLib.Items.length}`);
// Iterate through items in the library
for (const item of coreLib.Items) {
console.log(` ${item.Type}: ${item.Name}`);
console.log(` URL: ${item.URL}`);
console.log(` Content length: ${item.HTMLContent.length} chars`);
}
}
```
### Accessing All Library Items
The flat `LibraryItems` array provides access to all items across all libraries.
```typescript
const docEngine = DocumentationEngine.Instance;
// Get all library items regardless of library
const allItems = docEngine.LibraryItems;
// Filter by type
const allClasses = allItems.filter(item => item.Type === 'Class');
const allInterfaces = allItems.filter(item => item.Type === 'Interface');
// Find a specific item by name and library
const baseEntity = allItems.find(
item => item.Name === 'BaseEntity' && item.Library === '@memberjunction/core'
);
if (baseEntity) {
console.log(`Documentation URL: ${baseEntity.URL}`);
console.log(`HTML Content: ${baseEntity.HTMLContent}`);
}
```
### Force Refreshing Documentation
Pass `true` to `Config()` to reload all metadata from the database and re-fetch documentation content.
```typescript
const docEngine = DocumentationEngine.Instance;
// Force a complete reload
await docEngine.Config(true);
```
## API Reference
### DocumentationEngine
The primary class providing access to MJ library documentation. Extends `BaseEngine` and uses the singleton pattern.
| Member | Type | Description |
|--------|------|-------------|
| `Instance` (static) | `DocumentationEngine` | Returns the singleton instance |
| `Libraries` | `MJLibraryEntityExtended[]` | All loaded libraries with their items |
| `LibraryItems` | `MJLibraryItemEntityExtended[]` | Flat list of all library items across all libraries |
| `Config(forceRefresh?, contextUser?, provider?)` | `Promise` | Initializes the engine: loads metadata, fetches and parses documentation |
### MJLibraryEntityExtended
Extended entity class for libraries. Registered via `@RegisterClass(BaseEntity, "Libraries")`.
| Member | Type | Description |
|--------|------|-------------|
| `ID` | `string` | Unique identifier |
| `Name` | `string` | Library package name (e.g., `@memberjunction/core`) |
| `Description` | `string \| null` | Human-readable description |
| `Status` | `'Active' \| 'Disabled' \| 'Pending'` | Library availability status |
| `TypeDefinitions` | `string \| null` | Type/function definitions for reference by humans and AI |
| `SampleCode` | `string \| null` | Usage examples for the library |
| `Items` | `MJLibraryItemEntityExtended[]` | All items belonging to this library |
### MJLibraryItemEntityExtended
Extended entity class for individual library items (classes, interfaces, functions, etc.). Registered via `@RegisterClass(BaseEntity, "Library Items")`.
| Member | Type | Description |
|--------|------|-------------|
| `ID` | `string` | Unique identifier |
| `Name` | `string` | Item name (e.g., `BaseEntity`, `RunView`) |
| `LibraryID` | `string` | Foreign key to the parent library |
| `Library` | `string` | Denormalized library name from the view |
| `Type` | `'Class' \| 'Function' \| 'Interface' \| 'Module' \| 'Type' \| 'Variable'` | The kind of exported item |
| `URL` | `string` | Generated documentation URL for this item |
| `HTMLContent` | `string` | Parsed HTML content from the documentation page |
| `TypeURLSegment` | `string` (getter) | URL path segment derived from `Type` (e.g., `classes`, `interfaces`) |
### URL Generation
Documentation URLs are constructed automatically using the pattern:
```
https://memberjunction.github.io/MJ/{typeSegment}/{sanitizedLibraryName}.{ItemName}.html
```
Where:
- `{typeSegment}` is the pluralized, lowercase item type (`classes`, `interfaces`, `functions`, `modules`, `types`, `variables`)
- `{sanitizedLibraryName}` is the library name with `@`, `.`, `/`, and `\` characters replaced by `_`
- `{ItemName}` is the exact name of the exported item
For example, `BaseEntity` (a Class) in `@memberjunction/core` resolves to:
```
https://memberjunction.github.io/MJ/classes/_memberjunction_core.BaseEntity.html
```
## URL Routing by Item Type
```mermaid
graph LR
Item["Library Item"]
Item -->|Class| C["/classes/"]
Item -->|Interface| I["/interfaces/"]
Item -->|Function| F["/functions/"]
Item -->|Module| M["/modules/"]
Item -->|Type| T["/types/"]
Item -->|Variable| V["/variables/"]
style Item fill:#2d6a9f,stroke:#1a4971,color:#fff
style C fill:#2d8659,stroke:#1a5c3a,color:#fff
style I fill:#2d8659,stroke:#1a5c3a,color:#fff
style F fill:#2d8659,stroke:#1a5c3a,color:#fff
style M fill:#b8762f,stroke:#8a5722,color:#fff
style T fill:#b8762f,stroke:#8a5722,color:#fff
style V fill:#b8762f,stroke:#8a5722,color:#fff
```
## Integration with MemberJunction
This package integrates with the broader MemberJunction ecosystem through several mechanisms:
- **Entity System**: Uses `@RegisterClass` to register `MJLibraryEntityExtended` and `MJLibraryItemEntityExtended` as entity subclasses, ensuring the MJ class factory returns the extended types when loading Libraries and Library Items.
- **BaseEngine Pattern**: Extends `BaseEngine` with the `Config()` / `AdditionalLoading()` lifecycle, allowing consistent initialization and caching across all MJ engine classes.
- **User Context**: Supports `contextUser` for proper data isolation and security when running on the server side.
- **Metadata Provider**: Accepts an optional `IMetadataProvider` for environments with custom metadata access patterns.
## Build
```bash
# Build the package
cd packages/DocUtils
npm run build
# Development mode with file watching
npm start
```
## Source Files
| File | Description |
|------|-------------|
| `src/index.ts` | Public API surface -- re-exports from `Engine.ts` |
| `src/Engine.ts` | Core implementation: `DocumentationEngine`, `MJLibraryEntityExtended`, `MJLibraryItemEntityExtended` |
## Notes
- Documentation is fetched from [https://memberjunction.github.io/MJ/](https://memberjunction.github.io/MJ/) using `axios` HTTP GET requests.
- HTML content is parsed with `jsdom`, extracting the inner HTML of the `div.col-content` element from each page.
- All fetched content is cached in memory after the initial `Config()` call. Subsequent calls to `Config()` without `forceRefresh=true` return immediately.
- Library names containing special characters (`@`, `.`, `/`, `\`) are sanitized by replacing them with underscores for URL compatibility.
- If a documentation page cannot be fetched (network error, 404, etc.), the `HTMLContent` for that item is set to an error or placeholder string rather than throwing an exception.