Skip to content

Commit

Permalink
Add MojoRenderOptions and MojoURLOptions to exported types for use in…
Browse files Browse the repository at this point in the history
… plugins
  • Loading branch information
kraih committed Nov 11, 2022
1 parent 7ff95fa commit 2769e6e
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 28 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -8,6 +8,7 @@ This package strictly follows [Semantic Versioning](https://semver.org).
### Features

* Added `labelFor` helper.
* Added `MojoRenderOptions` and `MojoURLOptions` to exported types for use in plugins.
* Improved `ctx.urlFor()` and `ctx.urlWith()` to throw an exception for missing routes.

## v1.10.0 (2022-11-07)
Expand Down
29 changes: 18 additions & 11 deletions src/context.ts
Expand Up @@ -4,7 +4,14 @@ import type {Plan} from './router/plan.js';
import type {ServerRequest} from './server/request.js';
import type {ServerResponse} from './server/response.js';
import type {SessionData} from './types.js';
import type {MojoAction, MojoContext, MojoModels, RenderOptions, URLOptions, ValidatorFunction} from './types.js';
import type {
MojoAction,
MojoContext,
MojoModels,
MojoRenderOptions,
MojoURLOptions,
ValidatorFunction
} from './types.js';
import type {UserAgent} from './user-agent.js';
import type {WebSocket} from './websocket.js';
import type Path from '@mojojs/path';
Expand Down Expand Up @@ -234,7 +241,7 @@ class Context extends EventEmitter {
/**
* Send `302` redirect response.
*/
async redirectTo(target: string, options: URLOptions & {status?: number} = {}): Promise<void> {
async redirectTo(target: string, options: MojoURLOptions & {status?: number} = {}): Promise<void> {
await this.res
.status(options.status ?? 302)
.set('Location', this.urlFor(target, {absolute: true, ...options}) ?? '')
Expand All @@ -253,7 +260,7 @@ class Context extends EventEmitter {
* // Render view "users/list.*.*" and pass it a stash value
* await ctx.render({view: 'users/list'}, {foo: 'bar'});
*/
async render(options: RenderOptions = {}, stash?: Record<string, any>): Promise<boolean> {
async render(options: MojoRenderOptions = {}, stash?: Record<string, any>): Promise<boolean> {
if (stash !== undefined) Object.assign(this.stash, stash);

const app = this.app;
Expand All @@ -269,7 +276,7 @@ class Context extends EventEmitter {
/**
* Try to render dynamic content to string.
*/
async renderToString(options: RenderOptions, stash?: Record<string, any>): Promise<string | null> {
async renderToString(options: MojoRenderOptions, stash?: Record<string, any>): Promise<string | null> {
if (typeof options === 'string') options = {view: options};
Object.assign(this.stash, stash);
const result = await this.app.renderer.render(this as unknown as MojoContext, options);
Expand All @@ -279,10 +286,10 @@ class Context extends EventEmitter {
/**
* Automatically select best possible representation for resource.
*/
async respondTo(spec: Record<string, MojoAction | RenderOptions>): Promise<void> {
async respondTo(spec: Record<string, MojoAction | MojoRenderOptions>): Promise<void> {
const formats = this.accepts() ?? [];

let handler: MojoAction | RenderOptions | undefined;
let handler: MojoAction | MojoRenderOptions | undefined;
for (const format of formats) {
if (spec[format] === undefined) continue;
handler = spec[format];
Expand Down Expand Up @@ -342,7 +349,7 @@ class Context extends EventEmitter {
* // Absolute URL for path
* const url = ctx.urlFor('/some/path', {absolute: true});
*/
urlFor(target?: string, options: URLOptions = {}): string {
urlFor(target?: string, options: MojoURLOptions = {}): string {
if (target === undefined || target === 'current') {
if (this.plan === null) throw new Error('No current route to generate URL for');
const result = this.plan.render(options.values);
Expand All @@ -360,14 +367,14 @@ class Context extends EventEmitter {
/**
* Generate URL for static asset.
*/
urlForAsset(path: string, options: URLOptions = {}): string {
urlForAsset(path: string, options: MojoURLOptions = {}): string {
return ABSOLUTE.test(path) === true ? path : this._urlForPath(this.app.static.assetPath(path), false, options);
}

/**
* Generate URL for static file.
*/
urlForFile(path: string, options: URLOptions = {}): string {
urlForFile(path: string, options: MojoURLOptions = {}): string {
return ABSOLUTE.test(path) === true ? path : this._urlForPath(this.app.static.filePath(path), false, options);
}

Expand All @@ -377,7 +384,7 @@ class Context extends EventEmitter {
* // Remove a specific query parameter
* const url = ctx.urlWith('current', {query: {foo: null}});
*/
urlWith(target?: string, options: URLOptions = {}): string {
urlWith(target?: string, options: MojoURLOptions = {}): string {
options.query = Object.fromEntries(
Object.entries({...this.req.query.toObject(), ...(options.query ?? {})}).filter(([, v]) => v !== null)
);
Expand All @@ -392,7 +399,7 @@ class Context extends EventEmitter {
return this._ws?.deref() ?? null;
}

_urlForPath(path: string, isWebSocket: boolean, options: URLOptions): string {
_urlForPath(path: string, isWebSocket: boolean, options: MojoURLOptions): string {
path = this.req.basePath + path;

let query = '';
Expand Down
11 changes: 10 additions & 1 deletion src/core.ts
Expand Up @@ -48,4 +48,13 @@ export {TestUserAgent} from './user-agent/test.js';
export {UserAgent} from './user-agent.js';
export * as util from './util.js';

export {JSONValue, MojoAction, MojoApp, MojoContext, MojoModels, MojoRoute} from './types.js';
export {
JSONValue,
MojoAction,
MojoApp,
MojoContext,
MojoModels,
MojoRenderOptions,
MojoRoute,
MojoURLOptions
} from './types.js';
6 changes: 3 additions & 3 deletions src/plugins/default-helpers.ts
@@ -1,4 +1,4 @@
import type {MojoApp, MojoContext, RenderOptions, TagAttrs, URLOptions, URLTarget} from '../types.js';
import type {MojoApp, MojoContext, MojoRenderOptions, MojoURLOptions, TagAttrs, URLTarget} from '../types.js';
import type {InspectOptions} from 'node:util';
import {inspect} from 'node:util';
import {Logger} from '../logger.js';
Expand Down Expand Up @@ -189,7 +189,7 @@ async function inputTag(ctx: MojoContext, name: string, attrs: TagAttrs = {}): P

async function include(
ctx: MojoContext,
options: RenderOptions,
options: MojoRenderOptions,
stash: Record<string, any>
): Promise<SafeString | null> {
const str = await ctx.renderToString(options, stash);
Expand Down Expand Up @@ -281,7 +281,7 @@ async function websocketException(ctx: MojoContext, error: any): Promise<boolean
return true;
}

function urlTarget(target: URLTarget): [string, URLOptions] {
function urlTarget(target: URLTarget): [string, MojoURLOptions] {
return typeof target === 'string' ? [target, {}] : target;
}

Expand Down
4 changes: 2 additions & 2 deletions src/plugins/tmpl-engine.ts
@@ -1,5 +1,5 @@
import type {App} from '../app.js';
import type {MojoContext, RenderOptions} from '../types.js';
import type {MojoContext, MojoRenderOptions} from '../types.js';
import {createHash} from 'node:crypto';
import {Cache} from '../cache.js';
import Path from '@mojojs/path';
Expand All @@ -15,7 +15,7 @@ export default function tmplEnginePlugin(app: App): void {
class TmplEngine {
cache: Cache<(data?: Record<string, any>) => Promise<string>> = new Cache();

async render(ctx: MojoContext, options: RenderOptions): Promise<Buffer> {
async render(ctx: MojoContext, options: MojoRenderOptions): Promise<Buffer> {
let template;

if (options.inline !== undefined) {
Expand Down
12 changes: 6 additions & 6 deletions src/renderer.ts
@@ -1,4 +1,4 @@
import type {MojoContext, RenderOptions} from './types.js';
import type {MojoContext, MojoRenderOptions} from './types.js';
import {promisify} from 'node:util';
import {gzip} from 'node:zlib';
import Path from '@mojojs/path';
Expand All @@ -16,7 +16,7 @@ interface ViewSuggestion {
}
type ViewIndex = Record<string, ViewSuggestion[]>;
interface ViewEngine {
render: (ctx: MojoContext, options: RenderOptions) => Promise<Buffer>;
render: (ctx: MojoContext, options: MojoRenderOptions) => Promise<Buffer>;
}

const gzipPromise = promisify(gzip);
Expand Down Expand Up @@ -65,7 +65,7 @@ export class Renderer {
/**
* Find a view for render parameters.
*/
findView(options: RenderOptions): ViewSuggestion | null {
findView(options: MojoRenderOptions): ViewSuggestion | null {
const view = options.view;
const index = this._viewIndex;
if (view === undefined || index === undefined || index[view] === undefined) return null;
Expand All @@ -87,7 +87,7 @@ export class Renderer {
/**
* Render output through one of the template engines.
*/
async render(ctx: MojoContext, options: RenderOptions): Promise<EngineResult | null> {
async render(ctx: MojoContext, options: MojoRenderOptions): Promise<EngineResult | null> {
const log = ctx.log;
if (options.text !== undefined) {
log.trace('Rendering text response');
Expand Down Expand Up @@ -198,13 +198,13 @@ export class Renderer {
}
}

async _renderInline(ctx: MojoContext, options: RenderOptions): Promise<EngineResult | null> {
async _renderInline(ctx: MojoContext, options: MojoRenderOptions): Promise<EngineResult | null> {
const engine = this.engines[options.engine ?? this.defaultEngine];
if (engine === undefined) return null;
return {output: await engine.render(ctx, options), format: options.format ?? this.defaultFormat};
}

async _renderView(ctx: MojoContext, options: RenderOptions): Promise<EngineResult | null> {
async _renderView(ctx: MojoContext, options: MojoRenderOptions): Promise<EngineResult | null> {
const view = this.findView(options);
if (view === null) return null;

Expand Down
10 changes: 5 additions & 5 deletions src/types.ts
Expand Up @@ -39,7 +39,7 @@ export interface MojoContext extends Context {
htmlNotFound: () => Promise<boolean>;
httpException: (error: any) => Promise<boolean>;
imageTag: (target: string, attrs?: TagAttrs) => SafeString;
include: (options: RenderOptions, stash: Record<string, any>) => Promise<SafeString | null>;
include: (options: MojoRenderOptions, stash: Record<string, any>) => Promise<SafeString | null>;
inspect: (object: Record<string, any>, options: InspectOptions) => string;
inputTag: (name: string, attrs?: TagAttrs) => Promise<SafeString>;
jsonException: (error: Error) => Promise<boolean>;
Expand Down Expand Up @@ -112,7 +112,9 @@ export interface CookieOptions {
secure?: boolean;
}

export interface RenderOptions {
export type MojoURLOptions = {absolute?: boolean; query?: Record<string, string>; values?: Record<string, string>};

export interface MojoRenderOptions {
engine?: string;
format?: string;
inline?: string;
Expand Down Expand Up @@ -184,9 +186,7 @@ export interface UserAgentWebSocketOptions extends SharedUserAgentRequestOptions
protocols?: string[];
}

export type URLOptions = {absolute?: boolean; query?: Record<string, string>; values?: Record<string, string>};

export type URLTarget = string | [string, URLOptions];
export type URLTarget = string | [string, MojoURLOptions];

export type TestUserAgentOptions = UserAgentOptions & {tap?: Tap.Test};

Expand Down

0 comments on commit 2769e6e

Please sign in to comment.