wikiparser-node 1.41.0 → 1.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.
Files changed (51) hide show
  1. package/README.md +5 -3
  2. package/bundle/bundle-es8.min.js +27 -27
  3. package/bundle/bundle-lsp.min.js +28 -28
  4. package/bundle/bundle.min.js +19 -19
  5. package/dist/addon/attribute.js +1 -1
  6. package/dist/addon/transclude.js +1 -3
  7. package/dist/bin/config.js +1 -1
  8. package/dist/index.js +1 -2
  9. package/dist/lib/element.d.ts +3 -8
  10. package/dist/lib/element.js +2 -26
  11. package/dist/lib/lsp.d.ts +2 -0
  12. package/dist/lib/lsp.js +8 -20
  13. package/dist/lib/node.d.ts +2 -0
  14. package/dist/lib/node.js +0 -7
  15. package/dist/lib/range.d.ts +0 -7
  16. package/dist/lib/range.js +5 -14
  17. package/dist/lib/text.js +3 -5
  18. package/dist/map.d.ts +66 -0
  19. package/dist/map.js +2 -0
  20. package/dist/mixin/attributesParent.d.ts +4 -3
  21. package/dist/mixin/elementLike.d.ts +13 -0
  22. package/dist/mixin/elementLike.js +66 -53
  23. package/dist/parser/selector.js +3 -3
  24. package/dist/render/extension.js +139 -8
  25. package/dist/render/html.js +72 -3
  26. package/dist/src/attribute.d.ts +2 -2
  27. package/dist/src/attribute.js +17 -13
  28. package/dist/src/attributes.d.ts +3 -3
  29. package/dist/src/attributes.js +30 -14
  30. package/dist/src/extLink.js +5 -4
  31. package/dist/src/heading.js +11 -3
  32. package/dist/src/index.js +3 -4
  33. package/dist/src/link/base.js +2 -4
  34. package/dist/src/link/file.js +5 -5
  35. package/dist/src/link/galleryImage.js +1 -3
  36. package/dist/src/magicLink.js +6 -5
  37. package/dist/src/multiLine/gallery.js +2 -3
  38. package/dist/src/nowiki/doubleUnderscore.d.ts +1 -0
  39. package/dist/src/nowiki/doubleUnderscore.js +4 -1
  40. package/dist/src/nowiki/quote.js +1 -3
  41. package/dist/src/parameter.js +5 -2
  42. package/dist/src/table/td.d.ts +2 -2
  43. package/dist/src/table/td.js +1 -1
  44. package/dist/src/tag/html.js +29 -12
  45. package/dist/src/tagPair/ext.js +4 -1
  46. package/dist/src/tagPair/translate.d.ts +1 -1
  47. package/dist/src/tagPair/translate.js +1 -1
  48. package/dist/util/debug.js +5 -7
  49. package/dist/util/html.js +3 -11
  50. package/extensions/dist/base.js +1 -1
  51. package/package.json +5 -5
@@ -40,13 +40,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
40
40
  exports.AstElement = void 0;
41
41
  const string_1 = require("../util/string");
42
42
  const debug_1 = require("../util/debug");
43
- const selector_1 = require("../util/selector");
44
43
  const node_1 = require("./node");
45
44
  const elementLike_1 = require("../mixin/elementLike");
46
45
  /* NOT FOR BROWSER */
47
46
  const fs_1 = __importDefault(require("fs"));
48
47
  const path_1 = __importDefault(require("path"));
49
48
  const constants_1 = require("../util/constants");
49
+ const selector_1 = require("../util/selector");
50
50
  const readOnly_1 = require("../mixin/readOnly");
51
51
  /**
52
52
  * HTMLElement-like
@@ -113,8 +113,7 @@ let AstElement = (() => {
113
113
  }
114
114
  /** all internal, external and free external links / 所有内链、外链和自由外链 */
