wikilint 2.20.0 → 2.20.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.
@@ -6,7 +6,11 @@ import type { Token } from '../internal';
6
6
  declare interface Jax {
7
7
  tex2mml(tex: string): string;
8
8
  }
9
- export declare const MathJax: Promise<Jax | undefined>;
9
+ /**
10
+ * Load MathJax
11
+ * @param id MathJax module ID
12
+ */
13
+ export declare const loadMathJax: (id?: string) => Promise<Jax> | undefined;
10
14
  export declare const jsonTags: string[];
11
15
  export declare const jsonLSP: import("vscode-json-languageservice").LanguageService | undefined;
12
16
  export declare const cssLSP: import("vscode-css-languageservice").LanguageService | undefined;
@@ -3,13 +3,18 @@ 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.EmbeddedCSSDocument = exports.EmbeddedJSONDocument = exports.stylelint = exports.htmlData = exports.cssLSP = exports.jsonLSP = exports.jsonTags = exports.MathJax = void 0;
6
+ exports.EmbeddedCSSDocument = exports.EmbeddedJSONDocument = exports.stylelint = exports.htmlData = exports.cssLSP = exports.jsonLSP = exports.jsonTags = exports.loadMathJax = void 0;
7
7
  const path_1 = __importDefault(require("path"));
8
8
  const common_1 = require("@bhsd/common");
