yiki/compile.js

115 lines
4.2 KiB
JavaScript

// Copyright (c) 2024 yellows111
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
// local
const Package = require("./package.json");
// npm
const Remarkable = require("remarkable").Remarkable; // remove .Remarkable if you're using Remarkable ^1.0.0!
const TOCGenerator = require("markdown-toc");
const RemarkableHeaderIDs = require("remarkable-header-ids");
const HTMLFormatter = require("@liquify/prettify").formatSync;
// natives
const Process = require("process");
const Filesystem = require("fs");
const Path = require("path");
if(Process.argv.length < 4 && require.main === module) {
console.error("You need a source.md and target.htm path!");
Process.exit(1);
}
function markup(input, options) {
let tableOfContents = new Remarkable().use(TOCGenerator.plugin(options)).render(input);
let output = new Remarkable().use(RemarkableHeaderIDs()).render("# Table of contents:\n"+tableOfContents.content+"\n"+input);
return output;
}
function format(data, name) {
var wikiName = "A new yiki!";
var rootPrefix = "/";
if(process.env["WIKINAME"]) {
wikiName = process.env["WIKINAME"];
}
if(process.env["VPREFIX"]) {
rootPrefix = process.env["VPREFIX"];
}
// forceIndent screws with text nodes pretty bad but the alternative is to not allow the full document to be formatted
const formatterRules = {"indentChar": "\t", "indentSize": 1, "markup": {"forceAttribute": false, "forceIndent": true}};
function render() {
return HTMLFormatter(data, formatterRules)
.split("\n") /* split by every newline */
.join("\n\t\t\t") /* then add padding and convert back into string */
.replace( /* multitag text node fix (should really just encase all text with <span>, but whatever) */
/(\t*)(<(?:code|a href=".*")>)\n\t*(.*)\n\t*(<\/(?:code|a)>)/g,
"$1$2$3$4"
)
.replace( /* multitag prefix fix for ( and [ */
/([(\[])\n\t*(<(?:code|a href=".*")>.*<\/(?:code|a)>)/g,
"$1$2"
)
.replace( /* multitag suffix fix for special characters. */
/(<\/(?:a|code)>)\n\t*([.)\];:,])/g,
"$1$2"
)
.replace( /* fix tag attached to word and not whitespace */
/(\w+)(<[a-zA-Z]\w*>)/g,
"$1 $2"
);
}
// probably should bring in a better templating engine but whatever
return ( /* eslint-disable indent */
`<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=2.0">
<meta name="description" content="${name} on ${wikiName}">
<title>${name} - Documentation</title>
<link rel="stylesheet" type="text/css" href="${rootPrefix}yiki.css">
</head>
<body>
<nav>
<span>${wikiName}</span>
<span> | </span>
<a href="${rootPrefix}index.html">home</a>
</nav>
<hr>
<main>
${render()}
</main>
<hr>
<footer>
<span>page rendered by ${Package.name} ${Package.version} on ${new Date().toGMTString()}</span>
</footer>
</body>
</html>`
); /* eslint-enable indent */
}
module.exports = {"markup": markup, "format": format};
if(require.main === module) {
let content = markup(Filesystem.readFileSync(Process.argv[2]).toString());
Filesystem.writeFileSync(Process.argv[3], format(content, Path.basename(Process.argv[3], ".html").replace(/_/g, " ")));
}