@inseefr/lunatic 3.12.1 → 3.12.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.
Files changed (79) hide show
  1. package/components/Dropdown/Dropdown.js +1 -2
  2. package/components/Dropdown/Dropdown.js.map +1 -1
  3. package/components/Dropdown/Dropdown.spec.js +13 -5
  4. package/components/Dropdown/Dropdown.spec.js.map +1 -1
  5. package/components/Suggester/CustomSuggester.d.ts +6 -0
  6. package/components/Suggester/CustomSuggester.js +1 -1
  7. package/components/Suggester/CustomSuggester.js.map +1 -1
  8. package/components/shared/Combobox/Combobox.js +5 -6
  9. package/components/shared/Combobox/Combobox.js.map +1 -1
  10. package/components/shared/Combobox/ComboboxType.d.ts +1 -0
  11. package/components/shared/Combobox/Panel/ComboboxOption.d.ts +1 -0
  12. package/components/shared/Combobox/Panel/ComboboxOption.js +4 -4
  13. package/components/shared/Combobox/Panel/ComboboxOption.js.map +1 -1
  14. package/components/shared/Combobox/Panel/ComboboxOption.spec.js +18 -5
  15. package/components/shared/Combobox/Panel/ComboboxOption.spec.js.map +1 -1
  16. package/components/shared/Combobox/Panel/ComboboxPanel.d.ts +1 -1
  17. package/components/shared/Combobox/Panel/ComboboxPanel.js +2 -2
  18. package/components/shared/Combobox/Panel/ComboboxPanel.js.map +1 -1
  19. package/components/type.d.ts +6 -0
  20. package/esm/components/Dropdown/Dropdown.js +1 -2
  21. package/esm/components/Dropdown/Dropdown.js.map +1 -1
  22. package/esm/components/Dropdown/Dropdown.spec.js +14 -6
  23. package/esm/components/Dropdown/Dropdown.spec.js.map +1 -1
  24. package/esm/components/Suggester/CustomSuggester.d.ts +6 -0
  25. package/esm/components/Suggester/CustomSuggester.js +1 -1
  26. package/esm/components/Suggester/CustomSuggester.js.map +1 -1
  27. package/esm/components/shared/Combobox/Combobox.js +5 -6
  28. package/esm/components/shared/Combobox/Combobox.js.map +1 -1
  29. package/esm/components/shared/Combobox/ComboboxType.d.ts +1 -0
  30. package/esm/components/shared/Combobox/Panel/ComboboxOption.d.ts +1 -0
  31. package/esm/components/shared/Combobox/Panel/ComboboxOption.js +5 -5
  32. package/esm/components/shared/Combobox/Panel/ComboboxOption.js.map +1 -1
  33. package/esm/components/shared/Combobox/Panel/ComboboxOption.spec.js +18 -5
  34. package/esm/components/shared/Combobox/Panel/ComboboxOption.spec.js.map +1 -1
  35. package/esm/components/shared/Combobox/Panel/ComboboxPanel.d.ts +1 -1
  36. package/esm/components/shared/Combobox/Panel/ComboboxPanel.js +2 -2
  37. package/esm/components/shared/Combobox/Panel/ComboboxPanel.js.map +1 -1
  38. package/esm/components/type.d.ts +6 -0
  39. package/esm/utils/search/SearchMiniSearch.spec.js +16 -1
  40. package/esm/utils/search/SearchMiniSearch.spec.js.map +1 -1
  41. package/esm/utils/search/SearchMinisearch.js +26 -1
  42. package/esm/utils/search/SearchMinisearch.js.map +1 -1
  43. package/esm/utils/search/tokenizer.js +1 -14
  44. package/esm/utils/search/tokenizer.js.map +1 -1
  45. package/esm/utils/search/utils.d.ts +7 -0
  46. package/esm/utils/search/utils.js +15 -0
  47. package/esm/utils/search/utils.js.map +1 -0
  48. package/package.json +8 -8
  49. package/src/components/Dropdown/Dropdown.spec.tsx +22 -6
  50. package/src/components/Dropdown/Dropdown.tsx +1 -2
  51. package/src/components/Dropdown/__snapshots__/Dropdown.spec.tsx.snap +2 -2
  52. package/src/components/Suggester/CustomSuggester.tsx +7 -0
  53. package/src/components/shared/Combobox/Combobox.tsx +5 -4
  54. package/src/components/shared/Combobox/ComboboxType.ts +1 -0
  55. package/src/components/shared/Combobox/Panel/ComboboxOption.spec.tsx +27 -5
  56. package/src/components/shared/Combobox/Panel/ComboboxOption.tsx +10 -6
  57. package/src/components/shared/Combobox/Panel/ComboboxPanel.tsx +3 -1
  58. package/src/components/type.ts +6 -0
  59. package/src/utils/search/SearchMiniSearch.spec.ts +21 -1
  60. package/src/utils/search/SearchMinisearch.ts +34 -1
  61. package/src/utils/search/tokenizer.ts +1 -15
  62. package/src/utils/search/utils.ts +14 -0
  63. package/tsconfig.build.tsbuildinfo +1 -1
  64. package/utils/search/SearchMiniSearch.spec.js +15 -1
  65. package/utils/search/SearchMiniSearch.spec.js.map +1 -1
  66. package/utils/search/SearchMinisearch.js +26 -1
  67. package/utils/search/SearchMinisearch.js.map +1 -1
  68. package/utils/search/tokenizer.js +6 -19
  69. package/utils/search/tokenizer.js.map +1 -1
  70. package/utils/search/utils.d.ts +7 -0
  71. package/utils/search/utils.js +19 -0
  72. package/utils/search/utils.js.map +1 -0
  73. package/components/Dropdown/renderer/SimpleOptionRenderer.d.ts +0 -7
  74. package/components/Dropdown/renderer/SimpleOptionRenderer.js +0 -16
  75. package/components/Dropdown/renderer/SimpleOptionRenderer.js.map +0 -1
  76. package/esm/components/Dropdown/renderer/SimpleOptionRenderer.d.ts +0 -7
  77. package/esm/components/Dropdown/renderer/SimpleOptionRenderer.js +0 -10
  78. package/esm/components/Dropdown/renderer/SimpleOptionRenderer.js.map +0 -1
  79. package/src/components/Dropdown/renderer/SimpleOptionRenderer.tsx +0 -26
