wikilint 2.40.0 → 2.42.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 CHANGED
@@ -5,8 +5,8 @@
5
5
  [![npm version](https://badge.fury.io/js/wikilint.svg)](https://www.npmjs.com/package/wikilint)
6
6
  [![CodeQL](https://github.com/bhsd-harry/wikiparser-node/actions/workflows/codeql.yml/badge.svg)](https://github.com/bhsd-harry/wikiparser-node/actions/workflows/codeql.yml)
7
7
  [![CI](https://github.com/bhsd-harry/wikiparser-node/actions/workflows/node.js.yml/badge.svg)](https://github.com/bhsd-harry/wikiparser-node/actions/workflows/node.js.yml)
8
- [![Codacy Badge](https://app.codacy.com/project/badge/Grade/a2fbe7641031451baca2947ae6d7891f)](https://app.codacy.com/gh/bhsd-harry/wikiparser-node/dashboard)
9
- ![Istanbul coverage](./coverage/badge.svg)
8
+ [![NPM downloads](https://img.shields.io/npm/dm/wikilint)](https://www.npmjs.com/package/wikilint)
9
+ ![Coverage](./coverage/badge.svg)
10
10
 
11
11
  This is a minimal version of [WikiParser-Node](https://www.npmjs.com/package/wikiparser-node). The [Wikitext LSP](https://www.npmjs.com/package/wikitext-lsp) and the [WikiParser Language Server](https://marketplace.visualstudio.com/items?itemName=Bhsd.vscode-extension-wikiparser) VS Code extension is written based on this package.
12
12
 
@@ -242,6 +242,11 @@
242
242
  "description": "base URL of internal links",
243
243
  "type": "string",
244
244
  "pattern": "\\$1"
245
+ },
246
+ "server": {
247
+ "description": "base URL of the server",
248
+ "type": "string",
249
+ "pattern": "^(?:https?:)?//"
245
250
  }
246
251
  },
247
252
  "required": [
@@ -1465,7 +1465,7 @@
1465
1465
  "EXPECTUNUSEDTEMPLATE": "EXPECTUNUSEDTEMPLATE"
1466
1466
  }
1467
1467
  ],
1468
- "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|wikipedia://|worldwind://|xmpp:",
1468
+ "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|wikipedia://|worldwind://|xmpp:|commonsfinder://",
1469
1469
  "interwiki": [],
1470
1470
  "img": {
1471
1471
  "thumbnail": "thumbnail",
@@ -591,7 +591,7 @@
591
591
  "EXPECTED_UNCONNECTED_PAGE": "EXPECTEDUNCONNECTEDPAGE"
592
592
  }
593
593
  ],
594
- "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|wikipedia://|worldwind://|xmpp:",
594
+ "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|wikipedia://|worldwind://|xmpp:|commonsfinder://",
595
595
  "interwiki": [],
596
596
  "img": {
597
597
  "alt=$1": "alt",
@@ -632,5 +632,6 @@
632
632
  "#redirect"
633
633
  ],
634
634
  "variants": [],
635
- "articlePath": "/wiki/$1"
635
+ "articlePath": "/wiki/$1",
636
+ "server": "//en.wikipedia.org"
636
637
  }
@@ -899,7 +899,7 @@
899
899
  "EXPECTED_UNCONNECTED_PAGE": "EXPECTEDUNCONNECTEDPAGE"
900
900
  }
901
901
  ],
902
- "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|wikipedia://|worldwind://|xmpp:",
902
+ "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|wikipedia://|worldwind://|xmpp:|commonsfinder://",
903
903
  "interwiki": [],
904
904
  "img": {
905
905
  "代替文=$1": "alt",
@@ -915,12 +915,14 @@
915
915
  "中央": "center",
916
916
  "center": "center",
917
917
  "centre": "center",
918
+ "class=$1": "class",
918
919
  "フレーム": "framed",
919
920
  "frame": "framed",
920
921
  "framed": "framed",
921
922
  "enframed": "framed",
922
923
  "フレームなし": "frameless",
923
924
  "frameless": "frameless",
925
+ "lang=$1": "lang",
924
926
  "左": "left",
925
927
  "left": "left",
926
928
  "リンク=$1": "link",
@@ -959,9 +961,7 @@
959
961
  "upright=$1": "upright",
960
962
  "upright $1": "upright",
961
963
  "$1ピクセル": "width",
962
- "$1px": "width",
963
- "class=$1": "class",
964
- "lang=$1": "lang"
964
+ "$1px": "width"
965
965
  },
966
966
  "redirection": [
967
967
  "#転送",
@@ -971,5 +971,6 @@
971
971
  "#redirect"
972
972
  ],
973
973
  "variants": [],
974
- "articlePath": "/wiki/$1"
974
+ "articlePath": "/wiki/$1",
975
+ "server": "//ja.wikipedia.org"
975
976
  }
@@ -1011,5 +1011,6 @@
1011
1011
  "zh-sg",
1012
1012
  "zh-tw"
1013
1013
  ],
1014
- "articlePath": "/zh/$1"
1014
+ "articlePath": "/zh/$1",
1015
+ "server": "//llwiki.org"
1015
1016
  }
@@ -125,7 +125,7 @@
125
125
  {},
126
126
  {}
127
127
  ],
128
- "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|wikipedia://|worldwind://|xmpp:",
128
+ "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|wikipedia://|worldwind://|xmpp:|commonsfinder://",
129
129
  "interwiki": [],
130
130
  "img": {},
131
131
  "redirection": [
@@ -997,5 +997,6 @@
997
997
  "zh-hk",
998
998
  "zh-tw"
999
999
  ],
1000
- "articlePath": "/$1"
1000
+ "articlePath": "/$1",
1001
+ "server": "https://zh.moegirl.org.cn"
1001
1002
  }
@@ -961,7 +961,7 @@
961
961
  "EXPECTED_UNCONNECTED_PAGE": "EXPECTEDUNCONNECTEDPAGE"
962
962
  }
963
963
  ],
964
- "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|wikipedia://|worldwind://|xmpp:",
964
+ "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|wikipedia://|worldwind://|xmpp:|commonsfinder://",
965
965
  "interwiki": [],
966
966
  "img": {
967
967
  "alt=$1": "alt",
@@ -1060,5 +1060,6 @@
1060
1060
  "zh-sg",
1061
1061
  "zh-tw"
1062
1062
  ],
1063
- "articlePath": "/wiki/$1"
1063
+ "articlePath": "/wiki/$1",
1064
+ "server": "//zh.wikipedia.org"
1064
1065
  }
