@pie-players/pie-assessment-toolkit 0.2.0

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 (194) hide show
  1. package/README.md +520 -0
  2. package/dist/attempt/TestSession.d.ts +90 -0
  3. package/dist/attempt/TestSession.d.ts.map +1 -0
  4. package/dist/attempt/TestSession.js +174 -0
  5. package/dist/attempt/TestSession.js.map +1 -0
  6. package/dist/core/TypedEventBus.d.ts +48 -0
  7. package/dist/core/TypedEventBus.d.ts.map +1 -0
  8. package/dist/core/TypedEventBus.js +63 -0
  9. package/dist/core/TypedEventBus.js.map +1 -0
  10. package/dist/index.d.ts +37 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +44 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/item-loader.d.ts +45 -0
  15. package/dist/item-loader.d.ts.map +1 -0
  16. package/dist/item-loader.js +62 -0
  17. package/dist/item-loader.js.map +1 -0
  18. package/dist/player/AssessmentPlayer.d.ts +388 -0
  19. package/dist/player/AssessmentPlayer.d.ts.map +1 -0
  20. package/dist/player/AssessmentPlayer.js +965 -0
  21. package/dist/player/AssessmentPlayer.js.map +1 -0
  22. package/dist/player/index.d.ts +17 -0
  23. package/dist/player/index.d.ts.map +1 -0
  24. package/dist/player/index.js +15 -0
  25. package/dist/player/index.js.map +1 -0
  26. package/dist/player/navigation-types.d.ts +63 -0
  27. package/dist/player/navigation-types.d.ts.map +1 -0
  28. package/dist/player/navigation-types.js +7 -0
  29. package/dist/player/navigation-types.js.map +1 -0
  30. package/dist/player/qti-navigation.d.ts +29 -0
  31. package/dist/player/qti-navigation.d.ts.map +1 -0
  32. package/dist/player/qti-navigation.js +160 -0
  33. package/dist/player/qti-navigation.js.map +1 -0
  34. package/dist/reference-layout/index.d.ts +19 -0
  35. package/dist/reference-layout/index.d.ts.map +1 -0
  36. package/dist/reference-layout/index.js +20 -0
  37. package/dist/reference-layout/index.js.map +1 -0
  38. package/dist/services/AccessibilityCatalogResolver.d.ts +141 -0
  39. package/dist/services/AccessibilityCatalogResolver.d.ts.map +1 -0
  40. package/dist/services/AccessibilityCatalogResolver.js +249 -0
  41. package/dist/services/AccessibilityCatalogResolver.js.map +1 -0
  42. package/dist/services/AssessmentAuthoringService.d.ts +60 -0
  43. package/dist/services/AssessmentAuthoringService.d.ts.map +1 -0
  44. package/dist/services/AssessmentAuthoringService.js +183 -0
  45. package/dist/services/AssessmentAuthoringService.js.map +1 -0
  46. package/dist/services/ContextVariableStore.d.ts +114 -0
  47. package/dist/services/ContextVariableStore.d.ts.map +1 -0
  48. package/dist/services/ContextVariableStore.js +207 -0
  49. package/dist/services/ContextVariableStore.js.map +1 -0
  50. package/dist/services/ElementToolStateStore.d.ts +125 -0
  51. package/dist/services/ElementToolStateStore.d.ts.map +1 -0
  52. package/dist/services/ElementToolStateStore.js +200 -0
  53. package/dist/services/ElementToolStateStore.js.map +1 -0
  54. package/dist/services/HighlightCoordinator.d.ts +179 -0
  55. package/dist/services/HighlightCoordinator.d.ts.map +1 -0
  56. package/dist/services/HighlightCoordinator.js +446 -0
  57. package/dist/services/HighlightCoordinator.js.map +1 -0
  58. package/dist/services/I18nService.d.ts +121 -0
  59. package/dist/services/I18nService.d.ts.map +1 -0
  60. package/dist/services/I18nService.js +276 -0
  61. package/dist/services/I18nService.js.map +1 -0
  62. package/dist/services/PNPMapper.d.ts +71 -0
  63. package/dist/services/PNPMapper.d.ts.map +1 -0
  64. package/dist/services/PNPMapper.js +98 -0
  65. package/dist/services/PNPMapper.js.map +1 -0
  66. package/dist/services/PNPToolResolver.d.ts +127 -0
  67. package/dist/services/PNPToolResolver.d.ts.map +1 -0
  68. package/dist/services/PNPToolResolver.js +222 -0
  69. package/dist/services/PNPToolResolver.js.map +1 -0
  70. package/dist/services/SSMLExtractor.d.ts +61 -0
  71. package/dist/services/SSMLExtractor.d.ts.map +1 -0
  72. package/dist/services/SSMLExtractor.js +181 -0
  73. package/dist/services/SSMLExtractor.js.map +1 -0
  74. package/dist/services/TTSService.d.ts +162 -0
  75. package/dist/services/TTSService.d.ts.map +1 -0
  76. package/dist/services/TTSService.js +465 -0
  77. package/dist/services/TTSService.js.map +1 -0
  78. package/dist/services/ThemeProvider.d.ts +95 -0
  79. package/dist/services/ThemeProvider.d.ts.map +1 -0
  80. package/dist/services/ThemeProvider.js +299 -0
  81. package/dist/services/ThemeProvider.js.map +1 -0
  82. package/dist/services/ToolConfigResolver.d.ts +162 -0
  83. package/dist/services/ToolConfigResolver.d.ts.map +1 -0
  84. package/dist/services/ToolConfigResolver.js +230 -0
  85. package/dist/services/ToolConfigResolver.js.map +1 -0
  86. package/dist/services/ToolCoordinator.d.ts +137 -0
  87. package/dist/services/ToolCoordinator.d.ts.map +1 -0
  88. package/dist/services/ToolCoordinator.js +318 -0
  89. package/dist/services/ToolCoordinator.js.map +1 -0
  90. package/dist/services/ToolkitCoordinator.d.ts +188 -0
  91. package/dist/services/ToolkitCoordinator.d.ts.map +1 -0
  92. package/dist/services/ToolkitCoordinator.js +252 -0
  93. package/dist/services/ToolkitCoordinator.js.map +1 -0
  94. package/dist/services/interfaces.d.ts +391 -0
  95. package/dist/services/interfaces.d.ts.map +1 -0
  96. package/dist/services/interfaces.js +12 -0
  97. package/dist/services/interfaces.js.map +1 -0
  98. package/dist/services/tool-providers/DesmosToolProvider.d.ts +103 -0
  99. package/dist/services/tool-providers/DesmosToolProvider.d.ts.map +1 -0
  100. package/dist/services/tool-providers/DesmosToolProvider.js +127 -0
  101. package/dist/services/tool-providers/DesmosToolProvider.js.map +1 -0
  102. package/dist/services/tool-providers/IToolProvider.d.ts +137 -0
  103. package/dist/services/tool-providers/IToolProvider.d.ts.map +1 -0
  104. package/dist/services/tool-providers/IToolProvider.js +13 -0
  105. package/dist/services/tool-providers/IToolProvider.js.map +1 -0
  106. package/dist/services/tool-providers/TIToolProvider.d.ts +107 -0
  107. package/dist/services/tool-providers/TIToolProvider.d.ts.map +1 -0
  108. package/dist/services/tool-providers/TIToolProvider.js +123 -0
  109. package/dist/services/tool-providers/TIToolProvider.js.map +1 -0
  110. package/dist/services/tool-providers/TTSToolProvider.d.ts +143 -0
  111. package/dist/services/tool-providers/TTSToolProvider.d.ts.map +1 -0
  112. package/dist/services/tool-providers/TTSToolProvider.js +168 -0
  113. package/dist/services/tool-providers/TTSToolProvider.js.map +1 -0
  114. package/dist/services/tool-providers/ToolProviderRegistry.d.ts +165 -0
  115. package/dist/services/tool-providers/ToolProviderRegistry.d.ts.map +1 -0
  116. package/dist/services/tool-providers/ToolProviderRegistry.js +240 -0
  117. package/dist/services/tool-providers/ToolProviderRegistry.js.map +1 -0
  118. package/dist/services/tool-providers/index.d.ts +18 -0
  119. package/dist/services/tool-providers/index.d.ts.map +1 -0
  120. package/dist/services/tool-providers/index.js +15 -0
  121. package/dist/services/tool-providers/index.js.map +1 -0
  122. package/dist/services/tts/browser-provider.d.ts +24 -0
  123. package/dist/services/tts/browser-provider.d.ts.map +1 -0
  124. package/dist/services/tts/browser-provider.js +177 -0
  125. package/dist/services/tts/browser-provider.js.map +1 -0
  126. package/dist/services/tts/provider-interface.d.ts +131 -0
  127. package/dist/services/tts/provider-interface.d.ts.map +1 -0
  128. package/dist/services/tts/provider-interface.js +10 -0
  129. package/dist/services/tts/provider-interface.js.map +1 -0
  130. package/dist/tools/calculators/desmos-provider.d.ts +54 -0
  131. package/dist/tools/calculators/desmos-provider.d.ts.map +1 -0
  132. package/dist/tools/calculators/desmos-provider.js +384 -0
  133. package/dist/tools/calculators/desmos-provider.js.map +1 -0
  134. package/dist/tools/calculators/mathjs-provider.d.ts +50 -0
  135. package/dist/tools/calculators/mathjs-provider.d.ts.map +1 -0
  136. package/dist/tools/calculators/mathjs-provider.js +660 -0
  137. package/dist/tools/calculators/mathjs-provider.js.map +1 -0
  138. package/dist/tools/calculators/ti-provider.d.ts +122 -0
  139. package/dist/tools/calculators/ti-provider.d.ts.map +1 -0
  140. package/dist/tools/calculators/ti-provider.js +587 -0
  141. package/dist/tools/calculators/ti-provider.js.map +1 -0
  142. package/dist/tools/client.d.ts +17 -0
  143. package/dist/tools/client.d.ts.map +1 -0
  144. package/dist/tools/client.js +26 -0
  145. package/dist/tools/client.js.map +1 -0
  146. package/dist/tools/index.d.ts +8 -0
  147. package/dist/tools/index.d.ts.map +1 -0
  148. package/dist/tools/index.js +10 -0
  149. package/dist/tools/index.js.map +1 -0
  150. package/dist/tools/library-loader.d.ts +63 -0
  151. package/dist/tools/library-loader.d.ts.map +1 -0
  152. package/dist/tools/library-loader.js +292 -0
  153. package/dist/tools/library-loader.js.map +1 -0
  154. package/dist/tools/response-discovery.d.ts +72 -0
  155. package/dist/tools/response-discovery.d.ts.map +1 -0
  156. package/dist/tools/response-discovery.js +183 -0
  157. package/dist/tools/response-discovery.js.map +1 -0
  158. package/dist/tools/tool-coordinator.d.ts +76 -0
  159. package/dist/tools/tool-coordinator.d.ts.map +1 -0
  160. package/dist/tools/tool-coordinator.js +197 -0
  161. package/dist/tools/tool-coordinator.js.map +1 -0
  162. package/dist/tools/types.d.ts +427 -0
  163. package/dist/tools/types.d.ts.map +1 -0
  164. package/dist/tools/types.js +13 -0
  165. package/dist/tools/types.js.map +1 -0
  166. package/dist/tools/variant-resolver.d.ts +48 -0
  167. package/dist/tools/variant-resolver.d.ts.map +1 -0
  168. package/dist/tools/variant-resolver.js +214 -0
  169. package/dist/tools/variant-resolver.js.map +1 -0
  170. package/dist/types/events.d.ts +157 -0
  171. package/dist/types/events.d.ts.map +1 -0
  172. package/dist/types/events.js +11 -0
  173. package/dist/types/events.js.map +1 -0
  174. package/dist/utils/logger.d.ts +7 -0
  175. package/dist/utils/logger.d.ts.map +1 -0
  176. package/dist/utils/logger.js +11 -0
  177. package/dist/utils/logger.js.map +1 -0
  178. package/package.json +71 -0
  179. package/src/README.md +626 -0
  180. package/src/components/QuestionToolBar.svelte +406 -0
  181. package/src/player/AssessmentLayout.svelte +68 -0
  182. package/src/player/README.md +154 -0
  183. package/src/reference-layout/README.md +135 -0
  184. package/src/reference-layout/ReferenceLayout.svelte +209 -0
  185. package/src/reference-layout/components/AssessmentContent.svelte +259 -0
  186. package/src/reference-layout/components/AssessmentFooter.svelte +89 -0
  187. package/src/reference-layout/components/AssessmentHeader.svelte +250 -0
  188. package/src/reference-layout/components/AssessmentNavigation.svelte +134 -0
  189. package/src/reference-layout/components/AssessmentToolsBar.svelte +176 -0
  190. package/src/reference-layout/components/ItemPanel.svelte +200 -0
  191. package/src/reference-layout/components/NotesPanel.svelte +179 -0
  192. package/src/reference-layout/components/PassagePanel.svelte +76 -0
  193. package/src/tools/README.md +616 -0
  194. package/src/tools/calculators/README.md +395 -0
