wikilint 2.3.8 → 2.3.9

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/dist/base.d.ts CHANGED
@@ -28,6 +28,9 @@ export interface AstNode {
28
28
  /** Linter */
29
29
  lint(): LintError[];
30
30
  }
31
+ /** 类似HTMLElement */
32
+ interface AstElement extends AstNode {
33
+ }
31
34
  export interface Parser {
32
35
  config: string | Config;
33
36
  i18n: string | Record<string, string> | undefined;
@@ -36,5 +39,6 @@ export interface Parser {
36
39
  * @param include 是否嵌入
37
40
  * @param maxStage 最大解析层级
38
41
  */
39
- parse(wikitext: string, include?: boolean, maxStage?: number, config?: Config): AstNode;
42
+ parse(wikitext: string, include?: boolean, maxStage?: number, config?: Config): AstElement;
40
43
  }
44
+ export {};
package/dist/lib/title.js CHANGED
@@ -36,7 +36,7 @@ class Title {
36
36
  const m = title.split(':');
37
37
  if (m.length > 1) {
38
38
  const id = nsid[m[0].trim().toLowerCase()];
39
- if (id !== undefined) {
39
+ if (id) {
40
40
  ns = id;
41
41
  title = m.slice(1).join(':').trim();
42
42
  }
@@ -50,7 +50,7 @@ class Title {
50
50
  title = title.slice(0, i).trim();
51
51
  }
52
52
  this.valid = Boolean(title
53
- || selfLink && this.fragment !== undefined) && !/\0\d+[eh!+-]\x7F|[<>[\]{}|]|%[\da-f]{2}/iu.test(title);
53
+ || selfLink && this.fragment !== undefined) && !/^:|\0\d+[eh!+-]\x7F|[<>[\]{}|]|%[\da-f]{2}/iu.test(title);
54
54
  }
55
55
  }
56
56
  exports.Title = Title;
@@ -84,7 +84,7 @@ const parseBraces = (wikitext, config = Parser.getConfig(), accum = []) => {
84
84
  }
85
85
  }
