@mintlify/common 1.0.1030 → 1.0.1032
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/mdx/plugins/remark/index.d.ts +1 -0
- package/dist/mdx/plugins/remark/index.js +1 -0
- package/dist/mdx/plugins/remark/remarkComponentIds.js +3 -2
- package/dist/mdx/plugins/remark/remarkValidateAccordions.d.ts +2 -0
- package/dist/mdx/plugins/remark/remarkValidateAccordions.js +29 -0
- package/dist/mdx/server-only/getMdx.js +2 -1
- package/dist/navigation/getScopedNavForPath.test.js +151 -2
- package/dist/navigation/scopeNavToPath.d.ts +2 -1
- package/dist/navigation/scopeNavToPath.js +44 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +2 -2
|
@@ -14,6 +14,7 @@ export * from './remarkSplitCodeGroup.js';
|
|
|
14
14
|
export * from './remarkSplitTabs.js';
|
|
15
15
|
export * from './remarkComponentIds.js';
|
|
16
16
|
export * from './remarkMdxExtractPanel.js';
|
|
17
|
+
export * from './remarkValidateAccordions.js';
|
|
17
18
|
export * from './remarkValidateSteps.js';
|
|
18
19
|
export * from './remarkValidateVisibility.js';
|
|
19
20
|
export * from './remarkValidateTabs.js';
|
|
@@ -14,6 +14,7 @@ export * from './remarkSplitCodeGroup.js';
|
|
|
14
14
|
export * from './remarkSplitTabs.js';
|
|
15
15
|
export * from './remarkComponentIds.js';
|
|
16
16
|
export * from './remarkMdxExtractPanel.js';
|
|
17
|
+
export * from './remarkValidateAccordions.js';
|
|
17
18
|
export * from './remarkValidateSteps.js';
|
|
18
19
|
export * from './remarkValidateVisibility.js';
|
|
19
20
|
export * from './remarkValidateTabs.js';
|
|
@@ -165,8 +165,9 @@ export const remarkComponentIds = (pageMetadata) => (tree) => {
|
|
|
165
165
|
if (hasId)
|
|
166
166
|
return;
|
|
167
167
|
const title = titleAttr.value;
|
|
168
|
-
const
|
|
169
|
-
accordionCounts.
|
|
168
|
+
const baseSlug = generateComponentId(title);
|
|
169
|
+
const count = (_a = accordionCounts.get(baseSlug)) !== null && _a !== void 0 ? _a : 0;
|
|
170
|
+
accordionCounts.set(baseSlug, count + 1);
|
|
170
171
|
node.attributes.push(createMdxJsxAttribute('id', generateComponentId(title, count)));
|
|
171
172
|
});
|
|
172
173
|
// Generate IDs for View components from their title.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { visit } from 'unist-util-visit';
|
|
2
|
+
import { generateComponentId } from './remarkComponentIds.js';
|
|
3
|
+
const findAttribute = (node, name) => node.attributes.find((attr) => attr.type === 'mdxJsxAttribute' && attr.name === name);
|
|
4
|
+
export const remarkValidateAccordions = () => (tree) => {
|
|
5
|
+
const seenSlugs = new Set();
|
|
6
|
+
const validate = (node) => {
|
|
7
|
+
var _a, _b;
|
|
8
|
+
if (node.name !== 'Accordion')
|
|
9
|
+
return;
|
|
10
|
+
const titleValue = (_a = findAttribute(node, 'title')) === null || _a === void 0 ? void 0 : _a.value;
|
|
11
|
+
if (titleValue != null && typeof titleValue !== 'string') {
|
|
12
|
+
console.warn('<Accordion> has a non-string title expression — deep linking is disabled for that accordion. Use a plain string title.');
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (!titleValue) {
|
|
16
|
+
console.warn('<Accordion> is missing a title — its content will not deep-link correctly. Add a descriptive title.');
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const idValue = (_b = findAttribute(node, 'id')) === null || _b === void 0 ? void 0 : _b.value;
|
|
20
|
+
const slug = typeof idValue === 'string' && idValue ? idValue : generateComponentId(titleValue);
|
|
21
|
+
if (seenSlugs.has(slug)) {
|
|
22
|
+
console.warn(`<Accordion title="${titleValue}"> duplicates another accordion title on this page — deep links and assistive technology may target the wrong accordion. Use unique titles.`);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
seenSlugs.add(slug);
|
|
26
|
+
};
|
|
27
|
+
visit(tree, 'mdxJsxFlowElement', validate);
|
|
28
|
+
visit(tree, 'mdxJsxTextElement', validate);
|
|
29
|
+
};
|
|
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
};
|
|
10
10
|
import { serialize } from '@mintlify/mdx/server';
|
|
11
11
|
import { getTailwindSelectors } from '../../css/tailwind.js';
|
|
12
|
-
import { getMDXOptions, remarkMdxRemoveJs, remarkExpandContent, remarkSplitCodeGroup, remarkSplitTabs, remarkValidateSteps, remarkValidateVisibility, remarkValidateTabs, } from '../../index.js';
|
|
12
|
+
import { getMDXOptions, remarkMdxRemoveJs, remarkExpandContent, remarkSplitCodeGroup, remarkSplitTabs, remarkValidateAccordions, remarkValidateSteps, remarkValidateVisibility, remarkValidateTabs, } from '../../index.js';
|
|
13
13
|
import { codeStylingToThemeOrThemes } from '../getCodeStyling.js';
|
|
14
14
|
import { preprocessCustomHeadingIds } from '../preprocessCustomHeadingIds.js';
|
|
15
15
|
import { replaceVariables } from '../replaceVariables.js';
|
|
@@ -36,6 +36,7 @@ export function getMdx(_a) {
|
|
|
36
36
|
remarkValidateSteps,
|
|
37
37
|
remarkValidateTabs,
|
|
38
38
|
remarkValidateVisibility,
|
|
39
|
+
remarkValidateAccordions,
|
|
39
40
|
...remarkPlugins,
|
|
40
41
|
];
|
|
41
42
|
if (pageType === 'pdf') {
|
|
@@ -87,12 +87,16 @@ function divisionSummary(result) {
|
|
|
87
87
|
function mapHrefs(map) {
|
|
88
88
|
return new Map([...map.entries()].map(([key, value]) => [key, value.href]));
|
|
89
89
|
}
|
|
90
|
-
function assertInvariantForEveryPath(nav) {
|
|
90
|
+
function assertInvariantForEveryPath(nav, includeProductVersionMetadata = false) {
|
|
91
91
|
const paths = getAllPathsInDecoratedNav(nav);
|
|
92
92
|
expect(paths.length).toBeGreaterThan(0);
|
|
93
93
|
for (const path of paths) {
|
|
94
94
|
const currentPath = `/${path.replace(/^\//, '')}`;
|
|
95
|
-
const scoped = getScopedNavForPath({
|
|
95
|
+
const scoped = getScopedNavForPath({
|
|
96
|
+
decoratedNav: nav,
|
|
97
|
+
currentPath,
|
|
98
|
+
includeProductVersionMetadata,
|
|
99
|
+
});
|
|
96
100
|
const full = filterWith(nav, currentPath, scoped.currentVersion, scoped.currentLanguage);
|
|
97
101
|
const rescoped = filterWith(scoped.scopedNav, currentPath, scoped.currentVersion, scoped.currentLanguage);
|
|
98
102
|
expect(rescoped.groupsOrPages, currentPath).toEqual(full.groupsOrPages);
|
|
@@ -132,4 +136,149 @@ describe(getScopedNavForPath, () => {
|
|
|
132
136
|
expect(serialized).not.toContain('/v1/es/guides/overview');
|
|
133
137
|
expect(serialized).toContain('/en/guides/new-in-v2');
|
|
134
138
|
});
|
|
139
|
+
describe('includeProductVersionMetadata', () => {
|
|
140
|
+
const productNav = {
|
|
141
|
+
products: [
|
|
142
|
+
{
|
|
143
|
+
product: 'Model Serving',
|
|
144
|
+
versions: [
|
|
145
|
+
{
|
|
146
|
+
version: '6.0',
|
|
147
|
+
default: true,
|
|
148
|
+
groups: [
|
|
149
|
+
{
|
|
150
|
+
group: 'Guides',
|
|
151
|
+
pages: [
|
|
152
|
+
{ title: 'Quickstart', href: '/serving/6.0/quickstart' },
|
|
153
|
+
{ title: 'Endpoints', href: '/serving/6.0/endpoints' },
|
|
154
|
+
],
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
version: '5.9',
|
|
160
|
+
groups: [
|
|
161
|
+
{
|
|
162
|
+
group: 'Guides',
|
|
163
|
+
pages: [{ title: 'Quickstart', href: '/serving/5.9/quickstart' }],
|
|
164
|
+
},
|
|
165
|
+
],
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
product: 'Workbench',
|
|
171
|
+
global: {
|
|
172
|
+
versions: [{ version: 'external-9.9', href: 'https://legacy.example.com' }],
|
|
173
|
+
},
|
|
174
|
+
versions: [
|
|
175
|
+
{
|
|
176
|
+
version: '3.2',
|
|
177
|
+
name: 'Workbench 3.2',
|
|
178
|
+
default: true,
|
|
179
|
+
groups: [
|
|
180
|
+
{ group: 'Guides', pages: [{ title: 'Setup', href: '/workbench/3.2/setup' }] },
|
|
181
|
+
],
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
version: '3.1',
|
|
185
|
+
groups: [
|
|
186
|
+
{ group: 'Guides', pages: [{ title: 'Setup', href: '/workbench/3.1/setup' }] },
|
|
187
|
+
],
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
version: '3.0-beta',
|
|
191
|
+
hidden: true,
|
|
192
|
+
groups: [
|
|
193
|
+
{ group: 'Guides', pages: [{ title: 'Setup', href: '/workbench/3.0/setup' }] },
|
|
194
|
+
],
|
|
195
|
+
},
|
|
196
|
+
],
|
|
197
|
+
},
|
|
198
|
+
],
|
|
199
|
+
};
|
|
200
|
+
const currentPath = '/serving/6.0/quickstart';
|
|
201
|
+
function findProduct(nav, name) {
|
|
202
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- structural nav traversal over the zod union types
|
|
203
|
+
const products = nav.products;
|
|
204
|
+
return products.find((product) => product.product === name);
|
|
205
|
+
}
|
|
206
|
+
it('drops sibling product versions by default', () => {
|
|
207
|
+
var _a;
|
|
208
|
+
const scoped = getScopedNavForPath({ decoratedNav: productNav, currentPath });
|
|
209
|
+
expect((_a = findProduct(scoped.scopedNav, 'Workbench')) === null || _a === void 0 ? void 0 : _a.versions).toBeUndefined();
|
|
210
|
+
});
|
|
211
|
+
it('keeps pageless version metadata on sibling product stubs when enabled', () => {
|
|
212
|
+
var _a;
|
|
213
|
+
const scoped = getScopedNavForPath({
|
|
214
|
+
decoratedNav: productNav,
|
|
215
|
+
currentPath,
|
|
216
|
+
includeProductVersionMetadata: true,
|
|
217
|
+
});
|
|
218
|
+
expect((_a = findProduct(scoped.scopedNav, 'Workbench')) === null || _a === void 0 ? void 0 : _a.versions).toEqual([
|
|
219
|
+
{ version: '3.2', name: 'Workbench 3.2' },
|
|
220
|
+
{ version: '3.1' },
|
|
221
|
+
]);
|
|
222
|
+
expect(JSON.stringify(scoped.scopedNav)).not.toContain('/workbench/3.1/setup');
|
|
223
|
+
expect(JSON.stringify(scoped.scopedNav)).not.toContain('external-9.9');
|
|
224
|
+
});
|
|
225
|
+
it('leaves the active product and jump maps unchanged when enabled', () => {
|
|
226
|
+
const scoped = getScopedNavForPath({ decoratedNav: productNav, currentPath });
|
|
227
|
+
const withMetadata = getScopedNavForPath({
|
|
228
|
+
decoratedNav: productNav,
|
|
229
|
+
currentPath,
|
|
230
|
+
includeProductVersionMetadata: true,
|
|
231
|
+
});
|
|
232
|
+
expect(findProduct(withMetadata.scopedNav, 'Model Serving')).toEqual(findProduct(scoped.scopedNav, 'Model Serving'));
|
|
233
|
+
expect(withMetadata.firstHrefInVersion).toEqual(scoped.firstHrefInVersion);
|
|
234
|
+
expect(withMetadata.firstHrefInLanguage).toEqual(scoped.firstHrefInLanguage);
|
|
235
|
+
expect(withMetadata.currentVersion).toBe(scoped.currentVersion);
|
|
236
|
+
});
|
|
237
|
+
it('filters identically to the full nav for every path when enabled', () => {
|
|
238
|
+
assertInvariantForEveryPath(multiDivisionNav, true);
|
|
239
|
+
assertInvariantForEveryPath(decoratedNavigationConfig, true);
|
|
240
|
+
});
|
|
241
|
+
it('changes nothing but the added metadata for every path', () => {
|
|
242
|
+
const paths = getAllPathsInDecoratedNav(productNav);
|
|
243
|
+
expect(paths.length).toBeGreaterThan(0);
|
|
244
|
+
for (const path of paths) {
|
|
245
|
+
const currentPath = `/${path.replace(/^\//, '')}`;
|
|
246
|
+
const scopedOff = getScopedNavForPath({ decoratedNav: productNav, currentPath });
|
|
247
|
+
const scopedOn = getScopedNavForPath({
|
|
248
|
+
decoratedNav: productNav,
|
|
249
|
+
currentPath,
|
|
250
|
+
includeProductVersionMetadata: true,
|
|
251
|
+
});
|
|
252
|
+
expect(stripMetadataVersions(scopedOn.scopedNav), currentPath).toEqual(scopedOff.scopedNav);
|
|
253
|
+
expect(scopedOn.firstHrefInVersion, currentPath).toEqual(scopedOff.firstHrefInVersion);
|
|
254
|
+
expect(scopedOn.firstHrefInLanguage, currentPath).toEqual(scopedOff.firstHrefInLanguage);
|
|
255
|
+
expect(scopedOn.currentVersion, currentPath).toBe(scopedOff.currentVersion);
|
|
256
|
+
expect(scopedOn.currentLanguage, currentPath).toBe(scopedOff.currentLanguage);
|
|
257
|
+
const filteredOff = filterWith(scopedOff.scopedNav, currentPath, scopedOff.currentVersion, scopedOff.currentLanguage);
|
|
258
|
+
const filteredOn = filterWith(scopedOn.scopedNav, currentPath, scopedOn.currentVersion, scopedOn.currentLanguage);
|
|
259
|
+
expect(divisionSummary(filteredOn), currentPath).toEqual(divisionSummary(filteredOff));
|
|
260
|
+
expect(filteredOn.groupsOrPages, currentPath).toEqual(filteredOff.groupsOrPages);
|
|
261
|
+
expect(mapHrefs(filteredOn.firstHrefInVersion), currentPath).toEqual(mapHrefs(filteredOff.firstHrefInVersion));
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
});
|
|
135
265
|
});
|
|
266
|
+
function stripMetadataVersions(value) {
|
|
267
|
+
if (Array.isArray(value))
|
|
268
|
+
return value.map(stripMetadataVersions);
|
|
269
|
+
if (typeof value !== 'object' || value === null)
|
|
270
|
+
return value;
|
|
271
|
+
const entries = Object.entries(value).flatMap(([key, entry]) => {
|
|
272
|
+
if (key === 'versions' &&
|
|
273
|
+
Array.isArray(entry) &&
|
|
274
|
+
entry.every((version) => typeof version === 'object' &&
|
|
275
|
+
version !== null &&
|
|
276
|
+
!('pages' in version) &&
|
|
277
|
+
!('groups' in version) &&
|
|
278
|
+
!('href' in version))) {
|
|
279
|
+
return [];
|
|
280
|
+
}
|
|
281
|
+
return [[key, stripMetadataVersions(entry)]];
|
|
282
|
+
});
|
|
283
|
+
return Object.fromEntries(entries);
|
|
284
|
+
}
|
|
@@ -10,9 +10,10 @@ export type ScopedNavForPath = {
|
|
|
10
10
|
currentVersion: string | undefined;
|
|
11
11
|
currentLanguage: LocaleType | undefined;
|
|
12
12
|
};
|
|
13
|
-
export declare function getScopedNavForPath({ decoratedNav, currentPath, userGroups, isPreview, }: {
|
|
13
|
+
export declare function getScopedNavForPath({ decoratedNav, currentPath, userGroups, isPreview, includeProductVersionMetadata, }: {
|
|
14
14
|
decoratedNav: DecoratedNavigationConfig;
|
|
15
15
|
currentPath: string;
|
|
16
16
|
userGroups?: Set<string>;
|
|
17
17
|
isPreview?: boolean;
|
|
18
|
+
includeProductVersionMetadata?: boolean;
|
|
18
19
|
}): ScopedNavForPath;
|
|
@@ -357,6 +357,40 @@ function scopeDivisionArray(entries, key, ctx) {
|
|
|
357
357
|
return stubDivision(entry, key, ctx);
|
|
358
358
|
});
|
|
359
359
|
}
|
|
360
|
+
function collectProductVersionMetadata(node, out, seen) {
|
|
361
|
+
if (Array.isArray(node)) {
|
|
362
|
+
for (const entry of node) {
|
|
363
|
+
collectProductVersionMetadata(entry, out, seen);
|
|
364
|
+
}
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
if (!isNavNode(node))
|
|
368
|
+
return;
|
|
369
|
+
for (const [key, value] of Object.entries(node)) {
|
|
370
|
+
// versions under a nested product belong to that product, and global
|
|
371
|
+
// holds external links never attributed to a product by the consumer
|
|
372
|
+
if (key === 'products' || key === 'global')
|
|
373
|
+
continue;
|
|
374
|
+
if (key === 'versions' && Array.isArray(value)) {
|
|
375
|
+
for (const version of value) {
|
|
376
|
+
if (!isNavNode(version))
|
|
377
|
+
continue;
|
|
378
|
+
if (typeof version.version !== 'string' || version.hidden === true)
|
|
379
|
+
continue;
|
|
380
|
+
if (seen.has(version.version))
|
|
381
|
+
continue;
|
|
382
|
+
seen.add(version.version);
|
|
383
|
+
const metadata = { version: version.version };
|
|
384
|
+
if (typeof version.name === 'string')
|
|
385
|
+
metadata.name = version.name;
|
|
386
|
+
out.push(metadata);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
if (Array.isArray(value) || isNavNode(value)) {
|
|
390
|
+
collectProductVersionMetadata(value, out, seen);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
360
394
|
function stubProduct(product, ctx) {
|
|
361
395
|
if (typeof product.href === 'string')
|
|
362
396
|
return product;
|
|
@@ -373,6 +407,14 @@ function stubProduct(product, ctx) {
|
|
|
373
407
|
stub[entryKey] = value;
|
|
374
408
|
}
|
|
375
409
|
}
|
|
410
|
+
if (ctx.includeProductVersionMetadata) {
|
|
411
|
+
const versionMetadata = [];
|
|
412
|
+
collectProductVersionMetadata(product, versionMetadata, new Set());
|
|
413
|
+
// pageless version entries so the search version filter can list a
|
|
414
|
+
// non-active product's versions; invisible to sidebar/dict consumers
|
|
415
|
+
if (versionMetadata.length)
|
|
416
|
+
stub.versions = versionMetadata;
|
|
417
|
+
}
|
|
376
418
|
stub.pages = target.isRaw
|
|
377
419
|
? [target.href]
|
|
378
420
|
: [makeStubPage(typeof product.product === 'string' ? product.product : '', target)];
|
|
@@ -433,7 +475,7 @@ export function scopeDocsConfigNavToPath(docsConfig, currentPath) {
|
|
|
433
475
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- structural nav traversal over the zod union types
|
|
434
476
|
navigation: scopeNode(docsConfig.navigation, { currentPath }) });
|
|
435
477
|
}
|
|
436
|
-
export function getScopedNavForPath({ decoratedNav, currentPath, userGroups = new Set(), isPreview = false, }) {
|
|
478
|
+
export function getScopedNavForPath({ decoratedNav, currentPath, userGroups = new Set(), isPreview = false, includeProductVersionMetadata = false, }) {
|
|
437
479
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
438
480
|
const containingProductNames = new Set();
|
|
439
481
|
collectContainingProductNames(
|
|
@@ -489,6 +531,7 @@ export function getScopedNavForPath({ decoratedNav, currentPath, userGroups = ne
|
|
|
489
531
|
userGroups,
|
|
490
532
|
isPreview,
|
|
491
533
|
skipVersionLanguageStubs: productAmbiguous,
|
|
534
|
+
includeProductVersionMetadata,
|
|
492
535
|
}
|
|
493
536
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- structural nav traversal over the zod union types
|
|
494
537
|
);
|