| 194 | } |
| 195 | |
| 196 | *iterSubstrings(): IterableIterator<[string, T[]]> { |
| 197 | const activeSpansById = new Map<number, Span<T>>(); |
| 198 | |
| 199 | function getActiveAttributes() { |
| 200 | return ( |
| 201 | Array.from(activeSpansById.values()) |
| 202 | // Attributes should be returned in the order they were |
| 203 | // applied. |
| 204 | .sort((a, b) => a.id - b.id) |
| 205 | .map((span) => span.attribute) |
| 206 | ); |
| 207 | } |
| 208 | |
| 209 | let lastIndex = 0; |
| 210 | for (let spanIndex = 0; spanIndex <= this._string.length; spanIndex++) { |
| 211 | const spans = this._spanMarkers[spanIndex]; |
| 212 | |
| 213 | if (spans === undefined || spans.length === 0) { |
| 214 | continue; |
| 215 | } |
| 216 | |
| 217 | if (spanIndex > lastIndex) { |
| 218 | yield [ |
| 219 | this._string.slice(lastIndex, spanIndex), |
| 220 | getActiveAttributes(), |
| 221 | ]; |
| 222 | } |
| 223 | |
| 224 | for (const span of spans) { |
| 225 | if (span.isStart) { |
| 226 | activeSpansById.set(span.id, span); |
| 227 | } else { |
| 228 | activeSpansById.delete(span.id); |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | lastIndex = spanIndex; |
| 233 | } |
| 234 | |
| 235 | if (lastIndex < this._string.length) { |
| 236 | yield [this._string.slice(lastIndex), getActiveAttributes()]; |
| 237 | } |
| 238 | } |
| 239 | } |