feat: enable oxlint suspicious category, fix 24 violations (#22727)

This commit is contained in:
Kit Langton
2026-04-15 22:53:10 -04:00
committed by GitHub
parent 665a843086
commit 702f741267
20 changed files with 49 additions and 22 deletions

View File

@@ -1,5 +1,8 @@
{
"$schema": "https://raw.githubusercontent.com/nicolo-ribaudo/oxc-project.github.io/refs/heads/json-schema/src/public/.oxlintrc.schema.json",
"categories": {
"suspicious": "warn"
},
"rules": {
// Effect uses `function*` with Effect.gen/Effect.fnUntraced that don't always yield
"require-yield": "off",
@@ -10,7 +13,24 @@
// Intentional control char matching (ANSI escapes, null byte sanitization)
"no-control-regex": "off",
// SST and plugin tools require triple-slash references
"triple-slash-reference": "off"
"triple-slash-reference": "off",
// Suspicious category: suppress noisy rules
// Effect's nested function* closures inherently shadow outer scope
"no-shadow": "off",
// Namespace-heavy codebase makes this too noisy
"unicorn/consistent-function-scoping": "off",
// Opinionated — .sort()/.reverse() mutation is fine in this codebase
"unicorn/no-array-sort": "off",
"unicorn/no-array-reverse": "off",
// Not relevant — this isn't a DOM event handler codebase
"unicorn/prefer-add-event-listener": "off",
// Bundler handles module resolution
"unicorn/require-module-specifiers": "off",
// postMessage target origin not relevant for this codebase
"unicorn/require-post-message-target-origin": "off",
// Side-effectful constructors are intentional in some places
"no-new": "off"
},
"ignorePatterns": ["**/node_modules", "**/dist", "**/.build", "**/.sst", "**/*.d.ts"]
}

View File

@@ -542,7 +542,7 @@ async function subscribeSessionEvents() {
? JSON.stringify(part.state.input)
: "Unknown"
console.log()
console.log(color + `|`, "\x1b[0m\x1b[2m" + ` ${tool.padEnd(7, " ")}`, "", "\x1b[0m" + title)
console.log(`${color}|`, `\x1b[0m\x1b[2m ${tool.padEnd(7, " ")}`, "", `\x1b[0m${title}`)
}
if (part.type === "text") {
@@ -776,7 +776,7 @@ async function assertPermissions() {
console.log(` permission: ${permission}`)
} catch (error) {
console.error(`Failed to check permissions: ${error}`)
throw new Error(`Failed to check permissions for user ${actor}: ${error}`)
throw new Error(`Failed to check permissions for user ${actor}: ${error}`, { cause: error })
}
if (!["admin", "write"].includes(permission)) throw new Error(`User ${actor} does not have write permissions`)

View File

@@ -128,6 +128,7 @@ export const { use: useGlobalSDK, provider: GlobalSDKProvider } = createSimpleCo
if (started) return run
started = true
run = (async () => {
// oxlint-disable-next-line no-unmodified-loop-condition -- `started` is set to false by stop() which also aborts; both flags are checked to allow graceful exit
while (!abort.signal.aborted && started) {
attempt = new AbortController()
lastEventAt = Date.now()

View File

@@ -46,7 +46,9 @@ describe("runtime adapters", () => {
})
test("resolves speech recognition constructor with webkit precedence", () => {
// oxlint-disable-next-line no-extraneous-class
class SpeechCtor {}
// oxlint-disable-next-line no-extraneous-class
class WebkitCtor {}
const ctor = getSpeechRecognitionCtor({
SpeechRecognition: SpeechCtor,

View File

@@ -90,7 +90,7 @@ export function ReloadSection() {
}
const info = billingInfo()!
setStore("show", true)
setStore("reload", info.reload ? true : true)
setStore("reload", true)
setStore("reloadAmount", info.reloadAmount.toString())
setStore("reloadTrigger", info.reloadTrigger.toString())
}

View File

@@ -28,7 +28,7 @@ export function wslPath(path: string, mode: "windows" | "linux" | null): string
const output = execFileSync("wsl", ["-e", "wslpath", flag, path])
return output.toString().trim()
} catch (error) {
throw new Error(`Failed to run wslpath: ${String(error)}`)
throw new Error(`Failed to run wslpath: ${String(error)}`, { cause: error })
}
}

View File

@@ -13,6 +13,7 @@ type Env = {
}
export class SyncServer extends DurableObject<Env> {
// oxlint-disable-next-line no-useless-constructor
constructor(ctx: DurableObjectState, env: Env) {
super(ctx, env)
}

View File

@@ -64,7 +64,7 @@ function findBinary() {
return { binaryPath, binaryName }
} catch (error) {
throw new Error(`Could not find package ${packageName}: ${error.message}`)
throw new Error(`Could not find package ${packageName}: ${error.message}`, { cause: error })
}
}

View File

@@ -25,7 +25,7 @@ export namespace BusEvent {
properties: def.properties,
})
.meta({
ref: "Event" + "." + def.type,
ref: `Event.${def.type}`,
})
})
.toArray()

View File

@@ -111,6 +111,7 @@ function parseToolParams(input?: string) {
} catch (evalError) {
throw new Error(
`Failed to parse --params. Use JSON or a JS object literal. JSON error: ${jsonError}. Eval error: ${evalError}.`,
{ cause: evalError },
)
}
}

View File

@@ -1031,6 +1031,7 @@ export const GithubRunCommand = cmd({
console.error("Failed to get OIDC token:", error instanceof Error ? error.message : error)
throw new Error(
"Could not fetch an OIDC token. Make sure to add `id-token: write` to your workflow permissions.",
{ cause: error },
)
}
}
@@ -1221,7 +1222,7 @@ export const GithubRunCommand = cmd({
console.log(` permission: ${permission}`)
} catch (error) {
console.error(`Failed to check permissions: ${error}`)
throw new Error(`Failed to check permissions for user ${actor}: ${error}`)
throw new Error(`Failed to check permissions for user ${actor}: ${error}`, { cause: error })
}
if (!["admin", "write"].includes(permission)) throw new Error(`User ${actor} does not have write permissions`)

View File

@@ -34,7 +34,7 @@ export const WebCommand = cmd({
describe: "start opencode server and open web interface",
handler: async (args) => {
if (!Flag.OPENCODE_SERVER_PASSWORD) {
UI.println(UI.Style.TEXT_WARNING_BOLD + "! " + "OPENCODE_SERVER_PASSWORD is not set; server is unsecured.")
UI.println(UI.Style.TEXT_WARNING_BOLD + "! OPENCODE_SERVER_PASSWORD is not set; server is unsecured.")
}
const opts = await resolveNetworkOptions(args)
const server = await Server.listen(opts)

View File

@@ -313,7 +313,7 @@ export function deriveNewContentsFromChunks(filePath: string, chunks: UpdateFile
try {
originalContent = readFileSync(filePath, "utf-8")
} catch (error) {
throw new Error(`Failed to read file ${filePath}: ${error}`)
throw new Error(`Failed to read file ${filePath}: ${error}`, { cause: error })
}
let originalLines = originalContent.split("\n")

View File

@@ -339,7 +339,7 @@ export const TuiRoutes = lazy(() =>
properties: def.properties,
})
.meta({
ref: "Event" + "." + def.type,
ref: `Event.${def.type}`,
})
}),
),

View File

@@ -260,8 +260,7 @@ export namespace SessionPrompt {
messageID: userMessage.info.id,
sessionID: userMessage.info.sessionID,
type: "text",
text:
BUILD_SWITCH + "\n\n" + `A plan file exists at ${plan}. You should execute on the plan defined within it`,
text: `${BUILD_SWITCH}\n\nA plan file exists at ${plan}. You should execute on the plan defined within it`,
synthetic: true,
})
userMessage.parts.push(part)

View File

@@ -273,7 +273,7 @@ export function payloads() {
data: def.schema,
})
.meta({
ref: "SyncEvent" + "." + def.type,
ref: `SyncEvent.${def.type}`,
})
})
.toArray()