115
115
  get links() {
116
- return this.querySelectorAll('link,redirect-target,ext-link,free-ext-link,magic-link,image-parameter#link').filter(({ parentNode }) => !parentNode?.is('image-parameter')
117
- || parentNode.name !== 'link');
116
+ return this.querySelectorAll('link,redirect-target,ext-link,free-ext-link,magic-link,image-parameter#link').filter(({ parentNode }) => !parentNode?.is('image-parameter') || parentNode.name !== 'link');
118
117
  }
119
118
  /** all templates and modules / 所有模板和模块 */
120
119
  get embeds() {
@@ -165,23 +164,6 @@ let AstElement = (() => {
165
164
  (0, debug_1.setChildNodes)(this, i, 0, [node]);
166
165
  return node;
167
166
  }
168
- /**
169
- * Get the closest ancestor node that matches the selector
170
- *
171
- * 最近的符合选择器的祖先节点
172
- * @param selector selector / 选择器
173
- */
174
- closest(selector) {
175
- const condition = (0, selector_1.getCondition)(selector, this);
176
- let { parentNode } = this;
177
- while (parentNode) {
178
- if (condition(parentNode)) {
179
- return parentNode;
180
- }
181
- ({ parentNode } = parentNode);
182
- }
183
- return undefined;
184
- }
185
167
  /** @private */
186
168
  isInside(type) {
187
169
  return this.closest(`${type},ext`)?.type === type;
@@ -404,12 +386,6 @@ let AstElement = (() => {
404
386
  }
405
387
  this.setAttribute('childNodes', childNodes);
406
388
  }
407
- /**
408
- * Check if the current element matches the selector
409
- *
410
- * 检查是否符合选择器
411
- * @param selector selector / 选择器
412
- */
413
389
  matches(selector) {
414
390
  return (0, selector_1.getCondition)(selector, this)(this);
415
391
  }
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
@@ -158,15 +158,6 @@ const getRefName = (token) => getRefAttr(token, refTags, nameAttrs);
158
158
  * @param token `group` attribute token
159
159
  */
160
160
  const getRefGroup = (token) => getRefAttr(token, referencesTags, groupAttrs);
161
- /**
162
- * Get the attribute of a `<ref>` tag.
163
- * @param token extension token
164
- * @param target attribute name
165
- */
166
- const getRefTagAttr = (token, target) => {
167
- const attr = token?.getAttr(target);
168
- return attr !== true && attr || false;
169
- };
170
161
  /**
171
162
  * Get the effective name of a token.
172
163
  * @param token
@@ -682,8 +673,7 @@ class LanguageService {
682
673
  }),
683
674
  ...match.startsWith('#')
684
675
  ? []
685
- : getCompletion(root.querySelectorAll('template').filter(token => token !== cur)
686
- .map(token => {
676
+ : getCompletion(root.querySelectorAll('template').filter(token => token !== cur).map(token => {
687
677
  const { name } = token;
688
678
  if (colon) {
689
679
  return name;
@@ -1173,8 +1163,7 @@ class LanguageService {
1173
1163
  * @param position position / 位置
1174
1164
  */
1175
1165
  async provideReferences(text, position) {
1176
- const root = await this.#queue(text), { offsetNode, offset } = caretPositionFromWord(root, this.#text, position), element = offsetNode.type === 'text' ? offsetNode.parentNode : offsetNode, node = offset === 0
1177
- && (element.is('ext-attr-dirty') || element.is('html-attr-dirty'))
1166
+ 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'))
1178
1167
  ? element.parentNode.parentNode
1179
1168
  : element, { type } = node, refName = getRefName(node), refGroup = getRefGroup(node);
1180
1169
  if (!refName && !refGroup && !referenceTypes.has(type)) {
@@ -1201,13 +1190,13 @@ class LanguageService {
1201
1190
  }
1202
1191
  const ext = node.is('ext') && node.name === 'ref'
1203
1192
  ? node
1204
- : node.closest('ext#ref'), refName = getRefTagAttr(ext, 'name');
1193
+ : node.closest('ext#ref'), refName = ext?.getAttr('name');
1205
1194
  if (!refName) {
1206
1195
  return undefined;
1207
1196
  }
1208
- const refGroup = getRefTagAttr(ext, 'group'), refs = root.querySelectorAll('ext#ref').filter(token => token.innerText
1209
- && getRefTagAttr(token, 'name') === refName
1210
- && getRefTagAttr(token, 'group') === refGroup).reverse().map(({ lastChild }) => ({
1197
+ const refGroup = ext.getAttr('group'), refs = root.querySelectorAll('ext#ref').filter(token => token.innerText
1198
+ && token.getAttr('name') === refName
1199
+ && token.getAttr('group') === refGroup).reverse().map(({ lastChild }) => ({
1211
1200
  range: createNodeRange(lastChild),
1212
1201
  }));
1213
1202
  return refs.length === 0 ? undefined : refs;
@@ -1244,7 +1233,7 @@ class LanguageService {
1244
1233
  if (!node) {
1245
1234
  return undefined;
1246
1235
  }
1247
- 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 => {
1236
+ 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 => {
1248
1237
  const { type: t } = token.parentNode;
1249
1238
  if (type === 'link-target' && t !== 'link' && t !== 'redirect-target') {
1250
1239
  return false;
@@ -1252,7 +1241,7 @@ class LanguageService {
1252
1241
  return type === 'attr-value'
1253
1242
  ? getRefGroup(token) === refGroup
1254
1243
  || getRefName(token) === refName
1255
- && getRefTagAttr(token.parentNode.parentNode, 'group') === refNameGroup
1244
+ && token.parentNode.parentNode.getAttr('group') === refNameGroup
1256
1245
  : getName(token) === name;
1257
1246
  });
1258
1247
  return refs.length === 0
@@ -1452,7 +1441,6 @@ class LanguageService {
1452
1441
  }
1453
1442
  return hints;
1454
1443
  }
1455
- /** @private */
1456
1444
  querySelectorAll(selector) {
1457
1445
  return this.#done.querySelectorAll(selector);
1458
1446
  }
@@ -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;
@@ -136,6 +137,7 @@ export declare abstract class AstNode implements AstNodeBase {
136
137
  * @param type token type / 节点类型
137
138
  * @since v1.10.0
138
139
  */
140
+ is<K extends SelectedTokenTypes>(type: K): this is TokenTypeMap[K];
139
141
  is<T extends Token>(type: TokenTypes): this is T;
140
142
  /**
141
143
  * Get the text and the start/end positions of all lines
package/dist/lib/node.js CHANGED
@@ -371,13 +371,6 @@ let AstNode = (() => {
371
371
  ...this.getRootNode().posFromIndex(this.getAbsoluteIndex()),
372
372
  };
373
373
  }
374
- /**
375
- * Whether to be of a certain type
376
- *
377
- * 是否是某种类型的节点
378
- * @param type token type / 节点类型
379
- * @since v1.10.0
380
- */
381
374
  is(type) {
382
375
  return this.type === type;
383
376
  }
@@ -211,13 +211,6 @@ export declare class AstRange {
211
211
  * @since v1.23.0
212
212
  */
213
213
  getRootNode(): AstNodes;
214
- /**
215
- * Get the closest ancestor node that matches the selector
216
- *
217
- * 最近的符合选择器的祖先节点
218
- * @param selector selector / 选择器
219
- */
220
- closest<T = Token>(selector: string): T | undefined;
221
214
  /**
222
215
  * Insert a batch of child nodes at the end
223
216
  *
package/dist/lib/range.js CHANGED
@@ -146,6 +146,11 @@ let AstRange = (() => {
146
146
  get childNodes() {
147
147
  return this.extractContents();
148
148
  }
149
+ /** @private */
150
+ get parentNode() {
151
+ const { commonAncestorContainer } = this;
152
+ return commonAncestorContainer.type === 'text' ? commonAncestorContainer.parentNode : commonAncestorContainer;
153
+ }
149
154
  /**
150
155
  * 检查起点和终点的设置是否有效
151
156
  * @throws `RangeError` 起点和终点不是兄弟节点
@@ -601,20 +606,6 @@ let AstRange = (() => {
601
606
  getRootNode() {
602
607
  return (this.#endContainer ?? this.startContainer).getRootNode();
603
608
  }
604
- /**
605
- * Get the closest ancestor node that matches the selector
606
- *
607
- * 最近的符合选择器的祖先节点
608
- * @param selector selector / 选择器
609
- */
610
- closest(selector) {
611
- const { commonAncestorContainer } = this;
612
- if (commonAncestorContainer.type === 'text') {
613
- const { parentNode } = commonAncestorContainer;
614
- return parentNode?.matches(selector) ? parentNode : parentNode?.closest(selector);
615
- }
616
- return commonAncestorContainer.closest(selector);
617
- }
618
609
  /**
619
610
  * Insert a batch of child nodes at the end
620
611
  *
package/dist/lib/text.js CHANGED
@@ -260,8 +260,7 @@ let AstText = (() => {
260
260
  // Rule & Severity
261
261
  let startIndex = start + index, endIndex = startIndex + length, rule, severity, endLine, endCol;
262
262
  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()
263
- || rbrack && previousType === 'free-ext-link'
264
- && !data.slice(0, index).includes(']');
263
+ || rbrack && previousType === 'free-ext-link' && index === 0;
265
264
  if (magicLink) {
266
265
  rule = 'lonely-http';
267
266
  error = error.toUpperCase();
@@ -571,9 +570,8 @@ let AstText = (() => {
571
570
  if (/\s$/u.test(this.data)) {
572
571
  const spaces = [], mt = /\n[^\S\n]*$/u.exec(this.data);
573
572
  let { nextSibling } = this, mt2 = null;
574
- while (nextSibling && (nextSibling.is('comment')
575
- || nextSibling.is('category')
576
- || nextSibling.type === 'text')) {
573
+ while (nextSibling
574
+ && (nextSibling.is('comment') || nextSibling.is('category') || nextSibling.type === 'text')) {
577
575
  if (nextSibling.type === 'text') {
578
576
  mt2 = mt && /^[^\S\n]*(?=\n)/u.exec(nextSibling.data);
579
577
  if (mt2 || nextSibling.data.trim()) {
package/dist/map.d.ts ADDED
@@ -0,0 +1,66 @@
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, ListRangeToken } 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
+ 'list-range': ListRangeToken;
65
+ }
66
+ export type SelectedTokenTypes = keyof TokenTypeMap;
package/dist/map.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,6 +1,7 @@
1
1
  export interface AttributesParentBase {
2
2
  /** all attributes / 全部属性 */
3
- attributes: Record<string, string | true>;
3
+ get attributes(): Record<string, string>;
4
+ set attributes(attrs: Record<string, string | true>);
4
5
  /** class attribute in string / 以字符串表示的class属性 */
5
6
  className: string;
6
7
  /** class attribute in Set / 以Set表示的class属性 */
@@ -20,7 +21,7 @@ export interface AttributesParentBase {
20
21
  * 获取指定属性
21
22
  * @param key attribute name / 属性键
22
23
  */
23
- getAttr(key: string): string | true | undefined;
24
+ getAttr(key: string): string | undefined;
24
25
  /**
25
26
  * Get all attribute names
26
27
  *
@@ -32,7 +33,7 @@ export interface AttributesParentBase {
32
33
  *
33
34
  * 获取全部属性
34
35
  */
35
- getAttrs(): Record<string, string | true>;
36
+ getAttrs(): Record<string, string>;
36
37
  /**
37
38
  * Set the attribute
38
39
  *
@@ -1,5 +1,7 @@
1
1
  import type { AstNodes, Token, HtmlToken, ExtToken } 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
  detach?: () => void;
5
7
  };
@@ -12,12 +14,21 @@ export interface ElementLike {
12
14
  readonly lastElementChild: Token | undefined;
13
15
  /** number of child elements / 非文本子节点总数 */
14
16
  readonly childElementCount: number;
17
+ /**
18
+ * Get the closest ancestor node that matches the selector
19
+ *
20
+ * 最近的符合选择器的祖先节点
21
+ * @param selector selector / 选择器
22
+ */
23
+ closest<K extends SelectedTokenTypes>(selector: K): TokenTypeMap[K] | undefined;
24
+ closest<T = Token>(selector: string): T | undefined;
15
25
  /**
16
26
  * Get the first descendant that matches the selector
17
27
  *
18
28
  * 符合选择器的第一个后代节点
19
29
  * @param selector selector / 选择器
20
30
  */
31
+ querySelector<K extends SelectedTokenTypes>(selector: K): TokenTypeMap[K] | undefined;
21
32
  querySelector<T = Token>(selector: string): T | undefined;
22
33
  /**
23
34
  * Get all descendants that match the selector
@@ -25,6 +36,7 @@ export interface ElementLike {
25
36
  * 符合选择器的所有后代节点
26
37
  * @param selector selector / 选择器
27
38
  */
39
+ querySelectorAll<K extends SelectedTokenTypes>(selector: K): TokenTypeMap[K][];
28
40
  querySelectorAll<T = Token>(selector: string): T[];
29
41
  /**
30
42
  * Escape `=` and `|`
@@ -39,6 +51,7 @@ export interface ElementLike {
39
51
  * 类型选择器
40
52
  * @param types token types / 节点类型
41
53
  */
54
+ getElementByTypes<K extends SelectedTokenTypes>(types: K): TokenTypeMap[K] | undefined;
42
55
  getElementByTypes<T = Token>(types: string): T | undefined;
43
56
  /**
44
57
  * Get the first descendant with the id
@@ -7,30 +7,41 @@ const selector_1 = require("../util/selector");
7
7
  const constants_1 = require("../util/constants");
8
8
  /** @ignore */
9
9
  const elementLike = (constructor) => {
10
- LINT: {
11
- class ElementLike extends constructor {
12
- /* NOT FOR BROWSER */
13
- get children() {
14
- return this.childNodes.filter((child) => child.type !== 'text');
15
- }
16
- get firstElementChild() {
17
- return this.childNodes.find((child) => child.type !== 'text');
18
- }
19
- get lastElementChild() {
20
- return this.childNodes.findLast((child) => child.type !== 'text');
21
- }
22
- get childElementCount() {
23
- return this.children.length;
24
- }
25
- /* NOT FOR BROWSER END */
26
- #getCondition(selector) {
27
- return (0, selector_1.getCondition)(selector,
28
- // eslint-disable-next-line unicorn/no-negated-condition
29
- !('type' in this) ?
30
- undefined :
31
- this);
10
+ class ElementLike extends constructor {
11
+ /* NOT FOR BROWSER */
12
+ get children() {
13
+ return this.childNodes.filter((child) => child.type !== 'text');
14
+ }
15
+ get firstElementChild() {
16
+ return this.childNodes.find((child) => child.type !== 'text');
17
+ }
18
+ get lastElementChild() {
19
+ return this.childNodes.findLast((child) => child.type !== 'text');
20
+ }
21
+ get childElementCount() {
22
+ return this.children.length;
23
+ }
24
+ /* NOT FOR BROWSER END */
25
+ #getCondition(selector) {
26
+ return (0, selector_1.getCondition)(selector,
27
+ // eslint-disable-next-line unicorn/no-negated-condition
28
+ !('type' in this) ?
29
+ undefined :
30
+ this);
31
+ }
32
+ closest(selector) {
33
+ const condition = this.#getCondition(selector);
34
+ let { parentNode } = this;
35
+ while (parentNode) {
36
+ if (condition(parentNode)) {
37
+ return parentNode;
38
+ }
39
+ ({ parentNode } = parentNode);
32
40
  }
33
- getElementBy(condition) {
41
+ return undefined;
42
+ }
43
+ getElementBy(condition) {
44
+ LINT: {
34
45
  const stack = [...this.childNodes].reverse();
35
46
  while (stack.length > 0) {
36
47
  const child = stack.pop(), { type, childNodes } = child;
@@ -46,10 +57,12 @@ const elementLike = (constructor) => {
46
57
  }
47
58
  return undefined;
48
59
  }
49
- querySelector(selector) {
50
- return this.getElementBy(this.#getCondition(selector));
51
- }
52
- getElementsBy(condition) {
60
+ }
61
+ querySelector(selector) {
62
+ LINT: return this.getElementBy(this.#getCondition(selector));
63
+ }
64
+ getElementsBy(condition) {
65
+ LINT: {
53
66
  const stack = [...this.childNodes].reverse(), descendants = [];
54
67
  while (stack.length > 0) {
55
68
  const child = stack.pop(), { type, childNodes } = child;
@@ -65,36 +78,36 @@ const elementLike = (constructor) => {
65
78
  }
66
79
  return descendants;
67
80
  }
68
- querySelectorAll(selector) {
69
- return this.getElementsBy(this.#getCondition(selector));
70
- }
71
- escape() {
72
- LSP: {
73
- for (const child of this.childNodes) {
74
- child.escape();
75
- }
76
- /* NOT FOR BROWSER */
77
- this.detach?.();
81
+ }
82
+ querySelectorAll(selector) {
83
+ LINT: return this.getElementsBy(this.#getCondition(selector));
84
+ }
85
+ escape() {
86
+ LSP: {
87
+ for (const child of this.childNodes) {
88
+ child.escape();
78
89
  }
90
+ /* NOT FOR BROWSER */
91
+ this.detach?.();
79
92
  }
80
- /* NOT FOR BROWSER */
81
- getElementByTypes(types) {
82
- const typeSet = new Set(types.split(',').map(str => str.trim()));
83
- return this.getElementBy((({ type }) => typeSet.has(type)));
84
- }
85
- getElementById(id) {
86
- return this.getElementBy((token => 'id' in token && token.id === id));
87
- }
88
- getElementsByClassName(className) {
89
- return this.getElementsBy((token => 'classList' in token && token.classList.has(className)));
90
- }
91
- getElementsByTagName(tag) {
92
- return this.getElementsBy((({ type, name }) => name === tag && (type === 'html' || type === 'ext')));
93
- }
94
93
  }
95
- (0, debug_1.mixin)(ElementLike, constructor);
96
- return ElementLike;
94
+ /* NOT FOR BROWSER */
95
+ getElementByTypes(types) {
96
+ const typeSet = new Set(types.split(',').map(str => str.trim()));
97
+ return this.getElementBy((({ type }) => typeSet.has(type)));
98
+ }
99
+ getElementById(id) {
100
+ return this.getElementBy((token => 'id' in token && token.id === id));
101
+ }
102
+ getElementsByClassName(className) {
103
+ return this.getElementsBy((token => 'classList' in token && token.classList.has(className)));
104
+ }
105
+ getElementsByTagName(tag) {
106
+ return this.getElementsBy((({ type, name }) => name === tag && (type === 'html' || type === 'ext')));
107
+ }
97
108
  }
109
+ (0, debug_1.mixin)(ElementLike, constructor);
110
+ return ElementLike;
98
111
  };
99
112
  exports.elementLike = elementLike;
100
113
  constants_1.mixins['elementLike'] = __filename;
@@ -163,8 +163,8 @@ const matches = (token, step, scope, has) => {
163
163
  }
164
164
  }
165
165
  else if (selector.length === 4) { // 情形2:属性选择器
166
- const [key, equal, val = '', i] = selector, isAttr = typeof token.hasAttr === 'function' && typeof token.getAttr === 'function';
167
- if (!(key in token || isAttr && token.hasAttr(key))) {
166
+ const [key, equal, val = '', i] = selector;
167
+ if (!(key in token || typeof token.hasAttr === 'function' && token.hasAttr(key))) {
168
168
  return equal === '!=';
169
169
  }
170
170
  const v = toCase(val, i), thisVal = getAttr(token, key);
@@ -234,7 +234,7 @@ const matches = (token, step, scope, has) => {
234
234
  for (; node; node = node.parentNode) {
235
235
  const lang = node.attributes?.['lang'];
236
236
  if (lang !== undefined) {
237
- return typeof lang === 'string' && regex.test(lang);
237
+ return regex.test(lang);
238
238
  }
239
239
  }
240
240
  return false;