nodester 0.0.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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/Readme.md +125 -0
  3. package/docs/App.md +13 -0
  4. package/docs/Queries.md +61 -0
  5. package/docs/Readme.md +2 -0
  6. package/docs/Routing.md +34 -0
  7. package/examples/goal/index.js +23 -0
  8. package/examples/rest/index.js +25 -0
  9. package/examples/rest/node_modules/.package-lock.json +40 -0
  10. package/examples/rest/package-lock.json +72 -0
  11. package/examples/rest/package.json +14 -0
  12. package/lib/application/MiddlewareStack.js +125 -0
  13. package/lib/application/http/request.js +462 -0
  14. package/lib/application/http/response.js +1107 -0
  15. package/lib/application/http/utils.js +254 -0
  16. package/lib/application/index.js +292 -0
  17. package/lib/constants/ConstantsEnum.js +13 -0
  18. package/lib/constants/ResponseFormats.js +7 -0
  19. package/lib/controllers/Controller.js +474 -0
  20. package/lib/controllers/JWTController.js +240 -0
  21. package/lib/controllers/ServiceController.js +109 -0
  22. package/lib/controllers/WebController.js +75 -0
  23. package/lib/facades/Facade.js +388 -0
  24. package/lib/facades/FacadeParams.js +11 -0
  25. package/lib/facades/ServiceFacade.js +17 -0
  26. package/lib/facades/jwt.facade.js +273 -0
  27. package/lib/factories/errors/CustomError.js +22 -0
  28. package/lib/factories/errors/index.js +9 -0
  29. package/lib/factories/responses/api.js +90 -0
  30. package/lib/factories/responses/html.js +55 -0
  31. package/lib/logger/console.js +24 -0
  32. package/lib/models/DisabledRefreshToken.js +68 -0
  33. package/lib/models/Extractor.js +320 -0
  34. package/lib/models/define.js +62 -0
  35. package/lib/models/mixins.js +369 -0
  36. package/lib/policies/Role.js +77 -0
  37. package/lib/policies/RoleExtracting.js +97 -0
  38. package/lib/preprocessors/BodyPreprocessor.js +61 -0
  39. package/lib/preprocessors/IncludesPreprocessor.js +55 -0
  40. package/lib/preprocessors/QueryPreprocessor.js +64 -0
  41. package/lib/routers/Default/index.js +143 -0
  42. package/lib/routers/Default/layer.js +50 -0
  43. package/lib/routers/Main/index.js +10 -0
  44. package/lib/routers/Roles/index.js +81 -0
  45. package/lib/services/includes.service.js +79 -0
  46. package/lib/services/jwt.service.js +147 -0
  47. package/lib/tools/sql.tool.js +82 -0
  48. package/lib/utils/dates.util.js +23 -0
  49. package/lib/utils/forms.util.js +22 -0
  50. package/lib/utils/json.util.js +49 -0
  51. package/lib/utils/mappers/Routes/index.js +100 -0
  52. package/lib/utils/mappers/Routes/utils.js +20 -0
  53. package/lib/utils/modelAssociations.util.js +44 -0
  54. package/lib/utils/objects.util.js +69 -0
  55. package/lib/utils/params.util.js +19 -0
  56. package/lib/utils/path.util.js +26 -0
  57. package/lib/utils/queries.util.js +240 -0
  58. package/lib/utils/sanitizations.util.js +111 -0
  59. package/lib/utils/sql.util.js +78 -0
  60. package/lib/utils/strings.util.js +43 -0
  61. package/lib/utils/types.util.js +26 -0
  62. package/package.json +63 -0
  63. package/tests/index.test.js +35 -0
