@blackglory/match 0.4.0 → 0.4.1
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 +67 -6
- package/lib/match-element.d.ts +2 -3
- package/lib/match-element.js +3 -1
- package/lib/match-element.js.map +1 -1
- package/lib/match.d.ts +2 -3
- package/lib/match.js +3 -1
- package/lib/match.js.map +1 -1
- package/lib/matchers/child-nodes.js +2 -1
- package/lib/matchers/child-nodes.js.map +1 -1
- package/lib/matchers/children.js +2 -1
- package/lib/matchers/children.js.map +1 -1
- package/lib/matchers/css.js +2 -2
- package/lib/matchers/css.js.map +1 -1
- package/lib/matchers/element.js +4 -4
- package/lib/matchers/element.js.map +1 -1
- package/lib/matchers/node.js +4 -4
- package/lib/matchers/node.js.map +1 -1
- package/lib/matchers/optional.js.map +1 -1
- package/lib/matchers/text-node.js +2 -2
- package/lib/matchers/text-node.js.map +1 -1
- package/lib/matchers/xpath.js +5 -5
- package/lib/matchers/xpath.js.map +1 -1
- package/lib/types.d.ts +3 -2
- package/lib/utils/match-one-by-one.js +2 -2
- package/lib/utils/match-one-by-one.js.map +1 -1
- package/lib/utils/merge-in-place.d.ts +2 -1
- package/lib/utils/merge-in-place.js.map +1 -1
- package/package.json +3 -3
- package/src/match-element.ts +6 -2
- package/src/match.ts +6 -2
- package/src/matchers/child-nodes.ts +2 -1
- package/src/matchers/children.ts +2 -1
- package/src/matchers/css.ts +2 -2
- package/src/matchers/element.ts +40 -15
- package/src/matchers/node.ts +33 -11
- package/src/matchers/optional.ts +3 -1
- package/src/matchers/text-node.ts +10 -6
- package/src/matchers/xpath.ts +8 -8
- package/src/types.ts +7 -4
- package/src/utils/match-one-by-one.ts +2 -2
- package/src/utils/merge-in-place.ts +3 -3
- package/lib/utils/concat.d.ts +0 -1
- package/lib/utils/concat.js +0 -10
- package/lib/utils/concat.js.map +0 -1
- package/src/utils/concat.ts +0 -9
package/README.md
CHANGED
|
@@ -9,11 +9,63 @@ yarn add @blackglory/match
|
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
## Usage
|
|
12
|
+
### Match only
|
|
12
13
|
```ts
|
|
13
14
|
import { matchElement, element, css, childNodes, textNode, children, multiple } from '@blackglory/match'
|
|
15
|
+
import { parseNodes, getBySelector } from 'extra-dom'
|
|
16
|
+
|
|
17
|
+
const div = parseNodes(`
|
|
18
|
+
<div>
|
|
19
|
+
<header>Heading</header>
|
|
20
|
+
<article>
|
|
21
|
+
<p>Paragraph1</p>
|
|
22
|
+
<p>Paragraph2</p>
|
|
23
|
+
</article>
|
|
24
|
+
</div>
|
|
25
|
+
`.trim())[0] as Element
|
|
26
|
+
const header = getBySelector.call(div, 'header')
|
|
27
|
+
|
|
28
|
+
const result = matchElement(
|
|
29
|
+
header
|
|
30
|
+
, element(
|
|
31
|
+
css`header`
|
|
32
|
+
, childNodes(
|
|
33
|
+
textNode()
|
|
34
|
+
)
|
|
35
|
+
)
|
|
36
|
+
, element(
|
|
37
|
+
css`article`
|
|
38
|
+
, children(
|
|
39
|
+
multiple([1, Infinity], element(
|
|
40
|
+
css`p`
|
|
41
|
+
, childNodes(
|
|
42
|
+
textNode()
|
|
43
|
+
)
|
|
44
|
+
))
|
|
45
|
+
)
|
|
46
|
+
)
|
|
47
|
+
)
|
|
48
|
+
// {}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Match and collect nodes
|
|
52
|
+
```ts
|
|
53
|
+
import { matchElement, element, css, childNodes, textNode, children, multiple } from '@blackglory/match'
|
|
54
|
+
import { parseNodes, getBySelector } from 'extra-dom'
|
|
55
|
+
|
|
56
|
+
const div = parseNodes(`
|
|
57
|
+
<div>
|
|
58
|
+
<header>Heading</header>
|
|
59
|
+
<article>
|
|
60
|
+
<p>Paragraph1</p>
|
|
61
|
+
<p>Paragraph2</p>
|
|
62
|
+
</article>
|
|
63
|
+
</div>
|
|
64
|
+
`.trim())[0] as Element
|
|
65
|
+
const header = getBySelector.call(div, 'header')
|
|
14
66
|
|
|
15
67
|
const result = matchElement(
|
|
16
|
-
|
|
68
|
+
header
|
|
17
69
|
, element(
|
|
18
70
|
css`header`
|
|
19
71
|
, childNodes(
|
|
@@ -21,7 +73,7 @@ const result = matchElement(
|
|
|
21
73
|
)
|
|
22
74
|
)
|
|
23
75
|
, element(
|
|
24
|
-
css`
|
|
76
|
+
css`article`
|
|
25
77
|
, children(
|
|
26
78
|
multiple([1, Infinity], element(
|
|
27
79
|
css`p`
|
|
@@ -32,7 +84,13 @@ const result = matchElement(
|
|
|
32
84
|
)
|
|
33
85
|
)
|
|
34
86
|
)
|
|
35
|
-
// {
|
|
87
|
+
// {
|
|
88
|
+
// heading: [object Text "Heading"]
|
|
89
|
+
// , paragraph: [
|
|
90
|
+
// [object Text "Paragraph1"]
|
|
91
|
+
// , [object Text "Paragraph2"]
|
|
92
|
+
// ]
|
|
93
|
+
// }
|
|
36
94
|
```
|
|
37
95
|
|
|
38
96
|
## API
|
|
@@ -80,7 +138,7 @@ function match(
|
|
|
80
138
|
this: void | Document
|
|
81
139
|
, node: Node
|
|
82
140
|
, ...matchers: Array<IMatcher<Node>>
|
|
83
|
-
):
|
|
141
|
+
): Record<string, Arrayable<Node>> | null
|
|
84
142
|
```
|
|
85
143
|
|
|
86
144
|
### matchElement
|
|
@@ -89,7 +147,7 @@ function matchElement(
|
|
|
89
147
|
this: void | Document
|
|
90
148
|
, element: Element
|
|
91
149
|
, ...matchers: Array<IMatcher<Element>>
|
|
92
|
-
):
|
|
150
|
+
): Record<string, Arrayable<Node>> | null
|
|
93
151
|
```
|
|
94
152
|
|
|
95
153
|
### Matchers
|
|
@@ -129,7 +187,10 @@ function element(
|
|
|
129
187
|
strings: TemplateStringsArray
|
|
130
188
|
, ...values: string[]
|
|
131
189
|
): (
|
|
132
|
-
...matchers: Array<
|
|
190
|
+
...matchers: Array<
|
|
191
|
+
| INestedMatcher<Element>
|
|
192
|
+
| ITerminalMatcher<Element>
|
|
193
|
+
>
|
|
133
194
|
) => INestedMatcher<Node>
|
|
134
195
|
function element(
|
|
135
196
|
name: string
|
package/lib/match-element.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
import { IMatcher } from './types.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
} | null;
|
|
2
|
+
import { Arrayable } from '@blackglory/prelude';
|
|
3
|
+
export declare function matchElement(this: void | Document, element: Element, ...matchers: Array<IMatcher<Element>>): Record<string, Arrayable<Node>> | null;
|
package/lib/match-element.js
CHANGED
|
@@ -2,7 +2,9 @@ import { isDocument } from 'extra-dom';
|
|
|
2
2
|
import { matchOneByOne } from "./utils/match-one-by-one.js";
|
|
3
3
|
import { nextElementSibling } from "./utils/next-element-sibling.js";
|
|
4
4
|
export function matchElement(element, ...matchers) {
|
|
5
|
-
const document = isDocument(this)
|
|
5
|
+
const document = isDocument(this)
|
|
6
|
+
? this
|
|
7
|
+
: globalThis.document;
|
|
6
8
|
const context = {
|
|
7
9
|
document,
|
|
8
10
|
collection: {},
|
package/lib/match-element.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"match-element.js","sourceRoot":"","sources":["../src/match-element.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAEtC,OAAO,EAAE,aAAa,EAAE,oCAAkC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,wCAAsC;
|
|
1
|
+
{"version":3,"file":"match-element.js","sourceRoot":"","sources":["../src/match-element.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAEtC,OAAO,EAAE,aAAa,EAAE,oCAAkC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,wCAAsC;AAGnE,MAAM,UAAU,YAAY,CAE1B,OAAgB,EAChB,GAAG,QAAkC;IAErC,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC;QAClB,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAA;IAEpC,MAAM,OAAO,GAAa;QACxB,QAAQ;QACR,UAAU,EAAE,EAAE;QACd,IAAI,EAAE,kBAAkB;KACzB,CAAA;IAED,IAAI,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAC,EAAE,CAAC;QACjD,OAAO,OAAO,CAAC,UAAU,CAAA;IAC3B,CAAC;SAAM,CAAC;QACN,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC"}
|
package/lib/match.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
import { IMatcher } from './types.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
} | null;
|
|
2
|
+
import { Arrayable } from '@blackglory/prelude';
|
|
3
|
+
export declare function match(this: void | Document, node: Node, ...matchers: Array<IMatcher<Node>>): Record<string, Arrayable<Node>> | null;
|
package/lib/match.js
CHANGED
|
@@ -2,7 +2,9 @@ import { isDocument } from 'extra-dom';
|
|
|
2
2
|
import { matchOneByOne } from "./utils/match-one-by-one.js";
|
|
3
3
|
import { nextSibling } from "./utils/next-sibling.js";
|
|
4
4
|
export function match(node, ...matchers) {
|
|
5
|
-
const document = isDocument(this)
|
|
5
|
+
const document = isDocument(this)
|
|
6
|
+
? this
|
|
7
|
+
: globalThis.document;
|
|
6
8
|
const context = {
|
|
7
9
|
document,
|
|
8
10
|
collection: {},
|
package/lib/match.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"match.js","sourceRoot":"","sources":["../src/match.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAEtC,OAAO,EAAE,aAAa,EAAE,oCAAkC;AAC1D,OAAO,EAAE,WAAW,EAAE,gCAA8B;
|
|
1
|
+
{"version":3,"file":"match.js","sourceRoot":"","sources":["../src/match.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAEtC,OAAO,EAAE,aAAa,EAAE,oCAAkC;AAC1D,OAAO,EAAE,WAAW,EAAE,gCAA8B;AAGpD,MAAM,UAAU,KAAK,CAEnB,IAAU,EACV,GAAG,QAA+B;IAElC,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC;QAClB,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAA;IAEpC,MAAM,OAAO,GAAa;QACxB,QAAQ;QACR,UAAU,EAAE,EAAE;QACd,IAAI,EAAE,WAAW;KAClB,CAAA;IAED,IAAI,aAAa,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC,EAAE,CAAC;QAC9C,OAAO,OAAO,CAAC,UAAU,CAAA;IAC3B,CAAC;SAAM,CAAC;QACN,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { isEmptyArray } from '@blackglory/prelude';
|
|
1
2
|
import { matchOneByOne } from "../utils/match-one-by-one.js";
|
|
2
3
|
import { mergeInPlace } from "../utils/merge-in-place.js";
|
|
3
4
|
import { nextSibling } from "../utils/next-sibling.js";
|
|
4
5
|
export function childNodes(...matchers) {
|
|
5
6
|
return function (node) {
|
|
6
7
|
// 空matchers意味着"childNodes应该为空".
|
|
7
|
-
if (matchers
|
|
8
|
+
if (isEmptyArray(matchers)) {
|
|
8
9
|
return node.childNodes.length === 0;
|
|
9
10
|
}
|
|
10
11
|
if (node.childNodes.length === 0)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"child-nodes.js","sourceRoot":"","sources":["../../src/matchers/child-nodes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"child-nodes.js","sourceRoot":"","sources":["../../src/matchers/child-nodes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAElD,OAAO,EAAE,aAAa,EAAE,qCAAkC;AAC1D,OAAO,EAAE,YAAY,EAAE,mCAAgC;AACvD,OAAO,EAAE,WAAW,EAAE,iCAA8B;AAEpD,MAAM,UAAU,UAAU,CAAC,GAAG,QAA+B;IAC3D,OAAO,UAAkC,IAAU;QACjD,gCAAgC;QAChC,IAAI,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,CAAA;QACrC,CAAC;QAED,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,KAAK,CAAA;QAE9C,MAAM,OAAO,GAAqB;YAChC,GAAG,IAAI;YACP,UAAU,EAAE,EAAE;YACd,IAAI,EAAE,WAAW;SAClB,CAAA;QAED,MAAM,MAAM,GAAG,aAAa,CAC1B,OAAO,EACP,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAClB,GAAG,QAAQ,CACZ,CAAA;QAED,IAAI,MAAM,EAAE,CAAC;YACX,YAAY,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,CAAA;QACnD,CAAC;QAED,OAAO,MAAM,CAAA;IACf,CAAC,CAAA;AACH,CAAC"}
|
package/lib/matchers/children.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { isEmptyArray } from '@blackglory/prelude';
|
|
1
2
|
import { matchOneByOne } from "../utils/match-one-by-one.js";
|
|
2
3
|
import { mergeInPlace } from "../utils/merge-in-place.js";
|
|
3
4
|
import { nextElementSibling } from "../utils/next-element-sibling.js";
|
|
4
5
|
export function children(...matchers) {
|
|
5
6
|
return function (element) {
|
|
6
7
|
// 空matchers意味着"children应该为空".
|
|
7
|
-
if (matchers
|
|
8
|
+
if (isEmptyArray(matchers)) {
|
|
8
9
|
return element.children.length === 0;
|
|
9
10
|
}
|
|
10
11
|
if (element.children.length === 0)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"children.js","sourceRoot":"","sources":["../../src/matchers/children.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"children.js","sourceRoot":"","sources":["../../src/matchers/children.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAElD,OAAO,EAAE,aAAa,EAAE,qCAAkC;AAC1D,OAAO,EAAE,YAAY,EAAE,mCAAgC;AACvD,OAAO,EAAE,kBAAkB,EAAE,yCAAsC;AAEnE,MAAM,UAAU,QAAQ,CACtB,GAAG,QAAkC;IAErC,OAAO,UAAkC,OAAgB;QACvD,8BAA8B;QAC9B,IAAI,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC3B,OAAO,OAAO,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAA;QACtC,CAAC;QAED,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,KAAK,CAAA;QAE/C,MAAM,OAAO,GAAqB;YAChC,GAAG,IAAI;YACP,UAAU,EAAE,EAAE;YACd,IAAI,EAAE,kBAAkB;SACzB,CAAA;QAED,MAAM,MAAM,GAAG,aAAa,CAC1B,OAAO,EACP,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EACnB,GAAG,QAAQ,CACZ,CAAA;QAED,IAAI,MAAM,EAAE,CAAC;YACX,YAAY,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,CAAA;QACnD,CAAC;QAED,OAAO,MAAM,CAAA;IACf,CAAC,CAAA;AACH,CAAC"}
|
package/lib/matchers/css.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { concat } from
|
|
1
|
+
import { concat } from 'extra-tags';
|
|
2
2
|
import { isString } from '@blackglory/prelude';
|
|
3
3
|
export function css(...args) {
|
|
4
4
|
if (isString(args[0])) {
|
|
@@ -7,7 +7,7 @@ export function css(...args) {
|
|
|
7
7
|
}
|
|
8
8
|
else {
|
|
9
9
|
const [strings, ...values] = args;
|
|
10
|
-
const selector = concat(strings, values)
|
|
10
|
+
const selector = concat(strings, ...values);
|
|
11
11
|
return css(selector);
|
|
12
12
|
}
|
|
13
13
|
}
|
package/lib/matchers/css.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"css.js","sourceRoot":"","sources":["../../src/matchers/css.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"css.js","sourceRoot":"","sources":["../../src/matchers/css.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAEnC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAO9C,MAAM,UAAU,GAAG,CAAC,GAAG,IAE+B;IAEpD,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACtB,MAAM,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAA;QAEvB,OAAO,CAAC,OAAgB,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IACxD,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,GAAG,IAAI,CAAA;QACjC,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,CAAA;QAE3C,OAAO,GAAG,CAAC,QAAQ,CAAC,CAAA;IACtB,CAAC;AACH,CAAC"}
|
package/lib/matchers/element.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { isntElement } from 'extra-dom';
|
|
2
|
-
import { isArray, isString } from '@blackglory/prelude';
|
|
3
|
-
import { concat } from
|
|
2
|
+
import { isArray, isEmptyArray, isString } from '@blackglory/prelude';
|
|
3
|
+
import { concat } from 'extra-tags';
|
|
4
4
|
import { mergeInPlace } from "../utils/merge-in-place.js";
|
|
5
5
|
export function element(...args) {
|
|
6
6
|
if (isArray(args[0])) {
|
|
7
7
|
const [strings, ...values] = args;
|
|
8
|
-
const name = concat(strings, values)
|
|
8
|
+
const name = concat(strings, ...values);
|
|
9
9
|
return (...matchers) => element(name, ...matchers);
|
|
10
10
|
}
|
|
11
11
|
if (isString(args[0])) {
|
|
@@ -22,7 +22,7 @@ export function element(...args) {
|
|
|
22
22
|
return function (element) {
|
|
23
23
|
if (isntElement(element))
|
|
24
24
|
return false;
|
|
25
|
-
if (matchers
|
|
25
|
+
if (isEmptyArray(matchers))
|
|
26
26
|
return true;
|
|
27
27
|
return matchers.every(match => match.call(this, element));
|
|
28
28
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"element.js","sourceRoot":"","sources":["../../src/matchers/element.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAEvC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"element.js","sourceRoot":"","sources":["../../src/matchers/element.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAEvC,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AACrE,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACnC,OAAO,EAAE,YAAY,EAAE,mCAAgC;AAkBvD,MAAM,UAAU,OAAO,CAAC,GAAG,IAGgD;IAEzE,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACrB,MAAM,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,GAAG,IAG5B,CAAA;QACD,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,CAAA;QAEvC,OAAO,CACL,GAAG,QAGF,EACD,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,CAAA;IACjC,CAAC;IAED,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACtB,MAAM,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,GAAG,IAM3B,CAAA;QAED,OAAO,UAAkC,QAAiB;YACxD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;YACxD,IAAI,MAAM,EAAE,CAAC;gBACX,YAAY,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAA;YACrD,CAAC;YACD,OAAO,MAAM,CAAA;QACf,CAAC,CAAA;IACH,CAAC;IAED,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,IAKrB,CAAA;IAED,OAAO,UAAkC,OAAgB;QACvD,IAAI,WAAW,CAAC,OAAO,CAAC;YAAE,OAAO,KAAK,CAAA;QACtC,IAAI,YAAY,CAAC,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAA;QAEvC,OAAO,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAA;IAC3D,CAAC,CAAA;AACH,CAAC"}
|
package/lib/matchers/node.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { isArray, isString } from '@blackglory/prelude';
|
|
2
|
-
import { concat } from
|
|
1
|
+
import { isArray, isEmptyArray, isString } from '@blackglory/prelude';
|
|
2
|
+
import { concat } from 'extra-tags';
|
|
3
3
|
import { mergeInPlace } from "../utils/merge-in-place.js";
|
|
4
4
|
export function node(...args) {
|
|
5
5
|
if (isArray(args[0])) {
|
|
6
6
|
const [strings, ...values] = args;
|
|
7
|
-
const name = concat(strings, values)
|
|
7
|
+
const name = concat(strings, ...values);
|
|
8
8
|
return (...matchers) => node(name, ...matchers);
|
|
9
9
|
}
|
|
10
10
|
if (isString(args[0])) {
|
|
@@ -19,7 +19,7 @@ export function node(...args) {
|
|
|
19
19
|
}
|
|
20
20
|
const [...matchers] = args;
|
|
21
21
|
return function (node) {
|
|
22
|
-
if (matchers
|
|
22
|
+
if (isEmptyArray(matchers))
|
|
23
23
|
return true;
|
|
24
24
|
return matchers.every(match => match.call(this, node));
|
|
25
25
|
};
|
package/lib/matchers/node.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../src/matchers/node.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../src/matchers/node.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AACrE,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACnC,OAAO,EAAE,YAAY,EAAE,mCAAgC;AAkBvD,MAAM,UAAU,IAAI,CAAC,GAAG,IAG6C;IAEnE,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACrB,MAAM,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,GAAG,IAG5B,CAAA;QACD,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,CAAA;QAEvC,OAAO,CACL,GAAG,QAGF,EACD,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,CAAA;IAC9B,CAAC;IAED,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACtB,MAAM,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,GAAG,IAM3B,CAAA;QAED,OAAO,UAAkC,KAAW;YAClD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;YAClD,IAAI,MAAM,EAAE,CAAC;gBACX,YAAY,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;YAClD,CAAC;YACD,OAAO,MAAM,CAAA;QACf,CAAC,CAAA;IACH,CAAC;IAED,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,IAKrB,CAAA;IAED,OAAO,UAAkC,IAAU;QACjD,IAAI,YAAY,CAAC,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAA;QAEvC,OAAO,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAA;IACxD,CAAC,CAAA;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"optional.js","sourceRoot":"","sources":["../../src/matchers/optional.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAExC,MAAM,UAAU,QAAQ,
|
|
1
|
+
{"version":3,"file":"optional.js","sourceRoot":"","sources":["../../src/matchers/optional.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAExC,MAAM,UAAU,QAAQ,CACtB,OAAgD;IAEhD,OAAO,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;AACpD,CAAC"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { isArray, isString } from '@blackglory/prelude';
|
|
2
|
-
import { concat } from
|
|
2
|
+
import { concat } from 'extra-tags';
|
|
3
3
|
import { isntTextNode } from 'extra-dom';
|
|
4
4
|
import { mergeInPlace } from "../utils/merge-in-place.js";
|
|
5
5
|
export function textNode(...args) {
|
|
6
6
|
if (isArray(args[0])) {
|
|
7
7
|
const [strings, ...values] = args;
|
|
8
|
-
const name = concat(strings, values)
|
|
8
|
+
const name = concat(strings, ...values);
|
|
9
9
|
return (...matchers) => textNode(name, ...matchers);
|
|
10
10
|
}
|
|
11
11
|
if (isString(args[0])) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text-node.js","sourceRoot":"","sources":["../../src/matchers/text-node.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EAAE,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"text-node.js","sourceRoot":"","sources":["../../src/matchers/text-node.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,EAAE,YAAY,EAAE,mCAAgC;AAavD,MAAM,UAAU,QAAQ,CAAC,GAAG,IAGkB;IAE5C,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACrB,MAAM,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,GAAG,IAG5B,CAAA;QACD,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,CAAA;QAEvC,OAAO,CAAC,GAAG,QAAuC,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,CAAA;IACpF,CAAC;IAED,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACtB,MAAM,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,GAAG,IAG3B,CAAA;QAED,OAAO,UAAkC,IAAU;YACjD,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;YACrD,IAAI,MAAM,EAAE,CAAC;gBACX,YAAY,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAA;YACjD,CAAC;YACD,OAAO,MAAM,CAAA;QACf,CAAC,CAAA;IACH,CAAC;IAED,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,IAAoD,CAAA;IAE1E,OAAO,UAAkC,IAAU;QACjD,IAAI,YAAY,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAA;QACpC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAA;QAEtC,OAAO,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAA;IACxD,CAAC,CAAA;AACH,CAAC"}
|
package/lib/matchers/xpath.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isString } from '@blackglory/prelude';
|
|
2
|
-
import { concat } from
|
|
1
|
+
import { isntNull, isString } from '@blackglory/prelude';
|
|
2
|
+
import { concat } from 'extra-tags';
|
|
3
3
|
import { assert } from '@blackglory/prelude';
|
|
4
4
|
const UNORDERED_NODE_ITERATOR_TYPE = 'XPathResult' in globalThis
|
|
5
5
|
? XPathResult.UNORDERED_NODE_ITERATOR_TYPE
|
|
@@ -7,21 +7,21 @@ const UNORDERED_NODE_ITERATOR_TYPE = 'XPathResult' in globalThis
|
|
|
7
7
|
export function xpath(...args) {
|
|
8
8
|
if (isString(args[0])) {
|
|
9
9
|
const [expression] = args;
|
|
10
|
-
assert(expression.startsWith('
|
|
10
|
+
assert(expression.startsWith('/'), 'XPath expressions must start with "/"');
|
|
11
11
|
return function (node) {
|
|
12
12
|
return xpathMatches(this.document, expression, node);
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
15
|
else {
|
|
16
16
|
const [strings, ...values] = args;
|
|
17
|
-
const expression = concat(strings, values)
|
|
17
|
+
const expression = concat(strings, ...values);
|
|
18
18
|
return xpath(expression);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
function xpathMatches(document, expression, node) {
|
|
22
22
|
const iterator = document.evaluate(expression, node, null, UNORDERED_NODE_ITERATOR_TYPE, null);
|
|
23
23
|
let value;
|
|
24
|
-
while (
|
|
24
|
+
while (value = iterator.iterateNext(), isntNull(value)) {
|
|
25
25
|
if (value === node)
|
|
26
26
|
return true;
|
|
27
27
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xpath.js","sourceRoot":"","sources":["../../src/matchers/xpath.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"xpath.js","sourceRoot":"","sources":["../../src/matchers/xpath.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAE5C,MAAM,4BAA4B,GAChC,aAAa,IAAI,UAAU;IAC7B,CAAC,CAAC,WAAW,CAAC,4BAA4B;IAC1C,CAAC,CAAC,CAAC,CAAA;AASH,MAAM,UAAU,KAAK,CAAC,GAAG,IAE6B;IAEpD,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACtB,MAAM,CAAC,UAAU,CAAC,GAAG,IAAI,CAAA;QACzB,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,uCAAuC,CAAC,CAAA;QAE3E,OAAO,UAEL,IAAU;YAEV,OAAO,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,CAAC,CAAA;QACtD,CAAC,CAAA;IACH,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,GAAG,IAAI,CAAA;QACjC,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,CAAA;QAE7C,OAAO,KAAK,CAAC,UAAU,CAAC,CAAA;IAC1B,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,QAAkB,EAAE,UAAkB,EAAE,IAAU;IACtE,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAChC,UAAU,EACV,IAAI,EACJ,IAAI,EACJ,4BAA4B,EAC5B,IAAI,CACL,CAAA;IAED,IAAI,KAAkB,CAAA;IACtB,OAAO,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACvD,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,IAAI,CAAA;IACjC,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC"}
|
package/lib/types.d.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
+
import { Arrayable } from '@blackglory/prelude';
|
|
1
2
|
export interface IContext {
|
|
2
3
|
readonly document: Document;
|
|
3
4
|
readonly next: (node: Node, distance?: number) => Node | undefined;
|
|
4
5
|
readonly collection: {
|
|
5
|
-
[name: string]: Node
|
|
6
|
+
[name: string]: Arrayable<Node>;
|
|
6
7
|
};
|
|
7
8
|
}
|
|
8
9
|
export interface IReadonlyContext {
|
|
9
10
|
readonly document: Document;
|
|
10
11
|
readonly next: (node: Node, distance?: number) => Node | undefined;
|
|
11
12
|
readonly collection: {
|
|
12
|
-
readonly [name: string]: Node
|
|
13
|
+
readonly [name: string]: Arrayable<Node>;
|
|
13
14
|
};
|
|
14
15
|
}
|
|
15
16
|
export type IMatcher<T extends Node> = ITerminalMatcher<T> | INestedMatcher<T> | ISkipMatcher<T> | (<T extends Node>(this: IReadonlyContext, node: T) => boolean | number | Iterable<number>);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { isBoolean, isNumber, isIterable } from '@blackglory/prelude';
|
|
1
|
+
import { isBoolean, isNumber, isIterable, isEmptyArray } from '@blackglory/prelude';
|
|
2
2
|
export function matchOneByOne(context, source, ...matchers) {
|
|
3
|
-
if (matchers
|
|
3
|
+
if (isEmptyArray(matchers))
|
|
4
4
|
return true;
|
|
5
5
|
if (!source)
|
|
6
6
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"match-one-by-one.js","sourceRoot":"","sources":["../../src/utils/match-one-by-one.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"match-one-by-one.js","sourceRoot":"","sources":["../../src/utils/match-one-by-one.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAEnF,MAAM,UAAU,aAAa,CAC3B,OAAyB,EACzB,MAAgB,EAChB,GAAG,QAA4B;IAE/B,IAAI,YAAY,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAA;IACvC,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAA;IAEzB,MAAM,CAAC,OAAO,EAAE,GAAG,aAAa,CAAC,GAAG,QAAQ,CAAA;IAE5C,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,CAA+B,CAAA;IAEtF,kBAAkB;IAClB,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;QACtB,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAa,CAAA;YACjD,OAAO,aAAa,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,aAAa,CAAC,CAAA;QAC3D,CAAC;aAAM,CAAC;YACN,OAAO,KAAK,CAAA;QACd,CAAC;IACH,CAAC;IAED,wCAAwC;IACxC,IAAI,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACrB,MAAM,QAAQ,GAAG,MAAM,CAAA;QACvB,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAa,CAAA;QAC3D,OAAO,aAAa,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,aAAa,CAAC,CAAA;IAC3D,CAAC;IAED,6CAA6C;IAC7C,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACvB,KAAK,MAAM,QAAQ,IAAI,MAAM,EAAE,CAAC;YAC9B,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAa,CAAA;YAC3D,IAAI,aAAa,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,aAAa,CAAC,EAAE,CAAC;gBACvD,OAAO,IAAI,CAAA;YACb,CAAC;QACH,CAAC;QAED,uBAAuB;QACvB,OAAO,KAAK,CAAA;IACd,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAA;AACzC,CAAC"}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import { Arrayable } from '@blackglory/prelude';
|
|
2
|
+
export declare function mergeInPlace<T>(target: Record<string, Arrayable<T>>, source: Record<string, Arrayable<T>>): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merge-in-place.js","sourceRoot":"","sources":["../../src/utils/merge-in-place.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"merge-in-place.js","sourceRoot":"","sources":["../../src/utils/merge-in-place.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAExD,MAAM,UAAU,YAAY,CAC1B,MAAoC,EACpC,MAAoC;IAEpC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YAChB,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;gBACzB,IAAI,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;oBACnB,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAQ,EAAE,GAAG,KAAK,CAAC,CAAA;gBACjD,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAQ,EAAE,KAAK,CAAC,CAAA;gBAC9C,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,IAAI,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;oBACnB,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAM,EAAE,GAAG,KAAK,CAAC,CAAA;gBAC5C,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAM,EAAE,KAAK,CAAC,CAAA;gBACzC,CAAC;YACH,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;QACrB,CAAC;IACH,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blackglory/match",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "A module for matching nodes from pages",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"query",
|
|
@@ -43,7 +43,6 @@
|
|
|
43
43
|
"@types/jsdom": "^27.0.0",
|
|
44
44
|
"eslint": "^9.39.2",
|
|
45
45
|
"husky": "^4.3.8",
|
|
46
|
-
"iterable-operator": "^5.1.0",
|
|
47
46
|
"jsdom": "^27.4.0",
|
|
48
47
|
"npm-run-all": "^4.1.5",
|
|
49
48
|
"rimraf": "^6.1.2",
|
|
@@ -59,6 +58,7 @@
|
|
|
59
58
|
"dependencies": {
|
|
60
59
|
"@blackglory/prelude": "^0.4.0",
|
|
61
60
|
"extra-dom": "^0.7.0",
|
|
62
|
-
"extra-generator": "^0.5.9"
|
|
61
|
+
"extra-generator": "^0.5.9",
|
|
62
|
+
"extra-tags": "^0.5.4"
|
|
63
63
|
}
|
|
64
64
|
}
|
package/src/match-element.ts
CHANGED
|
@@ -2,13 +2,17 @@ import { isDocument } from 'extra-dom'
|
|
|
2
2
|
import { IMatcher, IContext } from './types.js'
|
|
3
3
|
import { matchOneByOne } from '@utils/match-one-by-one.js'
|
|
4
4
|
import { nextElementSibling } from '@utils/next-element-sibling.js'
|
|
5
|
+
import { Arrayable } from '@blackglory/prelude'
|
|
5
6
|
|
|
6
7
|
export function matchElement(
|
|
7
8
|
this: void | Document
|
|
8
9
|
, element: Element
|
|
9
10
|
, ...matchers: Array<IMatcher<Element>>
|
|
10
|
-
):
|
|
11
|
-
const document = isDocument(this)
|
|
11
|
+
): Record<string, Arrayable<Node>> | null {
|
|
12
|
+
const document = isDocument(this)
|
|
13
|
+
? this
|
|
14
|
+
: globalThis.document
|
|
15
|
+
|
|
12
16
|
const context: IContext = {
|
|
13
17
|
document
|
|
14
18
|
, collection: {}
|
package/src/match.ts
CHANGED
|
@@ -2,13 +2,17 @@ import { isDocument } from 'extra-dom'
|
|
|
2
2
|
import { IMatcher, IContext } from './types.js'
|
|
3
3
|
import { matchOneByOne } from '@utils/match-one-by-one.js'
|
|
4
4
|
import { nextSibling } from '@utils/next-sibling.js'
|
|
5
|
+
import { Arrayable } from '@blackglory/prelude'
|
|
5
6
|
|
|
6
7
|
export function match(
|
|
7
8
|
this: void | Document
|
|
8
9
|
, node: Node
|
|
9
10
|
, ...matchers: Array<IMatcher<Node>>
|
|
10
|
-
):
|
|
11
|
-
const document = isDocument(this)
|
|
11
|
+
): Record<string, Arrayable<Node>> | null {
|
|
12
|
+
const document = isDocument(this)
|
|
13
|
+
? this
|
|
14
|
+
: globalThis.document
|
|
15
|
+
|
|
12
16
|
const context: IContext = {
|
|
13
17
|
document
|
|
14
18
|
, collection: {}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isEmptyArray } from '@blackglory/prelude'
|
|
1
2
|
import { INestedMatcher, IMatcher, IReadonlyContext } from '@src/types.js'
|
|
2
3
|
import { matchOneByOne } from '@utils/match-one-by-one.js'
|
|
3
4
|
import { mergeInPlace } from '@utils/merge-in-place.js'
|
|
@@ -6,7 +7,7 @@ import { nextSibling } from '@utils/next-sibling.js'
|
|
|
6
7
|
export function childNodes(...matchers: Array<IMatcher<Node>>): INestedMatcher<Node> {
|
|
7
8
|
return function (this: IReadonlyContext, node: Node) {
|
|
8
9
|
// 空matchers意味着"childNodes应该为空".
|
|
9
|
-
if (matchers
|
|
10
|
+
if (isEmptyArray(matchers)) {
|
|
10
11
|
return node.childNodes.length === 0
|
|
11
12
|
}
|
|
12
13
|
|
package/src/matchers/children.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isEmptyArray } from '@blackglory/prelude'
|
|
1
2
|
import { IMatcher, INestedMatcher, IReadonlyContext } from '@src/types.js'
|
|
2
3
|
import { matchOneByOne } from '@utils/match-one-by-one.js'
|
|
3
4
|
import { mergeInPlace } from '@utils/merge-in-place.js'
|
|
@@ -8,7 +9,7 @@ export function children(
|
|
|
8
9
|
): INestedMatcher<Element> {
|
|
9
10
|
return function (this: IReadonlyContext, element: Element) {
|
|
10
11
|
// 空matchers意味着"children应该为空".
|
|
11
|
-
if (matchers
|
|
12
|
+
if (isEmptyArray(matchers)) {
|
|
12
13
|
return element.children.length === 0
|
|
13
14
|
}
|
|
14
15
|
|
package/src/matchers/css.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { concat } from '
|
|
1
|
+
import { concat } from 'extra-tags'
|
|
2
2
|
import { ITerminalMatcher } from '@src/types.js'
|
|
3
3
|
import { isString } from '@blackglory/prelude'
|
|
4
4
|
|
|
@@ -17,7 +17,7 @@ export function css(...args:
|
|
|
17
17
|
return (element: Element) => element.matches(selector)
|
|
18
18
|
} else {
|
|
19
19
|
const [strings, ...values] = args
|
|
20
|
-
const selector = concat(strings, values)
|
|
20
|
+
const selector = concat(strings, ...values)
|
|
21
21
|
|
|
22
22
|
return css(selector)
|
|
23
23
|
}
|
package/src/matchers/element.ts
CHANGED
|
@@ -1,33 +1,53 @@
|
|
|
1
1
|
import { isntElement } from 'extra-dom'
|
|
2
2
|
import { INestedMatcher, ITerminalMatcher, IReadonlyContext } from '@src/types.js'
|
|
3
|
-
import { isArray, isString } from '@blackglory/prelude'
|
|
4
|
-
import { concat } from '
|
|
3
|
+
import { isArray, isEmptyArray, isString } from '@blackglory/prelude'
|
|
4
|
+
import { concat } from 'extra-tags'
|
|
5
5
|
import { mergeInPlace } from '@utils/merge-in-place.js'
|
|
6
6
|
|
|
7
7
|
export function element(
|
|
8
8
|
strings: TemplateStringsArray
|
|
9
9
|
, ...values: string[]
|
|
10
|
-
): (
|
|
11
|
-
|
|
12
|
-
INestedMatcher<
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
): (
|
|
11
|
+
...matchers: Array<
|
|
12
|
+
| INestedMatcher<Element>
|
|
13
|
+
| ITerminalMatcher<Element>
|
|
14
|
+
>
|
|
15
|
+
) => INestedMatcher<Node>
|
|
16
|
+
export function element(
|
|
17
|
+
name: string
|
|
18
|
+
, ...matchers: Array<INestedMatcher<Element>>
|
|
19
|
+
): INestedMatcher<Node>
|
|
20
|
+
export function element(
|
|
21
|
+
...matchers: Array<INestedMatcher<Element>>
|
|
22
|
+
): INestedMatcher<Node>
|
|
15
23
|
export function element(...args:
|
|
16
24
|
| [strings: TemplateStringsArray, ...values: string[]]
|
|
17
25
|
| [name: string, ...matchers: Array<INestedMatcher<Element> | ITerminalMatcher<Element>>]
|
|
18
26
|
| [...matchers: Array<INestedMatcher<Element> | ITerminalMatcher<Element>>]
|
|
19
27
|
) {
|
|
20
28
|
if (isArray(args[0])) {
|
|
21
|
-
const [strings, ...values] =
|
|
22
|
-
|
|
23
|
-
|
|
29
|
+
const [strings, ...values] = args as [
|
|
30
|
+
strings: TemplateStringsArray
|
|
31
|
+
, ...values: string[]
|
|
32
|
+
]
|
|
33
|
+
const name = concat(strings, ...values)
|
|
24
34
|
|
|
25
|
-
return (
|
|
35
|
+
return (
|
|
36
|
+
...matchers: Array<
|
|
37
|
+
| INestedMatcher<Element>
|
|
38
|
+
| ITerminalMatcher<Element>
|
|
39
|
+
>
|
|
40
|
+
) => element(name, ...matchers)
|
|
26
41
|
}
|
|
27
42
|
|
|
28
43
|
if (isString(args[0])) {
|
|
29
|
-
const [name, ...matchers] =
|
|
30
|
-
|
|
44
|
+
const [name, ...matchers] = args as [
|
|
45
|
+
name: string
|
|
46
|
+
, ...matchers: Array<
|
|
47
|
+
| INestedMatcher<Element>
|
|
48
|
+
| ITerminalMatcher<Element>
|
|
49
|
+
>
|
|
50
|
+
]
|
|
31
51
|
|
|
32
52
|
return function (this: IReadonlyContext, _element: Element) {
|
|
33
53
|
const result = element(...matchers).call(this, _element)
|
|
@@ -38,11 +58,16 @@ export function element(...args:
|
|
|
38
58
|
}
|
|
39
59
|
}
|
|
40
60
|
|
|
41
|
-
const [...matchers] = args as [
|
|
61
|
+
const [...matchers] = args as [
|
|
62
|
+
...matchers: Array<
|
|
63
|
+
| INestedMatcher<Element>
|
|
64
|
+
| ITerminalMatcher<Element>
|
|
65
|
+
>
|
|
66
|
+
]
|
|
42
67
|
|
|
43
68
|
return function (this: IReadonlyContext, element: Element) {
|
|
44
69
|
if (isntElement(element)) return false
|
|
45
|
-
if (matchers
|
|
70
|
+
if (isEmptyArray(matchers)) return true
|
|
46
71
|
|
|
47
72
|
return matchers.every(match => match.call(this, element))
|
|
48
73
|
}
|
package/src/matchers/node.ts
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import { INestedMatcher, ITerminalMatcher, IReadonlyContext } from '@src/types.js'
|
|
2
|
-
import { isArray, isString } from '@blackglory/prelude'
|
|
3
|
-
import { concat } from '
|
|
2
|
+
import { isArray, isEmptyArray, isString } from '@blackglory/prelude'
|
|
3
|
+
import { concat } from 'extra-tags'
|
|
4
4
|
import { mergeInPlace } from '@utils/merge-in-place.js'
|
|
5
5
|
|
|
6
6
|
export function node(
|
|
7
7
|
strings: TemplateStringsArray
|
|
8
8
|
, ...values: string[]
|
|
9
|
-
): (
|
|
9
|
+
): (
|
|
10
|
+
...matchers: Array<
|
|
11
|
+
| INestedMatcher<Node>
|
|
12
|
+
| ITerminalMatcher<Node>
|
|
13
|
+
>
|
|
14
|
+
) => INestedMatcher<Node>
|
|
10
15
|
export function node(
|
|
11
16
|
name: string
|
|
12
17
|
, ...matchers: Array<INestedMatcher<Node> | ITerminalMatcher<Node>>
|
|
@@ -20,16 +25,28 @@ export function node(...args:
|
|
|
20
25
|
| [...matchers: Array<INestedMatcher<Node> | ITerminalMatcher<Node>>]
|
|
21
26
|
) {
|
|
22
27
|
if (isArray(args[0])) {
|
|
23
|
-
const [strings, ...values] =
|
|
24
|
-
|
|
25
|
-
|
|
28
|
+
const [strings, ...values] = args as [
|
|
29
|
+
strings: TemplateStringsArray
|
|
30
|
+
, ...values: string[]
|
|
31
|
+
]
|
|
32
|
+
const name = concat(strings, ...values)
|
|
26
33
|
|
|
27
|
-
return (
|
|
34
|
+
return (
|
|
35
|
+
...matchers: Array<
|
|
36
|
+
| INestedMatcher<Node>
|
|
37
|
+
| ITerminalMatcher<Node>
|
|
38
|
+
>
|
|
39
|
+
) => node(name, ...matchers)
|
|
28
40
|
}
|
|
29
41
|
|
|
30
42
|
if (isString(args[0])) {
|
|
31
|
-
const [name, ...matchers] =
|
|
32
|
-
|
|
43
|
+
const [name, ...matchers] = args as [
|
|
44
|
+
name: string
|
|
45
|
+
, ...matchers: Array<
|
|
46
|
+
| INestedMatcher<Node>
|
|
47
|
+
| ITerminalMatcher<Node>
|
|
48
|
+
>
|
|
49
|
+
]
|
|
33
50
|
|
|
34
51
|
return function (this: IReadonlyContext, _node: Node) {
|
|
35
52
|
const result = node(...matchers).call(this, _node)
|
|
@@ -40,10 +57,15 @@ export function node(...args:
|
|
|
40
57
|
}
|
|
41
58
|
}
|
|
42
59
|
|
|
43
|
-
const [...matchers] = args as [
|
|
60
|
+
const [...matchers] = args as [
|
|
61
|
+
...matchers: Array<
|
|
62
|
+
| INestedMatcher<Node>
|
|
63
|
+
| ITerminalMatcher<Node>
|
|
64
|
+
>
|
|
65
|
+
]
|
|
44
66
|
|
|
45
67
|
return function (this: IReadonlyContext, node: Node) {
|
|
46
|
-
if (matchers
|
|
68
|
+
if (isEmptyArray(matchers)) return true
|
|
47
69
|
|
|
48
70
|
return matchers.every(match => match.call(this, node))
|
|
49
71
|
}
|
package/src/matchers/optional.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { INestedMatcher, ITerminalMatcher, ISkipMatcher } from '@src/types.js'
|
|
2
2
|
import { multiple } from './multiple.js'
|
|
3
3
|
|
|
4
|
-
export function optional<T extends Node>(
|
|
4
|
+
export function optional<T extends Node>(
|
|
5
|
+
matcher: INestedMatcher<T> | ITerminalMatcher<T>
|
|
6
|
+
): ISkipMatcher<T> {
|
|
5
7
|
return multiple([0, 1], matcher, { greedy: true })
|
|
6
8
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { INestedMatcher, ITerminalMatcher, IReadonlyContext } from '@src/types.js'
|
|
2
2
|
import { isArray, isString } from '@blackglory/prelude'
|
|
3
|
-
import { concat } from '
|
|
3
|
+
import { concat } from 'extra-tags'
|
|
4
4
|
import { isntTextNode } from 'extra-dom'
|
|
5
5
|
import { mergeInPlace } from '@utils/merge-in-place.js'
|
|
6
6
|
|
|
@@ -21,16 +21,20 @@ export function textNode(...args:
|
|
|
21
21
|
| [...matchers: Array<ITerminalMatcher<Node>>]
|
|
22
22
|
) {
|
|
23
23
|
if (isArray(args[0])) {
|
|
24
|
-
const [strings, ...values] =
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
const [strings, ...values] = args as [
|
|
25
|
+
strings: TemplateStringsArray
|
|
26
|
+
, ...values: string[]
|
|
27
|
+
]
|
|
28
|
+
const name = concat(strings, ...values)
|
|
27
29
|
|
|
28
30
|
return (...matchers: Array<ITerminalMatcher<Node>>) => textNode(name, ...matchers)
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
if (isString(args[0])) {
|
|
32
|
-
const [name, ...matchers] =
|
|
33
|
-
|
|
34
|
+
const [name, ...matchers] = args as [
|
|
35
|
+
name: string
|
|
36
|
+
, ...matchers: Array<ITerminalMatcher<Node>>
|
|
37
|
+
]
|
|
34
38
|
|
|
35
39
|
return function (this: IReadonlyContext, node: Node) {
|
|
36
40
|
const result = textNode(...matchers).call(this, node)
|
package/src/matchers/xpath.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { ITerminalMatcher, IReadonlyContext } from '@src/types.js'
|
|
2
|
-
import { isString } from '@blackglory/prelude'
|
|
3
|
-
import { concat } from '
|
|
2
|
+
import { isntNull, isString } from '@blackglory/prelude'
|
|
3
|
+
import { concat } from 'extra-tags'
|
|
4
4
|
import { assert } from '@blackglory/prelude'
|
|
5
5
|
|
|
6
6
|
const UNORDERED_NODE_ITERATOR_TYPE =
|
|
7
7
|
'XPathResult' in globalThis
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
? XPathResult.UNORDERED_NODE_ITERATOR_TYPE
|
|
9
|
+
: 4
|
|
10
10
|
|
|
11
11
|
export function xpath(
|
|
12
12
|
strings: TemplateStringsArray
|
|
@@ -21,7 +21,7 @@ export function xpath(...args:
|
|
|
21
21
|
): ITerminalMatcher<Node> {
|
|
22
22
|
if (isString(args[0])) {
|
|
23
23
|
const [expression] = args
|
|
24
|
-
assert(expression.startsWith('
|
|
24
|
+
assert(expression.startsWith('/'), 'XPath expressions must start with "/"')
|
|
25
25
|
|
|
26
26
|
return function (
|
|
27
27
|
this: Pick<IReadonlyContext, 'document'>
|
|
@@ -31,7 +31,7 @@ export function xpath(...args:
|
|
|
31
31
|
}
|
|
32
32
|
} else {
|
|
33
33
|
const [strings, ...values] = args
|
|
34
|
-
const expression = concat(strings, values)
|
|
34
|
+
const expression = concat(strings, ...values)
|
|
35
35
|
|
|
36
36
|
return xpath(expression)
|
|
37
37
|
}
|
|
@@ -46,8 +46,8 @@ function xpathMatches(document: Document, expression: string, node: Node): boole
|
|
|
46
46
|
, null
|
|
47
47
|
)
|
|
48
48
|
|
|
49
|
-
let value
|
|
50
|
-
while (
|
|
49
|
+
let value: Node | null
|
|
50
|
+
while (value = iterator.iterateNext(), isntNull(value)) {
|
|
51
51
|
if (value === node) return true
|
|
52
52
|
}
|
|
53
53
|
return false
|
package/src/types.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { Arrayable } from '@blackglory/prelude'
|
|
2
|
+
|
|
1
3
|
export interface IContext {
|
|
2
4
|
readonly document: Document
|
|
3
5
|
readonly next: (node: Node, distance?: number) => Node | undefined
|
|
4
6
|
readonly collection: {
|
|
5
|
-
[name: string]: Node
|
|
7
|
+
[name: string]: Arrayable<Node>
|
|
6
8
|
}
|
|
7
9
|
}
|
|
8
10
|
|
|
@@ -10,7 +12,7 @@ export interface IReadonlyContext {
|
|
|
10
12
|
readonly document: Document
|
|
11
13
|
readonly next: (node: Node, distance?: number) => Node | undefined
|
|
12
14
|
readonly collection: {
|
|
13
|
-
readonly [name: string]: Node
|
|
15
|
+
readonly [name: string]: Arrayable<Node>
|
|
14
16
|
}
|
|
15
17
|
}
|
|
16
18
|
|
|
@@ -19,8 +21,9 @@ export type IMatcher<T extends Node> =
|
|
|
19
21
|
| INestedMatcher<T>
|
|
20
22
|
| ISkipMatcher<T>
|
|
21
23
|
| (
|
|
22
|
-
<T extends Node>(
|
|
23
|
-
|
|
24
|
+
<T extends Node>(
|
|
25
|
+
this: IReadonlyContext, node: T
|
|
26
|
+
) => boolean | number | Iterable<number>
|
|
24
27
|
)
|
|
25
28
|
|
|
26
29
|
export type INestedMatcher<T extends Node> = (
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { IMatcher, IReadonlyContext } from '@src/types.js'
|
|
2
|
-
import { isBoolean, isNumber, isIterable } from '@blackglory/prelude'
|
|
2
|
+
import { isBoolean, isNumber, isIterable, isEmptyArray } from '@blackglory/prelude'
|
|
3
3
|
|
|
4
4
|
export function matchOneByOne<T extends Node>(
|
|
5
5
|
context: IReadonlyContext
|
|
6
6
|
, source: T | null
|
|
7
7
|
, ...matchers: Array<IMatcher<T>>
|
|
8
8
|
): boolean {
|
|
9
|
-
if (matchers
|
|
9
|
+
if (isEmptyArray(matchers)) return true
|
|
10
10
|
if (!source) return false
|
|
11
11
|
|
|
12
12
|
const [matcher, ...otherMatchers] = matchers
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { isArray } from '@blackglory/prelude'
|
|
1
|
+
import { Arrayable, isArray } from '@blackglory/prelude'
|
|
2
2
|
|
|
3
3
|
export function mergeInPlace<T>(
|
|
4
|
-
target: Record<string, T
|
|
5
|
-
, source: Record<string, T
|
|
4
|
+
target: Record<string, Arrayable<T>>
|
|
5
|
+
, source: Record<string, Arrayable<T>>
|
|
6
6
|
): void {
|
|
7
7
|
for (const [key, value] of Object.entries(source)) {
|
|
8
8
|
if (target[key]) {
|
package/lib/utils/concat.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function concat(strings: TemplateStringsArray, values: string[]): string[];
|
package/lib/utils/concat.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export function concat(strings, values) {
|
|
2
|
-
const result = [];
|
|
3
|
-
for (let i = 0, len = values.length; i < len; i++) {
|
|
4
|
-
result.push(strings[i]);
|
|
5
|
-
result.push(values[i]);
|
|
6
|
-
}
|
|
7
|
-
result.push(strings[strings.length - 1]);
|
|
8
|
-
return result;
|
|
9
|
-
}
|
|
10
|
-
//# sourceMappingURL=concat.js.map
|
package/lib/utils/concat.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"concat.js","sourceRoot":"","sources":["../../src/utils/concat.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,MAAM,CAAC,OAA6B,EAAE,MAAgB;IACpE,MAAM,MAAM,GAAG,EAAE,CAAA;IACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAClD,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;QACvB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;IACxB,CAAC;IACD,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAA;IACxC,OAAO,MAAM,CAAA;AACf,CAAC"}
|
package/src/utils/concat.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export function concat(strings: TemplateStringsArray, values: string[]): string[] {
|
|
2
|
-
const result = []
|
|
3
|
-
for (let i = 0, len = values.length; i < len; i++) {
|
|
4
|
-
result.push(strings[i])
|
|
5
|
-
result.push(values[i])
|
|
6
|
-
}
|
|
7
|
-
result.push(strings[strings.length - 1])
|
|
8
|
-
return result
|
|
9
|
-
}
|