wikiparser-node 1.18.0 → 1.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/config.js +3 -1
- package/bundle/bundle-es7.min.js +22 -22
- package/bundle/bundle-lsp.min.js +26 -26
- package/bundle/bundle.min.js +22 -22
- package/config/.schema.json +1 -1
- package/data/signatures.json +141 -353
- package/dist/base.d.mts +9 -1
- package/dist/base.d.ts +9 -1
- package/dist/bin/config.js +62 -56
- package/dist/index.js +4 -4
- package/dist/lib/lsp.d.ts +20 -3
- package/dist/lib/lsp.js +211 -69
- package/dist/src/attribute.js +10 -4
- package/dist/src/index.js +2 -2
- package/dist/src/nowiki/doubleUnderscore.js +3 -2
- package/dist/util/diff.js +1 -1
- package/dist/util/lint.js +31 -1
- package/extensions/dist/base.js +1 -1
- package/extensions/es7/base.js +1 -1
- package/i18n/zh-hans.json +1 -0
- package/i18n/zh-hant.json +1 -0
- package/package.json +6 -2
package/dist/lib/lsp.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.LanguageService = exports.tasks = void 0;
|
|
6
|
+
exports.LanguageService = exports.isAttr = exports.tasks = void 0;
|
|
7
7
|
const common_1 = require("@bhsd/common");
|
|
8
8
|
const sharable_1 = require("../util/sharable");
|
|
9
9
|
const lint_1 = require("../util/lint");
|
|
@@ -19,6 +19,7 @@ const util_1 = __importDefault(require("util"));
|
|
|
19
19
|
const child_process_1 = require("child_process");
|
|
20
20
|
const crypto_1 = require("crypto");
|
|
21
21
|
const stylelint_1 = require("@bhsd/common/dist/stylelint");
|
|
22
|
+
const config_1 = __importDefault(require("../bin/config"));
|
|
22
23
|
const document_1 = require("./document");
|
|
23
24
|
/** @see https://www.npmjs.com/package/stylelint-config-recommended */
|
|
24
25
|
const cssRules = {
|
|
@@ -42,11 +43,30 @@ const refTags = new Set(['ref']), referencesTags = new Set(['ref', 'references']
|
|
|
42
43
|
'heading',
|
|
43
44
|
...renameTypes,
|
|
44
45
|
]), plainTypes = new Set(['text', 'comment', 'noinclude', 'include']), cssSelector = ['ext', 'html', 'table'].map(s => `${s}-attr#style`).join();
|
|
46
|
+
/**
|
|
47
|
+
* Check if a token is a plain attribute.
|
|
48
|
+
* @param token
|
|
49
|
+
* @param token.type
|
|
50
|
+
* @param token.parentNode
|
|
51
|
+
* @param token.length
|
|
52
|
+
* @param token.firstChild
|
|
53
|
+
* @param style whether it is a style attribute
|
|
54
|
+
*/
|
|
55
|
+
const isAttr = ({ type, parentNode, length, firstChild }, style) => type === 'attr-value' && length === 1 && firstChild.type === 'text'
|
|
56
|
+
&& (!style
|
|
57
|
+
|| parentNode.name === 'style'
|
|
58
|
+
&& Boolean(document_1.cssLSP));
|
|
59
|
+
exports.isAttr = isAttr;
|
|
60
|
+
/**
|
|
61
|
+
* Check if a token is an HTML attribute.
|
|
62
|
+
* @param token
|
|
63
|
+
*/
|
|
64
|
+
const isHtmlAttr = (token) => token.type === 'html-attr' || token.type === 'table-attr';
|
|
45
65
|
/**
|
|
46
66
|
* Check if all child nodes are plain text or comments.
|
|
47
|
-
* @param
|
|
67
|
+
* @param token
|
|
48
68
|
*/
|
|
49
|
-
const isPlain = (
|
|
69
|
+
const isPlain = (token) => token.childNodes.every(({ type }) => plainTypes.has(type));
|
|
50
70
|
/**
|
|
51
71
|
* Get the position of a character in the document.
|
|
52
72
|
* @param root root token
|
|
@@ -216,11 +236,12 @@ const getStylelintPos = (rect, bottom, line, column) => {
|
|
|
216
236
|
};
|
|
217
237
|
/**
|
|
218
238
|
* Convert LilyPond errors to VSCode diagnostics.
|
|
239
|
+
* @param root root token
|
|
219
240
|
* @param token `<score>` extension token
|
|
220
241
|
* @param errors LilyPond errors
|
|
221
242
|
*/
|
|
222
|
-
const getLilyPondDiagnostics = (token, errors) => {
|
|
223
|
-
const { top, left } = token.lastChild.
|
|
243
|
+
const getLilyPondDiagnostics = (root, token, errors) => {
|
|
244
|
+
const { top, left } = root.posFromIndex(token.lastChild.getAbsoluteIndex());
|
|
224
245
|
return errors.map(({ line, col, message }) => {
|
|
225
246
|
const pos = (0, lint_1.getEndPos)(top, left, line, col);
|
|
226
247
|
return {
|
|
@@ -257,16 +278,20 @@ class LanguageService {
|
|
|
257
278
|
#completionConfig;
|
|
258
279
|
include = true;
|
|
259
280
|
/** @private */
|
|
281
|
+
config;
|
|
282
|
+
/** @private */
|
|
260
283
|
data;
|
|
261
284
|
/* NOT FOR BROWSER ONLY */
|
|
262
285
|
lilypond;
|
|
286
|
+
/** @private */
|
|
263
287
|
lilypondData;
|
|
264
288
|
/* NOT FOR BROWSER ONLY END */
|
|
265
289
|
/** @param uri 任务标识 */
|
|
266
290
|
constructor(uri) {
|
|
267
291
|
exports.tasks.set(uri, this);
|
|
268
|
-
/* NOT FOR BROWSER ONLY */
|
|
269
292
|
Object.defineProperties(this, {
|
|
293
|
+
config: { enumerable: false },
|
|
294
|
+
/* NOT FOR BROWSER ONLY */
|
|
270
295
|
data: {
|
|
271
296
|
value: require(path_1.default.join('..', '..', 'data', 'signatures')),
|
|
272
297
|
enumerable: false,
|
|
@@ -284,16 +309,18 @@ class LanguageService {
|
|
|
284
309
|
const dir = path_1.default.join(__dirname, 'lilypond');
|
|
285
310
|
if (fs_1.default.existsSync(dir)) {
|
|
286
311
|
for (const file of fs_1.default.readdirSync(dir)) {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
312
|
+
(async () => {
|
|
313
|
+
try {
|
|
314
|
+
await fs_1.default.promises.unlink(path_1.default.join(dir, file));
|
|
315
|
+
}
|
|
316
|
+
catch { }
|
|
317
|
+
})();
|
|
291
318
|
}
|
|
292
319
|
}
|
|
293
320
|
}
|
|
294
321
|
/** 检查解析设置有无更新 */
|
|
295
322
|
#checkConfig() {
|
|
296
|
-
return this.#config ===
|
|
323
|
+
return this.#config === this.config && this.#include === this.include;
|
|
297
324
|
}
|
|
298
325
|
/**
|
|
299
326
|
* 提交解析任务
|
|
@@ -319,10 +346,10 @@ class LanguageService {
|
|
|
319
346
|
* - 总是返回最新的解析结果
|
|
320
347
|
*/
|
|
321
348
|
async #parse() {
|
|
322
|
-
|
|
323
|
-
this.#config =
|
|
349
|
+
this.config ??= index_1.default.getConfig();
|
|
350
|
+
this.#config = this.config;
|
|
324
351
|
this.#include = this.include;
|
|
325
|
-
const text = this.#text, root = await index_1.default.partialParse(text, () => this.#text, this.include, config);
|
|
352
|
+
const text = this.#text, root = await index_1.default.partialParse(text, () => this.#text, this.include, this.config);
|
|
326
353
|
if (this.#checkConfig() && this.#text === text) {
|
|
327
354
|
this.#done = root;
|
|
328
355
|
this.#running = undefined;
|
|
@@ -357,10 +384,10 @@ class LanguageService {
|
|
|
357
384
|
* - 总是返回最新的解析结果
|
|
358
385
|
*/
|
|
359
386
|
async #parseSignature() {
|
|
360
|
-
|
|
361
|
-
this.#config =
|
|
387
|
+
this.config ??= index_1.default.getConfig();
|
|
388
|
+
this.#config = this.config;
|
|
362
389
|
this.#include = this.include;
|
|
363
|
-
const text = this.#text2, root = await index_1.default.partialParse(text, () => this.#text2, this.include, config);
|
|
390
|
+
const text = this.#text2, root = await index_1.default.partialParse(text, () => this.#text2, this.include, this.config);
|
|
364
391
|
if (this.#checkConfig() && this.#text2 === text) {
|
|
365
392
|
this.#done2 = root;
|
|
366
393
|
this.#running2 = undefined;
|
|
@@ -381,14 +408,38 @@ class LanguageService {
|
|
|
381
408
|
*/
|
|
382
409
|
async provideDocumentColors(rgba, text, hsl = true) {
|
|
383
410
|
const root = await this.#queue(text);
|
|
411
|
+
/* NOT FOR BROWSER ONLY */
|
|
412
|
+
let colors;
|
|
413
|
+
try {
|
|
414
|
+
colors = new RegExp(String.raw `\b${Object.keys((await import('color-name')).default).join('|')}\b`, 'giu');
|
|
415
|
+
}
|
|
416
|
+
catch { }
|
|
417
|
+
/* NOT FOR BROWSER ONLY END */
|
|
384
418
|
return root.querySelectorAll('attr-value,parameter-value,arg-default').reverse()
|
|
385
|
-
.flatMap(
|
|
386
|
-
|
|
419
|
+
.flatMap(token => {
|
|
420
|
+
const { type, childNodes,
|
|
421
|
+
/* NOT FOR BROWSER ONLY */
|
|
422
|
+
parentNode, } = token;
|
|
423
|
+
if (type !== 'attr-value' && !isPlain(token)) {
|
|
387
424
|
return [];
|
|
425
|
+
/* NOT FOR BROWSER ONLY */
|
|
426
|
+
}
|
|
427
|
+
else if ((0, exports.isAttr)(token, true)) {
|
|
428
|
+
const textDoc = new document_1.EmbeddedCSSDocument(root, token);
|
|
429
|
+
return document_1.cssLSP.findDocumentColors(textDoc, textDoc.styleSheet);
|
|
430
|
+
/* NOT FOR BROWSER ONLY END */
|
|
388
431
|
}
|
|
432
|
+
/* NOT FOR BROWSER ONLY */
|
|
433
|
+
const isStyle = colors && type === 'attr-value' && parentNode.name === 'style';
|
|
434
|
+
/* NOT FOR BROWSER ONLY END */
|
|
389
435
|
return childNodes.filter((child) => child.type === 'text').reverse()
|
|
390
436
|
.flatMap(child => {
|
|
391
|
-
const parts = (0, common_1.splitColors)(
|
|
437
|
+
const { data } = child, parts = (0, common_1.splitColors)(data, hsl).filter(([, , , isColor]) => isColor);
|
|
438
|
+
/* NOT FOR BROWSER ONLY */
|
|
439
|
+
if (isStyle) {
|
|
440
|
+
parts.push(...[...data.matchAll(colors)].map(({ index, 0: s }) => [s, index, index + s.length, true]));
|
|
441
|
+
}
|
|
442
|
+
/* NOT FOR BROWSER ONLY END */
|
|
392
443
|
if (parts.length === 0) {
|
|
393
444
|
return [];
|
|
394
445
|
}
|
|
@@ -426,8 +477,9 @@ class LanguageService {
|
|
|
426
477
|
}
|
|
427
478
|
/** 准备自动补全设置 */
|
|
428
479
|
#prepareCompletionConfig() {
|
|
429
|
-
if (!this.#completionConfig) {
|
|
430
|
-
|
|
480
|
+
if (!this.#completionConfig || this.#completionConfig[1] !== this.config) {
|
|
481
|
+
this.config ??= index_1.default.getConfig();
|
|
482
|
+
const { nsid, ext, html, parserFunction: [insensitive, sensitive, ...other], doubleUnderscore, protocol, img, } = this.config, tags = new Set([ext, html].flat(2));
|
|
431
483
|
// eslint-disable-next-line @typescript-eslint/no-unused-expressions, es-x/no-regexp-unicode-property-escapes
|
|
432
484
|
/(?:<\/?(\w*)|(\{{2,4}|\[\[)\s*([^|{}<>[\]\s][^|{}<>[\]#]*)?|(__(?:(?!__)[\p{L}\d_])*)|(?<!\[)\[([a-z:/]*)|\[\[\s*(?:file|image)\s*:[^[\]{}<>]+\|([^[\]{}<>|=]*)|<(\w+)(?:\s(?:[^<>{}|=\s]+(?:\s*=\s*(?:[^\s"']\S*|(["']).*?\8))?(?=\s))*)?\s(\w*))$/iu;
|
|
433
485
|
const re = new RegExp('(?:' // eslint-disable-line prefer-template
|
|
@@ -444,23 +496,27 @@ class LanguageService {
|
|
|
444
496
|
// attribute key
|
|
445
497
|
+ String.raw `<(\w+)(?:\s(?:[^<>{}|=\s]+(?:\s*=\s*(?:[^\s"']\S*|(["']).*?\8))?(?=\s))*)?\s(\w*)`
|
|
446
498
|
+ ')$', 'iu');
|
|
447
|
-
this.#completionConfig =
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
499
|
+
this.#completionConfig = [
|
|
500
|
+
{
|
|
501
|
+
re,
|
|
502
|
+
ext,
|
|
503
|
+
tags,
|
|
504
|
+
allTags: [...tags, 'onlyinclude', 'includeonly', 'noinclude'],
|
|
505
|
+
functions: [
|
|
506
|
+
Object.keys(insensitive),
|
|
507
|
+
Array.isArray(sensitive) ? /* istanbul ignore next */ sensitive : Object.keys(sensitive),
|
|
508
|
+
other,
|
|
509
|
+
].flat(2),
|
|
510
|
+
switches: doubleUnderscore.slice(0, 2).flat().map(w => `__${w}__`),
|
|
511
|
+
protocols: protocol.split('|'),
|
|
512
|
+
params: Object.keys(img)
|
|
513
|
+
.filter(k => k.endsWith('$1') || !k.includes('$1'))
|
|
514
|
+
.map(k => k.replace(/\$1$/u, '')),
|
|
515
|
+
},
|
|
516
|
+
this.config,
|
|
517
|
+
];
|
|
462
518
|
}
|
|
463
|
-
return this.#completionConfig;
|
|
519
|
+
return this.#completionConfig[0];
|
|
464
520
|
}
|
|
465
521
|
/**
|
|
466
522
|
* Provide auto-completion
|
|
@@ -470,13 +526,25 @@ class LanguageService {
|
|
|
470
526
|
* @param position 位置
|
|
471
527
|
*/
|
|
472
528
|
async provideCompletionItems(text, position) {
|
|
473
|
-
const { re, allTags, functions, switches, protocols, params, tags, ext } = this.#prepareCompletionConfig(), { line, character } = position, curLine = text.split(/\r?\n/u, line + 1)[line], mt = re.exec(curLine?.slice(0, character) ?? '');
|
|
529
|
+
const { re, allTags, functions, switches, protocols, params, tags, ext } = this.#prepareCompletionConfig(), { line, character } = position, curLine = text.split(/\r?\n/u, line + 1)[line], mt = re.exec(curLine?.slice(0, character) ?? ''), [, , iAlias = {}, sAlias = {}] = this.config.doubleUnderscore;
|
|
474
530
|
if (mt?.[1] !== undefined) { // tag
|
|
475
531
|
const closing = mt[1].startsWith('/');
|
|
476
532
|
return getCompletion(allTags, 'Class', mt[1].slice(closing ? 1 : 0), position, closing && !curLine?.slice(character).trim().startsWith('>') ? '>' : '');
|
|
477
533
|
}
|
|
478
534
|
else if (mt?.[4]) { // behavior switch
|
|
479
|
-
return getCompletion(switches, 'Constant', mt[4], position, '', name =>
|
|
535
|
+
return getCompletion(switches, 'Constant', mt[4], position, '', name => {
|
|
536
|
+
if (!this.data) {
|
|
537
|
+
return undefined;
|
|
538
|
+
}
|
|
539
|
+
name = name.slice(2, -2);
|
|
540
|
+
if (name in iAlias) {
|
|
541
|
+
name = iAlias[name];
|
|
542
|
+
}
|
|
543
|
+
else if (name in sAlias) {
|
|
544
|
+
name = sAlias[name];
|
|
545
|
+
}
|
|
546
|
+
return this.#getBehaviorSwitch(name.toLowerCase());
|
|
547
|
+
});
|
|
480
548
|
}
|
|
481
549
|
else if (mt?.[5] !== undefined) { // protocol
|
|
482
550
|
return getCompletion(protocols, 'Reference', mt[5], position);
|
|
@@ -490,12 +558,23 @@ class LanguageService {
|
|
|
490
558
|
return getCompletion(root.querySelectorAll('arg').filter(token => token.name && token !== cur)
|
|
491
559
|
.map(({ name }) => name), 'Variable', match, position);
|
|
492
560
|
}
|
|
493
|
-
const colon = match.startsWith(':'), str = colon ? match.slice(1).trimStart() : match;
|
|
561
|
+
const [insensitive, sensitive] = this.config.parserFunction, isOld = Array.isArray(sensitive), colon = match.startsWith(':'), str = colon ? match.slice(1).trimStart() : match;
|
|
494
562
|
return mt[2] === '[['
|
|
495
563
|
? getCompletion(// link
|
|
496
564
|
root.querySelectorAll('link,file,category,redirect-target').filter(token => token !== cur).map(({ name }) => name), 'Folder', str, position)
|
|
497
565
|
: [
|
|
498
|
-
...getCompletion(functions, 'Function', match, position, '', name =>
|
|
566
|
+
...getCompletion(functions, 'Function', match, position, '', name => {
|
|
567
|
+
if (!this.data) {
|
|
568
|
+
return undefined;
|
|
569
|
+
}
|
|
570
|
+
else if (name in insensitive) {
|
|
571
|
+
name = insensitive[name];
|
|
572
|
+
}
|
|
573
|
+
else if (!isOld && name in sensitive) {
|
|
574
|
+
name = sensitive[name];
|
|
575
|
+
}
|
|
576
|
+
return this.#getParserFunction(name.toLowerCase());
|
|
577
|
+
}),
|
|
499
578
|
...match.startsWith('#')
|
|
500
579
|
? []
|
|
501
580
|
: getCompletion(root.querySelectorAll('template').filter(token => token !== cur)
|
|
@@ -555,7 +634,7 @@ class LanguageService {
|
|
|
555
634
|
if (t === 'magic-word' && n !== 'invoke') {
|
|
556
635
|
return undefined;
|
|
557
636
|
}
|
|
558
|
-
const
|
|
637
|
+
const key = this.#text.slice(cur.getAbsoluteIndex(), root.indexFromPos(line, character)).trimStart(), [module, func] = t === 'magic-word' ? transclusion.getModule() : [];
|
|
559
638
|
return key
|
|
560
639
|
? getCompletion(root.querySelectorAll('parameter').filter(token => {
|
|
561
640
|
if (token === parentNode
|
|
@@ -573,7 +652,7 @@ class LanguageService {
|
|
|
573
652
|
: undefined;
|
|
574
653
|
/* NOT FOR BROWSER ONLY */
|
|
575
654
|
}
|
|
576
|
-
else if (
|
|
655
|
+
else if ((0, exports.isAttr)(cur, true)) {
|
|
577
656
|
const textDoc = new document_1.EmbeddedCSSDocument(root, cur);
|
|
578
657
|
return document_1.cssLSP.doComplete(textDoc, position, textDoc.styleSheet).items.map((item) => ({
|
|
579
658
|
...item,
|
|
@@ -592,7 +671,7 @@ class LanguageService {
|
|
|
592
671
|
if (lang !== undefined && lang !== 'lilypond') {
|
|
593
672
|
return undefined;
|
|
594
673
|
}
|
|
595
|
-
const
|
|
674
|
+
const before = this.#text.slice(cur.getAbsoluteIndex(), root.indexFromPos(line, character)), comment = before.lastIndexOf('%');
|
|
596
675
|
if (comment !== -1
|
|
597
676
|
&& (before.charAt(comment + 1) === '{' || !before.slice(comment).includes('\n'))) {
|
|
598
677
|
return undefined;
|
|
@@ -609,6 +688,14 @@ class LanguageService {
|
|
|
609
688
|
}
|
|
610
689
|
/* NOT FOR BROWSER ONLY END */
|
|
611
690
|
}
|
|
691
|
+
else if ((0, exports.isAttr)(cur) && isHtmlAttr(parentNode)) {
|
|
692
|
+
const data = lint_1.htmlData.provideValues(parentNode.tag, parentNode.name);
|
|
693
|
+
if (data.length === 0) {
|
|
694
|
+
return undefined;
|
|
695
|
+
}
|
|
696
|
+
const val = this.#text.slice(cur.getAbsoluteIndex(), root.indexFromPos(line, character)).trimStart();
|
|
697
|
+
return getCompletion(data.map(({ name }) => name), 'Value', val, position);
|
|
698
|
+
}
|
|
612
699
|
return undefined;
|
|
613
700
|
}
|
|
614
701
|
/**
|
|
@@ -700,7 +787,7 @@ class LanguageService {
|
|
|
700
787
|
lilypondDiagnostics = await Promise.all(tokens.map(async (token) => {
|
|
701
788
|
const { innerText } = token, score = `showLastLength = R1${token.getAttr('raw') === undefined ? ` \\score {\n${innerText}\n}` : `\n${innerText}`}`;
|
|
702
789
|
if (scores.has(score)) {
|
|
703
|
-
return getLilyPondDiagnostics(token, scores.get(score));
|
|
790
|
+
return getLilyPondDiagnostics(root, token, scores.get(score));
|
|
704
791
|
}
|
|
705
792
|
const hash = (0, crypto_1.createHash)('sha256');
|
|
706
793
|
hash.update(score);
|
|
@@ -722,7 +809,7 @@ class LanguageService {
|
|
|
722
809
|
};
|
|
723
810
|
});
|
|
724
811
|
scores.set(score, lilypondErrors);
|
|
725
|
-
return getLilyPondDiagnostics(token, lilypondErrors);
|
|
812
|
+
return getLilyPondDiagnostics(root, token, lilypondErrors);
|
|
726
813
|
}
|
|
727
814
|
}
|
|
728
815
|
return [];
|
|
@@ -802,8 +889,9 @@ class LanguageService {
|
|
|
802
889
|
* @param text source Wikitext / 源代码
|
|
803
890
|
*/
|
|
804
891
|
async provideLinks(text) {
|
|
892
|
+
this.config ??= index_1.default.getConfig();
|
|
805
893
|
/^(?:http:\/\/|\/\/)/iu; // eslint-disable-line @typescript-eslint/no-unused-expressions
|
|
806
|
-
const { articlePath, protocol } =
|
|
894
|
+
const { articlePath, protocol } = this.config, absolute = articlePath?.includes('//'), protocolRegex = new RegExp(`^(?:${protocol}|//)`, 'iu');
|
|
807
895
|
return (await this.#queue(text))
|
|
808
896
|
.querySelectorAll(`magic-link,ext-link-url,free-ext-link,attr-value,image-parameter#link${absolute ? ',link-target,template-name,invoke-module' : ''}`)
|
|
809
897
|
.reverse()
|
|
@@ -812,7 +900,7 @@ class LanguageService {
|
|
|
812
900
|
if (!(type !== 'attr-value'
|
|
813
901
|
|| name === 'src' && ['templatestyles', 'img'].includes(tag)
|
|
814
902
|
|| name === 'cite' && ['blockquote', 'del', 'ins', 'q'].includes(tag))
|
|
815
|
-
|| !isPlain(
|
|
903
|
+
|| !isPlain(token)) {
|
|
816
904
|
return false;
|
|
817
905
|
}
|
|
818
906
|
let target = childNodes.filter((node) => node.type === 'text')
|
|
@@ -852,8 +940,7 @@ class LanguageService {
|
|
|
852
940
|
else if (type === 'invoke-module') {
|
|
853
941
|
ns = 828;
|
|
854
942
|
}
|
|
855
|
-
const title = index_1.default
|
|
856
|
-
.normalizeTitle(target, ns, false, undefined, true);
|
|
943
|
+
const title = index_1.default.normalizeTitle(target, ns, false, this.config, true);
|
|
857
944
|
/* istanbul ignore if */
|
|
858
945
|
if (!title.valid) {
|
|
859
946
|
return false;
|
|
@@ -997,40 +1084,74 @@ class LanguageService {
|
|
|
997
1084
|
if (!this.data) {
|
|
998
1085
|
return undefined;
|
|
999
1086
|
}
|
|
1000
|
-
const root = await this.#queue(text)
|
|
1087
|
+
const root = await this.#queue(text);
|
|
1088
|
+
let { offsetNode, offset } = caretPositionFromWord(root, this.#text, position);
|
|
1089
|
+
if (offsetNode.type === 'text') {
|
|
1090
|
+
offset += offsetNode.getRelativeIndex();
|
|
1091
|
+
offsetNode = offsetNode.parentNode;
|
|
1092
|
+
}
|
|
1093
|
+
const { type, parentNode, length, name } = offsetNode;
|
|
1001
1094
|
let info, f, range;
|
|
1002
|
-
if (
|
|
1003
|
-
info = this.#getBehaviorSwitch(
|
|
1095
|
+
if (offsetNode.is('double-underscore') && offset > 0) {
|
|
1096
|
+
info = this.#getBehaviorSwitch(offsetNode.name);
|
|
1004
1097
|
}
|
|
1005
1098
|
else if (type === 'magic-word-name') {
|
|
1006
1099
|
info = this.#getParserFunction(parentNode.name);
|
|
1007
|
-
f =
|
|
1100
|
+
f = offsetNode.toString(true).trim();
|
|
1008
1101
|
}
|
|
1009
|
-
else if (
|
|
1010
|
-
&& (offset > 0 || root.posFromIndex(
|
|
1102
|
+
else if (offsetNode.is('magic-word') && !offsetNode.modifier && length === 1
|
|
1103
|
+
&& (offset > 0 || root.posFromIndex(offsetNode.getAbsoluteIndex()).left === position.character)) {
|
|
1011
1104
|
info = this.#getParserFunction(name);
|
|
1012
|
-
f =
|
|
1105
|
+
f = offsetNode.firstChild.toString(true).trim();
|
|
1013
1106
|
}
|
|
1014
|
-
else if ((
|
|
1015
|
-
&&
|
|
1016
|
-
f =
|
|
1107
|
+
else if ((offsetNode.is('magic-word') || offsetNode.is('template'))
|
|
1108
|
+
&& offsetNode.modifier && offset >= 2 && offsetNode.getRelativeIndex(0) > offset) {
|
|
1109
|
+
f = offsetNode.modifier.trim().slice(0, -1);
|
|
1017
1110
|
info = this.#getParserFunction(f.toLowerCase());
|
|
1018
1111
|
if (info) {
|
|
1019
|
-
const aIndex =
|
|
1112
|
+
const aIndex = offsetNode.getAbsoluteIndex();
|
|
1020
1113
|
range = {
|
|
1021
1114
|
start: positionAt(root, aIndex + 2),
|
|
1022
|
-
end: positionAt(root, aIndex +
|
|
1115
|
+
end: positionAt(root, aIndex + offsetNode.modifier.trimEnd().length + 1),
|
|
1023
1116
|
};
|
|
1024
1117
|
}
|
|
1025
1118
|
/* NOT FOR BROWSER ONLY */
|
|
1026
1119
|
}
|
|
1027
|
-
else if (
|
|
1028
|
-
const textDoc = new document_1.EmbeddedCSSDocument(root,
|
|
1120
|
+
else if ((0, exports.isAttr)(offsetNode, true)) {
|
|
1121
|
+
const textDoc = new document_1.EmbeddedCSSDocument(root, offsetNode);
|
|
1029
1122
|
return document_1.cssLSP.doHover(textDoc, position, textDoc.styleSheet) ?? undefined;
|
|
1030
1123
|
}
|
|
1031
1124
|
else if (document_1.jsonLSP && type === 'ext-inner' && document_1.jsonTags.includes(name)) {
|
|
1032
|
-
const textDoc = new document_1.EmbeddedJSONDocument(root,
|
|
1125
|
+
const textDoc = new document_1.EmbeddedJSONDocument(root, offsetNode);
|
|
1033
1126
|
return await document_1.jsonLSP.doHover(textDoc, position, textDoc.jsonDoc) ?? undefined;
|
|
1127
|
+
}
|
|
1128
|
+
else if (lint_1.htmlData.provideTags && lint_1.htmlData.provideAttributes) {
|
|
1129
|
+
if (type === 'html' && offset <= offsetNode.getRelativeIndex(0)
|
|
1130
|
+
|| type === 'html-attr-dirty' && offset === 0 && parentNode.firstChild === offsetNode) {
|
|
1131
|
+
const token = type === 'html' ? offsetNode : parentNode.parentNode, data = lint_1.htmlData.provideTags().find(({ name: n }) => n === token.name);
|
|
1132
|
+
if (data?.description) {
|
|
1133
|
+
const start = positionAt(root, token.getAbsoluteIndex());
|
|
1134
|
+
return {
|
|
1135
|
+
contents: data.description,
|
|
1136
|
+
range: {
|
|
1137
|
+
start,
|
|
1138
|
+
end: {
|
|
1139
|
+
line: start.line,
|
|
1140
|
+
character: start.character + token.getRelativeIndex(0),
|
|
1141
|
+
},
|
|
1142
|
+
},
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
else if (type === 'attr-key' && isHtmlAttr(parentNode)) {
|
|
1147
|
+
const data = lint_1.htmlData.provideAttributes(parentNode.tag).find(({ name: n }) => n === parentNode.name);
|
|
1148
|
+
if (data?.description) {
|
|
1149
|
+
return {
|
|
1150
|
+
contents: data.description,
|
|
1151
|
+
range: createNodeRange(offsetNode),
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1034
1155
|
/* NOT FOR BROWSER ONLY END */
|
|
1035
1156
|
}
|
|
1036
1157
|
return info && {
|
|
@@ -1041,7 +1162,7 @@ class LanguageService {
|
|
|
1041
1162
|
: '')
|
|
1042
1163
|
+ info.description,
|
|
1043
1164
|
},
|
|
1044
|
-
range: range ?? createNodeRange(
|
|
1165
|
+
range: range ?? createNodeRange(offsetNode),
|
|
1045
1166
|
};
|
|
1046
1167
|
}
|
|
1047
1168
|
/**
|
|
@@ -1114,8 +1235,7 @@ class LanguageService {
|
|
|
1114
1235
|
}
|
|
1115
1236
|
/** @private */
|
|
1116
1237
|
findStyleTokens() {
|
|
1117
|
-
return this.#done.querySelectorAll(cssSelector)
|
|
1118
|
-
.filter(({ lastChild: { length, firstChild } }) => length === 1 && firstChild.type === 'text');
|
|
1238
|
+
return this.#done.querySelectorAll(cssSelector).filter(({ lastChild }) => (0, exports.isAttr)(lastChild));
|
|
1119
1239
|
}
|
|
1120
1240
|
/* NOT FOR BROWSER ONLY */
|
|
1121
1241
|
/**
|
|
@@ -1177,6 +1297,28 @@ class LanguageService {
|
|
|
1177
1297
|
}
|
|
1178
1298
|
return symbols;
|
|
1179
1299
|
}
|
|
1300
|
+
/**
|
|
1301
|
+
* Set the target Wikipedia
|
|
1302
|
+
*
|
|
1303
|
+
* 设置目标维基百科
|
|
1304
|
+
* @param wiki Wikipedia URL / 维基百科网址
|
|
1305
|
+
* @throws `RangeError` 不是有效的维基百科网址
|
|
1306
|
+
*/
|
|
1307
|
+
async setTargetWikipedia(wiki) {
|
|
1308
|
+
const mt = /^https?:\/\/([^./]+)\.wikipedia\.org/iu.exec(wiki);
|
|
1309
|
+
if (!mt) {
|
|
1310
|
+
throw new RangeError('Invalid Wikipedia URL!');
|
|
1311
|
+
}
|
|
1312
|
+
const site = `${mt[1].toLowerCase()}wiki`;
|
|
1313
|
+
try {
|
|
1314
|
+
const config = require(path_1.default.join('..', '..', 'config', site));
|
|
1315
|
+
this.config = index_1.default.getConfig(config);
|
|
1316
|
+
}
|
|
1317
|
+
catch {
|
|
1318
|
+
this.config = index_1.default.getConfig(await (0, config_1.default)(site, `${mt[0]}/w`));
|
|
1319
|
+
}
|
|
1320
|
+
Object.assign(this.config, { articlePath: `${mt[0]}/wiki/` });
|
|
1321
|
+
}
|
|
1180
1322
|
}
|
|
1181
1323
|
exports.LanguageService = LanguageService;
|
|
1182
1324
|
constants_1.classes['LanguageService'] = __filename;
|
package/dist/src/attribute.js
CHANGED
|
@@ -51,7 +51,7 @@ const debug_1 = require("../util/debug");
|
|
|
51
51
|
const document_1 = require("../lib/document");
|
|
52
52
|
const fixed_1 = require("../mixin/fixed");
|
|
53
53
|
const stages = { 'ext-attr': 0, 'html-attr': 2, 'table-attr': 3 };
|
|
54
|
-
const insecureStyle = /expression|(?:accelerator|-o-link(?:-source)?|-o-replace)\s*:|(?:url|image(?:-set)?)\s*\(|attr\s*\([^)]+[\s,]url/u;
|
|
54
|
+
const insecureStyle = /expression|(?:accelerator|-o-link(?:-source)?|-o-replace)\s*:|(?:url|image(?:-set)?)\s*\(|attr\s*\([^)]+[\s,]url/u, complexTypes = new Set(['ext', 'arg', 'magic-word', 'template']);
|
|
55
55
|
/**
|
|
56
56
|
* attribute of extension and HTML tags
|
|
57
57
|
*
|
|
@@ -201,9 +201,6 @@ let AttributeToken = (() => {
|
|
|
201
201
|
e.suggestions = [{ desc: 'remove', range: [start, start + length], text: '' }];
|
|
202
202
|
errors.push(e);
|
|
203
203
|
}
|
|
204
|
-
else if (sharable_1.obsoleteAttrs[tag]?.has(name)) {
|
|
205
|
-
errors.push((0, lint_1.generateForChild)(firstChild, rect, 'obsolete-attr', 'obsolete attribute', 'warning'));
|
|
206
|
-
}
|
|
207
204
|
else if (name === 'style' && typeof value === 'string' && insecureStyle.test(value)) {
|
|
208
205
|
errors.push((0, lint_1.generateForChild)(lastChild, rect, 'insecure-style', 'insecure style'));
|
|
209
206
|
}
|
|
@@ -215,6 +212,15 @@ let AttributeToken = (() => {
|
|
|
215
212
|
];
|
|
216
213
|
errors.push(e);
|
|
217
214
|
}
|
|
215
|
+
else if (type !== 'ext-attr' && !lastChild.childNodes.some(({ type: t }) => complexTypes.has(t))) {
|
|
216
|
+
const data = lint_1.htmlData.provideValues(tag, name), v = String(value).toLowerCase();
|
|
217
|
+
if (data.length > 0 && data.every(({ name: n }) => n !== v)) {
|
|
218
|
+
errors.push((0, lint_1.generateForChild)(lastChild, rect, 'illegal-attr', 'illegal attribute value', 'warning'));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (sharable_1.obsoleteAttrs[tag]?.has(name)) {
|
|
222
|
+
errors.push((0, lint_1.generateForChild)(firstChild, rect, 'obsolete-attr', 'obsolete attribute', 'warning'));
|
|
223
|
+
}
|
|
218
224
|
return errors;
|
|
219
225
|
}
|
|
220
226
|
/**
|
package/dist/src/index.js
CHANGED
|
@@ -61,6 +61,7 @@ const range_1 = require("../lib/range");
|
|
|
61
61
|
/* NOT FOR BROWSER END */
|
|
62
62
|
/* NOT FOR BROWSER ONLY */
|
|
63
63
|
const document_1 = require("../lib/document");
|
|
64
|
+
const lsp_1 = require("../lib/lsp");
|
|
64
65
|
/* NOT FOR BROWSER */
|
|
65
66
|
/**
|
|
66
67
|
* 可接受的Token类型
|
|
@@ -524,8 +525,7 @@ class Token extends element_1.AstElement {
|
|
|
524
525
|
});
|
|
525
526
|
/* NOT FOR BROWSER ONLY */
|
|
526
527
|
}
|
|
527
|
-
else if (
|
|
528
|
-
&& this.parentNode.name === 'style') {
|
|
528
|
+
else if ((0, lsp_1.isAttr)(this, true)) {
|
|
529
529
|
const root = this.getRootNode(), textDoc = new document_1.EmbeddedCSSDocument(root, this);
|
|
530
530
|
errors.push(...document_1.cssLSP.doValidation(textDoc, textDoc.styleSheet)
|
|
531
531
|
.filter(({ code }) => code !== 'css-ruleorselectorexpected')
|
|
@@ -62,6 +62,7 @@ let DoubleUnderscoreToken = (() => {
|
|
|
62
62
|
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
63
63
|
__runInitializers(_classThis, _classExtraInitializers);
|
|
64
64
|
}
|
|
65
|
+
/* NOT FOR BROWSER */
|
|
65
66
|
#sensitive;
|
|
66
67
|
/* NOT FOR BROWSER END */
|
|
67
68
|
get type() {
|
|
@@ -73,10 +74,10 @@ let DoubleUnderscoreToken = (() => {
|
|
|
73
74
|
*/
|
|
74
75
|
constructor(word, sensitive, config, accum) {
|
|
75
76
|
super(word, config, accum);
|
|
77
|
+
const lc = word.toLowerCase(), { doubleUnderscore: [, , iAlias, sAlias] } = config;
|
|
78
|
+
this.setAttribute('name', (sensitive ? sAlias?.[word]?.toLowerCase() : iAlias?.[lc]) ?? lc);
|
|
76
79
|
/* NOT FOR BROWSER */
|
|
77
|
-
const lc = word.toLowerCase();
|
|
78
80
|
this.#sensitive = sensitive;
|
|
79
|
-
this.setAttribute('name', sensitive ? lc : config.doubleUnderscore[2]?.[lc] ?? lc);
|
|
80
81
|
this.setAttribute('pattern', new RegExp(`^${word}$`, sensitive ? 'u' : 'iu'));
|
|
81
82
|
}
|
|
82
83
|
/** @private */
|
package/dist/util/diff.js
CHANGED
|
@@ -73,7 +73,7 @@ const diff = async (oldStr, newStr, uid) => {
|
|
|
73
73
|
newFile,
|
|
74
74
|
]);
|
|
75
75
|
console.log(stdout?.split('\n').slice(4).join('\n'));
|
|
76
|
-
await Promise.
|
|
76
|
+
await Promise.allSettled([promises_1.default.unlink(oldFile), promises_1.default.unlink(newFile)]);
|
|
77
77
|
};
|
|
78
78
|
exports.diff = diff;
|
|
79
79
|
/* istanbul ignore next */
|
package/dist/util/lint.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.cache = exports.generateForSelf = exports.generateForChild = exports.getEndPos = void 0;
|
|
6
|
+
exports.htmlData = exports.cache = exports.generateForSelf = exports.generateForChild = exports.getEndPos = void 0;
|
|
7
7
|
const debug_1 = require("./debug");
|
|
8
8
|
const rect_1 = require("../lib/rect");
|
|
9
9
|
const index_1 = __importDefault(require("../index"));
|
|
@@ -65,3 +65,33 @@ const cache = (store, compute, update) => {
|
|
|
65
65
|
return result;
|
|
66
66
|
};
|
|
67
67
|
exports.cache = cache;
|
|
68
|
+
let htmlData;
|
|
69
|
+
try {
|
|
70
|
+
exports.htmlData = htmlData = require('vscode-html-languageservice')
|
|
71
|
+
.getDefaultHTMLDataProvider();
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
/**
|
|
75
|
+
* 获取HTML属性值可选列表
|
|
76
|
+
* @param tag 标签名
|
|
77
|
+
* @param attribute 属性名
|
|
78
|
+
*/
|
|
79
|
+
const provideValues = (tag, attribute) => {
|
|
80
|
+
if (tag === 'ol' && attribute === 'type') {
|
|
81
|
+
return ['1', 'a', 'A', 'i', 'I'];
|
|
82
|
+
}
|
|
83
|
+
else if (tag === 'th' && attribute === 'scope') {
|
|
84
|
+
return ['row', 'col', 'rowgroup', 'colgroup'];
|
|
85
|
+
}
|
|
86
|
+
else if (attribute === 'dir') {
|
|
87
|
+
return ['ltr', 'rtl', 'auto'];
|
|
88
|
+
}
|
|
89
|
+
return attribute === 'aria-hidden' ? ['true', 'false'] : [];
|
|
90
|
+
};
|
|
91
|
+
exports.htmlData = htmlData = {
|
|
92
|
+
/** @implements */
|
|
93
|
+
provideValues(tag, attribute) {
|
|
94
|
+
return provideValues(tag, attribute).map(value => ({ name: value }));
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
package/extensions/dist/base.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(() => {
|
|
2
2
|
var _a;
|
|
3
|
-
const version = '1.18.
|
|
3
|
+
const version = '1.18.1', src = (_a = document.currentScript) === null || _a === void 0 ? void 0 : _a.src, file = /\/extensions\/dist\/base\.(?:min\.)?js$/u, CDN = src && file.test(src)
|
|
4
4
|
? src.replace(file, '')
|
|
5
5
|
: `https://testingcf.jsdelivr.net/npm/wikiparser-node@${version}`;
|
|
6
6
|
const workerJS = () => {
|