@mintlify/common 1.0.1170 → 1.0.1171
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.
- package/dist/navigation/scopeNavToPath.js +72 -25
- package/dist/navigation/scopeOffPathDivisions.test.js +427 -3
- package/dist/navigation/scopePrecomputedTargets.test.d.ts +1 -0
- package/dist/navigation/scopePrecomputedTargets.test.js +175 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { locales } from '@mintlify/models';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { filterDivisions } from './filterDivisions.js';
|
|
4
|
+
import { getAllPathsInDecoratedNav } from './getAllPathsInDecoratedNav.js';
|
|
5
|
+
import { getScopedNavForPath } from './scopeNavToPath.js';
|
|
6
|
+
const page = (href) => ({ title: href, href });
|
|
7
|
+
const versionedItem = (item, v3, v2) => ({
|
|
8
|
+
item,
|
|
9
|
+
versions: [
|
|
10
|
+
{ version: 'v3', default: true, groups: [{ group: `${item} v3`, pages: v3.map(page) }] },
|
|
11
|
+
{ version: 'v2', groups: [{ group: `${item} v2`, pages: v2.map(page) }] },
|
|
12
|
+
],
|
|
13
|
+
});
|
|
14
|
+
const crossListedVersionNav = {
|
|
15
|
+
tabs: [
|
|
16
|
+
{
|
|
17
|
+
tab: 'Docs',
|
|
18
|
+
menu: [
|
|
19
|
+
{ item: 'Home', pages: [page('/home')] },
|
|
20
|
+
versionedItem('Studio', ['/studio/v3/a', '/studio/v3/b'], ['/studio/v2/a', '/shared']),
|
|
21
|
+
versionedItem('Engine', ['/engine/v3/a', '/shared', '/engine/v3/c'], ['/engine/v2/a']),
|
|
22
|
+
versionedItem('Solver', ['/solver/v3/a'], ['/solver/v2/a']),
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
{ tab: 'Other', pages: [page('/other')] },
|
|
26
|
+
],
|
|
27
|
+
};
|
|
28
|
+
const pathSimilarVersionNav = {
|
|
29
|
+
tabs: [
|
|
30
|
+
{
|
|
31
|
+
tab: 'Docs',
|
|
32
|
+
menu: [
|
|
33
|
+
versionedItem('Studio', ['/studio/v3/a'], ['/studio/v2/a', '/shared']),
|
|
34
|
+
versionedItem('Engine', ['/engine/v3/a', '/shared'], ['/engine/v2/intro', '/v2/shared']),
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
};
|
|
39
|
+
const dropdownVersionNav = {
|
|
40
|
+
tabs: [
|
|
41
|
+
{
|
|
42
|
+
tab: 'Docs',
|
|
43
|
+
menu: [
|
|
44
|
+
versionedItem('Studio', ['/studio/v3/a'], ['/studio/v2/a', '/shared']),
|
|
45
|
+
{
|
|
46
|
+
item: 'Engine',
|
|
47
|
+
versions: [
|
|
48
|
+
{ version: 'v3', default: true, pages: [page('/engine/v3/a'), page('/shared')] },
|
|
49
|
+
{
|
|
50
|
+
version: 'v2',
|
|
51
|
+
dropdowns: [
|
|
52
|
+
{ dropdown: 'Guides', pages: [page('/engine/v2/guides')] },
|
|
53
|
+
{ dropdown: 'Reference', pages: [page('/engine/v2/reference')] },
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
};
|
|
62
|
+
const localizedItem = (item, en, fr) => ({
|
|
63
|
+
item,
|
|
64
|
+
languages: [
|
|
65
|
+
{
|
|
66
|
+
language: 'en',
|
|
67
|
+
default: true,
|
|
68
|
+
groups: [{ group: `${item} en`, pages: en.map(page) }],
|
|
69
|
+
},
|
|
70
|
+
{ language: 'fr', groups: [{ group: `${item} fr`, pages: fr.map(page) }] },
|
|
71
|
+
],
|
|
72
|
+
});
|
|
73
|
+
const crossListedLanguageNav = {
|
|
74
|
+
tabs: [
|
|
75
|
+
{
|
|
76
|
+
tab: 'Docs',
|
|
77
|
+
menu: [
|
|
78
|
+
localizedItem('Studio', ['/studio/en'], ['/studio/fr', '/shared']),
|
|
79
|
+
localizedItem('Engine', ['/engine/en', '/shared'], ['/engine/fr']),
|
|
80
|
+
localizedItem('Solver', ['/solver/en'], ['/solver/fr']),
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
};
|
|
85
|
+
const toLocale = (value) => locales.find((locale) => locale === value);
|
|
86
|
+
function sessionValuesContaining(node, href, key, current) {
|
|
87
|
+
const found = new Set();
|
|
88
|
+
if (Array.isArray(node)) {
|
|
89
|
+
for (const entry of node) {
|
|
90
|
+
sessionValuesContaining(entry, href, key, current).forEach((value) => found.add(value));
|
|
91
|
+
}
|
|
92
|
+
return found;
|
|
93
|
+
}
|
|
94
|
+
if (typeof node !== 'object' || node === null)
|
|
95
|
+
return found;
|
|
96
|
+
const value = key in node ? Reflect.get(node, key) : undefined;
|
|
97
|
+
const scope = typeof value === 'string' ? value : current;
|
|
98
|
+
if (Reflect.get(node, 'href') === href)
|
|
99
|
+
found.add(scope);
|
|
100
|
+
for (const child of Object.values(node)) {
|
|
101
|
+
if (typeof child === 'object' && child !== null) {
|
|
102
|
+
sessionValuesContaining(child, href, key, scope).forEach((entry) => found.add(entry));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return found;
|
|
106
|
+
}
|
|
107
|
+
function filterWith(decoratedNav, currentPath, currentVersion, currentLanguage) {
|
|
108
|
+
return filterDivisions({
|
|
109
|
+
currentPath,
|
|
110
|
+
decoratedNav,
|
|
111
|
+
userGroups: new Set(),
|
|
112
|
+
currentVersion,
|
|
113
|
+
currentLanguage,
|
|
114
|
+
shouldUseDivisionMatch: true,
|
|
115
|
+
cache: { dropdownCache: new Map() },
|
|
116
|
+
isPreview: false,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
function chromeSummary(result) {
|
|
120
|
+
return {
|
|
121
|
+
tabs: result.tabs.map(({ name, href, isActive, menu }) => ({
|
|
122
|
+
name,
|
|
123
|
+
href,
|
|
124
|
+
isActive,
|
|
125
|
+
menu: menu === null || menu === void 0 ? void 0 : menu.map((item) => ({ name: item.name, href: item.href, isActive: item.isActive })),
|
|
126
|
+
})),
|
|
127
|
+
versions: result.versions.map(({ name, isActive }) => ({ name, isActive })),
|
|
128
|
+
languages: result.languages.map(({ name, isActive }) => ({ name, isActive })),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function mapHrefs(map) {
|
|
132
|
+
return Object.fromEntries([...map].map(([key, value]) => [String(key), value.href]));
|
|
133
|
+
}
|
|
134
|
+
function assertChromeInvariantForEverySession(nav, key, compareJumpMaps = true) {
|
|
135
|
+
for (const path of getAllPathsInDecoratedNav(nav)) {
|
|
136
|
+
const currentPath = `/${path.replace(/^\//, '')}`;
|
|
137
|
+
const scoped = getScopedNavForPath({ decoratedNav: nav, currentPath });
|
|
138
|
+
for (const value of sessionValuesContaining(nav, currentPath, key)) {
|
|
139
|
+
const version = key === 'version' ? value : scoped.currentVersion;
|
|
140
|
+
const language = key === 'language' ? toLocale(value) : scoped.currentLanguage;
|
|
141
|
+
const label = `${currentPath} ${key}=${value !== null && value !== void 0 ? value : '-'}`;
|
|
142
|
+
const full = filterWith(nav, currentPath, version, language);
|
|
143
|
+
const rescoped = filterWith(scoped.scopedNav, currentPath, version, language);
|
|
144
|
+
expect(rescoped.groupsOrPages, label).toEqual(full.groupsOrPages);
|
|
145
|
+
expect(chromeSummary(rescoped), label).toEqual(chromeSummary(full));
|
|
146
|
+
if (!compareJumpMaps)
|
|
147
|
+
continue;
|
|
148
|
+
expect(mapHrefs(rescoped.firstHrefInVersion), label).toEqual(mapHrefs(full.firstHrefInVersion));
|
|
149
|
+
expect(mapHrefs(rescoped.firstHrefInLanguage), label).toEqual(mapHrefs(full.firstHrefInLanguage));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
describe('precomputed switch targets on cross-listed pages', () => {
|
|
154
|
+
it('keeps every menu href identical to the full nav for every session version', () => {
|
|
155
|
+
assertChromeInvariantForEverySession(crossListedVersionNav, 'version');
|
|
156
|
+
});
|
|
157
|
+
it('keeps menu hrefs on the first page when a later page resembles the current path', () => {
|
|
158
|
+
assertChromeInvariantForEverySession(pathSimilarVersionNav, 'version');
|
|
159
|
+
});
|
|
160
|
+
it('keeps menu hrefs on the first dropdown page of a sibling version', () => {
|
|
161
|
+
assertChromeInvariantForEverySession(dropdownVersionNav, 'version', false);
|
|
162
|
+
});
|
|
163
|
+
it('keeps every menu href identical to the full nav for every session language', () => {
|
|
164
|
+
assertChromeInvariantForEverySession(crossListedLanguageNav, 'language');
|
|
165
|
+
});
|
|
166
|
+
it('points a containing sibling at its own version, not the shared page elsewhere', () => {
|
|
167
|
+
var _a, _b;
|
|
168
|
+
const { scopedNav } = getScopedNavForPath({
|
|
169
|
+
decoratedNav: crossListedVersionNav,
|
|
170
|
+
currentPath: '/shared',
|
|
171
|
+
});
|
|
172
|
+
const menu = (_a = filterWith(scopedNav, '/shared', 'v2', undefined).tabs[0]) === null || _a === void 0 ? void 0 : _a.menu;
|
|
173
|
+
expect((_b = menu === null || menu === void 0 ? void 0 : menu.find((item) => item.name === 'Engine')) === null || _b === void 0 ? void 0 : _b.href).toBe('/engine/v2/a');
|
|
174
|
+
});
|
|
175
|
+
});
|