Dependências na versão 0.x não recebem automaticamente a promessa de API estável associada ao SemVer após a versão 1.0. Uma atualização que parece pequena pode alterar parâmetros, retornos ou comportamento. A avaliação precisa considerar a política do projeto e o que mudou, além do número publicado.
Há outra distinção: a regra que decide quais versões um gerenciador pode instalar não verifica se elas funcionam com o seu código. Uma versão pode satisfazer o intervalo declarado e ainda exigir adaptação da aplicação.
Neste artigo
O que o zero significa no SemVer
A especificação de Versionamento Semântico reserva 0.y.z ao desenvolvimento inicial e diz que a API pública não deve ser considerada estável nessa fase. Depois de 1.0.0, a política distingue mudanças incompatíveis, funcionalidades compatíveis e correções.
Isso não torna toda biblioteca 0.x inadequada. Um projeto pode ter uso consolidado e documentar garantias mais restritas para suas versões. A informação decisiva é a política que ele assume e cumpre, não uma conclusão genérica sobre qualidade baseada no primeiro dígito.
Procure uma seção de compatibilidade, um guia de migração e as notas da versão pretendida. Quando não houver uma promessa adicional, não invente estabilidade que o padrão não oferece.
O gerenciador interpreta um intervalo, não o seu programa
No ecossistema npm, a implementação node-semver documenta intervalos como caret (^). Veja estas combinações, considerando versões normais, sem pré-lançamento:
| Intervalo declarado | Versão candidata | Satisfaz o intervalo? |
|---|---|---|
^0.2.3 |
0.2.9 |
Sim |
^0.2.3 |
0.3.0 |
Não |
^0.0.3 |
0.0.4 |
Não |
^1.2.3 |
1.9.0 |
Sim |
^1.2.3 |
2.0.0 |
Não |
Esses resultados foram conferidos com node-semver 7.8.5. A tabela demonstra a resolução do intervalo; não testa uma biblioteca real. Outros gerenciadores e outras sintaxes precisam ser consultados em sua própria documentação.
O intervalo ^0.2.3 permite versões a partir de 0.2.3 antes da próxima série 0.3. Isso limita a seleção, mas não cria uma garantia de comportamento que o mantenedor não declarou. Tampouco a aprovação numérica em ^1.2.3 comprova que um projeto cumpriu corretamente o SemVer.
Uma mudança de retorno que passa pelo intervalo
Imagine uma biblioteca fictícia cuja função retorna uma string em 0.2.3 e passa a retornar um objeto em 0.2.4. O consumidor usa .trim() no resultado:
const versao023 = () => "R$ 12,50";
const versao024 = () => ({ texto: "R$ 12,50" });
const consumidor = formatar => formatar().trim();
console.log(consumidor(versao023));
console.log(consumidor(versao024));
A primeira chamada produz a string. A segunda lança TypeError, porque o objeto não oferece esse método. O exemplo foi executado como uma demonstração local; não representa uma alteração feita por um pacote existente.
Ambas as versões pertencem ao intervalo ^0.2.3. A resolução pode estar correta e o consumidor, quebrado. O teste útil observa o contrato que a aplicação usa, em vez de apenas perguntar se a versão foi aceita pelo instalador.
Manifesto e lockfile respondem a perguntas diferentes
O manifesto informa dependências e intervalos. O lockfile registra uma árvore resolvida, com dados necessários para reproduzir aquela seleção, conforme a documentação de package-lock.json do npm.
Por isso, alterar um intervalo, atualizar uma dependência e instalar uma árvore já travada não são a mesma operação. Confira a diferença do lockfile: a atualização pode envolver dependências transitivas que não aparecem como nomes novos no manifesto.
O lockfile ajuda na reprodução, mas não prova que a árvore seja segura ou compatível. Conservar indefinidamente uma versão vulnerável para evitar qualquer mudança também deixa um problema por resolver. O objetivo é controlar e verificar a atualização, com um caminho para correção ou migração.
O que verificar antes de aceitar uma atualização
Comece pelas funções efetivamente usadas. Liste entradas, tipos de retorno, tratamento de erros e efeitos observáveis que importam para o produto. No exemplo, um teste curto de formatação já encontra a troca de string por objeto.
Depois leia todas as notas entre a versão instalada e a pretendida. Uma atualização que pula várias versões pode acumular migrações. Observe requisitos de runtime, opções removidas, novos padrões de configuração e alterações de serialização, além de nomes de métodos.
No projeto de teste, instale a versão candidata de forma controlada e execute os casos de contrato e integração pertinentes. Compare também o artefato que será distribuído. Um teste que importa uma função isolada pode não detectar uma mudança no empacotamento consumido em produção.
Uma decisão que pode ser reproduzida
Registre a versão de origem, a candidata, a política consultada, os pontos de integração e os resultados dos testes. Se a biblioteca oferece um guia de migração, associe cada etapa aos usos existentes na aplicação.
Quando houver quebra, adapte o consumidor ou selecione uma versão compatível enquanto prepara a migração. Preserve um lockfile coerente e o procedimento de instalação utilizado. Depois da atualização, confira o comportamento no ambiente de entrega antes de encerrar a mudança.