import isNodeJs from 'detect-node' export const escapeFilename = (s: string): string => { return s.replace(/[\s<>:{}"/\\|?*~.\0\cA-\cZ]+/g, '_') } export const getIndexPath = (id: number): string => { const idStr = String(id) // 获取最后三位,倒序排列 // x, y, z are the reversed last digits of the score id. Example: id 123456789, x = 9, y = 8, z = 7 // https://developers.musescore.com/#/file-urls // "5449062" -> ["2", "6", "0"] const indexN = idStr.split('').reverse().slice(0, 3) return indexN.join('/') } export const getFetch = (): typeof fetch => { if (!isNodeJs) { return fetch } else { // eslint-disable-next-line @typescript-eslint/no-unsafe-return return require('node-fetch') } } export const fetchData = async (url: string, init?: RequestInit): Promise => { const r = await fetch(url, init) const data = await r.arrayBuffer() return new Uint8Array(data) } export const assertRes = (r: Response): void => { if (!r.ok) throw new Error(`${r.url} ${r.status} ${r.statusText}`) } export const useTimeout = async (promise: T | Promise, ms: number): Promise => { if (!(promise instanceof Promise)) { return promise } return new Promise((resolve, reject) => { const i = setTimeout(() => { reject(new Error('timeout')) }, ms) promise.then(resolve, reject).finally(() => clearTimeout(i)) }) } export const getUnsafeWindow = (): Window => { // eslint-disable-next-line no-eval return window.eval('window') as Window } export const console: Console = window.console // Object.is(window.console, unsafeWindow.console) == false export const windowOpen: Window['open'] = (...args): Window | null => { return window.open(...args) // Object.is(window.open, unsafeWindow.open) == false } export const attachShadow = (el: Element): ShadowRoot => { return Element.prototype.attachShadow.call(el, { mode: 'closed' }) as ShadowRoot } export const waitForDocumentLoaded = (): Promise => { if (document.readyState !== 'complete') { return new Promise(resolve => { const cb = () => { if (document.readyState === 'complete') { resolve() document.removeEventListener('readystatechange', cb) } } document.addEventListener('readystatechange', cb) }) } else { return Promise.resolve() } }