@@ -1,5 +1,6 @@
1
1
  import { describe, it, expect, vi, beforeAll, afterEach } from 'vitest';
2
2
  import { SearchMinisearch } from './SearchMinisearch';
3
+ import { applyMelauto } from './melauto';
3
4
 
4
5
  vi.mock('minisearch', () => {
5
6
  return {
@@ -24,7 +25,13 @@ describe('SearchMinisearch', () => {
24
25
  beforeAll(() => {
25
26
  searchInstance = new SearchMinisearch({
26
27
  name: 'test-suggester',
27
- fields: [{ name: 'id' }, { name: 'label' }],
28
+ fields: [
29
+ { name: 'id' },
30
+ {
31
+ name: 'label',
32
+ synonyms: { accueil: ['ACCEUIL', 'ACUEIL'] },
33
+ },
34
+ ],
28
35
  queryParser: {
29
36
  type: 'tokenized',
30
37
  params: { language: 'English', pattern: '\\w+', min: 1 },
@@ -55,4 +62,17 @@ describe('SearchMinisearch', () => {
55
62
 
56
63
  expect(searchInstance.db?.addAll).not.toHaveBeenCalled();
57
64
  });
65
+
66
+ it('should expand query synonyms before melauto sorting', async () => {
67
+ await searchInstance.index(mockData);
68
+ (searchInstance.db?.search as any).mockReturnValue(mockData);
69
+ vi.mocked(applyMelauto).mockReturnValue(mockData as any);
70
+
71
+ await searchInstance.search('agent acceuil');
72
+
73
+ expect(applyMelauto).toHaveBeenCalledWith(
74
+ 'agent acceuil accueil',
75
+ mockData
76
+ );
77
+ });
58
78
  });
@@ -6,6 +6,39 @@ import type {
6
6
  import { applyMelauto } from './melauto';
7
7
  import MiniSearch from 'minisearch';
8
8
  import { tokenizer } from './tokenizer';
9
+ import { normalizeStr } from './utils';
10
+
11
+ function getMelautoQuery(query: string, info: SearchInfo) {
12
+ const tokens = tokenizer(info)(query);
13
+
14
+ // existing query tokens (already tokenized/normalized by tokenizer).
15
+ const expandedTokens = new Set(tokens);
16
+
17
+ // add synonyms to keep melauto ranking.
18
+ for (const field of info.fields) {
19
+ if (!field.synonyms) {
20
+ continue;
21
+ }
22
+ for (const source in field.synonyms) {
23
+ const normalizedSource = normalizeStr(source);
24
+ const normalizedSynonyms = field.synonyms[source].map((synonym) =>
25
+ normalizeStr(synonym)
26
+ );
27
+
28
+ // source -> synonyms
29
+ if (expandedTokens.has(normalizedSource)) {
30
+ normalizedSynonyms.forEach((synonym) => expandedTokens.add(synonym));
31
+ }
32
+
33
+ // synonym -> source
34
+ if (normalizedSynonyms.some((synonym) => expandedTokens.has(synonym))) {
35
+ expandedTokens.add(normalizedSource);
36
+ }
37
+ }
38
+ }
39
+
40
+ return Array.from(expandedTokens).join(' ');
41
+ }
9
42
 
10
43
  export class SearchMinisearch<T extends IndexEntry>
11
44
  implements SearchInterface<T>
@@ -45,7 +78,7 @@ export class SearchMinisearch<T extends IndexEntry>
45
78
  }) as any as T[];
46
79
 
47
80
  // Apply melauto to classify results
48
- data = applyMelauto(q, data);
81
+ data = applyMelauto(getMelautoQuery(q, this.info), data);
49
82
 
50
83
  data = data.slice(0, this.info.max);
51
84
 
@@ -1,5 +1,6 @@
1
1
  import type { SearchInfo } from './SearchInterface';
2
2
  import type { ItemOf } from '../../type.utils';
3
+ import { normalizeStr } from './utils';
3
4
 
4
5
  /**
5
6
  * Generates a tokenize method.
@@ -76,21 +77,6 @@ export const tokenizeIndex = (
76
77
  );
77
78
  };
78
79
 
79
- /**
80
- * Normalize a string
81
- * - Remove accent (é => e, à => a)
82
- * - remove ligatures (æ => ae, , Æ => ae, œ => oe, Œ => oe)
83
- * - Lowercase
84
- */
85
- const normalizeStr = (str: string) => {
86
- return str
87
- .toLowerCase()
88
- .replaceAll('œ', 'oe')
89
- .replaceAll('æ', 'ae')
90
- .normalize('NFD')
91
- .replace(/[\u0300-\u036f]/g, '');
92
- };
93
-
94
80
  /**
95
81
  * remove from a string all the words that are included in a stopwords list
96
82
  */
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Normalize a string
3
+ * - Remove accent (é => e, à => a)
4
+ * - remove ligatures (æ => ae, , Æ => ae, œ => oe, Œ => oe)
5
+ * - Lowercase
6
+ */
7
+ export const normalizeStr = (str: string) => {
8
+ return str
9
+ .toLowerCase()
10
+ .replaceAll('œ', 'oe')
11
+ .replaceAll('æ', 'ae')
12
+ .normalize('NFD')
13
+ .replace(/[\u0300-\u036f]/g, '');
14
+ };