@memizy/oqse 0.1.0 → 0.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/README.md +15 -8
- package/dist/index.cjs +2 -2
- package/dist/index.d.ts +8 -1
- package/dist/index.js +514 -415
- package/dist/src/index.d.ts +1 -0
- package/dist/src/manifest.d.ts +9 -5
- package/dist/src/manifestValidation.d.ts +6 -5
- package/dist/src/oqse.d.ts +0 -28
- package/dist/src/oqseValidation.d.ts +3 -44
- package/dist/src/richTextProcessor.d.ts +46 -0
- package/dist/src/richTextProcessor.test.d.ts +1 -0
- package/dist/src/utils.d.ts +9 -0
- package/package.json +6 -3
- package/schemas/oqse-manifest-v0.1.json +3 -6
- package/schemas/oqse-v0.1.json +3 -34
- package/SPECIFICATION.md +0 -2444
package/dist/index.js
CHANGED
|
@@ -15,58 +15,58 @@ function i(e) {
|
|
|
15
15
|
function a(e) {
|
|
16
16
|
return e.type === "mcq-multi";
|
|
17
17
|
}
|
|
18
|
-
function
|
|
18
|
+
function o(e) {
|
|
19
19
|
return e.type === "short-answer";
|
|
20
20
|
}
|
|
21
|
-
function
|
|
21
|
+
function ee(e) {
|
|
22
22
|
return e.type === "fill-in-blanks";
|
|
23
23
|
}
|
|
24
|
-
function
|
|
24
|
+
function te(e) {
|
|
25
25
|
return e.type === "fill-in-select";
|
|
26
26
|
}
|
|
27
|
-
function
|
|
27
|
+
function ne(e) {
|
|
28
28
|
return e.type === "match-pairs";
|
|
29
29
|
}
|
|
30
|
-
function
|
|
30
|
+
function re(e) {
|
|
31
31
|
return e.type === "match-complex";
|
|
32
32
|
}
|
|
33
|
-
function
|
|
33
|
+
function ie(e) {
|
|
34
34
|
return e.type === "sort-items";
|
|
35
35
|
}
|
|
36
|
-
function
|
|
36
|
+
function ae(e) {
|
|
37
37
|
return e.type === "slider";
|
|
38
38
|
}
|
|
39
|
-
function
|
|
39
|
+
function oe(e) {
|
|
40
40
|
return e.type === "pin-on-image";
|
|
41
41
|
}
|
|
42
|
-
function
|
|
42
|
+
function se(e) {
|
|
43
43
|
return e.type === "categorize";
|
|
44
44
|
}
|
|
45
|
-
function
|
|
45
|
+
function ce(e) {
|
|
46
46
|
return e.type === "timeline";
|
|
47
47
|
}
|
|
48
|
-
function
|
|
48
|
+
function le(e) {
|
|
49
49
|
return e.type === "matrix";
|
|
50
50
|
}
|
|
51
|
-
function
|
|
51
|
+
function ue(e) {
|
|
52
52
|
return e.type === "math-input";
|
|
53
53
|
}
|
|
54
|
-
function
|
|
54
|
+
function de(e) {
|
|
55
55
|
return e.type === "diagram-label";
|
|
56
56
|
}
|
|
57
|
-
function
|
|
57
|
+
function fe(e) {
|
|
58
58
|
return e.type === "open-ended";
|
|
59
59
|
}
|
|
60
|
-
function
|
|
60
|
+
function pe(e) {
|
|
61
61
|
return e.type === "numeric-input";
|
|
62
62
|
}
|
|
63
|
-
function
|
|
63
|
+
function me(e) {
|
|
64
64
|
return e.type === "pin-on-model";
|
|
65
65
|
}
|
|
66
|
-
function
|
|
66
|
+
function he(e) {
|
|
67
67
|
return e.type === "chess-puzzle";
|
|
68
68
|
}
|
|
69
|
-
function
|
|
69
|
+
function ge(e) {
|
|
70
70
|
return [
|
|
71
71
|
"note",
|
|
72
72
|
"flashcard",
|
|
@@ -75,52 +75,118 @@ function o(e) {
|
|
|
75
75
|
].includes(e.type);
|
|
76
76
|
}
|
|
77
77
|
function _e(e) {
|
|
78
|
-
return !
|
|
78
|
+
return !ge(e);
|
|
79
|
+
}
|
|
80
|
+
//#endregion
|
|
81
|
+
//#region src/manifest.ts
|
|
82
|
+
var ve = [
|
|
83
|
+
"render",
|
|
84
|
+
"edit",
|
|
85
|
+
"validate",
|
|
86
|
+
"import",
|
|
87
|
+
"export"
|
|
88
|
+
], s = [
|
|
89
|
+
"markdown",
|
|
90
|
+
"math",
|
|
91
|
+
"rtl",
|
|
92
|
+
"html",
|
|
93
|
+
"syntax-highlighting",
|
|
94
|
+
"mermaid",
|
|
95
|
+
"smiles",
|
|
96
|
+
"abc-notation",
|
|
97
|
+
"text-to-speech",
|
|
98
|
+
"voice-input",
|
|
99
|
+
"handwriting-recognition"
|
|
100
|
+
], c = [
|
|
101
|
+
"hints",
|
|
102
|
+
"explanation",
|
|
103
|
+
"incorrectFeedback",
|
|
104
|
+
"sources",
|
|
105
|
+
"relatedItems",
|
|
106
|
+
"dependencyItems",
|
|
107
|
+
"timeLimit",
|
|
108
|
+
"lang",
|
|
109
|
+
"topic",
|
|
110
|
+
"pedagogy"
|
|
111
|
+
], l = [
|
|
112
|
+
"description",
|
|
113
|
+
"thumbnail",
|
|
114
|
+
"subject",
|
|
115
|
+
"language",
|
|
116
|
+
"author",
|
|
117
|
+
"contributors",
|
|
118
|
+
"license",
|
|
119
|
+
"ageRestriction",
|
|
120
|
+
"tags",
|
|
121
|
+
"tagDefinitions",
|
|
122
|
+
"sourceMaterials",
|
|
123
|
+
"estimatedTime",
|
|
124
|
+
"prerequisites",
|
|
125
|
+
"translations",
|
|
126
|
+
"relatedSets"
|
|
127
|
+
];
|
|
128
|
+
function u(e) {
|
|
129
|
+
return /^\d+\.\d+$/.test(e);
|
|
130
|
+
}
|
|
131
|
+
function ye(e) {
|
|
132
|
+
return /^\d+\.\d+\.\d+(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$/.test(e);
|
|
133
|
+
}
|
|
134
|
+
function d(e, t) {
|
|
135
|
+
let [n = 0, r = 0] = e.split(".").map(Number), [i = 0, a = 0] = t.split(".").map(Number);
|
|
136
|
+
return n === i ? r - a : n - i;
|
|
137
|
+
}
|
|
138
|
+
function be(e) {
|
|
139
|
+
if (typeof e != "object" || !e) return !1;
|
|
140
|
+
let t = e;
|
|
141
|
+
return typeof t.version == "string" && typeof t.id == "string" && typeof t.appName == "string" && t.appName !== "" && typeof t.capabilities == "object" && t.capabilities !== null && Array.isArray(t.capabilities.actions);
|
|
142
|
+
}
|
|
143
|
+
function xe(e, t) {
|
|
144
|
+
return !(!u(e) || t.minOqseVersion && u(t.minOqseVersion) && d(e, t.minOqseVersion) < 0 || t.maxOqseVersion && u(t.maxOqseVersion) && d(e, t.maxOqseVersion) > 0);
|
|
79
145
|
}
|
|
80
146
|
//#endregion
|
|
81
147
|
//#region src/oqseValidation.ts
|
|
82
|
-
var
|
|
83
|
-
lang:
|
|
84
|
-
value: e.string().min(1, "URI
|
|
148
|
+
var f = e.string().uuid({ message: "Invalid UUID format" }), p = e.string().min(2, "Language code must have at least 2 characters").regex(/^[a-z]{2,3}(-[A-Z][a-z]{3})?(-[A-Z]{2})?$/, "Invalid BCP 47 format (e.g. \"cs\", \"en-US\")"), m = e.string().min(1, "License identifier must not be empty"), h = e.string().regex(/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d{3})?(Z|[+-]\d{2}:\d{2})?)?$/, "Invalid ISO 8601 format (e.g. \"2025-11-21T14:30:00Z\")"), g = e.string().url({ message: "Must be a valid absolute URL" }), _ = e.string().regex(/^[a-z0-9_-]+$/, "Asset key must contain only lowercase letters, numbers, hyphens and underscores"), v = e.string().min(1, "Text must not be empty"), y = e.string().min(1, "Content must not be empty"), b = e.string().optional(), Se = e.object({
|
|
149
|
+
lang: p,
|
|
150
|
+
value: e.string().min(1, "Subtitle URI must not be empty"),
|
|
85
151
|
label: e.string().optional(),
|
|
86
152
|
kind: e.enum([
|
|
87
153
|
"captions",
|
|
88
154
|
"subtitles",
|
|
89
155
|
"descriptions"
|
|
90
156
|
]).optional()
|
|
91
|
-
}),
|
|
157
|
+
}), Ce = e.object({
|
|
92
158
|
type: e.enum([
|
|
93
159
|
"image",
|
|
94
160
|
"audio",
|
|
95
161
|
"video",
|
|
96
162
|
"model"
|
|
97
163
|
]),
|
|
98
|
-
value: e.string().min(1, "URI
|
|
164
|
+
value: e.string().min(1, "Media URI must not be empty"),
|
|
99
165
|
mimeType: e.string().optional(),
|
|
100
166
|
altText: e.string().optional(),
|
|
101
|
-
transcript:
|
|
102
|
-
caption:
|
|
167
|
+
transcript: y.optional(),
|
|
168
|
+
caption: y.optional(),
|
|
103
169
|
width: e.number().int().positive().optional(),
|
|
104
170
|
height: e.number().int().positive().optional(),
|
|
105
171
|
start: e.number().nonnegative().optional(),
|
|
106
172
|
end: e.number().positive().optional(),
|
|
107
173
|
loop: e.boolean().optional(),
|
|
108
|
-
subtitles: e.array(
|
|
109
|
-
license:
|
|
174
|
+
subtitles: e.array(Se).optional(),
|
|
175
|
+
license: m.optional(),
|
|
110
176
|
attribution: e.string().optional(),
|
|
111
177
|
checksums: e.record(e.string(), e.string()).optional()
|
|
112
178
|
}).refine((e) => e.start !== void 0 && e.end !== void 0 ? e.start < e.end : !0, {
|
|
113
|
-
message: "
|
|
179
|
+
message: "Start time must be less than end time",
|
|
114
180
|
path: ["end"]
|
|
115
181
|
}).refine((e) => !(e.type === "image" && !e.altText), {
|
|
116
|
-
message: "
|
|
182
|
+
message: "Images must have alternative text (altText) defined for accessibility",
|
|
117
183
|
path: ["altText"]
|
|
118
|
-
}),
|
|
119
|
-
name:
|
|
184
|
+
}), x = e.record(_, Ce), S = e.object({
|
|
185
|
+
name: v,
|
|
120
186
|
role: e.string().optional(),
|
|
121
|
-
email: e.string().email("
|
|
122
|
-
url:
|
|
123
|
-
}),
|
|
187
|
+
email: e.string().email("Invalid email format").optional(),
|
|
188
|
+
url: g.optional()
|
|
189
|
+
}), C = e.enum([
|
|
124
190
|
"url",
|
|
125
191
|
"doi",
|
|
126
192
|
"isbn",
|
|
@@ -131,16 +197,16 @@ var s = e.string().uuid({ message: "Neplatn+� form+�t UUID" }), c = e.string
|
|
|
131
197
|
"image",
|
|
132
198
|
"model",
|
|
133
199
|
"other"
|
|
134
|
-
]),
|
|
135
|
-
id:
|
|
136
|
-
type:
|
|
137
|
-
value:
|
|
138
|
-
title:
|
|
200
|
+
]), w = e.object({
|
|
201
|
+
id: v,
|
|
202
|
+
type: C,
|
|
203
|
+
value: v,
|
|
204
|
+
title: v,
|
|
139
205
|
description: e.string().optional(),
|
|
140
|
-
authors: e.array(
|
|
141
|
-
publishedDate:
|
|
142
|
-
retrievedAt:
|
|
143
|
-
license:
|
|
206
|
+
authors: e.array(v).optional(),
|
|
207
|
+
publishedDate: h.optional(),
|
|
208
|
+
retrievedAt: h.optional(),
|
|
209
|
+
license: m.optional()
|
|
144
210
|
}).refine((e) => {
|
|
145
211
|
if ([
|
|
146
212
|
"url",
|
|
@@ -155,261 +221,241 @@ var s = e.string().uuid({ message: "Neplatn+� form+�t UUID" }), c = e.string
|
|
|
155
221
|
}
|
|
156
222
|
return !0;
|
|
157
223
|
}, {
|
|
158
|
-
message: "
|
|
224
|
+
message: "For url, pdf, video, audio and image types, value must be a valid URL",
|
|
159
225
|
path: ["value"]
|
|
160
|
-
}),
|
|
161
|
-
id:
|
|
226
|
+
}), T = e.object({
|
|
227
|
+
id: v,
|
|
162
228
|
location: e.string().optional(),
|
|
163
|
-
quote:
|
|
164
|
-
}),
|
|
165
|
-
wikidataId: e.string().regex(/^Q\d+$/, "Wikidata ID
|
|
229
|
+
quote: y.optional()
|
|
230
|
+
}), E = e.object({
|
|
231
|
+
wikidataId: e.string().regex(/^Q\d+$/, "Wikidata ID must have format Q followed by number").optional(),
|
|
166
232
|
description: e.string().optional()
|
|
167
|
-
}),
|
|
168
|
-
features: e.array(e.string().
|
|
169
|
-
latexPackages: e.array(e.string().min(1, "
|
|
170
|
-
itemProperties: e.array(e.string().
|
|
171
|
-
metaProperties: e.array(e.string().
|
|
172
|
-
}),
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
"math",
|
|
178
|
-
"media-image",
|
|
179
|
-
"media-audio",
|
|
180
|
-
"media-video",
|
|
181
|
-
"hotspots",
|
|
182
|
-
"complex-pairing",
|
|
183
|
-
"open-text"
|
|
184
|
-
]), E = e.object({
|
|
185
|
-
name: p,
|
|
186
|
-
type: T,
|
|
187
|
-
vendor: e.string().optional()
|
|
188
|
-
}).refine((e) => !(e.type === "proprietary" && !e.vendor), {
|
|
189
|
-
message: "Propriet+�rn+� funkce mus+� m+�t definovan+� vendor (nap+�. \"memizy.com\")",
|
|
190
|
-
path: ["vendor"]
|
|
191
|
-
}), D = e.object({
|
|
192
|
-
lang: c,
|
|
193
|
-
id: s,
|
|
194
|
-
title: p,
|
|
195
|
-
downloadUrl: d.optional()
|
|
233
|
+
}), we = e.record(e.string(), E), D = e.object({
|
|
234
|
+
features: e.array(e.string().refine((e) => s.includes(e) || e.startsWith("x-"), { message: "Feature must be an official key or have prefix \"x-\"" })).optional(),
|
|
235
|
+
latexPackages: e.array(e.string().min(1, "Package name must not be empty")).optional(),
|
|
236
|
+
itemProperties: e.array(e.string().refine((e) => c.includes(e) || e.startsWith("x-"), { message: "Item property must be an official key or have prefix \"x-\"" })).optional(),
|
|
237
|
+
metaProperties: e.array(e.string().refine((e) => l.includes(e) || e.startsWith("x-"), { message: "Meta property must be an official key or have prefix \"x-\"" })).optional()
|
|
238
|
+
}), Te = e.object({
|
|
239
|
+
lang: p,
|
|
240
|
+
id: f,
|
|
241
|
+
title: v,
|
|
242
|
+
downloadUrl: g.optional()
|
|
196
243
|
}), O = e.object({
|
|
197
|
-
id:
|
|
198
|
-
title:
|
|
199
|
-
downloadUrl:
|
|
200
|
-
}),
|
|
244
|
+
id: f,
|
|
245
|
+
title: v,
|
|
246
|
+
downloadUrl: g.optional()
|
|
247
|
+
}), Ee = e.enum([
|
|
201
248
|
"remember",
|
|
202
249
|
"understand",
|
|
203
250
|
"apply",
|
|
204
251
|
"analyze",
|
|
205
252
|
"evaluate",
|
|
206
253
|
"create"
|
|
207
|
-
]),
|
|
254
|
+
]), De = e.enum([
|
|
208
255
|
"low",
|
|
209
256
|
"medium",
|
|
210
257
|
"high"
|
|
211
|
-
]),
|
|
212
|
-
bloomLevel:
|
|
258
|
+
]), Oe = e.object({
|
|
259
|
+
bloomLevel: Ee.optional(),
|
|
213
260
|
irtDifficulty: e.number().optional(),
|
|
214
261
|
irtDiscrimination: e.number().optional(),
|
|
215
|
-
irtGuessing: e.number().min(0).max(1, "IRT guessing
|
|
262
|
+
irtGuessing: e.number().min(0).max(1, "IRT guessing must be between 0 and 1").optional(),
|
|
216
263
|
avgTime: e.number().positive().optional(),
|
|
217
|
-
cognitiveLoad:
|
|
264
|
+
cognitiveLoad: De.optional(),
|
|
218
265
|
partialCredit: e.boolean().optional(),
|
|
219
|
-
penaltyPerWrong: e.number().min(0).max(1, "
|
|
220
|
-
}),
|
|
221
|
-
renderer:
|
|
266
|
+
penaltyPerWrong: e.number().min(0).max(1, "Penalty must be between 0 and 1").optional()
|
|
267
|
+
}), ke = e.enum(["katex", "mathjax"]), Ae = e.object({
|
|
268
|
+
renderer: ke.optional(),
|
|
222
269
|
packages: e.array(e.string()).optional()
|
|
223
|
-
}),
|
|
224
|
-
id:
|
|
225
|
-
language:
|
|
226
|
-
title:
|
|
227
|
-
description:
|
|
228
|
-
thumbnail:
|
|
229
|
-
assets:
|
|
270
|
+
}), je = e.object({
|
|
271
|
+
id: f,
|
|
272
|
+
language: p,
|
|
273
|
+
title: v.max(500, "Title must not be longer than 500 characters"),
|
|
274
|
+
description: y.max(5e3, "Description must not be longer than 5000 characters").optional(),
|
|
275
|
+
thumbnail: _.optional(),
|
|
276
|
+
assets: x.optional(),
|
|
230
277
|
ageMin: e.number().int().nonnegative().optional(),
|
|
231
278
|
ageMax: e.number().int().nonnegative().optional(),
|
|
232
279
|
subject: e.string().optional(),
|
|
233
|
-
createdAt:
|
|
234
|
-
updatedAt:
|
|
235
|
-
author:
|
|
236
|
-
contributors: e.array(
|
|
237
|
-
license:
|
|
238
|
-
licenseUrl:
|
|
239
|
-
requirements:
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
sourceMaterials: e.array(b).optional(),
|
|
280
|
+
createdAt: h,
|
|
281
|
+
updatedAt: h,
|
|
282
|
+
author: S.optional(),
|
|
283
|
+
contributors: e.array(S).optional(),
|
|
284
|
+
license: m.optional(),
|
|
285
|
+
licenseUrl: g.optional(),
|
|
286
|
+
requirements: D.optional(),
|
|
287
|
+
tags: e.array(v).optional(),
|
|
288
|
+
tagDefinitions: we.optional(),
|
|
289
|
+
translations: e.array(Te).optional(),
|
|
290
|
+
sourceMaterials: e.array(w).optional(),
|
|
245
291
|
estimatedTime: e.number().positive().optional(),
|
|
246
292
|
prerequisites: e.array(O).optional(),
|
|
247
293
|
relatedSets: e.array(O).optional(),
|
|
248
|
-
mathSettings:
|
|
294
|
+
mathSettings: Ae.optional(),
|
|
249
295
|
customData: e.record(e.string(), e.unknown()).optional(),
|
|
250
296
|
appSpecific: e.record(e.string(), e.unknown()).optional()
|
|
251
297
|
}).refine((e) => e.ageMin !== void 0 && e.ageMax !== void 0 ? e.ageMin <= e.ageMax : !0, {
|
|
252
|
-
message: "
|
|
298
|
+
message: "Minimum age (ageMin) must be less than or equal to maximum age (ageMax)",
|
|
253
299
|
path: ["ageMax"]
|
|
254
300
|
}).refine((e) => new Date(e.createdAt) <= new Date(e.updatedAt), {
|
|
255
|
-
message: "
|
|
301
|
+
message: "Creation date (createdAt) must be before or equal to update date (updatedAt)",
|
|
256
302
|
path: ["updatedAt"]
|
|
257
|
-
}),
|
|
258
|
-
id:
|
|
303
|
+
}), k = e.object({
|
|
304
|
+
id: f,
|
|
259
305
|
type: e.string(),
|
|
260
|
-
assets:
|
|
261
|
-
lang:
|
|
262
|
-
tags: e.array(
|
|
263
|
-
difficulty: e.number().int().min(1, "
|
|
264
|
-
timeLimit: e.number().positive("
|
|
265
|
-
hints: e.array(
|
|
266
|
-
explanation:
|
|
267
|
-
incorrectFeedback:
|
|
268
|
-
sources: e.array(
|
|
269
|
-
relatedItems: e.array(
|
|
270
|
-
dependencyItems: e.array(
|
|
271
|
-
pedagogy:
|
|
306
|
+
assets: x.optional(),
|
|
307
|
+
lang: p.optional(),
|
|
308
|
+
tags: e.array(v).optional(),
|
|
309
|
+
difficulty: e.number().int().min(1, "Difficulty must be at least 1").max(5, "Difficulty must be at most 5").optional(),
|
|
310
|
+
timeLimit: e.number().positive("Time limit must be a positive number").optional(),
|
|
311
|
+
hints: e.array(y.max(2e3, "Hint must not be longer than 2000 characters")).max(20, "Maximum 20 hints per item").optional(),
|
|
312
|
+
explanation: y.max(1e4, "Explanation must not be longer than 10000 characters").optional(),
|
|
313
|
+
incorrectFeedback: y.optional(),
|
|
314
|
+
sources: e.array(T).optional(),
|
|
315
|
+
relatedItems: e.array(f).optional(),
|
|
316
|
+
dependencyItems: e.array(f).optional(),
|
|
317
|
+
pedagogy: Oe.optional(),
|
|
272
318
|
customData: e.record(e.string(), e.unknown()).optional(),
|
|
273
319
|
appSpecific: e.record(e.string(), e.unknown()).optional()
|
|
274
|
-
}),
|
|
275
|
-
options: e.array(
|
|
320
|
+
}), Me = e.object({
|
|
321
|
+
options: e.array(y).min(1, "Must have at least 1 option"),
|
|
276
322
|
correctIndex: e.number().int().nonnegative()
|
|
277
323
|
}).refine((e) => e.correctIndex < e.options.length, {
|
|
278
|
-
message: "
|
|
324
|
+
message: "Correct answer index references non-existent option",
|
|
279
325
|
path: ["correctIndex"]
|
|
280
|
-
}),
|
|
326
|
+
}), A = e.object({
|
|
281
327
|
type: e.literal("rect"),
|
|
282
328
|
label: e.string().optional(),
|
|
283
|
-
x: e.number().min(0).max(100, "X
|
|
284
|
-
y: e.number().min(0).max(100, "Y
|
|
285
|
-
width: e.number().min(0).max(100, "
|
|
286
|
-
height: e.number().min(0).max(100, "
|
|
287
|
-
}),
|
|
329
|
+
x: e.number().min(0).max(100, "X must be in range 0-100%"),
|
|
330
|
+
y: e.number().min(0).max(100, "Y must be in range 0-100%"),
|
|
331
|
+
width: e.number().min(0).max(100, "Width must be in range 0-100%"),
|
|
332
|
+
height: e.number().min(0).max(100, "Height must be in range 0-100%")
|
|
333
|
+
}), j = e.object({
|
|
288
334
|
type: e.literal("circle"),
|
|
289
335
|
label: e.string().optional(),
|
|
290
|
-
x: e.number().min(0).max(100, "X
|
|
291
|
-
y: e.number().min(0).max(100, "Y
|
|
292
|
-
radius: e.number().min(0).max(100, "
|
|
293
|
-
}),
|
|
336
|
+
x: e.number().min(0).max(100, "X must be in range 0-100%"),
|
|
337
|
+
y: e.number().min(0).max(100, "Y must be in range 0-100%"),
|
|
338
|
+
radius: e.number().min(0).max(100, "Radius must be in range 0-100%")
|
|
339
|
+
}), M = e.object({
|
|
294
340
|
type: e.literal("polygon"),
|
|
295
341
|
label: e.string().optional(),
|
|
296
342
|
points: e.array(e.object({
|
|
297
343
|
x: e.number().min(0).max(100),
|
|
298
344
|
y: e.number().min(0).max(100)
|
|
299
|
-
})).min(3, "Polygon
|
|
300
|
-
}),
|
|
345
|
+
})).min(3, "Polygon must have at least 3 points")
|
|
346
|
+
}), N = e.object({
|
|
301
347
|
type: e.literal("mesh"),
|
|
302
348
|
label: e.string().optional(),
|
|
303
|
-
targetName:
|
|
304
|
-
}),
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
]),
|
|
349
|
+
targetName: v
|
|
350
|
+
}), P = e.discriminatedUnion("type", [
|
|
351
|
+
A,
|
|
352
|
+
j,
|
|
353
|
+
M,
|
|
354
|
+
N
|
|
355
|
+
]), F = e.object({
|
|
310
356
|
x: e.number(),
|
|
311
357
|
y: e.number(),
|
|
312
358
|
z: e.number()
|
|
313
|
-
}),
|
|
314
|
-
position:
|
|
315
|
-
target:
|
|
316
|
-
}),
|
|
317
|
-
id:
|
|
318
|
-
text:
|
|
359
|
+
}), I = e.object({
|
|
360
|
+
position: F.optional(),
|
|
361
|
+
target: F.optional()
|
|
362
|
+
}), L = e.object({
|
|
363
|
+
id: v,
|
|
364
|
+
text: y,
|
|
319
365
|
correctCategoryIndex: e.number().int().nonnegative()
|
|
320
|
-
}),
|
|
366
|
+
}), R = e.enum([
|
|
321
367
|
"year",
|
|
322
368
|
"month",
|
|
323
369
|
"day",
|
|
324
370
|
"datetime"
|
|
325
|
-
]),
|
|
326
|
-
id:
|
|
327
|
-
text:
|
|
328
|
-
date:
|
|
329
|
-
precision:
|
|
330
|
-
}),
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
]),
|
|
335
|
-
label:
|
|
336
|
-
percentage: e.number().min(0, "
|
|
371
|
+
]), z = e.object({
|
|
372
|
+
id: v,
|
|
373
|
+
text: y,
|
|
374
|
+
date: h,
|
|
375
|
+
precision: R.optional()
|
|
376
|
+
}), B = e.union([
|
|
377
|
+
A.extend({ correctLabelIndex: e.number().int().nonnegative() }),
|
|
378
|
+
j.extend({ correctLabelIndex: e.number().int().nonnegative() }),
|
|
379
|
+
M.extend({ correctLabelIndex: e.number().int().nonnegative() })
|
|
380
|
+
]), V = e.object({
|
|
381
|
+
label: v,
|
|
382
|
+
percentage: e.number().min(0, "Percentage must be non-negative").max(100, "Percentage must not exceed 100"),
|
|
337
383
|
description: e.string().optional()
|
|
338
|
-
}),
|
|
339
|
-
message: "
|
|
384
|
+
}), H = e.object({ criteria: e.array(V).min(1, "Rubric must have at least 1 criterion") }).refine((e) => e.criteria.reduce((e, t) => e + t.percentage, 0) > 0, {
|
|
385
|
+
message: "Sum of percentages of all criteria must be greater than 0",
|
|
340
386
|
path: ["criteria"]
|
|
341
|
-
}),
|
|
387
|
+
}), Ne = e.object({
|
|
342
388
|
min: e.number(),
|
|
343
389
|
max: e.number()
|
|
344
390
|
}).refine((e) => e.min <= e.max, {
|
|
345
|
-
message: "
|
|
391
|
+
message: "Minimum value must be less than or equal to maximum value",
|
|
346
392
|
path: ["max"]
|
|
347
|
-
}),
|
|
393
|
+
}), Pe = k.extend({
|
|
348
394
|
type: e.literal("note"),
|
|
349
395
|
title: e.string().optional(),
|
|
350
|
-
content:
|
|
351
|
-
}),
|
|
396
|
+
content: y.max(1e4, "Content must not be longer than 10000 characters")
|
|
397
|
+
}), Fe = k.extend({
|
|
352
398
|
type: e.literal("flashcard"),
|
|
353
|
-
front:
|
|
354
|
-
back:
|
|
355
|
-
}),
|
|
399
|
+
front: y.max(1e4, "Front side must not be longer than 10000 characters"),
|
|
400
|
+
back: y.max(1e4, "Back side must not be longer than 10000 characters")
|
|
401
|
+
}), Ie = k.extend({
|
|
356
402
|
type: e.literal("true-false"),
|
|
357
|
-
question:
|
|
403
|
+
question: y.max(1e4, "Question must not be longer than 10000 characters"),
|
|
358
404
|
answer: e.boolean()
|
|
359
|
-
}),
|
|
405
|
+
}), Le = k.extend({
|
|
360
406
|
type: e.literal("mcq-single"),
|
|
361
|
-
question:
|
|
362
|
-
options: e.array(
|
|
407
|
+
question: y.max(1e4, "Question must not be longer than 10000 characters"),
|
|
408
|
+
options: e.array(y.max(2e3, "Option must not be longer than 2000 characters")).min(2, "Question must have at least 2 options").max(100, "Maximum 100 options"),
|
|
363
409
|
correctIndex: e.number().int().nonnegative(),
|
|
364
410
|
shuffleOptions: e.boolean().optional(),
|
|
365
|
-
optionExplanations: e.array(e.union([
|
|
411
|
+
optionExplanations: e.array(e.union([y, e.null()])).optional()
|
|
366
412
|
}).refine((e) => e.correctIndex < e.options.length, {
|
|
367
|
-
message: "
|
|
413
|
+
message: "Correct answer index references non-existent option",
|
|
368
414
|
path: ["correctIndex"]
|
|
369
415
|
}).refine((e) => e.optionExplanations ? e.optionExplanations.length === e.options.length : !0, {
|
|
370
|
-
message: "
|
|
416
|
+
message: "Number of option explanations must match number of options",
|
|
371
417
|
path: ["optionExplanations"]
|
|
372
|
-
}),
|
|
418
|
+
}), Re = k.extend({
|
|
373
419
|
type: e.literal("mcq-multi"),
|
|
374
|
-
question:
|
|
375
|
-
options: e.array(
|
|
376
|
-
correctIndices: e.array(e.number().int().nonnegative()).min(1, "
|
|
420
|
+
question: y.max(1e4, "Question must not be longer than 10000 characters"),
|
|
421
|
+
options: e.array(y.max(2e3, "Option must not be longer than 2000 characters")).min(2, "Question must have at least 2 options").max(100, "Maximum 100 options"),
|
|
422
|
+
correctIndices: e.array(e.number().int().nonnegative()).min(1, "Must have at least 1 correct answer"),
|
|
377
423
|
minSelections: e.number().int().positive().optional(),
|
|
378
424
|
maxSelections: e.number().int().positive().optional(),
|
|
379
425
|
shuffleOptions: e.boolean().optional(),
|
|
380
|
-
optionExplanations: e.array(e.union([
|
|
426
|
+
optionExplanations: e.array(e.union([y, e.null()])).optional()
|
|
381
427
|
}).refine((e) => e.correctIndices.every((t) => t < e.options.length), {
|
|
382
|
-
message: "
|
|
428
|
+
message: "Some of correct answer indices reference non-existent option",
|
|
383
429
|
path: ["correctIndices"]
|
|
384
430
|
}).refine((e) => new Set(e.correctIndices).size === e.correctIndices.length, {
|
|
385
|
-
message: "
|
|
431
|
+
message: "Correct answer indices contain duplicates",
|
|
386
432
|
path: ["correctIndices"]
|
|
387
433
|
}).refine((e) => e.minSelections && e.maxSelections ? e.minSelections <= e.maxSelections : !0, {
|
|
388
|
-
message: "
|
|
434
|
+
message: "Minimum number of selections must be less than or equal to maximum",
|
|
389
435
|
path: ["maxSelections"]
|
|
390
436
|
}).refine((e) => e.maxSelections ? e.maxSelections <= e.options.length : !0, {
|
|
391
|
-
message: "
|
|
437
|
+
message: "Maximum number of selections must not exceed number of options",
|
|
392
438
|
path: ["maxSelections"]
|
|
393
439
|
}).refine((e) => e.optionExplanations ? e.optionExplanations.length === e.options.length : !0, {
|
|
394
|
-
message: "
|
|
440
|
+
message: "Number of option explanations must match number of options",
|
|
395
441
|
path: ["optionExplanations"]
|
|
396
|
-
}),
|
|
442
|
+
}), ze = k.extend({
|
|
397
443
|
type: e.literal("short-answer"),
|
|
398
|
-
question:
|
|
399
|
-
answers: e.array(
|
|
444
|
+
question: y.max(1e4, "Question must not be longer than 10000 characters"),
|
|
445
|
+
answers: e.array(v).min(1, "Must have at least 1 correct answer"),
|
|
400
446
|
caseSensitive: e.boolean().optional(),
|
|
401
447
|
trimWhitespace: e.boolean().optional(),
|
|
402
448
|
acceptPartial: e.boolean().optional(),
|
|
403
449
|
ignoreDiacritics: e.boolean().optional()
|
|
404
|
-
}),
|
|
450
|
+
}), Be = k.extend({
|
|
405
451
|
type: e.literal("fill-in-blanks"),
|
|
406
|
-
question:
|
|
407
|
-
text:
|
|
408
|
-
blanks: e.record(e.string(), e.array(
|
|
452
|
+
question: b,
|
|
453
|
+
text: y.max(1e4, "Text must not be longer than 10000 characters"),
|
|
454
|
+
blanks: e.record(e.string(), e.array(v).min(1, "Each blank must have at least 1 correct answer")),
|
|
409
455
|
caseSensitive: e.boolean().optional(),
|
|
410
456
|
trimWhitespace: e.boolean().optional()
|
|
411
457
|
}).refine((e) => Object.keys(e.blanks).length > 0, {
|
|
412
|
-
message: "Text
|
|
458
|
+
message: "Text must contain at least 1 blank to fill",
|
|
413
459
|
path: ["blanks"]
|
|
414
460
|
}).refine((e) => {
|
|
415
461
|
let t = /<blank:([a-zA-Z0-9_-]{1,64})\s*\/>/g, n = /* @__PURE__ */ new Set(), r;
|
|
@@ -419,15 +465,15 @@ var s = e.string().uuid({ message: "Neplatn+� form+�t UUID" }), c = e.string
|
|
|
419
465
|
for (let e of i) if (!n.has(e)) return !1;
|
|
420
466
|
return !0;
|
|
421
467
|
}, {
|
|
422
|
-
message: "
|
|
468
|
+
message: "All tokens in text must have definition in blanks and all definitions must be used in text",
|
|
423
469
|
path: ["blanks"]
|
|
424
|
-
}),
|
|
470
|
+
}), Ve = k.extend({
|
|
425
471
|
type: e.literal("fill-in-select"),
|
|
426
|
-
question:
|
|
427
|
-
text:
|
|
428
|
-
blanks: e.record(e.string(),
|
|
472
|
+
question: b,
|
|
473
|
+
text: y.max(1e4, "Text must not be longer than 10000 characters"),
|
|
474
|
+
blanks: e.record(e.string(), Me)
|
|
429
475
|
}).refine((e) => Object.keys(e.blanks).length > 0, {
|
|
430
|
-
message: "Text
|
|
476
|
+
message: "Text must contain at least 1 blank to select",
|
|
431
477
|
path: ["blanks"]
|
|
432
478
|
}).refine((e) => {
|
|
433
479
|
let t = /<blank:([a-zA-Z0-9_-]{1,64})\s*\/>/g, n = /* @__PURE__ */ new Set(), r;
|
|
@@ -437,95 +483,95 @@ var s = e.string().uuid({ message: "Neplatn+� form+�t UUID" }), c = e.string
|
|
|
437
483
|
for (let e of i) if (!n.has(e)) return !1;
|
|
438
484
|
return !0;
|
|
439
485
|
}, {
|
|
440
|
-
message: "
|
|
486
|
+
message: "All tokens in text must have definition in blanks and all definitions must be used in text",
|
|
441
487
|
path: ["blanks"]
|
|
442
|
-
}),
|
|
488
|
+
}), He = k.extend({
|
|
443
489
|
type: e.literal("match-pairs"),
|
|
444
|
-
question:
|
|
445
|
-
prompts: e.array(
|
|
446
|
-
matches: e.array(
|
|
490
|
+
question: b,
|
|
491
|
+
prompts: e.array(y).min(2, "Must have at least 2 pairs to match"),
|
|
492
|
+
matches: e.array(y).min(2, "Must have at least 2 pairs to match")
|
|
447
493
|
}).refine((e) => e.prompts.length === e.matches.length, {
|
|
448
|
-
message: "
|
|
494
|
+
message: "Number of prompts must match number of matches",
|
|
449
495
|
path: ["matches"]
|
|
450
|
-
}),
|
|
496
|
+
}), Ue = k.extend({
|
|
451
497
|
type: e.literal("match-complex"),
|
|
452
|
-
question:
|
|
453
|
-
leftItems: e.array(
|
|
454
|
-
rightItems: e.array(
|
|
455
|
-
connections: e.array(e.tuple([e.number().int().nonnegative(), e.number().int().nonnegative()])).min(1, "
|
|
498
|
+
question: b,
|
|
499
|
+
leftItems: e.array(y).min(1, "Must have at least 1 item on left"),
|
|
500
|
+
rightItems: e.array(y).min(1, "Must have at least 1 item on right"),
|
|
501
|
+
connections: e.array(e.tuple([e.number().int().nonnegative(), e.number().int().nonnegative()])).min(1, "Must have at least 1 connection"),
|
|
456
502
|
minCorrect: e.number().int().positive().optional()
|
|
457
503
|
}).refine((e) => e.connections.every(([t, n]) => t < e.leftItems.length && n < e.rightItems.length), {
|
|
458
|
-
message: "
|
|
504
|
+
message: "Some connection references non-existent item",
|
|
459
505
|
path: ["connections"]
|
|
460
506
|
}).refine((e) => new Set(e.connections.map((e) => `${e[0]}-${e[1]}`)).size === e.connections.length, {
|
|
461
|
-
message: "
|
|
507
|
+
message: "Connections contain duplicates",
|
|
462
508
|
path: ["connections"]
|
|
463
509
|
}).refine((e) => e.minCorrect ? e.minCorrect <= e.connections.length : !0, {
|
|
464
|
-
message: "
|
|
510
|
+
message: "Minimum correct answers must not exceed total number of connections",
|
|
465
511
|
path: ["minCorrect"]
|
|
466
|
-
}),
|
|
512
|
+
}), We = k.extend({
|
|
467
513
|
type: e.literal("sort-items"),
|
|
468
|
-
question:
|
|
469
|
-
items: e.array(
|
|
470
|
-
}),
|
|
514
|
+
question: y.max(1e4, "Question must not be longer than 10000 characters"),
|
|
515
|
+
items: e.array(y).min(2, "Must have at least 2 items to sort")
|
|
516
|
+
}), Ge = k.extend({
|
|
471
517
|
type: e.literal("slider"),
|
|
472
|
-
question:
|
|
518
|
+
question: y.max(1e4, "Question must not be longer than 10000 characters"),
|
|
473
519
|
min: e.number(),
|
|
474
520
|
max: e.number(),
|
|
475
|
-
step: e.number().positive("
|
|
521
|
+
step: e.number().positive("Step must be a positive number"),
|
|
476
522
|
correctAnswer: e.number(),
|
|
477
|
-
tolerance: e.number().nonnegative("Tolerance
|
|
523
|
+
tolerance: e.number().nonnegative("Tolerance must be non-negative"),
|
|
478
524
|
unit: e.string().optional()
|
|
479
525
|
}).refine((e) => e.min < e.max, {
|
|
480
|
-
message: "
|
|
526
|
+
message: "Minimum value must be less than maximum value",
|
|
481
527
|
path: ["max"]
|
|
482
528
|
}).refine((e) => e.correctAnswer >= e.min && e.correctAnswer <= e.max, {
|
|
483
|
-
message: "
|
|
529
|
+
message: "Correct answer must be in range min-max",
|
|
484
530
|
path: ["correctAnswer"]
|
|
485
531
|
}).refine((e) => {
|
|
486
532
|
let t = (e.correctAnswer - e.min) / e.step;
|
|
487
533
|
return Math.abs(t - Math.round(t)) < 1e-4;
|
|
488
534
|
}, {
|
|
489
|
-
message: "
|
|
535
|
+
message: "Correct answer must be reachable by defined step",
|
|
490
536
|
path: ["correctAnswer"]
|
|
491
537
|
}).refine((e) => e.tolerance <= (e.max - e.min) / 2, {
|
|
492
|
-
message: "Tolerance
|
|
538
|
+
message: "Tolerance must not be greater than half of value range",
|
|
493
539
|
path: ["tolerance"]
|
|
494
|
-
}),
|
|
540
|
+
}), Ke = k.extend({
|
|
495
541
|
type: e.literal("pin-on-image"),
|
|
496
|
-
question:
|
|
497
|
-
targetAsset:
|
|
498
|
-
hotspots: e.array(
|
|
542
|
+
question: y.max(1e4, "Question must not be longer than 10000 characters"),
|
|
543
|
+
targetAsset: _,
|
|
544
|
+
hotspots: e.array(P).min(1, "Must have at least 1 hotspot"),
|
|
499
545
|
multipleCorrect: e.boolean().optional(),
|
|
500
546
|
minCorrect: e.number().int().positive().optional()
|
|
501
547
|
}).refine((e) => e.minCorrect ? e.minCorrect <= e.hotspots.length : !0, {
|
|
502
|
-
message: "
|
|
548
|
+
message: "Minimum correct answers must not exceed number of hotspots",
|
|
503
549
|
path: ["minCorrect"]
|
|
504
|
-
}),
|
|
550
|
+
}), qe = k.extend({
|
|
505
551
|
type: e.literal("categorize"),
|
|
506
|
-
question:
|
|
507
|
-
categories: e.array(
|
|
508
|
-
items: e.array(
|
|
552
|
+
question: y.max(1e4, "Question must not be longer than 10000 characters"),
|
|
553
|
+
categories: e.array(v).min(2, "Must have at least 2 categories"),
|
|
554
|
+
items: e.array(L).min(1, "Must have at least 1 item to categorize")
|
|
509
555
|
}).refine((e) => e.items.every((t) => t.correctCategoryIndex < e.categories.length), {
|
|
510
|
-
message: "
|
|
556
|
+
message: "Some item references non-existent category",
|
|
511
557
|
path: ["items"]
|
|
512
|
-
}),
|
|
558
|
+
}), Je = k.extend({
|
|
513
559
|
type: e.literal("timeline"),
|
|
514
|
-
question:
|
|
515
|
-
events: e.array(
|
|
560
|
+
question: y.max(1e4, "Question must not be longer than 10000 characters"),
|
|
561
|
+
events: e.array(z).min(2, "Must have at least 2 events"),
|
|
516
562
|
randomize: e.boolean().optional()
|
|
517
|
-
}),
|
|
563
|
+
}), Ye = k.extend({
|
|
518
564
|
type: e.literal("matrix"),
|
|
519
|
-
question:
|
|
520
|
-
rows: e.array(
|
|
521
|
-
columns: e.array(
|
|
522
|
-
correctCells: e.array(e.tuple([e.number().int().nonnegative(), e.number().int().nonnegative()])).min(1, "
|
|
565
|
+
question: y.max(1e4, "Question must not be longer than 10000 characters"),
|
|
566
|
+
rows: e.array(v).min(1, "Must have at least 1 row"),
|
|
567
|
+
columns: e.array(v).min(1, "Must have at least 1 column"),
|
|
568
|
+
correctCells: e.array(e.tuple([e.number().int().nonnegative(), e.number().int().nonnegative()])).min(1, "Must have at least 1 correct cell"),
|
|
523
569
|
multiplePerRow: e.boolean().optional()
|
|
524
570
|
}).refine((e) => e.correctCells.every(([t, n]) => t < e.rows.length && n < e.columns.length), {
|
|
525
|
-
message: "
|
|
571
|
+
message: "Some cell coordinates reference non-existent row or column",
|
|
526
572
|
path: ["correctCells"]
|
|
527
573
|
}).refine((e) => new Set(e.correctCells.map((e) => `${e[0]}-${e[1]}`)).size === e.correctCells.length, {
|
|
528
|
-
message: "
|
|
574
|
+
message: "Correct cells contain duplicates",
|
|
529
575
|
path: ["correctCells"]
|
|
530
576
|
}).refine((e) => {
|
|
531
577
|
if (!e.multiplePerRow) {
|
|
@@ -535,68 +581,60 @@ var s = e.string().uuid({ message: "Neplatn+� form+�t UUID" }), c = e.string
|
|
|
535
581
|
}
|
|
536
582
|
return !0;
|
|
537
583
|
}, {
|
|
538
|
-
message: "
|
|
584
|
+
message: "If multiplePerRow is false, each row may have maximum 1 correct cell",
|
|
539
585
|
path: ["correctCells"]
|
|
540
|
-
}),
|
|
586
|
+
}), Xe = k.extend({
|
|
541
587
|
type: e.literal("math-input"),
|
|
542
|
-
question:
|
|
543
|
-
correctAnswer:
|
|
544
|
-
alternativeAnswers: e.array(
|
|
588
|
+
question: y.max(1e4, "Question must not be longer than 10000 characters"),
|
|
589
|
+
correctAnswer: v,
|
|
590
|
+
alternativeAnswers: e.array(v).optional(),
|
|
545
591
|
tolerance: e.number().nonnegative().optional()
|
|
546
|
-
}),
|
|
592
|
+
}), Ze = k.extend({
|
|
547
593
|
type: e.literal("diagram-label"),
|
|
548
|
-
question:
|
|
549
|
-
targetAsset:
|
|
550
|
-
labels: e.array(
|
|
594
|
+
question: y.max(1e4, "Question must not be longer than 10000 characters"),
|
|
595
|
+
targetAsset: _,
|
|
596
|
+
labels: e.array(y).min(1, "Must have at least 1 label"),
|
|
551
597
|
caseSensitive: e.boolean().optional(),
|
|
552
598
|
requireTyping: e.boolean().optional(),
|
|
553
|
-
zones: e.array(
|
|
599
|
+
zones: e.array(B).min(1, "Must have at least 1 zone")
|
|
554
600
|
}).refine((e) => e.zones.every((t) => t.correctLabelIndex < e.labels.length), {
|
|
555
|
-
message: "
|
|
601
|
+
message: "Some zone references non-existent label",
|
|
556
602
|
path: ["zones"]
|
|
557
|
-
}),
|
|
603
|
+
}), Qe = k.extend({
|
|
558
604
|
type: e.literal("open-ended"),
|
|
559
|
-
question:
|
|
605
|
+
question: y.max(1e4, "Question must not be longer than 10000 characters"),
|
|
560
606
|
minWords: e.number().int().positive().optional(),
|
|
561
607
|
maxWords: e.number().int().positive().optional(),
|
|
562
|
-
sampleAnswer:
|
|
563
|
-
rubric:
|
|
608
|
+
sampleAnswer: y.optional(),
|
|
609
|
+
rubric: H.optional()
|
|
564
610
|
}).refine((e) => e.minWords && e.maxWords ? e.minWords <= e.maxWords : !0, {
|
|
565
|
-
message: "
|
|
611
|
+
message: "Minimum word count must be less than or equal to maximum",
|
|
566
612
|
path: ["maxWords"]
|
|
567
|
-
}),
|
|
613
|
+
}), $e = k.extend({
|
|
568
614
|
type: e.literal("numeric-input"),
|
|
569
|
-
question:
|
|
615
|
+
question: y.max(1e4, "Question must not be longer than 10000 characters"),
|
|
570
616
|
value: e.number(),
|
|
571
617
|
tolerance: e.number().nonnegative().optional(),
|
|
572
|
-
range:
|
|
618
|
+
range: Ne.optional(),
|
|
573
619
|
unit: e.string().optional()
|
|
574
|
-
}),
|
|
620
|
+
}), et = k.extend({
|
|
575
621
|
type: e.literal("pin-on-model"),
|
|
576
|
-
question:
|
|
577
|
-
targetAsset:
|
|
578
|
-
hotspots: e.array(
|
|
622
|
+
question: y.max(1e4, "Question must not be longer than 10000 characters"),
|
|
623
|
+
targetAsset: _,
|
|
624
|
+
hotspots: e.array(N).min(1, "Must have at least 1 hotspot"),
|
|
579
625
|
multipleCorrect: e.boolean().optional(),
|
|
580
626
|
minCorrect: e.number().int().positive().optional(),
|
|
581
|
-
camera:
|
|
627
|
+
camera: I.optional()
|
|
582
628
|
}).refine((e) => e.minCorrect ? e.minCorrect <= e.hotspots.length : !0, {
|
|
583
|
-
message: "
|
|
629
|
+
message: "Minimum correct answers must not exceed number of hotspots",
|
|
584
630
|
path: ["minCorrect"]
|
|
585
|
-
}),
|
|
631
|
+
}), tt = k.extend({
|
|
586
632
|
type: e.literal("chess-puzzle"),
|
|
587
|
-
question:
|
|
588
|
-
fen:
|
|
589
|
-
answers: e.array(e.array(
|
|
590
|
-
elo: e.number().int().nonnegative("ELO
|
|
591
|
-
}),
|
|
592
|
-
De,
|
|
593
|
-
Oe,
|
|
594
|
-
ke,
|
|
595
|
-
Ae,
|
|
596
|
-
je,
|
|
597
|
-
W,
|
|
598
|
-
Me,
|
|
599
|
-
Ne,
|
|
633
|
+
question: y.max(1e4, "Question must not be longer than 10000 characters"),
|
|
634
|
+
fen: v,
|
|
635
|
+
answers: e.array(e.array(v).min(1, "Move sequence must not be empty")).min(1, "Must have at least 1 correct move sequence"),
|
|
636
|
+
elo: e.number().int().nonnegative("ELO must be non-negative integer").optional()
|
|
637
|
+
}), U = e.discriminatedUnion("type", [
|
|
600
638
|
Pe,
|
|
601
639
|
Fe,
|
|
602
640
|
Ie,
|
|
@@ -610,12 +648,20 @@ var s = e.string().uuid({ message: "Neplatn+� form+�t UUID" }), c = e.string
|
|
|
610
648
|
We,
|
|
611
649
|
Ge,
|
|
612
650
|
Ke,
|
|
613
|
-
qe
|
|
614
|
-
|
|
651
|
+
qe,
|
|
652
|
+
Je,
|
|
653
|
+
Ye,
|
|
654
|
+
Xe,
|
|
655
|
+
Ze,
|
|
656
|
+
Qe,
|
|
657
|
+
$e,
|
|
658
|
+
et,
|
|
659
|
+
tt
|
|
660
|
+
]), W = e.object({
|
|
615
661
|
$schema: e.string().url().optional(),
|
|
616
|
-
version: e.string().regex(/^\d+\.\d+$/, "
|
|
617
|
-
meta:
|
|
618
|
-
items: e.array(
|
|
662
|
+
version: e.string().regex(/^\d+\.\d+$/, "Version must be in MAJOR.MINOR format (e.g. \"0.1\")"),
|
|
663
|
+
meta: je,
|
|
664
|
+
items: e.array(U).max(1e4, "Maximum 10000 items per set")
|
|
619
665
|
}).refine((e) => {
|
|
620
666
|
let t = new Set(e.items.map((e) => e.id));
|
|
621
667
|
for (let n of e.items) {
|
|
@@ -628,10 +674,10 @@ var s = e.string().uuid({ message: "Neplatn+� form+�t UUID" }), c = e.string
|
|
|
628
674
|
}
|
|
629
675
|
return !0;
|
|
630
676
|
}, {
|
|
631
|
-
message: "
|
|
677
|
+
message: "Some item references non-existent relatedItems or dependencyItems",
|
|
632
678
|
path: ["items"]
|
|
633
679
|
}).refine((e) => e.meta.thumbnail && e.meta.assets ? e.meta.thumbnail in e.meta.assets : !0, {
|
|
634
|
-
message: "Thumbnail
|
|
680
|
+
message: "Thumbnail references non-existent asset",
|
|
635
681
|
path: ["meta", "thumbnail"]
|
|
636
682
|
}).refine((e) => {
|
|
637
683
|
let t = new Set((e.meta.sourceMaterials || []).map((e) => e.id));
|
|
@@ -640,14 +686,14 @@ var s = e.string().uuid({ message: "Neplatn+� form+�t UUID" }), c = e.string
|
|
|
640
686
|
}
|
|
641
687
|
return !0;
|
|
642
688
|
}, {
|
|
643
|
-
message: "
|
|
689
|
+
message: "Some item references non-existent source material",
|
|
644
690
|
path: ["items"]
|
|
645
691
|
});
|
|
646
|
-
function
|
|
647
|
-
return
|
|
692
|
+
function nt(e) {
|
|
693
|
+
return W.parse(e);
|
|
648
694
|
}
|
|
649
|
-
function
|
|
650
|
-
let t =
|
|
695
|
+
function rt(e) {
|
|
696
|
+
let t = W.safeParse(e);
|
|
651
697
|
return t.success ? {
|
|
652
698
|
success: !0,
|
|
653
699
|
data: t.data
|
|
@@ -656,11 +702,11 @@ function Ye(e) {
|
|
|
656
702
|
error: t.error
|
|
657
703
|
};
|
|
658
704
|
}
|
|
659
|
-
function
|
|
660
|
-
return
|
|
705
|
+
function it(e) {
|
|
706
|
+
return U.parse(e);
|
|
661
707
|
}
|
|
662
|
-
function
|
|
663
|
-
let t =
|
|
708
|
+
function at(e) {
|
|
709
|
+
let t = U.safeParse(e);
|
|
664
710
|
return t.success ? {
|
|
665
711
|
success: !0,
|
|
666
712
|
data: t.data
|
|
@@ -669,128 +715,96 @@ function Ze(e) {
|
|
|
669
715
|
error: t.error
|
|
670
716
|
};
|
|
671
717
|
}
|
|
672
|
-
function
|
|
718
|
+
function ot(e) {
|
|
673
719
|
return e.issues.map((e) => {
|
|
674
|
-
let t =
|
|
675
|
-
return
|
|
720
|
+
let t = "";
|
|
721
|
+
return e.path.forEach((n, r) => {
|
|
722
|
+
if (typeof n == "number") t += `[${n}]`;
|
|
723
|
+
else {
|
|
724
|
+
let i = r === 0 || typeof e.path[r - 1] == "number";
|
|
725
|
+
t += (i ? "" : ".") + String(n);
|
|
726
|
+
}
|
|
727
|
+
}), t ? `${t}: ${e.message}` : e.message;
|
|
676
728
|
});
|
|
677
729
|
}
|
|
678
730
|
//#endregion
|
|
679
|
-
//#region src/manifest.ts
|
|
680
|
-
function q(e) {
|
|
681
|
-
return /^\d+\.\d+$/.test(e);
|
|
682
|
-
}
|
|
683
|
-
function $e(e) {
|
|
684
|
-
return /^\d+\.\d+\.\d+(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$/.test(e);
|
|
685
|
-
}
|
|
686
|
-
function J(e, t) {
|
|
687
|
-
let [n = 0, r = 0] = e.split(".").map(Number), [i = 0, a = 0] = t.split(".").map(Number);
|
|
688
|
-
return n === i ? r - a : n - i;
|
|
689
|
-
}
|
|
690
|
-
function et(e) {
|
|
691
|
-
if (typeof e != "object" || !e) return !1;
|
|
692
|
-
let t = e;
|
|
693
|
-
return typeof t.version == "string" && typeof t.id == "string" && typeof t.appName == "string" && t.appName !== "" && typeof t.capabilities == "object" && t.capabilities !== null && Array.isArray(t.capabilities.actions);
|
|
694
|
-
}
|
|
695
|
-
function tt(e, t) {
|
|
696
|
-
return !(!q(e) || t.minOqseVersion && q(t.minOqseVersion) && J(e, t.minOqseVersion) < 0 || t.maxOqseVersion && q(t.maxOqseVersion) && J(e, t.maxOqseVersion) > 0);
|
|
697
|
-
}
|
|
698
|
-
//#endregion
|
|
699
731
|
//#region src/manifestValidation.ts
|
|
700
|
-
var
|
|
701
|
-
"render",
|
|
702
|
-
"edit",
|
|
703
|
-
"validate",
|
|
704
|
-
"import",
|
|
705
|
-
"export"
|
|
706
|
-
], at = e.string().refine((e) => it.includes(e) || e.startsWith("x-"), { message: "Akce mus+� b+�t jedna z [render, edit, validate, import, export] nebo m+�t prefix \"x-\"" }), ot = e.enum([
|
|
732
|
+
var G = e.string().min(1, "Value must not be empty").trim(), st = e.string().url("Must be a valid absolute URL").refine((e) => e.startsWith("http://") || e.startsWith("https://"), { message: "URL must use http or https scheme" }), K = e.string().regex(/^\d+\.\d+$/, "Version must be in MAJOR.MINOR format (e.g. \"0.1\")"), ct = e.string().regex(/^\d+\.\d+\.\d+$/, "Version must be in MAJOR.MINOR.PATCH format (e.g. \"1.2.3\")"), lt = e.string().refine((e) => ve.includes(e) || e.startsWith("x-"), { message: "Action must be one of [render, edit, validate, import, export] or have prefix \"x-\"" }), ut = e.enum([
|
|
707
733
|
"game",
|
|
708
734
|
"fun",
|
|
709
735
|
"drill"
|
|
710
|
-
]),
|
|
736
|
+
]), dt = e.enum([
|
|
711
737
|
"low",
|
|
712
738
|
"medium",
|
|
713
739
|
"high"
|
|
714
|
-
]),
|
|
715
|
-
|
|
716
|
-
"media",
|
|
717
|
-
"media-image",
|
|
718
|
-
"media-audio",
|
|
719
|
-
"media-video",
|
|
720
|
-
"media-model",
|
|
721
|
-
"hotspots",
|
|
722
|
-
"hotspots-3d",
|
|
723
|
-
"complex-pairing",
|
|
724
|
-
"open-text",
|
|
725
|
-
"chess"
|
|
726
|
-
], lt = e.string().refine((e) => ct.includes(e) || e.startsWith("x-"), { message: "Funkce mus+� b+�t jedna z ofici+�ln+�ch kl+���+� nebo m+�t prefix \"x-\"" }), ut = e.string().min(1, "Kl+��� vlastnosti polo+�ky nesm+� b+�t pr+�zdn+�"), dt = e.string().min(1, "Kl+��� vlastnosti metadat nesm+� b+�t pr+�zdn+�");
|
|
727
|
-
function Z(t) {
|
|
740
|
+
]), ft = e.string().refine((e) => s.includes(e) || e.startsWith("x-"), { message: "Feature must be one of official keys or have prefix \"x-\"" }), pt = e.string().refine((e) => c.includes(e) || e.startsWith("x-"), { message: "Item property must be an official key or have prefix \"x-\"" }), mt = e.string().refine((e) => l.includes(e) || e.startsWith("x-"), { message: "Meta property must be an official key or have prefix \"x-\"" });
|
|
741
|
+
function q(t) {
|
|
728
742
|
return e.union([
|
|
729
743
|
e.tuple([e.literal("*")]),
|
|
730
744
|
e.array(t),
|
|
731
745
|
e.null()
|
|
732
746
|
]);
|
|
733
747
|
}
|
|
734
|
-
var
|
|
735
|
-
image:
|
|
736
|
-
audio:
|
|
737
|
-
video:
|
|
738
|
-
model:
|
|
739
|
-
}),
|
|
740
|
-
actions: e.array(
|
|
741
|
-
types:
|
|
742
|
-
assets:
|
|
743
|
-
}),
|
|
744
|
-
$schema:
|
|
745
|
-
id:
|
|
746
|
-
appName:
|
|
747
|
-
version:
|
|
748
|
-
pluginVersion:
|
|
749
|
-
minOqseVersion:
|
|
750
|
-
maxOqseVersion:
|
|
751
|
-
capabilities:
|
|
752
|
-
author: e.string().max(100, "
|
|
753
|
-
authorUrl:
|
|
754
|
-
locales: e.array(
|
|
755
|
-
description: e.string().max(500, "
|
|
748
|
+
var ht = e.string().refine((e) => e.startsWith("image/"), { message: "Must be a valid image MIME type (image/...)" }), gt = e.string().refine((e) => e.startsWith("audio/"), { message: "Must be a valid audio MIME type (audio/...)" }), _t = e.string().refine((e) => e.startsWith("video/"), { message: "Must be a valid video MIME type (video/...)" }), vt = e.string().refine((e) => e.startsWith("model/") || e === "application/octet-stream", { message: "Must be a valid 3D model MIME type (model/... or application/octet-stream)" }), yt = e.object({
|
|
749
|
+
image: q(ht).optional(),
|
|
750
|
+
audio: q(gt).optional(),
|
|
751
|
+
video: q(_t).optional(),
|
|
752
|
+
model: q(vt).optional()
|
|
753
|
+
}), bt = D.extend({
|
|
754
|
+
actions: e.array(lt).min(1, "Application must support at least one action"),
|
|
755
|
+
types: q(G).optional(),
|
|
756
|
+
assets: yt.optional()
|
|
757
|
+
}), J = e.object({
|
|
758
|
+
$schema: st.optional(),
|
|
759
|
+
id: G.regex(/^[a-z0-9-]+(\.[a-z0-9-]+)*$/, "ID must be in reverse-domain format (e.g. \"com.acme.app\")"),
|
|
760
|
+
appName: G.max(100, "Name must not be longer than 100 characters"),
|
|
761
|
+
version: K,
|
|
762
|
+
pluginVersion: ct.optional(),
|
|
763
|
+
minOqseVersion: K.optional(),
|
|
764
|
+
maxOqseVersion: K.optional(),
|
|
765
|
+
capabilities: bt,
|
|
766
|
+
author: e.string().max(100, "Author name must not be longer than 100 characters").optional(),
|
|
767
|
+
authorUrl: st.optional(),
|
|
768
|
+
locales: e.array(G).optional(),
|
|
769
|
+
description: e.string().max(500, "Description must not be longer than 500 characters").optional(),
|
|
756
770
|
emoji: e.string().optional(),
|
|
757
|
-
tags: e.array(
|
|
758
|
-
studyMode:
|
|
759
|
-
questionDensity:
|
|
771
|
+
tags: e.array(G).optional(),
|
|
772
|
+
studyMode: ut.optional(),
|
|
773
|
+
questionDensity: dt.optional(),
|
|
760
774
|
appSpecific: e.record(e.string(), e.unknown()).optional()
|
|
761
775
|
}).refine((e) => {
|
|
762
776
|
if (!e.minOqseVersion || !e.maxOqseVersion) return !0;
|
|
763
|
-
let t = e.minOqseVersion.split("."), n = e.maxOqseVersion.split("."), r = Number(t[0]), i = Number(t[1]), a = Number(n[0]),
|
|
764
|
-
return r === a ? i <=
|
|
777
|
+
let t = e.minOqseVersion.split("."), n = e.maxOqseVersion.split("."), r = Number(t[0]), i = Number(t[1]), a = Number(n[0]), o = Number(n[1]);
|
|
778
|
+
return r === a ? i <= o : r < a;
|
|
765
779
|
}, {
|
|
766
|
-
message: "minOqseVersion
|
|
780
|
+
message: "minOqseVersion must not be greater than maxOqseVersion",
|
|
767
781
|
path: ["minOqseVersion"]
|
|
768
782
|
});
|
|
769
|
-
function
|
|
770
|
-
return
|
|
783
|
+
function xt(e) {
|
|
784
|
+
return J.parse(e);
|
|
771
785
|
}
|
|
772
|
-
function
|
|
773
|
-
return
|
|
786
|
+
function St(e) {
|
|
787
|
+
return J.safeParse(e);
|
|
774
788
|
}
|
|
775
|
-
function
|
|
789
|
+
function Ct(e) {
|
|
776
790
|
return e.issues.map((e) => {
|
|
777
791
|
let t = e.path.map((e) => String(e)).join(".");
|
|
778
792
|
return t ? `${t}: ${e.message}` : e.message;
|
|
779
793
|
}).join("\n");
|
|
780
794
|
}
|
|
781
|
-
function
|
|
782
|
-
return
|
|
795
|
+
function wt(e) {
|
|
796
|
+
return J.safeParse(e).success;
|
|
783
797
|
}
|
|
784
798
|
//#endregion
|
|
785
799
|
//#region src/progressValidation.ts
|
|
786
|
-
var
|
|
800
|
+
var Tt = e.object({
|
|
787
801
|
attempts: e.number().int().nonnegative(),
|
|
788
802
|
incorrect: e.number().int().nonnegative(),
|
|
789
803
|
streak: e.number().int().nonnegative()
|
|
790
804
|
}).refine((e) => e.incorrect <= e.attempts, {
|
|
791
|
-
message: "incorrect
|
|
805
|
+
message: "incorrect cannot be higher than attempts",
|
|
792
806
|
path: ["incorrect"]
|
|
793
|
-
}),
|
|
807
|
+
}), Y = e.object({
|
|
794
808
|
isCorrect: e.boolean(),
|
|
795
809
|
confidence: e.union([
|
|
796
810
|
e.literal(1),
|
|
@@ -798,14 +812,14 @@ var St = e.object({
|
|
|
798
812
|
e.literal(3),
|
|
799
813
|
e.literal(4)
|
|
800
814
|
]).optional(),
|
|
801
|
-
answeredAt:
|
|
815
|
+
answeredAt: h,
|
|
802
816
|
timeSpent: e.number().int().nonnegative().optional(),
|
|
803
817
|
hintsUsed: e.number().int().nonnegative().optional(),
|
|
804
818
|
isSkipped: e.boolean().optional()
|
|
805
819
|
}).refine((e) => !e.isSkipped || e.isCorrect === !1, {
|
|
806
|
-
message: "
|
|
820
|
+
message: "If isSkipped=true, isCorrect must be false",
|
|
807
821
|
path: ["isCorrect"]
|
|
808
|
-
}),
|
|
822
|
+
}), Et = e.object({
|
|
809
823
|
bucket: e.union([
|
|
810
824
|
e.literal(0),
|
|
811
825
|
e.literal(1),
|
|
@@ -813,33 +827,118 @@ var St = e.object({
|
|
|
813
827
|
e.literal(3),
|
|
814
828
|
e.literal(4)
|
|
815
829
|
]),
|
|
816
|
-
nextReviewAt:
|
|
817
|
-
stats:
|
|
818
|
-
lastAnswer:
|
|
830
|
+
nextReviewAt: h.optional(),
|
|
831
|
+
stats: Tt,
|
|
832
|
+
lastAnswer: Y.optional(),
|
|
819
833
|
appSpecific: e.record(e.string(), e.unknown()).optional()
|
|
820
|
-
}),
|
|
821
|
-
setId:
|
|
822
|
-
exportedAt:
|
|
823
|
-
algorithm: e.string().regex(/^[a-z0-9-]+$/, "algorithm
|
|
824
|
-
}),
|
|
834
|
+
}), Dt = e.object({
|
|
835
|
+
setId: f,
|
|
836
|
+
exportedAt: h,
|
|
837
|
+
algorithm: e.string().regex(/^[a-z0-9-]+$/, "algorithm must be lowercase alphanumeric with hyphens format").optional()
|
|
838
|
+
}), X = e.object({
|
|
825
839
|
$schema: e.string().url().optional(),
|
|
826
|
-
version: e.string().regex(/^\d+\.\d+$/, "
|
|
827
|
-
meta:
|
|
828
|
-
records: e.record(
|
|
840
|
+
version: e.string().regex(/^\d+\.\d+$/, "Version must be in MAJOR.MINOR format"),
|
|
841
|
+
meta: Dt,
|
|
842
|
+
records: e.record(f, Et)
|
|
829
843
|
});
|
|
830
|
-
function
|
|
831
|
-
return
|
|
844
|
+
function Ot(e) {
|
|
845
|
+
return X.parse(e);
|
|
846
|
+
}
|
|
847
|
+
function kt(e) {
|
|
848
|
+
return X.safeParse(e);
|
|
849
|
+
}
|
|
850
|
+
//#endregion
|
|
851
|
+
//#region node_modules/uuid/dist/regex.js
|
|
852
|
+
var At = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/i;
|
|
853
|
+
//#endregion
|
|
854
|
+
//#region node_modules/uuid/dist/validate.js
|
|
855
|
+
function jt(e) {
|
|
856
|
+
return typeof e == "string" && At.test(e);
|
|
857
|
+
}
|
|
858
|
+
//#endregion
|
|
859
|
+
//#region node_modules/uuid/dist/stringify.js
|
|
860
|
+
var Z = [];
|
|
861
|
+
for (let e = 0; e < 256; ++e) Z.push((e + 256).toString(16).slice(1));
|
|
862
|
+
function Mt(e, t = 0) {
|
|
863
|
+
return (Z[e[t + 0]] + Z[e[t + 1]] + Z[e[t + 2]] + Z[e[t + 3]] + "-" + Z[e[t + 4]] + Z[e[t + 5]] + "-" + Z[e[t + 6]] + Z[e[t + 7]] + "-" + Z[e[t + 8]] + Z[e[t + 9]] + "-" + Z[e[t + 10]] + Z[e[t + 11]] + Z[e[t + 12]] + Z[e[t + 13]] + Z[e[t + 14]] + Z[e[t + 15]]).toLowerCase();
|
|
864
|
+
}
|
|
865
|
+
//#endregion
|
|
866
|
+
//#region node_modules/uuid/dist/rng.js
|
|
867
|
+
var Q, Nt = new Uint8Array(16);
|
|
868
|
+
function Pt() {
|
|
869
|
+
if (!Q) {
|
|
870
|
+
if (typeof crypto > "u" || !crypto.getRandomValues) throw Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
|
|
871
|
+
Q = crypto.getRandomValues.bind(crypto);
|
|
872
|
+
}
|
|
873
|
+
return Q(Nt);
|
|
874
|
+
}
|
|
875
|
+
//#endregion
|
|
876
|
+
//#region node_modules/uuid/dist/v7.js
|
|
877
|
+
var $ = {};
|
|
878
|
+
function Ft(e, t, n) {
|
|
879
|
+
let r;
|
|
880
|
+
if (e) r = Lt(e.random ?? e.rng?.() ?? Pt(), e.msecs, e.seq, t, n);
|
|
881
|
+
else {
|
|
882
|
+
let e = Date.now(), i = Pt();
|
|
883
|
+
It($, e, i), r = Lt(i, $.msecs, $.seq, t, n);
|
|
884
|
+
}
|
|
885
|
+
return t ?? Mt(r);
|
|
832
886
|
}
|
|
833
|
-
function
|
|
834
|
-
return
|
|
887
|
+
function It(e, t, n) {
|
|
888
|
+
return e.msecs ??= -Infinity, e.seq ??= 0, t > e.msecs ? (e.seq = n[6] << 23 | n[7] << 16 | n[8] << 8 | n[9], e.msecs = t) : (e.seq = e.seq + 1 | 0, e.seq === 0 && e.msecs++), e;
|
|
889
|
+
}
|
|
890
|
+
function Lt(e, t, n, r, i = 0) {
|
|
891
|
+
if (e.length < 16) throw Error("Random bytes length must be >= 16");
|
|
892
|
+
if (!r) r = new Uint8Array(16), i = 0;
|
|
893
|
+
else if (i < 0 || i + 16 > r.length) throw RangeError(`UUID byte range ${i}:${i + 15} is out of buffer bounds`);
|
|
894
|
+
return t ??= Date.now(), n ??= e[6] * 127 << 24 | e[7] << 16 | e[8] << 8 | e[9], r[i++] = t / 1099511627776 & 255, r[i++] = t / 4294967296 & 255, r[i++] = t / 16777216 & 255, r[i++] = t / 65536 & 255, r[i++] = t / 256 & 255, r[i++] = t & 255, r[i++] = 112 | n >>> 28 & 15, r[i++] = n >>> 20 & 255, r[i++] = 128 | n >>> 14 & 63, r[i++] = n >>> 6 & 255, r[i++] = n << 2 & 255 | e[10] & 3, r[i++] = e[11], r[i++] = e[12], r[i++] = e[13], r[i++] = e[14], r[i++] = e[15], r;
|
|
835
895
|
}
|
|
836
896
|
//#endregion
|
|
837
897
|
//#region src/utils.ts
|
|
838
|
-
function
|
|
839
|
-
return
|
|
898
|
+
function Rt(e) {
|
|
899
|
+
return jt(e);
|
|
900
|
+
}
|
|
901
|
+
function zt() {
|
|
902
|
+
return Ft();
|
|
840
903
|
}
|
|
841
|
-
|
|
842
|
-
|
|
904
|
+
//#endregion
|
|
905
|
+
//#region src/richTextProcessor.ts
|
|
906
|
+
function Bt(e) {
|
|
907
|
+
let t = {};
|
|
908
|
+
return {
|
|
909
|
+
text: e.replace(/<(asset|blank):([a-zA-Z0-9_-]+)\s*\/>/gi, (e, n, r) => {
|
|
910
|
+
let i = `[[__OQSE_TOKEN_${Math.random().toString(36).substring(2, 15)}__]]`;
|
|
911
|
+
return t[i] = {
|
|
912
|
+
type: n.toLowerCase(),
|
|
913
|
+
key: r.toLowerCase(),
|
|
914
|
+
originalTag: e
|
|
915
|
+
}, i;
|
|
916
|
+
}),
|
|
917
|
+
tokens: t
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
function Vt(e) {
|
|
921
|
+
let t = e.replace(/`{1,}[^`]*`{1,}/g, "").replace(/~{3,}[\s\S]*?~{3,}/g, "");
|
|
922
|
+
if (/<[a-zA-Z\/][^>]*>/.test(t)) throw Error("OQSE Security Error: Raw HTML tags are not allowed in Tier 1 (Pure Markdown). If the set requires HTML formatting, it MUST declare the 'html' feature in meta.requirements.");
|
|
923
|
+
}
|
|
924
|
+
function Ht(e, t, n) {
|
|
925
|
+
let r = e;
|
|
926
|
+
for (let [e, i] of Object.entries(t)) {
|
|
927
|
+
let t = i.originalTag;
|
|
928
|
+
i.type === "asset" && n.assetReplacer ? t = n.assetReplacer(i.key) : i.type === "blank" && n.blankReplacer && (t = n.blankReplacer(i.key)), r = r.replace(e, t);
|
|
929
|
+
}
|
|
930
|
+
return r;
|
|
931
|
+
}
|
|
932
|
+
function Ut(e, t, n) {
|
|
933
|
+
if (!e) return "";
|
|
934
|
+
let r = t?.features?.includes("html") ?? !1, { text: i, tokens: a } = Bt(e);
|
|
935
|
+
r || Vt(i);
|
|
936
|
+
let o = n.markdownParser(i);
|
|
937
|
+
if (r) {
|
|
938
|
+
if (!n.htmlSanitizer) throw Error("OQSE Security Error: Set requires 'html' (Tier 2), but no htmlSanitizer (like DOMPurify) was provided to the options.");
|
|
939
|
+
o = n.htmlSanitizer(o);
|
|
940
|
+
}
|
|
941
|
+
return Ht(o, a, n);
|
|
843
942
|
}
|
|
844
943
|
//#endregion
|
|
845
|
-
export {
|
|
944
|
+
export { g as AbsoluteURLSchema, x as AssetDictionarySchema, _ as AssetKeySchema, gt as AudioMimeTypeSchema, k as BaseItemSchema, Ee as BloomLevelSchema, I as CameraSetupSchema, L as CategorizeItemObjectSchema, qe as CategorizeItemSchema, tt as ChessPuzzleItemSchema, j as CircleHotspotSchema, De as CognitiveLoadSchema, Ze as DiagramLabelItemSchema, B as DiagramZoneSchema, ft as FeatureFlagSchema, D as FeatureProfileSchema, Be as FillInBlanksItemSchema, Ve as FillInSelectItemSchema, Fe as FlashcardItemSchema, P as HotspotObjectSchema, h as ISO8601DateTimeSchema, ht as ImageMimeTypeSchema, pt as ItemPropertyKeySchema, p as LanguageCodeSchema, Y as LastAnswerObjectSchema, O as LinkedSetObjectSchema, Re as MCQMultiItemSchema, Le as MCQSingleItemSchema, yt as ManifestAssetsSchema, bt as ManifestCapabilitiesSchema, Ue as MatchComplexItemSchema, He as MatchPairsItemSchema, Xe as MathInputItemSchema, ke as MathRendererSchema, Ae as MathSettingsSchema, Ye as MatrixItemSchema, Ce as MediaObjectSchema, N as MeshHotspotSchema, mt as MetaPropertyKeySchema, vt as ModelMimeTypeSchema, Pe as NoteItemSchema, $e as NumericInputItemSchema, Ne as NumericRangeSchema, ve as OFFICIAL_ACTIONS, s as OFFICIAL_FEATURE_KEYS, c as OFFICIAL_ITEM_PROPERTIES, l as OFFICIAL_META_PROPERTIES, lt as OQSEActionSchema, W as OQSEFileSchema, U as OQSEItemSchema, J as OQSEManifestSchema, je as OQSEMetaSchema, X as OQSEPFileSchema, dt as OQSEQuestionDensitySchema, ut as OQSEStudyModeSchema, Qe as OpenEndedItemSchema, b as OptionalRichContentSchema, Oe as PedagogySchema, S as PersonObjectSchema, Ke as PinOnImageItemSchema, et as PinOnModelItemSchema, v as PlainTextSchema, M as PolygonHotspotSchema, Dt as ProgressMetaSchema, Et as ProgressRecordSchema, A as RectHotspotSchema, y as RichContentSchema, V as RubricCriterionSchema, H as RubricSchema, m as SPDXLicenseSchema, Me as SelectBlankObjectSchema, ze as ShortAnswerItemSchema, Ge as SliderItemSchema, We as SortItemsItemSchema, w as SourceMaterialSchema, C as SourceMaterialTypeSchema, T as SourceReferenceSchema, Tt as StatsObjectSchema, Se as SubtitleTrackSchema, we as TagDefinitionDictionarySchema, E as TagDefinitionSchema, z as TimelineEventSchema, Je as TimelineItemSchema, R as TimelinePrecisionSchema, Te as TranslationObjectSchema, Ie as TrueFalseItemSchema, f as UUIDSchema, F as Vector3Schema, _t as VideoMimeTypeSchema, d as compareManifestVersions, Ht as detokenizeOqseTags, Ct as formatManifestErrors, ot as formatValidationErrors, zt as generateUUID, se as isCategorize, he as isChessPuzzle, ge as isCoreItem, de as isDiagramLabel, _e as isExtendedItem, ee as isFillInBlanks, te as isFillInSelect, n as isFlashcard, a as isMCQMulti, i as isMCQSingle, re as isMatchComplex, ne as isMatchPairs, ue as isMathInput, le as isMatrix, t as isNote, pe as isNumericInput, be as isOQSEManifest, fe as isOpenEnded, oe as isPinOnImage, me as isPinOnModel, o as isShortAnswer, ae as isSlider, ie as isSortItems, ce as isTimeline, r as isTrueFalse, u as isValidManifestVersion, wt as isValidOQSEManifest, ye as isValidSemVer, Rt as isValidUUID, xe as isVersionCompatible, Ut as prepareRichTextForDisplay, St as safeValidateManifest, rt as safeValidateOQSEFile, at as safeValidateOQSEItem, kt as safeValidateOQSEPFile, Bt as tokenizeOqseTags, xt as validateManifest, nt as validateOQSEFile, it as validateOQSEItem, Ot as validateOQSEPFile, Vt as validateTier1Markdown };
|