@bhsd/codemirror-mediawiki 2.29.1 → 2.30.0
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/README.md +1 -2
- package/dist/codemirror.js +19 -4
- package/dist/config.d.ts +1 -0
- package/dist/config.js +1 -0
- package/dist/fold.d.ts +4 -2
- package/dist/fold.js +31 -14
- package/dist/linter.d.ts +15 -6
- package/dist/linter.js +18 -9
- package/dist/main.min.js +20 -20
- package/dist/mw.min.js +25 -25
- package/dist/openLinks.js +19 -8
- package/dist/statusBar.js +2 -2
- package/dist/token.js +1529 -1432
- package/dist/wiki.min.js +24 -24
- package/i18n/en.json +3 -2
- package/i18n/zh-hans.json +3 -2
- package/i18n/zh-hant.json +3 -2
- package/mediawiki.css +1 -1
- package/package.json +6 -6
package/dist/token.js
CHANGED
|
@@ -3,6 +3,40 @@
|
|
|
3
3
|
* @license GPL-2.0-or-later
|
|
4
4
|
* @see https://gerrit.wikimedia.org/g/mediawiki/extensions/CodeMirror
|
|
5
5
|
*/
|
|
6
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
7
|
+
var useValue = arguments.length > 2;
|
|
8
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
9
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
10
|
+
}
|
|
11
|
+
return useValue ? value : void 0;
|
|
12
|
+
};
|
|
13
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
14
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
15
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
16
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
17
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
18
|
+
var _, done = false;
|
|
19
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
20
|
+
var context = {};
|
|
21
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
22
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
23
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
24
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
25
|
+
if (kind === "accessor") {
|
|
26
|
+
if (result === void 0) continue;
|
|
27
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
28
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
29
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
30
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
31
|
+
}
|
|
32
|
+
else if (_ = accept(result)) {
|
|
33
|
+
if (kind === "field") initializers.unshift(_);
|
|
34
|
+
else descriptor[key] = _;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
38
|
+
done = true;
|
|
39
|
+
};
|
|
6
40
|
import { Tag } from '@lezer/highlight';
|
|
7
41
|
import { decodeHTML, getRegex } from '@bhsd/common';
|
|
8
42
|
import { otherParserFunctions } from '@bhsd/common/dist/cm';
|
|
@@ -313,1576 +347,1639 @@ const syntaxHighlight = new Set(['syntaxhighlight', 'source', 'pre']), pageFunct
|
|
|
313
347
|
? /<\/onlyinclude(?:>|$)/u
|
|
314
348
|
: new RegExp(String.raw `</${name}\s*(?:>|$)`, 'iu')), getNestedRegex = getRegex(tag => new RegExp(String.raw `^(?:[^<]|<(?!${tag}(?:[\s/>]|$)))+`, 'iu'));
|
|
315
349
|
/** Adapted from the original CodeMirror 5 stream parser by Pavel Astakhov */
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
this.
|
|
350
|
+
let MediaWiki = (() => {
|
|
351
|
+
let _instanceExtraInitializers = [];
|
|
352
|
+
let _inChars_decorators;
|
|
353
|
+
let _inStr_decorators;
|
|
354
|
+
let _eatWikiText_decorators;
|
|
355
|
+
let _eatApostrophes_decorators;
|
|
356
|
+
let _eatExternalLinkProtocol_decorators;
|
|
357
|
+
let _inExternalLink_decorators;
|
|
358
|
+
let _inLink_decorators;
|
|
359
|
+
let _inLinkText_decorators;
|
|
360
|
+
let _get_eatStartTable_decorators;
|
|
361
|
+
let _inTableDefinition_decorators;
|
|
362
|
+
let _get_inTable_decorators;
|
|
363
|
+
let _inTableCell_decorators;
|
|
364
|
+
let _inSectionHeader_decorators;
|
|
365
|
+
let _get_inComment_decorators;
|
|
366
|
+
let _eatTagName_decorators;
|
|
367
|
+
let _inHtmlTagAttribute_decorators;
|
|
368
|
+
let _inExtTagAttribute_decorators;
|
|
369
|
+
let _eatExtTagArea_decorators;
|
|
370
|
+
let _inExtTokens_decorators;
|
|
371
|
+
let _inVariable_decorators;
|
|
372
|
+
let _inParserFunctionName_decorators;
|
|
373
|
+
let _inTemplatePageName_decorators;
|
|
374
|
+
let _inParserFunctionArgument_decorators;
|
|
375
|
+
let _inTemplateArgument_decorators;
|
|
376
|
+
let _inConvert_decorators;
|
|
377
|
+
let _inPre_decorators;
|
|
378
|
+
let _inNested_decorators;
|
|
379
|
+
let _get_inInputbox_decorators;
|
|
380
|
+
let _inGallery_decorators;
|
|
381
|
+
return class MediaWiki {
|
|
382
|
+
static {
|
|
383
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
384
|
+
_inChars_decorators = [getTokenizer];
|
|
385
|
+
_inStr_decorators = [getTokenizer];
|
|
386
|
+
_eatWikiText_decorators = [getTokenizer];
|
|
387
|
+
_eatApostrophes_decorators = [getTokenizer];
|
|
388
|
+
_eatExternalLinkProtocol_decorators = [getTokenizer];
|
|
389
|
+
_inExternalLink_decorators = [getTokenizer];
|
|
390
|
+
_inLink_decorators = [getTokenizer];
|
|
391
|
+
_inLinkText_decorators = [getTokenizer];
|
|
392
|
+
_get_eatStartTable_decorators = [getTokenizer];
|
|
393
|
+
_inTableDefinition_decorators = [getTokenizer];
|
|
394
|
+
_get_inTable_decorators = [getTokenizer];
|
|
395
|
+
_inTableCell_decorators = [getTokenizer];
|
|
396
|
+
_inSectionHeader_decorators = [getTokenizer];
|
|
397
|
+
_get_inComment_decorators = [getTokenizer];
|
|
398
|
+
_eatTagName_decorators = [getTokenizer];
|
|
399
|
+
_inHtmlTagAttribute_decorators = [getTokenizer];
|
|
400
|
+
_inExtTagAttribute_decorators = [getTokenizer];
|
|
401
|
+
_eatExtTagArea_decorators = [getTokenizer];
|
|
402
|
+
_inExtTokens_decorators = [getTokenizer];
|
|
403
|
+
_inVariable_decorators = [getTokenizer];
|
|
404
|
+
_inParserFunctionName_decorators = [getTokenizer];
|
|
405
|
+
_inTemplatePageName_decorators = [getTokenizer];
|
|
406
|
+
_inParserFunctionArgument_decorators = [getTokenizer];
|
|
407
|
+
_inTemplateArgument_decorators = [getTokenizer];
|
|
408
|
+
_inConvert_decorators = [getTokenizer];
|
|
409
|
+
_inPre_decorators = [getTokenizer];
|
|
410
|
+
_inNested_decorators = [getTokenizer];
|
|
411
|
+
_get_inInputbox_decorators = [(getTokenizer)];
|
|
412
|
+
_inGallery_decorators = [getTokenizer];
|
|
413
|
+
__esDecorate(this, null, _inChars_decorators, { kind: "method", name: "inChars", static: false, private: false, access: { has: obj => "inChars" in obj, get: obj => obj.inChars }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
414
|
+
__esDecorate(this, null, _inStr_decorators, { kind: "method", name: "inStr", static: false, private: false, access: { has: obj => "inStr" in obj, get: obj => obj.inStr }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
415
|
+
__esDecorate(this, null, _eatWikiText_decorators, { kind: "method", name: "eatWikiText", static: false, private: false, access: { has: obj => "eatWikiText" in obj, get: obj => obj.eatWikiText }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
416
|
+
__esDecorate(this, null, _eatApostrophes_decorators, { kind: "method", name: "eatApostrophes", static: false, private: false, access: { has: obj => "eatApostrophes" in obj, get: obj => obj.eatApostrophes }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
417
|
+
__esDecorate(this, null, _eatExternalLinkProtocol_decorators, { kind: "method", name: "eatExternalLinkProtocol", static: false, private: false, access: { has: obj => "eatExternalLinkProtocol" in obj, get: obj => obj.eatExternalLinkProtocol }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
418
|
+
__esDecorate(this, null, _inExternalLink_decorators, { kind: "method", name: "inExternalLink", static: false, private: false, access: { has: obj => "inExternalLink" in obj, get: obj => obj.inExternalLink }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
419
|
+
__esDecorate(this, null, _inLink_decorators, { kind: "method", name: "inLink", static: false, private: false, access: { has: obj => "inLink" in obj, get: obj => obj.inLink }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
420
|
+
__esDecorate(this, null, _inLinkText_decorators, { kind: "method", name: "inLinkText", static: false, private: false, access: { has: obj => "inLinkText" in obj, get: obj => obj.inLinkText }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
421
|
+
__esDecorate(this, null, _get_eatStartTable_decorators, { kind: "getter", name: "eatStartTable", static: false, private: false, access: { has: obj => "eatStartTable" in obj, get: obj => obj.eatStartTable }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
422
|
+
__esDecorate(this, null, _inTableDefinition_decorators, { kind: "method", name: "inTableDefinition", static: false, private: false, access: { has: obj => "inTableDefinition" in obj, get: obj => obj.inTableDefinition }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
423
|
+
__esDecorate(this, null, _get_inTable_decorators, { kind: "getter", name: "inTable", static: false, private: false, access: { has: obj => "inTable" in obj, get: obj => obj.inTable }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
424
|
+
__esDecorate(this, null, _inTableCell_decorators, { kind: "method", name: "inTableCell", static: false, private: false, access: { has: obj => "inTableCell" in obj, get: obj => obj.inTableCell }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
425
|
+
__esDecorate(this, null, _inSectionHeader_decorators, { kind: "method", name: "inSectionHeader", static: false, private: false, access: { has: obj => "inSectionHeader" in obj, get: obj => obj.inSectionHeader }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
426
|
+
__esDecorate(this, null, _get_inComment_decorators, { kind: "getter", name: "inComment", static: false, private: false, access: { has: obj => "inComment" in obj, get: obj => obj.inComment }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
427
|
+
__esDecorate(this, null, _eatTagName_decorators, { kind: "method", name: "eatTagName", static: false, private: false, access: { has: obj => "eatTagName" in obj, get: obj => obj.eatTagName }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
428
|
+
__esDecorate(this, null, _inHtmlTagAttribute_decorators, { kind: "method", name: "inHtmlTagAttribute", static: false, private: false, access: { has: obj => "inHtmlTagAttribute" in obj, get: obj => obj.inHtmlTagAttribute }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
429
|
+
__esDecorate(this, null, _inExtTagAttribute_decorators, { kind: "method", name: "inExtTagAttribute", static: false, private: false, access: { has: obj => "inExtTagAttribute" in obj, get: obj => obj.inExtTagAttribute }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
430
|
+
__esDecorate(this, null, _eatExtTagArea_decorators, { kind: "method", name: "eatExtTagArea", static: false, private: false, access: { has: obj => "eatExtTagArea" in obj, get: obj => obj.eatExtTagArea }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
431
|
+
__esDecorate(this, null, _inExtTokens_decorators, { kind: "method", name: "inExtTokens", static: false, private: false, access: { has: obj => "inExtTokens" in obj, get: obj => obj.inExtTokens }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
432
|
+
__esDecorate(this, null, _inVariable_decorators, { kind: "method", name: "inVariable", static: false, private: false, access: { has: obj => "inVariable" in obj, get: obj => obj.inVariable }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
433
|
+
__esDecorate(this, null, _inParserFunctionName_decorators, { kind: "method", name: "inParserFunctionName", static: false, private: false, access: { has: obj => "inParserFunctionName" in obj, get: obj => obj.inParserFunctionName }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
434
|
+
__esDecorate(this, null, _inTemplatePageName_decorators, { kind: "method", name: "inTemplatePageName", static: false, private: false, access: { has: obj => "inTemplatePageName" in obj, get: obj => obj.inTemplatePageName }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
435
|
+
__esDecorate(this, null, _inParserFunctionArgument_decorators, { kind: "method", name: "inParserFunctionArgument", static: false, private: false, access: { has: obj => "inParserFunctionArgument" in obj, get: obj => obj.inParserFunctionArgument }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
436
|
+
__esDecorate(this, null, _inTemplateArgument_decorators, { kind: "method", name: "inTemplateArgument", static: false, private: false, access: { has: obj => "inTemplateArgument" in obj, get: obj => obj.inTemplateArgument }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
437
|
+
__esDecorate(this, null, _inConvert_decorators, { kind: "method", name: "inConvert", static: false, private: false, access: { has: obj => "inConvert" in obj, get: obj => obj.inConvert }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
438
|
+
__esDecorate(this, null, _inPre_decorators, { kind: "method", name: "inPre", static: false, private: false, access: { has: obj => "inPre" in obj, get: obj => obj.inPre }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
439
|
+
__esDecorate(this, null, _inNested_decorators, { kind: "method", name: "inNested", static: false, private: false, access: { has: obj => "inNested" in obj, get: obj => obj.inNested }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
440
|
+
__esDecorate(this, null, _get_inInputbox_decorators, { kind: "getter", name: "inInputbox", static: false, private: false, access: { has: obj => "inInputbox" in obj, get: obj => obj.inInputbox }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
441
|
+
__esDecorate(this, null, _inGallery_decorators, { kind: "method", name: "inGallery", static: false, private: false, access: { has: obj => "inGallery" in obj, get: obj => obj.inGallery }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
442
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
407
443
|
}
|
|
408
|
-
|
|
409
|
-
this
|
|
444
|
+
constructor(config) {
|
|
445
|
+
__runInitializers(this, _instanceExtraInitializers);
|
|
446
|
+
const { urlProtocols, permittedHtmlTags, implicitlyClosedHtmlTags, tags, nsid, variants, redirection = ['#REDIRECT'], img = {}, } = config;
|
|
447
|
+
this.config = config;
|
|
448
|
+
this.tokenTable = { ...tokenTable };
|
|
449
|
+
this.hiddenTable = {};
|
|
450
|
+
this.permittedHtmlTags = new Set([
|
|
451
|
+
...htmlTags,
|
|
452
|
+
...permittedHtmlTags ?? [],
|
|
453
|
+
]);
|
|
454
|
+
this.voidHtmlTags = new Set([
|
|
455
|
+
...voidHtmlTags,
|
|
456
|
+
...implicitlyClosedHtmlTags ?? [],
|
|
457
|
+
]);
|
|
458
|
+
this.urlProtocols = new RegExp(String.raw `^(?:${urlProtocols})(?=[^\p{Zs}[\]<>"])`, 'iu');
|
|
459
|
+
this.linkRegex = new RegExp(String.raw `^\[(?!${urlProtocols})\s*`, 'iu');
|
|
460
|
+
this.fileRegex = new RegExp(String.raw `^(?:${Object.entries(nsid).filter(([, id]) => id === 6).map(([ns]) => ns).join('|')})\s*:`, 'iu');
|
|
461
|
+
this.redirectRegex = new RegExp(String.raw `^\s*(?:${redirection.join('|')})(\s*:)?\s*(?=\[\[|$)`, 'iu');
|
|
462
|
+
this.img = Object.keys(img).filter(word => !/\$1./u.test(word));
|
|
463
|
+
this.imgRegex = new RegExp(String.raw `^(?:${this.img.filter(word => word.endsWith('$1')).map(word => word.slice(0, -2))
|
|
464
|
+
.join('|')}|(?:${this.img.filter(word => !word.endsWith('$1')).join('|')}|(?:\d+x?|\d*x\d+)\s*(?:px)?px)\s*(?=\||\]\]|$))`, 'u');
|
|
465
|
+
this.tags = [...Object.keys(tags), 'includeonly', 'noinclude', 'onlyinclude'];
|
|
466
|
+
this.convertRegex = new RegExp(String.raw `^(?:[^}|;&='{[<~_-]|\}(?!-)|=(?!>)|\[(?!\[|${urlProtocols})|${lookahead("'{<~_-")})+`, 'u');
|
|
467
|
+
this.convertSemicolon = variants && new RegExp(String.raw `^;\s*(?=(?:[^;]*?=>\s*)?(?:${variants.join('|')})\s*:|(?:$|\}-))`, 'u');
|
|
468
|
+
this.convertLang = variants
|
|
469
|
+
&& new RegExp(String.raw `^(?:=>\s*)?(?:${variants.join('|')})\s*:`, 'u');
|
|
470
|
+
this.hasVariants = Boolean(variants?.length);
|
|
471
|
+
this.preRegex = [false, true].map(begin => new RegExp(String.raw `^(?:[^<&-]|-${this.hasVariants ? String.raw `(?!\{)` : ''}|<(?!${begin ? '/' : ''}nowiki>))+`, 'iu'));
|
|
472
|
+
this.autocompleteNamespaces = {
|
|
473
|
+
0: '',
|
|
474
|
+
6: 'File:',
|
|
475
|
+
8: 'MediaWiki:',
|
|
476
|
+
10: 'Template:',
|
|
477
|
+
274: 'Widget:',
|
|
478
|
+
828: 'Module:',
|
|
479
|
+
};
|
|
480
|
+
this.registerGroundTokens();
|
|
410
481
|
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
482
|
+
/**
|
|
483
|
+
* Dynamically register a token in CodeMirror.
|
|
484
|
+
* This is solely for use by this.addTag() and CodeMirrorModeMediaWiki.makeLocalStyle().
|
|
485
|
+
*
|
|
486
|
+
* @param token
|
|
487
|
+
* @param hidden Whether the token is not highlighted
|
|
488
|
+
* @param parent
|
|
489
|
+
*/
|
|
490
|
+
addToken(token, hidden = false, parent) {
|
|
491
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
492
|
+
this[hidden ? 'hiddenTable' : 'tokenTable'][`mw-${token}`] ??= Tag.define(parent);
|
|
414
493
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
494
|
+
/**
|
|
495
|
+
* Register the ground tokens. These aren't referenced directly in the StreamParser, nor do
|
|
496
|
+
* they have a parent Tag, so we don't need them as constants like we do for other tokens.
|
|
497
|
+
* See makeLocalStyle() for how these tokens are used.
|
|
498
|
+
*/
|
|
499
|
+
registerGroundTokens() {
|
|
500
|
+
const grounds = [
|
|
501
|
+
'ext',
|
|
502
|
+
'ext-link',
|
|
503
|
+
'ext2',
|
|
504
|
+
'ext2-link',
|
|
505
|
+
'ext3',
|
|
506
|
+
'ext3-link',
|
|
507
|
+
'link',
|
|
508
|
+
'template-ext',
|
|
509
|
+
'template-ext-link',
|
|
510
|
+
'template-ext2',
|
|
511
|
+
'template-ext2-link',
|
|
512
|
+
'template-ext3',
|
|
513
|
+
'template-ext3-link',
|
|
514
|
+
'template',
|
|
515
|
+
'template-link',
|
|
516
|
+
'template2-ext',
|
|
517
|
+
'template2-ext-link',
|
|
518
|
+
'template2-ext2',
|
|
519
|
+
'template2-ext2-link',
|
|
520
|
+
'template2-ext3',
|
|
521
|
+
'template2-ext3-link',
|
|
522
|
+
'template2',
|
|
523
|
+
'template2-link',
|
|
524
|
+
'template3-ext',
|
|
525
|
+
'template3-ext-link',
|
|
526
|
+
'template3-ext2',
|
|
527
|
+
'template3-ext2-link',
|
|
528
|
+
'template3-ext3',
|
|
529
|
+
'template3-ext3-link',
|
|
530
|
+
'template3',
|
|
531
|
+
'template3-link',
|
|
532
|
+
];
|
|
533
|
+
for (const ground of grounds) {
|
|
534
|
+
this.addToken(`${ground}-ground`);
|
|
535
|
+
}
|
|
536
|
+
for (let i = 1; i < 7; i++) {
|
|
537
|
+
this.addToken(`section--${i}`);
|
|
538
|
+
}
|
|
539
|
+
for (const tag of this.tags) {
|
|
540
|
+
this.addToken(`tag-${tag}`, tag !== 'nowiki' && tag !== 'pre');
|
|
541
|
+
this.addToken(`ext-${tag}`, true);
|
|
542
|
+
}
|
|
543
|
+
for (const tag of this.permittedHtmlTags) {
|
|
544
|
+
this.addToken(`html-${tag}`, true);
|
|
545
|
+
}
|
|
546
|
+
for (const i in this.autocompleteNamespaces) {
|
|
547
|
+
if (Number.isInteger(Number(i))) {
|
|
548
|
+
this.addToken(`function-${i}`, true);
|
|
549
|
+
}
|
|
421
550
|
}
|
|
422
551
|
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
inChars({ length }, tag) {
|
|
427
|
-
return (stream, state) => {
|
|
428
|
-
stream.pos += length;
|
|
429
|
-
pop(state);
|
|
430
|
-
return makeLocalTagStyle(tag, state);
|
|
431
|
-
};
|
|
432
|
-
}
|
|
433
|
-
@getTokenizer
|
|
434
|
-
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
435
|
-
inStr(str, tag, errorTag = 'error') {
|
|
436
|
-
return (stream, state) => {
|
|
437
|
-
if (stream.match(str, Boolean(tag))) {
|
|
552
|
+
inChars({ length }, tag) {
|
|
553
|
+
return (stream, state) => {
|
|
554
|
+
stream.pos += length;
|
|
438
555
|
pop(state);
|
|
439
|
-
return
|
|
440
|
-
}
|
|
441
|
-
else if (!stream.skipTo(str)) {
|
|
442
|
-
stream.skipToEnd();
|
|
443
|
-
}
|
|
444
|
-
return makeLocalTagStyle(errorTag, state);
|
|
445
|
-
};
|
|
446
|
-
}
|
|
447
|
-
@getTokenizer
|
|
448
|
-
eatWikiText(style) {
|
|
449
|
-
if (style in tokens) {
|
|
450
|
-
style = tokens[style]; // eslint-disable-line no-param-reassign
|
|
556
|
+
return makeLocalTagStyle(tag, state);
|
|
557
|
+
};
|
|
451
558
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
559
|
+
inStr(str, tag, errorTag = 'error') {
|
|
560
|
+
return (stream, state) => {
|
|
561
|
+
if (stream.match(str, Boolean(tag))) {
|
|
562
|
+
pop(state);
|
|
563
|
+
return tag ? makeLocalTagStyle(tag, state) : '';
|
|
564
|
+
}
|
|
565
|
+
else if (!stream.skipTo(str)) {
|
|
566
|
+
stream.skipToEnd();
|
|
567
|
+
}
|
|
568
|
+
return makeLocalTagStyle(errorTag, state);
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
eatWikiText(style) {
|
|
572
|
+
if (style in tokens) {
|
|
573
|
+
style = tokens[style]; // eslint-disable-line no-param-reassign
|
|
457
574
|
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
state.sof = false;
|
|
464
|
-
const mt = stream.match(this.redirectRegex);
|
|
465
|
-
if (mt) {
|
|
466
|
-
state.redirect = { colon: !mt[1] };
|
|
467
|
-
return tokens.redirect;
|
|
468
|
-
}
|
|
575
|
+
const regex = /^(?:(?:RFC|PMID)[\p{Zs}\t]+\d+|ISBN[\p{Zs}\t]+(?:97[89][\p{Zs}\t-]?)?(?:\d[\p{Zs}\t-]?){9}[\dxX])\b/u;
|
|
576
|
+
return (stream, state) => {
|
|
577
|
+
let ch;
|
|
578
|
+
if (stream.eol()) {
|
|
579
|
+
return '';
|
|
469
580
|
}
|
|
470
|
-
else if (
|
|
471
|
-
if (
|
|
472
|
-
|
|
581
|
+
else if (stream.sol()) {
|
|
582
|
+
if (state.sof) {
|
|
583
|
+
if (stream.match(/^\s+$/u)) {
|
|
584
|
+
return '';
|
|
585
|
+
}
|
|
586
|
+
state.sof = false;
|
|
587
|
+
const mt = stream.match(this.redirectRegex);
|
|
588
|
+
if (mt) {
|
|
589
|
+
state.redirect = { colon: !mt[1] };
|
|
590
|
+
return tokens.redirect;
|
|
591
|
+
}
|
|
473
592
|
}
|
|
474
|
-
else if (state.redirect
|
|
475
|
-
|
|
476
|
-
|
|
593
|
+
else if (state.redirect) {
|
|
594
|
+
if (stream.match(/^\s+(?=$|\[\[)/u)) {
|
|
595
|
+
return '';
|
|
596
|
+
}
|
|
597
|
+
else if (state.redirect.colon && stream.match(/^\s*:\s*(?=$|\[\[)/u)) {
|
|
598
|
+
state.redirect.colon = false;
|
|
599
|
+
return tokens.redirect;
|
|
600
|
+
}
|
|
601
|
+
state.redirect = false;
|
|
477
602
|
}
|
|
478
|
-
|
|
603
|
+
ch = stream.next();
|
|
604
|
+
const isTemplate = ['inTemplateArgument', 'inParserFunctionArgument', 'inVariable']
|
|
605
|
+
.includes(state.tokenize.name);
|
|
606
|
+
switch (ch) {
|
|
607
|
+
case '#':
|
|
608
|
+
case ';':
|
|
609
|
+
case '*':
|
|
610
|
+
stream.backUp(1);
|
|
611
|
+
return this.eatList(stream, state);
|
|
612
|
+
case ':':
|
|
613
|
+
// Highlight indented tables :{|, bug T108454
|
|
614
|
+
if (stream.match(indentedTableRegex[isTemplate ? 1 : 0])) {
|
|
615
|
+
chain(state, this.eatStartTable);
|
|
616
|
+
return makeLocalTagStyle('list', state);
|
|
617
|
+
}
|
|
618
|
+
return this.eatList(stream, state);
|
|
619
|
+
case '=': {
|
|
620
|
+
const tmp = stream
|
|
621
|
+
.match(/^(={0,5})(.+?(=\1\s*)(?:<!--(?!.*-->\s*\S).*)?)$/u);
|
|
622
|
+
// Title
|
|
623
|
+
if (tmp) {
|
|
624
|
+
stream.backUp(tmp[2].length);
|
|
625
|
+
chain(state, this.inSectionHeader(tmp[3]));
|
|
626
|
+
return makeLocalStyle(`${tokens.sectionHeader} mw-section--${tmp[1].length + 1}`, state);
|
|
627
|
+
}
|
|
628
|
+
break;
|
|
629
|
+
}
|
|
630
|
+
case '{':
|
|
631
|
+
if (stream.match(tableRegex[isTemplate ? 1 : 0])) {
|
|
632
|
+
chain(state, this.inTableDefinition());
|
|
633
|
+
return makeLocalTagStyle('tableBracket', state);
|
|
634
|
+
}
|
|
635
|
+
break;
|
|
636
|
+
case '-':
|
|
637
|
+
if (stream.match(/^-{3,}/u)) {
|
|
638
|
+
return tokens.hr;
|
|
639
|
+
}
|
|
640
|
+
break;
|
|
641
|
+
default:
|
|
642
|
+
if (!ch.trim()) {
|
|
643
|
+
// Leading spaces is valid syntax for tables, bug T108454
|
|
644
|
+
const mt = stream.match(spacedTableRegex[isTemplate ? 1 : 0]);
|
|
645
|
+
if (mt) {
|
|
646
|
+
chain(state, this.eatStartTable);
|
|
647
|
+
return makeLocalStyle(mt[1] ? tokens.list : '', state);
|
|
648
|
+
}
|
|
649
|
+
else if (ch === ' '
|
|
650
|
+
&& !/^ \s*(?=<!--)(?:\s|<!--(?:(?!-->).)*-->)+$/u.test(stream.string)) {
|
|
651
|
+
/** @todo indent-pre is sometimes suppressed */
|
|
652
|
+
return tokens.skipFormatting;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
else {
|
|
658
|
+
ch = stream.next();
|
|
479
659
|
}
|
|
480
|
-
ch = stream.next();
|
|
481
|
-
const isTemplate = ['inTemplateArgument', 'inParserFunctionArgument', 'inVariable']
|
|
482
|
-
.includes(state.tokenize.name);
|
|
483
660
|
switch (ch) {
|
|
484
|
-
case '
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
case '
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
return makeLocalTagStyle('list', state);
|
|
661
|
+
case '~':
|
|
662
|
+
if (stream.match(/^~{2,4}/u)) {
|
|
663
|
+
return tokens.signature;
|
|
664
|
+
}
|
|
665
|
+
break;
|
|
666
|
+
case '<': {
|
|
667
|
+
if (stream.match('!--')) { // comment
|
|
668
|
+
chain(state, this.inComment);
|
|
669
|
+
return makeLocalTagStyle('comment', state);
|
|
494
670
|
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
671
|
+
const isCloseTag = Boolean(stream.eat('/')), mt = stream.match(/^([a-z][^\s/>]*)>?/iu, false);
|
|
672
|
+
if (mt) {
|
|
673
|
+
const tagname = mt[1].toLowerCase();
|
|
674
|
+
if ((mt[0] === 'onlyinclude>' || tagname !== 'onlyinclude')
|
|
675
|
+
&& state.data.tags.includes(tagname)) {
|
|
676
|
+
// Extension tag
|
|
677
|
+
return this.eatExtTag(tagname, isCloseTag, state);
|
|
678
|
+
}
|
|
679
|
+
else if (this.permittedHtmlTags.has(tagname)) {
|
|
680
|
+
// Html tag
|
|
681
|
+
return this.eatHtmlTag(tagname, isCloseTag, state);
|
|
682
|
+
}
|
|
504
683
|
}
|
|
505
684
|
break;
|
|
506
685
|
}
|
|
507
|
-
case '{':
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
686
|
+
case '{': {
|
|
687
|
+
// Can't be a variable when it starts with more than 3 brackets (T108450) or
|
|
688
|
+
// a single { followed by a template. E.g. {{{!}} starts a table (T292967).
|
|
689
|
+
if (stream.match(/^\{\{(?!\{|[^{}]*\}\}(?!\}))\s*/u)) {
|
|
690
|
+
state.nVar++;
|
|
691
|
+
chain(state, this.inVariable());
|
|
692
|
+
return makeLocalTagStyle('templateVariableBracket', state);
|
|
693
|
+
}
|
|
694
|
+
const mt = stream.match(/^\{(?!\{(?!\{))/u);
|
|
695
|
+
if (mt) {
|
|
696
|
+
return this.eatTransclusion(stream, state) ?? makeStyle(style, state);
|
|
511
697
|
}
|
|
512
698
|
break;
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
699
|
+
}
|
|
700
|
+
case '_': {
|
|
701
|
+
const { pos } = stream;
|
|
702
|
+
stream.eatWhile('_');
|
|
703
|
+
switch (stream.pos - pos) {
|
|
704
|
+
case 0:
|
|
705
|
+
break;
|
|
706
|
+
case 1:
|
|
707
|
+
return this.eatDoubleUnderscore(style, stream, state);
|
|
708
|
+
default:
|
|
709
|
+
if (!stream.eol()) {
|
|
710
|
+
stream.backUp(2);
|
|
711
|
+
}
|
|
712
|
+
return makeStyle(style, state);
|
|
516
713
|
}
|
|
517
714
|
break;
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
715
|
+
}
|
|
716
|
+
case '[':
|
|
717
|
+
// Link Example: [[ Foo | Bar ]]
|
|
718
|
+
if (stream.match(this.linkRegex)) {
|
|
719
|
+
const { redirect } = state;
|
|
720
|
+
if (redirect || /[^[\]|]/u.test(stream.peek() || '')) {
|
|
721
|
+
state.nLink++;
|
|
722
|
+
state.lbrack = undefined;
|
|
723
|
+
chain(state, this.inLink(!redirect && Boolean(stream.match(this.fileRegex, false))));
|
|
724
|
+
return makeLocalTagStyle('linkBracket', state);
|
|
525
725
|
}
|
|
526
|
-
else if (
|
|
527
|
-
|
|
528
|
-
/** @todo indent-pre is sometimes suppressed */
|
|
529
|
-
return tokens.skipFormatting;
|
|
726
|
+
else if (stream.match(']]')) {
|
|
727
|
+
return makeStyle(style, state);
|
|
530
728
|
}
|
|
531
729
|
}
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
if (stream.match(/^~{2,4}/u)) {
|
|
540
|
-
return tokens.signature;
|
|
541
|
-
}
|
|
542
|
-
break;
|
|
543
|
-
case '<': {
|
|
544
|
-
if (stream.match('!--')) { // comment
|
|
545
|
-
chain(state, this.inComment);
|
|
546
|
-
return makeLocalTagStyle('comment', state);
|
|
547
|
-
}
|
|
548
|
-
const isCloseTag = Boolean(stream.eat('/')), mt = stream.match(/^([a-z][^\s/>]*)>?/iu, false);
|
|
549
|
-
if (mt) {
|
|
550
|
-
const tagname = mt[1].toLowerCase();
|
|
551
|
-
if ((mt[0] === 'onlyinclude>' || tagname !== 'onlyinclude')
|
|
552
|
-
&& state.data.tags.includes(tagname)) {
|
|
553
|
-
// Extension tag
|
|
554
|
-
return this.eatExtTag(tagname, isCloseTag, state);
|
|
730
|
+
else {
|
|
731
|
+
const mt = stream.match(this.urlProtocols, false);
|
|
732
|
+
if (mt) {
|
|
733
|
+
state.nExtLink++;
|
|
734
|
+
chain(state, this.eatExternalLinkProtocol(mt[0], false));
|
|
735
|
+
return makeLocalTagStyle('extLinkBracket', state);
|
|
736
|
+
}
|
|
555
737
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
738
|
+
break;
|
|
739
|
+
case "'": {
|
|
740
|
+
const result = this.eatApostrophes(state)(stream, state);
|
|
741
|
+
if (result) {
|
|
742
|
+
return result;
|
|
559
743
|
}
|
|
744
|
+
break;
|
|
560
745
|
}
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
break;
|
|
576
|
-
}
|
|
577
|
-
case '_': {
|
|
578
|
-
const { pos } = stream;
|
|
579
|
-
stream.eatWhile('_');
|
|
580
|
-
switch (stream.pos - pos) {
|
|
581
|
-
case 0:
|
|
582
|
-
break;
|
|
583
|
-
case 1:
|
|
584
|
-
return this.eatDoubleUnderscore(style, stream, state);
|
|
585
|
-
default:
|
|
586
|
-
if (!stream.eol()) {
|
|
587
|
-
stream.backUp(2);
|
|
588
|
-
}
|
|
589
|
-
return makeStyle(style, state);
|
|
590
|
-
}
|
|
591
|
-
break;
|
|
746
|
+
case ':':
|
|
747
|
+
if (needColon(state)) {
|
|
748
|
+
state.dt.n--;
|
|
749
|
+
return makeLocalTagStyle('list', state);
|
|
750
|
+
}
|
|
751
|
+
break;
|
|
752
|
+
case '&':
|
|
753
|
+
return makeStyle(this.eatEntity(stream, style), state);
|
|
754
|
+
case '-':
|
|
755
|
+
if (this.config.variants?.length && stream.match(/^\{(?!\{)\s*/u)) {
|
|
756
|
+
chain(state, this.inConvert(style, true));
|
|
757
|
+
return makeLocalTagStyle('convertBracket', state);
|
|
758
|
+
}
|
|
759
|
+
// no default
|
|
592
760
|
}
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
state.nLink++;
|
|
599
|
-
state.lbrack = undefined;
|
|
600
|
-
chain(state, this.inLink(!redirect && Boolean(stream.match(this.fileRegex, false))));
|
|
601
|
-
return makeLocalTagStyle('linkBracket', state);
|
|
761
|
+
if (state.stack.length === 0) {
|
|
762
|
+
if (ch !== '_') {
|
|
763
|
+
// highlight free external links, bug T108448
|
|
764
|
+
if (/[\p{L}\p{N}]/u.test(ch)) {
|
|
765
|
+
stream.backUp(1);
|
|
602
766
|
}
|
|
603
|
-
else
|
|
604
|
-
|
|
767
|
+
else {
|
|
768
|
+
stream.eatWhile(/[^\p{L}\p{N}_&'{[<~:-]/u);
|
|
605
769
|
}
|
|
606
|
-
}
|
|
607
|
-
else {
|
|
608
770
|
const mt = stream.match(this.urlProtocols, false);
|
|
609
771
|
if (mt) {
|
|
610
|
-
state.
|
|
611
|
-
|
|
612
|
-
|
|
772
|
+
chain(state, this.eatExternalLinkProtocol(mt[0]));
|
|
773
|
+
return makeStyle(style, state);
|
|
774
|
+
}
|
|
775
|
+
const mtMagic = stream.match(regex, false);
|
|
776
|
+
if (mtMagic) {
|
|
777
|
+
chain(state, this.inChars(mtMagic[0], 'magicLink'));
|
|
778
|
+
return makeStyle(style, state);
|
|
613
779
|
}
|
|
614
780
|
}
|
|
615
|
-
|
|
616
|
-
case "'": {
|
|
617
|
-
const result = this.eatApostrophes(state)(stream, state);
|
|
618
|
-
if (result) {
|
|
619
|
-
return result;
|
|
620
|
-
}
|
|
621
|
-
break;
|
|
781
|
+
stream.eatWhile(/[\p{L}\p{N}]/u);
|
|
622
782
|
}
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
return
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
// highlight free external links, bug T108448
|
|
641
|
-
if (/[\p{L}\p{N}]/u.test(ch)) {
|
|
642
|
-
stream.backUp(1);
|
|
643
|
-
}
|
|
644
|
-
else {
|
|
645
|
-
stream.eatWhile(/[^\p{L}\p{N}_&'{[<~:-]/u);
|
|
646
|
-
}
|
|
647
|
-
const mt = stream.match(this.urlProtocols, false);
|
|
648
|
-
if (mt) {
|
|
649
|
-
chain(state, this.eatExternalLinkProtocol(mt[0]));
|
|
650
|
-
return makeStyle(style, state);
|
|
651
|
-
}
|
|
652
|
-
const mtMagic = stream.match(regex, false);
|
|
653
|
-
if (mtMagic) {
|
|
654
|
-
chain(state, this.inChars(mtMagic[0], 'magicLink'));
|
|
655
|
-
return makeStyle(style, state);
|
|
783
|
+
return makeStyle(style, state);
|
|
784
|
+
};
|
|
785
|
+
}
|
|
786
|
+
eatApostrophes(obj) {
|
|
787
|
+
return (stream, state) => {
|
|
788
|
+
// skip the irrelevant apostrophes ( >5 or =4 )
|
|
789
|
+
if (stream.match(/^'*(?='{5})/u) || stream.match(/^'''(?!')/u, false)) {
|
|
790
|
+
return false;
|
|
791
|
+
}
|
|
792
|
+
else if (stream.match("''''")) { // bold italic
|
|
793
|
+
obj.bold = !obj.bold;
|
|
794
|
+
obj.italic = !obj.italic;
|
|
795
|
+
return makeLocalTagStyle('apostrophes', state);
|
|
796
|
+
}
|
|
797
|
+
else if (stream.match("''")) { // bold
|
|
798
|
+
if (obj === state && state.data.firstSingleLetterWord === null) {
|
|
799
|
+
prepareItalicForCorrection(stream, state);
|
|
656
800
|
}
|
|
801
|
+
obj.bold = !obj.bold;
|
|
802
|
+
return makeLocalTagStyle('apostrophes', state);
|
|
657
803
|
}
|
|
658
|
-
stream.
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
};
|
|
662
|
-
}
|
|
663
|
-
@getTokenizer
|
|
664
|
-
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
665
|
-
eatApostrophes(obj) {
|
|
666
|
-
return (stream, state) => {
|
|
667
|
-
// skip the irrelevant apostrophes ( >5 or =4 )
|
|
668
|
-
if (stream.match(/^'*(?='{5})/u) || stream.match(/^'''(?!')/u, false)) {
|
|
669
|
-
return false;
|
|
670
|
-
}
|
|
671
|
-
else if (stream.match("''''")) { // bold italic
|
|
672
|
-
obj.bold = !obj.bold;
|
|
673
|
-
obj.italic = !obj.italic;
|
|
674
|
-
return makeLocalTagStyle('apostrophes', state);
|
|
675
|
-
}
|
|
676
|
-
else if (stream.match("''")) { // bold
|
|
677
|
-
if (obj === state && state.data.firstSingleLetterWord === null) {
|
|
678
|
-
prepareItalicForCorrection(stream, state);
|
|
804
|
+
else if (stream.eat("'")) { // italic
|
|
805
|
+
obj.italic = !obj.italic;
|
|
806
|
+
return makeLocalTagStyle('apostrophes', state);
|
|
679
807
|
}
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
}
|
|
683
|
-
else if (stream.eat("'")) { // italic
|
|
684
|
-
obj.italic = !obj.italic;
|
|
685
|
-
return makeLocalTagStyle('apostrophes', state);
|
|
686
|
-
}
|
|
687
|
-
return false;
|
|
688
|
-
};
|
|
689
|
-
}
|
|
690
|
-
@getTokenizer
|
|
691
|
-
eatExternalLinkProtocol({ length }, free = true) {
|
|
692
|
-
return (stream, state) => {
|
|
693
|
-
stream.pos += length;
|
|
694
|
-
state.tokenize = free ? this.eatFreeExternalLink : this.inExternalLink();
|
|
695
|
-
return makeLocalTagStyle(free ? 'freeExtLinkProtocol' : 'extLinkProtocol', state);
|
|
696
|
-
};
|
|
697
|
-
}
|
|
698
|
-
@getTokenizer
|
|
699
|
-
inExternalLink(text) {
|
|
700
|
-
return (stream, state) => {
|
|
701
|
-
const t = state.stack[0], equal = getEqual(t), isNested = ['inTemplateArgument', 'inParserFunctionArgument', 'inVariable', 'inTableCell']
|
|
702
|
-
.includes(t.name), pipe = (isNested ? '|' : '') + equal, peek = stream.peek();
|
|
703
|
-
if (stream.sol()
|
|
704
|
-
|| stream.match(/^\p{Zs}*\]/u)
|
|
705
|
-
|| isNested && peek === '|'
|
|
706
|
-
|| equal && peek === '=') {
|
|
707
|
-
pop(state);
|
|
708
|
-
return makeLocalTagStyle('extLinkBracket', state, 'nExtLink');
|
|
709
|
-
}
|
|
710
|
-
else if (text) {
|
|
711
|
-
return stream.match(getExtLinkTextRegex(pipe))
|
|
712
|
-
? makeTagStyle('extLinkText', state)
|
|
713
|
-
: this.eatWikiText('extLinkText')(stream, state);
|
|
714
|
-
}
|
|
715
|
-
else if (stream.match(getExtLinkRegex(pipe))) {
|
|
716
|
-
return makeLocalTagStyle('extLink', state);
|
|
717
|
-
}
|
|
718
|
-
state.tokenize = this.inExternalLink(true);
|
|
719
|
-
return '';
|
|
720
|
-
};
|
|
721
|
-
}
|
|
722
|
-
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
723
|
-
eatFreeExternalLink(stream, state) {
|
|
724
|
-
const mt = stream.match(freeRegex[0]);
|
|
725
|
-
if (!stream.eol() && mt[0].includes('(') && getPunctuations().includes(stream.peek())) {
|
|
726
|
-
stream.match(freeRegex[1]);
|
|
808
|
+
return false;
|
|
809
|
+
};
|
|
727
810
|
}
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
return makeLocalTagStyle('linkBracket', state, 'nLink');
|
|
746
|
-
}
|
|
747
|
-
lt = undefined;
|
|
748
|
-
const space = stream.eatSpace(), { redirect } = state;
|
|
749
|
-
if (!section && stream.match(/^#\s*/u)) {
|
|
750
|
-
state.tokenize = this.inLink(file, true);
|
|
751
|
-
return makeTagStyle(file ? 'error' : 'linkToSection', state);
|
|
752
|
-
}
|
|
753
|
-
else if (stream.match(/^\|\s*/u)) {
|
|
754
|
-
state.tokenize = this.inLinkText(file);
|
|
755
|
-
let s = redirect ? 'error' : 'linkDelimiter';
|
|
756
|
-
if (file) {
|
|
757
|
-
s = 'fileDelimiter';
|
|
758
|
-
this.toEatImageParameter(stream, state);
|
|
811
|
+
eatExternalLinkProtocol({ length }, free = true) {
|
|
812
|
+
return (stream, state) => {
|
|
813
|
+
stream.pos += length;
|
|
814
|
+
state.tokenize = free ? this.eatFreeExternalLink : this.inExternalLink();
|
|
815
|
+
return makeLocalTagStyle(free ? 'freeExtLinkProtocol' : 'extLinkProtocol', state);
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
inExternalLink(text) {
|
|
819
|
+
return (stream, state) => {
|
|
820
|
+
const t = state.stack[0], equal = getEqual(t), isNested = ['inTemplateArgument', 'inParserFunctionArgument', 'inVariable', 'inTableCell']
|
|
821
|
+
.includes(t.name), pipe = (isNested ? '|' : '') + equal, peek = stream.peek();
|
|
822
|
+
if (stream.sol()
|
|
823
|
+
|| stream.match(/^\p{Zs}*\]/u)
|
|
824
|
+
|| isNested && peek === '|'
|
|
825
|
+
|| equal && peek === '=') {
|
|
826
|
+
pop(state);
|
|
827
|
+
return makeLocalTagStyle('extLinkBracket', state, 'nExtLink');
|
|
759
828
|
}
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
[regex] = linkErrorRegex;
|
|
765
|
-
}
|
|
766
|
-
else if (section) {
|
|
767
|
-
[, regex] = linkErrorRegex;
|
|
768
|
-
}
|
|
769
|
-
else {
|
|
770
|
-
[, , regex] = linkErrorRegex;
|
|
771
|
-
}
|
|
772
|
-
if (stream.match(regex)) {
|
|
773
|
-
return makeTagStyle('error', state);
|
|
774
|
-
}
|
|
775
|
-
else if (redirect) {
|
|
776
|
-
stream.match(/^(?:[^|<>[\]{}%]|%(?!3[ce]|[57][bd]))+/iu);
|
|
777
|
-
return makeStyle(style, state);
|
|
778
|
-
}
|
|
779
|
-
else if (stream.match(re) || space) {
|
|
780
|
-
return makeStyle(style, state);
|
|
781
|
-
}
|
|
782
|
-
else if (stream.match(/^<(?!(?:includeonly|noinclude)(?:\/?>|\s|$))[/a-z]/iu, false)
|
|
783
|
-
&& !stream.match(/^<onlyinclude>/u, false)) {
|
|
784
|
-
lt = stream.pos + 1;
|
|
785
|
-
}
|
|
786
|
-
return this.eatWikiText(section ? style : 'error')(stream, state);
|
|
787
|
-
};
|
|
788
|
-
}
|
|
789
|
-
@getTokenizer
|
|
790
|
-
inLinkText(file, gallery) {
|
|
791
|
-
const linkState = { bold: false, italic: false }, regex = linkTextRegex[file ? 1 : 0];
|
|
792
|
-
return (stream, state) => {
|
|
793
|
-
const tmpstyle = `${tokens[file ? 'fileText' : 'linkText']} ${linkState.bold ? tokens.strong : ''} ${linkState.italic ? tokens.em : ''} ${file && state.imgLink ? tokens.pageName : ''}`, { redirect, lbrack } = state, closing = stream.match(']]');
|
|
794
|
-
if (closing || !file && stream.match('[[', false)) {
|
|
795
|
-
if (gallery) {
|
|
796
|
-
return makeStyle(tmpstyle, state);
|
|
797
|
-
}
|
|
798
|
-
else if (closing && !redirect && lbrack && stream.peek() === ']') {
|
|
799
|
-
stream.backUp(1);
|
|
800
|
-
state.lbrack = false;
|
|
801
|
-
return makeStyle(tmpstyle, state);
|
|
829
|
+
else if (text) {
|
|
830
|
+
return stream.match(getExtLinkTextRegex(pipe))
|
|
831
|
+
? makeTagStyle('extLinkText', state)
|
|
832
|
+
: this.eatWikiText('extLinkText')(stream, state);
|
|
802
833
|
}
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
pop(state);
|
|
806
|
-
return makeLocalTagStyle('linkBracket', state, 'nLink');
|
|
807
|
-
}
|
|
808
|
-
else if (redirect) {
|
|
809
|
-
if (!stream.skipTo(']]')) {
|
|
810
|
-
stream.skipToEnd();
|
|
834
|
+
else if (stream.match(getExtLinkRegex(pipe))) {
|
|
835
|
+
return makeLocalTagStyle('extLink', state);
|
|
811
836
|
}
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
this.toEatImageParameter(stream, state);
|
|
816
|
-
return makeLocalTagStyle('fileDelimiter', state);
|
|
817
|
-
}
|
|
818
|
-
else if (stream.match(/^'(?=')/u)) {
|
|
819
|
-
return this.eatApostrophes(linkState)(stream, state) || makeStyle(tmpstyle, state);
|
|
820
|
-
}
|
|
821
|
-
else if (file && isSolSyntax(stream, true, true)
|
|
822
|
-
|| stream.sol() && stream.match('{|', false)) {
|
|
823
|
-
return this.eatWikiText(tmpstyle)(stream, state);
|
|
824
|
-
}
|
|
825
|
-
const mt = stream.match(regex);
|
|
826
|
-
if (lbrack === undefined && mt?.[0].includes('[')) {
|
|
827
|
-
state.lbrack = true;
|
|
828
|
-
}
|
|
829
|
-
return mt ? makeStyle(tmpstyle, state) : this.eatWikiText(tmpstyle)(stream, state);
|
|
830
|
-
};
|
|
831
|
-
}
|
|
832
|
-
toEatImageParameter(stream, state) {
|
|
833
|
-
state.imgLink = false;
|
|
834
|
-
const mt = stream.match(this.imgRegex, false);
|
|
835
|
-
if (mt) {
|
|
836
|
-
if (this.config.img?.[`${mt[0]}$1`] === 'img_link') {
|
|
837
|
-
state.imgLink = true;
|
|
838
|
-
}
|
|
839
|
-
chain(state, this.inChars(mt[0], 'imageParameter'));
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
843
|
-
eatList(stream, state) {
|
|
844
|
-
const mt = stream.match(/^[*#;:]*/u), { dt } = state;
|
|
845
|
-
if (mt[0].includes(';')) {
|
|
846
|
-
dt.n = mt[0].split(';').length - 1;
|
|
847
|
-
copyNesting(dt, state);
|
|
837
|
+
state.tokenize = this.inExternalLink(true);
|
|
838
|
+
return '';
|
|
839
|
+
};
|
|
848
840
|
}
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
if (Object.prototype.hasOwnProperty.call(doubleUnderscore[0], `__${name[0].toLowerCase()}`)
|
|
855
|
-
|| Object.prototype.hasOwnProperty.call(doubleUnderscore[1], `__${name[0]}`)) {
|
|
856
|
-
return tokens.doubleUnderscore;
|
|
857
|
-
}
|
|
858
|
-
else if (!stream.eol()) {
|
|
859
|
-
// Two underscore symbols at the end can be the beginning of another double underscored Magic Word
|
|
860
|
-
stream.backUp(2);
|
|
841
|
+
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
842
|
+
eatFreeExternalLink(stream, state) {
|
|
843
|
+
const mt = stream.match(freeRegex[0]);
|
|
844
|
+
if (!stream.eol() && mt[0].includes('(') && getPunctuations().includes(stream.peek())) {
|
|
845
|
+
stream.match(freeRegex[1]);
|
|
861
846
|
}
|
|
847
|
+
pop(state);
|
|
848
|
+
return makeTagStyle('freeExtLink', state);
|
|
862
849
|
}
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
stream
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
850
|
+
inLink(file, section) {
|
|
851
|
+
const style = section ? tokens[file ? 'error' : 'linkToSection'] : `${tokens.linkPageName} ${tokens.pageName}`, re = section
|
|
852
|
+
? /^(?:[^|<[\]{}]|<(?!!--|\/?[a-z]))+/iu
|
|
853
|
+
: /^(?:&#(?:\d+|x[a-f\d]+);|[^#|<>[\]{}%]|%(?!3[ce]|[57][bd]))+/iu;
|
|
854
|
+
let lt;
|
|
855
|
+
return (stream, state) => {
|
|
856
|
+
if (stream.sol()
|
|
857
|
+
|| lt && stream.pos > lt
|
|
858
|
+
|| stream.match(/^\s*\]\]/u)
|
|
859
|
+
|| stream.match(/^\[\[/u, false)) {
|
|
860
|
+
state.redirect = false;
|
|
861
|
+
state.lbrack = false;
|
|
862
|
+
pop(state);
|
|
863
|
+
return makeLocalTagStyle('linkBracket', state, 'nLink');
|
|
864
|
+
}
|
|
865
|
+
lt = undefined;
|
|
866
|
+
const space = stream.eatSpace(), { redirect } = state;
|
|
867
|
+
if (!section && stream.match(/^#\s*/u)) {
|
|
868
|
+
state.tokenize = this.inLink(file, true);
|
|
869
|
+
return makeTagStyle(file ? 'error' : 'linkToSection', state);
|
|
870
|
+
}
|
|
871
|
+
else if (stream.match(/^\|\s*/u)) {
|
|
872
|
+
state.tokenize = this.inLinkText(file);
|
|
873
|
+
let s = redirect ? 'error' : 'linkDelimiter';
|
|
874
|
+
if (file) {
|
|
875
|
+
s = 'fileDelimiter';
|
|
876
|
+
this.toEatImageParameter(stream, state);
|
|
877
|
+
}
|
|
878
|
+
return makeLocalTagStyle(s, state);
|
|
879
|
+
}
|
|
880
|
+
let regex;
|
|
881
|
+
if (redirect) {
|
|
882
|
+
[regex] = linkErrorRegex;
|
|
883
|
+
}
|
|
884
|
+
else if (section) {
|
|
885
|
+
[, regex] = linkErrorRegex;
|
|
894
886
|
}
|
|
895
887
|
else {
|
|
896
|
-
|
|
888
|
+
[, , regex] = linkErrorRegex;
|
|
897
889
|
}
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
else if (quote === '') { // 无引号的属性值
|
|
901
|
-
if (peekSpace(stream)) {
|
|
902
|
-
state.tokenize = this.inTableDefinition(tr);
|
|
903
|
-
return '';
|
|
890
|
+
if (stream.match(regex)) {
|
|
891
|
+
return makeTagStyle('error', state);
|
|
904
892
|
}
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
return makeLocalTagStyle('tableDelimiter', state);
|
|
893
|
+
else if (redirect) {
|
|
894
|
+
stream.match(/^(?:[^|<>[\]{}%]|%(?!3[ce]|[57][bd]))+/iu);
|
|
895
|
+
return makeStyle(style, state);
|
|
896
|
+
}
|
|
897
|
+
else if (stream.match(re) || space) {
|
|
898
|
+
return makeStyle(style, state);
|
|
899
|
+
}
|
|
900
|
+
else if (stream.match(/^<(?!(?:includeonly|noinclude)(?:\/?>|\s|$))[/a-z]/iu, false)
|
|
901
|
+
&& !stream.match(/^<onlyinclude>/u, false)) {
|
|
902
|
+
lt = stream.pos + 1;
|
|
903
|
+
}
|
|
904
|
+
return this.eatWikiText(section ? style : 'error')(stream, state);
|
|
905
|
+
};
|
|
906
|
+
}
|
|
907
|
+
inLinkText(file, gallery) {
|
|
908
|
+
const linkState = { bold: false, italic: false }, regex = linkTextRegex[file ? 1 : 0];
|
|
909
|
+
return (stream, state) => {
|
|
910
|
+
const tmpstyle = `${tokens[file ? 'fileText' : 'linkText']} ${linkState.bold ? tokens.strong : ''} ${linkState.italic ? tokens.em : ''} ${file && state.imgLink ? tokens.pageName : ''}`, { redirect, lbrack } = state, closing = stream.match(']]');
|
|
911
|
+
if (closing || !file && stream.match('[[', false)) {
|
|
912
|
+
if (gallery) {
|
|
913
|
+
return makeStyle(tmpstyle, state);
|
|
927
914
|
}
|
|
928
|
-
else if (
|
|
929
|
-
|
|
930
|
-
|
|
915
|
+
else if (closing && !redirect && lbrack && stream.peek() === ']') {
|
|
916
|
+
stream.backUp(1);
|
|
917
|
+
state.lbrack = false;
|
|
918
|
+
return makeStyle(tmpstyle, state);
|
|
931
919
|
}
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
920
|
+
state.redirect = false;
|
|
921
|
+
state.lbrack = false;
|
|
922
|
+
pop(state);
|
|
923
|
+
return makeLocalTagStyle('linkBracket', state, 'nLink');
|
|
924
|
+
}
|
|
925
|
+
else if (redirect) {
|
|
926
|
+
if (!stream.skipTo(']]')) {
|
|
927
|
+
stream.skipToEnd();
|
|
935
928
|
}
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
929
|
+
return makeLocalTagStyle('error', state);
|
|
930
|
+
}
|
|
931
|
+
else if (file && stream.match(/^\|\s*/u)) {
|
|
932
|
+
this.toEatImageParameter(stream, state);
|
|
933
|
+
return makeLocalTagStyle('fileDelimiter', state);
|
|
934
|
+
}
|
|
935
|
+
else if (stream.match(/^'(?=')/u)) {
|
|
936
|
+
return this.eatApostrophes(linkState)(stream, state) || makeStyle(tmpstyle, state);
|
|
939
937
|
}
|
|
940
|
-
else if (stream
|
|
941
|
-
|
|
942
|
-
return
|
|
938
|
+
else if (file && isSolSyntax(stream, true, true)
|
|
939
|
+
|| stream.sol() && stream.match('{|', false)) {
|
|
940
|
+
return this.eatWikiText(tmpstyle)(stream, state);
|
|
943
941
|
}
|
|
944
|
-
|
|
945
|
-
|
|
942
|
+
const mt = stream.match(regex);
|
|
943
|
+
if (lbrack === undefined && mt?.[0].includes('[')) {
|
|
944
|
+
state.lbrack = true;
|
|
945
|
+
}
|
|
946
|
+
return mt ? makeStyle(tmpstyle, state) : this.eatWikiText(tmpstyle)(stream, state);
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
toEatImageParameter(stream, state) {
|
|
950
|
+
state.imgLink = false;
|
|
951
|
+
const mt = stream.match(this.imgRegex, false);
|
|
952
|
+
if (mt) {
|
|
953
|
+
if (this.config.img?.[`${mt[0]}$1`] === 'img_link') {
|
|
954
|
+
state.imgLink = true;
|
|
946
955
|
}
|
|
956
|
+
chain(state, this.inChars(mt[0], 'imageParameter'));
|
|
947
957
|
}
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
+
}
|
|
959
|
+
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
960
|
+
eatList(stream, state) {
|
|
961
|
+
const mt = stream.match(/^[*#;:]*/u), { dt } = state;
|
|
962
|
+
if (mt[0].includes(';')) {
|
|
963
|
+
dt.n = mt[0].split(';').length - 1;
|
|
964
|
+
copyNesting(dt, state);
|
|
965
|
+
}
|
|
966
|
+
return makeLocalTagStyle('list', state);
|
|
967
|
+
}
|
|
968
|
+
eatDoubleUnderscore(style, stream, state) {
|
|
969
|
+
const { config: { doubleUnderscore } } = this, name = stream.match(/^[\p{L}\p{N}_]+?__/u);
|
|
970
|
+
if (name) {
|
|
971
|
+
if (Object.prototype.hasOwnProperty.call(doubleUnderscore[0], `__${name[0].toLowerCase()}`)
|
|
972
|
+
|| Object.prototype.hasOwnProperty.call(doubleUnderscore[1], `__${name[0]}`)) {
|
|
973
|
+
return tokens.doubleUnderscore;
|
|
974
|
+
}
|
|
975
|
+
else if (!stream.eol()) {
|
|
976
|
+
// Two underscore symbols at the end can be the beginning of another double underscored Magic Word
|
|
977
|
+
stream.backUp(2);
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
return makeStyle(style, state);
|
|
981
|
+
}
|
|
982
|
+
get eatStartTable() {
|
|
983
|
+
return (stream, state) => {
|
|
984
|
+
stream.match(/^(?:\{\||\{\{(?:\{\s*|\s*\()!\s*\}\})\s*/u);
|
|
985
|
+
state.tokenize = this.inTableDefinition();
|
|
986
|
+
return makeLocalTagStyle('tableBracket', state);
|
|
987
|
+
};
|
|
988
|
+
}
|
|
989
|
+
inTableDefinition(tr, quote) {
|
|
990
|
+
const style = quote === undefined
|
|
991
|
+
? `${tokens.tableDefinition} mw-html-${tr ? 'tr' : 'table'}`
|
|
992
|
+
: tokens.tableDefinitionValue;
|
|
993
|
+
return (stream, state) => {
|
|
994
|
+
if (stream.sol()) {
|
|
958
995
|
state.tokenize = this.inTable;
|
|
959
996
|
return '';
|
|
960
997
|
}
|
|
961
|
-
|
|
962
|
-
|
|
998
|
+
const t = state.stack[0], equal = getEqual(t);
|
|
999
|
+
if (equal && stream.peek() === '=') {
|
|
1000
|
+
pop(state);
|
|
963
1001
|
return '';
|
|
964
1002
|
}
|
|
965
|
-
else if (
|
|
1003
|
+
else if (stream.match(/^(?:&|\{\{|<(?:!--|\/?[a-z]))/iu, false)) {
|
|
966
1004
|
return this.eatWikiText(style)(stream, state);
|
|
967
1005
|
}
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|| style === tokens.tableTh && stream.match(/^!!\s*/u)) {
|
|
972
|
-
state.bold = false;
|
|
973
|
-
state.italic = false;
|
|
974
|
-
if (!needAttr) {
|
|
975
|
-
state.tokenize = this.inTableCell(style);
|
|
1006
|
+
else if (quote) { // 有引号的属性值
|
|
1007
|
+
if (stream.eat(quote[0])) {
|
|
1008
|
+
state.tokenize = this.inTableDefinition(tr, quote[1]);
|
|
976
1009
|
}
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
state.italic = false;
|
|
982
|
-
state.tokenize = this.inTableCell(style, false);
|
|
983
|
-
return makeLocalTagStyle('tableDelimiter2', state);
|
|
984
|
-
}
|
|
985
|
-
else if (needAttr && stream.match('[[', false)) {
|
|
986
|
-
state.tokenize = this.inTableCell(style, false);
|
|
1010
|
+
else {
|
|
1011
|
+
stream.match(getTableDefinitionRegex(equal + quote[0]));
|
|
1012
|
+
}
|
|
1013
|
+
return makeLocalStyle(style, state);
|
|
987
1014
|
}
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
? makeStyle(style, state)
|
|
996
|
-
: this.eatWikiText(style)(stream, state);
|
|
997
|
-
};
|
|
998
|
-
}
|
|
999
|
-
@getTokenizer
|
|
1000
|
-
inSectionHeader(str) {
|
|
1001
|
-
return (stream, state) => {
|
|
1002
|
-
if (stream.sol()) {
|
|
1003
|
-
pop(state);
|
|
1004
|
-
return '';
|
|
1005
|
-
}
|
|
1006
|
-
else if (stream.match(headerRegex)) {
|
|
1007
|
-
if (stream.eol()) {
|
|
1008
|
-
stream.backUp(str.length);
|
|
1009
|
-
state.tokenize = this.inStr(str, 'sectionHeader');
|
|
1015
|
+
else if (quote === '') { // 无引号的属性值
|
|
1016
|
+
if (peekSpace(stream)) {
|
|
1017
|
+
state.tokenize = this.inTableDefinition(tr);
|
|
1018
|
+
return '';
|
|
1019
|
+
}
|
|
1020
|
+
stream.match(tableDefinitionValueRegex[equal ? 1 : 0]);
|
|
1021
|
+
return makeLocalStyle(style, state);
|
|
1010
1022
|
}
|
|
1011
|
-
else if (stream.match(
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
state.tokenize = this.inStr('<!--', false, 'sectionHeader');
|
|
1023
|
+
else if (stream.match(/^=\s*/u)) {
|
|
1024
|
+
state.tokenize = this.inTableDefinition(tr, getQuote(stream));
|
|
1025
|
+
return makeLocalStyle(style, state);
|
|
1015
1026
|
}
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
};
|
|
1020
|
-
}
|
|
1021
|
-
@getTokenizer
|
|
1022
|
-
get inComment() {
|
|
1023
|
-
return this.inStr('-->', 'comment', 'comment');
|
|
1024
|
-
}
|
|
1025
|
-
eatExtTag(tagname, isCloseTag, state) {
|
|
1026
|
-
if (isCloseTag) {
|
|
1027
|
-
chain(state, this.inStr('>', 'error'));
|
|
1028
|
-
return makeLocalTagStyle('error', state);
|
|
1027
|
+
stream.match(tableDefinitionRegex);
|
|
1028
|
+
return makeLocalStyle(style, state);
|
|
1029
|
+
};
|
|
1029
1030
|
}
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1031
|
+
get inTable() {
|
|
1032
|
+
return (stream, state) => {
|
|
1033
|
+
if (stream.sol()) {
|
|
1034
|
+
stream.eatSpace();
|
|
1035
|
+
const mt = stream.match(/^(?:\||\{\{\s*!([!)+-])?\s*\}\})/u);
|
|
1036
|
+
if (mt) {
|
|
1037
|
+
if (mt[1] === '-' || !mt[1] && stream.eat('-')) {
|
|
1038
|
+
stream.match(/^-*\s*/u);
|
|
1039
|
+
state.tokenize = this.inTableDefinition(true);
|
|
1040
|
+
return makeLocalTagStyle('tableDelimiter', state);
|
|
1041
|
+
}
|
|
1042
|
+
else if (mt[1] === '+' || !mt[1] && stream.match(/^\+\s*/u)) {
|
|
1043
|
+
state.tokenize = this.inTableCell(tokens.tableCaption);
|
|
1044
|
+
return makeLocalTagStyle('tableDelimiter', state);
|
|
1045
|
+
}
|
|
1046
|
+
else if (mt[1] === ')' || !mt[1] && stream.eat('}')) {
|
|
1047
|
+
pop(state);
|
|
1048
|
+
return makeLocalTagStyle('tableBracket', state);
|
|
1049
|
+
}
|
|
1050
|
+
stream.eatSpace();
|
|
1051
|
+
state.tokenize = this.inTableCell(tokens.tableTd, mt[1] !== '!');
|
|
1052
|
+
return makeLocalTagStyle('tableDelimiter', state);
|
|
1053
|
+
}
|
|
1054
|
+
else if (stream.match(/^!\s*/u)) {
|
|
1055
|
+
state.tokenize = this.inTableCell(tokens.tableTh);
|
|
1056
|
+
return makeLocalTagStyle('tableDelimiter', state);
|
|
1057
|
+
}
|
|
1058
|
+
else if (isSolSyntax(stream, true)) {
|
|
1059
|
+
return this.eatWikiText('error')(stream, state);
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
return stream.match(wikiRegex)
|
|
1063
|
+
? makeTagStyle('error', state)
|
|
1064
|
+
: this.eatWikiText('error')(stream, state);
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
inTableCell(style, needAttr = true, firstLine = true) {
|
|
1068
|
+
return (stream, state) => {
|
|
1069
|
+
if (stream.sol()) {
|
|
1070
|
+
if (stream.match(/^\s*(?:[|!]|\{\{\s*![!)+-]?\s*\}\})/u, false)) {
|
|
1071
|
+
state.tokenize = this.inTable;
|
|
1072
|
+
return '';
|
|
1073
|
+
}
|
|
1074
|
+
else if (firstLine) {
|
|
1075
|
+
state.tokenize = this.inTableCell(style, false, false);
|
|
1076
|
+
return '';
|
|
1077
|
+
}
|
|
1078
|
+
else if (isSolSyntax(stream, true)) {
|
|
1079
|
+
return this.eatWikiText(style)(stream, state);
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
if (firstLine) {
|
|
1083
|
+
if (stream.match(/^(?:(?:\||\{\{\s*!\s*\}\}){2}|\{\{\s*!!\s*\}\})\s*/u)
|
|
1084
|
+
|| style === tokens.tableTh && stream.match(/^!!\s*/u)) {
|
|
1085
|
+
state.bold = false;
|
|
1086
|
+
state.italic = false;
|
|
1087
|
+
if (!needAttr) {
|
|
1088
|
+
state.tokenize = this.inTableCell(style);
|
|
1089
|
+
}
|
|
1090
|
+
return makeLocalTagStyle('tableDelimiter', state);
|
|
1091
|
+
}
|
|
1092
|
+
else if (needAttr && stream.match(/^(?:\||\{\{\s*!\s*\}\})\s*/u)) {
|
|
1093
|
+
state.bold = false;
|
|
1094
|
+
state.italic = false;
|
|
1095
|
+
state.tokenize = this.inTableCell(style, false);
|
|
1096
|
+
return makeLocalTagStyle('tableDelimiter2', state);
|
|
1097
|
+
}
|
|
1098
|
+
else if (needAttr && stream.match('[[', false)) {
|
|
1099
|
+
state.tokenize = this.inTableCell(style, false);
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
const t = state.stack[0], equal = getEqual(t);
|
|
1103
|
+
if (equal && stream.peek() === '=') {
|
|
1104
|
+
pop(state);
|
|
1105
|
+
return '';
|
|
1047
1106
|
}
|
|
1107
|
+
return stream.match(getTableCellRegex((firstLine ? '|!' : ':') + equal))
|
|
1108
|
+
? makeStyle(style, state)
|
|
1109
|
+
: this.eatWikiText(style)(stream, state);
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1112
|
+
inSectionHeader(str) {
|
|
1113
|
+
return (stream, state) => {
|
|
1114
|
+
if (stream.sol()) {
|
|
1115
|
+
pop(state);
|
|
1116
|
+
return '';
|
|
1117
|
+
}
|
|
1118
|
+
else if (stream.match(headerRegex)) {
|
|
1119
|
+
if (stream.eol()) {
|
|
1120
|
+
stream.backUp(str.length);
|
|
1121
|
+
state.tokenize = this.inStr(str, 'sectionHeader');
|
|
1122
|
+
}
|
|
1123
|
+
else if (stream.match(/^<!--(?!.*?-->.*?=)/u, false)) {
|
|
1124
|
+
// T171074: handle trailing comments
|
|
1125
|
+
stream.backUp(str.length);
|
|
1126
|
+
state.tokenize = this.inStr('<!--', false, 'sectionHeader');
|
|
1127
|
+
}
|
|
1128
|
+
return makeLocalTagStyle('section', state);
|
|
1129
|
+
}
|
|
1130
|
+
return this.eatWikiText('section')(stream, state);
|
|
1131
|
+
};
|
|
1132
|
+
}
|
|
1133
|
+
get inComment() {
|
|
1134
|
+
return this.inStr('-->', 'comment', 'comment');
|
|
1135
|
+
}
|
|
1136
|
+
eatExtTag(tagname, isCloseTag, state) {
|
|
1137
|
+
if (isCloseTag) {
|
|
1138
|
+
chain(state, this.inStr('>', 'error'));
|
|
1048
1139
|
return makeLocalTagStyle('error', state);
|
|
1049
1140
|
}
|
|
1141
|
+
chain(state, this.eatTagName(tagname));
|
|
1142
|
+
return makeLocalTagStyle('extTagBracket', state);
|
|
1050
1143
|
}
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
return (stream, state) => {
|
|
1057
|
-
stream.match(name, true, true);
|
|
1058
|
-
stream.eatSpace();
|
|
1059
|
-
if (isHtmlTag) {
|
|
1060
|
-
state.tokenize = isCloseTag
|
|
1061
|
-
? this.inStr('>', 'htmlTagBracket')
|
|
1062
|
-
: this.inHtmlTagAttribute(name);
|
|
1063
|
-
return makeLocalTagStyle('htmlTagName', state);
|
|
1064
|
-
}
|
|
1065
|
-
// it is the extension tag
|
|
1066
|
-
state.tokenize = isCloseTag ? this.inStr('>', 'extTagBracket') : this.inExtTagAttribute(name);
|
|
1067
|
-
return makeLocalTagStyle('extTagName', state);
|
|
1068
|
-
};
|
|
1069
|
-
}
|
|
1070
|
-
@getTokenizer
|
|
1071
|
-
inHtmlTagAttribute(name, quote) {
|
|
1072
|
-
const style = quote === undefined
|
|
1073
|
-
? `${tokens.htmlTagAttribute} mw-html-${name}`
|
|
1074
|
-
: tokens.htmlTagAttributeValue;
|
|
1075
|
-
return (stream, state) => {
|
|
1076
|
-
if (stream.match(new RegExp(`^${lookahead('<', state)}`, 'iu'), false)) {
|
|
1077
|
-
pop(state);
|
|
1078
|
-
return '';
|
|
1079
|
-
}
|
|
1080
|
-
const mt = stream.match(/^\/?>/u);
|
|
1081
|
-
if (mt) {
|
|
1082
|
-
if (!this.voidHtmlTags.has(name) && (mt[0] === '>' || !selfClosingTags.includes(name))) {
|
|
1083
|
-
state.inHtmlTag.unshift(name);
|
|
1084
|
-
state.dt.html++;
|
|
1144
|
+
eatHtmlTag(tagname, isCloseTag, state) {
|
|
1145
|
+
if (isCloseTag) {
|
|
1146
|
+
const { dt, inHtmlTag } = state;
|
|
1147
|
+
if (dt.n && dt.html) {
|
|
1148
|
+
dt.html--;
|
|
1085
1149
|
}
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
}
|
|
1089
|
-
const t = state.stack[0], pipe = (['inTemplateArgument', 'inParserFunctionArgument', 'inVariable'].includes(t.name) ? '|' : '')
|
|
1090
|
-
+ getEqual(t);
|
|
1091
|
-
if (pipe.includes(stream.peek() ?? '')) {
|
|
1092
|
-
pop(state);
|
|
1093
|
-
return makeLocalTagStyle('htmlTagBracket', state);
|
|
1094
|
-
}
|
|
1095
|
-
else if (stream.match(/^(?:[&<]|\{\{)/u, false)) {
|
|
1096
|
-
return this.eatWikiText(style)(stream, state);
|
|
1097
|
-
}
|
|
1098
|
-
else if (quote) { // 有引号的属性值
|
|
1099
|
-
if (stream.eat(quote[0])) {
|
|
1100
|
-
state.tokenize = this.inHtmlTagAttribute(name, quote[1]);
|
|
1150
|
+
if (tagname === inHtmlTag[0]) {
|
|
1151
|
+
inHtmlTag.shift();
|
|
1101
1152
|
}
|
|
1102
1153
|
else {
|
|
1103
|
-
|
|
1154
|
+
chain(state, this.inStr('>', 'error'));
|
|
1155
|
+
const i = inHtmlTag.lastIndexOf(tagname);
|
|
1156
|
+
if (i !== -1) {
|
|
1157
|
+
inHtmlTag.splice(i, 1);
|
|
1158
|
+
}
|
|
1159
|
+
return makeLocalTagStyle('error', state);
|
|
1104
1160
|
}
|
|
1105
|
-
return makeLocalStyle(style, state);
|
|
1106
1161
|
}
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1162
|
+
chain(state, this.eatTagName(tagname, isCloseTag, true));
|
|
1163
|
+
return makeLocalTagStyle('htmlTagBracket', state);
|
|
1164
|
+
}
|
|
1165
|
+
eatTagName(name, isCloseTag, isHtmlTag) {
|
|
1166
|
+
return (stream, state) => {
|
|
1167
|
+
stream.match(name, true, true);
|
|
1168
|
+
stream.eatSpace();
|
|
1169
|
+
if (isHtmlTag) {
|
|
1170
|
+
state.tokenize = isCloseTag
|
|
1171
|
+
? this.inStr('>', 'htmlTagBracket')
|
|
1172
|
+
: this.inHtmlTagAttribute(name);
|
|
1173
|
+
return makeLocalTagStyle('htmlTagName', state);
|
|
1174
|
+
}
|
|
1175
|
+
// it is the extension tag
|
|
1176
|
+
state.tokenize = isCloseTag ? this.inStr('>', 'extTagBracket') : this.inExtTagAttribute(name);
|
|
1177
|
+
return makeLocalTagStyle('extTagName', state);
|
|
1178
|
+
};
|
|
1179
|
+
}
|
|
1180
|
+
inHtmlTagAttribute(name, quote) {
|
|
1181
|
+
const style = quote === undefined
|
|
1182
|
+
? `${tokens.htmlTagAttribute} mw-html-${name}`
|
|
1183
|
+
: tokens.htmlTagAttributeValue;
|
|
1184
|
+
return (stream, state) => {
|
|
1185
|
+
if (stream.match(new RegExp(`^${lookahead('<', state)}`, 'iu'), false)) {
|
|
1186
|
+
pop(state);
|
|
1110
1187
|
return '';
|
|
1111
1188
|
}
|
|
1112
|
-
stream.match(
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
return makeLocalStyle(style, state);
|
|
1121
|
-
};
|
|
1122
|
-
}
|
|
1123
|
-
@getTokenizer
|
|
1124
|
-
inExtTagAttribute(name, quote, isLang, isPage) {
|
|
1125
|
-
const style = `${tokens.extTagAttribute} mw-ext-${name}`;
|
|
1126
|
-
const advance = (stream, state, re) => {
|
|
1127
|
-
const mt = stream.match(re);
|
|
1128
|
-
if (isLang) {
|
|
1129
|
-
switch (mt[0].trim().toLowerCase()) {
|
|
1130
|
-
case 'js':
|
|
1131
|
-
case 'javascript':
|
|
1132
|
-
state.extMode = javascript;
|
|
1133
|
-
break;
|
|
1134
|
-
case 'css':
|
|
1135
|
-
state.extMode = css;
|
|
1136
|
-
break;
|
|
1137
|
-
case 'json':
|
|
1138
|
-
state.extMode = json;
|
|
1139
|
-
// no default
|
|
1189
|
+
const mt = stream.match(/^\/?>/u);
|
|
1190
|
+
if (mt) {
|
|
1191
|
+
if (!this.voidHtmlTags.has(name) && (mt[0] === '>' || !selfClosingTags.includes(name))) {
|
|
1192
|
+
state.inHtmlTag.unshift(name);
|
|
1193
|
+
state.dt.html++;
|
|
1194
|
+
}
|
|
1195
|
+
pop(state);
|
|
1196
|
+
return makeLocalTagStyle('htmlTagBracket', state);
|
|
1140
1197
|
}
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
const { config: { tagModes } } = this;
|
|
1147
|
-
state.extName = name;
|
|
1148
|
-
state.extMode ||= name in tagModes
|
|
1149
|
-
&& this[tagModes[name]](state.data.tags.filter(tag => tag !== name));
|
|
1150
|
-
if (state.extMode) {
|
|
1151
|
-
state.extState = state.extMode.startState(0);
|
|
1152
|
-
}
|
|
1153
|
-
state.tokenize = this.eatExtTagArea(name);
|
|
1154
|
-
return makeLocalTagStyle('extTagBracket', state);
|
|
1155
|
-
}
|
|
1156
|
-
else if (stream.match('/>')) {
|
|
1157
|
-
state.extMode = false;
|
|
1158
|
-
pop(state);
|
|
1159
|
-
return makeLocalTagStyle('extTagBracket', state);
|
|
1160
|
-
}
|
|
1161
|
-
else if (quote) { // 有引号的属性值
|
|
1162
|
-
if (stream.eat(quote[0])) {
|
|
1163
|
-
const [, remains] = quote;
|
|
1164
|
-
state.tokenize = this.inExtTagAttribute(name, remains, isLang && Boolean(remains), isPage && Boolean(remains));
|
|
1165
|
-
return makeLocalTagStyle('extTagAttributeValue', state);
|
|
1198
|
+
const t = state.stack[0], pipe = (['inTemplateArgument', 'inParserFunctionArgument', 'inVariable'].includes(t.name) ? '|' : '')
|
|
1199
|
+
+ getEqual(t);
|
|
1200
|
+
if (pipe.includes(stream.peek() ?? '')) {
|
|
1201
|
+
pop(state);
|
|
1202
|
+
return makeLocalTagStyle('htmlTagBracket', state);
|
|
1166
1203
|
}
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
else if (quote === '') { // 无引号的属性值
|
|
1170
|
-
if (peekSpace(stream, true)) {
|
|
1171
|
-
state.tokenize = this.inExtTagAttribute(name);
|
|
1172
|
-
return '';
|
|
1204
|
+
else if (stream.match(/^(?:[&<]|\{\{)/u, false)) {
|
|
1205
|
+
return this.eatWikiText(style)(stream, state);
|
|
1173
1206
|
}
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
state.tokenize = this.inExtTagAttribute(name, undefined, syntaxHighlight.has(name) && /(?:^|\s)lang\s*$/iu.test(mt[0]), name === 'templatestyles' && /(?:^|\s)src\s*$/iu.test(mt[0]));
|
|
1183
|
-
}
|
|
1184
|
-
return makeLocalStyle(style, state);
|
|
1185
|
-
};
|
|
1186
|
-
}
|
|
1187
|
-
@getTokenizer
|
|
1188
|
-
eatExtTagArea(name) {
|
|
1189
|
-
return (stream, state) => {
|
|
1190
|
-
const { pos } = stream, i = stream.string.slice(pos).search(getExtTagCloseRegex(name));
|
|
1191
|
-
if (i === 0) {
|
|
1192
|
-
stream.match('</');
|
|
1193
|
-
state.tokenize = this.eatTagName(name, true);
|
|
1194
|
-
state.extName = false;
|
|
1195
|
-
state.extMode = false;
|
|
1196
|
-
state.extState = false;
|
|
1197
|
-
return makeLocalTagStyle('extTagBracket', state);
|
|
1198
|
-
}
|
|
1199
|
-
let origString = '';
|
|
1200
|
-
if (i !== -1) {
|
|
1201
|
-
origString = stream.string;
|
|
1202
|
-
stream.string = origString.slice(0, pos + i);
|
|
1203
|
-
}
|
|
1204
|
-
chain(state, this.inExtTokens(origString));
|
|
1205
|
-
return '';
|
|
1206
|
-
};
|
|
1207
|
-
}
|
|
1208
|
-
@getTokenizer
|
|
1209
|
-
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
1210
|
-
inExtTokens(origString) {
|
|
1211
|
-
return (stream, state) => {
|
|
1212
|
-
let ret;
|
|
1213
|
-
if (state.extMode === false) {
|
|
1214
|
-
ret = `mw-tag-${state.extName} ${tokens.extTag}`;
|
|
1215
|
-
stream.skipToEnd();
|
|
1216
|
-
}
|
|
1217
|
-
else {
|
|
1218
|
-
ret = `mw-tag-${state.extName} ${state.extMode.token(stream, state.extState) ?? ''}`;
|
|
1219
|
-
}
|
|
1220
|
-
if (stream.eol()) {
|
|
1221
|
-
if (origString) {
|
|
1222
|
-
stream.string = origString;
|
|
1207
|
+
else if (quote) { // 有引号的属性值
|
|
1208
|
+
if (stream.eat(quote[0])) {
|
|
1209
|
+
state.tokenize = this.inHtmlTagAttribute(name, quote[1]);
|
|
1210
|
+
}
|
|
1211
|
+
else {
|
|
1212
|
+
stream.match(getHtmlAttrRegex(pipe + quote[0]));
|
|
1213
|
+
}
|
|
1214
|
+
return makeLocalStyle(style, state);
|
|
1223
1215
|
}
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1216
|
+
else if (quote === '') { // 无引号的属性值
|
|
1217
|
+
if (peekSpace(stream, true)) {
|
|
1218
|
+
state.tokenize = this.inHtmlTagAttribute(name);
|
|
1219
|
+
return '';
|
|
1220
|
+
}
|
|
1221
|
+
stream.match(getHtmlAttrRegex(String.raw `\s${pipe}`));
|
|
1222
|
+
return makeLocalStyle(style, state);
|
|
1223
|
+
}
|
|
1224
|
+
else if (stream.match(/^=\s*/u)) {
|
|
1225
|
+
state.tokenize = this.inHtmlTagAttribute(name, getQuote(stream));
|
|
1226
|
+
return makeLocalStyle(style, state);
|
|
1227
|
+
}
|
|
1228
|
+
stream.match(getHtmlAttrKeyRegex(pipe));
|
|
1229
|
+
return makeLocalStyle(style, state);
|
|
1230
|
+
};
|
|
1234
1231
|
}
|
|
1235
|
-
|
|
1236
|
-
|
|
1232
|
+
inExtTagAttribute(name, quote, isLang, isPage) {
|
|
1233
|
+
const style = `${tokens.extTagAttribute} mw-ext-${name}`;
|
|
1234
|
+
const advance = (stream, state, re) => {
|
|
1235
|
+
const mt = stream.match(re);
|
|
1236
|
+
if (isLang) {
|
|
1237
|
+
switch (mt[0].trim().toLowerCase()) {
|
|
1238
|
+
case 'js':
|
|
1239
|
+
case 'javascript':
|
|
1240
|
+
state.extMode = javascript;
|
|
1241
|
+
break;
|
|
1242
|
+
case 'css':
|
|
1243
|
+
state.extMode = css;
|
|
1244
|
+
break;
|
|
1245
|
+
case 'json':
|
|
1246
|
+
state.extMode = json;
|
|
1247
|
+
// no default
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
return makeLocalStyle(tokens.extTagAttributeValue + (isPage ? ` ${tokens.pageName}` : ''), state);
|
|
1251
|
+
};
|
|
1252
|
+
return (stream, state) => {
|
|
1253
|
+
if (stream.eat('>')) {
|
|
1254
|
+
const { config: { tagModes } } = this;
|
|
1255
|
+
state.extName = name;
|
|
1256
|
+
state.extMode ||= name in tagModes
|
|
1257
|
+
&& this[tagModes[name]](state.data.tags.filter(tag => tag !== name));
|
|
1258
|
+
if (state.extMode) {
|
|
1259
|
+
state.extState = state.extMode.startState(0);
|
|
1260
|
+
}
|
|
1261
|
+
state.tokenize = this.eatExtTagArea(name);
|
|
1262
|
+
return makeLocalTagStyle('extTagBracket', state);
|
|
1263
|
+
}
|
|
1264
|
+
else if (stream.match('/>')) {
|
|
1265
|
+
state.extMode = false;
|
|
1266
|
+
pop(state);
|
|
1267
|
+
return makeLocalTagStyle('extTagBracket', state);
|
|
1268
|
+
}
|
|
1269
|
+
else if (quote) { // 有引号的属性值
|
|
1270
|
+
if (stream.eat(quote[0])) {
|
|
1271
|
+
const [, remains] = quote;
|
|
1272
|
+
state.tokenize = this.inExtTagAttribute(name, remains, isLang && Boolean(remains), isPage && Boolean(remains));
|
|
1273
|
+
return makeLocalTagStyle('extTagAttributeValue', state);
|
|
1274
|
+
}
|
|
1275
|
+
return advance(stream, state, getExtAttrRegex(quote[0]));
|
|
1276
|
+
}
|
|
1277
|
+
else if (quote === '') { // 无引号的属性值
|
|
1278
|
+
if (peekSpace(stream, true)) {
|
|
1279
|
+
state.tokenize = this.inExtTagAttribute(name);
|
|
1280
|
+
return '';
|
|
1281
|
+
}
|
|
1282
|
+
return advance(stream, state, /^(?:[^>/\s]|\/(?!>))+/u);
|
|
1283
|
+
}
|
|
1284
|
+
else if (stream.match(/^=\s*/u)) {
|
|
1285
|
+
state.tokenize = this.inExtTagAttribute(name, getQuote(stream), isLang, isPage);
|
|
1286
|
+
return makeLocalStyle(style, state);
|
|
1287
|
+
}
|
|
1288
|
+
const mt = stream.match(/^(?:[^>/=]|\/(?!>))+/u);
|
|
1289
|
+
if (stream.peek() === '=') {
|
|
1290
|
+
state.tokenize = this.inExtTagAttribute(name, undefined, syntaxHighlight.has(name) && /(?:^|\s)lang\s*$/iu.test(mt[0]), name === 'templatestyles' && /(?:^|\s)src\s*$/iu.test(mt[0]));
|
|
1291
|
+
}
|
|
1292
|
+
return makeLocalStyle(style, state);
|
|
1293
|
+
};
|
|
1237
1294
|
}
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1295
|
+
eatExtTagArea(name) {
|
|
1296
|
+
return (stream, state) => {
|
|
1297
|
+
const { pos } = stream, i = stream.string.slice(pos).search(getExtTagCloseRegex(name));
|
|
1298
|
+
if (i === 0) {
|
|
1299
|
+
stream.match('</');
|
|
1300
|
+
state.tokenize = this.eatTagName(name, true);
|
|
1301
|
+
state.extName = false;
|
|
1302
|
+
state.extMode = false;
|
|
1303
|
+
state.extState = false;
|
|
1304
|
+
return makeLocalTagStyle('extTagBracket', state);
|
|
1248
1305
|
}
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
else if (stream.match('<!--')) {
|
|
1256
|
-
chain(state, this.inComment);
|
|
1257
|
-
return makeLocalTagStyle('comment', state);
|
|
1258
|
-
}
|
|
1259
|
-
else if (pos === 0 && sol) {
|
|
1260
|
-
state.nVar--;
|
|
1261
|
-
pop(state);
|
|
1262
|
-
stream.pos = 0;
|
|
1306
|
+
let origString = '';
|
|
1307
|
+
if (i !== -1) {
|
|
1308
|
+
origString = stream.string;
|
|
1309
|
+
stream.string = origString.slice(0, pos + i);
|
|
1310
|
+
}
|
|
1311
|
+
chain(state, this.inExtTokens(origString));
|
|
1263
1312
|
return '';
|
|
1264
|
-
}
|
|
1265
|
-
return pos === 1 && isSolSyntax(stream) || !stream.match(re)
|
|
1266
|
-
? this.eatWikiText(tag)(stream, state)
|
|
1267
|
-
: (pos === 1 ? makeTagStyle : makeLocalTagStyle)(tag, state);
|
|
1268
|
-
};
|
|
1269
|
-
}
|
|
1270
|
-
eatTransclusion(stream, state) {
|
|
1271
|
-
const [{ length }] = stream.match(/^\s*/u);
|
|
1272
|
-
// Parser function
|
|
1273
|
-
if (stream.peek() === '#') {
|
|
1274
|
-
stream.backUp(length);
|
|
1275
|
-
state.nExt++;
|
|
1276
|
-
chain(state, this.inParserFunctionName());
|
|
1277
|
-
return makeLocalTagStyle('parserFunctionBracket', state);
|
|
1313
|
+
};
|
|
1278
1314
|
}
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1315
|
+
inExtTokens(origString) {
|
|
1316
|
+
return (stream, state) => {
|
|
1317
|
+
let ret;
|
|
1318
|
+
if (state.extMode === false) {
|
|
1319
|
+
ret = `mw-tag-${state.extName} ${tokens.extTag}`;
|
|
1320
|
+
stream.skipToEnd();
|
|
1321
|
+
}
|
|
1322
|
+
else {
|
|
1323
|
+
ret = `mw-tag-${state.extName} ${state.extMode.token(stream, state.extState) ?? ''}`;
|
|
1324
|
+
}
|
|
1325
|
+
if (stream.eol()) {
|
|
1326
|
+
if (origString) {
|
|
1327
|
+
stream.string = origString;
|
|
1328
|
+
}
|
|
1329
|
+
pop(state);
|
|
1330
|
+
}
|
|
1331
|
+
return ret;
|
|
1332
|
+
};
|
|
1333
|
+
}
|
|
1334
|
+
inVariable(pos = 0) {
|
|
1335
|
+
let tag = 'comment';
|
|
1336
|
+
if (pos === 0) {
|
|
1337
|
+
tag = 'templateVariableName';
|
|
1286
1338
|
}
|
|
1287
|
-
else if (
|
|
1288
|
-
|
|
1339
|
+
else if (pos === 1) {
|
|
1340
|
+
tag = 'templateVariable';
|
|
1289
1341
|
}
|
|
1290
|
-
const
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1342
|
+
const re = variableRegex[pos === 1 ? 1 : 0];
|
|
1343
|
+
return (stream, state) => {
|
|
1344
|
+
const sol = stream.sol();
|
|
1345
|
+
stream.eatSpace();
|
|
1346
|
+
if (stream.eol()) {
|
|
1347
|
+
return makeLocalStyle('', state);
|
|
1348
|
+
}
|
|
1349
|
+
else if (stream.eat('|')) {
|
|
1350
|
+
if (pos < 2) {
|
|
1351
|
+
state.tokenize = this.inVariable(pos + 1);
|
|
1352
|
+
}
|
|
1353
|
+
return makeLocalTagStyle('templateVariableDelimiter', state);
|
|
1354
|
+
}
|
|
1355
|
+
else if (stream.match(/^\}{2,3}/u)) {
|
|
1356
|
+
pop(state);
|
|
1357
|
+
return makeLocalTagStyle('templateVariableBracket', state, 'nVar');
|
|
1358
|
+
}
|
|
1359
|
+
else if (stream.match('<!--')) {
|
|
1360
|
+
chain(state, this.inComment);
|
|
1361
|
+
return makeLocalTagStyle('comment', state);
|
|
1362
|
+
}
|
|
1363
|
+
else if (pos === 0 && sol) {
|
|
1364
|
+
state.nVar--;
|
|
1365
|
+
pop(state);
|
|
1366
|
+
stream.pos = 0;
|
|
1367
|
+
return '';
|
|
1368
|
+
}
|
|
1369
|
+
return pos === 1 && isSolSyntax(stream) || !stream.match(re)
|
|
1370
|
+
? this.eatWikiText(tag)(stream, state)
|
|
1371
|
+
: (pos === 1 ? makeTagStyle : makeLocalTagStyle)(tag, state);
|
|
1372
|
+
};
|
|
1373
|
+
}
|
|
1374
|
+
eatTransclusion(stream, state) {
|
|
1375
|
+
const [{ length }] = stream.match(/^\s*/u);
|
|
1376
|
+
// Parser function
|
|
1377
|
+
if (stream.peek() === '#') {
|
|
1300
1378
|
stream.backUp(length);
|
|
1301
1379
|
state.nExt++;
|
|
1302
1380
|
chain(state, this.inParserFunctionName());
|
|
1303
1381
|
return makeLocalTagStyle('parserFunctionBracket', state);
|
|
1304
1382
|
}
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
state.nExt--;
|
|
1332
|
-
pop(state);
|
|
1333
|
-
stream.pos = 0;
|
|
1334
|
-
return '';
|
|
1383
|
+
// Check for parser function without '#'
|
|
1384
|
+
const name = stream.match(/^([^}<{|::]+)(.?)/u, false);
|
|
1385
|
+
if (name) {
|
|
1386
|
+
const [, f, delimiter] = name, fullWidth = delimiter === ':';
|
|
1387
|
+
let ff = f;
|
|
1388
|
+
if (fullWidth) {
|
|
1389
|
+
ff += ':';
|
|
1390
|
+
}
|
|
1391
|
+
else if (delimiter !== ':') {
|
|
1392
|
+
ff = f.trim();
|
|
1393
|
+
}
|
|
1394
|
+
const ffLower = ff.toLowerCase(), { config: { functionSynonyms, variableIDs, functionHooks } } = this, canonicalName = Object.prototype.hasOwnProperty.call(functionSynonyms[1], ff)
|
|
1395
|
+
&& functionSynonyms[1][ff]
|
|
1396
|
+
|| Object.prototype.hasOwnProperty.call(functionSynonyms[0], ffLower)
|
|
1397
|
+
&& functionSynonyms[0][ffLower];
|
|
1398
|
+
if ((!delimiter || fullWidth || delimiter === ':' || delimiter === '}')
|
|
1399
|
+
&& canonicalName
|
|
1400
|
+
&& (fullWidth || delimiter === ':' || !variableIDs || variableIDs.includes(canonicalName))
|
|
1401
|
+
&& (!fullWidth && delimiter !== ':'
|
|
1402
|
+
|| !functionHooks
|
|
1403
|
+
|| functionHooks.includes(canonicalName) || otherParserFunctions.has(canonicalName))) {
|
|
1404
|
+
stream.backUp(length);
|
|
1405
|
+
state.nExt++;
|
|
1406
|
+
chain(state, this.inParserFunctionName());
|
|
1407
|
+
return makeLocalTagStyle('parserFunctionBracket', state);
|
|
1408
|
+
}
|
|
1335
1409
|
}
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
state.tokenize = subst && stream.match(/^\s*#/u, false)
|
|
1339
|
-
? this.inParserFunctionName()
|
|
1340
|
-
: this.inParserFunctionArgument(invoke, n, ns);
|
|
1341
|
-
return makeLocalTagStyle(space || ch === '|' ? 'error' : 'parserFunctionDelimiter', state);
|
|
1410
|
+
if (stream.match('}}')) {
|
|
1411
|
+
return undefined;
|
|
1342
1412
|
}
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
case 'switch':
|
|
1355
|
-
state.tokenize = this.inParserFunctionName(undefined, 1);
|
|
1356
|
-
break;
|
|
1357
|
-
case 'tag':
|
|
1358
|
-
state.tokenize = this.inParserFunctionName(undefined, 2);
|
|
1359
|
-
break;
|
|
1360
|
-
case 'ifexist':
|
|
1361
|
-
case 'lst':
|
|
1362
|
-
case 'lstx':
|
|
1363
|
-
case 'lsth':
|
|
1364
|
-
state.tokenize = this.inParserFunctionName(Infinity);
|
|
1365
|
-
// no default
|
|
1366
|
-
}
|
|
1413
|
+
// Template
|
|
1414
|
+
stream.backUp(length);
|
|
1415
|
+
state.nTemplate++;
|
|
1416
|
+
chain(state, this.inTemplatePageName());
|
|
1417
|
+
return makeLocalTagStyle('templateBracket', state);
|
|
1418
|
+
}
|
|
1419
|
+
inParserFunctionName(invoke, n, ns, subst) {
|
|
1420
|
+
return (stream, state) => {
|
|
1421
|
+
const sol = stream.sol(), space = stream.eatSpace();
|
|
1422
|
+
if (stream.eol()) {
|
|
1423
|
+
return makeLocalStyle('', state);
|
|
1367
1424
|
}
|
|
1368
|
-
else {
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1425
|
+
else if (stream.eat('}')) {
|
|
1426
|
+
pop(state);
|
|
1427
|
+
return makeLocalTagStyle(stream.eat('}') ? 'parserFunctionBracket' : 'error', state, 'nExt');
|
|
1428
|
+
}
|
|
1429
|
+
else if (stream.match('<!--')) {
|
|
1430
|
+
chain(state, this.inComment);
|
|
1431
|
+
return makeLocalTagStyle('comment', state);
|
|
1432
|
+
}
|
|
1433
|
+
else if (sol) {
|
|
1434
|
+
state.nExt--;
|
|
1435
|
+
pop(state);
|
|
1436
|
+
stream.pos = 0;
|
|
1437
|
+
return '';
|
|
1438
|
+
}
|
|
1439
|
+
const ch = stream.eat(/[::|]/u);
|
|
1440
|
+
if (ch) {
|
|
1441
|
+
state.tokenize = subst && stream.match(/^\s*#/u, false)
|
|
1442
|
+
? this.inParserFunctionName()
|
|
1443
|
+
: this.inParserFunctionArgument(invoke, n, ns);
|
|
1444
|
+
return makeLocalTagStyle(space || ch === '|' ? 'error' : 'parserFunctionDelimiter', state);
|
|
1445
|
+
}
|
|
1446
|
+
const mt = stream.match(/^(?:[^::}{|<>[\]\s]|\s(?![::]))+/u);
|
|
1447
|
+
if (mt) {
|
|
1448
|
+
const name = mt[0].trim().toLowerCase() + (stream.peek() === ':' ? ':' : ''), { config: { functionSynonyms: [insensitive] } } = this;
|
|
1449
|
+
if (name.startsWith('#')) {
|
|
1450
|
+
switch (insensitive[name] ?? insensitive[name.slice(1)]) {
|
|
1451
|
+
case 'invoke':
|
|
1452
|
+
state.tokenize = this.inParserFunctionName(2);
|
|
1375
1453
|
break;
|
|
1376
|
-
case '
|
|
1377
|
-
|
|
1454
|
+
case 'widget':
|
|
1455
|
+
state.tokenize = this.inParserFunctionName(1);
|
|
1378
1456
|
break;
|
|
1379
|
-
case '
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1457
|
+
case 'switch':
|
|
1458
|
+
state.tokenize = this.inParserFunctionName(undefined, 1);
|
|
1459
|
+
break;
|
|
1460
|
+
case 'tag':
|
|
1461
|
+
state.tokenize = this.inParserFunctionName(undefined, 2);
|
|
1462
|
+
break;
|
|
1463
|
+
case 'ifexist':
|
|
1464
|
+
case 'lst':
|
|
1465
|
+
case 'lstx':
|
|
1466
|
+
case 'lsth':
|
|
1467
|
+
state.tokenize = this.inParserFunctionName(Infinity);
|
|
1383
1468
|
// no default
|
|
1384
1469
|
}
|
|
1385
|
-
state.tokenize = canonicalName === 'subst' || canonicalName === 'safesubst'
|
|
1386
|
-
? this.inParserFunctionName(invoke, n, ns, true)
|
|
1387
|
-
: this.inParserFunctionName(Infinity, Infinity, namespace);
|
|
1388
1470
|
}
|
|
1471
|
+
else {
|
|
1472
|
+
const canonicalName = insensitive[name];
|
|
1473
|
+
if (pageFunctions.has(canonicalName)) {
|
|
1474
|
+
let namespace = 0;
|
|
1475
|
+
switch (canonicalName) {
|
|
1476
|
+
case 'filepath':
|
|
1477
|
+
namespace = 6;
|
|
1478
|
+
break;
|
|
1479
|
+
case 'int':
|
|
1480
|
+
namespace = 8;
|
|
1481
|
+
break;
|
|
1482
|
+
case 'raw':
|
|
1483
|
+
case 'msg':
|
|
1484
|
+
case 'msgnw':
|
|
1485
|
+
namespace = 10;
|
|
1486
|
+
// no default
|
|
1487
|
+
}
|
|
1488
|
+
state.tokenize = canonicalName === 'subst' || canonicalName === 'safesubst'
|
|
1489
|
+
? this.inParserFunctionName(invoke, n, ns, true)
|
|
1490
|
+
: this.inParserFunctionName(Infinity, Infinity, namespace);
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
return makeLocalTagStyle('parserFunctionName', state);
|
|
1389
1494
|
}
|
|
1390
|
-
return makeLocalTagStyle('parserFunctionName', state);
|
|
1391
|
-
}
|
|
1392
|
-
pop(state);
|
|
1393
|
-
return makeLocalStyle('', state, 'nExt');
|
|
1394
|
-
};
|
|
1395
|
-
}
|
|
1396
|
-
@getTokenizer
|
|
1397
|
-
inTemplatePageName(haveEaten, anchor) {
|
|
1398
|
-
const style = anchor ? tokens.error : `${tokens.templateName} ${tokens.pageName}`, chars = '{}<', re = anchor ? templateRegex : /^(?:&#(?:\d+|x[a-f\d]+);|[^|{}<>[\]#%]|%(?![\da-f]{2}))+/iu;
|
|
1399
|
-
return (stream, state) => {
|
|
1400
|
-
const sol = stream.sol(), space = stream.eatSpace();
|
|
1401
|
-
if (stream.eol()) {
|
|
1402
|
-
return makeLocalStyle('', state);
|
|
1403
|
-
}
|
|
1404
|
-
else if (stream.match('}}')) {
|
|
1405
|
-
pop(state);
|
|
1406
|
-
return makeLocalTagStyle('templateBracket', state, 'nTemplate');
|
|
1407
|
-
}
|
|
1408
|
-
else if (stream.match('<!--')) {
|
|
1409
|
-
chain(state, this.inComment);
|
|
1410
|
-
return makeLocalTagStyle('comment', state);
|
|
1411
|
-
}
|
|
1412
|
-
else if (stream.match(/^<\/?onlyinclude>/u)
|
|
1413
|
-
|| stream.match(/^<(?:(?:includeonly|noinclude)(?:\s[^>]*)?\/?>|\/(?:includeonly|noinclude)\s*>)/iu)) {
|
|
1414
|
-
return makeLocalTagStyle('comment', state);
|
|
1415
|
-
}
|
|
1416
|
-
else if (stream.eat('|')) {
|
|
1417
|
-
state.tokenize = this.inTemplateArgument(true);
|
|
1418
|
-
return makeLocalTagStyle('templateDelimiter', state);
|
|
1419
|
-
}
|
|
1420
|
-
else if (haveEaten && sol) {
|
|
1421
|
-
state.nTemplate--;
|
|
1422
1495
|
pop(state);
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
}
|
|
1426
|
-
else if (!anchor && stream.eat('#')) {
|
|
1427
|
-
state.tokenize = this.inTemplatePageName(true, true);
|
|
1428
|
-
return makeLocalTagStyle('error', state);
|
|
1429
|
-
}
|
|
1430
|
-
else if (!anchor
|
|
1431
|
-
&& stream.match(new RegExp(String.raw `^(?:[>[\]]|%[\da-f]{2}|${lookahead(chars, state)})+`, 'iu'))) {
|
|
1432
|
-
return makeLocalTagStyle('error', state);
|
|
1433
|
-
}
|
|
1434
|
-
else if (!anchor && stream.peek() === '<') {
|
|
1435
|
-
pop(state);
|
|
1436
|
-
return makeLocalStyle('', state, 'nTemplate');
|
|
1437
|
-
}
|
|
1438
|
-
else if (space && !haveEaten) {
|
|
1439
|
-
return makeLocalStyle('', state);
|
|
1440
|
-
}
|
|
1441
|
-
else if (stream.match(re)) {
|
|
1442
|
-
if (!haveEaten) {
|
|
1443
|
-
state.tokenize = this.inTemplatePageName(true, anchor);
|
|
1444
|
-
}
|
|
1445
|
-
return makeLocalStyle(style, state);
|
|
1446
|
-
}
|
|
1447
|
-
return space
|
|
1448
|
-
? makeLocalStyle(style, state)
|
|
1449
|
-
: this.eatWikiText(style)(stream, state);
|
|
1450
|
-
};
|
|
1451
|
-
}
|
|
1452
|
-
@getTokenizer
|
|
1453
|
-
inParserFunctionArgument(module, n = module ?? Infinity, ns = 0) {
|
|
1454
|
-
if (n === 0) {
|
|
1455
|
-
return this.inTemplateArgument(true, true);
|
|
1456
|
-
}
|
|
1457
|
-
const chars = n === 2 ? '}{<' : "}{<~'_-"; // `#invoke`/`#tag`
|
|
1458
|
-
let style = `${tokens.parserFunction} ${module ? tokens.pageName : ''}`;
|
|
1459
|
-
switch (module) {
|
|
1460
|
-
case 1:
|
|
1461
|
-
style += ' mw-function-274';
|
|
1462
|
-
break;
|
|
1463
|
-
case 2:
|
|
1464
|
-
style += ' mw-function-828';
|
|
1465
|
-
break;
|
|
1466
|
-
case Infinity:
|
|
1467
|
-
style += ` mw-function-${ns}`;
|
|
1468
|
-
// no default
|
|
1496
|
+
return makeLocalStyle('', state, 'nExt');
|
|
1497
|
+
};
|
|
1469
1498
|
}
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1499
|
+
inTemplatePageName(haveEaten, anchor) {
|
|
1500
|
+
const style = anchor ? tokens.error : `${tokens.templateName} ${tokens.pageName}`, chars = '{}<', re = anchor ? templateRegex : /^(?:&#(?:\d+|x[a-f\d]+);|[^|{}<>[\]#%]|%(?![\da-f]{2}))+/iu;
|
|
1501
|
+
return (stream, state) => {
|
|
1502
|
+
const sol = stream.sol(), space = stream.eatSpace();
|
|
1503
|
+
if (stream.eol()) {
|
|
1504
|
+
return makeLocalStyle('', state);
|
|
1474
1505
|
}
|
|
1475
|
-
else if (
|
|
1476
|
-
state
|
|
1506
|
+
else if (stream.match('}}')) {
|
|
1507
|
+
pop(state);
|
|
1508
|
+
return makeLocalTagStyle('templateBracket', state, 'nTemplate');
|
|
1477
1509
|
}
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
pop(state);
|
|
1482
|
-
return makeLocalTagStyle('parserFunctionBracket', state, 'nExt');
|
|
1483
|
-
}
|
|
1484
|
-
return !isSolSyntax(stream)
|
|
1485
|
-
&& stream.match(parserFunctionRegex[module ? 0 : Number(needColon(state)) + 1](chars))
|
|
1486
|
-
? makeLocalStyle(style, state)
|
|
1487
|
-
: this.eatWikiText('parserFunction')(stream, state);
|
|
1488
|
-
};
|
|
1489
|
-
}
|
|
1490
|
-
@getTokenizer
|
|
1491
|
-
inTemplateArgument(expectName, parserFunction) {
|
|
1492
|
-
const tag = parserFunction ? 'parserFunction' : 'template';
|
|
1493
|
-
return (stream, state) => {
|
|
1494
|
-
const space = stream.eatSpace();
|
|
1495
|
-
if (stream.eol()) {
|
|
1496
|
-
return makeLocalTagStyle(tag, state);
|
|
1497
|
-
}
|
|
1498
|
-
else if (stream.eat('|')) {
|
|
1499
|
-
if (!expectName) {
|
|
1500
|
-
state.tokenize = this.inTemplateArgument(true, parserFunction);
|
|
1510
|
+
else if (stream.match('<!--')) {
|
|
1511
|
+
chain(state, this.inComment);
|
|
1512
|
+
return makeLocalTagStyle('comment', state);
|
|
1501
1513
|
}
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
if (space) {
|
|
1506
|
-
return makeLocalTagStyle(tag, state);
|
|
1514
|
+
else if (stream.match(/^<\/?onlyinclude>/u)
|
|
1515
|
+
|| stream.match(/^<(?:(?:includeonly|noinclude)(?:\s[^>]*)?\/?>|\/(?:includeonly|noinclude)\s*>)/iu)) {
|
|
1516
|
+
return makeLocalTagStyle('comment', state);
|
|
1507
1517
|
}
|
|
1508
|
-
stream.
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
}
|
|
1512
|
-
else if (stream.sol() && stream.peek() === '=') {
|
|
1513
|
-
const style = this.eatWikiText(tag)(stream, state);
|
|
1514
|
-
if (style.includes(tokens.sectionHeader)) {
|
|
1515
|
-
return style;
|
|
1518
|
+
else if (stream.eat('|')) {
|
|
1519
|
+
state.tokenize = this.inTemplateArgument(true);
|
|
1520
|
+
return makeLocalTagStyle('templateDelimiter', state);
|
|
1516
1521
|
}
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
return makeLocalTagStyle('templateArgumentName', state);
|
|
1523
|
-
}
|
|
1524
|
-
else if (isSolSyntax(stream) && stream.peek() !== '=') {
|
|
1525
|
-
return this.eatWikiText(tag)(stream, state);
|
|
1526
|
-
}
|
|
1527
|
-
return stream.match(needColon(state) ? argumentRegex : styleRegex) || space
|
|
1528
|
-
? makeLocalTagStyle(tag, state)
|
|
1529
|
-
: this.eatWikiText(tag)(stream, state);
|
|
1530
|
-
};
|
|
1531
|
-
}
|
|
1532
|
-
@getTokenizer
|
|
1533
|
-
inConvert(style, needFlag, needLang = true, plain) {
|
|
1534
|
-
return (stream, state) => {
|
|
1535
|
-
const space = stream.eatSpace();
|
|
1536
|
-
if (stream.match('}-')) {
|
|
1537
|
-
pop(state);
|
|
1538
|
-
return makeLocalTagStyle('convertBracket', state);
|
|
1539
|
-
}
|
|
1540
|
-
else if (needFlag && stream.match(/^[;\sa-z-]*(?=\|)/iu)) {
|
|
1541
|
-
chain(state, this.inConvert(style, false, true, plain));
|
|
1542
|
-
state.tokenize = this.inStr('|', 'convertDelimiter');
|
|
1543
|
-
return makeLocalTagStyle('convertFlag', state);
|
|
1544
|
-
}
|
|
1545
|
-
else if (stream.match(this.convertSemicolon)) {
|
|
1546
|
-
if (needFlag || !needLang) {
|
|
1547
|
-
state.tokenize = this.inConvert(style, false, true, plain);
|
|
1522
|
+
else if (haveEaten && sol) {
|
|
1523
|
+
state.nTemplate--;
|
|
1524
|
+
pop(state);
|
|
1525
|
+
stream.pos = 0;
|
|
1526
|
+
return '';
|
|
1548
1527
|
}
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
state.tokenize = this.inConvert(style, false, false, plain);
|
|
1553
|
-
return makeLocalTagStyle('convertLang', state);
|
|
1554
|
-
}
|
|
1555
|
-
else if (plain) {
|
|
1556
|
-
if (stream.match('-{', false)) {
|
|
1557
|
-
return this.eatWikiText(style)(stream, state);
|
|
1528
|
+
else if (!anchor && stream.eat('#')) {
|
|
1529
|
+
state.tokenize = this.inTemplatePageName(true, true);
|
|
1530
|
+
return makeLocalTagStyle('error', state);
|
|
1558
1531
|
}
|
|
1559
|
-
|
|
1560
|
-
|
|
1532
|
+
else if (!anchor
|
|
1533
|
+
&& stream.match(new RegExp(String.raw `^(?:[>[\]]|%[\da-f]{2}|${lookahead(chars, state)})+`, 'iu'))) {
|
|
1534
|
+
return makeLocalTagStyle('error', state);
|
|
1535
|
+
}
|
|
1536
|
+
else if (!anchor && stream.peek() === '<') {
|
|
1537
|
+
pop(state);
|
|
1538
|
+
return makeLocalStyle('', state, 'nTemplate');
|
|
1539
|
+
}
|
|
1540
|
+
else if (space && !haveEaten) {
|
|
1541
|
+
return makeLocalStyle('', state);
|
|
1542
|
+
}
|
|
1543
|
+
else if (stream.match(re)) {
|
|
1544
|
+
if (!haveEaten) {
|
|
1545
|
+
state.tokenize = this.inTemplatePageName(true, anchor);
|
|
1546
|
+
}
|
|
1547
|
+
return makeLocalStyle(style, state);
|
|
1548
|
+
}
|
|
1549
|
+
return space
|
|
1550
|
+
? makeLocalStyle(style, state)
|
|
1551
|
+
: this.eatWikiText(style)(stream, state);
|
|
1552
|
+
};
|
|
1553
|
+
}
|
|
1554
|
+
inParserFunctionArgument(module, n = module ?? Infinity, ns = 0) {
|
|
1555
|
+
if (n === 0) {
|
|
1556
|
+
return this.inTemplateArgument(true, true);
|
|
1557
|
+
}
|
|
1558
|
+
const chars = n === 2 ? '}{<' : "}{<~'_-"; // `#invoke`/`#tag`
|
|
1559
|
+
let style = `${tokens.parserFunction} ${module ? tokens.pageName : ''}`;
|
|
1560
|
+
switch (module) {
|
|
1561
|
+
case 1:
|
|
1562
|
+
style += ' mw-function-274';
|
|
1563
|
+
break;
|
|
1564
|
+
case 2:
|
|
1565
|
+
style += ' mw-function-828';
|
|
1566
|
+
break;
|
|
1567
|
+
case Infinity:
|
|
1568
|
+
style += ` mw-function-${ns}`;
|
|
1569
|
+
// no default
|
|
1561
1570
|
}
|
|
1562
|
-
return
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
}
|
|
1567
|
-
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
1568
|
-
eatEntity(stream, style) {
|
|
1569
|
-
const entity = stream.match(/^(?:#x[a-f\d]+|#\d+|[a-z\d]+);/iu);
|
|
1570
|
-
return entity && isHtmlEntity(entity[0]) ? tokens.htmlEntity : style;
|
|
1571
|
-
}
|
|
1572
|
-
/**
|
|
1573
|
-
* main entry
|
|
1574
|
-
*
|
|
1575
|
-
* @see https://codemirror.net/docs/ref/#language.StreamParser
|
|
1576
|
-
*
|
|
1577
|
-
* @param tags
|
|
1578
|
-
*/
|
|
1579
|
-
mediawiki(tags) {
|
|
1580
|
-
return {
|
|
1581
|
-
startState: () => startState(this.eatWikiText(''), tags ?? this.tags, tags === undefined),
|
|
1582
|
-
copyState,
|
|
1583
|
-
token(stream, state) {
|
|
1584
|
-
const { data } = state, { readyTokens } = data;
|
|
1585
|
-
let { oldToken } = data;
|
|
1586
|
-
while (oldToken
|
|
1587
|
-
&& (
|
|
1588
|
-
// 如果 PartialParse 的起点位于当前位置之后
|
|
1589
|
-
stream.pos > oldToken.pos
|
|
1590
|
-
|| stream.pos === oldToken.pos && state.tokenize !== oldToken.state.tokenize)) {
|
|
1591
|
-
oldToken = readyTokens.shift();
|
|
1592
|
-
}
|
|
1593
|
-
if (
|
|
1594
|
-
// 检查起点
|
|
1595
|
-
stream.pos === oldToken?.pos
|
|
1596
|
-
&& stream.string === oldToken.string
|
|
1597
|
-
&& cmpNesting(state, oldToken.state)) {
|
|
1598
|
-
const { pos, string, state: { bold, italic, ...other }, style } = readyTokens[0];
|
|
1599
|
-
Object.assign(state, other);
|
|
1600
|
-
if (!(state.extName && state.extMode)
|
|
1601
|
-
&& state.nLink === 0
|
|
1602
|
-
&& typeof style === 'string'
|
|
1603
|
-
&& style.includes(tokens.apostrophes)) {
|
|
1604
|
-
if (data.mark === pos) {
|
|
1605
|
-
// rollback
|
|
1606
|
-
data.mark = null;
|
|
1607
|
-
// add one apostrophe, next token will be italic (two apostrophes)
|
|
1608
|
-
stream.string = string.slice(0, pos - 2);
|
|
1609
|
-
const s = state.tokenize(stream, state);
|
|
1610
|
-
stream.string = string;
|
|
1611
|
-
oldToken.pos++;
|
|
1612
|
-
data.oldToken = oldToken;
|
|
1613
|
-
return makeFullStyle(s, state);
|
|
1614
|
-
}
|
|
1615
|
-
const length = pos - stream.pos;
|
|
1616
|
-
if (length !== 3) {
|
|
1617
|
-
state.italic = !state.italic;
|
|
1618
|
-
}
|
|
1619
|
-
if (length !== 2) {
|
|
1620
|
-
state.bold = !state.bold;
|
|
1621
|
-
}
|
|
1571
|
+
return (stream, state) => {
|
|
1572
|
+
if (stream.eat('|')) {
|
|
1573
|
+
if (module) {
|
|
1574
|
+
state.tokenize = this.inParserFunctionArgument(undefined, module - 1);
|
|
1622
1575
|
}
|
|
1623
|
-
else if (
|
|
1624
|
-
state.
|
|
1625
|
-
state.italic = false;
|
|
1576
|
+
else if (n !== Infinity) {
|
|
1577
|
+
state.tokenize = this.inParserFunctionArgument(undefined, n - 1);
|
|
1626
1578
|
}
|
|
1627
|
-
|
|
1628
|
-
data.oldToken = readyTokens.shift();
|
|
1629
|
-
stream.pos = pos;
|
|
1630
|
-
stream.string = string;
|
|
1631
|
-
return makeFullStyle(style, state);
|
|
1579
|
+
return makeLocalTagStyle('parserFunctionDelimiter', state);
|
|
1632
1580
|
}
|
|
1633
|
-
else if (stream.
|
|
1634
|
-
|
|
1635
|
-
state
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1581
|
+
else if (stream.match('}}')) {
|
|
1582
|
+
pop(state);
|
|
1583
|
+
return makeLocalTagStyle('parserFunctionBracket', state, 'nExt');
|
|
1584
|
+
}
|
|
1585
|
+
return !isSolSyntax(stream)
|
|
1586
|
+
&& stream.match(parserFunctionRegex[module ? 0 : Number(needColon(state)) + 1](chars))
|
|
1587
|
+
? makeLocalStyle(style, state)
|
|
1588
|
+
: this.eatWikiText('parserFunction')(stream, state);
|
|
1589
|
+
};
|
|
1590
|
+
}
|
|
1591
|
+
inTemplateArgument(expectName, parserFunction) {
|
|
1592
|
+
const tag = parserFunction ? 'parserFunction' : 'template';
|
|
1593
|
+
return (stream, state) => {
|
|
1594
|
+
const space = stream.eatSpace();
|
|
1595
|
+
if (stream.eol()) {
|
|
1596
|
+
return makeLocalTagStyle(tag, state);
|
|
1597
|
+
}
|
|
1598
|
+
else if (stream.eat('|')) {
|
|
1599
|
+
if (!expectName) {
|
|
1600
|
+
state.tokenize = this.inTemplateArgument(true, parserFunction);
|
|
1648
1601
|
}
|
|
1602
|
+
return makeLocalTagStyle(parserFunction ? 'parserFunctionDelimiter' : 'templateDelimiter', state);
|
|
1649
1603
|
}
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1604
|
+
else if (stream.match('}}', false)) {
|
|
1605
|
+
if (space) {
|
|
1606
|
+
return makeLocalTagStyle(tag, state);
|
|
1607
|
+
}
|
|
1608
|
+
stream.pos += 2;
|
|
1609
|
+
pop(state);
|
|
1610
|
+
return makeLocalTagStyle(parserFunction ? 'parserFunctionBracket' : 'templateBracket', state, parserFunction ? 'nExt' : 'nTemplate');
|
|
1611
|
+
}
|
|
1612
|
+
else if (stream.sol() && stream.peek() === '=') {
|
|
1613
|
+
const style = this.eatWikiText(tag)(stream, state);
|
|
1614
|
+
if (style.includes(tokens.sectionHeader)) {
|
|
1615
|
+
return style;
|
|
1616
|
+
}
|
|
1617
|
+
stream.pos = 0;
|
|
1618
|
+
}
|
|
1619
|
+
if (expectName
|
|
1620
|
+
&& stream.match(new RegExp(`^(?:[^=|}{[<]|${lookahead('}{[<', state)})*=`, 'iu'))) {
|
|
1621
|
+
state.tokenize = this.inTemplateArgument(false, parserFunction);
|
|
1622
|
+
return makeLocalTagStyle('templateArgumentName', state);
|
|
1623
|
+
}
|
|
1624
|
+
else if (isSolSyntax(stream) && stream.peek() !== '=') {
|
|
1625
|
+
return this.eatWikiText(tag)(stream, state);
|
|
1626
|
+
}
|
|
1627
|
+
return stream.match(needColon(state) ? argumentRegex : styleRegex) || space
|
|
1628
|
+
? makeLocalTagStyle(tag, state)
|
|
1629
|
+
: this.eatWikiText(tag)(stream, state);
|
|
1630
|
+
};
|
|
1631
|
+
}
|
|
1632
|
+
inConvert(style, needFlag, needLang = true, plain) {
|
|
1633
|
+
return (stream, state) => {
|
|
1634
|
+
const space = stream.eatSpace();
|
|
1635
|
+
if (stream.match('}-')) {
|
|
1636
|
+
pop(state);
|
|
1637
|
+
return makeLocalTagStyle('convertBracket', state);
|
|
1638
|
+
}
|
|
1639
|
+
else if (needFlag && stream.match(/^[;\sa-z-]*(?=\|)/iu)) {
|
|
1640
|
+
chain(state, this.inConvert(style, false, true, plain));
|
|
1641
|
+
state.tokenize = this.inStr('|', 'convertDelimiter');
|
|
1642
|
+
return makeLocalTagStyle('convertFlag', state);
|
|
1643
|
+
}
|
|
1644
|
+
else if (stream.match(this.convertSemicolon)) {
|
|
1645
|
+
if (needFlag || !needLang) {
|
|
1646
|
+
state.tokenize = this.inConvert(style, false, true, plain);
|
|
1647
|
+
}
|
|
1648
|
+
return makeLocalTagStyle('convertDelimiter', state);
|
|
1649
|
+
}
|
|
1650
|
+
else if (needLang && stream.match(this.convertLang)) {
|
|
1651
|
+
state.tokenize = this.inConvert(style, false, false, plain);
|
|
1652
|
+
return makeLocalTagStyle('convertLang', state);
|
|
1653
|
+
}
|
|
1654
|
+
else if (plain) {
|
|
1655
|
+
if (stream.match('-{', false)) {
|
|
1656
|
+
return this.eatWikiText(style)(stream, state);
|
|
1657
|
+
}
|
|
1658
|
+
stream.match(/^(?:(?:[^};=-]|\}(?!-)|=(?!>)|-(?!\{))+|;|=>)/u);
|
|
1659
|
+
return makeStyle(style, state);
|
|
1660
|
+
}
|
|
1661
|
+
return !isSolSyntax(stream, true) && stream.match(this.convertRegex) || space
|
|
1662
|
+
? makeStyle(style, state)
|
|
1663
|
+
: this.eatWikiText(style)(stream, state);
|
|
1664
|
+
};
|
|
1665
|
+
}
|
|
1666
|
+
// eslint-disable-next-line @typescript-eslint/class-methods-use-this
|
|
1667
|
+
eatEntity(stream, style) {
|
|
1668
|
+
const entity = stream.match(/^(?:#x[a-f\d]+|#\d+|[a-z\d]+);/iu);
|
|
1669
|
+
return entity && isHtmlEntity(entity[0]) ? tokens.htmlEntity : style;
|
|
1670
|
+
}
|
|
1671
|
+
/**
|
|
1672
|
+
* main entry
|
|
1673
|
+
*
|
|
1674
|
+
* @see https://codemirror.net/docs/ref/#language.StreamParser
|
|
1675
|
+
*
|
|
1676
|
+
* @param tags
|
|
1677
|
+
*/
|
|
1678
|
+
mediawiki(tags) {
|
|
1679
|
+
return {
|
|
1680
|
+
startState: () => startState(this.eatWikiText(''), tags ?? this.tags, tags === undefined),
|
|
1681
|
+
copyState,
|
|
1682
|
+
token(stream, state) {
|
|
1683
|
+
const { data } = state, { readyTokens } = data;
|
|
1684
|
+
let { oldToken } = data;
|
|
1685
|
+
while (oldToken
|
|
1686
|
+
&& (
|
|
1687
|
+
// 如果 PartialParse 的起点位于当前位置之后
|
|
1688
|
+
stream.pos > oldToken.pos
|
|
1689
|
+
|| stream.pos === oldToken.pos && state.tokenize !== oldToken.state.tokenize)) {
|
|
1690
|
+
oldToken = readyTokens.shift();
|
|
1691
|
+
}
|
|
1692
|
+
if (
|
|
1693
|
+
// 检查起点
|
|
1694
|
+
stream.pos === oldToken?.pos
|
|
1695
|
+
&& stream.string === oldToken.string
|
|
1696
|
+
&& cmpNesting(state, oldToken.state)) {
|
|
1697
|
+
const { pos, string, state: { bold, italic, ...other }, style } = readyTokens[0];
|
|
1698
|
+
Object.assign(state, other);
|
|
1699
|
+
if (!(state.extName && state.extMode)
|
|
1700
|
+
&& state.nLink === 0
|
|
1701
|
+
&& typeof style === 'string'
|
|
1702
|
+
&& style.includes(tokens.apostrophes)) {
|
|
1703
|
+
if (data.mark === pos) {
|
|
1704
|
+
// rollback
|
|
1705
|
+
data.mark = null;
|
|
1706
|
+
// add one apostrophe, next token will be italic (two apostrophes)
|
|
1707
|
+
stream.string = string.slice(0, pos - 2);
|
|
1708
|
+
const s = state.tokenize(stream, state);
|
|
1709
|
+
stream.string = string;
|
|
1710
|
+
oldToken.pos++;
|
|
1711
|
+
data.oldToken = oldToken;
|
|
1712
|
+
return makeFullStyle(s, state);
|
|
1713
|
+
}
|
|
1714
|
+
const length = pos - stream.pos;
|
|
1715
|
+
if (length !== 3) {
|
|
1716
|
+
state.italic = !state.italic;
|
|
1670
1717
|
}
|
|
1718
|
+
if (length !== 2) {
|
|
1719
|
+
state.bold = !state.bold;
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
else if (typeof style === 'string' && style.includes(tokens.tableDelimiter)) {
|
|
1723
|
+
state.bold = false;
|
|
1724
|
+
state.italic = false;
|
|
1671
1725
|
}
|
|
1726
|
+
// return first saved token
|
|
1727
|
+
data.oldToken = readyTokens.shift();
|
|
1728
|
+
stream.pos = pos;
|
|
1729
|
+
stream.string = string;
|
|
1730
|
+
return makeFullStyle(style, state);
|
|
1672
1731
|
}
|
|
1673
|
-
else if (
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1732
|
+
else if (stream.sol()) {
|
|
1733
|
+
// reset bold and italic status in every new line
|
|
1734
|
+
state.bold = false;
|
|
1735
|
+
state.italic = false;
|
|
1736
|
+
state.dt.n = 0;
|
|
1737
|
+
state.dt.html = 0;
|
|
1738
|
+
data.firstSingleLetterWord = null;
|
|
1739
|
+
data.firstMultiLetterWord = null;
|
|
1740
|
+
data.firstSpace = null;
|
|
1741
|
+
if (state.tokenize.name === 'inExtTokens') {
|
|
1742
|
+
pop(state); // dispose inExtTokens
|
|
1743
|
+
pop(state); // dispose eatExtTagArea
|
|
1744
|
+
state.extName = false;
|
|
1745
|
+
state.extMode = false;
|
|
1746
|
+
state.extState = false;
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
readyTokens.length = 0;
|
|
1750
|
+
data.mark = null;
|
|
1751
|
+
data.oldToken = { pos: stream.pos, string: stream.string, state: copyState(state), style: '' };
|
|
1752
|
+
const { start } = stream;
|
|
1753
|
+
do {
|
|
1754
|
+
// get token style
|
|
1755
|
+
stream.start = stream.pos;
|
|
1756
|
+
const char = stream.peek(), style = state.tokenize(stream, state);
|
|
1757
|
+
if (typeof style === 'string' && style.includes(tokens.templateArgumentName)) {
|
|
1758
|
+
for (let i = readyTokens.length - 1; i >= 0; i--) {
|
|
1759
|
+
const token = readyTokens[i];
|
|
1760
|
+
if (cmpNesting(state, token.state, true)) {
|
|
1761
|
+
const types = typeof token.style === 'string' && token.style.split(' '), j = types && types.indexOf(tokens.template);
|
|
1762
|
+
if (j !== false && j !== -1) {
|
|
1763
|
+
types[j] = tokens.templateArgumentName;
|
|
1764
|
+
token.style = types.join(' ');
|
|
1765
|
+
}
|
|
1766
|
+
else if (types && types.includes(tokens.templateDelimiter)) {
|
|
1767
|
+
break;
|
|
1768
|
+
}
|
|
1685
1769
|
}
|
|
1686
1770
|
}
|
|
1687
1771
|
}
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1772
|
+
else if (typeof style === 'string' && style.includes(tokens.tableDelimiter2)) {
|
|
1773
|
+
for (let i = readyTokens.length - 1; i >= 0; i--) {
|
|
1774
|
+
const token = readyTokens[i];
|
|
1775
|
+
if (cmpNesting(state, token.state, true)) {
|
|
1776
|
+
const { style: s } = token, local = typeof s === 'string', type = !local
|
|
1777
|
+
&& s[0].split(' ')
|
|
1778
|
+
.find(t => t && !t.endsWith('-ground'));
|
|
1779
|
+
if (type && type.startsWith('mw-table-')) {
|
|
1780
|
+
token.style = `${s[0].replace('mw-table-', 'mw-html-')} ${tokens.tableDefinition}`;
|
|
1781
|
+
}
|
|
1782
|
+
else if (local && s.includes(tokens.tableDelimiter)) {
|
|
1698
1783
|
break;
|
|
1699
1784
|
}
|
|
1700
1785
|
}
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
else if (char === '|' && typeof style === 'string' && style.includes(tokens.convertDelimiter)) {
|
|
1789
|
+
let count = 0;
|
|
1790
|
+
for (let i = readyTokens.length - 1; i >= 0; i--) {
|
|
1791
|
+
const token = readyTokens[i];
|
|
1792
|
+
if (cmpNesting(state, token.state, true)) {
|
|
1793
|
+
const { style: s } = token;
|
|
1794
|
+
if (typeof s === 'string' && s.includes(tokens.convertBracket)) {
|
|
1795
|
+
count += token.char === '-' ? 1 : -1;
|
|
1796
|
+
if (count === 1) {
|
|
1797
|
+
break;
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
else if (typeof s === 'object') {
|
|
1801
|
+
token.style = s[0]
|
|
1802
|
+
+ (s[0].includes(tokens.convertFlag) ? '' : ` ${tokens.convertFlag}`);
|
|
1803
|
+
}
|
|
1704
1804
|
}
|
|
1705
1805
|
}
|
|
1706
1806
|
}
|
|
1807
|
+
// save token
|
|
1808
|
+
readyTokens.push({ pos: stream.pos, char, string: stream.string, state: copyState(state), style });
|
|
1809
|
+
} while ( /** @todo should end at table delimiter as well */!stream.eol());
|
|
1810
|
+
if (!state.bold || !state.italic) {
|
|
1811
|
+
// no need to rollback
|
|
1812
|
+
data.mark = null;
|
|
1707
1813
|
}
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
? undefined
|
|
1733
|
-
: {
|
|
1734
|
-
tokenTable: {
|
|
1735
|
-
...this.tokenTable,
|
|
1736
|
-
...this.hiddenTable,
|
|
1737
|
-
'': Tag.define(),
|
|
1814
|
+
stream.start = start;
|
|
1815
|
+
stream.pos = data.oldToken.pos;
|
|
1816
|
+
stream.string = data.oldToken.string;
|
|
1817
|
+
Object.assign(state, data.oldToken.state);
|
|
1818
|
+
return '';
|
|
1819
|
+
},
|
|
1820
|
+
blankLine(state) {
|
|
1821
|
+
if (state.extName && state.extMode && state.extMode.blankLine) {
|
|
1822
|
+
state.extMode.blankLine(state.extState, 0);
|
|
1823
|
+
}
|
|
1824
|
+
},
|
|
1825
|
+
indent(state, textAfter, context) {
|
|
1826
|
+
return state.extName && state.extMode && state.extMode.indent
|
|
1827
|
+
? state.extMode.indent(state.extState, textAfter, context)
|
|
1828
|
+
: null;
|
|
1829
|
+
},
|
|
1830
|
+
...tags
|
|
1831
|
+
? undefined
|
|
1832
|
+
: {
|
|
1833
|
+
tokenTable: {
|
|
1834
|
+
...this.tokenTable,
|
|
1835
|
+
...this.hiddenTable,
|
|
1836
|
+
'': Tag.define(),
|
|
1837
|
+
},
|
|
1738
1838
|
},
|
|
1839
|
+
};
|
|
1840
|
+
}
|
|
1841
|
+
'text/mediawiki'(tags) {
|
|
1842
|
+
return this.mediawiki(tags);
|
|
1843
|
+
}
|
|
1844
|
+
'text/nowiki'() {
|
|
1845
|
+
return {
|
|
1846
|
+
startState() {
|
|
1847
|
+
return {};
|
|
1739
1848
|
},
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1849
|
+
token: (stream) => {
|
|
1850
|
+
if (stream.eatWhile(/[^&]/u)) {
|
|
1851
|
+
return '';
|
|
1852
|
+
}
|
|
1853
|
+
// eat &
|
|
1854
|
+
stream.next();
|
|
1855
|
+
return this.eatEntity(stream, '');
|
|
1856
|
+
},
|
|
1857
|
+
};
|
|
1858
|
+
}
|
|
1859
|
+
inPre(begin) {
|
|
1860
|
+
return (stream, state) => {
|
|
1861
|
+
if (stream.match(begin ? /^<\/nowiki>/iu : /^<nowiki>/iu)) {
|
|
1862
|
+
state.tokenize = this.inPre(!begin);
|
|
1863
|
+
return tokens.ignored;
|
|
1753
1864
|
}
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1865
|
+
else if (this.hasVariants && stream.match('-{')) {
|
|
1866
|
+
chain(state, this.inConvert('', true, true, true));
|
|
1867
|
+
return tokens.convertBracket;
|
|
1868
|
+
}
|
|
1869
|
+
else if (stream.eat('&')) {
|
|
1870
|
+
return this.eatEntity(stream, '');
|
|
1871
|
+
}
|
|
1872
|
+
stream.match(this.preRegex[begin ? 1 : 0]);
|
|
1873
|
+
return '';
|
|
1874
|
+
};
|
|
1875
|
+
}
|
|
1876
|
+
'text/pre'() {
|
|
1877
|
+
return {
|
|
1878
|
+
startState: () => startState(this.inPre(), []),
|
|
1879
|
+
token: simpleToken,
|
|
1880
|
+
};
|
|
1881
|
+
}
|
|
1882
|
+
inNested(tag) {
|
|
1883
|
+
const re = tag === 'ref' ? /^(?:\{|(?:[^<{]|\{(?!\{)|<(?!!--|ref(?:[\s/>]|$)))+)/iu : getNestedRegex(tag);
|
|
1884
|
+
return (stream, state) => {
|
|
1885
|
+
if (tag === 'ref') {
|
|
1886
|
+
if (stream.match('<!--')) {
|
|
1887
|
+
chain(state, this.inComment);
|
|
1888
|
+
return makeLocalTagStyle('comment', state);
|
|
1889
|
+
}
|
|
1890
|
+
else if (stream.match(/^\{{3}(?!\{|[^{}]*\}\}(?!\}))\s*/u)) {
|
|
1891
|
+
chain(state, this.inVariable());
|
|
1892
|
+
return tokens.templateVariableBracket;
|
|
1893
|
+
}
|
|
1894
|
+
const mt = stream.match(/^\{\{(?!\{(?!\{))/u);
|
|
1895
|
+
if (mt) {
|
|
1896
|
+
return this.eatTransclusion(stream, state) ?? tokens.ignored;
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
if (stream.match(re)) {
|
|
1900
|
+
return tokens.ignored;
|
|
1901
|
+
}
|
|
1902
|
+
stream.eat('<');
|
|
1903
|
+
chain(state, this.eatTagName(tag));
|
|
1904
|
+
return tokens.extTagBracket;
|
|
1905
|
+
};
|
|
1906
|
+
}
|
|
1907
|
+
'text/references'(tags) {
|
|
1908
|
+
return {
|
|
1909
|
+
startState: () => startState(this.inNested('ref'), tags),
|
|
1910
|
+
token: simpleToken,
|
|
1911
|
+
};
|
|
1912
|
+
}
|
|
1913
|
+
'text/choose'(tags) {
|
|
1914
|
+
return {
|
|
1915
|
+
startState: () => startState(this.inNested('option'), tags),
|
|
1916
|
+
token: simpleToken,
|
|
1917
|
+
};
|
|
1918
|
+
}
|
|
1919
|
+
'text/combobox'(tags) {
|
|
1920
|
+
return {
|
|
1921
|
+
startState: () => startState(this.inNested('combooption'), tags),
|
|
1922
|
+
token: simpleToken,
|
|
1923
|
+
};
|
|
1924
|
+
}
|
|
1925
|
+
get inInputbox() {
|
|
1926
|
+
return (stream, state) => {
|
|
1789
1927
|
if (stream.match('<!--')) {
|
|
1790
1928
|
chain(state, this.inComment);
|
|
1791
|
-
return
|
|
1929
|
+
return tokens.comment;
|
|
1792
1930
|
}
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1931
|
+
/** @todo braces should also be parsed */
|
|
1932
|
+
stream.match(/^(?:[^<]|<(?!!--))+/u);
|
|
1933
|
+
return '';
|
|
1934
|
+
};
|
|
1935
|
+
}
|
|
1936
|
+
'text/inputbox'() {
|
|
1937
|
+
return {
|
|
1938
|
+
startState: () => startState(this.inInputbox, []),
|
|
1939
|
+
token: simpleToken,
|
|
1940
|
+
};
|
|
1941
|
+
}
|
|
1942
|
+
inGallery(section) {
|
|
1943
|
+
const style = section ? tokens.error : `${tokens.linkPageName} ${tokens.pageName}`, regex = section ? /^(?:[[}\]]|\{(?!\{))+/u : /^(?:[>[}\]]|\{(?!\{)|<(?!!--))+/u, re = section ? /^(?:[^|<[\]{}]|<(?!!--))+/u : /^(?:&#(?:\d+|x[a-f\d]+);|[^#|<>[\]{}])+/u;
|
|
1944
|
+
return (stream, state) => {
|
|
1945
|
+
const space = stream.eatSpace();
|
|
1946
|
+
if (!section && stream.match(/^#\s*/u)) {
|
|
1947
|
+
state.tokenize = this.inGallery(true);
|
|
1948
|
+
return makeTagStyle('error', state);
|
|
1796
1949
|
}
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1950
|
+
else if (stream.match(/^\|\s*/u)) {
|
|
1951
|
+
state.tokenize = this.inLinkText(true, true);
|
|
1952
|
+
this.toEatImageParameter(stream, state);
|
|
1953
|
+
return makeLocalTagStyle('fileDelimiter', state);
|
|
1800
1954
|
}
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
return tokens.comment;
|
|
1804
|
-
}
|
|
1805
|
-
stream.eat('<');
|
|
1806
|
-
chain(state, this.eatTagName(tag));
|
|
1807
|
-
return tokens.extTagBracket;
|
|
1808
|
-
};
|
|
1809
|
-
}
|
|
1810
|
-
'text/references'(tags) {
|
|
1811
|
-
return {
|
|
1812
|
-
startState: () => startState(this.inNested('ref'), tags),
|
|
1813
|
-
token: simpleToken,
|
|
1814
|
-
};
|
|
1815
|
-
}
|
|
1816
|
-
'text/choose'(tags) {
|
|
1817
|
-
return {
|
|
1818
|
-
startState: () => startState(this.inNested('option'), tags),
|
|
1819
|
-
token: simpleToken,
|
|
1820
|
-
};
|
|
1821
|
-
}
|
|
1822
|
-
'text/combobox'(tags) {
|
|
1823
|
-
return {
|
|
1824
|
-
startState: () => startState(this.inNested('combooption'), tags),
|
|
1825
|
-
token: simpleToken,
|
|
1826
|
-
};
|
|
1827
|
-
}
|
|
1828
|
-
@getTokenizer
|
|
1829
|
-
get inInputbox() {
|
|
1830
|
-
return (stream, state) => {
|
|
1831
|
-
if (stream.match('<!--')) {
|
|
1832
|
-
chain(state, this.inComment);
|
|
1833
|
-
return tokens.comment;
|
|
1834
|
-
}
|
|
1835
|
-
/** @todo braces should also be parsed */
|
|
1836
|
-
stream.match(/^(?:[^<]|<(?!!--))+/u);
|
|
1837
|
-
return '';
|
|
1838
|
-
};
|
|
1839
|
-
}
|
|
1840
|
-
'text/inputbox'() {
|
|
1841
|
-
return {
|
|
1842
|
-
startState: () => startState(this.inInputbox, []),
|
|
1843
|
-
token: simpleToken,
|
|
1844
|
-
};
|
|
1845
|
-
}
|
|
1846
|
-
@getTokenizer
|
|
1847
|
-
inGallery(section) {
|
|
1848
|
-
const style = section ? tokens.error : `${tokens.linkPageName} ${tokens.pageName}`, regex = section ? /^(?:[[}\]]|\{(?!\{))+/u : /^(?:[>[}\]]|\{(?!\{)|<(?!!--))+/u, re = section ? /^(?:[^|<[\]{}]|<(?!!--))+/u : /^(?:&#(?:\d+|x[a-f\d]+);|[^#|<>[\]{}])+/u;
|
|
1849
|
-
return (stream, state) => {
|
|
1850
|
-
const space = stream.eatSpace();
|
|
1851
|
-
if (!section && stream.match(/^#\s*/u)) {
|
|
1852
|
-
state.tokenize = this.inGallery(true);
|
|
1853
|
-
return makeTagStyle('error', state);
|
|
1854
|
-
}
|
|
1855
|
-
else if (stream.match(/^\|\s*/u)) {
|
|
1856
|
-
state.tokenize = this.inLinkText(true, true);
|
|
1857
|
-
this.toEatImageParameter(stream, state);
|
|
1858
|
-
return makeLocalTagStyle('fileDelimiter', state);
|
|
1859
|
-
}
|
|
1860
|
-
else if (stream.match(regex)) {
|
|
1861
|
-
return makeTagStyle('error', state);
|
|
1862
|
-
}
|
|
1863
|
-
return stream.match(re) || space
|
|
1864
|
-
? makeStyle(style, state)
|
|
1865
|
-
: this.eatWikiText(section ? style : 'error')(stream, state);
|
|
1866
|
-
};
|
|
1867
|
-
}
|
|
1868
|
-
'text/gallery'(tags) {
|
|
1869
|
-
return {
|
|
1870
|
-
startState: () => startState(this.inGallery(), tags),
|
|
1871
|
-
token: (stream, state) => {
|
|
1872
|
-
if (stream.sol()) {
|
|
1873
|
-
Object.assign(state, startState(this.inGallery(), state.data.tags));
|
|
1955
|
+
else if (stream.match(regex)) {
|
|
1956
|
+
return makeTagStyle('error', state);
|
|
1874
1957
|
}
|
|
1875
|
-
return
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
}
|
|
1958
|
+
return stream.match(re) || space
|
|
1959
|
+
? makeStyle(style, state)
|
|
1960
|
+
: this.eatWikiText(section ? style : 'error')(stream, state);
|
|
1961
|
+
};
|
|
1962
|
+
}
|
|
1963
|
+
'text/gallery'(tags) {
|
|
1964
|
+
return {
|
|
1965
|
+
startState: () => startState(this.inGallery(), tags),
|
|
1966
|
+
token: (stream, state) => {
|
|
1967
|
+
if (stream.sol()) {
|
|
1968
|
+
Object.assign(state, startState(this.inGallery(), state.data.tags));
|
|
1969
|
+
}
|
|
1970
|
+
return simpleToken(stream, state);
|
|
1971
|
+
},
|
|
1972
|
+
};
|
|
1973
|
+
}
|
|
1974
|
+
javascript() {
|
|
1975
|
+
return javascript;
|
|
1976
|
+
}
|
|
1977
|
+
css() {
|
|
1978
|
+
return css;
|
|
1979
|
+
}
|
|
1980
|
+
json() {
|
|
1981
|
+
return json;
|
|
1982
|
+
}
|
|
1983
|
+
};
|
|
1984
|
+
})();
|
|
1985
|
+
export { MediaWiki };
|