Habilidade de Revisão de Regra de Lint (ESLint)
Revise uma regra de lint da forma que um mantenedor com milhares de comentários de revisão anteriores faria. O hábito definidor desse mantenedor é empírico: ele não apenas lê uma regra, ele tenta quebrá-la. Ele deleta uma condição e vê se um teste falha, e inventa a sintaxe em que ninguém pensou. Siga esse hábito aqui. Uma descoberta apoiada por um teste com falha ou um mutante sobrevivente vale muito mais do que uma que parece plausível, e o ruído que parece plausível é o que faz as revisões automatizadas serem ignoradas.
As descobertas vão para o usuário, que decide o que fazer com elas. Escrever a revisão em um arquivo local é todo o trabalho: publicar no GitHub, ou enviar qualquer coisa, acontece apenas se o usuário pedir separadamente.
1. Entender a mudança
Descubra o que está sendo revisado: um PR, uma branch ou um arquivo de regra. Para um PR, faça checkout do commit principal, se possível, porque as etapas posteriores executam o código.
Leia isto antes de formar opiniões:
- A regra, seus testes e sua página de documentação
- A descrição do PR e a issue vinculada, porque uma regra é julgada contra seu propósito, não contra seu próprio algoritmo
- Duas ou três regras irmãs no mesmo repositório, mais a documentação
CONTRIBUTING
Anote qualquer pergunta que o autor faça na descrição. A revisão deve respondê-la.
As convenções do repositório prevalecem sobre as referências desta habilidade. As referências vêm de vários projetos, portanto, se um padrão contradizer o que o repositório claramente faz, siga o repositório.
As referências são grandes, então não as leia de ponta a ponta. Comece em references/index.md, que lista todos os padrões, e extraia apenas as seções que se encaixam nesta mudança. Leia também references/extra-checks.md, que é curto e cobre armadilhas de ferramentas, além de verificações para fixadores, regras de importação e Flint.
2. Verificar o design da regra
Escolha da lista design.md no índice pelo tipo de mudança:
- Nova regra: se ela pertence, seu escopo, sobreposição com outras regras, informações de tipo, opções e posicionamento no preset.
- Mudança em uma regra estabelecida: impacto semântico (semver), regras irmãs que precisam da mesma mudança e se a mudança atende à issue. Pule o resto.
Se o PR for bruto, como ainda não ter testes ou um design que precise ser repensado, pare em uma revisão de alto nível e diga isso, e pule a mutação, que não pode lhe dizer nada sem testes. Ainda assim, tente a regra em alguns casos, já que um bug real vale a pena ser relatado em qualquer estágio. Comentários detalhados sobre código que está prestes a mudar perdem o tempo de todos.
3. Ler cada linha adicionada
Use o índice para extrair as seções que correspondem ao que mudou:
| Mudou | Olhe em |
|---|---|
| Lógica da regra | bugs.md, simplification.md, performance.md |
| Fixadores ou sugestões | fixes.md |
| Mensagens | messages.md |
| Testes | test-method.md |
| Páginas de documentação | docs.md |
| Novos nomes, opções ou regras | naming.md |
Faça isso antes de tentar quebrar qualquer coisa, porque a caça a bugs toma conta uma vez que começa. Faça anotações enquanto avança e classifique-as na etapa 5.
Percorra o diff uma linha adicionada de cada vez e pergunte-se sobre cada uma:
- Nomes: você saberia dizer o que este identificador contém ou faz sem ler mais? Cuidado com nomes que descrevem um tipo em vez de um propósito, e nomes que alegam a ação errada. Se foi preciso ler duas vezes para entender, diga isso e sugira um nome melhor.
- Variáveis locais: esta variável é usada uma vez, logo após ser definida? Sugira inline.
- Condições: ela colapsa?
!x || x.kind !== yse tornax?.kind !== y.ifs aninhados ou adjacentes geralmente se fundem, e umifbooleano geralmente retorna diretamente. - Guardas: este estado realmente pode acontecer, dado o AST e o código acima dele?
- Reutilização: um utilitário compartilhado já faz isso?
Verifique antes de aceitar qualquer auxiliar.
Um auxiliar precisaria de menos parâmetros se vivesse dentro de
create? - Comprimento: existe menos código que faça a mesma coisa? Simplificação é a maior categoria em revisões passadas.
- Vale a pena fazer: este código ou
TODOplaneja algo que ninguém precisa? Diga que pode ir.
Se o código parecer assistido por IA, leia-o com um olhar mais crítico, porque é aí que o excesso tende a se acumular.
Varra cada comentário e frase da documentação. A caça a bugs ofusca isso, mas é uma fonte regular de comentários de revisão reais, então faça isso como uma passagem separada sobre cada comentário adicionado e cada linha de documentação adicionada. Não pergunte se está correto, pergunte se deveria estar lá como escrito:
- Este comentário ficará desatualizado? Anotações sobre cobertura de teste, histórico ou o que um teste cobre ficam desatualizadas, então sugira deletá-las.
- Ele repete o código? Sugira deletá-lo.
- É um atalho significativo e conhecido, como um fork de código upstream?
Peça um
TODO, com um link para a issue se existir, e sugira o comentário exato. - Um usuário final se importaria com esta frase da documentação? Detalhes de implementação não pertencem à página.
- Este exemplo de documentação carrega código que não precisa? Sugira cortar qualquer coisa além do que mostra o comportamento.
- A frase é precisa? Cuidado com redações que soam universais ou sempre verdadeiras quando não são, e sugira uma reescrita.
Dê estes como blocos `sugestão'.
Eles são rápidos para o autor aceitar.
Observe o que é bom. Anote qualquer coisa que o ajudou a revisar ou que lida com algo complicado, e mencione-o especificamente, no corpo da revisão ou como um comentário [Elogio].
4. Tentar quebrar
Esta etapa produz as descobertas de maior valor, então não a pule. Comece fazendo os testes existentes da regra passarem, para que você tenha um comando funcional que execute apenas os testes desta regra.
Mutar as condições. Execute o script incluído a partir da raiz do repositório. Ele precisa do Node 22.18 ou mais novo, que pode diferir da versão que o repositório fixa. Cada mutante é uma execução de teste, então execute-o em segundo plano. Ele edita a regra no lugar, portanto, qualquer outra coisa que você executar nesse meio tempo precisa usar uma cópia da regra salva com um nome temporário:
node <diretório-da-habilidade>/scripts/mutate-conditions.ts --file <regra> --test "<comando de teste>" --base <ref base>
--base limita os mutantes às linhas que o PR mudou, e --diff <arquivo> faz o mesmo a partir de um diff.
Omita ambos para mutar uma regra nova inteira.
Os mutantes são executados na ordem de origem até --max, 60 por padrão, então aumente se o resumo mostrar algum não testado.
Se os testes forem executados de uma pasta de pacote, execute o script a partir dela. --out <arquivo> salva os resultados completos, e uma lista curta de sobreviventes é sempre impressa por último.
Ele primeiro verifica se os testes falham quando a regra lança uma exceção, e para se não falharem, porque então eles não estão exercitando a regra.
O script restaura o arquivo quando termina ou é interrompido.
Se for morto abruptamente, a próxima execução se recusa a iniciar e imprime onde o original está salvo, então compare os dois antes de alterar a regra, porque você pode tê-la editado desde então.
Se o comando de teste construir a regra, reconstrua depois, porque a saída da construção ainda contém o último mutante.
Ele faz o parsing com o typescript do repositório, e no TypeScript 7 ou posterior, ele imprime como passar uma cópia mais antiga com --typescript.
Os mutantes que os testes não percebem são sobreviventes: cada um significa que um teste está faltando ou o código está morto, e você deve descobrir qual.
Delete a condição e pense em qual entrada precisaria dela.
Se você não conseguir construir uma, recomende deletar o código.
Se conseguir, adicione-a à próxima etapa.
Sobreviventes marcados como likelyTypeOnly são saídas de verificação nula nuas que geralmente existem apenas para o compilador, então olhe para eles por último, mas verifique se o branch não está simplesmente não testado.
Se o executor de teste fizer verificação de tipo, um mutante também pode "falhar" apenas porque não compila, então use um comando de apenas transpilação quando puder.
O script cobre apenas mutações comuns. Tente também manualmente qualquer coisa que ele não possa alcançar e da qual o PR dependa, como trocar um argumento por uma variável similar já no escopo.
Comparar cabeça e base. Para uma mudança em uma regra existente, esta é a verificação mais importante.
Uma regressão em código que costumava funcionar importa muito mais do que uma lacuna que já estava lá, e você não pode diferenciá-las sem executar ambas as versões.
Salve a versão base ao lado da regra, por exemplo com git show <base>:./<regra> > <diretório-da-regra>/<nome>.base-tmp.ts, ou aplicando o diff de forma reversa.
Em seguida, copie assets/compare-rule.test.ts ao lado dos testes da regra e ajuste suas linhas marcadas.
Ele ordena cada caso comparando contagens de relatórios, e também registra mensagens, intervalos, saída de correção, sugestões, travamentos e erros de compilação em cada fixture.
Leia os resultados SAÍDA ALTERADA (CHANGED OUTPUT) você mesmo, porque uma mensagem ou correção alterada pode ser o bug, e ignore qualquer caso com fixtureErrors até que sua fixture compile.
Para um PR que adiciona um fixador, a saída de correção e sugestão é a principal coisa a ser lida, então defina expectedOutput nesses casos.
Se o PR adicionar uma opção, defina baseOptions para que o esquema da versão base aceite o caso.
Sem isso, o caso é julgado apenas na cabeça.
Para uma nova regra, importe-a como head e base, para que o harness relate ok ou ERRADO (WRONG) em vez de comparar versões.
Se o harness não se encaixar no plugin, use um arquivo de teste temporário no harness de teste do próprio repositório.
Escrever casos adversários. Escolha as categorias de references/test-cases.md que se encaixam na sintaxe e nos tipos que esta regra toca, e escreva casos literais. Decida o comportamento correto antes de executar cada caso, porque isso impede você de racionalizar o que quer que retorne. Imprima também os dados da mensagem, bem como as contagens de relatórios, já que um nome de tipo errado em uma mensagem também é um bug. Emparelhe um caso em sintaxe nova com um controle em sintaxe antiga, como uma chave de símbolo com o mesmo caso usando uma chave de string. Procure por:
- Travamentos
- Falsos positivos, onde código válido é reportado
- Falsos negativos, onde código inválido não é reportado
- Correções que produzem código inválido, mudam comportamento ou removem comentários
- Intervalos de relatório que são mais largos do que o código ofensor
Mantenha os casos que expuseram algo para que possam ir na revisão como casos de teste literais.
Literal é importante: este mantenedor pede casos escritos à mão e rejeita .map, fábricas e testes gerados.
Provar grandes sugestões. Se você acha que um redesign removeria vários bugs, faça um protótipo e execute os testes existentes. "267 de 268 testes passam, e aqui está o porquê do outro falhar" é muito mais útil do que uma suposição.
Limpar. Execute git status e remova cada arquivo temporário antes de prosseguir, para que o repositório volte ao estado em que você o encontrou.
5. Filtrar as descobertas
Antes de escrever qualquer coisa, passe por cada descoberta:
- Bugs: inclua o caso e o que realmente aconteceu.
Se você não conseguiu reproduzi-lo, corte-o, ou rebaixe-o para uma
[Pergunta]se você ainda tiver um motivo específico para suspeitar dele. - Ordem: regressões vêm primeiro, depois bugs em código novo, depois bugs existentes que o PR toca.
- Uma causa raiz: se um redesign consertaria vários bugs, faça um comentário e liste os casos nele. Mantenha um comentário separado apenas onde um bug precisa de sua própria correção de qualquer maneira, como uma regressão.
- Posições contestadas: trate-as como perguntas não bloqueantes: verificações
inem nós, uso deesquery, forma do esquema de opções e estiloimport ts. Outros mantenedores discordaram razoavelmente sobre eles. - Ampliar ou adiar: se uma lacuna é o mesmo conceito que a regra e usuários reais a encontrariam, peça-a neste PR. Caso contrário, sugira uma issue de acompanhamento.
- Adicionar ou remover uma opção: peça uma opção apenas onde a regra de outra forma baniria código válido, ou onde um usuário real pediu uma.
- Código existente: deixe de fora problemas que o PR não tocou, a menos que sejam sérios, e marque-os como
[Não Acionável]. - Duplicatas: mescle repetições em um comentário que diga "aqui e em outros lugares".
Ruído custa mais do que uma omissão: um autor que passa por cima de três comentários fracos também passará por cima do real. Comentários bloqueantes devem ser apenas o que deve mudar antes do merge. Mantenha no máximo cerca de oito comentários não bloqueantes, escolhendo aqueles que mais melhoram o código, com uma sugestão pronta para aplicar sempre que o comentário solicitar uma mudança. Corte estes primeiro:
- Questões de gosto sem ganho real em clareza, como reformular uma mensagem ou colapsar um condicional que está bom
- Qualquer coisa que a descrição diga ser deliberada, como scaffolding para trabalho planejado
- Bugs que você tentou e não conseguiu encontrar um caso real para eles, sem nenhuma razão específica restante para suspeitar
- Espaços em branco e estilo de aspas
- Solicitações de processo que não acrescentam nada, como uma issue de rastreamento para cada pequeno
TODO
Nada a relatar é um resultado perfeitamente aceitável, então não invente descobertas para parecer minucioso.
Combine o veredito com os comentários bloqueantes. Se nada bloquear, aprove e deixe o resto como sugestões. Muitas revisões deste mantenedor em PRs sólidos são uma aprovação calorosa com uma ou duas pequenas solicitações.
6. Escrever a revisão
Leia references/review-voice.md, então escreva lint-rule-review-skill-<pr-ou-regra>.md no diretório atual, sem fazer commit.
Mantenha o corpo da revisão em algumas frases, indo mais longe apenas para responder às perguntas do autor ou explicar uma decisão de design.
Use esta estrutura:
# Revisão de <PR ou regra>
**Veredito:** aprovar | solicitar alterações | apenas alto nível
<Corpo da revisão, seguindo a ordem em review-voice.md>
## Comentários inline
### `path/to/file.ts:42` · bloqueante
[Bug] <Comentário como seria postado>
```ts
<Caso literal de falha ou sugestão>
Evidência: <O que você executou e o que aconteceu, ou "não reproduzido">
Não verificado
<Qualquer coisa que você não conseguiu executar ou verificar, e por que>
Marque cada comentário como `bloqueante` ou `não bloqueante`, ordenados bloqueantes primeiro. "Evidência" é para o usuário e não seria postada no GitHub; é a base para sua confiança na descoberta.
Se o bug for reproduzível, escreva o caso exato que falha.
## 7. Auto-verificação
Depois de escrever, verifique:
- **Nada enviado:** você verificou que nenhum arquivo foi adicionado ou alterado além do arquivo de revisão e dos arquivos temporários limpos na etapa 4?
`git status` mostrará aqueles.
- **Nenhum trabalho residual:** o repositório está de volta ao estado do commit head do PR, sem patches aplicados, mutantes ou versões base?
- **Arquivo de revisão no diretório de trabalho:** a revisão foi salva no diretório de trabalho atual, não em algum lugar de difícil acesso?
- **Referências não deixadas para trás:** você removeu todas as referências a caminhos do sistema que não seriam válidos para o autor?