wikiparser-node 1.38.1 → 1.39.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/dist/index.js CHANGED
@@ -30,6 +30,7 @@ const jsonRequire = (file) => {
30
30
  if (fullPath.endsWith('.json')) {
31
31
  return require(fullPath);
32
32
  }
33
+ /* c8 ignore next */
33
34
  throw new RangeError('Only JSON files are supported!');
34
35
  };
35
36
  /**
@@ -138,7 +139,7 @@ const Parser = {
138
139
  this.config = rootRequire(this.config, 'config');
139
140
  }
140
141
  /* c8 ignore next 3 */
141
- if (this.config.doubleUnderscore.length < 3 || !('functionHook' in this.config)) {
142
+ if (!('functionHook' in this.config)) {
142
143
  (0, diff_1.error)(`The schema (${path_1.default.join(__dirname, '..', 'config', '.schema.json')}) of parser configuration is updated.`);
143
144
  }
144
145
  return this.getConfig();
@@ -148,7 +149,7 @@ const Parser = {
148
149
  /* NOT FOR BROWSER */
149
150
  conversionTable, redirects, } = parserConfig;
150
151
  for (let i = 0; i < 2; i++) {
151
- if (doubleUnderscore.length > i + 2 && doubleUnderscore[i].length === 0) {
152
+ if (doubleUnderscore[i].length === 0) {
152
153
  doubleUnderscore[i] = Object.keys(doubleUnderscore[i + 2]);
153
154
  }
154
155
  }
@@ -260,7 +261,7 @@ const Parser = {
260
261
  /* NOT FOR BROWSER ONLY END */
261
262
  });
262
263
  /* NOT FOR BROWSER */
263
- if (types?.includes('list-range')) {
264
+ if (maxStage > constants_1.MAX_STAGE || types?.includes('list-range')) {
264
265
  root.buildLists();
265
266
  }
266
267
  /* c8 ignore start */
package/dist/lib/lsp.js CHANGED
@@ -261,6 +261,7 @@ const partialParse = async (wikitext, watch, include, config = index_1.default.g
261
261
  set(parseOnce, 0);
262
262
  }
263
263
  else {
264
+ /* c8 ignore next */
264
265
  resolve();
265
266
  }
266
267
  },
@@ -505,6 +506,7 @@ class LanguageService {
505
506
  colors = new RegExp(String.raw `\b${Object.keys(colorName).join('|')}\b`, 'giu');
506
507
  }
507
508
  catch {
509
+ /* c8 ignore next */
508
510
  colors = false;
509
511
  }
510
512
  }
