From c0f352b01f0a1a85326eb9b4e230ce87ef81a8a0 Mon Sep 17 00:00:00 2001 From: Sora Morimoto Date: Tue, 1 Apr 2025 22:27:05 +0900 Subject: [PATCH 1/2] _ Signed-off-by: Sora Morimoto --- .github/workflows/typedoc.yml | 51 + .gitignore | 1 + README.md | 3 +- package.json | 18 +- ...ognition.js => NativeSpeechRecognition.ts} | 2 +- ...nitionManager.js => RecognitionManager.ts} | 90 +- ...echRecognition.js => SpeechRecognition.ts} | 69 +- src/actions.js | 15 - src/actions.ts | 24 + src/{constants.js => constants.ts} | 0 src/global.d.ts | 11 + src/index.js | 4 - src/index.ts | 6 + src/{isAndroid.js => isAndroid.ts} | 0 src/{reducers.js => reducers.ts} | 10 +- src/types.ts | 107 ++ src/{utils.js => utils.ts} | 38 +- tsconfig.json | 16 + typedoc.json | 7 + yarn.lock | 930 +++++++++++------- 20 files changed, 919 insertions(+), 483 deletions(-) create mode 100644 .github/workflows/typedoc.yml rename src/{NativeSpeechRecognition.js => NativeSpeechRecognition.ts} (85%) rename src/{RecognitionManager.js => RecognitionManager.ts} (76%) rename src/{SpeechRecognition.js => SpeechRecognition.ts} (82%) delete mode 100644 src/actions.js create mode 100644 src/actions.ts rename src/{constants.js => constants.ts} (100%) create mode 100644 src/global.d.ts delete mode 100644 src/index.js create mode 100644 src/index.ts rename src/{isAndroid.js => isAndroid.ts} (100%) rename src/{reducers.js => reducers.ts} (69%) create mode 100644 src/types.ts rename src/{utils.js => utils.ts} (78%) create mode 100644 tsconfig.json create mode 100644 typedoc.json diff --git a/.github/workflows/typedoc.yml b/.github/workflows/typedoc.yml new file mode 100644 index 0000000..9cedc01 --- /dev/null +++ b/.github/workflows/typedoc.yml @@ -0,0 +1,51 @@ +name: Deploy typedoc to Pages + +on: + push: + branches: + - master + workflow_dispatch: + +permissions: read-all + +concurrency: + group: pages + cancel-in-progress: true + +jobs: + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + permissions: + contents: read + pages: write + id-token: write + runs-on: ubuntu-latest + steps: + - name: Checkout tree + uses: actions/checkout@v4 + + - name: Set-up Node.js + uses: actions/setup-node@v4 + with: + check-latest: true + node-version-file: .nvmrc + + - run: corepack enable + + - run: yarn install --immutable + + - run: yarn typedoc + + - name: Set-up Pages + uses: actions/configure-pages@v5 + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: _site + + - name: Deploy odoc to GitHub Pages + uses: actions/deploy-pages@v4 + id: deployment diff --git a/.gitignore b/.gitignore index 1d3bfd8..f123531 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/_site/ /.yarn/ /coverage/ /dist/ diff --git a/README.md b/README.md index adf0092..79739eb 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ -# react-speech-recognition A React hook that converts speech from the microphone to text and makes it available to your React components. [![npm version](https://img.shields.io/npm/v/react-speech-recognition.svg)](https://www.npmjs.com/package/react-speech-recognition) @@ -88,7 +87,7 @@ By default, speech recognition is not supported in all browsers, with the best n * ❌ Without a polyfill, your users' voice data will be sent to big tech companies like Google or Apple to be transcribed * ✅ With a polyfill, `react-speech-recognition` will be suitable for use in commercial applications * ❌ Without a polyfill, `react-speech-recognition` will still be fine for personal projects or use cases where cross-browser support is not needed - + `react-speech-recognition` currently supports polyfills for the following cloud providers:
diff --git a/package.json b/package.json index a4fca1d..5065e52 100644 --- a/package.json +++ b/package.json @@ -16,15 +16,18 @@ "exports": { ".": { "import": { + "types": "./dist/index.d.ts", "default": "./dist/index.js" }, "require": { + "types": "./dist/index.d.cts", "default": "./dist/index.cjs" } } }, "main": "./dist/index.cjs", "module": "./dist/index.js", + "types": "./dist/index.d.cts", "files": [ "dist" ], @@ -33,19 +36,26 @@ "fix": "biome check --fix", "lint": "biome check", "prepack": "bunchee", - "test": "vitest" + "test": "vitest", + "typedoc": "typedoc" + }, + "dependencies": { + "lodash.debounce": "^4.0.8" }, "devDependencies": { "@biomejs/biome": "1.9.4", "@testing-library/react-hooks": "3.7.0", - "@vitest/coverage-v8": "3.0.8", - "bunchee": "6.4.0", + "@tsconfig/strictest": "2.0.5", + "@types/lodash.debounce": "4.0.9", + "@vitest/coverage-v8": "3.1.1", + "bunchee": "6.5.0", "jsdom": "26.0.0", "react": "16.14.0", "react-dom": "16.14.0", "react-test-renderer": "16.14.0", + "typedoc": "0.28.1", "typescript": "5.8.2", - "vitest": "3.0.8" + "vitest": "3.1.1" }, "peerDependencies": { "react": ">=16.8.0" diff --git a/src/NativeSpeechRecognition.js b/src/NativeSpeechRecognition.ts similarity index 85% rename from src/NativeSpeechRecognition.js rename to src/NativeSpeechRecognition.ts index 734f214..30b032b 100644 --- a/src/NativeSpeechRecognition.js +++ b/src/NativeSpeechRecognition.ts @@ -6,7 +6,7 @@ const NativeSpeechRecognition = window.msSpeechRecognition || window.oSpeechRecognition); -export const isNative = (SpeechRecognition) => +export const isNative = (SpeechRecognition: unknown) => SpeechRecognition === NativeSpeechRecognition; export default NativeSpeechRecognition; diff --git a/src/RecognitionManager.js b/src/RecognitionManager.ts similarity index 76% rename from src/RecognitionManager.js rename to src/RecognitionManager.ts index 5070d30..f4eeeb8 100644 --- a/src/RecognitionManager.js +++ b/src/RecognitionManager.ts @@ -1,19 +1,31 @@ -import { isNative } from "./NativeSpeechRecognition"; -import isAndroid from "./isAndroid"; -import { browserSupportsPolyfills, concatTranscripts, debounce } from "./utils"; +import debounce from "lodash.debounce"; +import { isNative } from "./NativeSpeechRecognition.js"; +import isAndroid from "./isAndroid.js"; +import { + Disconnect, + type ListeningOptions, + type SpeechRecognition, + type SpeechRecognitionErrorEvent, + type SpeechRecognitionEvent, + type SubscriberCallbacks, + type SubscriberId, + type SubscriberMap, + type Transcript, +} from "./types.js"; +import { browserSupportsPolyfills, concatTranscripts } from "./utils.js"; export default class RecognitionManager { - constructor(SpeechRecognition) { - this.recognition = null; - this.pauseAfterDisconnect = false; - this.interimTranscript = ""; - this.finalTranscript = ""; - this.listening = false; - this.isMicrophoneAvailable = true; - this.subscribers = {}; - this.onStopListening = () => {}; - this.previousResultWasFinalOnly = false; + private recognition: SpeechRecognition | null = null; + private pauseAfterDisconnect = false; + public interimTranscript = ""; + private finalTranscript = ""; + public listening = false; + public isMicrophoneAvailable = true; + private subscribers: SubscriberMap = {}; + private onStopListening = () => {}; + private previousResultWasFinalOnly = false; + constructor(SpeechRecognition: SpeechRecognition) { this.resetTranscript = this.resetTranscript.bind(this); this.startListening = this.startListening.bind(this); this.stopListening = this.stopListening.bind(this); @@ -24,15 +36,11 @@ export default class RecognitionManager { this.setSpeechRecognition(SpeechRecognition); if (isAndroid()) { - this.updateFinalTranscript = debounce( - this.updateFinalTranscript, - 250, - true, - ); + this.updateFinalTranscript = debounce(this.updateFinalTranscript, 250); } } - setSpeechRecognition(SpeechRecognition) { + setSpeechRecognition(SpeechRecognition: SpeechRecognition) { const browserSupportsRecogniser = !!SpeechRecognition && (isNative(SpeechRecognition) || browserSupportsPolyfills()); @@ -48,15 +56,15 @@ export default class RecognitionManager { this.emitBrowserSupportsSpeechRecognitionChange(browserSupportsRecogniser); } - subscribe(id, callbacks) { + subscribe(id: SubscriberId, callbacks: SubscriberCallbacks) { this.subscribers[id] = callbacks; } - unsubscribe(id) { + unsubscribe(id: SubscriberId) { delete this.subscribers[id]; } - emitListeningChange(listening) { + emitListeningChange(listening: boolean) { this.listening = listening; Object.keys(this.subscribers).forEach((id) => { const { onListeningChange } = this.subscribers[id]; @@ -64,7 +72,7 @@ export default class RecognitionManager { }); } - emitMicrophoneAvailabilityChange(isMicrophoneAvailable) { + emitMicrophoneAvailabilityChange(isMicrophoneAvailable: boolean) { this.isMicrophoneAvailable = isMicrophoneAvailable; Object.keys(this.subscribers).forEach((id) => { const { onMicrophoneAvailabilityChange } = this.subscribers[id]; @@ -72,7 +80,10 @@ export default class RecognitionManager { }); } - emitTranscriptChange(interimTranscript, finalTranscript) { + emitTranscriptChange( + interimTranscript: Transcript, + finalTranscript: Transcript, + ) { Object.keys(this.subscribers).forEach((id) => { const { onTranscriptChange } = this.subscribers[id]; onTranscriptChange(interimTranscript, finalTranscript); @@ -87,7 +98,7 @@ export default class RecognitionManager { } emitBrowserSupportsSpeechRecognitionChange( - browserSupportsSpeechRecognitionChange, + browserSupportsSpeechRecognitionChange: boolean, ) { Object.keys(this.subscribers).forEach((id) => { const { @@ -103,18 +114,18 @@ export default class RecognitionManager { }); } - disconnect(disconnectType) { + disconnect(disconnectType: Disconnect) { if (this.recognition && this.listening) { switch (disconnectType) { - case "ABORT": + case Disconnect.Abort: this.pauseAfterDisconnect = true; this.abort(); break; - case "RESET": + case Disconnect.Reset: this.pauseAfterDisconnect = false; this.abort(); break; - case "STOP": + case Disconnect.Stop: default: this.pauseAfterDisconnect = true; this.stop(); @@ -133,7 +144,7 @@ export default class RecognitionManager { } } - onError(event) { + onError(event: SpeechRecognitionErrorEvent) { if (event && event.error && event.error === "not-allowed") { this.emitMicrophoneAvailabilityChange(false); this.disableRecognition(); @@ -155,7 +166,7 @@ export default class RecognitionManager { this.pauseAfterDisconnect = false; } - updateTranscript({ results, resultIndex }) { + updateTranscript({ results, resultIndex }: SpeechRecognitionEvent) { const currentIndex = resultIndex === undefined ? results.length - 1 : resultIndex; this.interimTranscript = ""; @@ -187,7 +198,7 @@ export default class RecognitionManager { } } - updateFinalTranscript(newFinalTranscript) { + updateFinalTranscript(newFinalTranscript: Transcript) { this.finalTranscript = concatTranscripts( this.finalTranscript, newFinalTranscript, @@ -195,10 +206,13 @@ export default class RecognitionManager { } resetTranscript() { - this.disconnect("RESET"); + this.disconnect(Disconnect.Reset); } - async startListening({ continuous = false, language } = {}) { + async startListening({ + continuous = false, + language, + }: ListeningOptions = {}) { if (!this.recognition) { return; } @@ -234,17 +248,17 @@ export default class RecognitionManager { } async abortListening() { - this.disconnect("ABORT"); + this.disconnect(Disconnect.Abort); this.emitListeningChange(false); - await new Promise((resolve) => { + await new Promise((resolve) => { this.onStopListening = resolve; }); } async stopListening() { - this.disconnect("STOP"); + this.disconnect(Disconnect.Stop); this.emitListeningChange(false); - await new Promise((resolve) => { + await new Promise((resolve) => { this.onStopListening = resolve; }); } diff --git a/src/SpeechRecognition.js b/src/SpeechRecognition.ts similarity index 82% rename from src/SpeechRecognition.js rename to src/SpeechRecognition.ts index 6690456..209c531 100644 --- a/src/SpeechRecognition.js +++ b/src/SpeechRecognition.ts @@ -1,27 +1,31 @@ import { useCallback, useEffect, useReducer, useRef, useState } from "react"; -import NativeSpeechRecognition from "./NativeSpeechRecognition"; -import RecognitionManager from "./RecognitionManager"; -import { appendTranscript, clearTranscript } from "./actions"; -import isAndroid from "./isAndroid"; -import { transcriptReducer } from "./reducers"; +import NativeSpeechRecognition from "./NativeSpeechRecognition.js"; +import RecognitionManager from "./RecognitionManager.js"; +import { appendTranscript, clearTranscript } from "./actions.js"; +import isAndroid from "./isAndroid.js"; +import { transcriptReducer } from "./reducers.js"; +import type { + FuzzyMatch, + ListeningOptions, + Match, + Phrase, + SpeechRecognition as PolyfillSpeechRecognition, + Transcript, + UseSpeechRecognitionOptions, +} from "./types.js"; import { browserSupportsPolyfills, commandToRegExp, compareTwoStringsUsingDiceCoefficient, concatTranscripts, -} from "./utils"; - -let _browserSupportsSpeechRecognition = !!NativeSpeechRecognition; -let _browserSupportsContinuousListening = - _browserSupportsSpeechRecognition && !isAndroid(); -let recognitionManager; +} from "./utils.js"; const useSpeechRecognition = ({ transcribing = true, clearTranscriptOnListen = true, commands = [], -} = {}) => { - const [recognitionManager] = useState( +}: UseSpeechRecognitionOptions = {}) => { + const [recognitionManager] = useState( SpeechRecognition.getRecognitionManager(), ); const [ @@ -55,7 +59,11 @@ const useSpeechRecognition = ({ dispatchClearTranscript(); }, [recognitionManager]); - const testFuzzyMatch = (command, input, fuzzyMatchingThreshold) => { + const testFuzzyMatch = ( + command: Phrase, + input: Transcript, + fuzzyMatchingThreshold: number, + ): FuzzyMatch | null => { const commandToString = typeof command === "object" ? command.toString() : command; const commandWithoutSpecials = commandToString @@ -77,20 +85,21 @@ const useSpeechRecognition = ({ return null; }; - const testMatch = (command, input) => { + const testMatch = (command: Phrase, input: Transcript): Match | null => { const pattern = commandToRegExp(command); const result = pattern.exec(input); if (result) { return { command, parameters: result.slice(1), + // isFuzzyMatch: false, }; } return null; }; const matchCommands = useCallback( - (newInterimTranscript, newFinalTranscript) => { + (newInterimTranscript: Transcript, newFinalTranscript: Transcript) => { commandsRef.current.forEach( ({ command, @@ -116,10 +125,13 @@ const useSpeechRecognition = ({ } return testMatch(subcommand, input); }) - .filter((x) => x); + .filter((x): x is FuzzyMatch | Match => x !== null); if (isFuzzyMatch && bestMatchOnly && results.length >= 2) { - results.sort((a, b) => b.howSimilar - a.howSimilar); - const { command, commandWithoutSpecials, howSimilar } = results[0]; + (results as FuzzyMatch[]).sort( + (a, b) => b.howSimilar - a.howSimilar, + ); + const { command, commandWithoutSpecials, howSimilar } = + results[0] as FuzzyMatch; callback(commandWithoutSpecials, input, howSimilar, { command, resetTranscript, @@ -127,13 +139,14 @@ const useSpeechRecognition = ({ } else { results.forEach((result) => { if (result.isFuzzyMatch) { - const { command, commandWithoutSpecials, howSimilar } = result; + const { command, commandWithoutSpecials, howSimilar } = + result as FuzzyMatch; callback(commandWithoutSpecials, input, howSimilar, { command, resetTranscript, }); } else { - const { command, parameters } = result; + const { command, parameters } = result as Match; callback(...parameters, { command, resetTranscript }); } }); @@ -145,7 +158,7 @@ const useSpeechRecognition = ({ ); const handleTranscriptChange = useCallback( - (newInterimTranscript, newFinalTranscript) => { + (newInterimTranscript: string, newFinalTranscript: string) => { if (transcribing) { dispatch(appendTranscript(newInterimTranscript, newFinalTranscript)); } @@ -161,7 +174,7 @@ const useSpeechRecognition = ({ }, [clearTranscriptOnListen]); useEffect(() => { - const id = SpeechRecognition.counter; + const id = SpeechRecognition.counter.toString(); SpeechRecognition.counter += 1; const callbacks = { onListeningChange: setListening, @@ -198,9 +211,15 @@ const useSpeechRecognition = ({ browserSupportsContinuousListening, }; }; + +let _browserSupportsSpeechRecognition = !!NativeSpeechRecognition; +let _browserSupportsContinuousListening = + _browserSupportsSpeechRecognition && !isAndroid(); +let recognitionManager: RecognitionManager; + const SpeechRecognition = { counter: 0, - applyPolyfill: (PolyfillSpeechRecognition) => { + applyPolyfill: (PolyfillSpeechRecognition: PolyfillSpeechRecognition) => { if (recognitionManager) { recognitionManager.setSpeechRecognition(PolyfillSpeechRecognition); } else { @@ -231,7 +250,7 @@ const SpeechRecognition = { const recognitionManager = SpeechRecognition.getRecognitionManager(); return recognitionManager.getRecognition(); }, - startListening: async ({ continuous, language } = {}) => { + startListening: async ({ continuous, language }: ListeningOptions = {}) => { const recognitionManager = SpeechRecognition.getRecognitionManager(); await recognitionManager.startListening({ continuous, language }); }, diff --git a/src/actions.js b/src/actions.js deleted file mode 100644 index 43851de..0000000 --- a/src/actions.js +++ /dev/null @@ -1,15 +0,0 @@ -import { APPEND_TRANSCRIPT, CLEAR_TRANSCRIPT } from "./constants"; - -export const clearTranscript = () => { - return { type: CLEAR_TRANSCRIPT }; -}; - -export const appendTranscript = (interimTranscript, finalTranscript) => { - return { - type: APPEND_TRANSCRIPT, - payload: { - interimTranscript, - finalTranscript, - }, - }; -}; diff --git a/src/actions.ts b/src/actions.ts new file mode 100644 index 0000000..df07ccf --- /dev/null +++ b/src/actions.ts @@ -0,0 +1,24 @@ +import { APPEND_TRANSCRIPT, CLEAR_TRANSCRIPT } from "./constants.js"; +import type { Transcript } from "./types.js"; + +export const clearTranscript = () => { + return { type: CLEAR_TRANSCRIPT } as const; +}; + +export const appendTranscript = ( + interimTranscript: Transcript, + finalTranscript: Transcript, +) => { + return { + type: APPEND_TRANSCRIPT, + payload: { + interimTranscript, + finalTranscript, + }, + } as const; +}; + +type ClearTranscriptAction = ReturnType; +type AppendTranscriptAction = ReturnType; +export type TranscriptState = AppendTranscriptAction["payload"]; +export type TranscriptAction = ClearTranscriptAction | AppendTranscriptAction; diff --git a/src/constants.js b/src/constants.ts similarity index 100% rename from src/constants.js rename to src/constants.ts diff --git a/src/global.d.ts b/src/global.d.ts new file mode 100644 index 0000000..acf82a2 --- /dev/null +++ b/src/global.d.ts @@ -0,0 +1,11 @@ +import type { SpeechRecognition } from "./types"; + +declare global { + interface Window { + SpeechRecognition?: SpeechRecognition; + webkitSpeechRecognition?: SpeechRecognition; + mozSpeechRecognition?: SpeechRecognition; + msSpeechRecognition?: SpeechRecognition; + oSpeechRecognition?: SpeechRecognition; + } +} diff --git a/src/index.js b/src/index.js deleted file mode 100644 index ff25382..0000000 --- a/src/index.js +++ /dev/null @@ -1,4 +0,0 @@ -import SpeechRecognition, { useSpeechRecognition } from "./SpeechRecognition"; - -export { useSpeechRecognition }; -export default SpeechRecognition; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..281a8c4 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,6 @@ +import SpeechRecognition, { + useSpeechRecognition, +} from "./SpeechRecognition.js"; + +export { useSpeechRecognition }; +export default SpeechRecognition; diff --git a/src/isAndroid.js b/src/isAndroid.ts similarity index 100% rename from src/isAndroid.js rename to src/isAndroid.ts diff --git a/src/reducers.js b/src/reducers.ts similarity index 69% rename from src/reducers.js rename to src/reducers.ts index 0f1a39c..0453fd7 100644 --- a/src/reducers.js +++ b/src/reducers.ts @@ -1,7 +1,11 @@ -import { APPEND_TRANSCRIPT, CLEAR_TRANSCRIPT } from "./constants"; -import { concatTranscripts } from "./utils"; +import type { TranscriptAction, TranscriptState } from "./actions.js"; +import { APPEND_TRANSCRIPT, CLEAR_TRANSCRIPT } from "./constants.js"; +import { concatTranscripts } from "./utils.js"; -const transcriptReducer = (state, action) => { +const transcriptReducer = ( + state: TranscriptState, + action: TranscriptAction, +): TranscriptState => { switch (action.type) { case CLEAR_TRANSCRIPT: return { diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..bf0d5c4 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,107 @@ +export type Transcript = string; + +export type SubscriberId = string; + +export type SubscriberCallbacks = { + onListeningChange: (listening: boolean) => void; + onMicrophoneAvailabilityChange: (isMicrophoneAvailable: boolean) => void; + onTranscriptChange: ( + interimTranscript: Transcript, + finalTranscript: Transcript, + ) => void; + onClearTranscript: () => void; + onBrowserSupportsSpeechRecognitionChange: ( + browserSupportsSpeechRecognitionChange: boolean, + ) => void; + onBrowserSupportsContinuousListeningChange: ( + browserSupportsSpeechRecognitionChange: boolean, + ) => void; +}; + +export type SubscriberMap = { + [id: SubscriberId]: SubscriberCallbacks; +}; + +export enum Disconnect { + Abort = "ABORT", + Stop = "STOP", + Reset = "RESET", +} + +export type ListeningOptions = { + continuous?: boolean; + language?: string; +}; + +export type SpeechRecognitionAlternative = { + transcript: string; + confidence: number; +}; + +export type SpeechRecognitionResult = { + 0: SpeechRecognitionAlternative; + isFinal: boolean; +}; + +export type SpeechRecognitionEvent = { + results: SpeechRecognitionResult[]; + resultIndex: number; +}; + +export type SpeechRecognitionErrorEvent = { + error: "not-allowed" | "audio-capture"; + message: string; +}; + +export type SpeechRecognitionEventCallback = ( + speechRecognitionEvent: SpeechRecognitionEvent, +) => void; + +export type SpeechEndCallback = () => void; + +export type SpeechErrorCallback = ( + speechRecognitionErrorEvent: SpeechRecognitionErrorEvent, +) => void; + +export interface SpeechRecognition { + lang: string; + continuous: boolean; + interimResults: boolean; + onresult: SpeechRecognitionEventCallback; + onend: SpeechEndCallback; + onerror: SpeechErrorCallback; + start: () => Promise; + stop: () => Promise; + abort: () => Promise; + new (): SpeechRecognition; +} + +export type Phrase = string | RegExp; + +export type FuzzyMatch = { + command: Phrase; + commandWithoutSpecials: string; + howSimilar: number; + isFuzzyMatch: boolean; +}; + +export type Match = { + command: Phrase; + parameters: string[]; + isFuzzyMatch: boolean; +}; + +export type Command = { + command: Phrase | Phrase[]; + callback: (...args: any[]) => void; + matchInterim: boolean; + isFuzzyMatch: boolean; + fuzzyMatchingThreshold: number; + bestMatchOnly: boolean; +}; + +export type UseSpeechRecognitionOptions = { + transcribing?: boolean; + clearTranscriptOnListen?: boolean; + commands?: Command[]; +}; diff --git a/src/utils.js b/src/utils.ts similarity index 78% rename from src/utils.js rename to src/utils.ts index 76efec3..5424e7a 100644 --- a/src/utils.js +++ b/src/utils.ts @@ -1,20 +1,12 @@ -const debounce = (func, wait, immediate) => { - let timeout; - return function () { - const context = this; - const args = arguments; - const later = function () { - timeout = null; - if (!immediate) func.apply(context, args); - }; - const callNow = immediate && !timeout; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - if (callNow) func.apply(context, args); - }; -}; +import type { Phrase } from "./types"; + +declare global { + interface Window { + webkitAudioContext?: typeof AudioContext; + } +} -const concatTranscripts = (...transcriptParts) => { +const concatTranscripts = (...transcriptParts: string[]) => { return transcriptParts .map((t) => t.trim()) .join(" ") @@ -27,7 +19,7 @@ const optionalRegex = /(\(\?:[^)]+\))\?/g; const namedParam = /(\(\?)?:\w+/g; const splatParam = /\*/g; const escapeRegExp = /[-{}[\]+?.,\\^$|#]/g; -const commandToRegExp = (command) => { +const commandToRegExp = (command: Phrase) => { if (command instanceof RegExp) { return new RegExp(command.source, "i"); } @@ -43,7 +35,10 @@ const commandToRegExp = (command) => { }; // this is from https://github.com/aceakash/string-similarity -const compareTwoStringsUsingDiceCoefficient = (first, second) => { +const compareTwoStringsUsingDiceCoefficient = ( + first: string, + second: string, +) => { first = first.replace(/\s+/g, "").toLowerCase(); second = second.replace(/\s+/g, "").toLowerCase(); @@ -53,10 +48,10 @@ const compareTwoStringsUsingDiceCoefficient = (first, second) => { if (first.length === 1 && second.length === 1) return 0; // both are 1-letter strings if (first.length < 2 || second.length < 2) return 0; // if either is a 1-letter string - const firstBigrams = new Map(); + const firstBigrams = new Map(); for (let i = 0; i < first.length - 1; i++) { const bigram = first.substring(i, i + 2); - const count = firstBigrams.has(bigram) ? firstBigrams.get(bigram) + 1 : 1; + const count = firstBigrams.has(bigram) ? firstBigrams.get(bigram)! + 1 : 1; firstBigrams.set(bigram, count); } @@ -64,7 +59,7 @@ const compareTwoStringsUsingDiceCoefficient = (first, second) => { let intersectionSize = 0; for (let i = 0; i < second.length - 1; i++) { const bigram = second.substring(i, i + 2); - const count = firstBigrams.has(bigram) ? firstBigrams.get(bigram) : 0; + const count = firstBigrams.has(bigram) ? firstBigrams.get(bigram)! : 0; if (count > 0) { firstBigrams.set(bigram, count - 1); @@ -87,7 +82,6 @@ const browserSupportsPolyfills = () => { }; export { - debounce, concatTranscripts, commandToRegExp, compareTwoStringsUsingDiceCoefficient, diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..0fbe8f1 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "@tsconfig/strictest", + "compilerOptions": { + "exactOptionalPropertyTypes": false, + "forceConsistentCasingInFileNames": true, + "jsx": "react", + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, + "noPropertyAccessFromIndexSignature": false, + "noUncheckedIndexedAccess": false, + "target": "ESNext" + }, + "include": ["**/*.ts", "**/*.tsx"], + "exclude": ["_site", "node_modules", "dist", "coverage"] +} diff --git a/typedoc.json b/typedoc.json new file mode 100644 index 0000000..b189cea --- /dev/null +++ b/typedoc.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "name": "React Speech Recognition API Reference", + "entryPoints": ["src/*.ts"], + "projectDocuments": ["docs/POLYFILLS.md", "docs/V3-MIGRATION.md"], + "out": "_site" +} diff --git a/yarn.lock b/yarn.lock index f1d43dd..b876be1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -28,7 +28,7 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.24.2": +"@babel/code-frame@npm:^7.26.2": version: 7.26.2 resolution: "@babel/code-frame@npm:7.26.2" dependencies: @@ -54,32 +54,32 @@ __metadata: linkType: hard "@babel/parser@npm:^7.25.4": - version: 7.26.10 - resolution: "@babel/parser@npm:7.26.10" + version: 7.27.0 + resolution: "@babel/parser@npm:7.27.0" dependencies: - "@babel/types": "npm:^7.26.10" + "@babel/types": "npm:^7.27.0" bin: parser: ./bin/babel-parser.js - checksum: 10c0/c47f5c0f63cd12a663e9dc94a635f9efbb5059d98086a92286d7764357c66bceba18ccbe79333e01e9be3bfb8caba34b3aaebfd8e62c3d5921c8cf907267be75 + checksum: 10c0/ba2ed3f41735826546a3ef2a7634a8d10351df221891906e59b29b0a0cd748f9b0e7a6f07576858a9de8e77785aad925c8389ddef146de04ea2842047c9d2859 languageName: node linkType: hard "@babel/runtime@npm:^7.12.5": - version: 7.26.10 - resolution: "@babel/runtime@npm:7.26.10" + version: 7.27.0 + resolution: "@babel/runtime@npm:7.27.0" dependencies: regenerator-runtime: "npm:^0.14.0" - checksum: 10c0/6dc6d88c7908f505c4f7770fb4677dfa61f68f659b943c2be1f2a99cb6680343462867abf2d49822adc435932919b36c77ac60125793e719ea8745f2073d3745 + checksum: 10c0/35091ea9de48bd7fd26fb177693d64f4d195eb58ab2b142b893b7f3fa0f1d7c677604d36499ae0621a3703f35ba0c6a8f6c572cc8f7dc0317213841e493cf663 languageName: node linkType: hard -"@babel/types@npm:^7.25.4, @babel/types@npm:^7.26.10": - version: 7.26.10 - resolution: "@babel/types@npm:7.26.10" +"@babel/types@npm:^7.25.4, @babel/types@npm:^7.27.0": + version: 7.27.0 + resolution: "@babel/types@npm:7.27.0" dependencies: "@babel/helper-string-parser": "npm:^7.25.9" "@babel/helper-validator-identifier": "npm:^7.25.9" - checksum: 10c0/7a7f83f568bfc3dfabfaf9ae3a97ab5c061726c0afa7dcd94226d4f84a81559da368ed79671e3a8039d16f12476cf110381a377ebdea07587925f69628200dac + checksum: 10c0/6f1592eabe243c89a608717b07b72969be9d9d2fce1dee21426238757ea1fa60fdfc09b29de9e48d8104311afc6e6fb1702565a9cc1e09bc1e76f2b2ddb0f6e1 languageName: node linkType: hard @@ -227,177 +227,177 @@ __metadata: languageName: node linkType: hard -"@esbuild/aix-ppc64@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/aix-ppc64@npm:0.25.1" +"@esbuild/aix-ppc64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/aix-ppc64@npm:0.25.2" conditions: os=aix & cpu=ppc64 languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/android-arm64@npm:0.25.1" +"@esbuild/android-arm64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/android-arm64@npm:0.25.2" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@esbuild/android-arm@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/android-arm@npm:0.25.1" +"@esbuild/android-arm@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/android-arm@npm:0.25.2" conditions: os=android & cpu=arm languageName: node linkType: hard -"@esbuild/android-x64@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/android-x64@npm:0.25.1" +"@esbuild/android-x64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/android-x64@npm:0.25.2" conditions: os=android & cpu=x64 languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/darwin-arm64@npm:0.25.1" +"@esbuild/darwin-arm64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/darwin-arm64@npm:0.25.2" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/darwin-x64@npm:0.25.1" +"@esbuild/darwin-x64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/darwin-x64@npm:0.25.2" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/freebsd-arm64@npm:0.25.1" +"@esbuild/freebsd-arm64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/freebsd-arm64@npm:0.25.2" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/freebsd-x64@npm:0.25.1" +"@esbuild/freebsd-x64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/freebsd-x64@npm:0.25.2" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/linux-arm64@npm:0.25.1" +"@esbuild/linux-arm64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/linux-arm64@npm:0.25.2" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/linux-arm@npm:0.25.1" +"@esbuild/linux-arm@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/linux-arm@npm:0.25.2" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/linux-ia32@npm:0.25.1" +"@esbuild/linux-ia32@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/linux-ia32@npm:0.25.2" conditions: os=linux & cpu=ia32 languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/linux-loong64@npm:0.25.1" +"@esbuild/linux-loong64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/linux-loong64@npm:0.25.2" conditions: os=linux & cpu=loong64 languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/linux-mips64el@npm:0.25.1" +"@esbuild/linux-mips64el@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/linux-mips64el@npm:0.25.2" conditions: os=linux & cpu=mips64el languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/linux-ppc64@npm:0.25.1" +"@esbuild/linux-ppc64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/linux-ppc64@npm:0.25.2" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/linux-riscv64@npm:0.25.1" +"@esbuild/linux-riscv64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/linux-riscv64@npm:0.25.2" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/linux-s390x@npm:0.25.1" +"@esbuild/linux-s390x@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/linux-s390x@npm:0.25.2" conditions: os=linux & cpu=s390x languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/linux-x64@npm:0.25.1" +"@esbuild/linux-x64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/linux-x64@npm:0.25.2" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"@esbuild/netbsd-arm64@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/netbsd-arm64@npm:0.25.1" +"@esbuild/netbsd-arm64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/netbsd-arm64@npm:0.25.2" conditions: os=netbsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/netbsd-x64@npm:0.25.1" +"@esbuild/netbsd-x64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/netbsd-x64@npm:0.25.2" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/openbsd-arm64@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/openbsd-arm64@npm:0.25.1" +"@esbuild/openbsd-arm64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/openbsd-arm64@npm:0.25.2" conditions: os=openbsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/openbsd-x64@npm:0.25.1" +"@esbuild/openbsd-x64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/openbsd-x64@npm:0.25.2" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/sunos-x64@npm:0.25.1" +"@esbuild/sunos-x64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/sunos-x64@npm:0.25.2" conditions: os=sunos & cpu=x64 languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/win32-arm64@npm:0.25.1" +"@esbuild/win32-arm64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/win32-arm64@npm:0.25.2" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/win32-ia32@npm:0.25.1" +"@esbuild/win32-ia32@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/win32-ia32@npm:0.25.2" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.25.1": - version: 0.25.1 - resolution: "@esbuild/win32-x64@npm:0.25.1" +"@esbuild/win32-x64@npm:0.25.2": + version: 0.25.2 + resolution: "@esbuild/win32-x64@npm:0.25.2" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -409,6 +409,19 @@ __metadata: languageName: node linkType: hard +"@gerrit0/mini-shiki@npm:^3.2.1": + version: 3.2.2 + resolution: "@gerrit0/mini-shiki@npm:3.2.2" + dependencies: + "@shikijs/engine-oniguruma": "npm:^3.2.1" + "@shikijs/langs": "npm:^3.2.1" + "@shikijs/themes": "npm:^3.2.1" + "@shikijs/types": "npm:^3.2.1" + "@shikijs/vscode-textmate": "npm:^10.0.2" + checksum: 10c0/0714ddea5a3d727b7b8a517f01b45a03f4134c8716b435a92d3087d2ab657ec0488c5da9416159a74835f2eef6b44982190707a1ae9c31ac38ba6acf63b51dd1 + languageName: node + linkType: hard + "@isaacs/cliui@npm:^8.0.2": version: 8.0.2 resolution: "@isaacs/cliui@npm:8.0.2" @@ -634,225 +647,277 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-android-arm-eabi@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-android-arm-eabi@npm:4.35.0" +"@rollup/rollup-android-arm-eabi@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.38.0" conditions: os=android & cpu=arm languageName: node linkType: hard -"@rollup/rollup-android-arm64@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-android-arm64@npm:4.35.0" +"@rollup/rollup-android-arm64@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-android-arm64@npm:4.38.0" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-arm64@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-darwin-arm64@npm:4.35.0" +"@rollup/rollup-darwin-arm64@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-darwin-arm64@npm:4.38.0" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-x64@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-darwin-x64@npm:4.35.0" +"@rollup/rollup-darwin-x64@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-darwin-x64@npm:4.38.0" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-freebsd-arm64@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-freebsd-arm64@npm:4.35.0" +"@rollup/rollup-freebsd-arm64@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.38.0" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-freebsd-x64@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-freebsd-x64@npm:4.35.0" +"@rollup/rollup-freebsd-x64@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-freebsd-x64@npm:4.38.0" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-linux-arm-gnueabihf@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.35.0" +"@rollup/rollup-linux-arm-gnueabihf@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.38.0" conditions: os=linux & cpu=arm & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm-musleabihf@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.35.0" +"@rollup/rollup-linux-arm-musleabihf@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.38.0" conditions: os=linux & cpu=arm & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-arm64-gnu@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.35.0" +"@rollup/rollup-linux-arm64-gnu@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.38.0" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm64-musl@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-linux-arm64-musl@npm:4.35.0" +"@rollup/rollup-linux-arm64-musl@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.38.0" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-loongarch64-gnu@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.35.0" +"@rollup/rollup-linux-loongarch64-gnu@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.38.0" conditions: os=linux & cpu=loong64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-powerpc64le-gnu@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.35.0" +"@rollup/rollup-linux-powerpc64le-gnu@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.38.0" conditions: os=linux & cpu=ppc64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-gnu@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.35.0" +"@rollup/rollup-linux-riscv64-gnu@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.38.0" conditions: os=linux & cpu=riscv64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-s390x-gnu@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.35.0" +"@rollup/rollup-linux-riscv64-musl@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.38.0" + conditions: os=linux & cpu=riscv64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-s390x-gnu@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.38.0" conditions: os=linux & cpu=s390x & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-gnu@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-linux-x64-gnu@npm:4.35.0" +"@rollup/rollup-linux-x64-gnu@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.38.0" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-musl@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-linux-x64-musl@npm:4.35.0" +"@rollup/rollup-linux-x64-musl@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.38.0" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-win32-arm64-msvc@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.35.0" +"@rollup/rollup-win32-arm64-msvc@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.38.0" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-win32-ia32-msvc@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.35.0" +"@rollup/rollup-win32-ia32-msvc@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.38.0" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@rollup/rollup-win32-x64-msvc@npm:4.35.0": - version: 4.35.0 - resolution: "@rollup/rollup-win32-x64-msvc@npm:4.35.0" +"@rollup/rollup-win32-x64-msvc@npm:4.38.0": + version: 4.38.0 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.38.0" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.11.9": - version: 1.11.9 - resolution: "@swc/core-darwin-arm64@npm:1.11.9" +"@shikijs/engine-oniguruma@npm:^3.2.1": + version: 3.2.1 + resolution: "@shikijs/engine-oniguruma@npm:3.2.1" + dependencies: + "@shikijs/types": "npm:3.2.1" + "@shikijs/vscode-textmate": "npm:^10.0.2" + checksum: 10c0/8c4c51738740f9cfa610ccefaaea2378833820336e4329bb88b9a2208e3deb994b0b7bea2d6657eb915fb668ca2090a2168a84dfeac2b820c1fee00631ca9bed + languageName: node + linkType: hard + +"@shikijs/langs@npm:^3.2.1": + version: 3.2.1 + resolution: "@shikijs/langs@npm:3.2.1" + dependencies: + "@shikijs/types": "npm:3.2.1" + checksum: 10c0/8a4e8c066795f1e96686bee271ad9783febcb1cece2ebb9815dfb3d59c856ac869cf9dddc7d90cbcd186a782ddc0628b37486fcc4a46516be6825907f0e74178 + languageName: node + linkType: hard + +"@shikijs/themes@npm:^3.2.1": + version: 3.2.1 + resolution: "@shikijs/themes@npm:3.2.1" + dependencies: + "@shikijs/types": "npm:3.2.1" + checksum: 10c0/674aae42244832142f584037504ab102dc141f9918f5b11b62aa0dc1abb6a763daf74f86124ae5f2362116dd095b5fc62c9a249aa8c14fdae847e5b8b955b11b + languageName: node + linkType: hard + +"@shikijs/types@npm:3.2.1, @shikijs/types@npm:^3.2.1": + version: 3.2.1 + resolution: "@shikijs/types@npm:3.2.1" + dependencies: + "@shikijs/vscode-textmate": "npm:^10.0.2" + "@types/hast": "npm:^3.0.4" + checksum: 10c0/3380fde198d466a8771137b7ca3d4756a54d7d24c6e65f852737472a280c12c07f2123b9ad3d7eb2edec86d8d2c53bc207abe0fc0c7f78d337e52e742dc34edf + languageName: node + linkType: hard + +"@shikijs/vscode-textmate@npm:^10.0.2": + version: 10.0.2 + resolution: "@shikijs/vscode-textmate@npm:10.0.2" + checksum: 10c0/36b682d691088ec244de292dc8f91b808f95c89466af421cf84cbab92230f03c8348649c14b3251991b10ce632b0c715e416e992dd5f28ff3221dc2693fd9462 + languageName: node + linkType: hard + +"@swc/core-darwin-arm64@npm:1.11.15": + version: 1.11.15 + resolution: "@swc/core-darwin-arm64@npm:1.11.15" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.11.9": - version: 1.11.9 - resolution: "@swc/core-darwin-x64@npm:1.11.9" +"@swc/core-darwin-x64@npm:1.11.15": + version: 1.11.15 + resolution: "@swc/core-darwin-x64@npm:1.11.15" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.11.9": - version: 1.11.9 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.11.9" +"@swc/core-linux-arm-gnueabihf@npm:1.11.15": + version: 1.11.15 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.11.15" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.11.9": - version: 1.11.9 - resolution: "@swc/core-linux-arm64-gnu@npm:1.11.9" +"@swc/core-linux-arm64-gnu@npm:1.11.15": + version: 1.11.15 + resolution: "@swc/core-linux-arm64-gnu@npm:1.11.15" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.11.9": - version: 1.11.9 - resolution: "@swc/core-linux-arm64-musl@npm:1.11.9" +"@swc/core-linux-arm64-musl@npm:1.11.15": + version: 1.11.15 + resolution: "@swc/core-linux-arm64-musl@npm:1.11.15" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.11.9": - version: 1.11.9 - resolution: "@swc/core-linux-x64-gnu@npm:1.11.9" +"@swc/core-linux-x64-gnu@npm:1.11.15": + version: 1.11.15 + resolution: "@swc/core-linux-x64-gnu@npm:1.11.15" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.11.9": - version: 1.11.9 - resolution: "@swc/core-linux-x64-musl@npm:1.11.9" +"@swc/core-linux-x64-musl@npm:1.11.15": + version: 1.11.15 + resolution: "@swc/core-linux-x64-musl@npm:1.11.15" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.11.9": - version: 1.11.9 - resolution: "@swc/core-win32-arm64-msvc@npm:1.11.9" +"@swc/core-win32-arm64-msvc@npm:1.11.15": + version: 1.11.15 + resolution: "@swc/core-win32-arm64-msvc@npm:1.11.15" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.11.9": - version: 1.11.9 - resolution: "@swc/core-win32-ia32-msvc@npm:1.11.9" +"@swc/core-win32-ia32-msvc@npm:1.11.15": + version: 1.11.15 + resolution: "@swc/core-win32-ia32-msvc@npm:1.11.15" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.11.9": - version: 1.11.9 - resolution: "@swc/core-win32-x64-msvc@npm:1.11.9" +"@swc/core-win32-x64-msvc@npm:1.11.15": + version: 1.11.15 + resolution: "@swc/core-win32-x64-msvc@npm:1.11.15" conditions: os=win32 & cpu=x64 languageName: node linkType: hard "@swc/core@npm:^1.10.16": - version: 1.11.9 - resolution: "@swc/core@npm:1.11.9" - dependencies: - "@swc/core-darwin-arm64": "npm:1.11.9" - "@swc/core-darwin-x64": "npm:1.11.9" - "@swc/core-linux-arm-gnueabihf": "npm:1.11.9" - "@swc/core-linux-arm64-gnu": "npm:1.11.9" - "@swc/core-linux-arm64-musl": "npm:1.11.9" - "@swc/core-linux-x64-gnu": "npm:1.11.9" - "@swc/core-linux-x64-musl": "npm:1.11.9" - "@swc/core-win32-arm64-msvc": "npm:1.11.9" - "@swc/core-win32-ia32-msvc": "npm:1.11.9" - "@swc/core-win32-x64-msvc": "npm:1.11.9" + version: 1.11.15 + resolution: "@swc/core@npm:1.11.15" + dependencies: + "@swc/core-darwin-arm64": "npm:1.11.15" + "@swc/core-darwin-x64": "npm:1.11.15" + "@swc/core-linux-arm-gnueabihf": "npm:1.11.15" + "@swc/core-linux-arm64-gnu": "npm:1.11.15" + "@swc/core-linux-arm64-musl": "npm:1.11.15" + "@swc/core-linux-x64-gnu": "npm:1.11.15" + "@swc/core-linux-x64-musl": "npm:1.11.15" + "@swc/core-win32-arm64-msvc": "npm:1.11.15" + "@swc/core-win32-ia32-msvc": "npm:1.11.15" + "@swc/core-win32-x64-msvc": "npm:1.11.15" "@swc/counter": "npm:^0.1.3" - "@swc/types": "npm:^0.1.19" + "@swc/types": "npm:^0.1.21" peerDependencies: "@swc/helpers": "*" dependenciesMeta: @@ -879,7 +944,7 @@ __metadata: peerDependenciesMeta: "@swc/helpers": optional: true - checksum: 10c0/84730a4693a91db9602c36de2d8e6c3444140357da945d69d61c6a6017c9bd96949d3a5650d456e519acff9a32176edab079bf1430a8b21da79a13fa79dd9337 + checksum: 10c0/b561f35080ad5bbde2e261289f74728562e5da5bc5e76d3304beb0c06f92044ec7a35c0aa8413c07495d5bce3bc5b8470f58ee53480cc0b9a39392c84e538040 languageName: node linkType: hard @@ -899,12 +964,12 @@ __metadata: languageName: node linkType: hard -"@swc/types@npm:^0.1.19": - version: 0.1.19 - resolution: "@swc/types@npm:0.1.19" +"@swc/types@npm:^0.1.21": + version: 0.1.21 + resolution: "@swc/types@npm:0.1.21" dependencies: "@swc/counter": "npm:^0.1.3" - checksum: 10c0/21b727d97d38f1bdbe9ef8fdf693bca19ebd5334ab32d7d2624a925d9adc8934935ad0f168cdbfd938b2f4b754a1fb7581f253bf47ab416177b6ac2c5c72578b + checksum: 10c0/2baa89c824426e0de0c84e212278010e2df8dc2d6ffaa6f1e306e1b2930c6404b3d3f8989307e8c42ceb95ac143ab7a80be138af6a014d5c782dce5be94dcd5e languageName: node linkType: hard @@ -921,10 +986,42 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:*, @types/estree@npm:1.0.6, @types/estree@npm:^1.0.0": - version: 1.0.6 - resolution: "@types/estree@npm:1.0.6" - checksum: 10c0/cdfd751f6f9065442cd40957c07fd80361c962869aa853c1c2fd03e101af8b9389d8ff4955a43a6fcfa223dd387a089937f95be0f3eec21ca527039fd2d9859a +"@tsconfig/strictest@npm:2.0.5": + version: 2.0.5 + resolution: "@tsconfig/strictest@npm:2.0.5" + checksum: 10c0/cfc86da2d57f7b4b0827701b132c37a4974284e5c40649656c0e474866dfd8a69f57c6718230d8a8139967e2a95438586b8224c13ab0ff9d3a43eda771c50cc4 + languageName: node + linkType: hard + +"@types/estree@npm:*, @types/estree@npm:1.0.7, @types/estree@npm:^1.0.0": + version: 1.0.7 + resolution: "@types/estree@npm:1.0.7" + checksum: 10c0/be815254316882f7c40847336cd484c3bc1c3e34f710d197160d455dc9d6d050ffbf4c3bc76585dba86f737f020ab20bdb137ebe0e9116b0c86c7c0342221b8c + languageName: node + linkType: hard + +"@types/hast@npm:^3.0.4": + version: 3.0.4 + resolution: "@types/hast@npm:3.0.4" + dependencies: + "@types/unist": "npm:*" + checksum: 10c0/3249781a511b38f1d330fd1e3344eed3c4e7ea8eff82e835d35da78e637480d36fad37a78be5a7aed8465d237ad0446abc1150859d0fde395354ea634decf9f7 + languageName: node + linkType: hard + +"@types/lodash.debounce@npm:4.0.9": + version: 4.0.9 + resolution: "@types/lodash.debounce@npm:4.0.9" + dependencies: + "@types/lodash": "npm:*" + checksum: 10c0/9fbb24e5e52616faf60ba5c82d8c6517f4b86fc6e9ab353b4c56c0760f63d9bf53af3f2d8f6c37efa48090359fb96dba1087d497758511f6c40677002191d042 + languageName: node + linkType: hard + +"@types/lodash@npm:*": + version: 4.17.16 + resolution: "@types/lodash@npm:4.17.16" + checksum: 10c0/cf017901b8ab1d7aabc86d5189d9288f4f99f19a75caf020c0e2c77b8d4cead4db0d0b842d009b029339f92399f49f34377dd7c2721053388f251778b4c23534 languageName: node linkType: hard @@ -938,11 +1035,11 @@ __metadata: linkType: hard "@types/react@npm:*": - version: 19.0.10 - resolution: "@types/react@npm:19.0.10" + version: 19.0.12 + resolution: "@types/react@npm:19.0.12" dependencies: csstype: "npm:^3.0.2" - checksum: 10c0/41884cca21850c8b2d6578b172ca0ca4fff6021251a68532b19f2031ac23dc5a9222470208065f8d9985d367376047df2f49ece8d927f7d04cdc94922b1eb34b + checksum: 10c0/c814b6af5c0fbcf5c65d031b1c9bf98c5b857e015254d95811f2851b27b869c3d31c6f35dab127dc6921a3dbda0b0622c6323d493a14b31b231a6a58c41c5e84 languageName: node linkType: hard @@ -962,9 +1059,16 @@ __metadata: languageName: node linkType: hard -"@vitest/coverage-v8@npm:3.0.8": - version: 3.0.8 - resolution: "@vitest/coverage-v8@npm:3.0.8" +"@types/unist@npm:*": + version: 3.0.3 + resolution: "@types/unist@npm:3.0.3" + checksum: 10c0/2b1e4adcab78388e088fcc3c0ae8700f76619dbcb4741d7d201f87e2cb346bfc29a89003cfea2d76c996e1061452e14fcd737e8b25aacf949c1f2d6b2bc3dd60 + languageName: node + linkType: hard + +"@vitest/coverage-v8@npm:3.1.1": + version: 3.1.1 + resolution: "@vitest/coverage-v8@npm:3.1.1" dependencies: "@ampproject/remapping": "npm:^2.3.0" "@bcoe/v8-coverage": "npm:^1.0.2" @@ -975,36 +1079,36 @@ __metadata: istanbul-reports: "npm:^3.1.7" magic-string: "npm:^0.30.17" magicast: "npm:^0.3.5" - std-env: "npm:^3.8.0" + std-env: "npm:^3.8.1" test-exclude: "npm:^7.0.1" tinyrainbow: "npm:^2.0.0" peerDependencies: - "@vitest/browser": 3.0.8 - vitest: 3.0.8 + "@vitest/browser": 3.1.1 + vitest: 3.1.1 peerDependenciesMeta: "@vitest/browser": optional: true - checksum: 10c0/c1f4183d57c56e41a0b9708a43fdf05c83ff447ab1b4ad957aa16af14349b7221a299e157065ca7b2aa46583057633dd92a21d5437cd5e834619ae0be0d5ccf0 + checksum: 10c0/0f852d8a438d27605955f2a1177e017f48b0dcdc7069318b2b1e031e3561d02a54e4d9a108afacbc8365c8b42f4bcb13282ae7cfaf380bce27741991321e83d9 languageName: node linkType: hard -"@vitest/expect@npm:3.0.8": - version: 3.0.8 - resolution: "@vitest/expect@npm:3.0.8" +"@vitest/expect@npm:3.1.1": + version: 3.1.1 + resolution: "@vitest/expect@npm:3.1.1" dependencies: - "@vitest/spy": "npm:3.0.8" - "@vitest/utils": "npm:3.0.8" + "@vitest/spy": "npm:3.1.1" + "@vitest/utils": "npm:3.1.1" chai: "npm:^5.2.0" tinyrainbow: "npm:^2.0.0" - checksum: 10c0/48aebec816f5a1b1f64f82b474ccfba537801a654f9547c581ed1c2d30b5de72207b643d3db2ac2869809a63a585425df30f65481f86d2bbbf979d8f235661bd + checksum: 10c0/ef4528d0ebb89eb3cc044cf597d051c35df8471bb6ba4029e9b3412aa69d0d85a0ce4eb49531fc78fe1ebd97e6428260463068cc96a8d8c1a80150dedfd1ab3a languageName: node linkType: hard -"@vitest/mocker@npm:3.0.8": - version: 3.0.8 - resolution: "@vitest/mocker@npm:3.0.8" +"@vitest/mocker@npm:3.1.1": + version: 3.1.1 + resolution: "@vitest/mocker@npm:3.1.1" dependencies: - "@vitest/spy": "npm:3.0.8" + "@vitest/spy": "npm:3.1.1" estree-walker: "npm:^3.0.3" magic-string: "npm:^0.30.17" peerDependencies: @@ -1015,57 +1119,57 @@ __metadata: optional: true vite: optional: true - checksum: 10c0/bc89a31a5ebba900bb965b05d1fab581ae2872b6ddc17734f2a8433b9a3c7ae1fa0efd5f13bf03cf8075864b47954e8fcf609cf3a8258f0451375d68b81f135b + checksum: 10c0/9264558809e2d7c77ae9ceefad521dc5f886a567aaf0bdd021b73089b8906ffd92c893f3998d16814f38fc653c7413836f508712355c87749a0e86c7d435eec1 languageName: node linkType: hard -"@vitest/pretty-format@npm:3.0.8, @vitest/pretty-format@npm:^3.0.8": - version: 3.0.8 - resolution: "@vitest/pretty-format@npm:3.0.8" +"@vitest/pretty-format@npm:3.1.1, @vitest/pretty-format@npm:^3.1.1": + version: 3.1.1 + resolution: "@vitest/pretty-format@npm:3.1.1" dependencies: tinyrainbow: "npm:^2.0.0" - checksum: 10c0/9133052605f16966db91d5e495afb5e32c3eb9215602248710bc3fd9034b1b511d1a7f1093571afee8664beb2a83303d42f1d5896fdba2a39adbb5ca9af788f7 + checksum: 10c0/540cd46d317fc80298c93b185f3fb48dfe90eaaa3942fd700fde6e88d658772c01b56ad5b9b36e4ac368a02e0fc8e0dc72bbdd6dd07a5d75e89ef99c8df5ba6e languageName: node linkType: hard -"@vitest/runner@npm:3.0.8": - version: 3.0.8 - resolution: "@vitest/runner@npm:3.0.8" +"@vitest/runner@npm:3.1.1": + version: 3.1.1 + resolution: "@vitest/runner@npm:3.1.1" dependencies: - "@vitest/utils": "npm:3.0.8" + "@vitest/utils": "npm:3.1.1" pathe: "npm:^2.0.3" - checksum: 10c0/9a9d48dc82ca7101209b21309e18a4720e77d6015bf00a60ace6130e362320158d110f48cf9aa221e5e744729fe8a198811dd69e598688ffbb78c2fce2a842a1 + checksum: 10c0/35a541069c3c94a2dd02fca2d70cc8d5e66ba2e891cfb80da354174f510aeb96774ffb34fff39cecde9d5c969be4dd20e240a900beb9b225b7512a615ecc5503 languageName: node linkType: hard -"@vitest/snapshot@npm:3.0.8": - version: 3.0.8 - resolution: "@vitest/snapshot@npm:3.0.8" +"@vitest/snapshot@npm:3.1.1": + version: 3.1.1 + resolution: "@vitest/snapshot@npm:3.1.1" dependencies: - "@vitest/pretty-format": "npm:3.0.8" + "@vitest/pretty-format": "npm:3.1.1" magic-string: "npm:^0.30.17" pathe: "npm:^2.0.3" - checksum: 10c0/40564f60f7d166d10a03e9d1f8780daef164c76b2d85c1c8f5800168f907929c815395ac5c1f5c824da5ff29286f874e22dd8874b52044a53e0d858be67ceeb7 + checksum: 10c0/43e5fc5db580f20903eb1493d07f08752df8864f7b9b7293a202b2ffe93d8c196a5614d66dda096c6bacc16e12f1836f33ba41898812af6d32676d1eb501536a languageName: node linkType: hard -"@vitest/spy@npm:3.0.8": - version: 3.0.8 - resolution: "@vitest/spy@npm:3.0.8" +"@vitest/spy@npm:3.1.1": + version: 3.1.1 + resolution: "@vitest/spy@npm:3.1.1" dependencies: tinyspy: "npm:^3.0.2" - checksum: 10c0/7a940e6fbf5e6903758dfd904dedc9223df72ffa2a3d8c988706c2626c0fd3f9b129452bcd7af40bda014831f15ddb23ad7c1a7e42900acf4f3432b0c2bc8fb5 + checksum: 10c0/896659d4b42776cfa2057a1da2c33adbd3f2ebd28005ca606d1616d08d2e726dc1460fb37f1ea7f734756b5bccf926c7165f410e63f0a3b8d992eb5489528b08 languageName: node linkType: hard -"@vitest/utils@npm:3.0.8": - version: 3.0.8 - resolution: "@vitest/utils@npm:3.0.8" +"@vitest/utils@npm:3.1.1": + version: 3.1.1 + resolution: "@vitest/utils@npm:3.1.1" dependencies: - "@vitest/pretty-format": "npm:3.0.8" + "@vitest/pretty-format": "npm:3.1.1" loupe: "npm:^3.1.3" tinyrainbow: "npm:^2.0.0" - checksum: 10c0/929e71582d27f5ec2fe422d72112471b36517620beb2c4398c116598ca55b36340b0fa97958d8584bc05153d92dbd60324664d5b623ec6eed8c72e50e226633c + checksum: 10c0/a9cfe0c0f095b58644ce3ba08309de5be8564c10dad9e62035bd378e60b2834e6a256e6e4ded7dcf027fdc2371301f7965040ad3e6323b747d5b3abbb7ceb0d6 languageName: node linkType: hard @@ -1113,6 +1217,13 @@ __metadata: languageName: node linkType: hard +"argparse@npm:^2.0.1": + version: 2.0.1 + resolution: "argparse@npm:2.0.1" + checksum: 10c0/c5640c2d89045371c7cedd6a70212a04e360fd34d6edeae32f6952c63949e3525ea77dbec0289d8213a99bbaeab5abfa860b5c12cf88a2e6cf8106e90dd27a7e + languageName: node + linkType: hard + "assertion-error@npm:^2.0.1": version: 2.0.1 resolution: "assertion-error@npm:2.0.1" @@ -1152,9 +1263,9 @@ __metadata: languageName: node linkType: hard -"bunchee@npm:6.4.0": - version: 6.4.0 - resolution: "bunchee@npm:6.4.0" +"bunchee@npm:6.5.0": + version: 6.5.0 + resolution: "bunchee@npm:6.5.0" dependencies: "@rollup/plugin-commonjs": "npm:^28.0.2" "@rollup/plugin-json": "npm:^6.1.0" @@ -1185,7 +1296,7 @@ __metadata: optional: true bin: bunchee: dist/bin/cli.js - checksum: 10c0/d068dbab318780e64d585b0b508b7b62d802e5136e4c4cac0a22f241aa87b3756ec18e9bb2ebb486d5491572c4ddcec5440578e2192a137a31e29e7bf357fe9d + checksum: 10c0/ec9d7546df1974e396645414bd3abec550f566bda0dfbe8c6e672f50b1d2729cf3c358e97972c68aa2f6bd9c22a9b755f713f3cbe03c5f566e9079d91c4073e1 languageName: node linkType: hard @@ -1454,7 +1565,7 @@ __metadata: languageName: node linkType: hard -"entities@npm:^4.5.0": +"entities@npm:^4.4.0, entities@npm:^4.5.0": version: 4.5.0 resolution: "entities@npm:4.5.0" checksum: 10c0/5b039739f7621f5d1ad996715e53d964035f75ad3b9a4d38c6b3804bb226e282ffeae2443624d8fdd9c47d8e926ae9ac009c54671243f0c3294c26af7cc85250 @@ -1518,34 +1629,34 @@ __metadata: linkType: hard "esbuild@npm:^0.25.0": - version: 0.25.1 - resolution: "esbuild@npm:0.25.1" - dependencies: - "@esbuild/aix-ppc64": "npm:0.25.1" - "@esbuild/android-arm": "npm:0.25.1" - "@esbuild/android-arm64": "npm:0.25.1" - "@esbuild/android-x64": "npm:0.25.1" - "@esbuild/darwin-arm64": "npm:0.25.1" - "@esbuild/darwin-x64": "npm:0.25.1" - "@esbuild/freebsd-arm64": "npm:0.25.1" - "@esbuild/freebsd-x64": "npm:0.25.1" - "@esbuild/linux-arm": "npm:0.25.1" - "@esbuild/linux-arm64": "npm:0.25.1" - "@esbuild/linux-ia32": "npm:0.25.1" - "@esbuild/linux-loong64": "npm:0.25.1" - "@esbuild/linux-mips64el": "npm:0.25.1" - "@esbuild/linux-ppc64": "npm:0.25.1" - "@esbuild/linux-riscv64": "npm:0.25.1" - "@esbuild/linux-s390x": "npm:0.25.1" - "@esbuild/linux-x64": "npm:0.25.1" - "@esbuild/netbsd-arm64": "npm:0.25.1" - "@esbuild/netbsd-x64": "npm:0.25.1" - "@esbuild/openbsd-arm64": "npm:0.25.1" - "@esbuild/openbsd-x64": "npm:0.25.1" - "@esbuild/sunos-x64": "npm:0.25.1" - "@esbuild/win32-arm64": "npm:0.25.1" - "@esbuild/win32-ia32": "npm:0.25.1" - "@esbuild/win32-x64": "npm:0.25.1" + version: 0.25.2 + resolution: "esbuild@npm:0.25.2" + dependencies: + "@esbuild/aix-ppc64": "npm:0.25.2" + "@esbuild/android-arm": "npm:0.25.2" + "@esbuild/android-arm64": "npm:0.25.2" + "@esbuild/android-x64": "npm:0.25.2" + "@esbuild/darwin-arm64": "npm:0.25.2" + "@esbuild/darwin-x64": "npm:0.25.2" + "@esbuild/freebsd-arm64": "npm:0.25.2" + "@esbuild/freebsd-x64": "npm:0.25.2" + "@esbuild/linux-arm": "npm:0.25.2" + "@esbuild/linux-arm64": "npm:0.25.2" + "@esbuild/linux-ia32": "npm:0.25.2" + "@esbuild/linux-loong64": "npm:0.25.2" + "@esbuild/linux-mips64el": "npm:0.25.2" + "@esbuild/linux-ppc64": "npm:0.25.2" + "@esbuild/linux-riscv64": "npm:0.25.2" + "@esbuild/linux-s390x": "npm:0.25.2" + "@esbuild/linux-x64": "npm:0.25.2" + "@esbuild/netbsd-arm64": "npm:0.25.2" + "@esbuild/netbsd-x64": "npm:0.25.2" + "@esbuild/openbsd-arm64": "npm:0.25.2" + "@esbuild/openbsd-x64": "npm:0.25.2" + "@esbuild/sunos-x64": "npm:0.25.2" + "@esbuild/win32-arm64": "npm:0.25.2" + "@esbuild/win32-ia32": "npm:0.25.2" + "@esbuild/win32-x64": "npm:0.25.2" dependenciesMeta: "@esbuild/aix-ppc64": optional: true @@ -1599,7 +1710,7 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 10c0/80fca30dd0f21aec23fdfab34f0a8d5f55df5097dd7f475f2ab561d45662c32ee306f5649071cd1a0ba0614b164c48ca3dc3ee1551a4daf204b8af90e4d893f5 + checksum: 10c0/87ce0b78699c4d192b8cf7e9b688e9a0da10e6f58ff85a368bf3044ca1fa95626c98b769b5459352282e0065585b6f994a5e6699af5cccf9d31178960e2b58fd languageName: node linkType: hard @@ -1626,10 +1737,10 @@ __metadata: languageName: node linkType: hard -"expect-type@npm:^1.1.0": - version: 1.2.0 - resolution: "expect-type@npm:1.2.0" - checksum: 10c0/6069e1980bf16b9385646800e23499c1447df636c433014f6bbabe4bb0e20bd0033f30d38a6f9ae0938b0203a9e870cc82cdfd74b7c837b480cefb8e8240d8e8 +"expect-type@npm:^1.2.0": + version: 1.2.1 + resolution: "expect-type@npm:1.2.1" + checksum: 10c0/b775c9adab3c190dd0d398c722531726cdd6022849b4adba19dceab58dda7e000a7c6c872408cd73d665baa20d381eca36af4f7b393a4ba60dd10232d1fb8898 languageName: node linkType: hard @@ -1800,7 +1911,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^10.2.2, glob@npm:^10.3.10, glob@npm:^10.3.7, glob@npm:^10.4.1": +"glob@npm:^10.2.2, glob@npm:^10.3.10, glob@npm:^10.4.1": version: 10.4.5 resolution: "glob@npm:10.4.5" dependencies: @@ -2128,6 +2239,22 @@ __metadata: languageName: node linkType: hard +"linkify-it@npm:^5.0.0": + version: 5.0.0 + resolution: "linkify-it@npm:5.0.0" + dependencies: + uc.micro: "npm:^2.0.0" + checksum: 10c0/ff4abbcdfa2003472fc3eb4b8e60905ec97718e11e33cca52059919a4c80cc0e0c2a14d23e23d8c00e5402bc5a885cdba8ca053a11483ab3cc8b3c7a52f88e2d + languageName: node + linkType: hard + +"lodash.debounce@npm:^4.0.8": + version: 4.0.8 + resolution: "lodash.debounce@npm:4.0.8" + checksum: 10c0/762998a63e095412b6099b8290903e0a8ddcb353ac6e2e0f2d7e7d03abd4275fe3c689d88960eb90b0dde4f177554d51a690f22a343932ecbc50a5d111849987 + languageName: node + linkType: hard + "log-symbols@npm:^6.0.0": version: 6.0.0 resolution: "log-symbols@npm:6.0.0" @@ -2163,7 +2290,14 @@ __metadata: languageName: node linkType: hard -"magic-string@npm:^0.30.10, magic-string@npm:^0.30.17, magic-string@npm:^0.30.3, magic-string@npm:^0.30.5": +"lunr@npm:^2.3.9": + version: 2.3.9 + resolution: "lunr@npm:2.3.9" + checksum: 10c0/77d7dbb4fbd602aac161e2b50887d8eda28c0fa3b799159cee380fbb311f1e614219126ecbbd2c3a9c685f1720a8109b3c1ca85cc893c39b6c9cc6a62a1d8a8b + languageName: node + linkType: hard + +"magic-string@npm:^0.30.17, magic-string@npm:^0.30.3, magic-string@npm:^0.30.5": version: 0.30.17 resolution: "magic-string@npm:0.30.17" dependencies: @@ -2211,6 +2345,22 @@ __metadata: languageName: node linkType: hard +"markdown-it@npm:^14.1.0": + version: 14.1.0 + resolution: "markdown-it@npm:14.1.0" + dependencies: + argparse: "npm:^2.0.1" + entities: "npm:^4.4.0" + linkify-it: "npm:^5.0.0" + mdurl: "npm:^2.0.0" + punycode.js: "npm:^2.3.1" + uc.micro: "npm:^2.1.0" + bin: + markdown-it: bin/markdown-it.mjs + checksum: 10c0/9a6bb444181d2db7016a4173ae56a95a62c84d4cbfb6916a399b11d3e6581bf1cc2e4e1d07a2f022ae72c25f56db90fbe1e529fca16fbf9541659dc53480d4b4 + languageName: node + linkType: hard + "math-intrinsics@npm:^1.1.0": version: 1.1.0 resolution: "math-intrinsics@npm:1.1.0" @@ -2218,6 +2368,13 @@ __metadata: languageName: node linkType: hard +"mdurl@npm:^2.0.0": + version: 2.0.0 + resolution: "mdurl@npm:2.0.0" + checksum: 10c0/633db522272f75ce4788440669137c77540d74a83e9015666a9557a152c02e245b192edc20bc90ae953bbab727503994a53b236b4d9c99bdaee594d0e7dd2ce0 + languageName: node + linkType: hard + "merge2@npm:^1.3.0": version: 1.4.1 resolution: "merge2@npm:1.4.1" @@ -2258,7 +2415,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^9.0.4": +"minimatch@npm:^9.0.4, minimatch@npm:^9.0.5": version: 9.0.5 resolution: "minimatch@npm:9.0.5" dependencies: @@ -2335,12 +2492,11 @@ __metadata: linkType: hard "minizlib@npm:^3.0.1": - version: 3.0.1 - resolution: "minizlib@npm:3.0.1" + version: 3.0.2 + resolution: "minizlib@npm:3.0.2" dependencies: - minipass: "npm:^7.0.4" - rimraf: "npm:^5.0.5" - checksum: 10c0/82f8bf70da8af656909a8ee299d7ed3b3372636749d29e105f97f20e88971be31f5ed7642f2e898f00283b68b701cc01307401cdc209b0efc5dd3818220e5093 + minipass: "npm:^7.1.2" + checksum: 10c0/9f3bd35e41d40d02469cb30470c55ccc21cae0db40e08d1d0b1dff01cc8cc89a6f78e9c5d2b7c844e485ec0a8abc2238111213fdc5b2038e6d1012eacf316f78 languageName: node linkType: hard @@ -2361,11 +2517,11 @@ __metadata: linkType: hard "nanoid@npm:^3.3.8": - version: 3.3.9 - resolution: "nanoid@npm:3.3.9" + version: 3.3.11 + resolution: "nanoid@npm:3.3.11" bin: nanoid: bin/nanoid.cjs - checksum: 10c0/4515abe53db7b150cf77074558efc20d8e916d6910d557b5ce72e8bbf6f8e7554d3d7a0d180bfa65e5d8e99aa51b207aa8a3bf5f3b56233897b146d592e30b24 + checksum: 10c0/40e7f70b3d15f725ca072dfc4f74e81fcf1fbb02e491cf58ac0c79093adc9b0a73b152bcde57df4b79cd097e13023d7504acb38404a4da7bc1cd8e887b82fe0b languageName: node linkType: hard @@ -2408,9 +2564,9 @@ __metadata: linkType: hard "nwsapi@npm:^2.2.16": - version: 2.2.18 - resolution: "nwsapi@npm:2.2.18" - checksum: 10c0/fb64761f02d838a1964ef3f15f324779ae5b735c878843ed6592b07d85652928f8f34458605fee0ff379514bf5ffa5afeef5dc8290bfb0959a854069e2af300b + version: 2.2.20 + resolution: "nwsapi@npm:2.2.20" + checksum: 10c0/07f4dafa3186aef7c007863e90acd4342a34ba9d44b22f14f644fdb311f6086887e21c2fc15efaa826c2bc39ab2bc841364a1a630e7c87e0cb723ba59d729297 languageName: node linkType: hard @@ -2575,6 +2731,13 @@ __metadata: languageName: node linkType: hard +"punycode.js@npm:^2.3.1": + version: 2.3.1 + resolution: "punycode.js@npm:2.3.1" + checksum: 10c0/1d12c1c0e06127fa5db56bd7fdf698daf9a78104456a6b67326877afc21feaa821257b171539caedd2f0524027fa38e67b13dd094159c8d70b6d26d2bea4dfdb + languageName: node + linkType: hard + "punycode@npm:^2.3.1": version: 2.3.1 resolution: "punycode@npm:2.3.1" @@ -2616,14 +2779,18 @@ __metadata: dependencies: "@biomejs/biome": "npm:1.9.4" "@testing-library/react-hooks": "npm:3.7.0" - "@vitest/coverage-v8": "npm:3.0.8" - bunchee: "npm:6.4.0" + "@tsconfig/strictest": "npm:2.0.5" + "@types/lodash.debounce": "npm:4.0.9" + "@vitest/coverage-v8": "npm:3.1.1" + bunchee: "npm:6.5.0" jsdom: "npm:26.0.0" + lodash.debounce: "npm:^4.0.8" react: "npm:16.14.0" react-dom: "npm:16.14.0" react-test-renderer: "npm:16.14.0" + typedoc: "npm:0.28.1" typescript: "npm:5.8.2" - vitest: "npm:3.0.8" + vitest: "npm:3.1.1" peerDependencies: react: ">=16.8.0" languageName: unknown @@ -2725,30 +2892,19 @@ __metadata: languageName: node linkType: hard -"rimraf@npm:^5.0.5": - version: 5.0.10 - resolution: "rimraf@npm:5.0.10" - dependencies: - glob: "npm:^10.3.7" - bin: - rimraf: dist/esm/bin.mjs - checksum: 10c0/7da4fd0e15118ee05b918359462cfa1e7fe4b1228c7765195a45b55576e8c15b95db513b8466ec89129666f4af45ad978a3057a02139afba1a63512a2d9644cc - languageName: node - linkType: hard - "rollup-plugin-dts@npm:^6.1.1": - version: 6.1.1 - resolution: "rollup-plugin-dts@npm:6.1.1" + version: 6.2.1 + resolution: "rollup-plugin-dts@npm:6.2.1" dependencies: - "@babel/code-frame": "npm:^7.24.2" - magic-string: "npm:^0.30.10" + "@babel/code-frame": "npm:^7.26.2" + magic-string: "npm:^0.30.17" peerDependencies: rollup: ^3.29.4 || ^4 typescript: ^4.5 || ^5.0 dependenciesMeta: "@babel/code-frame": optional: true - checksum: 10c0/2b042198ff00fb10c9c70087bbac9013f748dc34be0dbfcca82c6353884ead1467b4a8a37bafe9a8b9356479d43715c7cbc591eeb8e4112c583452431c1cb0a0 + checksum: 10c0/f21c8726470851a40e6ca68ae580261cee8bc6275775291b9c0fdf93b868ed54f12b11c8c0dddce2c14f5691d6032b6647d094835ab9b6789226efa60e1aa71e languageName: node linkType: hard @@ -2779,29 +2935,30 @@ __metadata: linkType: hard "rollup@npm:^4.30.1, rollup@npm:^4.34.7": - version: 4.35.0 - resolution: "rollup@npm:4.35.0" - dependencies: - "@rollup/rollup-android-arm-eabi": "npm:4.35.0" - "@rollup/rollup-android-arm64": "npm:4.35.0" - "@rollup/rollup-darwin-arm64": "npm:4.35.0" - "@rollup/rollup-darwin-x64": "npm:4.35.0" - "@rollup/rollup-freebsd-arm64": "npm:4.35.0" - "@rollup/rollup-freebsd-x64": "npm:4.35.0" - "@rollup/rollup-linux-arm-gnueabihf": "npm:4.35.0" - "@rollup/rollup-linux-arm-musleabihf": "npm:4.35.0" - "@rollup/rollup-linux-arm64-gnu": "npm:4.35.0" - "@rollup/rollup-linux-arm64-musl": "npm:4.35.0" - "@rollup/rollup-linux-loongarch64-gnu": "npm:4.35.0" - "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.35.0" - "@rollup/rollup-linux-riscv64-gnu": "npm:4.35.0" - "@rollup/rollup-linux-s390x-gnu": "npm:4.35.0" - "@rollup/rollup-linux-x64-gnu": "npm:4.35.0" - "@rollup/rollup-linux-x64-musl": "npm:4.35.0" - "@rollup/rollup-win32-arm64-msvc": "npm:4.35.0" - "@rollup/rollup-win32-ia32-msvc": "npm:4.35.0" - "@rollup/rollup-win32-x64-msvc": "npm:4.35.0" - "@types/estree": "npm:1.0.6" + version: 4.38.0 + resolution: "rollup@npm:4.38.0" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.38.0" + "@rollup/rollup-android-arm64": "npm:4.38.0" + "@rollup/rollup-darwin-arm64": "npm:4.38.0" + "@rollup/rollup-darwin-x64": "npm:4.38.0" + "@rollup/rollup-freebsd-arm64": "npm:4.38.0" + "@rollup/rollup-freebsd-x64": "npm:4.38.0" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.38.0" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.38.0" + "@rollup/rollup-linux-arm64-gnu": "npm:4.38.0" + "@rollup/rollup-linux-arm64-musl": "npm:4.38.0" + "@rollup/rollup-linux-loongarch64-gnu": "npm:4.38.0" + "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.38.0" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.38.0" + "@rollup/rollup-linux-riscv64-musl": "npm:4.38.0" + "@rollup/rollup-linux-s390x-gnu": "npm:4.38.0" + "@rollup/rollup-linux-x64-gnu": "npm:4.38.0" + "@rollup/rollup-linux-x64-musl": "npm:4.38.0" + "@rollup/rollup-win32-arm64-msvc": "npm:4.38.0" + "@rollup/rollup-win32-ia32-msvc": "npm:4.38.0" + "@rollup/rollup-win32-x64-msvc": "npm:4.38.0" + "@types/estree": "npm:1.0.7" fsevents: "npm:~2.3.2" dependenciesMeta: "@rollup/rollup-android-arm-eabi": @@ -2830,6 +2987,8 @@ __metadata: optional: true "@rollup/rollup-linux-riscv64-gnu": optional: true + "@rollup/rollup-linux-riscv64-musl": + optional: true "@rollup/rollup-linux-s390x-gnu": optional: true "@rollup/rollup-linux-x64-gnu": @@ -2846,7 +3005,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 10c0/5a04add5a48173b1d95deb5422a96833b7df91b14ccec462c048be48241a79ecee2c1b843511b91ca8b6124bdbae134ccfebe80d4222a93e98e73795d161d3cc + checksum: 10c0/931a6d3bf34fa13adec44a8660319bb7b2f61fbabbf2030f4d29df991fb37b6a685cd7dc203fde8d4ab8b4fe783f1fe8814e448a97f651dc4727511faf958cb4 languageName: node linkType: hard @@ -2996,7 +3155,7 @@ __metadata: languageName: node linkType: hard -"std-env@npm:^3.8.0": +"std-env@npm:^3.8.1": version: 3.8.1 resolution: "std-env@npm:3.8.1" checksum: 10c0/e9b19cca6bc6f06f91607db5b636662914ca8ec9efc525a99da6ec7e493afec109d3b017d21d9782b4369fcfb2891c7c4b4e3c60d495fdadf6861ce434e07bf8 @@ -3144,21 +3303,21 @@ __metadata: languageName: node linkType: hard -"tldts-core@npm:^6.1.84": - version: 6.1.84 - resolution: "tldts-core@npm:6.1.84" - checksum: 10c0/e64b2f1d13788dc67a8c9f61e1d227b20e83328565a1eb8aeb704d991dc9ae1a0b48665260a78927ba7809793e000bb3071a21a9686d9a02a9be17f8a527e6bb +"tldts-core@npm:^6.1.85": + version: 6.1.85 + resolution: "tldts-core@npm:6.1.85" + checksum: 10c0/f028759b361bef86d3dd8dbaaa010b4c3aca236ec7ba097658b9a595243bb34c98206e410cc3631055af6ed34012f5da7e9af2c4e38e218d5fc693df6ab3da33 languageName: node linkType: hard "tldts@npm:^6.1.32": - version: 6.1.84 - resolution: "tldts@npm:6.1.84" + version: 6.1.85 + resolution: "tldts@npm:6.1.85" dependencies: - tldts-core: "npm:^6.1.84" + tldts-core: "npm:^6.1.85" bin: tldts: bin/cli.js - checksum: 10c0/84c865197ff8eb83283e1c1b7bc45a7e7ff9a41922dad0348c586791df63d6605a5a8e8efb6d4962b63459b2f3c0096d683041f65e29b468ccaf53fe99d9a9e0 + checksum: 10c0/83bc222046f36a9ca071b662e3272bb1e98e849fa4bddfab0a3eba8804a4a539b02bcbe55e1277fe713de6677e55104da2ef9a54d006c642b6e9f26c7595d5aa languageName: node linkType: hard @@ -3196,6 +3355,23 @@ __metadata: languageName: node linkType: hard +"typedoc@npm:0.28.1": + version: 0.28.1 + resolution: "typedoc@npm:0.28.1" + dependencies: + "@gerrit0/mini-shiki": "npm:^3.2.1" + lunr: "npm:^2.3.9" + markdown-it: "npm:^14.1.0" + minimatch: "npm:^9.0.5" + yaml: "npm:^2.7.0 " + peerDependencies: + typescript: 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x + bin: + typedoc: bin/typedoc + checksum: 10c0/9932b28a7bcfebc523d9bd32c6a97bdb6a87556921a68ba9bf6792ce87ba964c7d5af0eebd954a6ecb6bbbc5bbc9282a7554c71e5fc201642a4b87bbb0443369 + languageName: node + linkType: hard + "typescript@npm:5.8.2": version: 5.8.2 resolution: "typescript@npm:5.8.2" @@ -3216,6 +3392,13 @@ __metadata: languageName: node linkType: hard +"uc.micro@npm:^2.0.0, uc.micro@npm:^2.1.0": + version: 2.1.0 + resolution: "uc.micro@npm:2.1.0" + checksum: 10c0/8862eddb412dda76f15db8ad1c640ccc2f47cdf8252a4a30be908d535602c8d33f9855dfcccb8b8837855c1ce1eaa563f7fa7ebe3c98fd0794351aab9b9c55fa + languageName: node + linkType: hard + "unique-filename@npm:^4.0.0": version: 4.0.0 resolution: "unique-filename@npm:4.0.0" @@ -3234,9 +3417,9 @@ __metadata: languageName: node linkType: hard -"vite-node@npm:3.0.8": - version: 3.0.8 - resolution: "vite-node@npm:3.0.8" +"vite-node@npm:3.1.1": + version: 3.1.1 + resolution: "vite-node@npm:3.1.1" dependencies: cac: "npm:^6.7.14" debug: "npm:^4.4.0" @@ -3245,13 +3428,13 @@ __metadata: vite: "npm:^5.0.0 || ^6.0.0" bin: vite-node: vite-node.mjs - checksum: 10c0/1e7243ad04edc71ccff67b1a686cc85b59ad803645b83c524eab6cde92d6c8f06d595cc99cd3236b4017de27d6760808c419711cd728471eb36ec9a6734ef651 + checksum: 10c0/15ee73c472ae00f042a7cee09a31355d2c0efbb2dab160377545be9ba4b980a5f4cb2841b98319d87bedf630bbbb075e6b40796b39f65610920cf3fde66fdf8d languageName: node linkType: hard "vite@npm:^5.0.0 || ^6.0.0": - version: 6.2.2 - resolution: "vite@npm:6.2.2" + version: 6.2.4 + resolution: "vite@npm:6.2.4" dependencies: esbuild: "npm:^0.25.0" fsevents: "npm:~2.3.3" @@ -3297,40 +3480,40 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 10c0/52f5b1c10cfe5e3b6382c6de1811ebbf76df9b5a8bab3d65169446c6b54a5f1528f775b1548009a6d8aad11def20fba046bb3e9abb10c0c2c9ccd78118623bb8 + checksum: 10c0/5a011ee5cce91de023a22564a314f04bf64d0d02b420d92c3d539d10257448d60e98e52b491404656426fba4a50dc25f107282540d7388fc5303dc441280155e languageName: node linkType: hard -"vitest@npm:3.0.8": - version: 3.0.8 - resolution: "vitest@npm:3.0.8" - dependencies: - "@vitest/expect": "npm:3.0.8" - "@vitest/mocker": "npm:3.0.8" - "@vitest/pretty-format": "npm:^3.0.8" - "@vitest/runner": "npm:3.0.8" - "@vitest/snapshot": "npm:3.0.8" - "@vitest/spy": "npm:3.0.8" - "@vitest/utils": "npm:3.0.8" +"vitest@npm:3.1.1": + version: 3.1.1 + resolution: "vitest@npm:3.1.1" + dependencies: + "@vitest/expect": "npm:3.1.1" + "@vitest/mocker": "npm:3.1.1" + "@vitest/pretty-format": "npm:^3.1.1" + "@vitest/runner": "npm:3.1.1" + "@vitest/snapshot": "npm:3.1.1" + "@vitest/spy": "npm:3.1.1" + "@vitest/utils": "npm:3.1.1" chai: "npm:^5.2.0" debug: "npm:^4.4.0" - expect-type: "npm:^1.1.0" + expect-type: "npm:^1.2.0" magic-string: "npm:^0.30.17" pathe: "npm:^2.0.3" - std-env: "npm:^3.8.0" + std-env: "npm:^3.8.1" tinybench: "npm:^2.9.0" tinyexec: "npm:^0.3.2" tinypool: "npm:^1.0.2" tinyrainbow: "npm:^2.0.0" vite: "npm:^5.0.0 || ^6.0.0" - vite-node: "npm:3.0.8" + vite-node: "npm:3.1.1" why-is-node-running: "npm:^2.3.0" peerDependencies: "@edge-runtime/vm": "*" "@types/debug": ^4.1.12 "@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0 - "@vitest/browser": 3.0.8 - "@vitest/ui": 3.0.8 + "@vitest/browser": 3.1.1 + "@vitest/ui": 3.1.1 happy-dom: "*" jsdom: "*" peerDependenciesMeta: @@ -3350,7 +3533,7 @@ __metadata: optional: true bin: vitest: vitest.mjs - checksum: 10c0/007a951c4e10ceda1eecad38e5bcc7aa25ed90269614e1394eb2c5fa5f51bbe05d915bcec27fc2e18da8bdea27cea80d428095ef818b97857c51422fddda34ff + checksum: 10c0/680f31d2a7ca59509f837acdbacd9dff405e1b00c606d7cd29717127c6b543f186055854562c2604f74c5cd668b70174968d28feb4ed948a7e013c9477a68d50 languageName: node linkType: hard @@ -3502,6 +3685,15 @@ __metadata: languageName: node linkType: hard +"yaml@npm:^2.7.0 ": + version: 2.7.1 + resolution: "yaml@npm:2.7.1" + bin: + yaml: bin.mjs + checksum: 10c0/ee2126398ab7d1fdde566b4013b68e36930b9e6d8e68b6db356875c99614c10d678b6f45597a145ff6d63814961221fc305bf9242af8bf7450177f8a68537590 + languageName: node + linkType: hard + "yargs-parser@npm:^21.1.1": version: 21.1.1 resolution: "yargs-parser@npm:21.1.1" From 67188a8650cef55c38201711311992dca31df171 Mon Sep 17 00:00:00 2001 From: Sora Morimoto Date: Wed, 2 Apr 2025 00:47:30 +0900 Subject: [PATCH 2/2] _ Signed-off-by: Sora Morimoto --- package.json | 1 + src/SpeechRecognition.test.js | 1044 --------------------------------- src/android.test.js | 71 --- src/android.test.ts | 60 ++ src/isAndroid.test.js | 34 -- src/isAndroid.test.ts | 28 + tests/vendor/corti.js | 231 -------- yarn.lock | 8 + 8 files changed, 97 insertions(+), 1380 deletions(-) delete mode 100644 src/SpeechRecognition.test.js delete mode 100644 src/android.test.js create mode 100644 src/android.test.ts delete mode 100644 src/isAndroid.test.js create mode 100644 src/isAndroid.test.ts delete mode 100644 tests/vendor/corti.js diff --git a/package.json b/package.json index 5065e52..49506ad 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "@types/lodash.debounce": "4.0.9", "@vitest/coverage-v8": "3.1.1", "bunchee": "6.5.0", + "corti": "1.0.0", "jsdom": "26.0.0", "react": "16.14.0", "react-dom": "16.14.0", diff --git a/src/SpeechRecognition.test.js b/src/SpeechRecognition.test.js deleted file mode 100644 index 3ded1be..0000000 --- a/src/SpeechRecognition.test.js +++ /dev/null @@ -1,1044 +0,0 @@ -// @vitest-environment jsdom -import { renderHook } from "@testing-library/react-hooks"; -import { beforeEach, describe, expect, test, vi } from "vitest"; -import { CortiSpeechRecognition } from "../tests/vendor/corti.js"; -import RecognitionManager from "./RecognitionManager.js"; -import SpeechRecognition, { - useSpeechRecognition, -} from "./SpeechRecognition.js"; -import isAndroid from "./isAndroid.js"; -import { browserSupportsPolyfills } from "./utils.js"; - -vi.mock("./isAndroid"); -vi.mock("./utils", async () => { - return { - ...(await vi.importActual("./utils")), - browserSupportsPolyfills: vi.fn(), - }; -}); - -const mockRecognitionManager = () => { - const recognitionManager = new RecognitionManager(window.SpeechRecognition); - SpeechRecognition.getRecognitionManager = () => recognitionManager; - return recognitionManager; -}; - -const mockMicrophoneUnavailable = () => { - const mockSpeechRecognition = vi.fn().mockImplementation(() => ({ - start: async () => Promise.reject(new Error()), - })); - SpeechRecognition.applyPolyfill(mockSpeechRecognition); - const recognitionManager = new RecognitionManager(mockSpeechRecognition); - SpeechRecognition.getRecognitionManager = () => recognitionManager; -}; - -describe("SpeechRecognition", () => { - beforeEach(() => { - isAndroid.mockClear(); - browserSupportsPolyfills.mockImplementation(() => true); - SpeechRecognition.applyPolyfill(CortiSpeechRecognition); - }); - - test("sets applyPolyfill correctly", () => { - const MockSpeechRecognition = class {}; - - expect( - SpeechRecognition.getRecognition() instanceof CortiSpeechRecognition, - ).toBe(true); - - SpeechRecognition.applyPolyfill(MockSpeechRecognition); - - expect(SpeechRecognition.browserSupportsSpeechRecognition()).toBe(true); - expect( - SpeechRecognition.getRecognition() instanceof MockSpeechRecognition, - ).toBe(true); - }); - - test("does not collect transcripts from previous speech recognition after polyfill applied", async () => { - const cortiSpeechRecognition = SpeechRecognition.getRecognition(); - - const { result } = renderHook(() => useSpeechRecognition()); - const speech = "This is a test"; - await SpeechRecognition.startListening(); - SpeechRecognition.applyPolyfill(class {}); - cortiSpeechRecognition.say(speech); - - const { transcript, interimTranscript, finalTranscript } = result.current; - expect(transcript).toBe(""); - expect(interimTranscript).toBe(""); - expect(finalTranscript).toBe(""); - }); - - test("stops listening after polyfill applied", async () => { - const { result } = renderHook(() => useSpeechRecognition()); - await SpeechRecognition.startListening(); - SpeechRecognition.applyPolyfill(class {}); - - const { listening } = result.current; - expect(listening).toBe(false); - }); - - test("sets browserSupportsContinuousListening to false when using polyfill on unsupported browser", () => { - browserSupportsPolyfills.mockImplementation(() => false); - const MockSpeechRecognition = class {}; - SpeechRecognition.applyPolyfill(MockSpeechRecognition); - - const { result } = renderHook(() => useSpeechRecognition()); - const { browserSupportsContinuousListening } = result.current; - - expect(browserSupportsContinuousListening).toBe(false); - expect(SpeechRecognition.browserSupportsContinuousListening()).toBe(false); - }); - - test("sets browserSupportsSpeechRecognition to false when using polyfill on unsupported browser", () => { - browserSupportsPolyfills.mockImplementation(() => false); - const MockSpeechRecognition = class {}; - SpeechRecognition.applyPolyfill(MockSpeechRecognition); - - const { result } = renderHook(() => useSpeechRecognition()); - const { browserSupportsSpeechRecognition } = result.current; - - expect(browserSupportsSpeechRecognition).toBe(false); - expect(SpeechRecognition.browserSupportsSpeechRecognition()).toBe(false); - }); - - test("reverts to native recognition when removePolyfill called", () => { - const MockSpeechRecognition = class {}; - SpeechRecognition.applyPolyfill(MockSpeechRecognition); - - expect( - SpeechRecognition.getRecognition() instanceof MockSpeechRecognition, - ).toBe(true); - - browserSupportsPolyfills.mockImplementation(() => false); - SpeechRecognition.applyPolyfill(); - - expect(SpeechRecognition.browserSupportsSpeechRecognition()).toBe(false); - expect(SpeechRecognition.browserSupportsContinuousListening()).toBe(false); - - SpeechRecognition.removePolyfill(); - - expect(SpeechRecognition.browserSupportsSpeechRecognition()).toBe(true); - expect(SpeechRecognition.browserSupportsContinuousListening()).toBe(true); - expect( - SpeechRecognition.getRecognition() instanceof CortiSpeechRecognition, - ).toBe(true); - }); - - test("sets browserSupportsContinuousListening to false when given falsey SpeechRecognition", () => { - SpeechRecognition.applyPolyfill(); - - const { result } = renderHook(() => useSpeechRecognition()); - const { browserSupportsContinuousListening } = result.current; - - expect(browserSupportsContinuousListening).toBe(false); - expect(SpeechRecognition.browserSupportsContinuousListening()).toBe(false); - }); - - test("sets browserSupportsSpeechRecognition to false when given falsey SpeechRecognition", () => { - SpeechRecognition.applyPolyfill(); - - const { result } = renderHook(() => useSpeechRecognition()); - const { browserSupportsSpeechRecognition } = result.current; - - expect(browserSupportsSpeechRecognition).toBe(false); - expect(SpeechRecognition.browserSupportsSpeechRecognition()).toBe(false); - }); - - test("sets default transcripts correctly", () => { - const { result } = renderHook(() => useSpeechRecognition()); - - const { transcript, interimTranscript, finalTranscript } = result.current; - expect(transcript).toBe(""); - expect(interimTranscript).toBe(""); - expect(finalTranscript).toBe(""); - }); - - test("updates transcripts correctly", async () => { - mockRecognitionManager(); - const { result } = renderHook(() => useSpeechRecognition()); - const speech = "This is a test"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - const { transcript, interimTranscript, finalTranscript } = result.current; - expect(transcript).toBe(speech); - expect(interimTranscript).toBe(""); - expect(finalTranscript).toBe(speech); - }); - - test("resets transcripts correctly", async () => { - mockRecognitionManager(); - const { result } = renderHook(() => useSpeechRecognition()); - const speech = "This is a test"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - result.current.resetTranscript(); - - const { transcript, interimTranscript, finalTranscript } = result.current; - expect(transcript).toBe(""); - expect(interimTranscript).toBe(""); - expect(finalTranscript).toBe(""); - }); - - test("is listening when Speech Recognition is listening", async () => { - mockRecognitionManager(); - const { result } = renderHook(() => useSpeechRecognition()); - await SpeechRecognition.startListening(); - - expect(result.current.listening).toBe(true); - }); - - test("is not listening when Speech Recognition is not listening", () => { - mockRecognitionManager(); - const { result } = renderHook(() => useSpeechRecognition()); - - expect(result.current.listening).toBe(false); - }); - - test("exposes Speech Recognition object", () => { - const recognitionManager = mockRecognitionManager(); - - expect(SpeechRecognition.getRecognition()).toBe( - recognitionManager.recognition, - ); - }); - - test("ignores speech when listening is stopped", () => { - mockRecognitionManager(); - const { result } = renderHook(() => useSpeechRecognition()); - const speech = "This is a test"; - - SpeechRecognition.getRecognition().say(speech); - - const { transcript, interimTranscript, finalTranscript } = result.current; - expect(transcript).toBe(""); - expect(interimTranscript).toBe(""); - expect(finalTranscript).toBe(""); - }); - - test("ignores speech when listening is aborted", async () => { - mockRecognitionManager(); - const { result } = renderHook(() => useSpeechRecognition()); - const speech = "This is a test"; - - await SpeechRecognition.startListening(); - SpeechRecognition.abortListening(); - SpeechRecognition.getRecognition().say(speech); - - const { transcript, interimTranscript, finalTranscript } = result.current; - expect(transcript).toBe(""); - expect(interimTranscript).toBe(""); - expect(finalTranscript).toBe(""); - }); - - test("transcibes when listening is started", async () => { - mockRecognitionManager(); - const { result } = renderHook(() => useSpeechRecognition()); - const speech = "This is a test"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - const { transcript, interimTranscript, finalTranscript } = result.current; - expect(transcript).toBe(speech); - expect(interimTranscript).toBe(""); - expect(finalTranscript).toBe(speech); - }); - - test("does not transcibe when listening is started but not transcribing", async () => { - mockRecognitionManager(); - const { result } = renderHook(() => - useSpeechRecognition({ transcribing: false }), - ); - const speech = "This is a test"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - const { transcript, interimTranscript, finalTranscript } = result.current; - expect(transcript).toBe(""); - expect(interimTranscript).toBe(""); - expect(finalTranscript).toBe(""); - }); - - test("listens discontinuously by default", async () => { - mockRecognitionManager(); - renderHook(() => useSpeechRecognition()); - const speech = "This is a test"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - SpeechRecognition.getRecognition().say(speech); - }); - - test("can turn continuous listening on", async () => { - mockRecognitionManager(); - const { result } = renderHook(() => useSpeechRecognition()); - const speech = "This is a test"; - const expectedTranscript = [speech, speech].join(" "); - - await SpeechRecognition.startListening({ continuous: true }); - SpeechRecognition.getRecognition().say(speech); - SpeechRecognition.getRecognition().say(speech); - - const { transcript, interimTranscript, finalTranscript } = result.current; - expect(transcript).toBe(expectedTranscript); - expect(interimTranscript).toBe(""); - expect(finalTranscript).toBe(expectedTranscript); - }); - - test("can reset transcript from command callback", async () => { - mockRecognitionManager(); - const commands = [ - { - command: "clear", - callback: ({ resetTranscript }) => resetTranscript(), - }, - ]; - const { result } = renderHook(() => useSpeechRecognition({ commands })); - - await SpeechRecognition.startListening({ continuous: true }); - SpeechRecognition.getRecognition().say("test"); - - expect(result.current.transcript).toBe("test"); - - SpeechRecognition.getRecognition().say("clear"); - - const { transcript, interimTranscript, finalTranscript } = result.current; - expect(transcript).toBe(""); - expect(interimTranscript).toBe(""); - expect(finalTranscript).toBe(""); - }); - - test("can set language", async () => { - mockRecognitionManager(); - renderHook(() => useSpeechRecognition()); - - await SpeechRecognition.startListening({ language: "zh-CN" }); - - expect(SpeechRecognition.getRecognition().lang).toBe("zh-CN"); - }); - - test("does not collect transcript after listening is stopped", async () => { - mockRecognitionManager(); - const { result } = renderHook(() => useSpeechRecognition()); - const speech = "This is a test"; - - await SpeechRecognition.startListening(); - SpeechRecognition.stopListening(); - SpeechRecognition.getRecognition().say(speech); - - const { transcript, interimTranscript, finalTranscript } = result.current; - expect(transcript).toBe(""); - expect(interimTranscript).toBe(""); - expect(finalTranscript).toBe(""); - }); - - test("sets interim transcript correctly", async () => { - mockRecognitionManager(); - const { result } = renderHook(() => useSpeechRecognition()); - const speech = "This is a test"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech, { onlyFirstResult: true }); - - const { transcript, interimTranscript, finalTranscript } = result.current; - expect(transcript).toBe("This"); - expect(interimTranscript).toBe("This"); - expect(finalTranscript).toBe(""); - }); - - test("appends interim transcript correctly", async () => { - mockRecognitionManager(); - const { result } = renderHook(() => useSpeechRecognition()); - const speech = "This is a test"; - - await SpeechRecognition.startListening({ continuous: true }); - SpeechRecognition.getRecognition().say(speech); - SpeechRecognition.getRecognition().say(speech, { onlyFirstResult: true }); - - const { transcript, interimTranscript, finalTranscript } = result.current; - expect(transcript).toBe("This is a test This"); - expect(interimTranscript).toBe("This"); - expect(finalTranscript).toBe(speech); - }); - - test("appends interim transcript correctly on Android", async () => { - isAndroid.mockReturnValue(true); - mockRecognitionManager(); - const { result } = renderHook(() => useSpeechRecognition()); - const speech = "This is a test"; - - await SpeechRecognition.startListening({ continuous: true }); - SpeechRecognition.getRecognition().say(speech, { isAndroid: true }); - SpeechRecognition.getRecognition().say(speech, { - onlyFirstResult: true, - isAndroid: true, - }); - - const { transcript, interimTranscript, finalTranscript } = result.current; - expect(transcript).toBe("This is a test This"); - expect(interimTranscript).toBe("This"); - expect(finalTranscript).toBe(speech); - }); - - test("resets transcript on subsequent discontinuous speech when clearTranscriptOnListen set", async () => { - mockRecognitionManager(); - const { result } = renderHook(() => useSpeechRecognition()); - const speech = "This is a test"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(result.current.transcript).toBe(speech); - expect(result.current.interimTranscript).toBe(""); - expect(result.current.finalTranscript).toBe(speech); - - SpeechRecognition.stopListening(); - - expect(result.current.transcript).toBe(speech); - expect(result.current.interimTranscript).toBe(""); - expect(result.current.finalTranscript).toBe(speech); - - await SpeechRecognition.startListening(); - - expect(result.current.transcript).toBe(""); - expect(result.current.interimTranscript).toBe(""); - expect(result.current.finalTranscript).toBe(""); - }); - - test("does not reset transcript on subsequent discontinuous speech when clearTranscriptOnListen not set", async () => { - mockRecognitionManager(); - const { result } = renderHook(() => - useSpeechRecognition({ clearTranscriptOnListen: false }), - ); - const speech = "This is a test"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - expect(result.current.transcript).toBe(speech); - expect(result.current.interimTranscript).toBe(""); - expect(result.current.finalTranscript).toBe(speech); - - SpeechRecognition.stopListening(); - - expect(result.current.transcript).toBe(speech); - expect(result.current.interimTranscript).toBe(""); - expect(result.current.finalTranscript).toBe(speech); - - await SpeechRecognition.startListening(); - - expect(result.current.transcript).toBe(speech); - expect(result.current.interimTranscript).toBe(""); - expect(result.current.finalTranscript).toBe(speech); - }); - - test("does not call command callback when no command matched", async () => { - mockRecognitionManager(); - const mockCommandCallback = vi.fn(); - const commands = [ - { - command: "hello world", - callback: mockCommandCallback, - matchInterim: false, - }, - ]; - renderHook(() => useSpeechRecognition({ commands })); - const speech = "This is a test"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(mockCommandCallback).not.toHaveBeenCalled(); - }); - - test("matches simple command", async () => { - mockRecognitionManager(); - const mockCommandCallback = vi.fn(); - const commands = [ - { - command: "hello world", - callback: mockCommandCallback, - }, - ]; - renderHook(() => useSpeechRecognition({ commands })); - const speech = "hello world"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(mockCommandCallback).toHaveBeenCalledTimes(1); - }); - - test("matches one splat", async () => { - mockRecognitionManager(); - const mockCommandCallback = vi.fn(); - const command = "I want to eat * and fries"; - const commands = [ - { - command, - callback: mockCommandCallback, - }, - ]; - const { result } = renderHook(() => useSpeechRecognition({ commands })); - const { resetTranscript } = result.current; - const speech = "I want to eat pizza and fries"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(mockCommandCallback).toHaveBeenCalledTimes(1); - expect(mockCommandCallback).toHaveBeenCalledWith("pizza", { - command, - resetTranscript, - }); - }); - - test("matches one splat at the end of the sentence", async () => { - mockRecognitionManager(); - const mockCommandCallback = vi.fn(); - const command = "I want to eat *"; - const commands = [ - { - command, - callback: mockCommandCallback, - }, - ]; - const { result } = renderHook(() => useSpeechRecognition({ commands })); - const { resetTranscript } = result.current; - const speech = "I want to eat pizza and fries"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(mockCommandCallback).toHaveBeenCalledTimes(1); - expect(mockCommandCallback).toHaveBeenCalledWith("pizza and fries", { - command, - resetTranscript, - }); - }); - - test("matches two splats", async () => { - mockRecognitionManager(); - const mockCommandCallback = vi.fn(); - const command = "I want to eat * and *"; - const commands = [ - { - command, - callback: mockCommandCallback, - }, - ]; - const { result } = renderHook(() => useSpeechRecognition({ commands })); - const { resetTranscript } = result.current; - const speech = "I want to eat pizza and fries"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(mockCommandCallback).toHaveBeenCalledTimes(1); - expect(mockCommandCallback).toHaveBeenCalledWith("pizza", "fries", { - command, - resetTranscript, - }); - }); - - test("matches optional words when optional word spoken", async () => { - mockRecognitionManager(); - const mockCommandCallback = vi.fn(); - const commands = [ - { - command: "Hello (to) you", - callback: mockCommandCallback, - }, - ]; - renderHook(() => useSpeechRecognition({ commands })); - const speech = "Hello to you"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(mockCommandCallback).toHaveBeenCalledTimes(1); - }); - - test("matches optional words when optional word not spoken", async () => { - mockRecognitionManager(); - const mockCommandCallback = vi.fn(); - const commands = [ - { - command: "Hello (to) you", - callback: mockCommandCallback, - }, - ]; - renderHook(() => useSpeechRecognition({ commands })); - const speech = "Hello you"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(mockCommandCallback).toHaveBeenCalledTimes(1); - }); - - test("matches named variable", async () => { - mockRecognitionManager(); - const mockCommandCallback = vi.fn(); - const command = "I :action with my little eye"; - const commands = [ - { - command, - callback: mockCommandCallback, - }, - ]; - const { result } = renderHook(() => useSpeechRecognition({ commands })); - const { resetTranscript } = result.current; - const speech = "I spy with my little eye"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(mockCommandCallback).toHaveBeenCalledTimes(1); - expect(mockCommandCallback).toHaveBeenCalledWith("spy", { - command, - resetTranscript, - }); - }); - - test("matches regex", async () => { - mockRecognitionManager(); - const mockCommandCallback = vi.fn(); - const commands = [ - { - command: /This is a \s+ test\.+/, - callback: mockCommandCallback, - }, - ]; - renderHook(() => useSpeechRecognition({ commands })); - const speech = "This is a test......."; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(mockCommandCallback).toHaveBeenCalledTimes(1); - }); - - test("matches regex case-insensitively", async () => { - mockRecognitionManager(); - const mockCommandCallback = vi.fn(); - const commands = [ - { - command: /This is a \s+ test\.+/, - callback: mockCommandCallback, - }, - ]; - renderHook(() => useSpeechRecognition({ commands })); - const speech = "this is a TEST......."; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(mockCommandCallback).toHaveBeenCalledTimes(1); - }); - - test("matches multiple commands", async () => { - mockRecognitionManager(); - const mockCommandCallback1 = vi.fn(); - const mockCommandCallback2 = vi.fn(); - const mockCommandCallback3 = vi.fn(); - const command1 = "I want to eat * and *"; - const command2 = "* and fries are great"; - const commands = [ - { - command: command1, - callback: mockCommandCallback1, - }, - { - command: command2, - callback: mockCommandCallback2, - }, - { - command: "flibble", - callback: mockCommandCallback3, - }, - ]; - const { result } = renderHook(() => useSpeechRecognition({ commands })); - const { resetTranscript } = result.current; - const speech = "I want to eat pizza and fries are great"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(mockCommandCallback1).toHaveBeenCalledTimes(1); - expect(mockCommandCallback1).toHaveBeenCalledWith( - "pizza", - "fries are great", - { command: command1, resetTranscript }, - ); - expect(mockCommandCallback2).toHaveBeenCalledTimes(1); - expect(mockCommandCallback2).toHaveBeenCalledWith("I want to eat pizza", { - command: command2, - resetTranscript, - }); - expect(mockCommandCallback3).not.toHaveBeenCalled(); - }); - - test("matches arrays of commands", async () => { - mockRecognitionManager(); - const mockCommandCallback1 = vi.fn(); - const mockCommandCallback2 = vi.fn(); - const command1 = "I want to eat * and *"; - const command2 = "* and fries are great"; - const command3 = "* and * are great"; - const commands = [ - { - command: [command1, command2], - callback: mockCommandCallback1, - }, - { - command: command3, - callback: mockCommandCallback2, - }, - ]; - const { result } = renderHook(() => useSpeechRecognition({ commands })); - const { resetTranscript } = result.current; - const speech = "I want to eat pizza and fries are great"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(mockCommandCallback1).toHaveBeenCalledTimes(2); - expect(mockCommandCallback1).toHaveBeenNthCalledWith( - 1, - "pizza", - "fries are great", - { command: command1, resetTranscript }, - ); - expect(mockCommandCallback1).toHaveBeenNthCalledWith( - 2, - "I want to eat pizza", - { command: command2, resetTranscript }, - ); - expect(mockCommandCallback2).toHaveBeenCalledTimes(1); - expect(mockCommandCallback2).toHaveBeenCalledWith( - "I want to eat pizza", - "fries", - { command: command3, resetTranscript }, - ); - }); - - test("does not match interim results by default", async () => { - mockRecognitionManager(); - const mockCommandCallback = vi.fn(); - const commands = [ - { - command: "This is", - callback: mockCommandCallback, - }, - ]; - renderHook(() => useSpeechRecognition({ commands })); - const speech = "This is a test"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(mockCommandCallback).not.toHaveBeenCalled(); - }); - - test("matches interim results when configured", async () => { - mockRecognitionManager(); - const mockCommandCallback = vi.fn(); - const commands = [ - { - command: "This is", - callback: mockCommandCallback, - matchInterim: true, - }, - ]; - renderHook(() => useSpeechRecognition({ commands })); - const speech = "This is a test"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(mockCommandCallback).toHaveBeenCalledTimes(1); - }); - - test("transcript resets should be per instance, not global", async () => { - mockRecognitionManager(); - const hook1 = renderHook(() => useSpeechRecognition()); - const hook2 = renderHook(() => useSpeechRecognition()); - const speech = "This is a test"; - - await SpeechRecognition.startListening({ continuous: true }); - SpeechRecognition.getRecognition().say(speech); - hook2.result.current.resetTranscript(); - - expect(hook2.result.current.transcript).toBe(""); - expect(hook2.result.current.interimTranscript).toBe(""); - expect(hook2.result.current.finalTranscript).toBe(""); - expect(hook1.result.current.transcript).toBe(speech); - expect(hook1.result.current.interimTranscript).toBe(""); - expect(hook1.result.current.finalTranscript).toBe(speech); - }); - - test("does not call command callback when isFuzzyMatch is not true", async () => { - mockRecognitionManager(); - const mockCommandCallback = vi.fn(); - const commands = [ - { - command: "hello world", - callback: mockCommandCallback, - }, - ]; - renderHook(() => useSpeechRecognition({ commands })); - const speech = "This is a test"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(mockCommandCallback).not.toHaveBeenCalled(); - }); - - test("does not call command callback when isFuzzyMatch is true and similarity is less than fuzzyMatchingThreshold", async () => { - mockRecognitionManager(); - const mockCommandCallback = vi.fn(); - const commands = [ - { - command: "hello world", - callback: mockCommandCallback, - isFuzzyMatch: true, - fuzzyMatchingThreshold: 0.7, - }, - ]; - renderHook(() => useSpeechRecognition({ commands })); - const speech = "Hello"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(mockCommandCallback).not.toHaveBeenCalled(); - }); - - test("does call command callback when isFuzzyMatch is true and similarity is equal or greater than fuzzyMatchingThreshold", async () => { - mockRecognitionManager(); - const mockCommandCallback = vi.fn(); - const commands = [ - { - command: "hello world", - callback: mockCommandCallback, - isFuzzyMatch: true, - fuzzyMatchingThreshold: 0.5, - }, - ]; - renderHook(() => useSpeechRecognition({ commands })); - const speech = "Hello"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(mockCommandCallback).toHaveBeenCalledTimes(1); - }); - - test("callback is called with command, transcript and similarity ratio between those", async () => { - mockRecognitionManager(); - const mockCommandCallback = vi.fn(); - const command = "I want to eat"; - const commands = [ - { - command, - callback: mockCommandCallback, - isFuzzyMatch: true, - fuzzyMatchingThreshold: 0.5, - }, - ]; - const { result } = renderHook(() => useSpeechRecognition({ commands })); - const { resetTranscript } = result.current; - const speech = "I want to drink"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(mockCommandCallback).toHaveBeenCalledTimes(1); - expect(mockCommandCallback).toHaveBeenCalledWith( - "I want to eat", - "I want to drink", - 0.6, - { command, resetTranscript }, - ); - }); - - test("different callbacks can be called for the same speech and with fuzzyMatchingThreshold", async () => { - mockRecognitionManager(); - const mockCommandCallback1 = vi.fn(); - const mockCommandCallback2 = vi.fn(); - const commands = [ - { - command: "I want to eat", - callback: mockCommandCallback1, - isFuzzyMatch: true, - fuzzyMatchingThreshold: 1, - }, - { - command: "I want to sleep", - callback: mockCommandCallback2, - isFuzzyMatch: true, - fuzzyMatchingThreshold: 0.2, - }, - ]; - renderHook(() => useSpeechRecognition({ commands })); - const speech = "I want to eat"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(mockCommandCallback1).toHaveBeenCalledTimes(1); - expect(mockCommandCallback2).toHaveBeenCalledTimes(1); - }); - - test("fuzzy callback called for each matching command in array by default", async () => { - mockRecognitionManager(); - const mockCommandCallback = vi.fn(); - const command1 = "I want to eat"; - const command2 = "I want to sleep"; - const commands = [ - { - command: [command1, command2], - callback: mockCommandCallback, - isFuzzyMatch: true, - fuzzyMatchingThreshold: 0.2, - }, - ]; - const { result } = renderHook(() => useSpeechRecognition({ commands })); - const { resetTranscript } = result.current; - const speech = "I want to leap"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(mockCommandCallback).toHaveBeenCalledTimes(2); - expect(mockCommandCallback).toHaveBeenNthCalledWith( - 1, - command1, - "I want to leap", - 0.7368421052631579, - { command: command1, resetTranscript }, - ); - expect(mockCommandCallback).toHaveBeenNthCalledWith( - 2, - command2, - "I want to leap", - 0.6666666666666666, - { command: command2, resetTranscript }, - ); - }); - - test("fuzzy callback called only for best matching command in array when bestMatchOnly is true", async () => { - mockRecognitionManager(); - const mockCommandCallback = vi.fn(); - const command1 = "I want to eat"; - const command2 = "I want to sleep"; - const commands = [ - { - command: [command1, command2], - callback: mockCommandCallback, - isFuzzyMatch: true, - fuzzyMatchingThreshold: 0.2, - bestMatchOnly: true, - }, - ]; - const { result } = renderHook(() => useSpeechRecognition({ commands })); - const { resetTranscript } = result.current; - const speech = "I want to leap"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(mockCommandCallback).toHaveBeenCalledTimes(1); - expect(mockCommandCallback).toHaveBeenNthCalledWith( - 1, - command1, - "I want to leap", - 0.7368421052631579, - { command: command1, resetTranscript }, - ); - }); - - test("when command is regex with fuzzy match true runs similarity check with regex converted to string", async () => { - mockRecognitionManager(); - const mockCommandCallback = vi.fn(); - const command = /This is a \s+ test\.+/; - const commands = [ - { - command, - callback: mockCommandCallback, - isFuzzyMatch: true, - }, - ]; - const { result } = renderHook(() => useSpeechRecognition({ commands })); - const { resetTranscript } = result.current; - const speech = "This is a test"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(mockCommandCallback).toHaveBeenCalledTimes(1); - expect(mockCommandCallback).toHaveBeenCalledWith( - "This is a s test", - "This is a test", - 0.8571428571428571, - { command, resetTranscript }, - ); - }); - - test("when command is string special characters with fuzzy match true, special characters are removed from string and then we test similarity", async () => { - mockRecognitionManager(); - const mockCommandCallback = vi.fn(); - const command = "! (I would :like) : * a :pizza "; - const commands = [ - { - command, - callback: mockCommandCallback, - isFuzzyMatch: true, - }, - ]; - const { result } = renderHook(() => useSpeechRecognition({ commands })); - const { resetTranscript } = result.current; - const speech = "I would like a pizza"; - - await SpeechRecognition.startListening(); - SpeechRecognition.getRecognition().say(speech); - - expect(mockCommandCallback).toHaveBeenCalledTimes(1); - expect(mockCommandCallback).toHaveBeenCalledWith( - "I would like a pizza", - "I would like a pizza", - 1, - { command, resetTranscript }, - ); - }); - - test("sets isMicrophoneAvailable to false when recognition.start() throws", async () => { - mockMicrophoneUnavailable(); - const { result } = renderHook(() => useSpeechRecognition()); - - expect(result.current.isMicrophoneAvailable).toBe(true); - - await SpeechRecognition.startListening(); - - expect(result.current.isMicrophoneAvailable).toBe(false); - }); - - test("sets isMicrophoneAvailable to false when not-allowed error emitted", async () => { - mockRecognitionManager(); - const { result } = renderHook(() => useSpeechRecognition()); - - expect(result.current.isMicrophoneAvailable).toBe(true); - - await SpeechRecognition.getRecognitionManager().recognition.onerror({ - error: "not-allowed", - }); - - expect(result.current.isMicrophoneAvailable).toBe(false); - }); -}); diff --git a/src/android.test.js b/src/android.test.js deleted file mode 100644 index 5cff486..0000000 --- a/src/android.test.js +++ /dev/null @@ -1,71 +0,0 @@ -// @vitest-environment jsdom -import { renderHook } from "@testing-library/react-hooks"; -import { beforeEach, describe, expect, test, vi } from "vitest"; -import "../tests/vendor/corti.js"; -import RecognitionManager from "./RecognitionManager.js"; -import SpeechRecognition, { - useSpeechRecognition, -} from "./SpeechRecognition.js"; -import { browserSupportsPolyfills } from "./utils.js"; - -vi.mock("./isAndroid", () => ({ - default: () => true, -})); - -vi.mock("./utils", async () => { - return { - ...(await vi.importActual("./utils")), - browserSupportsPolyfills: vi.fn(), - }; -}); - -const mockRecognitionManager = () => { - const recognitionManager = new RecognitionManager(window.SpeechRecognition); - SpeechRecognition.getRecognitionManager = () => recognitionManager; - return recognitionManager; -}; - -describe("SpeechRecognition (Android)", () => { - beforeEach(() => { - browserSupportsPolyfills.mockImplementation(() => true); - }); - - test("sets browserSupportsContinuousListening to false on Android", async () => { - mockRecognitionManager(); - - const { result } = renderHook(() => useSpeechRecognition()); - const { browserSupportsContinuousListening } = result.current; - - expect(browserSupportsContinuousListening).toEqual(false); - expect(SpeechRecognition.browserSupportsContinuousListening()).toEqual( - false, - ); - }); - - test("sets browserSupportsContinuousListening to true when using polyfill", () => { - const MockSpeechRecognition = class {}; - SpeechRecognition.applyPolyfill(MockSpeechRecognition); - - const { result } = renderHook(() => useSpeechRecognition()); - const { browserSupportsContinuousListening } = result.current; - - expect(browserSupportsContinuousListening).toEqual(true); - expect(SpeechRecognition.browserSupportsContinuousListening()).toEqual( - true, - ); - }); - - test("sets browserSupportsContinuousListening to false when using polyfill on unsupported browser", () => { - browserSupportsPolyfills.mockImplementation(() => false); - const MockSpeechRecognition = class {}; - SpeechRecognition.applyPolyfill(MockSpeechRecognition); - - const { result } = renderHook(() => useSpeechRecognition()); - const { browserSupportsContinuousListening } = result.current; - - expect(browserSupportsContinuousListening).toEqual(false); - expect(SpeechRecognition.browserSupportsContinuousListening()).toEqual( - false, - ); - }); -}); diff --git a/src/android.test.ts b/src/android.test.ts new file mode 100644 index 0000000..8346eb1 --- /dev/null +++ b/src/android.test.ts @@ -0,0 +1,60 @@ +// @vitest-environment jsdom + +// @ts-expect-error +import { SpeechRecognition as SpeechRecognitionMock } from "corti"; + +import { renderHook } from "@testing-library/react-hooks"; +import { afterAll, beforeAll, expect, test, vi } from "vitest"; +import SpeechRecognition, { + useSpeechRecognition, +} from "./SpeechRecognition.js"; + +const browserSupportsPolyfillsMock = vi.hoisted(() => vi.fn()); + +vi.mock(import("./isAndroid.js"), () => { + return { + default: vi.fn(() => true), + }; +}); + +vi.mock(import("./utils.js"), async (importOriginal) => { + const module = await importOriginal(); + return { + ...module, + browserSupportsPolyfills: browserSupportsPolyfillsMock, + }; +}); + +beforeAll(() => { + vi.stubGlobal("SpeechRecognition", SpeechRecognitionMock); +}); + +afterAll(() => { + vi.unstubAllGlobals(); +}); + +test("sets browserSupportsContinuousListening to false on Android", async () => { + browserSupportsPolyfillsMock.mockReturnValue(false); + const { result } = renderHook(() => useSpeechRecognition()); + const { browserSupportsContinuousListening } = result.current; + expect(browserSupportsContinuousListening).toEqual(false); + expect(SpeechRecognition.browserSupportsContinuousListening()).toEqual(false); +}); + +test("sets browserSupportsContinuousListening to true when using polyfill", () => { + browserSupportsPolyfillsMock.mockReturnValue(true); + SpeechRecognition.applyPolyfill(SpeechRecognitionMock); + const { result } = renderHook(() => useSpeechRecognition()); + const { browserSupportsContinuousListening } = result.current; + expect(browserSupportsContinuousListening).toEqual(true); + expect(SpeechRecognition.browserSupportsContinuousListening()).toEqual(true); +}); + +test("sets browserSupportsContinuousListening to false when using polyfill on unsupported browser", () => { + browserSupportsPolyfillsMock.mockReturnValue(false); + SpeechRecognition.applyPolyfill(SpeechRecognitionMock); + const { result } = renderHook(() => useSpeechRecognition()); + const { browserSupportsContinuousListening } = result.current; + expect(browserSupportsContinuousListening).toEqual(false); + expect(SpeechRecognition.browserSupportsContinuousListening()).toEqual(false); +}); diff --git a/src/isAndroid.test.js b/src/isAndroid.test.js deleted file mode 100644 index 1155424..0000000 --- a/src/isAndroid.test.js +++ /dev/null @@ -1,34 +0,0 @@ -import { afterEach, beforeEach, describe, expect, test, vi } from "vitest"; -import isAndroid from "./isAndroid.js"; - -describe("isAndroid", () => { - beforeEach(() => { - vi.stubGlobal("navigator", { userAgent: "" }); - }); - - afterEach(() => { - vi.unstubAllGlobals(); - }); - - test("returns false when navigator.userAgent does not contain android string", () => { - vi.stubGlobal("navigator", { userAgent: "safari browser" }); - const result = isAndroid(); - - expect(result).toBe(false); - }); - - test("returns true when navigator.userAgent contains android string", () => { - vi.stubGlobal("navigator", { userAgent: "android browser" }); - const result = isAndroid(); - - expect(result).toBe(true); - }); - - test("returns false when navigator is undefined", () => { - // navigatorをundefinedにモック - vi.stubGlobal("navigator", undefined); - const result = isAndroid(); - - expect(result).toBe(false); - }); -}); diff --git a/src/isAndroid.test.ts b/src/isAndroid.test.ts new file mode 100644 index 0000000..b34a2ba --- /dev/null +++ b/src/isAndroid.test.ts @@ -0,0 +1,28 @@ +import { afterEach, beforeEach, expect, test, vi } from "vitest"; +import isAndroid from "./isAndroid.js"; + +beforeEach(() => { + vi.stubGlobal("navigator", { userAgent: undefined }); +}); + +afterEach(() => { + vi.unstubAllGlobals(); +}); + +test("returns false when navigator.userAgent does not contain android string", () => { + vi.stubGlobal("navigator", { userAgent: "safari browser" }); + const result = isAndroid(); + expect(result).toBe(false); +}); + +test("returns true when navigator.userAgent contains android string", () => { + vi.stubGlobal("navigator", { userAgent: "android browser" }); + const result = isAndroid(); + expect(result).toBe(true); +}); + +test("returns false when navigator is undefined", () => { + vi.stubGlobal("navigator", undefined); + const result = isAndroid(); + expect(result).toBe(false); +}); diff --git a/tests/vendor/corti.js b/tests/vendor/corti.js deleted file mode 100644 index 3a7c5f8..0000000 --- a/tests/vendor/corti.js +++ /dev/null @@ -1,231 +0,0 @@ -//! Corti - Replaces the browser's SpeechRecognition with a fake object. -//! version : 0.4.0 -//! author : Tal Ater @TalAter -//! license : MIT -//! https://github.com/TalAter/Corti - -const Corti = (_root) => { - // Holds the browser's implementation - var _productionVersion = false; - - // Patch DOMException - // eslint-disable-next-line no-use-before-define - var DOMException = DOMException || TypeError; - - // Speech Recognition attributes - var _maxAlternatives = 1; - var _lang = ""; - var _continuous = false; - var _interimResults = false; - - var newSpeechRecognition = function () { - var _self = this; - var _listeners = document.createElement("div"); - _self._started = false; - _self._soundStarted = false; - _self.eventListenerTypes = ["start", "soundstart", "end", "result"]; - _self.maxAlternatives = 1; - - // Add listeners for events registered through attributes (e.g. recognition.onend = function) and not as proper listeners - _self.eventListenerTypes.forEach(function (eventName) { - _listeners.addEventListener( - eventName, - function () { - if (typeof _self["on" + eventName] === "function") { - _self["on" + eventName].apply(_listeners, arguments); - } - }, - false, - ); - }); - - Object.defineProperty(this, "maxAlternatives", { - get: function () { - return _maxAlternatives; - }, - set: function (val) { - if (typeof val === "number") { - _maxAlternatives = Math.floor(val); - } else { - _maxAlternatives = 0; - } - }, - }); - - Object.defineProperty(this, "lang", { - get: function () { - return _lang; - }, - set: function (val) { - if (val === undefined) { - val = "undefined"; - } - _lang = val.toString(); - }, - }); - - Object.defineProperty(this, "continuous", { - get: function () { - return _continuous; - }, - set: function (val) { - _continuous = Boolean(val); - }, - }); - - Object.defineProperty(this, "interimResults", { - get: function () { - return _interimResults; - }, - set: function (val) { - _interimResults = Boolean(val); - }, - }); - - this.start = function () { - if (_self._started) { - throw new DOMException( - "Failed to execute 'start' on 'SpeechRecognition': recognition has already started.", - ); - } - _self._started = true; - // Create and dispatch an event - var event = document.createEvent("CustomEvent"); - event.initCustomEvent("start", false, false, null); - _listeners.dispatchEvent(event); - }; - - this.abort = function () { - if (!_self._started) { - return; - } - _self._started = false; - _self._soundStarted = false; - // Create and dispatch an event - var event = document.createEvent("CustomEvent"); - event.initCustomEvent("end", false, false, null); - _listeners.dispatchEvent(event); - }; - - this.stop = function () { - return _self.abort(); - }; - - this.isStarted = function () { - return _self._started; - }; - - this.emitStartEvent = function (text, isFinal, itemFunction, isAndroid) { - var startEvent = document.createEvent("CustomEvent"); - startEvent.initCustomEvent("result", false, false, { sentence: text }); - startEvent.resultIndex = 0; - startEvent.results = { - item: itemFunction, - 0: { - item: itemFunction, - isFinal: isFinal || isAndroid, - }, - }; - startEvent.results[0][0] = { - transcript: text, - confidence: isAndroid && !isFinal ? 0 : 1, - }; - Object.defineProperty(startEvent.results, "length", { - get: function () { - return 1; - }, - }); - Object.defineProperty(startEvent.results[0], "length", { - get: function () { - return _maxAlternatives; - }, - }); - startEvent.interpretation = null; - startEvent.emma = null; - _listeners.dispatchEvent(startEvent); - - // Create soundstart event - if (!_self._soundStarted) { - _self._soundStarted = true; - var soundStartEvent = document.createEvent("CustomEvent"); - soundStartEvent.initCustomEvent("soundstart", false, false, null); - _listeners.dispatchEvent(soundStartEvent); - } - }; - - this.say = function ( - sentence, - { onlyFirstResult = false, isAndroid = false } = {}, - ) { - if (!_self._started) { - return; - } - - var itemFunction = function (index) { - if (undefined === index) { - throw new DOMException( - "Failed to execute 'item' on 'SpeechRecognitionResult': 1 argument required, but only 0 present.", - ); - } - index = Number(index); - if (isNaN(index)) { - index = 0; - } - if (index >= this.length) { - return null; - } else { - return this[index]; - } - }; - - const words = sentence.split(" "); - if (onlyFirstResult) { - this.emitStartEvent(words[0], false, itemFunction); - } else { - let text = ""; - words.forEach((word) => { - text = [text, word].join(" "); - this.emitStartEvent(text, false, itemFunction, isAndroid); - }); - this.emitStartEvent(sentence, true, itemFunction); - if (isAndroid) { - this.emitStartEvent(sentence, true, itemFunction); - } - } - - // stop if not set to continuous mode - if (!_self.continuous) { - _self.abort(); - } - }; - - this.addEventListener = function (event, callback) { - _listeners.addEventListener(event, callback, false); - }; - }; - - // Expose functionality - return { - patch: function () { - if (_productionVersion === false) { - _productionVersion = - _root.SpeechRecognition || - _root.webkitSpeechRecognition || - _root.mozSpeechRecognition || - _root.msSpeechRecognition || - _root.oSpeechRecognition; - } - _root.SpeechRecognition = newSpeechRecognition; - }, - unpatch: function () { - _root.SpeechRecognition = _productionVersion; - }, - newSpeechRecognition, - }; -}; - -const mockSpeechRecognition = Corti(global); -mockSpeechRecognition.patch(); -export const CortiSpeechRecognition = - mockSpeechRecognition.newSpeechRecognition; -export default mockSpeechRecognition; diff --git a/yarn.lock b/yarn.lock index b876be1..2e7d90a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1439,6 +1439,13 @@ __metadata: languageName: node linkType: hard +"corti@npm:1.0.0": + version: 1.0.0 + resolution: "corti@npm:1.0.0" + checksum: 10c0/8223f7ef6c0b950a11b4acb38acf85f600c32f0fd419fe03a2d787a246629781023b194f6134c06ced34036376abe7a0e6cb6d33520fe191ec12b4efdc41e1ee + languageName: node + linkType: hard + "cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" @@ -2783,6 +2790,7 @@ __metadata: "@types/lodash.debounce": "npm:4.0.9" "@vitest/coverage-v8": "npm:3.1.1" bunchee: "npm:6.5.0" + corti: "npm:1.0.0" jsdom: "npm:26.0.0" lodash.debounce: "npm:^4.0.8" react: "npm:16.14.0"