nodester 0.0.2 → 0.0.3

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.
@@ -170,7 +170,7 @@ function _withDefaultErrorProcessing(controller, opts={}) {
170
170
  }
171
171
  case('InternalValidationError'): {
172
172
  statusCode = 500;
173
- errorResponse.details = { message:'Error' };
173
+ errorResponse.details = { message: 'Error' };
174
174
  break;
175
175
  }
176
176
  default: {
@@ -181,7 +181,7 @@ function _withDefaultErrorProcessing(controller, opts={}) {
181
181
 
182
182
  // Send error response with provided status code:
183
183
  const data = {
184
- error: {
184
+ error: {
185
185
  ...errorResponse,
186
186
  code: statusCode
187
187
  },
@@ -26,19 +26,24 @@ function _parseRouteHandler(routeHandler={}) {
26
26
  }
27
27
 
28
28
  const result = {
29
+ actionName: undefined,
29
30
  before: null,
30
31
  controllerName: undefined,
31
- actionName: undefined,
32
+ providerName: undefined
32
33
  };
33
34
 
34
35
  const {
36
+ action,
35
37
  before,
36
38
 
37
39
  controller,
38
40
  controlledBy,
39
- action
41
+
42
+ provider,
43
+ providedBy,
40
44
  } = routeHandler;
41
45
 
46
+ // Controllers:
42
47
  if (!!controlledBy) {
43
48
  const parts = controlledBy.split('.');
44
49
  const controllerName = parts[0];
@@ -49,6 +54,21 @@ function _parseRouteHandler(routeHandler={}) {
49
54
  else if (!!controller) {
50
55
  result.controllerName = `${ controller }`;
51
56
  }
57
+ // Controllers\
58
+
59
+ // Providers:
60
+ else if (!!providedBy) {
61
+ const parts = providedBy.split('.');
62
+ const providerName = parts[0];
63
+ const actionName = parts[1];
64
+ result.providerName = providerName;
65
+ result.actionName = actionName;
66
+ }
67
+ else if (!!provider) {
68
+ result.providerName = `${ provider }`;
69
+ }
70
+ // Providers\
71
+
52
72
  else if (!!action) {
53
73
  result.actionName = `${ action }`;
54
74
  }
@@ -11,6 +11,7 @@ const Route = require('./route');
11
11
  // Utils:
12
12
  const { typeOf } = require('../utils/types.util');
13
13
  const { wrapRouteHandler } = require('./routes.util');
14
+ const { parseProviderFileNames } = require('./utils');
14
15
  // File system:
15
16
  const Path = require('path');
16
17
  const fs = require('fs');
@@ -34,14 +35,17 @@ module.exports = class NodesterRouter {
34
35
  * @api public
35
36
  */
36
37
  constructor(opts={}) {
38
+ // Reference to the controllers stack.
39
+ this._controllers = new Map();
40
+
37
41
  // Reference to middlewares stack.
38
42
  this._middlewares = new MiddlewareStack({ finalhandlerEnabled: !!opts.finalhandlerEnabled });
39
43
 
40
44
  // Reference to the markers stack.
41
45
  this._markers = new MarkersStack();
42
46
 
43
- // Reference to the controllers stack.
44
- this._controllers = new Map();
47
+ // Reference to the providers stack.
48
+ this._providers = new Map();
45
49
 
46
50
  this.codeFileExtensions = commonExtensions.code;
47
51
  this.paths = {};
@@ -55,29 +59,20 @@ module.exports = class NodesterRouter {
55
59
  this.codeFileExtensions = [...opts.codeFileExtensions];
56
60
  }
57
61
 
58
- // If "controllersPath" was set, cache all controllers in directory:
62
+ // If "controllersPath" was set,
63
+ // cache all controllers in directory:
59
64
  if (!!opts.controllersPath) {
60
65
  // Save path.
61
66
  this.paths.controllers = opts.controllersPath;
62
67
 
63
- const availableFileExtensions = this.codeFileExtensions;
64
68
  // Only get files, which have available file extensions:
69
+ const availableFileExtensions = this.codeFileExtensions;
65
70
  const fileNames = fs.readdirSync(this.paths.controllers);
66
- for (const fileName of fileNames) {
67
71
 
68
- const nameParts = fileName.split('.');
69
- const extension = nameParts.pop();
70
- if (availableFileExtensions.indexOf(extension) === -1) {
71
- continue;
72
- }
73
-
74
- // If the name format is <model>.<controller>,
75
- // but second part is not "controller":
76
- if (nameParts.length > 1 && nameParts[1] !== 'controller')
77
- continue;
72
+ const controllersNames = parseProviderFileNames(fileNames, availableFileExtensions, 'controller');
78
73
 
74
+ for (const { fileName, controllerName } of controllersNames) {
79
75
  const controller = require(Path.join(this.paths.controllers, fileName));
80
- const controllerName = nameParts[0];
81
76
  this.addController(controller, controllerName);
82
77
  }
83
78
  }
@@ -94,6 +89,37 @@ module.exports = class NodesterRouter {
94
89
  this.addController(controllerDefinition, controllerName);
95
90
  }
96
91
  }
92
+
93
+ // If "providersPath" was set,
94
+ // cache all providers in directory:
95
+ if (!!opts.providersPath) {
96
+ // Save path.
97
+ this.paths.providers = opts.providersPath;
98
+
99
+ // Only get files, which have available file extensions:
100
+ const availableFileExtensions = this.codeFileExtensions;
101
+ const fileNames = fs.readdirSync(this.paths.providers);
102
+
103
+ const providersNames = parseProviderFileNames(fileNames, availableFileExtensions, 'provider');
104
+
105
+ for (const { fileName, providerName } of providersNames) {
106
+ const provider = require(Path.join(this.paths.providers, fileName));
107
+ this.addProvider(provider, providerName);
108
+ }
109
+ }
110
+
111
+ // If "providers" were provided as an Object:
112
+ if (!!opts.providers) {
113
+ if (typeOf(opts.providers) !== 'Object') {
114
+ const err = new TypeError(`"providers" must be an Object.`);
115
+ throw err;
116
+ }
117
+
118
+ const entities = Object.entities(opts.providers);
119
+ for (const [providerName, providerDefinition] of entities) {
120
+ this.addProvider(providerDefinition, providerName);
121
+ }
122
+ }
97
123
  }
98
124
 
99
125
 
@@ -111,6 +137,7 @@ module.exports = class NodesterRouter {
111
137
  controller: this.addController.bind(this),
112
138
  middleware: this.addMiddleware.bind(this),
113
139
  marker: this.addMarker.bind(this),
140
+ provider: this.addProvider.bind(this),
114
141
  route: this.addRoute.bind(this),
115
142
  routes: this.addRoutes.bind(this),
116
143
  }
@@ -182,6 +209,33 @@ module.exports = class NodesterRouter {
182
209
  }
183
210
 
184
211
 
212
+ /*
213
+ * Adds new provider to the providers stack.
214
+ *
215
+ * @param {Function|Object} provider
216
+ * @param {String} providerName
217
+ *
218
+ * @api public
219
+ */
220
+ addProvider(fnOrObject, providerName=null) {
221
+ const providerType = typeOf(fnOrObject);
222
+ const name = providerName ?? fnOrObject?.name ?? fnOrObject.constructor.name;
223
+
224
+ // If provider was exported as Object:
225
+ if (providerType === 'Object') {
226
+ this._providers.set(name, fnOrObject);
227
+ }
228
+ // If provider was exported as a constructor function:
229
+ else if (providerType === 'function') {
230
+ this._providers.set(name, new fnOrObject());
231
+ }
232
+ else {
233
+ const err = new TypeError(`Please check how you exported ${ name }, it should be either Object or constructor function.`);
234
+ throw err;
235
+ }
236
+ }
237
+
238
+
185
239
  /*
186
240
  * Creates route middleware and adds it to the stack.
187
241
  *
@@ -200,8 +254,9 @@ module.exports = class NodesterRouter {
200
254
  throw err;
201
255
  }
202
256
 
203
- if (handlerType === 'Object' && !this.paths.controllers) {
204
- const err = new TypeError(`Please set "controllersPath" during Router initialization.`);
257
+ if (handlerType === 'Object' && !this.paths.controllers && !this.paths.providers) {
258
+ const msg = `Please set "controllersPath" or "providersPath" during Router initialization.`;
259
+ const err = new TypeError(msg);
205
260
  throw err;
206
261
  }
207
262
 
@@ -48,17 +48,36 @@ function _wrapRouteHandler(routeInstance, handler) {
48
48
  else {
49
49
  const parsedHandler = parseRouteHandler(handler);
50
50
 
51
- // Get provided method from controller:
52
- const controller = this._controllers.get(parsedHandler.controllerName);
53
- const controllerAction = controller[parsedHandler.actionName];
51
+ let providedAction = null;
54
52
 
55
- // If User set any middleware before, call it first:
53
+ // If Controller:
54
+ if (parsedHandler.controllerName !== undefined) {
55
+ // Get method (action) from Controller:
56
+ const controller = this._controllers.get(parsedHandler.controllerName);
57
+ const controllerAction = controller[parsedHandler.actionName];
58
+
59
+ providedAction = controllerAction;
60
+ }
61
+ // If Controller\
62
+
63
+ // If Provider:
64
+ else {
65
+ // Get method (action) from Provider:
66
+ const provider = this._providers.get(parsedHandler.providerName);
67
+ const providerAction = provider[parsedHandler.actionName];
68
+
69
+ providedAction = providerAction;
70
+ }
71
+ // If Provider\
72
+
73
+ // If User set any handler before,
74
+ // call it first:
56
75
  if (typeOf(parsedHandler.before) === 'function') {
57
76
  // Expose nquery first.
58
77
  await parsedHandler.before(req.nquery, req, res);
59
78
  }
60
79
 
61
- await controllerAction(req, res);
80
+ await providedAction(req, res);
62
81
  }
63
82
  };
64
83
 
@@ -0,0 +1,30 @@
1
+
2
+ module.exports = {
3
+ parseProviderFileNames: _parseProviderFileNames
4
+ }
5
+
6
+ function _parseProviderFileNames(fileNames, availableFileExtensions, term='controller') {
7
+ const resultNames = [];
8
+
9
+ for (const fileName of fileNames) {
10
+
11
+ const nameParts = fileName.split('.');
12
+ const extension = nameParts.pop();
13
+ if (availableFileExtensions.indexOf(extension) === -1) {
14
+ continue;
15
+ }
16
+
17
+ // If the name format is <model>.<term>,
18
+ // but second part is not "term":
19
+ if (nameParts.length > 1 && nameParts[1] !== term)
20
+ continue;
21
+
22
+ const result = {
23
+ fileName: fileName,
24
+ [`${ term }Name`]: nameParts[0]
25
+ }
26
+ resultNames.push(result);
27
+ }
28
+
29
+ return resultNames;
30
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodester",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "A boilerplate framework for Node.js",
5
5
  "exports": {
6
6
  ".": "./lib/application/index.js",