2022-10-03 14:19:54 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								// Copyright 2022 Signal Messenger, LLC
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								// SPDX-License-Identifier: AGPL-3.0-only
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import type {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  MessageFormatElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  LiteralElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  ArgumentElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  NumberElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  DateElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  TimeElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  SelectElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  PluralElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  PoundElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  TagElement,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								} from '@formatjs/icu-messageformat-parser';
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import { TYPE } from '@formatjs/icu-messageformat-parser';
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								export type VisitorMethod<T extends MessageFormatElement> = (
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-04 12:05:50 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								  element: T,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  parent: MessageFormatElement | null
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-03 14:19:54 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								) => void;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								export type Visitor = {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  enterLiteral?: VisitorMethod<LiteralElement>;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  exitLiteral?: VisitorMethod<LiteralElement>;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  enterArgument?: VisitorMethod<ArgumentElement>;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  exitArgument?: VisitorMethod<ArgumentElement>;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  enterNumber?: VisitorMethod<NumberElement>;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  exitNumber?: VisitorMethod<NumberElement>;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  enterDate?: VisitorMethod<DateElement>;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  exitDate?: VisitorMethod<DateElement>;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  enterTime?: VisitorMethod<TimeElement>;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  exitTime?: VisitorMethod<TimeElement>;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  enterSelect?: VisitorMethod<SelectElement>;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  exitSelect?: VisitorMethod<SelectElement>;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  enterPlural?: VisitorMethod<PluralElement>;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  exitPlural?: VisitorMethod<PluralElement>;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  enterPound?: VisitorMethod<PoundElement>;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  exitPound?: VisitorMethod<PoundElement>;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  enterTag?: VisitorMethod<TagElement>;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  exitTag?: VisitorMethod<TagElement>;
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								};
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								export function traverse(
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-04 12:05:50 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								  parent: MessageFormatElement | null,
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-03 14:19:54 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  elements: Array<MessageFormatElement>,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  visitor: Visitor
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								): void {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  for (const element of elements) {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if (element.type === TYPE.literal) {
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-04 12:05:50 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      visitor.enterLiteral?.(element, parent);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      visitor.exitLiteral?.(element, parent);
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-03 14:19:54 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    } else if (element.type === TYPE.argument) {
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-04 12:05:50 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      visitor.enterArgument?.(element, parent);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      visitor.exitArgument?.(element, parent);
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-03 14:19:54 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    } else if (element.type === TYPE.number) {
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-04 12:05:50 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      visitor.enterNumber?.(element, parent);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      visitor.exitNumber?.(element, parent);
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-03 14:19:54 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    } else if (element.type === TYPE.date) {
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-04 12:05:50 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      visitor.enterDate?.(element, parent);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      visitor.exitDate?.(element, parent);
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-03 14:19:54 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    } else if (element.type === TYPE.time) {
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-04 12:05:50 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      visitor.enterTime?.(element, parent);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      visitor.exitTime?.(element, parent);
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-03 14:19:54 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    } else if (element.type === TYPE.select) {
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-04 12:05:50 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      visitor.enterSelect?.(element, parent);
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-03 14:19:54 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      for (const node of Object.values(element.options)) {
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-04 12:05:50 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        traverse(element, node.value, visitor);
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-03 14:19:54 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-04 12:05:50 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      visitor.exitSelect?.(element, parent);
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-03 14:19:54 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    } else if (element.type === TYPE.plural) {
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-04 12:05:50 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      visitor.enterPlural?.(element, parent);
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-03 14:19:54 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      for (const node of Object.values(element.options)) {
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-04 12:05:50 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        traverse(element, node.value, visitor);
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-03 14:19:54 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      }
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-04 12:05:50 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      visitor.exitPlural?.(element, parent);
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-03 14:19:54 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    } else if (element.type === TYPE.pound) {
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-04 12:05:50 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      visitor.enterPound?.(element, parent);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      visitor.exitPound?.(element, parent);
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-03 14:19:54 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    } else if (element.type === TYPE.tag) {
							 | 
						
					
						
							
								
									
										
										
										
											2023-04-04 12:05:50 -07:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								      visitor.enterTag?.(element, parent);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      traverse(element, element.children, visitor);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      visitor.exitTag?.(element, parent);
							 | 
						
					
						
							
								
									
										
										
										
											2022-10-03 14:19:54 -07:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    } else {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								      unreachable(element);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								function unreachable(x: never): never {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								  throw new Error(`unreachable: ${x}`);
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								}
							 |