9
- exports.MathJax = (async () => {
9
+ let MathJax;
10
+ /**
11
+ * Load MathJax
12
+ * @param id MathJax module ID
13
+ */
14
+ const loadMathJax = (id = 'mathjax') => {
10
15
  try {
11
- const jax = require('mathjax');
12
- return await jax.init({
16
+ const jax = require(id);
17
+ MathJax ??= jax.init({
13
18
  loader: {
14
19
  load: ['input/tex', '[tex]/mhchem'],
15
20
  },
@@ -22,11 +27,13 @@ exports.MathJax = (async () => {
22
27
  },
23
28
  startup: { typeset: false },
24
29
  });
30
+ return MathJax;
25
31
  }
26
32
  catch {
27
33
  return undefined;
28
34
  }
29
- })();
35
+ };
36
+ exports.loadMathJax = loadMathJax;
30
37
  exports.jsonTags = ['templatedata', 'mapframe', 'maplink'];
31
38
  exports.jsonLSP = (() => {
32
39
  try {
package/dist/lib/lsp.js CHANGED
@@ -280,7 +280,6 @@ class LanguageService {
280
280
  config;
281
281
  /** @private */
282
282
  data;
283
- /* NOT FOR BROWSER ONLY */
284
283
  lilypond;
285
284
  #lilypondData;
286
285
  #mathData;
@@ -840,7 +839,7 @@ class LanguageService {
840
839
  }));
841
840
  }
842
841
  }
843
- const MathJax = await document_1.MathJax, data = this.#mathSet, mathDiagnostics = root.querySelectorAll(mathSelector)
842
+ const MathJax = await (0, document_1.loadMathJax)(this.mathjax), data = this.#mathSet, mathDiagnostics = root.querySelectorAll(mathSelector)
844
843
  .map(token => {
845
844
  const { selfClosing, innerText, lastChild, name } = token;
846
845
  if (selfClosing) {
@@ -13,6 +13,10 @@ export interface CaretPosition {
13
13
  readonly offsetNode: AstNodes;
14
14
  readonly offset: number;
15
15
  }
16
+ export interface Font {
17
+ bold: boolean;
18
+ italic: boolean;
19
+ }
16
20
  /**
17
21
  * Node-like
18
22
  *
package/dist/lib/text.js CHANGED
@@ -25,7 +25,7 @@ const errorSyntaxUrl = new RegExp(source, 'giu'), noLinkTypes = new Set(['attr-v
25
25
  r: 'lonely-http',
26
26
  p: 'lonely-http',
27
27
  i: 'lonely-http',
28
- }, disallowedTags = [
28
+ }, disallowedTags = new Set([
29
29
  'html',
30
30
  'head',
31
31
  'style',
@@ -51,7 +51,7 @@ const errorSyntaxUrl = new RegExp(source, 'giu'), noLinkTypes = new Set(['attr-v
51
51
  'option',
52
52
  'select',
53
53
  'textarea',
54
- ];
54
+ ]);
55
55
  let wordRegex;
56
56
  try {
57
57
  // eslint-disable-next-line prefer-regex-literals, es-x/no-regexp-unicode-property-escapes
@@ -100,7 +100,8 @@ class AstText extends node_1.AstNode {
100
100
  if (grandType !== 'ext-attr') {
101
101
  isHtmlAttrVal = true;
102
102
  }
103
- else if (tag === 'choose' && (grandName === 'before' || grandName === 'after')) {
103
+ else if (tag === 'ref' && (grandName === 'name' || grandName === 'extends' || grandName === 'follow')
104
+ || tag === 'choose' && (grandName === 'before' || grandName === 'after')) {
104
105
  return [];
105
106
  }
106
107
  }
@@ -145,16 +146,15 @@ class AstText extends node_1.AstNode {
145
146
  else if (char === ']' && (index || length > 1)) {
146
147
  errorRegex.lastIndex--;
147
148
  }
148
- const startIndex = start + index, endIndex = startIndex + length, nextChar = rootStr[endIndex], previousChar = rootStr[startIndex - 1], severity = length > 1 && !(char === '<' && !/[\s/>]/u.test(nextChar ?? '')
149
+ const startIndex = start + index, endIndex = startIndex + length, nextChar = rootStr[endIndex], previousChar = rootStr[startIndex - 1], severity = length > 1 && !(char === '<' && (/^<\s/u.test(error) || !/[\s/>]/u.test(nextChar ?? '') || disallowedTags.has(tag))
149
150
  || isHtmlAttrVal && (char === '[' || char === ']')
150
- || magicLink && type === 'parameter-value')
151
+ || magicLink && type === 'parameter-value'
152
+ || /^(?:rfc|pmid|isbn)$/iu.test(error))
151
153
  || char === '{' && (nextChar === char || previousChar === '-')
152
154
  || char === '}' && (previousChar === char || nextChar === '-')
153
- || char === '[' && (nextChar === char
154
- || type === 'ext-link-text'
155
- || nextType === 'free-ext-link' && !data.slice(index + 1).trim())
156
- || char === ']' && (previousChar === char
157
- || previousType === 'free-ext-link' && !data.slice(0, index).includes(']'))
155
+ || char === '[' && (type === 'ext-link-text' || nextType === 'free-ext-link' && !data.slice(index + 1).trim())
156
+ || char === ']' && previousType === 'free-ext-link'
157
+ && !data.slice(0, index).includes(']')
158
158
  ? 'error'
159
159
  : 'warning';
160
160
  const leftBracket = char === '{' || char === '[', rightBracket = char === ']' || char === '}';
@@ -56,9 +56,17 @@ const parseQuotes = (wikitext, config, accum, tidy) => {
56
56
  arr[i - 1] += `'`;
57
57
  }
58
58
  }
59
+ let bold = true, italic = true;
59
60
  for (let i = 1; i < length; i += 2) {
61
+ const n = arr[i].length, isBold = n !== 2, isItalic = n !== 3;
62
+ if (isBold) {
63
+ bold = !bold;
64
+ }
65
+ if (isItalic) {
66
+ italic = !italic;
67
+ }
60
68
  // @ts-expect-error abstract class
61
- new quote_1.QuoteToken(arr[i], config, accum);
69
+ new quote_1.QuoteToken(arr[i], { bold: isBold && bold, italic: isItalic && italic }, config, accum);
62
70
  arr[i] = `\0${accum.length - 1}q\x7F`;
63
71
  }
64
72
  return arr.join('');
@@ -81,8 +81,8 @@ class AttributesToken extends index_2.Token {
81
81
  /** @private */
82
82
  afterBuild() {
83
83
  const { parentNode } = this;
84
- if (parentNode?.type === 'td' && parentNode.subtype === 'caption') {
85
- this.setAttribute('name', 'caption');
84
+ if (parentNode?.type === 'td') {
85
+ this.setAttribute('name', parentNode.subtype);
86
86
  }
87
87
  super.afterBuild();
88
88
  }
@@ -106,7 +106,9 @@ let GalleryToken = (() => {
106
106
  errors.push({
107
107
  rule: 'no-ignored',
108
108
  message: index_1.default.msg('invalid content in <$1>', 'gallery'),
109
- severity: trimmed.startsWith('|') ? 'warning' : 'error',
109
+ severity: trimmed.endsWith('-->') || /^(?:\||<!--)/u.test(trimmed)
110
+ ? 'warning'
111
+ : 'error',
110
112
  startIndex: start,
111
113
  endIndex,
112
114
  startLine,
@@ -33,7 +33,7 @@ class RedirectTargetToken extends base_1.LinkBaseToken {
33
33
  lint(start = this.getAbsoluteIndex()) {
34
34
  const errors = super.lint(start, false);
35
35
  if (this.length === 2) {
36
- const e = (0, lint_1.generateForChild)(this.lastChild, { start }, 'no-ignored', 'useless link text');
36
+ const e = (0, lint_1.generateForChild)(this.lastChild, { start }, 'no-ignored', 'useless link text', 'warning');
37
37
  e.startIndex--;
38
38
  e.startCol--;
39
39
  e.fix = { range: [e.startIndex, e.endIndex], text: '', desc: 'remove' };
@@ -1,6 +1,6 @@
1
1
  import { NowikiBaseToken } from './base';
2
2
  import type { LintError, Config } from '../../base';
3
- import type { Token } from '../index';
3
+ import type { Token } from '../../internal';
4
4
  /**
5
5
  * invisible HTML comment
6
6
  *
@@ -1,6 +1,6 @@
1
1
  import { NowikiBaseToken } from './base';
2
2
  import type { Config } from '../../base';
3
- import type { Token } from '../index';
3
+ import type { Token } from '../../internal';
4
4
  /**
5
5
  * behavior switch
6
6
  *
@@ -1,14 +1,21 @@
1
1
  import { NowikiBaseToken } from './base';
2
- import type { LintError } from '../../base';
2
+ import type { LintError, Config } from '../../base';
3
+ import type { Font } from '../../lib/node';
4
+ import type { Token } from '../../internal';
3
5
  /**
4
6
  * `''` and `'''`
5
7
  *
6
8
  * `''`和`'''`
7
9
  */
8
10
  export declare abstract class QuoteToken extends NowikiBaseToken {
11
+ #private;
9
12
  get type(): 'quote';
10
13
  /** 是否粗体 */
11
14
  get bold(): boolean;
12
15
  /** 是否斜体 */
13
16
  get italic(): boolean;
17
+ /** whether to be closing quotes / 是否闭合 */
18
+ get closing(): Partial<Font>;
19
+ /** @param closing 是否闭合 */
20
+ constructor(wikitext: string, closing: Font, config?: Config, accum?: Token[]);
14
21
  }
@@ -14,6 +14,7 @@ const base_1 = require("./base");
14
14
  * `''`和`'''`
15
15
  */
16
16
  class QuoteToken extends base_1.NowikiBaseToken {
17
+ #closing;
17
18
  get type() {
18
19
  return 'quote';
19
20
  }
@@ -25,6 +26,18 @@ class QuoteToken extends base_1.NowikiBaseToken {
25
26
  get italic() {
26
27
  return this.innerText.length !== 3;
27
28
  }
29
+ /** whether to be closing quotes / 是否闭合 */
30
+ get closing() {
31
+ return {
32
+ ...this.bold ? { bold: this.#closing.bold } : undefined,
33
+ ...this.italic ? { italic: this.#closing.italic } : undefined,
34
+ };
35
+ }
36
+ /** @param closing 是否闭合 */
37
+ constructor(wikitext, closing, config, accum) {
38
+ super(wikitext, config, accum);
39
+ this.#closing = closing;
40
+ }
28
41
  /** @private */
29
42
  text() {
30
43
  const { parentNode, innerText } = this;
@@ -32,7 +45,7 @@ class QuoteToken extends base_1.NowikiBaseToken {
32
45
  }
33
46
  /** @private */
34
47
  lint(start = this.getAbsoluteIndex()) {
35
- const { previousSibling, nextSibling, bold } = this, message = index_1.default.msg('lonely "$1"', `'`), errors = [], rect = new rect_1.BoundingRect(this, start);
48
+ const { previousSibling, nextSibling, bold, closing } = this, previousData = previousSibling?.type === 'text' ? previousSibling.data : undefined, nextData = nextSibling?.type === 'text' ? nextSibling.data : undefined, message = index_1.default.msg('lonely "$1"', `'`), errors = [], rect = new rect_1.BoundingRect(this, start);
36
49
  /**
37
50
  * 获取建议
38
51
  * @param startIndex 起点
@@ -43,8 +56,11 @@ class QuoteToken extends base_1.NowikiBaseToken {
43
56
  { desc: 'escape', range: [startIndex, endIndex], text: '&apos;'.repeat(length) },
44
57
  { desc: 'remove', range: [startIndex, endIndex], text: '' },
45
58
  ];
46
- if (previousSibling?.type === 'text' && previousSibling.data.endsWith(`'`)) {
47
- const e = (0, lint_1.generateForSelf)(this, rect, 'lonely-apos', message), { startIndex: endIndex, startLine: endLine, startCol: endCol } = e, [, { length }] = /(?:^|[^'])('+)$/u.exec(previousSibling.data), startIndex = start - length;
59
+ if (previousData?.endsWith(`'`)) {
60
+ const e = (0, lint_1.generateForSelf)(this, rect, 'lonely-apos', message, (closing.bold || closing.italic)
61
+ && (/[a-z\d]'$/iu.test(previousData) || nextData && /^[a-z\d]/iu.test(nextData))
62
+ ? 'warning'
63
+ : 'error'), { startIndex: endIndex, startLine: endLine, startCol: endCol } = e, [, { length }] = /(?:^|[^'])('+)$/u.exec(previousData), startIndex = start - length;
48
64
  errors.push({
49
65
  ...e,
50
66
  startIndex,
@@ -55,8 +71,8 @@ class QuoteToken extends base_1.NowikiBaseToken {
55
71
  suggestions: getSuggestion(startIndex, endIndex, length),
56
72
  });
57
73
  }
58
- if (nextSibling?.type === 'text' && nextSibling.data.startsWith(`'`)) {
59
- const e = (0, lint_1.generateForSelf)(this, rect, 'lonely-apos', message), { endIndex: startIndex, endLine: startLine, endCol: startCol } = e, [{ length }] = /^'+/u.exec(nextSibling.data), endIndex = startIndex + length;
74
+ if (nextData?.startsWith(`'`)) {
75
+ const e = (0, lint_1.generateForSelf)(this, rect, 'lonely-apos', message), { endIndex: startIndex, endLine: startLine, endCol: startCol } = e, [{ length }] = /^'+/u.exec(nextData), endIndex = startIndex + length;
60
76
  errors.push({
61
77
  ...e,
62
78
  startIndex,
@@ -1,6 +1,6 @@
1
1
  import Parser from '../../index';
2
2
  import { ParamTagToken } from './index';
3
- import type { Token } from '../index';
3
+ import type { Token } from '../../internal';
4
4
  /** `<inputbox>` */
5
5
  export declare abstract class InputboxToken extends ParamTagToken {
6
6
  /** @class */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wikilint",
3
- "version": "2.20.0",
3
+ "version": "2.20.1",
4
4
  "description": "A Node.js linter for MediaWiki markup",
5
5
  "keywords": [
6
6
  "mediawiki",
@@ -76,9 +76,9 @@
76
76
  "mathjax": "^3.2.2",
77
77
  "minimatch": "^10.0.1",
78
78
  "stylelint": "^16.14.1",
79
- "vscode-css-languageservice": "^6.3.2",
80
- "vscode-html-languageservice": "^5.3.1",
81
- "vscode-json-languageservice": "^5.4.3"
79
+ "vscode-css-languageservice": "^6.3.4",
80
+ "vscode-html-languageservice": "^5.3.3",
81
+ "vscode-json-languageservice": "^5.4.4"
82
82
  },
83
83
  "devDependencies": {
84
84
  "@stylistic/eslint-plugin": "^3.1.0",