Skip to content

Commit ecd17a1

Browse files
authoredJul 23, 2024
Merge pull request #71 from expressots/fix/render-engine-config
Fix/render engine config
2 parents b1a8aa9 + 522d6e2 commit ecd17a1

File tree

9 files changed

+103
-28
lines changed

9 files changed

+103
-28
lines changed
 

‎src/adapter-express/application-express.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { InversifyExpressServer } from "./express-utils/inversify-express-server
1616
import { EjsOptions, setEngineEjs } from "./render/ejs/ejs.config";
1717
import { Engine, EngineOptions, RenderOptions } from "./render/engine";
1818
import { HandlebarsOptions, setEngineHandlebars } from "./render/handlebars/hbs.config";
19-
import { packageResolver } from "./render/resolve-render";
19+
import { PugOptions, setEnginePug } from "./render/pug/pug.config";
2020

2121
/**
2222
* The AppExpress class provides methods for configuring and running an Express application.
@@ -188,6 +188,9 @@ class AppExpress extends ApplicationBase implements IWebServer {
188188
case Engine.EJS:
189189
await setEngineEjs(this.app, this.renderOptions.options as EjsOptions);
190190
break;
191+
case Engine.PUG:
192+
await setEnginePug(this.app, this.renderOptions.options as PugOptions);
193+
break;
191194
default:
192195
throw new Error("Unsupported engine type!");
193196
}
@@ -205,8 +208,6 @@ class AppExpress extends ApplicationBase implements IWebServer {
205208
* @param {EngineOptions} [options] - The configuration options for the view engine
206209
*/
207210
public async setEngine<T extends EngineOptions>(engine: Engine, options?: T): Promise<void> {
208-
packageResolver(engine, options);
209-
210211
try {
211212
if (options) {
212213
this.renderOptions = { engine, options };

‎src/adapter-express/express-utils/constants.ts

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ export const HTTP_CODE_METADATA = {
1717
path: "inversify-express-utils:path",
1818
};
1919

20+
export const RENDER_METADATA_KEY = Symbol("Render");
21+
2022
export enum PARAMETER_TYPE {
2123
REQUEST,
2224
RESPONSE,

‎src/adapter-express/express-utils/decorators.ts

+24
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
PARAMETER_TYPE,
88
HTTP_VERBS_ENUM,
99
HTTP_CODE_METADATA,
10+
RENDER_METADATA_KEY,
1011
} from "./constants";
1112
import type {
1213
Controller,
@@ -383,6 +384,29 @@ export function params(type: PARAMETER_TYPE, parameterName?: string): ParameterD
383384
};
384385
}
385386

387+
/**
388+
* Render decorator to define the template and default data for a route
389+
* @param template The template to render
390+
* @param defaultData The default data to pass to the template
391+
* @returns
392+
*/
393+
export function Render(template: string, defaultData?: Record<string, unknown>): MethodDecorator {
394+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
395+
return (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void => {
396+
Reflect.defineMetadata(RENDER_METADATA_KEY, { template, defaultData }, target, propertyKey);
397+
};
398+
}
399+
400+
export function getRenderMetadata(
401+
target: object,
402+
propertyKey: string | symbol,
403+
): {
404+
template?: string;
405+
defaultData?: Record<string, unknown>;
406+
} {
407+
return Reflect.getMetadata(RENDER_METADATA_KEY, target, propertyKey) || {};
408+
}
409+
386410
/**
387411
* Converts a string value to the specified type.
388412
* @param value The value to convert.

‎src/adapter-express/express-utils/inversify-express-server.ts

+14-8
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import type {
4040
RoutingConfig,
4141
} from "./interfaces";
4242
import type { OutgoingHttpHeaders } from "node:http";
43+
import { getRenderMetadata } from "./decorators";
4344

4445
export class InversifyExpressServer {
4546
private _router: Router;
@@ -245,21 +246,26 @@ export class InversifyExpressServer {
245246
controllerName: string,
246247
key: string,
247248
parameterMetadata: Array<ParameterMetadata>,
248-
): express.RequestHandler {
249+
): RequestHandler {
249250
return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
250251
try {
251252
const args = this.extractParameters(req, res, next, parameterMetadata);
252253
const httpContext = this._getHttpContext(req);
253254
httpContext.container.bind<HttpContext>(TYPE.HttpContext).toConstantValue(httpContext);
254255

255256
// invoke controller's action
256-
const value = await (
257-
httpContext.container.getNamed<BaseController>(TYPE.Controller, controllerName)[
258-
key
259-
] as ControllerHandler
260-
)(...args);
261-
262-
if (value instanceof HttpResponseMessage) {
257+
const controller = httpContext.container.getNamed<BaseController>(
258+
TYPE.Controller,
259+
controllerName,
260+
);
261+
const value = await (controller[key] as ControllerHandler)(...args);
262+
263+
const { template, defaultData } = getRenderMetadata(controller, key);
264+
265+
if (template) {
266+
const data = value || defaultData || {};
267+
res.render(template, data as Record<string, unknown>);
268+
} else if (value instanceof HttpResponseMessage) {
263269
await this.handleHttpResponseMessage(value, res);
264270
} else if (instanceOfIHttpActionResult(value)) {
265271
const httpResponseMessage = await value.executeAsync();

‎src/adapter-express/render/ejs/ejs.config.ts

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Application } from "express";
22
import { join } from "path";
33
import { Options } from "./ejs.types";
4+
import { packageResolver } from "../resolve-render";
45

56
/**
67
* Ejs options
@@ -37,6 +38,8 @@ export async function setEngineEjs(
3738
app: Application,
3839
options: EjsOptions = EJS_DEFAULTS,
3940
): Promise<void> {
41+
packageResolver("ejs");
42+
4043
app.set("view engine", options.viewEngine || EJS_DEFAULTS.viewEngine);
4144
app.set("views", options.viewsDir || EJS_DEFAULTS.viewsDir);
4245

‎src/adapter-express/render/engine.ts

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export type RenderOptions = {
2020
export enum Engine {
2121
HBS = "hbs",
2222
EJS = "ejs",
23+
PUG = "pug",
2324
}
2425

2526
/**

‎src/adapter-express/render/handlebars/hbs.config.ts

+14-17
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import express from "express";
22
import { join } from "path";
33
import { Logger } from "@expressots/core";
4+
import { packageResolver } from "../resolve-render";
45

56
/**
67
* Handlebars options
@@ -11,9 +12,9 @@ import { Logger } from "@expressots/core";
1112
*
1213
*/
1314
export type HandlebarsOptions = {
14-
viewsDir?: string | Array<string>;
1515
viewEngine?: string;
16-
serverOptions?: unknown;
16+
viewsDir?: string;
17+
partialsDir?: string;
1718
};
1819

1920
/**
@@ -23,11 +24,16 @@ export type HandlebarsOptions = {
2324
* @default
2425
*/
2526
const HANDLEBARS_DEFAULTS: HandlebarsOptions = {
26-
viewsDir: join(process.cwd(), "views"),
2727
viewEngine: "hbs",
28-
serverOptions: {},
28+
viewsDir: join(process.cwd(), "views"),
29+
partialsDir: join(process.cwd(), "views/partials"),
2930
};
3031

32+
/**
33+
* Default partials directory
34+
*/
35+
const DEFAULT_PARTIALS_DIR: string = join(process.cwd(), "views/partials");
36+
3137
/**
3238
* Set Handlebars as the view engine
3339
* @param {express.Application} app - The express application
@@ -40,21 +46,12 @@ export async function setEngineHandlebars(
4046
const logger = new Logger();
4147

4248
try {
43-
app.set("view engine", options.viewEngine || (HANDLEBARS_DEFAULTS.viewEngine as string));
44-
app.set("views", options.viewsDir || (HANDLEBARS_DEFAULTS.viewsDir as string));
49+
const hbs = packageResolver("hbs");
4550

46-
if (Array.isArray(options.viewsDir)) {
47-
options.viewsDir.forEach((dir) => {
48-
app.set("views", dir);
49-
});
50-
}
51+
hbs.registerPartials(options.partialsDir || DEFAULT_PARTIALS_DIR);
5152

52-
if (options.serverOptions) {
53-
app.locals = {
54-
...app.locals,
55-
...(options.serverOptions as Record<string, unknown>),
56-
};
57-
}
53+
app.set("view engine", options.viewEngine || (HANDLEBARS_DEFAULTS.viewEngine as string));
54+
app.set("views", options.viewsDir || (HANDLEBARS_DEFAULTS.viewsDir as string));
5855
} catch (error: unknown) {
5956
logger.error((error as Error).message, "handlebars-config");
6057
}

‎src/adapter-express/render/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export { EjsOptions as EJS } from "./ejs/ejs.config";
22
export { HandlebarsOptions as HBS } from "./handlebars/hbs.config";
3+
export { PugOptions as PUG } from "./pug/pug.config";
34
export { Engine } from "./engine";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { join } from "path";
2+
import { packageResolver } from "../resolve-render";
3+
import { Application } from "express";
4+
5+
/**
6+
* Pug options
7+
* @typedef {Object} PugOptions
8+
* @property {string} viewEngine - The view engine to be used
9+
* @property {string} viewsDir - The path to the views folder
10+
*/
11+
export type PugOptions = {
12+
viewEngine?: string;
13+
viewsDir?: string;
14+
};
15+
16+
/**
17+
* Pug defaults
18+
* @type {PugOptions}
19+
* @constant
20+
* @default
21+
*/
22+
const PUG_DEFAULTS: PugOptions = {
23+
viewEngine: "pug",
24+
viewsDir: join(process.cwd(), "views"),
25+
};
26+
27+
/**
28+
* Set Pug as the view engine
29+
* @param {express.Application} app - The express application
30+
* @param {PugOptions} [options=PUG_DEFAULTS] - The pug options
31+
*/
32+
export async function setEnginePug(
33+
app: Application,
34+
options: PugOptions = PUG_DEFAULTS,
35+
): Promise<void> {
36+
packageResolver("pug");
37+
38+
app.set("view engine", options.viewEngine || (PUG_DEFAULTS.viewEngine as string));
39+
app.set("views", options.viewsDir || (PUG_DEFAULTS.viewsDir as string));
40+
}

0 commit comments

Comments
 (0)