uniqueId.ts
1 import { getContext } from 'svelte'; 2 3 export const UNIQUE_ID_CONTEXT_NAME = 'amp-web-unique-id'; 4 5 interface UniqueContext { 6 nextId: number; 7 } 8 9 // TODO: rdar://84029606 (Extract logger into shared util) 10 interface Logger { 11 warn(...args: any[]): string; 12 } 13 interface LoggerFactory { 14 loggerFor(name: string): Logger; 15 } 16 17 export function initializeUniqueIdContext( 18 context: Map<string, unknown>, 19 loggerFactory: LoggerFactory, 20 ): void { 21 const logger = loggerFactory.loggerFor('uniqueIdContext'); 22 23 if (context.has(UNIQUE_ID_CONTEXT_NAME)) { 24 logger.warn( 25 `${UNIQUE_ID_CONTEXT_NAME} context has already been created. Cannot be created more than once`, 26 ); 27 } else { 28 const INITAL_STATE: UniqueContext = { nextId: 0 }; 29 context.set(UNIQUE_ID_CONTEXT_NAME, INITAL_STATE); 30 } 31 } 32 33 /** 34 * Creates a unique Id string based on string provided 35 * 36 * @returns unique id string 37 */ 38 export type UniqueIdGenerator = () => string; 39 40 // Custom elements most likely will not be used in an environment has that initialized the Svelte 41 // context. Components that are later wrapped by a custom element should use this function so that 42 // they can generate unique ids automatically when used inside a Svelte app, but not throw an error 43 // when used in other contexts. 44 // 45 export function maybeGetUniqueIdGenerator(): UniqueIdGenerator | undefined { 46 const UNIQUE_ID_PREFIX = 'uid-'; 47 const state: UniqueContext = getContext(UNIQUE_ID_CONTEXT_NAME); 48 const isNextIdANumber = typeof state?.nextId === 'number'; 49 50 if (!isNextIdANumber) { 51 return; 52 } 53 54 return () => { 55 const id = `${UNIQUE_ID_PREFIX}${state.nextId}`; 56 state.nextId += 1; 57 return id; 58 }; 59 } 60 61 export function getUniqueIdGenerator(): UniqueIdGenerator { 62 const uniqueIdGenerator = maybeGetUniqueIdGenerator(); 63 64 if (!uniqueIdGenerator) { 65 throw new Error( 66 `${UNIQUE_ID_CONTEXT_NAME} context has not been initialized. Initialize at application bootstrap.`, 67 ); 68 } 69 70 return uniqueIdGenerator; 71 }