wikilint 2.19.0 → 2.20.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.
Files changed (83) hide show
  1. package/config/default.json +49 -3
  2. package/config/minimum.json +5 -1
  3. package/data/ext/math.json +660 -0
  4. package/dist/base.d.mts +1 -1
  5. package/dist/base.d.ts +1 -1
  6. package/dist/bin/cli.js +19 -6
  7. package/dist/bin/config.js +26 -8
  8. package/dist/index.js +10 -1
  9. package/dist/internal.d.ts +2 -0
  10. package/dist/lib/document.d.ts +1 -0
  11. package/dist/lib/document.js +10 -1
  12. package/dist/lib/element.js +15 -4
  13. package/dist/lib/lsp.js +87 -57
  14. package/dist/lib/node.js +0 -7
  15. package/dist/lib/text.js +3 -7
  16. package/dist/lib/title.js +1 -6
  17. package/dist/mixin/attributesParent.js +1 -1
  18. package/dist/mixin/gapped.d.ts +4 -0
  19. package/dist/mixin/gapped.js +20 -0
  20. package/dist/mixin/hidden.js +1 -1
  21. package/dist/mixin/multiLine.d.ts +4 -0
  22. package/dist/mixin/multiLine.js +26 -0
  23. package/dist/mixin/padded.d.ts +5 -0
  24. package/dist/mixin/padded.js +20 -0
  25. package/dist/parser/braces.js +8 -12
  26. package/dist/parser/commentAndExt.js +18 -2
  27. package/dist/parser/magicLinks.js +1 -1
  28. package/dist/parser/selector.js +5 -2
  29. package/dist/src/arg.js +131 -84
  30. package/dist/src/attribute.js +4 -4
  31. package/dist/src/attributes.js +2 -2
  32. package/dist/src/commented.d.ts +19 -0
  33. package/dist/src/commented.js +41 -0
  34. package/dist/src/converter.js +90 -43
  35. package/dist/src/converterFlags.js +113 -66
  36. package/dist/src/converterRule.d.ts +1 -1
  37. package/dist/src/extLink.d.ts +2 -3
  38. package/dist/src/extLink.js +97 -54
  39. package/dist/src/gallery.d.ts +3 -4
  40. package/dist/src/gallery.js +114 -72
  41. package/dist/src/heading.js +10 -10
  42. package/dist/src/imageParameter.d.ts +1 -1
  43. package/dist/src/imageParameter.js +4 -3
  44. package/dist/src/imagemap.d.ts +1 -1
  45. package/dist/src/imagemap.js +126 -86
  46. package/dist/src/imagemapLink.d.ts +1 -1
  47. package/dist/src/index.js +11 -8
  48. package/dist/src/link/base.d.ts +2 -3
  49. package/dist/src/link/base.js +149 -105
  50. package/dist/src/link/file.d.ts +2 -3
  51. package/dist/src/link/file.js +2 -2
  52. package/dist/src/link/galleryImage.d.ts +2 -3
  53. package/dist/src/link/galleryImage.js +89 -47
  54. package/dist/src/nested.d.ts +1 -1
  55. package/dist/src/nowiki/comment.js +2 -5
  56. package/dist/src/nowiki/doubleUnderscore.js +2 -5
  57. package/dist/src/nowiki/index.d.ts +1 -1
  58. package/dist/src/nowiki/index.js +2 -1
  59. package/dist/src/onlyinclude.js +63 -15
  60. package/dist/src/paramTag/index.d.ts +1 -1
  61. package/dist/src/paramTag/index.js +89 -47
  62. package/dist/src/parameter.d.ts +3 -4
  63. package/dist/src/parameter.js +4 -8
  64. package/dist/src/pre.d.ts +3 -4
  65. package/dist/src/pre.js +5 -9
  66. package/dist/src/syntax.d.ts +1 -1
  67. package/dist/src/table/base.d.ts +2 -2
  68. package/dist/src/table/base.js +3 -7
  69. package/dist/src/table/index.js +1 -1
  70. package/dist/src/table/td.d.ts +2 -3
  71. package/dist/src/table/td.js +3 -7
  72. package/dist/src/table/tr.d.ts +1 -1
  73. package/dist/src/tagPair/ext.js +34 -31
  74. package/dist/src/tagPair/index.d.ts +1 -1
  75. package/dist/src/tagPair/index.js +94 -47
  76. package/dist/src/tagPair/translate.d.ts +22 -0
  77. package/dist/src/tagPair/translate.js +48 -0
  78. package/dist/src/transclude.js +378 -332
  79. package/dist/util/lint.js +17 -30
  80. package/dist/util/sharable.js +29 -1
  81. package/dist/util/sharable.mjs +31 -3
  82. package/dist/util/string.js +14 -1
  83. package/package.json +3 -2
