Skip to content

Commit 9b05184

Browse files
authored
Merge pull request relayjs#63 from gaearon/smarter-search-match
Match search at word boundaries
2 parents 6c5c2cd + 2afda3d commit 9b05184

File tree

1 file changed

+61
-1
lines changed

1 file changed

+61
-1
lines changed

src/devtools/views/utils.js

+61-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,67 @@ import { meta } from '../../hydration';
66
import type { HooksTree } from 'src/backend/types';
77

88
export function createRegExp(string: string): RegExp {
9-
return new RegExp(escapeStringRegExp(string), 'i');
9+
// Allow /regex/ syntax with optional last /
10+
if (string[0] === '/') {
11+
// Cut off first slash
12+
string = string.substring(1);
13+
// Cut off last slash, but only if it's there
14+
if (string[string.length - 1] === '/') {
15+
string = string.substring(0, string.length - 1);
16+
}
17+
try {
18+
return new RegExp(string, 'i');
19+
} catch (err) {
20+
// Bad regex. Make it not match anything.
21+
// TODO: maybe warn in console?
22+
return new RegExp('.^');
23+
}
24+
}
25+
26+
function isLetter(char: string) {
27+
return char.toLowerCase() !== char.toUpperCase();
28+
}
29+
30+
function matchAnyCase(char: string) {
31+
if (!isLetter(char)) {
32+
// Don't mess with special characters like [.
33+
return char;
34+
}
35+
return '[' + char.toLowerCase() + char.toUpperCase() + ']';
36+
}
37+
38+
// 'item' should match 'Item' and 'ListItem', but not 'InviteMom'.
39+
// To do this, we'll slice off 'tem' and check first letter separately.
40+
const escaped = escapeStringRegExp(string);
41+
const firstChar = escaped[0];
42+
let restRegex = '';
43+
// For 'item' input, restRegex becomes '[tT][eE][mM]'
44+
// We can't simply make it case-insensitive because first letter case matters.
45+
for (let i = 1; i < escaped.length; i++) {
46+
restRegex += matchAnyCase(escaped[i]);
47+
}
48+
49+
if (!isLetter(firstChar)) {
50+
// We can't put a non-character like [ in a group
51+
// so we fall back to the simple case.
52+
return new RegExp(firstChar + restRegex);
53+
}
54+
55+
// Construct a smarter regex.
56+
return new RegExp(
57+
// For example:
58+
// (^[iI]|I)[tT][eE][mM]
59+
// Matches:
60+
// 'Item'
61+
// 'ListItem'
62+
// but not 'InviteMom'
63+
'(^' +
64+
matchAnyCase(firstChar) +
65+
'|' +
66+
firstChar.toUpperCase() +
67+
')' +
68+
restRegex
69+
);
1070
}
1171

1272
export function getMetaValueLabel(data: Object): string | null {

0 commit comments

Comments
 (0)