@laboratoria/sdk-js 5.3.1 → 6.0.0-beta.0
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/laboratoria-sdk-es.js +9017 -0
- package/dist/laboratoria-sdk-umd.js +1486 -2
- package/package.json +23 -22
- package/.babelrc +0 -5
- package/dist/laboratoria-sdk-esm.js +0 -2
- package/dist/laboratoria-sdk-esm.js.LICENSE.txt +0 -101
- package/dist/laboratoria-sdk-umd.js.LICENSE.txt +0 -101
- package/examples/esm.html +0 -4
- package/examples/umd.html +0 -4
- package/index.js +0 -64
- package/lib/client.js +0 -25
- package/lib/core.js +0 -373
- package/lib/curriculum.js +0 -59
- package/lib/model.js +0 -343
- package/lib/roles.js +0 -10
- package/lib/util.js +0 -68
- package/schemas/core.json +0 -1945
- package/webpack.config.mjs +0 -28
package/lib/model.js
DELETED
@@ -1,343 +0,0 @@
|
|
1
|
-
import { createClient } from './client.js';
|
2
|
-
|
3
|
-
|
4
|
-
const createValidator = (schema) => {
|
5
|
-
const properties = schema.properties || {};
|
6
|
-
const inputProps = schema.inputProps || Object.keys(properties);
|
7
|
-
|
8
|
-
const validateAttr = (key, value) => {
|
9
|
-
const propSchema = properties[key] || {};
|
10
|
-
const isNullVal = [null, undefined].includes(value);
|
11
|
-
|
12
|
-
if (isNullVal) {
|
13
|
-
if (!propSchema.isRequired) {
|
14
|
-
return;
|
15
|
-
}
|
16
|
-
|
17
|
-
return { id: 'value-missing-validation-error' };
|
18
|
-
}
|
19
|
-
|
20
|
-
if (propSchema.enum) {
|
21
|
-
if (propSchema.enum.includes(value)) {
|
22
|
-
return;
|
23
|
-
}
|
24
|
-
return {
|
25
|
-
id: 'enum-validation-error',
|
26
|
-
values: { enum: propSchema.enum, value },
|
27
|
-
};
|
28
|
-
}
|
29
|
-
|
30
|
-
switch (propSchema.type) {
|
31
|
-
case 'integer':
|
32
|
-
if (propSchema.isScalar && (typeof value !== 'number' || Number.isNaN(value))) {
|
33
|
-
return { id: 'invalid-number-validation-error' };
|
34
|
-
}
|
35
|
-
// if (propSchema.isRequired && Number.isNaN(parsedValue)) {
|
36
|
-
// return { id: 'invalid-number-validation-error' };
|
37
|
-
// }
|
38
|
-
// const parsedValue = parseInt(value, 10);
|
39
|
-
// if (propSchema.isRequired && Number.isNaN(parsedValue)) {
|
40
|
-
// return { id: 'invalid-number-validation-error' };
|
41
|
-
// }
|
42
|
-
break;
|
43
|
-
case 'date':
|
44
|
-
break;
|
45
|
-
case 'boolean':
|
46
|
-
break;
|
47
|
-
case 'json':
|
48
|
-
case 'string':
|
49
|
-
default:
|
50
|
-
if (propSchema.isRequired && !value) {
|
51
|
-
return { id: 'value-missing-validation-error' };
|
52
|
-
}
|
53
|
-
break;
|
54
|
-
}
|
55
|
-
};
|
56
|
-
|
57
|
-
return {
|
58
|
-
validate: attrs => inputProps.reduce(
|
59
|
-
(memo, key) => {
|
60
|
-
const err = validateAttr(key, attrs[key]);
|
61
|
-
if (err) {
|
62
|
-
return { ...memo, [key]: err };
|
63
|
-
}
|
64
|
-
return memo;
|
65
|
-
},
|
66
|
-
{},
|
67
|
-
),
|
68
|
-
validateAttr,
|
69
|
-
};
|
70
|
-
};
|
71
|
-
|
72
|
-
|
73
|
-
const qToQs = (q = {}) => Object.keys(q).length ? `?q=${JSON.stringify(q)}` : '';
|
74
|
-
|
75
|
-
|
76
|
-
const toKebabCase = (str) => [...str].reduce(
|
77
|
-
(memo, char) => (
|
78
|
-
char === char.toUpperCase()
|
79
|
-
? `${memo}-${char.toLowerCase()}`
|
80
|
-
: `${memo}${char}`
|
81
|
-
),
|
82
|
-
'',
|
83
|
-
);
|
84
|
-
|
85
|
-
const lcFirst = str => `${str[0].toLowerCase()}${str.slice(1)}`;
|
86
|
-
|
87
|
-
|
88
|
-
const createBuildURL = (collectionName) => {
|
89
|
-
const base = toKebabCase(collectionName);
|
90
|
-
return (id, q) => {
|
91
|
-
return `/${base}${id ? `/${encodeURIComponent(id)}` : ''}${qToQs(q)}`;
|
92
|
-
};
|
93
|
-
};
|
94
|
-
|
95
|
-
|
96
|
-
const serializeData = (data, schema) => {
|
97
|
-
const hasInputProps = Array.isArray(schema.inputProps);
|
98
|
-
return Object.keys(data).reduce(
|
99
|
-
(memo, key) => {
|
100
|
-
if (hasInputProps && !schema.inputProps.includes(key)) {
|
101
|
-
return memo;
|
102
|
-
}
|
103
|
-
// TODO: Deberíamos incluir props que no aparecen en el schema??
|
104
|
-
const { isRef, isScalar, isRequired } = schema.properties[key] || {};
|
105
|
-
if (isRef && isScalar && !isRequired && data[key] === null) {
|
106
|
-
return memo;
|
107
|
-
}
|
108
|
-
return {
|
109
|
-
...memo,
|
110
|
-
[key]: data[key],
|
111
|
-
};
|
112
|
-
},
|
113
|
-
{},
|
114
|
-
);
|
115
|
-
};
|
116
|
-
|
117
|
-
|
118
|
-
const parseSchema = ({ primaryKey, properties, ...rest }) => {
|
119
|
-
return {
|
120
|
-
primaryKey: primaryKey || 'id',
|
121
|
-
properties: Object.keys(properties || {}).reduce(
|
122
|
-
(memo, key) => {
|
123
|
-
const propSchema = properties[key] || {};
|
124
|
-
const { type, isScalar, isRequired, isRef = false } = (
|
125
|
-
typeof propSchema.type === 'string'
|
126
|
-
? propSchema.type === 'array'
|
127
|
-
? !!propSchema.enum
|
128
|
-
? { type: 'string', isScalar: false, isRequired: false }
|
129
|
-
: !!propSchema.items?.$ref
|
130
|
-
? { type: propSchema.items.$ref.split('/').pop(), isScalar: false, isRequired: false, isRef: true }
|
131
|
-
: { type: propSchema.items?.type, isScalar: false, isRequired: false }
|
132
|
-
: { type: propSchema.format === 'date-time' ? 'date' : propSchema.type, isScalar: true, isRequired: true }
|
133
|
-
: Array.isArray(propSchema.type)
|
134
|
-
? propSchema.type.length === 2
|
135
|
-
? { type: propSchema.format === 'date-time' ? 'date' : propSchema.type[0], isScalar: true, isRequired: false }
|
136
|
-
: { type: 'json', isScalar: true, isRequired: propSchema.type.includes('null') }
|
137
|
-
: !!propSchema.$ref
|
138
|
-
? { type: propSchema.$ref.split('/').pop(), isScalar: true, isRequired: true, isRef: true }
|
139
|
-
: { type: propSchema.anyOf[0].$ref.split('/').pop(), isScalar: true, isRequired: false, isRef: true }
|
140
|
-
);
|
141
|
-
|
142
|
-
const inputType = propSchema.inputType || (
|
143
|
-
type === 'integer'
|
144
|
-
? 'number'
|
145
|
-
: type
|
146
|
-
);
|
147
|
-
|
148
|
-
return {
|
149
|
-
...memo,
|
150
|
-
[key]: {
|
151
|
-
...properties[key],
|
152
|
-
type,
|
153
|
-
isScalar,
|
154
|
-
isRequired: (
|
155
|
-
typeof propSchema.isRequired === 'boolean'
|
156
|
-
? propSchema.isRequired
|
157
|
-
: isRequired
|
158
|
-
),
|
159
|
-
isRef,
|
160
|
-
inputType,
|
161
|
-
},
|
162
|
-
};
|
163
|
-
},
|
164
|
-
{},
|
165
|
-
),
|
166
|
-
...rest,
|
167
|
-
};
|
168
|
-
};
|
169
|
-
|
170
|
-
|
171
|
-
export const createModel = (
|
172
|
-
baseUrl,
|
173
|
-
state,
|
174
|
-
collectionName,
|
175
|
-
schema = {},
|
176
|
-
models = {},
|
177
|
-
) => {
|
178
|
-
const parsedSchema = parseSchema(schema);
|
179
|
-
const { primaryKey, properties } = parsedSchema;
|
180
|
-
const validator = createValidator(parsedSchema);
|
181
|
-
const buildURL = createBuildURL(collectionName);
|
182
|
-
const req = (...args) => createClient(baseUrl, state.authUser)(...args);
|
183
|
-
const create = ({ data, ...q }) => req(buildURL(null, q), {
|
184
|
-
method: 'POST',
|
185
|
-
body: serializeData(data, parsedSchema),
|
186
|
-
});
|
187
|
-
const put = ({ data, ...q }) => {
|
188
|
-
const { where, ...rest } = q;
|
189
|
-
return req(buildURL(where[primaryKey], rest), {
|
190
|
-
method: 'PUT',
|
191
|
-
body: serializeData(data, parsedSchema),
|
192
|
-
});
|
193
|
-
};
|
194
|
-
|
195
|
-
const parse = (data) => {
|
196
|
-
if (!data) {
|
197
|
-
return data;
|
198
|
-
}
|
199
|
-
|
200
|
-
const parsed = Object.keys(data).reduce(
|
201
|
-
(memo, key) => {
|
202
|
-
const propSchema = properties[key] || {};
|
203
|
-
const { type, isScalar, isRef, format, items } = propSchema;
|
204
|
-
|
205
|
-
if (isRef) {
|
206
|
-
const relationModelName = lcFirst(type);
|
207
|
-
if (!isScalar) {
|
208
|
-
return {
|
209
|
-
...memo,
|
210
|
-
[key]: (
|
211
|
-
typeof models[relationModelName]?.parse === 'function'
|
212
|
-
? data[key].map(obj => models[relationModelName].parse(obj))
|
213
|
-
: data[key]
|
214
|
-
),
|
215
|
-
};
|
216
|
-
}
|
217
|
-
return {
|
218
|
-
...memo,
|
219
|
-
[key]: models[relationModelName].parse(data[key]),
|
220
|
-
};
|
221
|
-
}
|
222
|
-
|
223
|
-
return {
|
224
|
-
...memo,
|
225
|
-
[key]: (
|
226
|
-
type === 'date' && data[key]
|
227
|
-
? new Date(data[key])
|
228
|
-
: data[key]
|
229
|
-
),
|
230
|
-
};
|
231
|
-
},
|
232
|
-
{},
|
233
|
-
);
|
234
|
-
|
235
|
-
return (
|
236
|
-
typeof parsedSchema.parse === 'function'
|
237
|
-
? parsedSchema.parse(parsed)
|
238
|
-
: parsed
|
239
|
-
);
|
240
|
-
};
|
241
|
-
|
242
|
-
const relations = Object.keys(properties || {}).reduce(
|
243
|
-
(memo, key) => (
|
244
|
-
properties[key].isRef && properties[key].isScalar && properties[key].isRequired
|
245
|
-
? Object.assign(memo, {
|
246
|
-
all: memo.all.concat(key),
|
247
|
-
oneToOne: memo.oneToOne.concat(key),
|
248
|
-
requiredOneToOne: memo.requiredOneToOne.concat(key),
|
249
|
-
})
|
250
|
-
: properties[key].isRef && properties[key].isScalar
|
251
|
-
? Object.assign(memo, {
|
252
|
-
all: memo.all.concat(key),
|
253
|
-
oneToOne: memo.oneToOne.concat(key),
|
254
|
-
optionalOneToOne: memo.optionalOneToOne.concat(key),
|
255
|
-
})
|
256
|
-
: properties[key].isRef
|
257
|
-
? Object.assign(memo, {
|
258
|
-
all: memo.all.concat(key),
|
259
|
-
oneToMany: memo.oneToMany.concat(key),
|
260
|
-
})
|
261
|
-
: memo
|
262
|
-
),
|
263
|
-
{
|
264
|
-
all: [],
|
265
|
-
oneToOne: [],
|
266
|
-
requiredOneToOne: [],
|
267
|
-
optionalOneToOne: [],
|
268
|
-
oneToMany: [],
|
269
|
-
},
|
270
|
-
);
|
271
|
-
|
272
|
-
return {
|
273
|
-
get schema() {
|
274
|
-
return parsedSchema;
|
275
|
-
},
|
276
|
-
get relations() {
|
277
|
-
return relations;
|
278
|
-
},
|
279
|
-
parse,
|
280
|
-
validateAttr: validator.validateAttr,
|
281
|
-
validate: validator.validate,
|
282
|
-
findMany: q => req(buildURL(null, q))
|
283
|
-
.then(results => results.map(parse)),
|
284
|
-
findById: (id, q) => req(buildURL(id, q))
|
285
|
-
.then(parse),
|
286
|
-
create,
|
287
|
-
update: put,
|
288
|
-
upsert: opts => (
|
289
|
-
!opts.where[primaryKey]
|
290
|
-
? create({ data: opts.create })
|
291
|
-
: put({ where: opts.where, data: opts.update })
|
292
|
-
),
|
293
|
-
delete: id => req(buildURL(id), { method: 'DELETE' }),
|
294
|
-
stats: () => req(buildURL('_stats')),
|
295
|
-
};
|
296
|
-
};
|
297
|
-
|
298
|
-
|
299
|
-
export const createModels = (url, state, schema) => {
|
300
|
-
return Object.keys(schema.properties).reduce(
|
301
|
-
(prev, key) => {
|
302
|
-
const name = schema.properties[key].$ref.split('/').pop();
|
303
|
-
return Object.assign(prev, {
|
304
|
-
[key]: createModel(
|
305
|
-
url,
|
306
|
-
state,
|
307
|
-
schema.definitions[name].plural || `${key}s`,
|
308
|
-
schema.definitions[name],
|
309
|
-
prev,
|
310
|
-
),
|
311
|
-
});
|
312
|
-
},
|
313
|
-
{},
|
314
|
-
);
|
315
|
-
};
|
316
|
-
|
317
|
-
|
318
|
-
export const extendSchemaDefinitions = (schema, extended) => {
|
319
|
-
return Object.keys(schema.definitions).reduce(
|
320
|
-
(memo, key) => ({
|
321
|
-
...memo,
|
322
|
-
[key]: (
|
323
|
-
!extended[key]
|
324
|
-
? schema.definitions[key]
|
325
|
-
: {
|
326
|
-
...schema.definitions[key],
|
327
|
-
...extended[key],
|
328
|
-
properties: Object.keys(schema.definitions[key].properties).reduce(
|
329
|
-
(prev, propName) => ({
|
330
|
-
...prev,
|
331
|
-
[propName]: {
|
332
|
-
...schema.definitions[key].properties[propName],
|
333
|
-
...(extended[key].properties || {})[propName],
|
334
|
-
},
|
335
|
-
}),
|
336
|
-
extended[key].properties || {},
|
337
|
-
),
|
338
|
-
}
|
339
|
-
),
|
340
|
-
}),
|
341
|
-
{},
|
342
|
-
);
|
343
|
-
};
|
package/lib/roles.js
DELETED
package/lib/util.js
DELETED
@@ -1,68 +0,0 @@
|
|
1
|
-
const pad = n => n > 9 ? `${n}` : `0${n}`;
|
2
|
-
|
3
|
-
export const formatDate = date => (
|
4
|
-
`${pad(date.getUTCDate())}/${pad(date.getUTCMonth() + 1)}/${date.getUTCFullYear()}`
|
5
|
-
);
|
6
|
-
|
7
|
-
export const formatTime = date => (
|
8
|
-
`${pad(date.getUTCHours())}:${pad(date.getUTCMinutes())}:${date.getUTCSeconds()} UTC`
|
9
|
-
);
|
10
|
-
|
11
|
-
export const formatDateTime = date => `${formatDate(date)} ${formatTime(date)}`;
|
12
|
-
|
13
|
-
const locales = {
|
14
|
-
es: 'es-ES',
|
15
|
-
pt: 'pt-BR',
|
16
|
-
};
|
17
|
-
|
18
|
-
export const formatMonth = (date, lang = 'es', showYear = false) => {
|
19
|
-
return new Intl.DateTimeFormat(locales[lang], {
|
20
|
-
...(showYear && {
|
21
|
-
year: 'numeric',
|
22
|
-
}),
|
23
|
-
month: 'long',
|
24
|
-
day: 'numeric',
|
25
|
-
timeZone: 'UTC',
|
26
|
-
}).format(new Date(date));
|
27
|
-
};
|
28
|
-
|
29
|
-
export const getAgeAt = (dateOfBirth, at) => {
|
30
|
-
let age = at.getFullYear() - dateOfBirth.getFullYear();
|
31
|
-
const m = at.getMonth() - dateOfBirth.getMonth();
|
32
|
-
|
33
|
-
if (m < 0 || (m === 0 && at.getDate() < dateOfBirth.getDate())) {
|
34
|
-
age--;
|
35
|
-
}
|
36
|
-
|
37
|
-
return age;
|
38
|
-
};
|
39
|
-
|
40
|
-
const createCurrencyFormatter = (
|
41
|
-
lang,
|
42
|
-
countryCode,
|
43
|
-
currencyCode,
|
44
|
-
) => new Intl.NumberFormat(
|
45
|
-
`${lang}-${countryCode}`,
|
46
|
-
{ currency: currencyCode },
|
47
|
-
);
|
48
|
-
|
49
|
-
export const formatCurrency = (
|
50
|
-
val,
|
51
|
-
lang,
|
52
|
-
countryCode,
|
53
|
-
currencyCode,
|
54
|
-
) => createCurrencyFormatter(
|
55
|
-
lang,
|
56
|
-
countryCode,
|
57
|
-
currencyCode,
|
58
|
-
).format(val);
|
59
|
-
|
60
|
-
export const parseCurrency = val => parseInt(val.replace(/[,\.]/g, ''), 10);
|
61
|
-
|
62
|
-
export const loadFromLocalStorage = (path) => {
|
63
|
-
try {
|
64
|
-
return JSON.parse(window.localStorage.getItem(path));
|
65
|
-
} catch (_) {
|
66
|
-
return null;
|
67
|
-
}
|
68
|
-
};
|