@eggjs/view 3.0.1 → 4.0.0-beta.18

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.
Files changed (59) hide show
  1. package/README.md +18 -15
  2. package/dist/app/extend/application.d.ts +15 -0
  3. package/dist/app/extend/application.js +19 -0
  4. package/dist/app/extend/context.d.ts +39 -0
  5. package/dist/app/extend/context.js +49 -0
  6. package/dist/config/config.default.d.ts +33 -0
  7. package/dist/config/config.default.js +14 -0
  8. package/dist/config/config.local.d.ts +6 -0
  9. package/dist/config/config.local.js +5 -0
  10. package/dist/index.d.ts +3 -0
  11. package/dist/index.js +8 -0
  12. package/dist/lib/context_view.d.ts +52 -0
  13. package/dist/lib/context_view.js +86 -0
  14. package/dist/lib/index.d.ts +3 -0
  15. package/dist/lib/index.js +4 -0
  16. package/dist/lib/view_manager.d.ts +61 -0
  17. package/dist/lib/view_manager.js +83 -0
  18. package/dist/types.d.ts +28 -0
  19. package/dist/types.js +1 -0
  20. package/package.json +41 -66
  21. package/dist/commonjs/app/extend/application.d.ts +0 -17
  22. package/dist/commonjs/app/extend/application.js +0 -20
  23. package/dist/commonjs/app/extend/context.d.ts +0 -44
  24. package/dist/commonjs/app/extend/context.js +0 -50
  25. package/dist/commonjs/config/config.default.d.ts +0 -52
  26. package/dist/commonjs/config/config.default.js +0 -16
  27. package/dist/commonjs/config/config.local.d.ts +0 -3
  28. package/dist/commonjs/config/config.local.js +0 -8
  29. package/dist/commonjs/index.d.ts +0 -3
  30. package/dist/commonjs/index.js +0 -6
  31. package/dist/commonjs/lib/context_view.d.ts +0 -48
  32. package/dist/commonjs/lib/context_view.js +0 -104
  33. package/dist/commonjs/lib/view_manager.d.ts +0 -57
  34. package/dist/commonjs/lib/view_manager.js +0 -98
  35. package/dist/commonjs/package.json +0 -3
  36. package/dist/esm/app/extend/application.d.ts +0 -17
  37. package/dist/esm/app/extend/application.js +0 -17
  38. package/dist/esm/app/extend/context.d.ts +0 -44
  39. package/dist/esm/app/extend/context.js +0 -47
  40. package/dist/esm/config/config.default.d.ts +0 -52
  41. package/dist/esm/config/config.default.js +0 -11
  42. package/dist/esm/config/config.local.d.ts +0 -3
  43. package/dist/esm/config/config.local.js +0 -6
  44. package/dist/esm/index.d.ts +0 -3
  45. package/dist/esm/index.js +0 -4
  46. package/dist/esm/lib/context_view.d.ts +0 -48
  47. package/dist/esm/lib/context_view.js +0 -97
  48. package/dist/esm/lib/view_manager.d.ts +0 -57
  49. package/dist/esm/lib/view_manager.js +0 -91
  50. package/dist/esm/package.json +0 -3
  51. package/dist/package.json +0 -4
  52. package/src/app/extend/application.ts +0 -25
  53. package/src/app/extend/context.ts +0 -66
  54. package/src/config/config.default.ts +0 -56
  55. package/src/config/config.local.ts +0 -7
  56. package/src/index.ts +0 -3
  57. package/src/lib/context_view.ts +0 -111
  58. package/src/lib/view_manager.ts +0 -122
  59. package/src/typings/index.d.ts +0 -4
package/README.md CHANGED
@@ -1,10 +1,7 @@
1
1
  # @eggjs/view
2
2
 