86
86
  catch (e) {
87
- if (e instanceof SyntaxError && e.message.startsWith('非法的模板名称:')) {
87
+ if (e instanceof SyntaxError && e.message === '非法的模板名称') {
88
88
  skip = true;
89
89
  }
90
90
  else {
@@ -32,7 +32,7 @@ const commonHtmlAttrs = new Set([
32
32
  'itemref',
33
33
  'itemscope',
34
34
  'itemtype',
35
- ]), blockAttrs = new Set(['align']), citeAttrs = new Set(['cite']), citeAndAttrs = new Set(['cite', 'datetime']), widthAttrs = new Set(['width']), tdAttrs = new Set(['align', 'valign', 'abbr', 'axis', 'headers', 'scope', 'rowspan', 'colspan', 'width', 'height', 'bgcolor']), typeAttrs = new Set(['type']), htmlAttrs = {
35
+ ]), blockAttrs = new Set(['align']), citeAttrs = new Set(['cite']), citeAndAttrs = new Set(['cite', 'datetime']), widthAttrs = new Set(['width']), obsoleteTdAttrs = new Set(['axis', 'align', 'bgcolor', 'height', 'width', 'valign']), tdAttrs = new Set([...obsoleteTdAttrs, 'abbr', 'headers', 'scope', 'rowspan', 'colspan']), typeAttrs = new Set(['type']), obsoleteTableAttrs = new Set(['summary', 'align', 'bgcolor', 'cellpadding', 'cellspacing', 'frame', 'rules', 'width']), brAttrs = new Set(['clear']), trAttrs = new Set(['bgcolor', 'align', 'valign']), htmlAttrs = {
36
36
  div: blockAttrs,
37
37
  h1: blockAttrs,
38
38
  h2: blockAttrs,
@@ -43,16 +43,16 @@ const commonHtmlAttrs = new Set([
43
43
  blockquote: citeAttrs,
44
44
  q: citeAttrs,
45
45
  p: blockAttrs,
46
- br: new Set(['clear']),
46
+ br: brAttrs,
47
47
  pre: widthAttrs,
48
48
  ins: citeAndAttrs,
49
49
  del: citeAndAttrs,
50
50
  ul: typeAttrs,
51
51
  ol: new Set(['type', 'start', 'reversed']),
52
52
  li: new Set(['type', 'value']),
53
- table: new Set(['summary', 'width', 'border', 'frame', 'rules', 'cellspacing', 'cellpadding', 'align', 'bgcolor']),
53
+ table: new Set([...obsoleteTableAttrs, 'border']),
54
54
  caption: blockAttrs,
55
- tr: new Set(['bgcolor', 'align', 'valign']),
55
+ tr: trAttrs,
56
56
  td: tdAttrs,
57
57
  th: tdAttrs,
58
58
  img: new Set(['alt', 'src', 'width', 'height', 'srcset']),
@@ -118,7 +118,26 @@ const commonHtmlAttrs = new Set([
118
118
  + '|'
119
119
  + '(?:url|image(?:-set)?)\\s*\\('
120
120
  + '|'
121
- + 'attr\\s*\\([^)]+[\\s,]url', 'u');
121
+ + 'attr\\s*\\([^)]+[\\s,]url', 'u'), obsoleteAttrs = {
122
+ table: obsoleteTableAttrs,
123
+ td: new Set([...obsoleteTdAttrs, 'scope']),
124
+ th: obsoleteTdAttrs,
125
+ br: brAttrs,
126
+ caption: blockAttrs,
127
+ div: blockAttrs,
128
+ hr: widthAttrs,
129
+ h1: blockAttrs,
130
+ h2: blockAttrs,
131
+ h3: blockAttrs,
132
+ h4: blockAttrs,
133
+ h5: blockAttrs,
134
+ h6: blockAttrs,
135
+ li: typeAttrs,
136
+ p: blockAttrs,
137
+ pre: widthAttrs,
138
+ tr: trAttrs,
139
+ ul: typeAttrs,
140
+ };
122
141
  /**
123
142
  * 扩展和HTML标签属性
124
143
  * @classdesc `{childNodes: [AtomToken, Token|AtomToken]}`
@@ -223,6 +242,10 @@ class AttributeToken extends index_1.Token {
223
242
  rect ??= { start, ...this.getRootNode().posFromIndex(start) };
224
243
  errors.push((0, lint_1.generateForChild)(firstChild, rect, 'illegal attribute name'));
225
244
  }
245
+ else if (obsoleteAttrs[tag]?.has(name)) {
246
+ rect ??= { start, ...this.getRootNode().posFromIndex(start) };
247
+ errors.push((0, lint_1.generateForChild)(firstChild, rect, 'obsolete attribute', 'warning'));
248
+ }
226
249
  else if (name === 'style' && typeof value === 'string' && insecureStyle.test(value)) {
227
250
  rect ??= { start, ...this.getRootNode().posFromIndex(start) };
228
251
  errors.push((0, lint_1.generateForChild)(lastChild, rect, 'insecure style'));
@@ -55,18 +55,27 @@ class HeadingToken extends index_1.Token {
55
55
  }
56
56
  /** @override */
57
57
  lint(start = this.getAbsoluteIndex()) {
58
- const errors = super.lint(start), { firstChild } = this, innerStr = String(firstChild);
59
- let refError;
58
+ const errors = super.lint(start), { firstChild, level } = this, innerStr = String(firstChild), quotes = firstChild.childNodes.filter((node) => node.type === 'quote'), boldQuotes = quotes.filter(({ bold }) => bold), italicQuotes = quotes.filter(({ italic }) => italic);
59
+ let rect;
60
60
  if (this.level === 1) {
61
- refError = (0, lint_1.generateForChild)(firstChild, { start }, '<h1>');
62
- errors.push(refError);
61
+ rect = { start, ...this.getRootNode().posFromIndex(start) };
62
+ errors.push((0, lint_1.generateForChild)(firstChild, rect, '<h1>'));
63
63
  }
64
64
  if (innerStr.startsWith('=') || innerStr.endsWith('=')) {
65
- refError ??= (0, lint_1.generateForChild)(firstChild, { start }, '');
66
- errors.push({ ...refError, message: Parser.msg('unbalanced "=" in a section header') });
65
+ rect ??= { start, ...this.getRootNode().posFromIndex(start) };
66
+ errors.push((0, lint_1.generateForChild)(firstChild, rect, Parser.msg('unbalanced $1 in a section header', '"="')));
67
67
  }
68
68
  if (this.closest('html-attrs, table-attrs')) {
69
- errors.push({ ...(0, lint_1.generateForSelf)(this, { start }, ''), message: Parser.msg('section header in a HTML tag') });
69
+ rect ??= { start, ...this.getRootNode().posFromIndex(start) };
70
+ errors.push((0, lint_1.generateForSelf)(this, rect, 'section header in a HTML tag'));
71
+ }
72
+ if (boldQuotes.length % 2) {
73
+ rect ??= { start, ...this.getRootNode().posFromIndex(start) };
74
+ errors.push((0, lint_1.generateForChild)(boldQuotes[boldQuotes.length - 1], { ...rect, start: start + level, left: rect.left + level }, Parser.msg('unbalanced $1 in a section header', 'bold apostrophes')));
75
+ }
76
+ if (italicQuotes.length % 2) {
77
+ rect ??= { start, ...this.getRootNode().posFromIndex(start) };
78
+ errors.push((0, lint_1.generateForChild)(italicQuotes[italicQuotes.length - 1], { start: start + level }, Parser.msg('unbalanced $1 in a section header', 'italic apostrophes')));
70
79
  }
71
80
  return errors;
72
81
  }
package/dist/src/html.js CHANGED
@@ -5,7 +5,33 @@ const lint_1 = require("../util/lint");
5
5
  const string_1 = require("../util/string");
6
6
  const Parser = require("../index");
7
7
  const index_1 = require("./index");
8
- const magicWords = new Set(['if', 'ifeq', 'ifexpr', 'ifexist', 'iferror', 'switch']);
8
+ const magicWords = new Set(['if', 'ifeq', 'ifexpr', 'ifexist', 'iferror', 'switch']), formattingTags = new Set([
9
+ 'b',
10
+ 'big',
11
+ 'center',
12
+ 'cite',
13
+ 'code',
14
+ 'del',
15
+ 'dfn',
16
+ 'em',
17
+ 'font',
18
+ 'i',
19
+ 'ins',
20
+ 'kbd',
21
+ 'mark',
22
+ 'pre',
23
+ 'q',
24
+ 's',
25
+ 'samp',
26
+ 'small',
27
+ 'strike',
28
+ 'strong',
29
+ 'sub',
30
+ 'sup',
31
+ 'tt',
32
+ 'u',
33
+ 'var',
34
+ ]), obsoleteTags = new Set(['strike', 'big', 'center', 'font', 'tt']);
9
35
  /**
10
36
  * HTML标签
11
37
  * @classdesc `{childNodes: [AttributesToken]}`
@@ -74,7 +100,7 @@ class HtmlToken extends index_1.Token {
74
100
  const { message: errorMsg } = e;
75
101
  refError ??= (0, lint_1.generateForSelf)(this, { start }, '');
76
102
  const [msg] = errorMsg.split(':'), error = { ...refError, message: Parser.msg(msg) };
77
- if (msg === 'unclosed tag') {
103
+ if (msg === 'unclosed tag' && !formattingTags.has(this.name)) {
78
104
  error.severity = 'warning';
79
105
  }
80
106
  else if (msg === 'unmatched closing tag') {
@@ -86,6 +112,14 @@ class HtmlToken extends index_1.Token {
86
112
  errors.push(error);
87
113
  }
88
114
  }
115
+ if (obsoleteTags.has(this.name)) {
116
+ refError ??= (0, lint_1.generateForSelf)(this, { start }, '');
117
+ errors.push({
118
+ ...refError,
119
+ message: Parser.msg('obsolete HTML tag'),
120
+ severity: 'warning',
121
+ });
122
+ }
89
123
  return errors;
90
124
  }
91
125
  /**
@@ -92,6 +92,10 @@ class LinkBaseToken extends index_1.Token {
92
92
  rect ??= { start, ...this.getRootNode().posFromIndex(start) };
93
93
  errors.push((0, lint_1.generateForChild)(target, rect, 'useless fragment'));
94
94
  }
95
+ if (linkType === 'link' && this.closest('ext-link-text')) {
96
+ rect ??= { start, ...this.getRootNode().posFromIndex(start) };
97
+ errors.push((0, lint_1.generateForSelf)(this, rect, 'internal link in an external link'));
98
+ }
95
99
  return errors;
96
100
  }
97
101
  /** @private */
@@ -3,6 +3,10 @@ import type { LintError } from '../../base';
3
3
  /** `''`和`'''` */
4
4
  export declare class QuoteToken extends NowikiBaseToken {
5
5
  readonly type = "quote";
6
+ /** 是否粗体 */
7
+ get bold(): boolean;
8
+ /** 是否斜体 */
9
+ get italic(): boolean;
6
10
  /** @override */
7
11
  lint(start?: number): LintError[];
8
12
  }
@@ -8,6 +8,14 @@ const base_1 = require("./base");
8
8
  // @ts-expect-error not implementing all abstract methods
9
9
  class QuoteToken extends base_1.NowikiBaseToken {
10
10
  type = 'quote';
11
+ /** 是否粗体 */
12
+ get bold() {
13
+ return this.innerText.length !== 2;
14
+ }
15
+ /** 是否斜体 */
16
+ get italic() {
17
+ return this.innerText.length !== 3;
18
+ }
11
19
  /** @override */
12
20
  lint(start = this.getAbsoluteIndex()) {
13
21
  const { previousSibling, nextSibling } = this, message = Parser.msg('lonely "$1"', `'`), errors = [];
@@ -70,9 +70,9 @@ class TranscludeToken extends index_1.Token {
70
70
  }
71
71
  if (this.type === 'template') {
72
72
  const name = (0, string_1.removeComment)((0, string_1.decodeHtml)(title)).split('#')[0].trim();
73
- if (!name || /\0\d+[eh!+-]\x7F|[<>[\]{}\n]|%[\da-f]{2}/u.test(name)) {
73
+ if (!name || /^:[\s_]*:|\0\d+[eh!+-]\x7F|[<>[\]{}\n]|%[\da-f]{2}/iu.test(name)) {
74
74
  accum.pop();
75
- throw new SyntaxError(`非法的模板名称:${(0, string_1.noWrap)(name)}`);
75
+ throw new SyntaxError('非法的模板名称');
76
76
  }
77
77
  const token = new atom_1.AtomToken(title, 'template-name', config, accum, {});
78
78
  super.insertAt(token);
package/i18n/zh-hans.json CHANGED
@@ -4,6 +4,7 @@
4
4
  "additional \"|\" in a table cell": "表格单元格中多余的\"|\"",
5
5
  "additional \"|\" in the link text": "链接文本中多余的\"|\"",
6
6
  "attributes of a closing tag": "位于闭合标签的属性",
7
+ "bold": "粗体单引号",
7
8
  "conflicting image $1 parameter": "冲突的图片$1参数",
8
9
  "containing invalid attribute": "包含无效属性",
9
10
  "content to be moved out from the table": "将被移出表格的内容",
@@ -19,6 +20,7 @@
19
20
  "illegal attribute name": "非法的属性名",
20
21
  "illegal module name": "非法的模块名称",
21
22
  "insecure style": "不安全的样式",
23
+ "internal link in an external link": "外链中的内链",
22
24
  "invalid content in <$1>": "<$1>内的无效内容",
23
25
  "invalid conversion flag": "无效的转换标记",
24
26
  "invalid gallery image": "无效的图库图片",
@@ -27,17 +29,20 @@
27
29
  "invalid parameter of $1": "$1的无效参数",
28
30
  "invalid self-closing tag": "无效自封闭标签",
29
31
  "invisible content inside triple brackets": "三重括号内的不可见部分",
32
+ "italic": "斜体单引号",
30
33
  "lonely \"$1\"": "孤立的\"$1\"",
31
34
  "missing module function": "缺少模块函数",
32
35
  "missing module name": "缺少模块名称",
33
36
  "nonzero tabindex": "不为0的tabindex",
34
37
  "nothing should be in <$1>": "<$1>标签内不应有任何内容",
38
+ "obsolete attribute": "过时的属性",
39
+ "obsolete HTML tag": "过时的HTML标签",
35
40
  "quotes": "引号",
36
41
  "section header in a HTML tag": "HTML标签属性中的段落标题",
37
42
  "table": "表格",
38
43
  "tag that is both closing and self-closing": "同时闭合和自封闭的标签",
39
44
  "template in an internal link target": "内链目标包含模板",
40
- "unbalanced \"=\" in a section header": "段落标题中不平衡的\"=\"",
45
+ "unbalanced $1 in a section header": "段落标题中不平衡的$1",
41
46
  "unclosed $1": "未闭合的$1",
42
47
  "unclosed tag": "未闭合的标签",
43
48
  "unescaped query string in an anonymous parameter": "匿名参数中未转义的查询参数",
package/i18n/zh-hant.json CHANGED
@@ -4,6 +4,7 @@
4
4
  "additional \"|\" in a table cell": "表哥單元格中多餘的\"|\"",
5
5
  "additional \"|\" in the link text": "連結文本中多餘的\"|\"",
6
6
  "attributes of a closing tag": "位於閉合標籤的屬性",
7
+ "bold apostrophes": "粗體撇號",
7
8
  "conflicting image $1 parameter": "衝突的圖片$1參數",
8
9
  "containing invalid attribute": "包含無效屬性",
9
10
  "content to be moved out from the table": "將被移出表格的內容",
@@ -19,6 +20,7 @@
19
20
  "illegal attribute name": "非法的屬性名",
20
21
  "illegal module name": "非法的模組名稱",
21
22
  "insecure style": "不安全的樣式",
23
+ "internal link in an external link": "外部連結中的內部連結",
22
24
  "invalid content in <$1>": "<$1>內的無效內容",
23
25
  "invalid conversion flag": "無效的轉換標記",
24
26
  "invalid gallery image": "無效的圖庫圖片",
@@ -27,17 +29,20 @@
27
29
  "invalid parameter of $1": "$1的無效參數",
28
30
  "invalid self-closing tag": "無效自封閉標籤",
29
31
  "invisible content inside triple brackets": "三重括號內的不可見部分",
32
+ "italic apostrophes": "斜體撇號",
30
33
  "lonely \"$1\"": "孤立的\"$1\"",
31
34
  "missing module function": "缺少模組函式",
32
35
  "missing module name": "缺少模組名稱",
33
36
  "nonzero tabindex": "不為0的tabindex",
34
37
  "nothing should be in <$1>": "<$1>標籤內不應有任何內容",
38
+ "obsolete attribute": "過時的屬性",
39
+ "obsolete HTML tag": "過時的HTML標籤",
35
40
  "quotes": "引號",
36
41
  "section header in a HTML tag": "HTML標籤屬性中的段落標題",
37
42
  "table": "表格",
38
43
  "tag that is both closing and self-closing": "同時閉合和自封閉的標籤",
39
44
  "template in an internal link target": "內部連結目標包含模板",
40
- "unbalanced \"=\" in a section header": "段落標題中不平衡的\"=\"",
45
+ "unbalanced $1 in a section header": "段落標題中不平衡的$1",
41
46
  "unclosed $1": "未閉合的$1",
42
47
  "unclosed tag": "未閉合的標籤",
43
48
  "unescaped query string in an anonymous parameter": "匿名參數中未轉義的查詢參數",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wikilint",
3
- "version": "2.3.8",
3
+ "version": "2.3.9",
4
4
  "description": "A Node.js linter for MediaWiki markup",
5
5
  "keywords": [
6
6
  "mediawiki",