Support registering namespaced view directories; add lib() universal path
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2021-06-24 00:14:04 -05:00
parent a69c81ed35
commit 7506d6567d
9 changed files with 201 additions and 17 deletions

View File

@@ -1,7 +1,8 @@
import {Instantiable} from './types'
import {DependencyKey, Instantiable} from './types'
import NamedFactory from './factory/NamedFactory'
import {AbstractFactory} from './factory/AbstractFactory'
import {Factory} from './factory/Factory'
import {ClosureFactory} from './factory/ClosureFactory'
export class ContainerBlueprint {
private static instance?: ContainerBlueprint
@@ -36,6 +37,16 @@ export class ContainerBlueprint {
return this
}
/**
* Register a producer function as a ClosureFactory with this container.
* @param key
* @param producer
*/
registerProducer(key: DependencyKey, producer: () => any): this {
this.factories.push(() => new ClosureFactory(key, producer))
return this
}
resolve(): AbstractFactory<any>[] {
return this.factories.map(x => x())
}

View File

@@ -1,4 +1,5 @@
export * from './util'
export * from './lib'
export * from './di'
export * from './event/types'

8
src/lib.ts Normal file
View File

@@ -0,0 +1,8 @@
import {UniversalPath} from './util'
/**
* Get the path to the root of the @extollo/lib package.
*/
export function lib(): UniversalPath {
return new UniversalPath(__dirname)
}

View File

@@ -0,0 +1,3 @@
html
body
h1 Extollo Login Page

View File

@@ -5,6 +5,8 @@ import {Logging} from './Logging'
import {Route} from '../http/routing/Route'
import {HTTPMethod} from '../http/lifecycle/Request'
import {ViewEngineFactory} from '../views/ViewEngineFactory'
import {ViewEngine} from '../views/ViewEngine'
import {lib} from '../lib'
/**
* Application unit that loads the various route files from `app/http/routes` and pre-compiles the route handlers.
@@ -18,6 +20,9 @@ export class Routing extends Unit {
public async up(): Promise<void> {
this.app().registerFactory(new ViewEngineFactory())
const engine = <ViewEngine> this.make(ViewEngine)
this.logging.verbose('Registering @extollo view engine namespace.')
engine.registerNamespace('extollo', lib().concat('resources', 'views'))
for await ( const entry of this.path.walk() ) {
if ( !entry.endsWith('.routes.js') ) {

View File

@@ -20,11 +20,8 @@ export class PugViewEngine extends ViewEngine {
return compiled(locals)
}
if ( !templateName.endsWith('.pug') ) {
templateName += '.pug'
}
const filePath = this.path.concat(...templateName.split(':'))
compiled = pug.compileFile(filePath.toLocal, this.getOptions())
const filePath = this.resolveName(templateName)
compiled = pug.compileFile(filePath.toLocal, this.getOptions(templateName))
this.compileCache[templateName] = compiled
return compiled(locals)
@@ -34,9 +31,9 @@ export class PugViewEngine extends ViewEngine {
* Get the object of options passed to Pug's compile methods.
* @protected
*/
protected getOptions(): pug.Options {
protected getOptions(templateName?: string): pug.Options {
return {
basedir: this.path.toLocal,
basedir: templateName ? this.resolveBasePath(templateName).toLocal : this.path.toLocal,
debug: this.debug,
compileDebug: this.debug,
globals: [],

View File

@@ -1,7 +1,7 @@
import {AppClass} from '../lifecycle/AppClass'
import {Config} from '../service/Config'
import {Container} from '../di'
import {UniversalPath} from '../util'
import {ErrorWithContext, UniversalPath} from '../util'
/**
* Abstract base class for rendering views via different view engines.
@@ -11,6 +11,8 @@ export abstract class ViewEngine extends AppClass {
protected readonly debug: boolean
protected readonly namespaces: {[key: string]: UniversalPath} = {}
constructor() {
super()
this.config = Container.getContainer().make(Config)
@@ -38,4 +40,53 @@ export abstract class ViewEngine extends AppClass {
* @param locals
*/
public abstract renderByName(templateName: string, locals: {[key: string]: any}): string | Promise<string>
public registerNamespace(namespace: string, basePath: UniversalPath): this {
if ( namespace.startsWith('@') ) {
namespace = namespace.substr(1)
}
this.namespaces[namespace] = basePath
return this
}
public resolveName(templateName: string): UniversalPath {
let path = this.path
if ( templateName.startsWith('@') ) {
const [namespace, ...parts] = templateName.split(':')
path = this.namespaces[namespace.substr(1)]
if ( !path ) {
throw new ErrorWithContext('Invalid template namespace: ' + namespace, {
namespace,
templateName,
})
}
templateName = parts.join(':')
}
if ( !templateName.endsWith('.pug') ) {
templateName += '.pug'
}
return path.concat(...templateName.split(':'))
}
public resolveBasePath(templateName: string): UniversalPath {
let path = this.path
if ( templateName.startsWith('@') ) {
const [namespace] = templateName.split(':')
path = this.namespaces[namespace.substr(1)]
if ( !path ) {
throw new ErrorWithContext('Invalid template namespace: ' + namespace, {
namespace,
templateName,
})
}
}
return path
}
}