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

@designliquido/lmht-js

v0.6.1

Published

Biblioteca de transformação de documentos LMHT para HTML em JavaScript

Readme

lmht-js

Biblioteca de transformação de documentos LMHT para HTML, para JavaScript e TypeScript.

Formas de uso

Versão 0.6.0 ou superiores — fluxo Lexador → Avaliador Sintático → Tradutor

A partir da versão 0.6.0 é possível usar cada etapa da pipeline de transformação diretamente, o que permite inspecionar tokens e a árvore sintática (AST) antes de gerar o HTML.

import { LexadorLmht, AvaliadorSintaticoLmht, TradutorHtml } from "@designliquido/lmht-js";

const lexador = new LexadorLmht();
const avaliadorSintatico = new AvaliadorSintaticoLmht();
const tradutor = new TradutorHtml();

const codigo = `<lmht><cabeca><titulo>Teste</titulo></cabeca><corpo>Olá, mundo!</corpo></lmht>`;

// 1. Lexar: transforma o texto em tokens
const retornoLexador = lexador.mapear(codigo);

// 2. Analisar: transforma os tokens em uma árvore sintática
const retornoAvaliador = avaliadorSintatico.analisar(retornoLexador.tokens);

// 3. Traduzir: transforma a árvore sintática em HTML
const html = tradutor.traduzir(retornoAvaliador.arvore);
console.log(html);
// Resultado:
// <!DOCTYPE html>
// <html>
//   <head>
//     <title>Teste</title>
//   </head>
//   <body>Olá, mundo!</body>
// </html>

O TradutorHtml aceita opções de formatação e também permite verificar erros de cada etapa:

import { LexadorLmht, AvaliadorSintaticoLmht, TradutorHtml } from "@designliquido/lmht-js";

const tradutor = new TradutorHtml({
    identacao: 4,                // Número de espaços por nível de identação (padrão: 2)
    usarTabulacao: false,        // Usar tabulação em vez de espaços (padrão: false)
    formatarSaida: true,         // Formatar a saída com quebras de linha (padrão: true)
    preservarComentarios: true,  // Preservar comentários na saída HTML (padrão: false)
    incluirDeclaracaoXml: false, // Incluir declaração <?xml ...?> (padrão: false)
    incluirDocType: true,        // Incluir <!DOCTYPE html> (padrão: true)
});

const lexador = new LexadorLmht();
const avaliadorSintatico = new AvaliadorSintaticoLmht();

const codigo = `<lmht><cabeca><titulo>Teste</titulo></cabeca><corpo>Olá, mundo!</corpo></lmht>`;

const { tokens, erros: errosLexador } = lexador.mapear(codigo);
const { arvore, erros: errosAvaliador } = avaliadorSintatico.analisar(tokens);

if (errosLexador.length > 0 || errosAvaliador.length > 0) {
    console.error("Erros:", [...errosLexador, ...errosAvaliador]);
} else {
    console.log(tradutor.traduzir(arvore));
}

Versão 0.5.0 ou superiores

Até esta versão, apenas os métodos de conversão usando transformação XSLT estavam disponíveis. Entre as opções de conversão, há converterPorArquivo e converterPorTexto, ambos para LMHT e HTML. Os métodos de conversão são assíncronos, e retornam uma Promise que resolve para o resultado da conversão.

Exemplos de LMHT para HTML

import { ConversorLmht } from "@designliquido/lmht-js";

const conversorLmht = new ConversorLmht();
// Ou
const resultado = await conversorLmht.converterPorArquivo("meu-arquivo.lmht");
console.log(resultado);

// Ou
conversorLmht.converterPorArquivo("meu-arquivo.lmht").then(resultado => {
    console.log(resultado);
});
import { ConversorLmht } from "@designliquido/lmht-js";

const conversorLmht = new ConversorLmht();
// Ou
const resultado = await conversorLmht.converterPorTexto("<lmht><cabeca><titulo>Teste</titulo></cabeca><corpo>Teste</corpo></lmht>");
console.log(resultado); // Resultado: <html><head><title>Teste</title></head><body>Teste</body></html>

// Ou
conversorLmht.converterPorTexto("<lmht><cabeca><titulo>Teste</titulo></cabeca><corpo>Teste</corpo></lmht>").then(resultado => {
    console.log(resultado); // Resultado: <html><head><title>Teste</title></head><body>Teste</body></html>
});

Exemplos de HTML para LMHT

import { ConversorHtml } from "@designliquido/lmht-js";

const conversorHtml = new ConversorHtml();
// Ou
const resultado = await conversorHtml.converterPorArquivo("meu-arquivo.html");
console.log(resultado);

// Ou
conversorHtml.converterPorArquivo("meu-arquivo.html").then(resultado => {
    console.log(resultado);
});
import { ConversorHtml } from "@designliquido/lmht-js";

const conversorHtml = new ConversorHtml();
// Ou
const resultado = await conversorHtml.converterPorTexto("<html><head><title>Teste</title></head><body>Teste</body></html>");
console.log(resultado); // Resultado: <lmht><cabeca><titulo>Teste</titulo></cabeca><corpo>Teste</corpo></lmht>

