/
templateEngine.ts
100 lines (83 loc) · 2.87 KB
/
templateEngine.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import {Pod} from './pod';
export interface TemplateEngineComponent {
pod: Pod;
/**
* Renders the template string using the template engine and the given context.
*/
render: (template: string, context: any) => Promise<string>;
/**
* Renders the template from a string using the template engine and the given context.
*/
renderFromString: (template: string, k) => Promise<string>;
}
export interface TemplateEngineConstructor {
new (pod: Pod): TemplateEngineComponent;
}
export interface TemplateEngineRenderResult {
// Path of the rendered template.
path?: string;
// Contents of the rendered template.
content: string;
// Context passed for rendering.
context: any;
}
export class TemplateEngineManager {
pod: Pod;
private engines: Record<string, TemplateEngineComponent>;
private extToClass: Record<string, TemplateEngineConstructor>;
constructor(pod: Pod) {
this.pod = pod;
this.engines = {};
this.extToClass = {};
}
associate(extension: string, TemplateEngineClass: TemplateEngineConstructor) {
if (!extension || !extension.startsWith('.')) {
throw new InvalidExtensionError(
'Template engine extensions needs to start with a period (.).'
);
}
this.extToClass[extension] = TemplateEngineClass;
}
getEngineByExtension(extension: string): TemplateEngineComponent {
if (!(extension in this.extToClass)) {
throw new MissingTemplateEngineError(
`Unable to find template engine for the ${extension} extension.`
);
}
// Only need to create one template engine instance per extension.
// Allows each extension's template engine to be configured separately
// by using the plugin hook.
if (!this.engines[extension]) {
this.engines[extension] = new this.extToClass[extension](this.pod);
// Trigger the plugin hook for new template engines.
this.pod.plugins.triggerSync(
'createTemplateEngine',
this.engines[extension],
extension
);
}
return this.engines[extension];
}
getEngineByFilename(fileName: string): TemplateEngineComponent {
// Go through the extensions starting with the longest extension.
// This allows for sub extensions to take priority. (Ex: .foo.bar > .bar).
const knownExtensions = Object.keys(this.extToClass).sort(
(a, b) => b.length - a.length
);
fileName = fileName.trim();
let knownExtension: string | undefined = undefined;
for (const ext of knownExtensions) {
if (fileName.endsWith(ext)) {
knownExtension = ext;
}
}
if (!knownExtension) {
throw new MissingTemplateEngineError(
`Unable to find template engine for the ${fileName} file name.`
);
}
return this.getEngineByExtension(knownExtension);
}
}
export class InvalidExtensionError extends Error {}
export class MissingTemplateEngineError extends Error {}