View File

@@ -181,7 +181,7 @@ export const ReadTool = Tool.define(
)
}
let output = [`<path>${filepath}</path>`, `<type>file</type>`, "<content>" + "\n"].join("\n")
let output = [`<path>${filepath}</path>`, `<type>file</type>`, "<content>\n"].join("\n")
output += file.raw.map((line, i) => `${i + file.offset}: ${line}`).join("\n")
const last = file.offset + file.raw.length - 1

View File

@@ -78,7 +78,7 @@ export namespace Tool {
) {
return () =>
Effect.gen(function* () {
const toolInfo = init instanceof Function ? { ...(yield* init()) } : { ...init }
const toolInfo = typeof init === "function" ? { ...(yield* init()) } : { ...init }
const execute = toolInfo.execute
toolInfo.execute = (args, ctx) => {
const attrs = {

View File

@@ -53,6 +53,7 @@ function getOrCreateClientState(name?: string): MockClientState {
class MockStdioTransport {
stderr: null = null
pid = 12345
// oxlint-disable-next-line no-useless-constructor
constructor(_opts: any) {}
async start() {
if (connectShouldHang) return new Promise<void>(() => {}) // never resolves
@@ -64,6 +65,7 @@ class MockStdioTransport {
}
class MockStreamableHTTP {
// oxlint-disable-next-line no-useless-constructor
constructor(_url: URL, _opts?: any) {}
async start() {
if (connectShouldHang) return new Promise<void>(() => {}) // never resolves
@@ -76,6 +78,7 @@ class MockStreamableHTTP {
}
class MockSSE {
// oxlint-disable-next-line no-useless-constructor
constructor(_url: URL, _opts?: any) {}
async start() {
if (connectShouldHang) return new Promise<void>(() => {}) // never resolves

View File

@@ -60,12 +60,11 @@ function chat(text: string) {
function hanging(ready: () => void) {
const encoder = new TextEncoder()
let timer: ReturnType<typeof setTimeout> | undefined
const first =
`data: ${JSON.stringify({
id: "chatcmpl-1",
object: "chat.completion.chunk",
choices: [{ delta: { role: "assistant" } }],
})}` + "\n\n"
const first = `data: ${JSON.stringify({
id: "chatcmpl-1",
object: "chat.completion.chunk",
choices: [{ delta: { role: "assistant" } }],
})}\n\n`
const rest =
[
`data: ${JSON.stringify({