3
3
  [![NPM version](https://img.shields.io/npm/v/@eggjs/view.svg?style=flat-square)](https://npmjs.org/package/@eggjs/view)
4
- [![NPM quality](http://npm.packagequality.com/shield/@eggjs/view.svg?style=flat-square)](http://packagequality.com/#?package=@eggjs/view)
5
4
  [![NPM download](https://img.shields.io/npm/dm/@eggjs/view.svg?style=flat-square)](https://npmjs.org/package/@eggjs/view)
6
- [![Continuous Integration](https://github.com/eggjs/view/actions/workflows/nodejs.yml/badge.svg)](https://github.com/eggjs/view/actions/workflows/nodejs.yml)
7
- [![Test coverage](https://img.shields.io/codecov/c/github/eggjs/view.svg?style=flat-square)](https://codecov.io/gh/eggjs/view)
8
5
  [![Node.js Version](https://img.shields.io/node/v/@eggjs/view.svg?style=flat)](https://nodejs.org/en/download/)
9
6
  [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://makeapullrequest.com)
10
7
  ![CodeRabbit Pull Request Reviews](https://img.shields.io/coderabbit/prs/github/eggjs/view)
@@ -76,9 +73,13 @@ module.exports = app => {
76
73
  return class UserController extends app.Controller {
77
74
  async list() {
78
75
  const { ctx } = this;
79
- ctx.body = await ctx.renderString('<%= user %>', { user: 'popomore' }, {
80
- viewEngine: 'ejs',
81
- });
76
+ ctx.body = await ctx.renderString(
77
+ '<%= user %>',
78
+ { user: 'popomore' },
79
+ {
80
+ viewEngine: 'ejs',
81
+ }
82
+ );
82
83
  }
83
84
  };
84
85
  };
@@ -128,7 +129,9 @@ module.exports = class MyView {
128
129
  return myengine.render(fullpath, locals);
129
130
  }
130
131
 
131
- async renderString() { throw new Error('not implement'); }
132
+ async renderString() {
133
+ throw new Error('not implement');
134
+ }
132
135
  };
133
136
  ```
134
137
 
@@ -149,7 +152,7 @@ class MyView {
149
152
  });
150
153
  });
151
154
  }
152
- };
155
+ }
153
156
  ```
154
157
 
155
158
  These methods receive three arguments, `renderString` will pass tpl as the first argument instead of name in `render`.
@@ -191,7 +194,7 @@ Define plugin name and depend on [egg-view]
191
194
  {
192
195
  "eggPlugin": {
193
196
  "name": "myName",
194
- "dependencies": [ "view" ]
197
+ "dependencies": ["view"]
195
198
  }
196
199
  }
197
200
  ```
@@ -218,10 +221,10 @@ module.exports = appInfo => {
218
221
  const baseDir = appInfo.baseDir;
219
222
  return {
220
223
  view: {
221
- root: `${baseDir}/app/view,${baseDir}/app/view2`
222
- }
223
- }
224
- }
224
+ root: `${baseDir}/app/view,${baseDir}/app/view2`,
225
+ },
226
+ };
227
+ };
225
228
  ```
226
229
 
227
230
  ### defaultExtension
@@ -259,7 +262,7 @@ exports.view = {
259
262
  };
260
263
  ```
261
264
 
262
- see [config/config.default.ts](https://github.com/eggjs/view/blob/master/src/config/config.default.ts) for more detail.
265
+ see [config/config.default.ts](https://github.com/eggjs/egg/blob/next/plugins/view/src/config/config.default.ts) for more detail.
263
266
 
264
267
  ## Questions & Suggestions
265
268
 
@@ -271,7 +274,7 @@ Please open an issue [here](https://github.com/eggjs/egg/issues).
271
274
 
272
275
  ## Contributors
273
276
 
274
- [![Contributors](https://contrib.rocks/image?repo=eggjs/logrotator)](https://github.com/eggjs/logrotator/graphs/contributors)
277
+ [![Contributors](https://contrib.rocks/image?repo=eggjs/egg)](https://github.com/eggjs/egg/graphs/contributors)
275
278
 
276
279
  Made with [contributors-img](https://contrib.rocks).
277
280
 
@@ -0,0 +1,15 @@
1
+ import { ViewManager } from "../../lib/view_manager.js";
2
+ import { Application } from "egg";
3
+
4
+ //#region src/app/extend/application.d.ts
5
+ declare const VIEW: unique symbol;
6
+ declare class ViewApplication extends Application {
7
+ [VIEW]: ViewManager;
8
+ /**
9
+ * Retrieve ViewManager instance
10
+ * @member {ViewManager} Application#view
11
+ */
12
+ get view(): ViewManager;
13
+ }
14
+ //#endregion
15
+ export { ViewApplication as default };
@@ -0,0 +1,19 @@
1
+ import { ViewManager } from "../../lib/view_manager.js";
2
+ import { Application } from "egg";
3
+
4
+ //#region src/app/extend/application.ts
5
+ const VIEW = Symbol("Application#view");
6
+ var ViewApplication = class extends Application {
7
+ [VIEW];
8
+ /**
9
+ * Retrieve ViewManager instance
10
+ * @member {ViewManager} Application#view
11
+ */
12
+ get view() {
13
+ if (!this[VIEW]) this[VIEW] = new ViewManager(this);
14
+ return this[VIEW];
15
+ }
16
+ };
17
+
18
+ //#endregion
19
+ export { ViewApplication as default };
@@ -0,0 +1,39 @@
1
+ import { RenderOptions } from "../../lib/view_manager.js";
2
+ import { ContextView } from "../../lib/context_view.js";
3
+ import { Context } from "egg";
4
+
5
+ //#region src/app/extend/context.d.ts
6
+ declare const VIEW: unique symbol;
7
+ declare class ViewContext extends Context {
8
+ [VIEW]: ContextView;
9
+ /**
10
+ * Render a file by view engine, then set to body
11
+ * @param {String} name - the file path based on root
12
+ * @param {Object} [locals] - data used by template
13
+ * @param {Object} [options] - view options, you can use `options.viewEngine` to specify view engine
14
+ */
15
+ render(name: string, locals?: Record<string, any>, options?: RenderOptions): Promise<void>;
16
+ /**
17
+ * Render a file by view engine and return it
18
+ * @param {String} name - the file path based on root
19
+ * @param {Object} [locals] - data used by template
20
+ * @param {Object} [options] - view options, you can use `options.viewEngine` to specify view engine
21
+ * @return {Promise<String>} result - return a promise with a render result
22
+ */
23
+ renderView(name: string, locals?: Record<string, any>, options?: RenderOptions): Promise<string>;
24
+ /**
25
+ * Render template string by view engine and return it
26
+ * @param {String} tpl - template string
27
+ * @param {Object} [locals] - data used by template
28
+ * @param {Object} [options] - view options, you can use `options.viewEngine` to specify view engine
29
+ * @return {Promise<String>} result - return a promise with a render result
30
+ */
31
+ renderString(tpl: string, locals?: Record<string, any>, options?: RenderOptions): Promise<string>;
32
+ /**
33
+ * View instance that is created every request
34
+ * @member {ContextView} Context#view
35
+ */
36
+ get view(): ContextView;
37
+ }
38
+ //#endregion
39
+ export { ViewContext as default };
@@ -0,0 +1,49 @@
1
+ import "../../lib/view_manager.js";
2
+ import { ContextView } from "../../lib/context_view.js";
3
+ import { Context } from "egg";
4
+
5
+ //#region src/app/extend/context.ts
6
+ const VIEW = Symbol("Context#view");
7
+ var ViewContext = class extends Context {
8
+ [VIEW];
9
+ /**
10
+ * Render a file by view engine, then set to body
11
+ * @param {String} name - the file path based on root
12
+ * @param {Object} [locals] - data used by template
13
+ * @param {Object} [options] - view options, you can use `options.viewEngine` to specify view engine
14
+ */
15
+ async render(name, locals, options) {
16
+ this.body = await this.renderView(name, locals, options);
17
+ }
18
+ /**
19
+ * Render a file by view engine and return it
20
+ * @param {String} name - the file path based on root
21
+ * @param {Object} [locals] - data used by template
22
+ * @param {Object} [options] - view options, you can use `options.viewEngine` to specify view engine
23
+ * @return {Promise<String>} result - return a promise with a render result
24
+ */
25
+ async renderView(name, locals, options) {
26
+ return await this.view.render(name, locals, options);
27
+ }
28
+ /**
29
+ * Render template string by view engine and return it
30
+ * @param {String} tpl - template string
31
+ * @param {Object} [locals] - data used by template
32
+ * @param {Object} [options] - view options, you can use `options.viewEngine` to specify view engine
33
+ * @return {Promise<String>} result - return a promise with a render result
34
+ */
35
+ async renderString(tpl, locals, options) {
36
+ return await this.view.renderString(tpl, locals, options);
37
+ }
38
+ /**
39
+ * View instance that is created every request
40
+ * @member {ContextView} Context#view
41
+ */
42
+ get view() {
43
+ if (!this[VIEW]) this[VIEW] = new ContextView(this);
44
+ return this[VIEW];
45
+ }
46
+ };
47
+
48
+ //#endregion
49
+ export { ViewContext as default };
@@ -0,0 +1,33 @@
1
+ import * as egg1 from "egg";
2
+
3
+ //#region src/config/config.default.d.ts
4
+ interface ViewConfig {
5
+ /**
6
+ * give a path to find the file, you can specify multiple path with `,` delimiter
7
+ * Default is `${baseDir}/app/view`
8
+ */
9
+ root: string;
10
+ /**
11
+ * whether cache the file's path
12
+ * Default is `true`
13
+ */
14
+ cache: boolean;
15
+ /**
16
+ * defaultExtension can be added automatically when there is no extension when call `ctx.render`
17
+ * Default is `.html`
18
+ */
19
+ defaultExtension: string;
20
+ /**
21
+ * set the default view engine if you don't want specify the viewEngine every request.
22
+ * Default is `''`
23
+ */
24
+ defaultViewEngine: string;
25
+ /**
26
+ * map the file extension to view engine, such as `{ '.ejs': 'ejs' }`
27
+ * Default is `{}`
28
+ */
29
+ mapping: Record<string, string>;
30
+ }
31
+ declare const _default: egg1.EggConfigFactory;
32
+ //#endregion
33
+ export { ViewConfig, _default as default };
@@ -0,0 +1,14 @@
1
+ import path from "node:path";
2
+ import { defineConfigFactory } from "egg";
3
+
4
+ //#region src/config/config.default.ts
5
+ var config_default_default = defineConfigFactory((appInfo) => ({ view: {
6
+ root: path.join(appInfo.baseDir, "app/view"),
7
+ cache: true,
8
+ defaultExtension: ".html",
9
+ defaultViewEngine: "",
10
+ mapping: {}
11
+ } }));
12
+
13
+ //#endregion
14
+ export { config_default_default as default };
@@ -0,0 +1,6 @@
1
+ import { EggAppConfig } from "egg";
2
+
3
+ //#region src/config/config.local.d.ts
4
+ declare const _default: EggAppConfig;
5
+ //#endregion
6
+ export { _default as default };
@@ -0,0 +1,5 @@
1
+ //#region src/config/config.local.ts
2
+ var config_local_default = { view: { cache: false } };
3
+
4
+ //#endregion
5
+ export { config_local_default as default };
@@ -0,0 +1,3 @@
1
+ import { PlainObject, RenderOptions, ViewEngine, ViewEngineClass, ViewManager, ViewManagerConfig } from "./lib/view_manager.js";
2
+ import { ContextView } from "./lib/context_view.js";
3
+ export { ContextView, PlainObject, RenderOptions, ViewEngine, ViewEngineClass, ViewManager, ViewManagerConfig };
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ import "./config/config.default.js";
2
+ import { ViewManager } from "./lib/view_manager.js";
3
+ import "./app/extend/application.js";
4
+ import { ContextView } from "./lib/context_view.js";
5
+ import "./app/extend/context.js";
6
+ import "./lib/index.js";
7
+
8
+ export { ContextView, ViewManager };
@@ -0,0 +1,52 @@
1
+ import { RenderOptions, ViewEngine, ViewManager, ViewManagerConfig } from "./view_manager.js";
2
+ import * as egg0 from "egg";
3
+ import { Application, Context } from "egg";
4
+
5
+ //#region src/lib/context_view.d.ts
6
+ declare const RENDER: unique symbol;
7
+ declare const RENDER_STRING: unique symbol;
8
+ declare const GET_VIEW_ENGINE: unique symbol;
9
+ declare const SET_LOCALS: unique symbol;
10
+ /**
11
+ * View instance for each request.
12
+ *
13
+ * It will find the view engine, and render it.
14
+ * The view engine should be registered in {@link ViewManager}.
15
+ */
16
+ declare class ContextView {
17
+ protected ctx: Context;
18
+ protected app: Application;
19
+ protected viewManager: ViewManager;
20
+ protected config: ViewManagerConfig;
21
+ constructor(ctx: Context);
22
+ /**
23
+ * Render a file by view engine
24
+ * @param {String} name - the file path based on root
25
+ * @param {Object} [locals] - data used by template
26
+ * @param {Object} [options] - view options, you can use `options.viewEngine` to specify view engine
27
+ * @return {Promise<String>} result - return a promise with a render result
28
+ */
29
+ render(name: string, locals?: Record<string, any>, options?: RenderOptions): Promise<string>;
30
+ /**
31
+ * Render a template string by view engine
32
+ * @param {String} tpl - template string
33
+ * @param {Object} [locals] - data used by template
34
+ * @param {Object} [options] - view options, you can use `options.viewEngine` to specify view engine
35
+ * @return {Promise<String>} result - return a promise with a render result
36
+ */
37
+ renderString(tpl: string, locals?: Record<string, any>, options?: RenderOptions): Promise<string>;
38
+ [RENDER](name: string, locals?: Record<string, any>, options?: RenderOptions): Promise<string>;
39
+ [RENDER_STRING](tpl: string, locals?: Record<string, any>, options?: RenderOptions): Promise<string>;
40
+ [GET_VIEW_ENGINE](name: string): ViewEngine;
41
+ /**
42
+ * set locals for view, inject `locals.ctx`, `locals.request`, `locals.helper`
43
+ * @private
44
+ */
45
+ [SET_LOCALS](locals?: Record<string, any>): {
46
+ ctx: Context;
47
+ request: egg0.Request;
48
+ helper: egg0.Helper;
49
+ } & Record<string, any>;
50
+ }
51
+ //#endregion
52
+ export { ContextView };
@@ -0,0 +1,86 @@
1
+ import "./view_manager.js";
2
+ import path from "node:path";
3
+ import assert from "node:assert";
4
+
5
+ //#region src/lib/context_view.ts
6
+ const RENDER = Symbol.for("contextView#render");
7
+ const RENDER_STRING = Symbol.for("contextView#renderString");
8
+ const GET_VIEW_ENGINE = Symbol.for("contextView#getViewEngine");
9
+ const SET_LOCALS = Symbol.for("contextView#setLocals");
10
+ /**
11
+ * View instance for each request.
12
+ *
13
+ * It will find the view engine, and render it.
14
+ * The view engine should be registered in {@link ViewManager}.
15
+ */
16
+ var ContextView = class {
17
+ ctx;
18
+ app;
19
+ viewManager;
20
+ config;
21
+ constructor(ctx) {
22
+ this.ctx = ctx;
23
+ this.app = this.ctx.app;
24
+ this.viewManager = this.app.view;
25
+ this.config = this.app.view.config;
26
+ }
27
+ /**
28
+ * Render a file by view engine
29
+ * @param {String} name - the file path based on root
30
+ * @param {Object} [locals] - data used by template
31
+ * @param {Object} [options] - view options, you can use `options.viewEngine` to specify view engine
32
+ * @return {Promise<String>} result - return a promise with a render result
33
+ */
34
+ async render(name, locals, options) {
35
+ return await this[RENDER](name, locals, options);
36
+ }
37
+ /**
38
+ * Render a template string by view engine
39
+ * @param {String} tpl - template string
40
+ * @param {Object} [locals] - data used by template
41
+ * @param {Object} [options] - view options, you can use `options.viewEngine` to specify view engine
42
+ * @return {Promise<String>} result - return a promise with a render result
43
+ */
44
+ async renderString(tpl, locals, options) {
45
+ return await this[RENDER_STRING](tpl, locals, options);
46
+ }
47
+ async [RENDER](name, locals, options = {}) {
48
+ const filename = await this.viewManager.resolve(name);
49
+ options.name = name;
50
+ options.root = filename.replace(path.normalize(name), "").replace(/[/\\]$/, "");
51
+ options.locals = locals;
52
+ let viewEngineName = options.viewEngine;
53
+ if (!viewEngineName) {
54
+ const ext = path.extname(filename);
55
+ viewEngineName = this.viewManager.extMap.get(ext);
56
+ }
57
+ if (!viewEngineName) viewEngineName = this.config.defaultViewEngine;
58
+ assert(viewEngineName, `Can't find viewEngine for ${filename}`);
59
+ return await this[GET_VIEW_ENGINE](viewEngineName).render(filename, this[SET_LOCALS](locals), options);
60
+ }
61
+ async [RENDER_STRING](tpl, locals, options) {
62
+ let viewEngineName = options && options.viewEngine;
63
+ if (!viewEngineName) viewEngineName = this.config.defaultViewEngine;
64
+ assert(viewEngineName, "Can't find viewEngine");
65
+ return await this[GET_VIEW_ENGINE](viewEngineName).renderString(tpl, this[SET_LOCALS](locals), options);
66
+ }
67
+ [GET_VIEW_ENGINE](name) {
68
+ const ViewEngine = this.viewManager.get(name);
69
+ assert(ViewEngine, `Can't find ViewEngine "${name}"`);
70
+ return new ViewEngine(this.ctx);
71
+ }
72
+ /**
73
+ * set locals for view, inject `locals.ctx`, `locals.request`, `locals.helper`
74
+ * @private
75
+ */
76
+ [SET_LOCALS](locals) {
77
+ return Object.assign({
78
+ ctx: this.ctx,
79
+ request: this.ctx.request,
80
+ helper: this.ctx.helper
81
+ }, this.ctx.locals, locals);
82
+ }
83
+ };
84
+
85
+ //#endregion
86
+ export { ContextView };
@@ -0,0 +1,3 @@
1
+ import { PlainObject, RenderOptions, ViewEngine, ViewEngineClass, ViewManager, ViewManagerConfig } from "./view_manager.js";
2
+ import { ContextView } from "./context_view.js";
3
+ export { ContextView, PlainObject, RenderOptions, ViewEngine, ViewEngineClass, ViewManager, ViewManagerConfig };
@@ -0,0 +1,4 @@
1
+ import { ViewManager } from "./view_manager.js";
2
+ import { ContextView } from "./context_view.js";
3
+
4
+ export { ContextView, ViewManager };
@@ -0,0 +1,61 @@
1
+ import { ViewConfig } from "../config/config.default.js";
2
+ import { Application, Context } from "egg";
3
+
4
+ //#region src/lib/view_manager.d.ts
5
+ interface ViewManagerConfig extends Omit<ViewConfig, 'root'> {
6
+ root: string[];
7
+ }
8
+ type PlainObject<T = any> = {
9
+ [key: string]: T;
10
+ };
11
+ interface RenderOptions extends PlainObject {
12
+ name?: string;
13
+ root?: string;
14
+ locals?: PlainObject;
15
+ viewEngine?: string;
16
+ }
17
+ interface ViewEngine {
18
+ render: (name: string, locals?: Record<string, any>, options?: RenderOptions) => Promise<string>;
19
+ renderString: (tpl: string, locals?: Record<string, any>, options?: RenderOptions) => Promise<string>;
20
+ }
21
+ type ViewEngineClass = new (app: Context) => ViewEngine;
22
+ /**
23
+ * ViewManager will manage all view engine that is registered.
24
+ *
25
+ * It can find the real file, then retrieve the view engine based on extension.
26
+ * The plugin just register view engine using {@link ViewManager#use}
27
+ */
28
+ declare class ViewManager extends Map<string, ViewEngineClass> {
29
+ config: ViewManagerConfig;
30
+ extMap: Map<string, string>;
31
+ fileMap: Map<string, string>;
32
+ /**
33
+ * @param {Application} app - application instance
34
+ */
35
+ constructor(app: Application);
36
+ /**
37
+ * This method can register view engine.
38
+ *
39
+ * You can define a view engine class contains two method, `render` and `renderString`
40
+ *
41
+ * ```js
42
+ * class View {
43
+ * render() {}
44
+ * renderString() {}
45
+ * }
46
+ * ```
47
+ * @param {String} name - the name of view engine
48
+ * @param {Object} viewEngine - the class of view engine
49
+ */
50
+ use(name: string, viewEngine: ViewEngineClass): void;
51
+ /**
52
+ * Resolve the path based on the given name,
53
+ * if the name is `user.html` and root is `app/view` (by default),
54
+ * it will return `app/view/user.html`
55
+ * @param {String} name - the given path name, it's relative to config.root
56
+ * @return {String} filename - the full path
57
+ */
58
+ resolve(name: string): Promise<string>;
59
+ }
60
+ //#endregion
61
+ export { PlainObject, RenderOptions, ViewEngine, ViewEngineClass, ViewManager, ViewManagerConfig };
@@ -0,0 +1,83 @@
1
+ import path from "node:path";
2
+ import assert from "node:assert";
3
+ import { existsSync } from "node:fs";
4
+ import { exists } from "utility";
5
+ import { isGeneratorFunction } from "is-type-of";
6
+
7
+ //#region src/lib/view_manager.ts
8
+ /**
9
+ * ViewManager will manage all view engine that is registered.
10
+ *
11
+ * It can find the real file, then retrieve the view engine based on extension.
12
+ * The plugin just register view engine using {@link ViewManager#use}
13
+ */
14
+ var ViewManager = class extends Map {
15
+ config;
16
+ extMap;
17
+ fileMap;
18
+ /**
19
+ * @param {Application} app - application instance
20
+ */
21
+ constructor(app) {
22
+ super();
23
+ this.config = app.config.view;
24
+ this.config.root = app.config.view.root.split(/\s*,\s*/g).filter((filepath) => existsSync(filepath));
25
+ this.extMap = /* @__PURE__ */ new Map();
26
+ this.fileMap = /* @__PURE__ */ new Map();
27
+ for (const ext of Object.keys(this.config.mapping)) this.extMap.set(ext, this.config.mapping[ext]);
28
+ }
29
+ /**
30
+ * This method can register view engine.
31
+ *
32
+ * You can define a view engine class contains two method, `render` and `renderString`
33
+ *
34
+ * ```js
35
+ * class View {
36
+ * render() {}
37
+ * renderString() {}
38
+ * }
39
+ * ```
40
+ * @param {String} name - the name of view engine
41
+ * @param {Object} viewEngine - the class of view engine
42
+ */
43
+ use(name, viewEngine) {
44
+ assert(name, "name is required");
45
+ assert(!this.has(name), `${name} has been registered`);
46
+ assert(viewEngine, "viewEngine is required");
47
+ assert(viewEngine.prototype.render, "viewEngine should implement `render` method");
48
+ assert(!isGeneratorFunction(viewEngine.prototype.render), "viewEngine `render` method should not be generator function");
49
+ assert(viewEngine.prototype.renderString, "viewEngine should implement `renderString` method");
50
+ assert(!isGeneratorFunction(viewEngine.prototype.renderString), "viewEngine `renderString` method should not be generator function");
51
+ this.set(name, viewEngine);
52
+ }
53
+ /**
54
+ * Resolve the path based on the given name,
55
+ * if the name is `user.html` and root is `app/view` (by default),
56
+ * it will return `app/view/user.html`
57
+ * @param {String} name - the given path name, it's relative to config.root
58
+ * @return {String} filename - the full path
59
+ */
60
+ async resolve(name) {
61
+ const config = this.config;
62
+ let filename = this.fileMap.get(name);
63
+ if (config.cache && filename) return filename;
64
+ filename = await resolvePath([name, name + config.defaultExtension], config.root);
65
+ assert(filename, `Can't find ${name} from ${config.root.join(",")}`);
66
+ this.fileMap.set(name, filename);
67
+ return filename;
68
+ }
69
+ };
70
+ async function resolvePath(names, root) {
71
+ for (const name of names) for (const dir of root) {
72
+ const filename = path.join(dir, name);
73
+ if (await exists(filename)) {
74
+ if (inpath(dir, filename)) return filename;
75
+ }
76
+ }
77
+ }
78
+ function inpath(parent, sub) {
79
+ return sub.indexOf(parent) > -1;
80
+ }
81
+
82
+ //#endregion
83
+ export { ViewManager };
@@ -0,0 +1,28 @@
1
+ import { ViewConfig } from "./config/config.default.js";
2
+ import { RenderOptions, ViewManager } from "./lib/view_manager.js";
3
+ import { ContextView } from "./lib/context_view.js";
4
+
5
+ //#region src/types.d.ts
6
+ declare module 'egg' {
7
+ interface EggAppConfig {
8
+ /**
9
+ * view default config
10
+ * @member Config#view
11
+ * @property {String} [root=${baseDir}/app/view] - give a path to find the file, you can specify multiple path with `,` delimiter
12
+ * @property {Boolean} [cache=true] - whether cache the file's path
13
+ * @property {String} [defaultExtension] - defaultExtension can be added automatically when there is no extension when call `ctx.render`
14
+ * @property {String} [defaultViewEngine] - set the default view engine if you don't want specify the viewEngine every request.
15
+ * @property {Object} mapping - map the file extension to view engine, such as `{ '.ejs': 'ejs' }`
16
+ */
17
+ view: ViewConfig;
18
+ }
19
+ interface Application {
20
+ get view(): ViewManager;
21
+ }
22
+ interface Context {
23
+ view: ContextView;
24
+ render(name: string, locals?: Record<string, any>, options?: RenderOptions): Promise<void>;
25
+ renderView(name: string, locals?: Record<string, any>, options?: RenderOptions): Promise<string>;
26
+ renderString(tpl: string, locals?: Record<string, any>, options?: RenderOptions): Promise<string>;
27
+ }
28
+ }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export { };