@inseefr/lunatic 3.7.6-rc.0 → 3.7.6-rc.alphanumeric-sorting.1

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.
@@ -1,5 +1,11 @@
1
1
  /**
2
2
  * Apply Melauto sorting algorithm on the data
3
+ *
4
+ * 1. Sort by melauto score
5
+ * 2. When scores are equal, sort alphabetically with numeric awareness
6
+ * This ensures consistent ordering for items with identical scores
7
+ * (e.g., "0111Z" will appear before "0115Z" when both match "011")
8
+ * Numeric awareness means "item2" will come before "item10" (not "item10" before "item2")
3
9
  */
4
10
  export declare function applyMelauto<T extends {
5
11
  id: string;
@@ -1,11 +1,27 @@
1
1
  /**
2
2
  * Apply Melauto sorting algorithm on the data
3
+ *
4
+ * 1. Sort by melauto score
5
+ * 2. When scores are equal, sort alphabetically with numeric awareness
6
+ * This ensures consistent ordering for items with identical scores
7
+ * (e.g., "0111Z" will appear before "0115Z" when both match "011")
8
+ * Numeric awareness means "item2" will come before "item10" (not "item10" before "item2")
3
9
  */
4
10
  export function applyMelauto(query, data) {
5
11
  return data.sort((a, b) => {
6
- var _a, _b;
7
- return melautoScore((_a = b.label) !== null && _a !== void 0 ? _a : b.id, query) -
8
- melautoScore((_b = a.label) !== null && _b !== void 0 ? _b : a.id, query);
12
+ var _a, _b, _c, _d;
13
+ const sa = melautoScore((_a = a.label) !== null && _a !== void 0 ? _a : a.id, query);
14
+ const sb = melautoScore((_b = b.label) !== null && _b !== void 0 ? _b : b.id, query);
15
+ const diff = sb - sa;
16
+ if (diff !== 0)
17
+ return diff;
18
+ // If scores are equals: alphanumeric sort with numeric awareness
19
+ const ta = ((_c = a.label) !== null && _c !== void 0 ? _c : a.id).toString();
20
+ const tb = ((_d = b.label) !== null && _d !== void 0 ? _d : b.id).toString();
21
+ return ta.localeCompare(tb, undefined, {
22
+ numeric: true,
23
+ sensitivity: 'base',
24
+ });
9
25
  });
10
26
  }
11
27
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"melauto.js","sourceRoot":"","sources":["../../../src/utils/search/melauto.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,YAAY,CAC3B,KAAa,EACb,IAAS;IAET,OAAO,IAAI,CAAC,IAAI,CACf,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;;QACR,OAAA,YAAY,CAAC,MAAA,CAAC,CAAC,KAAK,mCAAI,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC;YACpC,YAAY,CAAC,MAAA,CAAC,CAAC,KAAK,mCAAI,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,CAAA;KAAA,CACrC,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,SAAS,GAAG,CAAC,GAAW,EAAU,EAAE;IACzC,OAAO,GAAG;SACR,SAAS,CAAC,KAAK,CAAC;SAChB,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;SAC/B,WAAW,EAAE;SACb,KAAK,CAAC,YAAY,CAAC;SACnB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;SAC3B,IAAI,CAAC,GAAG,CAAC,CAAC;AACb,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,KAAa;IACtD,MAAM,UAAU,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,UAAU,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/C,OAAO,UAAU,CAAC,MAAM,CAAC,UAAU,KAAK,EAAE,KAAK,EAAE,CAAC;QACjD,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YACf,OAAO,KAAK,CAAC;QACd,CAAC;QACD,MAAM,GAAG,GAAG,CAAC,UAAU,CAAC,MAAM,GAAG,KAAK,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC;QAC5D,MAAM,MAAM,GAAG,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC;QAC3D,OAAO,KAAK,GAAG,GAAG,GAAG,MAAM,CAAC;IAC7B,CAAC,EAAE,CAAC,CAAC,CAAC;AACP,CAAC"}
1
+ {"version":3,"file":"melauto.js","sourceRoot":"","sources":["../../../src/utils/search/melauto.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAC3B,KAAa,EACb,IAAS;IAET,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;;QACzB,MAAM,EAAE,GAAG,YAAY,CAAC,MAAA,CAAC,CAAC,KAAK,mCAAI,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAChD,MAAM,EAAE,GAAG,YAAY,CAAC,MAAA,CAAC,CAAC,KAAK,mCAAI,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAChD,MAAM,IAAI,GAAG,EAAE,GAAG,EAAE,CAAC;QACrB,IAAI,IAAI,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAE5B,iEAAiE;QACjE,MAAM,EAAE,GAAG,CAAC,MAAA,CAAC,CAAC,KAAK,mCAAI,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;QACxC,MAAM,EAAE,GAAG,CAAC,MAAA,CAAC,CAAC,KAAK,mCAAI,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;QACxC,OAAO,EAAE,CAAC,aAAa,CAAC,EAAE,EAAE,SAAS,EAAE;YACtC,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,MAAM;SACnB,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,SAAS,GAAG,CAAC,GAAW,EAAU,EAAE;IACzC,OAAO,GAAG;SACR,SAAS,CAAC,KAAK,CAAC;SAChB,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;SAC/B,WAAW,EAAE;SACb,KAAK,CAAC,YAAY,CAAC;SACnB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;SAC3B,IAAI,CAAC,GAAG,CAAC,CAAC;AACb,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,KAAa;IACtD,MAAM,UAAU,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,UAAU,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/C,OAAO,UAAU,CAAC,MAAM,CAAC,UAAU,KAAK,EAAE,KAAK,EAAE,CAAC;QACjD,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YACf,OAAO,KAAK,CAAC;QACd,CAAC;QACD,MAAM,GAAG,GAAG,CAAC,UAAU,CAAC,MAAM,GAAG,KAAK,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC;QAC5D,MAAM,MAAM,GAAG,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC;QAC3D,OAAO,KAAK,GAAG,GAAG,GAAG,MAAM,CAAC;IAC7B,CAAC,EAAE,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -8,16 +8,6 @@ const data = [
8
8
  { id: '4', label: 'Greetings planet' },
9
9
  ];
10
10
  describe('applyMelauto', () => {
11
- it('should sort data by relevance to the query', () => {
12
- const sortedData = applyMelauto('hello', data);
13
- const expectedSortedData = [
14
- { id: '1', label: 'Hello world' },
15
- { id: '3', label: 'Hello everyone' },
16
- { id: '2', label: 'Bonjour le monde' },
17
- { id: '4', label: 'Greetings planet' },
18
- ];
19
- expect(sortedData).toStrictEqual(expectedSortedData);
20
- });
21
11
  it('should return data in original order if query is empty', () => {
22
12
  const sortedData = applyMelauto('', data);
23
13
  expect(sortedData).toEqual(data);
@@ -63,5 +53,51 @@ describe('melautoScore', () => {
63
53
  const score2 = melautoScore('Hello world', 'héllo-wOrld');
64
54
  expect(score1).toBeCloseTo(score2, 2);
65
55
  });
56
+ it('should sort alphabetically with numeric awareness when scores are equal', () => {
57
+ const numericData = [
58
+ { id: '0115Z', label: '0115Z' },
59
+ { id: '0111Z', label: '0111Z' },
60
+ { id: '0120A', label: '0120A' },
61
+ { id: '0112B', label: '0112B' },
62
+ ];
63
+ const sortedData = applyMelauto('011', numericData);
64
+ const expectedSortedData = [
65
+ { id: '0111Z', label: '0111Z' },
66
+ { id: '0112B', label: '0112B' },
67
+ { id: '0115Z', label: '0115Z' },
68
+ { id: '0120A', label: '0120A' },
69
+ ];
70
+ expect(sortedData).toStrictEqual(expectedSortedData);
71
+ });
72
+ it('should apply alphanumeric sort with numeric awareness', () => {
73
+ const mixedData = [
74
+ { id: 'code10', label: 'code10' },
75
+ { id: 'code2', label: 'code2' },
76
+ { id: 'code20', label: 'code20' },
77
+ ];
78
+ const sorted = applyMelauto('code', mixedData);
79
+ // Should sort numerically: code2, code10, code20
80
+ expect(sorted.map((d) => d.id)).toStrictEqual([
81
+ 'code2',
82
+ 'code10',
83
+ 'code20',
84
+ ]);
85
+ });
86
+ it('should handle mixed alphanumeric queries with numeric sorting', () => {
87
+ const data = [
88
+ { id: 'item10B', label: 'item10B' },
89
+ { id: 'item2A', label: 'item2A' },
90
+ { id: 'item20C', label: 'item20C' },
91
+ { id: 'item3D', label: 'item3D' },
92
+ ];
93
+ const sortedData = applyMelauto('item2', data);
94
+ // "item2A" scores highest (exact match), others sorted alphanumerically
95
+ expect(sortedData.map((d) => d.id)).toStrictEqual([
96
+ 'item2A',
97
+ 'item20C',
98
+ 'item3D',
99
+ 'item10B',
100
+ ]);
101
+ });
66
102
  });
67
103
  //# sourceMappingURL=melauto.spec.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"melauto.spec.js","sourceRoot":"","sources":["../../../src/utils/search/melauto.spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEvD,4CAA4C;AAC5C,MAAM,IAAI,GAAG;IACZ,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,aAAa,EAAE;IACjC,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,kBAAkB,EAAE;IACtC,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,gBAAgB,EAAE;IACpC,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,kBAAkB,EAAE;CACtC,CAAC;AAEF,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACrD,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAC/C,MAAM,kBAAkB,GAAG;YAC1B,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,aAAa,EAAE;YACjC,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,gBAAgB,EAAE;YACpC,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,kBAAkB,EAAE;YACtC,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,kBAAkB,EAAE;SACtC,CAAC;QACF,MAAM,CAAC,UAAU,CAAC,CAAC,aAAa,CAAC,kBAAkB,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QACjE,MAAM,UAAU,GAAG,YAAY,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAC1C,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAChE,MAAM,WAAW,GAAG;YACnB,EAAE,EAAE,EAAE,GAAG,EAAE;YACX,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE;YAC3B,EAAE,EAAE,EAAE,SAAS,EAAE;SACjB,CAAC;QACF,MAAM,UAAU,GAAG,YAAY,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QACtD,MAAM,kBAAkB,GAAG;YAC1B,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE;YAC3B,EAAE,EAAE,EAAE,SAAS,EAAE;YACjB,EAAE,EAAE,EAAE,GAAG,EAAE;SACX,CAAC;QACF,MAAM,CAAC,UAAU,CAAC,CAAC,aAAa,CAAC,kBAAkB,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACzC,MAAM,KAAK,GAAG,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QACnD,MAAM,aAAa,GAAG,CAAC,CAAC;QACxB,MAAM,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACxD,MAAM,MAAM,GAAG,YAAY,CAAC,uBAAuB,EAAE,aAAa,CAAC,CAAC;QACpE,MAAM,MAAM,GAAG,YAAY,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC;QAC9D,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gFAAgF,EAAE,GAAG,EAAE;QACzF,MAAM,MAAM,GAAG,YAAY,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QACpD,MAAM,MAAM,GAAG,YAAY,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC;QAC9D,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACxC,MAAM,KAAK,GAAG,YAAY,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC;QACxD,MAAM,aAAa,GAAG,CAAC,CAAC;QACxB,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAChE,MAAM,MAAM,GAAG,YAAY,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;QAC1D,MAAM,MAAM,GAAG,YAAY,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;QAC1D,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"melauto.spec.js","sourceRoot":"","sources":["../../../src/utils/search/melauto.spec.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inseefr/lunatic",
3
- "version": "3.7.6-rc.0",
3
+ "version": "3.7.6-rc.alphanumeric-sorting.1",
4
4
  "description": "Library of questionnaire components",
5
5
  "repository": {
6
6
  "type": "git",
@@ -10,17 +10,6 @@ const data = [
10
10
  ];
11
11
 
12
12
  describe('applyMelauto', () => {
13
- it('should sort data by relevance to the query', () => {
14
- const sortedData = applyMelauto('hello', data);
15
- const expectedSortedData = [
16
- { id: '1', label: 'Hello world' },
17
- { id: '3', label: 'Hello everyone' },
18
- { id: '2', label: 'Bonjour le monde' },
19
- { id: '4', label: 'Greetings planet' },
20
- ];
21
- expect(sortedData).toStrictEqual(expectedSortedData);
22
- });
23
-
24
13
  it('should return data in original order if query is empty', () => {
25
14
  const sortedData = applyMelauto('', data);
26
15
  expect(sortedData).toEqual(data);
@@ -72,4 +61,54 @@ describe('melautoScore', () => {
72
61
  const score2 = melautoScore('Hello world', 'héllo-wOrld');
73
62
  expect(score1).toBeCloseTo(score2, 2);
74
63
  });
64
+
65
+ it('should sort alphabetically with numeric awareness when scores are equal', () => {
66
+ const numericData = [
67
+ { id: '0115Z', label: '0115Z' },
68
+ { id: '0111Z', label: '0111Z' },
69
+ { id: '0120A', label: '0120A' },
70
+ { id: '0112B', label: '0112B' },
71
+ ];
72
+ const sortedData = applyMelauto('011', numericData);
73
+ const expectedSortedData = [
74
+ { id: '0111Z', label: '0111Z' },
75
+ { id: '0112B', label: '0112B' },
76
+ { id: '0115Z', label: '0115Z' },
77
+ { id: '0120A', label: '0120A' },
78
+ ];
79
+ expect(sortedData).toStrictEqual(expectedSortedData);
80
+ });
81
+
82
+ it('should apply alphanumeric sort with numeric awareness', () => {
83
+ const mixedData = [
84
+ { id: 'code10', label: 'code10' },
85
+ { id: 'code2', label: 'code2' },
86
+ { id: 'code20', label: 'code20' },
87
+ ];
88
+
89
+ const sorted = applyMelauto('code', mixedData);
90
+ // Should sort numerically: code2, code10, code20
91
+ expect(sorted.map((d) => d.id)).toStrictEqual([
92
+ 'code2',
93
+ 'code10',
94
+ 'code20',
95
+ ]);
96
+ });
97
+
98
+ it('should handle mixed alphanumeric queries with numeric sorting', () => {
99
+ const data = [
100
+ { id: 'item10B', label: 'item10B' },
101
+ { id: 'item2A', label: 'item2A' },
102
+ { id: 'item20C', label: 'item20C' },
103
+ { id: 'item3D', label: 'item3D' },
104
+ ];
105
+ const sortedData = applyMelauto('item2', data);
106
+ // "item2A" scores highest (exact match), others sorted alphanumerically
107
+ expect(sortedData.map((d) => d.id)).toStrictEqual([
108
+ 'item2A',
109
+ 'item20C',
110
+ 'item3D',
111
+ 'item10B',
112
+ ]);
113
+ });
75
114
  });
@@ -1,15 +1,30 @@
1
1
  /**
2
2
  * Apply Melauto sorting algorithm on the data
3
+ *
4
+ * 1. Sort by melauto score
5
+ * 2. When scores are equal, sort alphabetically with numeric awareness
6
+ * This ensures consistent ordering for items with identical scores
7
+ * (e.g., "0111Z" will appear before "0115Z" when both match "011")
8
+ * Numeric awareness means "item2" will come before "item10" (not "item10" before "item2")
3
9
  */
4
10
  export function applyMelauto<T extends { id: string; label?: string }>(
5
11
  query: string,
6
12
  data: T[]
7
13
  ): T[] {
8
- return data.sort(
9
- (a, b) =>
10
- melautoScore(b.label ?? b.id, query) -
11
- melautoScore(a.label ?? a.id, query)
12
- );
14
+ return data.sort((a, b) => {
15
+ const sa = melautoScore(a.label ?? a.id, query);
16
+ const sb = melautoScore(b.label ?? b.id, query);
17
+ const diff = sb - sa;
18
+ if (diff !== 0) return diff;
19
+
20
+ // If scores are equals: alphanumeric sort with numeric awareness
21
+ const ta = (a.label ?? a.id).toString();
22
+ const tb = (b.label ?? b.id).toString();
23
+ return ta.localeCompare(tb, undefined, {
24
+ numeric: true,
25
+ sensitivity: 'base',
26
+ });
27
+ });
13
28
  }
14
29
 
15
30
  /**