@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.
Files changed (45) hide show
  1. package/README.md +67 -6
  2. package/lib/match-element.d.ts +2 -3
  3. package/lib/match-element.js +3 -1
  4. package/lib/match-element.js.map +1 -1
  5. package/lib/match.d.ts +2 -3
  6. package/lib/match.js +3 -1
  7. package/lib/match.js.map +1 -1
  8. package/lib/matchers/child-nodes.js +2 -1
  9. package/lib/matchers/child-nodes.js.map +1 -1
  10. package/lib/matchers/children.js +2 -1
  11. package/lib/matchers/children.js.map +1 -1
  12. package/lib/matchers/css.js +2 -2
  13. package/lib/matchers/css.js.map +1 -1
  14. package/lib/matchers/element.js +4 -4
  15. package/lib/matchers/element.js.map +1 -1
  16. package/lib/matchers/node.js +4 -4
  17. package/lib/matchers/node.js.map +1 -1
  18. package/lib/matchers/optional.js.map +1 -1
  19. package/lib/matchers/text-node.js +2 -2
  20. package/lib/matchers/text-node.js.map +1 -1
  21. package/lib/matchers/xpath.js +5 -5
  22. package/lib/matchers/xpath.js.map +1 -1
  23. package/lib/types.d.ts +3 -2
  24. package/lib/utils/match-one-by-one.js +2 -2
  25. package/lib/utils/match-one-by-one.js.map +1 -1
  26. package/lib/utils/merge-in-place.d.ts +2 -1
  27. package/lib/utils/merge-in-place.js.map +1 -1
  28. package/package.json +3 -3
  29. package/src/match-element.ts +6 -2
  30. package/src/match.ts +6 -2
  31. package/src/matchers/child-nodes.ts +2 -1
  32. package/src/matchers/children.ts +2 -1
  33. package/src/matchers/css.ts +2 -2
  34. package/src/matchers/element.ts +40 -15
  35. package/src/matchers/node.ts +33 -11
  36. package/src/matchers/optional.ts +3 -1
  37. package/src/matchers/text-node.ts +10 -6
  38. package/src/matchers/xpath.ts +8 -8
  39. package/src/types.ts +7 -4
  40. package/src/utils/match-one-by-one.ts +2 -2
  41. package/src/utils/merge-in-place.ts +3 -3
  42. package/lib/utils/concat.d.ts +0 -1
  43. package/lib/utils/concat.js +0 -10
  44. package/lib/utils/concat.js.map +0 -1
  45. 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
- node
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`section`
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
- // { heading: Text, paragraph: [ Text, Text ] }
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
- ): { [name: string]: Node | Node[] } | null
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
- ): { [name: string]: Node | Node[] } | null
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<INestedMatcher<Element> | ITerminalMatcher<Element>>
190
+ ...matchers: Array<
191
+ | INestedMatcher<Element>
192
+ | ITerminalMatcher<Element>
193
+ >
133
194
  ) => INestedMatcher<Node>
134
195
  function element(
135
196
  name: string
@@ -1,4 +1,3 @@
1
1
  import { IMatcher } from './types.js';
2
- export declare function matchElement(this: void | Document, element: Element, ...matchers: Array<IMatcher<Element>>): {
3
- [name: string]: Node | Node[];
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;
@@ -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) ? this : globalThis.document;
5
+ const document = isDocument(this)
6
+ ? this
7
+ : globalThis.document;
6
8
  const context = {
7
9
  document,
8
10
  collection: {},
@@ -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;AAEnE,MAAM,UAAU,YAAY,CAE1B,OAAgB,EAChB,GAAG,QAAkC;IAErC,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAA;IAC9D,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"}
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
- export declare function match(this: void | Document, node: Node, ...matchers: Array<IMatcher<Node>>): {
3
- [name: string]: Node | Node[];
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) ? this : globalThis.document;
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;AAEpD,MAAM,UAAU,KAAK,CAEnB,IAAU,EACV,GAAG,QAA+B;IAElC,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAA;IAC9D,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
+ {"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.length === 0) {
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":"AACA,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,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,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"}
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"}
@@ -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.length === 0) {
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":"AACA,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,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,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"}
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"}
@@ -1,4 +1,4 @@
1
- import { concat } from "../utils/concat.js";
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).join('');
10
+ const selector = concat(strings, ...values);
11
11
  return css(selector);
12
12
  }
13
13
  }
