wikity 1.3.0 → 1.3.2
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/bin/index.js +2 -0
- package/dist/cli.d.ts +1 -0
- package/{src → dist}/cli.js +58 -47
- package/dist/common.d.ts +20 -0
- package/dist/common.js +7 -0
- package/{src → dist}/compile.d.ts +3 -3
- package/dist/compile.js +145 -0
- package/{src → dist}/index.d.ts +11 -8
- package/dist/index.js +11 -0
- package/{src → dist}/parse.d.ts +3 -3
- package/dist/parse.js +271 -0
- package/dist/wiki.css.d.ts +2 -0
- package/dist/wiki.css.js +31 -0
- package/license.md +1 -1
- package/package.json +55 -54
- package/readme.md +49 -20
- package/src/cli.d.ts +0 -2
- package/src/common.d.ts +0 -15
- package/src/common.js +0 -15
- package/src/compile.js +0 -153
- package/src/index.js +0 -8
- package/src/parse.js +0 -239
package/src/parse.js
DELETED
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parse = exports.rawParse = void 0;
|
|
4
|
-
const fs = require('fs');
|
|
5
|
-
const htmlEscape = require('escape-html');
|
|
6
|
-
const dateFormat = require('dateformat');
|
|
7
|
-
const common_1 = require("./common");
|
|
8
|
-
const r = String.raw;
|
|
9
|
-
const MAX_RECURSION = 20;
|
|
10
|
-
const arg = r `\s*([^|}]+?)\s*`;
|
|
11
|
-
function rawParse(data, config = {}) {
|
|
12
|
-
return parse(data, config).toString();
|
|
13
|
-
}
|
|
14
|
-
exports.rawParse = rawParse;
|
|
15
|
-
function parse(data, config = {}) {
|
|
16
|
-
const vars = {};
|
|
17
|
-
const metadata = {};
|
|
18
|
-
let nowikis = [];
|
|
19
|
-
let nowikiCount = 0;
|
|
20
|
-
let rawExtLinkCount = 0;
|
|
21
|
-
let refCount = 0;
|
|
22
|
-
let refs = [];
|
|
23
|
-
let outText = data;
|
|
24
|
-
for (let l = 0, last = ''; l < MAX_RECURSION; l++) {
|
|
25
|
-
if (last === outText)
|
|
26
|
-
break;
|
|
27
|
-
last = outText;
|
|
28
|
-
outText = outText
|
|
29
|
-
// Nowiki: <nowiki></nowiki>
|
|
30
|
-
.replace(common_1.RegExpBuilder(r `<nowiki> ([^]+?) </nowiki>`), (_, m) => `%NOWIKI#${nowikis.push(m), nowikiCount++}%`)
|
|
31
|
-
// Sanitise unacceptable HTML
|
|
32
|
-
.replace(common_1.RegExpBuilder(r `<(/?) \s* (?= script|link|meta|iframe|frameset|object|embed|applet|form|input|button|textarea )`), '<$1')
|
|
33
|
-
.replace(common_1.RegExpBuilder(r `(?<= <[^>]+ ) (\bon(\w+))`), 'data-$2')
|
|
34
|
-
// Comments: <!-- -->
|
|
35
|
-
.replace(/<!--[^]+?-->/g, '')
|
|
36
|
-
// Lines: ----
|
|
37
|
-
.replace(/^-{4,}/gm, '<hr>')
|
|
38
|
-
// Metadata: displayTitle, __NOTOC__, etc
|
|
39
|
-
.replace(common_1.RegExpBuilder(r `{{ \s* displayTitle: ([^}]+) }}`), (_, title) => (metadata.displayTitle = title, ''))
|
|
40
|
-
.replace(common_1.RegExpBuilder(r `__NOINDEX__`), () => (metadata.noindex = true, ''))
|
|
41
|
-
.replace(common_1.RegExpBuilder(r `__NOTOC__`), () => (metadata.notoc = true, ''))
|
|
42
|
-
.replace(common_1.RegExpBuilder(r `__FORCETOC__`), () => (metadata.toc = true, ''))
|
|
43
|
-
.replace(common_1.RegExpBuilder(r `__TOC__`), () => (metadata.toc = true, `<toc></toc>`))
|
|
44
|
-
// Magic words: {{!}}, {{reflist}}, etc
|
|
45
|
-
.replace(common_1.RegExpBuilder(r `{{ \s* ! \s* }}`), '|')
|
|
46
|
-
.replace(common_1.RegExpBuilder(r `{{ \s* = \s* }}`), '=')
|
|
47
|
-
.replace(common_1.RegExpBuilder(r `{{ \s* [Rr]eflist \s* }}`), '<references/>')
|
|
48
|
-
// String functions: {{lc:}}, {{ucfirst:}}, {{len:}}, etc
|
|
49
|
-
.replace(common_1.RegExpBuilder(r `{{ \s* #? urlencode: ${arg} }}`), (_, m) => encodeURI(m))
|
|
50
|
-
.replace(common_1.RegExpBuilder(r `{{ \s* #? urldecode: ${arg} }}`), (_, m) => decodeURI(m))
|
|
51
|
-
.replace(common_1.RegExpBuilder(r `{{ \s* #? lc: ${arg} }}`), (_, m) => m.toLowerCase())
|
|
52
|
-
.replace(common_1.RegExpBuilder(r `{{ \s* #? uc: ${arg} }}`), (_, m) => m.toUpperCase())
|
|
53
|
-
.replace(common_1.RegExpBuilder(r `{{ \s* #? lcfirst: ${arg} }}`), (_, m) => m[0].toLowerCase() + m.substr(1))
|
|
54
|
-
.replace(common_1.RegExpBuilder(r `{{ \s* #? ucfirst: ${arg} }}`), (_, m) => m[0].toUpperCase() + m.substr(1))
|
|
55
|
-
.replace(common_1.RegExpBuilder(r `{{ \s* #? len: ${arg} }}`), (_, m) => m.length)
|
|
56
|
-
.replace(common_1.RegExpBuilder(r `{{ \s* #? pos: ${arg} \|${arg} (?: \s*\|${arg} )? }}`), (_, find, str, n = 0) => find.substr(n).indexOf(str))
|
|
57
|
-
.replace(common_1.RegExpBuilder(r `{{ \s* #? sub: ${arg} \|${arg} (?:\|${arg})? }}`), (_, str, from, len) => str.substr(+from - 1, +len))
|
|
58
|
-
.replace(common_1.RegExpBuilder(r `{{ \s* #? padleft: ${arg} \|${arg} \|${arg} }}`), (_, str, n, char) => str.padStart(+n, char))
|
|
59
|
-
.replace(common_1.RegExpBuilder(r `{{ \s* #? padright: ${arg} \|${arg} \|${arg} }}`), (_, str, n, char) => str.padEnd(+n, char))
|
|
60
|
-
.replace(common_1.RegExpBuilder(r `{{ \s* #? replace: ${arg} \|${arg} \|${arg} }}`), (_, str, find, rep) => str.split(find).join(rep))
|
|
61
|
-
.replace(common_1.RegExpBuilder(r `{{ \s* #? explode: ${arg} \|${arg} \|${arg} }}`), (_, str, delim, pos) => str.split(delim)[+pos])
|
|
62
|
-
// Parser functions: {{#if:}}, {{#switch:}}, etc
|
|
63
|
-
.replace(common_1.RegExpBuilder(r `{{ \s* (#\w+) \s* : \s* ( [^{}]+ ) \s* }} ( ?!} )`), (_, name, content) => {
|
|
64
|
-
if (/{{\s*#/.test(content))
|
|
65
|
-
return _;
|
|
66
|
-
const args = content.trim().split(/\s*\|\s*/);
|
|
67
|
-
switch (name) {
|
|
68
|
-
case '#if':
|
|
69
|
-
return (args[0] ? args[1] : args[2]) || '';
|
|
70
|
-
case '#ifeq':
|
|
71
|
-
return (args[0] === args[1] ? args[2] : args[3]) || '';
|
|
72
|
-
case '#vardefine':
|
|
73
|
-
vars[args[0]] = args[1] || '';
|
|
74
|
-
return '';
|
|
75
|
-
case '#var':
|
|
76
|
-
if (common_1.RegExpBuilder(r `{{ \s* #vardefine \s* : \s* ${args[0]}`).test(outText))
|
|
77
|
-
return _; // wait until var is set
|
|
78
|
-
return vars[args[0]] || args[1] || '';
|
|
79
|
-
case '#switch':
|
|
80
|
-
return args.slice(1)
|
|
81
|
-
.map(arg => arg.split(/\s*=\s*/))
|
|
82
|
-
.filter(duo => args[0] === duo[0].replace('#default', args[0]))[0][1];
|
|
83
|
-
case '#time':
|
|
84
|
-
case '#date':
|
|
85
|
-
case '#datetime':
|
|
86
|
-
// make sure the characters are not inside a string
|
|
87
|
-
let parsedMatch = args[0].replace(/".+?"/g, '').replace(/'.+?'/g, '');
|
|
88
|
-
if (/[abcefgijkqruvx]/i.test(parsedMatch)) {
|
|
89
|
-
console.warn(`<Wikity> [WARN] Wikity does not use Wikipedia's #time function syntax. Use repetition-based formatting instead.`);
|
|
90
|
-
}
|
|
91
|
-
return dateFormat(args[1] ? new Date(args[1]) : new Date(), args[0]);
|
|
92
|
-
}
|
|
93
|
-
})
|
|
94
|
-
// Templates: {{template}}
|
|
95
|
-
.replace(common_1.RegExpBuilder(r `{{ \s* ([^#}|]+?) (\|[^}]+)? }} (?!})`), (_, title, params = '') => {
|
|
96
|
-
if (/{{/.test(params))
|
|
97
|
-
return _;
|
|
98
|
-
const page = (config.templatesFolder || 'templates') + '/' + title.trim().replace(/ /g, '_');
|
|
99
|
-
// Retrieve template content
|
|
100
|
-
let content = '';
|
|
101
|
-
try {
|
|
102
|
-
content = fs.readFileSync('./' + page + '.wiki', { encoding: 'utf8' });
|
|
103
|
-
}
|
|
104
|
-
catch {
|
|
105
|
-
return `<a class="internal-link redlink" title="${title}" href="${page}">${title}</a>`;
|
|
106
|
-
}
|
|
107
|
-
// Remove non-template sections
|
|
108
|
-
content = content
|
|
109
|
-
.replace(/<noinclude>.*?<\/noinclude>/gs, '')
|
|
110
|
-
.replace(/.*<(includeonly|onlyinclude)>|<\/(includeonly|onlyinclude)>.*/gs, '');
|
|
111
|
-
// Substitite arguments
|
|
112
|
-
const argMatch = (arg) => common_1.RegExpBuilder(r `{{{ \s* ${arg} (?:\|([^}]*))? \s* }}}`);
|
|
113
|
-
let args = params.split('|').slice(1);
|
|
114
|
-
for (let i in args) {
|
|
115
|
-
let parts = args[i].split('=');
|
|
116
|
-
let [arg, val] = parts[1] ? [parts[0], ...parts.slice(1)] : [(+i + 1) + '', parts[0]];
|
|
117
|
-
content = content.replace(argMatch(arg), (_, m) => val || m || '');
|
|
118
|
-
}
|
|
119
|
-
for (let i = 1; i <= 10; i++) {
|
|
120
|
-
content = content.replace(argMatch(arg), '$2');
|
|
121
|
-
}
|
|
122
|
-
return content;
|
|
123
|
-
})
|
|
124
|
-
// Images: [[File:Image.png|options|caption]]
|
|
125
|
-
.replace(common_1.RegExpBuilder(r `\[\[ (?:File|Image): (.+?) (\|.+?)? \]\]`), (_, file, params) => {
|
|
126
|
-
if (/{{/.test(params))
|
|
127
|
-
return _;
|
|
128
|
-
const path = (config.imagesFolder || 'images') + '/' + file.trim().replace(/ /g, '_');
|
|
129
|
-
let caption = '';
|
|
130
|
-
let imageData = {};
|
|
131
|
-
let imageArgs = params.split('|').map((arg) => arg.replace(/"/g, '"'));
|
|
132
|
-
for (const param of imageArgs) {
|
|
133
|
-
if (['left', 'right', 'center', 'none'].includes(param)) {
|
|
134
|
-
imageData.float = param;
|
|
135
|
-
}
|
|
136
|
-
if (['baseline', 'sub', 'super', 'top', 'text-bottom', 'middle', 'bottom', 'text-bottom'].includes(param)) {
|
|
137
|
-
imageData.align = param;
|
|
138
|
-
}
|
|
139
|
-
else if (['border', 'frameless', 'frame', 'framed', 'thumb', 'thumbnail'].includes(param)) {
|
|
140
|
-
imageData.type = { framed: 'frame', thumbnail: 'thumb' }[param] || param;
|
|
141
|
-
if (imageData.type === 'thumb')
|
|
142
|
-
imageData.hasCaption = true;
|
|
143
|
-
}
|
|
144
|
-
else if (param.endsWith('px')) {
|
|
145
|
-
param.replace(/(?:(\w+)?(x))?(\w+)px/, (_, size1, auto, size2) => {
|
|
146
|
-
if (size1)
|
|
147
|
-
Object.assign(imageData, { width: size1, height: size2 });
|
|
148
|
-
else if (auto)
|
|
149
|
-
Object.assign(imageData, { width: 'auto', height: size2 });
|
|
150
|
-
else
|
|
151
|
-
Object.assign(imageData, { width: size2, height: 'auto' });
|
|
152
|
-
return '';
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
else if (param.startsWith('upright=')) {
|
|
156
|
-
imageData.width = +param.replace('upright=', '') * 300;
|
|
157
|
-
}
|
|
158
|
-
else if (param.startsWith('link=')) {
|
|
159
|
-
imageData.link = param.replace('link=', '');
|
|
160
|
-
}
|
|
161
|
-
else if (param.startsWith('alt=')) {
|
|
162
|
-
imageData.alt = param.replace('alt=', '');
|
|
163
|
-
}
|
|
164
|
-
else if (param.startsWith('style=')) {
|
|
165
|
-
imageData.style = param.replace('style=', '');
|
|
166
|
-
}
|
|
167
|
-
else if (param.startsWith('class=')) {
|
|
168
|
-
imageData.class = param.replace('class=', '');
|
|
169
|
-
}
|
|
170
|
-
else {
|
|
171
|
-
caption = param;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
let content = `
|
|
175
|
-
<figure
|
|
176
|
-
class="${imageData.class || ''} image-container image-${imageData.type || 'default'}"
|
|
177
|
-
style="float:${imageData.float || 'none'};vertical-align:${imageData.align || 'unset'};${imageData.style || ''}"
|
|
178
|
-
>
|
|
179
|
-
<img
|
|
180
|
-
src="${path}"
|
|
181
|
-
alt="${imageData.alt || file}"
|
|
182
|
-
width="${imageData.width || 300}"
|
|
183
|
-
height="${imageData.height || 300}"
|
|
184
|
-
>
|
|
185
|
-
${imageData.hasCaption ? `<figcaption>${caption}</figcaption>` : ''}
|
|
186
|
-
</figure>
|
|
187
|
-
`;
|
|
188
|
-
if (imageData.link)
|
|
189
|
-
content = `<a href="/${imageData.link}" title="${imageData.link}">${content}</a>`;
|
|
190
|
-
return content;
|
|
191
|
-
})
|
|
192
|
-
// Markup: '''bold''' and '''italic'''
|
|
193
|
-
.replace(common_1.RegExpBuilder(r `''' ([^']+?) '''`), '<b>$1</b>')
|
|
194
|
-
.replace(common_1.RegExpBuilder(r `'' ([^']+?) ''`), '<i>$1</i>')
|
|
195
|
-
// Headings: ==heading==
|
|
196
|
-
.replace(common_1.RegExpBuilder(r `^ (=+) \s* (.+?) \s* \1 \s* $`), (_, lvl, txt) => `<h${lvl.length} id="${encodeURI(txt.replace(/ /g, '_'))}">${txt}</h${lvl.length}>`)
|
|
197
|
-
// Internal links: [[Page]] and [[Page|Text]]
|
|
198
|
-
.replace(common_1.RegExpBuilder(r `\[\[ ([^\]|]+?) \]\]`), `<a class="internal-link" title="$1" href="$1">$1</a>`)
|
|
199
|
-
.replace(common_1.RegExpBuilder(r `\[\[ ([^\]|]+?) \| ([^\]]+?) \]\]`), `<a class="internal-link" title="$1" href="/$1">$2</a>`)
|
|
200
|
-
.replace(common_1.RegExpBuilder(r `(</a>)([a-z]+)`), '$2$1')
|
|
201
|
-
// External links: [href Page] and just [href]
|
|
202
|
-
.replace(common_1.RegExpBuilder(r `\[ ((?:\w+:)?\/\/ [^\s\]]+) (\s [^\]]+?)? \]`), (_, href, txt) => `<a class="external-link" href="${href}">${txt || '[' + (++rawExtLinkCount) + ']'}</a>`)
|
|
203
|
-
// Bulleted list: *item
|
|
204
|
-
.replace(common_1.RegExpBuilder(r `^ (\*+) (.+?) $`), (_, lvl, txt) => `${'<ul>'.repeat(lvl.length)}<li>${txt}</li>${'</ul>'.repeat(lvl.length)}`)
|
|
205
|
-
.replace(common_1.RegExpBuilder(r `</ul> (\s*?) <ul>`), '$1')
|
|
206
|
-
// Numbered list: #item
|
|
207
|
-
.replace(common_1.RegExpBuilder(r `^ (#+) (.+?) $`), (_, lvl, txt) => `${'<ol>'.repeat(lvl.length)}<li>${txt}</li>${'</ol>'.repeat(lvl.length)}`)
|
|
208
|
-
.replace(common_1.RegExpBuilder(r `</ol> (\s*?) <ol>`), '$1')
|
|
209
|
-
// Definition list: ;head, :item
|
|
210
|
-
.replace(common_1.RegExpBuilder(r `^ ; (.+) $`), '<dl><dt>$1</dt></dl>')
|
|
211
|
-
.replace(common_1.RegExpBuilder(r `^ (:+) (.+?) $`), (_, lvl, txt) => `${'<dl>'.repeat(lvl.length)}<dd>${txt}</dd>${'</dl>'.repeat(lvl.length)}`)
|
|
212
|
-
.replace(common_1.RegExpBuilder(r `</dl> (\s*?) <dl>`), '$1')
|
|
213
|
-
// Tables: {|, |+, !, |-, |, |}
|
|
214
|
-
.replace(common_1.RegExpBuilder(r `^ \{\| (.*?) $`), (_, attrs) => `<table ${attrs}><tr>`)
|
|
215
|
-
.replace(common_1.RegExpBuilder(r `^ ! ([^]+?) (?= \n^[!|] )`), (_, content) => `<th>${content}</th>`)
|
|
216
|
-
.replace(common_1.RegExpBuilder(r `^ \|\+ (.*?) $`), (_, content) => `<caption>${content}</caption>`)
|
|
217
|
-
.replace(common_1.RegExpBuilder(r `^ \|[^-+}] ([^]*?) (?= \n^[!|] )`), (_, content) => `<td>${content}</td>`)
|
|
218
|
-
.replace(common_1.RegExpBuilder(r `^ \|- (.*?) $`), (_, attrs) => `</tr><tr ${attrs}>`)
|
|
219
|
-
.replace(common_1.RegExpBuilder(r `^ \|\}`), `</tr></table>`)
|
|
220
|
-
// References: <ref></ref>, <references/>
|
|
221
|
-
.replace(common_1.RegExpBuilder(r `<ref> (.+?) </ref>`), (_, text) => {
|
|
222
|
-
refs.push(text);
|
|
223
|
-
refCount++;
|
|
224
|
-
return `<sup><a id="cite-${refCount}" class="ref" href="#ref-${refCount}">[${refCount}]</a></sup>`;
|
|
225
|
-
})
|
|
226
|
-
.replace(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>')
|
|
227
|
-
// Nonstandard: ``code`` and ```code blocks```
|
|
228
|
-
.replace(common_1.RegExpBuilder(r ` \`\`\` ([^\`]+?) \`\`\` `), '<pre>$1</pre>')
|
|
229
|
-
.replace(common_1.RegExpBuilder(r ` \`\` ([^\`]+?) \`\` `), '<code>$1</code>')
|
|
230
|
-
// Spacing
|
|
231
|
-
.replace(/(\r?\n){2}/g, '\n</p><p>\n')
|
|
232
|
-
// Restore nowiki contents
|
|
233
|
-
.replace(/%NOWIKI#(\d+)%/g, (_, n) => htmlEscape(nowikis[n]));
|
|
234
|
-
}
|
|
235
|
-
let result = new common_1.Result(outText);
|
|
236
|
-
result.metadata = metadata;
|
|
237
|
-
return result;
|
|
238
|
-
}
|
|
239
|
-
exports.parse = parse;
|