@seniorsistemas/schematics
v1.0.0
Published
Collection de Angular Schematics da Senior Sistemas.
Readme
@seniorsistemas/schematics
Collection de Angular Schematics da Senior Sistemas. Este repositório não
contém nenhum app/lib Angular — é só o motor de schematics, publicado como pacote npm e pensado pra rodar uma vez
só, numa migração, via npx — sem instalar nada no projeto, porque isso não é uma lib de runtime que faça sentido
ficar pendurada no package.json.
npx @seniorsistemas/schematics migrate-tailwindNão sabe o nome do schematic de cor? Roda sem argumento nenhum — tem o mesmo efeito de ... list (abaixo) e abre um
menu pra escolher com as setas do teclado qual rodar:
npx @seniorsistemas/schematics(existe também um caminho via ng generate, coberto no fim do README — só relevante se você tiver um motivo
específico pra instalar a lib como devDependency temporária, por exemplo pra pinar uma versão exata num pipeline.
Nesse caminho não tem equivalente ao "roda sem argumento" acima — o ng generate exige um nome de schematic
explícito antes até de olhar pra essa collection; ng g @seniorsistemas/schematics:list é o equivalente, com o
mesmo menu de setas.)
Schematics disponíveis
list
npx @seniorsistemas/schematics list
# ou, via ng generate:
ng g @seniorsistemas/schematics:listMostra um menu (setas + Enter) com todos os outros schematics desta collection e a description de cada um, direto
do collection.json, e roda o que você escolher — sem precisar saber o nome de antemão. É pra onde
npx @seniorsistemas/schematics (sem argumento nenhum) cai por padrão. Sem terminal interativo (CI, pipe) ele não
abre o menu — só imprime a lista e não faz mais nada, pra não travar esperando uma resposta que nunca vem.
migrate-tailwind
npx @seniorsistemas/schematics migrate-tailwindReescreve classes CSS antigas — o grid legado do PrimeFaces (ui-g-*) e o PrimeFlex (p-*/sintaxe atual) — para as
classes Tailwind equivalentes na configuração da Senior (@seniorsistemas/tailwind-config),
em todo .html e .ts do projeto.
Opções:
| Opção | Descrição |
| ------------------- | ----------------------------------------------------------------------------------------------- |
| path | Pasta raiz (dentro do workspace) a escanear. Default: raiz inteira do workspace. |
| project | Nome do projeto Angular — só usado pra resolver o path padrão via angular.json. |
| skipTailwindCheck | Pula a verificação de que o projeto já tem tailwindcss + @seniorsistemas/tailwind-config configurados (ver abaixo). Default false. |
| skipImplicitGridFix | Pula a detecção/correção automática de containers de grid implícitos (ver abaixo). Default false. |
Use --dry-run primeiro pra revisar o diff proposto antes de aplicar: npx @seniorsistemas/schematics migrate-tailwind --dry-run.
Antes de rodar, o schematic confere se o projeto já tem tailwindcss e @seniorsistemas/tailwind-config no
package.json e se algum tailwind.config.(js|ts|cjs|mjs) de fato referencia a lib da Senior — sem isso, as
classes convertidas não teriam CSS correspondente e o projeto ficaria sem estilo. Se faltar algo, o schematic recusa
rodar e lista exatamente o que está faltando. Use --skip-tailwind-check só se tiver certeza do que está fazendo.
Como funciona
A migração segue a mesma cadeia de 3 estágios da ferramenta oficial do PrimeFaces/PrimeTek (primefaces-cli +
primeclt), com o último estágio adaptado pra apontar pros nossos próprios tokens Tailwind em vez dos tokens de tema
do PrimeNG:
- Grid legado do PrimeFaces → PrimeFlex 2 (
ui-g,ui-g-N,ui-{sm,md,lg,xl}-N,ui-g-offset-N,ui-g-nopad) - PrimeFlex 2 → PrimeFlex 3 (sintaxe com prefixo
p-/traço → sintaxe atual, parecida com Tailwind) - PrimeFlex 3 → Tailwind da Senior (único estágio que diverge da ferramenta oficial — aponta pros tokens de
@seniorsistemas/tailwind-configem vez dos tokens de tema do PrimeNG)
Um token que já estiver em qualquer estágio intermediário (ex. um .html que já usa col-6 em vez de ui-g-6) pula
direto pros estágios seguintes — o pipeline funciona independente da "era" das classes do projeto.
Antes dos 3 estágios, ainda tem um passo de correção de aliases mortos: algumas classes ui-* (ex. ui-fluid,
ui-state-disabled) não são utilitários de layout — são o nome antigo e morto de uma classe de componente PrimeNG
que hoje tem outro nome (p-fluid, p-disabled). Essas são renomeadas de verdade no arquivo (não convertidas pra
Tailwind — é uma correção de nome legado, baseada em ~80 pares confirmados comparando as branches do tema real da
Senior nas versões v9 e v18 do PrimeNG — ver THIRD_PARTY_NOTICES.md).
O motor reconhece 4 formas de atributo/binding: class="...", styleClass="...", [class.x]="condição" e
[ngClass]="..."/[class]="..." (objeto, array, string ou ternário) — nos 3 últimos, só o nome da classe é tocado,
a condição/expressão ao redor nunca é alterada.
Regra de ouro: nenhuma classe que pareça PrimeFlex/PrimeFaces (p-*/ui-*, ou uma classe PrimeFlex 3 "pura" tipo
surface-500) desaparece em silêncio. Toda classe encontrada termina de um jeito:
- Convertida pro Tailwind final (ou renomeada de um alias morto) — nada é reportado, o arquivo já está correto.
p-fluid/ui-fluidsão um exemplo: convertem direto praw-full, porque confirmamos no tema real da Senior (v18) que o único efeito geral de.p-fluidhoje éwidth: 100%nele mesmo — não existe mais cascata pra filho nenhuma (isso mudou entre v9 e v18, verTHIRD_PARTY_NOTICES.md). - Mantida + reportada em
MIGRATE-TAILWIND-REPORT.md(criado na raiz do projeto), agrupada em 4 categorias:- Classes de componente PrimeNG mantidas — ex.
p-button,p-inputtext. Não são utilitários de layout, são a API visual do próprio componente PrimeNG — não têm equivalente em Tailwind sem quebrar comportamento. Ficam assim até a migração pra@seniorsistemas/angular-components. - Componentes removidos ou nunca migrados — ex.
ui-datagrid,ui-widget,ui-inputswitch. Confirmadas como mortas nas duas versões do PrimeNG pesquisadas (v9 e v18) — não têm substituto real, então não são renomeadas pra uma formap-*inventada. O motivo no relatório é diferente do anterior: não é "espera a migração futura", é "isso já não faz nada, questione se o markup ainda é necessário". - Cores/tema pendentes de decisão — ex.
surface-500,bg-primary,bluegray-*. A paleta da Senior usa nomes de token completamente diferentes; qual token usar no lugar é uma decisão de design, não automatizável. - Classes não reconhecidas — parecem PrimeFlex/PrimeFaces (prefixo
p-/ui-) mas não bateram em nenhuma regra conhecida. É a rede de segurança: melhor aparecer aqui pra alguém investigar do que sumir sem rastro.
- Classes de componente PrimeNG mantidas — ex.
Veja THIRD_PARTY_NOTICES.md pra saber o que foi adaptado de qual ferramenta oficial (e de onde veio a tabela de
aliases/componentes removidos).
Containers de grid implícitos (float → CSS Grid)
Renomear classe por classe não basta pra preservar o layout, porque o grid legado do PrimeFaces/PrimeNG v9 é feito
com float: left e o Tailwind usa CSS Grid — e os dois têm exigências diferentes sobre o elemento pai.
Float não exige nada do pai: um .ui-g-6 flutua e quebra linha sozinho dentro de qualquer container. Por isso este
markup é válido e funciona em produção hoje, com o div do meio sem a classe ui-g:
<div class="ui-g">
<div class="ui-g-12">
<div class="ui-g-6 ui-md-3 ui-sm-12">campo</div>
<!-- +5 campos iguais -->
</div>
</div>Já col-span-N (grid-column: span N) só tem efeito se o pai direto for display: grid. Uma conversão puramente
token-a-token daria col-span-12 ao div do meio e nada mais — ele não viraria grid container, e os 6 filhos
empilhariam em coluna única. Foi exatamente isso que aconteceu numa tela real ao migrar.
Pra isso o schematic faz um passo extra só nos .html: parseia a árvore de elementos de verdade
(htmlparser2) e procura elementos que eram container "implícito" no mundo do
float — isto é, têm filhos que são item de grid legado, mas nunca tiveram uma classe de container (ui-g e afins).
Neles é injetado o token grid, que os 3 estágios normais expandem pra grid grid-cols-12 gap-4.
Virar display: grid também afeta os filhos que não são item de grid: sob o float antigo eles eram um bloco
comum e ocupavam 100% da largura; num grid CSS eles virariam item auto-posicionado em 1 das 12 colunas, encolhendo
pra ~8%. Foi exatamente esse efeito colateral que causou uma regressão real em produção (uma tela com *ngFor e
dois <s-empty-state> sem classe, que encolheram depois da migração). Por isso cada um desses filhos recebe
col-span-12, pra manter a largura cheia que tinha antes. Cada correção de container fica registrada na seção
Containers de grid implícitos corrigidos automaticamente, e cada col-span-12 injetado num filho fica na seção
Filhos de containers de grid implícitos corrigidos automaticamente com col-span-12 — ambas com arquivo:linha; não
é um erro pendente, é pra você entender no diff por que uma classe nova apareceu num elemento que originalmente não
tinha ui-g/col-span-*.
Filhos mistos (uns são item de grid legado, outros não) deixaram de ser um caso ambíguo: o col-span-12
injetado no filho que não é item de grid resolve a mesma incerteza que antes obrigava revisão manual, então esse
caso agora é corrigido automaticamente em vez de só reportado. Os casos que continuam ambíguos e só são
reportados como revisar manualmente, sem nenhuma correção às cegas, são os que dependem de informação que o
schematic não tem estaticamente: tag de componente (<p-panel>, onde os filhos escritos ali são projetados pra
dentro do template do componente e o pai DOM real pode ser outro), classe de grid vinda só de styleClass (mesmo
problema — o pai DOM real dos filhos aqui escritos pode não ser este elemento), e elementos que só têm
[ngClass]/[class] dinâmico (não dá pra confirmar estaticamente se ele já é ou não um container de grid).
Uma outra combinação de filhos continua fora do escopo desta correção automática, por ser um problema diferente:
elementos cujos filhos são só classe moderna (col-*, p-col-*) e nenhum item legado — essas classes
sempre exigiram um pai flex/grid, então um pai faltando aí já estava quebrado antes desta migração, não é regressão
introduzida por ela, e "consertar" mudaria um layout que ninguém pediu pra mudar. Esse caso (diferente do de filhos
mistos com item legado, que agora É corrigido — ver acima) continua virando só entrada de revisão.
Limitações conhecidas
- A conversão de
p-fluid/ui-fluidpraw-fullnão preserva dois efeitos secundários bem específicos que encontramos no tema real da Senior:.p-fluid { s-button button { width: 100%; } }(botão dentro do wrapper<s-button>da Senior fica full-width) e.p-fluid .ui-inputgroup input { min-width: 0; }(input em grupo perde omin-width). São gambiarras específicas de uma migração anterior de v9 pra v18, não comportamento oficial do PrimeNG — avaliado que não vale a pena complicar a conversão geral pra preservar esses dois casos raros. styleClassatribuído como propriedade de objeto em.tspuro (ex.{ label: 'Salvar', styleClass: 'ui-g-12' }, comum em itens de menu/breadcrumb montados dinamicamente fora de um template) não é tocado — é a única exceção deliberada à regra de ouro. O schematic só reconhecestyleClass="..."(atributo/binding de template), nãostyleClass: '...'(propriedade de objeto TypeScript, usa:em vez de=).- Interpolação de template literal dentro de
[ngClass]/[class](ex.`ui-g-${size}`) não é convertida — o token resultante não bate em nenhuma regra (não é só dígitos) e cai como "não reconhecida" no relatório, nunca é mal-convertida. - A tabela de aliases (
known-component-aliases.json) não é exaustiva pra 100% dos componentes PrimeNG — cobre só os ~80 pares com evidência forte encontrados na pesquisa (verTHIRD_PARTY_NOTICES.md). Um par de baixa confiança ou não pesquisado cai na rede de segurança ("não reconhecida") em vez de ser inventado. - Uma classe do dicionário pode colidir com uma classe própria do projeto de mesmo nome. Isso é uma consequência
do PrimeFlex 3 usar nomes de utilitário genéricos (sem prefixo
p-/ui-) parecidos com o próprio Tailwind — ex.grid,gap-3,flex. Na verificação end-to-end contra um projeto real encontramos exatamente esse caso: o projeto define.gap-3 { gap: 12px }à mão nostyles.scss(coincidindo com o valor real do Tailwindgap-3), e o schematic converteu pragap-4(assumindo a escala não-linear do PrimeFlex, ondegap-3= 1rem) — uma mudança visual real de 12px pra 16px nesse caso específico. Sempre revise o diff antes de commitar, prestando atenção especial emgap-*/p-*/m-*se o projeto tiver utilitários customizados com nomes parecidos. - Classes com relação seletor pai>filho do PrimeFlex (ex.
.field > label) ficam fora de escopo — exigiriam reescrever CSS/SCSS, não só classes em HTML/TS. - Rodar o schematic duas vezes no mesmo projeto corrompe o resultado. A conversão não distingue "arquivo legado"
de "arquivo já migrado", e alguns nomes existem nos dois mundos com significados diferentes —
gap-4do PrimeFlex vale 1.5rem e viragap-6no Tailwind, então umgap-4que já é Tailwind seria convertido de novo;gridtambém re-expande. Rode uma vez só, a partir de um working tree limpo, e revise o diff. Se precisar rodar de novo, façagit revert/git checkoutdo resultado anterior antes. - A detecção de container de grid implícito não roda em templates inline (
template: \...`dentro de um.ts). Eles têm hierarquia real e sofrem do mesmo problema, mas por ora só a conversão token-a-token se aplica ali — arquivos.htmlexternos (templateUrl`) têm cobertura completa. - A semântica dos breakpoints não é invertida. Os prefixos do grid legado (
ui-sm-*,ui-md-*) eram desktop-first (max-width) no PrimeNG antigo, enquantosm:/md:do Tailwind são mobile-first (min-width). A conversão repassa o prefixo 1:1, o que pode inverter o comportamento responsivo em telas que dependiam disso — vale conferir o resultado em telas pequenas.
Desenvolvimento
npm install
npm test # builda (pretest) e roda unit tests + teste de integração via SchematicTestRunner, uma vez só
npm run test:watch # a mesma suíte, mas em modo watch
npm run build # compila src/ -> dist/ (é o que é publicado no npm)Estrutura: cada schematic mora em src/<nome>/ (factory, schema.json, engine própria). Infraestrutura comum
(percorrer arquivos, gerar relatório) fica em src/utils/, reaproveitável por schematics futuros.
Testando localmente contra um projeto de verdade
Jeito mais rápido (roda o cli.ts deste repo direto, sem publicar nem instalar nada no projeto alvo — é o mesmo
código que o npx @seniorsistemas/schematics ... final vai executar):
npm run build
cd /caminho/do/projeto/que/voce/quer/migrar
node /caminho/do/senior-schematics/dist/cli.js migrate-tailwind --dry-runTire o --dry-run quando quiser aplicar de verdade. Pra ver a lista de schematics disponíveis sem lembrar de nomes,
roda node /caminho/do/senior-schematics/dist/cli.js sem argumento nenhum (ou ... list, é a mesma coisa).
Via ng generate (secundário — não é o jeito recomendado de uso, já que instalar a lib como dependência não faz
sentido pra uma ferramenta de migração one-shot; só existe porque vem de graça por migrate-tailwind ser um
Angular Schematic de verdade. Só use se tiver um motivo concreto pra querer a lib instalada, ex. pinar versão num
pipeline):
# no senior-schematics
npm run build
npm link
# no projeto Angular alvo (com node_modules instalado)
npm link @seniorsistemas/schematics
ng g @seniorsistemas/schematics:migrate-tailwind --dry-runPra desfazer o link depois: npm unlink @seniorsistemas/schematics no projeto alvo.
Em todos os casos, depois de rodar sem --dry-run confira o MIGRATE-TAILWIND-REPORT.md gerado na raiz do projeto.
