-
Notifications
You must be signed in to change notification settings - Fork 196
Expand file tree
/
Copy pathkey-utils.ts
More file actions
167 lines (148 loc) · 5.6 KB
/
key-utils.ts
File metadata and controls
167 lines (148 loc) · 5.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/**
* Given a usage key like `lb:org:lib:html:id` or `block-v1:org+type@html+block@1`, get the type (e.g. `html`)
* @param usageKey e.g. `lb:org:lib:html:id`, `block-v1:org+type@html+block@1`
* @returns The block type as a string
*/
export function getBlockType(
usageKey: string,
onInvalid: 'empty' | 'error' = 'error',
): string {
if (usageKey) {
if (usageKey.startsWith('lb:') || usageKey.startsWith('lct:')) {
const blockType = usageKey.split(':')[3];
if (blockType) {
return blockType;
}
} else if (usageKey.startsWith('block-v1:')) {
const blockType = usageKey.match(/type@([^+]+)/);
if (blockType) {
return blockType[1];
}
}
}
if (onInvalid === 'empty') {
return '';
}
throw new Error(`Invalid usageKey: ${usageKey}`);
}
/**
* Parses a library key and returns the organization and library name as an object.
*/
export function parseLibraryKey(libraryKey: string): { org: string; lib: string; } {
const splitKey = libraryKey?.split(':') || [];
if (splitKey.length !== 3) {
throw new Error(`Invalid libraryKey: ${libraryKey}`);
}
const [, org, lib] = splitKey;
if (org && lib) {
return { org, lib };
}
throw new Error(`Invalid libraryKey: ${libraryKey}`);
}
/**
* Given a usage key like `lb:org:lib:html:id`, get the library key
* @param usageKey e.g. `lb:org:lib:html:id`
* @returns The library key, e.g. `lib:org:lib`
*/
export function getLibraryId(usageKey: string): string {
const [blockType, org, lib] = usageKey?.split(':') || [];
if (['lb', 'lib-collection', 'lct'].includes(blockType) && org && lib) {
return `lib:${org}:${lib}`;
}
throw new Error(`Invalid usageKey: ${usageKey}`);
}
/**
* Given a usage key like `block-v1:org:course:html:id`, get the course key
*/
export function getCourseKey(usageKey: string): string {
const [prefix] = usageKey?.split('@') || [];
const [blockType, courseInfo] = prefix?.split(':') || [];
const [org, course, run] = courseInfo?.split('+') || [];
if (blockType === 'block-v1' && org && course && run) {
return `course-v1:${org}+${course}+${run}`;
}
throw new Error(`Invalid usageKey: ${usageKey}`);
}
/** Check if this is a course key */
export function isCourseKey(learningContextKey: string | undefined | null): learningContextKey is string {
return typeof learningContextKey === 'string' && learningContextKey.startsWith('course-v1:');
}
/** Check if this is a V2 library key. */
export function isLibraryKey(learningContextKey: string | undefined | null): learningContextKey is string {
return typeof learningContextKey === 'string' && learningContextKey.startsWith('lib:');
}
/** Check if this is a V1 library key. */
export function isLibraryV1Key(learningContextKey: string | undefined | null): learningContextKey is string {
return typeof learningContextKey === 'string' && learningContextKey.startsWith('library-v1:');
}
/** Check if this is a V1 block key. */
export function isBlockV1Key(usageKey: string | undefined | null): boolean {
return typeof usageKey === 'string' && usageKey.startsWith('block-v1:');
}
/**
* Build a collection usage key from library V2 context key and collection Id.
* This Collection Usage Key is only used on tagging.
*/
export const buildCollectionUsageKey = (learningContextKey: string, collectionId: string) => {
if (!isLibraryKey(learningContextKey)) {
return '';
}
const orgLib = learningContextKey.replace('lib:', '');
return `lib-collection:${orgLib}:${collectionId}`;
};
export enum ContainerType {
Section = 'section',
Subsection = 'subsection',
Unit = 'unit',
/**
* Chapter, Sequential and Vertical are the old names for section, subsection and unit.
* Generally, **please avoid using this term entirely in any libraries code** or
* anything based on the new Learning Core "Containers" framework - just call it a unit, section or subsection. We
* do still need to use this in the modulestore-based courseware, and currently the /xblock/ API used to copy
* library containers into courses also requires specifying this, though that should change to a better API
* that does the unit->vertical conversion automatically in the future.
*/
Chapter = 'chapter',
Sequential = 'sequential',
Vertical = 'vertical',
/**
* Components are not strictly a container type, but we add this here for simplicity when rendering the container
* hierarchy.
*/
Components = 'components',
}
/**
* Normalize a container type to the standard version. For example, 'sequential' will be normalized to 'subsection'.
*/
export function normalizeContainerType(containerType: ContainerType | string) {
switch (containerType) {
case ContainerType.Chapter:
return ContainerType.Section;
case ContainerType.Sequential:
return ContainerType.Subsection;
case ContainerType.Vertical:
return ContainerType.Unit;
default:
return containerType;
}
}
/**
* Check whether a block/container type points to a container (section/subsection/unit),
* including legacy names (chapter/sequential/vertical).
*/
export function isContainerType(containerType: ContainerType | string): boolean {
const normalizedType = normalizeContainerType(containerType);
return [ContainerType.Section, ContainerType.Subsection, ContainerType.Unit].includes(
normalizedType as ContainerType,
);
}
/**
* Check whether a usage key belongs to a container.
*/
export function isContainerUsageKey(usageKey: string | undefined | null): boolean {
if (typeof usageKey !== 'string') {
return false;
}
const blockType = getBlockType(usageKey, 'empty');
return blockType ? isContainerType(blockType) : false;
}