diff --git a/babel.config.cjs b/babel.config.cjs index 14c7ac8f..d1325604 100644 --- a/babel.config.cjs +++ b/babel.config.cjs @@ -3,7 +3,7 @@ const plugins = [ ['@babel/plugin-proposal-decorators', { legacy: true }], ['@babel/plugin-transform-runtime'], ['@babel/plugin-transform-object-rest-spread'], - ['babel-plugin-react-compiler'], + ['babel-plugin-react-compiler'] ] module.exports = { @@ -12,20 +12,20 @@ module.exports = { '@babel/preset-env', { targets: { - browsers: ['> 1%', 'last 2 versions', 'not ie <= 8'], + browsers: ['> 1%', 'last 2 versions', 'not ie <= 8'] }, modules: false, useBuiltIns: 'entry', - corejs: 3, - }, + corejs: 3 + } ], [ '@babel/preset-react', { - runtime: 'automatic', - }, + runtime: 'automatic' + } ], - '@babel/preset-typescript', + '@babel/preset-typescript' ], compact: true, comments: true, @@ -35,7 +35,7 @@ module.exports = { : plugins, env: { development: { - plugins: ['react-refresh/babel'], - }, - }, + plugins: ['react-refresh/babel'] + } + } } diff --git a/eslint.config.js b/eslint.config.js index 83776a9e..3dc48af5 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -24,8 +24,8 @@ export default [ 'coverage/', '**/*.d.ts', 'CHANGELOG.md', - 'package-lock.json', - ], + 'package-lock.json' + ] }, // 基础推荐规则 @@ -40,29 +40,29 @@ export default [ plugins: { 'react-hooks': reactHooks, import: importPlugin, - unicorn: unicorn, - react: react, - '@typescript-eslint': typescriptEslint, + unicorn, + react, + '@typescript-eslint': typescriptEslint }, languageOptions: { globals: { ...globals.browser, ...globals.node, ...globals.es2021, - React: 'readonly', + React: 'readonly' }, parser: typescriptParser, ecmaVersion: 'latest', - sourceType: 'module', + sourceType: 'module' }, settings: { react: { - version: 'detect', + version: 'detect' }, 'import/resolver': { typescript: true, - node: true, - }, + node: true + } }, rules: { // React Hooks 严格检查 @@ -84,8 +84,8 @@ export default [ '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }], // avoid hard failure on empty blocks - 'no-empty': 'warn', - }, + 'no-empty': 'warn' + } }, // Jest globals for test files @@ -93,11 +93,11 @@ export default [ files: ['**/*.test.{js,jsx,ts,tsx}', '**/*.spec.{js,jsx,ts,tsx}'], languageOptions: { globals: { - ...globals.jest, - }, - }, + ...globals.jest + } + } }, // Prettier 放在最后(Flat 兼容入口) - prettierConfig, + prettierConfig ] diff --git a/scripts/optimize-media.mjs b/scripts/optimize-media.mjs index 3aaeae93..2498b318 100644 --- a/scripts/optimize-media.mjs +++ b/scripts/optimize-media.mjs @@ -26,14 +26,14 @@ const MP4_AUDIO_BITRATE = process.env.MP4_AUDIO_BITRATE || '128k' const MIN_SAVINGS_PCT = Number(process.env.MEDIA_MIN_SAVINGS_PCT || '5') const SKIP_SMALL_KB = Number(process.env.MEDIA_SKIP_SMALL_KB || '256') -function bytesToMiB(bytes) { +function bytesToMiB (bytes) { return (bytes / 1024 / 1024).toFixed(2) } -function runFfmpeg(args) { +function runFfmpeg (args) { const result = spawnSync('ffmpeg', args, { stdio: 'inherit', - windowsHide: true, + windowsHide: true }) if (result.error) { throw result.error @@ -43,7 +43,7 @@ function runFfmpeg(args) { } } -function isFileExists(filePath) { +function isFileExists (filePath) { try { fsSync.accessSync(filePath) return true @@ -52,29 +52,29 @@ function isFileExists(filePath) { } } -async function ensureDir(dirPath) { +async function ensureDir (dirPath) { await fs.mkdir(dirPath, { recursive: true }) } -async function cleanDir(dirPath) { +async function cleanDir (dirPath) { await fs.rm(dirPath, { recursive: true, force: true }) await ensureDir(dirPath) } -async function* walkFiles(dirPath) { +async function * walkFiles (dirPath) { if (!isFileExists(dirPath)) return const entries = await fs.readdir(dirPath, { withFileTypes: true }) for (const entry of entries) { const fullPath = path.join(dirPath, entry.name) if (entry.isDirectory()) { - yield* walkFiles(fullPath) + yield * walkFiles(fullPath) } else if (entry.isFile()) { yield fullPath } } } -async function copyAll({ fromDir, toDir }) { +async function copyAll ({ fromDir, toDir }) { if (!isFileExists(fromDir)) return { scanned: 0, copied: 0 } await ensureDir(toDir) let scanned = 0 @@ -90,7 +90,7 @@ async function copyAll({ fromDir, toDir }) { return { scanned, copied } } -async function optimizeOne({ inputPath, inputBaseDir, outputBaseDir }) { +async function optimizeOne ({ inputPath, inputBaseDir, outputBaseDir }) { const relPath = path.relative(inputBaseDir, inputPath) const outputPath = path.join(outputBaseDir, relPath) @@ -132,7 +132,7 @@ async function optimizeOne({ inputPath, inputBaseDir, outputBaseDir }) { MP3_BITRATE, '-id3v2_version', '3', - tmpPath, + tmpPath ]) } else { // Re-encode MP4 (H.264 + AAC) and enable faststart @@ -154,7 +154,7 @@ async function optimizeOne({ inputPath, inputBaseDir, outputBaseDir }) { MP4_AUDIO_BITRATE, '-movflags', '+faststart', - tmpPath, + tmpPath ]) } @@ -188,12 +188,12 @@ if (SKIP_OPTIMIZE_MEDIA) { process.exit(0) } -function checkFfmpegAvailable() { +function checkFfmpegAvailable () { const result = spawnSync('ffmpeg', ['-version'], { stdio: 'ignore', windowsHide: true }) return result.status === 0 } -async function main() { +async function main () { if (!checkFfmpegAvailable()) { console.error('[optimize:media] ffmpeg not found in PATH.') console.error('Install ffmpeg and ensure `ffmpeg` is available in your terminal, then re-run.') @@ -204,7 +204,7 @@ async function main() { const targets = [ { inputDir: SRC_AUDIO_DIR, outputDir: OUT_AUDIO_DIR }, { inputDir: SRC_VIDEO_DIR, outputDir: OUT_VIDEO_DIR }, - { inputDir: SRC_PUBLIC_AUDIO_DIR, outputDir: OUT_PUBLIC_AUDIO_DIR }, + { inputDir: SRC_PUBLIC_AUDIO_DIR, outputDir: OUT_PUBLIC_AUDIO_DIR } ] let changedCount = 0 @@ -225,7 +225,7 @@ async function main() { const result = await optimizeOne({ inputPath, inputBaseDir: target.inputDir, - outputBaseDir: target.outputDir, + outputBaseDir: target.outputDir }) if (result.changed) { changedCount += 1 diff --git a/scripts/run-lighthouse.mjs b/scripts/run-lighthouse.mjs index ed1c03d9..5f204619 100644 --- a/scripts/run-lighthouse.mjs +++ b/scripts/run-lighthouse.mjs @@ -51,8 +51,8 @@ const fetchOk = async (url) => { signal: controller.signal, headers: { // Some dev servers behave differently for default fetch UA. - 'User-Agent': 'wui-react-lighthouse-probe', - }, + 'User-Agent': 'wui-react-lighthouse-probe' + } }) if (!res.ok) return false const text = await res.text() @@ -107,7 +107,7 @@ const runLighthouse = (url) => { const args = ['--view', url, '--preset=desktop'] const result = spawnSync('lighthouse', args, { stdio: 'inherit', - shell: process.platform === 'win32', + shell: process.platform === 'win32' }) process.exit(result.status ?? 1) diff --git a/scripts/run-sonar-scanner.cjs b/scripts/run-sonar-scanner.cjs index 49fb879e..70b38dca 100644 --- a/scripts/run-sonar-scanner.cjs +++ b/scripts/run-sonar-scanner.cjs @@ -4,7 +4,7 @@ const { spawnSync } = require('node:child_process') const path = require('node:path') const fs = require('node:fs') -function main() { +function main () { const token = process.env.SONAR_TOKEN if (!token) { @@ -41,7 +41,7 @@ function main() { const result = spawnSync(localScanner, args, { stdio: 'inherit', shell: false, - windowsHide: true, + windowsHide: true }) process.exit(result.status ?? 1) diff --git a/scripts/svg_tools.cjs b/scripts/svg_tools.cjs index 94fab80d..0b3e3d3f 100644 --- a/scripts/svg_tools.cjs +++ b/scripts/svg_tools.cjs @@ -2,12 +2,12 @@ const fs = require('fs') const path = require('path') -function resolveTargetFile(provided) { +function resolveTargetFile (provided) { if (provided) return path.resolve(provided) return path.join(__dirname, '..', 'src', 'pages', 'svgViewer', 'index.jsx') } -function readFile(fp) { +function readFile (fp) { try { return fs.readFileSync(fp, 'utf8') } catch (e) { @@ -16,16 +16,16 @@ function readFile(fp) { } } -function writeFile(fp, content) { +function writeFile (fp, content) { fs.writeFileSync(fp, content, 'utf8') } -function findSvgSource(content) { +function findSvgSource (content) { const m = content.match(/const\s+SVG_SOURCE\s*=\s*`([\s\S]*?)`;/m) return m ? { fullMatch: m[0], svg: m[1], index: m.index } : null } -function showContext(svg, idx, label) { +function showContext (svg, idx, label) { if (idx < 0) { console.log(`${label}: not found`) return @@ -35,7 +35,7 @@ function showContext(svg, idx, label) { console.log(`\n${label} context (around index ${idx}):\n---START---\n${svg.slice(start, end)}\n---END---`) } -function cmd_check(fp) { +function cmd_check (fp) { const content = readFile(fp) const found = findSvgSource(content) if (!found) { @@ -43,7 +43,7 @@ function cmd_check(fp) { process.exit(2) } const svg = found.svg - function countTag(tag) { + function countTag (tag) { const openRe = new RegExp('<' + tag + '[\\s>]', 'gi') const closeRe = new RegExp('', 'gi') const opens = (svg.match(openRe) || []).length @@ -70,7 +70,7 @@ function cmd_check(fp) { // stack-based scan for unclosed const tagRegex = /<\/?g[\s>]/gi - let stack = [] + const stack = [] let m while ((m = tagRegex.exec(svg)) !== null) { if (m[0].startsWith(' occurrences found to replace') process.exit(0) } - const newContent = content.replace(found.fullMatch, `const SVG_SOURCE = ` + '`' + replaced + '`;') + const newContent = content.replace(found.fullMatch, 'const SVG_SOURCE = ' + '`' + replaced + '`;') writeFile(fp, newContent) console.log('Replaced
with
in SVG_SOURCE') } -function cmd_fix_unclosed_g(fp) { +function cmd_fix_unclosed_g (fp) { const content = readFile(fp) const found = findSvgSource(content) if (!found) { console.error('Cannot find SVG_SOURCE') process.exit(2) } - let svg = found.svg + const svg = found.svg const openCount = (svg.match(/]/gi) || []).length const closeCount = (svg.match(/<\/g>/gi) || []).length const missing = openCount - closeCount @@ -135,12 +135,12 @@ function cmd_fix_unclosed_g(fp) { } const inserts = '
'.repeat(missing) const newSvg = svg.slice(0, lastCloseSvgIdx) + inserts + svg.slice(lastCloseSvgIdx) - const newContent = content.replace(found.fullMatch, `const SVG_SOURCE = ` + '`' + newSvg + '`;') + const newContent = content.replace(found.fullMatch, 'const SVG_SOURCE = ' + '`' + newSvg + '`;') writeFile(fp, newContent) console.log(`Inserted ${missing} before closing `) } -function usage() { +function usage () { console.log('Usage: node scripts/svg_tools.cjs [--file=path]') console.log('Commands:') console.log(' check : analyze tag counts and find unclosed ') @@ -150,10 +150,10 @@ function usage() { console.log(' --file=PATH : specify target file (defaults to src/pages/svgViewer/index.jsx)') } -function main() { +function main () { const rawArgs = process.argv.slice(2) if (rawArgs.length === 0) return usage() - let cmd = rawArgs[0] + const cmd = rawArgs[0] let fileArg = null for (let i = 1; i < rawArgs.length; i++) { const a = rawArgs[i] diff --git a/src/app-hooks/useSafeNavigate/index.js b/src/app-hooks/useSafeNavigate/index.js index 61ea7030..405afeff 100644 --- a/src/app-hooks/useSafeNavigate/index.js +++ b/src/app-hooks/useSafeNavigate/index.js @@ -16,7 +16,7 @@ const safeShowDenied = () => { }) } -export default function useSafeNavigate() { +export default function useSafeNavigate () { const navigate = useNavigate() const lastDeniedRef = useRef(null) diff --git a/src/pages/layout/proHeader/index.jsx b/src/pages/layout/proHeader/index.jsx index 3353249e..e509a974 100644 --- a/src/pages/layout/proHeader/index.jsx +++ b/src/pages/layout/proHeader/index.jsx @@ -15,7 +15,7 @@ import { MoreOutlined, RocketOutlined, BookOutlined, - SearchOutlined, + SearchOutlined } from '@ant-design/icons' import { useNavigate } from 'react-router-dom' import { removeLocalStorage, getLocalStorage } from '@utils/publicFn' @@ -63,29 +63,29 @@ const buildUserMenuItems = ({ t, tokenValue, isAuthenticated, user }) => [ { key: 'token', label: <>{tokenValue}, - disabled: true, + disabled: true }, { type: 'divider' }, { key: '1', label: {t('header.userCenter')}, - icon: , + icon: }, { key: '2', label: {t('header.userSettings')}, - icon: , + icon: }, { key: '3', label: {t('header.contactMe')}, - icon: , + icon: }, { key: '4', label: {t('header.logout')}, - icon: , - }, + icon: + } ] const buildMobileMoreItems = ({ @@ -94,43 +94,43 @@ const buildMobileMoreItems = ({ onSettingClick, redirectGithub, redirectWiki, - redirectWrapped, + redirectWrapped }) => [ ...(Array.isArray(primaryNavItems) ? primaryNavItems : []).map((it) => ({ ...it, - label: it?.i18nKey ? t(it.i18nKey) : it?.label, + label: it?.i18nKey ? t(it.i18nKey) : it?.label })), { type: 'divider' }, { key: 'notification', label: , icon: null, - onClick: undefined, + onClick: undefined }, { key: 'github', label: t('header.github'), icon: , - onClick: redirectGithub, + onClick: redirectGithub }, { key: 'wiki', label: t('header.wiki'), icon: , - onClick: redirectWiki, + onClick: redirectWiki }, { key: 'wrapped', label: t('header.wrapped'), icon: , - onClick: redirectWrapped, + onClick: redirectWrapped }, { key: 'setting', label: t('header.preferences'), icon: , - onClick: onSettingClick, - }, + onClick: onSettingClick + } ] const safeLogoutCleanup = () => { @@ -170,7 +170,7 @@ const renderMobileMenuTrigger = (isMobile, onMobileMenuClick) => { if (!isMobile) return null return (