@01-edu/shared 2.0.3 → 2.0.5
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/attrs-defs.js +1 -1
- package/definitions-checker.js +11 -3
- package/hasura-core.js +217 -0
- package/hasura-model.js +138 -0
- package/hasura-prepare.js +44 -0
- package/onboarding.js +0 -14
- package/package.json +10 -2
- package/qa-utils.js +13 -0
- package/toolbox.js +0 -43
package/attrs-defs.js
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
numTime,
|
|
9
9
|
} from './event-utils.js'
|
|
10
10
|
import { flatGraphContents, getCoreOfSattelite, limitations } from './graph.js'
|
|
11
|
-
import { onboardingTypes } from './
|
|
11
|
+
import { onboardingTypes } from './object-structure.ts'
|
|
12
12
|
import { getObjectFromRelativePath } from './path.js'
|
|
13
13
|
import { gamesScoring } from './score.js'
|
|
14
14
|
import { hasRequiredSkills, skillsSet } from './skill-definitions.js'
|
package/definitions-checker.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { attributes, relationAttributes } from './attrs.js'
|
|
2
|
-
import { childTypes, objectTypes } from './
|
|
2
|
+
import { childTypes, objectTypes } from './object-structure.ts'
|
|
3
3
|
|
|
4
4
|
const normalize = str =>
|
|
5
5
|
str
|
|
@@ -9,14 +9,22 @@ const normalize = str =>
|
|
|
9
9
|
.replaceAll(' ', '-')
|
|
10
10
|
|
|
11
11
|
const assertDef = def => {
|
|
12
|
-
const {
|
|
13
|
-
|
|
12
|
+
const {
|
|
13
|
+
type,
|
|
14
|
+
name,
|
|
15
|
+
attrs,
|
|
16
|
+
children: _children,
|
|
17
|
+
childrenAttrs,
|
|
18
|
+
referencePath: _referencePath,
|
|
19
|
+
...rest
|
|
20
|
+
} = def
|
|
14
21
|
const [extra] = Object.keys(rest)
|
|
15
22
|
if (extra) {
|
|
16
23
|
throw Error(
|
|
17
24
|
`Unexpected property ${extra}, did you mean to define an attribute ?`,
|
|
18
25
|
)
|
|
19
26
|
}
|
|
27
|
+
if (type === 'campus') throw Error(`Campuses can't be defined in definitions`)
|
|
20
28
|
if (!objectTypes.has(type)) throw Error(`Invalid type property`)
|
|
21
29
|
if (!name || typeof name !== 'string') throw Error(`Invalid name property`)
|
|
22
30
|
if (!attrs || typeof attrs !== 'object' || Array.isArray(attrs)) {
|
package/hasura-core.js
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
export class HasuraError extends Error {
|
|
2
|
+
constructor({ extensions, message, ...props }, cause) {
|
|
3
|
+
super(message, cause)
|
|
4
|
+
Object.assign(this, props)
|
|
5
|
+
Object.assign(this, extensions)
|
|
6
|
+
Error.captureStackTrace?.(this, HasuraError)
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const initClient = ({ debug, address, log, ...params }) => {
|
|
11
|
+
log || (log = debug ? console.debug : () => {})
|
|
12
|
+
const handlers = new Map()
|
|
13
|
+
const subscribers = new Map()
|
|
14
|
+
|
|
15
|
+
const getId = () => {
|
|
16
|
+
const id = Math.random().toString(36).slice(2)
|
|
17
|
+
return handlers.has(id) ? getId() : id
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const rejectAllPending = err => {
|
|
21
|
+
subscribers.clear() // TODO: store subscribers query and re-trigger them
|
|
22
|
+
for (const [id, { reject, noCleanup }] of handlers) {
|
|
23
|
+
noCleanup || activeQueries.delete(id)
|
|
24
|
+
handlers.delete(id)
|
|
25
|
+
reject(err)
|
|
26
|
+
}
|
|
27
|
+
return err
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const end = (handler, props = {}) => {
|
|
31
|
+
props.duration = Date.now() - handler.start
|
|
32
|
+
props.size = handler.size
|
|
33
|
+
props.name = handler.query
|
|
34
|
+
props.id = handler.id
|
|
35
|
+
log('query', props)
|
|
36
|
+
handlers.delete(handler.id)
|
|
37
|
+
handler.noCleanup || activeQueries.delete(handler.id)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const messageFail = (handler, payload, id) => {
|
|
41
|
+
if (!handler) return log('missing-handler', { id, type: 'error' })
|
|
42
|
+
|
|
43
|
+
end(handler, { payload, type: 'error' })
|
|
44
|
+
handlers.delete(id)
|
|
45
|
+
return handler.reject(
|
|
46
|
+
new HasuraError(payload.errors[0], debug && { cause: handler.cause }),
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const handleMessage = (data, resolve, reject) => {
|
|
51
|
+
if (data === '{"type":"ka"}') return // ignore keep alive
|
|
52
|
+
|
|
53
|
+
const { type, payload, id } = JSON.parse(data)
|
|
54
|
+
const handler = handlers.get(id)
|
|
55
|
+
handler && (handler.size += data.length)
|
|
56
|
+
|
|
57
|
+
log('raw', data)
|
|
58
|
+
|
|
59
|
+
switch (type) {
|
|
60
|
+
case 'connection_ack': {
|
|
61
|
+
return resolve(payload)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
case 'connection_error': {
|
|
65
|
+
const err = rejectAllPending(new HasuraError({ errors: [payload] }))
|
|
66
|
+
return reject(err)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
case 'data': {
|
|
70
|
+
if (payload.errors) return messageFail(handler, payload, id)
|
|
71
|
+
|
|
72
|
+
const sub = subscribers.get(id)
|
|
73
|
+
if (!sub) {
|
|
74
|
+
return handler
|
|
75
|
+
? (handler.payload = payload)
|
|
76
|
+
: log('missing-handler', { id, type: 'error' })
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
sub(payload.data)
|
|
80
|
+
if (handler) {
|
|
81
|
+
end(handler, { type, payload })
|
|
82
|
+
handler.resolve()
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
case 'error': {
|
|
89
|
+
return messageFail(handler, payload, id)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
case 'complete': {
|
|
93
|
+
if (!handler) return
|
|
94
|
+
end(handler, { type, payload })
|
|
95
|
+
return handler.resolve(handler.payload?.data)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const handleFail = (event, type) =>
|
|
101
|
+
rejectAllPending(
|
|
102
|
+
new HasuraError({ message: `WebSocket connection ${type}`, event }),
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
let ws = new WebSocket(address, 'graphql-ws')
|
|
106
|
+
let activeQueries = new Map()
|
|
107
|
+
const exec = async (id, payload, name, noCleanup) => {
|
|
108
|
+
await connection
|
|
109
|
+
const handler = {
|
|
110
|
+
id,
|
|
111
|
+
size: 0,
|
|
112
|
+
query: name,
|
|
113
|
+
start: Date.now(),
|
|
114
|
+
noCleanup,
|
|
115
|
+
}
|
|
116
|
+
const result = new Promise((resolve, reject) => {
|
|
117
|
+
handler.resolve = resolve
|
|
118
|
+
handler.reject = reject
|
|
119
|
+
})
|
|
120
|
+
debug && (handler.cause = Error('hasuraClient.exec'))
|
|
121
|
+
handlers.set(id, handler)
|
|
122
|
+
activeQueries.set(id, { payload, name })
|
|
123
|
+
log('start', { id, payload })
|
|
124
|
+
ws.send(`{"type":"start","id":"${id}","payload":${payload}}`)
|
|
125
|
+
return result
|
|
126
|
+
}
|
|
127
|
+
const runFromString = (payload, name) => exec(getId(), payload, name)
|
|
128
|
+
|
|
129
|
+
const subscribeFromString = (sub, payload, name) => {
|
|
130
|
+
const id = getId()
|
|
131
|
+
subscribers.set(id, sub)
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
execution: exec(id, payload, name, true),
|
|
135
|
+
unsubscribe: () => {
|
|
136
|
+
subscribers.delete(id)
|
|
137
|
+
activeQueries.delete(id)
|
|
138
|
+
log('stop', { id })
|
|
139
|
+
ws.send(`{"type":"stop","id":"${id}"}`)
|
|
140
|
+
},
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
let connected = false
|
|
145
|
+
const getConnection = async () => {
|
|
146
|
+
connected = false
|
|
147
|
+
const { promise, resolve, reject } = Promise.withResolvers()
|
|
148
|
+
const onError = () => reject(handleFail(undefined, 'failed'))
|
|
149
|
+
const onClose = event =>
|
|
150
|
+
reject(handleFail({ code: event.code, reason: event.reason }, 'close'))
|
|
151
|
+
ws.addEventListener('error', onError, { once: true })
|
|
152
|
+
ws.addEventListener('close', onClose, { once: true })
|
|
153
|
+
ws.addEventListener('message', event =>
|
|
154
|
+
handleMessage(event.data, resolve, reject),
|
|
155
|
+
)
|
|
156
|
+
try {
|
|
157
|
+
await promise
|
|
158
|
+
return (connected = true)
|
|
159
|
+
} finally {
|
|
160
|
+
ws.removeEventListener('error', onError)
|
|
161
|
+
ws.removeEventListener('close', onClose)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
let connection = getConnection()
|
|
166
|
+
|
|
167
|
+
const connect = async ({ adminSecret, token, role, headers }) => {
|
|
168
|
+
const previousActiveQueries = activeQueries
|
|
169
|
+
const reload = connected
|
|
170
|
+
if (reload) {
|
|
171
|
+
ws.close()
|
|
172
|
+
ws = new WebSocket(address, 'graphql-ws')
|
|
173
|
+
connection = getConnection()
|
|
174
|
+
activeQueries = new Map()
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (!ws.readyState) {
|
|
178
|
+
await new Promise(s => ws.addEventListener('open', s, { once: true }))
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const payload = {
|
|
182
|
+
headers: adminSecret
|
|
183
|
+
? { 'x-hasura-admin-secret': adminSecret, ...headers }
|
|
184
|
+
: { Authorization: `Bearer ${token}`, ...headers },
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
role && (payload.headers['x-hasura-role'] = role)
|
|
188
|
+
|
|
189
|
+
ws.send(JSON.stringify({ type: 'connection_init', payload }))
|
|
190
|
+
|
|
191
|
+
reload &&
|
|
192
|
+
connection.then(() => {
|
|
193
|
+
// re exec all previous active queries
|
|
194
|
+
for (const [id, { payload, name }] of previousActiveQueries) {
|
|
195
|
+
exec(id, payload, name)
|
|
196
|
+
}
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
return connection
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (params.adminSecret || params.token) {
|
|
203
|
+
connect(params)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
ws,
|
|
208
|
+
connect,
|
|
209
|
+
connection,
|
|
210
|
+
runFromString,
|
|
211
|
+
subscribeFromString,
|
|
212
|
+
run: (query, variables) =>
|
|
213
|
+
runFromString(JSON.stringify({ query, variables })),
|
|
214
|
+
subscribe: (sub, query, variables) =>
|
|
215
|
+
subscribeFromString(sub, JSON.stringify({ query, variables })),
|
|
216
|
+
}
|
|
217
|
+
}
|
package/hasura-model.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
export const buildModel =
|
|
2
|
+
prepare =>
|
|
3
|
+
(name, key = 'id', type = 'Int') => {
|
|
4
|
+
const list = `${key}_list`
|
|
5
|
+
const insertQuery = prepare(`
|
|
6
|
+
mutation insert_${name} ($objects: [${name}_insert_input!]!){
|
|
7
|
+
insert_${name} (objects: $objects) { returning { ${key} } }
|
|
8
|
+
}`)
|
|
9
|
+
|
|
10
|
+
const updateQuery = prepare(`
|
|
11
|
+
mutation update_${name} ($${key}: ${type}!, $changes: ${name}_set_input!) {
|
|
12
|
+
update_${name} (where: {${key}: {_eq: $${key}}}, _set: $changes) { affected_rows }
|
|
13
|
+
}`)
|
|
14
|
+
|
|
15
|
+
const updateQueryAll = prepare(`
|
|
16
|
+
mutation update_${name} ($${list}: [${type}!], $changes: ${name}_set_input!) {
|
|
17
|
+
update_${name} (where: {${key}: {_in: $${list}}}, _set: $changes) { affected_rows }
|
|
18
|
+
}`)
|
|
19
|
+
|
|
20
|
+
const deleteQuery = prepare(`
|
|
21
|
+
mutation delete_${name} ($${key}: ${type}!) {
|
|
22
|
+
delete_${name} (where: {${key}: {_eq: $${key}}}) { affected_rows }
|
|
23
|
+
}`)
|
|
24
|
+
|
|
25
|
+
const deleteQueryAll = prepare(`
|
|
26
|
+
mutation delete_${name} ($${list}: [${type}!]) {
|
|
27
|
+
delete_${name} (where: {id: {_in: $${list}} }) { affected_rows }
|
|
28
|
+
}`)
|
|
29
|
+
|
|
30
|
+
const getCountQuery = prepare(`
|
|
31
|
+
query ${name}_count {
|
|
32
|
+
${name}_aggregate { aggregate { count } }
|
|
33
|
+
}`)
|
|
34
|
+
|
|
35
|
+
const getKey = _ => _[key]
|
|
36
|
+
const updateOne = ({ [key]: _, ...changes }) =>
|
|
37
|
+
updateQuery({ [key]: _, changes })
|
|
38
|
+
|
|
39
|
+
const mutations = {
|
|
40
|
+
key,
|
|
41
|
+
list,
|
|
42
|
+
insertQuery,
|
|
43
|
+
deleteQuery,
|
|
44
|
+
updateQuery,
|
|
45
|
+
updateQueryAll,
|
|
46
|
+
deleteQueryAll,
|
|
47
|
+
remove: _ =>
|
|
48
|
+
Array.isArray(_)
|
|
49
|
+
? deleteQueryAll({ [list]: _ })
|
|
50
|
+
: deleteQuery({ [key]: _ }),
|
|
51
|
+
update: (changes, _) => {
|
|
52
|
+
if (!_) return updateOne(changes)
|
|
53
|
+
return Array.isArray(_)
|
|
54
|
+
? updateQueryAll({ changes, [list]: _ })
|
|
55
|
+
: updateQuery({ changes, [key]: _ })
|
|
56
|
+
},
|
|
57
|
+
add: async _ => {
|
|
58
|
+
const isArray = Array.isArray(_)
|
|
59
|
+
const result = await insertQuery.all({ objects: isArray ? _ : [_] })
|
|
60
|
+
|
|
61
|
+
return isArray
|
|
62
|
+
? result[`insert_${name}`].returning.map(getKey)
|
|
63
|
+
: result[`insert_${name}`].returning[0][key]
|
|
64
|
+
},
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return fields => {
|
|
68
|
+
const oneById = `($${key}: ${type}!) {
|
|
69
|
+
${name} (where: {${key}: {_eq: $${key}}} limit: 1) {${key} ${fields}}
|
|
70
|
+
}`
|
|
71
|
+
|
|
72
|
+
const allById = `($${list}: [${type}!]) {
|
|
73
|
+
${name} (where: {${key}: {_in: $${list}}}) {${key} ${fields}}
|
|
74
|
+
}`
|
|
75
|
+
|
|
76
|
+
const byWhere = `($where: ${name}_bool_exp!) {
|
|
77
|
+
${name} (where: $where) {${key} ${fields}}
|
|
78
|
+
}`
|
|
79
|
+
|
|
80
|
+
const toPaginate = `(
|
|
81
|
+
$where: ${name}_bool_exp!, $orderBy: ${name}_order_by!, $limit: Int!, $offset: Int!,
|
|
82
|
+
) {
|
|
83
|
+
${name} ( order_by: [$orderBy] offset: $offset limit: $limit where: $where ) { ${fields} }
|
|
84
|
+
}`
|
|
85
|
+
|
|
86
|
+
const toPaginateWithCount = `(
|
|
87
|
+
$where: ${name}_bool_exp!, $orderBy: ${name}_order_by!, $limit: Int!, $offset: Int!,
|
|
88
|
+
) {
|
|
89
|
+
${name} ( order_by: [$orderBy] offset: $offset limit: $limit where: $where ) { ${fields} }
|
|
90
|
+
${name}_aggregate (where: $where) { aggregate { count } }
|
|
91
|
+
}`
|
|
92
|
+
|
|
93
|
+
const selectQuery = prepare(`query ${oneById}`)
|
|
94
|
+
const selectQueryAll = prepare(`query ${allById}`)
|
|
95
|
+
const selectQueryWhere = prepare(`query ${byWhere}`)
|
|
96
|
+
const selectQueryPaginated = prepare(
|
|
97
|
+
`query get_${name}_paginate ${toPaginate}`,
|
|
98
|
+
)
|
|
99
|
+
const selectQueryPaginatedWithCount = prepare(
|
|
100
|
+
`query get_${name}_with_count ${toPaginateWithCount}`,
|
|
101
|
+
)
|
|
102
|
+
const subscribeQuery = prepare(`subscription ${oneById}`)
|
|
103
|
+
const subscribeQueryAll = prepare(`subscription ${allById}`)
|
|
104
|
+
const subscribeQueryWhere = prepare(`subscription ${byWhere}`)
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
...mutations,
|
|
108
|
+
selectQuery,
|
|
109
|
+
selectQueryAll,
|
|
110
|
+
selectQueryWhere,
|
|
111
|
+
subscribeQuery,
|
|
112
|
+
subscribeQueryAll,
|
|
113
|
+
subscribeQueryWhere,
|
|
114
|
+
get: _ => {
|
|
115
|
+
if (Array.isArray(_)) return selectQueryAll({ [list]: _ })
|
|
116
|
+
return _ && typeof _ === 'object'
|
|
117
|
+
? selectQueryWhere({ where: _ })
|
|
118
|
+
: selectQuery.one(_ && { [key]: _ })
|
|
119
|
+
},
|
|
120
|
+
subscribe: (sub, _) => {
|
|
121
|
+
if (Array.isArray(_)) return subscribeQueryAll(sub, { [list]: _ })
|
|
122
|
+
return _ && typeof _ === 'object'
|
|
123
|
+
? subscribeQueryWhere(sub, { where: _ })
|
|
124
|
+
: subscribeQuery.one(sub, _ && { [key]: _ })
|
|
125
|
+
},
|
|
126
|
+
getCount: async elems => (await getCountQuery(elems)).aggregate.count,
|
|
127
|
+
getPaginated: selectQueryPaginated,
|
|
128
|
+
getPaginatedWithCount: async elems => {
|
|
129
|
+
const elemsWithCount = await selectQueryPaginatedWithCount.all(elems)
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
[name]: elemsWithCount[name],
|
|
133
|
+
count: elemsWithCount[`${name}_aggregate`].aggregate.count,
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const get = _ => Object.values(_)[0]
|
|
2
|
+
const getAll = _ => _
|
|
3
|
+
const getOne = _ => Object.values(_)[0][0]
|
|
4
|
+
export const prepare = ({ runFromString, subscribeFromString }, query) => {
|
|
5
|
+
if (typeof query !== 'string') {
|
|
6
|
+
throw Error(`Query must be a string but was ${typeof query}`)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let [_, type, name] = query.split(/^\s*(\w+)(?:\s+(\w+))?\b/)
|
|
10
|
+
if (!type) {
|
|
11
|
+
type = 'query'
|
|
12
|
+
} else if (!/^(subscription|mutation|query)$/.test(type)) {
|
|
13
|
+
throw Error(`Invalid query, type must be query, mutation or subscription`)
|
|
14
|
+
}
|
|
15
|
+
name || (name = `${type}_${query.split(/{\s*(.+?)\b/)[1]}`)
|
|
16
|
+
const payload = JSON.stringify({ query })
|
|
17
|
+
const noVars = payload
|
|
18
|
+
const base = payload.slice(0, -1)
|
|
19
|
+
const build = vars => {
|
|
20
|
+
if (!vars) return noVars
|
|
21
|
+
if (typeof vars === 'function') {
|
|
22
|
+
throw Error(
|
|
23
|
+
'variables should not be functions, verify the order of your parameters',
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
const stringified = JSON.stringify(vars)
|
|
27
|
+
if (stringified === '{}') return noVars
|
|
28
|
+
return `${base},"variables":${stringified}}`
|
|
29
|
+
}
|
|
30
|
+
const map =
|
|
31
|
+
type === 'subscription'
|
|
32
|
+
? mapper => (sub, vars) =>
|
|
33
|
+
subscribeFromString(value => sub(mapper(value)), build(vars), name)
|
|
34
|
+
: mapper => async vars => mapper(await runFromString(build(vars), name))
|
|
35
|
+
|
|
36
|
+
const run = map(get)
|
|
37
|
+
run.all = map(getAll)
|
|
38
|
+
run.one = map(getOne)
|
|
39
|
+
run.map = map
|
|
40
|
+
run.query = query
|
|
41
|
+
return run
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const initPrepare = client => query => prepare(client, query)
|
package/onboarding.js
CHANGED
|
@@ -1,17 +1,3 @@
|
|
|
1
|
-
export const onboardingTypes = new Set([
|
|
2
|
-
'onboarding',
|
|
3
|
-
'piscine-registration',
|
|
4
|
-
'interview',
|
|
5
|
-
'games',
|
|
6
|
-
'administration',
|
|
7
|
-
'module-registration',
|
|
8
|
-
'form-step',
|
|
9
|
-
'sign-step',
|
|
10
|
-
'upload-step',
|
|
11
|
-
'contact-validation-step',
|
|
12
|
-
'avatar-step',
|
|
13
|
-
])
|
|
14
|
-
|
|
15
1
|
export const prevValidated = (key, object) => {
|
|
16
2
|
const { prev } = (
|
|
17
3
|
object.parent.type !== 'onboarding' ? object : object.parent
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@01-edu/shared",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "",
|
|
6
6
|
"scripts": {
|
|
@@ -13,14 +13,22 @@
|
|
|
13
13
|
"./attrs.js",
|
|
14
14
|
"./attrs-defs.js",
|
|
15
15
|
"./graph.js",
|
|
16
|
+
"./hasura-core.js",
|
|
17
|
+
"./hasura-model.js",
|
|
18
|
+
"./hasura-prepare.js",
|
|
16
19
|
"./languages.js",
|
|
17
20
|
"./definitions-checker.js",
|
|
18
21
|
"./path.js",
|
|
19
22
|
"./programming-languages.js",
|
|
20
23
|
"./score.js",
|
|
21
24
|
"./skill-definitions.js",
|
|
22
|
-
"./toolbox.js"
|
|
25
|
+
"./toolbox.js",
|
|
26
|
+
"./object-structure.js",
|
|
27
|
+
"./qa-utils.js"
|
|
23
28
|
],
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"esbuild": "^0.25.12"
|
|
31
|
+
},
|
|
24
32
|
"license": "Fair",
|
|
25
33
|
"bin": {
|
|
26
34
|
"check-defs": "./bin/check-definitions.js"
|
package/qa-utils.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const stringifyJSX = value => {
|
|
2
|
+
if (!value) return ''
|
|
3
|
+
if (typeof value === 'string') return value
|
|
4
|
+
if (Array.isArray(value)) return value.map(stringifyJSX).join('')
|
|
5
|
+
return stringifyJSX(value.props?.children)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const toTestId = value =>
|
|
9
|
+
stringifyJSX(value)
|
|
10
|
+
.toLowerCase()
|
|
11
|
+
.replace(/([^a-z0-9]+)/g, ' ')
|
|
12
|
+
.trim()
|
|
13
|
+
.replaceAll(' ', '-')
|
package/toolbox.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { isFinished } from './event-utils.js'
|
|
2
|
-
import { onboardingTypes } from './onboarding.js'
|
|
3
2
|
|
|
4
3
|
const keyCodes = {
|
|
5
4
|
13: ({ save, value, event, allowLineBreak }) => {
|
|
@@ -11,48 +10,6 @@ const keyCodes = {
|
|
|
11
10
|
event.metaKey || event.ctrlKey ? save(value) : false, // cmd+s
|
|
12
11
|
}
|
|
13
12
|
|
|
14
|
-
export const contentObjects = new Set([
|
|
15
|
-
'module',
|
|
16
|
-
'piscine',
|
|
17
|
-
'exam',
|
|
18
|
-
'raid',
|
|
19
|
-
'quest',
|
|
20
|
-
'exercise',
|
|
21
|
-
'project',
|
|
22
|
-
'signup',
|
|
23
|
-
])
|
|
24
|
-
|
|
25
|
-
export const objectTypes = new Set([...contentObjects, ...onboardingTypes])
|
|
26
|
-
|
|
27
|
-
export const childTypes = {
|
|
28
|
-
campus: ['signup', 'onboarding', 'piscine', 'module'],
|
|
29
|
-
signup: [
|
|
30
|
-
'form-step',
|
|
31
|
-
'sign-step',
|
|
32
|
-
'upload-step',
|
|
33
|
-
'contact-validation-step',
|
|
34
|
-
'avatar-step',
|
|
35
|
-
],
|
|
36
|
-
onboarding: [
|
|
37
|
-
'games',
|
|
38
|
-
'administration',
|
|
39
|
-
'interview',
|
|
40
|
-
'piscine-registration',
|
|
41
|
-
'module-registration',
|
|
42
|
-
],
|
|
43
|
-
administration: [
|
|
44
|
-
'form-step',
|
|
45
|
-
'sign-step',
|
|
46
|
-
'upload-step',
|
|
47
|
-
'contact-validation-step',
|
|
48
|
-
'avatar-step',
|
|
49
|
-
],
|
|
50
|
-
piscine: ['quest', 'exam', 'raid', 'project'],
|
|
51
|
-
exam: ['exercise'],
|
|
52
|
-
quest: ['exercise'],
|
|
53
|
-
module: ['project', 'piscine', 'exam'],
|
|
54
|
-
}
|
|
55
|
-
|
|
56
13
|
export const handleKeyDownEvent = args => {
|
|
57
14
|
const handler = keyCodes[args.event.keyCode]
|
|
58
15
|
|