{"version":3,"sources":["../src/corti.ts","../src/SpeechRecognitionEvent.ts","../src/SpeechRecognitionResultList.ts","../src/SpeechRecognitionResult.ts","../src/SpeechRecognitionAlternative.ts"],"sourcesContent":["import SpeechRecognitionEvent from './SpeechRecognitionEvent';\nimport SpeechRecognitionResultList from './SpeechRecognitionResultList';\nimport SpeechRecognitionResult from './SpeechRecognitionResult';\nimport SpeechRecognitionAlternative from './SpeechRecognitionAlternative';\n\ntype CortiEventType = 'start' | 'soundstart' | 'end' | 'result';\ntype CortiEventListener = (event: Event) => void;\n\nclass SpeechRecognition {\n  #maxAlternatives = 1;\n  #lang = '';\n  #continuous = false;\n  #interimResults = false;\n  #started = false;\n\n  #listeners = new Map<CortiEventType, CortiEventListener[]>([\n    ['start', []],\n    ['soundstart', []],\n    ['end', []],\n    ['result', []],\n  ]);\n\n  // @todo Add support for other listeners defined in the spec https://dvcs.w3.org/hg/speech-api/raw-file/tip/webspeechapi#speechreco-events\n  #onListeners = new Map<string, CortiEventListener | null>([\n    ['onstart', null],\n    ['onsoundstart', null],\n    ['onend', null],\n    ['onresult', null],\n  ]);\n\n  get onstart(): CortiEventListener | null {\n    return this.#onListeners.get('onstart') ?? null;\n  }\n\n  set onstart(value: CortiEventListener) {\n    if (typeof value === 'function') {\n      this.#onListeners.set('onstart', value);\n    }\n  }\n\n  get onsoundstart(): CortiEventListener | null {\n    return this.#onListeners.get('onsoundstart') ?? null;\n  }\n\n  set onsoundstart(value: CortiEventListener) {\n    if (typeof value === 'function') {\n      this.#onListeners.set('onsoundstart', value);\n    }\n  }\n\n  get onend(): CortiEventListener | null {\n    return this.#onListeners.get('onend') ?? null;\n  }\n\n  set onend(value: CortiEventListener) {\n    if (typeof value === 'function') {\n      this.#onListeners.set('onend', value);\n    }\n  }\n\n  get onresult(): CortiEventListener | null {\n    return this.#onListeners.get('onresult') ?? null;\n  }\n\n  set onresult(value: CortiEventListener) {\n    if (typeof value === 'function') {\n      this.#onListeners.set('onresult', value);\n    }\n  }\n\n  get maxAlternatives(): number {\n    return this.#maxAlternatives;\n  }\n\n  set maxAlternatives(val: any) {\n    if (typeof val === 'number') {\n      this.#maxAlternatives = Math.floor(val);\n    } else {\n      this.#maxAlternatives = 0;\n    }\n  }\n\n  get lang(): string {\n    return this.#lang;\n  }\n\n  set lang(val: any) {\n    if (val === undefined) {\n      this.#lang = 'undefined';\n    } else {\n      this.#lang = val.toString();\n    }\n  }\n\n  get continuous(): boolean {\n    return this.#continuous;\n  }\n\n  set continuous(val: any) {\n    this.#continuous = Boolean(val);\n  }\n\n  get interimResults(): boolean {\n    return this.#interimResults;\n  }\n\n  set interimResults(val: any) {\n    this.#interimResults = Boolean(val);\n  }\n\n  /**\n   * Checks if the recognition has started.\n   * This is not part of the spec, but is used by the mock object for testing.\n   */\n  isStarted(): boolean {\n    return this.#started;\n  }\n\n  /**\n   * Starts the speech recognition.\n   * @throws {DOMException} If recognition has already started\n   */\n  start(): void {\n    if (this.#started) {\n      throw new DOMException(\"Failed to execute 'start' on 'SpeechRecognition': recognition has already started.\");\n    }\n\n    this.#started = true;\n\n    this.#emit('start');\n    this.#emit('soundstart');\n  }\n\n  /**\n   * Aborts the speech recognition.\n   */\n  abort(): void {\n    if (!this.#started) {\n      return;\n    }\n    this.#started = false;\n    this.#emit('end');\n  }\n\n  /**\n   * Stops the speech recognition and attempts to return a SpeechRecognitionResult.\n   * @todo Implement stop's behavior according to the spec. Unlike abort, stop will attempt to return a SpeechRecognitionResult using the audio captured so far.\n   */\n  stop(): void {\n    return this.abort();\n  }\n\n  /**\n   * Register an event listener for the given event type.\n   */\n  addEventListener(type: string, listener: CortiEventListener): void {\n    if (this.#listeners.has(type as CortiEventType)) {\n      this.#listeners.get(type as CortiEventType)!.push(listener);\n    }\n  }\n\n  /**\n   * Remove an event listener for the given event type.\n   * @todo Implement removeEventListener\n   */\n  removeEventListener(_type: string, _listener: CortiEventListener): void {}\n\n  /**\n   * Simulate speech said and recognized (if SpeechRecognition is running).\n   */\n  say(alternatives: string | string[]): void {\n    if (!this.#started) {\n      return;\n    }\n\n    const sentences = Array.isArray(alternatives) ? alternatives : [alternatives];\n\n    // Ensure the length of speechRecognitionAlternatives matches #maxAlternatives\n    if (sentences.length > this.#maxAlternatives) {\n      sentences.splice(this.#maxAlternatives);\n    } else {\n      const paddingNeeded = this.#maxAlternatives - sentences.length;\n      let previousPaddedSentence = sentences[0];\n      for (let i = 0; i < paddingNeeded; i += 1) {\n        if (i % 2 === 0) {\n          previousPaddedSentence = `${previousPaddedSentence} and so on`;\n        } else {\n          previousPaddedSentence = `${previousPaddedSentence} and so forth`;\n        }\n        sentences.push(previousPaddedSentence);\n      }\n    }\n\n    const speechRecognitionAlternatives = sentences.map((sentence, index) => {\n      const confidence = Math.max(0.95 * 0.9 ** index, 0.01);\n      return new SpeechRecognitionAlternative(sentence, confidence);\n    });\n\n    const SREvent = new SpeechRecognitionEvent('result', {\n      results: new SpeechRecognitionResultList([new SpeechRecognitionResult(speechRecognitionAlternatives)]),\n      resultIndex: 0,\n    });\n    this.#emit('result', SREvent);\n\n    if (!this.#continuous) {\n      this.abort();\n    }\n  }\n\n  /**\n   * Emit an event to all registered listeners.\n   * @todo Corti will emit events in the order they were registered with addEventListener and then with the on* property. This is not the same as the Chrome implementation which will emit the listener registered with on* at the order it was registered.\n   */\n  #emit(eventType: CortiEventType, eventObject?: Event): void {\n    const eventToEmit = eventObject || new Event(eventType);\n\n    const listeners = this.#listeners.get(eventType);\n    if (listeners) {\n      listeners.forEach(listener => listener(eventToEmit));\n    }\n    const onListener = this.#onListeners.get(`on${eventType}`);\n    if (onListener) {\n      onListener(eventToEmit);\n    }\n  }\n}\n\n/**\n * Interface for casting a DOM SpeechRecognition instance to access Corti-specific\n * test methods (say, isStarted). Extends the DOM SpeechRecognition interface so\n * consumers can cast without going through `unknown`:\n *\n *   const sr = getSpeechRecognizer() as CortiSpeechRecognition;\n *   sr.say('hello');\n */\ninterface CortiSpeechRecognition extends globalThis.SpeechRecognition {\n  say(alternatives: string | string[]): void;\n  isStarted(): boolean;\n}\n\nexport {\n  SpeechRecognition,\n  SpeechRecognitionEvent,\n  SpeechRecognitionResultList,\n  SpeechRecognitionResult,\n  SpeechRecognitionAlternative,\n};\nexport type { CortiSpeechRecognition };\n","import SpeechRecognitionResultList from './SpeechRecognitionResultList';\n\nclass SpeechRecognitionEvent extends Event {\n  readonly interpretation: null = null;\n  readonly emma: null = null;\n  readonly resultIndex: number;\n  readonly results: SpeechRecognitionResultList;\n\n  constructor(type: string, { resultIndex, results }: { resultIndex: number; results: SpeechRecognitionResultList }) {\n    super(type);\n    this.resultIndex = resultIndex;\n    this.results = results;\n  }\n}\n\nexport default SpeechRecognitionEvent;\n","import SpeechRecognitionResult from './SpeechRecognitionResult';\n\nclass SpeechRecognitionResultList {\n  readonly length: number;\n  [index: number]: SpeechRecognitionResult;\n\n  constructor(results: SpeechRecognitionResult[] = []) {\n    results.forEach((result, index) => {\n      this[index] = result;\n    });\n    this.length = results.length;\n  }\n\n  item(index?: number | string): SpeechRecognitionResult | null {\n    if (arguments.length === 0) {\n      throw new TypeError(\n        \"Failed to execute 'item' on 'SpeechRecognitionResultList': 1 argument required, but only 0 present.\"\n      );\n    }\n    if (typeof index !== 'number' || Number.isNaN(index)) {\n      return this[0] || null;\n    }\n    return this[index] || null;\n  }\n\n  *[Symbol.iterator](): Iterator<SpeechRecognitionResult> {\n    for (let i = 0; i < this.length; i += 1) {\n      yield this[i];\n    }\n  }\n}\n\nexport default SpeechRecognitionResultList;\n","import SpeechRecognitionAlternative from './SpeechRecognitionAlternative';\n\nclass SpeechRecognitionResult {\n  readonly isFinal: boolean = true;\n  readonly length: number;\n  [index: number]: SpeechRecognitionAlternative;\n\n  constructor(alternatives: SpeechRecognitionAlternative[] = []) {\n    alternatives.forEach((alternative, index) => {\n      this[index] = alternative;\n    });\n    this.length = alternatives.length;\n  }\n\n  item(index?: number | string): SpeechRecognitionAlternative | null {\n    if (arguments.length === 0) {\n      throw new TypeError(\n        \"Failed to execute 'item' on 'SpeechRecognitionResult': 1 argument required, but only 0 present.\"\n      );\n    }\n    if (typeof index !== 'number' || Number.isNaN(index)) {\n      return this[0] || null;\n    }\n    return this[index] || null;\n  }\n\n  *[Symbol.iterator](): Iterator<SpeechRecognitionAlternative> {\n    for (let i = 0; i < this.length; i += 1) {\n      yield this[i];\n    }\n  }\n}\n\nexport default SpeechRecognitionResult;\n","class SpeechRecognitionAlternative {\n  readonly transcript: string;\n  readonly confidence: number;\n\n  constructor(transcript: string, confidence: number = 1) {\n    this.transcript = transcript;\n    this.confidence = confidence;\n  }\n}\n\nexport default SpeechRecognitionAlternative;\n"],"mappings":"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","names":[]}