@eggjs/view 3.0.1 → 4.0.0-beta.17

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
@@ -1,25 +0,0 @@
1
- import { EggCore } from '@eggjs/core';
2
- import { ViewManager } from '../../lib/view_manager.js';
3
-
4
- const VIEW = Symbol('Application#view');
5
-
6
- export default class Application extends EggCore {
7
- [VIEW]: ViewManager;
8
-
9
- /**
10
- * Retrieve ViewManager instance
11
- * @member {ViewManager} Application#view
12
- */
13
- get view(): ViewManager {
14
- if (!this[VIEW]) {
15
- this[VIEW] = new ViewManager(this);
16
- }
17
- return this[VIEW];
18
- }
19
- }
20
-
21
- declare module '@eggjs/core' {
22
- interface EggCore {
23
- get view(): ViewManager;
24
- }
25
- }
@@ -1,66 +0,0 @@
1
- import { Context } from '@eggjs/core';
2
- import { ContextView } from '../../lib/context_view.js';
3
- import { RenderOptions } from '../../lib/view_manager.js';
4
-
5
- const VIEW = Symbol('Context#view');
6
-
7
- export default class ViewContext extends Context {
8
- [VIEW]: ContextView;
9
-
10
- /**
11
- * Render a file by view engine, then set to body
12
- * @param {String} name - the file path based on root
13
- * @param {Object} [locals] - data used by template
14
- * @param {Object} [options] - view options, you can use `options.viewEngine` to specify view engine
15
- */
16
- async render(name: string, locals?: Record<string, any>, options?: RenderOptions): Promise<void> {
17
- const body = await this.renderView(name, locals, options);
18
- this.body = body;
19
- }
20
-
21
- /**
22
- * Render a file by view engine and return it
23
- * @param {String} name - the file path based on root
24
- * @param {Object} [locals] - data used by template
25
- * @param {Object} [options] - view options, you can use `options.viewEngine` to specify view engine
26
- * @return {Promise<String>} result - return a promise with a render result
27
- */
28
- async renderView(
29
- name: string,
30
- locals?: Record<string, any>,
31
- options?: RenderOptions,
32
- ): Promise<string> {
33
- return await this.view.render(name, locals, options);
34
- }
35
-
36
- /**
37
- * Render template string by view engine and return it
38
- * @param {String} tpl - template string
39
- * @param {Object} [locals] - data used by template
40
- * @param {Object} [options] - view options, you can use `options.viewEngine` to specify view engine
41
- * @return {Promise<String>} result - return a promise with a render result
42
- */
43
- async renderString(tpl: string, locals?: Record<string, any>, options?: RenderOptions): Promise<string> {
44
- return await this.view.renderString(tpl, locals, options);
45
- }
46
-
47
- /**
48
- * View instance that is created every request
49
- * @member {ContextView} Context#view
50
- */
51
- get view() {
52
- if (!this[VIEW]) {
53
- this[VIEW] = new ContextView(this);
54
- }
55
- return this[VIEW];
56
- }
57
- }
58
-
59
- declare module '@eggjs/core' {
60
- interface Context {
61
- view: ContextView;
62
- render(name: string, locals?: Record<string, any>, options?: RenderOptions): Promise<void>;
63
- renderView(name: string, locals?: Record<string, any>, options?: RenderOptions): Promise<string>;
64
- renderString(tpl: string, locals?: Record<string, any>, options?: RenderOptions): Promise<string>;
65
- }
66
- }
@@ -1,56 +0,0 @@
1
- import path from 'node:path';
2
- import type { EggAppInfo } from '@eggjs/core';
3
-
4
- /**
5
- * view default config
6
- * @member Config#view
7
- * @property {String} [root=${baseDir}/app/view] - give a path to find the file, you can specify multiple path with `,` delimiter
8
- * @property {Boolean} [cache=true] - whether cache the file's path
9
- * @property {String} [defaultExtension] - defaultExtension can be added automatically when there is no extension when call `ctx.render`
10
- * @property {String} [defaultViewEngine] - set the default view engine if you don't want specify the viewEngine every request.
11
- * @property {Object} mapping - map the file extension to view engine, such as `{ '.ejs': 'ejs' }`
12
- */
13
- export interface ViewConfig {
14
- /**
15
- * give a path to find the file, you can specify multiple path with `,` delimiter
16
- * Default is `${baseDir}/app/view`
17
- */
18
- root: string;
19
- /**
20
- * whether cache the file's path
21
- * Default is `true`
22
- */
23
- cache: boolean;
24
- /**
25
- * defaultExtension can be added automatically when there is no extension when call `ctx.render`
26
- * Default is `.html`
27
- */
28
- defaultExtension: string;
29
- /**
30
- * set the default view engine if you don't want specify the viewEngine every request.
31
- * Default is `''`
32
- */
33
- defaultViewEngine: string;
34
- /**
35
- * map the file extension to view engine, such as `{ '.ejs': 'ejs' }`
36
- * Default is `{}`
37
- */
38
- mapping: Record<string, string>;
39
- }
40
-
41
- export default (appInfo: EggAppInfo) => ({
42
- view: {
43
- root: path.join(appInfo.baseDir, 'app/view'),
44
- cache: true,
45
- defaultExtension: '.html',
46
- defaultViewEngine: '',
47
- mapping: {},
48
- },
49
- });
50
-
51
- declare module '@eggjs/core' {
52
- // add EggAppConfig overrides types
53
- interface EggAppConfig {
54
- view: ViewConfig;
55
- }
56
- }
@@ -1,7 +0,0 @@
1
- import type { EggAppConfig } from '@eggjs/core';
2
-
3
- export default {
4
- view: {
5
- cache: false,
6
- },
7
- } as EggAppConfig;
package/src/index.ts DELETED
@@ -1,3 +0,0 @@
1
- import './config/config.default.js';
2
- import './app/extend/application.js';
3
- import './app/extend/context.js';
@@ -1,111 +0,0 @@
1
- import path from 'node:path';
2
- import assert from 'node:assert';
3
- import type { Context, EggCore } from '@eggjs/core';
4
- import { ViewManager, type ViewManagerConfig, type RenderOptions } from './view_manager.js';
5
-
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
- /**
12
- * View instance for each request.
13
- *
14
- * It will find the view engine, and render it.
15
- * The view engine should be registered in {@link ViewManager}.
16
- */
17
- export class ContextView {
18
- protected ctx: Context;
19
- protected app: EggCore;
20
- protected viewManager: ViewManager;
21
- protected config: ViewManagerConfig;
22
-
23
- constructor(ctx: Context) {
24
- this.ctx = ctx;
25
- this.app = this.ctx.app;
26
- this.viewManager = this.app.view;
27
- this.config = this.app.view.config;
28
- }
29
-
30
- /**
31
- * Render a file by view engine
32
- * @param {String} name - the file path based on root
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
- async render(name: string, locals?: Record<string, any>, options?: RenderOptions): Promise<string> {
38
- return await this[RENDER](name, locals, options);
39
- }
40
-
41
- /**
42
- * Render a template string by view engine
43
- * @param {String} tpl - template string
44
- * @param {Object} [locals] - data used by template
45
- * @param {Object} [options] - view options, you can use `options.viewEngine` to specify view engine
46
- * @return {Promise<String>} result - return a promise with a render result
47
- */
48
- async renderString(tpl: string, locals?: Record<string, any>, options?: RenderOptions): Promise<string> {
49
- return await this[RENDER_STRING](tpl, locals, options);
50
- }
51
-
52
- // ext -> viewEngineName -> viewEngine
53
- async [RENDER](name: string, locals?: Record<string, any>, options: RenderOptions = {}) {
54
- // retrieve fullpath matching name from `config.root`
55
- const filename = await this.viewManager.resolve(name);
56
- options.name = name;
57
- options.root = filename.replace(path.normalize(name), '').replace(/[\/\\]$/, '');
58
- options.locals = locals;
59
-
60
- // get the name of view engine,
61
- // if viewEngine is specified in options, don't match extension
62
- let viewEngineName = options.viewEngine;
63
- if (!viewEngineName) {
64
- const ext = path.extname(filename);
65
- viewEngineName = this.viewManager.extMap.get(ext);
66
- }
67
- // use the default view engine that is configured if no matching above
68
- if (!viewEngineName) {
69
- viewEngineName = this.config.defaultViewEngine;
70
- }
71
- assert(viewEngineName, `Can't find viewEngine for ${filename}`);
72
-
73
- // get view engine and render
74
- const viewEngine = this[GET_VIEW_ENGINE](viewEngineName);
75
- return await viewEngine.render(filename, this[SET_LOCALS](locals), options);
76
- }
77
-
78
- async [RENDER_STRING](tpl: string, locals?: Record<string, any>, options?: RenderOptions) {
79
- let viewEngineName = options && options.viewEngine;
80
- if (!viewEngineName) {
81
- viewEngineName = this.config.defaultViewEngine;
82
- }
83
- assert(viewEngineName, 'Can\'t find viewEngine');
84
-
85
- // get view engine and render
86
- const viewEngine = this[GET_VIEW_ENGINE](viewEngineName);
87
- return await viewEngine.renderString(tpl, this[SET_LOCALS](locals), options);
88
- }
89
-
90
- [GET_VIEW_ENGINE](name: string) {
91
- // get view engine
92
- const ViewEngine = this.viewManager.get(name);
93
- assert(ViewEngine, `Can't find ViewEngine "${name}"`);
94
-
95
- // use view engine to render
96
- const engine = new ViewEngine(this.ctx);
97
- return engine;
98
- }
99
-
100
- /**
101
- * set locals for view, inject `locals.ctx`, `locals.request`, `locals.helper`
102
- * @private
103
- */
104
- [SET_LOCALS](locals?: Record<string, any>) {
105
- return Object.assign({
106
- ctx: this.ctx,
107
- request: this.ctx.request,
108
- helper: this.ctx.helper,
109
- }, this.ctx.locals, locals);
110
- }
111
- }
@@ -1,122 +0,0 @@
1
- import assert from 'node:assert';
2
- import path from 'node:path';
3
- import { existsSync } from 'node:fs';
4
- import { exists } from 'utility';
5
- import type { Context, EggCore } from '@eggjs/core';
6
- import { isGeneratorFunction } from 'is-type-of';
7
- import type { ViewConfig } from '../config/config.default.js';
8
-
9
- export interface ViewManagerConfig extends Omit<ViewConfig, 'root'> {
10
- root: string[];
11
- }
12
-
13
- export type PlainObject<T = any> = { [key: string]: T };
14
-
15
- export interface RenderOptions extends PlainObject {
16
- name?: string;
17
- root?: string;
18
- locals?: PlainObject;
19
- viewEngine?: string;
20
- }
21
-
22
- export interface ViewEngine {
23
- render: (name: string, locals?: Record<string, any>, options?: RenderOptions) => Promise<string>;
24
- renderString: (tpl: string, locals?: Record<string, any>, options?: RenderOptions) => Promise<string>;
25
- }
26
-
27
- export type ViewEngineClass = new (app: Context) => ViewEngine;
28
-
29
- /**
30
- * ViewManager will manage all view engine that is registered.
31
- *
32
- * It can find the real file, then retrieve the view engine based on extension.
33
- * The plugin just register view engine using {@link ViewManager#use}
34
- */
35
- export class ViewManager extends Map<string, ViewEngineClass> {
36
- config: ViewManagerConfig;
37
- extMap: Map<string, string>;
38
- fileMap: Map<string, string>;
39
-
40
- /**
41
- * @param {Application} app - application instance
42
- */
43
- constructor(app: EggCore) {
44
- super();
45
- this.config = app.config.view as any;
46
- this.config.root = app.config.view.root
47
- .split(/\s*,\s*/g)
48
- .filter(filepath => existsSync(filepath));
49
- this.extMap = new Map();
50
- this.fileMap = new Map();
51
- for (const ext of Object.keys(this.config.mapping)) {
52
- this.extMap.set(ext, this.config.mapping[ext]);
53
- }
54
- }
55
-
56
- /**
57
- * This method can register view engine.
58
- *
59
- * You can define a view engine class contains two method, `render` and `renderString`
60
- *
61
- * ```js
62
- * class View {
63
- * render() {}
64
- * renderString() {}
65
- * }
66
- * ```
67
- * @param {String} name - the name of view engine
68
- * @param {Object} viewEngine - the class of view engine
69
- */
70
- use(name: string, viewEngine: ViewEngineClass) {
71
- assert(name, 'name is required');
72
- assert(!this.has(name), `${name} has been registered`);
73
-
74
- assert(viewEngine, 'viewEngine is required');
75
- assert(viewEngine.prototype.render, 'viewEngine should implement `render` method');
76
- assert(!isGeneratorFunction(viewEngine.prototype.render), 'viewEngine `render` method should not be generator function');
77
- assert(viewEngine.prototype.renderString, 'viewEngine should implement `renderString` method');
78
- assert(!isGeneratorFunction(viewEngine.prototype.renderString), 'viewEngine `renderString` method should not be generator function');
79
-
80
- this.set(name, viewEngine);
81
- }
82
-
83
- /**
84
- * Resolve the path based on the given name,
85
- * if the name is `user.html` and root is `app/view` (by default),
86
- * it will return `app/view/user.html`
87
- * @param {String} name - the given path name, it's relative to config.root
88
- * @return {String} filename - the full path
89
- */
90
- async resolve(name: string): Promise<string> {
91
- const config = this.config;
92
-
93
- // check cache
94
- let filename = this.fileMap.get(name);
95
- if (config.cache && filename) return filename;
96
-
97
- // try find it with default extension
98
- filename = await resolvePath([ name, name + config.defaultExtension ], config.root);
99
- assert(filename, `Can't find ${name} from ${config.root.join(',')}`);
100
-
101
- // set cache
102
- this.fileMap.set(name, filename);
103
- return filename;
104
- }
105
- }
106
-
107
- async function resolvePath(names: string[], root: string[]) {
108
- for (const name of names) {
109
- for (const dir of root) {
110
- const filename = path.join(dir, name);
111
- if (await exists(filename)) {
112
- if (inpath(dir, filename)) {
113
- return filename;
114
- }
115
- }
116
- }
117
- }
118
- }
119
-
120
- function inpath(parent: string, sub: string) {
121
- return sub.indexOf(parent) > -1;
122
- }
@@ -1,4 +0,0 @@
1
- // make sure to import egg typings and let typescript know about it
2
- // @see https://github.com/whxaxes/blog/issues/11
3
- // and https://www.typescriptlang.org/docs/handbook/declaration-merging.html
4
- import 'egg';