feat: 增加单元测试

This commit is contained in:
qier222 2022-04-13 16:17:21 +08:00
parent e6b1b91c01
commit 0c89b4aa53
No known key found for this signature in database
GPG Key ID: 9C85007ED905F14D
9 changed files with 777 additions and 90 deletions

34
auto-imports.d.ts vendored Normal file
View File

@ -0,0 +1,34 @@
// Generated by 'unplugin-auto-import'
// We suggest you to commit this file into source control
declare global {
const classNames: typeof import('classnames')['default']
const createRef: typeof import('react')['createRef']
const forwardRef: typeof import('react')['forwardRef']
const lazy: typeof import('react')['lazy']
const memo: typeof import('react')['memo']
const startTransition: typeof import('react')['startTransition']
const toast: typeof import('react-hot-toast')['toast']
const useCallback: typeof import('react')['useCallback']
const useContext: typeof import('react')['useContext']
const useDebugValue: typeof import('react')['useDebugValue']
const useDeferredValue: typeof import('react')['useDeferredValue']
const useEffect: typeof import('react')['useEffect']
const useEffectOnce: typeof import('react-use')['useEffectOnce']
const useId: typeof import('react')['useId']
const useImperativeHandle: typeof import('react')['useImperativeHandle']
const useInfiniteQuery: typeof import('react-query')['useInfiniteQuery']
const useInsertionEffect: typeof import('react')['useInsertionEffect']
const useLayoutEffect: typeof import('react')['useLayoutEffect']
const useMemo: typeof import('react')['useMemo']
const useMutation: typeof import('react-query')['useMutation']
const useNavigate: typeof import('react-router-dom')['useNavigate']
const useParams: typeof import('react-router-dom')['useParams']
const useQuery: typeof import('react-query')['useQuery']
const useReducer: typeof import('react')['useReducer']
const useRef: typeof import('react')['useRef']
const useSnapshot: typeof import('valtio')['useSnapshot']
const useState: typeof import('react')['useState']
const useSyncExternalStore: typeof import('react')['useSyncExternalStore']
const useTransition: typeof import('react')['useTransition']
}
export {}

View File

@ -23,6 +23,9 @@
"build:app-linux": "npm run build && electron-builder --config .electron-builder.config.js --linux",
"typecheck": "tsc --noEmit --project src/renderer/tsconfig.json",
"debug": "cross-env-shell NODE_ENV=debug \"npm run typecheck && node scripts/build.mjs && vite ./src/renderer\"",
"test": "vitest",
"test:ui": "vitest --ui",
"test:coverage": "vitest run --coverage",
"eslint": "eslint --ext .ts,.js ./",
"prettier": "prettier --write './**/*.{ts,js,tsx,jsx}'"
},
@ -54,11 +57,13 @@
"@types/qrcode": "^1.4.2",
"@types/react": "^18.0.1",
"@types/react-dom": "^18.0.0",
"@typescript-eslint/eslint-plugin": "^5.18.0",
"@typescript-eslint/parser": "^5.18.0",
"@typescript-eslint/eslint-plugin": "^5.19.0",
"@typescript-eslint/parser": "^5.19.0",
"@vitejs/plugin-react": "^1.3.0",
"@vitest/ui": "^0.9.3",
"autoprefixer": "^10.4.4",
"axios": "^0.26.1",
"c8": "^7.11.0",
"classnames": "^2.3.1",
"color.js": "^1.2.0",
"colord": "^2.9.2",
@ -80,6 +85,7 @@
"framer-motion": "^6.2.9",
"howler": "^2.2.3",
"js-cookie": "^3.0.1",
"jsdom": "^19.0.0",
"lodash-es": "^4.17.21",
"md5": "^2.3.0",
"minimist": "^1.2.6",
@ -106,6 +112,7 @@
"valtio-persist": "^1.0.2",
"vite": "^2.9.1",
"vite-plugin-svg-icons": "^2.0.1",
"vitest": "^0.9.3",
"wait-on": "^6.0.1"
}
}

View File

