@douyinfe/semi-foundation 2.70.1 → 2.71.0-alpha.3
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/cascader/constants.ts +2 -0
- package/cascader/foundation.ts +49 -2
- package/dragMove/foundation.ts +194 -0
- package/highlight/foundation.ts +211 -0
- package/jsonViewer/constants.ts +7 -0
- package/jsonViewer/foundation.ts +72 -0
- package/jsonViewer/jsonViewer.scss +200 -0
- package/jsonViewer/script/build.js +51 -0
- package/jsonViewer/variables.scss +15 -0
- package/lib/cjs/cascader/constants.d.ts +2 -0
- package/lib/cjs/cascader/constants.js +3 -1
- package/lib/cjs/cascader/foundation.d.ts +3 -0
- package/lib/cjs/cascader/foundation.js +55 -3
- package/lib/cjs/dragMove/foundation.d.ts +45 -0
- package/lib/cjs/dragMove/foundation.js +162 -0
- package/lib/cjs/highlight/foundation.d.ts +84 -0
- package/lib/cjs/highlight/foundation.js +184 -0
- package/lib/cjs/jsonViewer/constants.d.ts +4 -0
- package/lib/cjs/jsonViewer/constants.js +10 -0
- package/lib/cjs/jsonViewer/foundation.d.ts +24 -0
- package/lib/cjs/jsonViewer/foundation.js +69 -0
- package/lib/cjs/jsonViewer/jsonViewer.css +168 -0
- package/lib/cjs/jsonViewer/jsonViewer.scss +200 -0
- package/lib/cjs/jsonViewer/variables.scss +15 -0
- package/lib/cjs/lottie/foundation.d.ts +1 -1
- package/lib/cjs/resizable/foundation.d.ts +6 -2
- package/lib/cjs/tree/tree.css +1 -0
- package/lib/cjs/tree/tree.scss +2 -0
- package/lib/es/cascader/constants.d.ts +2 -0
- package/lib/es/cascader/constants.js +3 -1
- package/lib/es/cascader/foundation.d.ts +3 -0
- package/lib/es/cascader/foundation.js +55 -3
- package/lib/es/dragMove/foundation.d.ts +45 -0
- package/lib/es/dragMove/foundation.js +153 -0
- package/lib/es/highlight/foundation.d.ts +84 -0
- package/lib/es/highlight/foundation.js +174 -0
- package/lib/es/jsonViewer/constants.d.ts +4 -0
- package/lib/es/jsonViewer/constants.js +5 -0
- package/lib/es/jsonViewer/foundation.d.ts +24 -0
- package/lib/es/jsonViewer/foundation.js +62 -0
- package/lib/es/jsonViewer/jsonViewer.css +168 -0
- package/lib/es/jsonViewer/jsonViewer.scss +200 -0
- package/lib/es/jsonViewer/variables.scss +15 -0
- package/lib/es/lottie/foundation.d.ts +1 -1
- package/lib/es/resizable/foundation.d.ts +6 -2
- package/lib/es/resizable/foundation.js +3 -2
- package/lib/es/tree/tree.css +1 -0
- package/lib/es/tree/tree.scss +2 -0
- package/lottie/foundation.ts +2 -2
- package/package.json +5 -3
- package/resizable/foundation.ts +19 -5
- package/tree/tree.scss +2 -0
- package/tsconfig.json +1 -1
- package/lib/cjs/utils/getHighlight.d.ts +0 -45
- package/lib/cjs/utils/getHighlight.js +0 -175
- package/lib/es/utils/getHighlight.d.ts +0 -45
- package/lib/es/utils/getHighlight.js +0 -166
- package/utils/getHighlight.ts +0 -178
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.findAll = void 0;
|
|
7
|
-
var _isString2 = _interopRequireDefault(require("lodash/isString"));
|
|
8
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
-
// Modified version based on 'highlight-words-core'
|
|
10
|
-
|
|
11
|
-
const escapeRegExpFn = string => string.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
|
|
12
|
-
/**
|
|
13
|
-
* Examine text for any matches.
|
|
14
|
-
* If we find matches, add them to the returned array as a "chunk" object ({start:number, end:number}).
|
|
15
|
-
* @return { start:number, end:number }[]
|
|
16
|
-
*/
|
|
17
|
-
const findChunks = _ref => {
|
|
18
|
-
let {
|
|
19
|
-
autoEscape,
|
|
20
|
-
caseSensitive,
|
|
21
|
-
searchWords,
|
|
22
|
-
sourceString
|
|
23
|
-
} = _ref;
|
|
24
|
-
return searchWords.filter(searchWord => searchWord) // Remove empty words
|
|
25
|
-
.reduce((chunks, searchWord) => {
|
|
26
|
-
if (autoEscape) {
|
|
27
|
-
searchWord = escapeRegExpFn(searchWord);
|
|
28
|
-
}
|
|
29
|
-
const regex = new RegExp(searchWord, caseSensitive ? 'g' : 'gi');
|
|
30
|
-
let match;
|
|
31
|
-
while (match = regex.exec(sourceString)) {
|
|
32
|
-
const start = match.index;
|
|
33
|
-
const end = regex.lastIndex;
|
|
34
|
-
// We do not return zero-length matches
|
|
35
|
-
if (end > start) {
|
|
36
|
-
chunks.push({
|
|
37
|
-
highlight: false,
|
|
38
|
-
start,
|
|
39
|
-
end
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
// Prevent browsers like Firefox from getting stuck in an infinite loop
|
|
43
|
-
// See http://www.regexguru.com/2008/04/watch-out-for-zero-length-matches/
|
|
44
|
-
if (match.index === regex.lastIndex) {
|
|
45
|
-
regex.lastIndex++;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
return chunks;
|
|
49
|
-
}, []);
|
|
50
|
-
};
|
|
51
|
-
/**
|
|
52
|
-
* Takes an array of {start:number, end:number} objects and combines chunks that overlap into single chunks.
|
|
53
|
-
* @return {start:number, end:number}[]
|
|
54
|
-
*/
|
|
55
|
-
const combineChunks = _ref2 => {
|
|
56
|
-
let {
|
|
57
|
-
chunks
|
|
58
|
-
} = _ref2;
|
|
59
|
-
chunks = chunks.sort((first, second) => first.start - second.start).reduce((processedChunks, nextChunk) => {
|
|
60
|
-
// First chunk just goes straight in the array...
|
|
61
|
-
if (processedChunks.length === 0) {
|
|
62
|
-
return [nextChunk];
|
|
63
|
-
} else {
|
|
64
|
-
// ... subsequent chunks get checked to see if they overlap...
|
|
65
|
-
const prevChunk = processedChunks.pop();
|
|
66
|
-
if (nextChunk.start <= prevChunk.end) {
|
|
67
|
-
// It may be the case that prevChunk completely surrounds nextChunk, so take the
|
|
68
|
-
// largest of the end indeces.
|
|
69
|
-
const endIndex = Math.max(prevChunk.end, nextChunk.end);
|
|
70
|
-
processedChunks.push({
|
|
71
|
-
highlight: false,
|
|
72
|
-
start: prevChunk.start,
|
|
73
|
-
end: endIndex
|
|
74
|
-
});
|
|
75
|
-
} else {
|
|
76
|
-
processedChunks.push(prevChunk, nextChunk);
|
|
77
|
-
}
|
|
78
|
-
return processedChunks;
|
|
79
|
-
}
|
|
80
|
-
}, []);
|
|
81
|
-
return chunks;
|
|
82
|
-
};
|
|
83
|
-
/**
|
|
84
|
-
* Given a set of chunks to highlight, create an additional set of chunks
|
|
85
|
-
* to represent the bits of text between the highlighted text.
|
|
86
|
-
* @param chunksToHighlight {start:number, end:number}[]
|
|
87
|
-
* @param totalLength number
|
|
88
|
-
* @return {start:number, end:number, highlight:boolean}[]
|
|
89
|
-
*/
|
|
90
|
-
const fillInChunks = _ref3 => {
|
|
91
|
-
let {
|
|
92
|
-
chunksToHighlight,
|
|
93
|
-
totalLength
|
|
94
|
-
} = _ref3;
|
|
95
|
-
const allChunks = [];
|
|
96
|
-
const append = (start, end, highlight) => {
|
|
97
|
-
if (end - start > 0) {
|
|
98
|
-
allChunks.push({
|
|
99
|
-
start,
|
|
100
|
-
end,
|
|
101
|
-
highlight
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
if (chunksToHighlight.length === 0) {
|
|
106
|
-
append(0, totalLength, false);
|
|
107
|
-
} else {
|
|
108
|
-
let lastIndex = 0;
|
|
109
|
-
chunksToHighlight.forEach(chunk => {
|
|
110
|
-
append(lastIndex, chunk.start, false);
|
|
111
|
-
append(chunk.start, chunk.end, true);
|
|
112
|
-
lastIndex = chunk.end;
|
|
113
|
-
});
|
|
114
|
-
append(lastIndex, totalLength, false);
|
|
115
|
-
}
|
|
116
|
-
return allChunks;
|
|
117
|
-
};
|
|
118
|
-
/**
|
|
119
|
-
* Creates an array of chunk objects representing both higlightable and non highlightable pieces of text that match each search word.
|
|
120
|
-
*
|
|
121
|
-
findAll ['z'], 'aaazaaazaaa'
|
|
122
|
-
result #=> [
|
|
123
|
-
{ start: 0, end: 3, highlight: false }
|
|
124
|
-
{ start: 3, end: 4, highlight: true }
|
|
125
|
-
{ start: 4, end: 7, highlight: false }
|
|
126
|
-
{ start: 7, end: 8, highlight: true }
|
|
127
|
-
{ start: 8, end: 11, highlight: false }
|
|
128
|
-
]
|
|
129
|
-
|
|
130
|
-
findAll ['do', 'dollar'], 'aaa do dollar aaa'
|
|
131
|
-
#=> chunks: [
|
|
132
|
-
{ start: 4, end: 6 },
|
|
133
|
-
{ start: 7, end: 9 },
|
|
134
|
-
{ start: 7, end: 13 },
|
|
135
|
-
]
|
|
136
|
-
#=> chunksToHight: [
|
|
137
|
-
{ start: 4, end: 6 },
|
|
138
|
-
{ start: 7, end: 13 },
|
|
139
|
-
]
|
|
140
|
-
#=> result: [
|
|
141
|
-
{ start: 0, end: 4, highlight: false },
|
|
142
|
-
{ start: 4, end: 6, highlight: true },
|
|
143
|
-
{ start: 6, end: 7, highlight: false },
|
|
144
|
-
{ start: 7, end: 13, highlight: true },
|
|
145
|
-
{ start: 13, end: 17, highlight: false },
|
|
146
|
-
]
|
|
147
|
-
|
|
148
|
-
* @return Array of "chunks" (where a Chunk is { start:number, end:number, highlight:boolean })
|
|
149
|
-
*/
|
|
150
|
-
const findAll = _ref4 => {
|
|
151
|
-
let {
|
|
152
|
-
autoEscape = true,
|
|
153
|
-
caseSensitive = false,
|
|
154
|
-
searchWords,
|
|
155
|
-
sourceString
|
|
156
|
-
} = _ref4;
|
|
157
|
-
if ((0, _isString2.default)(searchWords)) {
|
|
158
|
-
searchWords = [searchWords];
|
|
159
|
-
}
|
|
160
|
-
const chunks = findChunks({
|
|
161
|
-
autoEscape,
|
|
162
|
-
caseSensitive,
|
|
163
|
-
searchWords,
|
|
164
|
-
sourceString
|
|
165
|
-
});
|
|
166
|
-
const chunksToHighlight = combineChunks({
|
|
167
|
-
chunks
|
|
168
|
-
});
|
|
169
|
-
const result = fillInChunks({
|
|
170
|
-
chunksToHighlight,
|
|
171
|
-
totalLength: sourceString ? sourceString.length : 0
|
|
172
|
-
});
|
|
173
|
-
return result;
|
|
174
|
-
};
|
|
175
|
-
exports.findAll = findAll;
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
interface ChunkQuery {
|
|
2
|
-
autoEscape?: boolean;
|
|
3
|
-
caseSensitive?: boolean;
|
|
4
|
-
searchWords: string[];
|
|
5
|
-
sourceString: string;
|
|
6
|
-
}
|
|
7
|
-
interface Chunk {
|
|
8
|
-
start: number;
|
|
9
|
-
end: number;
|
|
10
|
-
highlight: boolean;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Creates an array of chunk objects representing both higlightable and non highlightable pieces of text that match each search word.
|
|
14
|
-
*
|
|
15
|
-
findAll ['z'], 'aaazaaazaaa'
|
|
16
|
-
result #=> [
|
|
17
|
-
{ start: 0, end: 3, highlight: false }
|
|
18
|
-
{ start: 3, end: 4, highlight: true }
|
|
19
|
-
{ start: 4, end: 7, highlight: false }
|
|
20
|
-
{ start: 7, end: 8, highlight: true }
|
|
21
|
-
{ start: 8, end: 11, highlight: false }
|
|
22
|
-
]
|
|
23
|
-
|
|
24
|
-
findAll ['do', 'dollar'], 'aaa do dollar aaa'
|
|
25
|
-
#=> chunks: [
|
|
26
|
-
{ start: 4, end: 6 },
|
|
27
|
-
{ start: 7, end: 9 },
|
|
28
|
-
{ start: 7, end: 13 },
|
|
29
|
-
]
|
|
30
|
-
#=> chunksToHight: [
|
|
31
|
-
{ start: 4, end: 6 },
|
|
32
|
-
{ start: 7, end: 13 },
|
|
33
|
-
]
|
|
34
|
-
#=> result: [
|
|
35
|
-
{ start: 0, end: 4, highlight: false },
|
|
36
|
-
{ start: 4, end: 6, highlight: true },
|
|
37
|
-
{ start: 6, end: 7, highlight: false },
|
|
38
|
-
{ start: 7, end: 13, highlight: true },
|
|
39
|
-
{ start: 13, end: 17, highlight: false },
|
|
40
|
-
]
|
|
41
|
-
|
|
42
|
-
* @return Array of "chunks" (where a Chunk is { start:number, end:number, highlight:boolean })
|
|
43
|
-
*/
|
|
44
|
-
declare const findAll: ({ autoEscape, caseSensitive, searchWords, sourceString }: ChunkQuery) => Chunk[];
|
|
45
|
-
export { findAll };
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import _isString from "lodash/isString"; // Modified version based on 'highlight-words-core'
|
|
2
|
-
const escapeRegExpFn = string => string.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
|
|
3
|
-
/**
|
|
4
|
-
* Examine text for any matches.
|
|
5
|
-
* If we find matches, add them to the returned array as a "chunk" object ({start:number, end:number}).
|
|
6
|
-
* @return { start:number, end:number }[]
|
|
7
|
-
*/
|
|
8
|
-
const findChunks = _ref => {
|
|
9
|
-
let {
|
|
10
|
-
autoEscape,
|
|
11
|
-
caseSensitive,
|
|
12
|
-
searchWords,
|
|
13
|
-
sourceString
|
|
14
|
-
} = _ref;
|
|
15
|
-
return searchWords.filter(searchWord => searchWord) // Remove empty words
|
|
16
|
-
.reduce((chunks, searchWord) => {
|
|
17
|
-
if (autoEscape) {
|
|
18
|
-
searchWord = escapeRegExpFn(searchWord);
|
|
19
|
-
}
|
|
20
|
-
const regex = new RegExp(searchWord, caseSensitive ? 'g' : 'gi');
|
|
21
|
-
let match;
|
|
22
|
-
while (match = regex.exec(sourceString)) {
|
|
23
|
-
const start = match.index;
|
|
24
|
-
const end = regex.lastIndex;
|
|
25
|
-
// We do not return zero-length matches
|
|
26
|
-
if (end > start) {
|
|
27
|
-
chunks.push({
|
|
28
|
-
highlight: false,
|
|
29
|
-
start,
|
|
30
|
-
end
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
// Prevent browsers like Firefox from getting stuck in an infinite loop
|
|
34
|
-
// See http://www.regexguru.com/2008/04/watch-out-for-zero-length-matches/
|
|
35
|
-
if (match.index === regex.lastIndex) {
|
|
36
|
-
regex.lastIndex++;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return chunks;
|
|
40
|
-
}, []);
|
|
41
|
-
};
|
|
42
|
-
/**
|
|
43
|
-
* Takes an array of {start:number, end:number} objects and combines chunks that overlap into single chunks.
|
|
44
|
-
* @return {start:number, end:number}[]
|
|
45
|
-
*/
|
|
46
|
-
const combineChunks = _ref2 => {
|
|
47
|
-
let {
|
|
48
|
-
chunks
|
|
49
|
-
} = _ref2;
|
|
50
|
-
chunks = chunks.sort((first, second) => first.start - second.start).reduce((processedChunks, nextChunk) => {
|
|
51
|
-
// First chunk just goes straight in the array...
|
|
52
|
-
if (processedChunks.length === 0) {
|
|
53
|
-
return [nextChunk];
|
|
54
|
-
} else {
|
|
55
|
-
// ... subsequent chunks get checked to see if they overlap...
|
|
56
|
-
const prevChunk = processedChunks.pop();
|
|
57
|
-
if (nextChunk.start <= prevChunk.end) {
|
|
58
|
-
// It may be the case that prevChunk completely surrounds nextChunk, so take the
|
|
59
|
-
// largest of the end indeces.
|
|
60
|
-
const endIndex = Math.max(prevChunk.end, nextChunk.end);
|
|
61
|
-
processedChunks.push({
|
|
62
|
-
highlight: false,
|
|
63
|
-
start: prevChunk.start,
|
|
64
|
-
end: endIndex
|
|
65
|
-
});
|
|
66
|
-
} else {
|
|
67
|
-
processedChunks.push(prevChunk, nextChunk);
|
|
68
|
-
}
|
|
69
|
-
return processedChunks;
|
|
70
|
-
}
|
|
71
|
-
}, []);
|
|
72
|
-
return chunks;
|
|
73
|
-
};
|
|
74
|
-
/**
|
|
75
|
-
* Given a set of chunks to highlight, create an additional set of chunks
|
|
76
|
-
* to represent the bits of text between the highlighted text.
|
|
77
|
-
* @param chunksToHighlight {start:number, end:number}[]
|
|
78
|
-
* @param totalLength number
|
|
79
|
-
* @return {start:number, end:number, highlight:boolean}[]
|
|
80
|
-
*/
|
|
81
|
-
const fillInChunks = _ref3 => {
|
|
82
|
-
let {
|
|
83
|
-
chunksToHighlight,
|
|
84
|
-
totalLength
|
|
85
|
-
} = _ref3;
|
|
86
|
-
const allChunks = [];
|
|
87
|
-
const append = (start, end, highlight) => {
|
|
88
|
-
if (end - start > 0) {
|
|
89
|
-
allChunks.push({
|
|
90
|
-
start,
|
|
91
|
-
end,
|
|
92
|
-
highlight
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
};
|
|
96
|
-
if (chunksToHighlight.length === 0) {
|
|
97
|
-
append(0, totalLength, false);
|
|
98
|
-
} else {
|
|
99
|
-
let lastIndex = 0;
|
|
100
|
-
chunksToHighlight.forEach(chunk => {
|
|
101
|
-
append(lastIndex, chunk.start, false);
|
|
102
|
-
append(chunk.start, chunk.end, true);
|
|
103
|
-
lastIndex = chunk.end;
|
|
104
|
-
});
|
|
105
|
-
append(lastIndex, totalLength, false);
|
|
106
|
-
}
|
|
107
|
-
return allChunks;
|
|
108
|
-
};
|
|
109
|
-
/**
|
|
110
|
-
* Creates an array of chunk objects representing both higlightable and non highlightable pieces of text that match each search word.
|
|
111
|
-
*
|
|
112
|
-
findAll ['z'], 'aaazaaazaaa'
|
|
113
|
-
result #=> [
|
|
114
|
-
{ start: 0, end: 3, highlight: false }
|
|
115
|
-
{ start: 3, end: 4, highlight: true }
|
|
116
|
-
{ start: 4, end: 7, highlight: false }
|
|
117
|
-
{ start: 7, end: 8, highlight: true }
|
|
118
|
-
{ start: 8, end: 11, highlight: false }
|
|
119
|
-
]
|
|
120
|
-
|
|
121
|
-
findAll ['do', 'dollar'], 'aaa do dollar aaa'
|
|
122
|
-
#=> chunks: [
|
|
123
|
-
{ start: 4, end: 6 },
|
|
124
|
-
{ start: 7, end: 9 },
|
|
125
|
-
{ start: 7, end: 13 },
|
|
126
|
-
]
|
|
127
|
-
#=> chunksToHight: [
|
|
128
|
-
{ start: 4, end: 6 },
|
|
129
|
-
{ start: 7, end: 13 },
|
|
130
|
-
]
|
|
131
|
-
#=> result: [
|
|
132
|
-
{ start: 0, end: 4, highlight: false },
|
|
133
|
-
{ start: 4, end: 6, highlight: true },
|
|
134
|
-
{ start: 6, end: 7, highlight: false },
|
|
135
|
-
{ start: 7, end: 13, highlight: true },
|
|
136
|
-
{ start: 13, end: 17, highlight: false },
|
|
137
|
-
]
|
|
138
|
-
|
|
139
|
-
* @return Array of "chunks" (where a Chunk is { start:number, end:number, highlight:boolean })
|
|
140
|
-
*/
|
|
141
|
-
const findAll = _ref4 => {
|
|
142
|
-
let {
|
|
143
|
-
autoEscape = true,
|
|
144
|
-
caseSensitive = false,
|
|
145
|
-
searchWords,
|
|
146
|
-
sourceString
|
|
147
|
-
} = _ref4;
|
|
148
|
-
if (_isString(searchWords)) {
|
|
149
|
-
searchWords = [searchWords];
|
|
150
|
-
}
|
|
151
|
-
const chunks = findChunks({
|
|
152
|
-
autoEscape,
|
|
153
|
-
caseSensitive,
|
|
154
|
-
searchWords,
|
|
155
|
-
sourceString
|
|
156
|
-
});
|
|
157
|
-
const chunksToHighlight = combineChunks({
|
|
158
|
-
chunks
|
|
159
|
-
});
|
|
160
|
-
const result = fillInChunks({
|
|
161
|
-
chunksToHighlight,
|
|
162
|
-
totalLength: sourceString ? sourceString.length : 0
|
|
163
|
-
});
|
|
164
|
-
return result;
|
|
165
|
-
};
|
|
166
|
-
export { findAll };
|
package/utils/getHighlight.ts
DELETED
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
// Modified version based on 'highlight-words-core'
|
|
2
|
-
import { isString } from 'lodash';
|
|
3
|
-
|
|
4
|
-
const escapeRegExpFn = (string: string) => string.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
|
|
5
|
-
interface ChunkQuery {
|
|
6
|
-
autoEscape?: boolean;
|
|
7
|
-
caseSensitive?: boolean;
|
|
8
|
-
searchWords: string[];
|
|
9
|
-
sourceString: string
|
|
10
|
-
}
|
|
11
|
-
interface Chunk {
|
|
12
|
-
start: number;
|
|
13
|
-
end: number;
|
|
14
|
-
highlight: boolean
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Examine text for any matches.
|
|
18
|
-
* If we find matches, add them to the returned array as a "chunk" object ({start:number, end:number}).
|
|
19
|
-
* @return { start:number, end:number }[]
|
|
20
|
-
*/
|
|
21
|
-
const findChunks = ({
|
|
22
|
-
autoEscape,
|
|
23
|
-
caseSensitive,
|
|
24
|
-
searchWords,
|
|
25
|
-
sourceString
|
|
26
|
-
}: ChunkQuery): Chunk[] => (
|
|
27
|
-
searchWords
|
|
28
|
-
.filter(searchWord => searchWord) // Remove empty words
|
|
29
|
-
.reduce((chunks, searchWord) => {
|
|
30
|
-
if (autoEscape) {
|
|
31
|
-
searchWord = escapeRegExpFn(searchWord);
|
|
32
|
-
}
|
|
33
|
-
const regex = new RegExp(searchWord, caseSensitive ? 'g' : 'gi');
|
|
34
|
-
|
|
35
|
-
let match;
|
|
36
|
-
while ((match = regex.exec(sourceString))) {
|
|
37
|
-
const start = match.index;
|
|
38
|
-
const end = regex.lastIndex;
|
|
39
|
-
// We do not return zero-length matches
|
|
40
|
-
if (end > start) {
|
|
41
|
-
chunks.push({ highlight: false, start, end });
|
|
42
|
-
}
|
|
43
|
-
// Prevent browsers like Firefox from getting stuck in an infinite loop
|
|
44
|
-
// See http://www.regexguru.com/2008/04/watch-out-for-zero-length-matches/
|
|
45
|
-
if (match.index === regex.lastIndex) {
|
|
46
|
-
regex.lastIndex++;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return chunks;
|
|
50
|
-
}, [])
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Takes an array of {start:number, end:number} objects and combines chunks that overlap into single chunks.
|
|
55
|
-
* @return {start:number, end:number}[]
|
|
56
|
-
*/
|
|
57
|
-
const combineChunks = ({ chunks }: { chunks: Chunk[] }) => {
|
|
58
|
-
chunks = chunks
|
|
59
|
-
.sort((first, second) => first.start - second.start)
|
|
60
|
-
.reduce((processedChunks, nextChunk) => {
|
|
61
|
-
// First chunk just goes straight in the array...
|
|
62
|
-
if (processedChunks.length === 0) {
|
|
63
|
-
return [nextChunk];
|
|
64
|
-
} else {
|
|
65
|
-
// ... subsequent chunks get checked to see if they overlap...
|
|
66
|
-
const prevChunk = processedChunks.pop();
|
|
67
|
-
if (nextChunk.start <= prevChunk.end) {
|
|
68
|
-
// It may be the case that prevChunk completely surrounds nextChunk, so take the
|
|
69
|
-
// largest of the end indeces.
|
|
70
|
-
const endIndex = Math.max(prevChunk.end, nextChunk.end);
|
|
71
|
-
processedChunks.push({
|
|
72
|
-
highlight: false,
|
|
73
|
-
start: prevChunk.start,
|
|
74
|
-
end: endIndex
|
|
75
|
-
});
|
|
76
|
-
} else {
|
|
77
|
-
processedChunks.push(prevChunk, nextChunk);
|
|
78
|
-
}
|
|
79
|
-
return processedChunks;
|
|
80
|
-
}
|
|
81
|
-
}, []);
|
|
82
|
-
|
|
83
|
-
return chunks;
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Given a set of chunks to highlight, create an additional set of chunks
|
|
89
|
-
* to represent the bits of text between the highlighted text.
|
|
90
|
-
* @param chunksToHighlight {start:number, end:number}[]
|
|
91
|
-
* @param totalLength number
|
|
92
|
-
* @return {start:number, end:number, highlight:boolean}[]
|
|
93
|
-
*/
|
|
94
|
-
const fillInChunks = ({ chunksToHighlight, totalLength }: { chunksToHighlight: Chunk[]; totalLength: number }) => {
|
|
95
|
-
const allChunks: Chunk[] = [];
|
|
96
|
-
const append = (start: number, end: number, highlight: boolean) => {
|
|
97
|
-
if (end - start > 0) {
|
|
98
|
-
allChunks.push({
|
|
99
|
-
start,
|
|
100
|
-
end,
|
|
101
|
-
highlight
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
if (chunksToHighlight.length === 0) {
|
|
107
|
-
append(0, totalLength, false);
|
|
108
|
-
} else {
|
|
109
|
-
let lastIndex = 0;
|
|
110
|
-
chunksToHighlight.forEach(chunk => {
|
|
111
|
-
append(lastIndex, chunk.start, false);
|
|
112
|
-
append(chunk.start, chunk.end, true);
|
|
113
|
-
lastIndex = chunk.end;
|
|
114
|
-
});
|
|
115
|
-
append(lastIndex, totalLength, false);
|
|
116
|
-
}
|
|
117
|
-
return allChunks;
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Creates an array of chunk objects representing both higlightable and non highlightable pieces of text that match each search word.
|
|
123
|
-
*
|
|
124
|
-
findAll ['z'], 'aaazaaazaaa'
|
|
125
|
-
result #=> [
|
|
126
|
-
{ start: 0, end: 3, highlight: false }
|
|
127
|
-
{ start: 3, end: 4, highlight: true }
|
|
128
|
-
{ start: 4, end: 7, highlight: false }
|
|
129
|
-
{ start: 7, end: 8, highlight: true }
|
|
130
|
-
{ start: 8, end: 11, highlight: false }
|
|
131
|
-
]
|
|
132
|
-
|
|
133
|
-
findAll ['do', 'dollar'], 'aaa do dollar aaa'
|
|
134
|
-
#=> chunks: [
|
|
135
|
-
{ start: 4, end: 6 },
|
|
136
|
-
{ start: 7, end: 9 },
|
|
137
|
-
{ start: 7, end: 13 },
|
|
138
|
-
]
|
|
139
|
-
#=> chunksToHight: [
|
|
140
|
-
{ start: 4, end: 6 },
|
|
141
|
-
{ start: 7, end: 13 },
|
|
142
|
-
]
|
|
143
|
-
#=> result: [
|
|
144
|
-
{ start: 0, end: 4, highlight: false },
|
|
145
|
-
{ start: 4, end: 6, highlight: true },
|
|
146
|
-
{ start: 6, end: 7, highlight: false },
|
|
147
|
-
{ start: 7, end: 13, highlight: true },
|
|
148
|
-
{ start: 13, end: 17, highlight: false },
|
|
149
|
-
]
|
|
150
|
-
|
|
151
|
-
* @return Array of "chunks" (where a Chunk is { start:number, end:number, highlight:boolean })
|
|
152
|
-
*/
|
|
153
|
-
|
|
154
|
-
const findAll = ({
|
|
155
|
-
autoEscape = true,
|
|
156
|
-
caseSensitive = false,
|
|
157
|
-
searchWords,
|
|
158
|
-
sourceString
|
|
159
|
-
}: ChunkQuery) => {
|
|
160
|
-
if (isString(searchWords)) {
|
|
161
|
-
searchWords = [searchWords];
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const chunks = findChunks({
|
|
165
|
-
autoEscape,
|
|
166
|
-
caseSensitive,
|
|
167
|
-
searchWords,
|
|
168
|
-
sourceString
|
|
169
|
-
});
|
|
170
|
-
const chunksToHighlight = combineChunks({ chunks });
|
|
171
|
-
const result = fillInChunks({
|
|
172
|
-
chunksToHighlight,
|
|
173
|
-
totalLength: sourceString ? sourceString.length : 0
|
|
174
|
-
});
|
|
175
|
-
return result;
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
export { findAll };
|