package/dist/bin/cli.js CHANGED
@@ -7,8 +7,21 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const fs_1 = __importDefault(require("fs"));
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const assert_1 = __importDefault(require("assert"));
10
- const chalk_1 = __importDefault(require("chalk"));
11
10
  const index_1 = __importDefault(require("../index"));
11
+ const chalk = (() => {
12
+ try {
13
+ return require('chalk');
14
+ }
15
+ catch {
16
+ const f = ((text) => text), proxy = new Proxy(f, {
17
+ /** @private */
18
+ get() {
19
+ return proxy;
20
+ },
21
+ });
22
+ return proxy;
23
+ }
24
+ })();
12
25
  const man = `
13
26
  Available options:
14
27
  -c, --config <path or preset config> Choose parser's configuration
@@ -117,7 +130,7 @@ const plural = (n, word) => `${n} ${word}${n === 1 ? '' : 's'}`;
117
130
  * color the severity
118
131
  * @param severity problem severity
119
132
  */
120
- const coloredSeverity = (severity) => chalk_1.default[severity === 'error' ? 'red' : 'yellow'](severity.padEnd(7));
133
+ const coloredSeverity = (severity) => chalk[severity === 'error' ? 'red' : 'yellow'](severity.padEnd(7));
121
134
  for (let i = 2; i < argv.length; i++) {
122
135
  option = argv[i];
123
136
  switch (option) {
@@ -306,10 +319,10 @@ for (const file of new Set(files.map(f => path_1.default.resolve(f)))) {
306
319
  nFixableWarn += nLocalFixableWarn;
307
320
  }
308
321
  if (problems.length > 0) {
309
- console.error(`\n${chalk_1.default.underline('%s')}`, file);
322
+ console.error(`\n${chalk.underline('%s')}`, file);
310
323
  const maxLineChars = String(Math.max(...problems.map(({ startLine }) => startLine))).length, maxColChars = String(Math.max(...problems.map(({ startCol }) => startCol))).length, maxMessageChars = Math.max(...problems.map(({ message: { length } }) => length));
311
324
  for (const { rule, message, severity, startLine, startCol } of problems) {
312
- console.error(` ${chalk_1.default.dim('%s:%s')} %s %s ${chalk_1.default.dim('%s')}`, String(startLine).padStart(maxLineChars), String(startCol).padEnd(maxColChars), coloredSeverity(severity), message.padEnd(maxMessageChars), rule);
325
+ console.error(` ${chalk.dim('%s:%s')} %s %s ${chalk.dim('%s')}`, String(startLine).padStart(maxLineChars), String(startCol).padEnd(maxColChars), coloredSeverity(severity), message.padEnd(maxMessageChars), rule);
313
326
  }
314
327
  }
315
328
  nErr += nLocalErr;
@@ -317,9 +330,9 @@ for (const file of new Set(files.map(f => path_1.default.resolve(f)))) {
317
330
  exiting ||= Boolean(nLocalErr || strict && nLocalWarn);
318
331
  }
319
332
  if (nErr || nWarn) {
320
- console.error(chalk_1.default.red.bold('%s'), `\n✖ ${plural(nErr + nWarn, 'problem')} (${plural(nErr, 'error')}, ${plural(nWarn, 'warning')})`);
333
+ console.error(chalk.red.bold('%s'), `\n✖ ${plural(nErr + nWarn, 'problem')} (${plural(nErr, 'error')}, ${plural(nWarn, 'warning')})`);
321
334
  if (nFixableErr || nFixableWarn) {
322
- console.error(chalk_1.default.red.bold('%s'), ` ${plural(nFixableErr, 'error')} and ${plural(nFixableWarn, 'warning')} potentially fixable with the \`--fix\` option.`);
335
+ console.error(chalk.red.bold('%s'), ` ${plural(nFixableErr, 'error')} and ${plural(nFixableWarn, 'warning')} potentially fixable with the \`--fix\` option.`);
323
336
  }
324
337
  console.error();
325
338
  }
@@ -8,6 +8,7 @@ const path_1 = __importDefault(require("path"));
8
8
  const fs_1 = __importDefault(require("fs"));
9
9
  const assert_1 = __importDefault(require("assert"));
10
10
  const cm_1 = require("@bhsd/common/dist/cm");
11
+ const diff_1 = require("../util/diff");
11
12
  /**
12
13
  * Converts an array to an object.
13
14
  * @param config parser configuration
@@ -85,7 +86,7 @@ let mwConfig;
85
86
  */
