wikiparser-node 0.0.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 (65) hide show
  1. package/.eslintrc.json +229 -0
  2. package/LICENSE +674 -0
  3. package/README.md +1896 -0
  4. package/config/default.json +766 -0
  5. package/config/llwiki.json +686 -0
  6. package/config/moegirl.json +721 -0
  7. package/index.js +159 -0
  8. package/jsconfig.json +7 -0
  9. package/lib/element.js +690 -0
  10. package/lib/node.js +357 -0
  11. package/lib/ranges.js +122 -0
  12. package/lib/title.js +57 -0
  13. package/mixin/attributeParent.js +67 -0
  14. package/mixin/fixedToken.js +32 -0
  15. package/mixin/hidden.js +22 -0
  16. package/package.json +30 -0
  17. package/parser/brackets.js +107 -0
  18. package/parser/commentAndExt.js +61 -0
  19. package/parser/externalLinks.js +30 -0
  20. package/parser/hrAndDoubleUnderscore.js +26 -0
  21. package/parser/html.js +41 -0
  22. package/parser/links.js +92 -0
  23. package/parser/magicLinks.js +40 -0
  24. package/parser/quotes.js +63 -0
  25. package/parser/table.js +97 -0
  26. package/src/arg.js +150 -0
  27. package/src/atom/hidden.js +10 -0
  28. package/src/atom/index.js +33 -0
  29. package/src/attribute.js +342 -0
  30. package/src/extLink.js +116 -0
  31. package/src/heading.js +91 -0
  32. package/src/html.js +144 -0
  33. package/src/imageParameter.js +172 -0
  34. package/src/index.js +602 -0
  35. package/src/link/category.js +88 -0
  36. package/src/link/file.js +201 -0
  37. package/src/link/index.js +214 -0
  38. package/src/listToken.js +47 -0
  39. package/src/magicLink.js +66 -0
  40. package/src/nowiki/comment.js +45 -0
  41. package/src/nowiki/doubleUnderscore.js +42 -0
  42. package/src/nowiki/hr.js +41 -0
  43. package/src/nowiki/index.js +37 -0
  44. package/src/nowiki/noinclude.js +24 -0
  45. package/src/nowiki/quote.js +37 -0
  46. package/src/onlyinclude.js +42 -0
  47. package/src/parameter.js +165 -0
  48. package/src/syntax.js +80 -0
  49. package/src/table/index.js +867 -0
  50. package/src/table/td.js +259 -0
  51. package/src/table/tr.js +244 -0
  52. package/src/tagPair/ext.js +85 -0
  53. package/src/tagPair/include.js +45 -0
  54. package/src/tagPair/index.js +91 -0
  55. package/src/transclude.js +627 -0
  56. package/tool/index.js +898 -0
  57. package/typings/element.d.ts +28 -0
  58. package/typings/index.d.ts +49 -0
  59. package/typings/node.d.ts +23 -0
  60. package/typings/parser.d.ts +9 -0
  61. package/typings/table.d.ts +14 -0
  62. package/typings/token.d.ts +21 -0
  63. package/typings/tool.d.ts +10 -0
  64. package/util/debug.js +70 -0
  65. package/util/string.js +60 -0
