feat: enable oxlint suspicious category, fix 24 violations (#22727)
This commit is contained in:
+21
-1
@@ -1,5 +1,8 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://raw.githubusercontent.com/nicolo-ribaudo/oxc-project.github.io/refs/heads/json-schema/src/public/.oxlintrc.schema.json",
|
"$schema": "https://raw.githubusercontent.com/nicolo-ribaudo/oxc-project.github.io/refs/heads/json-schema/src/public/.oxlintrc.schema.json",
|
||||||
|
"categories": {
|
||||||
|
"suspicious": "warn"
|
||||||
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
// Effect uses `function*` with Effect.gen/Effect.fnUntraced that don't always yield
|
// Effect uses `function*` with Effect.gen/Effect.fnUntraced that don't always yield
|
||||||
"require-yield": "off",
|
"require-yield": "off",
|
||||||
@@ -10,7 +13,24 @@
|
|||||||
// Intentional control char matching (ANSI escapes, null byte sanitization)
|
// Intentional control char matching (ANSI escapes, null byte sanitization)
|
||||||
"no-control-regex": "off",
|
"no-control-regex": "off",
|
||||||
// SST and plugin tools require triple-slash references
|
// 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"]
|
"ignorePatterns": ["**/node_modules", "**/dist", "**/.build", "**/.sst", "**/*.d.ts"]
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -542,7 +542,7 @@ async function subscribeSessionEvents() {
|
|||||||
? JSON.stringify(part.state.input)
|
? JSON.stringify(part.state.input)
|
||||||
: "Unknown"
|
: "Unknown"
|
||||||
console.log()
|
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") {
|
if (part.type === "text") {
|
||||||
@@ -776,7 +776,7 @@ async function assertPermissions() {
|
|||||||
console.log(` permission: ${permission}`)
|
console.log(` permission: ${permission}`)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Failed to check permissions: ${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`)
|
if (!["admin", "write"].includes(permission)) throw new Error(`User ${actor} does not have write permissions`)
|
||||||
|
|||||||
@@ -128,6 +128,7 @@ export const { use: useGlobalSDK, provider: GlobalSDKProvider } = createSimpleCo
|
|||||||
if (started) return run
|
if (started) return run
|
||||||
started = true
|
started = true
|
||||||
run = (async () => {
|
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) {
|
while (!abort.signal.aborted && started) {
|
||||||
attempt = new AbortController()
|
attempt = new AbortController()
|
||||||
lastEventAt = Date.now()
|
lastEventAt = Date.now()
|
||||||
|
|||||||
@@ -46,7 +46,9 @@ describe("runtime adapters", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test("resolves speech recognition constructor with webkit precedence", () => {
|
test("resolves speech recognition constructor with webkit precedence", () => {
|
||||||
|
// oxlint-disable-next-line no-extraneous-class
|
||||||
class SpeechCtor {}
|
class SpeechCtor {}
|
||||||
|
// oxlint-disable-next-line no-extraneous-class
|
||||||
class WebkitCtor {}
|
class WebkitCtor {}
|
||||||
const ctor = getSpeechRecognitionCtor({
|
const ctor = getSpeechRecognitionCtor({
|
||||||
SpeechRecognition: SpeechCtor,
|
SpeechRecognition: SpeechCtor,
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ export function ReloadSection() {
|
|||||||
}
|
}
|
||||||
const info = billingInfo()!
|
const info = billingInfo()!
|
||||||
setStore("show", true)
|
setStore("show", true)
|
||||||
setStore("reload", info.reload ? true : true)
|
setStore("reload", true)
|
||||||
setStore("reloadAmount", info.reloadAmount.toString())
|
setStore("reloadAmount", info.reloadAmount.toString())
|
||||||
setStore("reloadTrigger", info.reloadTrigger.toString())
|
setStore("reloadTrigger", info.reloadTrigger.toString())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export function wslPath(path: string, mode: "windows" | "linux" | null): string
|
|||||||
const output = execFileSync("wsl", ["-e", "wslpath", flag, path])
|
const output = execFileSync("wsl", ["-e", "wslpath", flag, path])
|
||||||
return output.toString().trim()
|
return output.toString().trim()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(`Failed to run wslpath: ${String(error)}`)
|
throw new Error(`Failed to run wslpath: ${String(error)}`, { cause: error })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ type Env = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class SyncServer extends DurableObject<Env> {
|
export class SyncServer extends DurableObject<Env> {
|
||||||
|
// oxlint-disable-next-line no-useless-constructor
|
||||||
constructor(ctx: DurableObjectState, env: Env) {
|
constructor(ctx: DurableObjectState, env: Env) {
|
||||||
super(ctx, env)
|
super(ctx, env)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ function findBinary() {
|
|||||||
|
|
||||||
return { binaryPath, binaryName }
|
return { binaryPath, binaryName }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(`Could not find package ${packageName}: ${error.message}`)
|
throw new Error(`Could not find package ${packageName}: ${error.message}`, { cause: error })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export namespace BusEvent {
|
|||||||
properties: def.properties,
|
properties: def.properties,
|
||||||
})
|
})
|
||||||
.meta({
|
.meta({
|
||||||
ref: "Event" + "." + def.type,
|
ref: `Event.${def.type}`,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.toArray()
|
.toArray()
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ function parseToolParams(input?: string) {
|
|||||||
} catch (evalError) {
|
} catch (evalError) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Failed to parse --params. Use JSON or a JS object literal. JSON error: ${jsonError}. Eval error: ${evalError}.`,
|
`Failed to parse --params. Use JSON or a JS object literal. JSON error: ${jsonError}. Eval error: ${evalError}.`,
|
||||||
|
{ cause: evalError },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1031,6 +1031,7 @@ export const GithubRunCommand = cmd({
|
|||||||
console.error("Failed to get OIDC token:", error instanceof Error ? error.message : error)
|
console.error("Failed to get OIDC token:", error instanceof Error ? error.message : error)
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Could not fetch an OIDC token. Make sure to add `id-token: write` to your workflow permissions.",
|
"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}`)
|
console.log(` permission: ${permission}`)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Failed to check permissions: ${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`)
|
if (!["admin", "write"].includes(permission)) throw new Error(`User ${actor} does not have write permissions`)
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export const WebCommand = cmd({
|
|||||||
describe: "start opencode server and open web interface",
|
describe: "start opencode server and open web interface",
|
||||||
handler: async (args) => {
|
handler: async (args) => {
|
||||||
if (!Flag.OPENCODE_SERVER_PASSWORD) {
|
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 opts = await resolveNetworkOptions(args)
|
||||||
const server = await Server.listen(opts)
|
const server = await Server.listen(opts)
|
||||||
|
|||||||
@@ -313,7 +313,7 @@ export function deriveNewContentsFromChunks(filePath: string, chunks: UpdateFile
|
|||||||
try {
|
try {
|
||||||
originalContent = readFileSync(filePath, "utf-8")
|
originalContent = readFileSync(filePath, "utf-8")
|
||||||
} catch (error) {
|
} 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")
|
let originalLines = originalContent.split("\n")
|
||||||
|
|||||||
@@ -339,7 +339,7 @@ export const TuiRoutes = lazy(() =>
|
|||||||
properties: def.properties,
|
properties: def.properties,
|
||||||
})
|
})
|
||||||
.meta({
|
.meta({
|
||||||
ref: "Event" + "." + def.type,
|
ref: `Event.${def.type}`,
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -260,8 +260,7 @@ export namespace SessionPrompt {
|
|||||||
messageID: userMessage.info.id,
|
messageID: userMessage.info.id,
|
||||||
sessionID: userMessage.info.sessionID,
|
sessionID: userMessage.info.sessionID,
|
||||||
type: "text",
|
type: "text",
|
||||||
text:
|
text: `${BUILD_SWITCH}\n\nA plan file exists at ${plan}. You should execute on the plan defined within it`,
|
||||||
BUILD_SWITCH + "\n\n" + `A plan file exists at ${plan}. You should execute on the plan defined within it`,
|
|
||||||
synthetic: true,
|
synthetic: true,
|
||||||
})
|
})
|
||||||
userMessage.parts.push(part)
|
userMessage.parts.push(part)
|
||||||
|
|||||||
@@ -273,7 +273,7 @@ export function payloads() {
|
|||||||
data: def.schema,
|
data: def.schema,
|
||||||
})
|
})
|
||||||
.meta({
|
.meta({
|
||||||
ref: "SyncEvent" + "." + def.type,
|
ref: `SyncEvent.${def.type}`,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.toArray()
|
.toArray()
|
||||||
|
|||||||
@@ -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")
|
output += file.raw.map((line, i) => `${i + file.offset}: ${line}`).join("\n")
|
||||||
|
|
||||||
const last = file.offset + file.raw.length - 1
|
const last = file.offset + file.raw.length - 1
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ export namespace Tool {
|
|||||||
) {
|
) {
|
||||||
return () =>
|
return () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const toolInfo = init instanceof Function ? { ...(yield* init()) } : { ...init }
|
const toolInfo = typeof init === "function" ? { ...(yield* init()) } : { ...init }
|
||||||
const execute = toolInfo.execute
|
const execute = toolInfo.execute
|
||||||
toolInfo.execute = (args, ctx) => {
|
toolInfo.execute = (args, ctx) => {
|
||||||
const attrs = {
|
const attrs = {
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ function getOrCreateClientState(name?: string): MockClientState {
|
|||||||
class MockStdioTransport {
|
class MockStdioTransport {
|
||||||
stderr: null = null
|
stderr: null = null
|
||||||
pid = 12345
|
pid = 12345
|
||||||
|
// oxlint-disable-next-line no-useless-constructor
|
||||||
constructor(_opts: any) {}
|
constructor(_opts: any) {}
|
||||||
async start() {
|
async start() {
|
||||||
if (connectShouldHang) return new Promise<void>(() => {}) // never resolves
|
if (connectShouldHang) return new Promise<void>(() => {}) // never resolves
|
||||||
@@ -64,6 +65,7 @@ class MockStdioTransport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MockStreamableHTTP {
|
class MockStreamableHTTP {
|
||||||
|
// oxlint-disable-next-line no-useless-constructor
|
||||||
constructor(_url: URL, _opts?: any) {}
|
constructor(_url: URL, _opts?: any) {}
|
||||||
async start() {
|
async start() {
|
||||||
if (connectShouldHang) return new Promise<void>(() => {}) // never resolves
|
if (connectShouldHang) return new Promise<void>(() => {}) // never resolves
|
||||||
@@ -76,6 +78,7 @@ class MockStreamableHTTP {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MockSSE {
|
class MockSSE {
|
||||||
|
// oxlint-disable-next-line no-useless-constructor
|
||||||
constructor(_url: URL, _opts?: any) {}
|
constructor(_url: URL, _opts?: any) {}
|
||||||
async start() {
|
async start() {
|
||||||
if (connectShouldHang) return new Promise<void>(() => {}) // never resolves
|
if (connectShouldHang) return new Promise<void>(() => {}) // never resolves
|
||||||
|
|||||||
@@ -60,12 +60,11 @@ function chat(text: string) {
|
|||||||
function hanging(ready: () => void) {
|
function hanging(ready: () => void) {
|
||||||
const encoder = new TextEncoder()
|
const encoder = new TextEncoder()
|
||||||
let timer: ReturnType<typeof setTimeout> | undefined
|
let timer: ReturnType<typeof setTimeout> | undefined
|
||||||
const first =
|
const first = `data: ${JSON.stringify({
|
||||||
`data: ${JSON.stringify({
|
id: "chatcmpl-1",
|
||||||
id: "chatcmpl-1",
|
object: "chat.completion.chunk",
|
||||||
object: "chat.completion.chunk",
|
choices: [{ delta: { role: "assistant" } }],
|
||||||
choices: [{ delta: { role: "assistant" } }],
|
})}\n\n`
|
||||||
})}` + "\n\n"
|
|
||||||
const rest =
|
const rest =
|
||||||
[
|
[
|
||||||
`data: ${JSON.stringify({
|
`data: ${JSON.stringify({
|
||||||
|
|||||||
Reference in New Issue
Block a user