@@ -1 +1 @@
1
- {"version":3,"file":"css.js","sourceRoot":"","sources":["../../src/matchers/css.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,2BAAwB;AAEzC,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,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAEjD,OAAO,GAAG,CAAC,QAAQ,CAAC,CAAA;IACtB,CAAC;AACH,CAAC"}
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"}
@@ -1,11 +1,11 @@
1
1
  import { isntElement } from 'extra-dom';
2
- import { isArray, isString } from '@blackglory/prelude';
3
- import { concat } from "../utils/concat.js";
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).join('');
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.length === 0)
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;AACvD,OAAO,EAAE,MAAM,EAAE,2BAAwB;AACzC,OAAO,EAAE,YAAY,EAAE,mCAAgC;AAUvD,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,GACxB,IAA4D,CAAA;QAC9D,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAE7C,OAAO,CAAC,GAAG,QAAoE,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,CAAA;IAChH,CAAC;IAED,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACtB,MAAM,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,GACvB,IAA+F,CAAA;QAEjG,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,IAAiF,CAAA;IAEvG,OAAO,UAAkC,OAAgB;QACvD,IAAI,WAAW,CAAC,OAAO,CAAC;YAAE,OAAO,KAAK,CAAA;QACtC,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,OAAO,CAAC,CAAC,CAAA;IAC3D,CAAC,CAAA;AACH,CAAC"}
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"}
@@ -1,10 +1,10 @@
1
- import { isArray, isString } from '@blackglory/prelude';
2
- import { concat } from "../utils/concat.js";
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).join('');
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.length === 0)
22
+ if (isEmptyArray(matchers))
23
23
  return true;
24
24
  return matchers.every(match => match.call(this, node));
25
25
  };
@@ -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;AACvD,OAAO,EAAE,MAAM,EAAE,2BAAwB;AACzC,OAAO,EAAE,YAAY,EAAE,mCAAgC;AAavD,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,GACxB,IAA4D,CAAA;QAC9D,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAE7C,OAAO,CAAC,GAAG,QAA8D,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,CAAA;IACvG,CAAC;IAED,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACtB,MAAM,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,GACvB,IAAyF,CAAA;QAE3F,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,IAA2E,CAAA;IAEjG,OAAO,UAAkC,IAAU;QACjD,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"}
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,CAAiB,OAAgD;IACvF,OAAO,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;AACpD,CAAC"}
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 "../utils/concat.js";
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).join('');
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,2BAAwB;AACzC,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,GACxB,IAA4D,CAAA;QAC9D,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAE7C,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,GACvB,IAAkE,CAAA;QAEpE,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"}
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"}
@@ -1,5 +1,5 @@
1
- import { isString } from '@blackglory/prelude';
2
- import { concat } from "../utils/concat.js";
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('//*'), 'XPath expressions must start with "//*"');
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).join('');
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 ((value = iterator.iterateNext()) !== null) {
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;AAC9C,OAAO,EAAE,MAAM,EAAE,2BAAwB;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAE5C,MAAM,4BAA4B,GAChC,aAAa,IAAI,UAAU;IAC3B,CAAC,CAAC,WAAW,CAAC,4BAA4B;IAC1C,CAAC,CAAC,CAAC,CAAA;AASL,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,KAAK,CAAC,EAAE,yCAAyC,CAAC,CAAA;QAE/E,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,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAEnD,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,KAAK,CAAA;IACT,OAAO,CAAC,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;QACjD,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,IAAI,CAAA;IACjC,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC"}
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 | 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 | 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.length === 0)
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;AAErE,MAAM,UAAU,aAAa,CAC3B,OAAyB,EACzB,MAAgB,EAChB,GAAG,QAA4B;IAE/B,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACtC,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
+ {"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
- export declare function mergeInPlace<T>(target: Record<string, T | T[]>, source: Record<string, T | T[]>): void;
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,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAE7C,MAAM,UAAU,YAAY,CAC1B,MAA+B,EAC/B,MAA+B;IAE/B,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"}
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.0",
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
  }