86
87
  exports.default = async (site, url, force, internal) => {
87
88
  if (!site || !url) {
88
- console.error('Usage: npx getParserConfig <site> <script path> [force]');
89
+ (0, diff_1.error)('Usage: npx getParserConfig <site> <script path> [force]');
89
90
  process.exit(1);
90
91
  }
91
92
  else if (/(?:\.php|\/)$/u.test(url)) {
@@ -97,8 +98,11 @@ exports.default = async (site, url, force, internal) => {
97
98
  siprop: 'general|magicwords|functionhooks|namespaces|namespacealiases',
98
99
  format: 'json',
99
100
  formatversion: '2',
100
- }, { query: { general: { articlepath, variants }, magicwords, namespaces, namespacealiases, functionhooks, }, } = await (await fetch(`${url}/api.php?${new URLSearchParams(params).toString()}`)).json(), { query: { variables } } = await (await fetch(`${url}/api.php?${new URLSearchParams({ ...params, siprop: 'variables' }).toString()}`)).json();
101
+ }, { query: { general: { articlepath, variants }, magicwords, namespaces, namespacealiases, functionhooks, }, } = await (await fetch(`${url}/api.php?${new URLSearchParams(params).toString()}`)).json();
101
102
  eval(m); // eslint-disable-line no-eval
103
+ if (!mwConfig) {
104
+ throw new RangeError('Extension:CodeMirror is not installed!');
105
+ }
102
106
  const dir = path_1.default.join('..', '..', 'config'), ns = Object.entries(namespaces).filter(([id]) => filterGadget(id))
103
107
  .flatMap(([id, { name, canonical = '' }]) => [
104
108
  [id, name],
@@ -118,6 +122,12 @@ exports.default = async (site, url, force, internal) => {
118
122
  config.doubleUnderscore[0] = [];
119
123
  config.doubleUnderscore[1] = [];
120
124
  Object.assign(config.parserFunction[0], (0, cm_1.getConfig)(magicwords, ({ name }) => name === 'msgnw'));
125
+ config.parserFunction[2] = getAliases(magicwords, new Set(['msg', 'raw']));
126
+ config.parserFunction[3] = getAliases(magicwords, new Set(['subst', 'safesubst']));
127
+ if (!mwConfig.variableIDs) {
128
+ const { query: { variables } } = await (await fetch(`${url}/api.php?${new URLSearchParams({ ...params, siprop: 'variables' }).toString()}`)).json();
129
+ Object.assign(config, { variable: [...new Set([...variables, '='])] });
130
+ }
121
131
  if ('#choose' in config.parserFunction[0]) {
122
132
  delete config.parserFunction[0]['choose'];
123
133
  const i = config.variable.indexOf('choose');
@@ -125,17 +135,25 @@ exports.default = async (site, url, force, internal) => {
125
135
  config.variable.splice(i, 1);
126
136
  }
127
137
  }
128
- config.parserFunction[2] = getAliases(magicwords, new Set(['msg', 'raw']));
129
- config.parserFunction[3] = getAliases(magicwords, new Set(['subst', 'safesubst']));
130
- if (!config.variable) { // eslint-disable-line @typescript-eslint/no-unnecessary-condition
131
- Object.assign(config, { variable: [...new Set([...variables, '='])] });
132
- }
133
138
  const file = path_1.default.join(__dirname, dir, `${site}.json`);
134
139
  if (force || !fs_1.default.existsSync(file)) {
135
140
  fs_1.default.writeFileSync(file, `${JSON.stringify(config, null, '\t')}\n`);
136
141
  }
137
142
  else if (!internal) {
138
- assert_1.default.deepStrictEqual(arrToObj(require(file)), arrToObj(config));
143
+ const oldConfig = arrToObj(require(file)), newConfig = arrToObj(config);
144
+ for (const [k, v] of Object.entries(newConfig)) {
145
+ try {
146
+ assert_1.default.deepStrictEqual(oldConfig[k], v);
147
+ }
148
+ catch (e) {
149
+ if (e instanceof assert_1.default.AssertionError) {
150
+ (0, diff_1.error)(`Configuration mismatch for "${k}"`);
151
+ delete e.actual;
152
+ delete e.expected;
153
+ }
154
+ throw e;
155
+ }
156
+ }
139
157
  }
140
158
  return config;
141
159
  };
package/dist/index.js CHANGED
@@ -43,12 +43,21 @@ const Parser = {
43
43
  return this.getConfig();
44
44
  }
45
45
  /* NOT FOR BROWSER ONLY END */
46
- const parserConfig = config ?? this.config, { doubleUnderscore, } = parserConfig;
46
+ const parserConfig = config ?? this.config, { doubleUnderscore, ext, parserFunction, variable, } = parserConfig;
47
47
  for (let i = 0; i < 2; i++) {
48
48
  if (doubleUnderscore.length > i + 2 && doubleUnderscore[i].length === 0) {
49
49
  doubleUnderscore[i] = Object.keys(doubleUnderscore[i + 2]);
50
50
  }
51
51
  }
52
+ if (ext.includes('translate') && !variable.includes('translationlanguage')) {
53
+ variable.push('translationlanguage');
54
+ if (Array.isArray(parserFunction[1])) {
55
+ parserFunction[1].push('TRANSLATIONLANGUAGE');
56
+ }
57
+ else {
58
+ parserFunction[1]['TRANSLATIONLANGUAGE'] = 'translationlanguage';
59
+ }
60
+ }
52
61
  return {
53
62
  ...parserConfig,
54
63
  excludes: [],
@@ -44,3 +44,5 @@ export type { NestedToken } from './src/nested';
44
44
  export type { GalleryToken } from './src/gallery';
45
45
  export type { ImagemapLinkToken } from './src/imagemapLink';
46
46
  export type { ImagemapToken } from './src/imagemap';
47
+ export type { CommentedToken } from './src/commented';
48
+ export type { TranslateToken } from './src/tagPair/translate';
@@ -10,6 +10,7 @@ export declare const MathJax: Promise<Jax | undefined>;
10
10
  export declare const jsonTags: string[];
11
11
  export declare const jsonLSP: import("vscode-json-languageservice").LanguageService | undefined;
12
12
  export declare const cssLSP: import("vscode-css-languageservice").LanguageService | undefined;
13
+ export declare const htmlData: import("vscode-html-languageservice").IHTMLDataProvider | undefined;
13
14
  export declare const stylelint: Promise<import("stylelint").PublicApi | undefined>;
14
15
  /** embedded document */
15
16
  declare class EmbeddedDocument implements TextDocument {
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.EmbeddedCSSDocument = exports.EmbeddedJSONDocument = exports.stylelint = 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.MathJax = void 0;
7
7
  const path_1 = __importDefault(require("path"));
8
8
  const common_1 = require("@bhsd/common");
9
9
  exports.MathJax = (async () => {
@@ -68,6 +68,15 @@ exports.cssLSP = (() => {
68
68
  return undefined;
69
69
  }
70
70
  })();
71
+ exports.htmlData = (() => {
72
+ try {
73
+ return require('vscode-html-languageservice')
74
+ .getDefaultHTMLDataProvider();
75
+ }
76
+ catch {
77
+ return undefined;
78
+ }
79
+ })();
71
80
  exports.stylelint = (async () => {
72
81
  try {
73
82
  return (await import('stylelint')).default;
@@ -117,7 +117,7 @@ class AstElement extends node_1.AstNode {
117
117
  * @param condition 条件
118
118
  */
119
119
  #getElementsBy(condition) {
120
- const descendants = [];
120
+ let descendants = [];
121
121
  for (const child of this.childNodes) {
122
122
  if (child.type === 'text') {
123
123
  continue;
@@ -125,7 +125,7 @@ class AstElement extends node_1.AstNode {
125
125
  else if (condition(child)) {
126
126
  descendants.push(child);
127
127
  }
128
- descendants.push(...child.#getElementsBy(condition));
128
+ descendants = [...descendants, ...child.#getElementsBy(condition)];
129
129
  }
130
130
  return descendants;
131
131
  }
@@ -146,6 +146,10 @@ class AstElement extends node_1.AstNode {
146
146
  * @param elements nodes to be inserted / 插入节点
147
147
  */
148
148
  append(...elements) {
149
+ this.safeAppend(elements);
150
+ }
151
+ /** @private */
152
+ safeAppend(elements) {
149
153
  for (const element of elements) {
150
154
  this.insertAt(element);
151
155
  }
@@ -157,10 +161,14 @@ class AstElement extends node_1.AstNode {
157
161
  * @param elements nodes to be inserted / 新的子节点
158
162
  */
159
163
  replaceChildren(...elements) {
164
+ this.safeReplaceChildren(elements);
165
+ }
166
+ /** @private */
167
+ safeReplaceChildren(elements) {
160
168
  for (let i = this.length - 1; i >= 0; i--) {
161
169
  this.removeAt(i);
162
170
  }
163
- this.append(...elements);
171
+ this.safeAppend(elements);
164
172
  }
165
173
  /**
166
174
  * Modify the text child node
@@ -252,7 +260,10 @@ class AstElement extends node_1.AstNode {
252
260
  for (let i = 0, cur = start + this.getAttribute('padding'); i < this.length; i++) {
253
261
  const child = this.childNodes[i];
254
262
  child.setAttribute('aIndex', cur);
255
- errors.push(...child.lint(cur, re));
263
+ const childErrors = child.lint(cur, re);
264
+ if (childErrors.length > 0) {
265
+ errors.push(...childErrors);
266
+ }
256
267
  cur += child.toString().length + this.getGaps(i);
257
268
  }
258
269
  return errors;
package/dist/lib/lsp.js CHANGED
@@ -21,7 +21,7 @@ const document_1 = require("./document");
21
21
  const cssRules = {
22
22
  'block-no-empty': null,
23
23
  'property-no-unknown': null,
24
- }, jsonSelector = document_1.jsonTags.map(s => `ext#${s}`).join(), mathSelector = ['math', 'chem', 'ce'].map(s => `ext#${s}`).join(), scores = new Map();
24
+ }, jsonSelector = document_1.jsonTags.map(s => `ext#${s}`).join(), mathTags = ['math', 'chem', 'ce'], mathSelector = mathTags.map(s => `ext#${s}`).join(), scores = new Map();
25
25
  let colors;
26
26
  /* NOT FOR BROWSER ONLY END */
27
27
  exports.tasks = new WeakMap();
@@ -282,22 +282,25 @@ class LanguageService {
282
282
  data;
283
283
  /* NOT FOR BROWSER ONLY */
284
284
  lilypond;
285
- /** @private */
286
- lilypondData;
285
+ #lilypondData;
286
+ #mathData;
287
+ #mathSet;
287
288
  /* NOT FOR BROWSER ONLY END */
288
289
  /** @param uri 任务标识 */
289
290
  constructor(uri) {
290
291
  exports.tasks.set(uri, this);
292
+ /* NOT FOR BROWSER ONLY */
293
+ const dataDir = path_1.default.join('..', '..', 'data'), extDir = path_1.default.join(dataDir, 'ext');
294
+ this.#lilypondData = require(path_1.default.join(extDir, 'score'));
295
+ this.#mathData = require(path_1.default.join(extDir, 'math'));
296
+ this.#mathSet = new Set(this.#mathData);
297
+ /* NOT FOR BROWSER ONLY END */
291
298
  Object.defineProperties(this, {
292
299
  config: { enumerable: false },
293
300
  data: {
294
- value: require(path_1.default.join('..', '..', 'data', 'signatures')),
295
- enumerable: false,
296
- },
297
- /* NOT FOR BROWSER ONLY */
298
- lilypondData: {
299
- value: require(path_1.default.join('..', '..', 'data', 'ext', 'score')),
300
301
  enumerable: false,
302
+ /* NOT FOR BROWSER ONLY */
303
+ value: require(path_1.default.join(dataDir, 'signatures')),
301
304
  },
302
305
  });
303
306
  }
@@ -408,14 +411,15 @@ class LanguageService {
408
411
  async provideDocumentColors(rgba, text, hsl = true) {
409
412
  const root = await this.#queue(text);
410
413
  /* NOT FOR BROWSER ONLY */
411
- /* eslint-disable require-atomic-updates */
412
- try {
413
- colors ??= new RegExp(String.raw `\b${Object.keys((await import('color-name')).default).join('|')}\b`, 'giu');
414
- }
415
- catch {
416
- colors = false;
417
- }
418
- /* eslint-enable require-atomic-updates */
414
+ colors ??= (async () => {
415
+ try {
416
+ return new RegExp(String.raw `\b${Object.keys((await import('color-name')).default).join('|')}\b`, 'giu');
417
+ }
418
+ catch {
419
+ return false;
420
+ }
421
+ })();
422
+ const re = await colors;
419
423
  /* NOT FOR BROWSER ONLY END */
420
424
  return root.querySelectorAll('attr-value,parameter-value,arg-default').reverse()
421
425
  .flatMap(token => {
@@ -432,14 +436,14 @@ class LanguageService {
432
436
  /* NOT FOR BROWSER ONLY END */
433
437
  }
434
438
  /* NOT FOR BROWSER ONLY */
435
- const isStyle = colors && type === 'attr-value' && parentNode.name === 'style';
439
+ const isStyle = re && type === 'attr-value' && parentNode.name === 'style';
436
440
  /* NOT FOR BROWSER ONLY END */
437
441
  return childNodes.filter((child) => child.type === 'text').reverse()
438
442
  .flatMap(child => {
439
443
  const { data } = child, parts = (0, common_1.splitColors)(data, hsl).filter(([, , , isColor]) => isColor);
440
444
  /* NOT FOR BROWSER ONLY */
441
445
  if (isStyle) {
442
- parts.push(...[...data.matchAll(colors)].map(({ index, 0: s }) => [s, index, index + s.length, true]));
446
+ parts.push(...[...data.matchAll(re)].map(({ index, 0: s }) => [s, index, index + s.length, true]));
443
447
  }
444
448
  /* NOT FOR BROWSER ONLY END */
445
449
  if (parts.length === 0) {
@@ -487,7 +491,7 @@ class LanguageService {
487
491
  + '|'
488
492
  + String.raw `(\{{2,4}|\[\[)\s*([^|{}<>[\]\s][^|{}<>[\]#]*)?` // braces and brackets
489
493
  + '|'
490
- + String.raw `(__(?:(?!__)[\p{L}\d_])*)` // behavior switch
494
+ + String.raw `(__(?:(?!__)[\p{L}\p{N}_])*)` // behavior switch
491
495
  + '|'
492
496
  + String.raw `(?<!\[)\[([a-z:/]*)` // protocol
493
497
  + '|'
@@ -686,23 +690,32 @@ class LanguageService {
686
690
  }
687
691
  const word = /\\?\b(?:\w|\b(?:->?|\.)|\bly:)+$/u.exec(curLine.slice(0, character))?.[0];
688
692
  if (word) {
689
- const { lilypondData } = this;
693
+ const data = this.#lilypondData;
690
694
  return word.startsWith('\\')
691
- ? getCompletion(lilypondData.filter(w => w.startsWith('\\')), 'Function', word, position)
695
+ ? getCompletion(data.filter(w => w.startsWith('\\')), 'Function', word, position)
692
696
  : [
693
- ...getCompletion(lilypondData.filter(w => /^[a-z]/u.test(w)), 'Variable', word, position),
694
- ...getCompletion(lilypondData.filter(w => /^[A-Z]/u.test(w)), 'Class', word, position),
697
+ ...getCompletion(data.filter(w => /^[a-z]/u.test(w)), 'Variable', word, position),
698
+ ...getCompletion(data.filter(w => /^[A-Z]/u.test(w)), 'Class', word, position),
695
699
  ];
696
700
  }
701
+ }
702
+ else if (type === 'ext-inner' && mathTags.includes(cur.name)) {
703
+ const word = /\\\w+$/u.exec(curLine.slice(0, character))?.[0];
704
+ if (word) {
705
+ const data = this.#mathData;
706
+ return getCompletion(cur.name === 'math' && parentNode.getAttr('chem') !== undefined
707
+ ? [...data, String.raw `\ce`]
708
+ : data, 'Function', word, position);
709
+ }
697
710
  /* NOT FOR BROWSER ONLY END */
698
711
  }
699
712
  else if ((0, exports.isAttr)(cur) && isHtmlAttr(parentNode)) {
700
- const data = lint_1.htmlData.provideValues(parentNode.tag, parentNode.name);
713
+ const data = (0, lint_1.provideValues)(parentNode.tag, parentNode.name);
701
714
  if (data.length === 0) {
702
715
  return undefined;
703
716
  }
704
717
  const val = this.#text.slice(cur.getAbsoluteIndex(), root.indexFromPos(line, character)).trimStart();
705
- return getCompletion(data.map(({ name }) => name), 'Value', val, position);
718
+ return getCompletion(data, 'Value', val, position);
706
719
  }
707
720
  return undefined;
708
721
  }
@@ -827,32 +840,42 @@ class LanguageService {
827
840
  }));
828
841
  }
829
842
  }
830
- const MathJax = await document_1.MathJax, mathDiagnostics = MathJax
831
- ? root.querySelectorAll(mathSelector)
832
- .map(({ selfClosing, innerText, lastChild, name }) => {
833
- if (selfClosing) {
834
- return [];
835
- }
843
+ const MathJax = await document_1.MathJax, data = this.#mathSet, mathDiagnostics = root.querySelectorAll(mathSelector)
844
+ .map(token => {
845
+ const { selfClosing, innerText, lastChild, name } = token;
846
+ if (selfClosing) {
847
+ return [];
848
+ }
849
+ const hasCe = name === 'math' && token.getAttr('chem') !== undefined, mathErrors = [...innerText.matchAll(/\\\w+/gu)]
850
+ .filter(([macro]) => !(hasCe && macro === String.raw `\ce` || data.has(macro)))
851
+ .map(({ 0: macro, index }) => {
852
+ const aIndex = lastChild.getAbsoluteIndex() + index;
853
+ return {
854
+ range: createRange(root, aIndex, aIndex + macro.length),
855
+ severity: 2,
856
+ source: 'MathJax',
857
+ code: 'UnknownMacro',
858
+ message: `Unknown macro "${macro}"`,
859
+ };
860
+ });
861
+ if (MathJax) {
836
862
  try {
837
863
  MathJax.tex2mml(name === 'math' ? innerText : String.raw `\ce{${innerText}}`);
838
- return [];
839
864
  }
840
865
  catch (e) {
841
866
  if (e && typeof e === 'object' && 'id' in e && 'message' in e) {
842
- return [
843
- {
844
- range: createNodeRange(lastChild),
845
- severity: 1,
846
- source: 'MathJax',
847
- code: e.id,
848
- message: e.message,
849
- },
850
- ];
867
+ mathErrors.push({
868
+ range: createNodeRange(lastChild),
869
+ severity: 1,
870
+ source: 'MathJax',
871
+ code: e.id,
872
+ message: e.message,
873
+ });
851
874
  }
852
- return [];
853
875
  }
854
- })
855
- : [];
876
+ }
877
+ return mathErrors;
878
+ });
856
879
  /* NOT FOR BROWSER ONLY END */
857
880
  return [
858
881
  diagnostics,
@@ -915,7 +938,10 @@ class LanguageService {
915
938
  if (document_1.jsonLSP) {
916
939
  for (const { selfClosing, lastChild } of root.querySelectorAll(jsonSelector)) {
917
940
  if (!selfClosing) {
918
- ranges.push(...document_1.jsonLSP.getFoldingRanges(new document_1.EmbeddedJSONDocument(root, lastChild)));
941
+ const foldingRanges = document_1.jsonLSP.getFoldingRanges(new document_1.EmbeddedJSONDocument(root, lastChild));
942
+ if (foldingRanges.length > 0) {
943
+ ranges.push(...foldingRanges);
944
+ }
919
945
  }
920
946
  }
921
947
  }
@@ -1178,10 +1204,10 @@ class LanguageService {
1178
1204
  const textDoc = new document_1.EmbeddedJSONDocument(root, offsetNode);
1179
1205
  return await document_1.jsonLSP.doHover(textDoc, position, textDoc.jsonDoc) ?? undefined;
1180
1206
  }
1181
- else if (lint_1.htmlData.provideTags && lint_1.htmlData.provideAttributes) {
1207
+ else if (document_1.htmlData) {
1182
1208
  if (type === 'html' && offset <= offsetNode.getRelativeIndex(0)
1183
1209
  || type === 'html-attr-dirty' && offset === 0 && parentNode.firstChild === offsetNode) {
1184
- const token = type === 'html' ? offsetNode : parentNode.parentNode, data = lint_1.htmlData.provideTags().find(({ name: n }) => n === token.name);
1210
+ const token = type === 'html' ? offsetNode : parentNode.parentNode, data = document_1.htmlData.provideTags().find(({ name: n }) => n === token.name);
1185
1211
  if (data?.description) {
1186
1212
  const start = positionAt(root, token.getAbsoluteIndex());
1187
1213
  return {
@@ -1197,7 +1223,7 @@ class LanguageService {
1197
1223
  }
1198
1224
  }
1199
1225
  else if (type === 'attr-key' && isHtmlAttr(parentNode)) {
1200
- const data = lint_1.htmlData.provideAttributes(parentNode.tag).find(({ name: n }) => n === parentNode.name);
1226
+ const data = document_1.htmlData.provideAttributes(parentNode.tag).find(({ name: n }) => n === parentNode.name);
1201
1227
  if (data?.description) {
1202
1228
  return {
1203
1229
  contents: data.description,
@@ -1273,16 +1299,20 @@ class LanguageService {
1273
1299
  * @param text source Wikitext / 源代码
1274
1300
  */
1275
1301
  async provideInlayHints(text) {
1276
- const hints = [], root = await this.#queue(text);
1302
+ const root = await this.#queue(text);
1303
+ let hints = [];
1277
1304
  for (const token of root.querySelectorAll('template,magic-word#invoke').reverse()) {
1278
1305
  const { type, childNodes } = token;
1279
- hints.push(...childNodes.slice(type === 'template' ? 1 : 3).filter(({ anon }) => anon)
1280
- .reverse()
1281
- .map((parameter) => ({
1282
- position: positionAt(root, parameter.getAbsoluteIndex()),
1283
- label: `${parameter.name}=`,
1284
- kind: 2,
1285
- })));
1306
+ hints = [
1307
+ ...hints,
1308
+ ...childNodes.slice(type === 'template' ? 1 : 3).filter(({ anon }) => anon)
1309
+ .reverse()
1310
+ .map((parameter) => ({
1311
+ position: positionAt(root, parameter.getAbsoluteIndex()),
1312
+ label: `${parameter.name}=`,
1313
+ kind: 2,
1314
+ })),
1315
+ ];
1286
1316
  }
1287
1317
  return hints;
1288
1318
  }
package/dist/lib/node.js CHANGED
@@ -185,13 +185,6 @@ class AstNode {
185
185
  ...this.getRootNode().posFromIndex(this.getAbsoluteIndex()),
186
186
  };
187
187
  }
188
- /** @private */
189
- seal(key, permanent) {
190
- Object.defineProperty(this, key, {
191
- enumerable: !permanent && Boolean(this[key]),
192
- configurable: true,
193
- });
194
- }
195
188
  /**
196
189
  * Whether to be of a certain type
197
190
  *
package/dist/lib/text.js CHANGED
@@ -55,7 +55,7 @@ const errorSyntaxUrl = new RegExp(source, 'giu'), noLinkTypes = new Set(['attr-v
55
55
  let wordRegex;
56
56
  try {
57
57
  // eslint-disable-next-line prefer-regex-literals, es-x/no-regexp-unicode-property-escapes
58
- wordRegex = new RegExp(String.raw `[\p{L}\d_]`, 'u');
58
+ wordRegex = new RegExp(String.raw `[\p{L}\p{N}_]`, 'u');
59
59
  }
60
60
  catch /* istanbul ignore next */ {
61
61
  wordRegex = /\w/u;
@@ -73,11 +73,7 @@ class AstText extends node_1.AstNode {
73
73
  /** @param text 包含文本 */
74
74
  constructor(text) {
75
75
  super();
76
- Object.defineProperties(this, {
77
- data: {
78
- value: text,
79
- },
80
- });
76
+ this.data = text;
81
77
  }
82
78
  /** @private */
83
79
  toString(skip) {
@@ -143,7 +139,7 @@ class AstText extends node_1.AstNode {
143
139
  || char === '[' && type === 'ext-link-text' && (/&(?:rbrack|#93|#x5[Dd];);/u.test(data.slice(index + 1))
144
140
  || nextSibling?.is('ext') && nextName === 'nowiki'
145
141
  && nextSibling.innerText?.includes(']'))
146
- || magicLink && (!parentNode.getAttribute('plain') || noLinkTypes.has(type))) {
142
+ || magicLink && (!parentNode.isPlain() || noLinkTypes.has(type))) {
147
143
  continue;
148
144
  }
149
145
  else if (char === ']' && (index || length > 1)) {
package/dist/lib/title.js CHANGED
@@ -82,7 +82,7 @@ class Title {
82
82
  }
83
83
  const m = title.split(':');
84
84
  if (m.length > 1) {
85
- const k = m[0].trim().toLowerCase(), id = Object.prototype.hasOwnProperty.call(config.nsid, k) && config.nsid[k];
85
+ const k = (0, string_1.trimLc)(m[0]), id = Object.prototype.hasOwnProperty.call(config.nsid, k) && config.nsid[k];
86
86
  if (id) {
87
87
  ns = id;
88
88
  title = m.slice(1).join(':').trim();
@@ -112,11 +112,6 @@ class Title {
112
112
  if (!this.#path.includes('$1')) {
113
113
  this.#path += `${this.#path.endsWith('/') ? '' : '/'}$1`;
114
114
  }
115
- if (!temporary) {
116
- Object.defineProperties(this, {
117
- encoded: { enumerable: false, writable: false },
118
- });
119
- }
120
115
  }
121
116
  /**
122
117
  * Check if the title is a redirect
@@ -6,7 +6,7 @@ const debug_1 = require("../util/debug");
6
6
  * 子节点含有AttributesToken的类
7
7
  * @param i AttributesToken子节点的位置
8
8
  */
9
- const attributesParent = (i = 0) => (constructor, _) => {
9
+ const attributesParent = (i = 0) => (constructor) => {
10
10
  /** 子节点含有AttributesToken的类 */
11
11
  class AttributesParent extends constructor {
12
12
  /** AttributesToken子节点 */
@@ -0,0 +1,4 @@
1
+ /**
2
+ * 给定 gap 的类
3
+ * @param gap
4
+ */
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.gapped = void 0;
4
+ const debug_1 = require("../util/debug");
5
+ /**
6
+ * 给定 gap 的类
7
+ * @param gap
8
+ */
9
+ const gapped = (gap = 1) => (constructor) => {
10
+ /** 不可增删子节点的类 */
11
+ class GappedToken extends constructor {
12
+ /** @private */
13
+ getGaps() {
14
+ return gap;
15
+ }
16
+ }
17
+ (0, debug_1.mixin)(GappedToken, constructor);
18
+ return GappedToken;
19
+ };
20
+ exports.gapped = gapped;
@@ -7,7 +7,7 @@ const debug_1 = require("../util/debug");
7
7
  * @param linter 是否覆写 lint 方法
8
8
  * @param html 是否覆写 toHtml 方法
9
9
  */
10
- const hiddenToken = (linter = true, html = true) => (constructor, _) => {
10
+ const hiddenToken = (linter = true, html = true) => (constructor) => {
11
11
  /** 解析后不可见的类 */
12
12
  class AnyHiddenToken extends constructor {
13
13
  /** 没有可见部分 */
@@ -0,0 +1,4 @@
1
+ /**
2
+ * 逐行解析的类
3
+ * @ignore
4
+ */
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.multiLine = void 0;
4
+ const debug_1 = require("../util/debug");
5
+ /**
6
+ * 逐行解析的类
7
+ * @ignore
8
+ */
9
+ const multiLine = (constructor) => {
10
+ /** 不可包含换行符的类 */
11
+ class MultiLineToken extends constructor {
12
+ toString(skip) {
13
+ return super.toString(skip, '\n');
14
+ }
15
+ text() {
16
+ return super.text('\n').replace(/\n\s*\n/gu, '\n');
17
+ }
18
+ /** @private */
19
+ getGaps() {
20
+ return 1;
21
+ }
22
+ }
23
+ (0, debug_1.mixin)(MultiLineToken, constructor);
24
+ return MultiLineToken;
25
+ };
26
+ exports.multiLine = multiLine;