Для работы с Markdown и HTML через Node.js используются библиотеки Remark и Rehype. Remark отвечает за разбор и трансформацию Markdown, а Rehype — за работу с HTML.
npm install remark remark-cli rehype rehype-stringify unified
remark — основной пакет для работы с Markdown.remark-cli — позволяет использовать Remark из командной
строки.rehype — библиотека для обработки HTML.rehype-stringify — сериализация дерева HTML обратно в
строку.unified — ядро для построения конвейеров обработки
текста.Обработка файлов из командной строки строится вокруг потока unified. Конвейер может включать несколько этапов: чтение файла, разбор Markdown, трансформация AST, конвертация в HTML и запись результата.
Пример базового конвейера для конвертации Markdown в HTML:
import fs from 'fs';
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
const filePath = process.argv[2];
const fileContent = fs.readFileSync(filePath, 'utf-8');
const processed = unified()
.use(remarkParse) // Разбор Markdown
.use(remarkRehype) // Преобразование в HTML AST
.use(rehypeStringify) // Сериализация в HTML
.processSync(fileContent);
console.log(String(processed));
В этом примере:
process.argv[2] — путь к файлу, передаваемому через
командную строку.remarkParse преобразует текст Markdown в AST (Abstract
Syntax Tree).remarkRehype переводит Markdown AST в HTML AST.rehypeStringify превращает HTML AST обратно в текст
HTML.Для обработки сразу нескольких файлов удобно использовать цикл и встроенные возможности Node.js:
import path from 'path';
const files = process.argv.slice(2);
files.forEach(file => {
const content = fs.readFileSync(file, 'utf-8');
const result = unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeStringify)
.processSync(content);
const outputFile = path.basename(file, '.md') + '.html';
fs.writeFileSync(outputFile, String(result));
console.log(`Файл ${outputFile} создан`);
});
process.argv.slice(2) позволяет получать все переданные
файлы.path.basename используется для генерации имени
выходного файла.fs.writeFileSync записывает результат на диск.Remark и Rehype поддерживают плагины для расширения функциональности:
Пример использования плагина для подсветки кода:
import rehypeHighlight from 'rehype-highlight';
const result = unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeHighlight)
.use(rehypeStringify)
.processSync(fileContent);
Плагины могут принимать настройки, позволяя контролировать стиль вывода и детали трансформации.
При работе с файловой системой и конвейером Remark/Rehype важно учитывать асинхронность и обработку ошибок:
import { readFile, writeFile } from 'fs/promises';
async function processFile(file) {
try {
const content = await readFile(file, 'utf-8');
const result = await unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeStringify)
.process(content);
const outputFile = file.replace(/\.md$/, '.html');
await writeFile(outputFile, String(result));
console.log(`Обработан файл: ${outputFile}`);
} catch (error) {
console.error(`Ошибка обработки файла ${file}:`, error.message);
}
}
const files = process.argv.slice(2);
files.forEach(processFile);
fs/promises позволяет работать с файлами через
async/await.try/catch.Remark и Rehype могут работать не только с полным текстом, но и со стримами, что полезно для больших файлов или потоковой обработки данных:
import { createReadStream, createWriteStream } from 'fs';
import { pipeline } from 'stream';
import { promisify } from 'util';
const pipe = promisify(pipeline);
await pipe(
createReadStream('input.md'),
unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeStringify)
.stream(),
createWriteStream('output.html')
);
Remark CLI позволяет запускать обработку файлов без написания отдельного скрипта:
npx remark input.md --output output.html --use remark-rehype --use rehype-stringify
--use подключают нужные плагины.Remark/Rehype создают AST, с которым можно работать напрямую:
import { visit } from 'unist-util-visit';
const tree = unified().use(remarkParse).parse(fileContent);
visit(tree, 'heading', node => {
node.children.push({
type: 'text',
value: ' ?'
});
});
const html = unified()
.use(remarkRehype)
.use(rehypeStringify)
.stringify(tree);
visit позволяет обходить все узлы AST.Рекомендуемая структура проекта:
project/
├─ src/
│ ├─ cli.js
│ ├─ processor.js
├─ package.json
├─ README.md
cli.js — обработка аргументов командной строки.processor.js — создание конвейеров Remark/Rehype.Эта организация позволяет гибко обрабатывать файлы Markdown, интегрировать плагины и поддерживать как синхронные, так и асинхронные сценарии работы с командной строкой.