1
1
/**
2
2
* @typedef {import('unist').Parent } UnistParent
3
3
* @typedef {import('nlcst').Root } Root
4
- * @typedef {import('nlcst').Word } Word
5
4
* @typedef {import('nlcst').Content } Content
6
- * @typedef {Root|Content } Node
5
+ * @typedef {import('nlcst-normalize').Options } NormalizeOptions
6
+ */
7
+
8
+ /**
9
+ * @typedef {Root | Content } Node
7
10
* @typedef {Extract<Node, UnistParent> } Parent
8
- * @typedef {import('nlcst-normalize').NormalizeOptions } NormalizeOptions
9
11
*
10
- * @typedef {boolean } AllowApostrophes
11
12
* @typedef {NormalizeOptions & {allowLiterals?: boolean} } Options
12
13
* Configuration (optional).
14
+ *
13
15
* @typedef {Array<string> } PhrasesList
14
16
* List of phrases.
15
17
* @typedef {Record<string, unknown> } PhrasesMap
16
18
* Map where the keys are phrases.
17
- * @typedef {(nodes: Array<Content>, index: number, parent: Parent, pattern: string) => void } Handler
19
+ *
20
+ * @callback Handler
18
21
* Function called when a pattern matches.
22
+ * @param {Array<Content> } nodes
23
+ * Match.
24
+ * @param {number } index
25
+ * Index of first node of `nodes` in `parent.
26
+ * @param {Parent } parent
27
+ * Parent of `nodes`.
28
+ * @param {string } pattern
29
+ * The pattern that matched.
30
+ * @returns {void }
31
+ * Nothing.
19
32
*/
20
33
21
34
import { visit } from 'unist-util-visit'
@@ -25,25 +38,28 @@ import {isLiteral} from 'nlcst-is-literal'
25
38
const own = { } . hasOwnProperty
26
39
27
40
/**
41
+ * Search for patterns a tree.
42
+ *
28
43
* @param {Node } tree
29
- * @param {PhrasesList|PhrasesMap } phrases
44
+ * Tree to search.
45
+ * @param {PhrasesList | PhrasesMap } phrases
46
+ * Patterns.
30
47
* @param {Handler } handler
31
- * @param {AllowApostrophes|Options } [options=false]
48
+ * Handler.
49
+ * @param {boolean | Options } [options=false]
50
+ * Configuration.
51
+ * @returns {void }
52
+ * Nothing.
32
53
*/
54
+ // To do: next major: remove boolean overload.
55
+ // To do: next major: remove `PhrasesMap` support.
33
56
export function search ( tree , phrases , handler , options ) {
34
- /** @type {Record<string, Array<string>> } */
35
- const byWord = { '*' : [ ] }
36
- let index = - 1
37
- /** @type {string } */
38
- let key
39
- /** @type {Options } */
40
- let config
41
-
42
- if ( typeof options === 'boolean' ) {
43
- config = options ? { allowApostrophes : true } : { }
44
- } else {
45
- config = options || { }
46
- }
57
+ const config =
58
+ typeof options === 'boolean'
59
+ ? options
60
+ ? { allowApostrophes : true }
61
+ : { }
62
+ : options || { }
47
63
48
64
if ( ! tree || ! tree . type ) {
49
65
throw new Error ( 'Expected node' )
@@ -53,11 +69,18 @@ export function search(tree, phrases, handler, options) {
53
69
throw new TypeError ( 'Expected object for phrases' )
54
70
}
55
71
72
+ /** @type {Record<string, Array<string>> } */
73
+ const byWord = { '*' : [ ] }
74
+
56
75
if ( Array . isArray ( phrases ) ) {
76
+ let index = - 1
57
77
while ( ++ index < phrases . length ) {
58
78
handlePhrase ( phrases [ index ] )
59
79
}
60
80
} else {
81
+ /** @type {string } */
82
+ let key
83
+
61
84
for ( key in phrases ) {
62
85
if ( own . call ( phrases , key ) ) {
63
86
handlePhrase ( key )
@@ -66,9 +89,7 @@ export function search(tree, phrases, handler, options) {
66
89
}
67
90
68
91
// Search the tree.
69
- visit ( tree , 'WordNode' , ( node , position , parent_ ) => {
70
- const parent = /** @type {Parent } */ ( parent_ )
71
-
92
+ visit ( tree , 'WordNode' , ( node , position , parent ) => {
72
93
if (
73
94
! parent ||
74
95
position === null ||
@@ -78,9 +99,9 @@ export function search(tree, phrases, handler, options) {
78
99
}
79
100
80
101
const word = normalize ( node , config )
81
- const phrases = byWord [ '*' ] . concat (
82
- own . call ( byWord , word ) ? byWord [ word ] : [ ]
83
- )
102
+ const phrases = own . call ( byWord , word )
103
+ ? [ ... byWord [ '*' ] , ... byWord [ word ] ]
104
+ : byWord [ '*' ]
84
105
let index = - 1
85
106
86
107
while ( ++ index < phrases . length ) {
@@ -93,11 +114,16 @@ export function search(tree, phrases, handler, options) {
93
114
} )
94
115
95
116
/**
96
- * Test a phrase.
117
+ * Test a phrase (the first word already matched) .
97
118
*
98
119
* @param {string } phrase
120
+ * Normalized phrase.
99
121
* @param {number } position
122
+ * Index in `parent`.
100
123
* @param {Parent } parent
124
+ * Parent node.
125
+ * @returns {Array<Content> | void }
126
+ * Match, if found.
101
127
*/
102
128
function test ( phrase , position , parent ) {
103
129
const siblings = parent . children
@@ -135,9 +161,12 @@ export function search(tree, phrases, handler, options) {
135
161
}
136
162
137
163
/**
138
- * Handle a phrase.
164
+ * Index a phrase.
139
165
*
140
166
* @param {string } phrase
167
+ * Raw phrase.
168
+ * @returns {void }
169
+ * Nothing.
141
170
*/
142
171
function handlePhrase ( phrase ) {
143
172
const firstWord = normalize ( phrase . split ( ' ' , 1 ) [ 0 ] , config )
0 commit comments