Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mapas de fontes #106

Merged
merged 10 commits into from
Jan 6, 2024
33 changes: 33 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "FolEs > Menu de Ajuda",
"skipFiles": ["<node_internals>/**", "node_modules/**"],
"cwd": "${workspaceRoot}",
"console": "integratedTerminal",
"args": [
"${workspaceFolder}${pathSeparator}execucao.ts",
"-?"
],
"runtimeExecutable": "node",
"runtimeArgs": ["--nolazy", "-r", "ts-node/register/transpile-only"]
},
{
"type": "node",
"request": "launch",
Expand All @@ -13,11 +27,27 @@
"console": "integratedTerminal",
"args": [
"${workspaceFolder}${pathSeparator}execucao.ts",
"--console",
"${workspaceFolder}${pathSeparator}exemplos${pathSeparator}exemplo.foles"
],
"runtimeExecutable": "node",
"runtimeArgs": ["--nolazy", "-r", "ts-node/register/transpile-only"]
},
{
"type": "node",
"request": "launch",
"name": "FolEs > Exemplos > exemplo.foles (com mapas)",
"skipFiles": ["<node_internals>/**", "node_modules/**"],
"cwd": "${workspaceRoot}",
"console": "integratedTerminal",
"args": [
"${workspaceFolder}${pathSeparator}execucao.ts",
"--mapas",
"${workspaceFolder}${pathSeparator}exemplos${pathSeparator}mapas-fontes${pathSeparator}exemplo.foles"
],
"runtimeExecutable": "node",
"runtimeArgs": ["--nolazy", "-r", "ts-node/register/transpile-only"]
},
{
"type": "node",
"request": "launch",
Expand All @@ -27,6 +57,7 @@
"console": "integratedTerminal",
"args": [
"${workspaceFolder}${pathSeparator}execucao.ts",
"--console",
"${workspaceFolder}${pathSeparator}exemplos${pathSeparator}exemplo2.foles"
],
"runtimeExecutable": "node",
Expand All @@ -41,6 +72,7 @@
"console": "integratedTerminal",
"args": [
"${workspaceFolder}${pathSeparator}execucao.ts",
"--console",
"${workspaceFolder}${pathSeparator}exemplos${pathSeparator}importacao.foles"
],
"runtimeExecutable": "node",
Expand All @@ -55,6 +87,7 @@
"console": "integratedTerminal",
"args": [
"${workspaceFolder}${pathSeparator}execucao.ts",
"--console",
"${workspaceFolder}${pathSeparator}exemplos${pathSeparator}reverso${pathSeparator}exemplo.css"
],
"runtimeExecutable": "node",
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -717,3 +717,11 @@ ligacao {
| [visibilidade-conteudo](https://github.com/DesignLiquido/FolEs/wiki/Modificador-visibilidade-conte%C3%BAdo) | [content-visibility](https://developer.mozilla.org/en-US/docs/Web/CSS/content-visibility) |
| [visibilidade-conteúdo](https://github.com/DesignLiquido/FolEs/wiki/Modificador-visibilidade-conte%C3%BAdo) | [content-visibility](https://developer.mozilla.org/en-US/docs/Web/CSS/content-visibility) |
| [visibilidade-fundo](https://github.com/DesignLiquido/FolEs/wiki/Modificador-visibilidade-fundo) | [backface-visibility](https://developer.mozilla.org/pt-BR/docs/Web/CSS/backface-visibility) |

# Recursos para desenvolvedores

Alguns sites são fundamentais para entender a implementação feita aqui:

- https://sokra.github.io/source-map-visualization/#custom
- https://evanw.github.io/source-map-visualization
- https://lachlan-miller.me/articles/decoding-variable-length-quantity-vlq-for-source-maps
44 changes: 34 additions & 10 deletions execucao.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Exportador } from './fontes/exportador';
import { FolEs } from './fontes/foles';
import { Command } from 'commander';

Expand All @@ -6,12 +7,23 @@ const principal = () => {
let nomeArquivo: string;

analisadorArgumentos
.helpOption('-?, --ajuda', 'Exibe a ajuda para o comando.')
.argument('[arquivos...]', 'Nomes dos arquivos (opcional)')
.option(
'-a, --aninhamento',
'Gera CSS com aninhamento. Não recomendado usar se o CSS executar em navegadores antigos.',
false
)
.option(
'-m, --mapas',
'Gera CSS com mapas de fontes.',
true
)
.option(
'-c, --console',
'Escreve a saída da tradução em console.',
null
)
.action((arquivos) => {
if (arquivos.length > 0) {
nomeArquivo = arquivos[0];
Expand All @@ -22,24 +34,36 @@ const principal = () => {
const opcoes = analisadorArgumentos.opts();

if (!nomeArquivo) {
console.error('Favor informar nome do arquivo a ser traduzido.', 70);
return;
console.error('Favor informar nome do arquivo a ser traduzido.');
process.exit(70);
}

const foles = new FolEs(opcoes.aninhamento);
let resultadoTraducao: string;

if (nomeArquivo.endsWith("foles")) {
console.log(foles.converterParaCss(nomeArquivo));
return;
}

if (nomeArquivo.endsWith("css")) {
const retorno = foles.converterParaFolEs(nomeArquivo);
console.log(retorno);
resultadoTraducao = foles.converterParaCss(nomeArquivo);
} else if (nomeArquivo.endsWith("css")) {
resultadoTraducao = foles.converterParaFolEs(nomeArquivo);
} else {
console.error("Formato de arquivo não reconhecido.");
process.exit(70);
}

if (opcoes.console) {
console.log(resultadoTraducao);
return;
}

throw new Error("Formato de arquivo não reconhecido.");
if (opcoes.mapas) {
const resultadoMapas = foles.converterParaCssComMapas(nomeArquivo);
const exportador = new Exportador();
if (nomeArquivo.endsWith('foles')) {
exportador.exportar('css', nomeArquivo, resultadoMapas[0], resultadoMapas[1]);
} else {
exportador.exportar('foles', nomeArquivo, resultadoMapas[0], resultadoMapas[1]);
}
}
}

principal();
6 changes: 6 additions & 0 deletions exemplos/mapas-fontes/exemplo.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions exemplos/mapas-fontes/exemplo.css.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions exemplos/mapas-fontes/exemplo.foles
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
lmht {
largura-borda-direita: 130mm;
}
8 changes: 8 additions & 0 deletions exemplos/mapas-fontes/exemplo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<html>
<head>
<link rel="stylesheet" href="exemplo.css">
</head>
<body>
<p>Teste</p>
</body>
</html>
File renamed without changes.
29 changes: 19 additions & 10 deletions fontes/avaliador-sintatico/avaliador-sintatico-reverso.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
import { SeletorEstruturasHtml } from "../estruturas/seletor-estruturas-html";

import tiposDeSimbolos from "../tipos-de-simbolos/css";
import { Seletor } from "../seletores";
import { Seletor, SeletorEstrutura } from "../seletores";
import { AvaliadorSintaticoInterface, ImportadorInterface } from "../interfaces";
import { HexadecimalCor } from "../valores/metodos/hexadecimal-cor";
import { Estrutura } from "../estruturas/estrutura";

export class AvaliadorSintaticoReverso implements AvaliadorSintaticoInterface {
simbolos: Simbolo[];
Expand Down Expand Up @@ -77,14 +78,17 @@
protected seletorPorEstrutura(): Seletor {
const simboloSeletor = this.avancarEDevolverAnterior();
const pseudoclasse = this.resolverPseudoclasse();
return new SeletorEstruturasHtml(
simboloSeletor.lexema,
{
linha: simboloSeletor.linha,
colunaInicial: simboloSeletor.colunaInicial,
colunaFinal: simboloSeletor.colunaFinal
}
) as Seletor;
return new SeletorEstrutura(
new SeletorEstruturasHtml(
simboloSeletor.lexema,
{
linha: simboloSeletor.linha,
colunaInicial: simboloSeletor.colunaInicial,
colunaFinal: simboloSeletor.colunaFinal
}
) as Estrutura,
pseudoclasse
);
}

protected seletorPorId(): Seletor {
Expand Down Expand Up @@ -165,7 +169,12 @@
valorModificador instanceof Simbolo ? valorModificador.lexema : valorModificador,
quantificador && quantificador.hasOwnProperty('lexema') ?
quantificador.lexema :
quantificador
quantificador,

Check warning on line 172 in fontes/avaliador-sintatico/avaliador-sintatico-reverso.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🌿 Branch is not covered

Warning! Not covered branch
{
linha: modificador.linha,
colunaInicial: modificador.colunaInicial,
colunaFinal: modificador.colunaFinal
}
);

return classeModificadora as Modificador;
Expand Down
2 changes: 1 addition & 1 deletion fontes/avaliador-sintatico/avaliador-sintatico.ts
Original file line number Diff line number Diff line change
Expand Up @@ -471,11 +471,11 @@
declaracao(): Declaracao | null {
if (this.estaNoFinal()) return null;
switch (this.simbolos[this.atual].tipo) {
case tiposDeSimbolos.IMPORTAR:
this.avancarEDevolverAnterior();
const caminhoArquivo = this.simbolos[this.atual];
const resultadoImportacao = this.importador.importar(caminhoArquivo.literal, false);
this.simbolos.splice(this.atual - 1, 2, ...resultadoImportacao.simbolos);
this.simbolos.splice(this.atual - 1, 2, ...resultadoImportacao[1].simbolos);

Check warning on line 478 in fontes/avaliador-sintatico/avaliador-sintatico.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement
this.atual -= 1;
return null;

Check warning on line 480 in fontes/avaliador-sintatico/avaliador-sintatico.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🌿 Branch is not covered

Warning! Not covered branch
default:
Expand Down
3 changes: 3 additions & 0 deletions fontes/exportador/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Exportador

A função do exportador é escrever arquivos. Por ora, este exportador fica neste projeto mesmo, mas pode ser que precisemos migrar o exportador para um projeto dedicado a Node.js, assim como foi feito com Delégua. A razão disso é que JavaScript tradicional não tem acesso a um sistema de arquivos, e execuções de FolEs em um navegador de internet têm de ser possíveis.
38 changes: 38 additions & 0 deletions fontes/exportador/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import sistemaArquivos from 'fs';

/**
* Classe que exporta traduções em diferentes formatos de arquivos. Como possui dependência
* direta com Node.js, deve ser transferida futuramente para um projeto próprio.
*/
export class Exportador {

/**
* A exportação em si. Exporta para o mesmo diretório onde está o arquivo de origem.
* @param formato O formato do arquivo traduzido.
* @param arquivoOrigem O nome do arquivo de origem.
* @param conteudo O conteúdo da tradução.
* @param mapa Um mapa de fontes, se disponível.
*/
exportar(formato: string, arquivoOrigem: string, conteudo: string, mapa?: string) {
let conteudoCompleto = conteudo;
if (mapa) {
conteudoCompleto += `\n/*# sourceMappingURL=data:application/json;base64,`;
conteudoCompleto += `${mapa} */\n`;
}

switch (formato) {
case 'css':
sistemaArquivos.writeFile(arquivoOrigem.replace('foles', 'css'), conteudoCompleto, (erro) => {
if (erro) throw erro;
});
break;
case 'foles':
sistemaArquivos.writeFile(arquivoOrigem.replace('css', 'foles'), conteudoCompleto, (erro) => {
if (erro) throw erro;
});
break;
default:
throw new Error('Formato de arquivo não reconhecido.');
}
}
}
41 changes: 31 additions & 10 deletions fontes/foles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
import { SerializadorReverso } from './serializadores/serializador-reverso';
import { Importador } from './importador';
import { ResultadoLexadorInterface, SimboloInterface } from './interfaces';
import { Tradutor } from "./tradutores/tradutor";
import { TradutorReverso } from "./tradutores/tradutor-reverso";
import { Base64 } from "./utilidades/base64";

/**
* O núcleo da linguagem FolEs.
Expand All @@ -17,8 +20,10 @@
avaliadorSintaticoReverso: AvaliadorSintaticoReverso;
importador: Importador;
importadorReverso: Importador;
tradutor: Serializador;
tradutorReverso: SerializadorReverso;
serializador: Serializador;
serializadorReverso: SerializadorReverso;
tradutor: Tradutor;
tradutorReverso: TradutorReverso;

constructor(traduzirComAninhamentos: boolean) {
this.lexador = new Lexador();
Expand All @@ -28,8 +33,10 @@
this.importadorReverso.extensaoPadrao = ".css";
this.avaliadorSintatico = new AvaliadorSintatico(this.importador);
this.avaliadorSintaticoReverso = new AvaliadorSintaticoReverso(this.importadorReverso);
this.tradutor = new Serializador(traduzirComAninhamentos);
this.tradutorReverso = new SerializadorReverso(traduzirComAninhamentos);
this.serializador = new Serializador(traduzirComAninhamentos);
this.serializadorReverso = new SerializadorReverso(traduzirComAninhamentos);
this.tradutor = new Tradutor();
this.tradutorReverso = new TradutorReverso();
}

/**
Expand All @@ -39,28 +46,42 @@
*/
private converterParaCssInterno(simbolos: SimboloInterface[]): string {
const resultadoAvaliadorSintatico = this.avaliadorSintatico.analisar(simbolos);
const traducao = this.tradutor.serializar(resultadoAvaliadorSintatico);
const traducao = this.serializador.serializar(resultadoAvaliadorSintatico);
return traducao;
}

private converterParaFolEsInterno(simbolos: SimboloInterface[]): string {
const resultadoAvaliadorSintaticoReverso = this.avaliadorSintaticoReverso.analisar(simbolos);
const traducaoReversa = this.tradutorReverso.serializar(resultadoAvaliadorSintaticoReverso);
const traducaoReversa = this.serializadorReverso.serializar(resultadoAvaliadorSintaticoReverso);
return traducaoReversa;
}

converterParaCss(nomeArquivo: string): string {
const resultadoLexador: ResultadoLexadorInterface =
const resultadoLexador: [string[], ResultadoLexadorInterface] =
this.importador.importar(nomeArquivo, true);

return this.converterParaCssInterno(resultadoLexador.simbolos);
return this.converterParaCssInterno(resultadoLexador[1].simbolos);
}

converterParaCssComMapas(nomeArquivo: string): [string, string] {

Check warning on line 66 in fontes/foles.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🕹️ Function is not covered

Warning! Not covered function
const resultadoLexador: [string[], ResultadoLexadorInterface] =
this.importador.importar(nomeArquivo, true);

Check warning on line 68 in fontes/foles.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement
const resultadoAvaliadorSintatico = this.avaliadorSintatico.analisar(resultadoLexador[1].simbolos);

Check warning on line 69 in fontes/foles.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement
const traducao = this.serializador.serializar(resultadoAvaliadorSintatico);

Check warning on line 70 in fontes/foles.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement
const resultadoTraducao = this.tradutor.traduzir(resultadoAvaliadorSintatico);

Check warning on line 71 in fontes/foles.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement
const mapa = this.tradutor.gerarMapaFontes(resultadoTraducao, resultadoLexador[0].join('\n'));

Check warning on line 72 in fontes/foles.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement

return [
traducao,
new Base64().encode(JSON.stringify(mapa))
];

Check warning on line 77 in fontes/foles.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement
}

converterParaFolEs(nomeArquivo: string): string {
const resultadoLexador: ResultadoLexadorInterface =
const resultadoLexador: [string[], ResultadoLexadorInterface] =
this.importadorReverso.importar(nomeArquivo);

return this.converterParaFolEsInterno(resultadoLexador.simbolos);
return this.converterParaFolEsInterno(resultadoLexador[1].simbolos);

Check warning on line 84 in fontes/foles.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement
}

converterTextoParaCss(texto: string): string {
Expand Down
Loading
Loading