mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-01 01:29:31 +08:00
feat: normalize search text (#14449)
#### PR Dependency Tree * **PR #14449** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Improvements** * Search text normalization now applied consistently across doc titles, search results, and highlights for uniform display formatting. * **Tests** * Added comprehensive test coverage for search text normalization utility. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
import { normalizeSearchText } from '../normalize-search-text';
|
||||
|
||||
test('normalizeSearchText should keep plain text unchanged', () => {
|
||||
expect(normalizeSearchText('hello world')).toBe('hello world');
|
||||
});
|
||||
|
||||
test('normalizeSearchText should decode serialized single-item array', () => {
|
||||
expect(normalizeSearchText('["hello world"]')).toBe('hello world');
|
||||
});
|
||||
|
||||
test('normalizeSearchText should decode serialized highlighted array', () => {
|
||||
expect(normalizeSearchText('["<b>hello</b> world"]')).toBe(
|
||||
'<b>hello</b> world'
|
||||
);
|
||||
});
|
||||
|
||||
test('normalizeSearchText should join serialized multi-item array', () => {
|
||||
expect(normalizeSearchText('["hello","world"]')).toBe('hello world');
|
||||
});
|
||||
|
||||
test('normalizeSearchText should decode serialized string', () => {
|
||||
expect(normalizeSearchText('"hello world"')).toBe('hello world');
|
||||
});
|
||||
|
||||
test('normalizeSearchText should keep invalid serialized text unchanged', () => {
|
||||
expect(normalizeSearchText('["hello"')).toBe('["hello"');
|
||||
});
|
||||
|
||||
test('normalizeSearchText should support array input', () => {
|
||||
expect(normalizeSearchText(['hello', 'world'])).toBe('hello world');
|
||||
});
|
||||
@@ -2,6 +2,7 @@ export * from './channel';
|
||||
export * from './create-emotion-cache';
|
||||
export * from './event';
|
||||
export * from './extract-emoji-icon';
|
||||
export * from './normalize-search-text';
|
||||
export * from './string2color';
|
||||
export * from './toast';
|
||||
export * from './unflatten-object';
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
interface NormalizeSearchTextOptions {
|
||||
fallback?: string;
|
||||
arrayJoiner?: string;
|
||||
}
|
||||
|
||||
function tryParseSerializedText(value: string): unknown | null {
|
||||
const trimmed = value.trim();
|
||||
if (!trimmed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Indexer/storage may serialize text arrays as JSON strings like ["foo"].
|
||||
if (!trimmed.startsWith('[') && !trimmed.startsWith('"')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(trimmed);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function normalizeSearchText(
|
||||
value: unknown,
|
||||
{ fallback = '', arrayJoiner = ' ' }: NormalizeSearchTextOptions = {}
|
||||
): string {
|
||||
if (value === null || value === undefined) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
const normalized = value
|
||||
.map(item =>
|
||||
normalizeSearchText(item, {
|
||||
fallback: '',
|
||||
arrayJoiner,
|
||||
})
|
||||
)
|
||||
.filter(Boolean);
|
||||
|
||||
return normalized.length > 0 ? normalized.join(arrayJoiner) : fallback;
|
||||
}
|
||||
|
||||
if (typeof value !== 'string') {
|
||||
return String(value);
|
||||
}
|
||||
|
||||
const parsed = tryParseSerializedText(value);
|
||||
if (parsed === null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (typeof parsed === 'string' || Array.isArray(parsed)) {
|
||||
return normalizeSearchText(parsed, {
|
||||
fallback,
|
||||
arrayJoiner,
|
||||
});
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
Reference in New Issue
Block a user