Skip to content

Commit

Permalink
optimize
Browse files Browse the repository at this point in the history
  • Loading branch information
shhhplus committed May 18, 2023
1 parent 1ab4dce commit 131fb92
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 91 deletions.
74 changes: 14 additions & 60 deletions src/compile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,84 +2,43 @@ import compile from './compile';

test('no matched word should works', () => {
const content = 'Welcome everyone to come and join my birthday party.';
expect(compile(content, 'tom')).toMatchObject([
{
text: content,
matched: false,
},
]);
expect(compile(content, 'tom')).toMatchObject([content]);
});

test('a single matched word should works', () => {
const content = 'Welcome everyone to come and join my birthday party.';
expect(compile(content, 'party')).toMatchObject([
{
text: 'Welcome everyone to come and join my birthday ',
matched: false,
},
{
text: 'party',
matched: true,
},
{
text: '.',
matched: false,
},
'Welcome everyone to come and join my birthday ',
{ text: 'party', matched: true },
'.',
]);
});

test(`multiple matched words should works`, () => {
const content =
'hi, party time. Welcome everyone to come and join my birthday party.';
expect(compile(content, 'party')).toMatchObject([
{
text: 'hi, ',
matched: false,
},
{
text: 'party',
matched: true,
},
{
text: ' time. Welcome everyone to come and join my birthday ',
matched: false,
},
{
text: 'party',
matched: true,
},
{
text: '.',
matched: false,
},
'hi, ',
{ text: 'party', matched: true },
' time. Welcome everyone to come and join my birthday ',
{ text: 'party', matched: true },
'.',
]);
});

test('matched word at begin should works', () => {
const content = 'party.Welcome everyone.';
expect(compile(content, 'party')).toMatchObject([
{
text: 'party',
matched: true,
},
{
text: '.Welcome everyone.',
matched: false,
},
{ text: 'party', matched: true },
'.Welcome everyone.',
]);
});

test('matched word at end should works', () => {
const content = 'Welcome everyone to my party';
expect(compile(content, 'party')).toMatchObject([
{
text: 'Welcome everyone to my ',
matched: false,
},
{
text: 'party',
matched: true,
},
'Welcome everyone to my ',
{ text: 'party', matched: true },
]);
});

Expand All @@ -89,12 +48,7 @@ test('empty content should works', () => {

test('empty keywords should works', () => {
const content = 'Welcome everyone to my party';
expect(compile(content, '')).toMatchObject([
{
text: content,
matched: false,
},
]);
expect(compile(content, '')).toMatchObject([content]);
});

test('empty content and empty keywords should works', () => {
Expand Down
69 changes: 50 additions & 19 deletions src/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,22 @@ type Node = {
matched: boolean;
};

export default function compile(content: string, keywords: string) {
export default function compile(content: string, words: string | string[]) {
let keywords = typeof words === 'string' ? [words] : words;
keywords = keywords.filter((w) => w);
keywords = Array.from(new Set(keywords));

return innerCompile(content, keywords).map((node) => {
return node.matched ? node : node.text;
});
}

const innerCompile = (content: string, keywords: string[]) => {
if (!content) {
return [];
}

if (!keywords) {
if (keywords.length === 0) {
return [
{
text: content,
Expand All @@ -17,21 +27,42 @@ export default function compile(content: string, keywords: string) {
];
}

return content
.split(keywords)
.reduce((acc: Node[], cur, idx) => {
return [
...acc,
{
text: keywords,
matched: true,
},
{
text: cur,
matched: false,
},
];
let nodes: Node[] = [
{
text: content,
matched: false,
},
];
for (let keyword of keywords) {
nodes = nodes.reduce<Node[]>((acc, cur) => {
if (cur.matched) {
return [...acc, cur];
} else {
const list = split(cur.text, keyword);
return [...acc, ...list];
}
}, []);
}
return nodes;
};

const split = (content: string, keyword: string) => {
const nodes = content.split(keyword).map((text) => {
return {
text: text,
matched: false,
};
});
return join(nodes, {
text: keyword,
matched: true,
}).filter((node) => node.text);
};

const join = (arr: Node[], separator: Node) => {
return arr
.reduce((acc: Node[], cur) => {
return [...acc, separator, cur];
}, [])
.slice(1)
.filter((node) => node.text.length);
}
.slice(1);
};
25 changes: 13 additions & 12 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,37 @@
import { CSSProperties, FC, Fragment, useMemo } from 'react';
import compile from './compile';

const defaultStyle = {
color: '#00BC70',
};

type KeywordsHighlightProps = {
type HighlightWordsProps = {
keywords: string;
style?: CSSProperties;
children: string;
};

const KeywordsHighlight: FC<KeywordsHighlightProps> = ({
const HighlightWords: FC<HighlightWordsProps> = ({
keywords,
style = defaultStyle,
style,
children,
}) => {
const nodes = useMemo(() => {
return compile(children, keywords);
}, [children, keywords]);
const nodes = useMemo(
() => compile(children, keywords),
[children, keywords],
);

return (
<Fragment>
{nodes.map((node, idx) => {
return (
<Fragment key={idx}>
{node.matched ? <span style={style}>{node.text}</span> : node.text}
{typeof node === 'string' ? (
node
) : (
<span style={style}>{node.text}</span>
)}
</Fragment>
);
})}
</Fragment>
);
};

export default KeywordsHighlight;
export default HighlightWords;

0 comments on commit 131fb92

Please sign in to comment.