nodester 0.0.1 → 0.0.2
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 +33 -39
- package/lib/application/index.js +110 -38
- package/lib/constants/Operations.js +23 -0
- package/lib/controllers/methods/index.js +194 -0
- package/lib/controllers/mixins/index.js +222 -0
- package/lib/database/connection.js +34 -0
- package/lib/database/migration.js +42 -0
- package/lib/database/utils.js +19 -0
- package/lib/enums/Enum.js +16 -0
- package/lib/facades/methods/index.js +173 -0
- package/lib/facades/mixins/index.js +111 -0
- package/lib/factories/errors/CustomError.js +7 -5
- package/lib/factories/responses/html.js +7 -2
- package/lib/factories/responses/rest.js +110 -0
- package/lib/http/codes/index.js +157 -0
- package/lib/{application/http → http}/request.js +6 -30
- package/lib/{application/http → http}/response.js +20 -53
- package/lib/middlewares/etag/index.js +62 -0
- package/lib/middlewares/ql/sequelize/index.js +34 -0
- package/lib/middlewares/ql/sequelize/interpreter/ModelsTree.js +121 -0
- package/lib/middlewares/ql/sequelize/interpreter/QueryLexer.js +456 -0
- package/lib/models/associate.js +17 -0
- package/lib/models/define.js +56 -14
- package/lib/models/mixins.js +100 -78
- package/lib/params/Params.js +37 -0
- package/lib/queries/Colander.js +84 -0
- package/lib/queries/NodesterQueryParams.js +139 -0
- package/lib/queries/traverse.js +311 -0
- package/lib/router/handlers.util.js +61 -0
- package/lib/router/index.js +386 -0
- package/lib/router/route.js +124 -0
- package/lib/router/routes.util.js +66 -0
- package/lib/stacks/MarkersStack.js +35 -0
- package/lib/{application → stacks}/MiddlewareStack.js +47 -13
- package/lib/utils/path.util.js +3 -1
- package/lib/utils/types.util.js +51 -1
- package/lib/validators/dates.js +25 -0
- package/lib/validators/numbers.js +14 -0
- package/package.json +31 -4
- package/tests/index.test.js +7 -2
- package/tests/nql.test.js +277 -0
- package/docs/App.md +0 -13
- package/docs/Queries.md +0 -61
- package/docs/Readme.md +0 -2
- package/docs/Routing.md +0 -34
- package/examples/goal/index.js +0 -23
- package/examples/rest/index.js +0 -25
- package/examples/rest/node_modules/.package-lock.json +0 -40
- package/examples/rest/package-lock.json +0 -72
- package/examples/rest/package.json +0 -14
- package/lib/constants/ConstantsEnum.js +0 -13
- package/lib/controllers/Controller.js +0 -474
- package/lib/controllers/JWTController.js +0 -240
- package/lib/controllers/ServiceController.js +0 -109
- package/lib/controllers/WebController.js +0 -75
- package/lib/facades/Facade.js +0 -388
- package/lib/facades/FacadeParams.js +0 -11
- package/lib/facades/ServiceFacade.js +0 -17
- package/lib/facades/jwt.facade.js +0 -273
- package/lib/factories/responses/api.js +0 -90
- package/lib/models/DisabledRefreshToken.js +0 -68
- package/lib/models/Extractor.js +0 -320
- package/lib/routers/Default/index.js +0 -143
- package/lib/routers/Default/layer.js +0 -50
- package/lib/routers/Main/index.js +0 -10
- package/lib/routers/Roles/index.js +0 -81
- package/lib/utils/params.util.js +0 -19
- /package/lib/{application/http → http}/utils.js +0 -0
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
const ResponseFormats = require('nodester/constants/ResponseFormats');
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
module.exports = class APIResponseFactory {
|
|
5
|
-
constructor() {}
|
|
6
|
-
|
|
7
|
-
/*
|
|
8
|
-
Format for all API responses will be JSON
|
|
9
|
-
{
|
|
10
|
-
content: {...}
|
|
11
|
-
error: {...}
|
|
12
|
-
}
|
|
13
|
-
Status code is sent in header.
|
|
14
|
-
|
|
15
|
-
If error is not present, error should be null.
|
|
16
|
-
If error is present, content can be null (But it's not required).
|
|
17
|
-
*/
|
|
18
|
-
createGenericResponse(
|
|
19
|
-
options = {
|
|
20
|
-
res: null,
|
|
21
|
-
status: 200,
|
|
22
|
-
content: {},
|
|
23
|
-
error: null,
|
|
24
|
-
format: ResponseFormats.JSON
|
|
25
|
-
}
|
|
26
|
-
) {
|
|
27
|
-
try {
|
|
28
|
-
const data = {
|
|
29
|
-
content: options?.content ?? null,
|
|
30
|
-
error: options?.error ?? null
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
switch(options?.format) {
|
|
34
|
-
case ResponseFormats.JSON:
|
|
35
|
-
return options?.res.status(options?.status).json(data);
|
|
36
|
-
case ResponseFormats.XML:
|
|
37
|
-
break;
|
|
38
|
-
default: {
|
|
39
|
-
const err = new Error("No response format specified.");
|
|
40
|
-
throw err;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
catch(error) {
|
|
45
|
-
const err = new Error(`Could not create generic response: ${error.message}`);
|
|
46
|
-
err.name = error?.name;
|
|
47
|
-
err.code = error?.code;
|
|
48
|
-
|
|
49
|
-
console.error(err);
|
|
50
|
-
|
|
51
|
-
throw err;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Sends response with status code 200.
|
|
57
|
-
* Should be called on all successful respones.
|
|
58
|
-
*
|
|
59
|
-
* @param <Object> res
|
|
60
|
-
* @param <Object> content
|
|
61
|
-
* @param <String> format
|
|
62
|
-
*/
|
|
63
|
-
createOKResponse(options) {
|
|
64
|
-
|
|
65
|
-
return this.createGenericResponse({
|
|
66
|
-
...options,
|
|
67
|
-
status: 200,
|
|
68
|
-
format: options?.format ?? ResponseFormats.JSON
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Sends response with provided error code.
|
|
74
|
-
* Should be called on all failed respones.
|
|
75
|
-
*
|
|
76
|
-
* @param <Object> res
|
|
77
|
-
* @param <Object> error
|
|
78
|
-
* @param <Object> content (optional)
|
|
79
|
-
* @param <Int> status
|
|
80
|
-
* @param <String> format
|
|
81
|
-
*/
|
|
82
|
-
createErrorResponse(options) {
|
|
83
|
-
|
|
84
|
-
return this.createGenericResponse({
|
|
85
|
-
...options,
|
|
86
|
-
status: options?.status ?? 500,
|
|
87
|
-
format: options?.format ?? ResponseFormats.JSON
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
const defineModel = require('./define');
|
|
2
|
-
// ORM.
|
|
3
|
-
const { DataTypes } = require('sequelize');
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
module.exports = _defineDisabledRefreshToken;
|
|
7
|
-
|
|
8
|
-
function _defineDisabledRefreshToken(
|
|
9
|
-
database,
|
|
10
|
-
roleIds=[],
|
|
11
|
-
options={}
|
|
12
|
-
) {
|
|
13
|
-
|
|
14
|
-
const fields = {
|
|
15
|
-
id: {
|
|
16
|
-
type: DataTypes.INTEGER.UNSIGNED,
|
|
17
|
-
allowNull: false,
|
|
18
|
-
primaryKey: true,
|
|
19
|
-
autoIncrement: true,
|
|
20
|
-
_autoGenerated: true
|
|
21
|
-
},
|
|
22
|
-
|
|
23
|
-
token: {
|
|
24
|
-
type: DataTypes.STRING,
|
|
25
|
-
required: true,
|
|
26
|
-
allowNull: false,
|
|
27
|
-
unique: true
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
roleIds.forEach(roleId => fields[roleId] = {
|
|
32
|
-
type: DataTypes.INTEGER.UNSIGNED,
|
|
33
|
-
allowNull: true
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
const disabledRefreshToken = defineModel(database, 'DisabledRefreshToken',
|
|
37
|
-
(DataTypes) => ( fields ),
|
|
38
|
-
{ ...options }
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
disabledRefreshToken.createOrFind = function({
|
|
42
|
-
token,
|
|
43
|
-
...roleInfo
|
|
44
|
-
}) {
|
|
45
|
-
const where = {
|
|
46
|
-
token
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const defaults = {
|
|
50
|
-
token: token,
|
|
51
|
-
...roleInfo
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const query = {
|
|
55
|
-
where,
|
|
56
|
-
defaults
|
|
57
|
-
};
|
|
58
|
-
return this.findOrCreate(query);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
disabledRefreshToken.selectAll = function({ token }) {
|
|
62
|
-
const where = { token };
|
|
63
|
-
const query = { where };
|
|
64
|
-
return this.findAll(query);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return disabledRefreshToken;
|
|
68
|
-
}
|
package/lib/models/Extractor.js
DELETED
|
@@ -1,320 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* ModelDataExtractor (/models/Extractor.js)
|
|
3
|
-
* Reads data from Express's request and filters it,
|
|
4
|
-
* based on model parameters and always-present query parameters (limit, skip, etc.).
|
|
5
|
-
*/
|
|
6
|
-
// Constants:
|
|
7
|
-
const { DataTypes } = require('sequelize');
|
|
8
|
-
const IGNORED_KEYS = [
|
|
9
|
-
// Sequilize keys:
|
|
10
|
-
'createdAt',
|
|
11
|
-
'updatedAt',
|
|
12
|
-
'deletedAt',
|
|
13
|
-
|
|
14
|
-
'created_at',
|
|
15
|
-
'updated_at',
|
|
16
|
-
'deleted_at',
|
|
17
|
-
// Procedural keys.
|
|
18
|
-
'should_delete',
|
|
19
|
-
];
|
|
20
|
-
const PROCEDURAL_KEYS = {
|
|
21
|
-
'should_delete': new DataTypes.BOOLEAN()
|
|
22
|
-
};
|
|
23
|
-
// Utils:
|
|
24
|
-
const sntz = require('nodester/utils/sanitizations.util');
|
|
25
|
-
const Params = require('nodester/facades/FacadeParams');
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
module.exports = class ModelDataExtractor {
|
|
29
|
-
|
|
30
|
-
constructor(
|
|
31
|
-
modelDefinition,
|
|
32
|
-
options,
|
|
33
|
-
) {
|
|
34
|
-
if (!modelDefinition) {
|
|
35
|
-
throw new Error('"modelDefinition" attribute is invalid.');
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const {
|
|
39
|
-
withFiles
|
|
40
|
-
} = Params(options, {
|
|
41
|
-
withFiles: false
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
this.model = modelDefinition;
|
|
45
|
-
this.attributes = modelDefinition.tableAttributes;
|
|
46
|
-
this.options = {
|
|
47
|
-
withFiles: !!withFiles,
|
|
48
|
-
fileInstanceName: 'file',
|
|
49
|
-
filesArrayName: 'files',
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
extractData(
|
|
54
|
-
modelDefinition,
|
|
55
|
-
parentModelDefinition=null,
|
|
56
|
-
holder={},
|
|
57
|
-
includes=[],
|
|
58
|
-
skipIdValidation=false,
|
|
59
|
-
skipValidation=false,
|
|
60
|
-
) {
|
|
61
|
-
if (!modelDefinition) {
|
|
62
|
-
const err = new Error('"modelDefinition" attribute is invalid.');
|
|
63
|
-
err.name = 'InternalValidationError';
|
|
64
|
-
throw err;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const data = {};
|
|
68
|
-
const errors = {};
|
|
69
|
-
|
|
70
|
-
const attributes = modelDefinition.tableAttributes;
|
|
71
|
-
|
|
72
|
-
// Table attributes minus "special" keys.
|
|
73
|
-
const keysToCheck = Object.keys(attributes)
|
|
74
|
-
.filter(key => !IGNORED_KEYS.includes(key));
|
|
75
|
-
|
|
76
|
-
keysToCheck.forEach((key) => {
|
|
77
|
-
const {
|
|
78
|
-
type,
|
|
79
|
-
allowNull,
|
|
80
|
-
defaultValue,
|
|
81
|
-
primaryKey,
|
|
82
|
-
references
|
|
83
|
-
} = attributes[key];
|
|
84
|
-
|
|
85
|
-
// Extract raw value from passed object.
|
|
86
|
-
const dataValue = holder[key];
|
|
87
|
-
|
|
88
|
-
if (!!primaryKey && !!skipIdValidation) {
|
|
89
|
-
// Just put id to data object:
|
|
90
|
-
if (!!dataValue)
|
|
91
|
-
data[key] = dataValue;
|
|
92
|
-
|
|
93
|
-
// Skip further validation.
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// If this field references some other model:
|
|
98
|
-
if (!!references) {
|
|
99
|
-
const modelReferenced = references.model;
|
|
100
|
-
|
|
101
|
-
// If referenced model is the same as parentModel,
|
|
102
|
-
// skip (Sequilize will handle it):
|
|
103
|
-
if (modelReferenced === parentModelDefinition?.tableName) {
|
|
104
|
-
// Skip further validation.
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// If value is undefined, and null is allowed skip:
|
|
110
|
-
if (dataValue === undefined && allowNull) {
|
|
111
|
-
// Skip further validation.
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// If value is undefined, and null is allowed,
|
|
116
|
-
// set and skip:
|
|
117
|
-
if (dataValue === null && allowNull) {
|
|
118
|
-
data[key] = null;
|
|
119
|
-
// Skip further validation.
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (allowNull === false && (dataValue === undefined || dataValue === null)) {
|
|
124
|
-
|
|
125
|
-
// If default value can be set,
|
|
126
|
-
// or we're allowed to skip validation,
|
|
127
|
-
// skip:
|
|
128
|
-
if (defaultValue !== undefined || (!primaryKey && skipValidation === true)) {
|
|
129
|
-
// Skip further validation.
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return errors[key] = { message: `Field "${key}" can not be null.` };
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
data[key] = _sanitizeValue(dataValue, type);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
// Check procedural keys:
|
|
140
|
-
for (const [ key, dataType ] of Object.entries(PROCEDURAL_KEYS)) {
|
|
141
|
-
// Extract raw value from passed object.
|
|
142
|
-
const dataValue = holder[key];
|
|
143
|
-
|
|
144
|
-
// If value is defined:
|
|
145
|
-
if (dataValue !== undefined) {
|
|
146
|
-
data[key] = _sanitizeValue(dataValue, dataType);
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
// If model has associations:
|
|
151
|
-
if (Object.keys(modelDefinition?.associations)?.length > 0) {
|
|
152
|
-
|
|
153
|
-
// Go through association entries:
|
|
154
|
-
const associationEntries = Object.entries( modelDefinition.associations );
|
|
155
|
-
associationEntries.forEach(([
|
|
156
|
-
associationName,
|
|
157
|
-
associationDefinition
|
|
158
|
-
]) => {
|
|
159
|
-
|
|
160
|
-
// If data of this association is present:
|
|
161
|
-
if (!!holder[associationName]) {
|
|
162
|
-
|
|
163
|
-
const associatedModel = associationDefinition.target;
|
|
164
|
-
|
|
165
|
-
const isSingleInstance = Array.isArray( holder[associationName] ) === false;
|
|
166
|
-
|
|
167
|
-
// If single instance of associated model:
|
|
168
|
-
if (isSingleInstance) {
|
|
169
|
-
data[associationName] = this.extractData(
|
|
170
|
-
associatedModel,
|
|
171
|
-
modelDefinition,
|
|
172
|
-
holder[associationName],
|
|
173
|
-
[], // Includes
|
|
174
|
-
skipIdValidation,
|
|
175
|
-
skipValidation
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
// If multiple instances of associated model:
|
|
179
|
-
else {
|
|
180
|
-
data[associationName] = holder[associationName].map((associationData) => {
|
|
181
|
-
return this.extractData(
|
|
182
|
-
associatedModel,
|
|
183
|
-
modelDefinition,
|
|
184
|
-
associationData,
|
|
185
|
-
[], // Includes
|
|
186
|
-
skipIdValidation,
|
|
187
|
-
skipValidation
|
|
188
|
-
);
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// If options for "withFiles" is true,
|
|
196
|
-
// also check files in object.
|
|
197
|
-
if (this.options.withFiles === true) {
|
|
198
|
-
// Check for single file & array of files.
|
|
199
|
-
const keysToCheck = [
|
|
200
|
-
this.options.fileInstanceName,
|
|
201
|
-
this.options.filesArrayName,
|
|
202
|
-
];
|
|
203
|
-
|
|
204
|
-
keysToCheck.filter(key => holder[key] !== undefined)
|
|
205
|
-
.forEach(key => data[key] = holder[key]);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// If errors were set, throw ValidationError:
|
|
209
|
-
if (Object.keys(errors).length > 0) {
|
|
210
|
-
const err = new Error('');
|
|
211
|
-
err.name = 'ValidationError';
|
|
212
|
-
err.details = { ...errors };
|
|
213
|
-
throw err;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
return data;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
extractInstanceDataFromObject(
|
|
220
|
-
holder={},
|
|
221
|
-
includes,
|
|
222
|
-
options,
|
|
223
|
-
) {
|
|
224
|
-
const {
|
|
225
|
-
skipIdValidation,
|
|
226
|
-
skipValidation
|
|
227
|
-
} = Params(options, {
|
|
228
|
-
skipIdValidation: false,
|
|
229
|
-
skipValidation: false,
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
return this.extractData(
|
|
233
|
-
this.model,
|
|
234
|
-
null,
|
|
235
|
-
holder,
|
|
236
|
-
includes,
|
|
237
|
-
skipIdValidation,
|
|
238
|
-
skipValidation
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/* ! Warning !
|
|
243
|
-
* Not finished method
|
|
244
|
-
* Do not use!
|
|
245
|
-
*/
|
|
246
|
-
extractArrayDataFromObject(
|
|
247
|
-
holder={},
|
|
248
|
-
includes,
|
|
249
|
-
options,
|
|
250
|
-
) {
|
|
251
|
-
const {
|
|
252
|
-
skipIdValidation,
|
|
253
|
-
skipValidation
|
|
254
|
-
} = Params(options, {
|
|
255
|
-
skipIdValidation: false,
|
|
256
|
-
skipValidation: false,
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
const { instances } = holder;
|
|
260
|
-
|
|
261
|
-
// All model instances must be in an array by key "instances".
|
|
262
|
-
// If "instances" is not array, throw error:
|
|
263
|
-
if (Array.isArray(instances) === false) {
|
|
264
|
-
const err = new Error('');
|
|
265
|
-
err.name = 'ValidationError';
|
|
266
|
-
err.details = { message: 'Field "instances" must be an array' };
|
|
267
|
-
throw err;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
const results = instances.map((instance) =>
|
|
271
|
-
this.extractData(
|
|
272
|
-
this.model,
|
|
273
|
-
null,
|
|
274
|
-
instance,
|
|
275
|
-
skipIdValidation,
|
|
276
|
-
skipValidation
|
|
277
|
-
)
|
|
278
|
-
);
|
|
279
|
-
|
|
280
|
-
return results;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
function _sanitizeValue(
|
|
285
|
-
value,
|
|
286
|
-
dataType,
|
|
287
|
-
fallback=null,
|
|
288
|
-
) {
|
|
289
|
-
let result = null;
|
|
290
|
-
|
|
291
|
-
if (dataType instanceof DataTypes.INTEGER) {
|
|
292
|
-
result = sntz.INT(value, { fallback });
|
|
293
|
-
}
|
|
294
|
-
else if (dataType instanceof DataTypes.DECIMAL) {
|
|
295
|
-
result = sntz.NUMBER(value, { fallback });
|
|
296
|
-
}
|
|
297
|
-
else if (dataType instanceof DataTypes.FLOAT) {
|
|
298
|
-
result = sntz.NUMBER(value, { fallback });
|
|
299
|
-
}
|
|
300
|
-
else if (dataType instanceof DataTypes.STRING) {
|
|
301
|
-
result = sntz.STRING(value, { fallback });
|
|
302
|
-
}
|
|
303
|
-
else if (dataType instanceof DataTypes.TEXT) {
|
|
304
|
-
result = sntz.STRING(value, { fallback });
|
|
305
|
-
}
|
|
306
|
-
else if (dataType instanceof DataTypes.ENUM) {
|
|
307
|
-
result = sntz.STRING(value, { fallback });
|
|
308
|
-
}
|
|
309
|
-
else if (dataType instanceof DataTypes.JSON) {
|
|
310
|
-
result = sntz.JSON(value, { fallback });
|
|
311
|
-
}
|
|
312
|
-
else if (dataType instanceof DataTypes.BOOLEAN) {
|
|
313
|
-
result = sntz.BOOLEAN(value, { fallback });
|
|
314
|
-
}
|
|
315
|
-
else if (dataType instanceof DataTypes.DATE || dataType instanceof DataTypes.DATEONLY) {
|
|
316
|
-
result = sntz.DATE(value, { fallback });
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
return result;
|
|
320
|
-
}
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
const Layer = require('./layer');
|
|
2
|
-
|
|
3
|
-
// Utils:
|
|
4
|
-
const { getType } = require('../../utils/types.util');
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
module.exports = function NodesterDefaultRouter(app=null) {
|
|
8
|
-
this.markers = {};
|
|
9
|
-
this.layer = new Layer();
|
|
10
|
-
|
|
11
|
-
if (!!app) {
|
|
12
|
-
this.app = app
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// Expose methods:
|
|
16
|
-
// Markers:
|
|
17
|
-
this.addMarker = _addMarker;
|
|
18
|
-
this.getMarker = _getMarker;
|
|
19
|
-
|
|
20
|
-
// Routing:
|
|
21
|
-
this.handle = _handle;
|
|
22
|
-
this.only = _only;
|
|
23
|
-
this.route = _route;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Adds marker to the stack.
|
|
28
|
-
* Returns itself for chaining.
|
|
29
|
-
* @return {NodesterDefaultRouter}
|
|
30
|
-
*
|
|
31
|
-
* @alias addMarker
|
|
32
|
-
* @public
|
|
33
|
-
*/
|
|
34
|
-
function _addMarker(nameOrSymbol='', fn=()=>{}) {
|
|
35
|
-
if (typeof fn !== 'function') {
|
|
36
|
-
const err = new TypeError(`Router.addMarker() requires a middleware function but got a ${ getType(fn) }`);
|
|
37
|
-
throw err;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const marker = this.getMarker(nameOrSymbol);
|
|
41
|
-
if (marker.marker.index > -1) {
|
|
42
|
-
const err = new TypeError(`Marker with key ${ nameOrSymbol } is already set.`);
|
|
43
|
-
throw err;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
this.markers[nameOrSymbol] = fn;
|
|
47
|
-
|
|
48
|
-
return this;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Tries to find marker's data by provided key.
|
|
54
|
-
* @return {Object}
|
|
55
|
-
*
|
|
56
|
-
* @alias getMarker
|
|
57
|
-
* @public
|
|
58
|
-
*/
|
|
59
|
-
function _getMarker(nameOrSymbol='') {
|
|
60
|
-
const result = {
|
|
61
|
-
marker: {
|
|
62
|
-
key: nameOrSymbol,
|
|
63
|
-
index: -1,
|
|
64
|
-
},
|
|
65
|
-
middleware: undefined
|
|
66
|
-
}
|
|
67
|
-
try {
|
|
68
|
-
const keys = Object.keys(this.markers);
|
|
69
|
-
|
|
70
|
-
const index = keys.indexOf(nameOrSymbol);
|
|
71
|
-
if (keys.indexOf(nameOrSymbol) === -1) {
|
|
72
|
-
const err = new Error('NotFound');
|
|
73
|
-
throw err;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Marker found:
|
|
77
|
-
result.marker.index = index;
|
|
78
|
-
result.middleware = this.markers[nameOrSymbol];
|
|
79
|
-
}
|
|
80
|
-
catch(error) {
|
|
81
|
-
result.marker.index = -1;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return result;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Start routes pipeline processing.
|
|
89
|
-
*
|
|
90
|
-
* If no callback is provided, then default error handlers will respond
|
|
91
|
-
* in the event of an error bubbling through the stack.
|
|
92
|
-
*
|
|
93
|
-
* @alias handle
|
|
94
|
-
* @public
|
|
95
|
-
*/
|
|
96
|
-
function _handle(req, res, callback) {
|
|
97
|
-
const method = req.method;
|
|
98
|
-
const requestPath = req.url;
|
|
99
|
-
|
|
100
|
-
console.log(method, requestPath);
|
|
101
|
-
|
|
102
|
-
let markerName = null;
|
|
103
|
-
|
|
104
|
-
// Check if this request satisfies any markers:
|
|
105
|
-
const markers = Object.entries(this.markers);
|
|
106
|
-
console.log({ markers });
|
|
107
|
-
|
|
108
|
-
for (const [marker, fn] of markers) {
|
|
109
|
-
const result = fn(req, res, callback);
|
|
110
|
-
console.log(result);
|
|
111
|
-
|
|
112
|
-
if (result === true) {
|
|
113
|
-
markerName = marker;
|
|
114
|
-
break;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
console.log({ markerName });
|
|
119
|
-
|
|
120
|
-
return res.send(markerName ?? 'Hi!');
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
*
|
|
126
|
-
* @alias only
|
|
127
|
-
* @public
|
|
128
|
-
*/
|
|
129
|
-
function _only(condition) {
|
|
130
|
-
this.layer.push('condition', condition);
|
|
131
|
-
// Return layer for chaining.
|
|
132
|
-
return this.layer;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
*
|
|
138
|
-
* @alias route
|
|
139
|
-
* @public
|
|
140
|
-
*/
|
|
141
|
-
function _route() {
|
|
142
|
-
|
|
143
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
module.exports = function NodesterDefaultRouterLayer() {
|
|
3
|
-
this.conditions = [];
|
|
4
|
-
this.routesList = {};
|
|
5
|
-
|
|
6
|
-
this.push = _push;
|
|
7
|
-
this.route = _route;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
*
|
|
13
|
-
* @alias push
|
|
14
|
-
* @public
|
|
15
|
-
*/
|
|
16
|
-
function _push(key='condition') {
|
|
17
|
-
let args = [...arguments].shift();
|
|
18
|
-
|
|
19
|
-
switch(key) {
|
|
20
|
-
case 'condition':
|
|
21
|
-
// this.conditions[]
|
|
22
|
-
break;
|
|
23
|
-
case 'route':
|
|
24
|
-
const route = args.shift();
|
|
25
|
-
this.routesList[route] = args;
|
|
26
|
-
break;
|
|
27
|
-
break;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return this;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
*
|
|
36
|
-
* @alias route
|
|
37
|
-
* @public
|
|
38
|
-
*/
|
|
39
|
-
function _route(path='/') {
|
|
40
|
-
const middlewares = [...arguments].shift();
|
|
41
|
-
|
|
42
|
-
console.log({ path });
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
*
|
|
48
|
-
* @alias push
|
|
49
|
-
* @public
|
|
50
|
-
*/
|