@01-edu/shared 2.0.5 → 2.0.7

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.
Files changed (46) hide show
  1. package/dist/attrs-defs.js +1 -0
  2. package/dist/attrs.js +1 -0
  3. package/dist/bin/check-definitions.js +3 -0
  4. package/dist/chunk-727IHWVW.js +1 -0
  5. package/dist/chunk-7ZTI6THC.js +1 -0
  6. package/dist/chunk-CBWHFDVB.js +1 -0
  7. package/dist/chunk-EI7MMDWY.js +1 -0
  8. package/dist/chunk-EOY6G4KE.js +1 -0
  9. package/dist/chunk-K5Z4W5GV.js +1 -0
  10. package/dist/chunk-LDUPRVV4.js +1 -0
  11. package/dist/chunk-NQCTSDJE.js +1 -0
  12. package/dist/chunk-V47RDOUO.js +1 -0
  13. package/dist/chunk-XYW3ROIR.js +1 -0
  14. package/dist/definitions-checker.js +1 -0
  15. package/dist/event-utils.js +1 -0
  16. package/dist/games-utils.js +1 -0
  17. package/dist/graph.js +1 -0
  18. package/dist/hasura-core.js +1 -0
  19. package/dist/hasura-model.js +34 -0
  20. package/dist/hasura-prepare.js +1 -0
  21. package/dist/modular-steps-utils.js +1 -0
  22. package/dist/object-structure.js +1 -0
  23. package/dist/onboarding.js +1 -0
  24. package/dist/path.js +1 -0
  25. package/dist/qa-utils.js +1 -0
  26. package/dist/score.js +1 -0
  27. package/dist/skill-definitions.js +1 -0
  28. package/dist/toolbox.js +1 -0
  29. package/package.json +17 -6
  30. package/attrs-defs.js +0 -4273
  31. package/attrs.js +0 -423
  32. package/bin/check-definitions.js +0 -74
  33. package/definitions-checker.js +0 -233
  34. package/event-utils.js +0 -58
  35. package/graph.js +0 -96
  36. package/hasura-core.js +0 -217
  37. package/hasura-model.js +0 -138
  38. package/hasura-prepare.js +0 -44
  39. package/languages.js +0 -147
  40. package/onboarding.js +0 -25
  41. package/path.js +0 -73
  42. package/programming-languages.js +0 -21
  43. package/qa-utils.js +0 -13
  44. package/score.js +0 -80
  45. package/skill-definitions.js +0 -359
  46. package/toolbox.js +0 -532