@@ -0,0 +1,127 @@
1
+ /**
2
+ * PNP Tool Resolver
3
+ *
4
+ * Resolves tool availability from QTI 3.0 Personal Needs Profile (PNP) and
5
+ * assessment settings. Implements precedence hierarchy for tool configuration.
6
+ *
7
+ * Precedence (highest to lowest):
8
+ * 1. District block (absolute veto)
9
+ * 2. Test administration override
10
+ * 3. Item restriction (per-item block)
11
+ * 4. Item requirement (forces enable)
12
+ * 5. District requirement
13
+ * 6. PNP supports (student needs)
14
+ *
15
+ * Part of PIE Assessment Toolkit.
16
+ */
17
+ import type { AssessmentEntity, AssessmentItemRef } from "@pie-players/pie-players-shared/types";
18
+ /**
19
+ * Resolved tool configuration with source tracking
20
+ */
21
+ export interface ResolvedToolConfig {
22
+ id: string;
23
+ enabled: boolean;
24
+ required?: boolean;
25
+ alwaysAvailable?: boolean;
26
+ settings?: any;
27
+ source: "district" | "item" | "pnp" | "settings";
28
+ }
29
+ /**
30
+ * Resolves tool availability from QTI 3.0 assessment structure
31
+ */
32
+ export declare class PNPToolResolver {
33
+ /**
34
+ * Resolve all tools from QTI 3.0 assessment + optional item context
35
+ *
36
+ * @param assessment QTI 3.0 assessment with personalNeedsProfile
37
+ * @param currentItemRef Current item for item-specific requirements (optional)
38
+ * @returns Array of resolved tool configurations
39
+ *
40
+ * @example
41
+ * const resolver = new PNPToolResolver();
42
+ * const tools = resolver.resolveTools(assessment, itemRef);
43
+ * tools.forEach(tool => {
44
+ * console.log(`${tool.id}: ${tool.enabled ? 'enabled' : 'disabled'}`);
45
+ * });
46
+ */
47
+ resolveTools(assessment: AssessmentEntity, currentItemRef?: AssessmentItemRef): ResolvedToolConfig[];
48
+ /**
49
+ * Resolve availability of a single PNP support
50
+ *
51
+ * Applies precedence rules to determine if support should be enabled.
52
+ *
53
+ * @param supportId PNP support identifier
54
+ * @param context Resolution context with all configuration sources
55
+ * @returns Resolved config or null if blocked/disabled
56
+ */
57
+ private resolveSupport;
58
+ /**
59
+ * Build resolved tool configuration
60
+ *
61
+ * Maps PNP support ID to PIE tool ID and merges tool-specific settings.
62
+ *
63
+ * @param supportId PNP support identifier
64
+ * @param context Resolution context for settings lookup
65
+ * @param flags Availability flags (required, alwaysAvailable, source)
66
+ * @returns Complete resolved tool configuration
67
+ */
68
+ private buildToolConfig;
69
+ /**
70
+ * Check if a specific tool is enabled
71
+ *
72
+ * @param toolId PIE tool identifier (e.g., 'pie-tool-calculator')
73
+ * @param assessment Assessment with PNP
74
+ * @param itemRef Optional item context
75
+ * @returns true if tool is enabled
76
+ */
77
+ isToolEnabled(toolId: string, assessment: AssessmentEntity, itemRef?: AssessmentItemRef): boolean;
78
+ /**
79
+ * Check if a tool is required (cannot be disabled)
80
+ *
81
+ * @param toolId PIE tool identifier
82
+ * @param assessment Assessment with PNP
83
+ * @param itemRef Optional item context
84
+ * @returns true if tool is required or always available
85
+ */
86
+ isToolRequired(toolId: string, assessment: AssessmentEntity, itemRef?: AssessmentItemRef): boolean;
87
+ /**
88
+ * Get list of auto-activate tools from PNP
89
+ *
90
+ * Returns PIE tool IDs that should be automatically opened/activated
91
+ * when the assessment starts, based on PNP activateAtInit field.
92
+ *
93
+ * @param assessment Assessment with PNP
94
+ * @returns Array of PIE tool IDs to auto-activate
95
+ *
96
+ * @example
97
+ * const autoActivate = resolver.getAutoActivateTools(assessment);
98
+ * // Returns: ['pie-tool-text-to-speech', 'pie-tool-line-reader']
99
+ */
100
+ getAutoActivateTools(assessment: AssessmentEntity): string[];
101
+ /**
102
+ * Get all enabled tools
103
+ *
104
+ * @param assessment Assessment with PNP
105
+ * @param itemRef Optional item context
106
+ * @returns Array of PIE tool IDs that are enabled
107
+ */
108
+ getEnabledTools(assessment: AssessmentEntity, itemRef?: AssessmentItemRef): string[];
109
+ /**
110
+ * Get all required tools
111
+ *
112
+ * @param assessment Assessment with PNP
113
+ * @param itemRef Optional item context
114
+ * @returns Array of PIE tool IDs that are required
115
+ */
116
+ getRequiredTools(assessment: AssessmentEntity, itemRef?: AssessmentItemRef): string[];
117
+ /**
118
+ * Get tool configuration settings
119
+ *
120
+ * @param toolId PIE tool identifier
121
+ * @param assessment Assessment with PNP
122
+ * @param itemRef Optional item context
123
+ * @returns Tool-specific settings or null if not found
124
+ */
125
+ getToolSettings(toolId: string, assessment: AssessmentEntity, itemRef?: AssessmentItemRef): any | null;
126
+ }
127
+ //# sourceMappingURL=PNPToolResolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PNPToolResolver.d.ts","sourceRoot":"","sources":["../../src/services/PNPToolResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EACX,gBAAgB,EAChB,iBAAiB,EAIjB,MAAM,uCAAuC,CAAC;AAG/C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,KAAK,GAAG,UAAU,CAAC;CACjD;AAaD;;GAEG;AACH,qBAAa,eAAe;IAC3B;;;;;;;;;;;;;OAaG;IACH,YAAY,CACX,UAAU,EAAE,gBAAgB,EAC5B,cAAc,CAAC,EAAE,iBAAiB,GAChC,kBAAkB,EAAE;IAgCvB;;;;;;;;OAQG;IACH,OAAO,CAAC,cAAc;IAsDtB;;;;;;;;;OASG;IACH,OAAO,CAAC,eAAe;IA2BvB;;;;;;;OAOG;IACH,aAAa,CACZ,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,gBAAgB,EAC5B,OAAO,CAAC,EAAE,iBAAiB,GACzB,OAAO;IAKV;;;;;;;OAOG;IACH,cAAc,CACb,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,gBAAgB,EAC5B,OAAO,CAAC,EAAE,iBAAiB,GACzB,OAAO;IAMV;;;;;;;;;;;;OAYG;IACH,oBAAoB,CAAC,UAAU,EAAE,gBAAgB,GAAG,MAAM,EAAE;IAS5D;;;;;;OAMG;IACH,eAAe,CACd,UAAU,EAAE,gBAAgB,EAC5B,OAAO,CAAC,EAAE,iBAAiB,GACzB,MAAM,EAAE;IAKX;;;;;;OAMG;IACH,gBAAgB,CACf,UAAU,EAAE,gBAAgB,EAC5B,OAAO,CAAC,EAAE,iBAAiB,GACzB,MAAM,EAAE;IAOX;;;;;;;OAOG;IACH,eAAe,CACd,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,gBAAgB,EAC5B,OAAO,CAAC,EAAE,iBAAiB,GACzB,GAAG,GAAG,IAAI;CAKb"}
@@ -0,0 +1,222 @@
1
+ /**
2
+ * PNP Tool Resolver
3
+ *
4
+ * Resolves tool availability from QTI 3.0 Personal Needs Profile (PNP) and
5
+ * assessment settings. Implements precedence hierarchy for tool configuration.
6
+ *
7
+ * Precedence (highest to lowest):
8
+ * 1. District block (absolute veto)
9
+ * 2. Test administration override
10
+ * 3. Item restriction (per-item block)
11
+ * 4. Item requirement (forces enable)
12
+ * 5. District requirement
13
+ * 6. PNP supports (student needs)
14
+ *
15
+ * Part of PIE Assessment Toolkit.
16
+ */
17
+ import { mapPNPSupportToToolId } from "./PNPMapper";
18
+ /**
19
+ * Resolves tool availability from QTI 3.0 assessment structure
20
+ */
21
+ export class PNPToolResolver {
22
+ /**
23
+ * Resolve all tools from QTI 3.0 assessment + optional item context
24
+ *
25
+ * @param assessment QTI 3.0 assessment with personalNeedsProfile
26
+ * @param currentItemRef Current item for item-specific requirements (optional)
27
+ * @returns Array of resolved tool configurations
28
+ *
29
+ * @example
30
+ * const resolver = new PNPToolResolver();
31
+ * const tools = resolver.resolveTools(assessment, itemRef);
32
+ * tools.forEach(tool => {
33
+ * console.log(`${tool.id}: ${tool.enabled ? 'enabled' : 'disabled'}`);
34
+ * });
35
+ */
36
+ resolveTools(assessment, currentItemRef) {
37
+ const pnp = assessment.personalNeedsProfile;
38
+ const settings = assessment.settings;
39
+ const itemSettings = currentItemRef?.settings;
40
+ // Collect all PNP support IDs mentioned anywhere
41
+ const allSupports = new Set();
42
+ pnp?.supports?.forEach((s) => allSupports.add(s));
43
+ settings?.districtPolicy?.blockedTools?.forEach((s) => allSupports.add(s));
44
+ settings?.districtPolicy?.requiredTools?.forEach((s) => allSupports.add(s));
45
+ itemSettings?.requiredTools?.forEach((s) => allSupports.add(s));
46
+ itemSettings?.restrictedTools?.forEach((s) => allSupports.add(s));
47
+ const resolved = [];
48
+ for (const supportId of allSupports) {
49
+ const config = this.resolveSupport(supportId, {
50
+ pnp,
51
+ districtPolicy: settings?.districtPolicy,
52
+ testAdmin: settings?.testAdministration,
53
+ itemSettings,
54
+ toolConfigs: settings?.toolConfigs,
55
+ });
56
+ if (config) {
57
+ resolved.push(config);
58
+ }
59
+ }
60
+ return resolved;
61
+ }
62
+ /**
63
+ * Resolve availability of a single PNP support
64
+ *
65
+ * Applies precedence rules to determine if support should be enabled.
66
+ *
67
+ * @param supportId PNP support identifier
68
+ * @param context Resolution context with all configuration sources
69
+ * @returns Resolved config or null if blocked/disabled
70
+ */
71
+ resolveSupport(supportId, context) {
72
+ // Precedence (highest to lowest):
73
+ // 1. District block (absolute veto)
74
+ if (context.districtPolicy?.blockedTools?.includes(supportId)) {
75
+ return null; // Blocked
76
+ }
77
+ // 2. Test administration override
78
+ if (context.testAdmin?.toolOverrides?.[supportId] === false) {
79
+ return null; // Blocked
80
+ }
81
+ // 3. Item restriction
82
+ if (context.itemSettings?.restrictedTools?.includes(supportId)) {
83
+ return null; // Blocked for this item
84
+ }
85
+ // 4. Item requirement (forces enable)
86
+ if (context.itemSettings?.requiredTools?.includes(supportId)) {
87
+ return this.buildToolConfig(supportId, context, {
88
+ required: true,
89
+ source: "item",
90
+ });
91
+ }
92
+ // 5. District requirement
93
+ if (context.districtPolicy?.requiredTools?.includes(supportId)) {
94
+ return this.buildToolConfig(supportId, context, {
95
+ required: true,
96
+ source: "district",
97
+ });
98
+ }
99
+ // 6. PNP supports (student needs)
100
+ if (context.pnp?.supports?.includes(supportId)) {
101
+ // Check if prohibited
102
+ const isProhibited = context.pnp.prohibitedSupports?.includes(supportId);
103
+ if (!isProhibited) {
104
+ return this.buildToolConfig(supportId, context, {
105
+ alwaysAvailable: true,
106
+ source: "pnp",
107
+ });
108
+ }
109
+ }
110
+ // Not enabled
111
+ return null;
112
+ }
113
+ /**
114
+ * Build resolved tool configuration
115
+ *
116
+ * Maps PNP support ID to PIE tool ID and merges tool-specific settings.
117
+ *
118
+ * @param supportId PNP support identifier
119
+ * @param context Resolution context for settings lookup
120
+ * @param flags Availability flags (required, alwaysAvailable, source)
121
+ * @returns Complete resolved tool configuration
122
+ */
123
+ buildToolConfig(supportId, context, flags) {
124
+ // Map PNP support ID to PIE tool ID
125
+ const pieToolId = mapPNPSupportToToolId(supportId) || supportId;
126
+ // Get tool-specific config from settings (item takes precedence)
127
+ const toolConfig = context.itemSettings?.toolParameters?.[supportId] ||
128
+ context.toolConfigs?.[supportId];
129
+ return {
130
+ id: pieToolId,
131
+ enabled: true,
132
+ required: flags.required || false,
133
+ alwaysAvailable: flags.alwaysAvailable || false,
134
+ settings: toolConfig,
135
+ source: flags.source,
136
+ };
137
+ }
138
+ /**
139
+ * Check if a specific tool is enabled
140
+ *
141
+ * @param toolId PIE tool identifier (e.g., 'pie-tool-calculator')
142
+ * @param assessment Assessment with PNP
143
+ * @param itemRef Optional item context
144
+ * @returns true if tool is enabled
145
+ */
146
+ isToolEnabled(toolId, assessment, itemRef) {
147
+ const resolved = this.resolveTools(assessment, itemRef);
148
+ return resolved.some((t) => t.id === toolId && t.enabled);
149
+ }
150
+ /**
151
+ * Check if a tool is required (cannot be disabled)
152
+ *
153
+ * @param toolId PIE tool identifier
154
+ * @param assessment Assessment with PNP
155
+ * @param itemRef Optional item context
156
+ * @returns true if tool is required or always available
157
+ */
158
+ isToolRequired(toolId, assessment, itemRef) {
159
+ const resolved = this.resolveTools(assessment, itemRef);
160
+ const tool = resolved.find((t) => t.id === toolId);
161
+ return tool?.required || tool?.alwaysAvailable || false;
162
+ }
163
+ /**
164
+ * Get list of auto-activate tools from PNP
165
+ *
166
+ * Returns PIE tool IDs that should be automatically opened/activated
167
+ * when the assessment starts, based on PNP activateAtInit field.
168
+ *
169
+ * @param assessment Assessment with PNP
170
+ * @returns Array of PIE tool IDs to auto-activate
171
+ *
172
+ * @example
173
+ * const autoActivate = resolver.getAutoActivateTools(assessment);
174
+ * // Returns: ['pie-tool-text-to-speech', 'pie-tool-line-reader']
175
+ */
176
+ getAutoActivateTools(assessment) {
177
+ const pnp = assessment.personalNeedsProfile;
178
+ if (!pnp?.activateAtInit)
179
+ return [];
180
+ return pnp.activateAtInit
181
+ .map((supportId) => mapPNPSupportToToolId(supportId))
182
+ .filter(Boolean);
183
+ }
184
+ /**
185
+ * Get all enabled tools
186
+ *
187
+ * @param assessment Assessment with PNP
188
+ * @param itemRef Optional item context
189
+ * @returns Array of PIE tool IDs that are enabled
190
+ */
191
+ getEnabledTools(assessment, itemRef) {
192
+ const resolved = this.resolveTools(assessment, itemRef);
193
+ return resolved.filter((t) => t.enabled).map((t) => t.id);
194
+ }
195
+ /**
196
+ * Get all required tools
197
+ *
198
+ * @param assessment Assessment with PNP
199
+ * @param itemRef Optional item context
200
+ * @returns Array of PIE tool IDs that are required
201
+ */
202
+ getRequiredTools(assessment, itemRef) {
203
+ const resolved = this.resolveTools(assessment, itemRef);
204
+ return resolved
205
+ .filter((t) => t.required || t.alwaysAvailable)
206
+ .map((t) => t.id);
207
+ }
208
+ /**
209
+ * Get tool configuration settings
210
+ *
211
+ * @param toolId PIE tool identifier
212
+ * @param assessment Assessment with PNP
213
+ * @param itemRef Optional item context
214
+ * @returns Tool-specific settings or null if not found
215
+ */
216
+ getToolSettings(toolId, assessment, itemRef) {
217
+ const resolved = this.resolveTools(assessment, itemRef);
218
+ const tool = resolved.find((t) => t.id === toolId);
219
+ return tool?.settings || null;
220
+ }
221
+ }
222
+ //# sourceMappingURL=PNPToolResolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PNPToolResolver.js","sourceRoot":"","sources":["../../src/services/PNPToolResolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * SSMLExtractor
3
+ *
4
+ * Service for extracting embedded SSML from PIE item content and converting
5
+ * it into QTI 3.0 accessibility catalogs.
6
+ *
7
+ * Authors can embed <speak> SSML tags directly in content for convenience.
8
+ * The extractor automatically:
9
+ * 1. Parses markup and finds all <speak> elements
10
+ * 2. Extracts SSML content with language metadata
11
+ * 3. Generates accessibility catalogs with unique IDs
12
+ * 4. Cleans visual markup (removes SSML, adds data-catalog-id)
13
+ *
14
+ * This enables proper pronunciation, emphasis, and pacing for TTS without
15
+ * requiring authors to maintain separate catalog files.
16
+ *
17
+ * Part of PIE Assessment Toolkit.
18
+ */
19
+ import type { AccessibilityCatalog, ConfigEntity } from "@pie-players/pie-players-shared/types";
20
+ /**
21
+ * Result from extracting SSML from entire item config
22
+ */
23
+ export interface ExtractionResult {
24
+ catalogs: AccessibilityCatalog[];
25
+ cleanedConfig: ConfigEntity;
26
+ }
27
+ /**
28
+ * SSMLExtractor Service
29
+ *
30
+ * Extracts embedded SSML from PIE content and generates accessibility catalogs.
31
+ */
32
+ export declare class SSMLExtractor {
33
+ private catalogCounter;
34
+ /**
35
+ * Extract SSML from entire item config (markup + models)
36
+ *
37
+ * @param config Item configuration with potential embedded SSML
38
+ * @returns Extracted catalogs and cleaned config
39
+ */
40
+ extractFromItemConfig(config: ConfigEntity): ExtractionResult;
41
+ /**
42
+ * Extract SSML from markup string
43
+ *
44
+ * @param markup HTML markup potentially containing <speak> elements
45
+ * @param idPrefix Prefix for generating catalog IDs
46
+ * @returns Extracted catalogs and cleaned markup
47
+ */
48
+ private extractFromMarkup;
49
+ /**
50
+ * Generate unique catalog ID
51
+ *
52
+ * @param prefix Context prefix (e.g., 'prompt-q1', 'choice-q1-a')
53
+ * @returns Unique catalog ID (e.g., 'auto-prompt-q1-0')
54
+ */
55
+ private generateCatalogId;
56
+ /**
57
+ * Reset counter (useful for testing or new extraction contexts)
58
+ */
59
+ reset(): void;
60
+ }
61
+ //# sourceMappingURL=SSMLExtractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SSMLExtractor.d.ts","sourceRoot":"","sources":["../../src/services/SSMLExtractor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EACX,oBAAoB,EACpB,YAAY,EAEZ,MAAM,uCAAuC,CAAC;AAU/C;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,QAAQ,EAAE,oBAAoB,EAAE,CAAC;IACjC,aAAa,EAAE,YAAY,CAAC;CAC5B;AAED;;;;GAIG;AACH,qBAAa,aAAa;IACzB,OAAO,CAAC,cAAc,CAAK;IAE3B;;;;;OAKG;IACH,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,gBAAgB;IA6D7D;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IAmGzB;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IAMzB;;OAEG;IACH,KAAK,IAAI,IAAI;CAGb"}
@@ -0,0 +1,181 @@
1
+ /**
2
+ * SSMLExtractor
3
+ *
4
+ * Service for extracting embedded SSML from PIE item content and converting
5
+ * it into QTI 3.0 accessibility catalogs.
6
+ *
7
+ * Authors can embed <speak> SSML tags directly in content for convenience.
8
+ * The extractor automatically:
9
+ * 1. Parses markup and finds all <speak> elements
10
+ * 2. Extracts SSML content with language metadata
11
+ * 3. Generates accessibility catalogs with unique IDs
12
+ * 4. Cleans visual markup (removes SSML, adds data-catalog-id)
13
+ *
14
+ * This enables proper pronunciation, emphasis, and pacing for TTS without
15
+ * requiring authors to maintain separate catalog files.
16
+ *
17
+ * Part of PIE Assessment Toolkit.
18
+ */
19
+ /**
20
+ * SSMLExtractor Service
21
+ *
22
+ * Extracts embedded SSML from PIE content and generates accessibility catalogs.
23
+ */
24
+ export class SSMLExtractor {
25
+ catalogCounter = 0;
26
+ /**
27
+ * Extract SSML from entire item config (markup + models)
28
+ *
29
+ * @param config Item configuration with potential embedded SSML
30
+ * @returns Extracted catalogs and cleaned config
31
+ */
32
+ extractFromItemConfig(config) {
33
+ const allCatalogs = [];
34
+ // Deep clone config to avoid mutating original
35
+ const cleanedConfig = {
36
+ ...config,
37
+ models: config.models ? [...config.models] : [],
38
+ };
39
+ // 1. Extract from top-level markup (passages)
40
+ if (config.markup) {
41
+ const markupResult = this.extractFromMarkup(config.markup, "markup");
42
+ allCatalogs.push(...markupResult.catalogs);
43
+ cleanedConfig.markup = markupResult.cleanedMarkup;
44
+ }
45
+ // 2. Extract from models (prompts, choices, etc.)
46
+ if (config.models && config.models.length > 0) {
47
+ cleanedConfig.models = config.models.map((model) => {
48
+ const cleanedModel = { ...model };
49
+ const modelCatalogs = [];
50
+ // Extract from prompt
51
+ if (model.prompt && typeof model.prompt === "string") {
52
+ const promptResult = this.extractFromMarkup(model.prompt, `prompt-${model.id}`);
53
+ modelCatalogs.push(...promptResult.catalogs);
54
+ cleanedModel.prompt = promptResult.cleanedMarkup;
55
+ }
56
+ // Extract from choices
57
+ if (model.choices && Array.isArray(model.choices)) {
58
+ cleanedModel.choices = model.choices.map((choice) => {
59
+ if (choice.label && typeof choice.label === "string") {
60
+ const choiceResult = this.extractFromMarkup(choice.label, `choice-${model.id}-${choice.value}`);
61
+ modelCatalogs.push(...choiceResult.catalogs);
62
+ return {
63
+ ...choice,
64
+ label: choiceResult.cleanedMarkup,
65
+ };
66
+ }
67
+ return choice;
68
+ });
69
+ }
70
+ allCatalogs.push(...modelCatalogs);
71
+ return cleanedModel;
72
+ });
73
+ }
74
+ return {
75
+ catalogs: allCatalogs,
76
+ cleanedConfig,
77
+ };
78
+ }
79
+ /**
80
+ * Extract SSML from markup string
81
+ *
82
+ * @param markup HTML markup potentially containing <speak> elements
83
+ * @param idPrefix Prefix for generating catalog IDs
84
+ * @returns Extracted catalogs and cleaned markup
85
+ */
86
+ extractFromMarkup(markup, idPrefix) {
87
+ if (!markup || markup.trim() === "") {
88
+ return { catalogs: [], cleanedMarkup: markup };
89
+ }
90
+ // Check if running in browser environment
91
+ if (typeof window === "undefined" || typeof DOMParser === "undefined") {
92
+ console.warn("[SSMLExtractor] DOMParser not available (SSR?), skipping extraction");
93
+ return { catalogs: [], cleanedMarkup: markup };
94
+ }
95
+ const catalogs = [];
96
+ try {
97
+ const parser = new DOMParser();
98
+ const doc = parser.parseFromString(markup, "text/html");
99
+ // Find all <speak> elements
100
+ const speakElements = Array.from(doc.querySelectorAll("speak"));
101
+ if (speakElements.length === 0) {
102
+ // No SSML found, return original markup
103
+ return { catalogs: [], cleanedMarkup: markup };
104
+ }
105
+ // Process each <speak> element
106
+ for (const speakEl of speakElements) {
107
+ try {
108
+ // Generate unique catalog ID
109
+ const catalogId = this.generateCatalogId(idPrefix);
110
+ // Extract SSML content
111
+ const ssmlContent = speakEl.outerHTML;
112
+ // Extract language (check both xml:lang and lang attributes)
113
+ const language = speakEl.getAttribute("xml:lang") ||
114
+ speakEl.getAttribute("lang") ||
115
+ "en-US";
116
+ // Get plain text for visual display
117
+ const plainText = speakEl.textContent || "";
118
+ // Find parent element or create wrapper
119
+ let wrapper = speakEl.parentElement;
120
+ if (!wrapper || wrapper.tagName === "BODY") {
121
+ // SPEAK is at root level - create span wrapper
122
+ const span = doc.createElement("span");
123
+ speakEl.parentNode?.insertBefore(span, speakEl);
124
+ span.appendChild(doc.createTextNode(plainText));
125
+ wrapper = span;
126
+ speakEl.remove();
127
+ }
128
+ else {
129
+ // Just remove <speak> - visual content should be in sibling element
130
+ speakEl.remove();
131
+ }
132
+ // Add catalog ID to wrapper element
133
+ if (wrapper) {
134
+ wrapper.setAttribute("data-catalog-id", catalogId);
135
+ }
136
+ // Create catalog entry
137
+ catalogs.push({
138
+ identifier: catalogId,
139
+ cards: [
140
+ {
141
+ catalog: "spoken",
142
+ language,
143
+ content: ssmlContent,
144
+ },
145
+ ],
146
+ });
147
+ }
148
+ catch (error) {
149
+ console.error("[SSMLExtractor] Error processing <speak> element:", error);
150
+ // Continue with other elements
151
+ }
152
+ }
153
+ // Return cleaned markup
154
+ const cleanedMarkup = doc.body.innerHTML;
155
+ return { catalogs, cleanedMarkup };
156
+ }
157
+ catch (error) {
158
+ console.error("[SSMLExtractor] Error parsing markup:", error);
159
+ // Return original markup if parsing fails
160
+ return { catalogs: [], cleanedMarkup: markup };
161
+ }
162
+ }
163
+ /**
164
+ * Generate unique catalog ID
165
+ *
166
+ * @param prefix Context prefix (e.g., 'prompt-q1', 'choice-q1-a')
167
+ * @returns Unique catalog ID (e.g., 'auto-prompt-q1-0')
168
+ */
169
+ generateCatalogId(prefix) {
170
+ const id = `auto-${prefix}-${this.catalogCounter}`;
171
+ this.catalogCounter++;
172
+ return id;
173
+ }
174
+ /**
175
+ * Reset counter (useful for testing or new extraction contexts)
176
+ */
177
+ reset() {
178
+ this.catalogCounter = 0;
179
+ }
180
+ }
181
+ //# sourceMappingURL=SSMLExtractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SSMLExtractor.js","sourceRoot":"","sources":["../../src/services/SSMLExtractor.ts"],"names":[],"mappings":"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"}