(marbles?: string | null)
| 152 | } |
| 153 | |
| 154 | export function parseSubscriptionMarbles(marbles?: string | null): ParsedSubscription { |
| 155 | if (marbles == null) { |
| 156 | return { |
| 157 | subscribedFrame: 0, |
| 158 | unsubscribedFrame: Infinity, |
| 159 | }; |
| 160 | } |
| 161 | |
| 162 | const characters = [...marbles]; |
| 163 | let frame = 0; |
| 164 | let groupStart: number | undefined; |
| 165 | let subscribedFrame = Infinity; |
| 166 | let unsubscribedFrame = Infinity; |
| 167 | |
| 168 | for (let index = 0; index < characters.length; index++) { |
| 169 | const character = characters[index]; |
| 170 | if (character === undefined) { |
| 171 | break; |
| 172 | } |
| 173 | if (isWhitespace(character)) { |
| 174 | continue; |
| 175 | } |
| 176 | |
| 177 | const duration = readDuration(characters, index); |
| 178 | if (duration) { |
| 179 | frame += duration.milliseconds; |
| 180 | index += duration.length - 1; |
| 181 | continue; |
| 182 | } |
| 183 | |
| 184 | switch (character) { |
| 185 | case '-': |
| 186 | frame += 1; |
| 187 | break; |
| 188 | case '(': |
| 189 | if (groupStart !== undefined) { |
| 190 | throw new Error('Nested subscription groups are not supported.'); |
| 191 | } |
| 192 | groupStart = frame; |
| 193 | frame += 1; |
| 194 | break; |
| 195 | case ')': |
| 196 | if (groupStart === undefined) { |
| 197 | throw new Error('Found a closing subscription group without an opening group.'); |
| 198 | } |
| 199 | groupStart = undefined; |
| 200 | frame += 1; |
| 201 | break; |
| 202 | case '^': |
| 203 | if (subscribedFrame !== Infinity) { |
| 204 | throw new Error('A subscription marble diagram can contain only one "^".'); |
| 205 | } |
| 206 | subscribedFrame = groupStart ?? frame; |
| 207 | frame += 1; |
| 208 | break; |
| 209 | case '!': |
| 210 | if (unsubscribedFrame !== Infinity) { |
| 211 | throw new Error('A subscription marble diagram can contain only one "!".'); |
no test coverage detected