@longsightgroup/qti3-player 0.4.0 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (291) hide show
  1. package/README.md +146 -13
  2. package/dist/content/content-dom.d.ts +11 -0
  3. package/dist/content/content-dom.d.ts.map +1 -0
  4. package/dist/content/content-dom.js +262 -0
  5. package/dist/content/content-dom.js.map +1 -0
  6. package/dist/content/content-renderer.d.ts +17 -0
  7. package/dist/content/content-renderer.d.ts.map +1 -0
  8. package/dist/content/content-renderer.js +82 -0
  9. package/dist/content/content-renderer.js.map +1 -0
  10. package/dist/controls/remove-button.d.ts +3 -0
  11. package/dist/controls/remove-button.d.ts.map +1 -0
  12. package/dist/controls/remove-button.js +12 -0
  13. package/dist/controls/remove-button.js.map +1 -0
  14. package/dist/index.d.ts +13 -2
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +6 -0
  17. package/dist/index.js.map +1 -1
  18. package/dist/interactions/choice-interaction.d.ts +4 -0
  19. package/dist/interactions/choice-interaction.d.ts.map +1 -0
  20. package/dist/interactions/choice-interaction.js +81 -0
  21. package/dist/interactions/choice-interaction.js.map +1 -0
  22. package/dist/interactions/drawing-interaction.d.ts +6 -0
  23. package/dist/interactions/drawing-interaction.d.ts.map +1 -0
  24. package/dist/interactions/drawing-interaction.js +401 -0
  25. package/dist/interactions/drawing-interaction.js.map +1 -0
  26. package/dist/interactions/end-attempt-interaction.d.ts +4 -0
  27. package/dist/interactions/end-attempt-interaction.d.ts.map +1 -0
  28. package/dist/interactions/end-attempt-interaction.js +13 -0
  29. package/dist/interactions/end-attempt-interaction.js.map +1 -0
  30. package/dist/interactions/gap-match-interaction.d.ts +4 -0
  31. package/dist/interactions/gap-match-interaction.d.ts.map +1 -0
  32. package/dist/interactions/gap-match-interaction.js +277 -0
  33. package/dist/interactions/gap-match-interaction.js.map +1 -0
  34. package/dist/interactions/graphic-associate-interaction.d.ts +4 -0
  35. package/dist/interactions/graphic-associate-interaction.d.ts.map +1 -0
  36. package/dist/interactions/graphic-associate-interaction.js +297 -0
  37. package/dist/interactions/graphic-associate-interaction.js.map +1 -0
  38. package/dist/interactions/graphic-context.d.ts +3 -0
  39. package/dist/interactions/graphic-context.d.ts.map +1 -0
  40. package/dist/interactions/graphic-context.js +35 -0
  41. package/dist/interactions/graphic-context.js.map +1 -0
  42. package/dist/interactions/hotspot-interaction.d.ts +4 -0
  43. package/dist/interactions/hotspot-interaction.d.ts.map +1 -0
  44. package/dist/interactions/hotspot-interaction.js +68 -0
  45. package/dist/interactions/hotspot-interaction.js.map +1 -0
  46. package/dist/interactions/hottext-interaction.d.ts +3 -0
  47. package/dist/interactions/hottext-interaction.d.ts.map +1 -0
  48. package/dist/interactions/hottext-interaction.js +66 -0
  49. package/dist/interactions/hottext-interaction.js.map +1 -0
  50. package/dist/interactions/inline-choice-interaction.d.ts +4 -0
  51. package/dist/interactions/inline-choice-interaction.d.ts.map +1 -0
  52. package/dist/interactions/inline-choice-interaction.js +31 -0
  53. package/dist/interactions/inline-choice-interaction.js.map +1 -0
  54. package/dist/interactions/inline-controls.d.ts +6 -0
  55. package/dist/interactions/inline-controls.d.ts.map +1 -0
  56. package/dist/interactions/inline-controls.js +15 -0
  57. package/dist/interactions/inline-controls.js.map +1 -0
  58. package/dist/interactions/interaction-diagnostics.d.ts +7 -0
  59. package/dist/interactions/interaction-diagnostics.d.ts.map +1 -0
  60. package/dist/interactions/interaction-diagnostics.js +137 -0
  61. package/dist/interactions/interaction-diagnostics.js.map +1 -0
  62. package/dist/interactions/interaction-dispatch.d.ts +2 -0
  63. package/dist/interactions/interaction-dispatch.d.ts.map +1 -0
  64. package/dist/interactions/interaction-dispatch.js +2 -0
  65. package/dist/interactions/interaction-dispatch.js.map +1 -0
  66. package/dist/interactions/interaction-label.d.ts +4 -0
  67. package/dist/interactions/interaction-label.d.ts.map +1 -0
  68. package/dist/interactions/interaction-label.js +8 -0
  69. package/dist/interactions/interaction-label.js.map +1 -0
  70. package/dist/interactions/interaction-registry.d.ts +24 -0
  71. package/dist/interactions/interaction-registry.d.ts.map +1 -0
  72. package/dist/interactions/interaction-registry.js +138 -0
  73. package/dist/interactions/interaction-registry.js.map +1 -0
  74. package/dist/interactions/match-interaction.d.ts +4 -0
  75. package/dist/interactions/match-interaction.d.ts.map +1 -0
  76. package/dist/interactions/match-interaction.js +188 -0
  77. package/dist/interactions/match-interaction.js.map +1 -0
  78. package/dist/interactions/object-asset.d.ts +8 -0
  79. package/dist/interactions/object-asset.d.ts.map +1 -0
  80. package/dist/interactions/object-asset.js +182 -0
  81. package/dist/interactions/object-asset.js.map +1 -0
  82. package/dist/interactions/pair-interaction.d.ts +4 -0
  83. package/dist/interactions/pair-interaction.d.ts.map +1 -0
  84. package/dist/interactions/pair-interaction.js +125 -0
  85. package/dist/interactions/pair-interaction.js.map +1 -0
  86. package/dist/interactions/point-value.d.ts +16 -0
  87. package/dist/interactions/point-value.d.ts.map +1 -0
  88. package/dist/interactions/point-value.js +37 -0
  89. package/dist/interactions/point-value.js.map +1 -0
  90. package/dist/interactions/portable-custom-interaction.d.ts +16 -0
  91. package/dist/interactions/portable-custom-interaction.d.ts.map +1 -0
  92. package/dist/interactions/portable-custom-interaction.js +97 -0
  93. package/dist/interactions/portable-custom-interaction.js.map +1 -0
  94. package/dist/interactions/position-object-interaction.d.ts +4 -0
  95. package/dist/interactions/position-object-interaction.d.ts.map +1 -0
  96. package/dist/interactions/position-object-interaction.js +177 -0
  97. package/dist/interactions/position-object-interaction.js.map +1 -0
  98. package/dist/interactions/routing.d.ts +5 -0
  99. package/dist/interactions/routing.d.ts.map +1 -0
  100. package/dist/interactions/routing.js +24 -0
  101. package/dist/interactions/routing.js.map +1 -0
  102. package/dist/interactions/select-point-interaction.d.ts +4 -0
  103. package/dist/interactions/select-point-interaction.d.ts.map +1 -0
  104. package/dist/interactions/select-point-interaction.js +166 -0
  105. package/dist/interactions/select-point-interaction.js.map +1 -0
  106. package/dist/interactions/shared.d.ts +12 -0
  107. package/dist/interactions/shared.d.ts.map +1 -0
  108. package/dist/interactions/shared.js +65 -0
  109. package/dist/interactions/shared.js.map +1 -0
  110. package/dist/interactions/text-interaction.d.ts +6 -0
  111. package/dist/interactions/text-interaction.d.ts.map +1 -0
  112. package/dist/interactions/text-interaction.js +110 -0
  113. package/dist/interactions/text-interaction.js.map +1 -0
  114. package/dist/interactions/unsupported-interaction.d.ts +4 -0
  115. package/dist/interactions/unsupported-interaction.d.ts.map +1 -0
  116. package/dist/interactions/unsupported-interaction.js +23 -0
  117. package/dist/interactions/unsupported-interaction.js.map +1 -0
  118. package/dist/interactions/upload-interaction.d.ts +4 -0
  119. package/dist/interactions/upload-interaction.d.ts.map +1 -0
  120. package/dist/interactions/upload-interaction.js +10 -0
  121. package/dist/interactions/upload-interaction.js.map +1 -0
  122. package/dist/player/attempt-availability.d.ts +6 -0
  123. package/dist/player/attempt-availability.d.ts.map +1 -0
  124. package/dist/player/attempt-availability.js +27 -0
  125. package/dist/player/attempt-availability.js.map +1 -0
  126. package/dist/player/content-state.d.ts +19 -0
  127. package/dist/player/content-state.d.ts.map +1 -0
  128. package/dist/player/content-state.js +39 -0
  129. package/dist/player/content-state.js.map +1 -0
  130. package/dist/player/dynamic-body.d.ts +7 -0
  131. package/dist/player/dynamic-body.d.ts.map +1 -0
  132. package/dist/player/dynamic-body.js +28 -0
  133. package/dist/player/dynamic-body.js.map +1 -0
  134. package/dist/player/feedback-panel.d.ts +3 -0
  135. package/dist/player/feedback-panel.d.ts.map +1 -0
  136. package/dist/player/feedback-panel.js +14 -0
  137. package/dist/player/feedback-panel.js.map +1 -0
  138. package/dist/player/fetch-xml.d.ts +2 -0
  139. package/dist/player/fetch-xml.d.ts.map +1 -0
  140. package/dist/player/fetch-xml.js +10 -0
  141. package/dist/player/fetch-xml.js.map +1 -0
  142. package/dist/player/interaction-render.d.ts +14 -0
  143. package/dist/player/interaction-render.d.ts.map +1 -0
  144. package/dist/player/interaction-render.js +51 -0
  145. package/dist/player/interaction-render.js.map +1 -0
  146. package/dist/player/render-shell.d.ts +8 -0
  147. package/dist/player/render-shell.d.ts.map +1 -0
  148. package/dist/player/render-shell.js +37 -0
  149. package/dist/player/render-shell.js.map +1 -0
  150. package/dist/player/resolve-assets.d.ts +3 -0
  151. package/dist/player/resolve-assets.d.ts.map +1 -0
  152. package/dist/player/resolve-assets.js +12 -0
  153. package/dist/player/resolve-assets.js.map +1 -0
  154. package/dist/player/validation-messages.d.ts +17 -0
  155. package/dist/player/validation-messages.d.ts.map +1 -0
  156. package/dist/player/validation-messages.js +33 -0
  157. package/dist/player/validation-messages.js.map +1 -0
  158. package/dist/player-adapter.d.ts +62 -0
  159. package/dist/player-adapter.d.ts.map +1 -0
  160. package/dist/player-adapter.js +119 -0
  161. package/dist/player-adapter.js.map +1 -0
  162. package/dist/player-dev.d.ts +4 -0
  163. package/dist/player-dev.d.ts.map +1 -0
  164. package/dist/player-dev.js +14 -0
  165. package/dist/player-dev.js.map +1 -0
  166. package/dist/player-element.d.ts +14 -1
  167. package/dist/player-element.d.ts.map +1 -1
  168. package/dist/player-element.js +57 -5
  169. package/dist/player-element.js.map +1 -1
  170. package/dist/player-locale.d.ts +8 -3
  171. package/dist/player-locale.d.ts.map +1 -1
  172. package/dist/player-locale.js +16 -175
  173. package/dist/player-locale.js.map +1 -1
  174. package/dist/player-message-catalog-default.d.ts +4 -0
  175. package/dist/player-message-catalog-default.d.ts.map +1 -0
  176. package/dist/player-message-catalog-default.js +118 -0
  177. package/dist/player-message-catalog-default.js.map +1 -0
  178. package/dist/player-message-catalog-validate.d.ts +31 -0
  179. package/dist/player-message-catalog-validate.d.ts.map +1 -0
  180. package/dist/player-message-catalog-validate.js +327 -0
  181. package/dist/player-message-catalog-validate.js.map +1 -0
  182. package/dist/player-message-catalog.d.ts +18 -0
  183. package/dist/player-message-catalog.d.ts.map +1 -0
  184. package/dist/player-message-catalog.js +40 -0
  185. package/dist/player-message-catalog.js.map +1 -0
  186. package/dist/player-message-keys.d.ts +6 -0
  187. package/dist/player-message-keys.d.ts.map +1 -0
  188. package/dist/player-message-keys.js +7 -0
  189. package/dist/player-message-keys.js.map +1 -0
  190. package/dist/player-message-manifest.d.ts +272 -0
  191. package/dist/player-message-manifest.d.ts.map +1 -0
  192. package/dist/player-message-manifest.js +83 -0
  193. package/dist/player-message-manifest.js.map +1 -0
  194. package/dist/player-message-overrides.d.ts +3 -0
  195. package/dist/player-message-overrides.d.ts.map +1 -0
  196. package/dist/player-message-overrides.js +28 -0
  197. package/dist/player-message-overrides.js.map +1 -0
  198. package/dist/player-message-resolver.d.ts +31 -0
  199. package/dist/player-message-resolver.d.ts.map +1 -0
  200. package/dist/player-message-resolver.js +110 -0
  201. package/dist/player-message-resolver.js.map +1 -0
  202. package/dist/player-messages.d.ts +0 -38
  203. package/dist/player-messages.d.ts.map +1 -1
  204. package/dist/player-types.d.ts +12 -2
  205. package/dist/player-types.d.ts.map +1 -1
  206. package/dist/reorder/a11y.d.ts +7 -0
  207. package/dist/reorder/a11y.d.ts.map +1 -0
  208. package/dist/reorder/a11y.js +34 -0
  209. package/dist/reorder/a11y.js.map +1 -0
  210. package/dist/reorder/graphic-order-interaction.d.ts +4 -0
  211. package/dist/reorder/graphic-order-interaction.d.ts.map +1 -0
  212. package/dist/reorder/graphic-order-interaction.js +205 -0
  213. package/dist/reorder/graphic-order-interaction.js.map +1 -0
  214. package/dist/reorder/list-controls.d.ts +22 -0
  215. package/dist/reorder/list-controls.d.ts.map +1 -0
  216. package/dist/reorder/list-controls.js +75 -0
  217. package/dist/reorder/list-controls.js.map +1 -0
  218. package/dist/reorder/order-interaction.d.ts +4 -0
  219. package/dist/reorder/order-interaction.d.ts.map +1 -0
  220. package/dist/reorder/order-interaction.js +54 -0
  221. package/dist/reorder/order-interaction.js.map +1 -0
  222. package/dist/styles/base-styles.d.ts +2 -0
  223. package/dist/styles/base-styles.d.ts.map +1 -0
  224. package/dist/styles/base-styles.js +133 -0
  225. package/dist/styles/base-styles.js.map +1 -0
  226. package/dist/styles/choice-hottext-styles.d.ts +2 -0
  227. package/dist/styles/choice-hottext-styles.d.ts.map +1 -0
  228. package/dist/styles/choice-hottext-styles.js +76 -0
  229. package/dist/styles/choice-hottext-styles.js.map +1 -0
  230. package/dist/styles/control-styles.d.ts +2 -0
  231. package/dist/styles/control-styles.d.ts.map +1 -0
  232. package/dist/styles/control-styles.js +114 -0
  233. package/dist/styles/control-styles.js.map +1 -0
  234. package/dist/styles/drawing-styles.d.ts +2 -0
  235. package/dist/styles/drawing-styles.d.ts.map +1 -0
  236. package/dist/styles/drawing-styles.js +30 -0
  237. package/dist/styles/drawing-styles.js.map +1 -0
  238. package/dist/styles/gap-match-styles.d.ts +2 -0
  239. package/dist/styles/gap-match-styles.d.ts.map +1 -0
  240. package/dist/styles/gap-match-styles.js +33 -0
  241. package/dist/styles/gap-match-styles.js.map +1 -0
  242. package/dist/styles/graphic-styles.d.ts +2 -0
  243. package/dist/styles/graphic-styles.d.ts.map +1 -0
  244. package/dist/styles/graphic-styles.js +289 -0
  245. package/dist/styles/graphic-styles.js.map +1 -0
  246. package/dist/styles/match-pair-styles.d.ts +2 -0
  247. package/dist/styles/match-pair-styles.d.ts.map +1 -0
  248. package/dist/styles/match-pair-styles.js +62 -0
  249. package/dist/styles/match-pair-styles.js.map +1 -0
  250. package/dist/styles/text-slider-styles.d.ts +2 -0
  251. package/dist/styles/text-slider-styles.d.ts.map +1 -0
  252. package/dist/styles/text-slider-styles.js +35 -0
  253. package/dist/styles/text-slider-styles.js.map +1 -0
  254. package/package.json +8 -8
  255. package/src/controls/remove-button.ts +8 -5
  256. package/src/index.ts +61 -5
  257. package/src/interactions/choice-interaction.ts +6 -2
  258. package/src/interactions/drawing-interaction.ts +14 -9
  259. package/src/interactions/end-attempt-interaction.ts +3 -3
  260. package/src/interactions/gap-match-interaction.ts +32 -13
  261. package/src/interactions/graphic-associate-interaction.ts +15 -10
  262. package/src/interactions/hotspot-interaction.ts +10 -6
  263. package/src/interactions/inline-choice-interaction.ts +4 -4
  264. package/src/interactions/interaction-registry.ts +12 -12
  265. package/src/interactions/match-interaction.ts +9 -6
  266. package/src/interactions/pair-interaction.ts +22 -14
  267. package/src/interactions/position-object-interaction.ts +22 -13
  268. package/src/interactions/select-point-interaction.ts +25 -13
  269. package/src/interactions/shared.ts +21 -4
  270. package/src/interactions/text-interaction.ts +14 -4
  271. package/src/interactions/upload-interaction.ts +6 -3
  272. package/src/player/interaction-render.ts +4 -4
  273. package/src/player-adapter.ts +253 -0
  274. package/src/player-dev.ts +14 -0
  275. package/src/player-element.ts +78 -8
  276. package/src/player-locale.ts +28 -199
  277. package/src/player-message-catalog-default.ts +119 -0
  278. package/src/player-message-catalog-validate.ts +425 -0
  279. package/src/player-message-catalog.ts +72 -0
  280. package/src/player-message-keys.ts +12 -0
  281. package/src/player-message-manifest.ts +103 -0
  282. package/src/player-message-overrides.ts +38 -0
  283. package/src/player-message-resolver.ts +205 -0
  284. package/src/player-messages.ts +0 -30
  285. package/src/player-types.ts +15 -4
  286. package/src/reorder/a11y.ts +22 -7
  287. package/src/reorder/graphic-order-interaction.ts +23 -16
  288. package/src/reorder/list-controls.ts +8 -6
  289. package/src/reorder/order-interaction.ts +7 -5
  290. package/src/styles/base-styles.ts +20 -5
  291. package/src/styles/graphic-styles.ts +0 -6
