@where-org/where-common 2.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.
@@ -0,0 +1,90 @@
1
+ // casing
2
+ const casing = {
3
+
4
+ // pascal
5
+ toPascal: (word) => {
6
+ return word.replace(/[_-]./g, (s) => s[1].toUpperCase()).replace(/^./, (s) => s.toUpperCase());
7
+ },
8
+
9
+ camelToPascal: (word) => {
10
+ return word.replace(/^./, (s) => s.toUpperCase());
11
+ },
12
+
13
+ snakeToPascal: (word) => {
14
+ return word.replace(/_./g, (s) => s[1].toUpperCase()).replace(/^./, (s) => s.toUpperCase());
15
+ },
16
+
17
+ kebabToPascal: (word) => {
18
+ return word.replace(/-./g, (s) => s[1].toUpperCase()).replace(/^./, (s) => s.toUpperCase());
19
+ },
20
+
21
+ // camel
22
+ toCamel: (word) => {
23
+ return word.replace(/[_-]./g, (s) => s[1].toUpperCase()).replace(/^./, (s) => s.toLowerCase());
24
+ },
25
+
26
+ pascalToCamel: (word) => {
27
+ return word.replace(/^./, (s) => s.toLowerCase());
28
+ },
29
+
30
+ snakeToCamel: (word) => {
31
+ return word.replace(/_./g, (s) => s[1].toUpperCase());
32
+ },
33
+
34
+ kebabToCamel: (word) => {
35
+ return word.replace(/-./g, (s) => s[1].toUpperCase());
36
+ },
37
+
38
+ // snake
39
+ toSnake:(word) => {
40
+ return word.replace(/^./, (s) => s.toLowerCase()).replace(/([A-Z])/g, (s) => '_' + s[0].toLowerCase()).replace(/-/g, '_');
41
+ },
42
+
43
+ camelToSnake: (word) => {
44
+ return word.replace(/([A-Z])/g, (s) => '_' + s[0].toLowerCase());
45
+ },
46
+
47
+ pascalToSnake: (word) => {
48
+ return word.replace(/^./, (s) => s.toLowerCase()).replace(/([A-Z])/g, (s) => '_' + s[0].toLowerCase());
49
+ },
50
+
51
+ kebabToSnake: (word) => {
52
+ return word.replace(/^./, (s) => s.toLowerCase()).replace(/-/g, '_');
53
+ },
54
+
55
+ // kebab
56
+ toKebab: (word) => {
57
+ return word.replace(/^./, (s) => s.toLowerCase()).replace(/([A-Z])/g, (s) => '-' + s[0].toLowerCase()).replace(/_/g, '-');
58
+ },
59
+
60
+ camelToKebab: (word) => {
61
+ return word.replace(/([A-Z])/g, (s) => '-' + s[0].toLowerCase());
62
+ },
63
+
64
+ pascalToKebab: (word) => {
65
+ return word.replace(/^./, (s) => s.toLowerCase()).replace(/([A-Z])/g, (s) => '-' + s[0].toLowerCase());
66
+ },
67
+
68
+ snakeToKebab: (word) => {
69
+ return word.replace(/_/g, '-');
70
+ },
71
+
72
+ ...Object.entries({ keysToCamel: 'toCamel', keysToPascal: 'toPascal', keysToSnake: 'toSnake', keysToKebab : 'toKebab' }).reduce((o, [k, f]) => {
73
+
74
+ return { ...o, [k]: (data) => {
75
+
76
+ const isArray = Array.isArray(data);
77
+
78
+ const [first, ...rest] = (isArray ? data : [data]).map(v => {
79
+ return Object.entries(v).reduce((o, [k, v]) => ({ ...o, [casing[f](k)]: v }), {});
80
+ });
81
+
82
+ return isArray ? [first, ...rest] : first;
83
+
84
+ } };
85
+
86
+ }, {}),
87
+
88
+ };
89
+
90
+ export { casing };
@@ -0,0 +1,18 @@
1
+ import { date } from './date.js';
2
+
3
+ const cast = (value) => {
4
+
5
+ try {
6
+ return JSON.parse(value);
7
+ } catch (err) {
8
+ }
9
+
10
+ if (value.match(date.iso8601)) {
11
+ return new Date(value);
12
+ }
13
+
14
+ return value;
15
+
16
+ }
17
+
18
+ export { cast };
@@ -0,0 +1,25 @@
1
+ const date = {
2
+
3
+ iso8601: /^\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d(\.\d+)?([+-][0-2]\d:[0-5]\d|Z)$/,
4
+
5
+ isIsoString: (v) => {
6
+ return (v && v.match && v.match(date.iso8601)) ? true : false;
7
+ },
8
+
9
+ isString: (v) => {
10
+ return (date.isIsoString(v) || typeof v === 'string' && isNaN(v) && !isNaN(new Date(v).getDate())) ? true : false;
11
+ },
12
+
13
+ isDate: (v) => {
14
+ return v instanceof Date || Object.prototype.toString.call(v) === '[object Date]'
15
+ },
16
+
17
+ string: (v) => {
18
+ return new Intl.DateTimeFormat('ja-jp', {
19
+ year: 'numeric', month : '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit'
20
+ }).format(v).replace(/\//g, '-');
21
+ }
22
+
23
+ };
24
+
25
+ export { date };
@@ -0,0 +1,7 @@
1
+ import { casing } from './casing.js';
2
+ import { cast } from './cast.js';
3
+ import { date } from './date.js';
4
+ import { url } from './url.js';
5
+
6
+ const util = { casing, cast, date, url };
7
+ export { util };
@@ -0,0 +1,50 @@
1
+ import { UrlException } from '../../exception.js';
2
+
3
+ const socket = {
4
+
5
+ parse: (string) => {
6
+ const split = new URL(string).pathname.split('/').filter(v => v);
7
+
8
+ const lastIndex = split.length - 1,
9
+ userIndex = (split[lastIndex].match(':')) ? lastIndex - 1 : lastIndex;
10
+
11
+ const [app, group, user] = [...Array(3)].map((v, i) => split[userIndex - i]).reverse();
12
+
13
+ const option = (lastIndex === userIndex) ? {} : split[lastIndex].split(',').reduce((o, v1) => {
14
+ const [k, v] = v1.split(':');
15
+ return { ...o, [k]: v };
16
+ }, {});
17
+
18
+ return { url: string, app, group, user, ...option };
19
+ },
20
+
21
+ string: (pre) => {
22
+ const { url, group, user, ...option } = pre;
23
+
24
+ const optionString = Object.entries(option).map(([k, v]) => {
25
+ return [k, v].join(':');
26
+ }).join(',');
27
+
28
+ const [app] = url.replace(/\/?$/, '').split('/').reverse();
29
+ return { url: [url, group, user, optionString].join('/'), app, group, user, ...option };
30
+ },
31
+
32
+ either: (config) => {
33
+ const { url, group, user, ...option } = config;
34
+
35
+ try {
36
+ return (group && user) ? socket.string(config) : socket.parse(url);
37
+
38
+ } catch (err) {
39
+
40
+ throw (err instanceof TypeError)
41
+ ? new UrlException((url) ? `"${url}" invalid URL` : '"url" undefined')
42
+ : err;
43
+ }
44
+
45
+ }
46
+
47
+ };
48
+
49
+ const url = { socket };
50
+ export { url };
package/lib/common.js ADDED
@@ -0,0 +1,6 @@
1
+ export * as cq from './cq.js';
2
+ export * as da from './da.js';
3
+ export * as define from './define.js';
4
+ export * as common from './common/index.js';
5
+
6
+ export * from './exception.js';
package/lib/cq.js ADDED
@@ -0,0 +1,122 @@
1
+ import { cast } from './common/util/cast.js';
2
+
3
+ const operators = [
4
+ '=', '!', '<', '>', '<=', '>=', '-', '*', '!*',
5
+ ];
6
+
7
+ const shortToLong = {
8
+ s: 'select', w: 'where', o: 'order', l: 'limit',
9
+ };
10
+
11
+ const longToShort = Object.entries(shortToLong).reduce((o, [k, v]) => ({ ...o, [v]: k }), {});
12
+
13
+ const normalizeKey = Object.entries(shortToLong).reduce((o, [k, v]) => {
14
+ return { ...o, [k]: v, [v]: v };
15
+ }, {});
16
+
17
+ // parse
18
+ const parse = (string, ignore) => {
19
+
20
+ // prepare
21
+ const prepare = (string, ignore) => {
22
+
23
+ const r1 = /([^\/]*["'].*?["'][^\/]*)|\//,
24
+ sp = string.trim().replace(/^\/|\/$/g, '').split(r1).filter(v => v);
25
+
26
+ return sp.reduce((o, v, i, s) => {
27
+
28
+ if (i % 2 !== 0) {
29
+ return { ...o, [s[i - 1]]: v };
30
+ }
31
+
32
+ if (ignore || normalizeKey[v]) {
33
+ return o;
34
+ }
35
+
36
+ throw new Error(`${v} is not allowed.`);
37
+
38
+ }, {});
39
+
40
+ };
41
+
42
+ // split
43
+ const split = (string) => {
44
+
45
+ const r1 = /([^:]*?["'].*?["'][^:]*)|:/,
46
+ r2 = /([^,]*?["'].*?["'][^,]*)|,/,
47
+ r3 = /^["']|["']$/g;
48
+
49
+ return string.split(r1).filter(v => v).reduce((o, v) => {
50
+
51
+ const [k, first, ...values] = v.split(r2).filter(v => v).map((v) => cast(v.replace(r3, '')));
52
+ return { ...o, [k]: (values.length) ? [first, ...values] : (first !== undefined) ? first : null };
53
+
54
+ }, {});
55
+
56
+ }
57
+
58
+ const object = (typeof string === 'string') ? prepare(string, ignore) : string,
59
+ r1 = /([^\|]*["'].*?["'][^\|]*)|\|/;
60
+
61
+ const { select, limit, ...wo } = Object.entries(object).reduce((o, [k, v]) => {
62
+
63
+ if (!normalizeKey[k]) {
64
+ return o;
65
+ }
66
+
67
+ const [first, ...or] = v.split(r1).filter(v => v),
68
+ values = or.length ? { or: [first, ...or].map(v => split(v)) } : split(first);
69
+
70
+ return { ...o, [normalizeKey[k]]: values };
71
+
72
+ }, {});
73
+
74
+ const s = (!select) ? {} : {
75
+
76
+ select: Object.entries(select).reduce((o, [k, v]) => {
77
+ return [...o, k, ...(Array.isArray(v) ? v : [v])];
78
+ }, []).filter(v => v)
79
+
80
+ };
81
+
82
+ const l = !limit || 'offset' in limit && !('limit' in limit) || 'or' in limit
83
+ ? {}
84
+ : { limit: Object.entries(limit).reduce(
85
+ (o, [k, v]) => (['offset', 'limit'].includes(k) ? { ...o, [k]: v } : o), {}) };
86
+
87
+ return { ...s, ...wo, ...l };
88
+
89
+ }
90
+
91
+ // string
92
+ const string = (object) => {
93
+
94
+ const join = (object, separator) => {
95
+ return Object.entries(object).map(([k, v]) => [k, String(v)].join(',')).join(separator);
96
+ };
97
+
98
+ const { select, where, order, limit, ...rest } = object;
99
+
100
+ // genmitsu ni suru baai ha reigai wo hassei sasemasu.
101
+ //if(rest){
102
+ //throw new Error('no where condition object.');
103
+ //}
104
+
105
+ // s
106
+ const s = select ? [longToShort.select, select.join(',')].join('/') : undefined;
107
+
108
+ // w, o
109
+ const [w, o] = Object.entries({ where, order }).filter(([k, v]) => v).map(([k, v]) => {
110
+ const values = (v.or) ? v.or.map(v => join(v, ':')).join('|') : join(v, ':');
111
+ return [longToShort[k], values].join('/');
112
+ });
113
+
114
+ // l
115
+ const { offset: lo, limit: lv } = limit ?? {},
116
+ l = lv ? [longToShort.limit, [lo ? `offset,${lo}` : undefined, `limit,${lv}`].join(':')].join('/') : undefined;
117
+
118
+ return [s, w, o, l].filter(v => v).join('/');
119
+
120
+ }
121
+
122
+ export { parse, string };
package/lib/da.js ADDED
@@ -0,0 +1,291 @@
1
+ import { cast } from './common/util/cast.js';
2
+ import { multipartFormDataKey } from './define.js';
3
+
4
+ const operators = {
5
+
6
+ '=': (k, v, data) => {
7
+
8
+ const values = Array.isArray(v) ? v : [v];
9
+
10
+ const [first] = values,
11
+ v1 = (first === null) ? String(first) : first; //.toLowerCase();
12
+
13
+ const isNull = {
14
+ 'null' : true, 'not-null': false
15
+ };
16
+
17
+ if (Object.keys(isNull).includes(v1)) {
18
+ return (v1 === 'null') ? data === null : data !== null;
19
+
20
+ } else {
21
+ return values.filter(v => data === v).length > 0;
22
+ }
23
+ },
24
+
25
+ '!': (k, v, data) => {
26
+
27
+ const values = Array.isArray(v) ? v : [v];
28
+
29
+ const [first] = values,
30
+ v1 = (first === null) ? String(first) : first.toLowerCase();
31
+
32
+ const isNull = {
33
+ 'null' : true, 'not-null': false
34
+ };
35
+
36
+ if (Object.keys(isNull).includes(v1)) {
37
+ return (v1 === 'null') ? data !== null : data === null;
38
+
39
+ } else {
40
+ return values.filter(v => data !== v).length > 0;
41
+ }
42
+ },
43
+
44
+ '<': (k, v, data) => {
45
+ const v1 = Array.isArray(v) ? v[0] : v;
46
+ return (isNaN(v1) || isNaN(data)) ? false : data < v1;
47
+ },
48
+
49
+ '>': (k, v, data) => {
50
+ const v1 = Array.isArray(v) ? v[0] : v;
51
+ return (isNaN(v1) || isNaN(data)) ? false : data > v1;
52
+ },
53
+
54
+ '<=':(k, v, data) => {
55
+ const v1 = Array.isArray(v) ? v[0] : v;
56
+ return (isNaN(v1) || isNaN(data)) ? false : data <= v1;
57
+ },
58
+
59
+ '>=':(k, v, data) => {
60
+ const v1 = Array.isArray(v) ? v[0] : v;
61
+ return (isNaN(v1) || isNaN(data)) ? false : data >= v1;
62
+ },
63
+
64
+ '-': (k, v, data) => {
65
+
66
+ if (!Array.isArray(v) || isNaN(data)) {
67
+ return false;
68
+ }
69
+
70
+ const [v1, v2] = v;
71
+ return v1 <= data && data <= v2;
72
+ },
73
+
74
+ '*': (k, v, data) => {
75
+
76
+ if (Array.isArray(v)) {
77
+ return false;
78
+ }
79
+
80
+ const v1 = v.replace(/[\\^$.\-+?()[\]{}|]/g, '\\$&').replace(/\*/g, '.*');
81
+
82
+ try {
83
+ return data.match(new RegExp(`^${v1}$`, 's'));
84
+
85
+ } catch(err) {
86
+ return false;
87
+ }
88
+
89
+ },
90
+
91
+ '!*': (k, v, data) => {
92
+
93
+ if (Array.isArray(v)) {
94
+ return false;
95
+ }
96
+
97
+ const v1 = v.replace(/[\\^$.\-+?()[\]{}|]/g, '\\$&').replace(/\*/g, '.*');
98
+
99
+ try {
100
+ return !data.match(new RegExp(`^${v1}$`, 's'));
101
+
102
+ } catch(err) {
103
+ return false;
104
+ }
105
+
106
+ },
107
+
108
+ };
109
+
110
+ // split
111
+ const split = (operators) => {
112
+
113
+ const r1 = operators.map(v => v.replace(/[\\^$.\-*+?()[\]{}|]/g, '\\$&')).join('|'),
114
+ r2 = new RegExp(`(${r1})$`);
115
+
116
+ return (key) => {
117
+ return [key.replace(r2, ''), (key.match(r2)) ? key.match(r2)[0] : '='];
118
+ };
119
+
120
+ }
121
+
122
+ // pasrse
123
+ const parse = (object, contentType) => {
124
+
125
+ // { k1: [v1, v2], k2: [v1 , v2], ... } (multipart/form-data)
126
+
127
+ if (contentType && contentType.match(/multipart\/form-data/)) {
128
+
129
+ if (object && object[multipartFormDataKey]) {
130
+ const data = JSON.parse(object[multipartFormDataKey]);
131
+ return (Array.isArray(data)) ? data : [data];
132
+ }
133
+
134
+ return Object.values(Object.entries(object).reduce((o, [k, v]) => {
135
+ return ((Array.isArray(v)) ? v : [v]).reduce((o, v, i) => ({ ...o, [i]: { ...o[i], [k]: cast(v) } }), o);
136
+ }, {}));
137
+
138
+ }
139
+
140
+ // {k1: v1, ... }
141
+
142
+ if (Object.keys(object).filter(v => isNaN(v)).length) {
143
+ return [object];
144
+ }
145
+
146
+ const [header, ...body] = Object.values(object);
147
+
148
+ // [[k1, k2, ... ], [v1, v2, ... ], ... ]
149
+
150
+ if (header && Array.isArray(header)) {
151
+ return body.map((v) => v.reduce((o, v, i) => ({ ...o, [header[i]]: cast(v) }), {}));
152
+ }
153
+
154
+ // [{k1: v1}, {k2: v2}, ...] || {}
155
+
156
+ return (Array.isArray(object)) ? object : [object];
157
+
158
+ }
159
+
160
+ // filter
161
+ const filter = (() => {
162
+
163
+ const sp = split(Object.keys(operators));
164
+
165
+ const filter = {
166
+
167
+ select: (data, condition) => {
168
+
169
+ const [first] = data;
170
+
171
+ if (condition.includes('*') || !first) {
172
+ return data;
173
+ }
174
+
175
+ const keys = Object.keys(first);
176
+
177
+ if (condition.includes('count')) {
178
+
179
+ return [condition.reduce((o, k) => {
180
+
181
+ if (k !== 'count' && !keys.includes(k)) {
182
+ throw new Error(`No such column ${k}`);
183
+ }
184
+ return { ...o, [k]: (k == 'count') ? data.length : first[k] };
185
+
186
+ }, {})];
187
+
188
+ }
189
+
190
+ return condition.reduce((o, k) => {
191
+
192
+ if (!keys.includes(k)) {
193
+ throw new Error(`No such column ${k}`);
194
+ }
195
+
196
+ return o.map((v, i) => ({ ...v, [k]: data[i][k] }));
197
+
198
+ }, data.map(v => ({})));
199
+ },
200
+
201
+ where: (data, condition) => {
202
+
203
+ const [first] = data;
204
+
205
+ if (!first) {
206
+ return data;
207
+ }
208
+
209
+ const keys = Object.keys(first);
210
+
211
+ return data.filter((v) => {
212
+
213
+ const or = condition.filter((cv) => {
214
+
215
+ const conditionArray = Object.entries(cv);
216
+
217
+ return conditionArray.length === conditionArray.filter(([ak, av]) => {
218
+
219
+ const [k, op] = sp(ak);
220
+
221
+ if (!keys.includes(k)) {
222
+ throw new Error(`No such column ${k}`);
223
+ }
224
+
225
+ return operators[op](k, av, v[k]);
226
+
227
+ }).length;
228
+
229
+ });
230
+
231
+ return or.length > 0;
232
+ });
233
+
234
+ },
235
+
236
+ order: (data, condition) => {
237
+
238
+ return Object.entries(condition).reduce((o, [k, v]) => {
239
+
240
+ const asc = (v.toLowerCase() !== 'desc') ? true : false;
241
+
242
+ return [...o].sort((a, b) => {
243
+
244
+ const orderA = (asc) ? a[k] : b[k],
245
+ orderB = (asc) ? b[k] : a[k];
246
+
247
+ if (typeof orderA !== 'string' || typeof orderB !== 'string') {
248
+ return orderA - orderB;
249
+ }
250
+
251
+ const upperA = orderA.toUpperCase(),
252
+ upperB = orderB.toUpperCase();
253
+
254
+ return (upperA > upperB) ? 1 : (upperA < upperB) ? -1 : 0;
255
+ });
256
+
257
+ }, data);
258
+
259
+ },
260
+
261
+ limit: (data, condition) => {
262
+
263
+ if (!('limit' in condition)) {
264
+ return data;
265
+ }
266
+
267
+ const { offset = 0, limit } = condition;
268
+ return data.slice(offset, limit + offset);
269
+
270
+ }
271
+
272
+ };
273
+
274
+ return (object, condition) => {
275
+
276
+ const {where: w = null, order: o, select: s, limit: l} = condition || {},
277
+ where = (w) ? { where: (w.or) ? w.or : [w] } : {};
278
+
279
+ const [order, select, limit] = Object.entries({ order: o, select: s, limit: l }).map(([k, v]) => {
280
+ return (v) ? { [k]: v } : {};
281
+ });
282
+
283
+ return Object.entries({ ...where, ...order, ...select, ...limit }).reduce((o, [k, v]) => {
284
+ return filter[k](o, v);
285
+ }, object);
286
+
287
+ };
288
+
289
+ })();
290
+
291
+ export { split, parse, filter };
package/lib/define.js ADDED
@@ -0,0 +1,22 @@
1
+ const multipartFormDataKey = 'where-data-json',
2
+ filesKey = 'where-data-files';
3
+
4
+ const status = {
5
+ // 400
6
+ code400: { number: 400, message: '400 Bad Request' },
7
+ code401: { number: 401, message: '401 Unauthorized' },
8
+ code403: { number: 403, message: '403 Forbidden' },
9
+ code404: { number: 404, message: '404 Not Found' },
10
+ code405: { number: 405, message: '405 Method Not Allowed' },
11
+ code413: { number: 413, message: '413 Payload Too Large' },
12
+ code418: { number: 418, message: "418 I'm a teapot" },
13
+ code451: { number: 451, message: '451 Unavailable For Legal Reasons' },
14
+ // 500
15
+ code500: { number: 500, message: '500 Internal Server Error' },
16
+ code501: { number: 501, message: '501 Not Implemented' },
17
+ code502: { number: 502, message: '502 Bad Gateway' },
18
+ code503: { number: 503, message: '503 Service Unavailable' },
19
+ code504: { number: 504, message: '504 Gateway Timeout' },
20
+ };
21
+
22
+ export { multipartFormDataKey, filesKey, status };