package/toolbox.js DELETED
@@ -1,532 +0,0 @@
1
- import { isFinished } from './event-utils.js'
2
-
3
- const keyCodes = {
4
- 13: ({ save, value, event, allowLineBreak }) => {
5
- if (event.shiftKey || allowLineBreak) return false
6
- return save(value)
7
- }, // enter
8
- 27: ({ set, originalValue }) => set(originalValue), // esc
9
- 83: ({ save, value, event }) =>
10
- event.metaKey || event.ctrlKey ? save(value) : false, // cmd+s
11
- }
12
-
13
- export const handleKeyDownEvent = args => {
14
- const handler = keyCodes[args.event.keyCode]
15
-
16
- if (handler) {
17
- if (handler(args) !== false) {
18
- args.event.preventDefault()
19
- }
20
- }
21
- }
22
-
23
- export const last = array => array[array.length - 1]
24
-
25
- export const upperFirst = str =>
26
- str ? str[0].toUpperCase() + str.slice(1) : ''
27
-
28
- export const replaceMap = (arr, elem, mapper) =>
29
- arr.map(e => (e === elem ? mapper(e) : e))
30
-
31
- // DATE & TIME
32
-
33
- export const SEC = 1000
34
- export const MIN = 60 * SEC
35
- export const HOUR = 60 * MIN
36
- export const DAY = 24 * HOUR
37
- export const WEEK = 7 * DAY
38
- export const YEAR = 365 * DAY
39
-
40
- const unitsOfTime = Object.entries({
41
- year: YEAR,
42
- month: 2628000000,
43
- day: DAY,
44
- hour: HOUR,
45
- minute: MIN,
46
- second: SEC,
47
- })
48
-
49
- export const units = {
50
- years: YEAR,
51
- year: YEAR,
52
- yrs: YEAR,
53
- yr: YEAR,
54
- y: YEAR,
55
-
56
- weeks: WEEK,
57
- week: WEEK,
58
- w: WEEK,
59
-
60
- days: DAY,
61
- day: DAY,
62
- d: DAY,
63
-
64
- hours: HOUR,
65
- hour: HOUR,
66
- hrs: HOUR,
67
- hr: HOUR,
68
- h: HOUR,
69
-
70
- minutes: MIN,
71
- minute: MIN,
72
- mins: MIN,
73
- min: MIN,
74
- m: MIN,
75
-
76
- seconds: SEC,
77
- second: SEC,
78
- secs: SEC,
79
- sec: SEC,
80
- s: SEC,
81
-
82
- milliseconds: 1,
83
- millisecond: 1,
84
- ms: 1,
85
- }
86
-
87
- const rtf = new Intl.RelativeTimeFormat('en', { style: 'narrow' })
88
- export const relativeTime = elapsed => {
89
- for (const [unit, amount] of unitsOfTime) {
90
- if (Math.abs(elapsed) > amount || unit === 'second') {
91
- return rtf.format(Math.round(elapsed / amount), unit)
92
- }
93
- }
94
- }
95
-
96
- export const padStart0 = s => s.toString().padStart(2, '0')
97
-
98
- export const timeToMS = str => {
99
- if (typeof str !== 'string') return 0
100
- str = str.toLowerCase()
101
- const matcher = /(?<value>[0-9.-]+) *(?<type>[a-z]+)/g
102
- let match
103
- let result = 0
104
- while ((match = matcher.exec(str))) {
105
- const { type, value } = match.groups
106
- const unit = units[type]
107
- const n = Number(value)
108
- n && unit && (result += value * unit)
109
- }
110
- return Math.round(result)
111
- }
112
-
113
- // TODO: formated should be written formatted
114
- export const formatedDurationColons = (seconds, { hoursOnly } = {}) => {
115
- const d = !hoursOnly && Math.floor(seconds / 86400)
116
- const h = Math.floor((!hoursOnly ? seconds % 86400 : seconds) / 3600)
117
- const min = Math.floor((seconds % 3600) / 60)
118
- const sec = Math.floor(seconds % 60)
119
- const time = `${padStart0(h)}:${padStart0(min)}:${padStart0(sec)}`
120
- return d ? `${d}d ${time}` : time
121
- }
122
-
123
- export const formatedMS = ms => formatedDuration(Math.round(ms / SEC))
124
- export const timeUnits = [
125
- { label: 'y', fullLabel: 'year', size: 31536000 },
126
- { label: 'w', fullLabel: 'week', size: 604800 },
127
- { label: 'd', fullLabel: 'day', size: 86400 },
128
- { label: 'h', fullLabel: 'hour', size: 3600 },
129
- { label: 'm', fullLabel: 'minute', size: 60 },
130
- { label: 's', fullLabel: 'second', size: 1 },
131
- ]
132
- export const formatedDuration = (
133
- seconds,
134
- { noSeconds, stopFirst, useFullLabel, stopLabel } = {},
135
- ) => {
136
- const parts = []
137
- if (
138
- stopLabel &&
139
- seconds < timeUnits.find(u => u.fullLabel === stopLabel)?.size
140
- )
141
- return `less than 1${useFullLabel ? ` ${stopLabel}` : timeUnits.find(u => u.fullLabel === stopLabel).label}`
142
- for (const { label, size, fullLabel } of timeUnits) {
143
- const value = Math.floor(seconds / size)
144
- if (value !== 0) {
145
- parts.push(
146
- `${value}${useFullLabel ? ` ${fullLabel}` : label}${value > 1 && useFullLabel ? 's' : ''}`,
147
- )
148
- if (stopFirst) return parts
149
- seconds -= value * size
150
- }
151
- if (fullLabel === stopLabel) {
152
- return parts.join(' ') || (noSeconds ? '0m' : '0s')
153
- }
154
- }
155
- if (!noSeconds && seconds !== 0) {
156
- parts.push(`${seconds}s`)
157
- }
158
- return parts.join(' ') || (noSeconds ? '0m' : '0s')
159
- }
160
-
161
- // Returns the difference between two dates in the following format: "3 months"
162
- // Always returns the largest unit only
163
- // If only one date is provided, it returns the difference between that date and now, the value is absolute
164
- export const timeDiff = (date1, date2 = Date.now()) => {
165
- if (!date1) return null
166
- const diffMs = toDate(date1) - toDate(date2)
167
- return formatedDuration(Math.floor(Math.abs(diffMs) / 1000), {
168
- stopFirst: true,
169
- useFullLabel: true,
170
- })
171
- }
172
-
173
- const toDate = date => (date instanceof Date ? date : new Date(date))
174
- export const toDateFormat = (d, isISO = true) => {
175
- if (dateIsPermanent(d)) return '∞'
176
- const date = toDate(d)
177
- const month = (date.getMonth() + 1).toString().padStart(2, '0')
178
- const day = date.getDate().toString().padStart(2, '0')
179
-
180
- return isISO
181
- ? `${date.getFullYear()}-${month}-${day}`
182
- : `${day}/${month}/${date.getFullYear()}`
183
- }
184
-
185
- export const toISOStringWithTimeZone = d => toDate(d).toISOString()
186
-
187
- export const toDateFormatWithTime = (d, separator = 'T') => {
188
- const date = toDate(d)
189
- const hh = String(date.getHours()).padStart(2, '0')
190
- const mm = String(date.getMinutes()).padStart(2, '0')
191
-
192
- return `${toDateFormat(date)}${separator}${hh}:${mm}`
193
- }
194
-
195
- export const toPermanentDateFormatWithTime = (d, separator = 'T') => {
196
- const date = toDate(d)
197
- const hh = String(date.getHours()).padStart(2, '0')
198
- const mm = String(date.getMinutes()).padStart(2, '0')
199
- const month = (date.getMonth() + 1).toString().padStart(2, '0')
200
- const day = date.getDate().toString().padStart(2, '0')
201
-
202
- return `${date.getFullYear()}-${month}-${day}${separator}${hh}:${mm}`
203
- }
204
- export const displayDateTime = dateTime => toDateFormatWithTime(dateTime, ' | ')
205
-
206
- export const getMonthName = month => monthNames[month]
207
-
208
- export const getDayName = day => weekDays[day]
209
-
210
- export const monthNames = [
211
- 'Jan',
212
- 'Feb',
213
- 'Mar',
214
- 'Apr',
215
- 'May',
216
- 'Jun',
217
- 'Jul',
218
- 'Aug',
219
- 'Sep',
220
- 'Oct',
221
- 'Nov',
222
- 'Dec',
223
- ]
224
-
225
- export const weekDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
226
-
227
- const hour = hour => {
228
- if (hour === 0 || hour === 12) return 12
229
- return hour % 12
230
- }
231
-
232
- const minPad = min => String(min).padStart(2, '0')
233
-
234
- const suffix = hour => {
235
- if (hour === 0) return 'am'
236
- if (hour === 12) return 'pm'
237
- return hour < 12 ? 'am' : 'pm'
238
- }
239
-
240
- export const dateIsPermanent = endAt => {
241
- const date =
242
- endAt instanceof Date && !Number.isNaN(endAt.valueOf())
243
- ? endAt
244
- : new Date(endAt)
245
-
246
- // 32503683600000 = year 3000 timestamp
247
- return date.valueOf() > 32503683600000
248
- }
249
-
250
- const getDateElems = date => {
251
- const d = new Date(date)
252
- const day = d.getDay()
253
- const jj = d.getDate()
254
- const mm = d.getMonth()
255
- const yyyy = d.getFullYear()
256
- const hh = d.getHours()
257
- const min = d.getMinutes()
258
- return { day, jj, mm, yyyy, hh, min }
259
- }
260
-
261
- export const formatedDateTime = (date, splitter = 'at') => {
262
- if (!date) return '-'
263
- if (dateIsPermanent(date)) return '∞'
264
- const { jj, mm, yyyy, hh, min } = getDateElems(date)
265
-
266
- return `${monthNames[mm]} ${jj}, ${yyyy} ${splitter} ${hour(hh)}:${minPad(
267
- min,
268
- )} ${suffix(hh)}`
269
- }
270
-
271
- export const formatedDateTimeWithDay = date => {
272
- if (!date) return '-'
273
- if (dateIsPermanent(date)) return '∞'
274
- const { day, jj, mm, yyyy, hh, min } = getDateElems(date)
275
-
276
- return `${getDayName(day)}, ${monthNames[mm]} ${jj}, ${yyyy} at ${hour(
277
- hh,
278
- )}:${minPad(min)} ${suffix(hh)}`
279
- }
280
-
281
- export const formatedDate = date => {
282
- if (!date) return '-'
283
- if (dateIsPermanent(date)) return '∞'
284
- return toDateFormat(date)
285
- }
286
-
287
- export const defer = () => {
288
- const result = {}
289
- result.done = new Promise((resolve, reject) => {
290
- result.resolve = resolve
291
- result.reject = reject
292
- })
293
- return result
294
- }
295
-
296
- // slugify('A Test') => a-test
297
- export const slugify = str =>
298
- str
299
- .normalize('NFKD')
300
- .replace(/\p{M}+/gu, '')
301
- .toLowerCase()
302
- .replace(/\s+/g, ' ')
303
- .replace(/[^a-z0-9._ ]+/g, '')
304
- .trim()
305
- .replaceAll(' ', '-')
306
-
307
- export const fullName = ({ firstName, lastName }) =>
308
- `${firstName || ''} ${lastName || ''}`
309
-
310
- export const formatTime = t =>
311
- new Date(t)
312
- .toISOString()
313
- .substr(11, 8)
314
- .replace(/^[0:]+/, '')
315
-
316
- export const wait = delay => new Promise(resolve => setTimeout(resolve, delay))
317
-
318
- const lowertalize = str => str[0].toLowerCase() + str.slice(1)
319
- const upperFirstMatch = (_, firstMatch) => firstMatch.toUpperCase()
320
- export const toCamelCase = str =>
321
- lowertalize(
322
- str
323
- .trim()
324
- .toLowerCase()
325
- .replace(/[ _-]+(.?)/g, upperFirstMatch),
326
- )
327
- export const isNotCamel = str => /[ _-]+(.?)/g.test(str)
328
-
329
- const underscoreJoin = (_, a, b) => `${a}_${b}`
330
- const toSnakeCase = str =>
331
- str
332
- .trim()
333
- .replace(/(.)([A-Z])/g, underscoreJoin)
334
- .toLowerCase()
335
-
336
- // seems to match all cases:
337
- // 'FOO-BAR_01Chart ki' > f-o-o-b-a-r-01-chart-ki
338
- // phant0m-writ3r > pass
339
- // phoneValidation > phone-validation
340
- // CHart01 > c-hart01
341
- // addtionnal_info > addtionnal-info
342
- // id card > id-card
343
- // should be enough for unique usage we have of it in check-refs
344
- // checked the perfs and it is faster + more secure than using replace(s) + toLowerCase
345
- export const toKebabCase = str =>
346
- str
347
- .match(
348
- /[A-Z](?=[A-Z][a-z]+[0-9]*[a-z]|\b)|[A-Z]?[a-z]+[0-9]+[a-z]?[A-Z]*|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g,
349
- )
350
- .map(x => x.toLowerCase())
351
- .join('-')
352
-
353
- const spaceJoin = (_, a, b) => `${a} ${b}`
354
- export const breath = str =>
355
- str
356
- .trim()
357
- .replace(/(.)([A-Z])/g, spaceJoin)
358
- .toLowerCase()
359
- export const prettyKey = key => upperFirst(breath(key))
360
-
361
- const switchKeys = (object, switchCase, switchAll) =>
362
- mapEntries(object, ([key, value]) => [switchCase(key), switchAll(value)])
363
-
364
- export const toCamelKeys = object => switchKeys(object, toCamelCase, toCamelAll)
365
- export const toSnakeKeys = object => switchKeys(object, toSnakeCase, toSnakeAll)
366
-
367
- const switchAll = (elem, switchCase, switchKeys, toSwitchAll) => {
368
- if (!elem || typeof elem !== 'object') return elem
369
- return Array.isArray(elem)
370
- ? elem.map(toSwitchAll)
371
- : switchKeys(elem, switchCase, toSwitchAll)
372
- }
373
-
374
- export const toCamelAll = elem =>
375
- switchAll(elem, toCamelCase, toCamelKeys, toCamelAll)
376
-
377
- export const toSnakeAll = elem =>
378
- switchAll(elem, toSnakeCase, toSnakeKeys, toSnakeAll)
379
-
380
- export const arrayOf = (size, start = 0) =>
381
- [...Array(size + start).keys()].slice(start)
382
-
383
- export const trimSlashEnd = path =>
384
- path[path.length - 1] === '/' ? trimSlashEnd(path.slice(0, -1)) : path
385
-
386
- export const mapEntries = (obj, fn) =>
387
- Object.fromEntries(Object.entries(obj).map(fn))
388
-
389
- export const mapValues = (obj, fn) =>
390
- mapEntries(obj, ([k, v]) => [k, fn(v, k, obj)])
391
-
392
- export const filterEntries = (obj, fn) =>
393
- Object.fromEntries(Object.entries(obj).filter(fn))
394
-
395
- export const filterValues = (obj, fn) =>
396
- filterEntries(obj, ([k, v]) => [k, fn(v, k, obj)])
397
-
398
- export const getChanges = (newObject, refObject) =>
399
- filterEntries(newObject, ([key, value]) => !eq(value, refObject[key]))
400
-
401
- export const hasChanged = (newObject, refObject) =>
402
- Object.keys(getChanges(newObject, refObject)).length !== 0
403
-
404
- export const shuffle = arr => {
405
- const newArr = [...arr]
406
- let i = newArr.length
407
- let j, tmp
408
- while (--i > 0) {
409
- j = Math.floor(Math.random() * (i + 1))
410
- tmp = newArr[j]
411
- newArr[j] = newArr[i]
412
- newArr[i] = tmp
413
- }
414
- return newArr
415
- }
416
-
417
- // specific to data structure
418
- export const getChildByType = (obj, childType) =>
419
- obj && Object.values(obj).find(child => child.type === childType)
420
-
421
- export const getUserName = user => {
422
- if (!user) return '-'
423
- if (user.attrs?.name) return user.attrs.name
424
- const firstName = user.firstName || '-'
425
- const lastName = user.lastName || '-'
426
-
427
- return `${firstName} ${lastName}`
428
- }
429
-
430
- // This only works for JSON like value
431
- // no support for Dates, Regexp, Set, Map etc...
432
- // this is 100% fine for anything from the database
433
- export const eq = (a, b) => {
434
- if (a === b) return true
435
- if (typeof a !== typeof b) return false
436
- if (typeof a === 'number' && Number.isNaN(a) && Number.isNaN(b)) return true
437
- if (typeof a === 'object') {
438
- if (!a || !b) return false
439
- if (a.constructor !== b.constructor) return false
440
- const entries = Object.entries(a)
441
- if (entries.length !== Object.values(b).length) return false
442
- for (const [k, v] of entries) {
443
- if (!eq(b[k], v)) return false
444
- }
445
- return true
446
- }
447
- return false
448
- }
449
-
450
- export const getStatus = progress => {
451
- if (!progress || !progress.isDone) return
452
- return progress.succeeded ? 'succeeded' : 'failed'
453
- }
454
-
455
- const isAccessBlocked = record =>
456
- !record.type.canAccessPlatform &&
457
- (new Date(record.endAt) > Date.now() ||
458
- record.type.isPermanent ||
459
- !record.endAt) &&
460
- isFinished(record.startAt)
461
-
462
- // TODO: could maybe check user.public.canAccessPlatform?
463
- export const isBanned = user => {
464
- const records = user?.records
465
- const record = records?.find(isAccessBlocked)
466
- if (!record) return
467
- const err = Error('Banned')
468
- err.record = record
469
- return err
470
- }
471
-
472
- export const generateCode = () =>
473
- Math.random()
474
- .toString(36)
475
- .slice(2, 7)
476
- .padEnd(5, '#')
477
- .replace(/0/gi, '_')
478
- .replace(/o/gi, '-')
479
- .replace(/I/gi, '?')
480
- .replace(/l/gi, '$')
481
-
482
- export const base64Encode = str => {
483
- const encoder = new TextEncoder()
484
- const data = encoder.encode(str)
485
- return btoa(String.fromCharCode.apply(null, data))
486
- }
487
-
488
- export const timePlusDelay = (time, delay) =>
489
- new Date(new Date(time).getTime() + delay).toISOString()
490
-
491
- export const getRecordStatus = record => {
492
- if (!isFinished(record?.startAt)) return 'starting soon'
493
- if (record?.endAt && isFinished(record?.endAt)) {
494
- return 'finished'
495
- }
496
- if (record?.type.isPermanent) return 'permanent'
497
- return record?.endAt ? 'in progress' : 'unblock required'
498
- }
499
-
500
- export const createFrequencyMap = arr =>
501
- arr.reduce((map, item) => {
502
- map[item] = (map[item] || 0) + 1
503
- return map
504
- }, {})
505
-
506
- export const postgresIntervalToMS = intervalStr => {
507
- if (!intervalStr) return 0
508
- // Regex to capture years, months, days, hours, minutes, seconds
509
- const regex =
510
- /(?:(\d+)\s+years?)?\s*(?:(\d+)\s+mons?)?\s*(?:(\d+)\s+days?)?\s*(?:(\d+):(\d+):([\d.]+))?/
511
- const match = intervalStr.match(regex)
512
-
513
- if (!match) return 0
514
-
515
- const years = Number.parseInt(match[1] || 0, 10)
516
- const months = Number.parseInt(match[2] || 0, 10)
517
- const days = Number.parseInt(match[3] || 0, 10)
518
- const hours = Number.parseInt(match[4] || 0, 10)
519
- const minutes = Number.parseInt(match[5] || 0, 10)
520
- const seconds = Number.parseFloat(match[6] || 0)
521
-
522
- // Convert everything to milliseconds
523
- const ms =
524
- years * 365 * 24 * 60 * 60 * 1000 + // assume 1 year = 365 days
525
- months * 30 * 24 * 60 * 60 * 1000 + // assume 1 month = 30 days
526
- days * 24 * 60 * 60 * 1000 +
527
- hours * 60 * 60 * 1000 +
528
- minutes * 60 * 1000 +
529
- seconds * 1000
530
-
531
- return ms
532
- }