@mintlify/common 1.0.1023 → 1.0.1024

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 (38) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +1 -0
  3. package/dist/navigation/decoratedNavigationConfig.d.ts +2 -0
  4. package/dist/navigation/decoratedNavigationConfig.js +204 -0
  5. package/dist/navigation/filterDivisions.d.ts +65 -0
  6. package/dist/navigation/filterDivisions.js +697 -0
  7. package/dist/navigation/filterDivisions.test.d.ts +1 -0
  8. package/dist/navigation/filterDivisions.test.js +670 -0
  9. package/dist/navigation/getScopedNavForPath.test.d.ts +1 -0
  10. package/dist/navigation/getScopedNavForPath.test.js +135 -0
  11. package/dist/navigation/getVersionOrLanguageFromPath.d.ts +12 -0
  12. package/dist/navigation/getVersionOrLanguageFromPath.js +71 -0
  13. package/dist/navigation/getVersionOrLanguageFromPath.test.d.ts +1 -0
  14. package/dist/navigation/getVersionOrLanguageFromPath.test.js +133 -0
  15. package/dist/navigation/index.d.ts +5 -0
  16. package/dist/navigation/index.js +5 -0
  17. package/dist/navigation/isCommonPage.d.ts +8 -0
  18. package/dist/navigation/isCommonPage.js +36 -0
  19. package/dist/navigation/isCommonPage.test.d.ts +1 -0
  20. package/dist/navigation/isCommonPage.test.js +56 -0
  21. package/dist/navigation/pathsDifferByOneSegment.test.d.ts +1 -0
  22. package/dist/navigation/pathsDifferByOneSegment.test.js +91 -0
  23. package/dist/navigation/scopeNavToPath.d.ts +18 -0
  24. package/dist/navigation/scopeNavToPath.js +455 -0
  25. package/dist/navigation/scopeNavToPath.test.d.ts +1 -0
  26. package/dist/navigation/scopeNavToPath.test.js +117 -0
  27. package/dist/navigation/scopeOffPathDivisions.test.d.ts +1 -0
  28. package/dist/navigation/scopeOffPathDivisions.test.js +852 -0
  29. package/dist/navigation/scopeProductNav.test.d.ts +1 -0
  30. package/dist/navigation/scopeProductNav.test.js +288 -0
  31. package/dist/navigation/updateFirstHrefInDivision.d.ts +29 -0
  32. package/dist/navigation/updateFirstHrefInDivision.js +383 -0
  33. package/dist/paths/isEqualIgnoringLeadingSlash.d.ts +1 -0
  34. package/dist/paths/isEqualIgnoringLeadingSlash.js +21 -0
  35. package/dist/paths/isEqualIgnoringLeadingSlash.test.d.ts +1 -0
  36. package/dist/paths/isEqualIgnoringLeadingSlash.test.js +43 -0
  37. package/dist/tsconfig.build.tsbuildinfo +1 -1
  38. package/package.json +3 -3
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,670 @@
1
+ import { decoratedNavigationConfig } from './decoratedNavigationConfig.js';
2
+ import { filterDivisions, isActiveDivision } from './filterDivisions.js';
3
+ describe(filterDivisions, () => {
4
+ var _a;
5
+ const defaultArgs = {
6
+ decoratedNav: decoratedNavigationConfig,
7
+ currentPath: '',
8
+ userGroups: new Set(),
9
+ currentVersion: '',
10
+ currentLanguage: undefined,
11
+ shouldUseDivisionMatch: false,
12
+ cache: {
13
+ dropdownCache: new Map(),
14
+ },
15
+ };
16
+ const globalAnchors = (_a = decoratedNavigationConfig.global) === null || _a === void 0 ? void 0 : _a.anchors;
17
+ const allVersions = 'versions' in decoratedNavigationConfig ? decoratedNavigationConfig.versions : [];
18
+ it('finds the first page in the navigation if currentPath is /', () => {
19
+ var _a;
20
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { currentPath: '/' }));
21
+ expect(result.tabs).toHaveLength(2);
22
+ expect(result.anchors).toHaveLength(1 + ((_a = globalAnchors === null || globalAnchors === void 0 ? void 0 : globalAnchors.length) !== null && _a !== void 0 ? _a : 0));
23
+ expect(result.versions).toHaveLength(allVersions.length);
24
+ });
25
+ it('filter divisions when the currentPath is in the nested groups', () => {
26
+ var _a;
27
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { currentPath: '/web-editor' }));
28
+ expect(result.tabs).toHaveLength(2);
29
+ expect(result.anchors).toHaveLength(1 + ((_a = globalAnchors === null || globalAnchors === void 0 ? void 0 : globalAnchors.length) !== null && _a !== void 0 ? _a : 0));
30
+ expect(result.versions).toHaveLength(allVersions.length);
31
+ });
32
+ it('finds correct active divisions', () => {
33
+ var _a, _b, _c;
34
+ const { tabs, anchors, versions } = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { currentPath: '/content/components/accordion' }));
35
+ expect((_a = tabs.find(isActiveDivision)) === null || _a === void 0 ? void 0 : _a.tab).toBe('Components');
36
+ expect((_b = anchors.find(isActiveDivision)) === null || _b === void 0 ? void 0 : _b.anchor).toBe('Home');
37
+ expect((_c = versions.find(isActiveDivision)) === null || _c === void 0 ? void 0 : _c.version).toBe('v1');
38
+ });
39
+ it('can filter divisions with pages defined in versions', () => {
40
+ var _a;
41
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { currentPath: '/hello-world' }));
42
+ expect(result.tabs).toHaveLength(0);
43
+ expect(result.anchors).toHaveLength((_a = globalAnchors === null || globalAnchors === void 0 ? void 0 : globalAnchors.length) !== null && _a !== void 0 ? _a : 0);
44
+ expect(result.versions).toHaveLength(allVersions.length);
45
+ expect(result.groupsOrPages).toHaveLength(2);
46
+ });
47
+ it('preserves version tags from navigation config', () => {
48
+ var _a;
49
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { currentPath: '/v2/page', decoratedNav: {
50
+ versions: [
51
+ {
52
+ version: 'v2',
53
+ tag: 'Latest',
54
+ pages: [{ title: 'V2 Page', href: '/v2/page' }],
55
+ },
56
+ {
57
+ version: 'v1',
58
+ pages: [{ title: 'V1 Page', href: '/v1/page' }],
59
+ },
60
+ ],
61
+ } }));
62
+ expect((_a = result.versions.find((version) => version.version === 'v2')) === null || _a === void 0 ? void 0 : _a.tag).toBe('Latest');
63
+ });
64
+ it('preserves the selected version in the tab href when switching back to a versioned tab', () => {
65
+ var _a;
66
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { currentPath: '/api-reference/introduction', currentVersion: 'unstable', decoratedNav: {
67
+ tabs: [
68
+ {
69
+ tab: 'Versions',
70
+ versions: [
71
+ {
72
+ version: 'unstable',
73
+ pages: [{ title: 'Unstable', href: '/versions/unstable' }],
74
+ },
75
+ {
76
+ version: '2026.03.19',
77
+ default: true,
78
+ pages: [{ title: 'Latest', href: '/versions/v1' }],
79
+ },
80
+ ],
81
+ },
82
+ {
83
+ tab: 'API',
84
+ pages: [{ title: 'API Intro', href: '/api-reference/introduction' }],
85
+ },
86
+ ],
87
+ } }));
88
+ expect((_a = result.tabs.find((tab) => tab.tab === 'Versions')) === null || _a === void 0 ? void 0 : _a.href).toBe('/versions/unstable');
89
+ });
90
+ it('maps prefixed path to root equivalent when switching versions', () => {
91
+ var _a;
92
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { currentPath: '/2025_12/getting-started', decoratedNav: {
93
+ versions: [
94
+ {
95
+ version: '2026_03',
96
+ pages: [{ title: 'Getting Started', href: '/getting-started' }],
97
+ },
98
+ {
99
+ version: '2025_12',
100
+ pages: [{ title: 'Getting Started (2025)', href: '/2025_12/getting-started' }],
101
+ },
102
+ ],
103
+ } }));
104
+ expect((_a = result.firstHrefInVersion.get('2026_03')) === null || _a === void 0 ? void 0 : _a.href).toBe('/getting-started');
105
+ });
106
+ it('maps root path to prefixed equivalent when switching versions', () => {
107
+ var _a;
108
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { currentPath: '/getting-started', decoratedNav: {
109
+ versions: [
110
+ {
111
+ version: '2026_03',
112
+ pages: [{ title: 'Getting Started', href: '/getting-started' }],
113
+ },
114
+ {
115
+ version: '2025_12',
116
+ pages: [{ title: 'Getting Started (2025)', href: '/2025_12/getting-started' }],
117
+ },
118
+ ],
119
+ } }));
120
+ expect((_a = result.firstHrefInVersion.get('2025_12')) === null || _a === void 0 ? void 0 : _a.href).toBe('/2025_12/getting-started');
121
+ });
122
+ it('maps docs root path to prefixed equivalent when switching versions', () => {
123
+ var _a;
124
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { currentPath: '/docs/guides/overview', currentVersion: '2026_03', decoratedNav: {
125
+ versions: [
126
+ {
127
+ version: '2026_03',
128
+ pages: [{ title: 'Guides Overview', href: '/docs/guides/overview' }],
129
+ },
130
+ {
131
+ version: '2025_12',
132
+ pages: [{ title: 'Guides Overview (2025)', href: '/docs/2025_12/guides/overview' }],
133
+ },
134
+ ],
135
+ } }));
136
+ expect((_a = result.firstHrefInVersion.get('2025_12')) === null || _a === void 0 ? void 0 : _a.href).toBe('/docs/2025_12/guides/overview');
137
+ });
138
+ it('maps docs prefixed path to root equivalent when switching versions', () => {
139
+ var _a;
140
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { currentPath: '/docs/2025_12/guides/overview', currentVersion: '2025_12', decoratedNav: {
141
+ versions: [
142
+ {
143
+ version: '2026_03',
144
+ pages: [{ title: 'Guides Overview', href: '/docs/guides/overview' }],
145
+ },
146
+ {
147
+ version: '2025_12',
148
+ pages: [{ title: 'Guides Overview (2025)', href: '/docs/2025_12/guides/overview' }],
149
+ },
150
+ ],
151
+ } }));
152
+ expect((_a = result.firstHrefInVersion.get('2026_03')) === null || _a === void 0 ? void 0 : _a.href).toBe('/docs/guides/overview');
153
+ });
154
+ it('prefers same-group fallback when equivalent target page is missing', () => {
155
+ var _a;
156
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { currentPath: '/guides/new-in-2026', currentVersion: '2026_03', decoratedNav: {
157
+ versions: [
158
+ {
159
+ version: '2026_03',
160
+ groups: [
161
+ {
162
+ group: 'Guides',
163
+ pages: [
164
+ { title: 'Guides Overview', href: '/guides/overview' },
165
+ { title: 'New in 2026', href: '/guides/new-in-2026' },
166
+ ],
167
+ },
168
+ {
169
+ group: 'Getting Started',
170
+ pages: [{ title: 'Getting Started', href: '/getting-started' }],
171
+ },
172
+ ],
173
+ },
174
+ {
175
+ version: '2025_12',
176
+ groups: [
177
+ {
178
+ group: 'Getting Started',
179
+ pages: [{ title: 'Getting Started', href: '/2025_12/getting-started' }],
180
+ },
181
+ {
182
+ group: 'Guides',
183
+ pages: [{ title: 'Guides Overview', href: '/2025_12/guides/overview' }],
184
+ },
185
+ ],
186
+ },
187
+ ],
188
+ } }));
189
+ expect((_a = result.firstHrefInVersion.get('2025_12')) === null || _a === void 0 ? void 0 : _a.href).toBe('/2025_12/guides/overview');
190
+ });
191
+ it('preserves version segment when switching language on docs paths', () => {
192
+ var _a;
193
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { currentPath: '/docs/2025_12/getting-started', currentVersion: '2025_12', currentLanguage: 'en', decoratedNav: {
194
+ languages: [
195
+ {
196
+ language: 'en',
197
+ versions: [
198
+ {
199
+ version: '2026_03',
200
+ pages: [{ title: 'EN Latest', href: '/docs/getting-started' }],
201
+ },
202
+ {
203
+ version: '2025_12',
204
+ pages: [{ title: 'EN 2025_12', href: '/docs/2025_12/getting-started' }],
205
+ },
206
+ ],
207
+ },
208
+ {
209
+ language: 'es',
210
+ versions: [
211
+ {
212
+ version: '2026_03',
213
+ pages: [{ title: 'ES Latest', href: '/es/docs/getting-started' }],
214
+ },
215
+ {
216
+ version: '2025_12',
217
+ pages: [{ title: 'ES 2025_12', href: '/es/docs/2025_12/getting-started' }],
218
+ },
219
+ ],
220
+ },
221
+ ],
222
+ } }));
223
+ expect((_a = result.firstHrefInLanguage.get('es')) === null || _a === void 0 ? void 0 : _a.href).toBe('/es/docs/2025_12/getting-started');
224
+ });
225
+ });
226
+ describe('filterDivisions with partial auth', () => {
227
+ const defaultArgs = {
228
+ decoratedNav: { groups: [] },
229
+ currentPath: '',
230
+ userGroups: new Set(),
231
+ currentVersion: '',
232
+ currentLanguage: undefined,
233
+ shouldUseDivisionMatch: true,
234
+ cache: {
235
+ dropdownCache: new Map(),
236
+ },
237
+ };
238
+ it('filters pages with the correct groups', () => {
239
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { decoratedNav: {
240
+ pages: [
241
+ { title: 'Page 1', href: '/page-1' },
242
+ { title: 'Page 2', href: '/page-2', groups: [] },
243
+ ],
244
+ }, userGroups: new Set(['admin']) }));
245
+ expect(result.groupsOrPages).toEqual([{ title: 'Page 1', href: '/page-1' }]);
246
+ });
247
+ it('filters groups with the correct groups', () => {
248
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { decoratedNav: {
249
+ groups: [
250
+ { group: 'Group 1', pages: [{ title: 'Page 1', href: '/page-1', groups: [] }] },
251
+ { group: 'Group 2', pages: [{ title: 'Page 2', href: '/page-2', groups: ['admin'] }] },
252
+ ],
253
+ }, userGroups: new Set(['admin']), currentPath: '/page-2' }));
254
+ expect(result.groupsOrPages).toEqual([
255
+ { group: 'Group 2', pages: [{ title: 'Page 2', href: '/page-2', groups: ['admin'] }] },
256
+ ]);
257
+ });
258
+ it('allow empty userGroups and empty groups', () => {
259
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { decoratedNav: {
260
+ groups: [
261
+ { group: 'Group 1', pages: [{ title: 'Page 1', href: '/page-1' }] },
262
+ { group: 'Group 2', pages: [{ title: 'Page 2', href: '/page-2', groups: [] }] },
263
+ ],
264
+ } }));
265
+ expect(result.groupsOrPages).toEqual([
266
+ { group: 'Group 1', pages: [{ title: 'Page 1', href: '/page-1' }] },
267
+ ]);
268
+ });
269
+ it('should filter divisions with empty groups or pages after check nav access', () => {
270
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { decoratedNav: {
271
+ tabs: [
272
+ {
273
+ tab: 'Tab 1',
274
+ groups: [{ group: 'Group 1', pages: [{ title: 'Page 1', href: '/page-1' }] }],
275
+ },
276
+ {
277
+ tab: 'Tab 2',
278
+ groups: [
279
+ { group: 'Group 2', pages: [{ title: 'Page 2', href: '/page-2', groups: [] }] },
280
+ ],
281
+ },
282
+ ],
283
+ } }));
284
+ expect(result.tabs).toHaveLength(1);
285
+ expect(result.groupsOrPages).toEqual([
286
+ { group: 'Group 1', pages: [{ title: 'Page 1', href: '/page-1' }] },
287
+ ]);
288
+ });
289
+ it('should filter divisions with nested empty divisions after check nav access', () => {
290
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { decoratedNav: {
291
+ tabs: [
292
+ {
293
+ tab: 'Tab 1',
294
+ groups: [{ group: 'Group 1', pages: [{ title: 'Page 1', href: '/page-1' }] }],
295
+ },
296
+ {
297
+ tab: 'Tab 2',
298
+ dropdowns: [
299
+ {
300
+ dropdown: 'Empty Dropdown',
301
+ versions: [
302
+ {
303
+ version: 'Empty Version',
304
+ pages: [
305
+ {
306
+ group: 'Empty Group',
307
+ pages: [],
308
+ },
309
+ ],
310
+ },
311
+ ],
312
+ },
313
+ ],
314
+ },
315
+ ],
316
+ } }));
317
+ expect(result.tabs).toHaveLength(1);
318
+ expect(result.groupsOrPages).toEqual([
319
+ { group: 'Group 1', pages: [{ title: 'Page 1', href: '/page-1' }] },
320
+ ]);
321
+ });
322
+ it('should filter divisions with deeply nested empty divisions', () => {
323
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { decoratedNav: {
324
+ tabs: [
325
+ {
326
+ tab: 'Tab 1',
327
+ groups: [{ group: 'Group 1', pages: [{ title: 'Page 1', href: '/page-1' }] }],
328
+ },
329
+ {
330
+ tab: 'Tab 2',
331
+ dropdowns: [
332
+ {
333
+ dropdown: 'Empty Dropdown',
334
+ versions: [
335
+ {
336
+ version: 'Empty Version',
337
+ languages: [
338
+ {
339
+ language: 'en',
340
+ dropdowns: [
341
+ {
342
+ dropdown: 'Documentation',
343
+ groups: [
344
+ {
345
+ group: 'Getting Started',
346
+ pages: [],
347
+ },
348
+ ],
349
+ },
350
+ ],
351
+ },
352
+ ],
353
+ },
354
+ ],
355
+ },
356
+ ],
357
+ },
358
+ ],
359
+ } }));
360
+ expect(result.tabs).toHaveLength(1);
361
+ expect(result.groupsOrPages).toEqual([
362
+ { group: 'Group 1', pages: [{ title: 'Page 1', href: '/page-1' }] },
363
+ ]);
364
+ });
365
+ it('should keep the groups/divisions if there is at least one page accessible', () => {
366
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { decoratedNav: {
367
+ tabs: [
368
+ {
369
+ tab: 'Tab 1',
370
+ groups: [
371
+ {
372
+ group: 'Group 1',
373
+ pages: [
374
+ { title: 'Page 1', href: '/page-1' },
375
+ { title: 'Page 2', href: '/page-2', groups: [] },
376
+ ],
377
+ },
378
+ ],
379
+ },
380
+ {
381
+ tab: 'Tab 2',
382
+ groups: [{ group: 'Group 2', pages: [{ title: 'Page 3', href: '/page-3' }] }],
383
+ },
384
+ ],
385
+ } }));
386
+ expect(result.tabs).toHaveLength(2);
387
+ expect(result.groupsOrPages).toEqual([
388
+ { group: 'Group 1', pages: [{ title: 'Page 1', href: '/page-1' }] },
389
+ ]);
390
+ });
391
+ it('should add menu to the tabs', () => {
392
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { decoratedNav: {
393
+ tabs: [
394
+ {
395
+ tab: 'Tab 1',
396
+ menu: [{ item: 'Advanced Dropdown', pages: [{ title: 'Page 1', href: '/page-1' }] }],
397
+ },
398
+ ],
399
+ } }));
400
+ expect(result.tabs).toEqual([
401
+ {
402
+ name: 'Tab 1',
403
+ tab: 'Tab 1',
404
+ href: '/page-1',
405
+ isActive: true,
406
+ isGlobal: false,
407
+ menu: [
408
+ {
409
+ name: 'Advanced Dropdown',
410
+ item: 'Advanced Dropdown',
411
+ href: '/page-1',
412
+ isActive: true,
413
+ isGlobal: false,
414
+ },
415
+ ],
416
+ },
417
+ ]);
418
+ });
419
+ it('should add menu to the products', () => {
420
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { decoratedNav: {
421
+ products: [
422
+ {
423
+ product: 'Product 1',
424
+ menu: [{ item: 'Advanced Dropdown', pages: [{ title: 'Page 1', href: '/page-1' }] }],
425
+ },
426
+ ],
427
+ } }));
428
+ expect(result.products).toEqual([
429
+ {
430
+ name: 'Product 1',
431
+ product: 'Product 1',
432
+ href: '/page-1',
433
+ isActive: true,
434
+ isGlobal: false,
435
+ menu: [
436
+ {
437
+ name: 'Advanced Dropdown',
438
+ item: 'Advanced Dropdown',
439
+ href: '/page-1',
440
+ isActive: true,
441
+ isGlobal: false,
442
+ },
443
+ ],
444
+ },
445
+ ]);
446
+ });
447
+ it('finds page when currentPath matches a root page', () => {
448
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { decoratedNav: {
449
+ groups: [
450
+ {
451
+ group: 'Group 1',
452
+ root: { title: 'Root Page', href: '/root-page' },
453
+ pages: [{ title: 'Page 1', href: '/page-1' }],
454
+ },
455
+ ],
456
+ }, currentPath: '/root-page' }));
457
+ expect(result.groupsOrPages).toEqual([
458
+ {
459
+ group: 'Group 1',
460
+ root: { title: 'Root Page', href: '/root-page' },
461
+ pages: [{ title: 'Page 1', href: '/page-1' }],
462
+ },
463
+ ]);
464
+ });
465
+ it('keeps division accessible when only root page is accessible', () => {
466
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { decoratedNav: {
467
+ tabs: [
468
+ {
469
+ tab: 'Tab 1',
470
+ groups: [
471
+ {
472
+ group: 'Group 1',
473
+ root: { title: 'Root Page', href: '/root-page' },
474
+ pages: [{ title: 'Page 1', href: '/page-1', groups: [] }],
475
+ },
476
+ ],
477
+ },
478
+ ],
479
+ }, currentPath: '/root-page' }));
480
+ expect(result.tabs).toHaveLength(1);
481
+ });
482
+ it('filters root page from inaccessible pages', () => {
483
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { decoratedNav: {
484
+ groups: [
485
+ {
486
+ group: 'Group 1',
487
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- testing access control
488
+ root: {
489
+ title: 'Root Page',
490
+ href: '/root-page',
491
+ groups: [],
492
+ },
493
+ pages: [{ title: 'Page 1', href: '/page-1' }],
494
+ },
495
+ ],
496
+ }, userGroups: new Set(['admin']), currentPath: '/page-1' }));
497
+ expect(result.groupsOrPages).toEqual([
498
+ {
499
+ group: 'Group 1',
500
+ root: undefined,
501
+ pages: [{ title: 'Page 1', href: '/page-1' }],
502
+ },
503
+ ]);
504
+ });
505
+ it('should filter out hidden nested groups', () => {
506
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { decoratedNav: {
507
+ groups: [
508
+ {
509
+ group: 'Visible Group',
510
+ pages: [
511
+ { title: 'Page 1', href: '/page-1' },
512
+ {
513
+ group: 'Hidden Nested Group',
514
+ hidden: true,
515
+ pages: [{ title: 'Hidden Page', href: '/hidden-page' }],
516
+ },
517
+ {
518
+ group: 'Visible Nested Group',
519
+ pages: [{ title: 'Page 2', href: '/page-2' }],
520
+ },
521
+ ],
522
+ },
523
+ ],
524
+ } }));
525
+ expect(result.groupsOrPages).toEqual([
526
+ {
527
+ group: 'Visible Group',
528
+ pages: [
529
+ { title: 'Page 1', href: '/page-1' },
530
+ {
531
+ group: 'Visible Nested Group',
532
+ pages: [{ title: 'Page 2', href: '/page-2' }],
533
+ },
534
+ ],
535
+ },
536
+ ]);
537
+ });
538
+ it('should filter out hidden top-level groups', () => {
539
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { decoratedNav: {
540
+ groups: [
541
+ {
542
+ group: 'Visible Group',
543
+ pages: [{ title: 'Page 1', href: '/page-1' }],
544
+ },
545
+ {
546
+ group: 'Hidden Group',
547
+ hidden: true,
548
+ pages: [{ title: 'Hidden Page', href: '/hidden-page' }],
549
+ },
550
+ ],
551
+ } }));
552
+ expect(result.groupsOrPages).toEqual([
553
+ {
554
+ group: 'Visible Group',
555
+ pages: [{ title: 'Page 1', href: '/page-1' }],
556
+ },
557
+ ]);
558
+ });
559
+ describe('shared page product context resolution', () => {
560
+ const sharedPageNav = {
561
+ languages: [
562
+ {
563
+ language: 'en',
564
+ products: [
565
+ {
566
+ product: 'Product A',
567
+ tabs: [
568
+ {
569
+ tab: 'Doc 1',
570
+ pages: [
571
+ { title: 'A Overview', href: '/en/product_a/a-overview' },
572
+ { title: 'A Install', href: '/en/product_a/a-install' },
573
+ ],
574
+ },
575
+ {
576
+ tab: 'Doc 2',
577
+ pages: [
578
+ { title: 'Billing', href: '/en/shared/billing' },
579
+ { title: 'Security', href: '/en/shared/security' },
580
+ { title: 'Support', href: '/en/shared/support' },
581
+ ],
582
+ },
583
+ ],
584
+ },
585
+ {
586
+ product: 'Product B',
587
+ tabs: [
588
+ {
589
+ tab: 'Doc 1',
590
+ pages: [
591
+ { title: 'B Overview', href: '/en/product_b/b-overview' },
592
+ { title: 'B Install', href: '/en/product_b/b-install' },
593
+ ],
594
+ },
595
+ {
596
+ tab: 'Doc 2',
597
+ pages: [
598
+ { title: 'Billing', href: '/en/shared/billing' },
599
+ { title: 'Security', href: '/en/shared/security' },
600
+ { title: 'Support', href: '/en/shared/support' },
601
+ ],
602
+ },
603
+ ],
604
+ },
605
+ ],
606
+ },
607
+ ],
608
+ };
609
+ it('resolves shared page to Product B when currentProduct is Product B', () => {
610
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { currentPath: '/en/shared/billing', currentProduct: 'Product B', currentLanguage: 'en', decoratedNav: sharedPageNav }));
611
+ const activeProduct = result.products.find(isActiveDivision);
612
+ expect(activeProduct === null || activeProduct === void 0 ? void 0 : activeProduct.product).toBe('Product B');
613
+ });
614
+ it('resolves shared page to Product A when currentProduct is Product A', () => {
615
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { currentPath: '/en/shared/billing', currentProduct: 'Product A', currentLanguage: 'en', decoratedNav: sharedPageNav }));
616
+ const activeProduct = result.products.find(isActiveDivision);
617
+ expect(activeProduct === null || activeProduct === void 0 ? void 0 : activeProduct.product).toBe('Product A');
618
+ });
619
+ it('defaults to first product when no currentProduct is set', () => {
620
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { currentPath: '/en/shared/billing', currentProduct: undefined, currentLanguage: 'en', decoratedNav: sharedPageNav }));
621
+ const activeProduct = result.products.find(isActiveDivision);
622
+ expect(activeProduct === null || activeProduct === void 0 ? void 0 : activeProduct.product).toBe('Product A');
623
+ });
624
+ it('falls back to first product if currentProduct is not in the config', () => {
625
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { currentPath: '/en/shared/billing', currentProduct: 'Product C', currentLanguage: 'en', decoratedNav: sharedPageNav }));
626
+ const activeProduct = result.products.find(isActiveDivision);
627
+ expect(activeProduct === null || activeProduct === void 0 ? void 0 : activeProduct.product).toBe('Product A');
628
+ });
629
+ it('resolves product-specific page correctly regardless of currentProduct', () => {
630
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { currentPath: '/en/product_b/b-overview', currentProduct: 'Product A', currentLanguage: 'en', decoratedNav: sharedPageNav }));
631
+ const activeProduct = result.products.find(isActiveDivision);
632
+ expect(activeProduct === null || activeProduct === void 0 ? void 0 : activeProduct.product).toBe('Product B');
633
+ });
634
+ it('matches on product identifier even when display name differs', () => {
635
+ const navWithDisplayName = {
636
+ products: [
637
+ {
638
+ product: 'prod-a',
639
+ name: 'Product A Display',
640
+ tabs: [
641
+ {
642
+ tab: 'Shared',
643
+ pages: [{ title: 'Shared Page', href: '/shared/page' }],
644
+ },
645
+ ],
646
+ },
647
+ {
648
+ product: 'prod-b',
649
+ name: 'Product B Display',
650
+ tabs: [
651
+ {
652
+ tab: 'Shared',
653
+ pages: [{ title: 'Shared Page', href: '/shared/page' }],
654
+ },
655
+ ],
656
+ },
657
+ ],
658
+ };
659
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { currentPath: '/shared/page', currentProduct: 'prod-b', decoratedNav: navWithDisplayName }));
660
+ const activeProduct = result.products.find(isActiveDivision);
661
+ expect(activeProduct === null || activeProduct === void 0 ? void 0 : activeProduct.product).toBe('prod-b');
662
+ });
663
+ it('preserves config order for product switcher UI regardless of currentProduct', () => {
664
+ var _a, _b;
665
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { currentPath: '/en/shared/billing', currentProduct: 'Product B', currentLanguage: 'en', decoratedNav: sharedPageNav }));
666
+ expect((_a = result.products[0]) === null || _a === void 0 ? void 0 : _a.product).toBe('Product A');
667
+ expect((_b = result.products[1]) === null || _b === void 0 ? void 0 : _b.product).toBe('Product B');
668
+ });
669
+ });
670
+ });
@@ -0,0 +1 @@
1
+ export {};