@01-edu/shared 1.1.0 → 1.1.2
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 +68 -2
- package/attrs.js +53 -22
- package/graph.js +96 -0
- package/package.json +2 -1
package/attrs-defs.js
CHANGED
|
@@ -63,7 +63,7 @@ const firstOfGroup = (a, _i, children) => {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
const getObjectPath = object => {
|
|
66
|
-
const core = getCoreOfSattelite(object)
|
|
66
|
+
const [core] = getCoreOfSattelite(object) || []
|
|
67
67
|
if (!core) return object.name
|
|
68
68
|
// special case only for projects with a core requirement set
|
|
69
69
|
// const coreName = getCoreName(object)
|
|
@@ -919,7 +919,7 @@ relationAttrs.difficultyMod = {
|
|
|
919
919
|
|
|
920
920
|
const getName = ({ name }) => name
|
|
921
921
|
const getProjectName = object => {
|
|
922
|
-
const core = getCoreOfSattelite(object)
|
|
922
|
+
const [core] = getCoreOfSattelite(object) || []
|
|
923
923
|
if (!core) return object.name
|
|
924
924
|
// only for projects with a core, and which name starts by the core name:
|
|
925
925
|
// remove the core name from the name to avoid repetition
|
|
@@ -4114,6 +4114,72 @@ relationAttrs.week = {
|
|
|
4114
4114
|
},
|
|
4115
4115
|
}
|
|
4116
4116
|
|
|
4117
|
+
const checkRaidLimitation = ({ object, value }) => {
|
|
4118
|
+
const raids = Object.values(object.parent.children).filter(
|
|
4119
|
+
({ type, key }) => key !== object.key && type === 'raid',
|
|
4120
|
+
)
|
|
4121
|
+
for (const { attrs } of raids) {
|
|
4122
|
+
if (attrs.branch === value) {
|
|
4123
|
+
throw Error('Raids should have their unique branch')
|
|
4124
|
+
}
|
|
4125
|
+
}
|
|
4126
|
+
}
|
|
4127
|
+
const checkBranchLimitation = ({ object, value, limit = 9 }) => {
|
|
4128
|
+
const contentInBranch = Object.values(object.parent.children).filter(
|
|
4129
|
+
({ key, attrs }) => key !== object.key && attrs.branch === value,
|
|
4130
|
+
)
|
|
4131
|
+
// + 1 for the current branch being added
|
|
4132
|
+
if (contentInBranch.length + 1 > limit) {
|
|
4133
|
+
throw Error(`The limit of content in a branch is ${limit}`)
|
|
4134
|
+
}
|
|
4135
|
+
}
|
|
4136
|
+
|
|
4137
|
+
const sharedBranchOptions = {
|
|
4138
|
+
label: 'Base Branch',
|
|
4139
|
+
instruction: 'From 1 to 4',
|
|
4140
|
+
description: 'Changing branch can disrupt the piscine timeline.',
|
|
4141
|
+
required: true,
|
|
4142
|
+
editable: true,
|
|
4143
|
+
}
|
|
4144
|
+
|
|
4145
|
+
const getBranchOptions = (object, limit = 9) => {
|
|
4146
|
+
const branchCounts = {}
|
|
4147
|
+
for (const child of Object.values(object.parent.children || {})) {
|
|
4148
|
+
const branch = child.attrs.branch
|
|
4149
|
+
branchCounts[branch] = (branchCounts[branch] || 0) + 1
|
|
4150
|
+
}
|
|
4151
|
+
const allBranches = [1, 2, 3, 4]
|
|
4152
|
+
return allBranches.filter(branch => (branchCounts[branch] || 0) < limit)
|
|
4153
|
+
}
|
|
4154
|
+
|
|
4155
|
+
const sharedBranch = Literal(1, {
|
|
4156
|
+
...sharedBranchOptions,
|
|
4157
|
+
options: getBranchOptions,
|
|
4158
|
+
check: (value, object) => {
|
|
4159
|
+
checkNumberInBetween(value, 1, 4)
|
|
4160
|
+
checkBranchLimitation({ object, value })
|
|
4161
|
+
},
|
|
4162
|
+
})
|
|
4163
|
+
|
|
4164
|
+
const raidSharedBranch = Literal(1, {
|
|
4165
|
+
...sharedBranchOptions,
|
|
4166
|
+
options: [1, 2, 3, 4],
|
|
4167
|
+
check: (value, object) => {
|
|
4168
|
+
checkNumberInBetween(value, 1, 4)
|
|
4169
|
+
checkRaidLimitation({ object, value })
|
|
4170
|
+
checkBranchLimitation({ object, value })
|
|
4171
|
+
},
|
|
4172
|
+
})
|
|
4173
|
+
relationAttrs.branch = {
|
|
4174
|
+
piscine: {
|
|
4175
|
+
quest: sharedBranch,
|
|
4176
|
+
project: sharedBranch,
|
|
4177
|
+
raid: raidSharedBranch,
|
|
4178
|
+
sharedBranch,
|
|
4179
|
+
exam: sharedBranch,
|
|
4180
|
+
},
|
|
4181
|
+
}
|
|
4182
|
+
|
|
4117
4183
|
const sharedZeroXpIndex = Literal(0, {
|
|
4118
4184
|
required: true,
|
|
4119
4185
|
private: true,
|
package/attrs.js
CHANGED
|
@@ -344,42 +344,73 @@ const expandAttr = (key, value, defs, object, getUser) => {
|
|
|
344
344
|
}
|
|
345
345
|
}
|
|
346
346
|
|
|
347
|
-
|
|
347
|
+
// same as the `expandDynamicAttrs` this function would resolve dynamic attributes
|
|
348
|
+
// the special use of this function is that we can resolve certain attributes
|
|
349
|
+
// by providing a filter function
|
|
350
|
+
export const partialExpandDynamicAttrs = (object, getUser, filterFn) => {
|
|
348
351
|
if (!object.children) return (object.children = {})
|
|
352
|
+
const defautlAttrs = getDefaultAttrsEntries(object)
|
|
353
|
+
const filteredDefaultAttrs = defautlAttrs.filter(filterFn)
|
|
349
354
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
+
processAttributes(filteredDefaultAttrs, object, getUser)
|
|
356
|
+
let prev
|
|
357
|
+
for (const child of Object.values(object.children)) {
|
|
358
|
+
child.parent = object
|
|
359
|
+
prev && (prev.next = child) && (child.prev = prev)
|
|
360
|
+
prev = child
|
|
361
|
+
|
|
362
|
+
const childDefaultAttrs = getDefaultAttrsEntries(child)
|
|
363
|
+
const childRelAttrs = getDefaultRelAttrsEntries(object.type, child.type)
|
|
364
|
+
const [filteredChildAttrs, filteredRelAttrs] = [
|
|
365
|
+
childDefaultAttrs.filter(filterFn),
|
|
366
|
+
childRelAttrs.filter(filterFn),
|
|
367
|
+
]
|
|
368
|
+
|
|
369
|
+
// apply missing default functions
|
|
370
|
+
// a function can only be missing if it require the user,
|
|
371
|
+
// the event or current time
|
|
372
|
+
processAttributes(filteredChildAttrs, child, getUser)
|
|
373
|
+
processAttributes(filteredRelAttrs, child, getUser)
|
|
374
|
+
partialExpandDynamicAttrs(child, getUser, filterFn)
|
|
355
375
|
}
|
|
376
|
+
}
|
|
356
377
|
|
|
378
|
+
// this function allows us to resolve dynamic attributes
|
|
379
|
+
// by converting them into functions that can be re-evaluated
|
|
380
|
+
// this enables attributes to return updated values when re-checked
|
|
381
|
+
// without requiring additional api queries
|
|
382
|
+
// so the result can be recalculated as needed
|
|
383
|
+
export const expandDynamicAttrs = (object, getUser) => {
|
|
384
|
+
if (!object.children) return (object.children = {})
|
|
385
|
+
const defautlAttrs = getDefaultAttrsEntries(object)
|
|
386
|
+
|
|
387
|
+
processAttributes(defautlAttrs, object, getUser)
|
|
357
388
|
let prev
|
|
358
389
|
for (const child of Object.values(object.children)) {
|
|
359
390
|
child.parent = object
|
|
360
391
|
prev && (prev.next = child) && (child.prev = prev)
|
|
361
392
|
prev = child
|
|
362
393
|
|
|
394
|
+
const childDefaultAttrs = getDefaultAttrsEntries(child)
|
|
395
|
+
const childRelAttrs = getDefaultRelAttrsEntries(object.type, child.type)
|
|
396
|
+
|
|
363
397
|
// apply missing default functions
|
|
364
398
|
// a function can only be missing if it require the user,
|
|
365
399
|
// the event or current time
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
}
|
|
372
|
-
for (const [key, defs] of getDefaultRelAttrsEntries(
|
|
373
|
-
object.type,
|
|
374
|
-
child.type,
|
|
375
|
-
)) {
|
|
376
|
-
if (child.attrs[key] === null) {
|
|
377
|
-
console.warn(`value is null for ${child.name} - ${key} - ${child.id}`)
|
|
378
|
-
}
|
|
379
|
-
expandAttr(key, child.attrs, defs, child, getUser)
|
|
380
|
-
}
|
|
400
|
+
processAttributes(childDefaultAttrs, child, getUser)
|
|
401
|
+
processAttributes(childRelAttrs, child, getUser)
|
|
402
|
+
expandDynamicAttrs(child, getUser)
|
|
403
|
+
}
|
|
404
|
+
}
|
|
381
405
|
|
|
382
|
-
|
|
406
|
+
const processAttributes = (attrEntries, targetObject, getUser) => {
|
|
407
|
+
for (const [key, defs] of attrEntries) {
|
|
408
|
+
if (targetObject.attrs[key] === null) {
|
|
409
|
+
console.warn(
|
|
410
|
+
`value is null for ${targetObject.name} - ${key} - ${targetObject.id}`,
|
|
411
|
+
)
|
|
412
|
+
}
|
|
413
|
+
expandAttr(key, targetObject.attrs, defs, targetObject, getUser)
|
|
383
414
|
}
|
|
384
415
|
}
|
|
385
416
|
|
package/graph.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
const isCoreObj = (contentShape, coreKey) =>
|
|
2
|
+
typeof contentShape === 'object' && Object.keys(contentShape)[0] === coreKey
|
|
3
|
+
const isSatteliteObj = (contentShape, satteliteKey) =>
|
|
4
|
+
typeof contentShape === 'object' &&
|
|
5
|
+
Object.values(contentShape)[0].some(sat => sat === satteliteKey)
|
|
6
|
+
|
|
7
|
+
export const getCoreSattelites = (coreObject, objectsList) => {
|
|
8
|
+
const { key, parent } = coreObject
|
|
9
|
+
const objects = objectsList || Object.values(parent.children)
|
|
10
|
+
const sattelitesSection = parent.attrs.graph.innerCircle.find(
|
|
11
|
+
s => s.type === 'slice' && s.innerArc.contents.find(c => isCoreObj(c, key)),
|
|
12
|
+
)
|
|
13
|
+
if (!sattelitesSection) return []
|
|
14
|
+
const sattelitesObject = sattelitesSection.innerArc.contents.find(c =>
|
|
15
|
+
isCoreObj(c, key),
|
|
16
|
+
)
|
|
17
|
+
const sattelitesList = new Set(...Object.values(sattelitesObject))
|
|
18
|
+
|
|
19
|
+
return objects.filter(o => sattelitesList.has(o.key))
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const getCoreOfSattelite = (satteliteObject, objectsList) => {
|
|
23
|
+
const { key, parent } = satteliteObject
|
|
24
|
+
const objects = objectsList || Object.values(parent.children)
|
|
25
|
+
const sattelitesSection = parent.attrs.graph?.innerCircle?.find(
|
|
26
|
+
s =>
|
|
27
|
+
s.type === 'slice' &&
|
|
28
|
+
s.innerArc?.contents.find(c => isSatteliteObj(c, key)),
|
|
29
|
+
)
|
|
30
|
+
if (!sattelitesSection) return undefined
|
|
31
|
+
const coreObject = sattelitesSection.innerArc.contents.find(c =>
|
|
32
|
+
isSatteliteObj(c, key),
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
return objects.filter(o => o.key === Object.keys(coreObject)[0])
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const flatGraphContents = graph => [
|
|
39
|
+
...(graph.centralPoint ? [graph.centralPoint] : []),
|
|
40
|
+
...(graph.innerCircle || []).flatMap(section =>
|
|
41
|
+
section.type === 'slice'
|
|
42
|
+
? [
|
|
43
|
+
...(section.entryPoint ? [section.entryPoint] : []),
|
|
44
|
+
...(section.innerArc?.contents || []).flatMap(c =>
|
|
45
|
+
typeof c === 'string' ? c : Object.entries(c)[0].flat(),
|
|
46
|
+
),
|
|
47
|
+
...(section.outerArcs || []).flatMap(arc => arc.contents || []),
|
|
48
|
+
]
|
|
49
|
+
: section.contents,
|
|
50
|
+
),
|
|
51
|
+
...(graph.middleCircle || []).flatMap(arc => arc.contents || []),
|
|
52
|
+
...(graph.outerCircle || []).flatMap(arc => arc.contents || []),
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
// WARNING: without central point (for linear graph, already destructured)
|
|
56
|
+
export const flatAtomeAndCoreContents = graph => [
|
|
57
|
+
...(graph.innerCircle || []).flatMap(section =>
|
|
58
|
+
section.type === 'slice'
|
|
59
|
+
? [
|
|
60
|
+
...(section.entryPoint ? [section.entryPoint] : []),
|
|
61
|
+
...(section.innerArc?.contents || []).flatMap(c =>
|
|
62
|
+
typeof c === 'string' ? c : Object.keys(c)[0],
|
|
63
|
+
),
|
|
64
|
+
...(section.outerArcs || []).flatMap(arc => arc.contents || []),
|
|
65
|
+
]
|
|
66
|
+
: section.contents,
|
|
67
|
+
),
|
|
68
|
+
...(graph.middleCircle || []).flatMap(arc => arc.contents || []),
|
|
69
|
+
...(graph.outerCircle || []).flatMap(arc => arc.contents || []),
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
export const limitations = {
|
|
73
|
+
LINE: {
|
|
74
|
+
maxLinesCount: 6,
|
|
75
|
+
maxContentsCount: 7, // 7 contents max split along a single line
|
|
76
|
+
},
|
|
77
|
+
SLICE: {
|
|
78
|
+
maxSlicesCount: 4,
|
|
79
|
+
innerCircle: {
|
|
80
|
+
maxSubContentsCount: 5, // 5 sub-contents max by content
|
|
81
|
+
maxContentsCount: 30, // 30 contents max spread evenly over the number of inner cirlces of slices
|
|
82
|
+
},
|
|
83
|
+
outerArc: {
|
|
84
|
+
maxArcsCount: 2,
|
|
85
|
+
maxContentsCount: 10, // 10 contents max spread evenly over the 1 or 2 outer arcs
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
MIDDLE_CIRCLE: {
|
|
89
|
+
maxArcsCount: 8,
|
|
90
|
+
maxContentsCount: 70, // 70 contents max spread evenly over the number of arcs
|
|
91
|
+
},
|
|
92
|
+
OUTER_CIRCLE: {
|
|
93
|
+
maxArcsCount: 9,
|
|
94
|
+
maxContentsCount: 90, // 90 contents max spread evenly over the number of arcs
|
|
95
|
+
},
|
|
96
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@01-edu/shared",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "",
|
|
6
6
|
"scripts": {
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"./onboarding.js",
|
|
14
14
|
"./attrs.js",
|
|
15
15
|
"./attrs-defs.js",
|
|
16
|
+
"./graph.js",
|
|
16
17
|
"./languages.js",
|
|
17
18
|
"./definitions-checker.js",
|
|
18
19
|
"./path.js",
|