@ -15,13 +15,15 @@ specifiers:
'@types/qrcode': ^1.4.2
'@types/react': ^18.0.1
'@types/react-dom': ^18.0.0
'@typescript-eslint/eslint-plugin': ^5.18.0
'@typescript-eslint/parser': ^5.18.0
'@typescript-eslint/eslint-plugin': ^5.19.0
'@typescript-eslint/parser': ^5.19.0
'@vitejs/plugin-react': ^1.3.0
'@vitest/ui': ^0.9.3
NeteaseCloudMusicApi: ^4.5.11
autoprefixer: ^10.4.4
axios: ^0.26.1
better-sqlite3: 7.5.1
c8: ^7.11.0
change-case: ^4.1.2
classnames: ^2.3.1
color.js: ^1.2.0
@ -49,6 +51,7 @@ specifiers:
framer-motion: ^6.2.9
howler: ^2.2.3
js-cookie: ^3.0.1
jsdom: ^19.0.0
lodash-es: ^4.17.21
md5: ^2.3.0
minimist: ^1.2.6
@ -75,6 +78,7 @@ specifiers:
valtio-persist: ^1.0.2
vite: ^2.9.1
vite-plugin-svg-icons: ^2.0.1
vitest: ^0.9.3
wait-on: ^6.0.1
dependencies:
@ -102,11 +106,13 @@ devDependencies:
'@types/qrcode': 1.4.2
'@types/react': 18.0.1
'@types/react-dom': 18.0.0
'@typescript-eslint/eslint-plugin': 5.18.0_0dd9be2ba5ed9805045f3fec8be848f5
'@typescript-eslint/parser': 5.18.0_eslint@8.13.0+typescript@4.6.3
'@typescript-eslint/eslint-plugin': 5.19.0_f34adc8488d2e4f014fe61432d70cbf2
'@typescript-eslint/parser': 5.19.0_eslint@8.13.0+typescript@4.6.3
'@vitejs/plugin-react': 1.3.0
'@vitest/ui': 0.9.3
autoprefixer: 10.4.4_postcss@8.4.12
axios: 0.26.1
c8: 7.11.0
classnames: 2.3.1
color.js: 1.2.0
colord: 2.9.2
@ -128,6 +134,7 @@ devDependencies:
framer-motion: 6.2.9_react-dom@18.0.0+react@18.0.0
howler: 2.2.3
js-cookie: 3.0.1
jsdom: 19.0.0
lodash-es: 4.17.21
md5: 2.3.0
minimist: 1.2.6
@ -154,6 +161,7 @@ devDependencies:
valtio-persist: 1.0.2_valtio@1.5.2
vite: 2.9.1_sass@1.50.0
vite-plugin-svg-icons: 2.0.1_vite@2.9.1
vitest: 0.9.3_ac1eaec0e6cd6e44c577f894fa1b602e
wait-on: 6.0.1
packages:
@ -441,6 +449,10 @@ packages:
to-fast-properties: 2.0.0
dev: true
/@bcoe/v8-coverage/0.2.3:
resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
dev: true
/@develar/schema-utils/2.6.5:
resolution: {integrity: sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==}
engines: {node: '>= 8.9.0'}
@ -541,6 +553,11 @@ packages:
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
dev: true
/@istanbuljs/schema/0.1.3:
resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
engines: {node: '>=8'}
dev: true
/@jridgewell/resolve-uri/3.0.5:
resolution: {integrity: sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==}
engines: {node: '>=6.0.0'}
@ -619,6 +636,10 @@ packages:
rimraf: 3.0.2
dev: true
/@polka/url/1.0.0-next.21:
resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==}
dev: true
/@rollup/pluginutils/4.2.0:
resolution: {integrity: sha512-2WUyJNRkyH5p487pGnn4tWAsxhEFKN/pT8CMgHshd5H+IXkOnKvKZwsz5ZWz+YCXkleZRAU5kwbfgF8CPfDRqA==}
engines: {node: '>= 8.0.0'}
@ -799,6 +820,16 @@ packages:
'@types/responselike': 1.0.0
dev: true
/@types/chai-subset/1.3.3:
resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==}
dependencies:
'@types/chai': 4.3.0
dev: true
/@types/chai/4.3.0:
resolution: {integrity: sha512-/ceqdqeRraGolFTcfoXNiqjyQhZzbINDngeoAq9GoHa8PPK1yNzTaxWjA6BFWp5Ua9JpXEMSS4s5i9tS0hOJtw==}
dev: true
/@types/connect/3.4.35:
resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==}
dependencies:
@ -864,6 +895,10 @@ packages:
resolution: {integrity: sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==}
dev: true
/@types/istanbul-lib-coverage/2.0.4:
resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==}
dev: true
/@types/js-cookie/2.2.7:
resolution: {integrity: sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==}
dev: true
@ -999,8 +1034,8 @@ packages:
'@types/yargs-parser': 21.0.0
dev: true
/@typescript-eslint/eslint-plugin/5.18.0_0dd9be2ba5ed9805045f3fec8be848f5:
resolution: {integrity: sha512-tzrmdGMJI/uii9/V6lurMo4/o+dMTKDH82LkNjhJ3adCW22YQydoRs5MwTiqxGF9CSYxPxQ7EYb4jLNlIs+E+A==}
/@typescript-eslint/eslint-plugin/5.19.0_f34adc8488d2e4f014fe61432d70cbf2:
resolution: {integrity: sha512-w59GpFqDYGnWFim9p6TGJz7a3qWeENJuAKCqjGSx+Hq/bwq3RZwXYqy98KIfN85yDqz9mq6QXiY5h0FjGQLyEg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
'@typescript-eslint/parser': ^5.0.0
@ -1010,10 +1045,10 @@ packages:
typescript:
optional: true
dependencies:
'@typescript-eslint/parser': 5.18.0_eslint@8.13.0+typescript@4.6.3
'@typescript-eslint/scope-manager': 5.18.0
'@typescript-eslint/type-utils': 5.18.0_eslint@8.13.0+typescript@4.6.3
'@typescript-eslint/utils': 5.18.0_eslint@8.13.0+typescript@4.6.3
'@typescript-eslint/parser': 5.19.0_eslint@8.13.0+typescript@4.6.3
'@typescript-eslint/scope-manager': 5.19.0
'@typescript-eslint/type-utils': 5.19.0_eslint@8.13.0+typescript@4.6.3
'@typescript-eslint/utils': 5.19.0_eslint@8.13.0+typescript@4.6.3
debug: 4.3.4
eslint: 8.13.0
functional-red-black-tree: 1.0.1
@ -1026,8 +1061,8 @@ packages:
- supports-color
dev: true
/@typescript-eslint/parser/5.18.0_eslint@8.13.0+typescript@4.6.3:
resolution: {integrity: sha512-+08nYfurBzSSPndngnHvFw/fniWYJ5ymOrn/63oMIbgomVQOvIDhBoJmYZ9lwQOCnQV9xHGvf88ze3jFGUYooQ==}
/@typescript-eslint/parser/5.19.0_eslint@8.13.0+typescript@4.6.3:
resolution: {integrity: sha512-yhktJjMCJX8BSBczh1F/uY8wGRYrBeyn84kH6oyqdIJwTGKmzX5Qiq49LRQ0Jh0LXnWijEziSo6BRqny8nqLVQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
@ -1036,9 +1071,9 @@ packages:
typescript:
optional: true
dependencies:
'@typescript-eslint/scope-manager': 5.18.0
'@typescript-eslint/types': 5.18.0
'@typescript-eslint/typescript-estree': 5.18.0_typescript@4.6.3
'@typescript-eslint/scope-manager': 5.19.0
'@typescript-eslint/types': 5.19.0
'@typescript-eslint/typescript-estree': 5.19.0_typescript@4.6.3
debug: 4.3.4
eslint: 8.13.0
typescript: 4.6.3
@ -1046,16 +1081,16 @@ packages:
- supports-color
dev: true
/@typescript-eslint/scope-manager/5.18.0:
resolution: {integrity: sha512-C0CZML6NyRDj+ZbMqh9FnPscg2PrzSaVQg3IpTmpe0NURMVBXlghGZgMYqBw07YW73i0MCqSDqv2SbywnCS8jQ==}
/@typescript-eslint/scope-manager/5.19.0:
resolution: {integrity: sha512-Fz+VrjLmwq5fbQn5W7cIJZ066HxLMKvDEmf4eu1tZ8O956aoX45jAuBB76miAECMTODyUxH61AQM7q4/GOMQ5g==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
'@typescript-eslint/types': 5.18.0
'@typescript-eslint/visitor-keys': 5.18.0
'@typescript-eslint/types': 5.19.0
'@typescript-eslint/visitor-keys': 5.19.0
dev: true
/@typescript-eslint/type-utils/5.18.0_eslint@8.13.0+typescript@4.6.3:
resolution: {integrity: sha512-vcn9/6J5D6jtHxpEJrgK8FhaM8r6J1/ZiNu70ZUJN554Y3D9t3iovi6u7JF8l/e7FcBIxeuTEidZDR70UuCIfA==}
/@typescript-eslint/type-utils/5.19.0_eslint@8.13.0+typescript@4.6.3:
resolution: {integrity: sha512-O6XQ4RI4rQcBGshTQAYBUIGsKqrKeuIOz9v8bckXZnSeXjn/1+BDZndHLe10UplQeJLXDNbaZYrAytKNQO2T4Q==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: '*'
@ -1064,7 +1099,7 @@ packages:
typescript:
optional: true
dependencies:
'@typescript-eslint/utils': 5.18.0_eslint@8.13.0+typescript@4.6.3
'@typescript-eslint/utils': 5.19.0_eslint@8.13.0+typescript@4.6.3
debug: 4.3.4
eslint: 8.13.0
tsutils: 3.21.0_typescript@4.6.3
@ -1073,13 +1108,13 @@ packages:
- supports-color
dev: true
/@typescript-eslint/types/5.18.0:
resolution: {integrity: sha512-bhV1+XjM+9bHMTmXi46p1Led5NP6iqQcsOxgx7fvk6gGiV48c6IynY0apQb7693twJDsXiVzNXTflhplmaiJaw==}
/@typescript-eslint/types/5.19.0:
resolution: {integrity: sha512-zR1ithF4Iyq1wLwkDcT+qFnhs8L5VUtjgac212ftiOP/ZZUOCuuF2DeGiZZGQXGoHA50OreZqLH5NjDcDqn34w==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
/@typescript-eslint/typescript-estree/5.18.0_typescript@4.6.3:
resolution: {integrity: sha512-wa+2VAhOPpZs1bVij9e5gyVu60ReMi/KuOx4LKjGx2Y3XTNUDJgQ+5f77D49pHtqef/klglf+mibuHs9TrPxdQ==}
/@typescript-eslint/typescript-estree/5.19.0_typescript@4.6.3:
resolution: {integrity: sha512-dRPuD4ocXdaE1BM/dNR21elSEUPKaWgowCA0bqJ6YbYkvtrPVEvZ+zqcX5a8ECYn3q5iBSSUcBBD42ubaOp0Hw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
typescript: '*'
@ -1087,8 +1122,8 @@ packages:
typescript:
optional: true
dependencies:
'@typescript-eslint/types': 5.18.0
'@typescript-eslint/visitor-keys': 5.18.0
'@typescript-eslint/types': 5.19.0
'@typescript-eslint/visitor-keys': 5.19.0
debug: 4.3.4
globby: 11.1.0
is-glob: 4.0.3
@ -1099,16 +1134,16 @@ packages:
- supports-color
dev: true
/@typescript-eslint/utils/5.18.0_eslint@8.13.0+typescript@4.6.3:
resolution: {integrity: sha512-+hFGWUMMri7OFY26TsOlGa+zgjEy1ssEipxpLjtl4wSll8zy85x0GrUSju/FHdKfVorZPYJLkF3I4XPtnCTewA==}
/@typescript-eslint/utils/5.19.0_eslint@8.13.0+typescript@4.6.3:
resolution: {integrity: sha512-ZuEckdupXpXamKvFz/Ql8YnePh2ZWcwz7APICzJL985Rp5C2AYcHO62oJzIqNhAMtMK6XvrlBTZeNG8n7gS3lQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
dependencies:
'@types/json-schema': 7.0.11
'@typescript-eslint/scope-manager': 5.18.0
'@typescript-eslint/types': 5.18.0
'@typescript-eslint/typescript-estree': 5.18.0_typescript@4.6.3
'@typescript-eslint/scope-manager': 5.19.0
'@typescript-eslint/types': 5.19.0
'@typescript-eslint/typescript-estree': 5.19.0_typescript@4.6.3
eslint: 8.13.0
eslint-scope: 5.1.1
eslint-utils: 3.0.0_eslint@8.13.0
@ -1117,11 +1152,11 @@ packages:
- typescript
dev: true
/@typescript-eslint/visitor-keys/5.18.0:
resolution: {integrity: sha512-Hf+t+dJsjAKpKSkg3EHvbtEpFFb/1CiOHnvI8bjHgOD4/wAw3gKrA0i94LrbekypiZVanJu3McWJg7rWDMzRTg==}
/@typescript-eslint/visitor-keys/5.19.0:
resolution: {integrity: sha512-Ym7zZoMDZcAKWsULi2s7UMLREdVQdScPQ/fKWMYefarCztWlHPFVJo8racf8R0Gc8FAEJ2eD4of8As1oFtnQlQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
'@typescript-eslint/types': 5.18.0
'@typescript-eslint/types': 5.19.0
eslint-visitor-keys: 3.3.0
dev: true
@ -1141,6 +1176,12 @@ packages:
- supports-color
dev: true
/@vitest/ui/0.9.3:
resolution: {integrity: sha512-tnf/qFWSnoj8+DVaO9MJIu7uuRyFx7L4dgSwm+PzKUjavUILSVQjzrLfZOO9+KbKf4e4wcTcxkoYK0mG1MAXgA==}
dependencies:
sirv: 2.0.2
dev: true
/@xobotyi/scrollbar-width/1.9.5:
resolution: {integrity: sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==}
dev: true
@ -1165,6 +1206,10 @@ packages:
- supports-color
dev: false
/abab/2.0.5:
resolution: {integrity: sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==}
dev: true
/abbrev/1.1.1:
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
dev: true
@ -1177,6 +1222,13 @@ packages:
negotiator: 0.6.3
dev: false
/acorn-globals/6.0.0:
resolution: {integrity: sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==}
dependencies:
acorn: 7.4.1
acorn-walk: 7.2.0
dev: true
/acorn-jsx/5.3.2_acorn@8.7.0:
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
@ -1452,6 +1504,10 @@ packages:
dev: true
optional: true
/assertion-error/1.1.0:
resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
dev: true
/assign-symbols/1.0.0:
resolution: {integrity: sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=}
engines: {node: '>=0.10.0'}
@ -1702,6 +1758,10 @@ packages:
unload: 2.2.0
dev: true
/browser-process-hrtime/1.0.0:
resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==}
dev: true
/browserslist/4.20.2:
resolution: {integrity: sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
@ -1810,6 +1870,25 @@ packages:
engines: {node: '>= 0.8'}
dev: false
/c8/7.11.0:
resolution: {integrity: sha512-XqPyj1uvlHMr+Y1IeRndC2X5P7iJzJlEJwBpCdBbq2JocXOgJfr+JVfJkyNMGROke5LfKrhSFXGFXnwnRJAUJw==}
engines: {node: '>=10.12.0'}
hasBin: true
dependencies:
'@bcoe/v8-coverage': 0.2.3
'@istanbuljs/schema': 0.1.3
find-up: 5.0.0
foreground-child: 2.0.0
istanbul-lib-coverage: 3.2.0
istanbul-lib-report: 3.0.0
istanbul-reports: 3.1.4
rimraf: 3.0.2
test-exclude: 6.0.0
v8-to-istanbul: 8.1.1
yargs: 16.2.0
yargs-parser: 20.2.9
dev: true
/cacache/15.3.0:
resolution: {integrity: sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==}
engines: {node: '>= 10'}
@ -1925,6 +2004,19 @@ packages:
upper-case-first: 2.0.2
dev: false
/chai/4.3.6:
resolution: {integrity: sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==}
engines: {node: '>=4'}
dependencies:
assertion-error: 1.1.0
check-error: 1.0.2
deep-eql: 3.0.1
get-func-name: 2.0.0
loupe: 2.3.4
pathval: 1.1.1
type-detect: 4.0.8
dev: true
/chainsaw/0.1.0:
resolution: {integrity: sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=}
dependencies:
@ -1984,6 +2076,10 @@ packages:
/charenc/0.0.2:
resolution: {integrity: sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=}
/check-error/1.0.2:
resolution: {integrity: sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=}
dev: true
/chokidar/3.5.3:
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
engines: {node: '>= 8.10.0'}
@ -2412,6 +2508,21 @@ packages:
css-tree: 1.1.3
dev: true
/cssom/0.3.8:
resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==}
dev: true
/cssom/0.5.0:
resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==}
dev: true
/cssstyle/2.3.0:
resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==}
engines: {node: '>=8'}
dependencies:
cssom: 0.3.8
dev: true
/csstype/3.0.11:
resolution: {integrity: sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==}
dev: true
@ -2421,6 +2532,15 @@ packages:
engines: {node: '>= 6'}
dev: false
/data-urls/3.0.1:
resolution: {integrity: sha512-Ds554NeT5Gennfoo9KN50Vh6tpgtvYEwraYjejXnyTpu1C7oXKxdFk75REooENHE8ndTVOJuv+BEs4/J/xcozw==}
engines: {node: '>=12'}
dependencies:
abab: 2.0.5
whatwg-mimetype: 3.0.0
whatwg-url: 10.0.0
dev: true
/date-fns/2.28.0:
resolution: {integrity: sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==}
engines: {node: '>=0.11'}
@ -2457,6 +2577,10 @@ packages:
resolution: {integrity: sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=}
engines: {node: '>=0.10.0'}
/decimal.js/10.3.1:
resolution: {integrity: sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==}
dev: true
/decode-uri-component/0.2.0:
resolution: {integrity: sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=}
engines: {node: '>=0.10'}
@ -2475,6 +2599,13 @@ packages:
dependencies:
mimic-response: 3.1.0
/deep-eql/3.0.1:
resolution: {integrity: sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==}
engines: {node: '>=0.12'}
dependencies:
type-detect: 4.0.8
dev: true
/deep-extend/0.6.0:
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
engines: {node: '>=4.0.0'}
@ -2696,6 +2827,13 @@ packages:
resolution: {integrity: sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==}
dev: true
/domexception/4.0.0:
resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==}
engines: {node: '>=12'}
dependencies:
webidl-conversions: 7.0.0
dev: true
/domhandler/2.4.2:
resolution: {integrity: sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==}
dependencies:
@ -3233,6 +3371,19 @@ packages:
source-map: 0.6.1
dev: false
/escodegen/2.0.0:
resolution: {integrity: sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==}
engines: {node: '>=6.0'}
hasBin: true
dependencies:
esprima: 4.0.1
estraverse: 5.3.0
esutils: 2.0.3
optionator: 0.8.3
optionalDependencies:
source-map: 0.6.1
dev: true
/eslint-plugin-react-hooks/4.4.0_eslint@8.13.0:
resolution: {integrity: sha512-U3RVIfdzJaeKDQKEJbz5p3NW8/L80PCATJAfuojwbaEL+gBjfGdhUcGde+WGUW46Q5sr/NgxevsIiDtNXrvZaQ==}
engines: {node: '>=10'}
@ -3358,7 +3509,6 @@ packages:
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
engines: {node: '>=4'}
hasBin: true
dev: false
/esquery/1.4.0:
resolution: {integrity: sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==}
@ -3623,6 +3773,14 @@ packages:
locate-path: 5.0.0
path-exists: 4.0.0
/find-up/5.0.0:
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
engines: {node: '>=10'}
dependencies:
locate-path: 6.0.0
path-exists: 4.0.0
dev: true
/flat-cache/3.0.4:
resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==}
engines: {node: ^10.12.0 || >=12.0.0}
@ -3649,6 +3807,14 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/foreground-child/2.0.0:
resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==}
engines: {node: '>=8.0.0'}
dependencies:
cross-spawn: 7.0.3
signal-exit: 3.0.7
dev: true
/form-data/4.0.0:
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
engines: {node: '>= 6'}
@ -3813,6 +3979,10 @@ packages:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
/get-func-name/2.0.0:
resolution: {integrity: sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=}
dev: true
/get-intrinsic/1.1.1:
resolution: {integrity: sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==}
dependencies:
@ -4130,6 +4300,17 @@ packages:
resolution: {integrity: sha512-QM0FFkw0LRX1PR8pNzJVAY25JhIWvbKMBFM4gqk+QdV+kPXOhleWGCB6AiAF/goGjIHK2e/nIElplvjQwhr0jg==}
dev: true
/html-encoding-sniffer/3.0.0:
resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==}
engines: {node: '>=12'}
dependencies:
whatwg-encoding: 2.0.0
dev: true
/html-escaper/2.0.2:
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
dev: true
/htmlparser2/3.10.1:
resolution: {integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==}
dependencies:
@ -4547,6 +4728,10 @@ packages:
isobject: 3.0.1
dev: true
/is-potential-custom-element-name/1.0.1:
resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
dev: true
/is-regex/1.1.4:
resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
engines: {node: '>= 0.4'}
@ -4644,6 +4829,28 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/istanbul-lib-coverage/3.2.0:
resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==}
engines: {node: '>=8'}
dev: true
/istanbul-lib-report/3.0.0:
resolution: {integrity: sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==}
engines: {node: '>=8'}
dependencies:
istanbul-lib-coverage: 3.2.0
make-dir: 3.1.0
supports-color: 7.2.0
dev: true
/istanbul-reports/3.1.4:
resolution: {integrity: sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==}
engines: {node: '>=8'}
dependencies:
html-escaper: 2.0.2
istanbul-lib-report: 3.0.0
dev: true
/jake/10.8.4:
resolution: {integrity: sha512-MtWeTkl1qGsWUtbl/Jsca/8xSoK3x0UmS82sNbjqxxG/de/M/3b1DntdjHgPMC50enlTNwXOCRqPXLLt5cCfZA==}
engines: {node: '>=10'}
@ -4693,6 +4900,48 @@ packages:
argparse: 2.0.1
dev: true
/jsdom/19.0.0:
resolution: {integrity: sha512-RYAyjCbxy/vri/CfnjUWJQQtZ3LKlLnDqj+9XLNnJPgEGeirZs3hllKR20re8LUZ6o1b1X4Jat+Qd26zmP41+A==}
engines: {node: '>=12'}
peerDependencies:
canvas: ^2.5.0
peerDependenciesMeta:
canvas:
optional: true
dependencies:
abab: 2.0.5
acorn: 8.7.0
acorn-globals: 6.0.0
cssom: 0.5.0
cssstyle: 2.3.0
data-urls: 3.0.1
decimal.js: 10.3.1
domexception: 4.0.0
escodegen: 2.0.0
form-data: 4.0.0
html-encoding-sniffer: 3.0.0
http-proxy-agent: 5.0.0
https-proxy-agent: 5.0.0
is-potential-custom-element-name: 1.0.1
nwsapi: 2.2.0
parse5: 6.0.1
saxes: 5.0.1
symbol-tree: 3.2.4
tough-cookie: 4.0.0
w3c-hr-time: 1.0.2
w3c-xmlserializer: 3.0.0
webidl-conversions: 7.0.0
whatwg-encoding: 2.0.0
whatwg-mimetype: 3.0.0
whatwg-url: 10.0.0
ws: 8.5.0
xml-name-validator: 4.0.0
transitivePeerDependencies:
- bufferutil
- supports-color
- utf-8-validate
dev: true
/jsesc/2.5.2:
resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
engines: {node: '>=4'}
@ -4828,7 +5077,6 @@ packages:
dependencies:
prelude-ls: 1.1.2
type-check: 0.3.2
dev: false
/levn/0.4.1:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
@ -4885,6 +5133,13 @@ packages:
dependencies:
p-locate: 4.1.0
/locate-path/6.0.0:
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
engines: {node: '>=10'}
dependencies:
p-locate: 5.0.0
dev: true
/lodash-es/4.17.21:
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
dev: true
@ -4920,6 +5175,12 @@ packages:
js-tokens: 4.0.0
dev: true
/loupe/2.3.4:
resolution: {integrity: sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==}
dependencies:
get-func-name: 2.0.0
dev: true
/lower-case/2.0.2:
resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==}
dependencies:
@ -5231,6 +5492,11 @@ packages:
hasBin: true
dev: true
/mrmime/1.0.0:
resolution: {integrity: sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ==}
engines: {node: '>=10'}
dev: true
/ms/2.0.0:
resolution: {integrity: sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=}
@ -5441,6 +5707,10 @@ packages:
engines: {node: '>=0.10.0'}
dev: false
/nwsapi/2.2.0:
resolution: {integrity: sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==}
dev: true
/object-assign/4.1.1:
resolution: {integrity: sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=}
engines: {node: '>=0.10.0'}
@ -5567,7 +5837,6 @@ packages:
prelude-ls: 1.1.2
type-check: 0.3.2
word-wrap: 1.2.3
dev: false
/optionator/0.9.1:
resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==}
@ -5627,6 +5896,13 @@ packages:
dependencies:
p-try: 2.2.0
/p-limit/3.1.0:
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
engines: {node: '>=10'}
dependencies:
yocto-queue: 0.1.0
dev: true
/p-locate/3.0.0:
resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==}
engines: {node: '>=6'}
@ -5640,6 +5916,13 @@ packages:
dependencies:
p-limit: 2.3.0
/p-locate/5.0.0:
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
engines: {node: '>=10'}
dependencies:
p-limit: 3.1.0
dev: true
/p-map/4.0.0:
resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==}
engines: {node: '>=10'}
@ -5715,6 +5998,10 @@ packages:
lines-and-columns: 1.2.4
dev: true
/parse5/6.0.1:
resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==}
dev: true
/parseurl/1.3.3:
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
engines: {node: '>= 0.8'}
@ -5774,6 +6061,10 @@ packages:
resolution: {integrity: sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==}
dev: true
/pathval/1.1.1:
resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==}
dev: true
/peek-readable/4.1.0:
resolution: {integrity: sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==}
engines: {node: '>=8'}
@ -5964,7 +6255,6 @@ packages:
/prelude-ls/1.1.2:
resolution: {integrity: sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=}
engines: {node: '>= 0.8.0'}
dev: false
/prelude-ls/1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
@ -6036,6 +6326,10 @@ packages:
resolution: {integrity: sha512-wapJ3h/w8fRSyPEG0y2WMV+tf9xwvj3nxM6aHVuPEOwKs/t5xLSKZb44ubNTiqq2T6lmEMHEWGMTaU2L6ddaFA==}
dev: true
/psl/1.8.0:
resolution: {integrity: sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==}
dev: true
/pump/3.0.0:
resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
dependencies:
@ -6540,6 +6834,13 @@ packages:
resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==}
dev: true
/saxes/5.0.1:
resolution: {integrity: sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==}
engines: {node: '>=10'}
dependencies:
xmlchars: 2.2.0
dev: true
/scheduler/0.21.0:
resolution: {integrity: sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==}
dependencies:
@ -6694,6 +6995,15 @@ packages:
simple-concat: 1.0.1
dev: false
/sirv/2.0.2:
resolution: {integrity: sha512-4Qog6aE29nIjAOKe/wowFTxOdmbEZKb+3tsLljaBRzJwtqto0BChD2zzH0LhgCSXiI+V7X+Y45v14wBZQ1TK3w==}
engines: {node: '>= 10'}
dependencies:
'@polka/url': 1.0.0-next.21
mrmime: 1.0.0
totalist: 3.0.0
dev: true
/slash/3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'}
@ -7097,6 +7407,10 @@ packages:
stable: 0.1.8
dev: true
/symbol-tree/3.2.4:
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
dev: true
/tailwindcss/3.0.23_autoprefixer@10.4.4:
resolution: {integrity: sha512-+OZOV9ubyQ6oI2BXEhzw4HrqvgcARY38xv3zKcjnWtMIZstEsXdI9xftd1iB7+RbOnj2HOEzkA0OyB5BaSxPQA==}
engines: {node: '>=12.13.0'}
@ -7169,6 +7483,15 @@ packages:
fs-extra: 10.0.1
dev: true
/test-exclude/6.0.0:
resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
engines: {node: '>=8'}
dependencies:
'@istanbuljs/schema': 0.1.3
glob: 7.2.0
minimatch: 3.1.2
dev: true
/text-table/0.2.0:
resolution: {integrity: sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=}
dev: true
@ -7178,6 +7501,16 @@ packages:
engines: {node: '>=10'}
dev: true
/tinypool/0.1.2:
resolution: {integrity: sha512-fvtYGXoui2RpeMILfkvGIgOVkzJEGediv8UJt7TxdAOY8pnvUkFg/fkvqTfXG9Acc9S17Cnn1S4osDc2164guA==}
engines: {node: '>=14.0.0'}
dev: true
/tinyspy/0.3.2:
resolution: {integrity: sha512-2+40EP4D3sFYy42UkgkFFB+kiX2Tg3URG/lVvAZFfLxgGpnWl5qQJuBw1gaLttq8UOS+2p3C0WrhJnQigLTT2Q==}
engines: {node: '>=14.0.0'}
dev: true
/tmp-promise/3.0.3:
resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==}
dependencies:
@ -7249,6 +7582,27 @@ packages:
'@tokenizer/token': 0.3.0
ieee754: 1.2.1
/totalist/3.0.0:
resolution: {integrity: sha512-eM+pCBxXO/njtF7vdFsHuqb+ElbxqtI4r5EAvk6grfAFyJ6IvWlSkfZ5T9ozC6xWw3Fj1fGoSmrl0gUs46JVIw==}
engines: {node: '>=6'}
dev: true
/tough-cookie/4.0.0:
resolution: {integrity: sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==}
engines: {node: '>=6'}
dependencies:
psl: 1.8.0
punycode: 2.1.1
universalify: 0.1.2
dev: true
/tr46/3.0.0:
resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==}
engines: {node: '>=12'}
dependencies:
punycode: 2.1.1
dev: true
/traverse/0.3.9:
resolution: {integrity: sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=}
dev: false
@ -7303,7 +7657,6 @@ packages:
engines: {node: '>= 0.8.0'}
dependencies:
prelude-ls: 1.1.2
dev: false
/type-check/0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
@ -7312,6 +7665,11 @@ packages:
prelude-ls: 1.2.1
dev: true
/type-detect/4.0.8:
resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
engines: {node: '>=4'}
dev: true
/type-fest/0.13.1:
resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==}
engines: {node: '>=10'}
@ -7567,6 +7925,15 @@ packages:
resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==}
dev: true
/v8-to-istanbul/8.1.1:
resolution: {integrity: sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==}
engines: {node: '>=10.12.0'}
dependencies:
'@types/istanbul-lib-coverage': 2.0.4
convert-source-map: 1.8.0
source-map: 0.7.3
dev: true
/valtio-persist/1.0.2_valtio@1.5.2:
resolution: {integrity: sha512-OBVEUZTS1heiA5R3j8CPDuXIMmmjIvq/4CiO+pElXd7f7b7nR3vIH5qql35hXw/AkLdftqTUcVCNVf6yAJ1ypA==}
peerDependencies:
@ -7663,6 +8030,41 @@ packages:
fsevents: 2.3.2
dev: true
/vitest/0.9.3_ac1eaec0e6cd6e44c577f894fa1b602e:
resolution: {integrity: sha512-hKjqdBI732cV5giNLERyAsaJBebstrX5mvTbZr+jUDYUHnX1O4DpAJcHtqBOutuBi7lVIGQ5IF8eWvHHqbCHBA==}
engines: {node: '>=v14.16.0'}
hasBin: true
peerDependencies:
'@vitest/ui': '*'
c8: '*'
happy-dom: '*'
jsdom: '*'
peerDependenciesMeta:
'@vitest/ui':
optional: true
c8:
optional: true
happy-dom:
optional: true
jsdom:
optional: true
dependencies:
'@types/chai': 4.3.0
'@types/chai-subset': 1.3.3
'@vitest/ui': 0.9.3
c8: 7.11.0
chai: 4.3.6
jsdom: 19.0.0
local-pkg: 0.4.1
tinypool: 0.1.2
tinyspy: 0.3.2
vite: 2.9.1_sass@1.50.0
transitivePeerDependencies:
- less
- sass
- stylus
dev: true
/vm2/3.9.9:
resolution: {integrity: sha512-xwTm7NLh/uOjARRBs8/95H0e8fT3Ukw5D/JJWhxMbhKzNh1Nu981jQKvkep9iKYNxzlVrdzD0mlBGkDKZWprlw==}
engines: {node: '>=6.0'}
@ -7672,6 +8074,19 @@ packages:
acorn-walk: 8.2.0
dev: false
/w3c-hr-time/1.0.2:
resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==}
dependencies:
browser-process-hrtime: 1.0.0
dev: true
/w3c-xmlserializer/3.0.0:
resolution: {integrity: sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==}
engines: {node: '>=12'}
dependencies:
xml-name-validator: 4.0.0
dev: true
/wait-on/6.0.1:
resolution: {integrity: sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==}
engines: {node: '>=10.0.0'}
@ -7692,6 +8107,11 @@ packages:
defaults: 1.0.3
dev: true
/webidl-conversions/7.0.0:
resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
engines: {node: '>=12'}
dev: true
/webpack-sources/3.2.3:
resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==}
engines: {node: '>=10.13.0'}
@ -7701,6 +8121,26 @@ packages:
resolution: {integrity: sha512-5NUqC2JquIL2pBAAo/VfBP6KuGkHIZQXW/lNKupLPfhViwh8wNsu0BObtl09yuKZszeEUfbXz8xhrHvSG16Nqw==}
dev: true
/whatwg-encoding/2.0.0:
resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==}
engines: {node: '>=12'}
dependencies:
iconv-lite: 0.6.3
dev: true
/whatwg-mimetype/3.0.0:
resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==}
engines: {node: '>=12'}
dev: true
/whatwg-url/10.0.0:
resolution: {integrity: sha512-CLxxCmdUby142H5FZzn4D8ikO1cmypvXVQktsgosNy4a4BHrDHeciBBGZhb0bNoR5/MltoCatso+vFjjGx8t0w==}
engines: {node: '>=12'}
dependencies:
tr46: 3.0.0
webidl-conversions: 7.0.0
dev: true
/which-boxed-primitive/1.0.2:
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
dependencies:
@ -7766,11 +8206,29 @@ packages:
typedarray-to-buffer: 3.1.5
dev: true
/ws/8.5.0:
resolution: {integrity: sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: ^5.0.2
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
dev: true
/xdg-basedir/4.0.0:
resolution: {integrity: sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==}
engines: {node: '>=8'}
dev: true
/xml-name-validator/4.0.0:
resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
engines: {node: '>=12'}
dev: true
/xmlbuilder/15.1.1:
resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==}
engines: {node: '>=8.0'}
@ -7782,6 +8240,10 @@ packages:
engines: {node: '>=4.0'}
dev: true
/xmlchars/2.2.0:
resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
dev: true
/xregexp/2.0.0:
resolution: {integrity: sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=}
dev: false
@ -7886,3 +8348,8 @@ packages:
buffer-crc32: 0.2.13
fd-slicer: 1.1.0
dev: true
/yocto-queue/0.1.0:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
dev: true

