@tsed/platform-views 7.0.0-beta.7 → 7.0.0-rc.1
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/jest.config.js +14 -0
- package/lib/cjs/services/PlatformViews.js +31 -60
- package/lib/cjs/services/PlatformViews.js.map +1 -1
- package/lib/esm/services/PlatformViews.js +32 -61
- package/lib/esm/services/PlatformViews.js.map +1 -1
- package/lib/types/services/PlatformViews.d.ts +1 -5
- package/package.json +21 -21
- package/readme.md +3 -2
package/jest.config.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// For a detailed explanation regarding each configuration property, visit:
|
|
2
|
+
// https://jestjs.io/docs/en/configuration.html
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
...require("@tsed/jest-config")(__dirname, "platform-views"),
|
|
6
|
+
coverageThreshold: {
|
|
7
|
+
global: {
|
|
8
|
+
branches: 100,
|
|
9
|
+
functions: 80,
|
|
10
|
+
lines: 92,
|
|
11
|
+
statements: 92.3
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var _PlatformViews_extensions, _PlatformViews_engines, _PlatformViews_cachePaths;
|
|
3
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
3
|
exports.PlatformViews = void 0;
|
|
5
4
|
const tslib_1 = require("tslib");
|
|
6
5
|
const core_1 = require("@tsed/core");
|
|
7
6
|
const di_1 = require("@tsed/di");
|
|
7
|
+
const engines_1 = require("@tsed/engines");
|
|
8
8
|
const fs_1 = tslib_1.__importDefault(require("fs"));
|
|
9
9
|
const path_1 = require("path");
|
|
10
10
|
const PlatformViewsSettings_1 = require("../domain/PlatformViewsSettings");
|
|
@@ -19,74 +19,46 @@ async function patchEJS(ejs) {
|
|
|
19
19
|
}
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
|
-
async function tryImport(name) {
|
|
23
|
-
try {
|
|
24
|
-
return await Promise.resolve().then(() => tslib_1.__importStar(require(name)));
|
|
25
|
-
}
|
|
26
|
-
catch (er) {
|
|
27
|
-
// istanbul ignore next
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
22
|
/**
|
|
31
23
|
* @platform
|
|
32
24
|
*/
|
|
33
25
|
let PlatformViews = class PlatformViews {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
26
|
+
env;
|
|
27
|
+
root;
|
|
28
|
+
cache;
|
|
29
|
+
disabled;
|
|
30
|
+
viewEngine;
|
|
31
|
+
extensionsOptions;
|
|
32
|
+
engineOptions;
|
|
33
|
+
#extensions;
|
|
34
|
+
#engines = new Map();
|
|
35
|
+
#cachePaths = new Map();
|
|
39
36
|
async $onInit() {
|
|
40
37
|
if (!this.disabled) {
|
|
41
|
-
|
|
38
|
+
this.#extensions = new Map(Object.entries({
|
|
42
39
|
...PlatformViewsSettings_1.PLATFORM_VIEWS_EXTENSIONS,
|
|
43
40
|
...this.extensionsOptions
|
|
44
|
-
}))
|
|
45
|
-
await this.
|
|
46
|
-
await this.loadFromTsedEngines();
|
|
41
|
+
}));
|
|
42
|
+
await this.loadEngines();
|
|
47
43
|
}
|
|
48
44
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
tslib_1.__classPrivateFieldGet(this, _PlatformViews_extensions, "f").forEach((engineType) => {
|
|
57
|
-
if (cons[engineType]) {
|
|
58
|
-
const options = this.getEngineOptions(engineType);
|
|
59
|
-
if (options.requires) {
|
|
60
|
-
cons.requires[engineType] = options.requires;
|
|
61
|
-
}
|
|
62
|
-
this.registerEngine(engineType, {
|
|
63
|
-
options,
|
|
64
|
-
render: cons[engineType]
|
|
65
|
-
});
|
|
45
|
+
async loadEngines() {
|
|
46
|
+
engines_1.requires.set("ejs", await patchEJS(engines_1.requires.get("ejs")));
|
|
47
|
+
this.#extensions.forEach((engineType) => {
|
|
48
|
+
if (engines_1.engines.has(engineType)) {
|
|
49
|
+
const options = this.getEngineOptions(engineType);
|
|
50
|
+
if (options.requires) {
|
|
51
|
+
engines_1.requires.set(engineType, options.requires);
|
|
66
52
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
tsed.requires.set("ejs", await patchEJS(tsed.requires.get("ejs")));
|
|
74
|
-
tslib_1.__classPrivateFieldGet(this, _PlatformViews_extensions, "f").forEach((engineType) => {
|
|
75
|
-
if (tsed.engines.has(engineType)) {
|
|
76
|
-
const options = this.getEngineOptions(engineType);
|
|
77
|
-
if (options.requires) {
|
|
78
|
-
tsed.requires.set(engineType, options.requires);
|
|
79
|
-
}
|
|
80
|
-
this.registerEngine(engineType, {
|
|
81
|
-
options,
|
|
82
|
-
render: tsed.getEngine(engineType)
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
}
|
|
53
|
+
this.registerEngine(engineType, {
|
|
54
|
+
options,
|
|
55
|
+
render: (0, engines_1.getEngine)(engineType)
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
});
|
|
87
59
|
}
|
|
88
60
|
getEngines() {
|
|
89
|
-
return [...
|
|
61
|
+
return [...this.#extensions.entries()].map(([extension, engineType]) => {
|
|
90
62
|
const engine = this.getEngine(this.getExtension(engineType));
|
|
91
63
|
return {
|
|
92
64
|
extension,
|
|
@@ -95,17 +67,17 @@ let PlatformViews = class PlatformViews {
|
|
|
95
67
|
});
|
|
96
68
|
}
|
|
97
69
|
registerEngine(engineType, engine) {
|
|
98
|
-
|
|
70
|
+
this.#engines.set(engineType, engine);
|
|
99
71
|
return this;
|
|
100
72
|
}
|
|
101
73
|
getEngine(type) {
|
|
102
|
-
return
|
|
74
|
+
return this.#engines.get(this.#extensions.get(type) || type);
|
|
103
75
|
}
|
|
104
76
|
getEngineOptions(engineType) {
|
|
105
77
|
return (0, core_1.getValue)(this.engineOptions, engineType, {});
|
|
106
78
|
}
|
|
107
79
|
async render(viewPath, options = {}) {
|
|
108
|
-
const { path, extension } =
|
|
80
|
+
const { path, extension } = this.#cachePaths.get(viewPath) || this.#cachePaths.set(viewPath, this.resolve(viewPath)).get(viewPath);
|
|
109
81
|
const engine = this.getEngine(extension);
|
|
110
82
|
if (!engine) {
|
|
111
83
|
throw new Error(`Engine not found to render the following "${viewPath}"`);
|
|
@@ -130,7 +102,6 @@ let PlatformViews = class PlatformViews {
|
|
|
130
102
|
};
|
|
131
103
|
}
|
|
132
104
|
};
|
|
133
|
-
_PlatformViews_extensions = new WeakMap(), _PlatformViews_engines = new WeakMap(), _PlatformViews_cachePaths = new WeakMap();
|
|
134
105
|
tslib_1.__decorate([
|
|
135
106
|
(0, di_1.Constant)("env"),
|
|
136
107
|
tslib_1.__metadata("design:type", String)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlatformViews.js","sourceRoot":"","sources":["../../../src/services/PlatformViews.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PlatformViews.js","sourceRoot":"","sources":["../../../src/services/PlatformViews.ts"],"names":[],"mappings":"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","sourcesContent":["import {Env, getValue} from \"@tsed/core\";\nimport {Constant, Module} from \"@tsed/di\";\nimport {engines, getEngine, requires} from \"@tsed/engines\";\nimport Fs from \"fs\";\nimport {extname, join, resolve} from \"path\";\nimport {\n PLATFORM_VIEWS_EXTENSIONS,\n PlatformViewEngine,\n PlatformViewsEngineOptions,\n PlatformViewsExtensionsTypes\n} from \"../domain/PlatformViewsSettings\";\n\nasync function patchEJS(ejs: any) {\n if (!ejs) {\n const mod = await import(\"ejs\");\n ejs = mod.default;\n }\n\n return {\n compile(str: string, {client, ...options}: any) {\n return ejs.compile(str, options);\n }\n };\n}\n\n/**\n * @platform\n */\n@Module({\n views: {\n exists: true\n }\n})\nexport class PlatformViews {\n @Constant(\"env\")\n env: Env;\n\n @Constant(\"views.root\", `${process.cwd()}/views`)\n readonly root: string;\n\n @Constant(\"views.cache\")\n readonly cache: boolean;\n\n @Constant(\"views.disabled\", false)\n readonly disabled: string;\n\n @Constant(\"views.viewEngine\", \"ejs\")\n readonly viewEngine: string;\n\n @Constant(\"views.extensions\", {})\n protected extensionsOptions: PlatformViewsExtensionsTypes;\n\n @Constant(\"views.options\", {})\n protected engineOptions: Record<string, PlatformViewsEngineOptions>;\n\n #extensions: Map<string, string>;\n #engines = new Map<string, PlatformViewEngine>();\n #cachePaths = new Map<string, {path: string; extension: string}>();\n\n async $onInit() {\n if (!this.disabled) {\n this.#extensions = new Map(\n Object.entries({\n ...PLATFORM_VIEWS_EXTENSIONS,\n ...this.extensionsOptions\n })\n );\n\n await this.loadEngines();\n }\n }\n\n async loadEngines() {\n requires.set(\"ejs\", await patchEJS(requires.get(\"ejs\")));\n\n this.#extensions.forEach((engineType) => {\n if (engines.has(engineType)) {\n const options = this.getEngineOptions(engineType);\n\n if (options.requires) {\n requires.set(engineType, options.requires);\n }\n\n this.registerEngine(engineType, {\n options,\n render: getEngine(engineType)\n });\n }\n });\n }\n\n getEngines() {\n return [...this.#extensions.entries()].map(([extension, engineType]) => {\n const engine = this.getEngine(this.getExtension(engineType))!;\n\n return {\n extension,\n engine\n };\n });\n }\n\n registerEngine(engineType: string, engine: PlatformViewEngine) {\n this.#engines.set(engineType, engine);\n\n return this;\n }\n\n getEngine(type: string) {\n return this.#engines.get(this.#extensions.get(type) || type);\n }\n\n getEngineOptions(engineType: string): PlatformViewsEngineOptions {\n return getValue(this.engineOptions, engineType, {});\n }\n\n async render(viewPath: string, options: any = {}): Promise<string> {\n const {path, extension} = this.#cachePaths.get(viewPath) || this.#cachePaths.set(viewPath, this.resolve(viewPath)).get(viewPath)!;\n const engine = this.getEngine(extension);\n\n if (!engine) {\n throw new Error(`Engine not found to render the following \"${viewPath}\"`);\n }\n\n return engine.render(path, Object.assign({cache: this.cache || this.env === Env.PROD}, engine.options, options));\n }\n\n protected getExtension(viewPath: string) {\n return (extname(viewPath) || this.viewEngine).replace(/\\./, \"\");\n }\n\n protected resolve(viewPath: string) {\n const extension = this.getExtension(viewPath);\n\n viewPath = viewPath.replace(extname(viewPath), \"\") + \".\" + extension;\n\n const path =\n [\n viewPath,\n resolve(join(this.root, viewPath)),\n resolve(join(process.cwd(), \"views\", viewPath)),\n resolve(join(process.cwd(), \"public\", viewPath))\n ].find((file) => Fs.existsSync(file)) || viewPath;\n\n return {\n path,\n extension\n };\n }\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
import { __classPrivateFieldGet, __classPrivateFieldSet, __decorate, __metadata } from "tslib";
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
3
2
|
import { Env, getValue } from "@tsed/core";
|
|
4
3
|
import { Constant, Module } from "@tsed/di";
|
|
4
|
+
import { engines, getEngine, requires } from "@tsed/engines";
|
|
5
5
|
import Fs from "fs";
|
|
6
6
|
import { extname, join, resolve } from "path";
|
|
7
7
|
import { PLATFORM_VIEWS_EXTENSIONS } from "../domain/PlatformViewsSettings.js";
|
|
@@ -16,74 +16,46 @@ async function patchEJS(ejs) {
|
|
|
16
16
|
}
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
|
-
async function tryImport(name) {
|
|
20
|
-
try {
|
|
21
|
-
return await import(name);
|
|
22
|
-
}
|
|
23
|
-
catch (er) {
|
|
24
|
-
// istanbul ignore next
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
19
|
/**
|
|
28
20
|
* @platform
|
|
29
21
|
*/
|
|
30
22
|
let PlatformViews = class PlatformViews {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
23
|
+
env;
|
|
24
|
+
root;
|
|
25
|
+
cache;
|
|
26
|
+
disabled;
|
|
27
|
+
viewEngine;
|
|
28
|
+
extensionsOptions;
|
|
29
|
+
engineOptions;
|
|
30
|
+
#extensions;
|
|
31
|
+
#engines = new Map();
|
|
32
|
+
#cachePaths = new Map();
|
|
36
33
|
async $onInit() {
|
|
37
34
|
if (!this.disabled) {
|
|
38
|
-
|
|
35
|
+
this.#extensions = new Map(Object.entries({
|
|
39
36
|
...PLATFORM_VIEWS_EXTENSIONS,
|
|
40
37
|
...this.extensionsOptions
|
|
41
|
-
}))
|
|
42
|
-
await this.
|
|
43
|
-
await this.loadFromTsedEngines();
|
|
38
|
+
}));
|
|
39
|
+
await this.loadEngines();
|
|
44
40
|
}
|
|
45
41
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
__classPrivateFieldGet(this, _PlatformViews_extensions, "f").forEach((engineType) => {
|
|
54
|
-
if (cons[engineType]) {
|
|
55
|
-
const options = this.getEngineOptions(engineType);
|
|
56
|
-
if (options.requires) {
|
|
57
|
-
cons.requires[engineType] = options.requires;
|
|
58
|
-
}
|
|
59
|
-
this.registerEngine(engineType, {
|
|
60
|
-
options,
|
|
61
|
-
render: cons[engineType]
|
|
62
|
-
});
|
|
42
|
+
async loadEngines() {
|
|
43
|
+
requires.set("ejs", await patchEJS(requires.get("ejs")));
|
|
44
|
+
this.#extensions.forEach((engineType) => {
|
|
45
|
+
if (engines.has(engineType)) {
|
|
46
|
+
const options = this.getEngineOptions(engineType);
|
|
47
|
+
if (options.requires) {
|
|
48
|
+
requires.set(engineType, options.requires);
|
|
63
49
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
tsed.requires.set("ejs", await patchEJS(tsed.requires.get("ejs")));
|
|
71
|
-
__classPrivateFieldGet(this, _PlatformViews_extensions, "f").forEach((engineType) => {
|
|
72
|
-
if (tsed.engines.has(engineType)) {
|
|
73
|
-
const options = this.getEngineOptions(engineType);
|
|
74
|
-
if (options.requires) {
|
|
75
|
-
tsed.requires.set(engineType, options.requires);
|
|
76
|
-
}
|
|
77
|
-
this.registerEngine(engineType, {
|
|
78
|
-
options,
|
|
79
|
-
render: tsed.getEngine(engineType)
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
}
|
|
50
|
+
this.registerEngine(engineType, {
|
|
51
|
+
options,
|
|
52
|
+
render: getEngine(engineType)
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
});
|
|
84
56
|
}
|
|
85
57
|
getEngines() {
|
|
86
|
-
return [...
|
|
58
|
+
return [...this.#extensions.entries()].map(([extension, engineType]) => {
|
|
87
59
|
const engine = this.getEngine(this.getExtension(engineType));
|
|
88
60
|
return {
|
|
89
61
|
extension,
|
|
@@ -92,17 +64,17 @@ let PlatformViews = class PlatformViews {
|
|
|
92
64
|
});
|
|
93
65
|
}
|
|
94
66
|
registerEngine(engineType, engine) {
|
|
95
|
-
|
|
67
|
+
this.#engines.set(engineType, engine);
|
|
96
68
|
return this;
|
|
97
69
|
}
|
|
98
70
|
getEngine(type) {
|
|
99
|
-
return
|
|
71
|
+
return this.#engines.get(this.#extensions.get(type) || type);
|
|
100
72
|
}
|
|
101
73
|
getEngineOptions(engineType) {
|
|
102
74
|
return getValue(this.engineOptions, engineType, {});
|
|
103
75
|
}
|
|
104
76
|
async render(viewPath, options = {}) {
|
|
105
|
-
const { path, extension } =
|
|
77
|
+
const { path, extension } = this.#cachePaths.get(viewPath) || this.#cachePaths.set(viewPath, this.resolve(viewPath)).get(viewPath);
|
|
106
78
|
const engine = this.getEngine(extension);
|
|
107
79
|
if (!engine) {
|
|
108
80
|
throw new Error(`Engine not found to render the following "${viewPath}"`);
|
|
@@ -127,7 +99,6 @@ let PlatformViews = class PlatformViews {
|
|
|
127
99
|
};
|
|
128
100
|
}
|
|
129
101
|
};
|
|
130
|
-
_PlatformViews_extensions = new WeakMap(), _PlatformViews_engines = new WeakMap(), _PlatformViews_cachePaths = new WeakMap();
|
|
131
102
|
__decorate([
|
|
132
103
|
Constant("env"),
|
|
133
104
|
__metadata("design:type", String)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlatformViews.js","sourceRoot":"","sources":["../../../src/services/PlatformViews.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PlatformViews.js","sourceRoot":"","sources":["../../../src/services/PlatformViews.ts"],"names":[],"mappings":"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","sourcesContent":["import {Env, getValue} from \"@tsed/core\";\nimport {Constant, Module} from \"@tsed/di\";\nimport {engines, getEngine, requires} from \"@tsed/engines\";\nimport Fs from \"fs\";\nimport {extname, join, resolve} from \"path\";\nimport {\n PLATFORM_VIEWS_EXTENSIONS,\n PlatformViewEngine,\n PlatformViewsEngineOptions,\n PlatformViewsExtensionsTypes\n} from \"../domain/PlatformViewsSettings\";\n\nasync function patchEJS(ejs: any) {\n if (!ejs) {\n const mod = await import(\"ejs\");\n ejs = mod.default;\n }\n\n return {\n compile(str: string, {client, ...options}: any) {\n return ejs.compile(str, options);\n }\n };\n}\n\n/**\n * @platform\n */\n@Module({\n views: {\n exists: true\n }\n})\nexport class PlatformViews {\n @Constant(\"env\")\n env: Env;\n\n @Constant(\"views.root\", `${process.cwd()}/views`)\n readonly root: string;\n\n @Constant(\"views.cache\")\n readonly cache: boolean;\n\n @Constant(\"views.disabled\", false)\n readonly disabled: string;\n\n @Constant(\"views.viewEngine\", \"ejs\")\n readonly viewEngine: string;\n\n @Constant(\"views.extensions\", {})\n protected extensionsOptions: PlatformViewsExtensionsTypes;\n\n @Constant(\"views.options\", {})\n protected engineOptions: Record<string, PlatformViewsEngineOptions>;\n\n #extensions: Map<string, string>;\n #engines = new Map<string, PlatformViewEngine>();\n #cachePaths = new Map<string, {path: string; extension: string}>();\n\n async $onInit() {\n if (!this.disabled) {\n this.#extensions = new Map(\n Object.entries({\n ...PLATFORM_VIEWS_EXTENSIONS,\n ...this.extensionsOptions\n })\n );\n\n await this.loadEngines();\n }\n }\n\n async loadEngines() {\n requires.set(\"ejs\", await patchEJS(requires.get(\"ejs\")));\n\n this.#extensions.forEach((engineType) => {\n if (engines.has(engineType)) {\n const options = this.getEngineOptions(engineType);\n\n if (options.requires) {\n requires.set(engineType, options.requires);\n }\n\n this.registerEngine(engineType, {\n options,\n render: getEngine(engineType)\n });\n }\n });\n }\n\n getEngines() {\n return [...this.#extensions.entries()].map(([extension, engineType]) => {\n const engine = this.getEngine(this.getExtension(engineType))!;\n\n return {\n extension,\n engine\n };\n });\n }\n\n registerEngine(engineType: string, engine: PlatformViewEngine) {\n this.#engines.set(engineType, engine);\n\n return this;\n }\n\n getEngine(type: string) {\n return this.#engines.get(this.#extensions.get(type) || type);\n }\n\n getEngineOptions(engineType: string): PlatformViewsEngineOptions {\n return getValue(this.engineOptions, engineType, {});\n }\n\n async render(viewPath: string, options: any = {}): Promise<string> {\n const {path, extension} = this.#cachePaths.get(viewPath) || this.#cachePaths.set(viewPath, this.resolve(viewPath)).get(viewPath)!;\n const engine = this.getEngine(extension);\n\n if (!engine) {\n throw new Error(`Engine not found to render the following \"${viewPath}\"`);\n }\n\n return engine.render(path, Object.assign({cache: this.cache || this.env === Env.PROD}, engine.options, options));\n }\n\n protected getExtension(viewPath: string) {\n return (extname(viewPath) || this.viewEngine).replace(/\\./, \"\");\n }\n\n protected resolve(viewPath: string) {\n const extension = this.getExtension(viewPath);\n\n viewPath = viewPath.replace(extname(viewPath), \"\") + \".\" + extension;\n\n const path =\n [\n viewPath,\n resolve(join(this.root, viewPath)),\n resolve(join(process.cwd(), \"views\", viewPath)),\n resolve(join(process.cwd(), \"public\", viewPath))\n ].find((file) => Fs.existsSync(file)) || viewPath;\n\n return {\n path,\n extension\n };\n }\n}\n"]}
|
|
@@ -13,11 +13,7 @@ export declare class PlatformViews {
|
|
|
13
13
|
protected extensionsOptions: PlatformViewsExtensionsTypes;
|
|
14
14
|
protected engineOptions: Record<string, PlatformViewsEngineOptions>;
|
|
15
15
|
$onInit(): Promise<void>;
|
|
16
|
-
|
|
17
|
-
* @deprecated
|
|
18
|
-
*/
|
|
19
|
-
loadFromConsolidate(): Promise<void>;
|
|
20
|
-
loadFromTsedEngines(): Promise<void>;
|
|
16
|
+
loadEngines(): Promise<void>;
|
|
21
17
|
getEngines(): {
|
|
22
18
|
extension: string;
|
|
23
19
|
engine: PlatformViewEngine;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tsed/platform-views",
|
|
3
|
-
"version": "7.0.0-
|
|
3
|
+
"version": "7.0.0-rc.1",
|
|
4
4
|
"description": "Views module for Ts.ED Framework",
|
|
5
5
|
"private": false,
|
|
6
6
|
"source": "./src/index.ts",
|
|
@@ -17,28 +17,28 @@
|
|
|
17
17
|
"build": "yarn barrels && yarn run build:esm && yarn run build:cjs",
|
|
18
18
|
"build:cjs": "tsc --build tsconfig.compile.json",
|
|
19
19
|
"build:esm": "tsc --build tsconfig.compile.esm.json",
|
|
20
|
-
"barrels": "yarn barrelsby --delete -d ./src -e \"\\.spec\\.ts\" -e \"__mock__\" -e \".benchmark.ts\""
|
|
20
|
+
"barrels": "yarn barrelsby --delete -d ./src -e \"\\.spec\\.ts\" -e \"__mock__\" -e \".benchmark.ts\"",
|
|
21
|
+
"test": "cross-env NODE_ENV=test yarn jest --max-workers=2"
|
|
21
22
|
},
|
|
22
23
|
"dependencies": {
|
|
23
|
-
"
|
|
24
|
+
"@tsed/engines": "7.0.0-rc.1",
|
|
24
25
|
"ejs": "^3.1.5",
|
|
25
|
-
"tslib": "2.
|
|
26
|
+
"tslib": "2.4.0"
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|
|
28
|
-
"@tsed/core": "7.0.0-
|
|
29
|
-
"@tsed/di": "7.0.0-
|
|
30
|
-
"@tsed/engines": "7.0.0-
|
|
31
|
-
"@tsed/exceptions": "7.0.0-
|
|
32
|
-
"@tsed/schema": "7.0.0-
|
|
33
|
-
"@types/
|
|
34
|
-
"@types/ejs": "3.1.0"
|
|
29
|
+
"@tsed/core": "7.0.0-rc.1",
|
|
30
|
+
"@tsed/di": "7.0.0-rc.1",
|
|
31
|
+
"@tsed/engines": "7.0.0-rc.1",
|
|
32
|
+
"@tsed/exceptions": "7.0.0-rc.1",
|
|
33
|
+
"@tsed/schema": "7.0.0-rc.1",
|
|
34
|
+
"@types/ejs": "3.1.1"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
|
-
"@tsed/core": "^7.0.0-
|
|
38
|
-
"@tsed/di": "^7.0.0-
|
|
39
|
-
"@tsed/engines": "^7.0.0-
|
|
40
|
-
"@tsed/exceptions": "^7.0.0-
|
|
41
|
-
"@tsed/schema": "^7.0.0-
|
|
37
|
+
"@tsed/core": "^7.0.0-rc.1",
|
|
38
|
+
"@tsed/di": "^7.0.0-rc.1",
|
|
39
|
+
"@tsed/engines": "^7.0.0-rc.1",
|
|
40
|
+
"@tsed/exceptions": "^7.0.0-rc.1",
|
|
41
|
+
"@tsed/schema": "^7.0.0-rc.1"
|
|
42
42
|
},
|
|
43
43
|
"peerDependenciesMeta": {
|
|
44
44
|
"@tsed/core": {
|
|
@@ -52,16 +52,16 @@
|
|
|
52
52
|
},
|
|
53
53
|
"@tsed/schema": {
|
|
54
54
|
"optional": false
|
|
55
|
-
},
|
|
56
|
-
"@tsed/engines": {
|
|
57
|
-
"optional": true
|
|
58
55
|
}
|
|
59
56
|
},
|
|
60
57
|
"repository": "https://github.com/tsedio/tsed",
|
|
61
58
|
"bugs": {
|
|
62
59
|
"url": "https://github.com/tsedio/tsed/issues"
|
|
63
60
|
},
|
|
64
|
-
"homepage": "https://github.com/tsedio/tsed/tree/
|
|
61
|
+
"homepage": "https://github.com/tsedio/tsed/tree/rc/packages/platform/platform-views",
|
|
65
62
|
"author": "Romain Lenzotti",
|
|
66
|
-
"license": "MIT"
|
|
63
|
+
"license": "MIT",
|
|
64
|
+
"publishConfig": {
|
|
65
|
+
"tag": "rc"
|
|
66
|
+
}
|
|
67
67
|
}
|
package/readme.md
CHANGED
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
[](https://badge.fury.io/js/%40tsed%2Fcommon)
|
|
12
12
|
[](https://github.com/semantic-release/semantic-release)
|
|
13
13
|
[](https://github.com/prettier/prettier)
|
|
14
|
-
[](https://github.com/sponsors/romakita)
|
|
15
|
+
[](https://opencollective.com/tsed)
|
|
15
16
|
|
|
16
17
|
</div>
|
|
17
18
|
|
|
@@ -55,7 +56,7 @@ Support this project by becoming a sponsor. Your logo will show up here with a l
|
|
|
55
56
|
|
|
56
57
|
The MIT License (MIT)
|
|
57
58
|
|
|
58
|
-
Copyright (c) 2016 -
|
|
59
|
+
Copyright (c) 2016 - 2022 Romain Lenzotti
|
|
59
60
|
|
|
60
61
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
61
62
|
|