wikity 1.3.7 → 1.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +11 -4
- package/dist/common.js +2 -1
- package/dist/compile.js +13 -6
- package/dist/parse.js +11 -6
- package/dist/src/cli.d.ts +1 -0
- package/dist/src/cli.js +64 -0
- package/dist/src/common.d.ts +20 -0
- package/dist/src/common.js +6 -0
- package/dist/src/compile.d.ts +3 -0
- package/dist/src/compile.js +140 -0
- package/dist/src/index.d.ts +11 -0
- package/dist/src/index.js +11 -0
- package/dist/src/parse.d.ts +3 -0
- package/dist/src/parse.js +416 -0
- package/dist/src/wiki.css.d.ts +2 -0
- package/dist/src/wiki.css.js +36 -0
- package/package.json +4 -3
package/dist/cli.js
CHANGED
|
@@ -30,15 +30,22 @@ else if (arg(1).includes('c')) {
|
|
|
30
30
|
// Run compilation
|
|
31
31
|
const configArgs = args.slice(2);
|
|
32
32
|
const argsList = configArgs.join(' ');
|
|
33
|
-
//
|
|
34
|
-
const getArgContent = (
|
|
33
|
+
// Retrieve item from arguments list
|
|
34
|
+
const getArgContent = (match) => {
|
|
35
|
+
var _a;
|
|
36
|
+
const matchIndex = configArgs.findIndex((arg) => match.test(arg));
|
|
37
|
+
if (matchIndex === -1) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
return (_a = configArgs[matchIndex + 1]) !== null && _a !== void 0 ? _a : '';
|
|
41
|
+
};
|
|
35
42
|
// Fetch user-supplied arguments
|
|
36
43
|
const folder = arg(2) || '.';
|
|
37
44
|
const outputFolder = getArgContent(/^-+o/);
|
|
38
45
|
const templatesFolder = getArgContent(/^-+t/);
|
|
39
46
|
const imagesFolder = getArgContent(/^-+i/);
|
|
40
|
-
const eleventy = /^-+e
|
|
41
|
-
const defaultStyles = /^-+d
|
|
47
|
+
const eleventy = getArgContent(/^-+e/) !== undefined;
|
|
48
|
+
const defaultStyles = getArgContent(/^-+d/) !== undefined;
|
|
42
49
|
index_1.default.compile(folder, { outputFolder, templatesFolder, imagesFolder, eleventy, defaultStyles });
|
|
43
50
|
}
|
|
44
51
|
else if (arg(1).includes('p')) {
|
package/dist/common.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RegExpBuilder =
|
|
3
|
+
exports.RegExpBuilder = void 0;
|
|
4
4
|
function RegExpBuilder(regex, flag = 'mgi') {
|
|
5
5
|
return RegExp(regex.replace(/ /g, '').replace(/\|\|.+?\|\|/g, ''), flag);
|
|
6
6
|
}
|
|
7
|
+
exports.RegExpBuilder = RegExpBuilder;
|
package/dist/compile.js
CHANGED
|
@@ -3,17 +3,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.eleventyCompile =
|
|
7
|
-
|
|
6
|
+
exports.compile = exports.eleventyCompile = void 0;
|
|
7
|
+
const dedent_1 = __importDefault(require("dedent"));
|
|
8
8
|
const fs_1 = __importDefault(require("fs"));
|
|
9
|
-
const path_1 = __importDefault(require("path"));
|
|
10
9
|
const glob_1 = __importDefault(require("glob"));
|
|
11
|
-
const
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
12
11
|
const parse_1 = require("./parse");
|
|
13
12
|
const wiki_css_1 = __importDefault(require("./wiki.css"));
|
|
14
13
|
function eleventyCompile(dir = '.', config = {}) {
|
|
15
14
|
compile(dir, { eleventy: true, ...config });
|
|
16
15
|
}
|
|
16
|
+
exports.eleventyCompile = eleventyCompile;
|
|
17
17
|
function compile(dir = '.', config = {}) {
|
|
18
18
|
var _a, _b, _c;
|
|
19
19
|
// set defaults
|
|
@@ -83,7 +83,11 @@ function compile(dir = '.', config = {}) {
|
|
|
83
83
|
// Create plaintext of HTML for use as description/metadata property.
|
|
84
84
|
const plaintextData = parsedContent.replace(/<.+?>/gs, '');
|
|
85
85
|
// Create HTML
|
|
86
|
-
|
|
86
|
+
let folderUpCount = file.split(/[\/\\]/).length - dir.split(/[\/\\]/).length; // number of folders to go up by to get to root
|
|
87
|
+
if (!config.eleventy) {
|
|
88
|
+
// Regular mode puts both wiki.css and the root files in the root folder
|
|
89
|
+
folderUpCount--;
|
|
90
|
+
}
|
|
87
91
|
const html = (0, dedent_1.default) `
|
|
88
92
|
<html>
|
|
89
93
|
<head>
|
|
@@ -91,7 +95,9 @@ function compile(dir = '.', config = {}) {
|
|
|
91
95
|
<meta name="viewport" content="initial-scale=1.0, width=device-width">
|
|
92
96
|
<meta name="description" content="${plaintextData.substring(0, 256)}...">
|
|
93
97
|
<title>${displayTitle}</title>
|
|
98
|
+
${config.defaultStyles ? `
|
|
94
99
|
<link id="default-styles" rel="stylesheet" href="${'../'.repeat(folderUpCount)}./wiki.css">
|
|
100
|
+
` : ''}
|
|
95
101
|
</head>
|
|
96
102
|
<body>
|
|
97
103
|
<header>
|
|
@@ -123,7 +129,7 @@ function compile(dir = '.', config = {}) {
|
|
|
123
129
|
;
|
|
124
130
|
});
|
|
125
131
|
// Create site styles
|
|
126
|
-
if (!stylesCreated) {
|
|
132
|
+
if (!stylesCreated && (config.defaultStyles !== false || config.customStyles)) {
|
|
127
133
|
stylesCreated = true;
|
|
128
134
|
let styles = '';
|
|
129
135
|
if (config.defaultStyles !== false) {
|
|
@@ -138,3 +144,4 @@ function compile(dir = '.', config = {}) {
|
|
|
138
144
|
}
|
|
139
145
|
});
|
|
140
146
|
}
|
|
147
|
+
exports.compile = compile;
|
package/dist/parse.js
CHANGED
|
@@ -3,11 +3,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.rawParse =
|
|
7
|
-
|
|
6
|
+
exports.parse = exports.rawParse = void 0;
|
|
7
|
+
const dateformat_1 = __importDefault(require("dateformat"));
|
|
8
8
|
const fs_1 = __importDefault(require("fs"));
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
|
-
const dateformat_1 = __importDefault(require("dateformat"));
|
|
11
10
|
const common_1 = require("./common");
|
|
12
11
|
const r = String.raw;
|
|
13
12
|
const MAX_RECURSION = 20;
|
|
@@ -35,12 +34,12 @@ const escaper = (text, n = 0) => `%${text}#${n}`;
|
|
|
35
34
|
function rawParse(data, config = {}) {
|
|
36
35
|
return parse(data, config).data;
|
|
37
36
|
}
|
|
37
|
+
exports.rawParse = rawParse;
|
|
38
38
|
function parse(data, config = {}) {
|
|
39
|
-
var _a, _b
|
|
39
|
+
var _a, _b;
|
|
40
40
|
const KEY = Math.random().toString().slice(2); // key used to allow certain disallowed HTML elements
|
|
41
41
|
const templatesFolder = (_a = config.templatesFolder) !== null && _a !== void 0 ? _a : 'templates';
|
|
42
42
|
const imagesFolder = (_b = config.imagesFolder) !== null && _b !== void 0 ? _b : 'images';
|
|
43
|
-
const outputFolder = (_c = config.outputFolder) !== null && _c !== void 0 ? _c : 'wikity-out';
|
|
44
43
|
const vars = {};
|
|
45
44
|
const metadata = {};
|
|
46
45
|
const nowikis = [];
|
|
@@ -53,8 +52,11 @@ function parse(data, config = {}) {
|
|
|
53
52
|
break;
|
|
54
53
|
last = outText;
|
|
55
54
|
outText = outText
|
|
55
|
+
// Passthrough unparsed content
|
|
56
56
|
// Nowiki: <nowiki></nowiki>
|
|
57
57
|
.replace((0, common_1.RegExpBuilder)(r `<nowiki> ([^]+?) </nowiki>`), (_, m) => (nowikis.push(m), escaper('NOWIKI', nowikiCount++)))
|
|
58
|
+
// Pre: <pre></pre>
|
|
59
|
+
.replace((0, common_1.RegExpBuilder)(r `<pre> ([^]+?) </pre>`), (_, m) => (nowikis.push(m), escaper('PRE', nowikiCount++)))
|
|
58
60
|
// Sanitise unacceptable HTML
|
|
59
61
|
.replace((0, common_1.RegExpBuilder)(r `< \s* (?= (?: script|link|meta|iframe|frameset|object|embed|applet|form|input|button|textarea ) (?! \s* key.{0,10}${KEY}) )`), '<')
|
|
60
62
|
.replace((0, common_1.RegExpBuilder)(r `(?<= <[^>]+ ) (\bon(\w+))`), 'data-$2')
|
|
@@ -382,7 +384,9 @@ function parse(data, config = {}) {
|
|
|
382
384
|
for (let i = 0; i < nowikis.length; i++) {
|
|
383
385
|
outText = outText
|
|
384
386
|
// Restore nowiki contents
|
|
385
|
-
.replace(escaper('NOWIKI', i), nowikis[i])
|
|
387
|
+
.replace(escaper('NOWIKI', i), nowikis[i])
|
|
388
|
+
// Restore pre contents
|
|
389
|
+
.replace(escaper('PRE', i), '<pre>' + nowikis[i] + '</pre>');
|
|
386
390
|
}
|
|
387
391
|
outText = outText
|
|
388
392
|
// References: <references />
|
|
@@ -414,3 +418,4 @@ function parse(data, config = {}) {
|
|
|
414
418
|
const result = { data: outText, metadata: metadata };
|
|
415
419
|
return result;
|
|
416
420
|
}
|
|
421
|
+
exports.parse = parse;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/src/cli.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const VERSION = require('../package.json').version;
|
|
7
|
+
const index_1 = __importDefault(require("./index"));
|
|
8
|
+
// Helper functions
|
|
9
|
+
const indent = (n) => ' '.repeat(n * 4);
|
|
10
|
+
const usage = (command, ...desc) => {
|
|
11
|
+
console.log('\n' + indent(2) + command);
|
|
12
|
+
desc.forEach((msg) => console.log(indent(2.5) + msg));
|
|
13
|
+
};
|
|
14
|
+
const arg = (n) => process.argv[n + 1] || '';
|
|
15
|
+
const args = process.argv.slice(1);
|
|
16
|
+
// Run CLI
|
|
17
|
+
if (!arg(1)) {
|
|
18
|
+
// No arguments
|
|
19
|
+
console.log('Type `wikity help` for a list of commands.');
|
|
20
|
+
}
|
|
21
|
+
else if (arg(1).includes('h')) {
|
|
22
|
+
// Show help message
|
|
23
|
+
console.log(`\n${indent(1)}Wikity CLI commands:`);
|
|
24
|
+
usage(`wikity (help|-h)`, `Display this help message.`);
|
|
25
|
+
usage(`wikity compile [<folder>] [-o <folder>] [-t <folder>] -i <folder>] [-e] [-d]`, `Compile wikitext files from a given folder.`, ` [<folder>]\n${indent(3.5)}Input folder ('.' (current folder) if unset).`, ` (-o|--outputFolder) <folder>\n${indent(3.5)}Folder that compiled HTML files are placed in ('wikity-out' if unset).`, ` (-t|--templatesFolder) <folder>\n${indent(3.5)}Where to place wiki templates ('templates' if unset).`, ` (-i|--imagesFolder) <folder>\n${indent(3.5)}Where to place wiki images ('images' if unset).`, ` (-e|--eleventy)\n${indent(3.5)}Compiles files with Eleventy front matter (false if unset).`, ` (-d|--defaultStyles)\n${indent(3.5)}Add default wiki styling to all pages (true if unset).`);
|
|
26
|
+
usage(`wikity (parse|-p) "<input>"`, `Parse raw wikitext from the command line.`);
|
|
27
|
+
usage(`wikity (version|-v)`, `Display the current version of Wikity.`);
|
|
28
|
+
}
|
|
29
|
+
else if (arg(1).includes('c')) {
|
|
30
|
+
// Run compilation
|
|
31
|
+
const configArgs = args.slice(2);
|
|
32
|
+
const argsList = configArgs.join(' ');
|
|
33
|
+
// Retrieve item from arguments list
|
|
34
|
+
const getArgContent = (match) => {
|
|
35
|
+
const matchIndex = configArgs.findIndex((arg) => match.test(arg));
|
|
36
|
+
if (matchIndex === -1) {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
return configArgs[matchIndex + 1];
|
|
40
|
+
};
|
|
41
|
+
// Fetch user-supplied arguments
|
|
42
|
+
const folder = arg(2) || '.';
|
|
43
|
+
const outputFolder = getArgContent(/^-+o/);
|
|
44
|
+
const templatesFolder = getArgContent(/^-+t/);
|
|
45
|
+
const imagesFolder = getArgContent(/^-+i/);
|
|
46
|
+
const eleventy = /^-+e/.test(argsList);
|
|
47
|
+
const defaultStyles = /^-+d/.test(argsList);
|
|
48
|
+
index_1.default.compile(folder, { outputFolder, templatesFolder, imagesFolder, eleventy, defaultStyles });
|
|
49
|
+
}
|
|
50
|
+
else if (arg(1).includes('p')) {
|
|
51
|
+
// Run parsing
|
|
52
|
+
// second argument is inputted text
|
|
53
|
+
const input = arg(2);
|
|
54
|
+
const output = index_1.default.parse(input);
|
|
55
|
+
console.log(output);
|
|
56
|
+
}
|
|
57
|
+
else if (arg(1).includes('v')) {
|
|
58
|
+
// Show version
|
|
59
|
+
console.log('The current version of Wikity is ' + VERSION);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
// Unknown command
|
|
63
|
+
console.log('Unknown command; type `wikity help` for help');
|
|
64
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type Metadata = Record<string, any>;
|
|
2
|
+
export interface Config {
|
|
3
|
+
/** The folder that Wikity's compiled HTML files are outputted to (defaults to 'wikity-out') */
|
|
4
|
+
outputFolder?: string;
|
|
5
|
+
/** The folder that wiki templates are to be stored in relative to the root folder */
|
|
6
|
+
templatesFolder?: string;
|
|
7
|
+
/** The folder that images are to be stored in relative to the root folder */
|
|
8
|
+
imagesFolder?: string;
|
|
9
|
+
/** Whether to be set up for Eleventy integration (defaults to false) */
|
|
10
|
+
eleventy?: boolean;
|
|
11
|
+
/** Whether to use default wiki styling (defaults to true) */
|
|
12
|
+
defaultStyles?: boolean;
|
|
13
|
+
/** Custom CSS styles to add to the wiki pages */
|
|
14
|
+
customStyles?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface Result {
|
|
17
|
+
data: string;
|
|
18
|
+
metadata: Metadata;
|
|
19
|
+
}
|
|
20
|
+
export declare function RegExpBuilder(regex: string, flag?: string): RegExp;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.eleventyCompile = eleventyCompile;
|
|
7
|
+
exports.compile = compile;
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const glob_1 = __importDefault(require("glob"));
|
|
11
|
+
const dedent_1 = __importDefault(require("dedent"));
|
|
12
|
+
const parse_1 = require("./parse");
|
|
13
|
+
const wiki_css_1 = __importDefault(require("./wiki.css"));
|
|
14
|
+
function eleventyCompile(dir = '.', config = {}) {
|
|
15
|
+
compile(dir, { eleventy: true, ...config });
|
|
16
|
+
}
|
|
17
|
+
function compile(dir = '.', config = {}) {
|
|
18
|
+
var _a, _b, _c;
|
|
19
|
+
// set defaults
|
|
20
|
+
(_a = config.templatesFolder) !== null && _a !== void 0 ? _a : (config.templatesFolder = 'templates');
|
|
21
|
+
(_b = config.imagesFolder) !== null && _b !== void 0 ? _b : (config.imagesFolder = 'images');
|
|
22
|
+
(_c = config.outputFolder) !== null && _c !== void 0 ? _c : (config.outputFolder = 'wikity-out');
|
|
23
|
+
// directory variables (absolute paths)
|
|
24
|
+
const baseDir = path_1.default.resolve(dir);
|
|
25
|
+
const templatesFolder = path_1.default.join(baseDir, config.templatesFolder);
|
|
26
|
+
const imagesFolder = path_1.default.join(baseDir, config.imagesFolder);
|
|
27
|
+
const outputFolder = path_1.default.join(baseDir, config.outputFolder);
|
|
28
|
+
const outputImagesFolder = path_1.default.join(baseDir, config.outputFolder, config.imagesFolder);
|
|
29
|
+
const newConfig = { ...config, templatesFolder, imagesFolder, outputFolder };
|
|
30
|
+
let stylesCreated = false;
|
|
31
|
+
// Write wikitext files
|
|
32
|
+
const files = glob_1.default.sync(dir + "/**/*.wiki", {});
|
|
33
|
+
files.forEach((file) => {
|
|
34
|
+
var _a;
|
|
35
|
+
const fileData = fs_1.default.readFileSync(file, { encoding: 'utf8' });
|
|
36
|
+
const { data: parsedContent, metadata } = (0, parse_1.parse)(fileData, newConfig);
|
|
37
|
+
let outText = parsedContent;
|
|
38
|
+
const filename = file.replace(dir, '').replace(/^[\/\\]/, '');
|
|
39
|
+
const outFilename = filename.replace(/ /g, '_').replace('.wiki', '.html');
|
|
40
|
+
const outFilePath = path_1.default.join(outputFolder, outFilename);
|
|
41
|
+
const urlPath = outFilename.replace(/(?<=^|\/)\w/g, m => m.toUpperCase()); // capitalise first letters
|
|
42
|
+
const displayTitle = metadata.displayTitle || urlPath.replace('.html', '').replace(/_/g, ' ');
|
|
43
|
+
// Eleventy configuration
|
|
44
|
+
const frontMatter = config.eleventy ? (0, dedent_1.default) `
|
|
45
|
+
---
|
|
46
|
+
permalink: /wiki/${urlPath}
|
|
47
|
+
---
|
|
48
|
+
` : '';
|
|
49
|
+
// Create TOC
|
|
50
|
+
if (!metadata.notoc && (metadata.toc || (((_a = outText.match(/<h\d[^>]*>/g)) === null || _a === void 0 ? void 0 : _a.length) || 0) > 3)) {
|
|
51
|
+
let toc = '';
|
|
52
|
+
let headings = Array.from(parsedContent.match(/<h\d auto[^>]*>.+?<\/h\d>/gs) || []);
|
|
53
|
+
headings.forEach(match => {
|
|
54
|
+
var _a;
|
|
55
|
+
const headingInner = match.replace(/\s*<\/?h\d[^>]*>\s*/g, '');
|
|
56
|
+
const text = headingInner.replace(/<.+?>/g, ''); // remove tags from inner
|
|
57
|
+
const lvl = +(((_a = match.match(/\d/g)) === null || _a === void 0 ? void 0 : _a[0]) || -1);
|
|
58
|
+
toc += `${`<ol>`.repeat(lvl - 1)} <li> <a href="#${encodeURI(text.replace(/ /g, '_'))}">${text}</a> </li> ${`</ol>`.repeat(lvl - 1)}`;
|
|
59
|
+
});
|
|
60
|
+
toc = toc.replace(/<\/ol>\s*<ol>/g, '');
|
|
61
|
+
const tocElem = (0, dedent_1.default) `
|
|
62
|
+
<div id="page_toc">
|
|
63
|
+
<span id="page_toc_heading">
|
|
64
|
+
<strong>Contents</strong>
|
|
65
|
+
[<a href="javascript:void(0)" onclick="
|
|
66
|
+
document.getElementById('page_toc_contents').setAttribute('style', this.innerText === 'hide' ? 'display: none;' : '');
|
|
67
|
+
this.innerText = this.innerText === 'hide' ? 'show' : 'hide';
|
|
68
|
+
">hide</a>]
|
|
69
|
+
</span>
|
|
70
|
+
<ol id="page_toc_contents">${toc}</ol>
|
|
71
|
+
</div>
|
|
72
|
+
`;
|
|
73
|
+
// Set TOC on page
|
|
74
|
+
if (outText.includes('<toc></toc>')) {
|
|
75
|
+
// put TOC where explicitly declared
|
|
76
|
+
outText = outText.replace('<toc></toc>', tocElem);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// put TOC above first auto heading
|
|
80
|
+
outText = outText.replace(/<h[1-6] auto/, tocElem + '$&');
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Create plaintext of HTML for use as description/metadata property.
|
|
84
|
+
const plaintextData = parsedContent.replace(/<.+?>/gs, '');
|
|
85
|
+
// Create HTML
|
|
86
|
+
const folderUpCount = file.split(/[\/\\]/).length - dir.split(/[\/\\]/).length; // number of folders to go up by to get to root
|
|
87
|
+
const html = (0, dedent_1.default) `
|
|
88
|
+
<html>
|
|
89
|
+
<head>
|
|
90
|
+
<meta charset="utf-8">
|
|
91
|
+
<meta name="viewport" content="initial-scale=1.0, width=device-width">
|
|
92
|
+
<meta name="description" content="${plaintextData.substring(0, 256)}...">
|
|
93
|
+
<title>${displayTitle}</title>
|
|
94
|
+
<link id="default-styles" rel="stylesheet" href="${'../'.repeat(folderUpCount)}./wiki.css">
|
|
95
|
+
</head>
|
|
96
|
+
<body>
|
|
97
|
+
<header>
|
|
98
|
+
<h1 id="page-title">${displayTitle}</h1>
|
|
99
|
+
</header>
|
|
100
|
+
<main>
|
|
101
|
+
<p>\n${outText}
|
|
102
|
+
</p>
|
|
103
|
+
</main>
|
|
104
|
+
<footer>
|
|
105
|
+
<p id="credit_wikity">Created using <a href="https://github.com/Nixinova/Wikity">Wikity</a></p>
|
|
106
|
+
</footer>
|
|
107
|
+
</body>
|
|
108
|
+
</html>
|
|
109
|
+
`;
|
|
110
|
+
// Write to file
|
|
111
|
+
fs_1.default.mkdirSync(path_1.default.dirname(outFilePath), { recursive: true });
|
|
112
|
+
const formattedHtml = html.replace(/\n[\n\s]+/g, '\n');
|
|
113
|
+
fs_1.default.writeFileSync(outFilePath, frontMatter + '\n' + formattedHtml, 'utf8');
|
|
114
|
+
// Move images
|
|
115
|
+
(0, glob_1.default)(imagesFolder + '/*', {}, (err, files) => {
|
|
116
|
+
if (err) {
|
|
117
|
+
console.warn(err);
|
|
118
|
+
}
|
|
119
|
+
fs_1.default.mkdirSync(outputImagesFolder, { recursive: true });
|
|
120
|
+
for (const file of files) {
|
|
121
|
+
fs_1.default.copyFileSync(file, path_1.default.join(outputImagesFolder, path_1.default.basename(file)));
|
|
122
|
+
}
|
|
123
|
+
;
|
|
124
|
+
});
|
|
125
|
+
// Create site styles
|
|
126
|
+
if (!stylesCreated) {
|
|
127
|
+
stylesCreated = true;
|
|
128
|
+
let styles = '';
|
|
129
|
+
if (config.defaultStyles !== false) {
|
|
130
|
+
styles += wiki_css_1.default;
|
|
131
|
+
}
|
|
132
|
+
if (config.customStyles) {
|
|
133
|
+
styles += config.customStyles;
|
|
134
|
+
}
|
|
135
|
+
const cssOutput = config.eleventy ? ['---', 'permalink: /wiki.css', '---', styles].join('\n') : styles;
|
|
136
|
+
const cssOutFilename = config.eleventy ? 'wiki.css.njk' : 'wiki.css';
|
|
137
|
+
fs_1.default.writeFileSync(path_1.default.join(outputFolder, cssOutFilename), cssOutput);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { compile, eleventyCompile } from './compile';
|
|
2
|
+
import { rawParse } from './parse';
|
|
3
|
+
declare const _default: {
|
|
4
|
+
/** Parse wikitext from a string */
|
|
5
|
+
parse: typeof rawParse;
|
|
6
|
+
/** Compile a folder of wikitext files */
|
|
7
|
+
compile: typeof compile;
|
|
8
|
+
/** Compile a folder of wikitext files for output in Eleventy @deprecated */
|
|
9
|
+
eleventyPlugin: typeof eleventyCompile;
|
|
10
|
+
};
|
|
11
|
+
export = _default;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const compile_1 = require("./compile");
|
|
3
|
+
const parse_1 = require("./parse");
|
|
4
|
+
module.exports = {
|
|
5
|
+
/** Parse wikitext from a string */
|
|
6
|
+
parse: parse_1.rawParse,
|
|
7
|
+
/** Compile a folder of wikitext files */
|
|
8
|
+
compile: compile_1.compile,
|
|
9
|
+
/** Compile a folder of wikitext files for output in Eleventy @deprecated */
|
|
10
|
+
eleventyPlugin: compile_1.eleventyCompile,
|
|
11
|
+
};
|
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.rawParse = rawParse;
|
|
7
|
+
exports.parse = parse;
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const dateformat_1 = __importDefault(require("dateformat"));
|
|
11
|
+
const common_1 = require("./common");
|
|
12
|
+
const r = String.raw;
|
|
13
|
+
const MAX_RECURSION = 20;
|
|
14
|
+
const arg = r `\s*([^|}]+?)\s*`;
|
|
15
|
+
function toLinkText(link) {
|
|
16
|
+
const cleanedLink = encodeURI(link.trim().replace(/ /g, '_'));
|
|
17
|
+
return cleanedLink[0].toUpperCase() + cleanedLink.slice(1);
|
|
18
|
+
}
|
|
19
|
+
function toFileText(link) {
|
|
20
|
+
const cleanedLink = link.trim().replace(/ /g, '_');
|
|
21
|
+
return cleanedLink[0].toUpperCase() + cleanedLink.slice(1);
|
|
22
|
+
}
|
|
23
|
+
function parseDimensions(dimStr) {
|
|
24
|
+
const regex = /(\d*)(?:x(\d*))?px/;
|
|
25
|
+
const match = dimStr.match(regex);
|
|
26
|
+
if (!match)
|
|
27
|
+
return { width: 'auto', height: 'auto' };
|
|
28
|
+
const [, width, height] = match;
|
|
29
|
+
return {
|
|
30
|
+
width: width || 'auto',
|
|
31
|
+
height: height || 'auto',
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const escaper = (text, n = 0) => `%${text}#${n}`;
|
|
35
|
+
function rawParse(data, config = {}) {
|
|
36
|
+
return parse(data, config).data;
|
|
37
|
+
}
|
|
38
|
+
function parse(data, config = {}) {
|
|
39
|
+
var _a, _b, _c;
|
|
40
|
+
const KEY = Math.random().toString().slice(2); // key used to allow certain disallowed HTML elements
|
|
41
|
+
const templatesFolder = (_a = config.templatesFolder) !== null && _a !== void 0 ? _a : 'templates';
|
|
42
|
+
const imagesFolder = (_b = config.imagesFolder) !== null && _b !== void 0 ? _b : 'images';
|
|
43
|
+
const outputFolder = (_c = config.outputFolder) !== null && _c !== void 0 ? _c : 'wikity-out';
|
|
44
|
+
const vars = {};
|
|
45
|
+
const metadata = {};
|
|
46
|
+
const nowikis = [];
|
|
47
|
+
const refs = [];
|
|
48
|
+
let nowikiCount = 0;
|
|
49
|
+
let rawExtLinkCount = 0;
|
|
50
|
+
let outText = data;
|
|
51
|
+
for (let l = 0, last = ''; l < MAX_RECURSION; l++) {
|
|
52
|
+
if (last === outText)
|
|
53
|
+
break;
|
|
54
|
+
last = outText;
|
|
55
|
+
outText = outText
|
|
56
|
+
// Nowiki: <nowiki></nowiki>
|
|
57
|
+
.replace((0, common_1.RegExpBuilder)(r `<nowiki> ([^]+?) </nowiki>`), (_, m) => (nowikis.push(m), escaper('NOWIKI', nowikiCount++)))
|
|
58
|
+
// Sanitise unacceptable HTML
|
|
59
|
+
.replace((0, common_1.RegExpBuilder)(r `< \s* (?= (?: script|link|meta|iframe|frameset|object|embed|applet|form|input|button|textarea ) (?! \s* key.{0,10}${KEY}) )`), '<')
|
|
60
|
+
.replace((0, common_1.RegExpBuilder)(r `(?<= <[^>]+ ) (\bon(\w+))`), 'data-$2')
|
|
61
|
+
// Comments: <!-- -->
|
|
62
|
+
.replace(/<!--[^]+?-->/g, '')
|
|
63
|
+
// Lines: ----
|
|
64
|
+
.replace(/^-{4,}/gm, '<hr>')
|
|
65
|
+
// Images: [[File:Image.png|options|caption]]
|
|
66
|
+
.replace((0, common_1.RegExpBuilder)(r `\[\[ (?:File|Image): (.*?) (\|.+?)? \]\]`), (_, file, params = '') => {
|
|
67
|
+
var _a;
|
|
68
|
+
if (params.includes('{{'))
|
|
69
|
+
return _;
|
|
70
|
+
if (params.includes('[['))
|
|
71
|
+
return _;
|
|
72
|
+
if (!file)
|
|
73
|
+
return '';
|
|
74
|
+
const path = path_1.default.join(imagesFolder, file.trim().replace(/ /g, '_'));
|
|
75
|
+
let caption = '';
|
|
76
|
+
let imageData = {};
|
|
77
|
+
let imageArgs = params.split('|').map((arg) => arg.replace(/"/g, '"'));
|
|
78
|
+
for (const param of imageArgs) {
|
|
79
|
+
if (['left', 'right', 'center', 'none'].includes(param)) {
|
|
80
|
+
imageData.float = param;
|
|
81
|
+
}
|
|
82
|
+
if (['baseline', 'sub', 'super', 'top', 'text-bottom', 'middle', 'bottom', 'text-bottom'].includes(param)) {
|
|
83
|
+
imageData.align = param;
|
|
84
|
+
}
|
|
85
|
+
else if (['border', 'frameless', 'frame', 'framed', 'thumb', 'thumbnail'].includes(param)) {
|
|
86
|
+
imageData.type = { framed: 'frame', thumbnail: 'thumb' }[param] || param;
|
|
87
|
+
if (imageData.type === 'thumb') {
|
|
88
|
+
imageData.hasCaption = true;
|
|
89
|
+
(_a = imageData.float) !== null && _a !== void 0 ? _a : (imageData.float = 'right');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else if (param.endsWith('px')) {
|
|
93
|
+
const { width, height } = parseDimensions(param);
|
|
94
|
+
imageData.width = width;
|
|
95
|
+
imageData.height = height;
|
|
96
|
+
}
|
|
97
|
+
else if (param.startsWith('upright=')) {
|
|
98
|
+
imageData.width = +param.replace('upright=', '') * 300;
|
|
99
|
+
}
|
|
100
|
+
else if (param.startsWith('link=')) {
|
|
101
|
+
imageData.link = param.replace('link=', '');
|
|
102
|
+
}
|
|
103
|
+
else if (param.startsWith('alt=')) {
|
|
104
|
+
imageData.alt = param.replace('alt=', '');
|
|
105
|
+
}
|
|
106
|
+
else if (param.startsWith('style=')) {
|
|
107
|
+
imageData.style = param.replace('style=', '');
|
|
108
|
+
}
|
|
109
|
+
else if (param.startsWith('class=')) {
|
|
110
|
+
imageData.class = param.replace('class=', '');
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
caption = param;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
let content = `
|
|
117
|
+
<figure
|
|
118
|
+
class="
|
|
119
|
+
${imageData.class || ''}
|
|
120
|
+
image-container
|
|
121
|
+
image-${imageData.type || 'default'}
|
|
122
|
+
"
|
|
123
|
+
style="
|
|
124
|
+
margin: 8px;
|
|
125
|
+
float: ${imageData.float || 'none'};
|
|
126
|
+
clear: ${imageData.float || 'none'};
|
|
127
|
+
vertical-align: ${imageData.align || 'unset'};
|
|
128
|
+
background: #fff;
|
|
129
|
+
${imageData.style || ''}
|
|
130
|
+
"
|
|
131
|
+
>
|
|
132
|
+
<img
|
|
133
|
+
src="${path_1.default.basename(imagesFolder)}/${path_1.default.relative(imagesFolder, path)}"
|
|
134
|
+
alt="${imageData.alt || file}"
|
|
135
|
+
width="${imageData.width || 300}"
|
|
136
|
+
height="${imageData.height || ''}"
|
|
137
|
+
>
|
|
138
|
+
${imageData.hasCaption ? `<figcaption>${caption}</figcaption>` : ''}
|
|
139
|
+
</figure>
|
|
140
|
+
`;
|
|
141
|
+
const imageLink = imageData.link;
|
|
142
|
+
if (imageLink) {
|
|
143
|
+
content = `<a href="${toLinkText(imageLink)}" title="${imageLink}">${content}</a>`;
|
|
144
|
+
}
|
|
145
|
+
return content;
|
|
146
|
+
})
|
|
147
|
+
// Internal links
|
|
148
|
+
// [[Page]]
|
|
149
|
+
.replace((0, common_1.RegExpBuilder)(r `\[\[ ([^\]|]+?) \]\]`), (_, link) => {
|
|
150
|
+
if (_.includes('{{'))
|
|
151
|
+
return _;
|
|
152
|
+
if (/(?:File|Image):/.test(link))
|
|
153
|
+
return _;
|
|
154
|
+
const content = `<a class="internal-link" title="${link}" href="./${toLinkText(link)}">${link}</a>`;
|
|
155
|
+
return content;
|
|
156
|
+
})
|
|
157
|
+
// [[Page|Text]]
|
|
158
|
+
.replace((0, common_1.RegExpBuilder)(r `\[\[ ([^\]|]+?) \| ([^\]]+?) \]\]`), (_, link, text) => {
|
|
159
|
+
if (link.includes('{{'))
|
|
160
|
+
return _;
|
|
161
|
+
if (/(?:File|Image):/.test(link))
|
|
162
|
+
return _;
|
|
163
|
+
const content = `<a class="internal-link" title="${link}" href="./${toLinkText(link)}">${text}</a>`;
|
|
164
|
+
return content;
|
|
165
|
+
})
|
|
166
|
+
.replace((0, common_1.RegExpBuilder)(r `(</a>)([a-z]+)`), '$2$1')
|
|
167
|
+
// External links: [href Page] and just [href]
|
|
168
|
+
.replace((0, common_1.RegExpBuilder)(r `\[ ((?:\w+:)?\/\/ [^\s\]]+) (\s [^\]]+?)? \]`), (_, href, txt) => {
|
|
169
|
+
if (_.includes('{{'))
|
|
170
|
+
return _;
|
|
171
|
+
const content = `<a class="external-link" href="${href}">${txt || '[' + (++rawExtLinkCount) + ']'}</a>`;
|
|
172
|
+
return content;
|
|
173
|
+
})
|
|
174
|
+
// Magic words: {{!}}, {{reflist}}, etc
|
|
175
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* ! \s* }}`), escaper('VERT'))
|
|
176
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* !! \s* }}`), escaper('VERT').repeat(2))
|
|
177
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* = \s* }}`), escaper('EQUALS'))
|
|
178
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* [Rr]eflist \s* }}`), '<references/>')
|
|
179
|
+
// Metadata: displayTitle, __NOTOC__, etc
|
|
180
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* displayTitle: ([^}]+) }}`), (_, title) => (metadata.displayTitle = title, ''))
|
|
181
|
+
.replace((0, common_1.RegExpBuilder)(r `__NOINDEX__`), () => (metadata.noindex = true, ''))
|
|
182
|
+
.replace((0, common_1.RegExpBuilder)(r `__NOTOC__`), () => (metadata.notoc = true, ''))
|
|
183
|
+
.replace((0, common_1.RegExpBuilder)(r `__FORCETOC__`), () => (metadata.toc = true, ''))
|
|
184
|
+
.replace((0, common_1.RegExpBuilder)(r `__TOC__`), () => (metadata.toc = true, `<toc></toc>`))
|
|
185
|
+
// String functions: {{lc:}}, {{ucfirst:}}, {{len:}}, etc
|
|
186
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* #? urlencode: ${arg} }}`), (_, m) => encodeURI(m))
|
|
187
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* #? urldecode: ${arg} }}`), (_, m) => decodeURI(m))
|
|
188
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* #? lc: ${arg} }}`), (_, m) => m.toLowerCase())
|
|
189
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* #? uc: ${arg} }}`), (_, m) => m.toUpperCase())
|
|
190
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* #? lcfirst: ${arg} }}`), (_, m) => m[0].toLowerCase() + m.substr(1))
|
|
191
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* #? ucfirst: ${arg} }}`), (_, m) => m[0].toUpperCase() + m.substr(1))
|
|
192
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* #? len: ${arg} }}`), (_, m) => m.length)
|
|
193
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* #? pos: ${arg} \|${arg} (?: \s*\|${arg} )? }}`), (_, find, str, n = 0) => find.substr(n).indexOf(str))
|
|
194
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* #? sub: ${arg} \|${arg} (?:\|${arg})? }}`), (_, str, from, len) => str.substr(+from - 1, +len))
|
|
195
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* #? padleft: ${arg} \|${arg} \|${arg} }}`), (_, str, n, char) => str.padStart(+n, char))
|
|
196
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* #? padright: ${arg} \|${arg} \|${arg} }}`), (_, str, n, char) => str.padEnd(+n, char))
|
|
197
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* #? replace: ${arg} \|${arg} \|${arg} }}`), (_, str, find, rep) => str.split(find).join(rep))
|
|
198
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* #? explode: ${arg} \|${arg} \|${arg} }}`), (_, str, delim, pos) => str.split(delim)[+pos])
|
|
199
|
+
// Magic functions: {{#ev:youtube}}, etc
|
|
200
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* #? ev: \s* (\w+) \s* \| \s* ( [^{}]+ ) \s* }} ( ?!} )`), (_, platform, args) => {
|
|
201
|
+
var _a;
|
|
202
|
+
// See mediawiki.org/wiki/Extension:EmbedVideo_(fork) for docs
|
|
203
|
+
const params = args.split('|');
|
|
204
|
+
for (let i = 0; i < 10; i++)
|
|
205
|
+
(_a = params[i]) !== null && _a !== void 0 ? _a : (params[i] = ''); // fill up with empty strings
|
|
206
|
+
const [id, dimensions, alignment, description, container, urlargs, autoresize] = params;
|
|
207
|
+
const { width, height } = parseDimensions(dimensions);
|
|
208
|
+
const source = {
|
|
209
|
+
// Add platforms
|
|
210
|
+
'youtube': `//www.youtube.com/embed/${id}`,
|
|
211
|
+
'vimeo': `//player.vimeo.com/video/${id}`,
|
|
212
|
+
}[platform];
|
|
213
|
+
if (!source)
|
|
214
|
+
return `<code>Failed to load video ${id} from ${platform}.</code>`;
|
|
215
|
+
return `
|
|
216
|
+
<iframe key="${KEY}"
|
|
217
|
+
src="${source}"
|
|
218
|
+
width="${width}"
|
|
219
|
+
height="${height}"
|
|
220
|
+
frameborder="0"
|
|
221
|
+
allowfullscreen="true"
|
|
222
|
+
loading="lazy"
|
|
223
|
+
title="${description !== null && description !== void 0 ? description : 'Play video'}"
|
|
224
|
+
${alignment ? `style="float: ${alignment};"` : ''}
|
|
225
|
+
>
|
|
226
|
+
</iframe>
|
|
227
|
+
${description ? `<figcaption>${description}</figcaption>` : ''}
|
|
228
|
+
`;
|
|
229
|
+
})
|
|
230
|
+
// Parser functions: {{#if:}}, {{#switch:}}, etc
|
|
231
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* (#\w+) \s* : \s* ( [^{}]+ ) \s* }} ( ?!} )`), (_, name, content) => {
|
|
232
|
+
if (content.includes('{{'))
|
|
233
|
+
return _;
|
|
234
|
+
const args = content.trim().split(/\s*\|\s*/);
|
|
235
|
+
switch (name) {
|
|
236
|
+
case '#if':
|
|
237
|
+
return (args[0] ? args[1] : args[2]) || '';
|
|
238
|
+
case '#ifeq':
|
|
239
|
+
return (args[0] === args[1] ? args[2] : args[3]) || '';
|
|
240
|
+
case '#vardefine':
|
|
241
|
+
vars[args[0]] = args[1] || '';
|
|
242
|
+
return '';
|
|
243
|
+
case '#var':
|
|
244
|
+
if ((0, common_1.RegExpBuilder)(r `{{ \s* #vardefine \s* : \s* ${args[0]}`).test(outText))
|
|
245
|
+
return _; // wait until var is set
|
|
246
|
+
return vars[args[0]] || args[1] || '';
|
|
247
|
+
case '#switch':
|
|
248
|
+
return args.slice(1)
|
|
249
|
+
.map(arg => arg.split(/\s*=\s*/))
|
|
250
|
+
.filter(duo => args[0] === duo[0].replace('#default', args[0]))[0][1];
|
|
251
|
+
case '#time':
|
|
252
|
+
case '#date':
|
|
253
|
+
case '#datetime':
|
|
254
|
+
// make sure the characters are not inside a string
|
|
255
|
+
let parsedMatch = args[0].replace(/".+?"/g, '').replace(/'.+?'/g, '');
|
|
256
|
+
if (/[abcefgijkqruvx]/i.test(parsedMatch)) {
|
|
257
|
+
const errMsg = `Wikity does not use Wikipedia's #time function syntax. Use repetition-based formatting (e.g. yyyy-mm-dd) instead.`;
|
|
258
|
+
console.warn(`<Wikity> [WARN] ${errMsg}`);
|
|
259
|
+
}
|
|
260
|
+
try {
|
|
261
|
+
return (0, dateformat_1.default)(args[1] ? new Date(args[1]) : new Date(), args[0]);
|
|
262
|
+
}
|
|
263
|
+
catch {
|
|
264
|
+
return args[1] || args[0];
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
})
|
|
268
|
+
// Templates: {{template}}
|
|
269
|
+
.replace((0, common_1.RegExpBuilder)(r `(?<!{) {{ \s* ([^#{}|]+?) \s* (\|[^{}]+)? }} (?!})`), (_, title, params = '') => {
|
|
270
|
+
if (params.includes('{{'))
|
|
271
|
+
return _;
|
|
272
|
+
const templateFile = toFileText(title);
|
|
273
|
+
const page = path_1.default.join(templatesFolder, templateFile);
|
|
274
|
+
let content = '';
|
|
275
|
+
// Try retrieve template content
|
|
276
|
+
try {
|
|
277
|
+
content = fs_1.default.readFileSync(page + '.wiki', { encoding: 'utf8' });
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
// Return redlink if template doesn't exist
|
|
281
|
+
const relPage = path_1.default.basename(templatesFolder) + '/' + path_1.default.relative(templatesFolder, page);
|
|
282
|
+
return `<a class="internal-link redlink" title="${title}" href="${relPage}">${title}</a>`;
|
|
283
|
+
}
|
|
284
|
+
// Remove non-template sections
|
|
285
|
+
content = content.trim()
|
|
286
|
+
.replace(/<noinclude>.*?<\/noinclude>/gs, '')
|
|
287
|
+
.replace(/.*<(includeonly|onlyinclude)>|<\/(includeonly|onlyinclude)>.*/gs, '');
|
|
288
|
+
// Substitute arguments
|
|
289
|
+
const argMatch = (arg) => (0, common_1.RegExpBuilder)(r `{{{ \s* ${arg} (?:\|([^}]*))? \s* }}}`);
|
|
290
|
+
const args = params.split('|');
|
|
291
|
+
// parse provided key=value template arguments
|
|
292
|
+
for (let i = 1; i < args.length; i++) {
|
|
293
|
+
const data = args[i];
|
|
294
|
+
const parts = data.split('=');
|
|
295
|
+
const isNamed = parts.length > 1;
|
|
296
|
+
const arg = isNamed ? parts[0] : i.toString();
|
|
297
|
+
const val = isNamed ? parts.slice(1).join('=') : data;
|
|
298
|
+
content = content.replace(argMatch(arg), (_, defaultVal) => (val || defaultVal || '').trim());
|
|
299
|
+
}
|
|
300
|
+
return content;
|
|
301
|
+
})
|
|
302
|
+
// Unparsed arguments
|
|
303
|
+
.replace((0, common_1.RegExpBuilder)(r `{{{ \s* [^{}|]+? (?:\|([^}]*))? \s* }}}`), (_, defaultVal) => {
|
|
304
|
+
return defaultVal !== null && defaultVal !== void 0 ? defaultVal : '';
|
|
305
|
+
})
|
|
306
|
+
// Markup: '''bold''' and '''italic'''
|
|
307
|
+
.replace((0, common_1.RegExpBuilder)(r `''' ([^']+?) '''`), '<b>$1</b>')
|
|
308
|
+
.replace((0, common_1.RegExpBuilder)(r `'' ([^']+?) ''`), '<i>$1</i>')
|
|
309
|
+
// Headings: ==heading==
|
|
310
|
+
.replace((0, common_1.RegExpBuilder)(r `^ (=+) \s* (.+?) \s* \1 \s* $`), (_, lvl, txt) => {
|
|
311
|
+
const linkForm = encodeURI(txt.replace(/ /g, '_').replace(/<.+?>/g, ''));
|
|
312
|
+
return `<h${lvl.length} auto id="${linkForm}">${txt}</h${lvl.length}>`;
|
|
313
|
+
})
|
|
314
|
+
// Bulleted list: *item
|
|
315
|
+
.replace((0, common_1.RegExpBuilder)(r `^ (\*+) (.+?) $`), (_, lvl, content) => {
|
|
316
|
+
if (content.includes('{{'))
|
|
317
|
+
return _;
|
|
318
|
+
const depth = lvl.length;
|
|
319
|
+
return `${'<ul>'.repeat(depth)}<li>${content}</li>${'</ul>'.repeat(depth)}`;
|
|
320
|
+
})
|
|
321
|
+
.replace((0, common_1.RegExpBuilder)(r `</ul> (\s*?) <ul>`), '$1')
|
|
322
|
+
// Numbered list: #item
|
|
323
|
+
.replace((0, common_1.RegExpBuilder)(r `^ (#+) (.+?) $`), (_, lvl, content) => {
|
|
324
|
+
if (content.includes('{{'))
|
|
325
|
+
return _;
|
|
326
|
+
const depth = lvl.length;
|
|
327
|
+
return `${'<ol>'.repeat(depth)}<li>${content}</li>${'</ol>'.repeat(depth)}`;
|
|
328
|
+
})
|
|
329
|
+
.replace((0, common_1.RegExpBuilder)(r `</ol> (\s*?) <ol>`), '$1')
|
|
330
|
+
// Definition list: ;head, :item
|
|
331
|
+
.replace((0, common_1.RegExpBuilder)(r `^ ; (.+?) : (.+?) $`), `<dl><dt>$1</td><dd>$2</dd></dl>`)
|
|
332
|
+
.replace((0, common_1.RegExpBuilder)(r `^ (:+) (.+?) $`), (_, lvl, content) => {
|
|
333
|
+
if (content.includes('{{'))
|
|
334
|
+
return _;
|
|
335
|
+
const depth = lvl.length;
|
|
336
|
+
return `${'<dl>'.repeat(depth)}<dd>${content}</dd>${'</dl>'.repeat(depth)}`;
|
|
337
|
+
})
|
|
338
|
+
.replace((0, common_1.RegExpBuilder)(r `^ ; (.+) $`), '<dl><dt>$1</dt></dl>')
|
|
339
|
+
.replace((0, common_1.RegExpBuilder)(r `</dl> (\s*?) <dl>`), '$1')
|
|
340
|
+
// Tables: {|, |+, !, |-, |, |}
|
|
341
|
+
.replace(/\{\|.+\|\}/gs, (tableInner) => {
|
|
342
|
+
if (tableInner.includes('{{'))
|
|
343
|
+
return tableInner;
|
|
344
|
+
return tableInner
|
|
345
|
+
// {| data (open table)
|
|
346
|
+
.replace((0, common_1.RegExpBuilder)(r `^ \{\| (.*?) $`), (_, attrs) => `<table ${attrs}><tr>`)
|
|
347
|
+
// |+ data
|
|
348
|
+
.replace((0, common_1.RegExpBuilder)(r `^ \|\+ (.*?) $`), (_, content) => `<caption>${content}</caption>`)
|
|
349
|
+
// |- (new row)
|
|
350
|
+
.replace((0, common_1.RegExpBuilder)(r `^ \|- (.*?) $`), (_, attrs) => `</tr><tr ${attrs}>`)
|
|
351
|
+
// |} (close)
|
|
352
|
+
.replace((0, common_1.RegExpBuilder)(r `^ \|\}`), `</tr></table>`)
|
|
353
|
+
// content: !head, !data|head, |text, |data|text, !!head, ||data
|
|
354
|
+
.replace((0, common_1.RegExpBuilder)(r `( ^! | ^\| | !! | \|\| ) (?: ( [^|\n]+? ) \|)? ( [^|\n]*? ) (?= $ | !! | \|\| )`), (_, type, data, content) => {
|
|
355
|
+
const elem = /!/.test(type) ? 'th' : 'td';
|
|
356
|
+
return `<${elem} ${data !== null && data !== void 0 ? data : ''}>${content}</${elem}>`;
|
|
357
|
+
});
|
|
358
|
+
})
|
|
359
|
+
// References: <ref></ref>
|
|
360
|
+
.replace((0, common_1.RegExpBuilder)(r `< ref \s* (?: name \s* = \s* ["']? ([^>'"]+) ["']? [^>]* )?> (.+?) </ ref >`), (_, refname, text) => {
|
|
361
|
+
if (_.includes('{{'))
|
|
362
|
+
return _;
|
|
363
|
+
const refData = { ref: text, id: refs.length + 1, name: refname, i: 0 };
|
|
364
|
+
refs.push(refData);
|
|
365
|
+
return `<sup class="refnote"><a id="cite-${refData.id}" class="ref" href="#ref-${refData.id}">[${refData.id}]</a></sup>`;
|
|
366
|
+
})
|
|
367
|
+
.replace((0, common_1.RegExpBuilder)(r `< ref \s* name \s* = \s* ["']? ( [^>"']+ ) ["']? \s* (?: /> | > .*? </ref> )`), (_, refname) => {
|
|
368
|
+
const ref = refs.find(ref => ref.name === refname);
|
|
369
|
+
if (!ref)
|
|
370
|
+
return _;
|
|
371
|
+
ref.i++;
|
|
372
|
+
const citeId = `cite-${ref.id}${ref.i > 0 ? `_${ref.i}` : ''}`;
|
|
373
|
+
return `<sup class="refnote"><a id="${citeId}" class="ref" href="#ref-${ref.id}">[${ref.id}]</a></sup>`;
|
|
374
|
+
})
|
|
375
|
+
// Nonstandard: ``code`` and ```code blocks```
|
|
376
|
+
.replace((0, common_1.RegExpBuilder)(r ` \`\`\` ([^\`]+?) \`\`\` `), '<pre>$1</pre>')
|
|
377
|
+
.replace((0, common_1.RegExpBuilder)(r ` \`\` ([^\`]+?) \`\` `), '<code>$1</code>')
|
|
378
|
+
// Spacing
|
|
379
|
+
.replace(/(\r?\n){2}/g, '\n</p><p>\n');
|
|
380
|
+
}
|
|
381
|
+
// Final (one-time) substitutions
|
|
382
|
+
for (let i = 0; i < nowikis.length; i++) {
|
|
383
|
+
outText = outText
|
|
384
|
+
// Restore nowiki contents
|
|
385
|
+
.replace(escaper('NOWIKI', i), nowikis[i]);
|
|
386
|
+
}
|
|
387
|
+
outText = outText
|
|
388
|
+
// References: <references />
|
|
389
|
+
.replace((0, common_1.RegExpBuilder)(r `<references \s* /?>`), () => {
|
|
390
|
+
const references = refs.map((refdata) => {
|
|
391
|
+
let multiRefContent = '';
|
|
392
|
+
if (refdata.i > 0) {
|
|
393
|
+
for (let i = 0; i <= refdata.i; i++) {
|
|
394
|
+
multiRefContent += `<sup><a href="#cite-${refdata.id}${i > 0 ? `_${i}` : ''}">${i + 1}</a></sup> `;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
const refline = `
|
|
398
|
+
<li id="ref-${refdata.id}">
|
|
399
|
+
${refdata.i > 0 ? '↑' : `<a href="#cite-${refdata.id}">↑</a>`}
|
|
400
|
+
${multiRefContent}
|
|
401
|
+
${refdata.ref}
|
|
402
|
+
</li>
|
|
403
|
+
`;
|
|
404
|
+
return refline;
|
|
405
|
+
}).join('\n');
|
|
406
|
+
return `<ol>${references}</ol>`;
|
|
407
|
+
})
|
|
408
|
+
// Magic word functions
|
|
409
|
+
.replaceAll(escaper('VERT'), '|')
|
|
410
|
+
.replaceAll(escaper('EQUALS'), '=');
|
|
411
|
+
// Escape all {{ to avoid crashes
|
|
412
|
+
outText = outText
|
|
413
|
+
.replaceAll('{{', '{{');
|
|
414
|
+
const result = { data: outText, metadata: metadata };
|
|
415
|
+
return result;
|
|
416
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = String.raw `
|
|
4
|
+
body {font-family: sans-serif; margin: auto; max-width: 1000px; background: #eee;}
|
|
5
|
+
main {margin: 3em -1em; background: #fff; padding: 1em;}
|
|
6
|
+
h1, h2 {margin-bottom: 0.6em; font-weight: normal; border-bottom: 1px solid #a2a9b1;}
|
|
7
|
+
ul, ol {margin: 0.3em 0 0 1.6em; padding: 0;}
|
|
8
|
+
dt {font-weight: bold;}
|
|
9
|
+
dd, dl dl {margin-block: 0; margin-inline-start: 30px;}
|
|
10
|
+
|
|
11
|
+
figure {margin: 1em; width: 300px;}
|
|
12
|
+
.image-thumb, .image-frame {padding: 6px; border: 1px solid gray;}
|
|
13
|
+
.image-default {margin: 0;}
|
|
14
|
+
figcaption {padding-top: 6px;}
|
|
15
|
+
|
|
16
|
+
table.wikitable {border-collapse: collapse;}
|
|
17
|
+
table.wikitable, table.wikitable th, table.wikitable td {border: 1px solid gray; padding: 6px;}
|
|
18
|
+
table.wikitable th {background-color: #eaecf0; text-align: center;}
|
|
19
|
+
|
|
20
|
+
a:not(:hover) {text-decoration: none;}
|
|
21
|
+
a.internal-link {color: #04a;}
|
|
22
|
+
a.internal-link:visited {color: #26d;}
|
|
23
|
+
a.external-link {color: #36b;}
|
|
24
|
+
a.external-link:visited {color: #58d;}
|
|
25
|
+
a.external-link::after {content: '\1f855';}
|
|
26
|
+
a.redlink {color: #d33;}
|
|
27
|
+
a.redlink:visited {color: #b44;}
|
|
28
|
+
|
|
29
|
+
#page_toc {border: 1px solid #aab; padding: 8px; width: fit-content; background-color: #f8f8f8; font-size: 95%;}
|
|
30
|
+
#page_toc_heading {display: block; text-align: center;}
|
|
31
|
+
#page_toc ol {margin: 0 0 0 1.3em;}
|
|
32
|
+
|
|
33
|
+
#infobox {float: right; clear: right; margin: 0 0 1em 1em; width: 300px; padding: 2px; border: 1px solid #CCC; overflow: auto; font-size: 90%;}
|
|
34
|
+
#infobox tr:first-child :first-child {padding: 10px; text-align: center; font-weight: bold; font-size: 120%;}
|
|
35
|
+
#infobox th {padding-left: 10px; text-align: left;}
|
|
36
|
+
`;
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wikity",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.8",
|
|
4
4
|
"description": "Compile wikitext to HTML! Supporst use of wikitext as a templating language.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
+
"compile": "tsc",
|
|
7
8
|
"test": "tsc && cd test && eleventy"
|
|
8
9
|
},
|
|
9
10
|
"bin": {
|
|
@@ -39,7 +40,7 @@
|
|
|
39
40
|
"license": "ISC",
|
|
40
41
|
"dependencies": {
|
|
41
42
|
"dateformat": "^4.6.3",
|
|
42
|
-
"dedent": "^1.7.
|
|
43
|
+
"dedent": "^1.7.2",
|
|
43
44
|
"escape-html": "^1.0.3",
|
|
44
45
|
"glob": "^8.1.0"
|
|
45
46
|
},
|
|
@@ -48,7 +49,7 @@
|
|
|
48
49
|
"@types/dedent": "^0.7.2",
|
|
49
50
|
"@types/escape-html": "^1.0.4",
|
|
50
51
|
"@types/glob": "^8.1.0",
|
|
51
|
-
"@types/node": "
|
|
52
|
+
"@types/node": "^12.20.55",
|
|
52
53
|
"typescript": "~5.0.4 <5.1"
|
|
53
54
|
}
|
|
54
55
|
}
|