@pie-players/pie-assessment-toolkit 0.3.73 → 0.3.75

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 (274) hide show
  1. package/README.md +469 -318
  2. package/dist/attempt/AssessmentSession.d.ts +1 -5
  3. package/dist/attempt/AssessmentSession.js +0 -29
  4. package/dist/attempt/TestSession.d.ts +1 -20
  5. package/dist/attempt/TestSession.js +8 -99
  6. package/dist/components/ItemScope.custom-element.d.ts +1 -0
  7. package/dist/components/ItemScope.custom-element.js +1 -0
  8. package/dist/components/ItemToolBar.custom-element.d.ts +1 -0
  9. package/dist/components/ItemToolBar.custom-element.js +1 -1
  10. package/dist/components/PieAssessmentToolkit.custom-element.d.ts +1 -0
  11. package/dist/components/PieAssessmentToolkit.custom-element.js +13 -13
  12. package/dist/components/SectionToolBar.custom-element.d.ts +1 -0
  13. package/dist/components/SectionToolBar.custom-element.js +1 -1
  14. package/dist/components/chunks/ItemToolBar-7tt7v2xp.js +4 -0
  15. package/dist/components/chunks/ItemToolBar-97hx60z4.js +2 -0
  16. package/dist/components/chunks/ItemToolBar-bxwyhr5p.js +2 -0
  17. package/dist/components/chunks/ItemToolBar-jx38w99s.js +2 -0
  18. package/dist/components/chunks/ItemToolBar-rd2bb4p6.js +40 -0
  19. package/dist/components/chunks/ItemToolBar-vdkyn9f3.js +2 -0
  20. package/dist/components/chunks/sre-engine-jd8cc08x.js +1 -0
  21. package/dist/components/item-scope-element.d.ts +2 -0
  22. package/dist/components/item-scope-element.js +2 -0
  23. package/dist/context/assessment-toolkit-context.d.ts +32 -6
  24. package/dist/index.d.ts +23 -48
  25. package/dist/index.js +12 -37
  26. package/dist/policy/core/PolicySource.d.ts +1 -1
  27. package/dist/policy/core/ToolPolicyEngine.d.ts +85 -34
  28. package/dist/policy/core/ToolPolicyEngine.js +148 -46
  29. package/dist/policy/core/compose-decision.d.ts +28 -7
  30. package/dist/policy/core/compose-decision.js +75 -54
  31. package/dist/policy/core/decision-types.d.ts +65 -34
  32. package/dist/policy/core/feature-decision.d.ts +16 -9
  33. package/dist/policy/core/feature-decision.js +14 -8
  34. package/dist/policy/core/pnp-policy-inputs.d.ts +24 -33
  35. package/dist/policy/core/pnp-policy-inputs.js +28 -56
  36. package/dist/policy/core/provenance.d.ts +9 -4
  37. package/dist/policy/core/provenance.js +1 -1
  38. package/dist/policy/engine.d.ts +7 -23
  39. package/dist/policy/engine.js +5 -20
  40. package/dist/policy/sources/PnpPolicySource.d.ts +44 -61
  41. package/dist/policy/sources/PnpPolicySource.js +117 -118
  42. package/dist/runtime/SectionControllerBinding.d.ts +279 -0
  43. package/dist/runtime/SectionControllerBinding.js +450 -0
  44. package/dist/runtime/SectionRuntimeEngine.d.ts +26 -289
  45. package/dist/runtime/SectionRuntimeEngine.js +30 -372
  46. package/dist/runtime/adapter/SectionEngineAdapter.d.ts +19 -80
  47. package/dist/runtime/adapter/SectionEngineAdapter.js +19 -92
  48. package/dist/runtime/adapter/dom-event-bridge.d.ts +15 -30
  49. package/dist/runtime/adapter/dom-event-bridge.js +17 -44
  50. package/dist/runtime/adapter/subscriber-fanout.d.ts +1 -2
  51. package/dist/runtime/adapter/subscriber-fanout.js +1 -2
  52. package/dist/runtime/catalog-context.d.ts +19 -0
  53. package/dist/runtime/catalog-context.js +28 -0
  54. package/dist/runtime/composition-emit-scheduler.d.ts +9 -15
  55. package/dist/runtime/composition-emit-scheduler.js +9 -15
  56. package/dist/runtime/content-language.d.ts +32 -0
  57. package/dist/runtime/content-language.js +46 -0
  58. package/dist/runtime/content-region.d.ts +17 -0
  59. package/dist/runtime/content-region.js +29 -0
  60. package/dist/runtime/content-registration.d.ts +13 -0
  61. package/dist/runtime/content-registration.js +25 -0
  62. package/dist/runtime/core/SectionEngineCore.d.ts +2 -2
  63. package/dist/runtime/core/SectionEngineCore.js +2 -2
  64. package/dist/runtime/core/cohort.d.ts +1 -1
  65. package/dist/runtime/core/cohort.js +1 -1
  66. package/dist/runtime/core/engine-input.d.ts +18 -30
  67. package/dist/runtime/core/engine-input.js +11 -12
  68. package/dist/runtime/core/engine-output.d.ts +16 -40
  69. package/dist/runtime/core/engine-output.js +9 -21
  70. package/dist/runtime/core/engine-readiness.d.ts +5 -37
  71. package/dist/runtime/core/engine-readiness.js +8 -41
  72. package/dist/runtime/core/engine-resolver.d.ts +46 -74
  73. package/dist/runtime/core/engine-resolver.js +18 -43
  74. package/dist/runtime/core/engine-state.d.ts +28 -36
  75. package/dist/runtime/core/engine-state.js +18 -21
  76. package/dist/runtime/core/engine-transition.d.ts +14 -19
  77. package/dist/runtime/core/engine-transition.js +71 -51
  78. package/dist/runtime/engine.d.ts +16 -19
  79. package/dist/runtime/engine.js +12 -19
  80. package/dist/runtime/page-warnings.d.ts +13 -0
  81. package/dist/runtime/page-warnings.js +22 -0
  82. package/dist/runtime/policy-input-forwarding.d.ts +25 -0
  83. package/dist/runtime/policy-input-forwarding.js +25 -0
  84. package/dist/runtime/registration-events.d.ts +14 -0
  85. package/dist/runtime/runtime-event-claim.d.ts +8 -0
  86. package/dist/runtime/runtime-event-claim.js +15 -0
  87. package/dist/runtime/shell-event-bridge.d.ts +45 -0
  88. package/dist/runtime/shell-event-bridge.js +127 -0
  89. package/dist/runtime/shell-registration.d.ts +73 -0
  90. package/dist/runtime/shell-registration.js +95 -0
  91. package/dist/runtime/shell-scope.d.ts +68 -0
  92. package/dist/runtime/shell-scope.js +188 -0
  93. package/dist/runtime/tool-host-contract.d.ts +28 -10
  94. package/dist/runtime/tool-host-contract.js +31 -10
  95. package/dist/runtime/unclaimed-registration-watch.d.ts +7 -0
  96. package/dist/runtime/unclaimed-registration-watch.js +23 -0
  97. package/dist/services/ElementToolStateStore.d.ts +14 -10
  98. package/dist/services/ElementToolStateStore.js +37 -13
  99. package/dist/services/HighlightCoordinator.d.ts +22 -28
  100. package/dist/services/HighlightCoordinator.js +431 -327
  101. package/dist/services/RangeSerializer.d.ts +10 -1
  102. package/dist/services/RangeSerializer.js +87 -14
  103. package/dist/services/TTSService.d.ts +130 -69
  104. package/dist/services/TTSService.js +713 -570
  105. package/dist/services/ToolCoordinator.d.ts +43 -66
  106. package/dist/services/ToolCoordinator.js +164 -208
  107. package/dist/services/ToolRegistry.d.ts +78 -54
  108. package/dist/services/ToolRegistry.js +107 -105
  109. package/dist/services/ToolkitCoordinator.d.ts +261 -175
  110. package/dist/services/ToolkitCoordinator.js +667 -433
  111. package/dist/services/audio-handoff.d.ts +6 -7
  112. package/dist/services/audio-handoff.js +20 -14
  113. package/dist/services/catalog-owner.d.ts +11 -1
  114. package/dist/services/catalog-owner.js +25 -0
  115. package/dist/services/create-tools-config.d.ts +2 -2
  116. package/dist/services/framework-error-bus.d.ts +3 -6
  117. package/dist/services/framework-error-bus.js +3 -6
  118. package/dist/services/framework-error.d.ts +30 -8
  119. package/dist/services/framework-error.js +9 -7
  120. package/dist/services/interfaces.d.ts +158 -129
  121. package/dist/services/section-controller-types.d.ts +15 -0
  122. package/dist/services/section-session-assignment.d.ts +21 -0
  123. package/dist/services/section-session-assignment.js +82 -0
  124. package/dist/services/spoken-audio-cards.d.ts +0 -2
  125. package/dist/services/spoken-audio-cards.js +1 -3
  126. package/dist/services/tool-config-defaults.d.ts +3 -3
  127. package/dist/services/tool-config-defaults.js +3 -3
  128. package/dist/services/tool-config-validation.d.ts +14 -4
  129. package/dist/services/tool-config-validation.js +63 -71
  130. package/dist/services/tool-context.d.ts +0 -8
  131. package/dist/services/tool-context.js +29 -25
  132. package/dist/services/tool-icons.d.ts +4 -3
  133. package/dist/services/tool-icons.js +4 -3
  134. package/dist/services/tool-instance-id.d.ts +0 -1
  135. package/dist/services/tool-instance-id.js +0 -6
  136. package/dist/services/tool-providers/TTSToolProvider.d.ts +41 -80
  137. package/dist/services/tool-providers/TTSToolProvider.js +81 -40
  138. package/dist/services/tool-providers/ToolProviderApi.d.ts +10 -4
  139. package/dist/services/tool-providers/ToolProviderRegistry.d.ts +32 -28
  140. package/dist/services/tool-providers/ToolProviderRegistry.js +121 -107
  141. package/dist/services/tool-providers/index.d.ts +0 -9
  142. package/dist/services/tool-providers/index.js +2 -4
  143. package/dist/services/tool-request.d.ts +27 -12
  144. package/dist/services/tool-request.js +24 -14
  145. package/dist/services/toolbar-decided-tools.d.ts +15 -0
  146. package/dist/services/toolbar-decided-tools.js +28 -0
  147. package/dist/services/tools-config-normalizer.d.ts +37 -23
  148. package/dist/services/tools-config-normalizer.js +2 -10
  149. package/dist/services/tts/browser-provider.d.ts +38 -2
  150. package/dist/services/tts/browser-provider.js +276 -140
  151. package/dist/services/tts/catalog-span-alignment.d.ts +2 -17
  152. package/dist/services/tts/catalog-span-alignment.js +17 -142
  153. package/dist/services/tts/flat-tree.d.ts +71 -0
  154. package/dist/services/tts/flat-tree.js +269 -0
  155. package/dist/services/tts/generated-speech/assemble-plan.d.ts +3 -1
  156. package/dist/services/tts/generated-speech/assemble-plan.js +3 -1
  157. package/dist/services/tts/generated-speech/dom/build-dom-plan.d.ts +2 -0
  158. package/dist/services/tts/generated-speech/dom/build-dom-plan.js +1 -1
  159. package/dist/services/tts/generated-speech/math-speech-cache.d.ts +3 -1
  160. package/dist/services/tts/generated-speech/math-speech-cache.js +5 -1
  161. package/dist/services/tts/generated-speech/types.d.ts +0 -12
  162. package/dist/services/tts/highlight-pipeline/boundary-normalizer.js +12 -62
  163. package/dist/services/tts/highlight-pipeline/create-highlight-plan.js +38 -5
  164. package/dist/services/tts/highlight-pipeline/normalize-speech-chunks.js +3 -6
  165. package/dist/services/tts/highlight-pipeline/prose-boundary-resolver.js +6 -4
  166. package/dist/services/tts/highlight-pipeline/readable-region.js +3 -2
  167. package/dist/services/tts/highlight-pipeline/types.d.ts +5 -0
  168. package/dist/services/tts/highlight-pipeline/visible-map-range.d.ts +12 -0
  169. package/dist/services/tts/highlight-pipeline/visible-map-range.js +73 -7
  170. package/dist/services/tts/math-alignment/index.d.ts +0 -5
  171. package/dist/services/tts/math-alignment/index.js +5 -25
  172. package/dist/services/tts/math-alignment/speech-tokenizer.d.ts +9 -1
  173. package/dist/services/tts/math-alignment/speech-tokenizer.js +38 -36
  174. package/dist/services/tts/math-alignment/types.d.ts +4 -2
  175. package/dist/services/tts/math-aware-text-processing.d.ts +5 -1
  176. package/dist/services/tts/math-aware-text-processing.js +74 -18
  177. package/dist/services/tts/math-control-names.d.ts +21 -0
  178. package/dist/services/tts/math-control-names.js +142 -0
  179. package/dist/services/tts/math-speech.d.ts +16 -1
  180. package/dist/services/tts/math-speech.js +55 -19
  181. package/dist/services/tts/provider-options.d.ts +41 -0
  182. package/dist/services/tts/provider-options.js +1 -0
  183. package/dist/services/tts/sre-engine.d.ts +7 -0
  184. package/dist/services/tts/sre-engine.js +11 -0
  185. package/dist/services/tts/sre-locales.d.ts +14 -0
  186. package/dist/services/tts/sre-locales.js +57 -0
  187. package/dist/services/tts/ssml/spoken-text.d.ts +2 -26
  188. package/dist/services/tts/ssml/spoken-text.js +29 -0
  189. package/dist/services/tts/start-failure.d.ts +11 -0
  190. package/dist/services/tts/start-failure.js +19 -0
  191. package/dist/services/tts/text-processing.d.ts +9 -1
  192. package/dist/services/tts/text-processing.js +46 -34
  193. package/dist/services/tts/text-segmentation.d.ts +7 -0
  194. package/dist/services/tts/text-segmentation.js +47 -0
  195. package/dist/services/tts-runtime-config.d.ts +44 -18
  196. package/dist/services/tts-runtime-config.js +22 -93
  197. package/dist/tools/content-capability-resolution.d.ts +7 -9
  198. package/dist/tools/content-capability-resolution.js +8 -45
  199. package/dist/tools/registration.d.ts +58 -0
  200. package/dist/tools/registration.js +54 -0
  201. package/dist/tools/registrations/toolbar-registration-helpers.js +2 -2
  202. package/dist/tools/tool-surface-host.d.ts +6 -10
  203. package/dist/tools/tool-surface-host.js +44 -42
  204. package/dist/tools/tool-tag-map.d.ts +5 -15
  205. package/dist/tools/tool-tag-map.js +6 -20
  206. package/dist/utils/structural-equality.d.ts +11 -0
  207. package/dist/utils/structural-equality.js +47 -0
  208. package/package.json +24 -59
  209. package/dist/attempt/adapters/activity-to-test-attempt-session.d.ts +0 -49
  210. package/dist/attempt/adapters/activity-to-test-attempt-session.js +0 -138
  211. package/dist/components/chunks/ItemToolBar-byq80z42.js +0 -40
  212. package/dist/components/chunks/ItemToolBar-d36g3aw4.js +0 -49
  213. package/dist/context/runtime-context-consumer.d.ts +0 -13
  214. package/dist/context/runtime-context-consumer.js +0 -51
  215. package/dist/item-loader.d.ts +0 -44
  216. package/dist/item-loader.js +0 -61
  217. package/dist/policy/core/engine-context.d.ts +0 -29
  218. package/dist/policy/core/engine-context.js +0 -27
  219. package/dist/policy/core/policy-source-tag.d.ts +0 -31
  220. package/dist/policy/core/policy-source-tag.js +0 -28
  221. package/dist/policy/internal.d.ts +0 -25
  222. package/dist/policy/internal.js +0 -25
  223. package/dist/runtime/adapter/coordinator-bridge.d.ts +0 -92
  224. package/dist/runtime/adapter/coordinator-bridge.js +0 -126
  225. package/dist/runtime/adapter/framework-error-bridge.d.ts +0 -36
  226. package/dist/runtime/adapter/framework-error-bridge.js +0 -46
  227. package/dist/runtime/adapter/instrumentation-bridge.d.ts +0 -31
  228. package/dist/runtime/adapter/instrumentation-bridge.js +0 -38
  229. package/dist/runtime/core/engine-stage-derivation.d.ts +0 -18
  230. package/dist/runtime/core/engine-stage-derivation.js +0 -29
  231. package/dist/runtime/engine-context.d.ts +0 -39
  232. package/dist/runtime/engine-context.js +0 -31
  233. package/dist/runtime/internal.d.ts +0 -43
  234. package/dist/runtime/internal.js +0 -45
  235. package/dist/runtime/section-runtime-engine-host-context.d.ts +0 -80
  236. package/dist/runtime/section-runtime-engine-host-context.js +0 -95
  237. package/dist/runtime/stage-emit-gate.d.ts +0 -92
  238. package/dist/runtime/stage-emit-gate.js +0 -82
  239. package/dist/services/I18nService.d.ts +0 -47
  240. package/dist/services/I18nService.js +0 -84
  241. package/dist/services/ThemeProvider.d.ts +0 -95
  242. package/dist/services/ThemeProvider.js +0 -334
  243. package/dist/services/ToolConfigResolver.d.ts +0 -161
  244. package/dist/services/ToolConfigResolver.js +0 -229
  245. package/dist/services/catalog-media.d.ts +0 -56
  246. package/dist/services/catalog-media.js +0 -190
  247. package/dist/services/createDefaultToolRegistry.d.ts +0 -53
  248. package/dist/services/createDefaultToolRegistry.js +0 -45
  249. package/dist/services/defaultPersonalNeedsProfile.d.ts +0 -21
  250. package/dist/services/defaultPersonalNeedsProfile.js +0 -26
  251. package/dist/services/pnp-standard-features.d.ts +0 -238
  252. package/dist/services/pnp-standard-features.js +0 -338
  253. package/dist/services/tool-providers/CortexToolProvider.d.ts +0 -13
  254. package/dist/services/tool-providers/CortexToolProvider.js +0 -32
  255. package/dist/services/tool-providers/DesmosToolProvider.d.ts +0 -14
  256. package/dist/services/tool-providers/DesmosToolProvider.js +0 -32
  257. package/dist/services/tool-providers/GeoGebraToolProvider.d.ts +0 -16
  258. package/dist/services/tool-providers/GeoGebraToolProvider.js +0 -32
  259. package/dist/services/tool-providers/LazyCalculatorToolProvider.d.ts +0 -35
  260. package/dist/services/tool-providers/LazyCalculatorToolProvider.js +0 -95
  261. package/dist/services/tts/visual-line-ranges.d.ts +0 -18
  262. package/dist/services/tts/visual-line-ranges.js +0 -226
  263. package/dist/tools/client.d.ts +0 -12
  264. package/dist/tools/client.js +0 -14
  265. package/dist/tools/index.d.ts +0 -8
  266. package/dist/tools/index.js +0 -10
  267. package/dist/tools/internal.d.ts +0 -43
  268. package/dist/tools/internal.js +0 -41
  269. package/dist/tools/response-discovery.d.ts +0 -61
  270. package/dist/tools/response-discovery.js +0 -113
  271. package/dist/tools/types.d.ts +0 -337
  272. package/dist/tools/types.js +0 -12
  273. package/dist/tools/variant-resolver.d.ts +0 -41
  274. package/dist/tools/variant-resolver.js +0 -207