@@ -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
- ): { [name: string]: Node | Node[] } | null {
11
- const document = isDocument(this) ? this : globalThis.document
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
- ): { [name: string]: Node | Node[] } | null {
11
- const document = isDocument(this) ? this : globalThis.document
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.length === 0) {
10
+ if (isEmptyArray(matchers)) {
10
11
  return node.childNodes.length === 0
11
12
  }
12
13
 
@@ -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.length === 0) {
12
+ if (isEmptyArray(matchers)) {
12
13
  return element.children.length === 0
13
14
  }
14
15
 
@@ -1,4 +1,4 @@
1
- import { concat } from '@utils/concat.js'
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).join('')
20
+ const selector = concat(strings, ...values)
21
21
 
22
22
  return css(selector)
23
23
  }
@@ -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 '@utils/concat.js'
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
- ): (...matchers: Array<INestedMatcher<Element> | ITerminalMatcher<Element>>) => INestedMatcher<Node>
11
- export function element(name: string, ...matchers: Array<INestedMatcher<Element>>):
12
- INestedMatcher<Node>
13
- export function element(...matchers: Array<INestedMatcher<Element>>):
14
- INestedMatcher<Node>
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
- args as [strings: TemplateStringsArray, ...values: string[]]
23
- const name = concat(strings, values).join('')
29
+ const [strings, ...values] = args as [
30
+ strings: TemplateStringsArray
31
+ , ...values: string[]
32
+ ]
33
+ const name = concat(strings, ...values)
24
34
 
25
- return (...matchers: Array<INestedMatcher<Element> | ITerminalMatcher<Element>>) => element(name, ...matchers)
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
- args as [name: string, ...matchers: Array<INestedMatcher<Element> | ITerminalMatcher<Element>>]
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 [...matchers: Array<INestedMatcher<Element> | ITerminalMatcher<Element>>]
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.length === 0) return true
70
+ if (isEmptyArray(matchers)) return true
46
71
 
47
72
  return matchers.every(match => match.call(this, element))
48
73
  }
@@ -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 '@utils/concat.js'
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
- ): (...matchers: Array<INestedMatcher<Node> | ITerminalMatcher<Node>>) => INestedMatcher<Node>
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
- args as [strings: TemplateStringsArray, ...values: string[]]
25
- const name = concat(strings, values).join('')
28
+ const [strings, ...values] = args as [
29
+ strings: TemplateStringsArray
30
+ , ...values: string[]
31
+ ]
32
+ const name = concat(strings, ...values)
26
33
 
27
- return (...matchers: Array<INestedMatcher<Node> | ITerminalMatcher<Node>>) => node(name, ...matchers)
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
- args as [name: string, ...matchers: Array<INestedMatcher<Node> | ITerminalMatcher<Node>>]
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 [...matchers: Array<INestedMatcher<Node> | ITerminalMatcher<Node>>]
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.length === 0) return true
68
+ if (isEmptyArray(matchers)) return true
47
69
 
48
70
  return matchers.every(match => match.call(this, node))
49
71
  }
@@ -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>(matcher: INestedMatcher<T> | ITerminalMatcher<T>): ISkipMatcher<T> {
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 '@utils/concat.js'
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
- args as [strings: TemplateStringsArray, ...values: string[]]
26
- const name = concat(strings, values).join('')
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
- args as [name: string, ...matchers: Array<ITerminalMatcher<Node>>]
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)
@@ -1,12 +1,12 @@
1
1
  import { ITerminalMatcher, IReadonlyContext } from '@src/types.js'
2
- import { isString } from '@blackglory/prelude'
3
- import { concat } from '@utils/concat.js'
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
- ? XPathResult.UNORDERED_NODE_ITERATOR_TYPE
9
- : 4
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('//*'), 'XPath expressions must start with "//*"')
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).join('')
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 ((value = iterator.iterateNext()) !== null) {
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 | 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 | 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>(this: IReadonlyContext, node: T) =>
23
- boolean | number | Iterable<number>
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.length === 0) return true
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 | T[]>
5
- , source: Record<string, T | 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]) {
@@ -1 +0,0 @@
1
- export declare function concat(strings: TemplateStringsArray, values: string[]): string[];
@@ -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
@@ -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"}
@@ -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
- }