@@ -618,7 +620,7 @@ class LanguageService {
618
620
  * @param position position / 位置
619
621
  */
620
622
  async provideCompletionItems(text, position) {
621
- const { re, allTags, functions, switches, jaSwitches, 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;
623
+ const { re, allTags, functions, switches, jaSwitches, 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;
622
624
  if (mt?.[1] !== undefined) { // tag
623
625
  const closing = mt[1].startsWith('/');
624
626
  return getCompletion(allTags, 'Class', mt[1].slice(closing ? 1 : 0), position, closing && !curLine?.slice(character).trim().startsWith('>') ? '>' : '');
@@ -58,9 +58,9 @@ export declare class Title {
58
58
  */
59
59
  constructor(title: string, defaultNs: number, config: Config, { temporary, decode, selfLink, page }?: TitleOptions);
60
60
  /**
61
- * Check if the title is a redirect
61
+ * Check if the title is a redirect and get the redirect target
62
62
  *
63
- * 检测是否是重定向
63
+ * 检测是否是重定向并获取重定向目标
64
64
  * @since v1.12.2
65
65
  */
66
66
  getRedirection(): [boolean, string];
@@ -72,6 +72,13 @@ export declare class Title {
72
72
  * @since v1.10.0
73
73
  */
74
74
  getUrl(articlePath?: string): string;
75
+ /**
76
+ * Check if the title is a redirect
77
+ *
78
+ * 检测是否是重定向
79
+ * @since v1.38.2
80
+ */
81
+ isRedirect(): boolean;
75
82
  /**
76
83
  * Get the URL of the file
77
84
  *
package/dist/lib/title.js CHANGED
@@ -201,8 +201,9 @@ class Title {
201
201
  /**
202
202
  * 生成标题
203
203
  * @param prefix 前缀
204
+ * @param redirect 是否允许重定向
204
205
  */
205
- #getTitle(prefix) {
206
+ #getTitle(prefix, redirect = true) {
206
207
  let title = (prefix + this.main).replace(/ /gu, '_');
207
208
  if (title.startsWith('/')) {
208
209
  title = (this.page ?? '') + title.replace(/(.)\/$/u, '$1');
@@ -214,21 +215,23 @@ class Title {
214
215
  }
215
216
  }
216
217
  /* NOT FOR BROWSER */
217
- const media = title.startsWith('Media:');
218
- let redirected = this.redirects.get(media ? `File:${title.slice(6)}` : title);
219
- if (redirected) {
220
- const hash = redirected.indexOf('#');
221
- this.#redirectFragment = hash === -1 ? undefined : redirected.slice(hash + 1);
222
- redirected = hash === -1 ? redirected : redirected.slice(0, hash);
223
- return [true, media ? redirected.replace(/^File:/u, 'Media:') : redirected];
218
+ if (redirect) {
219
+ const media = title.startsWith('Media:');
220
+ let redirected = this.redirects.get(media ? `File:${title.slice(6)}` : title);
221
+ if (redirected) {
222
+ const hash = redirected.indexOf('#');
223
+ this.#redirectFragment = hash === -1 ? undefined : redirected.slice(hash + 1);
224
+ redirected = hash === -1 ? redirected : redirected.slice(0, hash);
225
+ return [true, media ? redirected.replace(/^File:/u, 'Media:') : redirected];
226
+ }
224
227
  }
225
228
  /* NOT FOR BROWSER */
226
229
  return [false, title];
227
230
  }
228
231
  /**
229
- * Check if the title is a redirect
232
+ * Check if the title is a redirect and get the redirect target
230
233
  *
231
- * 检测是否是重定向
234
+ * 检测是否是重定向并获取重定向目标
232
235
  * @since v1.12.2
233
236
  */
234
237
  getRedirection() {
@@ -280,6 +283,15 @@ class Title {
280
283
  }
281
284
  }
282
285
  /* NOT FOR BROWSER */
286
+ /**
287
+ * Check if the title is a redirect
288
+ *
289
+ * 检测是否是重定向
290
+ * @since v1.38.2
291
+ */
292
+ isRedirect() {
293
+ return this.getRedirection()[0];
294
+ }
283
295
  /**
284
296
  * Get the URL of the file
285
297
  *
@@ -308,10 +320,15 @@ class Title {
308
320
  return expandMagicWord('filepath', [main, `${width || ''}${height ? `x${height}` : ''}`]);
309
321
  }
310
322
  /** @private */
311
- toString(display) {
312
- return (display ? this.displayTitle : this.title) + (this.#fragment === undefined && this.#redirectFragment === undefined
313
- ? ''
314
- : `#${this.#fragment ?? this.#redirectFragment}`);
323
+ toString(display, redirect = true) {
324
+ if (redirect) {
325
+ return (display ? this.displayTitle : this.title) + (this.#fragment === undefined && this.#redirectFragment === undefined
326
+ ? ''
327
+ : `#${this.#fragment ?? this.#redirectFragment}`);
328
+ }
329
+ const { prefix, interwiki } = this, [, result] = this.#getTitle(interwiki + (interwiki && ':') + prefix, false);
330
+ return (display ? result.replaceAll('_', ' ') : result)
331
+ + (this.#fragment === undefined ? '' : `#${this.#fragment}`);
315
332
  }
316
333
  /**
317
334
  * Perform unidirectional language conversion
@@ -1,4 +1,4 @@
1
- import type { AstNodes, Token } from '../internal';
1
+ import type { AstNodes, Token, HtmlToken, ExtToken } from '../internal';
2
2
  declare type ElementConstructor = abstract new (...args: any[]) => {
3
3
  readonly childNodes: readonly AstNodes[];
4
4
  detach?: () => void;
@@ -60,6 +60,6 @@ export interface ElementLike {
60
60
  * 标签名选择器
61
61
  * @param tag tag name / 标签名
62
62
  */
63
- getElementsByTagName<T = Token>(tag: string): T[];
63
+ getElementsByTagName<T extends HtmlToken | ExtToken = HtmlToken | ExtToken>(tag: string): T[];
64
64
  }
65
65
  /** @ignore */
@@ -34,7 +34,7 @@ const parseHrAndDoubleUnderscore = ({ firstChild: { data }, type, name }, config
34
34
  if (caseSensitive || caseInsensitive) {
35
35
  // @ts-expect-error abstract class
36
36
  new doubleUnderscore_1.DoubleUnderscoreToken(key, caseSensitive, Boolean(p4), config, accum);
37
- return `\0${accum.length - 1}${caseInsensitive && (aliases?.[lc] ?? /* c8 ignore next */ lc) === 'toc' ? 'u' : 'n'}\x7F`;
37
+ return `\0${accum.length - 1}${caseInsensitive && (aliases[lc] ?? /* c8 ignore next */ lc) === 'toc' ? 'u' : 'n'}\x7F`;
38
38
  }
39
39
  return m;
40
40
  });
@@ -92,7 +92,7 @@ const parseTable = ({ firstChild: { data }, type, name }, config, accum) => {
92
92
  else if (row) {
93
93
  top = pop(top, stack);
94
94
  if (top.is('tr')) {
95
- top = stack.pop();
95
+ top = stack.pop(); // eslint-disable-line @typescript-eslint/no-unnecessary-type-assertion
96
96
  }
97
97
  // @ts-expect-error abstract class
98
98
  const tr = new tr_1.TrToken(`\n${spaces}${row}`, attr, config, accum);
@@ -224,7 +224,7 @@ let AttributeToken = (() => {
224
224
  // 不支持通用HTML属性的扩展标签
225
225
  type === 'ext-attr' && !attrs2
226
226
  // 或非通用HTML属性
227
- || !/^(?:xmlns:[\w:.-]+|data-(?!ooui|mw|parsoid)[^:]*)$/u.test(name)
227
+ || !/^(?:xmlns:[\w:.-]+|data-(?!ooui|mw|parsoid)[^:_]*)$/u.test(name)
228
228
  && (tag === 'meta' || tag === 'link' || !sharable_1.commonHtmlAttrs.has(name)))
229
229
  || (name === 'itemtype' || name === 'itemid' || name === 'itemref')
230
230
  && !parentNode?.hasAttr('itemscope')) {
@@ -1,6 +1,7 @@
1
+ import Parser from '../../index';
1
2
  import { Token } from '../index';
2
3
  import { AtomToken } from '../atom';
3
- import type { Config, LintError, AST } from '../../base';
4
+ import type { LintError, AST } from '../../base';
4
5
  import type { Title } from '../../lib/title';
5
6
  /**
6
7
  * internal link
@@ -33,7 +34,7 @@ export declare abstract class LinkBaseToken extends Token {
33
34
  * @param linkText 链接显示文字
34
35
  * @param delimiter `|`
35
36
  */
36
- constructor(link: string, linkText?: string, config?: Config, accum?: Token[], delimiter?: string);
37
+ constructor(link: string, linkText?: string, config?: Parser.Config, accum?: Token[], delimiter?: string);
37
38
  cloneNode(): this;
38
39
  /**
39
40
  * Set the link target
@@ -119,7 +119,7 @@ let LinkBaseToken = (() => {
119
119
  * @param linkText 链接显示文字
120
120
  * @param delimiter `|`
121
121
  */
122
- constructor(link, linkText, config, accum = [], delimiter = '|') {
122
+ constructor(link, linkText, config = index_1.default.getConfig(), accum = [], delimiter = '|') {
123
123
  super(undefined, config, accum, {
124
124
  AtomToken: 0, Token: 1,
125
125
  });
@@ -127,9 +127,7 @@ let LinkBaseToken = (() => {
127
127
  'Stage-2': ':', '!ExtToken': '', '!HeadingToken': '',
128
128
  }));
129
129
  if (linkText !== undefined) {
130
- const inner = new index_2.Token(linkText, config, accum, {
131
- 'Stage-5': ':', QuoteToken: ':', ConverterToken: ':',
132
- });
130
+ const inner = new index_2.Token(linkText, { ...config, excludes: [...config.excludes, 'list'] }, accum, { 'Stage-5': ':', QuoteToken: ':', ConverterToken: ':' });
133
131
  inner.type = 'link-text';
134
132
  inner.setAttribute('stage', constants_1.MAX_STAGE - 1);
135
133
  this.insertAt(inner);
@@ -30,7 +30,7 @@ class RedirectTargetToken extends base_1.LinkBaseToken {
30
30
  * @since v1.10.0
31
31
  */
32
32
  get innerText() {
33
- return this.link.toString(true);
33
+ return this.link.toString(true, false);
34
34
  }
35
35
  /* NOT FOR BROWSER END */
36
36
  /**
@@ -78,7 +78,7 @@ let DoubleUnderscoreToken = (() => {
78
78
  constructor(word, sensitive, fullWidth, config, accum) {
79
79
  super(word, config, accum);
80
80
  const lc = word.toLowerCase(), [, , iAlias, sAlias] = config.doubleUnderscore;
81
- this.setAttribute('name', (sensitive ? sAlias?.[word]?.toLowerCase() : iAlias?.[lc]) ?? lc);
81
+ this.setAttribute('name', (sensitive ? sAlias[word]?.toLowerCase() : iAlias[lc]) ?? lc);
82
82
  this.#fullWidth = fullWidth;
83
83
  /* NOT FOR BROWSER */
84
84
  this.#sensitive = sensitive;
@@ -24,7 +24,7 @@ class ListBaseToken extends base_1.NowikiBaseToken {
24
24
  /* NOT FOR BROWSER */
25
25
  /** @throws `Error` not `<dd>` only */
26
26
  set indent(indent) {
27
- if (/[^:]/u.test(this.innerText)) {
27
+ if (/[^:\s]/u.test(this.innerText)) {
28
28
  throw new Error('The token is not <dd>!');
29
29
  }
30
30
  this.setText(':'.repeat(indent));
@@ -682,6 +682,9 @@ let TranscludeToken = (() => {
682
682
  removeArg(key, exact) {
683
683
  debug_1.Shadow.run(() => {
684
684
  for (const token of this.getArgs(key, exact, false)) {
685
+ if (token.anon) {
686
+ this.anonToNamed();
687
+ }
685
688
  this.removeChild(token);
686
689
  }
687
690
  });
@@ -58,7 +58,7 @@ const decodeHtml = (str) => {
58
58
  if (typeof process === 'object' && typeof process.versions?.node === 'string') {
59
59
  try {
60
60
  const { decodeHTMLStrict } = require('entities');
61
- return (s) => decodeHTMLStrict(s).replace(/\xA0/gu, ' ');
61
+ return (s) => decodeHTMLStrict(s).replaceAll('\xA0', ' ');
62
62
  }
63
63
  catch /* c8 ignore next */ { }
64
64
  }
@@ -1,6 +1,6 @@
1
1
  (() => {
2
2
  var _a;
3
- const version = '1.38.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)
3
+ const version = '1.39.0', 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://fastly.jsdelivr.net/npm/wikiparser-node@${version}`;
6
6
  const workerJS = () => {
@@ -88,7 +88,8 @@ _LanguageService_id = new WeakMap(), _LanguageService_include = new WeakMap(), _
88
88
  if (!__classPrivateFieldGet(this, _LanguageService_hasData, "f")) {
89
89
  __classPrivateFieldSet(this, _LanguageService_hasData, true, "f");
90
90
  data !== null && data !== void 0 ? data : (data = (async () => (await fetch(`${wikiparse.CDN}/data/signatures.json`)).json())());
91
- wikiparse.provide('data', __classPrivateFieldGet(this, _LanguageService_id, "f"), await data, __classPrivateFieldGet(this, _LanguageService_include, "f"));
91
+ this.data = await data;
92
+ wikiparse.provide('data', __classPrivateFieldGet(this, _LanguageService_id, "f"), this.data, __classPrivateFieldGet(this, _LanguageService_include, "f"));
92
93
  }
93
94
  };
94
95
  wikiparse.LanguageService = LanguageService;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wikiparser-node",
3
- "version": "1.38.1",
3
+ "version": "1.39.0",
4
4
  "description": "A Node.js parser for MediaWiki markup with AST",
5
5
  "keywords": [
6
6
  "mediawiki",
@@ -16,7 +16,6 @@
16
16
  "author": "Bhsd",
17
17
  "files": [
18
18
  "/bundle/bundle*.js",
19
- "/extensions/typings.d.ts",
20
19
  "/extensions/dist/*.js",
21
20
  "/extensions/*.css",
22
21
  "!/extensions/dist/*-page*.js",
@@ -46,6 +45,7 @@
46
45
  "url": "git+https://github.com/bhsd-harry/wikiparser-node.git"
47
46
  },
48
47
  "scripts": {
48
+ "ls": "npm i --package-lock-only && npm ls --package-lock-only --all --omit=dev",
49
49
  "toc": "node dist/script/toc.js",
50
50
  "prepublishOnly": "npm run build:core",
51
51
  "build:core": "bash build.sh",
@@ -53,7 +53,7 @@
53
53
  "build": "npm run build:core && LC_ALL=en.UTF-8 node dist/script/parserTests.js",
54
54
  "diff": "bash diff.sh",
55
55
  "diff:stat": "f() { git diff --stat --ignore-all-space --color=always $1 $2 -- . | grep '\\.ts'; }; f",
56
- "lint:ts": "tsc --noEmit && eslint --cache . && eslint --no-config-lookup -c wiki/eslint.config.mjs wiki/*.md",
56
+ "lint:ts": "tsc --noEmit && eslint --cache .",
57
57
  "lint:json": "v8r -s config/.schema.json config/*.json && v8r -s data/.schema.json data/*.json && mocha dist/test/json.js",
58
58
  "lint:md": "markdownlint-cli2 '**/*.md'",
59
59
  "lint": "npm run lint:ts && npm run lint:json && npm run lint:md",
@@ -61,7 +61,7 @@
61
61
  "coverage": "tsc --declaration false --target es2024 && npm run build:define && c8 npm run test:ci && node dist/script/coverage.js && open coverage/index.html",
62
62
  "test:unit": "mocha dist/test/test.js",
63
63
  "test:math": "mocha dist/test/math.js",
64
- "test:clonenode": "CLONENODE=1 npm run test:unit",
64
+ "test:clonenode": "CLONENODE=1 mocha --require dist/test/env.js dist/test/test.js",
65
65
  "test:parser": "LC_ALL=en.UTF-8 mocha dist/test/parserTests.js",
66
66
  "test:perf": "mocha --reporter spec dist/test/perf.js",
67
67
  "test": "npm run test:unit && npm run test:clonenode && npm run test:parser",
@@ -86,7 +86,7 @@
86
86
  "@bhsd/cm-util": "^1.0.0",
87
87
  "@bhsd/common": "^2.0.0",
88
88
  "@bhsd/nodejs": "^1.0.0",
89
- "@bhsd/stylelint-util": "^1.0.1",
89
+ "@bhsd/stylelint-util": "^1.0.2",
90
90
  "binary-search": "^1.3.6",
91
91
  "vscode-languageserver-types": "^3.17.5"
92
92
  },
@@ -94,16 +94,16 @@
94
94
  "color-name": "^2.0.0",
95
95
  "entities": "^8.0.0",
96
96
  "mathoid-texvcjs": "^0.6.0",
97
- "prism-wiki": "^2.0.0",
97
+ "prism-wiki": "^2.1.0",
98
98
  "prismjs": "^1.30.0",
99
- "stylelint": "^17.6.0",
99
+ "stylelint": "^17.9.0",
100
100
  "vscode-css-languageservice": "^6.3.10",
101
101
  "vscode-html-languageservice": "^5.6.2",
102
102
  "vscode-json-languageservice": "^5.7.2"
103
103
  },
104
104
  "devDependencies": {
105
105
  "@bhsd/code-standard": "^2.2.0",
106
- "@bhsd/test-util": "^1.0.0",
106
+ "@bhsd/test-util": "^1.1.0",
107
107
  "@codemirror/lint": "^6.9.5",
108
108
  "@eslint/markdown": "^8.0.1",
109
109
  "@eslint-community/eslint-plugin-eslint-comments": "^4.7.1",
@@ -113,27 +113,31 @@
113
113
  "@types/mocha": "^10.0.10",
114
114
  "@types/node": "^24.11.0",
115
115
  "@types/prismjs": "^1.26.6",
116
- "@typescript-eslint/eslint-plugin": "^8.58.0",
117
- "@typescript-eslint/parser": "^8.58.0",
116
+ "@typescript-eslint/eslint-plugin": "^8.59.0",
117
+ "@typescript-eslint/parser": "^8.59.0",
118
118
  "c8": "^11.0.0",
119
119
  "codejar-async": "^4.3.0",
120
120
  "color-rgba": "^3.0.0",
121
121
  "diff2html-cli": "^5.2.15",
122
- "esbuild": "^0.27.7",
123
- "eslint": "^10.2.0",
124
- "eslint-plugin-jsdoc": "^62.7.1",
122
+ "esbuild": "^0.28.0",
123
+ "eslint": "^10.2.1",
124
+ "eslint-plugin-jsdoc": "^62.9.0",
125
125
  "eslint-plugin-jsonc": "^3.1.2",
126
126
  "eslint-plugin-n": "^17.24.0",
127
127
  "eslint-plugin-promise": "^7.2.1",
128
128
  "eslint-plugin-regexp": "^3.1.0",
129
129
  "eslint-plugin-unicorn": "^64.0.0",
130
- "markdownlint-cli2": "^0.21.0",
130
+ "markdownlint-cli2": "^0.22.1",
131
131
  "mocha": "^11.7.5",
132
132
  "monaco-editor": "~0.53.0",
133
- "typescript": "^6.0.2",
133
+ "tsx": "^4.21.0",
134
+ "typescript": "^6.0.3",
134
135
  "v8r": "^6.0.0",
135
136
  "vscode-languageserver-textdocument": "^1.0.12"
136
137
  },
138
+ "overrides": {
139
+ "eslint": "^10.2.1"
140
+ },
137
141
  "engines": {
138
142
  "node": "^20.19.0 || ^22.13.0 || >=24.11.0"
139
143
  }