no-banned-api
Bane APIs de runtime específicas que causam problemas de compatibilidade entre plataformas ou confiabilidade.
Detalhes da regra
Seção intitulada “Detalhes da regra”Algumas APIs funcionam corretamente em uma plataforma, mas falham em outra. Por exemplo, a API shell do Bun (Bun.$) trava no Windows devido a deadlocks de pipe. Esta regra detecta múltiplas variantes de uma API banida (a chamada direta, o import e o uso desestruturado), garantindo que nenhuma forma passe despercebida.
Este padrão se generaliza para qualquer API que você queira banir enquanto permite uma alternativa segura.
Exemplos de código incorreto
Seção intitulada “Exemplos de código incorreto”// Direct usageconst result = await Bun.$`git status`;
// Importimport { $ } from "bun";
// Destructured usageconst output = await $`ls -la`;Exemplos de código correto
Seção intitulada “Exemplos de código correto”const proc = Bun.spawn(["git", "status"], { stdout: "pipe", stderr: "pipe" });const output = await new Response(proc.stdout).text();Implementação da regra
Seção intitulada “Implementação da regra”/// <reference path="../rules.d.ts" />
export default { rules: { "no-bun-shell": { description: "Subprocess execution must use Bun.spawn, not Bun.$ (shell hangs on Windows)", async check(ctx) { const files = ctx.scopedFiles.filter( (f) => !f.includes("tests/") && !f.includes(".archgate/") );
// Variant 1: Bun.$` template literal const bunShellMatches = await Promise.all( files.map((file) => ctx.grep(file, /Bun\.\$`/)) ); for (const fileMatches of bunShellMatches) { for (const m of fileMatches) { ctx.report.violation({ message: "Do not use Bun.$ template literals. They hang on Windows. Use Bun.spawn instead.", file: m.file, line: m.line, fix: "Replace Bun.$`cmd args` with Bun.spawn(['cmd', 'args'], { stdout: 'pipe', stderr: 'pipe' })", }); } }
// Variant 2: import { $ } from "bun" const dollarImportMatches = await Promise.all( files.map((file) => ctx.grep(file, /import\s*\{[^}]*\$[^}]*\}\s*from\s*["']bun["']/) ) ); for (const fileMatches of dollarImportMatches) { for (const m of fileMatches) { ctx.report.violation({ message: 'Do not import $ from "bun". The shell API hangs on Windows. Use Bun.spawn instead.', file: m.file, line: m.line, fix: "Remove the $ import and replace shell calls with Bun.spawn", }); } }
// Variant 3: await $` (destructured) const destructuredMatches = await Promise.all( files.map((file) => ctx.grep(file, /await\s+\$`/)) ); for (const fileMatches of destructuredMatches) { for (const m of fileMatches) { ctx.report.violation({ message: "Do not use $` template literals. They hang on Windows. Use Bun.spawn instead.", file: m.file, line: m.line, fix: "Replace $`cmd args` with Bun.spawn(['cmd', 'args'], { stdout: 'pipe', stderr: 'pipe' })", }); } } }, }, },} satisfies RuleSet;Quando usar
Seção intitulada “Quando usar”Quando seu projeto precisa rodar em múltiplas plataformas e uma API específica é conhecida por falhar em uma delas. Também útil para banir APIs depreciadas com problemas conhecidos de confiabilidade.
Quando não usar
Seção intitulada “Quando não usar”Quando seu projeto tem como alvo uma única plataforma e a API banida funciona confiavelmente nela.