@fern-api/fdr-sdk 1.2.42-0c024f5b0d → 1.2.42-1fb0ba4870
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/js/navigation/ledger-root-builder.js +64 -19
- package/dist/js/navigation/ledger-root-builder.js.map +1 -1
- package/dist/js/navigation/ledger-root-builder.mjs +64 -19
- package/dist/js/navigation/ledger-root-builder.mjs.map +1 -1
- package/dist/navigation/__test__/ledger-root-builder.metadataPreservation.test.js +109 -4
- package/dist/navigation/__test__/ledger-root-builder.metadataPreservation.test.js.map +1 -1
- package/dist/navigation/__test__/ledger-root-builder.rootChildOrder.test.js +102 -0
- package/dist/navigation/__test__/ledger-root-builder.rootChildOrder.test.js.map +1 -1
- package/dist/navigation/__test__/ledger-root-builder.skipSlugSiblingSection.test.d.ts +2 -0
- package/dist/navigation/__test__/ledger-root-builder.skipSlugSiblingSection.test.d.ts.map +1 -0
- package/dist/navigation/__test__/ledger-root-builder.skipSlugSiblingSection.test.js +256 -0
- package/dist/navigation/__test__/ledger-root-builder.skipSlugSiblingSection.test.js.map +1 -0
- package/dist/navigation/ledger-root-builder.d.ts.map +1 -1
- package/dist/navigation/ledger-root-builder.js +100 -21
- package/dist/navigation/ledger-root-builder.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/navigation/__test__/ledger-root-builder.skipSlugSiblingSection.test.d.ts +2 -0
- package/dist/types/navigation/__test__/ledger-root-builder.skipSlugSiblingSection.test.d.ts.map +1 -0
- package/dist/types/navigation/ledger-root-builder.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import * as FernNavigation from "../index.js";
|
|
3
|
+
import { buildFullRootFromSegments } from "../ledger-root-builder.js";
|
|
4
|
+
/**
|
|
5
|
+
* Tests for the case where a section with skipUrlSlug (section="") sits inside
|
|
6
|
+
* a sidebarGroup alongside sibling sections. The `childIndex` metadata field
|
|
7
|
+
* (set by `walkNavSubTrees` on the write side) distinguishes these from true
|
|
8
|
+
* root-section wrappers (direct sidebarRoot children with no childIndex).
|
|
9
|
+
*
|
|
10
|
+
* Without the fix, the builder treats ANY section="" segment as a root wrapper,
|
|
11
|
+
* incorrectly nesting all depth-0 siblings under it and producing spurious
|
|
12
|
+
* breadcrumb entries (e.g. "Introduction > Echo" instead of just "Echo").
|
|
13
|
+
*
|
|
14
|
+
* Real-world repro: mangopay-ledger-test, where the "Introduction" section
|
|
15
|
+
* has skipUrlSlug (slug == tab slug) and shares a sidebarGroup with ~10 peer
|
|
16
|
+
* sections (Users, Echo, SCA, Payouts, …).
|
|
17
|
+
*/
|
|
18
|
+
function detail(opts) {
|
|
19
|
+
return {
|
|
20
|
+
id: opts.id,
|
|
21
|
+
displayName: opts.name,
|
|
22
|
+
icon: null,
|
|
23
|
+
sortOrder: 0,
|
|
24
|
+
hidden: false,
|
|
25
|
+
viewers: [],
|
|
26
|
+
orphaned: false,
|
|
27
|
+
featureFlags: [],
|
|
28
|
+
metadata: { slug: opts.slug, default: false, pointsTo: opts.pointsTo }
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function seg(opts) {
|
|
32
|
+
return {
|
|
33
|
+
segmentId: opts.segmentHash,
|
|
34
|
+
segmentHash: opts.segmentHash,
|
|
35
|
+
section: opts.section,
|
|
36
|
+
locale: "en",
|
|
37
|
+
sortOrder: opts.sortOrder ?? 0,
|
|
38
|
+
hidden: false,
|
|
39
|
+
metadata: {
|
|
40
|
+
type: opts.type,
|
|
41
|
+
...(opts.title != null ? { title: opts.title } : {}),
|
|
42
|
+
...(opts.childIndex != null ? { childIndex: opts.childIndex } : {})
|
|
43
|
+
},
|
|
44
|
+
product: null,
|
|
45
|
+
version: null,
|
|
46
|
+
variant: null,
|
|
47
|
+
tab: opts.tab ?? null
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function markdownRoute(fullPath, title, pageId) {
|
|
51
|
+
return { type: "markdown", fullPath, hidden: false, metadata: { title, pageId } };
|
|
52
|
+
}
|
|
53
|
+
function buildRoot(opts) {
|
|
54
|
+
return buildFullRootFromSegments({
|
|
55
|
+
basePath: opts.basePath,
|
|
56
|
+
title: "Test",
|
|
57
|
+
segments: opts.segments,
|
|
58
|
+
navBySegment: opts.navBySegment
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function findSectionNodes(root) {
|
|
62
|
+
const sections = [];
|
|
63
|
+
FernNavigation.traverseDF(root, (node) => {
|
|
64
|
+
if (node.type === "section") {
|
|
65
|
+
sections.push(node);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
return sections;
|
|
69
|
+
}
|
|
70
|
+
function findSidebarRootChildren(root) {
|
|
71
|
+
let sidebarChildren = [];
|
|
72
|
+
FernNavigation.traverseDF(root, (node) => {
|
|
73
|
+
if (node.type === "sidebarRoot" && sidebarChildren.length === 0) {
|
|
74
|
+
sidebarChildren = [...node.children];
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
return sidebarChildren;
|
|
78
|
+
}
|
|
79
|
+
describe("buildFullRootFromSegments — skipUrlSlug sibling sections are NOT adopted as root-section children", () => {
|
|
80
|
+
// Reproduces the mangopay-ledger-test bug: "Introduction" (section="",
|
|
81
|
+
// childIndex=0) shares a sidebarGroup with "Echo" and "Users".
|
|
82
|
+
// Without the fix, "Echo" and "Users" are incorrectly nested inside
|
|
83
|
+
// "Introduction", adding a spurious "Introduction" breadcrumb to every
|
|
84
|
+
// page under Echo and Users.
|
|
85
|
+
const tab = detail({
|
|
86
|
+
id: "t-guides",
|
|
87
|
+
name: "Guides",
|
|
88
|
+
slug: "guides",
|
|
89
|
+
pointsTo: "guides/e-wallet-system"
|
|
90
|
+
});
|
|
91
|
+
const tabRoot = seg({
|
|
92
|
+
segmentHash: "s-tabroot",
|
|
93
|
+
section: "",
|
|
94
|
+
type: "tabRoot",
|
|
95
|
+
tab
|
|
96
|
+
});
|
|
97
|
+
// "Introduction" section with skipUrlSlug — its slug matches the tab slug,
|
|
98
|
+
// so the write side assigns section="" with childIndex=0 (from walkNavSubTrees).
|
|
99
|
+
const introSection = seg({
|
|
100
|
+
segmentHash: "s-intro",
|
|
101
|
+
section: "",
|
|
102
|
+
type: "section",
|
|
103
|
+
title: "Introduction",
|
|
104
|
+
sortOrder: 1,
|
|
105
|
+
childIndex: 0,
|
|
106
|
+
tab
|
|
107
|
+
});
|
|
108
|
+
// Sibling sections — these should NOT be nested inside Introduction.
|
|
109
|
+
const echoSection = seg({
|
|
110
|
+
segmentHash: "s-echo",
|
|
111
|
+
section: "echo",
|
|
112
|
+
type: "section",
|
|
113
|
+
title: "Echo",
|
|
114
|
+
sortOrder: 2,
|
|
115
|
+
childIndex: 1,
|
|
116
|
+
tab
|
|
117
|
+
});
|
|
118
|
+
const usersSection = seg({
|
|
119
|
+
segmentHash: "s-users",
|
|
120
|
+
section: "users",
|
|
121
|
+
type: "section",
|
|
122
|
+
title: "Users",
|
|
123
|
+
sortOrder: 3,
|
|
124
|
+
childIndex: 2,
|
|
125
|
+
tab
|
|
126
|
+
});
|
|
127
|
+
const segments = [tabRoot, introSection, echoSection, usersSection];
|
|
128
|
+
const navBySegment = new Map([
|
|
129
|
+
["s-tabroot", []],
|
|
130
|
+
["s-intro", [markdownRoute("guides/e-wallet-system", "E-wallet system", "pg-ewallet")]],
|
|
131
|
+
[
|
|
132
|
+
"s-echo",
|
|
133
|
+
[
|
|
134
|
+
markdownRoute("guides/echo", "Mangopay Echo", "pg-echo"),
|
|
135
|
+
markdownRoute("guides/echo/reconciliation", "Reconciliation", "pg-recon")
|
|
136
|
+
]
|
|
137
|
+
],
|
|
138
|
+
["s-users", [markdownRoute("guides/users/types", "Types", "pg-user-types")]]
|
|
139
|
+
]);
|
|
140
|
+
it("sections with childIndex remain siblings, not nested under section='' segment", () => {
|
|
141
|
+
const root = buildRoot({ basePath: "", segments, navBySegment });
|
|
142
|
+
const sections = findSectionNodes(root);
|
|
143
|
+
const introSec = sections.find((s) => s.title === "Introduction");
|
|
144
|
+
const echoSec = sections.find((s) => s.title === "Echo");
|
|
145
|
+
const usersSec = sections.find((s) => s.title === "Users");
|
|
146
|
+
expect(introSec).toBeDefined();
|
|
147
|
+
expect(echoSec).toBeDefined();
|
|
148
|
+
expect(usersSec).toBeDefined();
|
|
149
|
+
// Echo and Users must NOT be children of Introduction.
|
|
150
|
+
const introChildren = (introSec?.children ?? [])
|
|
151
|
+
.filter((c) => c.type === "section")
|
|
152
|
+
.map((c) => c.title);
|
|
153
|
+
expect(introChildren).not.toContain("Echo");
|
|
154
|
+
expect(introChildren).not.toContain("Users");
|
|
155
|
+
// All three should be at the sidebar root level (possibly inside sidebarGroups).
|
|
156
|
+
const sidebarChildren = findSidebarRootChildren(root);
|
|
157
|
+
const topLevelTitles = [];
|
|
158
|
+
for (const child of sidebarChildren) {
|
|
159
|
+
if (child.type === "section") {
|
|
160
|
+
topLevelTitles.push(child.title);
|
|
161
|
+
}
|
|
162
|
+
else if (child.type === "sidebarGroup") {
|
|
163
|
+
for (const gc of child.children) {
|
|
164
|
+
if (gc.type === "section") {
|
|
165
|
+
topLevelTitles.push(gc.title);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
expect(topLevelTitles).toContain("Introduction");
|
|
171
|
+
expect(topLevelTitles).toContain("Echo");
|
|
172
|
+
expect(topLevelTitles).toContain("Users");
|
|
173
|
+
});
|
|
174
|
+
it("breadcrumb for a page inside Echo does NOT include Introduction", () => {
|
|
175
|
+
const root = buildRoot({ basePath: "", segments, navBySegment });
|
|
176
|
+
FernNavigation.utils.mutableUpdatePointsTo(root);
|
|
177
|
+
const found = FernNavigation.utils.findNode(root, FernNavigation.Slug("guides/echo"));
|
|
178
|
+
expect(found.type).toBe("found");
|
|
179
|
+
if (found.type !== "found") {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const breadcrumbTitles = found.breadcrumb.map((b) => b.title);
|
|
183
|
+
expect(breadcrumbTitles).toContain("Echo");
|
|
184
|
+
expect(breadcrumbTitles).not.toContain("Introduction");
|
|
185
|
+
});
|
|
186
|
+
it("breadcrumb for a page inside Users does NOT include Introduction", () => {
|
|
187
|
+
const root = buildRoot({ basePath: "", segments, navBySegment });
|
|
188
|
+
FernNavigation.utils.mutableUpdatePointsTo(root);
|
|
189
|
+
const found = FernNavigation.utils.findNode(root, FernNavigation.Slug("guides/users/types"));
|
|
190
|
+
expect(found.type).toBe("found");
|
|
191
|
+
if (found.type !== "found") {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const breadcrumbTitles = found.breadcrumb.map((b) => b.title);
|
|
195
|
+
expect(breadcrumbTitles).toContain("Users");
|
|
196
|
+
expect(breadcrumbTitles).not.toContain("Introduction");
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
describe("buildFullRootFromSegments — true root-section wrappers (no childIndex) still work", () => {
|
|
200
|
+
// Regression guard: when a section has section="" WITHOUT childIndex,
|
|
201
|
+
// it IS a true root wrapper and should adopt depth-0 children.
|
|
202
|
+
const tab = detail({
|
|
203
|
+
id: "t-docs",
|
|
204
|
+
name: "Docs",
|
|
205
|
+
slug: "docs",
|
|
206
|
+
pointsTo: "docs/overview/intro"
|
|
207
|
+
});
|
|
208
|
+
it("adopts depth-0 children when childIndex is absent", () => {
|
|
209
|
+
const root = buildRoot({
|
|
210
|
+
basePath: "",
|
|
211
|
+
segments: [
|
|
212
|
+
// True root section wrapper (no childIndex)
|
|
213
|
+
seg({
|
|
214
|
+
segmentHash: "s-root",
|
|
215
|
+
section: "",
|
|
216
|
+
type: "section",
|
|
217
|
+
title: "Overview",
|
|
218
|
+
tab
|
|
219
|
+
}),
|
|
220
|
+
seg({
|
|
221
|
+
segmentHash: "s-gs",
|
|
222
|
+
section: "get-started",
|
|
223
|
+
type: "section",
|
|
224
|
+
title: "Get Started",
|
|
225
|
+
sortOrder: 1,
|
|
226
|
+
tab
|
|
227
|
+
}),
|
|
228
|
+
seg({
|
|
229
|
+
segmentHash: "s-adv",
|
|
230
|
+
section: "advanced",
|
|
231
|
+
type: "section",
|
|
232
|
+
title: "Advanced",
|
|
233
|
+
sortOrder: 2,
|
|
234
|
+
tab
|
|
235
|
+
})
|
|
236
|
+
],
|
|
237
|
+
navBySegment: new Map([
|
|
238
|
+
["s-root", [markdownRoute("docs/overview/intro", "Intro", "pg-intro")]],
|
|
239
|
+
["s-gs", [markdownRoute("docs/overview/get-started/setup", "Setup", "pg-setup")]],
|
|
240
|
+
["s-adv", [markdownRoute("docs/overview/advanced/tips", "Tips", "pg-tips")]]
|
|
241
|
+
])
|
|
242
|
+
});
|
|
243
|
+
const sections = findSectionNodes(root);
|
|
244
|
+
const overviewSec = sections.find((s) => s.title === "Overview");
|
|
245
|
+
expect(overviewSec).toBeDefined();
|
|
246
|
+
// Child sections should be nested under Overview (root wrapper behavior)
|
|
247
|
+
const childTitles = (overviewSec?.children ?? [])
|
|
248
|
+
.filter((c) => c.type === "section")
|
|
249
|
+
.map((c) => c.title);
|
|
250
|
+
expect(childTitles).toContain("Get Started");
|
|
251
|
+
expect(childTitles).toContain("Advanced");
|
|
252
|
+
// 3 total sections (Overview + Get Started + Advanced), not duplicated
|
|
253
|
+
expect(sections.length).toBe(3);
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
//# sourceMappingURL=ledger-root-builder.skipSlugSiblingSection.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ledger-root-builder.skipSlugSiblingSection.test.js","sourceRoot":"","sources":["../../../src/navigation/__test__/ledger-root-builder.skipSlugSiblingSection.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ledger-root-builder.d.ts","sourceRoot":"","sources":["../../src/navigation/ledger-root-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,uBAAuB,EAAE,MAAM,wCAAwC,CAAC;AACnG,OAAO,KAAK,cAAc,MAAM,YAAY,CAAC;AAG7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,KAAK,OAAO,GAAG,uBAAuB,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;AA6B9C,MAAM,WAAW,gBAAgB;IAC7B,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;IACjB,yGAAyG;IACzG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,6DAA6D;IAC7D,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IACtC;;;;;;;;OAQG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;CACpC;AAID;;;;;;GAMG;AACH,UAAU,YAAY;IAClB,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,cAAc,CAAC,MAAM,CAAC;IAC/C,kFAAkF;IAClF,WAAW,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,cAAc,CAAC,IAAI,CAAC;CAC9D;AAED,2CAA2C;AAC3C,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,CAuBjE;
|
|
1
|
+
{"version":3,"file":"ledger-root-builder.d.ts","sourceRoot":"","sources":["../../src/navigation/ledger-root-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,uBAAuB,EAAE,MAAM,wCAAwC,CAAC;AACnG,OAAO,KAAK,cAAc,MAAM,YAAY,CAAC;AAG7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,KAAK,OAAO,GAAG,uBAAuB,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;AA6B9C,MAAM,WAAW,gBAAgB;IAC7B,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;IACjB,yGAAyG;IACzG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,6DAA6D;IAC7D,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IACtC;;;;;;;;OAQG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;CACpC;AAID;;;;;;GAMG;AACH,UAAU,YAAY;IAClB,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,cAAc,CAAC,MAAM,CAAC;IAC/C,kFAAkF;IAClF,WAAW,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,cAAc,CAAC,IAAI,CAAC;CAC9D;AAED,2CAA2C;AAC3C,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,CAuBjE;AAoRD;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GACjB,cAAc,CAAC,YAAY,GAC3B,cAAc,CAAC,WAAW,GAC1B,cAAc,CAAC,aAAa,GAC5B,cAAc,CAAC,QAAQ,GACvB,cAAc,CAAC,WAAW,CAAC;AAOjC;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACnC,KAAK,EAAE,QAAQ,EACf,QAAQ,EAAE,MAAM,EAChB,sBAAsB,EAAE,MAAM,GAC/B,WAAW,GAAG,SAAS,CAGzB;AA+KD;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACtC,MAAM,EAAE,QAAQ,EAAE,EAClB,QAAQ,EAAE,MAAM,EAChB,sBAAsB,EAAE,MAAM,GAC/B,WAAW,EAAE,CAKf;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,MAAM,GAAG,SAAS,CASxF;AAiWD;;;;;;GAMG;AACH,2CAA2C;AAC3C,wBAAgB,kBAAkB,CAC9B,GAAG,EAAE,YAAY,EACjB,SAAS,EAAE,WAAW,EAAE,EACxB,MAAM,EAAE,QAAQ,EAAE,GACnB,cAAc,CAAC,eAAe,EAAE,CAsElC;AA8oBD;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,gBAAgB,GAAG,cAAc,CAAC,QAAQ,CAmF5F"}
|
|
@@ -60,6 +60,41 @@ function metaStr(metadata, key) {
|
|
|
60
60
|
}
|
|
61
61
|
return undefined;
|
|
62
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* V1 availability values stored in ledger metadata are lowercase (e.g. "deprecated"),
|
|
65
|
+
* but the latest Availability type uses PascalCase (e.g. "Deprecated"). This map
|
|
66
|
+
* normalises both formats so the badge component can look up display names correctly.
|
|
67
|
+
*/
|
|
68
|
+
const AVAILABILITY_LOOKUP = {
|
|
69
|
+
// V1 lowercase values (stored by docsPublishTransform from V1 navigation tree)
|
|
70
|
+
alpha: FernNavigation.Availability.Alpha,
|
|
71
|
+
stable: FernNavigation.Availability.Stable,
|
|
72
|
+
"generally-available": FernNavigation.Availability.GenerallyAvailable,
|
|
73
|
+
"in-development": FernNavigation.Availability.InDevelopment,
|
|
74
|
+
"pre-release": FernNavigation.Availability.PreRelease,
|
|
75
|
+
deprecated: FernNavigation.Availability.Deprecated,
|
|
76
|
+
beta: FernNavigation.Availability.Beta,
|
|
77
|
+
preview: FernNavigation.Availability.Preview,
|
|
78
|
+
legacy: FernNavigation.Availability.Legacy,
|
|
79
|
+
// Latest PascalCase values (pass-through)
|
|
80
|
+
Alpha: FernNavigation.Availability.Alpha,
|
|
81
|
+
Stable: FernNavigation.Availability.Stable,
|
|
82
|
+
GenerallyAvailable: FernNavigation.Availability.GenerallyAvailable,
|
|
83
|
+
InDevelopment: FernNavigation.Availability.InDevelopment,
|
|
84
|
+
PreRelease: FernNavigation.Availability.PreRelease,
|
|
85
|
+
Deprecated: FernNavigation.Availability.Deprecated,
|
|
86
|
+
Beta: FernNavigation.Availability.Beta,
|
|
87
|
+
Preview: FernNavigation.Availability.Preview,
|
|
88
|
+
Legacy: FernNavigation.Availability.Legacy
|
|
89
|
+
};
|
|
90
|
+
/** Read an availability field from metadata, converting V1 lowercase to latest PascalCase. */
|
|
91
|
+
function metaAvailability(metadata) {
|
|
92
|
+
const raw = metaStr(metadata, "availability");
|
|
93
|
+
if (raw == null) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
return AVAILABILITY_LOOKUP[raw];
|
|
97
|
+
}
|
|
63
98
|
function metaBool(metadata, key) {
|
|
64
99
|
if (metadata != null && typeof metadata === "object" && key in metadata) {
|
|
65
100
|
const v = metadata[key];
|
|
@@ -198,7 +233,7 @@ function artifactToNode(ctx, route) {
|
|
|
198
233
|
}),
|
|
199
234
|
pageId: FernNavigation.PageId(pageId),
|
|
200
235
|
noindex: metaBool(md, "noindex"),
|
|
201
|
-
availability:
|
|
236
|
+
availability: metaAvailability(md)
|
|
202
237
|
};
|
|
203
238
|
return node;
|
|
204
239
|
}
|
|
@@ -269,7 +304,7 @@ function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId) {
|
|
|
269
304
|
endpointId: FernNavigation.EndpointId(endpointId),
|
|
270
305
|
apiDefinitionId,
|
|
271
306
|
isResponseStream: metaBool(md, "isResponseStream"),
|
|
272
|
-
availability:
|
|
307
|
+
availability: metaAvailability(md),
|
|
273
308
|
playground: undefined
|
|
274
309
|
};
|
|
275
310
|
}
|
|
@@ -285,7 +320,7 @@ function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId) {
|
|
|
285
320
|
method: method,
|
|
286
321
|
webhookId: FernNavigation.WebhookId(webhookId),
|
|
287
322
|
apiDefinitionId,
|
|
288
|
-
availability:
|
|
323
|
+
availability: metaAvailability(md)
|
|
289
324
|
};
|
|
290
325
|
}
|
|
291
326
|
if (route.type === "asyncapi") {
|
|
@@ -298,7 +333,7 @@ function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId) {
|
|
|
298
333
|
...meta,
|
|
299
334
|
webSocketId: FernNavigation.WebSocketId(webSocketId),
|
|
300
335
|
apiDefinitionId,
|
|
301
|
-
availability:
|
|
336
|
+
availability: metaAvailability(md),
|
|
302
337
|
playground: undefined
|
|
303
338
|
};
|
|
304
339
|
}
|
|
@@ -314,7 +349,7 @@ function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId) {
|
|
|
314
349
|
method: method,
|
|
315
350
|
grpcId: FernNavigation.GrpcId(grpcId),
|
|
316
351
|
apiDefinitionId,
|
|
317
|
-
availability:
|
|
352
|
+
availability: metaAvailability(md)
|
|
318
353
|
};
|
|
319
354
|
}
|
|
320
355
|
if (route.type === "graphql") {
|
|
@@ -330,7 +365,7 @@ function apiLeafNodeFromNavRouteInternal(ctx, route, segmentApiDefinitionId) {
|
|
|
330
365
|
graphqlOperationId: FernNavigation.GraphQlOperationId(graphqlOperationId),
|
|
331
366
|
graphqlOperationIds: undefined,
|
|
332
367
|
apiDefinitionId,
|
|
333
|
-
availability:
|
|
368
|
+
availability: metaAvailability(md),
|
|
334
369
|
playground: undefined
|
|
335
370
|
};
|
|
336
371
|
}
|
|
@@ -597,7 +632,7 @@ function sectionNode(ctx, scoped, sectionChildren, scopePrefix) {
|
|
|
597
632
|
noindex: metaBool(overview?.metadata, "noindex") ?? metaBool(seg.metadata, "noindex"),
|
|
598
633
|
collapsible: metaBool(seg.metadata, "collapsible") ?? (metaCollapsed(seg.metadata) === true ? true : undefined),
|
|
599
634
|
collapsedByDefault: metaBool(seg.metadata, "collapsedByDefault") ?? (metaCollapsed(seg.metadata) === true ? true : undefined),
|
|
600
|
-
availability:
|
|
635
|
+
availability: metaAvailability(seg.metadata),
|
|
601
636
|
pointsTo: metaPointsTo != null ? pointsToSlug(metaPointsTo) : undefined,
|
|
602
637
|
children: mergeChildrenByPosition(ctx, nav, sectionChildren)
|
|
603
638
|
};
|
|
@@ -686,7 +721,7 @@ function apiPackageChildNode(ctx, scoped, scopeSegs, parentApiDefinitionId, scop
|
|
|
686
721
|
featureFlags: metaFeatureFlags(seg.metadata)
|
|
687
722
|
}),
|
|
688
723
|
apiDefinitionId: FernNavigation.ApiDefinitionId(apiDefinitionId),
|
|
689
|
-
availability:
|
|
724
|
+
availability: metaAvailability(seg.metadata),
|
|
690
725
|
overviewPageId: overviewPageId != null ? FernNavigation.PageId(overviewPageId) : undefined,
|
|
691
726
|
noindex: metaBool(overview?.metadata, "noindex") ?? metaBool(seg.metadata, "noindex"),
|
|
692
727
|
pointsTo: metaPointsTo != null ? pointsToSlug(metaPointsTo) : undefined,
|
|
@@ -796,7 +831,7 @@ function apiReferenceNode(ctx, scoped, scopeSegs, scopePrefix) {
|
|
|
796
831
|
featureFlags: metaFeatureFlags(seg.metadata)
|
|
797
832
|
}),
|
|
798
833
|
apiDefinitionId: FernNavigation.ApiDefinitionId(apiDefinitionId),
|
|
799
|
-
availability:
|
|
834
|
+
availability: metaAvailability(seg.metadata),
|
|
800
835
|
overviewPageId: overviewPageId != null ? FernNavigation.PageId(overviewPageId) : undefined,
|
|
801
836
|
noindex: metaBool(overview?.metadata, "noindex") ?? metaBool(seg.metadata, "noindex"),
|
|
802
837
|
paginated: true,
|
|
@@ -1055,12 +1090,19 @@ function buildSectionTree(ctx, scopeSegs, parentPath, scopePrefix, changelogScop
|
|
|
1055
1090
|
function computeSiblingSortBoundaries(ordered) {
|
|
1056
1091
|
const result = new Map();
|
|
1057
1092
|
// Collect root-level sections grouped by their section path.
|
|
1093
|
+
// Sections with sec==="" (skip-slug sections) are included: when multiple
|
|
1094
|
+
// skip-slug sections exist at the root, they share path "" and need
|
|
1095
|
+
// boundaries so each only adopts its own children.
|
|
1058
1096
|
const sectionPaths = new Set(ordered.map((s) => s.seg.section));
|
|
1059
1097
|
const rootSections = [];
|
|
1060
1098
|
for (const s of ordered) {
|
|
1061
1099
|
const type = metaStr(s.seg.metadata, "type");
|
|
1062
1100
|
const sec = s.seg.section;
|
|
1063
|
-
if (type !== "section"
|
|
1101
|
+
if (type !== "section") {
|
|
1102
|
+
continue;
|
|
1103
|
+
}
|
|
1104
|
+
if (sec === "") {
|
|
1105
|
+
rootSections.push(s);
|
|
1064
1106
|
continue;
|
|
1065
1107
|
}
|
|
1066
1108
|
const parent = parentSectionPath(sec);
|
|
@@ -1109,6 +1151,17 @@ function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePre
|
|
|
1109
1151
|
// segments. Both index into the SAME child list at write time, so they
|
|
1110
1152
|
// interleave directly (e.g. [page 0, page 1, section 2…15, page 16, 17]).
|
|
1111
1153
|
const annotated = [];
|
|
1154
|
+
// ── Sibling section ownership ────────────────────────────────────────
|
|
1155
|
+
//
|
|
1156
|
+
// Multiple root-level sections can share the same section path (e.g.
|
|
1157
|
+
// three sections all with path equal to the version slug). When this
|
|
1158
|
+
// happens, buildSectionTree would incorrectly give ALL child subsections
|
|
1159
|
+
// to each sibling. We resolve ownership via sortOrder: a section owns
|
|
1160
|
+
// segments whose sortOrder falls between its own and the next sibling's.
|
|
1161
|
+
//
|
|
1162
|
+
// Computed first because hasRootSection (below) uses it to decide
|
|
1163
|
+
// whether bounded skip-slug siblings should activate adoption.
|
|
1164
|
+
const siblingBoundaries = computeSiblingSortBoundaries(ordered);
|
|
1112
1165
|
// ── Root-section adoption flow ──────────────────────────────────────
|
|
1113
1166
|
//
|
|
1114
1167
|
// A scope may contain a "root section" — a segment with type "section"
|
|
@@ -1127,15 +1180,20 @@ function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePre
|
|
|
1127
1180
|
// → SKIP — already adopted by (B) via buildSectionTree
|
|
1128
1181
|
//
|
|
1129
1182
|
// Without a root section, depth-0 sections are emitted directly.
|
|
1130
|
-
const hasRootSection = ordered.some((s) => metaStr(s.seg.metadata, "type") === "section" && s.seg.section === "");
|
|
1131
|
-
// ── Sibling section ownership ────────────────────────────────────────
|
|
1132
1183
|
//
|
|
1133
|
-
//
|
|
1134
|
-
//
|
|
1135
|
-
//
|
|
1136
|
-
//
|
|
1137
|
-
//
|
|
1138
|
-
|
|
1184
|
+
// A section with sec=="" AND `childIndex` in its metadata is a sibling
|
|
1185
|
+
// inside a V1 sidebarGroup that has skipUrlSlug — not a true structural
|
|
1186
|
+
// wrapper. `walkNavSubTrees` always passes `childIndex`; direct
|
|
1187
|
+
// sidebarRoot children (true wrappers) never receive one.
|
|
1188
|
+
//
|
|
1189
|
+
// Such siblings only activate adoption when they have sortOrder
|
|
1190
|
+
// boundaries (multiple sec="" sections sharing the same path), which
|
|
1191
|
+
// correctly scope each section's children. A *single* unbounded
|
|
1192
|
+
// skip-slug sibling (e.g. mangopay's "Introduction") must NOT adopt
|
|
1193
|
+
// its depth-0 peers — doing so produces spurious breadcrumb entries.
|
|
1194
|
+
const hasRootSection = ordered.some((s) => metaStr(s.seg.metadata, "type") === "section" &&
|
|
1195
|
+
s.seg.section === "" &&
|
|
1196
|
+
(metaNum(s.seg.metadata, "childIndex") == null || siblingBoundaries.has(s)));
|
|
1139
1197
|
for (const s of ordered) {
|
|
1140
1198
|
const type = metaStr(s.seg.metadata, "type");
|
|
1141
1199
|
const sec = s.seg.section;
|
|
@@ -1158,8 +1216,16 @@ function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePre
|
|
|
1158
1216
|
continue;
|
|
1159
1217
|
}
|
|
1160
1218
|
// (B) Root section wrapper — adopts depth-0 children via buildSectionTree.
|
|
1161
|
-
|
|
1162
|
-
|
|
1219
|
+
// Only applies to true root wrappers (no childIndex); sibling
|
|
1220
|
+
// sections with skipUrlSlug (have childIndex) fall through to (C).
|
|
1221
|
+
// When multiple sections share sec==="" (skip-slug), scope children
|
|
1222
|
+
// to each section's sortOrder range so subsections aren't duplicated.
|
|
1223
|
+
if (type === "section" && sec === "" && hasRootSection) {
|
|
1224
|
+
const bounds = siblingBoundaries.get(s);
|
|
1225
|
+
const ownedSegs = bounds != null
|
|
1226
|
+
? scopeSegs.filter((seg) => seg.seg.sortOrder >= bounds.lo && seg.seg.sortOrder < bounds.hi)
|
|
1227
|
+
: scopeSegs;
|
|
1228
|
+
const sectionChildren = buildSectionTree(ctx, ownedSegs, "", scopePrefix, changelogScopePrefix);
|
|
1163
1229
|
const node = sectionNode(ctx, s, sectionChildren, scopePrefix);
|
|
1164
1230
|
annotated.push({ node, pos: metaNum(s.seg.metadata, "childIndex"), isLeaf: false });
|
|
1165
1231
|
continue;
|
|
@@ -1190,7 +1256,20 @@ function buildSidebarRootChildren(ctx, scopeSegs, scopePrefix, changelogScopePre
|
|
|
1190
1256
|
const ownedSegs = bounds != null
|
|
1191
1257
|
? scopeSegs.filter((seg) => seg.seg.sortOrder >= bounds.lo && seg.seg.sortOrder < bounds.hi)
|
|
1192
1258
|
: scopeSegs;
|
|
1193
|
-
|
|
1259
|
+
// A section with sec="" that reaches here (not adopted as a
|
|
1260
|
+
// root wrapper in case B) is a skipUrlSlug sibling.
|
|
1261
|
+
// When sortOrder boundaries exist (multiple sec="" sections),
|
|
1262
|
+
// the scoped ownedSegs correctly limits which subsections
|
|
1263
|
+
// each section can adopt. When there are NO boundaries
|
|
1264
|
+
// (single sec="" section, e.g. mangopay's "Introduction"),
|
|
1265
|
+
// buildSectionTree("") would re-adopt all depth-0 peers;
|
|
1266
|
+
// pass an empty child list instead — its leaf artifacts are
|
|
1267
|
+
// already in its own segment nav.
|
|
1268
|
+
const isUnboundedSkipSlugSibling = sec === "" && metaNum(s.seg.metadata, "childIndex") != null && bounds == null;
|
|
1269
|
+
const sectionChildren = isUnboundedSkipSlugSibling
|
|
1270
|
+
? []
|
|
1271
|
+
: buildSectionTree(ctx, ownedSegs, sec, scopePrefix, changelogScopePrefix);
|
|
1272
|
+
node = sectionNode(ctx, s, sectionChildren, scopePrefix);
|
|
1194
1273
|
}
|
|
1195
1274
|
// Shared/merged sections (paths not rooted in scopePrefix) must not
|
|
1196
1275
|
// carry childIndex — their source-version positions would sort them
|