TypeDoc all the thngs

This commit is contained in:
2021-03-25 08:50:13 -05:00
parent 7cb0546b01
commit fad1184afe
52 changed files with 976 additions and 3 deletions

View File

@@ -8,12 +8,18 @@ import {Inject} from "@extollo/di";
import * as nodePath from 'path'
import {Unit} from "../lifecycle/Unit";
/**
* Interface describing a definition of a single canonical item loaded from the app.
*/
export interface CanonicalDefinition {
canonicalName: string,
originalName: string,
imported: any,
}
/**
* Type alias for a function that resolves a canonical name to a canonical item, if one exists.
*/
export type CanonicalResolver<T> = (key: string) => T | undefined
/**
@@ -25,6 +31,19 @@ export interface CanonicalReference {
particular?: string,
}
/**
* Abstract unit type that loads items recursively from a directory structure, assigning
* them normalized names ("canonical names"), and providing a way to fetch the resources
* by name.
*
* @example
* The Config service is a Canonical derivative that loads files ending with `.config.js`
* from the `app/config` directory.
*
* If, for example, there is a config file `app/config/auth/Forms.config.js` (in the
* generated code), it can be loaded by the canonical name `auth:Forms`.
*
*/
export abstract class Canonical<T> extends Unit {
@Inject()
protected readonly logging!: Logging
@@ -81,18 +100,26 @@ export abstract class Canonical<T> extends Unit {
}
}
/**
* Return an array of all loaded canonical names.
*/
public all(): string[] {
return Object.keys(this.loadedItems)
}
/**
* Get a Universal path to the base directory where this unit loads its canonical files from.
*/
public get path(): UniversalPath {
return this.app().appPath(...this.appPath)
}
/** Get the plural name of the canonical items provided by this unit. */
public get canonicalItems() {
return `${this.canonicalItem}s`
}
/** Get a canonical item by key. */
public get(key: string): T | undefined {
if ( key.startsWith('@') ) {
const [namespace, ...rest] = key.split(':')
@@ -112,6 +139,34 @@ export abstract class Canonical<T> extends Unit {
return this.loadedItems[key]
}
/**
* Register a namespace resolver with the canonical unit.
*
* Namespaces are canonical names that start with a particular key, beginning with the `@` character,
* which resolve their resources using a resolver function.
*
* @example
* ```typescript
* const items = {
* 'foo:bar': 123,
* 'bob': 456,
* }
*
* const resolver = (key: string) => items[key]
*
* canonical.registerNamespace('@mynamespace', resolver)
* ```
*
* Now, the items in the `@mynamespace` namespace can be accessed like so:
*
* ```typescript
* canonical.get('@mynamespace:foo:bar') // => 123
* canonical.get('@mynamespace:bob') // => 456
* ```
*
* @param name
* @param resolver
*/
public registerNamespace(name: string, resolver: CanonicalResolver<T>) {
if ( !name.startsWith('@') ) {
throw new ErrorWithContext(`Canonical namespaces must start with @.`, { name })
@@ -139,10 +194,20 @@ export abstract class Canonical<T> extends Unit {
this.canon.registerCanonical(this)
}
/**
* Called for each canonical item loaded from a file. This function should do any setup necessary and return the item
* that should be associated with the canonical name.
* @param definition
*/
public async initCanonicalItem(definition: CanonicalDefinition): Promise<T> {
return definition.imported.default ?? definition.imported[definition.canonicalName.split(':').reverse()[0]]
}
/**
* Given the path to a file in the canonical items directory, create a CanonicalDefinition record from that file.
* @param filePath
* @protected
*/
protected async buildCanonicalDefinition(filePath: string): Promise<CanonicalDefinition> {
const originalName = filePath.replace(this.path.toLocal, '').substr(1)
const pathRegex = new RegExp(nodePath.sep, 'g')