wikity 1.3.0 → 1.3.1

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/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 )`), '&lt;$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* }}`), '&vert;')
46
- .replace(common_1.RegExpBuilder(r `{{ \s* = \s* }}`), '&equals;')
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, '&quot;'));
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;