refactor: upgrade ESLint 9→10 and simplify React lint toolchain
- Upgrade eslint and @eslint/js to v10 - Replace eslint-plugin-react-x + eslint-plugin-react-dom + eslint-plugin-react-hooks with unified @eslint-react/eslint-plugin - Raise dev Node.js requirement to ^22.13.0 || >=24 (runtime packages unaffected) - Add .npmrc with engine-strict=true - Move all @eslint-react rule overrides to eslint.config.js, eliminating plugin-specific inline eslint-disable comments - Fix real issues caught by new rules: useless assignments, leaked setTimeout, ref naming, useState setter naming
This commit is contained in:
@@ -19,7 +19,7 @@ const log = console.log.bind(console, chalk.yellow('[autoFixer]'))
|
||||
* - etc.
|
||||
*/
|
||||
export function normalizeResponse(response: any, tools?: Map<string, PageAgentTool>): any {
|
||||
let resolvedArguments = null as any
|
||||
let resolvedArguments: any
|
||||
|
||||
const choice = (response as { choices?: Choice[] }).choices?.[0]
|
||||
if (!choice) throw new Error('No choices in response')
|
||||
|
||||
@@ -56,7 +56,7 @@ export class RemotePageController {
|
||||
}
|
||||
|
||||
async getBrowserState(): Promise<BrowserState> {
|
||||
let browserState = {} as BrowserState
|
||||
let browserState: BrowserState
|
||||
debug('getBrowserState', this.currentTabId)
|
||||
|
||||
const currentUrl = await this.getCurrentUrl()
|
||||
|
||||
@@ -49,7 +49,9 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) {
|
||||
const [showToken, setShowToken] = useState(false)
|
||||
const [showApiKey, setShowApiKey] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
const [prevConfig, setPrevConfig] = useState(config)
|
||||
if (prevConfig !== config) {
|
||||
setPrevConfig(config)
|
||||
setBaseURL(config?.baseURL || DEMO_BASE_URL)
|
||||
setModel(config?.model || DEMO_MODEL)
|
||||
setApiKey(config?.apiKey)
|
||||
@@ -59,7 +61,7 @@ export function ConfigPanel({ config, onSave, onClose }: ConfigPanelProps) {
|
||||
setExperimentalLlmsTxt(config?.experimentalLlmsTxt ?? false)
|
||||
setExperimentalIncludeAllTabs(config?.experimentalIncludeAllTabs ?? false)
|
||||
setDisableNamedToolChoice(config?.disableNamedToolChoice ?? false)
|
||||
}, [config])
|
||||
}
|
||||
|
||||
// Poll for user auth token every second until found
|
||||
useEffect(() => {
|
||||
|
||||
@@ -71,7 +71,6 @@ export function HistoryDetail({
|
||||
{/* Events (read-only) */}
|
||||
<div className="flex-1 overflow-y-auto p-3 space-y-2">
|
||||
{session.history.map((event, index) => (
|
||||
// eslint-disable-next-line react-x/no-array-index-key
|
||||
<EventCard key={index} event={event} />
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -34,7 +34,6 @@ export function HistoryList({
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||
load()
|
||||
}, [load])
|
||||
|
||||
|
||||
@@ -133,7 +133,6 @@ export default function App() {
|
||||
)}
|
||||
|
||||
{history.map((event, index) => (
|
||||
// eslint-disable-next-line react-x/no-array-index-key
|
||||
<EventCard key={index} event={event} />
|
||||
))}
|
||||
|
||||
|
||||
@@ -206,9 +206,9 @@ export function useHubWs(
|
||||
const [wsState, setWsState] = useState<HubWsState>(() => (wsPort ? 'connecting' : 'disconnected'))
|
||||
const hubWsRef = useRef<HubWs | null>(null)
|
||||
|
||||
const latest = useRef({ execute, stop, configure, config })
|
||||
const latestRef = useRef({ execute, stop, configure, config })
|
||||
useEffect(() => {
|
||||
latest.current = { execute, stop, configure, config }
|
||||
latestRef.current = { execute, stop, configure, config }
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
@@ -218,14 +218,14 @@ export function useHubWs(
|
||||
Number(wsPort),
|
||||
{
|
||||
onExecute: async (task, incomingConfig) => {
|
||||
const { execute, configure, config } = latest.current
|
||||
const { execute, configure, config } = latestRef.current
|
||||
if (incomingConfig) {
|
||||
await configure({ ...config, ...incomingConfig } as ExtConfig)
|
||||
}
|
||||
const result = await execute(task)
|
||||
return { success: result.success, data: result.data }
|
||||
},
|
||||
onStop: () => latest.current.stop(),
|
||||
onStop: () => latestRef.current.stop(),
|
||||
},
|
||||
setWsState
|
||||
)
|
||||
|
||||
@@ -178,7 +178,6 @@ export default function App() {
|
||||
{showEmptyState && <EmptyState />}
|
||||
|
||||
{history.map((event, index) => (
|
||||
// eslint-disable-next-line react-x/no-array-index-key
|
||||
<EventCard key={index} event={event} />
|
||||
))}
|
||||
|
||||
|
||||
@@ -169,7 +169,6 @@ function highlightSyntax(code: string): string {
|
||||
const HighlightSyntaxClient: React.FC<HighlightSyntaxProps> = ({ code }) => {
|
||||
const htmlContent = highlightSyntax(code)
|
||||
|
||||
// eslint-disable-next-line react-dom/no-dangerously-set-innerhtml
|
||||
return <code className={styles.syntax} dangerouslySetInnerHTML={{ __html: htmlContent }} />
|
||||
}
|
||||
|
||||
|
||||
@@ -140,6 +140,7 @@ function JSConsole({
|
||||
// 全局console拦截处理
|
||||
useEffect(() => {
|
||||
const interceptor = ConsoleInterceptor.getInstance()
|
||||
let scrollTimer: ReturnType<typeof setTimeout>
|
||||
|
||||
const handleGlobalConsole = (type: string, args: unknown[]) => {
|
||||
const content = args.map((arg) => formatResult(arg)).join(' ')
|
||||
@@ -152,8 +153,8 @@ function JSConsole({
|
||||
|
||||
setOutputs((prev) => [...prev, outputItem])
|
||||
|
||||
// 自动滚动到底部
|
||||
setTimeout(() => {
|
||||
clearTimeout(scrollTimer)
|
||||
scrollTimer = setTimeout(() => {
|
||||
if (outputRef.current) {
|
||||
outputRef.current.scrollTop = outputRef.current.scrollHeight
|
||||
}
|
||||
@@ -164,6 +165,7 @@ function JSConsole({
|
||||
|
||||
return () => {
|
||||
interceptor.unsubscribe(handleGlobalConsole)
|
||||
clearTimeout(scrollTimer)
|
||||
}
|
||||
}, [])
|
||||
|
||||
|
||||
@@ -9,19 +9,19 @@ const LanguageContext = createContext<{
|
||||
} | null>(null)
|
||||
|
||||
export function LanguageProvider({ children }: { children: ReactNode }) {
|
||||
const [language, setLang] = useState<Lang>(() => {
|
||||
const [language, setLanguage] = useState<Lang>(() => {
|
||||
const stored = localStorage.getItem('language') as Lang
|
||||
if (stored === 'zh-CN' || stored === 'en-US') return stored
|
||||
return navigator.language.startsWith('zh') ? 'zh-CN' : 'en-US'
|
||||
})
|
||||
|
||||
const setLanguage = (lang: Lang) => {
|
||||
setLang(lang)
|
||||
const switchLanguage = (lang: Lang) => {
|
||||
setLanguage(lang)
|
||||
localStorage.setItem('language', lang)
|
||||
}
|
||||
|
||||
return (
|
||||
<LanguageContext value={{ language, isZh: language === 'zh-CN', setLanguage }}>
|
||||
<LanguageContext value={{ language, isZh: language === 'zh-CN', setLanguage: switchLanguage }}>
|
||||
{children}
|
||||
</LanguageContext>
|
||||
)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* eslint-disable react-dom/no-dangerously-set-innerhtml */
|
||||
import type { PageAgent as PageAgentType } from 'page-agent'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Link, useSearchParams } from 'wouter'
|
||||
@@ -46,10 +45,11 @@ export default function HeroSection() {
|
||||
: 'Goto docs in navigation bar, find Quick-Start section, and summarize in markdown'
|
||||
|
||||
const [task, setTask] = useState(() => defaultTask)
|
||||
|
||||
useEffect(() => {
|
||||
const [prevDefaultTask, setPrevDefaultTask] = useState(defaultTask)
|
||||
if (prevDefaultTask !== defaultTask) {
|
||||
setPrevDefaultTask(defaultTask)
|
||||
setTask(defaultTask)
|
||||
}, [defaultTask])
|
||||
}
|
||||
|
||||
const [params] = useSearchParams()
|
||||
const isOther = params.has('try_other')
|
||||
|
||||
@@ -18,10 +18,12 @@ function ScrollToTop() {
|
||||
|
||||
export default function Router() {
|
||||
useEffect(() => {
|
||||
const schedule = globalThis.requestIdleCallback ?? ((cb: () => void) => setTimeout(cb, 1))
|
||||
const cancel = globalThis.cancelIdleCallback ?? clearTimeout
|
||||
const id = schedule(() => docsImport())
|
||||
return () => cancel(id)
|
||||
if ('requestIdleCallback' in globalThis) {
|
||||
const id = requestIdleCallback(() => docsImport())
|
||||
return () => cancelIdleCallback(id)
|
||||
}
|
||||
const id = setTimeout(() => docsImport(), 1)
|
||||
return () => clearTimeout(id)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user