@dwtechs/antity 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 DWTechs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,195 @@
1
+
2
+ [![License: MIT](https://img.shields.io/npm/l/@dwtechs/antity.svg?color=brightgreen)](https://opensource.org/licenses/MIT)
3
+ [![npm version](https://badge.fury.io/js/%40dwtechs%2Fantity.svg)](https://www.npmjs.com/package/@dwtechs/antity)
4
+ [![last version release date](https://img.shields.io/github/release-date/DWTechs/Antity.js)](https://www.npmjs.com/package/@dwtechs/antity)
5
+ [![minified size](https://img.shields.io/bundlephobia/min/@dwtechs/antity?color=brightgreen)](https://www.npmjs.com/package/@dwtechs/antity)
6
+
7
+ - [Synopsis](#synopsis)
8
+ - [Support](#support)
9
+ - [Installation](#installation)
10
+ - [Usage](#usage)
11
+ - [ES6](#es6)
12
+ - [API Reference](#api-reference)
13
+ - [Contributors](#contributors)
14
+ - [Stack](#stack)
15
+
16
+
17
+ ## Synopsis
18
+
19
+ **[Antity.js](https://github.com/DWTechs/Antity.js)** is an Open source library for easy entity management.
20
+
21
+ - Only 1 small dependency to check inputs variables
22
+ - Very lightweight
23
+ - Thoroughly tested
24
+ - Works in Javascript, Typescript
25
+ - Can be used as EcmaScrypt module
26
+ - Written in Typescript
27
+
28
+
29
+ ## Support
30
+
31
+ - node: 22
32
+
33
+ This is the oldest targeted versions. The library should work properly on older versions of Node.js but we do not support it officially.
34
+
35
+
36
+ ## Installation
37
+
38
+ ```bash
39
+ $ npm i @dwtechs/antity
40
+ ```
41
+
42
+
43
+ ## Usage
44
+
45
+
46
+ ### ES6 / TypeScript
47
+
48
+ ```javascript
49
+
50
+ import { Entity } from "@dwtechs/antity";
51
+ import { normalizeName, normalizeNickname } from "@dwtechs/checkard";
52
+
53
+ const entity = new Entity("consumer", "consumers", [
54
+ {
55
+ key: "id",
56
+ type: "integer",
57
+ min: 0,
58
+ max: 120,
59
+ typeCheck: true,
60
+ methods: ["get", "put", "delete"],
61
+ required: true,
62
+ sanitize: true,
63
+ normalize: true,
64
+ control: true,
65
+ sanitizer: null,
66
+ normalizer: null,
67
+ controller: null,
68
+ },
69
+ {
70
+ key: "firstName",
71
+ type: "string",
72
+ min: 0,
73
+ max: 255,
74
+ typeCheck: true,
75
+ methods: ["get", "post", "put", "delete"],
76
+ required: true,
77
+ sanitize: true,
78
+ normalize: true,
79
+ control: true,
80
+ sanitizer: null,
81
+ normalizer: normalizeName,
82
+ controller: null,
83
+ },
84
+ {
85
+ key: "lastName",
86
+ type: "string",
87
+ min: 0,
88
+ max: 255,
89
+ typeCheck: true,
90
+ methods: ["get", "post", "put", "delete"],
91
+ required: true,
92
+ sanitize: true,
93
+ normalize: true,
94
+ control: true,
95
+ sanitizer: null,
96
+ normalizer: normalizeName,
97
+ controller: null,
98
+ },
99
+ {
100
+ key: "nickname",
101
+ type: "string",
102
+ min: 0,
103
+ max: 255,
104
+ typeCheck: true,
105
+ methods: ["get", "post", "put", "delete"],
106
+ required: true,
107
+ sanitize: true,
108
+ normalize: true,
109
+ control: true,
110
+ sanitizer: null,
111
+ normalizer: normalizeNickname,
112
+ controller: null,
113
+ },
114
+ ]);
115
+
116
+ req.body = entity.normalize(req.body);
117
+ const check = entity.validate(req.body, req.method);
118
+
119
+ ```
120
+
121
+
122
+ ## API Reference
123
+
124
+
125
+ ```javascript
126
+
127
+ type Type = "boolean" | "string" | "number" | "integer" | "array";
128
+ type Method = "GET" | "PATCH" | "PUT" | "POST" | "DELETE";
129
+
130
+ class Property {
131
+ key: string;
132
+ type: Type;
133
+ min: number;
134
+ max: number;
135
+ required: boolean;
136
+ typeCheck: boolean;
137
+ verbs: Verb[];
138
+ sanitize: boolean;
139
+ normalize: boolean;
140
+ control: boolean;
141
+ sanitizer: Function | null;
142
+ normalizer: Function | null;
143
+ controller: Function | null;
144
+ };
145
+
146
+ class Entity {
147
+ name: string;
148
+ table: string;
149
+ properties: Property[];
150
+ normalize(rows: Record<string, any>[]): Record<string, any>[];
151
+ validate(rows: Record<string, any>[], method: Method): string | null;
152
+ }
153
+
154
+ ```
155
+
156
+
157
+ ### Available options for a property
158
+
159
+ Any of these can be passed into the options object for each function.
160
+
161
+ | Name | Type | Description | Default value |
162
+ | :-------------- | :------------------------ | :------------------------------------------------ | :-------------- |
163
+ | key | string | Name of the property |
164
+ | type | Type | Type of the property |
165
+ | min | number | Minimum value | 0
166
+ | max | number | Maximum value | 999999999
167
+ | required | boolean | Is this property required for these methods | false
168
+ | typeCheck | boolean | Type is checked if true | false
169
+ | methods | Method[] | REST Methods that use the property | [ "GET", "PATCH", "PUT", "POST", "DELETE" ]
170
+ | sanitize | boolean | Sanitize the property if true | true
171
+ | normalize | boolean | Normalize the property if true | false
172
+ | control | boolean | Control the property if true | true
173
+ | sanitizer | ((v:any) => any) \| null | Sanitizer function if sanitize is true | null
174
+ | normalizer | ((v:any) => any) \| null | Normalizer function if normalize is true | null
175
+ | controller | ((v:any, min:number, max:number, typeCheck:boolean) => any) \| null | Controller function if control is true | null
176
+
177
+ * *Min and max parameters are not used for boolean type*
178
+ * *TypeCheck Parameter is not used for boolean, string and array types*
179
+
180
+
181
+ ## Contributors
182
+
183
+ Antity.js is still in development and we would be glad to get all the help you can provide.
184
+ To contribute please read **[contributor.md](https://github.com/DWTechs/Antity.js/blob/main/contributor.md)** for detailed installation guide.
185
+
186
+
187
+ ## Stack
188
+
189
+ | Purpose | Choice | Motivation |
190
+ | :-------------- | :------------------------------------------: | -------------------------------------------------------------: |
191
+ | repository | [Github](https://github.com/) | hosting for software development version control using Git |
192
+ | package manager | [npm](https://www.npmjs.com/get-npm) | default node.js package manager |
193
+ | language | [TypeScript](https://www.typescriptlang.org) | static type checking along with the latest ECMAScript features |
194
+ | module bundler | [Rollup](https://rollupjs.org) | advanced module bundler for ES6 modules |
195
+ | unit testing | [Jest](https://jestjs.io/) | delightful testing with a focus on simplicity |
@@ -0,0 +1,282 @@
1
+ /*
2
+ MIT License
3
+
4
+ Copyright (c) 2024 DWTechs
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+
24
+ https://github.com/DWTechs/Antity.js
25
+ */
26
+
27
+ 'use strict';
28
+
29
+ /*
30
+ MIT License
31
+
32
+ Copyright (c) 2009 DWTechs
33
+
34
+ Permission is hereby granted, free of charge, to any person obtaining a copy
35
+ of this software and associated documentation files (the "Software"), to deal
36
+ in the Software without restriction, including without limitation the rights
37
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
38
+ copies of the Software, and to permit persons to whom the Software is
39
+ furnished to do so, subject to the following conditions:
40
+
41
+ The above copyright notice and this permission notice shall be included in all
42
+ copies or substantial portions of the Software.
43
+
44
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
45
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
46
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
47
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
48
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
49
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
50
+ SOFTWARE.
51
+
52
+ https://github.com/DWTechs/Checkard.js
53
+ */
54
+
55
+ function isNumeric(n) {
56
+ return !isNaN(n - parseFloat(n));
57
+ }
58
+ function getTag(t) {
59
+ return t == null ? t === undefined ? '[object Undefined]' : '[object Null]' : toString.call(t);
60
+ }
61
+
62
+ function isBoolean(b) {
63
+ return typeof b === "boolean";
64
+ }
65
+ function isNumber(n, type = true) {
66
+ return !isSymbol(n) && !((n === null || n === void 0 ? void 0 : n.constructor) === Array) && (type ? Number(n) === n : isNumeric(n));
67
+ }
68
+ function isSymbol(s) {
69
+ const type = typeof s;
70
+ return type === 'symbol' || (type === 'object' && s != null && getTag(s) === '[object Symbol]');
71
+ }
72
+ function isNil(n) {
73
+ return n == null;
74
+ }
75
+
76
+ function isFunction(func) {
77
+ return Boolean(func && getTag(func) === "[object Function]");
78
+ }
79
+
80
+ const comparisons = {
81
+ '=': (a, b) => a == b,
82
+ '<': (a, b) => a < b,
83
+ '>': (a, b) => a > b,
84
+ '<=': (a, b) => a <= b,
85
+ '>=': (a, b) => a >= b
86
+ };
87
+ function isInteger(n, type = true) {
88
+ if (!isNumber(n, type))
89
+ return false;
90
+ const int = Number.parseInt(String(n), 10);
91
+ return type ? n === int : n == int;
92
+ }
93
+
94
+ function isValidNumber(n, min = -999999999, max = 999999999, type = true) {
95
+ return isNumber(n, type) && n >= min && n <= max;
96
+ }
97
+ function isValidInteger(n, min = -999999999, max = 999999999, type = true) {
98
+ return isInteger(n, type) && n >= min && n <= max;
99
+ }
100
+
101
+ function isArray(a, comp, len) {
102
+ return (a === null || a === void 0 ? void 0 : a.constructor) === Array ? (comp && isValidInteger(len, 0, 999999999)) ? comparisons.hasOwnProperty(comp) ? comparisons[comp](a.length, len) : false : true : false;
103
+ }
104
+ function isArrayOfLength(a, min = -999999999, max = 999999999) {
105
+ if (isArray(a, null, null)) {
106
+ const n = a.length;
107
+ return n >= min && n <= max;
108
+ }
109
+ return false;
110
+ }
111
+ function isIn(val, arr) {
112
+ return isArray(arr, '>', 0) ? arr.includes(val) : false;
113
+ }
114
+
115
+ function isString(s, required = false) {
116
+ return typeof s === "string" && (required ? !!s : true);
117
+ }
118
+ function isStringOfLength(s, min = 0, max = 999999999) {
119
+ if (isString(s, false)) {
120
+ const l = s.length;
121
+ return l >= min && l <= max;
122
+ }
123
+ return false;
124
+ }
125
+
126
+ function isObject(o, empty = false) {
127
+ return o !== null && typeof o === "object" && !isArray(o) && (empty ? !!Object.keys(o).length : true);
128
+ }
129
+ function isProperty(val, obj) {
130
+ const v = String(val);
131
+ return isString(v, true) && isObject(obj) ? Object.keys(obj).includes(v) : false;
132
+ }
133
+
134
+ const Methods = ["GET", "PATCH", "PUT", "POST", "DELETE"];
135
+
136
+ const Types = {
137
+ boolean: {
138
+ validate: (v, _min, _max, _typeCheck) => isBoolean(v)
139
+ },
140
+ string: {
141
+ validate: (v, min, max, _typeCheck) => isStringOfLength(v, min, max)
142
+ },
143
+ number: {
144
+ validate: (v, min, max, typeCheck) => isValidNumber(v, min || undefined, max || undefined, typeCheck || undefined)
145
+ },
146
+ integer: {
147
+ validate: (v, min, max, typeCheck) => isValidInteger(v, min || undefined, max || undefined, typeCheck || undefined)
148
+ },
149
+ array: {
150
+ validate: (v, min, max, _typeCheck) => isArrayOfLength(v, min, max)
151
+ }
152
+ };
153
+ const Required = {
154
+ validate: (v) => !isNil(v)
155
+ };
156
+
157
+ class Property {
158
+ constructor(key, type, min, max, required, typeCheck, methods, sanitize, normalize, control, sanitizer, normalizer, controller) {
159
+ if (!isString(key, true))
160
+ throw new Error(`Property key must be a string. Received ${key}`);
161
+ if (!isProperty(type, Types))
162
+ throw new Error(`Property type must be a valid type. Received ${type}`);
163
+ if (isArray(methods)) {
164
+ for (const m of methods) {
165
+ if (!isIn(m, Methods))
166
+ throw new Error(`Property methods must be an array of REST Methods. Received ${m}`);
167
+ }
168
+ }
169
+ this.key = key;
170
+ this.type = type;
171
+ this.min = isInteger(min, true) ? min : 0;
172
+ this.max = isInteger(max, true) ? max : 999999999;
173
+ this.required = isBoolean(required) ? required : false;
174
+ this.typeCheck = isBoolean(typeCheck) ? typeCheck : false;
175
+ this.methods = methods || Methods;
176
+ this.sanitize = isBoolean(sanitize) ? sanitize : true;
177
+ this.normalize = isBoolean(normalize) ? normalize : false;
178
+ this.control = isBoolean(control) ? control : true;
179
+ this.sanitizer = isFunction(sanitizer) ? sanitizer : null;
180
+ this.normalizer = isFunction(normalizer) ? normalizer : null;
181
+ this.controller = isFunction(controller) ? controller : null;
182
+ }
183
+ }
184
+
185
+ const Messages = {
186
+ missing: (key) => `Missing ${key}`,
187
+ invalid: (key, type) => `Invalid ${key}, must be of type ${type}`,
188
+ };
189
+
190
+ class Entity {
191
+ constructor(name, table, properties) {
192
+ this.name = name;
193
+ this.table = table;
194
+ this.properties = this.init(properties);
195
+ }
196
+ init(properties) {
197
+ const props = [];
198
+ for (const p of properties) {
199
+ props.push(new Property(p.key, p.type, p.min, p.max, p.required, p.typeCheck, p.methods, p.sanitize, p.normalize, p.control, p.sanitizer, p.normalizer, p.controller));
200
+ }
201
+ return props;
202
+ }
203
+ cols(method) {
204
+ const cols = [];
205
+ for (const p of this.properties) {
206
+ if (isIn(method, p.methods))
207
+ cols.push(p.key);
208
+ }
209
+ return cols;
210
+ }
211
+ normalize(rows) {
212
+ for (const r of rows) {
213
+ for (const { key, sanitize, normalize, sanitizer, normalizer, } of this.properties) {
214
+ let v = r[key];
215
+ if (v) {
216
+ if (sanitize)
217
+ v = this.sanitize(v, sanitizer);
218
+ if (normalize && normalizer)
219
+ v = normalizer(v);
220
+ r[key] = v;
221
+ }
222
+ }
223
+ }
224
+ return rows;
225
+ }
226
+ validate(rows, method) {
227
+ for (const r of rows) {
228
+ for (const { key, type, min, max, required, typeCheck, methods, control, controller } of this.properties) {
229
+ const v = r[key];
230
+ if (method && isIn(method, methods)) {
231
+ if (required) {
232
+ const rq = this.require(v, key);
233
+ if (rq)
234
+ return rq;
235
+ }
236
+ if (control) {
237
+ const ct = this.control(v, key, type, min, max, typeCheck, controller);
238
+ if (ct)
239
+ return ct;
240
+ }
241
+ }
242
+ }
243
+ }
244
+ return null;
245
+ }
246
+ require(v, key) {
247
+ return Required.validate(v) ? null : Messages.missing(key);
248
+ }
249
+ control(v, key, type, min, max, typeCheck, cb) {
250
+ if (cb)
251
+ return cb(v) ? null : Messages.invalid(key, type);
252
+ return Types[type].validate(v, min, max, typeCheck) ? null : Messages.invalid(key, type);
253
+ }
254
+ sanitize(v, cb) {
255
+ if (cb)
256
+ return cb(v);
257
+ if (isArray(v, null, null)) {
258
+ for (let d of v) {
259
+ d = this.trim(d);
260
+ }
261
+ return v;
262
+ }
263
+ return this.trim(v);
264
+ }
265
+ trim(v) {
266
+ if (isString(v, true))
267
+ return v.trim();
268
+ if (isObject(v, true)) {
269
+ if (v.has)
270
+ for (const p in v) {
271
+ if (v.prototype.hasOwnProperty.call(p)) {
272
+ let o = v[p];
273
+ if (isString(o, true))
274
+ o = o.trim();
275
+ }
276
+ }
277
+ return v;
278
+ }
279
+ }
280
+ }
281
+
282
+ exports.Entity = Entity;
@@ -0,0 +1,113 @@
1
+ /*
2
+ MIT License
3
+
4
+ Copyright (c) 2024 DWTechs
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+
24
+ https://github.com/DWTechs/Antity.js
25
+ */
26
+
27
+
28
+ type Type = keyof typeof Types;
29
+ type Method = typeof Methods[number];
30
+
31
+ declare const Methods: readonly ["GET", "PATCH", "PUT", "POST", "DELETE"];
32
+
33
+ declare const Types: {
34
+ readonly boolean: {
35
+ readonly validate: (v: any, _min: number, _max: number, _typeCheck: boolean) => v is boolean;
36
+ };
37
+ readonly string: {
38
+ readonly validate: (v: any, min: number, max: number, _typeCheck: boolean) => v is string;
39
+ };
40
+ readonly number: {
41
+ readonly validate: (v: any, min: number, max: number, typeCheck: boolean) => v is number;
42
+ };
43
+ readonly integer: {
44
+ readonly validate: (v: any, min: number, max: number, typeCheck: boolean) => v is number;
45
+ };
46
+ readonly array: {
47
+ readonly validate: (v: any, min: number, max: number, _typeCheck: boolean) => v is any[];
48
+ };
49
+ };
50
+
51
+ declare const Required: {
52
+ validate: (v: any) => boolean;
53
+ };
54
+
55
+ declare class Entity {
56
+ name: string;
57
+ table: string;
58
+ properties: Property[];
59
+ constructor(name: string, table: string, properties: Property[]);
60
+ private init;
61
+ cols(method: Method): string[];
62
+ normalize(rows: Record<string, any>[]): Record<string, any>[];
63
+ validate(rows: Record<string, any>[], method: Method): string | null;
64
+ private require;
65
+ private control;
66
+ private sanitize;
67
+ private trim;
68
+ }
69
+
70
+ declare const Messages: {
71
+ missing: (key: string) => string;
72
+ invalid: (key: string, type: Type) => string;
73
+ };
74
+
75
+ declare class Property {
76
+ key: string;
77
+ type: Type;
78
+ min: number;
79
+ max: number;
80
+ required: boolean;
81
+ typeCheck: boolean;
82
+ methods: Method[];
83
+ sanitize: boolean;
84
+ normalize: boolean;
85
+ control: boolean;
86
+ sanitizer: ((v: any) => any) | null;
87
+ normalizer: ((v: any) => any) | null;
88
+ controller: ((v: any) => any) | null;
89
+ constructor(key: string,
90
+ type: Type,
91
+ min: number,
92
+ max: number,
93
+ required: boolean,
94
+ typeCheck: boolean,
95
+ methods: Method[],
96
+ sanitize: boolean,
97
+ normalize: boolean,
98
+ control: boolean,
99
+ sanitizer: ((v: any) => any) | null,
100
+ normalizer: ((v: any) => any) | null,
101
+ controller: ((v: any) => any) | null
102
+ );
103
+ }
104
+ export type { Type, Method };
105
+ export {
106
+ Entity,
107
+ Property,
108
+ Messages,
109
+ Types,
110
+ Required,
111
+ Methods
112
+ };
113
+
package/dist/antity.js ADDED
@@ -0,0 +1,177 @@
1
+ /*
2
+ MIT License
3
+
4
+ Copyright (c) 2024 DWTechs
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+
24
+ https://github.com/DWTechs/Antity.js
25
+ */
26
+
27
+ import { isBoolean, isStringOfLength, isValidNumber, isValidInteger, isArrayOfLength, isNil, isString, isProperty, isArray, isIn, isInteger, isFunction, isObject } from '@dwtechs/checkard';
28
+
29
+ const Methods = ["GET", "PATCH", "PUT", "POST", "DELETE"];
30
+
31
+ const Types = {
32
+ boolean: {
33
+ validate: (v, _min, _max, _typeCheck) => isBoolean(v)
34
+ },
35
+ string: {
36
+ validate: (v, min, max, _typeCheck) => isStringOfLength(v, min, max)
37
+ },
38
+ number: {
39
+ validate: (v, min, max, typeCheck) => isValidNumber(v, min || undefined, max || undefined, typeCheck || undefined)
40
+ },
41
+ integer: {
42
+ validate: (v, min, max, typeCheck) => isValidInteger(v, min || undefined, max || undefined, typeCheck || undefined)
43
+ },
44
+ array: {
45
+ validate: (v, min, max, _typeCheck) => isArrayOfLength(v, min, max)
46
+ }
47
+ };
48
+ const Required = {
49
+ validate: (v) => !isNil(v)
50
+ };
51
+
52
+ class Property {
53
+ constructor(key, type, min, max, required, typeCheck, methods, sanitize, normalize, control, sanitizer, normalizer, controller) {
54
+ if (!isString(key, true))
55
+ throw new Error(`Property key must be a string. Received ${key}`);
56
+ if (!isProperty(type, Types))
57
+ throw new Error(`Property type must be a valid type. Received ${type}`);
58
+ if (isArray(methods)) {
59
+ for (const m of methods) {
60
+ if (!isIn(m, Methods))
61
+ throw new Error(`Property methods must be an array of REST Methods. Received ${m}`);
62
+ }
63
+ }
64
+ this.key = key;
65
+ this.type = type;
66
+ this.min = isInteger(min, true) ? min : 0;
67
+ this.max = isInteger(max, true) ? max : 999999999;
68
+ this.required = isBoolean(required) ? required : false;
69
+ this.typeCheck = isBoolean(typeCheck) ? typeCheck : false;
70
+ this.methods = methods || Methods;
71
+ this.sanitize = isBoolean(sanitize) ? sanitize : true;
72
+ this.normalize = isBoolean(normalize) ? normalize : false;
73
+ this.control = isBoolean(control) ? control : true;
74
+ this.sanitizer = isFunction(sanitizer) ? sanitizer : null;
75
+ this.normalizer = isFunction(normalizer) ? normalizer : null;
76
+ this.controller = isFunction(controller) ? controller : null;
77
+ }
78
+ }
79
+
80
+ const Messages = {
81
+ missing: (key) => `Missing ${key}`,
82
+ invalid: (key, type) => `Invalid ${key}, must be of type ${type}`,
83
+ };
84
+
85
+ class Entity {
86
+ constructor(name, table, properties) {
87
+ this.name = name;
88
+ this.table = table;
89
+ this.properties = this.init(properties);
90
+ }
91
+ init(properties) {
92
+ const props = [];
93
+ for (const p of properties) {
94
+ props.push(new Property(p.key, p.type, p.min, p.max, p.required, p.typeCheck, p.methods, p.sanitize, p.normalize, p.control, p.sanitizer, p.normalizer, p.controller));
95
+ }
96
+ return props;
97
+ }
98
+ cols(method) {
99
+ const cols = [];
100
+ for (const p of this.properties) {
101
+ if (isIn(method, p.methods))
102
+ cols.push(p.key);
103
+ }
104
+ return cols;
105
+ }
106
+ normalize(rows) {
107
+ for (const r of rows) {
108
+ for (const { key, sanitize, normalize, sanitizer, normalizer, } of this.properties) {
109
+ let v = r[key];
110
+ if (v) {
111
+ if (sanitize)
112
+ v = this.sanitize(v, sanitizer);
113
+ if (normalize && normalizer)
114
+ v = normalizer(v);
115
+ r[key] = v;
116
+ }
117
+ }
118
+ }
119
+ return rows;
120
+ }
121
+ validate(rows, method) {
122
+ for (const r of rows) {
123
+ for (const { key, type, min, max, required, typeCheck, methods, control, controller } of this.properties) {
124
+ const v = r[key];
125
+ if (method && isIn(method, methods)) {
126
+ if (required) {
127
+ const rq = this.require(v, key);
128
+ if (rq)
129
+ return rq;
130
+ }
131
+ if (control) {
132
+ const ct = this.control(v, key, type, min, max, typeCheck, controller);
133
+ if (ct)
134
+ return ct;
135
+ }
136
+ }
137
+ }
138
+ }
139
+ return null;
140
+ }
141
+ require(v, key) {
142
+ return Required.validate(v) ? null : Messages.missing(key);
143
+ }
144
+ control(v, key, type, min, max, typeCheck, cb) {
145
+ if (cb)
146
+ return cb(v) ? null : Messages.invalid(key, type);
147
+ return Types[type].validate(v, min, max, typeCheck) ? null : Messages.invalid(key, type);
148
+ }
149
+ sanitize(v, cb) {
150
+ if (cb)
151
+ return cb(v);
152
+ if (isArray(v, null, null)) {
153
+ for (let d of v) {
154
+ d = this.trim(d);
155
+ }
156
+ return v;
157
+ }
158
+ return this.trim(v);
159
+ }
160
+ trim(v) {
161
+ if (isString(v, true))
162
+ return v.trim();
163
+ if (isObject(v, true)) {
164
+ if (v.has)
165
+ for (const p in v) {
166
+ if (v.prototype.hasOwnProperty.call(p)) {
167
+ let o = v[p];
168
+ if (isString(o, true))
169
+ o = o.trim();
170
+ }
171
+ }
172
+ return v;
173
+ }
174
+ }
175
+ }
176
+
177
+ export { Entity };
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@dwtechs/antity",
3
+ "version": "0.1.0",
4
+ "description": "Open source library for easy entity management",
5
+ "keywords": [
6
+ "entities"
7
+ ],
8
+ "homepage": "https://github.com/DWTechs/Antity.js",
9
+ "main": "dist/antity",
10
+ "types": "dist/antity",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/DWTechs/Antity.js"
14
+ },
15
+ "bugs": {
16
+ "url": "https://github.com/DWTechs/Antity.js/issues",
17
+ "email": ""
18
+ },
19
+ "license": "MIT",
20
+ "author": {
21
+ "name": "Ludovic Cluber",
22
+ "email": "http://www.lcluber.com/contact",
23
+ "url": "http://www.lcluber.com"
24
+ },
25
+ "contributors": [],
26
+ "scripts": {
27
+ "start": "",
28
+ "build": "node ./scripts/clear && tsc && npm run rollup && node ./scripts/copy && npm run test",
29
+ "rollup:mjs": "rollup --config rollup.config.mjs",
30
+ "rollup:cjs": "rollup --config rollup.config.cjs.mjs",
31
+ "rollup": "npm run rollup:mjs && npm run rollup:cjs",
32
+ "test": "jest --coverage"
33
+ },
34
+ "files": [
35
+ "dist/"
36
+ ],
37
+ "dependencies": {
38
+ "@dwtechs/checkard": "2.29.2"
39
+ },
40
+ "devDependencies": {
41
+ "@babel/core": "7.26.0",
42
+ "@babel/preset-env": "7.26.0",
43
+ "@rollup/plugin-commonjs": "28.0.1",
44
+ "@rollup/plugin-node-resolve": "15.3.0",
45
+ "@types/jest": "29.5.14",
46
+ "babel-jest": "29.7.0",
47
+ "core-js": "3.33.0",
48
+ "jest": "29.7.0",
49
+ "rollup": "4.24.0",
50
+ "typescript": "5.6.3"
51
+ }
52
+ }