package/dist/base.d.mts CHANGED
@@ -9,7 +9,6 @@ export interface Config {
9
9
  readonly parserFunction: [Record<string, string>, Record<string, string>, string[], string[]];
10
10
  readonly doubleUnderscore: [string[], string[], Record<string, string>, Record<string, string>];
11
11
  readonly protocol: string;
12
- readonly interwiki: string[];
13
12
  readonly img: Record<string, string>;
14
13
  readonly redirection: string[];
15
14
  readonly variants: string[];
@@ -267,8 +266,9 @@ export interface LanguageService {
267
266
  [Symbol.dispose](): void;
268
267
  }
269
268
  export type SeverityLevel = 0 | 1 | 2 | false | 'off' | 'warning' | 'error';
270
- export type LintConfigValue = SeverityLevel | [SeverityLevel, Record<string, SeverityLevel>?];
271
- export type LintRuleConfig = Partial<Record<LintError.Rule, LintConfigValue>>;
269
+ export type FullLintConfigValue = [SeverityLevel, Record<string, SeverityLevel>?];
270
+ export type LintConfigValue = SeverityLevel | FullLintConfigValue | Record<string, SeverityLevel>;
271
+ export type LintRuleConfig<T = LintConfigValue> = Partial<Record<LintError.Rule, T>>;
272
272
  export interface FullLintConfig {
273
273
  rules: LintRuleConfig;
274
274
  configurationComment?: string;
package/dist/base.d.ts CHANGED
@@ -9,7 +9,6 @@ export interface Config {
9
9
  readonly parserFunction: [Record<string, string>, Record<string, string>, string[], string[]];
10
10
  readonly doubleUnderscore: [string[], string[], Record<string, string>, Record<string, string>];
11
11
  readonly protocol: string;
12
- readonly interwiki: string[];
13
12
  readonly img: Record<string, string>;
14
13
  readonly redirection: string[];
15
14
  readonly variants: string[];
@@ -267,8 +266,9 @@ export interface LanguageService {
267
266
  [Symbol.dispose](): void;
268
267
  }
269
268
  export type SeverityLevel = 0 | 1 | 2 | false | 'off' | 'warning' | 'error';
270
- export type LintConfigValue = SeverityLevel | [SeverityLevel, Record<string, SeverityLevel>?];
271
- export type LintRuleConfig = Partial<Record<LintError.Rule, LintConfigValue>>;
269
+ export type FullLintConfigValue = [SeverityLevel, Record<string, SeverityLevel>?];
270
+ export type LintConfigValue = SeverityLevel | FullLintConfigValue | Record<string, SeverityLevel>;
271
+ export type LintRuleConfig<T = LintConfigValue> = Partial<Record<LintError.Rule, T>>;
272
272
  export interface FullLintConfig {
273
273
  rules: LintRuleConfig;
274
274
  configurationComment?: string;
package/dist/bin/cli.js CHANGED
@@ -148,7 +148,7 @@ const plural = (n, word) => `${n} ${word}${n === 1 ? '' : 's'}`;
148
148
  */
149
149
  const styleText = (format, text) => {
150
150
  if (!colors) {
151
- format = (Array.isArray(format) ? format : [format]).filter(f => !colorSet.has(f));
151
+ format = (Array.isArray(format) ? format : [format]).filter((f) => !colorSet.has(f));
152
152
  }
153
153
  return util_1.default.styleText(format, text);
154
154
  };
@@ -40,7 +40,7 @@ const filterGadget = (id) => {
40
40
  const n = Number(id);
41
41
  return n < 2300 || n > 2303; // Gadget, Gadget talk, Gadget definition, Gadget definition talk
42
42
  };
43
- const pkg = "wikilint", version = "2.40.0";
43
+ const pkg = "wikilint", version = "2.42.0";
44
44
  /**
45
45
  * Get the parser configuration for a Wikimedia Foundation project.
46
46
  * @param site site nickname
@@ -78,13 +78,7 @@ exports.default = async (site, url, user, force, internal) => {
78
78
  'User-Agent': `${pkg}/${version} (https://www.npmjs.com/package/${pkg}; ${user}) Node.js/${process.version}`,
79
79
  },
80
80
  }
81
- : undefined, m = await (await fetch(`${url}/load.php?modules=ext.CodeMirror.data|ext.CodeMirror`, headers)).text(), params = {
82
- action: 'query',
83
- meta: 'siteinfo',
84
- siprop: 'general|magicwords|functionhooks|namespaces|namespacealiases',
85
- format: 'json',
86
- formatversion: '2',
87
- }, { general: { articlepath, variants, langconversion }, magicwords, namespaces, namespacealiases, functionhooks, } = (await (await fetch(`${url}/api.php?${new URLSearchParams(params).toString()}`, headers)).json()).query, tempFile = path_1.default.join(__dirname, 'mw.js');
81
+ : undefined, m = await (await fetch(`${url}/load.php?modules=ext.CodeMirror.data|ext.CodeMirror`, headers)).text(), tempFile = path_1.default.join(__dirname, 'mw.js');
88
82
  fs_1.default.writeFileSync(tempFile, m);
89
83
  const { stdout, stderr } = (0, child_process_1.spawnSync)(process.execPath, [
90
84
  '-r',
@@ -108,13 +102,19 @@ exports.default = async (site, url, user, force, internal) => {
108
102
  catch {
109
103
  throw new RangeError('Extension:CodeMirror is not installed!');
110
104
  }
111
- const ns = Object.entries(namespaces).filter(([id]) => filterGadget(id))
105
+ const params = {
106
+ action: 'query',
107
+ meta: 'siteinfo',
108
+ siprop: `general|magicwords|namespaces|namespacealiases${mwConfig.functionHooks ? '' : '|functionhooks'}`,
109
+ format: 'json',
110
+ formatversion: '2',
111
+ }, { general: { articlepath, server, variants, langconversion }, magicwords, namespaces, namespacealiases, functionhooks, } = (await (await fetch(`${url}/api.php?${new URLSearchParams(params).toString()}`, headers)).json()).query, ns = Object.entries(namespaces).filter(([id]) => filterGadget(id))
112
112
  .flatMap(([id, { name, canonical = '' }]) => [
113
113
  [id, name],
114
114
  ...name === canonical ? [] : [[id, canonical]],
115
115
  ]), config = {
116
116
  ...(0, cm_util_1.getParserConfig)(require(path_1.default.join(dir, 'minimum.json')), mwConfig),
117
- ...(0, cm_util_1.getKeywords)(magicwords),
117
+ ...!(mwConfig.imageKeywords && mwConfig.redirection) && (0, cm_util_1.getKeywords)(magicwords),
118
118
  variants: langconversion ? (0, cm_util_1.getVariants)(variants) : [],
119
119
  namespaces: Object.fromEntries(ns),
120
120
  nsid: Object.fromEntries([
@@ -122,6 +122,7 @@ exports.default = async (site, url, user, force, internal) => {
122
122
  ...namespacealiases.filter(({ id }) => filterGadget(id)).map(({ id, alias }) => [alias.toLowerCase(), id]),
123
123
  ]),
124
124
  articlePath: articlepath,
125
+ server,
125
126
  }, { doubleUnderscore, parserFunction, variable } = config;
126
127
  doubleUnderscore[0] = [];
127
128
  doubleUnderscore[1] = [];
@@ -33,13 +33,6 @@ export declare abstract class AstElement extends AstNode {
33
33
  * @param i position to be inserted at / 插入位置
34
34
  */
35
35
  insertAt<T extends AstNodes>(node: T, i?: number): T;
36
- /**
37
- * Get the closest ancestor node that matches the selector
38
- *
39
- * 最近的符合选择器的祖先节点
40
- * @param selector selector / 选择器
41
- */
42
- closest<T = Token>(selector: string): T | undefined;
43
36
  /**
44
37
  * Insert a batch of child nodes at the end
45
38
  *
@@ -37,7 +37,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
37
37
  exports.AstElement = void 0;
38
38
  const string_1 = require("../util/string");
39
39
  const debug_1 = require("../util/debug");
40
- const selector_1 = require("../util/selector");
41
40
  const node_1 = require("./node");
42
41
  const elementLike_1 = require("../mixin/elementLike");
43
42
  /**
@@ -88,23 +87,6 @@ let AstElement = (() => {
88
87
  (0, debug_1.setChildNodes)(this, i, 0, [node]);
89
88
  return node;
90
89
  }
91
- /**
92
- * Get the closest ancestor node that matches the selector
93
- *
94
- * 最近的符合选择器的祖先节点
95
- * @param selector selector / 选择器
96
- */
97
- closest(selector) {
98
- const condition = (0, selector_1.getCondition)(selector, this);
99
- let { parentNode } = this;
100
- while (parentNode) {
101
- if (condition(parentNode)) {
102
- return parentNode;
103
- }
104
- ({ parentNode } = parentNode);
105
- }
106
- return undefined;
107
- }
108
90
  /** @private */
109
91
  isInside(type) {
110
92
  return this.closest(`${type},ext`)?.type === type;
@@ -12,8 +12,8 @@ const dict = new Map([
12
12
  ['error', 'error'],
13
13
  ]);
14
14
  const defaultLintRuleConfig = {
15
- 'arg-in-ext': 1,
16
- 'blank-alt': 1,
15
+ 'arg-in-ext': [1],
16
+ 'blank-alt': [1],
17
17
  'bold-header': [
18
18
  1,
19
19
  {
@@ -47,7 +47,7 @@ const defaultLintRuleConfig = {
47
47
  // value: 2,
48
48
  },
49
49
  ],
50
- 'insecure-style': 2,
50
+ 'insecure-style': [2],
51
51
  'invalid-gallery': [
52
52
  2,
53
53
  {
@@ -72,14 +72,14 @@ const defaultLintRuleConfig = {
72
72
  // name: 2,
73
73
  },
74
74
  ],
75
- 'invalid-isbn': 2,
75
+ 'invalid-isbn': [2],
76
76
  'invalid-json': [
77
77
  2,
78
78
  {
79
79
  duplicate: 1,
80
80
  },
81
81
  ],
82
- 'invalid-url': 1,
82
+ 'invalid-url': [1],
83
83
  'lonely-apos': [
84
84
  1,
85
85
  {
@@ -110,7 +110,7 @@ const defaultLintRuleConfig = {
110
110
  // ref: 2,
111
111
  },
112
112
  ],
113
- 'no-arg': 1,
113
+ 'no-arg': [1],
114
114
  'no-duplicate': [
115
115
  2,
116
116
  {
@@ -144,8 +144,8 @@ const defaultLintRuleConfig = {
144
144
  // references: 2,
145
145
  },
146
146
  ],
147
- 'obsolete-attr': 1,
148
- 'obsolete-tag': 1,
147
+ 'obsolete-attr': [1],
148
+ 'obsolete-tag': [1],
149
149
  'parsing-order': [
150
150
  2,
151
151
  {
@@ -182,7 +182,7 @@ const defaultLintRuleConfig = {
182
182
  // redirect: 2,
183
183
  },
184
184
  ],
185
- 'table-layout': 1,
185
+ 'table-layout': [1],
186
186
  'tag-like': [
187
187
  2,
188
188
  {
@@ -190,17 +190,17 @@ const defaultLintRuleConfig = {
190
190
  invalid: 1,
191
191
  },
192
192
  ],
193
- 'unbalanced-header': 2,
193
+ 'unbalanced-header': [2],
194
194
  'unclosed-comment': [
195
195
  1,
196
196
  {
197
197
  // include: 1,
198
198
  },
199
199
  ],
200
- 'unclosed-quote': 1,
201
- 'unclosed-table': 2,
202
- unescaped: 2,
203
- 'unknown-page': 1,
200
+ 'unclosed-quote': [1],
201
+ 'unclosed-table': [2],
202
+ unescaped: [2],
203
+ 'unknown-page': [1],
204
204
  'unmatched-tag': [
205
205
  1,
206
206
  {
@@ -247,7 +247,7 @@ const defaultLintRuleConfig = {
247
247
  warn: 1,
248
248
  },
249
249
  ],
250
- 'invalid-math': 2,
250
+ 'invalid-math': [2],
251
251
  };
252
252
  const defaultLintConfig = {
253
253
  configurationComment: 'lint',
@@ -264,8 +264,9 @@ const validateSeverity = (severity) => dict.has(severity);
264
264
  * 验证设置值是否符合规范
265
265
  * @param value 设置值
266
266
  */
267
- const validateConfigValue = (value) => validateSeverity(value)
268
- || Array.isArray(value) && validateSeverity(value[0]) && (value.length === 1 || typeof value[1] === 'object');
267
+ const validateConfigValue = (value) => validateSeverity(value) || (Array.isArray(value)
268
+ ? validateSeverity(value[0]) && (value.length === 1 || typeof value[1] === 'object')
269
+ : typeof value === 'object');
269
270
  /**
270
271
  * 设置语法检查规则
271
272
  * @param obj 语法检查设置对象
@@ -282,7 +283,16 @@ const set = (obj, key, value) => {
282
283
  return false;
283
284
  }
284
285
  if (validateConfigValue(value)) {
285
- obj[key] = value;
286
+ if (Array.isArray(value)) {
287
+ obj[key] = value;
288
+ }
289
+ else if (typeof value === 'object') {
290
+ const [base, options = {}] = defaultLintRuleConfig[key];
291
+ obj[key] = [base, { ...clone(options), ...value }];
292
+ }
293
+ else {
294
+ obj[key] = [value];
295
+ }
286
296
  return true;
287
297
  }
288
298
  /* c8 ignore next */
@@ -305,11 +315,8 @@ class LintRuleConfiguration {
305
315
  }
306
316
  /** @implements */
307
317
  getSeverity(rule, key) {
308
- const value = this[rule];
309
- if (typeof value !== 'object') {
310
- return dict.get(value);
311
- }
312
- return key ? dict.get(value[1]?.[key]) ?? dict.get(value[0]) : dict.get(value[0]);
318
+ const [base, options] = this[rule], severity = dict.get(base);
319
+ return key ? dict.get(options?.[key]) ?? severity : severity;
313
320
  }
314
321
  }
315
322
  /** 语法检查设置 */
package/dist/lib/lsp.d.ts CHANGED
@@ -3,6 +3,7 @@ import { Token } from '../src/index';
3
3
  import type { Range, Position, ColorInformation, ColorPresentation, FoldingRange, DocumentLink, Location, WorkspaceEdit, Diagnostic as DiagnosticBase, TextEdit, Hover, SignatureHelp, InlayHint, CodeAction, DocumentSymbol } from 'vscode-languageserver-types';
4
4
  import type { Config, LanguageService as LanguageServiceBase, CompletionItem, SignatureData } from '../base';
5
5
  import type { AttributeToken } from '../internal';
6
+ import type { TokenTypeMap, SelectedTokenTypes } from '../map';
6
7
  export interface QuickFixData extends TextEdit {
7
8
  title: string;
8
9
  fix: boolean;
@@ -128,6 +129,7 @@ export declare class LanguageService implements LanguageServiceBase {
128
129
  * @since v1.16.3
129
130
  */
130
131
  provideInlayHints(text: string): Promise<InlayHint[]>;
132
+ querySelectorAll<T = Token>(selector: string): T[];
131
133
  /**
132
134
  * Provide refactoring actions
133
135
  *
package/dist/lib/lsp.js CHANGED
@@ -157,15 +157,6 @@ const getRefName = (token) => getRefAttr(token, refTags, nameAttrs);
157
157
  * @param token `group` attribute token
158
158
  */
159
159
  const getRefGroup = (token) => getRefAttr(token, referencesTags, groupAttrs);
160
- /**
161
- * Get the attribute of a `<ref>` tag.
162
- * @param token extension token
163
- * @param target attribute name
164
- */
165
- const getRefTagAttr = (token, target) => {
166
- const attr = token?.getAttr(target);
167
- return attr !== true && attr || false;
168
- };
169
160
  /**
170
161
  * Get the effective name of a token.
171
162
  * @param token
@@ -673,8 +664,7 @@ class LanguageService {
673
664
  }),
674
665
  ...match.startsWith('#')
675
666
  ? []
676
- : getCompletion(root.querySelectorAll('template').filter(token => token !== cur)
677
- .map(token => {
667
+ : getCompletion(root.querySelectorAll('template').filter(token => token !== cur).map(token => {
678
668
  const { name } = token;
679
669
  if (colon) {
680
670
  return name;
@@ -1164,8 +1154,7 @@ class LanguageService {
1164
1154
  * @param position position / 位置
1165
1155
  */
1166
1156
  async provideReferences(text, position) {
1167
- const root = await this.#queue(text), { offsetNode, offset } = caretPositionFromWord(root, this.#text, position), element = offsetNode.type === 'text' ? offsetNode.parentNode : offsetNode, node = offset === 0
1168
- && (element.is('ext-attr-dirty') || element.is('html-attr-dirty'))
1157
+ const root = await this.#queue(text), { offsetNode, offset } = caretPositionFromWord(root, this.#text, position), element = offsetNode.type === 'text' ? offsetNode.parentNode : offsetNode, node = offset === 0 && (element.is('ext-attr-dirty') || element.is('html-attr-dirty'))
1169
1158
  ? element.parentNode.parentNode
1170
1159
  : element, { type } = node, refName = getRefName(node), refGroup = getRefGroup(node);
1171
1160
  if (!refName && !refGroup && !referenceTypes.has(type)) {
@@ -1192,13 +1181,13 @@ class LanguageService {
1192
1181
  }
1193
1182
  const ext = node.is('ext') && node.name === 'ref'
1194
1183
  ? node
1195
- : node.closest('ext#ref'), refName = getRefTagAttr(ext, 'name');
1184
+ : node.closest('ext#ref'), refName = ext?.getAttr('name');
1196
1185
  if (!refName) {
1197
1186
  return undefined;
1198
1187
  }
1199
- const refGroup = getRefTagAttr(ext, 'group'), refs = root.querySelectorAll('ext#ref').filter(token => token.innerText
1200
- && getRefTagAttr(token, 'name') === refName
1201
- && getRefTagAttr(token, 'group') === refGroup).reverse().map(({ lastChild }) => ({
1188
+ const refGroup = ext.getAttr('group'), refs = root.querySelectorAll('ext#ref').filter(token => token.innerText
1189
+ && token.getAttr('name') === refName
1190
+ && token.getAttr('group') === refGroup).reverse().map(({ lastChild }) => ({
1202
1191
  range: createNodeRange(lastChild),
1203
1192
  }));
1204
1193
  return refs.length === 0 ? undefined : refs;
@@ -1235,7 +1224,7 @@ class LanguageService {
1235
1224
  if (!node) {
1236
1225
  return undefined;
1237
1226
  }
1238
- const { type } = node, refName = getRefName(node), refNameGroup = refName && getRefTagAttr(node.parentNode.parentNode, 'group'), refGroup = getRefGroup(node), name = getName(node), refs = root.querySelectorAll(type).filter(token => {
1227
+ const { type } = node, refName = getRefName(node), refNameGroup = refName && node.parentNode.parentNode.getAttr('group'), refGroup = getRefGroup(node), name = getName(node), refs = root.querySelectorAll(type).filter(token => {
1239
1228
  const { type: t } = token.parentNode;
1240
1229
  if (type === 'link-target' && t !== 'link' && t !== 'redirect-target') {
1241
1230
  return false;
@@ -1243,7 +1232,7 @@ class LanguageService {
1243
1232
  return type === 'attr-value'
1244
1233
  ? getRefGroup(token) === refGroup
1245
1234
  || getRefName(token) === refName
1246
- && getRefTagAttr(token.parentNode.parentNode, 'group') === refNameGroup
1235
+ && token.parentNode.parentNode.getAttr('group') === refNameGroup
1247
1236
  : getName(token) === name;
1248
1237
  });
1249
1238
  return refs.length === 0
@@ -1443,7 +1432,6 @@ class LanguageService {
1443
1432
  }
1444
1433
  return hints;
1445
1434
  }
1446
- /** @private */
1447
1435
  querySelectorAll(selector) {
1448
1436
  return this.#done.querySelectorAll(selector);
1449
1437
  }
@@ -1,6 +1,7 @@
1
1
  import type { AstNode as AstNodeBase, TokenTypes, LintError } from '../base';
2
2
  import type { NodeLike } from '../mixin/nodeLike';
3
3
  import type { AstText, Token } from '../internal';
4
+ import type { TokenTypeMap, SelectedTokenTypes } from '../map';
4
5
  export type AstNodes = AstText | Token;
5
6
  export interface Dimension {
6
7
  readonly height: number;
@@ -93,6 +94,7 @@ export declare abstract class AstNode implements AstNodeBase {
93
94
  * @param type token type / 节点类型
94
95
  * @since v1.10.0
95
96
  */
97
+ is<K extends SelectedTokenTypes>(type: K): this is TokenTypeMap[K];
96
98
  is<T extends Token>(type: TokenTypes): this is T;
97
99
  /**
98
100
  * Get the text and the start/end positions of all lines
package/dist/lib/node.js CHANGED
@@ -238,13 +238,6 @@ let AstNode = (() => {
238
238
  ...this.getRootNode().posFromIndex(this.getAbsoluteIndex()),
239
239
  };
240
240
  }
241
- /**
242
- * Whether to be of a certain type
243
- *
244
- * 是否是某种类型的节点
245
- * @param type token type / 节点类型
246
- * @since v1.10.0
247
- */
248
241
  is(type) {
249
242
  return this.type === type;
250
243
  }
package/dist/lib/text.js CHANGED
@@ -104,7 +104,7 @@ class AstText extends node_1.AstNode {
104
104
  return [];
105
105
  }
106
106
  errorRegex.lastIndex = 0;
107
- const errors = [], nextType = nextSibling?.type, nextName = nextSibling?.name, previousType = previousSibling?.type, root = this.getRootNode(), rootStr = root.toString(), { ext, html, variants } = root.getAttribute('config'), { top, left } = root.posFromIndex(start), { lintConfig } = index_1.default, tagLike = lintConfig.rules['tag-like'], specified = typeof tagLike === 'object' && tagLike[1]
107
+ const errors = [], nextType = nextSibling?.type, nextName = nextSibling?.name, previousType = previousSibling?.type, root = this.getRootNode(), rootStr = root.toString(), { ext, html, variants } = root.getAttribute('config'), { top, left } = root.posFromIndex(start), { lintConfig } = index_1.default, tagLike = lintConfig.rules['tag-like'], specified = tagLike[1]
108
108
  ? new Set(Object.keys(tagLike[1]).filter(tag => tag !== 'invalid' && tag !== 'disallowed'))
109
109
  : new Set(), tags = new Set([
110
110
  'onlyinclude',
@@ -144,8 +144,7 @@ class AstText extends node_1.AstNode {
144
144
  // Rule & Severity
145
145
  let startIndex = start + index, endIndex = startIndex + length, rule, severity, endLine, endCol;
146
146
  const nextChar = rootStr[endIndex], previousChar = rootStr[startIndex - 1], leftBracket = lbrace || lbrack, lConverter = error === '{' && previousChar === '-' && variants.length > 0, rConverter = error === '}' && nextChar === '-' && variants.length > 0, brokenExtLink = lbrack && nextType === 'free-ext-link' && !data.slice(index + 1).trim()
147
- || rbrack && previousType === 'free-ext-link'
148
- && !data.slice(0, index).includes(']');
147
+ || rbrack && previousType === 'free-ext-link' && index === 0;
149
148
  if (magicLink) {
150
149
  rule = 'lonely-http';
151
150
  error = error.toUpperCase();
package/dist/map.d.ts ADDED
@@ -0,0 +1,65 @@
1
+ import type { RedirectToken, RedirectTargetToken, OnlyincludeToken, IncludeToken, CommentToken, ExtToken, AttributesToken, AttributeToken, AtomToken, ArgToken, TranscludeToken, SyntaxToken, ParameterToken, HeadingToken, HtmlToken, TableToken, TrToken, TdToken, DoubleUnderscoreToken, HrToken, LinkToken, CategoryToken, FileToken, ImageParameterToken, QuoteToken, ExtLinkToken, MagicLinkToken, ListToken, DdToken, ConverterToken, ConverterFlagsToken, ConverterRuleToken, TranslateToken, TvarToken, HiddenToken, GalleryImageToken, ParamLineToken, ImagemapLinkToken } from './internal';
2
+ export interface TokenTypeMap {
3
+ redirect: RedirectToken;
4
+ 'redirect-syntax': SyntaxToken;
5
+ 'redirect-target': RedirectTargetToken;
6
+ translate: TranslateToken;
7
+ 'translate-attr': SyntaxToken;
8
+ tvar: TvarToken;
9
+ 'tvar-name': SyntaxToken;
10
+ onlyinclude: OnlyincludeToken;
11
+ include: IncludeToken;
12
+ comment: CommentToken;
13
+ ext: ExtToken;
14
+ 'ext-attrs': AttributesToken;
15
+ 'ext-attr-dirty': AtomToken;
16
+ 'ext-attr': AttributeToken;
17
+ 'attr-key': AtomToken;
18
+ arg: ArgToken;
19
+ 'arg-name': AtomToken;
20
+ hidden: HiddenToken;
21
+ 'magic-word': TranscludeToken;
22
+ 'magic-word-name': SyntaxToken;
23
+ 'invoke-function': AtomToken;
24
+ 'invoke-module': AtomToken;
25
+ template: TranscludeToken;
26
+ 'template-name': AtomToken;
27
+ parameter: ParameterToken;
28
+ heading: HeadingToken;
29
+ 'heading-trail': SyntaxToken;
30
+ html: HtmlToken;
31
+ 'html-attrs': AttributesToken;
32
+ 'html-attr-dirty': AtomToken;
33
+ 'html-attr': AttributeToken;
34
+ table: TableToken;
35
+ tr: TrToken;
36
+ td: TdToken;
37
+ 'table-syntax': SyntaxToken;
38
+ 'table-attrs': AttributesToken;
39
+ 'table-attr-dirty': AtomToken;
40
+ 'table-attr': AttributeToken;
41
+ hr: HrToken;
42
+ 'double-underscore': DoubleUnderscoreToken;
43
+ link: LinkToken;
44
+ 'link-target': AtomToken;
45
+ category: CategoryToken;
46
+ file: FileToken;
47
+ 'gallery-image': GalleryImageToken;
48
+ 'imagemap-image': GalleryImageToken;
49
+ 'image-parameter': ImageParameterToken;
50
+ quote: QuoteToken;
51
+ 'ext-link': ExtLinkToken;
52
+ 'ext-link-url': MagicLinkToken;
53
+ 'free-ext-link': MagicLinkToken;
54
+ 'magic-link': MagicLinkToken;
55
+ list: ListToken;
56
+ dd: DdToken;
57
+ converter: ConverterToken;
58
+ 'converter-flags': ConverterFlagsToken;
59
+ 'converter-flag': AtomToken;
60
+ 'converter-rule': ConverterRuleToken;
61
+ 'converter-rule-variant': AtomToken;
62
+ 'param-line': ParamLineToken;
63
+ 'imagemap-link': ImagemapLinkToken;
64
+ }
65
+ export type SelectedTokenTypes = keyof TokenTypeMap;
package/dist/map.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -12,7 +12,7 @@ export interface AttributesParentBase {
12
12
  * 获取指定属性
13
13
  * @param key attribute name / 属性键
14
14
  */
15
- getAttr(key: string): string | true | undefined;
15
+ getAttr(key: string): string | undefined;
16
16
  }
17
17
  /**
18
18
  * 子节点含有AttributesToken的类
@@ -1,14 +1,25 @@
1
1
  import type { AstNodes, Token } from '../internal';
2
+ import type { TokenTypeMap, SelectedTokenTypes } from '../map';
2
3
  declare type ElementConstructor = abstract new (...args: any[]) => {
4
+ readonly parentNode: Token | undefined;
3
5
  readonly childNodes: readonly AstNodes[];
4
6
  };
5
7
  export interface ElementLike {
8
+ /**
9
+ * Get the closest ancestor node that matches the selector
10
+ *
11
+ * 最近的符合选择器的祖先节点
12
+ * @param selector selector / 选择器
13
+ */
14
+ closest<K extends SelectedTokenTypes>(selector: K): TokenTypeMap[K] | undefined;
15
+ closest<T = Token>(selector: string): T | undefined;
6
16
  /**
7
17
  * Get the first descendant that matches the selector
8
18
  *
9
19
  * 符合选择器的第一个后代节点
10
20
  * @param selector selector / 选择器
11
21
  */
22
+ querySelector<K extends SelectedTokenTypes>(selector: K): TokenTypeMap[K] | undefined;
12
23
  querySelector<T = Token>(selector: string): T | undefined;
13
24
  /**
14
25
  * Get all descendants that match the selector
@@ -16,6 +27,7 @@ export interface ElementLike {
16
27
  * 符合选择器的所有后代节点
17
28
  * @param selector selector / 选择器
18
29
  */
30
+ querySelectorAll<K extends SelectedTokenTypes>(selector: K): TokenTypeMap[K][];
19
31
  querySelectorAll<T = Token>(selector: string): T[];
20
32
  /**
21
33
  * Escape `=` and `|`
@@ -5,12 +5,23 @@ const debug_1 = require("../util/debug");
5
5
  const selector_1 = require("../util/selector");
6
6
  /** @ignore */
7
7
  const elementLike = (constructor) => {
8
- LINT: {
9
- class ElementLike extends constructor {
10
- #getCondition(selector) {
11
- return (0, selector_1.getCondition)(selector, this);
8
+ class ElementLike extends constructor {
9
+ #getCondition(selector) {
10
+ return (0, selector_1.getCondition)(selector, this);
11
+ }
12
+ closest(selector) {
13
+ const condition = this.#getCondition(selector);
14
+ let { parentNode } = this;
15
+ while (parentNode) {
16
+ if (condition(parentNode)) {
17
+ return parentNode;
18
+ }
19
+ ({ parentNode } = parentNode);
12
20
  }
13
- getElementBy(condition) {
21
+ return undefined;
22
+ }
23
+ getElementBy(condition) {
24
+ LINT: {
14
25
  const stack = [...this.childNodes].reverse();
15
26
  while (stack.length > 0) {
16
27
  const child = stack.pop(), { type, childNodes } = child;
@@ -26,10 +37,12 @@ const elementLike = (constructor) => {
26
37
  }
27
38
  return undefined;
28
39
  }
29
- querySelector(selector) {
30
- return this.getElementBy(this.#getCondition(selector));
31
- }
32
- getElementsBy(condition) {
40
+ }
41
+ querySelector(selector) {
42
+ LINT: return this.getElementBy(this.#getCondition(selector));
43
+ }
44
+ getElementsBy(condition) {
45
+ LINT: {
33
46
  const stack = [...this.childNodes].reverse(), descendants = [];
34
47
  while (stack.length > 0) {
35
48
  const child = stack.pop(), { type, childNodes } = child;
@@ -45,19 +58,19 @@ const elementLike = (constructor) => {
45
58
  }
46
59
  return descendants;
47
60
  }
48
- querySelectorAll(selector) {
49
- return this.getElementsBy(this.#getCondition(selector));
50
- }
51
- escape() {
52
- LSP: {
53
- for (const child of this.childNodes) {
54
- child.escape();
55
- }
61
+ }
62
+ querySelectorAll(selector) {
63
+ LINT: return this.getElementsBy(this.#getCondition(selector));
64
+ }
65
+ escape() {
66
+ LSP: {
67
+ for (const child of this.childNodes) {
68
+ child.escape();
56
69
  }
57
70
  }
58
71
  }
59
- (0, debug_1.mixin)(ElementLike, constructor);
60
- return ElementLike;
61
72
  }
73
+ (0, debug_1.mixin)(ElementLike, constructor);
74
+ return ElementLike;
62
75
  };
63
76
  exports.elementLike = elementLike;
@@ -40,5 +40,5 @@ export declare abstract class AttributeToken extends Token {
40
40
  *
41
41
  * 获取属性值
42
42
  */
43
- getValue(): string | true;
43
+ getValue(): string;
44
44
  }
@@ -151,14 +151,14 @@ class AttributeToken extends index_2.Token {
151
151
  }
152
152
  }
153
153
  }
154
- else if (name === 'style' && typeof value === 'string' && insecureStyle.test(value)) {
154
+ else if (name === 'style' && insecureStyle.test(value)) {
155
155
  LINT: {
156
156
  rule = 'insecure-style';
157
157
  const s = lintConfig.getSeverity(rule);
158
158
  return s && (0, lint_1.generateForChild)(lastChild, rect, rule, 'insecure-style', s);
159
159
  }
160
160
  }
161
- else if (name === 'tabindex' && typeof value === 'string' && value !== '0') {
161
+ else if (name === 'tabindex' && value !== '0') {
162
162
  LINT: {
163
163
  const s = lintConfig.getSeverity(rule, 'tabindex');
164
164
  if (s) {
@@ -173,18 +173,18 @@ class AttributeToken extends index_2.Token {
173
173
  }
174
174
  }
175
175
  }
176
- else if (typeof value === 'string' && ((/^xmlns:[\w:.-]+$/u.test(name) || urlAttrs.has(name)) && evil.test(value)
176
+ else if ((/^xmlns:[\w:.-]+$/u.test(name) || urlAttrs.has(name)) && evil.test(value)
177
177
  || simple
178
- && (name === 'href' || tag === 'img' && name === 'src')
178
+ && (name === 'href' || type === 'ext-attr' && tag === 'img' && name === 'src')
179
179
  && !new RegExp(String.raw `^(?:${this.getAttribute('config').protocol}|//)\S+$`, 'iu')
180
- .test(value))) {
180
+ .test(value)) {
181
181
  LINT: {
182
182
  const s = lintConfig.getSeverity(rule, 'value');
183
183
  return s && (0, lint_1.generateForChild)(lastChild, rect, rule, 'illegal-attribute-value', s);
184
184
  }
185
185
  }
186
186
  else if (simple && type !== 'ext-attr') {
187
- const data = (0, lint_1.provideValues)(tag, name), v = String(value).toLowerCase();
187
+ const data = (0, lint_1.provideValues)(tag, name), v = value.toLowerCase();
188
188
  if (data.length > 0 && data.every(n => n !== v)) {
189
189
  LINT: {
190
190
  const s = lintConfig.getSeverity(rule, 'value');
@@ -249,7 +249,7 @@ class AttributeToken extends index_2.Token {
249
249
  * 获取属性值
250
250
  */
251
251
  getValue() {
252
- return this.#equal ? this.lastChild.text().trim() : this.type === 'ext-attr' || '';
252
+ return this.#equal ? this.lastChild.text().replace(/[\t\r\n ]+/gu, ' ').trim() : '';
253
253
  }
254
254
  /** @private */
255
255
  escape() {
@@ -59,6 +59,6 @@ export declare abstract class AttributesToken extends Token {
59
59
  * 获取指定属性
60
60
  * @param key attribute name / 属性键
61
61
  */
62
- getAttr(key: string): string | true | undefined;
62
+ getAttr(key: string): string | undefined;
63
63
  }
64
64
  export {};
@@ -146,7 +146,7 @@ class AttributesToken extends index_2.Token {
146
146
  /** @private */
147
147
  lint(start = this.getAbsoluteIndex(), re) {
148
148
  LINT: {
149
- const errors = super.lint(start, re), { parentNode, childNodes, type, name: tag } = this, attrs = new Map(), duplicated = new Set(), rect = new rect_1.BoundingRect(this, start), rules = ['no-ignored', 'no-duplicate', 'required-attr'], { lintConfig } = index_1.default, { computeEditInfo, fix } = lintConfig, s = ['closingTag', 'invalidAttributes', 'nonWordAttributes']
149
+ const errors = super.lint(start, re), { parentNode, childNodes, type, name: tag } = this, attrs = new Map(), duplicated = new Set(), rect = new rect_1.BoundingRect(this, start), rules = ['no-ignored', 'required-attr', 'no-duplicate'], { lintConfig } = index_1.default, { computeEditInfo, fix } = lintConfig, s = ['closingTag', 'invalidAttributes', 'nonWordAttributes']
150
150
  .map(k => lintConfig.getSeverity(rules[0], k));
151
151
  if (s[0] && this.#lint()) {
152
152
  const e = (0, lint_1.generateForSelf)(this, rect, rules[0], 'attributes-of-closing-tag', s[0]);
@@ -182,28 +182,22 @@ class AttributesToken extends index_2.Token {
182
182
  }
183
183
  }
184
184
  if (type === 'ext-attrs' && required.has(tag)) {
185
- const severity = lintConfig.getSeverity(rules[2], tag);
185
+ const severity = lintConfig.getSeverity(rules[1], tag);
186
186
  if (severity) {
187
187
  for (const key of required.get(tag)) {
188
- const keys = typeof key === 'string' ? [key] : key, missing = keys.every(k => {
189
- const value = this.getAttr(k);
190
- return value === true || !value;
191
- });
192
- if (missing) {
193
- errors.push((0, lint_1.generateForSelf)(this, rect, rules[2], index_1.default.msg('required-attribute', keys.join('/')), severity));
188
+ const keys = typeof key === 'string' ? [key] : key;
189
+ if (!keys.some(k => this.getAttr(k))) {
190
+ errors.push((0, lint_1.generateForSelf)(this, rect, rules[1], index_1.default.msg('required-attribute', keys.join('/')), severity));
194
191
  }
195
192
  }
196
193
  }
197
194
  }
198
- const severity = lintConfig.getSeverity(rules[1], 'attribute');
195
+ const severity = lintConfig.getSeverity(rules[2], 'attribute');
199
196
  if (severity && duplicated.size > 0) {
200
197
  for (const key of duplicated) {
201
- const pairs = attrs.get(key).map(attr => {
202
- const value = attr.getValue();
203
- return [attr, value === true ? '' : value];
204
- });
198
+ const pairs = attrs.get(key).map(attr => [attr, attr.getValue()]);
205
199
  Array.prototype.push.apply(errors, pairs.map(([attr, value], i) => {
206
- const e = (0, lint_1.generateForChild)(attr, rect, rules[1], index_1.default.msg('duplicate-attribute', key), severity);
200
+ const e = (0, lint_1.generateForChild)(attr, rect, rules[2], index_1.default.msg('duplicate-attribute', key), severity);
207
201
  if (computeEditInfo || fix) {
208
202
  const remove = (0, lint_1.fixByRemove)(e);
209
203
  if (!value || pairs.slice(0, i).some(([, v]) => v === value)) {
package/dist/src/index.js CHANGED
@@ -372,9 +372,8 @@ class Token extends element_1.AstElement {
372
372
  }
373
373
  /** @private */
374
374
  inTableAttrs() {
375
- return this.isInside('table-attrs') && (this.closest('table-attrs,arg,parameter')?.is('table-attrs')
376
- ? 2
377
- : 1);
375
+ return this.isInside('table-attrs')
376
+ && (this.closest('table-attrs,arg,parameter')?.is('table-attrs') ? 2 : 1);
378
377
  }
379
378
  /** @private */
380
379
  inHtmlAttrs() {
@@ -395,7 +394,7 @@ class Token extends element_1.AstElement {
395
394
  }
396
395
  else {
397
396
  const value = cat.getValue();
398
- if (value && value !== true) {
397
+ if (value) {
399
398
  key = `#${value}`;
400
399
  }
401
400
  }
@@ -142,7 +142,7 @@ class MagicLinkToken extends index_2.Token {
142
142
  .getUrl(articlePath)
143
143
  : new URL(link.startsWith('RFC')
144
144
  ? `https://datatracker.ietf.org/doc/html/rfc${link.slice(4)}`
145
- : `https://pubmed.ncbi.nlm.nih.gov/${link.slice(5)}`);
145
+ : `https://www.ncbi.nlm.nih.gov/pubmed/${link.slice(5)}?dopt=Abstract`);
146
146
  }
147
147
  }
148
148
  }
@@ -44,7 +44,7 @@ const base_1 = require("./base");
44
44
  * 状态开关
45
45
  */
46
46
  let DoubleUnderscoreToken = (() => {
47
- let _classDecorators = [(0, hidden_1.hiddenToken)(), (0, padded_1.padded)('__')];
47
+ let _classDecorators = [(0, hidden_1.hiddenToken)(true, false), (0, padded_1.padded)('__')];
48
48
  let _classDescriptor;
49
49
  let _classExtraInitializers = [];
50
50
  let _classThis;
@@ -46,9 +46,7 @@ class QuoteToken extends base_1.NowikiBaseToken {
46
46
  /** @private */
47
47
  text() {
48
48
  const { parentNode, innerText } = this;
49
- return parentNode?.is('image-parameter') && parentNode.name !== 'caption'
50
- ? ''
51
- : innerText;
49
+ return parentNode?.is('image-parameter') && parentNode.name !== 'caption' ? '' : innerText;
52
50
  }
53
51
  /** @private */
54
52
  lint(start = this.getAbsoluteIndex()) {
@@ -7,7 +7,7 @@ export interface TdSpanAttrs {
7
7
  rowspan?: number;
8
8
  colspan?: number;
9
9
  }
10
- declare type TdAttrGetter<T extends string> = T extends keyof TdSpanAttrs ? number : string | true | undefined;
10
+ declare type TdAttrGetter<T extends string> = T extends keyof TdSpanAttrs ? number : string | undefined;
11
11
  /**
12
12
  * `<td>`, `<th>` or `<caption>`
13
13
  *
@@ -184,7 +184,7 @@ let TdToken = (() => {
184
184
  getAttr(key) {
185
185
  LINT: {
186
186
  const value = super.getAttr(key);
187
- return (key === 'rowspan' || key === 'colspan' ? parseInt(value) || 1 : value);
187
+ return (key === 'rowspan' || key === 'colspan' ? parseInt(value || '') || 1 : value);
188
188
  }
189
189
  }
190
190
  /** @private */
@@ -94,6 +94,7 @@ let ExtToken = (() => {
94
94
  innerToken = new PreToken(inner, newConfig, accum);
95
95
  break;
96
96
  }
97
+ newConfig.excludes.push('list');
97
98
  // fall through
98
99
  case 'indicator':
99
100
  case 'poem':
@@ -116,7 +117,9 @@ let ExtToken = (() => {
116
117
  case 'tab':
117
118
  newConfig.ext = newConfig.ext.filter(e => e !== 'tabs');
118
119
  break;
119
- // No default
120
+ case 'ref':
121
+ newConfig.ext = newConfig.ext.filter(e => e !== 'references');
122
+ // no default
120
123
  }
121
124
  innerToken = new index_2.Token(inner, newConfig, accum);
122
125
  break;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.mixin = exports.emptyArray = exports.getMagicWordInfo = exports.setChildNodes = exports.isLink = exports.isRowEnd = exports.isToken = exports.Shadow = void 0;
3
+ exports.mixin = exports.emptyArray = exports.getMagicWordInfo = exports.setChildNodes = exports.isLink = exports.isRowEnd = exports.Shadow = void 0;
4
+ exports.isToken = isToken;
4
5
  exports.Shadow = {
5
6
  running: false,
6
7
  /** @private */
@@ -33,12 +34,9 @@ exports.Shadow = {
33
34
  },
34
35
  rev: 0,
35
36
  };
36
- /**
37
- * 是否是某一特定类型的节点
38
- * @param type 节点类型
39
- */
40
- const isToken = (type) => (node) => node.type === type;
41
- exports.isToken = isToken;
37
+ function isToken(type) {
38
+ return (node) => node.type === type;
39
+ }
42
40
  /**
43
41
  * 是否是行尾
44
42
  * @param token 节点
@@ -88,6 +88,8 @@ exports.htmlAttrs = (() => ({
88
88
  categorytree: blockAttrs,
89
89
  combooption: blockAttrs,
90
90
  img: new Set(['alt', 'src', 'width', 'height', 'loading', 'srcset']),
91
+ /* NOT FOR BROWSER ONLY */
92
+ a: new Set(['href', 'rel', 'rev']),
91
93
  }))();
92
94
  exports.extAttrs = (() => ({
93
95
  pre: new Set(['format']),
@@ -85,7 +85,9 @@ const htmlAttrs = /* @__PURE__ */ (() => ({
85
85
  poem: blockAttrs,
86
86
  categorytree: blockAttrs,
87
87
  combooption: blockAttrs,
88
- img: /* @__PURE__ */ new Set(["alt", "src", "width", "height", "loading", "srcset"])
88
+ img: /* @__PURE__ */ new Set(["alt", "src", "width", "height", "loading", "srcset"]),
89
+ /* NOT FOR BROWSER ONLY */
90
+ a: /* @__PURE__ */ new Set(["href", "rel", "rev"])
89
91
  }))();
90
92
  const extAttrs = /* @__PURE__ */ (() => ({
91
93
  pre: /* @__PURE__ */ new Set(["format"]),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wikilint",
3
- "version": "2.40.0",
3
+ "version": "2.42.0",
4
4
  "description": "A Node.js linter for MediaWiki markup",
5
5
  "keywords": [
6
6
  "mediawiki",
@@ -18,7 +18,7 @@
18
18
  "/errors/README",
19
19
  "/config/",
20
20
  "!/config/mediawikiwiki.json",
21
- "!/config/testwiki.json",
21
+ "!/config/github.json",
22
22
  "/data/",
23
23
  "/i18n/",
24
24
  "/coverage/badge.svg",
@@ -74,9 +74,9 @@
74
74
  ]
75
75
  },
76
76
  "dependencies": {
77
- "@bhsd/cm-util": "^1.1.0",
77
+ "@bhsd/cm-util": "^2.0.1",
78
78
  "@bhsd/common": "^2.2.1",
79
- "@bhsd/stylelint-util": "^1.0.2",
79
+ "@bhsd/stylelint-util": "^1.0.3",
80
80
  "binary-search": "^1.3.6",
81
81
  "vscode-languageserver-types": "^3.17.5"
82
82
  },
@@ -84,29 +84,29 @@
84
84
  "color-name": "~2.0.2",
85
85
  "entities": "^8.0.0",
86
86
  "mathoid-texvcjs": "^0.6.0",
87
- "stylelint": "^17.11.0",
87
+ "stylelint": "^17.12.0",
88
88
  "vscode-css-languageservice": "^6.3.10",
89
89
  "vscode-html-languageservice": "^5.6.2",
90
90
  "vscode-json-languageservice": "^5.7.2"
91
91
  },
92
92
  "devDependencies": {
93
- "@bhsd/code-standard": "^2.4.2",
94
- "@bhsd/nodejs": "^1.0.0",
95
- "@bhsd/test-util": "^1.2.0",
93
+ "@bhsd/code-standard": "^2.5.1",
94
+ "@bhsd/nodejs": "^1.0.1",
95
+ "@bhsd/test-util": "^1.3.1",
96
96
  "@types/color-name": "^2.0.0",
97
97
  "@types/color-rgba": "^2.1.3",
98
98
  "@types/mocha": "^10.0.10",
99
- "@types/node": "^24.11.0",
100
- "@typescript-eslint/parser": "^8.59.2",
99
+ "@types/node": "^25.9.0",
100
+ "@typescript-eslint/parser": "^8.59.4",
101
101
  "c8": "^11.0.0",
102
102
  "color-rgba": "^3.0.0",
103
103
  "diff2html-cli": "^5.2.15",
104
104
  "esbuild": "^0.28.0",
105
- "eslint": "^10.3.0",
105
+ "eslint": "^10.4.1",
106
106
  "markdownlint-cli2": "^0.22.1",
107
- "mocha": "^11.7.5",
107
+ "mocha": "^11.7.6",
108
108
  "typescript": "^6.0.3",
109
- "v8r": "^6.0.0",
109
+ "v8r": "^6.1.0",
110
110
  "vscode-languageserver-textdocument": "^1.0.12"
111
111
  },
112
112
  "engines": {