@designliquido/delegua
Version:
Linguagem de programação simples e moderna usando português estruturado.
248 lines • 9.84 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EstilizadorDelegua = void 0;
const formatadores_1 = require("../formatadores");
const quebrador_linha_1 = require("./quebrador-linha");
/**
* Estilizador de código para Delégua.
* Aplica transformações no AST para enforcar convenções e melhorar qualidade do código.
*/
class EstilizadorDelegua {
constructor(regras = []) {
this.regras = regras;
this.violacoes = [];
this.modoValidacao = false;
}
adicionarRegra(regra) {
this.regras.push(regra);
}
removerRegra(nomeRegra) {
this.regras = this.regras.filter((r) => r.nome !== nomeRegra);
}
/**
* Aplica as regras de estilização recursivamente em uma declaração.
* @param declaracao A declaração a ser estilizada.
* @returns A declaração estilizada.
*/
estilizarDeclaracao(declaracao) {
let declaracaoAtual = declaracao;
// Aplica regras de declaração
for (const regra of this.regras) {
if (regra.aplicarEmDeclaracao) {
if (this.modoValidacao) {
// Em modo validação, clona a declaração antes de aplicar
const declaracaoClonada = this.clonarDeclaracao(declaracaoAtual);
const declaracaoModificada = regra.aplicarEmDeclaracao(declaracaoClonada);
// Verifica se houve mudança
if (this.declaracaoFoiModificada(declaracaoAtual, declaracaoModificada)) {
this.violacoes.push({
regra: regra.nome,
mensagem: `${regra.descricao}`,
linha: declaracao.linha,
hashArquivo: declaracao.hashArquivo,
severidade: 'aviso',
});
}
}
else {
// Em modo normal, aplica a transformação
declaracaoAtual = regra.aplicarEmDeclaracao(declaracaoAtual);
}
}
}
// Recursivamente estiliza construtos dentro da declaração
if (!this.modoValidacao) {
this.estilizarCamposDeclaracao(declaracaoAtual);
}
return declaracaoAtual;
}
/**
* Verifica se uma declaração foi modificada comparando propriedades relevantes.
*/
declaracaoFoiModificada(original, modificada) {
// Compara lexema do símbolo (para nomes)
if (original.simbolo && modificada.simbolo) {
if (original.simbolo.lexema !== modificada.simbolo.lexema) {
return true;
}
}
// Compara tipo
if (original.tipo !== modificada.tipo) {
return true;
}
// Compara tipoExplicito
if (original.tipoExplicito !== modificada.tipoExplicito) {
return true;
}
return false;
}
/**
* Clona uma declaração de forma superficial.
*/
clonarDeclaracao(declaracao) {
// Cria um novo objeto com o mesmo protótipo
const clone = Object.create(Object.getPrototypeOf(declaracao));
// Copia todas as propriedades
for (const chave in declaracao) {
if (declaracao.hasOwnProperty(chave)) {
// Para objetos aninhados, clona também
if (typeof declaracao[chave] === 'object' && declaracao[chave] !== null) {
if (Array.isArray(declaracao[chave])) {
clone[chave] = [...declaracao[chave]];
}
else {
clone[chave] = { ...declaracao[chave] };
}
}
else {
clone[chave] = declaracao[chave];
}
}
}
return clone;
}
/**
* Estiliza construtos dentro de uma declaração.
* @param declaracao A declaração cujos campos serão estilizados.
*/
estilizarCamposDeclaracao(declaracao) {
// Itera sobre as propriedades da declaração
for (const chave in declaracao) {
if (!declaracao.hasOwnProperty(chave))
continue;
const valor = declaracao[chave];
// Se é um construto, estiliza
if (valor && typeof valor === 'object' && 'aceitar' in valor) {
if (this.ehConstruto(valor)) {
declaracao[chave] = this.estilizarConstruto(valor);
}
}
// Se é um array, estiliza cada elemento
if (Array.isArray(valor)) {
for (let i = 0; i < valor.length; i++) {
if (this.ehDeclaracao(valor[i])) {
valor[i] = this.estilizarDeclaracao(valor[i]);
}
else if (this.ehConstruto(valor[i])) {
valor[i] = this.estilizarConstruto(valor[i]);
}
}
}
}
}
/**
* Aplica as regras de estilização em um construto.
* @param construto O construto a ser estilizado.
* @returns O construto estilizado.
*/
estilizarConstruto(construto) {
let construtoAtual = construto;
// Aplica regras de construto
for (const regra of this.regras) {
if (regra.aplicarEmConstruto) {
if (this.modoValidacao) {
// Em modo validação, não modifica, apenas verifica
const construtoOriginal = JSON.stringify(construtoAtual);
const construtoModificado = regra.aplicarEmConstruto(construtoAtual);
if (JSON.stringify(construtoModificado) !== construtoOriginal) {
this.violacoes.push({
regra: regra.nome,
mensagem: `${regra.descricao} não foi aplicada`,
linha: construto.linha || 0,
hashArquivo: -1,
severidade: 'aviso',
});
}
}
else {
construtoAtual = regra.aplicarEmConstruto(construtoAtual);
}
}
}
// Recursivamente estiliza campos do construto
this.estilizarCamposConstruto(construtoAtual);
return construtoAtual;
}
/**
* Estiliza campos dentro de um construto.
* @param construto O construto cujos campos serão estilizados.
*/
estilizarCamposConstruto(construto) {
for (const chave in construto) {
if (!construto.hasOwnProperty(chave))
continue;
const valor = construto[chave];
if (valor && typeof valor === 'object' && 'aceitar' in valor) {
if (this.ehConstruto(valor)) {
construto[chave] = this.estilizarConstruto(valor);
}
else if (this.ehDeclaracao(valor)) {
construto[chave] = this.estilizarDeclaracao(valor);
}
}
if (Array.isArray(valor)) {
for (let i = 0; i < valor.length; i++) {
if (this.ehDeclaracao(valor[i])) {
valor[i] = this.estilizarDeclaracao(valor[i]);
}
else if (this.ehConstruto(valor[i])) {
valor[i] = this.estilizarConstruto(valor[i]);
}
}
}
}
}
/**
* Verifica se um objeto é uma Declaração.
*/
ehDeclaracao(obj) {
return (obj &&
typeof obj === 'object' &&
'paraTexto' in obj &&
'linha' in obj &&
'hashArquivo' in obj);
}
/**
* Verifica se um objeto é um Construto.
*/
ehConstruto(obj) {
return obj && typeof obj === 'object' && 'aceitar' in obj && !('paraTexto' in obj);
}
estilizar(declaracoes) {
this.modoValidacao = false;
this.violacoes = [];
const declaracoesEstilizadas = [];
for (const declaracao of declaracoes) {
declaracoesEstilizadas.push(this.estilizarDeclaracao(declaracao));
}
return declaracoesEstilizadas;
}
validar(declaracoes) {
this.modoValidacao = true;
this.violacoes = [];
// Aplica estilização em modo validação (não modifica, apenas detecta violações)
for (const declaracao of declaracoes) {
this.estilizarDeclaracao(declaracao);
}
const violacoesEncontradas = [...this.violacoes];
this.violacoes = [];
this.modoValidacao = false;
return violacoesEncontradas;
}
estilizarEFormatar(declaracoes, opcoesFormatacao = {}) {
const declaracoesEstilizadas = this.estilizar(declaracoes);
const separadorLinha = opcoesFormatacao.quebraLinha || '\n';
const tamanhoIndentacao = opcoesFormatacao.tamanhoIndentacao ?? 4;
const formatador = new formatadores_1.FormatadorDelegua(separadorLinha, tamanhoIndentacao, {
delimitadorTexto: opcoesFormatacao.delimitadorTexto,
});
let codigo = formatador.formatar(declaracoesEstilizadas);
if (opcoesFormatacao.maximoCaracteresPorLinha !== undefined) {
const quebrador = new quebrador_linha_1.QuebradorDeLinha(opcoesFormatacao.maximoCaracteresPorLinha, tamanhoIndentacao, separadorLinha);
codigo = quebrador.quebrar(codigo);
}
return codigo;
}
}
exports.EstilizadorDelegua = EstilizadorDelegua;
//# sourceMappingURL=estilizador-delegua.js.map