@tsed/engines 8.0.1 → 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
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
2
|
+
import {Engine, EngineOptions} from "./Engine.js";
|
|
3
|
+
|
|
4
|
+
@ViewEngine("ractive")
|
|
5
|
+
export class RactiveEngine extends Engine {
|
|
6
|
+
protected $compile(template: string, options: EngineOptions) {
|
|
7
|
+
const Engine = this.engine;
|
|
8
|
+
const compile = this.engine.parse(template);
|
|
9
|
+
Engine.DEBUG = false;
|
|
10
|
+
return (options: EngineOptions) => {
|
|
11
|
+
options.template = compile;
|
|
12
|
+
return new Engine(this.clean(options)).toHTML();
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
protected clean(options: any) {
|
|
17
|
+
if (options.data === null || options.data === undefined) {
|
|
18
|
+
// Shallow clone the options object
|
|
19
|
+
options.data = Object.assign({}, options);
|
|
20
|
+
|
|
21
|
+
// Remove consolidate-specific properties from the clone
|
|
22
|
+
let i;
|
|
23
|
+
let length;
|
|
24
|
+
let properties = ["template", "filename", "cache", "partials"];
|
|
25
|
+
|
|
26
|
+
for (i = 0, length = properties.length; i < length; i++) {
|
|
27
|
+
const property = properties[i];
|
|
28
|
+
delete options.data[property];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return options;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import {readFileSync} from "fs";
|
|
2
|
+
import {resolve} from "path";
|
|
3
|
+
|
|
4
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
5
|
+
import {getCachedEngine, getFromCache, importEngine, setToCache} from "../utils/cache.js";
|
|
6
|
+
import {Engine, EngineOptions, ViewEngineOptions} from "./Engine.js";
|
|
7
|
+
|
|
8
|
+
@ViewEngine("react", {
|
|
9
|
+
requires: ["react"]
|
|
10
|
+
})
|
|
11
|
+
export class ReactEngine extends Engine {
|
|
12
|
+
constructor(name: string, options: ViewEngineOptions) {
|
|
13
|
+
super(name, options);
|
|
14
|
+
this.patchRequire();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async $onInit() {
|
|
18
|
+
await super.$onInit();
|
|
19
|
+
await importEngine("react-dom/server", "ReactDOM");
|
|
20
|
+
await importEngine("@babel/core", "babel");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
get babel() {
|
|
24
|
+
return getCachedEngine("babel");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get reactDOM() {
|
|
28
|
+
return getCachedEngine("ReactDOM");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
protected patchRequire() {
|
|
32
|
+
if (require.extensions) {
|
|
33
|
+
// Ensure JSX is transformed on require
|
|
34
|
+
if (!require.extensions[".jsx"]) {
|
|
35
|
+
require.extensions[".jsx"] = this.requireReact.bind(this);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Supporting .react extension as well as test cases
|
|
39
|
+
// Using .react extension is not recommended.
|
|
40
|
+
if (!require.extensions[".react"]) {
|
|
41
|
+
require.extensions[".react"] = this.requireReact.bind(this);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
protected configure(options: EngineOptions) {
|
|
47
|
+
const base = options.base;
|
|
48
|
+
delete options.base;
|
|
49
|
+
|
|
50
|
+
const enableCache = options.cache;
|
|
51
|
+
delete options.cache;
|
|
52
|
+
|
|
53
|
+
const isNonStatic = options.isNonStatic;
|
|
54
|
+
delete options.isNonStatic;
|
|
55
|
+
return {base, enableCache, isNonStatic};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
protected $compile(template: string, options: EngineOptions) {
|
|
59
|
+
// Assign HTML Base
|
|
60
|
+
const {base, enableCache, isNonStatic} = this.configure(options);
|
|
61
|
+
|
|
62
|
+
// Start Conversion
|
|
63
|
+
const Code = this.requireReactString(template);
|
|
64
|
+
const Factory = this.engine.createFactory(Code);
|
|
65
|
+
|
|
66
|
+
return () => {
|
|
67
|
+
const parsed = new Factory(options);
|
|
68
|
+
const content = isNonStatic ? this.reactDOM.renderToString(parsed) : this.reactDOM.renderToStaticMarkup(parsed);
|
|
69
|
+
|
|
70
|
+
if (base) {
|
|
71
|
+
options.content = content;
|
|
72
|
+
|
|
73
|
+
return this.renderWithBase(template, base, enableCache, options);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return content;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
protected async $compileFile(file: string, options: EngineOptions) {
|
|
81
|
+
// Assign HTML Base
|
|
82
|
+
const {base, enableCache, isNonStatic} = this.configure(options);
|
|
83
|
+
|
|
84
|
+
let path = resolve(file);
|
|
85
|
+
delete require.cache[path];
|
|
86
|
+
|
|
87
|
+
const ReactDOM = await importEngine("react-dom/server", "ReactDOM");
|
|
88
|
+
|
|
89
|
+
const {default: Code} = await import(path);
|
|
90
|
+
const Factory = this.engine.createFactory(Code);
|
|
91
|
+
|
|
92
|
+
return () => {
|
|
93
|
+
const parsed = new Factory(options);
|
|
94
|
+
const content = isNonStatic ? ReactDOM.renderToString(parsed) : ReactDOM.renderToStaticMarkup(parsed);
|
|
95
|
+
|
|
96
|
+
if (base) {
|
|
97
|
+
options.content = content;
|
|
98
|
+
|
|
99
|
+
return this.renderWithBase(file, base, enableCache, options);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return content;
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
protected renderWithBase(key: string, base: any, enableCache: undefined | boolean, options: EngineOptions) {
|
|
107
|
+
const baseStr = getFromCache(key) || readFileSync(resolve(base), "utf8");
|
|
108
|
+
|
|
109
|
+
if (enableCache) {
|
|
110
|
+
setToCache(key, baseStr);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return this.reactBaseTmpl(baseStr, options);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
protected transformFileSync(filename: string) {
|
|
117
|
+
return this.babel.transformFileSync(filename, {presets: ["@babel/preset-react"]}).code;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
protected transform(src: string) {
|
|
121
|
+
return this.babel.transform(src, {presets: ["@babel/preset-react"]}).code;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
protected requireReact(module: any, filename: string) {
|
|
125
|
+
const compiled = this.transformFileSync(filename);
|
|
126
|
+
return module._compile(compiled, filename);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
protected requireReactString(src: string, filename?: string) {
|
|
130
|
+
if (!filename) filename = "";
|
|
131
|
+
// @ts-ignore
|
|
132
|
+
const m = new module.constructor();
|
|
133
|
+
filename = filename || "";
|
|
134
|
+
|
|
135
|
+
// Compile Using React
|
|
136
|
+
const compiled = this.transform(src);
|
|
137
|
+
|
|
138
|
+
// Compile as a module
|
|
139
|
+
m.paths = module.paths;
|
|
140
|
+
m._compile(compiled, filename);
|
|
141
|
+
|
|
142
|
+
return m.exports;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
protected reactBaseTmpl(data: any, options: any) {
|
|
146
|
+
let exp: any;
|
|
147
|
+
let regex: any;
|
|
148
|
+
|
|
149
|
+
// Iterates through the keys in file object
|
|
150
|
+
// and interpolate / replace {{key}} with it's value
|
|
151
|
+
for (const k in options) {
|
|
152
|
+
if (options.hasOwnProperty(k)) {
|
|
153
|
+
exp = `{{${k}}}`;
|
|
154
|
+
regex = new RegExp(exp, "g");
|
|
155
|
+
if (data.match(regex)) {
|
|
156
|
+
data = data.replace(regex, options[k]);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return data;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {join} from "path";
|
|
2
|
+
|
|
3
|
+
import {getEngineFixture} from "../../test/getEngineFixture.js";
|
|
4
|
+
import {requires} from "../utils/cache.js";
|
|
5
|
+
import {SquirrellyEngine} from "./SquirrellyEngine.js";
|
|
6
|
+
|
|
7
|
+
describe("SquirrellyEngine", () => {
|
|
8
|
+
it("should render the given content (by string - no cache)", async () => {
|
|
9
|
+
const {render, locals, $compile, template} = await getEngineFixture({token: SquirrellyEngine});
|
|
10
|
+
await render();
|
|
11
|
+
|
|
12
|
+
expect(await render()).toEqual("<p>Tobi</p>");
|
|
13
|
+
expect($compile()).toHaveBeenCalledTimes(2);
|
|
14
|
+
expect($compile()).toHaveBeenCalledWith(template, {...locals, cache: false});
|
|
15
|
+
});
|
|
16
|
+
it("should render the given content (by string - with cache)", async () => {
|
|
17
|
+
const {render, locals, $compile, template} = await getEngineFixture({token: SquirrellyEngine, cache: true});
|
|
18
|
+
await render();
|
|
19
|
+
|
|
20
|
+
expect(await render()).toEqual("<p>Tobi</p>");
|
|
21
|
+
expect($compile()).toHaveBeenCalledTimes(2);
|
|
22
|
+
expect($compile()).toHaveBeenCalledWith(template, {...locals, cache: true});
|
|
23
|
+
});
|
|
24
|
+
it("should render the given content (by file - no cache)", async () => {
|
|
25
|
+
const {renderFile, locals, $compile, path, template} = await getEngineFixture({token: SquirrellyEngine});
|
|
26
|
+
await renderFile();
|
|
27
|
+
const content = await renderFile();
|
|
28
|
+
|
|
29
|
+
expect(content).toEqual("<p>Tobi</p>");
|
|
30
|
+
expect($compile()).toHaveBeenCalledTimes(2);
|
|
31
|
+
expect($compile()).toHaveBeenCalledWith(template, {
|
|
32
|
+
...locals,
|
|
33
|
+
partials: undefined,
|
|
34
|
+
filename: path,
|
|
35
|
+
cache: false
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
it("should render the given content (by file - with cache)", async () => {
|
|
39
|
+
const {renderFile, locals, $compile, path, template} = await getEngineFixture({
|
|
40
|
+
token: SquirrellyEngine,
|
|
41
|
+
cache: true
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
await renderFile();
|
|
45
|
+
const content = await renderFile();
|
|
46
|
+
|
|
47
|
+
expect(content).toEqual("<p>Tobi</p>");
|
|
48
|
+
expect($compile()).toHaveBeenCalledTimes(1);
|
|
49
|
+
expect($compile()).toHaveBeenCalledWith(template, {
|
|
50
|
+
...locals,
|
|
51
|
+
partials: undefined,
|
|
52
|
+
filename: path,
|
|
53
|
+
cache: true
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Use case: return safe HTML that won’t be escaped in the final render.
|
|
58
|
+
it("should support helpers", async () => {
|
|
59
|
+
const Sqrl = requires.get("squirrelly");
|
|
60
|
+
const user = {name: "<strong>Tobi</strong>"};
|
|
61
|
+
|
|
62
|
+
Sqrl.defineHelper("myhelper", (args: string[], content: any, blocks: any) => {
|
|
63
|
+
return args[0].slice(1, -1);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const {render} = await getEngineFixture({token: SquirrellyEngine, templateName: "helpers"});
|
|
67
|
+
|
|
68
|
+
const html = await render({user: user});
|
|
69
|
+
expect(html).toEqual("strong>Tobi</strong");
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// partials
|
|
73
|
+
it("should support partials", async () => {
|
|
74
|
+
const {renderFile} = await getEngineFixture({token: SquirrellyEngine, templateName: "partials"});
|
|
75
|
+
const locals = {
|
|
76
|
+
partials: {
|
|
77
|
+
partial: "user"
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const html = await renderFile(locals);
|
|
81
|
+
|
|
82
|
+
expect(html).toEqual("<p>Tobi</p>");
|
|
83
|
+
});
|
|
84
|
+
it("should support absolute path partial", async () => {
|
|
85
|
+
const {renderFile, rootDir, name} = await getEngineFixture({token: SquirrellyEngine, templateName: "partials"});
|
|
86
|
+
const locals = {partials: {partial: join(rootDir, "fixtures", name, "user")}};
|
|
87
|
+
const html = await renderFile(locals);
|
|
88
|
+
|
|
89
|
+
expect(html).toEqual("<p>Tobi</p>");
|
|
90
|
+
});
|
|
91
|
+
it("should support relative path partial", async () => {
|
|
92
|
+
const {renderFile, name} = await getEngineFixture({token: SquirrellyEngine, templateName: "partials"});
|
|
93
|
+
|
|
94
|
+
const locals = {partials: {partial: `../${name}/user`}};
|
|
95
|
+
const html = await renderFile(locals);
|
|
96
|
+
expect(html).toEqual("<p>Tobi</p>");
|
|
97
|
+
});
|
|
98
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
2
|
+
import {Engine, EngineOptions} from "./Engine.js";
|
|
3
|
+
|
|
4
|
+
@ViewEngine("squirrelly")
|
|
5
|
+
export class SquirrellyEngine extends Engine {
|
|
6
|
+
protected $compile(template: string, options: EngineOptions) {
|
|
7
|
+
for (const partial in options.partials) {
|
|
8
|
+
this.engine.definePartial(partial, options.partials[partial]);
|
|
9
|
+
}
|
|
10
|
+
for (const helper in options.helpers) {
|
|
11
|
+
this.engine.defineHelper(helper, options.helpers[helper]);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const compile = this.engine.Compile(template, options);
|
|
15
|
+
|
|
16
|
+
return (options: EngineOptions) => compile(options, this.engine);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
2
|
+
import {Engine} from "./Engine.js";
|
|
3
|
+
|
|
4
|
+
@ViewEngine("swig", {
|
|
5
|
+
requires: ["swig", "swig-templates"]
|
|
6
|
+
})
|
|
7
|
+
export class SwigEngine extends Engine {
|
|
8
|
+
protected $compile(template: string, options: any): (options: any) => Promise<string> {
|
|
9
|
+
if (options.cache === true) options.cache = "memory";
|
|
10
|
+
this.engine.setDefaults({cache: options.cache});
|
|
11
|
+
|
|
12
|
+
return this.engine.compile(template, options);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
2
|
+
import {Engine} from "./Engine.js";
|
|
3
|
+
|
|
4
|
+
@ViewEngine("templayed")
|
|
5
|
+
export class TemplayedEngine extends Engine {
|
|
6
|
+
protected $compile(template: string, options: any) {
|
|
7
|
+
return this.engine(template);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {getEngineFixture} from "../../test/getEngineFixture.js";
|
|
2
|
+
import {TwigEngine} from "./TwigEngine.js";
|
|
3
|
+
|
|
4
|
+
describe("TwigEngine", () => {
|
|
5
|
+
it("should render the given content (by string - no cache)", async () => {
|
|
6
|
+
const {render, $compile, template} = await getEngineFixture({token: TwigEngine});
|
|
7
|
+
await render();
|
|
8
|
+
|
|
9
|
+
expect(await render()).toEqual("<p>Tobi</p>");
|
|
10
|
+
expect($compile()).toHaveBeenCalledTimes(2);
|
|
11
|
+
expect($compile()).toHaveBeenCalledWith(template, {
|
|
12
|
+
allowInlineIncludes: undefined,
|
|
13
|
+
cache: false,
|
|
14
|
+
data: "<p>{{ user.name }}</p>",
|
|
15
|
+
namespaces: undefined,
|
|
16
|
+
path: undefined,
|
|
17
|
+
user: {name: "Tobi"}
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
it("should render the given content (by string - with cache)", async () => {
|
|
21
|
+
const {render, $compile} = await getEngineFixture({token: TwigEngine, cache: true});
|
|
22
|
+
await render();
|
|
23
|
+
|
|
24
|
+
expect(await render()).toEqual("<p>Tobi</p>");
|
|
25
|
+
expect($compile()).toHaveBeenCalledTimes(2);
|
|
26
|
+
});
|
|
27
|
+
it("should render the given content (by file - no cache)", async () => {
|
|
28
|
+
const {renderFile, $compileFile, path} = await getEngineFixture({token: TwigEngine});
|
|
29
|
+
await renderFile();
|
|
30
|
+
const content = await renderFile();
|
|
31
|
+
|
|
32
|
+
expect(content).toEqual("<p>Tobi</p>");
|
|
33
|
+
expect($compileFile()).toHaveBeenCalledTimes(2);
|
|
34
|
+
});
|
|
35
|
+
it("should render the given content (by file - with cache)", async () => {
|
|
36
|
+
const {renderFile, $compileFile} = await getEngineFixture({token: TwigEngine, 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
|
+
});
|
|
44
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
2
|
+
import {Engine, EngineOptions} from "./Engine.js";
|
|
3
|
+
|
|
4
|
+
@ViewEngine("twig")
|
|
5
|
+
export class TwigEngine extends Engine {
|
|
6
|
+
protected $cacheOptions(template: string, options: any) {
|
|
7
|
+
return {
|
|
8
|
+
...options,
|
|
9
|
+
data: template,
|
|
10
|
+
allowInlineIncludes: options.allowInlineIncludes,
|
|
11
|
+
namespaces: options.namespaces,
|
|
12
|
+
path: options.path
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
protected $compile(template: string, options: EngineOptions) {
|
|
17
|
+
const {twig: engine} = this.engine;
|
|
18
|
+
options.data = template;
|
|
19
|
+
|
|
20
|
+
const compile = engine(options);
|
|
21
|
+
|
|
22
|
+
return (options: EngineOptions) => compile.render(options);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {getEngineFixture} from "../../test/getEngineFixture.js";
|
|
2
|
+
import {TwingEngine} from "./TwingEngine.js";
|
|
3
|
+
|
|
4
|
+
describe("TwingEngine", () => {
|
|
5
|
+
it("should render the given content (by string - no cache)", async () => {
|
|
6
|
+
const {render, $compile} = await getEngineFixture({token: TwingEngine});
|
|
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} = await getEngineFixture({token: TwingEngine, 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: TwingEngine});
|
|
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, path} = await getEngineFixture({token: TwingEngine, 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
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {existsSync} from "fs";
|
|
2
|
+
|
|
3
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
4
|
+
import {Engine} from "./Engine.js";
|
|
5
|
+
|
|
6
|
+
@ViewEngine("twing")
|
|
7
|
+
export class TwingEngine extends Engine {
|
|
8
|
+
private instance: any;
|
|
9
|
+
|
|
10
|
+
protected $compile(template: string, options: any): (options: any) => Promise<string> {
|
|
11
|
+
const engine = this.engine;
|
|
12
|
+
|
|
13
|
+
if (!this.instance) {
|
|
14
|
+
let loader = new engine.TwingLoaderNull();
|
|
15
|
+
|
|
16
|
+
if (options.settings && options.settings.views && existsSync(options.settings.views)) {
|
|
17
|
+
loader = new engine.TwingLoaderFilesystem(options.settings.views);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
this.instance = new engine.TwingEnvironment(loader);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const $cmp = this.instance.createTemplate(template);
|
|
24
|
+
|
|
25
|
+
return async (options: any) => {
|
|
26
|
+
const compile = await $cmp;
|
|
27
|
+
|
|
28
|
+
return compile.render(options);
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
2
|
+
import {Engine} from "./Engine.js";
|
|
3
|
+
|
|
4
|
+
@ViewEngine("underscore")
|
|
5
|
+
export class UnderscoreEngine extends Engine {
|
|
6
|
+
async render(template: string, options: any) {
|
|
7
|
+
const tpl: string = await this.compile(template, options)(options);
|
|
8
|
+
return tpl.replace(/\n$/, "");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
protected $cacheOptions(template: string, options: any): any {
|
|
12
|
+
const partials: any = {};
|
|
13
|
+
|
|
14
|
+
for (const partial in options.partials) {
|
|
15
|
+
partials[partial] = this.engine.template(options.partials[partial]);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
options.partials = partials;
|
|
19
|
+
|
|
20
|
+
return options;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
protected $compile(template: string, options: any): (options: any) => Promise<string> {
|
|
24
|
+
return this.engine.template(template, null, options);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {promisify} from "util";
|
|
2
|
+
|
|
3
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
4
|
+
import {Engine} from "./Engine.js";
|
|
5
|
+
|
|
6
|
+
@ViewEngine("vash")
|
|
7
|
+
export class VashEngine extends Engine {
|
|
8
|
+
compile(template: string, options: any): (options: any) => Promise<string> {
|
|
9
|
+
if (options.helpers) {
|
|
10
|
+
for (const key in options.helpers) {
|
|
11
|
+
if (!options.helpers.hasOwnProperty(key) || typeof options.helpers[key] !== "function") {
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
this.engine.helpers[key] = options.helpers[key];
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const compile = promisify(this.engine.compile(template, options));
|
|
19
|
+
|
|
20
|
+
return async (options: any) => {
|
|
21
|
+
const ctx = await compile(options);
|
|
22
|
+
ctx.finishLayout();
|
|
23
|
+
return ctx.toString();
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async render(template: string, options: any) {
|
|
28
|
+
const compile = this.compile(template, options);
|
|
29
|
+
|
|
30
|
+
const tpl = await compile(options);
|
|
31
|
+
return tpl.replace(/\n$/, "");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {getEngineFixture} from "../../test/getEngineFixture.js";
|
|
2
|
+
import {VelocityEngine} from "./VelocityEngine.js";
|
|
3
|
+
|
|
4
|
+
describe("VelocityEngine", () => {
|
|
5
|
+
it("should render the given content (by string - no cache)", async () => {
|
|
6
|
+
const {render, locals, $compile} = await getEngineFixture({token: "velocityjs"});
|
|
7
|
+
await render();
|
|
8
|
+
|
|
9
|
+
expect(await render()).toEqual("<p>Tobi</p>\n");
|
|
10
|
+
expect($compile()).toHaveBeenCalledTimes(2);
|
|
11
|
+
expect($compile()).toHaveBeenCalledWith("<p>$user.name</p>\n", {...locals, cache: false});
|
|
12
|
+
});
|
|
13
|
+
it("should render the given content (by string - with cache)", async () => {
|
|
14
|
+
const {render, locals, $compile} = await getEngineFixture({token: VelocityEngine, cache: true});
|
|
15
|
+
await render();
|
|
16
|
+
|
|
17
|
+
expect(await render()).toEqual("<p>Tobi</p>\n");
|
|
18
|
+
expect($compile()).toHaveBeenCalledTimes(2);
|
|
19
|
+
expect($compile()).toHaveBeenCalledWith("<p>$user.name</p>\n", {...locals, cache: true});
|
|
20
|
+
});
|
|
21
|
+
it("should render the given content (by file - no cache)", async () => {
|
|
22
|
+
const {renderFile, locals, $compile, path, template} = await getEngineFixture({token: VelocityEngine});
|
|
23
|
+
await renderFile();
|
|
24
|
+
const content = await renderFile();
|
|
25
|
+
|
|
26
|
+
expect(content).toEqual("<p>Tobi</p>\n");
|
|
27
|
+
expect($compile()).toHaveBeenCalledTimes(2);
|
|
28
|
+
expect($compile()).toHaveBeenCalledWith(template, {
|
|
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, $compile, path, template} = await getEngineFixture({token: VelocityEngine, cache: true});
|
|
37
|
+
|
|
38
|
+
await renderFile();
|
|
39
|
+
const content = await renderFile();
|
|
40
|
+
|
|
41
|
+
expect(content).toEqual("<p>Tobi</p>\n");
|
|
42
|
+
expect($compile()).toHaveBeenCalledTimes(1);
|
|
43
|
+
expect($compile()).toHaveBeenCalledWith(template, {
|
|
44
|
+
...locals,
|
|
45
|
+
partials: undefined,
|
|
46
|
+
filename: path,
|
|
47
|
+
cache: true
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
2
|
+
import {Engine, EngineOptions} from "./Engine.js";
|
|
3
|
+
|
|
4
|
+
@ViewEngine("velocityjs")
|
|
5
|
+
export class VelocityEngine extends Engine {
|
|
6
|
+
protected $compile(template: string, options: EngineOptions) {
|
|
7
|
+
return (options: EngineOptions) => {
|
|
8
|
+
return Promise.resolve(this.engine.render(template, options).trimLeft());
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {ViewEngine} from "../decorators/viewEngine.js";
|
|
2
|
+
import {Engine} from "./Engine.js";
|
|
3
|
+
|
|
4
|
+
@ViewEngine("walrus")
|
|
5
|
+
export class WalrusEngine extends Engine {
|
|
6
|
+
protected $compile(template: string, options: any) {
|
|
7
|
+
const compile = this.engine.parse(template);
|
|
8
|
+
|
|
9
|
+
return (options: any) => compile.compile(options);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import {ViewEngineOptions} from "../components/Engine.js";
|
|
2
|
+
import {engines} from "../registries/EnginesContainer.js";
|
|
3
|
+
|
|
4
|
+
export function ViewEngine(name: string, options: ViewEngineOptions = {}): ClassDecorator {
|
|
5
|
+
return (target: any) => {
|
|
6
|
+
engines.set(target, {name, useClass: target, options});
|
|
7
|
+
};
|
|
8
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Automatically generated by @tsed/barrels.
|
|
3
|
+
*/
|
|
4
|
+
export * from "./components/AtplEngine.js";
|
|
5
|
+
export * from "./components/BracketEngine.js";
|
|
6
|
+
export * from "./components/DotEngine.js";
|
|
7
|
+
export * from "./components/DustEngine.js";
|
|
8
|
+
export * from "./components/EctEngine.js";
|
|
9
|
+
export * from "./components/EjsEngine.js";
|
|
10
|
+
export * from "./components/Engine.js";
|
|
11
|
+
export * from "./components/HamlCoffeeEngine.js";
|
|
12
|
+
export * from "./components/HamlEngine.js";
|
|
13
|
+
export * from "./components/HamletEngine.js";
|
|
14
|
+
export * from "./components/HandlebarsEngine.js";
|
|
15
|
+
export * from "./components/HoganEngine.js";
|
|
16
|
+
export * from "./components/HtmlingEngine.js";
|
|
17
|
+
export * from "./components/JazzEngine.js";
|
|
18
|
+
export * from "./components/JqtplEngine.js";
|
|
19
|
+
export * from "./components/JustEngine.js";
|
|
20
|
+
export * from "./components/LiquorEngine.js";
|
|
21
|
+
export * from "./components/LodashEngine.js";
|
|
22
|
+
export * from "./components/MoteEngine.js";
|
|
23
|
+
export * from "./components/MustacheEngine.js";
|
|
24
|
+
export * from "./components/NunjucksEngine.js";
|
|
25
|
+
export * from "./components/PlatesEngine.js";
|
|
26
|
+
export * from "./components/PugEngine.js";
|
|
27
|
+
export * from "./components/RactiveEngine.js";
|
|
28
|
+
export * from "./components/ReactEngine.js";
|
|
29
|
+
export * from "./components/SlmEngine.js";
|
|
30
|
+
export * from "./components/SquirrellyEngine.js";
|
|
31
|
+
export * from "./components/SwigEngine.js";
|
|
32
|
+
export * from "./components/TemplayedEngine.js";
|
|
33
|
+
export * from "./components/TwigEngine.js";
|
|
34
|
+
export * from "./components/TwingEngine.js";
|
|
35
|
+
export * from "./components/UnderscoreEngine.js";
|
|
36
|
+
export * from "./components/VashEngine.js";
|
|
37
|
+
export * from "./components/VelocityEngine.js";
|
|
38
|
+
export * from "./components/WalrusEngine.js";
|
|
39
|
+
export * from "./decorators/viewEngine.js";
|
|
40
|
+
export * from "./registries/EnginesContainer.js";
|
|
41
|
+
export * from "./utils/cache.js";
|
|
42
|
+
export * from "./utils/getEngines.js";
|