@dwtechs/antity 0.10.0 โ 0.11.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 +128 -23
- package/dist/antity.d.ts +1 -0
- package/dist/antity.js +50 -6
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -3,13 +3,11 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@dwtechs/antity)
|
|
4
4
|
[](https://www.npmjs.com/package/@dwtechs/antity)
|
|
5
5
|

|
|
6
|
-
[](https://www.npmjs.com/package/@dwtechs/antity)
|
|
7
6
|
|
|
8
7
|
- [Synopsis](#synopsis)
|
|
9
8
|
- [Support](#support)
|
|
10
9
|
- [Installation](#installation)
|
|
11
10
|
- [Usage](#usage)
|
|
12
|
-
- [ES6](#es6)
|
|
13
11
|
- [API Reference](#api-reference)
|
|
14
12
|
- [Contributors](#contributors)
|
|
15
13
|
- [Stack](#stack)
|
|
@@ -19,12 +17,10 @@
|
|
|
19
17
|
|
|
20
18
|
**[Antity.js](https://github.com/DWTechs/Antity.js)** is an Open source library for easy entity management.
|
|
21
19
|
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
- Can be used as EcmaScrypt module
|
|
27
|
-
- Written in Typescript
|
|
20
|
+
- ๐ชถ Very lightweight
|
|
21
|
+
- ๐งช Thoroughly tested
|
|
22
|
+
- ๐ Shipped as EcmaScrypt module
|
|
23
|
+
- ๐ Written in Typescript
|
|
28
24
|
|
|
29
25
|
|
|
30
26
|
## Support
|
|
@@ -44,8 +40,6 @@ $ npm i @dwtechs/antity
|
|
|
44
40
|
## Usage
|
|
45
41
|
|
|
46
42
|
|
|
47
|
-
### ES6 / TypeScript
|
|
48
|
-
|
|
49
43
|
```javascript
|
|
50
44
|
|
|
51
45
|
import { Entity } from "@dwtechs/antity";
|
|
@@ -120,6 +114,8 @@ const entity = new Entity("consumers", [
|
|
|
120
114
|
|
|
121
115
|
// add a consumer. Used when loggin in from user service
|
|
122
116
|
router.post("/", entity.normalize, entity.validate, ...);
|
|
117
|
+
// or use check method to both normalize and validate at once
|
|
118
|
+
router.put("/", entity.check, ...);
|
|
123
119
|
|
|
124
120
|
```
|
|
125
121
|
|
|
@@ -163,8 +159,8 @@ type Method = "GET" | "PATCH" | "PUT" | "POST" | "DELETE";
|
|
|
163
159
|
class Property {
|
|
164
160
|
key: string;
|
|
165
161
|
type: Type;
|
|
166
|
-
min: number | Date;
|
|
167
|
-
max: number | Date;
|
|
162
|
+
min: number | Date | null;
|
|
163
|
+
max: number | Date | null;
|
|
168
164
|
required: boolean;
|
|
169
165
|
safe: boolean;
|
|
170
166
|
typeCheck: boolean;
|
|
@@ -185,34 +181,143 @@ class Entity {
|
|
|
185
181
|
set name(name: string);
|
|
186
182
|
|
|
187
183
|
/**
|
|
188
|
-
*
|
|
184
|
+
* Returns a single property object matching the given key.
|
|
185
|
+
*
|
|
186
|
+
* - Searches the entity's properties for a property with the specified key
|
|
187
|
+
* - Useful for dynamic validation, normalization, or documentation
|
|
188
|
+
*
|
|
189
|
+
* @param {string} key - The property key to look up
|
|
190
|
+
* @returns {Property | undefined} The Property object if found, otherwise undefined
|
|
191
|
+
*
|
|
192
|
+
* **Input Properties Required:**
|
|
193
|
+
* - `key` (string) - Property key to look up
|
|
189
194
|
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
195
|
+
* **Output Properties:**
|
|
196
|
+
* - Property object matching the key, or undefined if not found
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* ```typescript
|
|
200
|
+
* const prop = entity.getProp('firstName');
|
|
201
|
+
* // prop contains the Property object for 'firstName' or undefined
|
|
202
|
+
* ```
|
|
192
203
|
*/
|
|
193
204
|
getProp(key: string): Property | undefined;
|
|
194
205
|
|
|
195
206
|
/**
|
|
196
|
-
*
|
|
207
|
+
* Returns all properties configured for a given REST method.
|
|
208
|
+
*
|
|
209
|
+
* - Filters the entity's properties by the specified method (e.g., 'POST', 'GET')
|
|
210
|
+
* - Useful for dynamic validation, normalization, or documentation
|
|
211
|
+
*
|
|
212
|
+
* @param {Method} method - The REST method to filter properties by (e.g., 'POST', 'GET')
|
|
213
|
+
* @returns {Property[]} Array of Property objects associated with the method
|
|
214
|
+
*
|
|
215
|
+
* **Input Properties Required:**
|
|
216
|
+
* - `method` (string) - REST method to filter by
|
|
197
217
|
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
218
|
+
* **Output Properties:**
|
|
219
|
+
* - Array of Property objects matching the method
|
|
220
|
+
*
|
|
221
|
+
* @example
|
|
222
|
+
* ```typescript
|
|
223
|
+
* const postProps = entity.getPropsByMethod('POST');
|
|
224
|
+
* // postProps contains all properties relevant for POST requests
|
|
225
|
+
* ```
|
|
200
226
|
*/
|
|
201
227
|
getPropsByMethod(method: Method): Property[];
|
|
202
228
|
|
|
203
229
|
/**
|
|
204
|
-
* Normalizes
|
|
205
|
-
*
|
|
230
|
+
* Normalizes each row in req.body.rows according to property config and HTTP method.
|
|
231
|
+
*
|
|
232
|
+
* - Applies sanitization if `sanitize: true` and method matches
|
|
233
|
+
* - Applies normalization if `normalize: true` and method matches
|
|
234
|
+
* - Mutates req.body.rows with sanitized/normalized values
|
|
235
|
+
* - Calls next(error) on failure, next() on success
|
|
236
|
+
*
|
|
237
|
+
* @param {Request} req - Express request object containing rows
|
|
238
|
+
* @param {Response} _res - Express response object (not used)
|
|
239
|
+
* @param {NextFunction} next - Express next function
|
|
240
|
+
*
|
|
241
|
+
* @returns {void}
|
|
242
|
+
*
|
|
243
|
+
* **Input Properties Required:**
|
|
244
|
+
* - `req.body.rows` (array) - Array of objects to normalize
|
|
245
|
+
* - Each property config can specify sanitize, normalize, etc.
|
|
246
|
+
*
|
|
247
|
+
* **Output Properties:**
|
|
248
|
+
* - Mutates `req.body.rows` with sanitized/normalized values
|
|
249
|
+
* - Calls next(error) if any row fails normalization, next() if all pass
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* ```typescript
|
|
253
|
+
* router.post('/entity', entity.normalize, (req, res) => {
|
|
254
|
+
* // req.body.rows are now sanitized and normalized
|
|
255
|
+
* res.json({ success: true });
|
|
256
|
+
* });
|
|
257
|
+
* ```
|
|
206
258
|
*/
|
|
207
259
|
normalize: (req: Request, _res: Response, next: NextFunction) => void;
|
|
208
260
|
|
|
209
261
|
/**
|
|
210
|
-
* Validates
|
|
262
|
+
* Validates each row in req.body.rows according to property config and HTTP method.
|
|
211
263
|
*
|
|
212
|
-
*
|
|
213
|
-
*
|
|
264
|
+
* - Checks required properties and validates values
|
|
265
|
+
* - Calls next(error) on failure, next() on success
|
|
266
|
+
*
|
|
267
|
+
* @param {Request} req - Express request object containing rows
|
|
268
|
+
* @param {Response} _res - Express response object (not used)
|
|
269
|
+
* @param {NextFunction} next - Express next function
|
|
270
|
+
*
|
|
271
|
+
* @returns {void}
|
|
272
|
+
*
|
|
273
|
+
* **Input Properties Required:**
|
|
274
|
+
* - `req.body.rows` (array) - Array of objects to validate
|
|
275
|
+
* - Each property config can specify validate, required, etc.
|
|
276
|
+
*
|
|
277
|
+
* **Output Properties:**
|
|
278
|
+
* - Calls next(error) if any row fails validation, next() if all pass
|
|
279
|
+
*
|
|
280
|
+
* @example
|
|
281
|
+
* ```typescript
|
|
282
|
+
* router.post('/entity', entity.validate, (req, res) => {
|
|
283
|
+
* // req.body.rows are now validated
|
|
284
|
+
* res.json({ success: true });
|
|
285
|
+
* });
|
|
286
|
+
* ```
|
|
214
287
|
*/
|
|
215
288
|
validate: (req: Request, _res: Response, next: NextFunction) => void;
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Checks, sanitizes, normalizes, and validates each row in req.body.rows according to property config and HTTP method.
|
|
292
|
+
*
|
|
293
|
+
* - Applies sanitization if `sanitize: true` and method matches
|
|
294
|
+
* - Applies normalization if `normalize: true` and method matches
|
|
295
|
+
* - Checks required properties and validates values
|
|
296
|
+
* - Calls next(error) on failure, next() on success
|
|
297
|
+
*
|
|
298
|
+
* @param {Request} req - Express request object containing rows
|
|
299
|
+
* @param {Response} _res - Express response object (not used)
|
|
300
|
+
* @param {NextFunction} next - Express next function
|
|
301
|
+
*
|
|
302
|
+
* @returns {void}
|
|
303
|
+
*
|
|
304
|
+
* **Input Properties Required:**
|
|
305
|
+
* - `req.body.rows` (array) - Array of objects to check
|
|
306
|
+
* - Each property config can specify sanitize, normalize, validate, required, etc.
|
|
307
|
+
*
|
|
308
|
+
* **Output Properties:**
|
|
309
|
+
* - Mutates `req.body.rows` with sanitized/normalized values
|
|
310
|
+
* - Calls next(error) if any row fails checks, next() if all pass
|
|
311
|
+
*
|
|
312
|
+
* @example
|
|
313
|
+
* ```typescript
|
|
314
|
+
* router.post('/entity', entity.check, (req, res) => {
|
|
315
|
+
* // req.body.rows are now sanitized, normalized, and validated
|
|
316
|
+
* res.json({ success: true });
|
|
317
|
+
* });
|
|
318
|
+
* ```
|
|
319
|
+
*/
|
|
320
|
+
check: (req: Request, _res: Response, next: NextFunction) => void;
|
|
216
321
|
}
|
|
217
322
|
|
|
218
323
|
```
|
package/dist/antity.d.ts
CHANGED
|
@@ -70,6 +70,7 @@ declare class Entity {
|
|
|
70
70
|
getPropsByMethod(method: Method): Property[];
|
|
71
71
|
normalize: (req: Request, _res: Response, next: NextFunction) => void;
|
|
72
72
|
validate: (req: Request, _res: Response, next: NextFunction) => void;
|
|
73
|
+
check: (req: Request, _res: Response, next: NextFunction) => void;
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
declare class Property {
|
package/dist/antity.js
CHANGED
|
@@ -205,12 +205,12 @@ function control(v, key, type, min, max, typeCheck, cb) {
|
|
|
205
205
|
c += ` and >= ${min}`;
|
|
206
206
|
if (!isNil(max))
|
|
207
207
|
c += ` and <= ${max}`;
|
|
208
|
-
return val ? null : {
|
|
208
|
+
return val ? null : { statusCode: 400, message: `Invalid ${key}, must be of type ${type}${c}` };
|
|
209
209
|
}
|
|
210
210
|
|
|
211
211
|
function require(v, key, type) {
|
|
212
212
|
log.debug(`require ${key}: ${type} = ${v}`);
|
|
213
|
-
return isNil(v) ? {
|
|
213
|
+
return isNil(v) ? { statusCode: 400, message: `Missing ${key} of type ${type}` } : null;
|
|
214
214
|
}
|
|
215
215
|
|
|
216
216
|
class Entity {
|
|
@@ -218,8 +218,9 @@ class Entity {
|
|
|
218
218
|
this.normalize = (req, _res, next) => {
|
|
219
219
|
var _a;
|
|
220
220
|
const rows = (_a = req.body) === null || _a === void 0 ? void 0 : _a.rows;
|
|
221
|
+
log.debug(`normalize ${this.name}`);
|
|
221
222
|
if (!isArray(rows, "!0"))
|
|
222
|
-
return next({
|
|
223
|
+
return next({ statusCode: 400, message: "Normalize: no rows found in request body" });
|
|
223
224
|
for (const r of rows) {
|
|
224
225
|
for (const { key, type, sanitize: sanitize$1, normalize, sanitizer, normalizer, } of this._properties) {
|
|
225
226
|
let v = r[key];
|
|
@@ -242,12 +243,13 @@ class Entity {
|
|
|
242
243
|
var _a;
|
|
243
244
|
const rows = (_a = req.body) === null || _a === void 0 ? void 0 : _a.rows;
|
|
244
245
|
const method = req.method;
|
|
246
|
+
log.debug(`validate ${this.name}`);
|
|
245
247
|
if (!isArray(rows, "!0"))
|
|
246
|
-
return next({
|
|
248
|
+
return next({ statusCode: 400, message: "Validate: no rows found in request body" });
|
|
247
249
|
if (!isIn(Methods, method))
|
|
248
250
|
return next({
|
|
249
|
-
|
|
250
|
-
|
|
251
|
+
statusCode: 400,
|
|
252
|
+
message: `Invalid REST method. Received: ${method}. Must be one of: ${Methods.toString()}`
|
|
251
253
|
});
|
|
252
254
|
for (const r of rows) {
|
|
253
255
|
for (const { key, type, min, max, required, typeCheck, methods, validate, validator } of this._properties) {
|
|
@@ -268,6 +270,48 @@ class Entity {
|
|
|
268
270
|
}
|
|
269
271
|
next();
|
|
270
272
|
};
|
|
273
|
+
this.check = (req, _res, next) => {
|
|
274
|
+
var _a;
|
|
275
|
+
const rows = (_a = req.body) === null || _a === void 0 ? void 0 : _a.rows;
|
|
276
|
+
const method = req.method;
|
|
277
|
+
log.debug(`check ${this.name}`);
|
|
278
|
+
if (!isArray(rows, "!0"))
|
|
279
|
+
return next({ statusCode: 400, message: "Check: no rows found in request body" });
|
|
280
|
+
if (!isIn(Methods, method))
|
|
281
|
+
return next({
|
|
282
|
+
statusCode: 400,
|
|
283
|
+
message: `Invalid REST method. Received: ${method}. Must be one of: ${Methods.toString()}`
|
|
284
|
+
});
|
|
285
|
+
for (const r of rows) {
|
|
286
|
+
for (const { key, type, min, max, required, typeCheck, methods, validate, sanitize: sanitize$1, normalize, sanitizer, normalizer, validator } of this._properties) {
|
|
287
|
+
let v = r[key];
|
|
288
|
+
if (isIn(methods, method)) {
|
|
289
|
+
if (v) {
|
|
290
|
+
if (sanitize$1) {
|
|
291
|
+
log.debug(`sanitize ${key}: ${type} = ${v}`);
|
|
292
|
+
v = sanitize(v, sanitizer);
|
|
293
|
+
}
|
|
294
|
+
if (normalize && isFunction(normalizer)) {
|
|
295
|
+
log.debug(`normalize ${key}: ${type} = ${v}`);
|
|
296
|
+
v = normalizer(v);
|
|
297
|
+
}
|
|
298
|
+
r[key] = v;
|
|
299
|
+
if (validate) {
|
|
300
|
+
const ct = control(v, key, type, min, max, typeCheck, validator);
|
|
301
|
+
if (ct)
|
|
302
|
+
return next(ct);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
if (required) {
|
|
306
|
+
const rq = require(v, key, type);
|
|
307
|
+
if (rq)
|
|
308
|
+
return next(rq);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
next();
|
|
314
|
+
};
|
|
271
315
|
this._name = name;
|
|
272
316
|
this._properties = [];
|
|
273
317
|
this._unsafeProps = [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dwtechs/antity",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "Open source library for easy entity management",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"entities"
|
|
@@ -38,8 +38,7 @@
|
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@dwtechs/checkard": "3.2.3",
|
|
40
40
|
"@dwtechs/winstan": "0.4.0",
|
|
41
|
-
"@dwtechs/sparray": "0.1.1"
|
|
42
|
-
"pg": "8.13.1"
|
|
41
|
+
"@dwtechs/sparray": "0.1.1"
|
|
43
42
|
},
|
|
44
43
|
"devDependencies": {
|
|
45
44
|
"@babel/core": "7.26.0",
|