@mintlify/common 1.0.1076 → 1.0.1077

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.
@@ -7,7 +7,7 @@ import { isEqualIgnoringLeadingSlash } from '../paths/isEqualIgnoringLeadingSlas
7
7
  import { checkNavAccess } from './checkNavAccess.js';
8
8
  import { getFirstPageFromNavigation } from './getFirstPageFromNavigation.js';
9
9
  import { isPage } from './isPage.js';
10
- import { updateFirstHrefInDivision } from './updateFirstHrefInDivision.js';
10
+ import { pathsDifferByOneSegment, updateFirstHrefInDivision, } from './updateFirstHrefInDivision.js';
11
11
  const DIVISION_NAME_MAP = {
12
12
  tabs: 'tab',
13
13
  anchors: 'anchor',
@@ -155,6 +155,7 @@ export const filterDivisions = ({ currentPath, currentVersion, currentLanguage,
155
155
  item,
156
156
  isActive,
157
157
  cache,
158
+ currentPath,
158
159
  currentVersion,
159
160
  currentLanguage,
160
161
  userGroups,
@@ -260,8 +261,8 @@ function upsertGlobalDivisions(navigationDivisions, globalConfig) {
260
261
  });
261
262
  }
262
263
  function buildDivisionItem(param) {
263
- var _a;
264
- const { item, isActive, cache, currentVersion, currentLanguage, userGroups, divisionKey, menuDivision, isPreview = false, parentDivisionNames = [], } = param;
264
+ var _a, _b;
265
+ const { item, isActive, cache, currentPath, currentVersion, currentLanguage, userGroups, divisionKey, menuDivision, isPreview = false, parentDivisionNames = [], } = param;
265
266
  const { dropdownCache } = cache;
266
267
  let href = '';
267
268
  // TODO: support this for other divisions (versions, languages, etc.)
@@ -282,11 +283,17 @@ function buildDivisionItem(param) {
282
283
  // if href is absolute url, use it, otherwise use the href from the first page
283
284
  if (!href) {
284
285
  const isUserDefinedHref = 'href' in item && isAbsoluteUrl(item.href);
285
- href = isUserDefinedHref ? item.href : (page === null || page === void 0 ? void 0 : page.href) || '/';
286
- // when users switch languages, we should stay on the same page
287
- // instead of switching to the first page in the new language
288
- if (!isUserDefinedHref && divisionKey === 'languages') {
289
- href = '';
286
+ if (!isUserDefinedHref && divisionKey === 'dropdowns' && !isActive && currentPath) {
287
+ href =
288
+ (_b = findCorrespondingDropdownHref(item, currentPath, userGroups !== null && userGroups !== void 0 ? userGroups : new Set(), isPreview)) !== null && _b !== void 0 ? _b : '';
289
+ }
290
+ if (!href) {
291
+ href = isUserDefinedHref ? item.href : (page === null || page === void 0 ? void 0 : page.href) || '/';
292
+ // when users switch languages, we should stay on the same page
293
+ // instead of switching to the first page in the new language
294
+ if (!isUserDefinedHref && divisionKey === 'languages') {
295
+ href = '';
296
+ }
290
297
  }
291
298
  }
292
299
  const baseResult = Object.assign(Object.assign({ name: findDivisionName(item) }, divisionItem), { href: href, isActive, isGlobal: false });
@@ -306,6 +313,7 @@ function buildDivisionItem(param) {
306
313
  item: menuItem,
307
314
  isActive: false, // menu items are not active by default
308
315
  cache,
316
+ currentPath,
309
317
  currentVersion,
310
318
  currentLanguage,
311
319
  userGroups,
@@ -322,6 +330,52 @@ function buildDivisionItem(param) {
322
330
  }
323
331
  return baseResult;
324
332
  }
333
+ function findCorrespondingDropdownHref(item, currentPath, userGroups, isPreview) {
334
+ let exactMatch;
335
+ let segmentMatch;
336
+ function walk(entry) {
337
+ if (exactMatch !== undefined || typeof entry !== 'object')
338
+ return;
339
+ if (isPage(entry)) {
340
+ if (!checkNavAccess(entry, userGroups, isPreview))
341
+ return;
342
+ if (isEqualIgnoringLeadingSlash(entry.href, currentPath)) {
343
+ exactMatch = entry.href;
344
+ }
345
+ else if (segmentMatch === undefined &&
346
+ pathsDifferByOneSegment(entry.href, currentPath, 'version')) {
347
+ segmentMatch = entry.href;
348
+ }
349
+ return;
350
+ }
351
+ if ('hidden' in entry && entry.hidden)
352
+ return;
353
+ if ('root' in entry && typeof entry.root === 'object') {
354
+ walk(entry.root);
355
+ }
356
+ if ('pages' in entry && Array.isArray(entry.pages)) {
357
+ for (const page of entry.pages) {
358
+ if (typeof page === 'object')
359
+ walk(page);
360
+ }
361
+ }
362
+ if ('groups' in entry && Array.isArray(entry.groups)) {
363
+ for (const group of entry.groups) {
364
+ walk(group);
365
+ }
366
+ }
367
+ for (const key of divisions) {
368
+ const subDivisions = readObjectArrayProperty(entry, key);
369
+ if (!subDivisions)
370
+ continue;
371
+ for (const subDivision of subDivisions) {
372
+ walk(subDivision);
373
+ }
374
+ }
375
+ }
376
+ walk(item);
377
+ return exactMatch !== null && exactMatch !== void 0 ? exactMatch : segmentMatch;
378
+ }
325
379
  function getFirstPageFromCurrentDivisions(item, currentVersion, currentLanguage, userGroups, isPreview = false) {
326
380
  var _a, _b;
327
381
  if ('versions' in item && currentVersion) {
@@ -629,6 +683,7 @@ function findMostRelevantDivisions(currentPath, decoratedNav, currentVersion, cu
629
683
  item,
630
684
  isActive,
631
685
  cache,
686
+ currentPath,
632
687
  currentVersion,
633
688
  currentLanguage,
634
689
  userGroups,
@@ -668,3 +668,124 @@ describe('filterDivisions with partial auth', () => {
668
668
  });
669
669
  });
670
670
  });
671
+ describe('filterDivisions dropdown corresponding pages', () => {
672
+ const defaultArgs = {
673
+ decoratedNav: { groups: [] },
674
+ currentPath: '',
675
+ userGroups: new Set(),
676
+ currentVersion: '',
677
+ currentLanguage: undefined,
678
+ shouldUseDivisionMatch: true,
679
+ cache: {
680
+ dropdownCache: new Map(),
681
+ },
682
+ };
683
+ const versionedDropdownNav = {
684
+ dropdowns: [
685
+ {
686
+ dropdown: 'Version 0.22',
687
+ groups: [
688
+ {
689
+ group: 'Get Started',
690
+ pages: [
691
+ { title: 'Overview', href: '/vega/0.22/overview' },
692
+ { title: 'Install', href: '/vega/0.22/install' },
693
+ { title: 'New Feature', href: '/vega/0.22/new-feature' },
694
+ ],
695
+ },
696
+ ],
697
+ },
698
+ {
699
+ dropdown: 'Version 0.21',
700
+ groups: [
701
+ {
702
+ group: 'Get Started',
703
+ pages: [
704
+ { title: 'Overview', href: '/vega/0.21/overview' },
705
+ { title: 'Install', href: '/vega/0.21/install' },
706
+ ],
707
+ },
708
+ ],
709
+ },
710
+ ],
711
+ };
712
+ it('points inactive dropdowns at the corresponding page when one exists', () => {
713
+ var _a;
714
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { decoratedNav: versionedDropdownNav, currentPath: '/vega/0.21/install' }));
715
+ expect((_a = result.dropdowns.find((d) => d.name === 'Version 0.22')) === null || _a === void 0 ? void 0 : _a.href).toBe('/vega/0.22/install');
716
+ });
717
+ it('keeps the first page href for the active dropdown', () => {
718
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { decoratedNav: versionedDropdownNav, currentPath: '/vega/0.21/install' }));
719
+ const active = result.dropdowns.find(isActiveDivision);
720
+ expect(active === null || active === void 0 ? void 0 : active.name).toBe('Version 0.21');
721
+ expect(active === null || active === void 0 ? void 0 : active.href).toBe('/vega/0.21/overview');
722
+ });
723
+ it('falls back to the first page when no corresponding page exists', () => {
724
+ var _a;
725
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { decoratedNav: versionedDropdownNav, currentPath: '/vega/0.22/new-feature' }));
726
+ expect((_a = result.dropdowns.find((d) => d.name === 'Version 0.21')) === null || _a === void 0 ? void 0 : _a.href).toBe('/vega/0.21/overview');
727
+ });
728
+ it('prefers a shared page at the same href over a segment match', () => {
729
+ var _a;
730
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { decoratedNav: {
731
+ dropdowns: [
732
+ {
733
+ dropdown: 'Guides',
734
+ pages: [
735
+ { title: 'Intro', href: '/guides/intro' },
736
+ { title: 'Changelog', href: '/changelog/latest' },
737
+ ],
738
+ },
739
+ {
740
+ dropdown: 'Reference',
741
+ pages: [
742
+ { title: 'Intro', href: '/reference/intro' },
743
+ { title: 'Changelog', href: '/changelog/latest' },
744
+ ],
745
+ },
746
+ ],
747
+ }, currentPath: '/changelog/latest' }));
748
+ expect((_a = result.dropdowns.find((d) => d.name === 'Reference')) === null || _a === void 0 ? void 0 : _a.href).toBe('/changelog/latest');
749
+ });
750
+ it('skips corresponding pages the viewer cannot access', () => {
751
+ var _a, _b;
752
+ const decoratedNav = {
753
+ dropdowns: [
754
+ {
755
+ dropdown: 'Version 0.22',
756
+ pages: [
757
+ { title: 'Overview', href: '/vega/0.22/overview' },
758
+ { title: 'Install', href: '/vega/0.22/install', groups: ['admin'] },
759
+ ],
760
+ },
761
+ {
762
+ dropdown: 'Version 0.21',
763
+ pages: [
764
+ { title: 'Overview', href: '/vega/0.21/overview' },
765
+ { title: 'Install', href: '/vega/0.21/install' },
766
+ ],
767
+ },
768
+ ],
769
+ };
770
+ const anonymous = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { decoratedNav, currentPath: '/vega/0.21/install' }));
771
+ expect((_a = anonymous.dropdowns.find((d) => d.name === 'Version 0.22')) === null || _a === void 0 ? void 0 : _a.href).toBe('/vega/0.22/overview');
772
+ const admin = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { decoratedNav, currentPath: '/vega/0.21/install', userGroups: new Set(['admin']) }));
773
+ expect((_b = admin.dropdowns.find((d) => d.name === 'Version 0.22')) === null || _b === void 0 ? void 0 : _b.href).toBe('/vega/0.22/install');
774
+ });
775
+ it('matches corresponding pages for dropdowns nested inside tabs', () => {
776
+ var _a;
777
+ const result = filterDivisions(Object.assign(Object.assign({}, defaultArgs), { decoratedNav: {
778
+ tabs: [
779
+ {
780
+ tab: 'Get Started',
781
+ dropdowns: versionedDropdownNav.dropdowns,
782
+ },
783
+ {
784
+ tab: 'Support',
785
+ pages: [{ title: 'Help', href: '/support/help' }],
786
+ },
787
+ ],
788
+ }, currentPath: '/vega/0.21/install' }));
789
+ expect((_a = result.dropdowns.find((d) => d.name === 'Version 0.22')) === null || _a === void 0 ? void 0 : _a.href).toBe('/vega/0.22/install');
790
+ });
791
+ });