@@ -0,0 +1,327 @@
1
+ import { defaultPlayerMessageCatalog } from "./player-message-catalog-default.js";
2
+ import { extractMessagePlaceholders } from "./player-message-catalog.js";
3
+ import { PLAYER_MESSAGE_MANIFEST, } from "./player-message-manifest.js";
4
+ const MANIFEST_KEYS = new Set(PLAYER_MESSAGE_MANIFEST.map((entry) => entry.key));
5
+ const MANIFEST_BY_KEY = new Map(PLAYER_MESSAGE_MANIFEST.map((entry) => [entry.key, entry]));
6
+ const AUXILIARY_STRING_KEYS = new Set([
7
+ "characterUnit.one",
8
+ "characterUnit.other",
9
+ "wordUnit.one",
10
+ "wordUnit.other",
11
+ ]);
12
+ const VALID_DIRECTION_KEYS = new Set(["up", "down", "left", "right"]);
13
+ function isPlainObject(value) {
14
+ return typeof value === "object" && value !== null && !Array.isArray(value);
15
+ }
16
+ function isNonEmptyString(value) {
17
+ return typeof value === "string";
18
+ }
19
+ function pushDiagnostic(diagnostics, diagnostic) {
20
+ diagnostics.push(diagnostic);
21
+ }
22
+ function isManifestStringKey(key) {
23
+ if (MANIFEST_KEYS.has(key))
24
+ return true;
25
+ if (AUXILIARY_STRING_KEYS.has(key))
26
+ return true;
27
+ const pluralMatch = /^(.+)\.(one|other)$/.exec(key);
28
+ if (pluralMatch && MANIFEST_KEYS.has(pluralMatch[1])) {
29
+ return MANIFEST_BY_KEY.get(pluralMatch[1])?.resolver === "plural";
30
+ }
31
+ return false;
32
+ }
33
+ /** Placeholders a host may use for a manifest entry (superset of manifest params). */
34
+ export function allowedCatalogPlaceholders(entry) {
35
+ switch (entry.resolver) {
36
+ case "plain":
37
+ case "typeLabel":
38
+ return [];
39
+ case "template":
40
+ case "plural":
41
+ case "directionTemplate":
42
+ return entry.params ?? [];
43
+ case "typeTemplate":
44
+ return [...(entry.params?.filter((name) => name !== "type") ?? []), "typeName"];
45
+ case "extendedTextCounter":
46
+ return ["characters", "words", "characterUnit", "wordUnit"];
47
+ default:
48
+ return [];
49
+ }
50
+ }
51
+ /**
52
+ * Placeholders a host template must include for a catalog string key.
53
+ * Uses the English default for that key when present; otherwise no placeholders are required.
54
+ * Manifest `params` bound required fields for resolvers that inject extra values at runtime
55
+ * (e.g. `extendedTextCounter` supplies `{characterUnit}` / `{wordUnit}` even when omitted).
56
+ */
57
+ export function requiredCatalogPlaceholders(catalogKey, entry) {
58
+ const manifestEntry = entry ?? manifestEntryForStringKey(catalogKey);
59
+ if (!manifestEntry) {
60
+ return [];
61
+ }
62
+ const allowed = new Set(allowedCatalogPlaceholders(manifestEntry));
63
+ const defaultTemplate = defaultPlayerMessageCatalog.strings[catalogKey];
64
+ const fromDefault = defaultTemplate
65
+ ? extractMessagePlaceholders(defaultTemplate).filter((name) => allowed.has(name))
66
+ : [];
67
+ if (manifestEntry.resolver === "extendedTextCounter") {
68
+ return (manifestEntry.params ?? []).filter((name) => allowed.has(name));
69
+ }
70
+ if (fromDefault.length > 0) {
71
+ return fromDefault;
72
+ }
73
+ return [];
74
+ }
75
+ function validateTemplate(key, template, entry, diagnostics) {
76
+ if (!template.trim()) {
77
+ pushDiagnostic(diagnostics, {
78
+ code: "empty-template",
79
+ key,
80
+ severity: "error",
81
+ message: `Message "${key}" is empty.`,
82
+ });
83
+ return;
84
+ }
85
+ const allowed = new Set(allowedCatalogPlaceholders(entry));
86
+ const actual = extractMessagePlaceholders(template);
87
+ const required = requiredCatalogPlaceholders(key, entry);
88
+ for (const placeholder of actual) {
89
+ if (!allowed.has(placeholder)) {
90
+ pushDiagnostic(diagnostics, {
91
+ code: "unknown-placeholder",
92
+ key,
93
+ severity: "error",
94
+ message: `Message "${key}" uses unknown placeholder "{${placeholder}}". Allowed: ${[...allowed].join(", ") || "(none)"}.`,
95
+ });
96
+ }
97
+ }
98
+ for (const placeholder of required) {
99
+ if (!actual.includes(placeholder)) {
100
+ pushDiagnostic(diagnostics, {
101
+ code: "missing-placeholder",
102
+ key,
103
+ severity: "error",
104
+ message: `Message "${key}" is missing required placeholder "{${placeholder}}" (required by English default for this key).`,
105
+ });
106
+ }
107
+ }
108
+ }
109
+ function manifestEntryForStringKey(key) {
110
+ const pluralMatch = /^(.+)\.(one|other)$/.exec(key);
111
+ const baseKey = (pluralMatch?.[1] ?? key);
112
+ return MANIFEST_BY_KEY.get(baseKey);
113
+ }
114
+ function normalizeCatalogInput(input, diagnostics) {
115
+ if (!isPlainObject(input)) {
116
+ pushDiagnostic(diagnostics, {
117
+ code: "invalid-catalog-root",
118
+ key: "(root)",
119
+ severity: "error",
120
+ message: "Player message catalog must be a JSON object.",
121
+ });
122
+ return null;
123
+ }
124
+ const normalized = {
125
+ strings: {},
126
+ interactionTypes: {},
127
+ directions: {},
128
+ };
129
+ if ("locale" in input) {
130
+ if (input.locale === undefined) {
131
+ // omit
132
+ }
133
+ else if (!isNonEmptyString(input.locale)) {
134
+ pushDiagnostic(diagnostics, {
135
+ code: "invalid-catalog-field",
136
+ key: "locale",
137
+ severity: "error",
138
+ message: "Catalog locale must be a string when provided.",
139
+ });
140
+ }
141
+ else {
142
+ normalized.locale = input.locale;
143
+ }
144
+ }
145
+ if (!("strings" in input) || input.strings === undefined) {
146
+ pushDiagnostic(diagnostics, {
147
+ code: "invalid-strings-field",
148
+ key: "strings",
149
+ severity: "error",
150
+ message: 'Catalog must include a "strings" object.',
151
+ });
152
+ }
153
+ else if (!isPlainObject(input.strings)) {
154
+ pushDiagnostic(diagnostics, {
155
+ code: "invalid-strings-field",
156
+ key: "strings",
157
+ severity: "error",
158
+ message: 'Catalog "strings" must be an object mapping message ids to template strings.',
159
+ });
160
+ }
161
+ else {
162
+ for (const [key, value] of Object.entries(input.strings)) {
163
+ if (!isNonEmptyString(value)) {
164
+ pushDiagnostic(diagnostics, {
165
+ code: "invalid-string-value",
166
+ key,
167
+ severity: "error",
168
+ message: `Catalog strings["${key}"] must be a string.`,
169
+ });
170
+ continue;
171
+ }
172
+ normalized.strings[key] = value;
173
+ }
174
+ }
175
+ if ("interactionTypes" in input && input.interactionTypes !== undefined) {
176
+ if (!isPlainObject(input.interactionTypes)) {
177
+ pushDiagnostic(diagnostics, {
178
+ code: "invalid-interaction-types-field",
179
+ key: "interactionTypes",
180
+ severity: "error",
181
+ message: 'Catalog "interactionTypes" must be an object mapping interaction type ids to labels.',
182
+ });
183
+ }
184
+ else {
185
+ for (const [typeId, label] of Object.entries(input.interactionTypes)) {
186
+ if (!isNonEmptyString(label)) {
187
+ pushDiagnostic(diagnostics, {
188
+ code: "invalid-interaction-type-value",
189
+ key: typeId,
190
+ severity: "error",
191
+ message: `Catalog interactionTypes["${typeId}"] must be a string.`,
192
+ });
193
+ continue;
194
+ }
195
+ normalized.interactionTypes[typeId] = label;
196
+ }
197
+ }
198
+ }
199
+ if ("directions" in input && input.directions !== undefined) {
200
+ if (!isPlainObject(input.directions)) {
201
+ pushDiagnostic(diagnostics, {
202
+ code: "invalid-directions-field",
203
+ key: "directions",
204
+ severity: "error",
205
+ message: 'Catalog "directions" must be an object mapping direction ids to labels.',
206
+ });
207
+ }
208
+ else {
209
+ for (const [direction, label] of Object.entries(input.directions)) {
210
+ if (!VALID_DIRECTION_KEYS.has(direction)) {
211
+ pushDiagnostic(diagnostics, {
212
+ code: "invalid-direction-key",
213
+ key: direction,
214
+ severity: "error",
215
+ message: `Unknown direction key "${direction}". Use up, down, left, or right.`,
216
+ });
217
+ continue;
218
+ }
219
+ if (!isNonEmptyString(label)) {
220
+ pushDiagnostic(diagnostics, {
221
+ code: "invalid-direction-value",
222
+ key: direction,
223
+ severity: "error",
224
+ message: `Catalog directions["${direction}"] must be a string.`,
225
+ });
226
+ continue;
227
+ }
228
+ normalized.directions[direction] = label;
229
+ }
230
+ }
231
+ }
232
+ for (const field of Object.keys(input)) {
233
+ if (field === "locale" ||
234
+ field === "strings" ||
235
+ field === "interactionTypes" ||
236
+ field === "directions") {
237
+ continue;
238
+ }
239
+ pushDiagnostic(diagnostics, {
240
+ code: "invalid-catalog-field",
241
+ key: field,
242
+ severity: "error",
243
+ message: `Unknown catalog field "${field}".`,
244
+ });
245
+ }
246
+ return normalized;
247
+ }
248
+ function validateNormalizedCatalog(catalog, options, diagnostics) {
249
+ const strings = catalog.strings;
250
+ for (const key of Object.keys(strings)) {
251
+ if (!isManifestStringKey(key)) {
252
+ pushDiagnostic(diagnostics, {
253
+ code: "unknown-string-key",
254
+ key,
255
+ severity: "error",
256
+ message: `Unknown catalog string key "${key}". See PLAYER_MESSAGE_KEYS.`,
257
+ });
258
+ continue;
259
+ }
260
+ const entry = manifestEntryForStringKey(key);
261
+ const template = strings[key];
262
+ if (!entry || template === undefined)
263
+ continue;
264
+ validateTemplate(key, template, entry, diagnostics);
265
+ }
266
+ if (options.requireAllKeys) {
267
+ for (const entry of PLAYER_MESSAGE_MANIFEST) {
268
+ const hasBase = strings[entry.key] !== undefined;
269
+ const hasPlural = entry.resolver === "plural" &&
270
+ (strings[`${entry.key}.one`] !== undefined || strings[`${entry.key}.other`] !== undefined);
271
+ if (entry.resolver === "typeLabel") {
272
+ continue;
273
+ }
274
+ if (entry.resolver === "plural") {
275
+ if (!hasBase && !hasPlural) {
276
+ pushDiagnostic(diagnostics, {
277
+ code: "missing-message-key",
278
+ key: entry.key,
279
+ severity: "error",
280
+ message: `Missing message "${entry.key}" (or "${entry.key}.one" / "${entry.key}.other").`,
281
+ });
282
+ }
283
+ if (!strings[`${entry.key}.one`] &&
284
+ defaultPlayerMessageCatalog.strings[`${entry.key}.one`]) {
285
+ pushDiagnostic(diagnostics, {
286
+ code: "missing-plural-form",
287
+ key: `${entry.key}.one`,
288
+ severity: "warning",
289
+ message: `Missing plural form "${entry.key}.one". English fallback will be used.`,
290
+ });
291
+ }
292
+ if (!strings[`${entry.key}.other`] &&
293
+ defaultPlayerMessageCatalog.strings[`${entry.key}.other`]) {
294
+ pushDiagnostic(diagnostics, {
295
+ code: "missing-plural-form",
296
+ key: `${entry.key}.other`,
297
+ severity: "warning",
298
+ message: `Missing plural form "${entry.key}.other". English fallback will be used.`,
299
+ });
300
+ }
301
+ }
302
+ else if (!hasBase) {
303
+ pushDiagnostic(diagnostics, {
304
+ code: "missing-message-key",
305
+ key: entry.key,
306
+ severity: "error",
307
+ message: `Missing message "${entry.key}".`,
308
+ });
309
+ }
310
+ }
311
+ }
312
+ }
313
+ /**
314
+ * Validates host player chrome JSON against {@link PLAYER_MESSAGE_MANIFEST}.
315
+ * Accepts raw `JSON.parse` output (`unknown`); returns structured diagnostics instead of throwing.
316
+ */
317
+ export function validatePlayerMessageCatalog(catalog, options = {}) {
318
+ const diagnostics = [];
319
+ const normalized = normalizeCatalogInput(catalog, diagnostics);
320
+ if (!normalized) {
321
+ return { valid: false, diagnostics };
322
+ }
323
+ validateNormalizedCatalog(normalized, options, diagnostics);
324
+ const errors = diagnostics.filter((item) => item.severity === "error");
325
+ return { valid: errors.length === 0, diagnostics };
326
+ }
327
+ //# sourceMappingURL=player-message-catalog-validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"player-message-catalog-validate.js","sourceRoot":"","sources":["../src/player-message-catalog-validate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { QtiPlayerMovementDirection } from "./player-messages.js";
2
+ export { defaultPlayerMessageCatalog } from "./player-message-catalog-default.js";
3
+ export { createPlayerMessageResolver, defaultPlayerMessageResolver, type PlayerMessageOverride, type PlayerMessageParams, type PlayerMessageResolver, type QtiPlayerMessageOverrides, } from "./player-message-resolver.js";
4
+ /** JSON-serializable chrome strings for Harbor/LMS locale files. */
5
+ export interface PlayerMessageCatalog {
6
+ /** BCP 47 tag (metadata only). */
7
+ locale?: string;
8
+ /** Message templates; use `{name}` placeholders. Plural forms: `key.one` / `key.other`. */
9
+ strings: Record<string, string>;
10
+ /** QTI interaction type id → short label inserted as `{typeName}`. */
11
+ interactionTypes?: Record<string, string>;
12
+ /** Labels for moveChoice / movePoint / moveObject (`{direction}`). */
13
+ directions?: Partial<Record<QtiPlayerMovementDirection, string>>;
14
+ }
15
+ export declare function mergePlayerMessageCatalogs(base: PlayerMessageCatalog, partial: Partial<PlayerMessageCatalog>): PlayerMessageCatalog;
16
+ export declare function extractMessagePlaceholders(template: string): string[];
17
+ export declare function formatPlayerMessage(template: string, values: Record<string, string | number>): string;
18
+ //# sourceMappingURL=player-message-catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"player-message-catalog.d.ts","sourceRoot":"","sources":["../src/player-message-catalog.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAEvE,OAAO,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,EACL,2BAA2B,EAC3B,4BAA4B,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,yBAAyB,GAC/B,MAAM,8BAA8B,CAAC;AAEtC,oEAAoE;AACpE,MAAM,WAAW,oBAAoB;IACnC,kCAAkC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2FAA2F;IAC3F,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,sEAAsE;IACtE,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,sEAAsE;IACtE,UAAU,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,0BAA0B,EAAE,MAAM,CAAC,CAAC,CAAC;CAClE;AAED,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,oBAAoB,EAC1B,OAAO,EAAE,OAAO,CAAC,oBAAoB,CAAC,GACrC,oBAAoB,CAiBtB;AAED,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAMrE;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GACtC,MAAM,CAaR"}
@@ -0,0 +1,40 @@
1
+ import { playerDevWarningsEnabled, warnPlayerMessageOnce } from "./player-dev.js";
2
+ export { defaultPlayerMessageCatalog } from "./player-message-catalog-default.js";
3
+ export { createPlayerMessageResolver, defaultPlayerMessageResolver, } from "./player-message-resolver.js";
4
+ export function mergePlayerMessageCatalogs(base, partial) {
5
+ const merged = {
6
+ strings: { ...base.strings, ...partial.strings },
7
+ };
8
+ const interactionTypes = { ...base.interactionTypes, ...partial.interactionTypes };
9
+ if (Object.keys(interactionTypes).length > 0) {
10
+ merged.interactionTypes = interactionTypes;
11
+ }
12
+ const directions = { ...base.directions, ...partial.directions };
13
+ if (Object.keys(directions).length > 0) {
14
+ merged.directions = directions;
15
+ }
16
+ const locale = partial.locale ?? base.locale;
17
+ if (locale !== undefined) {
18
+ merged.locale = locale;
19
+ }
20
+ return merged;
21
+ }
22
+ export function extractMessagePlaceholders(template) {
23
+ const names = new Set();
24
+ for (const match of template.matchAll(/\{(\w+)\}/g)) {
25
+ names.add(match[1] ?? "");
26
+ }
27
+ return [...names].filter(Boolean);
28
+ }
29
+ export function formatPlayerMessage(template, values) {
30
+ const placeholders = extractMessagePlaceholders(template);
31
+ const missing = placeholders.filter((name) => values[name] === undefined);
32
+ if (missing.length > 0 && playerDevWarningsEnabled()) {
33
+ warnPlayerMessageOnce(`missing-placeholder-values:${missing.join(",")}`, `Player message template is missing values for: ${missing.map((name) => `{${name}}`).join(", ")}.`);
34
+ }
35
+ return template.replace(/\{(\w+)\}/g, (_, key) => {
36
+ const value = values[key];
37
+ return value === undefined ? `{${key}}` : String(value);
38
+ });
39
+ }
40
+ //# sourceMappingURL=player-message-catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"player-message-catalog.js","sourceRoot":"","sources":["../src/player-message-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAGlF,OAAO,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,EACL,2BAA2B,EAC3B,4BAA4B,GAK7B,MAAM,8BAA8B,CAAC;AActC,MAAM,UAAU,0BAA0B,CACxC,IAA0B,EAC1B,OAAsC;IAEtC,MAAM,MAAM,GAAyB;QACnC,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE;KACjD,CAAC;IACF,MAAM,gBAAgB,GAAG,EAAE,GAAG,IAAI,CAAC,gBAAgB,EAAE,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IACnF,IAAI,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7C,MAAM,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;IAC7C,CAAC;IACD,MAAM,UAAU,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IACjE,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvC,MAAM,CAAC,UAAU,GAAG,UAAU,CAAC;IACjC,CAAC;IACD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC;IAC7C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,QAAgB;IACzD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QACpD,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,QAAgB,EAChB,MAAuC;IAEvC,MAAM,YAAY,GAAG,0BAA0B,CAAC,QAAQ,CAAC,CAAC;IAC1D,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,CAAC;IAC1E,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,wBAAwB,EAAE,EAAE,CAAC;QACrD,qBAAqB,CACnB,8BAA8B,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EACjD,kDAAkD,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACnG,CAAC;IACJ,CAAC;IACD,OAAO,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC,EAAE,GAAW,EAAE,EAAE;QACvD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC1B,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { type PlayerMessageKey } from "./player-message-manifest.js";
2
+ /** Chrome message ids (from {@link PLAYER_MESSAGE_MANIFEST}). */
3
+ export declare const PLAYER_MESSAGE_KEYS: readonly PlayerMessageKey[];
4
+ /** All `strings` keys in the English catalog (including plural/unit suffix keys). */
5
+ export declare const PLAYER_MESSAGE_STRING_KEYS: ReadonlyArray<string>;
6
+ //# sourceMappingURL=player-message-keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"player-message-keys.d.ts","sourceRoot":"","sources":["../src/player-message-keys.ts"],"names":[],"mappings":"AACA,OAAO,EAA2B,KAAK,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAE9F,iEAAiE;AACjE,eAAO,MAAM,mBAAmB,EAE3B,SAAS,gBAAgB,EAAE,CAAC;AAEjC,qFAAqF;AACrF,eAAO,MAAM,0BAA0B,EAElC,aAAa,CAAC,MAAM,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { defaultPlayerMessageCatalog } from "./player-message-catalog-default.js";
2
+ import { PLAYER_MESSAGE_MANIFEST } from "./player-message-manifest.js";
3
+ /** Chrome message ids (from {@link PLAYER_MESSAGE_MANIFEST}). */
4
+ export const PLAYER_MESSAGE_KEYS = PLAYER_MESSAGE_MANIFEST.map((entry) => entry.key);
5
+ /** All `strings` keys in the English catalog (including plural/unit suffix keys). */
6
+ export const PLAYER_MESSAGE_STRING_KEYS = Object.keys(defaultPlayerMessageCatalog.strings);
7
+ //# sourceMappingURL=player-message-keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"player-message-keys.js","sourceRoot":"","sources":["../src/player-message-keys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,EAAE,uBAAuB,EAAyB,MAAM,8BAA8B,CAAC;AAE9F,iEAAiE;AACjE,MAAM,CAAC,MAAM,mBAAmB,GAAG,uBAAuB,CAAC,GAAG,CAC5D,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CACU,CAAC;AAEjC,qFAAqF;AACrF,MAAM,CAAC,MAAM,0BAA0B,GAAG,MAAM,CAAC,IAAI,CACnD,2BAA2B,CAAC,OAAO,CACX,CAAC"}