nodester 0.6.5 → 0.6.7

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/Readme.md CHANGED
@@ -1,7 +1,11 @@
1
- # nodester
1
+ <div align="center">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/MarkKhramko/nodester/refs/heads/main/.github/assets/nodester_logo.png">
4
+ <img alt="nodester logo" src="https://raw.githubusercontent.com/MarkKhramko/nodester/refs/heads/main/.github/assets/nodester_logo.png">
5
+ </picture>
6
+ </div>
2
7
 
3
- [![NPM version](https://img.shields.io/npm/v/nodester)](https://www.npmjs.com/package/nodester)
4
- [![License](https://img.shields.io/npm/l/nodester)](https://www.npmjs.com/package/nodester)
8
+ # nodester [![NPM version](https://img.shields.io/npm/v/nodester)](https://www.npmjs.com/package/nodester) [![License](https://img.shields.io/npm/l/nodester)](https://www.npmjs.com/package/nodester)
5
9
 
6
10
  > **nodester** is a Node.js framework designed to solve the problem of a complex data querying over HTTP.
7
11
 
@@ -39,10 +43,14 @@ const db = require('#db');
39
43
  const app = new nodester();
40
44
  app.set.database(db);
41
45
 
46
+ // Do any synchronous initializations
47
+ // before app.listen here
48
+ // ...
49
+
42
50
  // Optional beforeStart hook:
43
51
  app.beforeStart(async () => {
44
52
  // Do any asynchronous initializations
45
- // before app.listen
53
+ // before app.listen here
46
54
  // ...
47
55
  });
48
56
 
@@ -6,7 +6,7 @@
6
6
  'use strict';
7
7
 
8
8
  const Emitter = require('events');
9
- const NodesterRouter = require('../router');
9
+ const NodesterRouter = require('nodester/router');
10
10
 
11
11
  // Server:
12
12
  const http = require('http');
@@ -1,3 +1,10 @@
1
+ /**
2
+ * nodester
3
+ * MIT Licensed
4
+ */
5
+
6
+ 'use strict';
7
+
1
8
  const Enum = require('nodester/enum');
2
9
 
3
10
  const limit = {
@@ -1,3 +1,10 @@
1
+ /**
2
+ * nodester
3
+ * MIT Licensed
4
+ */
5
+
6
+ 'use strict';
7
+
1
8
  const Enum = require('nodester/enum');
2
9
 
3
10
  const LIMIT = 'limit';
@@ -1,3 +1,10 @@
1
+ /**
2
+ * nodester
3
+ * MIT Licensed
4
+ */
5
+
6
+ 'use strict';
7
+
1
8
  const Enum = require('nodester/enum');
2
9
 
3
10
  const NODESTER_QUERY_ERROR = 'NodesterQueryError';
@@ -0,0 +1,44 @@
1
+ /**
2
+ * nodester
3
+ * MIT Licensed
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ // JS:
9
+ const jsCodeExtensions = [
10
+ 'js', // built-in
11
+ 'cjs', // https://nodejs.org/api/esm.html#esm_enabling
12
+ 'mjs', // https://nodejs.org/api/esm.html#esm_enabling
13
+ 'iced', // http://maxtaco.github.io/coffee-script/
14
+ 'liticed', // http://maxtaco.github.io/coffee-script/ (literate iced)
15
+ 'iced.md', // http://maxtaco.github.io/coffee-script/ (literate iced)
16
+ 'coffee', // http://coffeescript.org/
17
+ 'litcoffee', // http://coffeescript.org/ (literate coffee)
18
+ 'coffee.md', // http://coffeescript.org/ (literate coffee)
19
+ 'ts', // https://www.typescriptlang.org/
20
+ 'tsx', // https://www.typescriptlang.org/docs/handbook/jsx.html
21
+ 'cs', // http://bridge.net/ ??
22
+ 'ls', // http://livescript.net/
23
+ 'es6', // https://babeljs.io
24
+ 'es', // https://babeljs.io
25
+ 'jsx', // https://babeljs.io https://facebook.github.io/jsx/.
26
+ 'sjs', // http://onilabs.com/stratifiedjs
27
+ 'co', // http://satyr.github.io/coco/
28
+ 'eg' // http://www.earl-grey.io/
29
+ ];
30
+
31
+ const jsConfigExtensions = [
32
+ 'json', // built-in
33
+ 'json.ls', // http://livescript.net/
34
+ 'json5' // http://json5.org/
35
+ ];
36
+ // JS\
37
+
38
+
39
+ module.exports = {
40
+ js: {
41
+ code: jsCodeExtensions,
42
+ config: jsConfigExtensions
43
+ }
44
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * nodester
3
+ * MIT Licensed
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const Enum = require('nodester/enum');
9
+
10
+
11
+ module.exports = new Enum({
12
+ and: Symbol.for('and'),
13
+ between: Symbol.for('between'),
14
+ contains: Symbol.for('contains'),
15
+ eq: Symbol.for('eq'),
16
+ ne: Symbol.for('ne'),
17
+ gte: Symbol.for('gte'),
18
+ gt: Symbol.for('gt'),
19
+ lte: Symbol.for('lte'),
20
+ lt: Symbol.for('lt'),
21
+ not: Symbol.for('not'),
22
+ is: Symbol.for('is'),
23
+ in: Symbol.for('in'),
24
+ notIn: Symbol.for('notIn'),
25
+ like: Symbol.for('like'),
26
+ notLike: Symbol.for('notLike'),
27
+ notBetween: Symbol.for('notBetween'),
28
+ or: Symbol.for('or'),
29
+ xor: Symbol.for('xor'),
30
+ });
@@ -1,3 +1,10 @@
1
+ /**
2
+ * nodester
3
+ * MIT Licensed
4
+ */
5
+
6
+ 'use strict';
7
+
1
8
  const Enum = require('nodester/enum');
2
9
 
3
10
 
@@ -2,6 +2,7 @@
2
2
  * nodester
3
3
  * MIT Licensed
4
4
  */
5
+
5
6
  'use strict';
6
7
 
7
8
  const Enum = require('nodester/enum');
@@ -0,0 +1,29 @@
1
+ /**
2
+ * nodester
3
+ * MIT Licensed
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const Enum = require('nodester/enum');
9
+
10
+
11
+ module.exports = new Enum({
12
+ // Core REST methods:
13
+ GET: 'GET',
14
+ POST: 'POST',
15
+ PUT: 'PUT',
16
+ PATCH: 'PATCH',
17
+ DELETE: 'DELETE',
18
+ // Additional but common in REST APIs:
19
+ HEAD: 'HEAD',
20
+ OPTIONS: 'OPTIONS',
21
+
22
+ // Search and non-standard querying:
23
+ SEARCH: 'SEARCH',
24
+ QUERY: 'QUERY',
25
+
26
+ // Rarely used in REST but valid HTTP:
27
+ TRACE: 'TRACE',
28
+ CONNECT: 'CONNECT',
29
+ });
@@ -0,0 +1,38 @@
1
+ /**
2
+ * nodester
3
+ * MIT Licensed
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const {
9
+ HTTP_CODE_NOT_FOUND
10
+ } = require('nodester/http/codes');
11
+
12
+ const { createErrorResponse } = require('nodester/factories/responses/rest');
13
+
14
+
15
+ /**
16
+ * Initialize `404` middleware.
17
+ *
18
+ * @param {Object} [options]
19
+ *
20
+ * @return {Function}
21
+ *
22
+ * @access public
23
+ */
24
+ module.exports = function init404Middleware(options={}) {
25
+ const context = {
26
+ options
27
+ }
28
+ return handle.bind(context);
29
+ }
30
+
31
+ function handle(req, res, next) {
32
+ const err = new Error('Route not found');
33
+
34
+ return createErrorResponse(res, {
35
+ error: err,
36
+ status: HTTP_CODE_NOT_FOUND
37
+ });
38
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * nodester
3
+ * MIT Licensed
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const calculate = require('etag');
9
+ const Stream = require('stream');
10
+
11
+ // Utils:
12
+ const promisify = require('util').promisify;
13
+ const fs = require('fs');
14
+ const getFileStats = promisify(fs.stat);
15
+
16
+
17
+ module.exports = initETagMiddleware;
18
+
19
+ /**
20
+ * Initialize `etag` middleware.
21
+ *
22
+ * @param {Object} [options]
23
+ * @param {boolean} options.weak
24
+ *
25
+ * @return {Function}
26
+ *
27
+ * @access public
28
+ */
29
+ function initETagMiddleware(options) {
30
+ const context = {
31
+ options
32
+ }
33
+ return handle.bind(context);
34
+ }
35
+
36
+ /**
37
+ * Add ETag header field.
38
+ */
39
+ function handle(req, res, next) {
40
+ // console.log('e', req.headers);
41
+ return next();
42
+ }
43
+
44
+ async function _getResponseEntity(res) {
45
+ // If body is not defined:
46
+ const { body } = res;
47
+ if (!body || res.get('etag'))
48
+ return;
49
+
50
+ // Status code.
51
+ const status = res.statusCode / 100 | 0;
52
+
53
+ console.log('getResponseEntity', status, { tag: res.get('etag') });
54
+
55
+ // 2xx
56
+ if (status !== 2)
57
+ return;
58
+
59
+ if (body instanceof Stream) {
60
+ if (!body.path)
61
+ return;
62
+
63
+ const stats = await getFileStats(body.path);
64
+ return stats;
65
+ }
66
+ else if (typeof body === 'string' || Buffer.isBuffer(body)) {
67
+ return body;
68
+ }
69
+ else {
70
+ return JSON.stringify(body);
71
+ }
72
+ }
73
+
74
+ function _setEtag(res, entity, options) {
75
+ console.log('setEtag', typeof res, entity);
76
+
77
+ if (!entity)
78
+ return;
79
+
80
+ res.etag = calculate(entity, options);
81
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * nodester
3
+ * MIT Licensed
4
+ */
5
+
6
+ 'use strict';
7
+
8
+
9
+ module.exports = function initRenderMiddleware() {
10
+ return handle;
11
+ }
12
+
13
+
14
+ function handle(req, res, next) {
15
+ const context = { req, res, next };
16
+ res.render = _render.bind(context);
17
+ next();
18
+ }
19
+
20
+
21
+ /**
22
+ * Render `view` with the given `options` and optional callback `fn`.
23
+ * When a callback function is given a response will _not_ be made
24
+ * automatically, otherwise a response of _200_ and _text/html_ is given.
25
+ *
26
+ * Options:
27
+ *
28
+ * - `cache` boolean hinting to the engine it should cache
29
+ * - `filename` filename of the view being rendered
30
+ *
31
+ * @alias render
32
+ * @access public
33
+ */
34
+ function _render(view, options, callback) {
35
+ const app = this.req.app;
36
+ let done = callback;
37
+ let opts = options || {};
38
+
39
+ const req = this.req;
40
+ const res = this.res;
41
+ const next = this.next;
42
+
43
+ // support callback function as second arg
44
+ if (typeof options === 'function') {
45
+ done = options;
46
+ opts = {};
47
+ }
48
+
49
+ // merge res.locals
50
+ opts._locals = res.locals;
51
+
52
+ // default callback to respond
53
+ done = done || function (err, str) {
54
+ if (err)
55
+ return next(err);
56
+
57
+ res.send(str);
58
+ };
59
+
60
+ // render
61
+ app.render(view, opts, done);
62
+ };
@@ -5,6 +5,9 @@
5
5
 
6
6
  'use strict';
7
7
 
8
+ // Constants.
9
+ const FileExtensions = require('nodester/constants/FileExtensions');
10
+
8
11
  const MiddlewaresStack = require('nodester/stacks/middlewares');
9
12
  const Route = require('./route');
10
13
 
@@ -22,7 +25,6 @@ const { parseProviderFileNames } = require('./utils');
22
25
  // File system:
23
26
  const Path = require('path');
24
27
  const fs = require('fs');
25
- const commonExtensions = require('common-js-file-extensions');
26
28
 
27
29
  // Arguments validator.
28
30
  const { ensure } = require('nodester/validators/arguments');
@@ -59,7 +61,7 @@ module.exports = class NodesterRouter {
59
61
  // Reference to the providers stack.
60
62
  this._providers = new Map();
61
63
 
62
- this.codeFileExtensions = commonExtensions.code;
64
+ this.codeFileExtensions = FileExtensions.js.code;
63
65
  this.paths = {};
64
66
 
65
67
  // Options:
@@ -5,6 +5,8 @@
5
5
 
6
6
  'use strict';
7
7
 
8
+ const HTTP_METHODS = require('nodester/http/methods');
9
+
8
10
  const MiddlewaresStack = require('nodester/stacks/middlewares');
9
11
 
10
12
  // Utils:
@@ -20,7 +22,7 @@ module.exports = {
20
22
 
21
23
  function _validateParsedRouteMethood(parsedRoute) {
22
24
  if (!parsedRoute || parsedRoute?.method === undefined) {
23
- const err = new TypeError(`"route" should start with one of the following methods: [GET, POST, PUT, DELETE, QUERY, HEADER, OPTIONS]`);
25
+ const err = new TypeError(`Route definition must start with one of the following methods: ${ HTTP_METHODS.asArray.join(', ') } or any other custom one.`);
24
26
  throw err;
25
27
  }
26
28
 
@@ -52,7 +54,16 @@ function _wrapRouteHandler(routeInstance, handler) {
52
54
  if (parsedHandler.controllerName !== undefined) {
53
55
  // Get method (action) from Controller:
54
56
  const controller = this._controllers.get(parsedHandler.controllerName);
57
+ if (!controller) {
58
+ const err = new TypeError(`Controller named "${ parsedHandler.controllerName }" is not defined.`);
59
+ throw err;
60
+ }
61
+
55
62
  const controllerAction = controller[parsedHandler.actionName];
63
+ if (!controllerAction) {
64
+ const err = new TypeError(`Handler "${ parsedHandler.actionName }" is not defined in controller "${ parsedHandler.controllerName }".`);
65
+ throw err;
66
+ }
56
67
 
57
68
  providedAction = controllerAction;
58
69
  }
@@ -62,7 +73,16 @@ function _wrapRouteHandler(routeInstance, handler) {
62
73
  else {
63
74
  // Get method (action) from Provider:
64
75
  const provider = this._providers.get(parsedHandler.providerName);
76
+ if (!provider) {
77
+ const err = new TypeError(`Provider named "${ parsedHandler.providerName }" is not defined.`);
78
+ throw err;
79
+ }
80
+
65
81
  const providerAction = provider[parsedHandler.actionName];
82
+ if (!providerAction) {
83
+ const err = new TypeError(`Handler "${ parsedHandler.actionName }" is not defined in provider "${ parsedHandler.providerName }".`);
84
+ throw err;
85
+ }
66
86
 
67
87
  providedAction = providerAction;
68
88
  }
@@ -10,7 +10,7 @@ module.exports = {
10
10
  parseProviderFileNames: _parseProviderFileNames
11
11
  }
12
12
 
13
- function _parseProviderFileNames(fileNames, availableFileExtensions, term='controller') {
13
+ function _parseProviderFileNames(fileNames=[], availableFileExtensions=[], term='controller') {
14
14
  const resultNames = [];
15
15
 
16
16
  for (const fileName of fileNames) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodester",
3
- "version": "0.6.5",
3
+ "version": "0.6.7",
4
4
  "description": "A versatile REST framework for Node.js",
5
5
  "directories": {
6
6
  "docs": "docs",
@@ -16,6 +16,7 @@
16
16
  "./body/extract": "./lib/body/extract.js",
17
17
 
18
18
  "./constants/ErrorCodes": "./lib/constants/ErrorCodes.js",
19
+ "./constants/FileExtensions": "./lib/constants/FileExtensions.js",
19
20
 
20
21
  "./controllers/methods": "./lib/controllers/methods/index.js",
21
22
  "./controllers/mixins": "./lib/controllers/mixins/index.js",
@@ -42,6 +43,7 @@
42
43
  "./http/codes": "./lib/http/codes/index.js",
43
44
  "./http/codes/descriptions": "./lib/http/codes/descriptions.js",
44
45
  "./http/codes/symbols": "./lib/http/codes/symbols.js",
46
+ "./http/methods": "./lib/http/methods/index.js",
45
47
 
46
48
  "./loggers/console": "./lib/loggers/console.js",
47
49
  "./loggers/dev": "./lib/loggers/dev.js",
@@ -78,7 +80,6 @@
78
80
  "dependencies": {
79
81
  "@js-temporal/polyfill": "^0.4.3",
80
82
  "body-parser": "^1.20.2",
81
- "common-js-file-extensions": "^1.0.4",
82
83
  "cookie": "^1.0.0",
83
84
  "cookie-signature": "^1.2.0",
84
85
  "debug": "^4.3.4",
@@ -89,8 +90,8 @@
89
90
  "http-errors": "^2.0.0",
90
91
  "inflection": "^2.0.1",
91
92
  "mime": "^3.0.0",
92
- "mysql2": "^3.6.0",
93
- "pg": "^8.11.3",
93
+ "mysql2": "^3.14.4",
94
+ "pg": "^8.16.3",
94
95
  "pg-hstore": "^2.3.4",
95
96
  "qs": "^6.11.0",
96
97
  "sequelize": "^6.6.5"
package/tests/ast.js ADDED
@@ -0,0 +1,18 @@
1
+ const { ModelsTree } = require('../lib/middlewares/ql/sequelize/interpreter/ModelsTree');
2
+ const { AST_ModelsTree } = require('../lib/tools/nql.tool');
3
+
4
+ const tree = new ModelsTree();
5
+ tree.node.addWhere({ id: ['1000'] });
6
+ tree.include('comments').use('comments');
7
+ tree.node.order = 'desc';
8
+ tree.up();
9
+ tree.include('users');
10
+ tree.include('likes') && tree.use('likes');
11
+ tree.node.order = 'rand';
12
+ tree.up();
13
+ tree.include('reposts');
14
+
15
+ console.debug(
16
+ AST_ModelsTree(tree)
17
+ );
18
+
@@ -9,14 +9,13 @@ const {
9
9
  // Configs.
10
10
  const PORT = 8100;
11
11
 
12
- // Our lib.
13
- const Nodester = require('../lib/application');
12
+ const nodester = require('nodester');
14
13
 
15
14
 
16
15
  describe('nodester application', () => {
17
16
 
18
17
  // Init.
19
- const app = new Nodester();
18
+ const app = new nodester();
20
19
  it('construct', () => {
21
20
  expect(app).toBeDefined();
22
21
  });