@tsed/engines 8.0.0 → 8.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -3
- package/src/components/AtplEngine.ts +5 -0
- package/src/components/BracketEngine.ts +11 -0
- package/src/components/DotEngine.ts +14 -0
- package/src/components/DustEngine.ts +55 -0
- package/src/components/EctEngine.ts +24 -0
- package/src/components/EjsEngine.ts +5 -0
- package/src/components/Engine.ts +87 -0
- package/src/components/HamlCoffeeEngine.ts +5 -0
- package/src/components/HamlEngine.ts +12 -0
- package/src/components/HamletEngine.ts +12 -0
- package/src/components/HandlebarsEngine.ts +19 -0
- package/src/components/HoganEngine.spec.ts +79 -0
- package/src/components/HoganEngine.ts +14 -0
- package/src/components/HtmlingEngine.ts +11 -0
- package/src/components/JazzEngine.ts +10 -0
- package/src/components/JqtplEngine.ts +10 -0
- package/src/components/JustEngine.ts +24 -0
- package/src/components/LiquorEngine.ts +5 -0
- package/src/components/LodashEngine.ts +14 -0
- package/src/components/MoteEngine.ts +5 -0
- package/src/components/MustacheEngine.ts +9 -0
- package/src/components/NunjucksEngine.ts +58 -0
- package/src/components/PlatesEngine.ts +12 -0
- package/src/components/PugEngine.spec.ts +50 -0
- package/src/components/PugEngine.ts +15 -0
- package/src/components/RactiveEngine.spec.ts +36 -0
- package/src/components/RactiveEngine.ts +34 -0
- package/src/components/ReactEngine.ts +163 -0
- package/src/components/SlmEngine.ts +5 -0
- package/src/components/SquirrellyEngine.spec.ts +98 -0
- package/src/components/SquirrellyEngine.ts +18 -0
- package/src/components/SwigEngine.ts +14 -0
- package/src/components/TemplayedEngine.ts +9 -0
- package/src/components/TwigEngine.spec.ts +44 -0
- package/src/components/TwigEngine.ts +24 -0
- package/src/components/TwingEngine.spec.ts +36 -0
- package/src/components/TwingEngine.ts +31 -0
- package/src/components/UnderscoreEngine.ts +26 -0
- package/src/components/VashEngine.ts +33 -0
- package/src/components/VelocityEngine.spec.ts +50 -0
- package/src/components/VelocityEngine.ts +11 -0
- package/src/components/WalrusEngine.ts +11 -0
- package/src/decorators/viewEngine.ts +8 -0
- package/src/index.ts +42 -0
- package/src/registries/EnginesContainer.ts +37 -0
- package/src/utils/cache.spec.ts +13 -0
- package/src/utils/cache.ts +154 -0
- package/src/utils/getEngines.spec.ts +133 -0
- package/src/utils/getEngines.ts +58 -0
package/package.json
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
"name": "@tsed/engines",
|
|
3
3
|
"description": "Template engines library. Provide an API to adding custom engines from decorators.",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "8.0.
|
|
5
|
+
"version": "8.0.2",
|
|
6
6
|
"source": "./src/index.ts",
|
|
7
7
|
"main": "./lib/esm/index.js",
|
|
8
8
|
"module": "./lib/esm/index.js",
|
|
9
9
|
"typings": "./lib/types/index.d.ts",
|
|
10
10
|
"exports": {
|
|
11
11
|
".": {
|
|
12
|
+
"@tsed/source": "./src/index.ts",
|
|
12
13
|
"types": "./lib/types/index.d.ts",
|
|
13
14
|
"import": "./lib/esm/index.js",
|
|
14
15
|
"default": "./lib/esm/index.js"
|
|
@@ -29,8 +30,8 @@
|
|
|
29
30
|
"@babel/plugin-transform-runtime": "7.25.7",
|
|
30
31
|
"@babel/preset-env": "7.25.7",
|
|
31
32
|
"@babel/preset-react": "7.25.7",
|
|
32
|
-
"@tsed/barrels": "8.0.
|
|
33
|
-
"@tsed/typescript": "8.0.
|
|
33
|
+
"@tsed/barrels": "8.0.2",
|
|
34
|
+
"@tsed/typescript": "8.0.2",
|
|
34
35
|
"@types/semver": "^7.5.8",
|
|
35
36
|
"atpl": "0.9.3",
|
|
36
37
|
"bracket-template": "^1.1.5",
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
2
|
+
import {Engine} from "./Engine.js";
|
|
3
|
+
|
|
4
|
+
@ViewEngine("bracket", {
|
|
5
|
+
requires: "bracket-template"
|
|
6
|
+
})
|
|
7
|
+
export class BracketEngine extends Engine {
|
|
8
|
+
protected $compile(template: string, options: any) {
|
|
9
|
+
return this.engine.compile(template, options);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
2
|
+
import {Engine} from "./Engine.js";
|
|
3
|
+
|
|
4
|
+
@ViewEngine("dot")
|
|
5
|
+
export class DotEngine extends Engine {
|
|
6
|
+
getSettings(options: any) {
|
|
7
|
+
const settings = Object.assign({}, this.engine.templateSettings);
|
|
8
|
+
return Object.assign(settings, options ? options.dot : {});
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
protected $compile(template: string, options: any) {
|
|
12
|
+
return this.engine.template(template, this.getSettings(options), options);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import {extname} from "path";
|
|
2
|
+
import {promisify} from "util";
|
|
3
|
+
|
|
4
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
5
|
+
import {read} from "../utils/cache.js";
|
|
6
|
+
import {Engine} from "./Engine.js";
|
|
7
|
+
|
|
8
|
+
@ViewEngine("dust", {
|
|
9
|
+
requires: ["dustjs-helpers", "dustjs-linkedin"]
|
|
10
|
+
})
|
|
11
|
+
export class DustEngine extends Engine {
|
|
12
|
+
private views = ".";
|
|
13
|
+
private ext = "dust";
|
|
14
|
+
|
|
15
|
+
configure(options: any) {
|
|
16
|
+
if (options) {
|
|
17
|
+
if (options.ext) {
|
|
18
|
+
this.ext = options.ext;
|
|
19
|
+
}
|
|
20
|
+
if (options.views) {
|
|
21
|
+
this.views = options.views;
|
|
22
|
+
}
|
|
23
|
+
if (options.settings && options.settings.views) {
|
|
24
|
+
this.views = options.settings.views;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (!options || (options && !options.cache)) this.engine.cache = {};
|
|
28
|
+
|
|
29
|
+
this.engine.onLoad = async (path: string, callback: any) => {
|
|
30
|
+
if (extname(path) === "") {
|
|
31
|
+
path += `.${this.ext}`;
|
|
32
|
+
}
|
|
33
|
+
if (path[0] !== "/") {
|
|
34
|
+
path = `${this.views}/${path}`;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
callback(null, await read(path, options));
|
|
38
|
+
} catch (er) {
|
|
39
|
+
callback(er);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
protected $compile(template: string, options: any) {
|
|
45
|
+
this.configure(options);
|
|
46
|
+
|
|
47
|
+
let templateName;
|
|
48
|
+
|
|
49
|
+
if (options.filename) {
|
|
50
|
+
templateName = options.filename.replace(new RegExp("^" + this.views + "/"), "").replace(new RegExp("\\." + this.ext), "");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return promisify(this.engine.compileFn(template, templateName)) as any;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {promisify} from "util";
|
|
2
|
+
|
|
3
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
4
|
+
import {Engine} from "./Engine.js";
|
|
5
|
+
|
|
6
|
+
@ViewEngine("ect")
|
|
7
|
+
export class EctEngine extends Engine {
|
|
8
|
+
protected $compile(template: string, options: any) {
|
|
9
|
+
const ECT = this.engine;
|
|
10
|
+
const engine = new ECT({root: {page: template}});
|
|
11
|
+
const compile = promisify(engine.render.bind(engine));
|
|
12
|
+
|
|
13
|
+
return (options: any) => compile("page", options);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
protected $compileFile(file: string, options: any): Promise<(options: any) => any> {
|
|
17
|
+
const ECT = this.engine;
|
|
18
|
+
const engine = new ECT(options);
|
|
19
|
+
engine.configure({cache: options.cache});
|
|
20
|
+
const compile = promisify(engine.render.bind(engine));
|
|
21
|
+
|
|
22
|
+
return Promise.resolve((options: any) => compile(file, options));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import {cache, getCachedEngine, importEngine, read, readPartials} from "../utils/cache.js";
|
|
2
|
+
|
|
3
|
+
export interface ViewEngineOptions {
|
|
4
|
+
requires?: string | string[];
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface EngineOptions {
|
|
8
|
+
cache?: boolean;
|
|
9
|
+
|
|
10
|
+
[otherOptions: string]: any;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class Engine {
|
|
14
|
+
protected driverName: string;
|
|
15
|
+
|
|
16
|
+
constructor(
|
|
17
|
+
readonly name: string,
|
|
18
|
+
readonly options: ViewEngineOptions
|
|
19
|
+
) {}
|
|
20
|
+
|
|
21
|
+
get engine(): any {
|
|
22
|
+
return getCachedEngine(this.name);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async $onInit() {
|
|
26
|
+
await this.importEngine(this.name, this.options);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
compile(template: string, options: EngineOptions) {
|
|
30
|
+
options = this.$cacheOptions(template, options, false);
|
|
31
|
+
|
|
32
|
+
return cache(options) || cache(options, this.$compile.call(this, template, options));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
compileFile(file: string, options: EngineOptions) {
|
|
36
|
+
options = this.$cacheOptions(file, options, true);
|
|
37
|
+
|
|
38
|
+
return cache(options) || cache(options, this.$compileFile.call(this, file, options));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async render(template: string, options: EngineOptions) {
|
|
42
|
+
const compile = await this.compile(template, options);
|
|
43
|
+
|
|
44
|
+
return compile(options);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async renderFile(file: string, options: EngineOptions) {
|
|
48
|
+
const opts = await this.readPartials(file, options);
|
|
49
|
+
const compile = await this.compileFile(file, opts);
|
|
50
|
+
|
|
51
|
+
return compile(opts);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
protected async readPartials(file: string, options: EngineOptions) {
|
|
55
|
+
options.filename = file;
|
|
56
|
+
const partials = await readPartials(file, options);
|
|
57
|
+
|
|
58
|
+
const opts = Object.assign({}, options);
|
|
59
|
+
opts.partials = partials;
|
|
60
|
+
|
|
61
|
+
return opts;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
protected $cacheOptions(template: string, options: EngineOptions, fromFile?: boolean) {
|
|
65
|
+
return options;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
protected $compile(template: string, options: EngineOptions): (options: EngineOptions) => Promise<string> {
|
|
69
|
+
return this.engine.compile(template, options);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
protected async $compileFile(file: string, options: EngineOptions) {
|
|
73
|
+
const template = await read(file, options);
|
|
74
|
+
return this.$compile(template, options);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
protected async importEngine(name: string, options: ViewEngineOptions) {
|
|
78
|
+
const reqs = ([] as string[]).concat(options.requires || [name]);
|
|
79
|
+
|
|
80
|
+
for (const req of reqs) {
|
|
81
|
+
try {
|
|
82
|
+
await importEngine(req, name);
|
|
83
|
+
this.driverName = req;
|
|
84
|
+
} catch (er) {}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
2
|
+
import {Engine} from "./Engine.js";
|
|
3
|
+
|
|
4
|
+
@ViewEngine("haml")
|
|
5
|
+
export class HamlEngine extends Engine {
|
|
6
|
+
protected $compile(template: string, options: any) {
|
|
7
|
+
return (options: any) => {
|
|
8
|
+
options.locals = options;
|
|
9
|
+
return Promise.resolve(this.engine.render(template, options).trimLeft());
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
2
|
+
import {Engine} from "./Engine.js";
|
|
3
|
+
|
|
4
|
+
@ViewEngine("hamlet")
|
|
5
|
+
export class HamletEngine extends Engine {
|
|
6
|
+
protected $compile(template: string, options: any) {
|
|
7
|
+
return (options: any) => {
|
|
8
|
+
options.locals = options;
|
|
9
|
+
return Promise.resolve(this.engine.render(template, options).trimLeft());
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
2
|
+
import {Engine} from "./Engine.js";
|
|
3
|
+
|
|
4
|
+
@ViewEngine("handlebars")
|
|
5
|
+
export class HandlebarsEngine extends Engine {
|
|
6
|
+
protected configure(options: any) {
|
|
7
|
+
for (const partial in options.partials) {
|
|
8
|
+
this.engine.registerPartial(partial, options.partials[partial]);
|
|
9
|
+
}
|
|
10
|
+
for (const helper in options.helpers) {
|
|
11
|
+
this.engine.registerHelper(helper, options.helpers[helper]);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
protected $compile(template: string, options: any) {
|
|
16
|
+
this.configure(options);
|
|
17
|
+
return this.engine.compile(template, options);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import {join} from "path";
|
|
2
|
+
|
|
3
|
+
import {getEngineFixture} from "../../test/getEngineFixture.js";
|
|
4
|
+
import {HoganEngine} from "./HoganEngine.js";
|
|
5
|
+
|
|
6
|
+
describe("HoganEngine", () => {
|
|
7
|
+
it("should render the given content (by string - no cache)", async () => {
|
|
8
|
+
const {render, locals, $compile, template} = await getEngineFixture({token: HoganEngine});
|
|
9
|
+
await render();
|
|
10
|
+
|
|
11
|
+
expect(await render()).toEqual("<p>Tobi</p>");
|
|
12
|
+
expect($compile()).toHaveBeenCalledTimes(2);
|
|
13
|
+
expect($compile()).toHaveBeenCalledWith(template, {...locals, cache: false});
|
|
14
|
+
});
|
|
15
|
+
it("should render the given content (by string - with cache)", async () => {
|
|
16
|
+
const {render, locals, $compile, template} = await getEngineFixture({token: HoganEngine, cache: true});
|
|
17
|
+
await render();
|
|
18
|
+
|
|
19
|
+
expect(await render()).toEqual("<p>Tobi</p>");
|
|
20
|
+
expect($compile()).toHaveBeenCalledTimes(2);
|
|
21
|
+
expect($compile()).toHaveBeenCalledWith(template, {...locals, cache: true});
|
|
22
|
+
});
|
|
23
|
+
it("should render the given content (by file - no cache)", async () => {
|
|
24
|
+
const {renderFile, locals, $compile, path, template} = await getEngineFixture({token: HoganEngine});
|
|
25
|
+
await renderFile();
|
|
26
|
+
const content = await renderFile();
|
|
27
|
+
|
|
28
|
+
expect(content).toEqual("<p>Tobi</p>");
|
|
29
|
+
expect($compile()).toHaveBeenCalledTimes(2);
|
|
30
|
+
expect($compile()).toHaveBeenCalledWith(template, {
|
|
31
|
+
...locals,
|
|
32
|
+
partials: undefined,
|
|
33
|
+
filename: path,
|
|
34
|
+
cache: false
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
it("should render the given content (by file - with cache)", async () => {
|
|
38
|
+
const {renderFile, locals, $compile, path, template} = await getEngineFixture({token: HoganEngine, cache: true});
|
|
39
|
+
|
|
40
|
+
await renderFile();
|
|
41
|
+
const content = await renderFile();
|
|
42
|
+
|
|
43
|
+
expect(content).toEqual("<p>Tobi</p>");
|
|
44
|
+
expect($compile()).toHaveBeenCalledTimes(1);
|
|
45
|
+
expect($compile()).toHaveBeenCalledWith(template, {
|
|
46
|
+
...locals,
|
|
47
|
+
partials: undefined,
|
|
48
|
+
filename: path,
|
|
49
|
+
cache: true
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// partials
|
|
54
|
+
it("should support partials", async () => {
|
|
55
|
+
const {renderFile} = await getEngineFixture({token: HoganEngine, templateName: "partials"});
|
|
56
|
+
const locals = {
|
|
57
|
+
partials: {
|
|
58
|
+
partial: "user"
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const html = await renderFile(locals);
|
|
62
|
+
|
|
63
|
+
expect(html).toEqual("<p>Tobi</p>");
|
|
64
|
+
});
|
|
65
|
+
it("should support absolute path partial", async () => {
|
|
66
|
+
const {renderFile, rootDir, name} = await getEngineFixture({token: HoganEngine, templateName: "partials"});
|
|
67
|
+
const locals = {partials: {partial: join(rootDir, "fixtures", name, "user")}};
|
|
68
|
+
const html = await renderFile(locals);
|
|
69
|
+
|
|
70
|
+
expect(html).toEqual("<p>Tobi</p>");
|
|
71
|
+
});
|
|
72
|
+
it("should support relative path partial", async () => {
|
|
73
|
+
const {renderFile, name} = await getEngineFixture({token: HoganEngine, templateName: "partials"});
|
|
74
|
+
|
|
75
|
+
const locals = {partials: {partial: `../${name}/user`}};
|
|
76
|
+
const html = await renderFile(locals);
|
|
77
|
+
expect(html).toEqual("<p>Tobi</p>");
|
|
78
|
+
});
|
|
79
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
2
|
+
import {Engine, EngineOptions} from "./Engine.js";
|
|
3
|
+
|
|
4
|
+
@ViewEngine("hogan", {
|
|
5
|
+
requires: "hogan.js"
|
|
6
|
+
})
|
|
7
|
+
export class HoganEngine extends Engine {
|
|
8
|
+
protected $compile(template: string, options: EngineOptions) {
|
|
9
|
+
const compile = this.engine.compile(template, options);
|
|
10
|
+
return (options: EngineOptions) => {
|
|
11
|
+
return compile.render(options, options.partials);
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
2
|
+
import {Engine} from "./Engine.js";
|
|
3
|
+
|
|
4
|
+
@ViewEngine("htmling")
|
|
5
|
+
export class HtmlingEngine extends Engine {
|
|
6
|
+
protected $compile(template: string) {
|
|
7
|
+
const compile = this.engine.string(template);
|
|
8
|
+
|
|
9
|
+
return (options: any) => compile.render(options);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
2
|
+
import {Engine} from "./Engine.js";
|
|
3
|
+
|
|
4
|
+
@ViewEngine("jazz")
|
|
5
|
+
export class JazzEngine extends Engine {
|
|
6
|
+
protected $compile(template: string, options: any) {
|
|
7
|
+
const compile = this.engine.compile(template, options);
|
|
8
|
+
return (options: any) => new Promise<string>((resolve) => compile.eval(options, resolve));
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
2
|
+
import {Engine} from "./Engine.js";
|
|
3
|
+
|
|
4
|
+
@ViewEngine("jqtpl")
|
|
5
|
+
export class JqtplEngine extends Engine {
|
|
6
|
+
protected $compile(template: string, options: any) {
|
|
7
|
+
this.engine.template(template, template);
|
|
8
|
+
return (options: any) => this.engine.tmpl(template, options);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {promisify} from "util";
|
|
2
|
+
|
|
3
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
4
|
+
import {Engine} from "./Engine.js";
|
|
5
|
+
|
|
6
|
+
@ViewEngine("just")
|
|
7
|
+
export class JustEngine extends Engine {
|
|
8
|
+
protected $compile(template: string, options: any) {
|
|
9
|
+
const JUST = this.engine;
|
|
10
|
+
const engine = new JUST({root: {page: template}});
|
|
11
|
+
const compile = promisify(engine.render.bind(engine));
|
|
12
|
+
|
|
13
|
+
return (options: any) => compile("page", options);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
protected $compileFile(file: string, options: any) {
|
|
17
|
+
const JUST = this.engine;
|
|
18
|
+
const engine = new JUST(options);
|
|
19
|
+
engine.configure({useCache: options.cache});
|
|
20
|
+
const compile = promisify(engine.render.bind(engine));
|
|
21
|
+
|
|
22
|
+
return Promise.resolve((options: any) => compile(file, options));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
2
|
+
import {Engine} from "./Engine.js";
|
|
3
|
+
|
|
4
|
+
@ViewEngine("lodash")
|
|
5
|
+
export class LodashEngine extends Engine {
|
|
6
|
+
render(template: string, options: any) {
|
|
7
|
+
const compile = this.compile(template, options);
|
|
8
|
+
return compile(options).replace(/\n$/, "");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
protected $compile(template: string, options: any) {
|
|
12
|
+
return this.engine.template(template, options);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
2
|
+
import {Engine} from "./Engine.js";
|
|
3
|
+
|
|
4
|
+
@ViewEngine("mustache")
|
|
5
|
+
export class MustacheEngine extends Engine {
|
|
6
|
+
protected $compile(template: string, options: any) {
|
|
7
|
+
return (options: any) => this.engine.render(template, options, options.partials);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import {promisify} from "util";
|
|
2
|
+
|
|
3
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
4
|
+
import {Engine} from "./Engine.js";
|
|
5
|
+
|
|
6
|
+
@ViewEngine("nunjucks")
|
|
7
|
+
export class NunjucksEngine extends Engine {
|
|
8
|
+
protected configure(options: any) {
|
|
9
|
+
const engine = options.nunjucksEnv || this.engine;
|
|
10
|
+
let env = engine;
|
|
11
|
+
|
|
12
|
+
// deprecated fallback support for express
|
|
13
|
+
// <https://github.com/tj/consolidate.js/pull/152>
|
|
14
|
+
// <https://github.com/tj/consolidate.js/pull/224>
|
|
15
|
+
if (options.settings && options.settings.views) {
|
|
16
|
+
env = engine.configure(options.settings.views);
|
|
17
|
+
} else if (options.nunjucks && options.nunjucks.configure) {
|
|
18
|
+
env = engine.configure.apply(engine, options.nunjucks.configure);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
//
|
|
22
|
+
// because `renderString` does not initiate loaders
|
|
23
|
+
// we must manually create a loader for it based off
|
|
24
|
+
// either `options.settings.views` or `options.nunjucks` or `options.nunjucks.root`
|
|
25
|
+
//
|
|
26
|
+
// <https://github.com/mozilla/nunjucks/issues/730>
|
|
27
|
+
// <https://github.com/crocodilejs/node-email-templates/issues/182>
|
|
28
|
+
//
|
|
29
|
+
|
|
30
|
+
// so instead we simply check if we passed a custom loader
|
|
31
|
+
// otherwise we create a simple file based loader
|
|
32
|
+
if (options.loader) {
|
|
33
|
+
return new engine.Environment(options.loader);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (options.settings && options.settings.views) {
|
|
37
|
+
return new engine.Environment(new engine.FileSystemLoader(options.settings.views));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (options.nunjucks && options.nunjucks.loader) {
|
|
41
|
+
if (typeof options.nunjucks.loader === "string") {
|
|
42
|
+
return new engine.Environment(new engine.FileSystemLoader(options.nunjucks.loader));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return new engine.Environment(new engine.FileSystemLoader(options.nunjucks.loader[0], options.nunjucks.loader[1]));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return env;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
protected $compile(template: string, options: any) {
|
|
52
|
+
let engine = this.configure(options);
|
|
53
|
+
|
|
54
|
+
const render = promisify(engine.renderString.bind(engine));
|
|
55
|
+
|
|
56
|
+
return (options: any) => render(template, options);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
2
|
+
import {Engine} from "./Engine.js";
|
|
3
|
+
|
|
4
|
+
@ViewEngine("plates")
|
|
5
|
+
export class PlatesEngine extends Engine {
|
|
6
|
+
protected $compile(template: string, options: any) {
|
|
7
|
+
return (options: any) => {
|
|
8
|
+
const map = options.map || undefined;
|
|
9
|
+
return this.engine.bind(template, options, map);
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {getEngineFixture} from "../../test/getEngineFixture.js";
|
|
2
|
+
import {PugEngine} from "./PugEngine.js";
|
|
3
|
+
|
|
4
|
+
describe("PugEngine", () => {
|
|
5
|
+
it("should render the given content (by string - no cache)", async () => {
|
|
6
|
+
const {render, locals, $compile, template} = await getEngineFixture({token: PugEngine});
|
|
7
|
+
await render();
|
|
8
|
+
|
|
9
|
+
expect(await render()).toEqual("<p>Tobi</p>");
|
|
10
|
+
expect($compile()).toHaveBeenCalledTimes(2);
|
|
11
|
+
expect($compile()).toHaveBeenCalledWith(template, {...locals, cache: false});
|
|
12
|
+
});
|
|
13
|
+
it("should render the given content (by string - with cache)", async () => {
|
|
14
|
+
const {render, locals, $compile, template} = await getEngineFixture({token: PugEngine, cache: true});
|
|
15
|
+
await render();
|
|
16
|
+
|
|
17
|
+
expect(await render()).toEqual("<p>Tobi</p>");
|
|
18
|
+
expect($compile()).toHaveBeenCalledTimes(2);
|
|
19
|
+
expect($compile()).toHaveBeenCalledWith(template, {...locals, cache: true});
|
|
20
|
+
});
|
|
21
|
+
it("should render the given content (by file - no cache)", async () => {
|
|
22
|
+
const {renderFile, locals, $compileFile, path} = await getEngineFixture({token: PugEngine});
|
|
23
|
+
await renderFile();
|
|
24
|
+
const content = await renderFile();
|
|
25
|
+
|
|
26
|
+
expect(content).toEqual("<p>Tobi</p>");
|
|
27
|
+
expect($compileFile()).toHaveBeenCalledTimes(2);
|
|
28
|
+
expect($compileFile()).toHaveBeenCalledWith(path, {
|
|
29
|
+
...locals,
|
|
30
|
+
partials: undefined,
|
|
31
|
+
filename: path,
|
|
32
|
+
cache: false
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
it("should render the given content (by file - with cache)", async () => {
|
|
36
|
+
const {renderFile, locals, $compileFile, path} = await getEngineFixture({token: PugEngine, cache: true});
|
|
37
|
+
|
|
38
|
+
await renderFile();
|
|
39
|
+
const content = await renderFile();
|
|
40
|
+
|
|
41
|
+
expect(content).toEqual("<p>Tobi</p>");
|
|
42
|
+
expect($compileFile()).toHaveBeenCalledTimes(1);
|
|
43
|
+
expect($compileFile()).toHaveBeenCalledWith(path, {
|
|
44
|
+
...locals,
|
|
45
|
+
partials: undefined,
|
|
46
|
+
filename: path,
|
|
47
|
+
cache: true
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
2
|
+
import {Engine} from "./Engine.js";
|
|
3
|
+
|
|
4
|
+
@ViewEngine("pug", {
|
|
5
|
+
requires: ["pug", "then-pug"]
|
|
6
|
+
})
|
|
7
|
+
export class PugEngine extends Engine {
|
|
8
|
+
protected $compile(template: string, options: any) {
|
|
9
|
+
return this.engine.compile(template, options);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
protected $compileFile(file: string, options: any) {
|
|
13
|
+
return this.engine.compileFile(file, options);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {getEngineFixture} from "../../test/getEngineFixture.js";
|
|
2
|
+
import {RactiveEngine} from "./RactiveEngine.js";
|
|
3
|
+
|
|
4
|
+
describe("RactiveEngine", () => {
|
|
5
|
+
it("should render the given content (by string - no cache)", async () => {
|
|
6
|
+
const {render, locals, $compile, template} = await getEngineFixture({token: RactiveEngine});
|
|
7
|
+
await render();
|
|
8
|
+
|
|
9
|
+
expect(await render()).toEqual("<p>Tobi</p>");
|
|
10
|
+
expect($compile()).toHaveBeenCalledTimes(2);
|
|
11
|
+
});
|
|
12
|
+
it("should render the given content (by string - with cache)", async () => {
|
|
13
|
+
const {render, $compile, template} = await getEngineFixture({token: RactiveEngine, cache: true});
|
|
14
|
+
await render();
|
|
15
|
+
|
|
16
|
+
expect(await render()).toEqual("<p>Tobi</p>");
|
|
17
|
+
expect($compile()).toHaveBeenCalledTimes(2);
|
|
18
|
+
});
|
|
19
|
+
it("should render the given content (by file - no cache)", async () => {
|
|
20
|
+
const {renderFile, $compileFile} = await getEngineFixture({token: RactiveEngine});
|
|
21
|
+
await renderFile();
|
|
22
|
+
const content = await renderFile();
|
|
23
|
+
|
|
24
|
+
expect(content).toEqual("<p>Tobi</p>");
|
|
25
|
+
expect($compileFile()).toHaveBeenCalledTimes(2);
|
|
26
|
+
});
|
|
27
|
+
it("should render the given content (by file - with cache)", async () => {
|
|
28
|
+
const {renderFile, $compileFile} = await getEngineFixture({token: RactiveEngine, cache: true});
|
|
29
|
+
|
|
30
|
+
await renderFile();
|
|
31
|
+
const content = await renderFile();
|
|
32
|
+
|
|
33
|
+
expect(content).toEqual("<p>Tobi</p>");
|
|
34
|
+
expect($compileFile()).toHaveBeenCalledTimes(1);
|
|
35
|
+
});
|
|
36
|
+
});
|