@@ -1,43 +1,4 @@
1
- import { resolveSpokenBoundaryOffset } from "../catalog-span-alignment.js";
2
- import { resolveBoundaryToSpeechToken, tokenizeSpeechSource, } from "../math-alignment/speech-tokenizer.js";
3
- const normalizeBoundaryWord = (word) => {
4
- if (!word || /^<[^>]+>$/.test(word.trim()))
5
- return null;
6
- return (tokenizeSpeechSource({ speechText: word }).tokens[0]?.normalized || null);
7
- };
8
- // Resolve a provider boundary for a chunk that carries no catalog span
9
- // alignment — notably the generated-SSML math path, whose `speechText` is a
10
- // raw `<speak>` document. The provider's offset is an index into `speechText`
11
- // exactly as it was sent (which may include SSML tags), so we tokenize that
12
- // same string and let the shared speech tokenizer translate the offset into the
13
- // extracted spoken text. Returns the boundary in spoken-text space alongside
14
- // that spoken text, so the downstream word/offset checks share one coordinate
15
- // system. The previous "direct" path treated the raw-SSML offset as a
16
- // spoken-text offset and rejected every math boundary (PIE-623 regression).
17
- const speechSourceBoundary = (chunk, event) => {
18
- const tokenization = tokenizeSpeechSource({ speechText: chunk.speechText });
19
- if (!Number.isFinite(event.position)) {
20
- return { boundary: null, spokenText: tokenization.spokenText };
21
- }
22
- const resolved = resolveBoundaryToSpeechToken({
23
- tokenization,
24
- position: event.position,
25
- length: event.length,
26
- boundaryWord: event.word,
27
- });
28
- return {
29
- boundary: resolved
30
- ? { start: resolved.start, length: resolved.length }
31
- : null,
32
- spokenText: tokenization.spokenText,
33
- };
34
- };
35
- const tokenAtOffsetMatches = (speechText, start, normalizedWord) => {
36
- if (!normalizedWord)
37
- return true;
38
- const token = tokenizeSpeechSource({ speechText }).tokens.find((candidate) => candidate.start <= start && start < candidate.end);
39
- return token?.normalized === normalizedWord;
40
- };
1
+ import { normalizeBoundaryWord, resolveBoundaryToSpeechToken, tokenizeSpeechSource, } from "../math-alignment/speech-tokenizer.js";
41
2
  export const normalizeBoundaryEvent = (chunk, event) => {
42
3
  const normalizedWord = normalizeBoundaryWord(event.word);
43
4
  if (chunk.id !== event.chunkId) {
@@ -61,17 +22,16 @@ export const normalizeBoundaryEvent = (chunk, event) => {
61
22
  reason: "boundary offset space is unsupported",
62
23
  };
63
24
  }
64
- let boundary;
65
- let spokenText;
66
- if (chunk.catalogAlignment) {
67
- boundary = resolveSpokenBoundaryOffset(chunk.catalogAlignment, event.position, event.length, event.word);
68
- spokenText = chunk.catalogAlignment.spokenText;
69
- }
70
- else {
71
- const resolved = speechSourceBoundary(chunk, event);
72
- boundary = resolved.boundary;
73
- spokenText = resolved.spokenText;
74
- }
25
+ // The provider's offset indexes `speechText` exactly as sent, which may be a
26
+ // raw `<speak>` document; the shared tokenizer maps it into spoken text and
27
+ // checks it against the reported word, on the catalog path and without one.
28
+ const boundary = resolveBoundaryToSpeechToken({
29
+ tokenization: chunk.catalogAlignment?.speech ??
30
+ tokenizeSpeechSource({ speechText: chunk.speechText }),
31
+ position: event.position,
32
+ length: event.length,
33
+ boundaryWord: event.word,
34
+ });
75
35
  if (!boundary) {
76
36
  return {
77
37
  chunkId: chunk.id,
@@ -82,22 +42,12 @@ export const normalizeBoundaryEvent = (chunk, event) => {
82
42
  reason: "could not resolve provider boundary to chunk speech",
83
43
  };
84
44
  }
85
- if (!tokenAtOffsetMatches(spokenText, boundary.start, normalizedWord)) {
86
- return {
87
- chunkId: chunk.id,
88
- normalizedWord,
89
- chunkSpokenStart: null,
90
- chunkSpokenEnd: null,
91
- confidence: 0,
92
- reason: "could not resolve provider boundary to matching word",
93
- };
94
- }
95
45
  return {
96
46
  chunkId: chunk.id,
97
47
  normalizedWord,
98
48
  chunkSpokenStart: boundary.start,
99
49
  chunkSpokenEnd: boundary.start + boundary.length,
100
- confidence: normalizedWord ? 1 : 0.75,
50
+ confidence: boundary.confidence,
101
51
  reason: chunk.catalogAlignment
102
52
  ? "resolved through catalog alignment"
103
53
  : "resolved through speech tokenization",
@@ -3,11 +3,19 @@ import { createHighlightDecision } from "./highlight-policy.js";
3
3
  import { resolveMathBoundaryTarget } from "./math-semantic-resolver.js";
4
4
  import { resolveProseBoundaryTarget } from "./prose-boundary-resolver.js";
5
5
  import { classifyMathHighlightCapability, createRenderedMathTargetResolver, } from "./rendered-math-target-resolver.js";
6
+ import { composedContains, composedParentElement, rangeIntersectsComposedNode, } from "../flat-tree.js";
7
+ import { isNodeHiddenForTTS } from "../text-processing.js";
8
+ import { createRangesFromVisibleMap } from "./visible-map-range.js";
9
+ const regionRangesFor = (chunk) => {
10
+ const ranges = createRangesFromVisibleMap(chunk.visibleMap, 0, chunk.visibleText.length);
11
+ return ranges.length > 1 ? ranges : undefined;
12
+ };
6
13
  const regionTargetFor = (chunk) => chunk.regionRange
7
14
  ? {
8
15
  type: "range",
9
16
  quality: "region",
10
17
  range: chunk.regionRange,
18
+ ranges: regionRangesFor(chunk),
11
19
  }
12
20
  : chunk.regionElement
13
21
  ? {
@@ -28,12 +36,13 @@ const mathCandidatesForTarget = (target, chunk) => {
28
36
  return chunk.mathAlignments;
29
37
  return chunk.mathAlignments.filter(({ element }) => {
30
38
  try {
31
- if (target.type === "range")
32
- return target.range.intersectsNode(element);
39
+ if (target.type === "range") {
40
+ return (target.ranges ?? [target.range]).some((range) => rangeIntersectsComposedNode(range, element));
41
+ }
33
42
  if (target.type === "element") {
34
- return target.element === element || target.element.contains(element);
43
+ return composedContains(target.element, element);
35
44
  }
36
- return target.node.parentElement?.contains(element) || false;
45
+ return composedContains(composedParentElement(target.node), element);
37
46
  }
38
47
  catch {
39
48
  return false;
@@ -73,6 +82,25 @@ const wouldEscalateInsideTokenMath = (planned, target, candidates) => {
73
82
  element.contains(startContainer) &&
74
83
  element.contains(endContainer));
75
84
  };
85
+ // A prose range in hidden content paints nothing. Catalog words over MathJax
86
+ // math land in its clipped source MathML, so they select the equation, and a
87
+ // range over one source token resolves to that token's rendered glyph — the
88
+ // fill-in a single-text-node range gives native MathML.
89
+ const isHiddenRange = (target) => target?.type === "range" && isNodeHiddenForTTS(target.range.startContainer);
90
+ const renderHiddenProseTarget = (planned, target) => {
91
+ if (!isHiddenRange(target))
92
+ return null;
93
+ const { startContainer, endContainer, startOffset, endOffset } = target.range;
94
+ if (startContainer !== endContainer || startContainer.nodeType !== TEXT_NODE)
95
+ return null;
96
+ return planned.renderedMathTargetResolver({
97
+ type: "text-range",
98
+ quality: "exact-word",
99
+ node: startContainer,
100
+ startOffset,
101
+ endOffset,
102
+ });
103
+ };
76
104
  const createPlannedChunk = (chunk, mathTokenHighlighting) => ({
77
105
  chunk,
78
106
  regionTarget: regionTargetFor(chunk),
@@ -136,9 +164,13 @@ export const createTTSHighlightPlan = (args) => {
136
164
  const normalized = normalizeBoundaryEvent(chunk, event);
137
165
  const proseTarget = resolveProseBoundaryTarget(chunk, normalized);
138
166
  const mathCandidates = mathCandidatesForTarget(proseTarget, chunk);
139
- const mathTarget = (!proseTarget || mathCandidates.length > 0
167
+ const resolvedMathTarget = (!proseTarget || mathCandidates.length > 0
140
168
  ? resolveMathBoundaryTarget(chunk, normalized, event, mathCandidates, planned.renderedMathTargetResolver)
141
169
  : null) || null;
170
+ const mathTarget = resolvedMathTarget?.quality === "semantic-token"
171
+ ? resolvedMathTarget
172
+ : (renderHiddenProseTarget(planned, proseTarget) ??
173
+ resolvedMathTarget);
142
174
  const mathTokenTarget = mathTokenHighlighting &&
143
175
  mathTarget &&
144
176
  mathTarget.quality !== "expression"
@@ -169,6 +201,7 @@ export const createTTSHighlightPlan = (args) => {
169
201
  // highlighting is disabled, any prose range that lands inside a
170
202
  // formula is likewise rejected so the formula stays a single block.
171
203
  if (proseTarget &&
204
+ !isHiddenRange(proseTarget) &&
172
205
  (mathTokenHighlighting
173
206
  ? !wouldEscalateInsideTokenMath(planned, proseTarget, mathCandidates)
174
207
  : mathCandidates.length === 0)) {
@@ -1,10 +1,7 @@
1
1
  const chunkOffsetSpaceFor = (chunk) => {
2
- if (chunk.alignment?.boundaryOffsetMode)
3
- return chunk.alignment.boundaryOffsetMode;
4
- const mathOffsetSpace = chunk.mathAlignment?.speech.boundaryOffsetSpace;
5
- if (mathOffsetSpace)
6
- return mathOffsetSpace;
7
- return "plain-spoken-text";
2
+ return (chunk.alignment?.speech.boundaryOffsetSpace ??
3
+ chunk.mathAlignment?.speech.boundaryOffsetSpace ??
4
+ "plain-spoken-text");
8
5
  };
9
6
  const mathAlignmentsFor = (chunk) => {
10
7
  if (chunk.mathAlignments?.length)
@@ -1,19 +1,21 @@
1
1
  import { resolveVisibleSpanForBoundary } from "../catalog-span-alignment.js";
2
- import { createRangeFromVisibleMap } from "./visible-map-range.js";
2
+ import { createRangesFromVisibleMap } from "./visible-map-range.js";
3
3
  export const resolveProseBoundaryTarget = (chunk, boundary) => {
4
4
  if (!chunk.catalogAlignment || boundary.chunkSpokenStart === null)
5
5
  return null;
6
6
  const visibleSpan = resolveVisibleSpanForBoundary(chunk.catalogAlignment, boundary.chunkSpokenStart);
7
7
  if (!visibleSpan)
8
8
  return null;
9
- const range = createRangeFromVisibleMap(chunk.visibleMap, visibleSpan.start, visibleSpan.end);
10
- if (!range)
9
+ // One range per tree, as the uncataloged word path builds them.
10
+ const ranges = createRangesFromVisibleMap(chunk.visibleMap, visibleSpan.start, visibleSpan.end);
11
+ if (ranges.length === 0)
11
12
  return null;
12
13
  return {
13
14
  type: "range",
14
15
  quality: chunk.catalogAlignment.playbackMode === "exact-word"
15
16
  ? "exact-word"
16
17
  : "semantic-token",
17
- range,
18
+ range: ranges[0],
19
+ ranges: ranges.length > 1 ? ranges : undefined,
18
20
  };
19
21
  };
@@ -1,3 +1,4 @@
1
+ import { composedClosest, composedContains } from "../flat-tree.js";
1
2
  const READABLE_REGION_SELECTOR = [
2
3
  "[data-pie-tts-region]",
3
4
  "[data-catalog-region]",
@@ -10,8 +11,8 @@ const READABLE_REGION_SELECTOR = [
10
11
  "div",
11
12
  ].join(",");
12
13
  export const resolveReadableRegion = (sourceElement, contentRoot) => {
13
- const region = sourceElement.closest(READABLE_REGION_SELECTOR);
14
- if (region && contentRoot.contains(region)) {
14
+ const region = composedClosest(sourceElement, READABLE_REGION_SELECTOR);
15
+ if (region && composedContains(contentRoot, region)) {
15
16
  return region;
16
17
  }
17
18
  return sourceElement;
@@ -44,6 +44,11 @@ export type RenderableHighlightTarget = {
44
44
  type: "range";
45
45
  quality: "exact-word" | "semantic-token" | "expression" | "region";
46
46
  range: Range;
47
+ /**
48
+ * Every range to paint when the target crosses shadow boundaries, one per
49
+ * tree, `range` among them; absent when `range` covers the target.
50
+ */
51
+ ranges?: Range[];
47
52
  } | {
48
53
  type: "element";
49
54
  quality: "semantic-token" | "expression" | "region";
@@ -1,2 +1,14 @@
1
1
  import type { NormalizedTextMap } from "../text-processing.js";
2
+ /**
3
+ * The range over visible characters `start` to `end` (exclusive). A live range
4
+ * holds one tree, so when the span runs into a shadow tree, or out of one, the
5
+ * range ends at the last character in the tree it starts in.
6
+ */
2
7
  export declare const createRangeFromVisibleMap: (visibleMap: NormalizedTextMap | undefined, start: number, end: number) => Range | null;
8
+ /**
9
+ * The ranges over visible characters `start` to `end` (exclusive), one per run of
10
+ * characters in the same tree, so a span crossing shadow boundaries paints in
11
+ * each tree it covers. A span within one tree gives exactly
12
+ * {@link createRangeFromVisibleMap}'s range.
13
+ */
14
+ export declare const createRangesFromVisibleMap: (visibleMap: NormalizedTextMap | undefined, start: number, end: number) => Range[];
@@ -1,3 +1,20 @@
1
+ const treeOf = (mapping) => mapping.node.getRootNode?.() ?? mapping.node;
2
+ const rangeBetween = (start, end) => {
3
+ try {
4
+ const range = document.createRange();
5
+ range.setStart(start.node, start.offset);
6
+ range.setEnd(end.node, end.offset + 1);
7
+ return range;
8
+ }
9
+ catch {
10
+ return null;
11
+ }
12
+ };
13
+ /**
14
+ * The range over visible characters `start` to `end` (exclusive). A live range
15
+ * holds one tree, so when the span runs into a shadow tree, or out of one, the
16
+ * range ends at the last character in the tree it starts in.
17
+ */
1
18
  export const createRangeFromVisibleMap = (visibleMap, start, end) => {
2
19
  if (!visibleMap || typeof document === "undefined")
3
20
  return null;
@@ -9,13 +26,62 @@ export const createRangeFromVisibleMap = (visibleMap, start, end) => {
9
26
  return null;
10
27
  if (!endMapping)
11
28
  endMapping = startMapping;
12
- try {
13
- const range = document.createRange();
14
- range.setStart(startMapping.node, startMapping.offset);
15
- range.setEnd(endMapping.node, endMapping.offset + 1);
16
- return range;
29
+ if (treeOf(endMapping) !== treeOf(startMapping)) {
30
+ const tree = treeOf(startMapping);
31
+ endMapping = startMapping;
32
+ for (let index = start + 1; index < end; index++) {
33
+ const mapping = visibleMap.get(index);
34
+ if (mapping && treeOf(mapping) === tree)
35
+ endMapping = mapping;
36
+ }
17
37
  }
18
- catch {
19
- return null;
38
+ return rangeBetween(startMapping, endMapping);
39
+ };
40
+ /**
41
+ * The ranges over visible characters `start` to `end` (exclusive), one per run of
42
+ * characters in the same tree, so a span crossing shadow boundaries paints in
43
+ * each tree it covers. A span within one tree gives exactly
44
+ * {@link createRangeFromVisibleMap}'s range.
45
+ */
46
+ export const createRangesFromVisibleMap = (visibleMap, start, end) => {
47
+ if (!visibleMap || typeof document === "undefined" || end <= start)
48
+ return [];
49
+ const startMapping = visibleMap.get(start);
50
+ if (!startMapping)
51
+ return [];
52
+ const tree = treeOf(startMapping);
53
+ let crossesTrees = false;
54
+ for (let index = start + 1; index < end && !crossesTrees; index++) {
55
+ const mapping = visibleMap.get(index);
56
+ if (mapping && treeOf(mapping) !== tree)
57
+ crossesTrees = true;
58
+ }
59
+ if (!crossesTrees) {
60
+ const range = createRangeFromVisibleMap(visibleMap, start, end);
61
+ return range ? [range] : [];
62
+ }
63
+ const ranges = [];
64
+ let runStart = null;
65
+ let runEnd = null;
66
+ const closeRun = () => {
67
+ if (runStart && runEnd) {
68
+ const range = rangeBetween(runStart, runEnd);
69
+ if (range)
70
+ ranges.push(range);
71
+ }
72
+ runStart = null;
73
+ runEnd = null;
74
+ };
75
+ for (let index = start; index < end; index++) {
76
+ const mapping = visibleMap.get(index);
77
+ if (!mapping)
78
+ continue;
79
+ if (runStart && treeOf(runStart) !== treeOf(mapping))
80
+ closeRun();
81
+ if (!runStart)
82
+ runStart = mapping;
83
+ runEnd = mapping;
20
84
  }
85
+ closeRun();
86
+ return ranges;
21
87
  };
@@ -14,11 +14,6 @@ export declare const resolveHighlightTargetForBoundary: (alignment: MathAwareAli
14
14
  length?: number;
15
15
  boundaryWord?: string;
16
16
  }) => HighlightTarget;
17
- export declare const resolveMatchedHighlightTargetForBoundary: (alignment: MathAwareAlignment, args: {
18
- position: number;
19
- length?: number;
20
- boundaryWord?: string;
21
- }) => HighlightTarget | null;
22
17
  export declare const resolveMatchedHighlightTargetForSpokenBoundary: (alignment: MathAwareAlignment, args: {
23
18
  position: number;
24
19
  length?: number;
@@ -1,7 +1,7 @@
1
1
  import { tokenizeMathML } from "./mathml-tokenizer.js";
2
2
  import { resolveMatchedHighlightTargetForBoundary as resolveMatchedTargetForBoundary, resolveHighlightTargetForBoundary as resolveTargetForBoundary, } from "./range-resolver.js";
3
3
  import { alignSpeechToMath } from "./sequence-aligner.js";
4
- import { resolveBoundaryToSpeechToken, resolveSpokenOffsetToSpeechToken, tokenizeSpeechSource, } from "./speech-tokenizer.js";
4
+ import { normalizeBoundaryWord, resolveBoundaryToSpeechToken, resolveSpokenOffsetToSpeechToken, tokenizeSpeechSource, } from "./speech-tokenizer.js";
5
5
  export const createMathAwareAlignment = (args) => {
6
6
  const speech = tokenizeSpeechSource({ speechText: args.speechText });
7
7
  const math = tokenizeMathML(args.mathElement);
@@ -23,18 +23,6 @@ export const resolveHighlightTargetForBoundary = (alignment, args) => {
23
23
  boundary,
24
24
  });
25
25
  };
26
- export const resolveMatchedHighlightTargetForBoundary = (alignment, args) => {
27
- const boundary = resolveBoundaryToSpeechToken({
28
- tokenization: alignment.speech,
29
- position: args.position,
30
- length: args.length,
31
- boundaryWord: args.boundaryWord,
32
- });
33
- return resolveMatchedTargetForBoundary({
34
- alignment: alignment.result,
35
- boundary,
36
- });
37
- };
38
26
  export const resolveMatchedHighlightTargetForSpokenBoundary = (alignment, args) => {
39
27
  const boundary = resolveSpokenOffsetToSpeechToken({
40
28
  tokenization: alignment.speech,
@@ -48,18 +36,10 @@ export const resolveMatchedHighlightTargetForSpokenBoundary = (alignment, args)
48
36
  });
49
37
  };
50
38
  export const resolveUniqueMathTargetForBoundaryWord = (alignment, args) => {
51
- if (!args.boundaryWord || /^<[^>]+>$/.test(args.boundaryWord.trim())) {
52
- return null;
53
- }
54
- const boundaryToken = tokenizeSpeechSource({
55
- speechText: args.boundaryWord,
56
- }).tokens[0];
57
- if (!boundaryToken)
39
+ const normalized = normalizeBoundaryWord(args.boundaryWord);
40
+ if (!normalized)
58
41
  return null;
59
- const matches = alignment.math.tokens.filter((token) => {
60
- const normalized = boundaryToken.normalized.toLowerCase();
61
- return (token.normalized.toLowerCase() === normalized ||
62
- token.spokenAliases.some((alias) => alias.toLowerCase() === normalized));
63
- });
42
+ const matches = alignment.math.tokens.filter((token) => token.normalized.toLowerCase() === normalized ||
43
+ token.spokenAliases.some((alias) => alias.toLowerCase() === normalized));
64
44
  return matches.length === 1 ? matches[0].target : null;
65
45
  };
@@ -1,4 +1,4 @@
1
- import type { BoundaryOffsetSpace, SpeechAlignmentToken } from "./types.js";
1
+ import type { AlignmentTextToken, BoundaryOffsetSpace, SpeechAlignmentToken } from "./types.js";
2
2
  export interface SpeechSourceTokenization {
3
3
  speechText: string;
4
4
  spokenText: string;
@@ -14,9 +14,17 @@ export interface ResolvedSpeechBoundary {
14
14
  length: number;
15
15
  confidence: number;
16
16
  }
17
+ export declare const tokenizeAlignmentText: (text: string) => AlignmentTextToken[];
17
18
  export declare const tokenizeSpeechSource: (args: {
18
19
  speechText: string;
19
20
  }) => SpeechSourceTokenization;
21
+ /**
22
+ * A provider boundary word in the form spoken tokens compare in, or null when
23
+ * the word carries no token (empty, a control tag, punctuation). The word goes
24
+ * through the same SSML extraction as the chunk, so an entity-encoded word
25
+ * normalizes to the text it encodes.
26
+ */
27
+ export declare const normalizeBoundaryWord: (word?: string) => string | null;
20
28
  export declare const resolveBoundaryToSpeechToken: (args: {
21
29
  tokenization: SpeechSourceTokenization;
22
30
  position: number;
@@ -1,8 +1,8 @@
1
1
  import { extractSpokenText } from "../ssml/spoken-text.js";
2
2
  import { createSpeechAlignmentTokenPattern } from "../text-processing.js";
3
- // Shared Unicode-aware tokenizer, identical to the catalog span aligner's, so
4
- // spoken text tokenizes the same way on both paths (see
5
- // `createSpeechAlignmentTokenPattern`).
3
+ // The one tokenizer and normalization table for TTS alignment. Spoken text,
4
+ // visible catalog text and provider boundary words all tokenize here, so a word
5
+ // normalizes the same way on the catalog, math and generated-speech paths.
6
6
  const TOKEN_PATTERN = createSpeechAlignmentTokenPattern();
7
7
  const NUMERIC_WORDS = new Map([
8
8
  ["zero", "0"],
@@ -21,24 +21,27 @@ const normalizedTokenValue = (value) => {
21
21
  const normalized = value.toLowerCase();
22
22
  return NUMERIC_WORDS.get(normalized) || normalized;
23
23
  };
24
- const tokenizeSpokenText = (spokenText) => {
24
+ export const tokenizeAlignmentText = (text) => {
25
25
  const tokens = [];
26
- for (const match of spokenText.matchAll(TOKEN_PATTERN)) {
27
- const text = match[0];
26
+ for (const match of text.matchAll(TOKEN_PATTERN)) {
27
+ const value = match[0];
28
28
  const start = match.index ?? 0;
29
29
  tokens.push({
30
- id: `speech-token-${tokens.length}`,
31
- text,
32
- normalized: normalizedTokenValue(text),
30
+ text: value,
31
+ normalized: normalizedTokenValue(value),
33
32
  start,
34
- end: start + text.length,
35
- sourceStart: start,
36
- sourceEnd: start + text.length,
37
- coordinateSystem: "normalized-speech",
33
+ end: start + value.length,
38
34
  });
39
35
  }
40
36
  return tokens;
41
37
  };
38
+ const tokenizeSpokenText = (spokenText) => tokenizeAlignmentText(spokenText).map((token, index) => ({
39
+ ...token,
40
+ id: `speech-token-${index}`,
41
+ sourceStart: token.start,
42
+ sourceEnd: token.end,
43
+ coordinateSystem: "normalized-speech",
44
+ }));
42
45
  export const tokenizeSpeechSource = (args) => {
43
46
  const extracted = extractSpokenText(args.speechText);
44
47
  return {
@@ -55,15 +58,17 @@ export const tokenizeSpeechSource = (args) => {
55
58
  hasMarkup: extracted.hasMarkup,
56
59
  };
57
60
  };
58
- const normalizeBoundaryWord = (word) => {
59
- if (!word)
61
+ const isControlTagWord = (word) => Boolean(word && /^<[^>]+>$/.test(word.trim()));
62
+ /**
63
+ * A provider boundary word in the form spoken tokens compare in, or null when
64
+ * the word carries no token (empty, a control tag, punctuation). The word goes
65
+ * through the same SSML extraction as the chunk, so an entity-encoded word
66
+ * normalizes to the text it encodes.
67
+ */
68
+ export const normalizeBoundaryWord = (word) => {
69
+ if (!word || isControlTagWord(word))
60
70
  return null;
61
- if (/^<[^>]+>$/.test(word.trim()))
62
- return null;
63
- const match = word.match(TOKEN_PATTERN);
64
- if (!match?.[0])
65
- return null;
66
- return normalizedTokenValue(match[0]);
71
+ return (tokenizeSpeechSource({ speechText: word }).tokens[0]?.normalized ?? null);
67
72
  };
68
73
  const findTokenAtOffset = (tokens, offset) => tokens.find((token) => token.start <= offset && offset < token.end) || null;
69
74
  const mapRawOffsetToSpokenOffset = (tokenization, position) => {
@@ -92,32 +97,29 @@ const candidateForOffset = (tokenization, offset, length) => {
92
97
  confidence: 0.75,
93
98
  };
94
99
  };
95
- const candidateMatchesWord = (candidate, boundaryWord) => {
96
- const normalizedBoundary = normalizeBoundaryWord(boundaryWord);
97
- return Boolean(candidate &&
98
- normalizedBoundary &&
99
- candidate.token.normalized === normalizedBoundary);
100
- };
100
+ const candidateMatchesWord = (candidate, normalizedWord) => Boolean(candidate &&
101
+ normalizedWord &&
102
+ candidate.token.normalized === normalizedWord);
101
103
  export const resolveBoundaryToSpeechToken = (args) => {
102
104
  if (args.tokenization.boundaryOffsetSpace === "unsupported" ||
103
105
  !Number.isFinite(args.position) ||
104
- (args.boundaryWord && /^<[^>]+>$/.test(args.boundaryWord.trim()))) {
106
+ isControlTagWord(args.boundaryWord)) {
105
107
  return null;
106
108
  }
107
109
  const safeLength = Math.max(1, Number.isFinite(args.length) ? args.length : 1);
110
+ const normalizedWord = normalizeBoundaryWord(args.boundaryWord);
108
111
  const rawCandidate = candidateForOffset(args.tokenization, mapRawOffsetToSpokenOffset(args.tokenization, args.position), safeLength);
109
112
  const plainCandidate = candidateForOffset(args.tokenization, args.position >= 0 && args.position < args.tokenization.spokenText.length
110
113
  ? args.position
111
114
  : null, safeLength);
112
- if (candidateMatchesWord(rawCandidate, args.boundaryWord)) {
115
+ if (candidateMatchesWord(rawCandidate, normalizedWord)) {
113
116
  return { ...rawCandidate, confidence: 1 };
114
117
  }
115
- if (candidateMatchesWord(plainCandidate, args.boundaryWord)) {
118
+ if (candidateMatchesWord(plainCandidate, normalizedWord)) {
116
119
  return { ...plainCandidate, confidence: 1 };
117
120
  }
118
- if (args.boundaryWord && normalizeBoundaryWord(args.boundaryWord)) {
121
+ if (normalizedWord)
119
122
  return null;
120
- }
121
123
  return args.tokenization.boundaryOffsetSpace === "raw-ssml"
122
124
  ? rawCandidate || plainCandidate
123
125
  : plainCandidate || rawCandidate;
@@ -125,18 +127,18 @@ export const resolveBoundaryToSpeechToken = (args) => {
125
127
  export const resolveSpokenOffsetToSpeechToken = (args) => {
126
128
  if (args.tokenization.boundaryOffsetSpace === "unsupported" ||
127
129
  !Number.isFinite(args.position) ||
128
- (args.boundaryWord && /^<[^>]+>$/.test(args.boundaryWord.trim()))) {
130
+ isControlTagWord(args.boundaryWord)) {
129
131
  return null;
130
132
  }
131
133
  const safeLength = Math.max(1, Number.isFinite(args.length) ? args.length : 1);
134
+ const normalizedWord = normalizeBoundaryWord(args.boundaryWord);
132
135
  const spokenCandidate = candidateForOffset(args.tokenization, args.position >= 0 && args.position < args.tokenization.spokenText.length
133
136
  ? args.position
134
137
  : null, safeLength);
135
- if (candidateMatchesWord(spokenCandidate, args.boundaryWord)) {
138
+ if (candidateMatchesWord(spokenCandidate, normalizedWord)) {
136
139
  return { ...spokenCandidate, confidence: 1 };
137
140
  }
138
- if (args.boundaryWord && normalizeBoundaryWord(args.boundaryWord)) {
141
+ if (normalizedWord)
139
142
  return null;
140
- }
141
143
  return spokenCandidate;
142
144
  };
@@ -34,12 +34,14 @@ export interface MathMLTokenizationResult {
34
34
  }
35
35
  export type BoundaryCoordinateSystem = "normalized-speech" | "raw-ssml" | "provider-speech-marks";
36
36
  export type BoundaryOffsetSpace = "plain-spoken-text" | "raw-ssml" | "unsupported";
37
- export interface SpeechAlignmentToken {
38
- id: string;
37
+ export interface AlignmentTextToken {
39
38
  text: string;
40
39
  normalized: string;
41
40
  start: number;
42
41
  end: number;
42
+ }
43
+ export interface SpeechAlignmentToken extends AlignmentTextToken {
44
+ id: string;
43
45
  sourceStart: number;
44
46
  sourceEnd: number;
45
47
  coordinateSystem: BoundaryCoordinateSystem;
@@ -15,4 +15,8 @@ export interface MathAwareTextResult {
15
15
  chunks: MathAwareSpeechChunk[];
16
16
  containsMathMarkup: boolean;
17
17
  }
18
- export declare const collectMathAwareTextAndMap: (element: Element, options?: TextProcessingOptions) => MathAwareTextResult;
18
+ /**
19
+ * With `range`, only the part of `element` the range selects: text it selects
20
+ * and equations it holds whole.
21
+ */
22
+ export declare const collectMathAwareTextAndMap: (element: Element, options?: TextProcessingOptions, range?: Range) => MathAwareTextResult;