wikity 1.3.3 → 1.3.4
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/compile.js +5 -10
- package/dist/parse.js +224 -126
- package/dist/wiki.css.js +10 -3
- package/package.json +1 -1
- package/readme.md +1 -0
package/dist/compile.js
CHANGED
|
@@ -58,15 +58,15 @@ function compile(dir = '.', config = {}) {
|
|
|
58
58
|
toc += `${`<ol>`.repeat(lvl - 1)} <li> <a href="#${encodeURI(text.replace(/ /g, '_'))}">${text}</a> </li> ${`</ol>`.repeat(lvl - 1)}`;
|
|
59
59
|
});
|
|
60
60
|
const tocElem = (0, dedent_1.default) `
|
|
61
|
-
<div id="toc">
|
|
62
|
-
<span id="toc
|
|
61
|
+
<div id="page+toc">
|
|
62
|
+
<span id="page+toc+heading">
|
|
63
63
|
<strong>Contents</strong>
|
|
64
64
|
[<a href="javascript:void(0)" onclick="
|
|
65
|
-
document.
|
|
65
|
+
document.getElementById('page+toc+contents').setAttribute('style', this.innerText === 'hide' ? 'display: none;' : '');
|
|
66
66
|
this.innerText = this.innerText === 'hide' ? 'show' : 'hide';
|
|
67
67
|
">hide</a>]
|
|
68
68
|
</span>
|
|
69
|
-
<ol>${toc}</ol>
|
|
69
|
+
<ol id="page+toc+contents">${toc}</ol>
|
|
70
70
|
</div>
|
|
71
71
|
`;
|
|
72
72
|
// Set TOC on page
|
|
@@ -131,12 +131,7 @@ function compile(dir = '.', config = {}) {
|
|
|
131
131
|
if (config.customStyles) {
|
|
132
132
|
styles += config.customStyles;
|
|
133
133
|
}
|
|
134
|
-
const cssOutput = config.eleventy ?
|
|
135
|
-
---
|
|
136
|
-
permalink: /wiki.css
|
|
137
|
-
---
|
|
138
|
-
${styles}
|
|
139
|
-
` : styles;
|
|
134
|
+
const cssOutput = config.eleventy ? ['---', 'permalink: /wiki.css', '---', styles].join('\n') : styles;
|
|
140
135
|
const cssOutFilename = config.eleventy ? 'wiki.css.njk' : 'wiki.css';
|
|
141
136
|
fs_1.default.writeFileSync(path_1.default.join(outputFolder, cssOutFilename), cssOutput);
|
|
142
137
|
}
|
package/dist/parse.js
CHANGED
|
@@ -6,22 +6,33 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.parse = exports.rawParse = void 0;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const escape_html_1 = __importDefault(require("escape-html"));
|
|
10
9
|
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;
|
|
14
13
|
const arg = r `\s*([^|}]+?)\s*`;
|
|
15
|
-
function
|
|
16
|
-
return (
|
|
17
|
-
.replace(/{/g, '{'); // avoid keeping plain {{}} which is parsed as a template call
|
|
14
|
+
function cleanLink(link) {
|
|
15
|
+
return encodeURI(link.replace(/ /g, '_'));
|
|
18
16
|
}
|
|
17
|
+
function parseDimensions(dimStr) {
|
|
18
|
+
const regex = /(\d*)(?:x(\d*))?px/;
|
|
19
|
+
const match = dimStr.match(regex);
|
|
20
|
+
if (!match)
|
|
21
|
+
return { width: 'auto', height: 'auto' };
|
|
22
|
+
const [, width, height] = match;
|
|
23
|
+
return {
|
|
24
|
+
width: width || 'auto',
|
|
25
|
+
height: height || 'auto',
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const escaper = (text, n = 0) => `%${text}#${n}`;
|
|
19
29
|
function rawParse(data, config = {}) {
|
|
20
30
|
return parse(data, config).data;
|
|
21
31
|
}
|
|
22
32
|
exports.rawParse = rawParse;
|
|
23
33
|
function parse(data, config = {}) {
|
|
24
34
|
var _a, _b, _c;
|
|
35
|
+
const KEY = Math.random().toString().slice(2); // key used to allow certain disallowed HTML elements
|
|
25
36
|
const templatesFolder = (_a = config.templatesFolder) !== null && _a !== void 0 ? _a : 'templates';
|
|
26
37
|
const imagesFolder = (_b = config.imagesFolder) !== null && _b !== void 0 ? _b : 'images';
|
|
27
38
|
const outputFolder = (_c = config.outputFolder) !== null && _c !== void 0 ? _c : 'wikity-out';
|
|
@@ -31,9 +42,7 @@ function parse(data, config = {}) {
|
|
|
31
42
|
const refs = [];
|
|
32
43
|
let nowikiCount = 0;
|
|
33
44
|
let rawExtLinkCount = 0;
|
|
34
|
-
let refCount = 0;
|
|
35
45
|
let outText = data;
|
|
36
|
-
const escaper = (text, n) => `%${text}#${n}`;
|
|
37
46
|
for (let l = 0, last = ''; l < MAX_RECURSION; l++) {
|
|
38
47
|
if (last === outText)
|
|
39
48
|
break;
|
|
@@ -42,21 +51,113 @@ function parse(data, config = {}) {
|
|
|
42
51
|
// Nowiki: <nowiki></nowiki>
|
|
43
52
|
.replace((0, common_1.RegExpBuilder)(r `<nowiki> ([^]+?) </nowiki>`), (_, m) => (nowikis.push(m), escaper('NOWIKI', nowikiCount++)))
|
|
44
53
|
// Sanitise unacceptable HTML
|
|
45
|
-
.replace((0, common_1.RegExpBuilder)(r `<
|
|
54
|
+
.replace((0, common_1.RegExpBuilder)(r `< \s* (?= (?: script|link|meta|iframe|frameset|object|embed|applet|form|input|button|textarea ) (?! \s* key.{0,10}${KEY}) )`), '<')
|
|
46
55
|
.replace((0, common_1.RegExpBuilder)(r `(?<= <[^>]+ ) (\bon(\w+))`), 'data-$2')
|
|
47
56
|
// Comments: <!-- -->
|
|
48
57
|
.replace(/<!--[^]+?-->/g, '')
|
|
49
58
|
// Lines: ----
|
|
50
59
|
.replace(/^-{4,}/gm, '<hr>')
|
|
60
|
+
// Images: [[File:Image.png|options|caption]]
|
|
61
|
+
.replace((0, common_1.RegExpBuilder)(r `\[\[ (?:File|Image): (.*?) (\|.+?)? \]\]`), (_, file, params = '') => {
|
|
62
|
+
if (params.includes('{{'))
|
|
63
|
+
return _;
|
|
64
|
+
if (!file)
|
|
65
|
+
return '';
|
|
66
|
+
const path = path_1.default.join(imagesFolder, file.trim().replace(/ /g, '_'));
|
|
67
|
+
let caption = '';
|
|
68
|
+
let imageData = {};
|
|
69
|
+
let imageArgs = params.split('|').map((arg) => arg.replace(/"/g, '"'));
|
|
70
|
+
for (const param of imageArgs) {
|
|
71
|
+
if (['left', 'right', 'center', 'none'].includes(param)) {
|
|
72
|
+
imageData.float = param;
|
|
73
|
+
}
|
|
74
|
+
if (['baseline', 'sub', 'super', 'top', 'text-bottom', 'middle', 'bottom', 'text-bottom'].includes(param)) {
|
|
75
|
+
imageData.align = param;
|
|
76
|
+
}
|
|
77
|
+
else if (['border', 'frameless', 'frame', 'framed', 'thumb', 'thumbnail'].includes(param)) {
|
|
78
|
+
imageData.type = { framed: 'frame', thumbnail: 'thumb' }[param] || param;
|
|
79
|
+
if (imageData.type === 'thumb') {
|
|
80
|
+
imageData.hasCaption = true;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else if (param.endsWith('px')) {
|
|
84
|
+
const { width, height } = parseDimensions(param);
|
|
85
|
+
imageData.width = width;
|
|
86
|
+
imageData.height = height;
|
|
87
|
+
}
|
|
88
|
+
else if (param.startsWith('upright=')) {
|
|
89
|
+
imageData.width = +param.replace('upright=', '') * 300;
|
|
90
|
+
}
|
|
91
|
+
else if (param.startsWith('link=')) {
|
|
92
|
+
imageData.link = param.replace('link=', '');
|
|
93
|
+
}
|
|
94
|
+
else if (param.startsWith('alt=')) {
|
|
95
|
+
imageData.alt = param.replace('alt=', '');
|
|
96
|
+
}
|
|
97
|
+
else if (param.startsWith('style=')) {
|
|
98
|
+
imageData.style = param.replace('style=', '');
|
|
99
|
+
}
|
|
100
|
+
else if (param.startsWith('class=')) {
|
|
101
|
+
imageData.class = param.replace('class=', '');
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
caption = param;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
let content = `
|
|
108
|
+
<figure
|
|
109
|
+
class="
|
|
110
|
+
${imageData.class || ''}
|
|
111
|
+
image-container
|
|
112
|
+
image-${imageData.type || 'default'}
|
|
113
|
+
"
|
|
114
|
+
style="
|
|
115
|
+
display: inline-block;
|
|
116
|
+
float: ${imageData.float || 'none'};
|
|
117
|
+
vertical-align: ${imageData.align || 'unset'};
|
|
118
|
+
${imageData.style || ''}
|
|
119
|
+
"
|
|
120
|
+
>
|
|
121
|
+
<img
|
|
122
|
+
src="${path_1.default.basename(imagesFolder)}/${path_1.default.relative(imagesFolder, path)}"
|
|
123
|
+
alt="${imageData.alt || file}"
|
|
124
|
+
width="${imageData.width || 300}"
|
|
125
|
+
height="${imageData.height || 300}"
|
|
126
|
+
>
|
|
127
|
+
${imageData.hasCaption ? `<figcaption>${caption}</figcaption>` : ''}
|
|
128
|
+
</figure>
|
|
129
|
+
`;
|
|
130
|
+
const imageLink = imageData.link;
|
|
131
|
+
if (imageLink) {
|
|
132
|
+
content = `<a href="${cleanLink(imageLink)}" title="${imageLink}">${content}</a>`;
|
|
133
|
+
}
|
|
134
|
+
return content;
|
|
135
|
+
})
|
|
51
136
|
// Internal links: [[Page]] and [[Page|Text]]
|
|
52
|
-
.replace((0, common_1.RegExpBuilder)(r `\[\[ ([^\]|]+?) \]\]`),
|
|
53
|
-
|
|
137
|
+
.replace((0, common_1.RegExpBuilder)(r `\[\[ ([^\]|]+?) \]\]`), (_, link) => {
|
|
138
|
+
if (_.includes('{{'))
|
|
139
|
+
return _;
|
|
140
|
+
const content = `<a class="internal-link" title="${link}" href="./${cleanLink(link)}">${link}</a>`;
|
|
141
|
+
return content;
|
|
142
|
+
})
|
|
143
|
+
.replace((0, common_1.RegExpBuilder)(r `\[\[ ([^\]|]+?) \| ([^\]]+?) \]\]`), (_, link, text) => {
|
|
144
|
+
if (link.includes('{{'))
|
|
145
|
+
return _;
|
|
146
|
+
const content = `<a class="internal-link" title="${link}" href="./${cleanLink(link)}">${text}</a>`;
|
|
147
|
+
return content;
|
|
148
|
+
})
|
|
54
149
|
.replace((0, common_1.RegExpBuilder)(r `(</a>)([a-z]+)`), '$2$1')
|
|
55
150
|
// External links: [href Page] and just [href]
|
|
56
|
-
.replace((0, common_1.RegExpBuilder)(r `\[ ((?:\w+:)?\/\/ [^\s\]]+) (\s [^\]]+?)? \]`), (_, href, txt) =>
|
|
151
|
+
.replace((0, common_1.RegExpBuilder)(r `\[ ((?:\w+:)?\/\/ [^\s\]]+) (\s [^\]]+?)? \]`), (_, href, txt) => {
|
|
152
|
+
if (_.includes('{{'))
|
|
153
|
+
return _;
|
|
154
|
+
const content = `<a class="external-link" href="${href}">${txt || '[' + (++rawExtLinkCount) + ']'}</a>`;
|
|
155
|
+
return content;
|
|
156
|
+
})
|
|
57
157
|
// Magic words: {{!}}, {{reflist}}, etc
|
|
58
|
-
.replace((0, common_1.RegExpBuilder)(r `{{ \s* ! \s* }}`), escaper('VERT'
|
|
59
|
-
.replace((0, common_1.RegExpBuilder)(r `{{ \s*
|
|
158
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* ! \s* }}`), escaper('VERT'))
|
|
159
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* !! \s* }}`), escaper('VERT').repeat(2))
|
|
160
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* = \s* }}`), escaper('EQUALS'))
|
|
60
161
|
.replace((0, common_1.RegExpBuilder)(r `{{ \s* [Rr]eflist \s* }}`), '<references/>')
|
|
61
162
|
// Metadata: displayTitle, __NOTOC__, etc
|
|
62
163
|
.replace((0, common_1.RegExpBuilder)(r `{{ \s* displayTitle: ([^}]+) }}`), (_, title) => (metadata.displayTitle = title, ''))
|
|
@@ -78,9 +179,40 @@ function parse(data, config = {}) {
|
|
|
78
179
|
.replace((0, common_1.RegExpBuilder)(r `{{ \s* #? padright: ${arg} \|${arg} \|${arg} }}`), (_, str, n, char) => str.padEnd(+n, char))
|
|
79
180
|
.replace((0, common_1.RegExpBuilder)(r `{{ \s* #? replace: ${arg} \|${arg} \|${arg} }}`), (_, str, find, rep) => str.split(find).join(rep))
|
|
80
181
|
.replace((0, common_1.RegExpBuilder)(r `{{ \s* #? explode: ${arg} \|${arg} \|${arg} }}`), (_, str, delim, pos) => str.split(delim)[+pos])
|
|
182
|
+
// Magic functions: {{#ev:youtube}}, etc
|
|
183
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* #? ev: \s* (\w+) \s* \| \s* ( [^{}]+ ) \s* }} ( ?!} )`), (_, platform, args) => {
|
|
184
|
+
var _a;
|
|
185
|
+
// See mediawiki.org/wiki/Extension:EmbedVideo_(fork) for docs
|
|
186
|
+
const params = args.split('|');
|
|
187
|
+
for (let i = 0; i < 10; i++)
|
|
188
|
+
(_a = params[i]) !== null && _a !== void 0 ? _a : (params[i] = ''); // fill up with empty strings
|
|
189
|
+
const [id, dimensions, alignment, description, container, urlargs, autoresize] = params;
|
|
190
|
+
const { width, height } = parseDimensions(dimensions);
|
|
191
|
+
const source = {
|
|
192
|
+
// Add platforms
|
|
193
|
+
'youtube': `//www.youtube.com/embed/${id}`,
|
|
194
|
+
'vimeo': `//player.vimeo.com/video/${id}`,
|
|
195
|
+
}[platform];
|
|
196
|
+
if (!source)
|
|
197
|
+
return `<code>Failed to load video ${id} from ${platform}.</code>`;
|
|
198
|
+
return `
|
|
199
|
+
<iframe key="${KEY}"
|
|
200
|
+
src="${source}"
|
|
201
|
+
width="${width}"
|
|
202
|
+
height="${height}"
|
|
203
|
+
frameborder="0"
|
|
204
|
+
allowfullscreen="true"
|
|
205
|
+
loading="lazy"
|
|
206
|
+
title="${description !== null && description !== void 0 ? description : 'Play video'}"
|
|
207
|
+
${alignment ? `style="float: ${alignment};"` : ''}
|
|
208
|
+
>
|
|
209
|
+
</iframe>
|
|
210
|
+
${description ? `<figcaption>${description}</figcaption>` : ''}
|
|
211
|
+
`;
|
|
212
|
+
})
|
|
81
213
|
// Parser functions: {{#if:}}, {{#switch:}}, etc
|
|
82
|
-
.replace((0, common_1.RegExpBuilder)(r `{{ \s* (#\w+) \s* : \s* ( [^{}]+ ) \s* }}
|
|
83
|
-
if (
|
|
214
|
+
.replace((0, common_1.RegExpBuilder)(r `{{ \s* (#\w+) \s* : \s* ( [^{}]+ ) \s* }} ( ?!} )`), (_, name, content) => {
|
|
215
|
+
if (content.includes('{{'))
|
|
84
216
|
return _;
|
|
85
217
|
const args = content.trim().split(/\s*\|\s*/);
|
|
86
218
|
switch (name) {
|
|
@@ -112,8 +244,11 @@ function parse(data, config = {}) {
|
|
|
112
244
|
}
|
|
113
245
|
})
|
|
114
246
|
// Templates: {{template}}
|
|
115
|
-
.replace((0, common_1.RegExpBuilder)(r `(?<!{) {{ \s* ([^#{}|]+?) (\|[^{}]+)? }} (?!})`), (_, title, params = '') => {
|
|
116
|
-
|
|
247
|
+
.replace((0, common_1.RegExpBuilder)(r `(?<!{) {{ \s* ([^#{}|]+?) \s* (\|[^{}]+)? }} (?!})`), (_, title, params = '') => {
|
|
248
|
+
if (params.includes('{{'))
|
|
249
|
+
return _;
|
|
250
|
+
const templateFile = title.trim().replace(/ /g, '_');
|
|
251
|
+
const page = path_1.default.join(templatesFolder, templateFile);
|
|
117
252
|
let content = '';
|
|
118
253
|
// Try retrieve template content
|
|
119
254
|
try {
|
|
@@ -125,106 +260,26 @@ function parse(data, config = {}) {
|
|
|
125
260
|
return `<a class="internal-link redlink" title="${title}" href="${relPage}">${title}</a>`;
|
|
126
261
|
}
|
|
127
262
|
// Remove non-template sections
|
|
128
|
-
content = content
|
|
263
|
+
content = content.trim()
|
|
129
264
|
.replace(/<noinclude>.*?<\/noinclude>/gs, '')
|
|
130
265
|
.replace(/.*<(includeonly|onlyinclude)>|<\/(includeonly|onlyinclude)>.*/gs, '');
|
|
131
266
|
// Substitute arguments
|
|
132
267
|
const argMatch = (arg) => (0, common_1.RegExpBuilder)(r `{{{ \s* ${arg} (?:\|([^}]*))? \s* }}}`);
|
|
133
268
|
const args = params.split('|');
|
|
134
|
-
// provided key=value template arguments
|
|
269
|
+
// parse provided key=value template arguments
|
|
135
270
|
for (let i = 1; i < args.length; i++) {
|
|
136
|
-
const
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
271
|
+
const data = args[i];
|
|
272
|
+
const parts = data.split('=');
|
|
273
|
+
const isNamed = parts.length > 1;
|
|
274
|
+
const arg = isNamed ? parts[0] : i.toString();
|
|
275
|
+
const val = isNamed ? parts.slice(1).join('=') : data;
|
|
276
|
+
content = content.replace(argMatch(arg), (_, defaultVal) => (val || defaultVal || '').trim());
|
|
141
277
|
}
|
|
142
278
|
return content;
|
|
143
279
|
})
|
|
144
280
|
// Unparsed arguments
|
|
145
|
-
.replace((0, common_1.RegExpBuilder)(r `{{{ \s* [^{}|]+? (?:\|([^}]*))? \s* }}}`), (_,
|
|
281
|
+
.replace((0, common_1.RegExpBuilder)(r `{{{ \s* [^{}|]+? (?:\|([^}]*))? \s* }}}`), (_, defaultVal) => {
|
|
146
282
|
return defaultVal !== null && defaultVal !== void 0 ? defaultVal : '';
|
|
147
|
-
})
|
|
148
|
-
// Images: [[File:Image.png|options|caption]]
|
|
149
|
-
.replace((0, common_1.RegExpBuilder)(r `\[\[ (?:File|Image): (.+?) (\|.+?)? \]\]`), (_, file, params = '') => {
|
|
150
|
-
if (/{{/.test(params))
|
|
151
|
-
return _;
|
|
152
|
-
const path = path_1.default.join(imagesFolder, file.trim().replace(/ /g, '_'));
|
|
153
|
-
let caption = '';
|
|
154
|
-
let imageData = {};
|
|
155
|
-
let imageArgs = params.split('|').map((arg) => arg.replace(/"/g, '"'));
|
|
156
|
-
for (const param of imageArgs) {
|
|
157
|
-
if (['left', 'right', 'center', 'none'].includes(param)) {
|
|
158
|
-
imageData.float = param;
|
|
159
|
-
}
|
|
160
|
-
if (['baseline', 'sub', 'super', 'top', 'text-bottom', 'middle', 'bottom', 'text-bottom'].includes(param)) {
|
|
161
|
-
imageData.align = param;
|
|
162
|
-
}
|
|
163
|
-
else if (['border', 'frameless', 'frame', 'framed', 'thumb', 'thumbnail'].includes(param)) {
|
|
164
|
-
imageData.type = { framed: 'frame', thumbnail: 'thumb' }[param] || param;
|
|
165
|
-
if (imageData.type === 'thumb') {
|
|
166
|
-
imageData.hasCaption = true;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
else if (param.endsWith('px')) {
|
|
170
|
-
param.replace(/(?:(\w+)?(x))?(\w+)px/, (_, size1, auto, size2) => {
|
|
171
|
-
if (size1) {
|
|
172
|
-
Object.assign(imageData, { width: size1, height: size2 });
|
|
173
|
-
}
|
|
174
|
-
else if (auto) {
|
|
175
|
-
Object.assign(imageData, { width: 'auto', height: size2 });
|
|
176
|
-
}
|
|
177
|
-
else {
|
|
178
|
-
Object.assign(imageData, { width: size2, height: 'auto' });
|
|
179
|
-
}
|
|
180
|
-
return '';
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
else if (param.startsWith('upright=')) {
|
|
184
|
-
imageData.width = +param.replace('upright=', '') * 300;
|
|
185
|
-
}
|
|
186
|
-
else if (param.startsWith('link=')) {
|
|
187
|
-
imageData.link = param.replace('link=', '');
|
|
188
|
-
}
|
|
189
|
-
else if (param.startsWith('alt=')) {
|
|
190
|
-
imageData.alt = param.replace('alt=', '');
|
|
191
|
-
}
|
|
192
|
-
else if (param.startsWith('style=')) {
|
|
193
|
-
imageData.style = param.replace('style=', '');
|
|
194
|
-
}
|
|
195
|
-
else if (param.startsWith('class=')) {
|
|
196
|
-
imageData.class = param.replace('class=', '');
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
199
|
-
caption = param;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
let content = `
|
|
203
|
-
<figure
|
|
204
|
-
class="
|
|
205
|
-
${imageData.class || ''}
|
|
206
|
-
image-container
|
|
207
|
-
image-${imageData.type || 'default'}
|
|
208
|
-
"
|
|
209
|
-
style="
|
|
210
|
-
float: ${imageData.float || 'none'};
|
|
211
|
-
vertical-align: ${imageData.align || 'unset'};
|
|
212
|
-
${imageData.style || ''}
|
|
213
|
-
"
|
|
214
|
-
>
|
|
215
|
-
<img
|
|
216
|
-
src="${path_1.default.basename(imagesFolder)}/${path_1.default.relative(imagesFolder, path)}"
|
|
217
|
-
alt="${imageData.alt || file}"
|
|
218
|
-
width="${imageData.width || 300}"
|
|
219
|
-
height="${imageData.height || 300}"
|
|
220
|
-
>
|
|
221
|
-
${imageData.hasCaption ? `<figcaption>${caption}</figcaption>` : ''}
|
|
222
|
-
</figure>
|
|
223
|
-
`;
|
|
224
|
-
if (imageData.link) {
|
|
225
|
-
content = `<a href="/${imageData.link}" title="${imageData.link}">${content}</a>`;
|
|
226
|
-
}
|
|
227
|
-
return content;
|
|
228
283
|
})
|
|
229
284
|
// Markup: '''bold''' and '''italic'''
|
|
230
285
|
.replace((0, common_1.RegExpBuilder)(r `''' ([^']+?) '''`), '<b>$1</b>')
|
|
@@ -232,46 +287,89 @@ function parse(data, config = {}) {
|
|
|
232
287
|
// Headings: ==heading==
|
|
233
288
|
.replace((0, common_1.RegExpBuilder)(r `^ (=+) \s* (.+?) \s* \1 \s* $`), (_, lvl, txt) => `<h${lvl.length} id="${encodeURI(txt.replace(/ /g, '_'))}">${txt}</h${lvl.length}>`)
|
|
234
289
|
// Bulleted list: *item
|
|
235
|
-
.replace((0, common_1.RegExpBuilder)(r `^ (\*+) (.+?) $`), (_, lvl,
|
|
290
|
+
.replace((0, common_1.RegExpBuilder)(r `^ (\*+) (.+?) $`), (_, lvl, content) => {
|
|
291
|
+
if (content.includes('{{'))
|
|
292
|
+
return _;
|
|
293
|
+
const depth = lvl.length;
|
|
294
|
+
return `${'<ul>'.repeat(depth)}<li>${content}</li>${'</ul>'.repeat(depth)}`;
|
|
295
|
+
})
|
|
236
296
|
.replace((0, common_1.RegExpBuilder)(r `</ul> (\s*?) <ul>`), '$1')
|
|
237
297
|
// Numbered list: #item
|
|
238
|
-
.replace((0, common_1.RegExpBuilder)(r `^ (#+) (.+?) $`), (_, lvl,
|
|
298
|
+
.replace((0, common_1.RegExpBuilder)(r `^ (#+) (.+?) $`), (_, lvl, content) => {
|
|
299
|
+
if (content.includes('{{'))
|
|
300
|
+
return _;
|
|
301
|
+
const depth = lvl.length;
|
|
302
|
+
return `${'<ol>'.repeat(depth)}<li>${content}</li>${'</ol>'.repeat(depth)}`;
|
|
303
|
+
})
|
|
239
304
|
.replace((0, common_1.RegExpBuilder)(r `</ol> (\s*?) <ol>`), '$1')
|
|
240
305
|
// Definition list: ;head, :item
|
|
241
306
|
.replace((0, common_1.RegExpBuilder)(r `^ ; (.+?) : (.+?) $`), `<dl><dt>$1</td><dd>$2</dd></dl>`)
|
|
242
|
-
.replace((0, common_1.RegExpBuilder)(r `^ (:+) (.+?) $`), (_, lvl,
|
|
307
|
+
.replace((0, common_1.RegExpBuilder)(r `^ (:+) (.+?) $`), (_, lvl, content) => {
|
|
308
|
+
if (content.includes('{{'))
|
|
309
|
+
return _;
|
|
310
|
+
const depth = lvl.length;
|
|
311
|
+
return `${'<dl>'.repeat(depth)}<dd>${content}</dd>${'</dl>'.repeat(depth)}`;
|
|
312
|
+
})
|
|
243
313
|
.replace((0, common_1.RegExpBuilder)(r `^ ; (.+) $`), '<dl><dt>$1</dt></dl>')
|
|
244
314
|
.replace((0, common_1.RegExpBuilder)(r `</dl> (\s*?) <dl>`), '$1')
|
|
245
315
|
// Tables: {|, |+, !, |-, |, |}
|
|
246
|
-
.replace(
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
316
|
+
.replace(/\{\|.+\|\}/gs, (tableInner) => {
|
|
317
|
+
return tableInner
|
|
318
|
+
// {| data (open table)
|
|
319
|
+
.replace((0, common_1.RegExpBuilder)(r `^ \{\| (.*?) $`), (_, attrs) => `<table ${attrs}><tr>`)
|
|
320
|
+
// |+ data
|
|
321
|
+
.replace((0, common_1.RegExpBuilder)(r `^ \|\+ (.*?) $`), (_, content) => `<caption>${content}</caption>`)
|
|
322
|
+
// |- (new row)
|
|
323
|
+
.replace((0, common_1.RegExpBuilder)(r `^ \|- (.*?) $`), (_, attrs) => `</tr><tr ${attrs}>`)
|
|
324
|
+
// |} (close)
|
|
325
|
+
.replace((0, common_1.RegExpBuilder)(r `^ \|\}`), `</tr></table>`)
|
|
326
|
+
// content: !head, !data|head, |text, |data|text, !!head, ||data
|
|
327
|
+
.replace((0, common_1.RegExpBuilder)(r `( ^! | ^\| | !! | \|\| ) (?: ( [^|\n]+? ) \|)? ( [^|\n]*? ) (?= $ | !! | \|\| )`), (_, type, data, content) => {
|
|
328
|
+
const elem = /!/.test(type) ? 'th' : 'td';
|
|
329
|
+
return `<${elem} ${data !== null && data !== void 0 ? data : ''}>${content}</${elem}>`;
|
|
330
|
+
});
|
|
331
|
+
})
|
|
332
|
+
// References: <ref></ref>
|
|
333
|
+
.replace((0, common_1.RegExpBuilder)(r `< ref \s* (?: name \s* = \s* ["']? ([^>'"]+) ["']? [^>]* )?> (.+?) </ ref >`), (_, refname, text) => {
|
|
334
|
+
if (_.includes('{{'))
|
|
335
|
+
return _;
|
|
336
|
+
const refData = { ref: text, n: refs.length + 1, name: refname };
|
|
337
|
+
refs.push(refData);
|
|
338
|
+
return `<sup class="refnote"><a id="cite-${refData.n}" class="ref" href="#ref-${refData.n}">[${refData.n}]</a></sup>`;
|
|
339
|
+
})
|
|
340
|
+
.replace((0, common_1.RegExpBuilder)(r `< ref \s* name \s* = \s* ["']? ( [^>"']+ ) ["']? \s* (?: /> | > .* </ref> )`), (_, refname) => {
|
|
341
|
+
const ref = refs.find(ref => ref.name === refname);
|
|
342
|
+
if (!ref)
|
|
343
|
+
return '';
|
|
344
|
+
return `<sup class="refnote"><a id="cite-${ref.n}" class="ref" href="#ref-${ref.n}">[${ref.n}]</a></sup>`;
|
|
258
345
|
})
|
|
259
|
-
.replace((0, common_1.RegExpBuilder)(r `<references \s* /?>`), '<ol>' + refs.map((ref, i) => `<li id="ref-${+i + 1}"> <a href="#cite-${+i + 1}">↑</a> ${ref} </li>`).join('\n') + '</ol>')
|
|
260
346
|
// Nonstandard: ``code`` and ```code blocks```
|
|
261
347
|
.replace((0, common_1.RegExpBuilder)(r ` \`\`\` ([^\`]+?) \`\`\` `), '<pre>$1</pre>')
|
|
262
348
|
.replace((0, common_1.RegExpBuilder)(r ` \`\` ([^\`]+?) \`\` `), '<code>$1</code>')
|
|
263
349
|
// Spacing
|
|
264
350
|
.replace(/(\r?\n){2}/g, '\n</p><p>\n');
|
|
265
351
|
}
|
|
266
|
-
//
|
|
352
|
+
// Final (one-time) substitutions
|
|
267
353
|
for (let i = 0; i < nowikis.length; i++) {
|
|
268
354
|
outText = outText
|
|
269
|
-
|
|
355
|
+
// Restore nowiki contents
|
|
356
|
+
.replace(escaper('NOWIKI', i), nowikis[i]);
|
|
270
357
|
}
|
|
271
|
-
// Substitute magic word functions
|
|
272
358
|
outText = outText
|
|
273
|
-
|
|
274
|
-
.
|
|
359
|
+
// References: <references />
|
|
360
|
+
.replace((0, common_1.RegExpBuilder)(r `<references \s* /?>`), () => {
|
|
361
|
+
const references = refs.map(({ ref, n }) => {
|
|
362
|
+
const refline = `<li id="ref-${n}"> <a href="#cite-${n}">↑</a> ${ref} </li>`;
|
|
363
|
+
return refline;
|
|
364
|
+
}).join('\n');
|
|
365
|
+
return `<ol>${references}</ol>`;
|
|
366
|
+
})
|
|
367
|
+
// Magic word functions
|
|
368
|
+
.replaceAll(escaper('VERT'), '|')
|
|
369
|
+
.replaceAll(escaper('EQUALS'), '=');
|
|
370
|
+
// Escape all {{ to avoid crashes
|
|
371
|
+
outText = outText
|
|
372
|
+
.replaceAll('{{', '{{');
|
|
275
373
|
const result = { data: outText, metadata: metadata };
|
|
276
374
|
return result;
|
|
277
375
|
}
|
package/dist/wiki.css.js
CHANGED
|
@@ -10,6 +10,7 @@ dd, dl dl {margin-block: 0; margin-inline-start: 30px;}
|
|
|
10
10
|
|
|
11
11
|
figure {margin: 1em;}
|
|
12
12
|
.image-thumb, .image-frame {padding: 6px; border: 1px solid gray;}
|
|
13
|
+
.image-default {margin: 0;}
|
|
13
14
|
figcaption {padding-top: 6px;}
|
|
14
15
|
|
|
15
16
|
table.wikitable {border-collapse: collapse;}
|
|
@@ -25,7 +26,13 @@ a.external-link::after {content: '\1f855';}
|
|
|
25
26
|
a.redlink {color: #d33;}
|
|
26
27
|
a.redlink:visited {color: #b44;}
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
#toc
|
|
29
|
+
sup.refnote {margin-left: -5px;}
|
|
30
|
+
|
|
31
|
+
#page+toc {border: 1px solid #aab; padding: 8px; width: fit-content; background-color: #f8f8f8; font-size: 95%;}
|
|
32
|
+
#page+toc-heading {display: block; text-align: center;}
|
|
33
|
+
#page+toc ol {margin: 0 0 0 1.3em;}
|
|
34
|
+
|
|
35
|
+
#infobox {float: right; clear: right; margin: 0 0 1em 1em; width: 300px; padding: 2px; border: 1px solid #CCC; overflow: auto; font-size: 90%;}
|
|
36
|
+
#infobox tr:first-child :first-child {padding: 10px 10px 0; text-align: center; font-weight: bold; font-size: 120%;}
|
|
37
|
+
#infobox th {padding-left: 10px; text-align: left;}
|
|
31
38
|
`;
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -162,6 +162,7 @@ Your wikitext (`*.wiki`) files go in the root directory by default.
|
|
|
162
162
|
| `{{#explode:A-B-C-D\|-\|2}}` | C |
|
|
163
163
|
| `{{#urlencode:t e x t}}` | t%20e%20x%20t |
|
|
164
164
|
| `{{#urldecode:a%20b%27c}}` | a b'c |
|
|
165
|
+
| `{{#ev:youtube\|dQw4w9WgXcQ}}` | *(YouTube embed)* |
|
|
165
166
|
| `<noinclude>No</noinclude>` | *(blank outside a template)* |
|
|
166
167
|
| `<onlyinclude>Yes</onlyinclude>` | Yes |
|
|
167
168
|
| `<includeonly>Yes</includeonly>` | Yes *(blank inside a template)* |
|