// Ou
conversorHtml.converterPorTexto("<html><head><title>Teste</title></head><body>Teste</body></html>").then(resultado => {
    console.log(resultado); // Resultado: <lmht><cabeca><titulo>Teste</titulo></cabeca><corpo>Teste</corpo></lmht>
});

Versão 0.3.0 até versão 0.4.9

Os métodos de conversão são os mesmos, mas são síncronos:

import { ConversorLmht } from "@designliquido/lmht-js";

const conversorLmht = new ConversorLmht();
const resultado = conversorLmht.converterPorArquivo("meu-arquivo.lmht");
console.log(resultado);
import { ConversorLmht } from "@designliquido/lmht-js";

const conversorLmht = new ConversorLmht();
const resultado = conversorLmht.converterPorTexto("<lmht><cabeca><titulo>Teste</titulo></cabeca><corpo>Teste</corpo></lmht>");
console.log(resultado); // Resultado: <html><head><title>Teste</title></head><body>Teste</body></html>
import { ConversorHtml } from "@designliquido/lmht-js";

const conversorHtml = new ConversorHtml();
const resultado = conversorHtml.converterPorArquivo("meu-arquivo.html");
console.log(resultado);
import { ConversorHtml } from "@designliquido/lmht-js";

const conversorHtml = new ConversorHtml();
const resultado = conversorHtml.converterPorTexto("<html><head><title>Teste</title></head><body>Teste</body></html>");
console.log(resultado); // Resultado: <lmht><cabeca><titulo>Teste</titulo></cabeca><corpo>Teste</corpo></lmht>

Até a versão 0.2.0

Os métodos de conversão são assíncronos.

import { ConversorLmht } from "@designliquido/lmht-js";

const conversorLmht = new ConversorLmht();
conversorLmht.converterPorArquivo("meu-arquivo.lmht").then(resultado => {
    console.log(resultado);
});
import { ConversorHtml } from "@designliquido/lmht-js";

const conversorHtml = new ConversorHtml();
conversorHtml.converterPorArquivo("meu-arquivo.lmht").then(resultado => {
    console.log(resultado);
});

Conformidade com especificação

lmht-js segue a especificação mais recente de LMHT. O projeto da especificação é referenciado aqui como um submódulo git. Para sincronizar a especificação, use o comando:

git submodule update --init --recursive --remote

Versões 0.3.0 até 0.4.9, usando xslt-processor, e mudanças na versão 0.5.0

Na versão 0.3.0, tomamos a decisão de mudar para a biblioteca xslt-processor, 100% em código aberto, licença MIT, e mantida pela Design Líquido. Não apenas os bugs que tínhamos com a biblioteca anterior, saxon-js, são totalmente evitados como também a implementação de xslt-processor privilegia o projeto de LMHT.

Isso fez com que os métodos se tornassem síncronos. Depois da versão 3.0.0 de xslt-processor, em que o comando <xsl:include> foi implementado, o processamento de transformações XSLT passou a ser novamente assíncrono. O comando <xsl:include> exige um acesso a um sistema de arquivos ou um recurso na internet, o que pede para que todo o processo seja assíncrono. Para esta biblioteca, os comandos de conversão voltam a ser assíncronos na versão 0.5.0.

Versão 0.2.0 e saxon-js

Até a versão 0.2.0, usávamos a biblioteca saxon-js. Essa biblioteca tornou-se um problema por alguns motivos:

  • Documentação incompleta, em inglês e de baixa qualidade: https://www.saxonica.com/saxon-js/documentation2/index.html;
  • Apesar de ter uma licença gratuita, os fontes não são abertos;
  • Escrita em JavaScript puro e tipagem fraca, além de ter uma parte compilada em C;
  • Não funciona se usada em uma extensão do Visual Studio Code, que em teoria é Node.js, mas algo acontece ao importarmos a dependência e um erro estranho aparece.

Mantemos o suporte a versões anteriores por questões de retrocompatibilidade.

Especificação e arquivos .sef.json

saxon-js pede por arquivos .sef.json, que podem ser gerados pelos comandos abaixo:

PowerShell:

xslt3 -t "-xsl:especificacao/lmht.xslt" "-export:lmht.sef.json" -nogo -relocate
xslt3 -t "-xsl:especificacao/lmht-reverso-xml10.xslt" "-export:lmht-reverso-xml10.sef.json" -nogo -relocate

bash, zsh:

xslt3 -t -xsl:especificacao/lmht.xslt -export:lmht.sef.json -nogo -relocate
xslt3 -t -xsl:especificacao/lmht-reverso.xslt -export:lmht-reverso.sef.json -nogo -relocate

O arquivo XSLT da especificação ou da especificação reversa também podem ser usados, mas isso causa um atraso na carga de pelo menos 2 segundos por arquivo, que é o tempo que leva para compilar a especificação de XSLT para .sef.json. Para entender como isso funciona, verifique o fonte objeto-especificacao.ts.

Assim sendo, os arquivos .sef.json correspondentes ao commit apontado pelo submódulo são versionados neste diretório raiz, e distribuídos juntamente com o pacote NPM.

Compatibilidade com XML

SaxonJS não trabalha com XML 1.1, e por isso a especificação com XML 1.0 é usada aqui.