From 2f9353df607a2a4ca9b84adff03decfa9e8f26f3 Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Thu, 22 Jun 2023 01:16:58 +0300 Subject: [PATCH] Markdown preprocessor to compile multiple .md files into one --- docs/config/src/include.js | 145 +++++++++++++++++++++++++++++++++ docs/config/src/included.en.md | 65 +++++++++++++++ docs/config/src/included.ru.md | 65 +++++++++++++++ 3 files changed, 275 insertions(+) create mode 100755 docs/config/src/include.js create mode 100644 docs/config/src/included.en.md create mode 100644 docs/config/src/included.ru.md diff --git a/docs/config/src/include.js b/docs/config/src/include.js new file mode 100755 index 00000000..4a0a2677 --- /dev/null +++ b/docs/config/src/include.js @@ -0,0 +1,145 @@ +#!/usr/bin/nodejs + +const fsp = require('fs').promises; + +run(process.argv).catch(console.error); + +async function run(argv) +{ + if (argv.length < 3) + { + console.log('Markdown preprocessor\nUSAGE: ./include.js file.md'); + return; + } + const index_file = await fsp.realpath(argv[2]); + const re = /(\{\{[\s\S]*?\}\}|\[[^\]]+\]\([^\)]+\)|(?:^|\n)#[^\n]+)/; + let text = await fsp.readFile(index_file, { encoding: 'utf-8' }); + text = text.split(re); + let included = {}; + let heading = 0, heading_name = '', m; + for (let i = 0; i < text.length; i++) + { + if (text[i].substr(0, 2) == '{{') + { + // Inclusion + let incfile = text[i].substr(2, text[i].length-4); + let section = null; + let indent = heading; + incfile = incfile.replace(/\s*\|\s*indent\s*=\s*(-?\d+)\s*$/, (m, m1) => { indent = parseInt(m1); return ''; }); + incfile = incfile.replace(/\s*#\s*([^#]+)$/, (m, m1) => { section = m1; return ''; }); + let inc_heading = section; + incfile = rel2abs(index_file, incfile); + let inc = await fsp.readFile(incfile, { encoding: 'utf-8' }); + inc = inc.trim().replace(/^[\s\S]+?\n#/, '#'); // remove until the first header + inc = inc.split(re); + const indent_str = new Array(indent+1).join('#'); + let section_start = -1, section_end = -1; + for (let j = 0; j < inc.length; j++) + { + if ((m = /^(\n?)(#+\s*)([\s\S]+)$/.exec(inc[j]))) + { + if (!inc_heading) + { + inc_heading = m[3].trim(); + } + if (section) + { + if (m[3].trim() == section) + section_start = j; + else if (section_start >= 0) + { + section_end = j; + break; + } + } + inc[j] = m[1] + indent_str + m[2] + m[3]; + } + else if ((m = /^(\[[^\]]+\]\()([^\)]+)(\))$/.exec(inc[j])) && !/^https?:(\/\/)|^#/.exec(m[2])) + { + const abs_m2 = rel2abs(incfile, m[2]); + const rel_m = abs2rel(__filename, abs_m2); + if (rel_m.substr(0, 9) == '../../../') // outside docs + inc[j] = m[1] + 'https://git.yourcmc.ru/vitalif/vitastor/src/branch/master/'+rel2abs('docs/config/src/include.js', rel_m) + m[3]; + else + inc[j] = m[1] + abs_m2 + m[3]; + } + } + if (section) + { + inc = section_start >= 0 ? inc.slice(section_start, section_end < 0 ? inc.length : section_end) : []; + } + if (inc.length) + { + if (!inc_heading) + inc_heading = heading_name||''; + included[incfile+(section ? '#'+section : '')] = '#'+inc_heading.toLowerCase().replace(/\P{L}+/ug, '-').replace(/^-|-$/g, ''); + inc[0] = inc[0].replace(/^\s+/, ''); + inc[inc.length-1] = inc[inc.length-1].replace(/\s+$/, ''); + } + text.splice(i, 1, ...inc); + i = i + inc.length - 1; + } + else if ((m = /^\n?(#+)\s*([\s\S]+)$/.exec(text[i]))) + { + // Heading + heading = m[1].length; + heading_name = m[2].trim(); + } + } + for (let i = 0; i < text.length; i++) + { + if ((m = /^(\[[^\]]+\]\()([^\)]+)(\))$/.exec(text[i])) && !/^https?:(\/\/)|^#/.exec(m[2])) + { + const p = m[2].indexOf('#'); + if (included[m[2]]) + { + text[i] = m[1]+included[m[2]]+m[3]; + } + else if (p >= 0 && included[m[2].substr(0, p)]) + { + text[i] = m[1]+m[2].substr(p)+m[3]; + } + } + } + console.log(text.join('')); +} + +function rel2abs(ref, rel) +{ + rel = [ ...ref.replace(/^(.*)\/[^\/]+$/, '$1').split(/\/+/), ...rel.split(/\/+/) ]; + return killdots(rel).join('/'); +} + +function abs2rel(ref, abs) +{ + ref = ref.split(/\/+/); + abs = abs.split(/\/+/); + while (ref.length > 1 && ref[0] == abs[0]) + { + ref.shift(); + abs.shift(); + } + for (let i = 1; i < ref.length; i++) + { + abs.unshift('..'); + } + return killdots(abs).join('/'); +} + +function killdots(rel) +{ + for (let i = 0; i < rel.length; i++) + { + if (rel[i] == '.') + { + rel.splice(i, 1); + i--; + } + else if (i >= 1 && rel[i] == '..' && rel[i-1] != '..') + { + rel.splice(i-1, 2); + i -= 2; + } + } + return rel; +} diff --git a/docs/config/src/included.en.md b/docs/config/src/included.en.md new file mode 100644 index 00000000..3a8b8954 --- /dev/null +++ b/docs/config/src/included.en.md @@ -0,0 +1,65 @@ +# Vitastor + +{{../../../README.md#The Idea}} + +{{../../../README.md#Talks and presentations}} + +{{../../intro/features.en.md}} + +{{../../intro/quickstart.en.md}} + +{{../../intro/architecture.en.md}} + +## Installation + +{{../../installation/packages.en.md}} + +{{../../installation/proxmox.en.md}} + +{{../../installation/openstack.en.md}} + +{{../../installation/kubernetes.en.md}} + +{{../../installation/source.en.md}} + +{{../../config.en.md|indent=1}} + +{{../../config/common.en.md|indent=2}} + +{{../../config/network.en.md|indent=2}} + +{{../../config/layout-cluster.en.md|indent=2}} + +{{../../config/layout-osd.en.md|indent=2}} + +{{../../config/osd.en.md|indent=2}} + +{{../../config/monitor.en.md|indent=2}} + +{{../../config/pool.en.md|indent=2}} + +{{../../config/inode.en.md|indent=2}} + +## Usage + +{{../../usage/cli.en.md}} + +{{../../usage/disk.en.md}} + +{{../../usage/fio.en.md}} + +{{../../usage/nbd.en.md}} + +{{../../usage/qemu.en.md}} + +{{../../usage/nfs.en.md}} + +## Performance + +{{../../performance/understanding.en.md}} + +{{../../performance/theoretical.en.md}} + +{{../../performance/comparison1.en.md}} + +{{../../intro/author.en.md|indent=1}} diff --git a/docs/config/src/included.ru.md b/docs/config/src/included.ru.md new file mode 100644 index 00000000..457fd2e9 --- /dev/null +++ b/docs/config/src/included.ru.md @@ -0,0 +1,65 @@ +# Vitastor + +{{../../../README-ru.md#Идея|indent=0}} + +{{../../../README-ru.md#Презентации и записи докладов|indent=0}} + +{{../../intro/features.ru.md}} + +{{../../intro/quickstart.ru.md}} + +{{../../intro/architecture.ru.md}} + +## Установка + +{{../../installation/packages.ru.md}} + +{{../../installation/proxmox.ru.md}} + +{{../../installation/openstack.ru.md}} + +{{../../installation/kubernetes.ru.md}} + +{{../../installation/source.ru.md}} + +{{../../config.ru.md|indent=1}} + +{{../../config/common.ru.md|indent=2}} + +{{../../config/network.ru.md|indent=2}} + +{{../../config/layout-cluster.ru.md|indent=2}} + +{{../../config/layout-osd.ru.md|indent=2}} + +{{../../config/osd.ru.md|indent=2}} + +{{../../config/monitor.ru.md|indent=2}} + +{{../../config/pool.ru.md|indent=2}} + +{{../../config/inode.ru.md|indent=2}} + +## Использование + +{{../../usage/cli.ru.md}} + +{{../../usage/disk.ru.md}} + +{{../../usage/fio.ru.md}} + +{{../../usage/nbd.ru.md}} + +{{../../usage/qemu.ru.md}} + +{{../../usage/nfs.ru.md}} + +## Производительность + +{{../../performance/understanding.ru.md}} + +{{../../performance/theoretical.ru.md}} + +{{../../performance/comparison1.ru.md}} + +{{../../intro/author.ru.md|indent=1}}