npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@seniorsistemas/angular-upgrade-mcp

v1.0.2

Published

MCP Server para automação de upgrades do Angular (v9 até v18)

Readme

angular-upgrade-mcp

Servidor MCP (Model Context Protocol) para automação de upgrades do Angular de v9 até v18, incluindo migração automática de componentes @seniorsistemas/angular-components e PrimeNG via análise estática com tree-sitter.


Índice


O que faz

O angular-upgrade-mcp expõe ferramentas MCP que um agente de IA (Claude, Cursor, etc.) pode chamar para:

  1. Analisar compatibilidade de dependências com Angular 18 antes de iniciar, bloqueando o upgrade se alguma lib não tiver caminho de atualização conhecido.
  2. Fazer o upgrade sequencial de Angular v9 → v10 → ... → v18, cada etapa com validação de Node.js via NVM.
  3. Aplicar os ajustes pós-upgrade necessários para funcionar no Angular 18 (package.json, tailwind, tsconfig, eslint, Prettier).
  4. Migrar automaticamente todos os componentes @seniorsistemas/angular-components e PrimeNG no projeto usando análise de AST (tree-sitter), sem regex frágeis — e provar com um motor de verificação independente que os padrões antigos catalogados realmente desapareceram (ver Motor de verificação).
  5. Corrigir breaking changes obrigatórias do Angular 18 / RxJS 7 (.toPromise(), import moment, RouterEvent, retornos de HttpClient sem tipo).
  6. Atualizar libs @seniorsistemas/* para a versão mais nova compatível com Angular 18 que tenha schematic de migração (ng update), mediante confirmação do usuário.
  7. Corrigir erros TypeScript strict mode opcionalmente, via análise estática.

Arquitetura

angular-upgrade-mcp/
│
├── src/
│   ├── server.ts                          # Registra todas as tools MCP
│   ├── index.ts                           # Entrypoint (stdio transport)
│   │
│   ├── migration/                         # ENGINE GENÉRICO (lib-agnóstico)
│   │   ├── index.ts                       # migrateAngularComponent(ts, html, ctx, config, registry)
│   │   ├── ts-migrator.ts                 # Pipeline de migração TypeScript
│   │   ├── html-migrator.ts               # Pipeline de migração HTML
│   │   ├── verification.ts                # "Prova real" pós-migração (ver seção própria)
│   │   ├── inheritance-discovery.ts       # Descoberta de herança entre componentes
│   │   ├── module-declarations.ts         # Análise de declarations/imports de NgModule
│   │   ├── ts-entry-classification.ts     # classifyTsEntries() — puro, compartilhado com o playground
│   │   ├── eol.ts                         # Normalização de fim de linha (CRLF/LF)
│   │   ├── rules.ts                       # Interfaces: MigrationConfig, ComponentDefinition, etc.
│   │   ├── parser-adapter.ts              # Bridge tree-sitter nativo → TsLanguage/TsTree
│   │   ├── parser-types.ts                # Tipos internos do tree-sitter
│   │   └── custom-rules/
│   │       └── types.ts                   # CustomRule, CustomRuleContext, TextEdit, Warning
│   │
│   ├── migration-angular-components-v18/  # REGRAS: @seniorsistemas/angular-components
│   │   ├── rules.generated.v18.json       # Inventário auto-gerado (npm run scan)
│   │   ├── rules.manual.ts                # Renames manuais (inputs/outputs/selectors)
│   │   ├── enum-literal-migrations.ts     # Inventário de enums migrados p/ literal string
│   │   ├── merge.ts                       # Combina JSON + manual → MigrationConfig
│   │   └── custom-rules/
│   │       ├── registry.ts                # Mapa nome → função de regra
│   │       ├── verify-registry.ts         # Mapa nome → verificador ("prova real")
│   │       ├── accordion-switch-manual.ts
│   │       ├── button-model-to-menu-options.ts
│   │       ├── dynamic-form-fields-to-configs.ts
│   │       ├── enum-member-to-literal.ts
│   │       ├── file-upload-validate-errors.ts
│   │       ├── lookup-labels-to-labeloptions.ts
│   │       ├── lookup-removed-inputs.ts
│   │       └── steps-description-to-label.ts
│   │
│   ├── migration-primeng-v18/             # REGRAS: PrimeNG
│   │   ├── rules.manual.ts                # Regras manuais (sem auto-scan — lib externa)
│   │   ├── config.ts                      # Constrói MigrationConfig a partir de rules.manual
│   │   └── custom-rules/
│   │       ├── registry.ts
│   │       ├── verify-registry.ts         # Mapa nome → verificador ("prova real")
│   │       ├── datepicker-locale.ts
│   │       ├── dropdown-onchange.ts
│   │       ├── p-button-component.ts
│   │       ├── p-button-directive.ts
│   │       ├── p-tabMenu-to-p-tabs.ts
│   │       ├── p-tabView-to-s-tabs.ts
│   │       ├── p-tooltip-disabled.ts
│   │       ├── primeng-dialog-templates.ts
│   │       ├── primeng-messages-to-message-for.ts
│   │       ├── primeng-numeric-attrs.ts
│   │       ├── primeng-radiobutton-checkbox-label.ts
│   │       ├── primeng-table.ts
│   │       └── primeng-translation-config.ts
│   │
│   └── tools/
│       ├── v18-adjustments.ts             # Re-exports + guia de uso (v18-adjustments)
│       ├── start-upgrade.ts               # Ponto de entrada do fluxo
│       ├── check-prerequisites.ts
│       ├── prepare-upgrade.ts
│       ├── analyze-dependencies.ts        # Análise de compatibilidade de deps com Angular 18
│       ├── report-writer.ts               # appendToolSection() — grava UPGRADE-REPORT.md
│       ├── upgrade-shared.ts              # Utilitários compartilhados do fluxo de upgrade
│       ├── env-debug.ts                   # isLocalDryRunEnabled() — dry-run local via env-debug.json (debug, nunca via MCP)
│       ├── platform.ts                    # Detecção de SO / shell para comandos NVM
│       ├── upgrade-to-10.ts … upgrade-to-18.ts  # Uma tool por etapa do ng update
│       └── v18/
│           ├── migrate-angular-components.ts  # Tool MCP de migração (usa engine acima)
│           ├── fix-runtime.ts                 # Tool MCP de fixes obrigatórios RxJS 7 / Angular 18
│           ├── fix-strict-ts.ts               # Tool MCP de fix strict mode (estático, opcional)
│           ├── restore-package-json.ts
│           ├── package-versions.ts            # KNOWN_V18_VERSIONS + regras de merge
│           ├── fix-lib.ts
│           ├── v18-setup-lib.ts
│           ├── install-tailwind.ts
│           ├── fix-tsconfig.ts
│           ├── remove-polyfills.ts
│           ├── migrate-eslint.ts
│           ├── run-prettier.ts                # Tool MCP de formatação (Prettier)
│           ├── npm-install.ts
│           └── update-senior-libs.ts          # Tool MCP de update de libs @seniorsistemas/*
│
├── playground/                            # Ferramentas de debug (não entra no MCP)
│   ├── api/
│   │   ├── api.ts                         # Bootstrap fino: importa app.ts, faz app.listen()
│   │   ├── app.ts                         # App Express + rotas — mesmo engine do MCP, testável via supertest (não faz listen)
│   │   ├── lib-paths.ts
│   │   └── project-explorer.ts
│   └── src/                               # Frontend Angular 22 com Monaco Editor
│
├── scripts/
│   ├── extract-rules.ts                   # Auto-scan do angular-components via git worktree
│   ├── scan.config.ts                     # Branches/versões a scanear
│   ├── lib-paths.ts                       # Resolução do caminho do repo da lib
│   ├── ensure-angular-components-src.sh   # Garante ANGULAR_COMPONENTS_SRC — clona snr-angular-components (GitHub) se ausente
│   ├── copy-dist-assets.mjs               # Copia assets (WASM/grammars) pro dist/ no build
│   ├── update-grammars.mjs                # Atualiza gramáticas tree-sitter (.wasm)
│   └── debug-mcp-local.sh                 # Liga/desliga o dry-run local (env-debug.json) com trap EXIT
│
└── test/
    ├── helpers.ts                         # makeConfig() + migrate() para testes
    ├── setup.ts                           # Setup global do vitest
    ├── html-migrator.test.ts
    ├── ts-migrator.test.ts
    ├── merge.test.ts
    ├── integration.test.ts
    ├── custom-rules.test.ts
    ├── custom-rules-verify.test.ts        # Paridade customRule ↔ verificador ("prova real")
    ├── verification.test.ts               # Motor de verificação genérico
    ├── migrate-angular-components.test.ts # Relatório verificado (prova real) + E2E do handler em tmpdir
    ├── ts-entry-classification.test.ts    # classifyTsEntries — módulo puro compartilhado com o playground
    ├── playground-migration-parity.test.ts # Trava paridade MCP ↔ playground (mesmo arquivo modificado/warnings)
    ├── env-debug.test.ts                  # isLocalDryRunEnabled (flag local, expiração de 1h)
    ├── scan-signals.test.ts
    ├── extract-rules-worktree.test.ts
    ├── lib-paths.test.ts
    ├── fix-strict-ts.test.ts
    ├── fix-strict.test.ts
    ├── restore-package-json.test.ts
    ├── analyze-dependencies.test.ts
    ├── inheritance-discovery.test.ts
    ├── module-declarations.test.ts
    ├── eol.test.ts
    ├── npm-install.test.ts
    ├── migrate-eslint.test.ts
    ├── run-prettier.test.ts
    ├── update-senior-libs.test.ts
    ├── primeng-config.test.ts
    └── upgrade-shared.test.ts

Pré-requisitos

  • Node.js 20+
  • npm 10+
  • Gerenciador de versões de Node (para as tools de upgrade que alternam versões): fnm (recomendado) ou nvm
    • Linux/macOS: fnm ou nvm
    • Windows: fnm (recomendado — winget install Schniz.fnm, não requer Administrador) ou nvm-windows (o nvm use altera symlinks em Program Files e exige terminal Administrador)

O parser do servidor usa tree-sitter via WASM — nenhuma compilação nativa é necessária na instalação (sem Visual Studio Build Tools/Python no Windows).


Instalação

O pacote é executado via npx — não é necessário instalar globalmente. Veja a seção Configuração nos editores para conectá-lo ao seu editor.

Para desenvolvimento deste repositório:

git clone <repositorio>
cd angular-upgrade-mcp
npm install
npm run build

Para usar o auto-scan do @seniorsistemas/angular-components (regenerar rules.generated.v18.json), npm run scan precisa de ANGULAR_COMPONENTS_SRC apontando para um checkout do repositório da lib (senior-sistemas/snr-angular-components, privado). Se a variável não estiver definida, npm run scan clona esse repositório automaticamente (via gh repo clone, ou git clone como fallback) em _angular-components/ na raiz do projeto — veja scripts/ensure-angular-components-src.sh. Requer estar autenticado no GitHub (gh auth login) com acesso à org senior-sistemas.

Se preferir apontar pra um checkout próprio (ex: já tem a lib clonada em outro lugar), defina a variável manualmente antes:

# Linux/macOS
export ANGULAR_COMPONENTS_SRC=/caminho/para/angular-components
npm run scan
# Windows (PowerShell)
$env:ANGULAR_COMPONENTS_SRC = "C:\caminho\para\angular-components"
npm run scan

A variável aceita tanto a raiz do repositório quanto uma subpasta interna (projects/angular-components) — o script detecta automaticamente.

Git é necessário para contribuir com o projeto ou rodar o npm run scan (o scan cria um git worktree temporário para não alterar a working tree do repositório da lib).


Configuração nos editores

Windows: alguns clientes MCP no Windows não conseguem spawnar o npx diretamente. Se o servidor não iniciar, envolva o comando com cmd /c:

{
  "command": "cmd",
  "args": ["/c", "npx", "-y", "@seniorsistemas/angular-upgrade-mcp"]
}

VS Code

Crie .vscode/mcp.json na raiz do projeto:

{
  "servers": {
    "angular-upgrade-mcp": {
      "command": "npx",
      "args": ["-y", "@seniorsistemas/angular-upgrade-mcp"]
    }
  }
}

Kiro

Crie .kiro/settings/mcp.json na raiz do projeto (workspace) ou ~/.kiro/settings/mcp.json (global):

{
  "mcpServers": {
    "angular-upgrade-mcp": {
      "command": "npx",
      "args": ["-y", "@seniorsistemas/angular-upgrade-mcp"]
    }
  }
}

Claude Code

Via CLI — adiciona ao .mcp.json do projeto (compartilhado com o time):

claude mcp add --scope project angular-upgrade-mcp -- npx -y @seniorsistemas/angular-upgrade-mcp

Ou crie .mcp.json na raiz do projeto diretamente:

{
  "mcpServers": {
    "angular-upgrade-mcp": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@seniorsistemas/angular-upgrade-mcp"]
    }
  }
}

Build local (desenvolvimento)

Para usar o build local em qualquer editor, substitua o command/args por:

{
  "command": "node",
  "args": ["/caminho/para/angular-upgrade-mcp/dist/index.js"]
}

Tools MCP disponíveis

Fluxo de upgrade (v9 → v18)

| Tool | O que faz | | --------------------------------- | --------------------------------------------------------------------------------------------------- | | start-upgrade | Ponto de entrada obrigatório. Retorna o plano completo com a sequência exata de tools a chamar. | | check-prerequisites | Verifica se o projeto está em Angular v9 e se NVM está disponível. | | analyze-dependencies | Analisa compatibilidade de dependências com Angular 18; bloqueia o upgrade se alguma lib não tiver versão compatível conhecida; pode gerar angular-upgrade-overrides.jsonc e angular-upgrade-deps-report.md. | | prepare-upgrade | Salva backup do package.json e prepara a base limpa para o upgrade. | | upgrade-to-10 … upgrade-to-18 | Executa ng update para cada versão usando o Node correto via NVM. |

Ajustes pós-upgrade Angular 18

Chame v18-adjustments para receber o guia completo com a sequência e as instruções de uso. As tools individuais são:

| # | Tool | O que faz | | --- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 1 | v18-restore-package-json | Restaura o package.json do backup e aplica versões v18-compatíveis: Storybook 6→8 (com react-is→^16.13.1), injeta ngx-mask (peer dep de @seniorsistemas/angular-components), atualiza rxjs 6→7 e remove rxjs-compat. Roda npm install --force (Node 20) ao final. | | 2 | v18-setup-lib | Corrige builder ng-packagr; remove ~ do SCSS e @import primeng/resources/; separa lib/ng-package.json; remove CSS PrimeNG legado e garante angular-components/styles.css. | | 3 | v18-install-tailwind | Instala e configura TailwindCSS (tailwind.config.js, tailwind.css, angular.json). | | 4 | v18-fix-tsconfig | Remove test.ts/polyfills.ts dos files dos tsconfigs e allowJs; normaliza compilerOptions.module desatualizado (es2015/commonjs/etc. → es2022, necessário pro dynamic import de lazy loading) em todo tsconfig*.json do projeto; atualiza karma.conf.js para headless Chrome (detectando karma-coverage vs karma-coverage-istanbul-reporter); desativa strict: false + todas as flags granulares angularCompilerOptions (medida temporária — ver aviso no UPGRADE-REPORT.md). | | 5 | v18-migrate-angular-components | Migra automaticamente os componentes AC e PrimeNG (veja abaixo). | | 6 | v18-migrate-eslint | Migra de TSLint para ESLint compatível com Angular 18; busca recursiva de tslint.json em todos os subdiretórios. | | 7 | run-prettier | Instala o Prettier e formata .ts/.html/.scss do projeto; cria .prettierrc.json com parser: "angular" para *.component.html (veja abaixo). | | 8 | v18-npm-install | Roda npm install com Node 20 com fallback progressivo (--legacy-peer-deps, --force); reporta conflitos de peer deps detectados. | | 9 | v18-fix-runtime | OBRIGATÓRIO. Corrige breaking changes RxJS 7 / Angular 18 em todos os .ts do projeto (veja abaixo). | | 10 | v18-update-senior-libs (opcional — abrirá diálogo de confirmação) | Atualiza libs @seniorsistemas/*/@senior-gestao-empresarial/* via ng update para a versão mais nova compatível com Angular 18 que tenha schematic de migração. Só executar após confirmação do usuário (veja abaixo). | | 11 | v18-fix-strict-ts (opcional — abrirá diálogo de confirmação) | Corrige erros TypeScript strict mode via análise estática. Só executar após confirmação do usuário (veja abaixo). |

v18-fix-runtime

Corrige breaking changes obrigatórias do Angular 18 / RxJS 7 em todos os .ts do projeto (exceto *.spec.ts/*.d.ts/node_modules).

Fixes aplicados:

  • .toPromise() → firstValueFrom() — via tree-sitter; cobre .pipe(...).toPromise<any>() e similares; adiciona import { firstValueFrom } from 'rxjs' automaticamente se necessário.
  • import * as moment_ from 'moment' → import moment from 'moment' — namespace import não é callable no RxJS/momento moderno.
  • Remove RouterEvent de @angular/router quando não utilizado no corpo do arquivo (deprecated Angular 18).
  • Adiciona : Observable<any> em métodos de serviço que usam this.X.(get|post|put|delete|patch)() sem tipo de retorno explícito; adiciona import { Observable } from 'rxjs' se necessário. Itens marcados como requiresReview: true para o desenvolvedor refinar o tipo depois.
  • new Subject() sem generic → new Subject<void>() — só quando toda chamada .next() desse Subject no arquivo é sem argumento (padrão "sinal de destroy"); se houver .next(valor) em algum lugar, não altera (ambíguo).
  • import * as X from '.../package.json' → import X from '...' (default import) — named export de módulo default-exporting não é permitido pelo TS moderno.
  • Scripts .js na raiz do projeto que citam @angular/cli: dasheriza flags camelCase conhecidas do dev-server builder (--publicHost → --public-host, --disableHostCheck → --disable-host-check, etc.) — Angular CLI 18 registra as opções no yargs sempre em kebab-case.

Parâmetros:

{
  "projectPath": "/caminho/absoluto/do/projeto"
}

run-prettier

Instala o Prettier no projeto (devDependencies + script format) e formata todo .ts/.html/.scss do código-fonte, ignorando node_modules/dist/.angular. Cria .prettierrc.json com tabWidth: 4 e parser: "angular" para *.component.html (necessário para formatar templates Angular corretamente — o parser HTML genérico não entende *ngIf/interpolação/bindings). Não sobrescreve configuração do Prettier já existente. Deve ser chamada logo após v18-migrate-eslint e antes de v18-npm-install.

Parâmetros:

{
  "projectPath": "/caminho/absoluto/do/projeto"
}

v18-update-senior-libs (opcional)

⛔ Consulte o usuário antes de executar. Pergunte: "Deseja verificar e atualizar libs da Senior (@seniorsistemas/*, @senior-gestao-empresarial/*) que tenham versões mais novas com schematics de migração disponíveis? Isso roda ng update e pode quebrar a aplicação se algum schematic não cobrir 100% do seu caso de uso."

Escaneia dependencies/devDependencies do package.json por libs com prefixo Senior. Para cada uma, consulta o npm registry subindo major a major (18→19→20...) enquanto o peerDependencies de @angular/* continuar aceitando Angular 18, e só considera a versão final se ela tiver o campo ng-update (schematics). Roda ng update <lib>@<versão> --allow-dirty uma vez por lib qualificada (Node 20, @angular/cli@18).

Depois de cada ng update bem-sucedido, roda duas verificações e instala o que faltar num único npm install:

  1. peerDependencies novas (3rd-party) que a versão-alvo passou a declarar e que a versão antiga não tinha — ex.: [email protected] passou a exigir ngx-cookie-service/cropperjs que a 18.1.3 não exigia. Se ainda não estiverem no package.json do projeto, são adicionadas automaticamente.
  2. Peer dependencies Senior-para-Senior que ficaram inválidas (npm ls --all --json) por causa de outra lib Senior já atualizada — ex.: platform-components exigido em ^7.0.0 pelo angular-components atualizado. Corrige só o número da versão no package.json (sem ng update — a lib não tem schematics).

Isso cobre dependência declarada (peerDependencies). Não cobre dependência que a lib usa no bundle sem declarar em lugar nenhum (bug de empacotamento da lib publicada) — se aparecer Module not found pontual após o build, é preciso investigar/instalar manualmente.

Parâmetros:

{
  "projectPath": "/caminho/absoluto/do/projeto",
  "confirmed": true
}

v18-migrate-angular-components

A tool principal de migração. Faz o walk recursivo do projeto, processa cada par .component.ts + .component.html (e arquivos .ts sem HTML companion — services, módulos, pipes, guards — pelo pipeline TS-only) e aplica:

  • Quebra de imports do barrel em entry-points específicos (com deduplicação de @NgModule arrays)
  • Renames de inputs/outputs e de tipos TypeScript
  • Substituições de seletores HTML
  • Migrações de importPath
  • Regras customizadas via AST (accordion, dynamic-form, lookup, p-table, p-dialog, etc.)

A seção rica que essa tool escreve em UPGRADE-REPORT.md (ver abaixo) é verificada contra a "prova real" (src/migration/verification.ts): cada claim declarativo ("Atributo X removido automaticamente", etc.) só é afirmado se nenhum achado confirmed de resíduo contradizer aquele arquivo — quando contradiz, o relatório contesta o claim numa seção "Divergências encontradas pela prova real" em vez de afirmá-lo incondicionalmente.

Parâmetros:

{
  "projectPath": "/caminho/absoluto/do/projeto"
}

dryRun não é exposto no schema do MCP de propósito (nenhum client/agente deve conseguir pedir uma prévia sem gravar — commit 6de96c2). Pra debug local via prompt sem gravar num projeto real, existe um mecanismo fora do protocolo: npm run dryrun:local (ou dryrun:on/dryrun:off) cria um env-debug.json na raiz do repo (nunca commitado, expira sozinho em 1h) que só você, localmente, consegue ativar — ver src/tools/env-debug.ts.

v18-fix-strict-ts (opcional)

⛔ Consulte o usuário antes de executar. O build já funciona com strict: false — esta tool é opcional. Pergunte: "Deseja executar o v18-fix-strict-ts? Ele tenta corrigir erros de strict mode automaticamente mas não cobre 100% dos casos — itens restantes ficam no STRICT-REVIEW.md."

Corrige erros TypeScript strict mode via análise estática. Percorre todos os .ts do projeto e aplica correções em uma única passada.

Fixes aplicados:

  • TS2564 (propriedade sem inicializador), conforme o caso:
    • atribuída em ngOnInit → prop!: T (definite assignment)
    • tipo primitivo sem decorator → inicializador padrão (boolean → = false, string → = '', number → = 0)
    • @Input/@ViewChild sem implements → prop?: T
    • @Input/@ViewChild em classe com implements (contrato exige a prop) → prop!: T
    • tipo complexo sem decorator e sem ngOnInit → prop: T | undefined
  • TS2769 — callback de .subscribe() com parâmetro tipado → remove a anotação de tipo do parâmetro
  • TS2345 — this.prop (T[] | undefined) passado como argumento → this.prop ?? []
  • Usos de this.prop.X → this.prop?.X após a propriedade virar | undefined
  • .find() sem null-check → ?. nos acessos subsequentes
  • getElementById()/querySelector() → ?.method()
  • Template $event.target.value → $any($event.target).value
  • HTML: propriedade que virou | undefined com 2+ bindings na mesma linha → envolve o elemento em @if (prop) { ... }; binding único → ?.

Parâmetros:

{
  "projectPath": "/caminho/absoluto/do/projeto",
  "confirmed": true
}

Saída: lista de arquivos modificados + as correções com risco de falso positivo gravadas em STRICT-REVIEW.md na raiz do projeto.


Relatório de Upgrade (UPGRADE-REPORT.md)

Cada tool MCP grava automaticamente uma seção em UPGRADE-REPORT.md na raiz do projeto do cliente. O arquivo é criado pela start-upgrade e incrementado pelas tools subsequentes.

Estrutura do relatório

O relatório contém:

  • Cabeçalho — projeto, diretório e data de geração
  • Resumo da Migração (topo) — bloco inserido ao final do fluxo, com tempo total gasto, arquivos Angular Components modificados e arquivos PrimeNG migrados
  • Uma seção por tool — status (✅/❌/⚠️), duração, detalhes, avisos e erros
  • Seção rica de migração — para v18-migrate-angular-components, inclui métricas (incluindo separação AC vs PrimeNG e o total de divergências confirmadas pela prova real), distribuição de warnings, um <details> por componente migrado, e — quando a "prova real" encontra um resíduo confirmado para um claim declarado — uma subseção "⚠️ Divergências encontradas pela prova real" listando arquivo e mensagem
  • Aviso de strict mode desativado — a v18-fix-tsconfig registra no relatório que strict: false é temporário e orienta como ativar gradualmente

Extensibilidade para produtos

Tools de produto terceiro podem escrever no mesmo relatório usando appendToolSection de src/tools/report-writer.ts:

import { appendToolSection } from "./report-writer.js";

appendToolSection(projectPath, {
  toolName: "migrate-produto-x-components",
  displayName: "Migração Produto X — entry-points",
  status: "success",
  responsible: "Equipe Produto X",
  startTime: t0,
  endTime: Date.now(),
  details: ["42 entry-points convertidos"],
  warnings: [],
  errors: [],
  customMarkdown: buildProductComponentDetails(results),
});

O campo responsible aparece como atribuição de equipe na seção — cada tool declara o seu.


Motor de migração

O engine em src/migration/ é completamente genérico — não tem nenhuma referência a angular-components ou primeng. Ele recebe um MigrationConfig e um customRulesRegistry e sabe como aplicar qualquer conjunto de regras.

Interface principal

migrateAngularComponent(
  tsSource: string,
  htmlSource: string,
  context: MigrationContext,        // árvores parseadas (tree-sitter)
  config: MigrationConfig,          // regras da lib (entry-points + externalRules)
  customRulesRegistry: Record<string, CustomRule>,  // regras AST customizadas
): MigrationResult  // { ts, html, warnings }

MigrationConfig

interface MigrationConfig {
  sourceModule: string; // ex: '@seniorsistemas/angular-components'
  entryPoints: EntryPointDefinition[]; // componentes com entry-point específico
  externalRules?: ComponentDefinition[]; // componentes de libs externas (PrimeNG)
}

CustomRule

Função que recebe o contexto completo (AST do TS + AST do HTML) e retorna edits indexados:

type CustomRule = (ctx: CustomRuleContext) => CustomRuleResult;

interface CustomRuleResult {
  tsEdits: TextEdit[];
  htmlEdits: TextEdit[];
  warnings: Warning[];
}

As edits são aplicadas em ordem decrescente de startIndex para não deslocar posições.

Motor de verificação ("prova real")

Migrar sem quebrar a sintaxe não é o mesmo que migrar corretamente. Depois que migrateAngularComponent produz o TS/HTML migrado, src/migration/verification.ts reparseia esse resultado do zero e confere, para cada padrão antigo catalogado (attributeRenames, propertyRenames, selectorReplacement, attributeRemovals, importPathMigration, typeMigration), se ele realmente desapareceu — e se o padrão novo esperado apareceu no lugar.

O princípio central é independência: este módulo nunca importa a lógica de transformação do ts-migrator.ts/html-migrator.ts/custom rules para decidir onde procurar. Ele usa sua própria lógica de matching (tree-sitter + regex de segurança), deliberadamente separada — assim, um bug de matching na migração não se propaga silenciosamente para a verificação, o que evitaria detectar um arquivo que "passou" mas continua com o padrão antigo.

Cada achado (VerificationFinding) tem duas camadas de confiança:

  • Camada 1 — confirmed: query tree-sitter escopada à tag/seletor resultante (AST).
  • Camada 2 — needs-review: rede de segurança por regex sobre o texto (comentários/strings mascarados), ativada só quando a Camada 1 não confirma nada mas há sinal independente (ex: import do componente) de que ele está em jogo no arquivo.

Regras puramente declarativas (as quatro acima, definidas em rules.manual.ts) são cobertas automaticamente pelo motor genérico — nenhum código extra é necessário ao adicionar uma.

Toda customRule nova (registrada em custom-rules/registry.ts) precisa de um verificador correspondente com a mesma chave em custom-rules/verify-registry.ts (exportado em acCustomRuleVerifiers/primengCustomRuleVerifiers), também escrito sem importar a customRule que verifica. Sem isso, test/custom-rules-verify.test.ts tem um teste de paridade que falha propositalmente — mesmo espírito de "fail loud" do merge.ts.

Tanto o "Migrar Projeto" do playground quanto a tool MCP v18-migrate-angular-components rodam essa verificação após cada migração. O playground expõe os achados numa aba própria ("Prova real"); a tool MCP usa achados confirmed de resíduo/possible-silent-removal pra contestar (em vez de afirmar incondicionalmente) claims de "alteração aplicada" na seção rica do UPGRADE-REPORT.md — ver seção "Relatório de Upgrade" acima.

Como o angular-components usa o engine

  1. merge.ts lê rules.generated.v18.json (inventário auto-scan) + rules.manual.ts (renames manuais) e produz o MigrationConfig.
  2. custom-rules/registry.ts mapeia nomes de regra ('accordion-switch-manual') para funções.
  3. A tool MCP combina AC config + PrimeNG config e os dois registries antes de chamar o engine.

Performance: cache de discoverProjectInheritance e memoização de índices por config

O "Migrar Projeto" do playground chama o engine uma vez por arquivo do projeto (via HTTP, num processo Express single-thread e síncrono). Sem cuidado, isso faria com que trabalho que só depende do projeto como um todo — não do arquivo sendo migrado — fosse recalculado do zero a cada arquivo:

  • discoverProjectInheritance (src/migration/inheritance-discovery.ts) varre e reparseia com tree-sitter todos os .ts do projeto pra descobrir componentes que extends uma classe conhecida da lib. Chamar isso a cada arquivo custa O(N arquivos migrados × M arquivos do projeto) — em projetos com centenas/milhares de arquivos, isso é a causa raiz de requests de /migrate//migrate-ts-only levando dezenas de segundos.
  • buildClassIndex/typeMigByName (ts-migrator.ts) e a lista allComponents (verification.ts) são reconstruídos a partir do mesmo MigrationConfig a cada chamada.

Por isso:

  • discoverProjectInheritanceCached(projectDir, config) cacheia o resultado por (config, projectDir). A invalidação é automática: uma assinatura barata (contagem + path + mtime/size de cada .ts, via stat, sem ler conteúdo) é recalculada a cada chamada — se qualquer arquivo do projeto mudar, o cache é invalidado e o resultado recomputado é idêntico ao que se teria sem cache. discoverProjectInheritance (não-cacheada) continua existindo e é o que a tool MCP v18-migrate-angular-components usa (ela já só chama uma vez por run, antes do loop de arquivos — não sofre desse problema).
  • playground/api/app.ts também cacheia por projectDir o objeto config aumentado (config base + externalRules descobertas), reusando a mesma referência entre requests do mesmo projeto — isso é o que permite buildRuleIndexes (ts-migrator.ts) e getAllComponents (verification.ts) memoizarem por identidade de config (WeakMap) sem nenhuma mudança de contrato HTTP.

Auto-scan (npm run scan)

Precisa da env var ANGULAR_COMPONENTS_SRC apontando para o repositório do angular-components. Se ela não estiver definida, scripts/ensure-angular-components-src.sh (encadeado antes do scan no próprio npm run scan) clona automaticamente senior-sistemas/snr-angular-components (privado — requer acesso via gh/git já autenticado) em _angular-components/ na raiz do projeto e exporta a variável, sem passo manual:

npm run scan

Pra apontar pra um checkout próprio em vez de deixar o auto-clone rodar:

# Linux/macOS
export ANGULAR_COMPONENTS_SRC=/caminho/para/angular-components
npm run scan
# Windows (PowerShell)
$env:ANGULAR_COMPONENTS_SRC = "C:\caminho\para\angular-components"
npm run scan

Depois de resolvida a env var, o script cria um git worktree temporário na branch configurada em scripts/scan.config.ts, extrai classNames/selectors/inputs/outputs via tree-sitter e grava src/migration-angular-components-v18/rules.generated.v18.json.


API Express (playground)

API de debug que expõe o mesmo engine do MCP via HTTP.

npm run start:api
# http://localhost:3001

| Endpoint | Descrição | | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | | GET /health | Status + versão do parser | | GET /config | Config de migração carregada (AC + PrimeNG combinados) | | POST /migrate | { ts, html } → { ts, html, warnings, verification, crossFileImportRequests } | | POST /migrate-ts-only | { ts } → { code, warnings, verification } — espelha o pipeline TS-only da tool MCP (services/módulos/pipes/guards, sem HTML) | | POST /project/resolve-cross-file-imports | { projectPath, requests } → resolve, pra cada crossFileImportRequest, qual *.module.ts declara o componente (read-only, nunca escreve) | | POST /project/migration-report | { projectPath, files } → { markdown } — mesma seção rica (collectComponentSummaries/buildMigrationCustomMarkdown) que a tool MCP escreveria em UPGRADE-REPORT.md, sempre em modo dry-run (o playground nunca escreve) | | GET /project?path=abs | Árvore de arquivos de um projeto | | POST /project/check-syntax | { ts, html } → detecta erro de sintaxe via tree-sitter (hasError/contagem de nós ERROR) | | POST /project/verify-cross-file | Roda a "prova real" para regras cross-file (que afetam um arquivo diferente do par migrado, ex: setTranslation( → providePrimeNG) | | GET /search?q=termo[&path=abs] | Busca texto nos arquivos do angular-components | | GET /project/file?path=abs&file=rel | Lê um arquivo do projeto | | POST /analyze-dependencies | { projectPath, confirmOverrides? } → análise de deps vs Angular 18 | | POST /senior-libs-check | { projectPath } → analisa libs @seniorsistemas/* com update disponível (contraparte web de v18-update-senior-libs) | | POST /strict-analyze | { ts, html, fileName? } → detecta erros strict sem aplicar (TS2564, EventTarget, .find()) | | POST /strict-fix | { ts, html, fileName? } → { ts, html, issues } aplica as correções strict | | POST /runtime-fix | { ts, fileName? } → { ts, issues } aplica fixes de runtime (toPromise, moment, RouterEvent, HttpClient return types) | | POST /prettier-format | { ts, html, fileName?, projectDir? } → formata o resultado via Prettier (contraparte web de run-prettier) | | GET /project/branches?path=abs | Branches git ordenadas por commit mais recente | | POST /project/checkout | { path, branch } → checkout de branch |

A env var ANGULAR_COMPONENTS_SRC é opcional — se ausente, a API sobe usando apenas rules.generated.v18.json (sem busca no código-fonte da lib).


Playground Angular

Frontend com Monaco Editor para testar a migração interativamente.

npm run start:playground   # sobe API + frontend juntos
npm run start:frontend     # só o Angular (porta 4200)
npm run start:api          # só a API Express (porta 3001)

Funcionalidades:

  • Modo upload: arraste .ts/.html e veja o resultado da migração lado a lado
  • Modo project: aponte para um caminho absoluto, navegue na árvore e migre arquivo a arquivo ou em lote ("Migrar Projeto")
  • Branch selector: lista branches git do projeto ordenadas pela mais recente; ao trocar a branch o projeto é recarregado automaticamente
  • Migrar Projeto (lote): processa todo .ts do projeto (não só .component.ts — services/módulos/pipes/guards vão pelo pipeline TS-only via /migrate-ts-only, igual a tool MCP), checa sintaxe, roda a "prova real" pós-migração e análise strict (/strict-analyze) em paralelo
  • Batch report: filtros por erros, warnings, inputs removidos, achados de verificação (confirmed/needs-review, incluindo preview de imports de NgModule pendentes) e strict issues (TS2564, EventTarget, .find())
  • Aba "Relatório MCP": mostra a mesma seção rica que a tool MCP escreveria em UPGRADE-REPORT.md (reaproveita collectComponentSummaries/buildMigrationCustomMarkdown do servidor), renderizada como markdown de verdade via ngx-markdown (sanitizado por padrão via DomSanitizer) — é a forma de conferir, sem rodar a tool MCP de verdade, que o relatório não vai afirmar algo que a "prova real" contradiz
  • Analisar Deps: verifica compatibilidade de dependências com Angular 18
  • Runtime Fix: aplica fixes de runtime (toPromise, moment, RouterEvent, HttpClient return types) no resultado da migração atual
  • Prettier: formata o resultado da migração via /prettier-format
  • Senior Libs Check: lista libs @seniorsistemas/* com versão mais nova disponível via ng update
  • Busca por arquivo (Ctrl+E) e busca por conteúdo (Ctrl+Shift+F) no projeto carregado

Scripts

| Script | Descrição | | -------------------------- | --------------------------------------------------------------------- | | npm start | Compila e sobe o MCP server (build + node dist/index.js) | | npm run build | Compila o MCP server (TypeScript → dist/) | | npm run update:grammars | Atualiza as gramáticas tree-sitter (.wasm) usadas pelo parser | | npm run dev | MCP server em modo watch (tsx) | | npm run start:mcp | Sobe o MCP server compilado | | npm run start:api | Sobe a API Express (playground) | | npm run start:frontend | Sobe o Angular playground | | npm run start:playground | Sobe API + Angular juntos | | npm run scan | Regenera rules.generated.v18.json (clona snr-angular-components automaticamente se ANGULAR_COMPONENTS_SRC não estiver definida) | | npm test | Roda todos os testes (vitest) | | npm run test:watch | Testes em modo watch | | npm run inspector | Abre o MCP Inspector para testar as tools manualmente | | npm run dryrun:local | Liga o dry-run local (env-debug.json), espera você testar via prompt e desliga sozinho (trap EXIT) | | npm run dryrun:on / dryrun:off | Liga/desliga manualmente o dry-run local (expira sozinho em 1h) | | npm run prepublishOnly | Rodado automaticamente antes de npm publish: install + scan + build |


Testes

577 testes (28 arquivos) cobrindo:

| Arquivo | O que testa | | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | html-migrator.test.ts | Renames de atributos, seletor de atributo, attributeRemovals, sCalendarMask, herança, fixStrayGt, balance check, limite de tag sensível a aspas em applyComponentTransforms (> literal num atributo anterior não corta attributeRemovals cedo demais) | | ts-migrator.test.ts | Import split, propertyRenames, typeMigration, importPathMigration, herança, deduplicação de @NgModule arrays, remoção de @Injectable() com parâmetros não-injetáveis (Tier 1/2, incluindo resolução via node_modules), memoização de classIndex/typeMigByName por referência de config (buildRuleIndexes) sem vazar estado entre arquivos | | merge.test.ts | Merge JSON + manual, validação de renames, externalRules | | integration.test.ts | Fluxo completo com rules.generated.v18.json real | | custom-rules.test.ts | Todas as 21 regras customizadas (8 AC + 13 PrimeNG), incluindo lazyLoadLookup→onCompleteMethod e showDialog→async showDialog | | custom-rules-verify.test.ts | Paridade customRule ↔ verificador em verify-registry.ts (AC e PrimeNG); regressão do gap p-footer/p-header fora de <p-dialog>; regressão do falso positivo de pTemplate em componente não relacionado (ex: <p-table>) na regra p-tabView-to-s-tabs | | verification.test.ts | Motor genérico da "prova real" pós-migração (verifyMigration): camada AST confirmed + camada textual needs-review; memoização de allComponents por referência de config (getAllComponents) sem vazar findings entre arquivos | | migrate-angular-components.test.ts | Relatório da tool MCP verificado contra a prova real (collectComponentSummaries/describeComponentChanges/buildMigrationCustomMarkdown não afirmam remoção/rename quando há resíduo confirmed, e não contaminam claims de outros atributos) + E2E do handler completo em diretório descartável (dryRun: false grava e não afirma remoção que não aconteceu; dryRun: true não escreve nada e a seção rica aparece na resposta de texto) | | ts-entry-classification.test.ts | classifyTsEntries — exclusão de .d.ts/.spec.ts, pareamento com .html presente/ausente, paths absolutos/relativos — módulo puro compartilhado entre walkTsFiles (backend) e o playground | | playground-migration-parity.test.ts | Trava contra divergência futura entre a tool MCP e o playground: mesmo pareamento de arquivo, mesmo conjunto de arquivos modificados e tipos de warning por arquivo, e que /project/migration-report reusa collectComponentSummaries/buildMigrationCustomMarkdown do servidor | | env-debug.test.ts | isLocalDryRunEnabled — arquivo ausente/JSON inválido/dryRun falsy/activatedAt expirado → false; só true com flag recente | | scan-signals.test.ts | Extração de inputs/outputs via tree-sitter (decorators + signal API) | | extract-rules-worktree.test.ts | Resolução de branch/ref do git worktree usado pelo npm run scan | | lib-paths.test.ts | Resolução do ANGULAR_COMPONENTS_SRC em diferentes formatos | | fix-strict-ts.test.ts | Fixes strict mode estáticos (TS2564, TS2769, TS2345, primitivos, implements, ngOnInit→!), fixes de runtime (RouterEvent, HttpClient return types, toPromise tree-sitter, new Subject() sem generic, import * as X de package.json, dasherize de flags @angular/cli em scripts .js) | | fix-strict.test.ts | Fixes pontuais adicionais: acesso encadeado em parâmetro opcional, argumentos de parâmetro parcial, import * as moment_ → import moment | | fix-tsconfig.test.ts | Normalização de compilerOptions.module desatualizado (es2015/commonjs/etc. → es2022) em todo tsconfig*.json do projeto | | restore-package-json.test.ts | Merge de deps, ngx-mask, rxjs 6→7, pacotes removidos | | analyze-dependencies.test.ts | Análise de compatibilidade de dependências com Angular 18 | | inheritance-discovery.test.ts | Descoberta de herança entre componentes; discoverProjectInheritanceCached — cache hit devolve mesma referência, invalidação automática quando o projeto muda, paridade com a versão não-cacheada, isolamento por config | | module-declarations.test.ts | Descoberta de declarations de @NgModule e aplicação de imports cross-file | | eol.test.ts | Detecção/conversão de fim de linha (CRLF/LF) e preservação durante a migração | | npm-install.test.ts | Parsing/iteração do npm install | | migrate-eslint.test.ts | Elicitation do selectorPrefix na migração TSLint → ESLint | | run-prettier.test.ts | Instalação/config do Prettier, descoberta e formatação de arquivos, formatSource (reutilizada pelo playground) | | update-senior-libs.test.ts | Resolução de versão instalada/major mais recente estável, descoberta de update via npm registry para libs @seniorsistemas/*, diff de peerDependencies novas (diffNewPeerDeps) e reconciliação Senior-para-Senior pós-schematics | | primeng-config.test.ts | Conversão de PrimengManualEntry.selector → ComponentDefinition.selectors | | upgrade-shared.test.ts | Utilitários compartilhados do fluxo de upgrade |

npm test

Extensibilidade

A arquitetura foi projetada para adicionar novas libs sem tocar no engine.

Adicionar uma nova lib (ex: migration-platform-components-v18/)

  1. Criar src/migration-platform-components-v18/ com:
    • rules.manual.ts — entradas de rename/seletor/importPath
    • config.ts — constrói MigrationConfig a partir das regras manuais
    • custom-rules/registry.ts + arquivos de regras customizadas (se necessário)
  2. Em src/tools/v18/migrate-angular-components.ts, combinar o novo config e registry junto com os existentes.
  3. Zero alteração no engine src/migration/.

O engine não sabe nada sobre nenhuma lib específica — ele só executa o que o MigrationConfig e o customRulesRegistry descrevem.


Usando o engine em outro projeto

⚠️ Experimental — esta abordagem não foi testada com repositórios externos, mas é exatamente o mesmo mecanismo que o migration-angular-components-v18 e o migration-primeng-v18 usam internamente.

O engine em src/migration/ é completamente genérico. Para usá-lo com uma lib de terceiros:

1. Descrever as regras de migração

Crie um MigrationConfig descrevendo os componentes da lib:

import type { MigrationConfig } from "./src/migration/rules";

const myLibConfig: MigrationConfig = {
  sourceModule: "@minha-empresa/minha-lib",
  entryPoints: [
    {
      path: "button", // entry-point: @minha-empresa/minha-lib/button
      components: [
        {
          classNames: ["ButtonComponent"],
          selectors: ["ml-button"],
          propertyRenames: { onClick: "clicked" },
          attributeRenames: { "(onClick)": "(clicked)" },
        },
      ],
    },
  ],
  externalRules: [
    // componentes sem entry-point dedicado (ex: dependências de outras libs)
  ],
};

2. Regras customizadas (opcional)

Para transformações estruturais que vão além de renames simples, implemente a interface CustomRule:

import type { CustomRule } from "./src/migration/custom-rules/types";

const myRule: CustomRule = (ctx) => {
  // ctx.tsSource, ctx.htmlSource — código original
  // ctx.tsTree, ctx.tsLang     — AST TypeScript (tree-sitter)
  // ctx.htmlTree, ctx.htmlLang — AST Angular HTML (tree-sitter)
  // ctx.component              — ComponentDefinition que ativou esta regra
  return {
    tsEdits: [], // TextEdit[] aplicados no .ts
    htmlEdits: [], // TextEdit[] aplicados no .html
    warnings: [], // Warning[] reportados ao usuário
  };
};

3. Rodar a migração

import {
  parseTypeScript,
  parseAngularHtml,
} from "./src/migration/parser-adapter";
import { migrateAngularComponent } from "./src/migration";

const tsParsed = parseTypeScript(tsSource);
const htmlParsed = parseAngularHtml(htmlSource);

const result = migrateAngularComponent(
  tsSource,
  htmlSource,
  { ts: tsParsed, html: htmlParsed },
  myLibConfig,
  { "my-custom-rule": myRule },
);

console.log(result.ts); // TypeScript migrado
console.log(result.html); // HTML migrado
console.log(result.warnings); // Avisos para revisão manual