package/tool/index.js ADDED
@@ -0,0 +1,898 @@
1
+ 'use strict';
2
+
3
+ const {typeError, externalUse} = require('../util/debug'),
4
+ {text} = require('../util/string'),
5
+ Token = require('../src'),
6
+ assert = require('assert/strict');
7
+
8
+ const /** @type {WeakMap<Token, Record<string, any>>} */ dataStore = new WeakMap();
9
+
10
+ /**
11
+ * @param {string|Token|Token[]} selector
12
+ * @returns {(token: Token) => boolean}
13
+ */
14
+ const matchesGenerator = selector => {
15
+ if (typeof selector === 'string') {
16
+ return token => token instanceof Token && token.matches(selector);
17
+ } else if (Array.isArray(selector)) {
18
+ return token => selector.includes(token);
19
+ } else if (selector instanceof Token) {
20
+ return token => token === selector;
21
+ }
22
+ typeError('String', 'Token', 'Array');
23
+ };
24
+
25
+ /** @extends {Array<Token>} */
26
+ class TokenCollection extends Array {
27
+ /** @type {TokenCollection} */ prevObject;
28
+ /** @type {Set<Token>} */ #roots = new Set();
29
+
30
+ /** @param {...string|Token} arr */
31
+ constructor(...arr) {
32
+ super();
33
+ if (arr.length === 1 && arr[0] === 0) {
34
+ return;
35
+ }
36
+ for (const token of arr) {
37
+ if (token === undefined) {
38
+ continue;
39
+ } else if (typeof token === 'string') {
40
+ this.push(token);
41
+ } else if (!(token instanceof Token)) {
42
+ typeError('String', 'Token');
43
+ } else if (!this.includes(token)) {
44
+ this.#roots.add(token.getRootNode());
45
+ this.push(token);
46
+ }
47
+ }
48
+ Object.defineProperty(this, 'prevObject', {enumerable: false});
49
+ this.#sort();
50
+ }
51
+
52
+ #sort() {
53
+ if (this.some(token => typeof token === 'string')) {
54
+ return;
55
+ }
56
+ const rootArray = [...this.#roots];
57
+ this.sort((a, b) => {
58
+ const aRoot = a.getRootNode(),
59
+ bRoot = b.getRootNode();
60
+ return aRoot === bRoot ? a.comparePosition(b) : rootArray.indexOf(aRoot) - rootArray.indexOf(bRoot);
61
+ });
62
+ }
63
+
64
+ toArray() {
65
+ return Array.from(this);
66
+ }
67
+
68
+ _filter(selector = '') {
69
+ const arr = this.toArray().filter(ele => ele instanceof Token);
70
+ if (selector) {
71
+ return arr.filter(ele => ele.matches(selector));
72
+ }
73
+ return arr;
74
+ }
75
+
76
+ _find() {
77
+ return super.find(ele => ele instanceof Token);
78
+ }
79
+
80
+ /** @param {(arr: Token[]) => (string|Token)[]} map */
81
+ _create(map, filter = '') {
82
+ const $arr = $(map(this._filter())),
83
+ $filtered = filter ? $arr.filter(filter) : $arr;
84
+ $filtered.prevObject = this;
85
+ return $filtered;
86
+ }
87
+
88
+ /**
89
+ * @template {unknown} T
90
+ * @param {T} num
91
+ * @returns {T extends number ? string|Token : (string|Token)[]}
92
+ */
93
+ get(num) {
94
+ if (typeof num === 'number') {
95
+ return this.at(num);
96
+ }
97
+ return this.toArray();
98
+ }
99
+
100
+ /** @param {CollectionCallback<void, string|Token>} callback */
101
+ each(callback) {
102
+ this.forEach((ele, i) => { // 不能使用`for`...`of`
103
+ callback.call(ele, i, ele);
104
+ });
105
+ return this;
106
+ }
107
+
108
+ /** @param {CollectionCallback<any, string|Token>} callback */
109
+ map(callback) {
110
+ const arr = this.toArray().map((ele, i) => callback.call(ele, i, ele));
111
+ try {
112
+ const $arr = $(arr);
113
+ $arr.prevObject = this;
114
+ return $arr;
115
+ } catch {
116
+ return arr;
117
+ }
118
+ }
119
+
120
+ /**
121
+ * @param {number} start
122
+ * @param {number} end
123
+ */
124
+ slice(start, end) {
125
+ const $arr = $(this.toArray().slice(start, end));
126
+ $arr.prevObject = this;
127
+ return $arr;
128
+ }
129
+
130
+ first() {
131
+ return this.slice(0, 1);
132
+ }
133
+
134
+ last() {
135
+ return this.slice(-1);
136
+ }
137
+
138
+ /** @param {number} i */
139
+ eq(i) {
140
+ return this.slice(i, i === -1 ? undefined : i + 1);
141
+ }
142
+
143
+ /** 使用空字符串join */
144
+ toString() {
145
+ return this.toArray().map(String).join('');
146
+ }
147
+
148
+ /**
149
+ * @template {unknown} T
150
+ * @param {T} str
151
+ * @returns {T extends string|Function ? this : string}
152
+ */
153
+ text(str) {
154
+ /** @type {(ele: Token, i: number, str: string) => string} */
155
+ const callback = typeof str === 'function' ? str.call : () => str;
156
+ if (['string', 'function'].includes(typeof str)) {
157
+ for (const [i, ele] of this.entries()) {
158
+ if (ele instanceof Token) {
159
+ try {
160
+ ele.replaceChildren(callback(ele, i, ele.text()));
161
+ } catch {}
162
+ }
163
+ }
164
+ return this;
165
+ }
166
+ return text(this.toArray());
167
+ }
168
+
169
+ /** @param {string|CollectionCallback<boolean, string|Token>|Token|Token[]} selector */
170
+ is(selector) {
171
+ if (typeof selector === 'function') {
172
+ return this.some((ele, i) => selector.call(ele, i, ele));
173
+ }
174
+ const matches = matchesGenerator(selector);
175
+ return this.some(matches);
176
+ }
177
+
178
+ /** @param {string|CollectionCallback<boolean, string|Token>|Token|Token[]} selector */
179
+ filter(selector) {
180
+ const arr = this.toArray();
181
+ let $arr;
182
+ if (typeof selector === 'function') {
183
+ $arr = $(arr.filter((ele, i) => selector.call(ele, i, ele)));
184
+ } else {
185
+ const matches = matchesGenerator(selector);
186
+ $arr = $(arr.filter(matches));
187
+ }
188
+ $arr.prevObject = this;
189
+ return $arr;
190
+ }
191
+
192
+ /** @param {string|CollectionCallback<boolean, string|Token>|Token|Token[]} selector */
193
+ not(selector) {
194
+ const arr = this.toArray();
195
+ let $arr;
196
+ if (typeof selector === 'function') {
197
+ $arr = $(arr.filter((ele, i) => !selector.call(ele, i, ele)));
198
+ } else if (typeof selector === 'string') {
199
+ $arr = $(arr.filter(ele => ele instanceof Token && !ele.matches(selector)));
200
+ } else {
201
+ const matches = matchesGenerator(selector);
202
+ $arr = $(arr.filter(ele => !matches(ele)));
203
+ }
204
+ $arr.prevObject = this;
205
+ return $arr;
206
+ }
207
+
208
+ /** @param {string|Token|Token[]} selector */
209
+ find(selector) {
210
+ let /** @type {CollectionMap} */ map;
211
+ if (typeof selector === 'string') {
212
+ map = arr => arr.flatMap(token => token.querySelectorAll(selector));
213
+ } else if (Array.isArray(selector)) {
214
+ map = arr => [...selector].filter(ele => arr.some(token => token.contains(ele)));
215
+ } else if (selector instanceof Token) {
216
+ map = arr => arr.some(token => token.contains(selector)) ? [selector] : [];
217
+ } else {
218
+ typeError('String', 'Token', 'Array');
219
+ }
220
+ return this._create(map);
221
+ }
222
+
223
+ /** @param {string|Token} selector */
224
+ has(selector) {
225
+ const arr = this._filter();
226
+ if (typeof selector === 'string') {
227
+ return arr.some(ele => ele.querySelector(selector));
228
+ } else if (selector instanceof Token) {
229
+ return arr.some(ele => ele.contains(selector));
230
+ }
231
+ typeError('String', 'Token');
232
+ }
233
+
234
+ /** @param {string} selector */
235
+ closest(selector) {
236
+ if (typeof selector !== 'string') {
237
+ typeError('String');
238
+ }
239
+ return this._create(arr => arr.map(ele => ele.closest(selector)));
240
+ }
241
+
242
+ index() {
243
+ const firstToken = this._find();
244
+ if (!firstToken) {
245
+ return -1;
246
+ }
247
+ const {parentNode} = firstToken;
248
+ return parentNode ? parentNode.childNodes.indexOf(firstToken) : 0;
249
+ }
250
+
251
+ /** @param {string|Token|(string|Token)[]} elements */
252
+ add(elements) {
253
+ elements = Array.isArray(elements) ? elements : [elements];
254
+ const $arr = $([...this, ...elements]);
255
+ $arr.prevObject = this;
256
+ return $arr;
257
+ }
258
+
259
+ /** @param {string} selector */
260
+ addBack(selector) {
261
+ return this.add(selector ? this.prevObject.filter(selector) : this.prevObject);
262
+ }
263
+
264
+ parent(selector = '') {
265
+ return this._create(arr => arr.map(ele => ele.parentNode), selector);
266
+ }
267
+
268
+ parents(selector = '') {
269
+ return this._create(arr => arr.flatMap(ele => ele.getAncestors()), selector);
270
+ }
271
+
272
+ next(selector = '') {
273
+ return this._create(arr => arr.map(ele => ele.nextElementSibling), selector);
274
+ }
275
+
276
+ prev(selector = '') {
277
+ return this._create(arr => arr.map(ele => ele.previousElementSibling), selector);
278
+ }
279
+
280
+ /**
281
+ * @param {number|(i: number) => number} start
282
+ * @param {number|(i: number) => number} count
283
+ */
284
+ _siblings(start, count, selector = '') {
285
+ return this._create(arr => arr.flatMap(ele => {
286
+ const {parentElement} = ele;
287
+ if (!parentElement) {
288
+ return undefined;
289
+ }
290
+ const {children} = parentElement,
291
+ i = children.indexOf(ele);
292
+ children.splice(
293
+ typeof start === 'function' ? start(i) : start,
294
+ typeof count === 'function' ? count(i) : count,
295
+ );
296
+ return children;
297
+ }), selector);
298
+ }
299
+
300
+ nextAll(selector = '') {
301
+ return this._siblings(0, i => i + 1, selector);
302
+ }
303
+
304
+ prevAll(selector = '') {
305
+ return this._siblings(i => i, Infinity, selector);
306
+ }
307
+
308
+ siblings(selector = '') {
309
+ return this._siblings(i => i, 1, selector);
310
+ }
311
+
312
+ /**
313
+ * @param {'parents'|'nextAll'|'prevAll'} method
314
+ * @param {string|Token|Token[]} selector
315
+ */
316
+ _until(method, selector, filter = '') {
317
+ const matches = matchesGenerator(selector);
318
+ return this._create(arr => arr.flatMap(ele => {
319
+ const tokens = $(ele)[method]().toArray(),
320
+ tokenArray = method === 'nextAll' ? tokens : tokens.reverse(),
321
+ until = tokenArray.findIndex(end => matches(end));
322
+ return tokenArray.slice(0, until);
323
+ }), filter);
324
+ }
325
+
326
+ /** @param {string|Token|Token[]} selector */
327
+ parentsUntil(selector, filter = '') {
328
+ return this._until('parents', selector, filter);
329
+ }
330
+
331
+ /** @param {string|Token|Token[]} selector */
332
+ nextUntil(selector, filter = '') {
333
+ return this._until('nextAll', selector, filter);
334
+ }
335
+
336
+ /** @param {string|Token|Token[]} selector */
337
+ prevUntil(selector, filter = '') {
338
+ return this._until('prevAll', selector, filter);
339
+ }
340
+
341
+ children(selector = '') {
342
+ return this._create(arr => arr.flatMap(ele => ele.children), selector);
343
+ }
344
+
345
+ contents() {
346
+ return this._create(arr => arr.flatMap(ele => ele.childNodes));
347
+ }
348
+
349
+ /** @param {[string|Record<string, any>]} key */
350
+ data(key, value) {
351
+ if (value !== undefined && typeof key !== 'string') {
352
+ typeError('String');
353
+ } else if (value === undefined && typeof key !== 'object') {
354
+ const data = $.dataStore.get(this._find());
355
+ return key === undefined ? data : data?.[key];
356
+ }
357
+ for (const token of this._filter()) {
358
+ if (!$.dataStore.has(token)) {
359
+ $.dataStore.set(token, {});
360
+ }
361
+ const data = $.dataStore.get(token);
362
+ if (typeof key === 'string') {
363
+ data[key] = value;
364
+ } else {
365
+ Object.assign(data, key);
366
+ }
367
+ }
368
+ return this;
369
+ }
370
+
371
+ /** @param {string|string[]} name */
372
+ removeData(name) {
373
+ if (name !== undefined && typeof name !== 'string' && !Array.isArray(name)) {
374
+ typeError('String', 'Array');
375
+ }
376
+ name = typeof name === 'string' ? name.split(/\s/) : name;
377
+ for (const token of this._filter()) {
378
+ if (!$.dataStore.has(token)) {
379
+ continue;
380
+ } else if (name === undefined) {
381
+ $.dataStore.delete(token);
382
+ } else {
383
+ const data = $.dataStore.get(token);
384
+ for (const key of name) {
385
+ delete data[key];
386
+ }
387
+ }
388
+ }
389
+ return this;
390
+ }
391
+
392
+ /**
393
+ * @param {string|Record<string, AstListener>} events
394
+ * @param {string|AstListener} selector
395
+ * @param {AstListener} handler
396
+ */
397
+ _addEventListener(events, selector, handler, once = false) {
398
+ if (!['string', 'object'].includes(typeof events)) {
399
+ typeError('String', 'Object');
400
+ } else if (typeof selector === 'function') {
401
+ handler = selector;
402
+ selector = undefined;
403
+ }
404
+ const eventPair = typeof events === 'string'
405
+ ? events.split(/\s/).map(/** @returns {[string, AstListener]} */ event => [event, handler])
406
+ : Object.entries(events);
407
+ for (const token of this._filter(selector)) {
408
+ for (const [event, listener] of eventPair) {
409
+ token.addEventListener(event, listener, {once});
410
+ }
411
+ }
412
+ return this;
413
+ }
414
+
415
+ /**
416
+ * @param {string|Record<string, AstListener>} events
417
+ * @param {string|AstListener} selector
418
+ * @param {AstListener} handler
419
+ */
420
+ on(events, selector, handler) {
421
+ return this._addEventListener(events, selector, handler);
422
+ }
423
+
424
+ /**
425
+ * @param {string|Record<string, AstListener>} events
426
+ * @param {string|AstListener} selector
427
+ * @param {AstListener} handler
428
+ */
429
+ one(events, selector, handler) {
430
+ return this._addEventListener(events, selector, handler, true);
431
+ }
432
+
433
+ /**
434
+ * @param {string|Record<string, AstListener>|undefined} events
435
+ * @param {string|AstListener} selector
436
+ * @param {AstListener} handler
437
+ */
438
+ off(events, selector, handler) {
439
+ if (!['string', 'object', 'undefined'].includes(typeof events)) {
440
+ typeError('String', 'Object');
441
+ }
442
+ handler = typeof selector === 'function' ? selector : handler;
443
+ let eventPair;
444
+ if (events) {
445
+ eventPair = typeof events === 'string'
446
+ ? events.split(/\s/).map(/** @returns {[string, AstListener]} */ event => [event, handler])
447
+ : Object.entries(events);
448
+ }
449
+ for (const token of this._filter(selector)) {
450
+ if (events === undefined) {
451
+ token.removeAllEventListeners();
452
+ } else {
453
+ for (const [event, listener] of eventPair) {
454
+ if (typeof event !== 'string' || !['function', 'undefined'].includes(typeof listener)) {
455
+ typeError('String', 'Function');
456
+ } else if (listener) {
457
+ token.removeEventListener(event, listener);
458
+ } else {
459
+ token.removeAllEventListeners(event);
460
+ }
461
+ }
462
+ }
463
+ }
464
+ return this;
465
+ }
466
+
467
+ /** @param {string|Event} event */
468
+ trigger(event, data) {
469
+ for (const token of this._filter()) {
470
+ const e = typeof event === 'string' ? new Event(event, {bubbles: true}) : new Event(event.type, event);
471
+ token.dispatchEvent(e, data);
472
+ }
473
+ return this;
474
+ }
475
+
476
+ /** @param {string|Event} event */
477
+ triggerHandler(event, data) {
478
+ const firstToken = this._find();
479
+ if (!firstToken) {
480
+ return;
481
+ }
482
+ const e = typeof event === 'string' ? new Event(event) : event,
483
+ listeners = firstToken.listEventListeners(typeof event === 'string' ? event : event.type);
484
+ let result;
485
+ for (const listener of listeners) {
486
+ result = listener(e, data);
487
+ }
488
+ return result;
489
+ }
490
+
491
+ /**
492
+ * @param {'append'|'prepend'|'before'|'after'|'replaceChildren'|'replaceWith'} method
493
+ * @param {string|Token|CollectionCallback<string|Token|(string|Token)[], string>} content
494
+ * @param {...string|Token|(string|Token)[]} additional
495
+ */
496
+ _insert(method, content, ...additional) {
497
+ if (typeof content === 'function') {
498
+ for (const [i, token] of this.entries()) {
499
+ if (token instanceof Token) {
500
+ const result = content.call(token, i, token.toString());
501
+ if (typeof result === 'string' || result instanceof Token) {
502
+ token[method](result);
503
+ } else if (Array.isArray(result)) {
504
+ token[method](...result);
505
+ } else {
506
+ typeError('String', 'Token');
507
+ }
508
+ }
509
+ }
510
+ } else {
511
+ for (const token of this) {
512
+ if (token instanceof Token) {
513
+ token[method](...content, ...additional.flat());
514
+ }
515
+ }
516
+ }
517
+ return this;
518
+ }
519
+
520
+ /**
521
+ * @param {string|Token|CollectionCallback<string|Token|(string|Token)[], string>} content
522
+ * @param {...string|Token|(string|Token)[]} additional
523
+ */
524
+ append(content, ...additional) {
525
+ return this._insert('append', content, ...additional);
526
+ }
527
+
528
+ /**
529
+ * @param {string|Token|CollectionCallback<string|Token|(string|Token)[], string>} content
530
+ * @param {...string|Token|(string|Token)[]} additional
531
+ */
532
+ prepend(content, ...additional) {
533
+ return this._insert('prepend', content, ...additional);
534
+ }
535
+
536
+ /**
537
+ * @param {string|Token|CollectionCallback<string|Token|(string|Token)[], string>} content
538
+ * @param {...string|Token|(string|Token)[]} additional
539
+ */
540
+ before(content, ...additional) {
541
+ return this._insert('before', content, ...additional);
542
+ }
543
+
544
+ /**
545
+ * @param {string|Token|CollectionCallback<string|Token|(string|Token)[], string>} content
546
+ * @param {...string|Token|(string|Token)[]} additional
547
+ */
548
+ after(content, ...additional) {
549
+ return this._insert('after', content, ...additional);
550
+ }
551
+
552
+ /**
553
+ * @template {unknown} T
554
+ * @param {T} content
555
+ * @returns {T extends string|Token|CollectionCallback<string|Token|(string|Token)[], string> ? this : string}
556
+ */
557
+ html(content) {
558
+ if (content === undefined) {
559
+ return this.toString();
560
+ }
561
+ return this._insert('replaceChildren', content);
562
+ }
563
+
564
+ /** @param {string|Token|CollectionCallback<string|Token|(string|Token)[], string>} content */
565
+ replaceWith(content) {
566
+ return this._insert('replaceWith', content);
567
+ }
568
+
569
+ remove(selector = '') {
570
+ for (const token of this.removeData()._filter(selector)) {
571
+ token.remove();
572
+ token.removeAllEventListeners();
573
+ }
574
+ return this;
575
+ }
576
+
577
+ detach(selector = '') {
578
+ for (const token of this._filter(selector)) {
579
+ token.remove();
580
+ }
581
+ return this;
582
+ }
583
+
584
+ empty() {
585
+ for (const token of this) {
586
+ if (token instanceof Token) {
587
+ token.replaceChildren();
588
+ }
589
+ }
590
+ return this;
591
+ }
592
+
593
+ /**
594
+ * @param {'append'|'prepend'|'before'|'after'|'replaceWith'} method
595
+ * @param {Token|Token[]} target
596
+ */
597
+ _insertAdjacent(method, target) {
598
+ if (target instanceof Token) {
599
+ target[method](...this);
600
+ } else if (Array.isArray(target)) {
601
+ for (const token of target) {
602
+ if (token instanceof Token) {
603
+ token[method](...this);
604
+ }
605
+ }
606
+ } else {
607
+ typeError('Token', 'Array');
608
+ }
609
+ return this;
610
+ }
611
+
612
+ /** @param {Token|Token[]} target */
613
+ appendTo(target) {
614
+ return this._insertAdjacent('append', target);
615
+ }
616
+
617
+ /** @param {Token|Token[]} target */
618
+ prependTo(target) {
619
+ return this._insertAdjacent('prepend', target);
620
+ }
621
+
622
+ /** @param {Token|Token[]} target */
623
+ insertBefore(target) {
624
+ return this._insertAdjacent('before', target);
625
+ }
626
+
627
+ /** @param {Token|Token[]} target */
628
+ insertAfter(target) {
629
+ return this._insertAdjacent('after', target);
630
+ }
631
+
632
+ /** @param {Token|Token[]} target */
633
+ replaceAll(target) {
634
+ return this._insertAdjacent('replaceWith', target);
635
+ }
636
+
637
+ /** @param {string|string[]|CollectionCallback<string, string>} value */
638
+ val(value) {
639
+ if (value === undefined) {
640
+ const firstToken = this._find();
641
+ return firstToken?.getValue && firstToken.getValue();
642
+ }
643
+ let /** @type {(i: number, token: Token) => string} */ toValue;
644
+ if (typeof value === 'string') {
645
+ toValue = () => value;
646
+ } else if (typeof value === 'function') {
647
+ toValue = (i, token) => value.call(token, i, token.getValue && token.getValue());
648
+ } else if (Array.isArray(value)) {
649
+ toValue = i => value[i];
650
+ } else {
651
+ typeError('String', 'Array', 'Function');
652
+ }
653
+ for (const [i, token] of this.entries()) {
654
+ if (token instanceof Token && typeof token.setValue === 'function' && token.setValue.length === 1) {
655
+ token.setValue(toValue(i, token));
656
+ }
657
+ }
658
+ return this;
659
+ }
660
+
661
+ /**
662
+ * @param {'getAttr'|'getAttribute'} getter
663
+ * @param {'setAttr'|'setAttribute'} setter
664
+ * @param {string|Record<string, string>} name
665
+ * @param {any|CollectionCallback<string, any>} value
666
+ */
667
+ _attr(getter, setter, name, value) {
668
+ if (typeof name === 'string' && value === undefined) {
669
+ const firstToken = this._find();
670
+ return firstToken?.[getter] && firstToken[getter](name);
671
+ }
672
+ for (const [i, token] of this.entries()) {
673
+ if (token instanceof Token && typeof token[setter] === 'function') {
674
+ if (typeof value === 'string') {
675
+ token[setter](name, value);
676
+ } else if (typeof value === 'function') {
677
+ token[setter](name, value.call(token, i, token[getter] && token[getter](name)));
678
+ } else if (typeof name === 'object') {
679
+ for (const [k, v] of Object.entries(name)) {
680
+ token[setter](k, v);
681
+ }
682
+ }
683
+ }
684
+ }
685
+ return this;
686
+ }
687
+
688
+ /**
689
+ * @param {string|Record<string, string>} name
690
+ * @param {string|CollectionCallback<string, string>} value
691
+ */
692
+ attr(name, value) {
693
+ return this._attr('getAttr', 'setAttr', name, value);
694
+ }
695
+
696
+ /**
697
+ * @param {string|Record<string, string>} name
698
+ * @param {any|CollectionCallback<string, any>} value
699
+ */
700
+ prop(name, value) {
701
+ return this._attr('getAttribute', 'setAttribute', name, value);
702
+ }
703
+
704
+ /**
705
+ * @param {'removeAttr'|'removeAttribute'} method
706
+ * @param {string} name
707
+ */
708
+ _removeAttr(method, name) {
709
+ for (const token of this) {
710
+ if (token instanceof Token && typeof token[method] === 'function') {
711
+ token[method](name);
712
+ }
713
+ }
714
+ return this;
715
+ }
716
+
717
+ /** @param {string} name */
718
+ removeAttr(name) {
719
+ return this._removeAttr('removeAttr', name);
720
+ }
721
+
722
+ /** @param {string} name */
723
+ removeProp(name) {
724
+ return this._removeAttr('removeAttribute', name);
725
+ }
726
+
727
+ /**
728
+ * 出于实用角度,与jQuery的实现方式不同
729
+ * @param {string[]|CollectionCallback<string[], undefined>} wrapper
730
+ */
731
+ wrapAll(wrapper) {
732
+ if (typeof wrapper !== 'function' && !Array.isArray(wrapper)) {
733
+ typeError('Array', 'Function');
734
+ }
735
+ const firstToken = this._find(),
736
+ error = new Error('wrapAll 的主体应为同一个父节点下的连续子节点!');
737
+ if (!firstToken || !firstToken.parentNode) {
738
+ throw error;
739
+ }
740
+ const {parentNode} = firstToken,
741
+ {childNodes} = parentNode,
742
+ i = childNodes.indexOf(firstToken),
743
+ consecutiveSiblings = childNodes.slice(i, i + this.length);
744
+ try {
745
+ assert.deepStrictEqual(this.toArray(), consecutiveSiblings);
746
+ } catch (e) {
747
+ if (e instanceof assert.AssertionError) {
748
+ throw error;
749
+ }
750
+ }
751
+ const ranges = parentNode.getAttribute('protectedChildren'),
752
+ index = ranges.applyTo(childNodes).find(n => n >= i && n < i + this.length);
753
+ if (index !== undefined) {
754
+ throw new Error(`第 ${index} 个子节点受到保护!`);
755
+ }
756
+ const [pre, post] = typeof wrapper === 'function' ? wrapper.call(firstToken) : wrapper,
757
+ config = firstToken.getRootNode().getAttribute('config'),
758
+ token = new Token(`${pre}${this.toString()}${post}`, config).parse();
759
+ if (token.childNodes.length !== 1) {
760
+ throw new RangeError(`非法的 wrapper:\n${pre}\n${post}`);
761
+ }
762
+ for (let j = i + this.length - 1; j >= i; j--) {
763
+ parentNode.removeAt(j);
764
+ }
765
+ parentNode.insertAt(token.firstChild, i);
766
+ return this;
767
+ }
768
+
769
+ /**
770
+ * @param {'html'|'replaceWith'} method
771
+ * @param {string[]|CollectionCallback<string[], undefined>} wrapper
772
+ */
773
+ _wrap(method, wrapper) {
774
+ if (typeof wrapper !== 'function' && !Array.isArray(wrapper)) {
775
+ typeError('Array', 'Function');
776
+ }
777
+ return this[method](
778
+ /**
779
+ * @this {string|Token}
780
+ * @param {number} i
781
+ * @param {string} string
782
+ */
783
+ function(i, string) {
784
+ if (!(this instanceof Token)) {
785
+ return string;
786
+ }
787
+ const [pre, post] = typeof wrapper === 'function' ? wrapper.call(this, i) : wrapper,
788
+ config = this.getRootNode().getAttribute('config'),
789
+ token = new Token(`${pre}${string}${post}`, config).parse();
790
+ if (token.childNodes.length !== 1) {
791
+ throw new RangeError(`非法的 wrapper:\n${pre}\n${post}`);
792
+ }
793
+ return token.firstChild;
794
+ },
795
+ );
796
+ }
797
+
798
+ /** @param {string[]|CollectionCallback<string[], undefined>} wrapper */
799
+ wrapInner(wrapper) {
800
+ return this._wrap('html', wrapper);
801
+ }
802
+
803
+ /** @param {string[]|CollectionCallback<string[], undefined>} wrapper */
804
+ wrap(wrapper) {
805
+ return this._wrap('replaceWith', wrapper);
806
+ }
807
+
808
+ offset() {
809
+ const firstToken = this._find();
810
+ if (!firstToken) {
811
+ return;
812
+ }
813
+ const {top, left} = firstToken.getBoundingClientRect();
814
+ return {top, left};
815
+ }
816
+
817
+ position() {
818
+ const style = this._find()?.style;
819
+ return style && {top: style.top, left: style.left};
820
+ }
821
+
822
+ height() {
823
+ return this._find()?.offsetHeight;
824
+ }
825
+
826
+ width() {
827
+ return this._find()?.offsetWidth;
828
+ }
829
+ }
830
+
831
+ /** @param {string|Token|Iterable<string|Token>} tokens */
832
+ const $ = tokens => {
833
+ if (typeof tokens === 'string' || tokens instanceof Token) {
834
+ tokens = [tokens];
835
+ }
836
+ return new Proxy(new TokenCollection(...tokens), {
837
+ /** @param {PropertyKey} prop */
838
+ get(obj, prop) {
839
+ if (prop === Symbol.iterator || typeof obj[prop] !== 'function'
840
+ || !prop.startsWith('_') && Object.getOwnPropertyDescriptor(obj.constructor.prototype, prop)
841
+ || !externalUse(prop, true)
842
+ ) {
843
+ return obj[prop];
844
+ }
845
+ },
846
+ set(obj, prop, val) {
847
+ if (prop === 'prevObject' && (val === undefined || val instanceof TokenCollection)) {
848
+ obj[prop] = val;
849
+ return true;
850
+ }
851
+ return false;
852
+ },
853
+ });
854
+ };
855
+ $.hasData = /** @param {Token} element */ element => {
856
+ if (!(element instanceof Token)) {
857
+ typeError('Token');
858
+ }
859
+ return $.dataStore.has(element);
860
+ };
861
+ $.data = /** @type {(element: Token, key?: string, value?: any) => any} */ (element, key, value) => {
862
+ if (!(element instanceof Token)) {
863
+ typeError('Token');
864
+ } else if (key === undefined) {
865
+ return $.dataStore.get(element);
866
+ } else if (typeof key !== 'string') {
867
+ typeError('String');
868
+ } else if (value === undefined) {
869
+ return $.dataStore.get(element)?.[key];
870
+ } else if (!$.dataStore.has(element)) {
871
+ $.dataStore.set(element, {});
872
+ }
873
+ $.dataStore.get(element)[key] = value;
874
+ return value;
875
+ };
876
+ $.removeData = /** @type {(element: Token, name?: string) => void} */ (element, name) => {
877
+ if (!(element instanceof Token)) {
878
+ typeError('Token');
879
+ } else if (name === undefined) {
880
+ $.dataStore.delete(element);
881
+ } else if (typeof name !== 'string') {
882
+ typeError('String');
883
+ } else if ($.dataStore.has(element)) {
884
+ const data = $.dataStore.get(element);
885
+ delete data[name];
886
+ }
887
+ };
888
+ Object.defineProperty($, 'dataStore', {value: dataStore});
889
+ Object.defineProperty($, 'TokenCollection', {value: TokenCollection});
890
+ Object.defineProperty($, 'reload', {
891
+ value() {
892
+ delete require.cache[__filename];
893
+ const $$ = require('.');
894
+ return $$;
895
+ },
896
+ });
897
+
898
+ module.exports = $;