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.
- package/README.md +5 -3
- package/bundle/bundle-es8.min.js +27 -27
- package/bundle/bundle-lsp.min.js +28 -28
- package/bundle/bundle.min.js +19 -19
- package/dist/addon/attribute.js +1 -1
- package/dist/addon/transclude.js +1 -3
- package/dist/bin/config.js +1 -1
- package/dist/index.js +1 -2
- package/dist/lib/element.d.ts +3 -8
- package/dist/lib/element.js +2 -26
- package/dist/lib/lsp.d.ts +2 -0
- package/dist/lib/lsp.js +8 -20
- package/dist/lib/node.d.ts +2 -0
- package/dist/lib/node.js +0 -7
- package/dist/lib/range.d.ts +0 -7
- package/dist/lib/range.js +5 -14
- package/dist/lib/text.js +3 -5
- package/dist/map.d.ts +66 -0
- package/dist/map.js +2 -0
- package/dist/mixin/attributesParent.d.ts +4 -3
- package/dist/mixin/elementLike.d.ts +13 -0
- package/dist/mixin/elementLike.js +66 -53
- package/dist/parser/selector.js +3 -3
- package/dist/render/extension.js +139 -8
- package/dist/render/html.js +72 -3
- package/dist/src/attribute.d.ts +2 -2
- package/dist/src/attribute.js +17 -13
- package/dist/src/attributes.d.ts +3 -3
- package/dist/src/attributes.js +30 -14
- package/dist/src/extLink.js +5 -4
- package/dist/src/heading.js +11 -3
- package/dist/src/index.js +3 -4
- package/dist/src/link/base.js +2 -4
- package/dist/src/link/file.js +5 -5
- package/dist/src/link/galleryImage.js +1 -3
- package/dist/src/magicLink.js +6 -5
- package/dist/src/multiLine/gallery.js +2 -3
- package/dist/src/nowiki/doubleUnderscore.d.ts +1 -0
- package/dist/src/nowiki/doubleUnderscore.js +4 -1
- package/dist/src/nowiki/quote.js +1 -3
- package/dist/src/parameter.js +5 -2
- package/dist/src/table/td.d.ts +2 -2
- package/dist/src/table/td.js +1 -1
- package/dist/src/tag/html.js +29 -12
- package/dist/src/tagPair/ext.js +4 -1
- package/dist/src/tagPair/translate.d.ts +1 -1
- package/dist/src/tagPair/translate.js +1 -1
- package/dist/util/debug.js +5 -7
- package/dist/util/html.js +3 -11
- package/extensions/dist/base.js +1 -1
- package/package.json +5 -5
package/dist/lib/element.js
CHANGED
|
@@ -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 =
|
|
1193
|
+
: node.closest('ext#ref'), refName = ext?.getAttr('name');
|
|
1205
1194
|
if (!refName) {
|
|
1206
1195
|
return undefined;
|
|
1207
1196
|
}
|
|
1208
|
-
const refGroup =
|
|
1209
|
-
&&
|
|
1210
|
-
&&
|
|
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 &&
|
|
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
|
-
&&
|
|
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
|
}
|
package/dist/lib/node.d.ts
CHANGED
|
@@ -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
|
}
|
package/dist/lib/range.d.ts
CHANGED
|
@@ -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
|
|
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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export interface AttributesParentBase {
|
|
2
2
|
/** all attributes / 全部属性 */
|
|
3
|
-
attributes: Record<string, string
|
|
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 |
|
|
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
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
-
|
|
96
|
-
|
|
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;
|
package/dist/parser/selector.js
CHANGED
|
@@ -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
|
|
167
|
-
if (!(key in token ||
|
|
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
|
|
237
|
+
return regex.test(lang);
|
|
238
238
|
}
|
|
239
239
|
}
|
|
240
240
|
return false;
|