@@ -0,0 +1,49 @@
1
+ /*!
2
+ * /nodester
3
+ * MIT Licensed
4
+ */
5
+ 'use strict';
6
+
7
+
8
+ exports = module.exports = {
9
+ stringify: _stringify
10
+ }
11
+
12
+ /**
13
+ * Stringify JSON, like JSON.stringify, but v8 optimized, with the
14
+ * ability to escape characters that can trigger HTML sniffing.
15
+ *
16
+ * @param {*} value
17
+ * @param {function} replacer
18
+ * @param {number} spaces
19
+ * @param {boolean} escape
20
+ * @returns {string}
21
+ *
22
+ * @alias stringify
23
+ * @private
24
+ */
25
+ function _stringify (value, replacer, spaces, escape) {
26
+ // v8 checks arguments.length for optimizing simple call
27
+ // https://bugs.chromium.org/p/v8/issues/detail?id=4730
28
+ var json = replacer || spaces
29
+ ? JSON.stringify(value, replacer, spaces)
30
+ : JSON.stringify(value);
31
+
32
+ if (escape && typeof json === 'string') {
33
+ json = json.replace(/[<>&]/g, function (c) {
34
+ switch (c.charCodeAt(0)) {
35
+ case 0x3c:
36
+ return '\\u003c'
37
+ case 0x3e:
38
+ return '\\u003e'
39
+ case 0x26:
40
+ return '\\u0026'
41
+ /* istanbul ignore next: unreachable default */
42
+ default:
43
+ return c
44
+ }
45
+ })
46
+ }
47
+
48
+ return json
49
+ }
@@ -0,0 +1,100 @@
1
+ const express = require('express');
2
+ const path = require('path');
3
+
4
+ const cwd = process.cwd();
5
+
6
+ // Utils:
7
+ const { isString } = require('util');
8
+ const {
9
+ isConstructor,
10
+ splitByLastDot
11
+ } = require('./utils');
12
+
13
+
14
+ module.exports = function RoutesMapper(
15
+ routes,
16
+ pathToController,
17
+ middlewareGenerals = []
18
+ ) {
19
+ const router = express.Router();
20
+
21
+ let requestMethodPath;
22
+ let requestMethod;
23
+
24
+ let controllerMethod;
25
+ let controller;
26
+ let contr;
27
+
28
+ let handler;
29
+
30
+ let myPath;
31
+ const myPathToController = path.join(cwd, pathToController);
32
+
33
+ Object.entries(routes).forEach((value) => {
34
+ let middlewares;
35
+ // To let use an array or only one function as general middlewares:
36
+ if (Array.isArray(middlewareGenerals)) {
37
+ middlewares = [ ...middlewareGenerals ];
38
+ }
39
+ else if (typeof middlewareGenerals === 'function') {
40
+ middlewares = [ middlewareGenerals ];
41
+ }
42
+ else {
43
+ middlewares = [];
44
+ }
45
+ requestMethodPath = value[0].replace(/\s\s+/g, ' ');
46
+ requestMethod = requestMethodPath.split(' ')[0].toLocaleLowerCase();
47
+ myPath = requestMethodPath.split(' ')[1];
48
+
49
+ if (isString(value[1])) {
50
+ controller = splitByLastDot(value[1])[0];
51
+ controllerMethod = splitByLastDot(value[1])[1];
52
+ }
53
+ else {
54
+ // Contains middlewares and other configuration.
55
+ const props = value[1];
56
+
57
+ // Extract controller paths:
58
+ if (props.path !== undefined) {
59
+ controller = splitByLastDot(props.path)[0];
60
+ controllerMethod = splitByLastDot(props.path)[1];
61
+ }
62
+
63
+ // Extract middlewares:
64
+ if (
65
+ props.middlewares !== undefined &&
66
+ Array.isArray(props.middlewares)
67
+ ) {
68
+ middlewares.push(...props.middlewares);
69
+ }
70
+ }
71
+ middlewares = middlewares.filter(el => el != null);
72
+
73
+ try {
74
+ handler = require(`${ myPathToController }${ controller }`);
75
+ const isConstructable = isConstructor(handler);
76
+ const type = typeof handler;
77
+
78
+ if (isConstructable) {
79
+ contr = new handler();
80
+ }
81
+ else if (type === 'function') {
82
+ contr = handler();
83
+ }
84
+ else if (type === 'object') {
85
+ contr = handler;
86
+ }
87
+ }
88
+ catch (err) {
89
+ console.error('Routes mapper error:', err);
90
+
91
+ require('@babel/register');
92
+ handler = require(`${ myPathToController }${ controller }`).default;
93
+ contr = new handler();
94
+ }
95
+
96
+ router.route(myPath)[requestMethod](middlewares, contr[controllerMethod].bind(contr));
97
+ });
98
+
99
+ return router;
100
+ };
@@ -0,0 +1,20 @@
1
+
2
+ module.exports = {
3
+ isConstructor: _isConstructor,
4
+ splitByLastDot: _splitByLastDot,
5
+ }
6
+
7
+ function _isConstructor(functionOrClass) {
8
+ try {
9
+ new functionOrClass();
10
+ } catch (err) {
11
+ return false;
12
+ }
13
+
14
+ return true;
15
+ };
16
+
17
+ function _splitByLastDot(str) {
18
+ const index = str.lastIndexOf('.');
19
+ return [str.slice(0, index), str.slice(index + 1)];
20
+ };
@@ -0,0 +1,44 @@
1
+
2
+ module.exports = {
3
+ modelHasAssociations: _modelHasAssociations,
4
+ getModelAssociationProps: _getModelAssociationProps,
5
+ compileModelAssociationData: _compileModelAssociationData,
6
+ };
7
+
8
+ function _modelHasAssociations(modelDifinition) {
9
+ return Object.keys(modelDifinition.associations)?.length > 0;
10
+ }
11
+
12
+ function _getModelAssociationProps(
13
+ associationDefinition,
14
+ requestData
15
+ ) {
16
+ // Extract neccessary variables and functions:
17
+ const associatedModel = associationDefinition.target;
18
+ const { foreignKey } = associationDefinition.options;
19
+ const {
20
+ associationType,
21
+ accessors,
22
+ } = associationDefinition;
23
+
24
+ return {
25
+ associatedModel,
26
+ foreignKey,
27
+ associationType,
28
+ accessors,
29
+ };
30
+ }
31
+
32
+ function _compileModelAssociationData({
33
+ dataOfAssociation,
34
+ parentForeignKey,
35
+ parentModelId,
36
+ }) {
37
+ const result = {
38
+ ...dataOfAssociation,
39
+ [parentForeignKey]: parentModelId,
40
+ deletedAt: null
41
+ };
42
+
43
+ return result;
44
+ }
@@ -0,0 +1,69 @@
1
+ /*!
2
+ * /nodester
3
+ * MIT Licensed
4
+ */
5
+ 'use strict';
6
+
7
+
8
+ module.exports = {
9
+ copyWithCertainAttributes: _copyWithCertainAttributes,
10
+ merge: _merge
11
+ }
12
+
13
+ /**
14
+ * Copy key-value of target object
15
+ *
16
+ * @param {object} targetObj Object to copy attributes from
17
+ * @param {array} attributes Array of keys
18
+ * @returns {object} New object with attributes of targetObj
19
+ *
20
+ * @alias copyWithCertainAttributes
21
+ * @public
22
+ */
23
+ function _copyWithCertainAttributes(targetObj={}, attributes=[]) {
24
+ const result = {};
25
+
26
+ attributes.forEach(a => result[a] = targetObj[a]);
27
+
28
+ return result;
29
+ }
30
+
31
+ /**
32
+ * Merge the property descriptors of `src` into `dest`
33
+ *
34
+ * @param {object} dest Object to add descriptors to
35
+ * @param {object} src Object to clone descriptors from
36
+ * @param {boolean} [redefine=true] Redefine `dest` properties with `src` properties
37
+ * @returns {object} Reference to dest
38
+ *
39
+ * @alias merge
40
+ * @public
41
+ */
42
+ function _merge (dest={}, src={}, redefine=true) {
43
+ if (!dest) {
44
+ throw new TypeError('argument dest is required')
45
+ }
46
+
47
+ if (!src) {
48
+ throw new TypeError('argument src is required')
49
+ }
50
+
51
+ if (redefine === true) {
52
+ dest = Object.assign(dest, src);
53
+ }
54
+ else {
55
+ Object.getOwnPropertyNames(src)
56
+ .forEach(function forEachOwnPropertyName(name) {
57
+ if (!redefine && hasOwnProperty.call(dest, name)) {
58
+ // Skip descriptor.
59
+ return;
60
+ }
61
+
62
+ // Copy descriptor:
63
+ const descriptor = Object.getOwnPropertyDescriptor(src, name)
64
+ Object.defineProperty(dest, name, descriptor)
65
+ });
66
+ }
67
+
68
+ return dest;
69
+ }
@@ -0,0 +1,19 @@
1
+
2
+ module.exports = Params;
3
+
4
+ function Params(
5
+ sourceObject={},
6
+ defaultValuesList={}
7
+ ) {
8
+ const result = {};
9
+
10
+ const keys = Object.keys(defaultValuesList);
11
+ for (const key of keys) {
12
+ result[key] = typeof sourceObject[key] !== 'boolean' && !sourceObject[key] ?
13
+ defaultValuesList[key]
14
+ :
15
+ sourceObject[key];
16
+ }
17
+
18
+ return result;
19
+ }
@@ -0,0 +1,26 @@
1
+
2
+ exports = module.exports = {
3
+ isAbsolute: _isAbsolute
4
+ }
5
+
6
+ /**
7
+ * Check if `path` looks absolute.
8
+ *
9
+ * @param {String} path
10
+ * @return {Boolean}
11
+ * @api private
12
+ * @alias isAbsolute
13
+ */
14
+ function _isAbsolute(path) {
15
+ // Unix:
16
+ if ('/' === path[0])
17
+ return true;
18
+
19
+ // Windows:
20
+ if (':' === path[1] && ('\\' === path[2] || '/' === path[2]))
21
+ return true;
22
+
23
+ // Microsoft Azure:
24
+ if ('\\\\' === path.substring(0, 2))
25
+ return true;
26
+ };
@@ -0,0 +1,240 @@
1
+ // Constants.
2
+ const SubIncludesQueryRegex = /\([^)]*\)/g;
3
+
4
+ // Sequelize.
5
+ const Op = require('sequelize').Op;
6
+
7
+ // Utils.
8
+ const {
9
+ splitByDot,
10
+ splitByAmpersand
11
+ } = require('nodester/utils/strings.util');
12
+
13
+
14
+ module.exports = {
15
+ parseQueryParams: _parseQueryParams,
16
+ deleteQuerySortParams: _deleteQuerySortParams,
17
+
18
+ // SubIncludes Query:
19
+ hasSubIncludesQuery: _hasSubIncludesQuery,
20
+ cutSubIncludesQuery: _cutSubIncludesQuery,
21
+ parseSubIncludesQuery: _parseSubIncludesQuery
22
+ }
23
+
24
+ function _parseQueryParams(
25
+ requestQueryObject={},
26
+ sequilizeQuery=null
27
+ ) {
28
+ const skip = parseInt(requestQueryObject?.skip ?? 0);
29
+ const limit = parseInt(requestQueryObject?.limit ?? 50);
30
+
31
+ sequilizeQuery.offset = skip;
32
+ sequilizeQuery.limit = limit;
33
+
34
+ const order = requestQueryObject?.order;
35
+
36
+ // If order is set:
37
+ if (!!order) {
38
+ const orderBy = requestQueryObject?.order_by ?? 'id';
39
+
40
+ sequilizeQuery.order = [
41
+ [ orderBy, order ]
42
+ ];
43
+ }
44
+
45
+ // Clear sort params.
46
+ _deleteQuerySortParams(requestQueryObject);
47
+
48
+ // Get include names.
49
+ const _includes = sequilizeQuery?.include?.map( include => include.association ) ?? [];
50
+
51
+ // Count query keys.
52
+ const keysCount = Object.keys(requestQueryObject).length;
53
+
54
+ // If query has no keys,
55
+ // stop further execution:
56
+ if (keysCount === 0) {
57
+ return;
58
+ }
59
+
60
+ // This container is a reference to current "where".
61
+ let container = null;
62
+ let isContainerArray = false;
63
+
64
+ // If query has only 1 key:
65
+ if (keysCount === 1) {
66
+ // Define empty query's where.
67
+ sequilizeQuery.where = {};
68
+ container = sequilizeQuery.where;
69
+ }
70
+ else {
71
+ // Define conjuction of params in query's where.
72
+ sequilizeQuery.where = {
73
+ [Op.and]: []
74
+ };
75
+ container = sequilizeQuery.where[Op.and];
76
+ isContainerArray = true;
77
+ }
78
+
79
+ // Go through query's keys:
80
+ Object.keys(requestQueryObject)
81
+ .forEach((queryKey) => {
82
+
83
+ // Parse value of this key:
84
+ const value = requestQueryObject[queryKey];
85
+ // If value is not a number, parse it further.
86
+ const parsedValue = isNaN( value ) ? _parseHTTPQueryValue( `${ requestQueryObject[queryKey] }` ) : value;
87
+
88
+ // If we got nested key:
89
+ if (queryKey.indexOf('.') !== -1) {
90
+
91
+ // If this key is included as association:
92
+ const associationIndex = _includes.indexOf(queryKey.split('.')[0]);
93
+ if (associationIndex > -1) {
94
+ sequilizeQuery.include[associationIndex].where = { [`$${queryKey}$`]: parsedValue };
95
+ }
96
+ // Use special sequelize syntax for nested SELECT:
97
+ else if (isContainerArray) {
98
+ const selectObject = { [`$${queryKey}$`]: parsedValue };
99
+ container.push(selectObject);
100
+ }
101
+ else {
102
+ container[`$${queryKey}$`] = parsedValue;
103
+ }
104
+ }
105
+ // On regular key, set regular key-value pair:
106
+ else {
107
+ if (isContainerArray) {
108
+ const selectObject = { [queryKey]: parsedValue };
109
+ container.push(selectObject);
110
+ }
111
+ else {
112
+ container[queryKey] = parsedValue;
113
+ }
114
+ }
115
+ });
116
+ }
117
+
118
+ function _parseHTTPQueryValue(
119
+ value='',
120
+ isNumber=false
121
+ ) {
122
+ // If value matches "and()":
123
+ if (value.slice(0, 4) === 'and(') {
124
+ // Remove "and()".
125
+ const clearValuesString = value.substr(4, value.length - 'and()'.length);
126
+
127
+ const clearValues = clearValuesString.split(',');
128
+
129
+ return {
130
+ [Op.and]: clearValues.map(cv => _parseHTTPQueryValue(cv))
131
+ }
132
+ }
133
+ // If value matches "like(value)":
134
+ else if (value.slice(0, 5) === 'like(') {
135
+ // Remove "like()".
136
+ const clearValue = value.substr(5, value.length - 'like()'.length);
137
+
138
+ return {
139
+ [Op.like]: `%${ _parseHTTPQueryValue(clearValue) }%`
140
+ }
141
+ }
142
+ // If value matches "notLike(value)":
143
+ else if (value.slice(0, 8) === 'notLike(') {
144
+ // Remove "notLike()".
145
+ const clearValue = value.substr(8, value.length - 'notLike()'.length);
146
+
147
+ return {
148
+ [Op.notLike]: `%${ _parseHTTPQueryValue(clearValue) }%`
149
+ }
150
+ }
151
+ // If value matches "not(value)":
152
+ else if (value.slice(0, 4) === 'not(') {
153
+ // Remove "not()".
154
+ const clearValue = value.substr(4, value.length - 'not()'.length);
155
+
156
+ return {
157
+ [Op.not]: _parseHTTPQueryValue(clearValue)
158
+ };
159
+ }
160
+ // If value matches "or()":
161
+ else if (value.slice(0, 3) === 'or(') {
162
+ // Remove "or()".
163
+ const clearValuesString = value.substr(3, value.length - 'or()'.length);
164
+
165
+ const clearValues = clearValuesString.split(',');
166
+
167
+ return {
168
+ [Op.or]: clearValues.map(cv => _parseHTTPQueryValue(cv))
169
+ }
170
+ }
171
+ // If value is a number:
172
+ // else if (!isNaN(value)) {
173
+ // const number = parseFloat(value);
174
+ // return number;
175
+ // }
176
+ // For default, just set this value in "where"
177
+ return value;
178
+ }
179
+
180
+ function _deleteQuerySortParams(requestQueryObject={}) {
181
+ delete requestQueryObject.skip;
182
+ delete requestQueryObject.limit;
183
+ delete requestQueryObject.order;
184
+ delete requestQueryObject.order_by;
185
+ }
186
+
187
+ // If string has nested query "()":
188
+ function _hasSubIncludesQuery(string='') {
189
+ return SubIncludesQueryRegex.test(string);
190
+ }
191
+
192
+ function _cutSubIncludesQuery(string='') {
193
+ const query = string.match(SubIncludesQueryRegex)[0];
194
+ const newString = string.replace(SubIncludesQueryRegex, '');
195
+
196
+ return [ query, newString ];
197
+ }
198
+
199
+ function _parseSubIncludesQuery(
200
+ associationName,
201
+ subIncludesQuery='',
202
+ sequilizeQuery=null
203
+ ) {
204
+ const query = {};
205
+
206
+ // Magic trick to make everything work (DO NOT REMOVE).
207
+ sequilizeQuery.separate = true;
208
+
209
+ // If first "("" & ")" are set, cut them:
210
+ const subIncludesQueryRegex = /\([^)]*\)/g;
211
+ const clearQuery = subIncludesQueryRegex.test(subIncludesQuery) ?
212
+ subIncludesQuery.substr(1, subIncludesQuery.length - 2)
213
+ :
214
+ subIncludesQuery;
215
+
216
+ const keyValues = splitByAmpersand(clearQuery).map(kv => {
217
+ const keyValue = kv.split('=');
218
+ query[keyValue[0]] = keyValue[1];
219
+ });
220
+
221
+
222
+ if (!!query.skip) {
223
+ const skip = parseInt(query.skip ?? 0);
224
+ sequilizeQuery[`$${ associationName }.offset$`] = skip;
225
+ }
226
+
227
+ if (!!query.limit) {
228
+ const limit = parseInt(query.limit ?? 50);
229
+ sequilizeQuery[`$${ associationName }.limit$`] = limit;
230
+ }
231
+
232
+ // If order is set:
233
+ if (!!query.order) {
234
+ const orderBy = query?.order_by ?? 'id';
235
+
236
+ sequilizeQuery.order = [
237
+ [ orderBy, query.order ]
238
+ ];
239
+ }
240
+ }
@@ -0,0 +1,111 @@
1
+
2
+ module.exports = {
3
+ NUMBER: _NUMBER,
4
+ INT: _INT,
5
+ BOOLEAN: _BOOLEAN,
6
+ STRING: _STRING,
7
+
8
+ DATE: _DATE,
9
+
10
+ JSON: _JSON
11
+ }
12
+
13
+ function _isNumber(value) {
14
+ return !isNaN(`${value}`);
15
+ }
16
+
17
+ function _NUMBER(value=undefined, options={ fallback:undefined, min:undefined, max:undefined }) {
18
+ try {
19
+ if (!_isNumber(value))
20
+ throw new Error(`Not a number`);
21
+
22
+ if (_isNumber(options?.min) && value < options?.min)
23
+ return options?.min;
24
+
25
+ if (_isNumber(options?.max) && value > options?.max)
26
+ return options?.max;
27
+
28
+ return value;
29
+ }
30
+ catch(ex) {
31
+ return options?.fallback;
32
+ }
33
+ }
34
+
35
+ function _INT(value=undefined, options={ fallback:undefined, min:undefined, max:undefined }) {
36
+ const num = _NUMBER(value, { fallback:undefined, min:options?.min, max:options?.max });
37
+ return num === undefined ? options?.fallback : parseInt(num);
38
+ }
39
+
40
+ function _BOOLEAN(value=undefined, options={ fallback:undefined }) {
41
+ try {
42
+ // If clear boolean.
43
+ if (value === true || value === false || toString.call(value) === '[object Boolean]')
44
+ return value;
45
+
46
+ // If string-boolean.
47
+ if (typeof value === "string")
48
+ return value === "true";
49
+
50
+ throw new Error(`Not a Boolean`);
51
+ }
52
+ catch(ex) {
53
+ return options?.fallback;
54
+ }
55
+ }
56
+
57
+ function _STRING(value=undefined, options={ fallback:undefined }) {
58
+ try {
59
+ if (typeof value !== "string")
60
+ throw new Error(`Not a String`);
61
+
62
+ return value;
63
+ }
64
+ catch(ex) {
65
+ return options?.fallback;
66
+ }
67
+ }
68
+
69
+ function _DATE(value=undefined, options={ fallback:undefined }) {
70
+ try {
71
+ const type = Object.prototype.toString.call(value);
72
+
73
+ switch(type) {
74
+ case('[object Date]'): {
75
+ if (isNaN(value.valueOf())){
76
+ throw new Error('Not a date');
77
+ }
78
+ return value;
79
+ }
80
+ case('[object String]'): {
81
+ const check = new Date(value);
82
+ if (check instanceof Date)
83
+ return value;
84
+
85
+ break;
86
+ }
87
+ default:
88
+ break;
89
+ }
90
+
91
+ throw new Error('Not a date');
92
+ }
93
+ catch(ex) {
94
+ return options?.fallback;
95
+ }
96
+ }
97
+
98
+ function _JSON(value=undefined, options={ fallback:undefined }) {
99
+ try {
100
+ if (typeof value === "string")
101
+ return JSON.parse(value);
102
+
103
+ if (typeof value !== 'object')
104
+ throw new Error(`Not an object`);
105
+
106
+ return value;
107
+ }
108
+ catch(ex) {
109
+ return options?.fallback;
110
+ }
111
+ }