nodester 0.1.5 → 0.2.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.
- package/Readme.md +25 -61
- package/lib/application/index.js +185 -63
- package/lib/body/extract.js +15 -4
- package/lib/constants/Bounds.js +15 -0
- package/lib/constants/Clauses.js +13 -0
- package/lib/constants/ResponseFormats.js +2 -2
- package/lib/controllers/methods/index.js +7 -0
- package/lib/controllers/mixins/index.js +36 -36
- package/lib/database/connection.js +6 -0
- package/lib/database/migration.js +14 -4
- package/lib/facades/methods/index.js +10 -9
- package/lib/facades/mixins/index.js +67 -13
- package/lib/factories/responses/rest.js +25 -13
- package/lib/http/{request.js → request/index.js} +53 -75
- package/lib/http/request/utils.js +27 -0
- package/lib/http/response/headers.js +138 -0
- package/lib/http/response/index.js +248 -0
- package/lib/http/response/utils.js +38 -0
- package/lib/middlewares/SearchParams/index.js +25 -0
- package/lib/middlewares/cookies/index.js +44 -0
- package/lib/middlewares/etag/index.js +32 -15
- package/lib/middlewares/formidable/index.js +30 -25
- package/lib/middlewares/ql/sequelize/index.js +11 -2
- package/lib/middlewares/ql/sequelize/interpreter/QueryLexer.js +10 -2
- package/lib/middlewares/render/index.js +62 -0
- package/lib/models/associate.js +25 -1
- package/lib/models/define.js +19 -15
- package/lib/models/mixins.js +7 -0
- package/lib/query/traverse.js +97 -63
- package/lib/router/handlers.util.js +1 -0
- package/lib/router/index.js +193 -98
- package/lib/router/markers.js +7 -0
- package/lib/router/route.js +5 -0
- package/lib/router/routes.util.js +12 -14
- package/lib/router/utils.js +7 -0
- package/lib/stacks/MarkersStack.js +41 -3
- package/lib/stacks/MiddlewaresStack.js +200 -0
- package/lib/structures/Enum.js +46 -0
- package/lib/structures/Filter.js +157 -0
- package/lib/structures/Params.js +55 -0
- package/lib/tools/sql.tool.js +7 -0
- package/lib/utils/objects.util.js +31 -24
- package/lib/utils/sanitizations.util.js +10 -4
- package/lib/validators/arguments.js +68 -0
- package/lib/validators/dates.js +7 -0
- package/lib/validators/numbers.js +7 -0
- package/package.json +11 -8
- package/tests/index.test.js +4 -4
- package/tests/nql.test.js +18 -1
- package/lib/database/utils.js +0 -19
- package/lib/enums/Enum.js +0 -16
- package/lib/filters/Filter.js +0 -109
- package/lib/http/response.js +0 -1074
- package/lib/http/utils.js +0 -254
- package/lib/params/Params.js +0 -37
- package/lib/policies/Role.js +0 -77
- package/lib/policies/RoleExtracting.js +0 -97
- package/lib/services/includes.service.js +0 -79
- package/lib/services/jwt.service.js +0 -147
- package/lib/stacks/MiddlewareStack.js +0 -159
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* /nodester
|
|
3
|
+
* MIT Licensed
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const finalhandler = require('finalhandler');
|
|
9
|
+
|
|
10
|
+
// Arguments validator.
|
|
11
|
+
const { ensure } = require('../validators/arguments');
|
|
12
|
+
|
|
13
|
+
// Console:
|
|
14
|
+
const consl = require('nodester/loggers/console');
|
|
15
|
+
const debug = require('debug')('nodester:MiddlewaresStack');
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
/*
|
|
19
|
+
* Creates new MiddlewaresStack.
|
|
20
|
+
*
|
|
21
|
+
* @param {Object} [opts]
|
|
22
|
+
* @param {Boolean} opts.finalhandlerEnabled
|
|
23
|
+
*
|
|
24
|
+
* @return {MiddlewaresStack}
|
|
25
|
+
*
|
|
26
|
+
*/
|
|
27
|
+
module.exports = class MiddlewaresStack {
|
|
28
|
+
constructor(opts={}) {
|
|
29
|
+
// This array MUST stay flat!
|
|
30
|
+
this._middlewares = [];
|
|
31
|
+
|
|
32
|
+
// Indicates whether we can add more middlewares or no.
|
|
33
|
+
this._isLocked = false;
|
|
34
|
+
this.finalhandlerEnabled = !!opts.finalhandlerEnabled;
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
const env = process.env.NODE_ENV || 'development';
|
|
38
|
+
// Final middleware & error handler.
|
|
39
|
+
this.finalhandler = (req, res) => finalhandler(req, res, {
|
|
40
|
+
env: env,
|
|
41
|
+
onerror: consl.error.bind(this)
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Getters:
|
|
46
|
+
get middlewares() {
|
|
47
|
+
return this._middlewares;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
get length() {
|
|
51
|
+
return this._middlewares.length;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Indicates whether user can add more middlewares or not.
|
|
56
|
+
*
|
|
57
|
+
* @return {Boolean} isLocked
|
|
58
|
+
*
|
|
59
|
+
* @api public
|
|
60
|
+
*/
|
|
61
|
+
get isLocked() {
|
|
62
|
+
return this._isLocked === true;
|
|
63
|
+
}
|
|
64
|
+
// Getters\
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Add the given middleware `fn` to the stack.
|
|
69
|
+
*
|
|
70
|
+
* @param {Function} fn
|
|
71
|
+
* @param {Integer} index (0 or undefined)
|
|
72
|
+
*
|
|
73
|
+
* @return {Integer} index of the new middleware
|
|
74
|
+
*
|
|
75
|
+
* @api public
|
|
76
|
+
*/
|
|
77
|
+
add(fn, index) {
|
|
78
|
+
try {
|
|
79
|
+
ensure(fn, 'function,required', 'fn');
|
|
80
|
+
ensure(index, 'number', 'index');
|
|
81
|
+
|
|
82
|
+
if (this._isLocked) {
|
|
83
|
+
const err = new Error(`Can't add more middlewares while stack is locked.`);
|
|
84
|
+
throw err;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
let pushedIndex = -1;
|
|
88
|
+
|
|
89
|
+
if (index === 0) {
|
|
90
|
+
this._middlewares.unshift(fn);
|
|
91
|
+
pushedIndex = 0;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
pushedIndex = this.middlewares.push(fn);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
debug(`added middleware (${ pushedIndex })`);
|
|
98
|
+
return pushedIndex;
|
|
99
|
+
}
|
|
100
|
+
catch(error) {
|
|
101
|
+
Error.captureStackTrace(error, this.add);
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Removes middleware at index.
|
|
109
|
+
*
|
|
110
|
+
* @param {Integer} index
|
|
111
|
+
*
|
|
112
|
+
* @return {MiddlewaresStack} self
|
|
113
|
+
*
|
|
114
|
+
* @api public
|
|
115
|
+
*/
|
|
116
|
+
remove(index=-1) {
|
|
117
|
+
try {
|
|
118
|
+
ensure(index, 'number,required', 'index');
|
|
119
|
+
|
|
120
|
+
if (this._isLocked) {
|
|
121
|
+
const err = new Error(`Can't remove middlewares while stack is locked.`);
|
|
122
|
+
throw err;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
this._middlewares.splice(index, 1);
|
|
126
|
+
debug(`removed middleware (${ index })`);
|
|
127
|
+
return this;
|
|
128
|
+
}
|
|
129
|
+
catch(error) {
|
|
130
|
+
Error.captureStackTrace(error, this.remove);
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
/*
|
|
137
|
+
* Prepare stack for processing.
|
|
138
|
+
*
|
|
139
|
+
* @api public
|
|
140
|
+
*/
|
|
141
|
+
lock() {
|
|
142
|
+
if (this.finalhandlerEnabled) {
|
|
143
|
+
// Add final handler to the stack.
|
|
144
|
+
this.add((req, res)=>this.finalhandler(req, res)());
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Stack is ready.
|
|
148
|
+
this._isLocked = true;
|
|
149
|
+
|
|
150
|
+
debug(`stack is locked`);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
/*
|
|
155
|
+
* Unlocks stack.
|
|
156
|
+
*
|
|
157
|
+
* @api public
|
|
158
|
+
*/
|
|
159
|
+
unlock() {
|
|
160
|
+
this._isLocked = false;
|
|
161
|
+
|
|
162
|
+
if (this.finalhandlerEnabled) {
|
|
163
|
+
this._middlewares.pop();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
debug(`stack is unlocked`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
/*
|
|
171
|
+
* Start chain.
|
|
172
|
+
*
|
|
173
|
+
* @api public
|
|
174
|
+
*/
|
|
175
|
+
process(req, res, next) {
|
|
176
|
+
let middlewareOffset = -1;
|
|
177
|
+
|
|
178
|
+
const _next = (...args) => {
|
|
179
|
+
middlewareOffset += 1;
|
|
180
|
+
const fn = this._middlewares[middlewareOffset];
|
|
181
|
+
|
|
182
|
+
try {
|
|
183
|
+
if (!fn && !!next) {
|
|
184
|
+
// Middleware stack is finished:
|
|
185
|
+
return next.call(null, req, res, next, ...args);
|
|
186
|
+
}
|
|
187
|
+
else if (!!fn) {
|
|
188
|
+
return fn.call(null, req, res, _next, ...args);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
catch(error) {
|
|
192
|
+
return this.finalhandler(req, res)(error);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Initial start:
|
|
197
|
+
return _next();
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* /nodester
|
|
3
|
+
* MIT Licensed
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
module.exports = function Enum(constantsList={}) {
|
|
10
|
+
_setGetters(this, constantsList);
|
|
11
|
+
|
|
12
|
+
this.withValuePrefix = _withValuePrefix.bind(this);
|
|
13
|
+
this.withKeyPrefix = _withKeyPrefix.bind(this);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function _setGetters(enumTarget, constantsList) {
|
|
17
|
+
enumTarget.list = constantsList;
|
|
18
|
+
|
|
19
|
+
Object.keys(constantsList).forEach(key => {
|
|
20
|
+
enumTarget[key] = constantsList[key];
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Set constants in static array.
|
|
24
|
+
enumTarget.asArray = Object.values(constantsList);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
function _withValuePrefix(prefix='') {
|
|
29
|
+
const constantsList = {};
|
|
30
|
+
|
|
31
|
+
for (const [ key, value ] of Object.entries(this.list)) {
|
|
32
|
+
constantsList[key] = `${ prefix }${ value }`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
_setGetters(this, constantsList);
|
|
36
|
+
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function _withKeyPrefix(prefix='') {
|
|
41
|
+
Object.keys(this.list).forEach(key => {
|
|
42
|
+
this[`${ prefix }${ key }`] = this.list[key];
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* /nodester
|
|
3
|
+
* MIT Licensed
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const BOUNDS = require('../constants/Bounds');
|
|
9
|
+
const CLAUSES = require('../constants/Clauses');
|
|
10
|
+
|
|
11
|
+
const { isModel } = require('../utils/models');
|
|
12
|
+
const { ensure } = require('../validators/arguments');
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
module.exports = class NodesterFilter {
|
|
16
|
+
|
|
17
|
+
/*
|
|
18
|
+
*
|
|
19
|
+
* @param {Model} model
|
|
20
|
+
* @param {Object} options
|
|
21
|
+
* @param {Array} options.fields
|
|
22
|
+
* @param {Array} options.clauses
|
|
23
|
+
* @param {Object} options.includes
|
|
24
|
+
*
|
|
25
|
+
* @param {Object} options.bounds
|
|
26
|
+
* @param {Object} options.bounds.fields
|
|
27
|
+
* @param {Object} options.bounds.clauses
|
|
28
|
+
*
|
|
29
|
+
* @param {Object} options.statics
|
|
30
|
+
* @param {Object} options.statics.attributes
|
|
31
|
+
* @param {Object} options.statics.clauses
|
|
32
|
+
*
|
|
33
|
+
*
|
|
34
|
+
*/
|
|
35
|
+
constructor(model=null, options={}) {
|
|
36
|
+
ensure(options, 'object,required', 'options');
|
|
37
|
+
|
|
38
|
+
this._model = model;
|
|
39
|
+
|
|
40
|
+
this._fields = [];
|
|
41
|
+
this._clauses = [];
|
|
42
|
+
this._includes = {};
|
|
43
|
+
|
|
44
|
+
this._bounds = {
|
|
45
|
+
fields: {},
|
|
46
|
+
clauses: {}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
this._statics = {
|
|
50
|
+
attributes: {},
|
|
51
|
+
clauses: {}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// If model is present:
|
|
55
|
+
if (isModel(this.model)) {
|
|
56
|
+
this._fields = Object.keys(this.model.tableAttributes);
|
|
57
|
+
this._clauses = CLAUSES.asArray;
|
|
58
|
+
|
|
59
|
+
// ...and no 'bounds' and 'statics' are provided,
|
|
60
|
+
// set defaults:
|
|
61
|
+
if (!options.bounds && !options.statics) {
|
|
62
|
+
this._bounds.clauses.limit = {
|
|
63
|
+
min: BOUNDS.limit.min,
|
|
64
|
+
max: BOUNDS.limit.max
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const {
|
|
70
|
+
fields,
|
|
71
|
+
clauses,
|
|
72
|
+
includes,
|
|
73
|
+
bounds,
|
|
74
|
+
statics,
|
|
75
|
+
} = options;
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
// If fields are array:
|
|
79
|
+
if (Array.isArray(fields)) {
|
|
80
|
+
this._fields = fields;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (Array.isArray(clauses)) {
|
|
84
|
+
this._clauses = clauses;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Includes:
|
|
88
|
+
if (typeof includes === 'object') {
|
|
89
|
+
const { associations } = this.model;
|
|
90
|
+
for (const [ includeName, includeFilter ] of Object.entries(includes)) {
|
|
91
|
+
const association = associations[includeName];
|
|
92
|
+
// Validate association by name:
|
|
93
|
+
if (association === undefined) {
|
|
94
|
+
const error = new TypeError(`No include named '${ includeName }'.`);
|
|
95
|
+
Error.captureStackTrace(error, this.constructor);
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// If singular association:
|
|
100
|
+
// Fix of "Only HasMany associations support include.separate"
|
|
101
|
+
if ('HasMany' !== association.associationType) {
|
|
102
|
+
// Empty bounds.
|
|
103
|
+
includeFilter.noBounds = true;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
this._includes[includeName] = includeFilter;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Includes\
|
|
110
|
+
|
|
111
|
+
if (typeof bounds === 'object') {
|
|
112
|
+
this._bounds = bounds;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (typeof statics === 'object') {
|
|
116
|
+
if (typeof statics.attributes === 'object') {
|
|
117
|
+
this._statics.attributes = statics.attributes;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (typeof statics.clauses === 'object') {
|
|
121
|
+
this._statics.clauses = statics.clauses;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Getters:
|
|
127
|
+
get fields() {
|
|
128
|
+
return this._fields;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
get clauses() {
|
|
132
|
+
return this._clauses;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
get includes() {
|
|
136
|
+
return this._includes;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
get bounds() {
|
|
140
|
+
return this._bounds;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
get statics() {
|
|
144
|
+
return this._statics;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
get model() {
|
|
148
|
+
return this._model;
|
|
149
|
+
}
|
|
150
|
+
// Getters\
|
|
151
|
+
|
|
152
|
+
set noBounds(value) {
|
|
153
|
+
if (value === true) {
|
|
154
|
+
this._bounds.clauses = {};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* /nodester
|
|
3
|
+
* MIT Licensed
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
BOOLEAN
|
|
10
|
+
} = require('nodester/utils/sanitizations');
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
module.exports = Params;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Extracts only values set in the second argument from the first argument.
|
|
17
|
+
* If such values is missing in the first argument, will fallback to the value in the second argument.
|
|
18
|
+
*
|
|
19
|
+
* @param {Object} sourceObj
|
|
20
|
+
* @param {Object} defaultValuesList
|
|
21
|
+
*
|
|
22
|
+
* @return {Object} result
|
|
23
|
+
*
|
|
24
|
+
* @api public
|
|
25
|
+
*/
|
|
26
|
+
function Params(
|
|
27
|
+
sourceObj={},
|
|
28
|
+
defaultValuesList={}
|
|
29
|
+
) {
|
|
30
|
+
const result = {};
|
|
31
|
+
|
|
32
|
+
const keys = Object.keys(defaultValuesList);
|
|
33
|
+
for (const key of keys) {
|
|
34
|
+
|
|
35
|
+
// If value is not set,
|
|
36
|
+
// use default one from 'defaultValuesList':
|
|
37
|
+
if (sourceObj[key] === undefined) {
|
|
38
|
+
result[key] = defaultValuesList[key];
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// If String:
|
|
43
|
+
if (typeof defaultValuesList[key] === 'string') {
|
|
44
|
+
result[key] = `${ sourceObj[key] }`;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const isBoolean = toString.call(defaultValuesList[key]) === '[object Boolean]';
|
|
49
|
+
const isNumber = !isNaN(`${ defaultValuesList[key] }`);
|
|
50
|
+
|
|
51
|
+
result[key] = isBoolean ? BOOLEAN(sourceObj[key]) : (isNumber ? parseFloat(sourceObj[key]) : sourceObj[key]);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return result;
|
|
55
|
+
}
|
package/lib/tools/sql.tool.js
CHANGED
|
@@ -2,8 +2,12 @@
|
|
|
2
2
|
* /nodester
|
|
3
3
|
* MIT Licensed
|
|
4
4
|
*/
|
|
5
|
+
|
|
5
6
|
'use strict';
|
|
6
7
|
|
|
8
|
+
// Arguments validator.
|
|
9
|
+
const { ensure } = require('../validators/arguments');
|
|
10
|
+
|
|
7
11
|
|
|
8
12
|
module.exports = {
|
|
9
13
|
copyWithCertainAttributes: _copyWithCertainAttributes,
|
|
@@ -13,57 +17,60 @@ module.exports = {
|
|
|
13
17
|
/**
|
|
14
18
|
* Copy key-value of target object
|
|
15
19
|
*
|
|
16
|
-
* @param {object}
|
|
17
|
-
* @param {array} attributes Array of keys
|
|
18
|
-
*
|
|
20
|
+
* @param {object} target - Object to copy attributes from
|
|
21
|
+
* @param {array} attributes - Array of keys
|
|
22
|
+
*
|
|
23
|
+
* @return {object} New object with attributes of target
|
|
19
24
|
*
|
|
20
25
|
* @alias copyWithCertainAttributes
|
|
21
|
-
*
|
|
26
|
+
*
|
|
27
|
+
* @api public
|
|
22
28
|
*/
|
|
23
|
-
function _copyWithCertainAttributes(
|
|
29
|
+
function _copyWithCertainAttributes(target={}, attributes=[]) {
|
|
30
|
+
ensure(target, 'object,required', 'target');
|
|
31
|
+
ensure(attributes, 'array,required', 'attributes');
|
|
32
|
+
|
|
24
33
|
const result = {};
|
|
25
34
|
|
|
26
|
-
attributes.forEach(a => result[a] =
|
|
35
|
+
attributes.forEach(a => result[a] = target[a]);
|
|
27
36
|
|
|
28
37
|
return result;
|
|
29
38
|
}
|
|
30
39
|
|
|
31
40
|
/**
|
|
32
|
-
* Merge the property descriptors of `src` into `
|
|
41
|
+
* Merge the property descriptors of `src` into `target`
|
|
33
42
|
*
|
|
34
|
-
* @param {object}
|
|
35
|
-
* @param {object} src Object to clone descriptors from
|
|
36
|
-
* @param {boolean} [redefine=true] Redefine `
|
|
37
|
-
*
|
|
43
|
+
* @param {object} target - Object to add descriptors to
|
|
44
|
+
* @param {object} src - Object to clone descriptors from
|
|
45
|
+
* @param {boolean} [redefine=true] - Redefine `target` properties with `src` properties
|
|
46
|
+
*
|
|
47
|
+
* @return {object} Reference to target
|
|
38
48
|
*
|
|
39
49
|
* @alias merge
|
|
40
|
-
*
|
|
50
|
+
*
|
|
51
|
+
* @api public
|
|
41
52
|
*/
|
|
42
|
-
function _merge (
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (!src) {
|
|
48
|
-
throw new TypeError('argument src is required')
|
|
49
|
-
}
|
|
53
|
+
function _merge (target={}, src={}, redefine=true) {
|
|
54
|
+
ensure(target, 'object,required', 'target');
|
|
55
|
+
ensure(src, 'object,required', 'src');
|
|
56
|
+
ensure(redefine, 'boolean', 'redefine');
|
|
50
57
|
|
|
51
58
|
if (redefine === true) {
|
|
52
|
-
|
|
59
|
+
target = Object.assign(target, src);
|
|
53
60
|
}
|
|
54
61
|
else {
|
|
55
62
|
Object.getOwnPropertyNames(src)
|
|
56
63
|
.forEach(function forEachOwnPropertyName(name) {
|
|
57
|
-
if (!redefine && hasOwnProperty.call(
|
|
64
|
+
if (!redefine && hasOwnProperty.call(target, name)) {
|
|
58
65
|
// Skip descriptor.
|
|
59
66
|
return;
|
|
60
67
|
}
|
|
61
68
|
|
|
62
69
|
// Copy descriptor:
|
|
63
70
|
const descriptor = Object.getOwnPropertyDescriptor(src, name)
|
|
64
|
-
Object.defineProperty(
|
|
71
|
+
Object.defineProperty(target, name, descriptor)
|
|
65
72
|
});
|
|
66
73
|
}
|
|
67
74
|
|
|
68
|
-
return
|
|
75
|
+
return target;
|
|
69
76
|
}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* /nodester
|
|
3
|
+
* MIT Licensed
|
|
4
|
+
*/
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
1
7
|
|
|
2
8
|
module.exports = {
|
|
3
9
|
NUMBER: _NUMBER,
|
|
@@ -44,8 +50,8 @@ function _BOOLEAN(value=undefined, options={ fallback:undefined }) {
|
|
|
44
50
|
return value;
|
|
45
51
|
|
|
46
52
|
// If string-boolean.
|
|
47
|
-
if (typeof value ===
|
|
48
|
-
return value ===
|
|
53
|
+
if (typeof value === 'string')
|
|
54
|
+
return value === 'true';
|
|
49
55
|
|
|
50
56
|
throw new Error(`Not a Boolean`);
|
|
51
57
|
}
|
|
@@ -56,7 +62,7 @@ function _BOOLEAN(value=undefined, options={ fallback:undefined }) {
|
|
|
56
62
|
|
|
57
63
|
function _STRING(value=undefined, options={ fallback:undefined }) {
|
|
58
64
|
try {
|
|
59
|
-
if (typeof value !==
|
|
65
|
+
if (typeof value !== 'string')
|
|
60
66
|
throw new Error(`Not a String`);
|
|
61
67
|
|
|
62
68
|
return value;
|
|
@@ -97,7 +103,7 @@ function _DATE(value=undefined, options={ fallback:undefined }) {
|
|
|
97
103
|
|
|
98
104
|
function _JSON(value=undefined, options={ fallback:undefined }) {
|
|
99
105
|
try {
|
|
100
|
-
if (typeof value ===
|
|
106
|
+
if (typeof value === 'string')
|
|
101
107
|
return JSON.parse(value);
|
|
102
108
|
|
|
103
109
|
if (typeof value !== 'object')
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* /nodester
|
|
3
|
+
* MIT Licensed
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
module.exports = {
|
|
10
|
+
ensure: _ensure
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/*
|
|
14
|
+
* Validates given argument against rules.
|
|
15
|
+
*
|
|
16
|
+
* @param {Any} argument
|
|
17
|
+
* @param {String} rules
|
|
18
|
+
* @param {String} argumentName
|
|
19
|
+
*
|
|
20
|
+
* @api private
|
|
21
|
+
* @alias ensure
|
|
22
|
+
*/
|
|
23
|
+
function _ensure(argument, rules, argumentName) {
|
|
24
|
+
const name = argumentName ? `'${ argumentName }'` : 'Argument';
|
|
25
|
+
|
|
26
|
+
let rulesArray = rules.split(',');
|
|
27
|
+
|
|
28
|
+
let types = [];
|
|
29
|
+
let isRequired = undefined;
|
|
30
|
+
|
|
31
|
+
for (const rule of rulesArray) {
|
|
32
|
+
// Types:
|
|
33
|
+
if (rule.indexOf('|') > 0) {
|
|
34
|
+
types = [
|
|
35
|
+
...types,
|
|
36
|
+
...rule.split('|')
|
|
37
|
+
];
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (rule === 'required') {
|
|
42
|
+
if (argument === undefined || argument === null) {
|
|
43
|
+
throw new Error(`${ name } is required.`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
isRequired = true;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
types.push(rule);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (types.length === 0)
|
|
54
|
+
return true;
|
|
55
|
+
|
|
56
|
+
let mismatchedTypesCount = 0;
|
|
57
|
+
for (const type of types) {
|
|
58
|
+
if (typeof argument !== type) {
|
|
59
|
+
mismatchedTypesCount++;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (mismatchedTypesCount === types.length && argument !== undefined) {
|
|
64
|
+
throw new TypeError(`${ name } must be of type ${ types.join('|') }.`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return true;
|
|
68
|
+
}
|
package/lib/validators/dates.js
CHANGED