View File

@ -4,7 +4,7 @@ const fs = require('fs')
const minimist = require('minimist')
const pc = require('picocolors')
const releases = require('electron-releases')
const pkg = require('../package.json')
const pkg = require(`${process.cwd()}/package.json`)
const axios = require('axios')
const { execSync } = require('child_process')
@ -21,8 +21,10 @@ const isWin = process.platform === 'win32'
const isMac = process.platform === 'darwin'
const isLinux = process.platform === 'linux'
if (!fs.existsSync('./dist/main')) {
fs.mkdirSync('./dist/main', {
const projectDir = process.cwd()
if (!fs.existsSync(`${projectDir}/dist/main`)) {
fs.mkdirSync(`${projectDir}/dist/main`, {
recursive: true,
})
}
@ -33,7 +35,7 @@ const download = async arch => {
console.log(pc.red('No electron module version found! Skip download.'))
return false
}
const dir = './tmp/better-sqlite3'
const dir = `${projectDir}/tmp/better-sqlite3`
const fileName = `better-sqlite3-v${betterSqlite3Version}-electron-v${electronModuleVersion}-${process.platform}-${arch}`
const zipFileName = `${fileName}.tar.gz`
const url = `https://github.com/JoshuaWise/better-sqlite3/releases/download/v${betterSqlite3Version}/${zipFileName}`
@ -67,7 +69,7 @@ const download = async arch => {
try {
fs.copyFileSync(
`${dir}/build/Release/better_sqlite3.node`,
`./dist/main/better_sqlite3_${arch}.node`
`${projectDir}/dist/main/better_sqlite3_${arch}.node`
)
} catch (e) {
console.log(pc.red('Copy failed! Skip copy.', e))
@ -90,15 +92,15 @@ const build = async arch => {
console.log(pc.cyan(`Building for ${arch}...`))
await rebuild({
buildPath: process.cwd(),
buildPath: projectDir,
electronVersion,
arch: arch,
})
.then(() => {
console.info('Build succeeded')
fs.copyFileSync(
'./node_modules/better-sqlite3/build/Release/better_sqlite3.node',
`./dist/main/better_sqlite3_${arch}.node`
`${projectDir}/node_modules/better-sqlite3/build/Release/better_sqlite3.node`,
`${projectDir}/dist/main/better_sqlite3_${arch}.node`
)
})
.catch(e => {

View File

@ -1,7 +1,6 @@
import Player from './Player'
import { player, state } from '@/renderer/store'
import { resizeImage } from '@/renderer/utils/common'
import { average } from 'color.js'
import { getCoverColor } from '@/renderer/utils/common'
import { colord } from 'colord'
import IconButton from '../IconButton'
import SvgIcon from '../SvgIcon'
@ -16,21 +15,11 @@ const LyricPanel = () => {
const [bgColor, setBgColor] = useState({ from: '#222', to: '#222' })
useEffect(() => {
const cover = resizeImage(track?.al?.picUrl ?? '', 'xs')
if (cover) {
average(cover, { amount: 1, format: 'hex', sample: 1 }).then(color => {
let c = colord(color as string)
const hsl = c.toHsl()
if (hsl.s > 50) c = colord({ ...hsl, s: 50 })
if (hsl.l > 50) c = colord({ ...c.toHsl(), l: 50 })
if (hsl.l < 30) c = colord({ ...c.toHsl(), l: 30 })
const to = c.darken(0.15).rotate(-5).toHex()
setBgColor({
from: c.toHex(),
to,
})
})
}
getCoverColor(track?.al?.picUrl || '').then(color => {
if (!color) return
const to = colord(color).darken(0.15).rotate(-5).toHex()
setBgColor({ from: color, to })
})
}, [track?.al?.picUrl])
return (

View File

@ -279,18 +279,22 @@ const MoreAlbum = ({ album }: { album: Album | undefined }) => {
return (
<div>
<div className='my-5 h-px w-full bg-gray-100 dark:bg-gray-800'></div>
<div className='pl-px text-[1.375rem] font-semibold text-gray-800 dark:text-gray-100'>
More by{' '}
<NavLink
to={`/artist/${album?.artist?.id}`}
className='cursor-default hover:underline'
>
{album?.artist.name}
</NavLink>
</div>
{!isLoading && albums?.hotAlbums?.length && (
<div className='pl-px text-[1.375rem] font-semibold text-gray-800 dark:text-gray-100'>
More by{' '}
<NavLink
to={`/artist/${album?.artist?.id}`}
className='cursor-default hover:underline'
>
{album?.artist.name}
</NavLink>
</div>
)}
<div className='mt-3'>
<CoverRow
albums={filteredAlbums}
albums={
filteredAlbums.length ? filteredAlbums : albums?.hotAlbums || []
}
subtitle={Subtitle.TYPE_RELEASE_YEAR}
isSkeleton={isLoading}
rows={1}

View File

@ -0,0 +1,185 @@
import {
expect,
test,
describe,
afterEach,
vi,
beforeEach,
afterAll,
beforeAll,
} from 'vitest'
import {
resizeImage,
formatDate,
formatDuration,
cacheCoverColor,
calcCoverColor,
getCoverColor,
} from '@/renderer/utils/common'
import { IpcChannels } from '@/main/IpcChannelsName'
import { APIs } from '@/main/CacheAPIsName'
test('resizeImage', () => {
expect(resizeImage('https://test.com/test.jpg', 'xs')).toBe(
'https://test.com/test.jpg?param=128y128'
)
expect(resizeImage('https://test.com/test.jpg', 'sm')).toBe(
'https://test.com/test.jpg?param=256y256'
)
expect(resizeImage('https://test.com/test.jpg', 'md')).toBe(
'https://test.com/test.jpg?param=512y512'
)
expect(resizeImage('https://test.com/test.jpg', 'lg')).toBe(
'https://test.com/test.jpg?param=1024y1024'
)
// test http => https
expect(resizeImage('http://test.com/test.jpg', 'xs')).toBe(
'https://test.com/test.jpg?param=128y128'
)
expect(resizeImage('', 'xs')).toBe('')
})
test('formatDate', () => {
const time = 1650590574000
expect(formatDate(time)).toBe('2022年04月22日')
expect(formatDate(time, 'en')).toBe('Apr 22, 2022')
expect(formatDate(time, 'en', 'YYYY-MMM-DD')).toBe('2022-Apr-22')
expect(formatDate(time, 'zh-CN')).toBe('2022年04月22日')
expect(formatDate(time, 'zh-TW')).toBe('2022年04月22日')
})
test('formatDuration', () => {
expect(formatDuration(1000)).toBe('0:01')
expect(formatDuration(60000)).toBe('1:00')
expect(formatDuration(3600000)).toBe('1:00:00')
expect(formatDuration(3700000)).toBe('1:01:40')
expect(formatDuration(3600000, 'en', 'hh[hr] mm[min]')).toBe('1 hr')
expect(formatDuration(3600000, 'zh-CN', 'hh[hr] mm[min]')).toBe('1 小时')
expect(formatDuration(3600000, 'zh-TW', 'hh[hr] mm[min]')).toBe('1 小時')
expect(formatDuration(3700000, 'en', 'hh[hr] mm[min]')).toBe('1 hr 1 min')
expect(formatDuration(3700000, 'zh-CN', 'hh[hr] mm[min]')).toBe(
'1 小时 1 分钟'
)
expect(formatDuration(3700000, 'zh-TW', 'hh[hr] mm[min]')).toBe(
'1 小時 1 分鐘'
)
expect(formatDuration(0)).toBe('0:00')
expect(formatDuration(0, 'en', 'hh[hr] mm[min]')).toBe('0 min')
expect(formatDuration(0, 'zh-CN', 'hh[hr] mm[min]')).toBe('0 分钟')
})
test('cacheCoverColor', () => {
vi.stubGlobal('ipcRenderer', {
send: (channel: IpcChannels, ...args: any[]) => {
expect(channel).toBe(IpcChannels.CacheCoverColor)
expect(args[0].api).toBe(APIs.CoverColor)
expect(args[0].query).toEqual({
id: '109951165911363',
color: '#fff',
})
},
})
const sendSpy = vi.spyOn(window.ipcRenderer as any, 'send')
expect(
cacheCoverColor(
'https://p2.music.126.net/2qW-OYZod7SgrzxTwtyBqA==/109951165911363.jpg?param=256y256',
'#fff'
)
)
expect(sendSpy).toHaveBeenCalledTimes(1)
vi.stubGlobal('ipcRenderer', undefined)
})
test('calcCoverColor', async () => {
vi.mock('color.js', () => {
return {
average: vi.fn(
() =>
new Promise(resolve => {
resolve('#fff')
})
),
}
})
vi.stubGlobal('ipcRenderer', {
send: (channel: IpcChannels, ...args: any[]) => {
expect(channel).toBe(IpcChannels.CacheCoverColor)
expect(args[0].api).toBe(APIs.CoverColor)
expect(args[0].query).toEqual({
id: '109951165911363',
color: '#808080',
})
},
})
const sendSpy = vi.spyOn(window.ipcRenderer as any, 'send')
expect(
await calcCoverColor(
'https://p2.music.126.net/2qW-OYZod7SgrzxTwtyBqA==/109951165911363.jpg?param=256y256'
)
).toBe('#808080')
expect(sendSpy).toHaveBeenCalledTimes(1)
vi.stubGlobal('ipcRenderer', undefined)
})
describe('getCoverColor', () => {
test('hit cache', async () => {
vi.stubGlobal('ipcRenderer', {
sendSync: (channel: IpcChannels, ...args: any[]) => {
expect(channel).toBe(IpcChannels.GetApiCacheSync)
expect(args[0].api).toBe(APIs.CoverColor)
expect(args[0].query).toEqual({
id: '109951165911363',
})
return '#fff'
},
})
const sendSyncSpy = vi.spyOn(window.ipcRenderer as any, 'sendSync')
expect(
await getCoverColor(
'https://p2.music.126.net/2qW-OYZod7SgrzxTwtyBqA==/109951165911363.jpg?param=256y256'
)
).toBe('#fff')
expect(sendSyncSpy).toHaveBeenCalledTimes(1)
vi.stubGlobal('ipcRenderer', undefined)
})
test('did not hit cache', async () => {
vi.stubGlobal('ipcRenderer', {
sendSync: (channel: IpcChannels, ...args: any[]) => {
expect(channel).toBe(IpcChannels.GetApiCacheSync)
expect(args[0].api).toBe(APIs.CoverColor)
expect(args[0].query).toEqual({
id: '109951165911363',
})
return undefined
},
send: () => {
//
},
})
const sendSyncSpy = vi.spyOn(window.ipcRenderer as any, 'sendSync')
const sendSpy = vi.spyOn(window.ipcRenderer as any, 'send')
expect(
await getCoverColor(
'https://p2.music.126.net/2qW-OYZod7SgrzxTwtyBqA==/109951165911363.jpg?param=256y256'
)
).toBe('#808080')
expect(sendSyncSpy).toHaveBeenCalledTimes(1)
expect(sendSpy).toHaveBeenCalledTimes(1)
vi.stubGlobal('ipcRenderer', undefined)
})
})

View File

@ -15,15 +15,13 @@ export function resizeImage(
size: 'xs' | 'sm' | 'md' | 'lg'
): string {
if (!url) return ''
const sizeMap = {
xs: '128',
sm: '256',
md: '512',
lg: '1024',
}
if (!Object.keys(sizeMap).includes(size)) {
console.error(`Invalid cover size: ${size}`)
}
return `${url}?param=${sizeMap[size]}y${sizeMap[size]}`.replace(
'http://',
'https://'
@ -48,7 +46,7 @@ export const storage = {
*/
export function formatDate(
timestamp: number,
locale: 'en' | 'zh-TW' | 'zh-CN' = 'en',
locale: 'en' | 'zh-TW' | 'zh-CN' = 'zh-CN',
format: string = 'default'
): string {
if (!timestamp) return ''
@ -67,11 +65,9 @@ export function formatDate(
*/
export function formatDuration(
milliseconds: number,
locale: 'en' | 'zh-TW' | 'zh-CN' = 'en',
locale: 'en' | 'zh-TW' | 'zh-CN' = 'zh-CN',
format: 'hh:mm:ss' | 'hh[hr] mm[min]' = 'hh:mm:ss'
): string {
if (!milliseconds) return ''
dayjs.extend(duration)
const time = dayjs.duration(milliseconds)
@ -98,18 +94,17 @@ export function formatDuration(
mins: '分鐘',
},
}
return hours !== '0'
? `${hours} ${units[locale].hours} ${mins}`
? `${hours} ${units[locale].hours}${
mins === '0' ? '' : ` ${mins} ${units[locale].mins}`
}`
: `${mins} ${units[locale].mins}`
}
return String(milliseconds)
}
export function sleep(time: number) {
return new Promise(resolve => setTimeout(resolve, time))
}
export function scrollToTop(smooth = false) {
const main = document.getElementById('mainContainer')
if (!main) return

View File

@ -1,3 +1,4 @@
/// <reference types="vitest" />
import react from '@vitejs/plugin-react'
import dotenv from 'dotenv'
import path, { join } from 'path'
@ -79,4 +80,7 @@ export default defineConfig({
},
},
},
test: {
environment: 'jsdom',
},
})