@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,383 @@
1
+ import { locales } from '@mintlify/models';
2
+ import { divisions, } from '@mintlify/validation';
3
+ import { readObjectArrayProperty } from '../divisions/iterateObjectArrayProperty.js';
4
+ import { isEqualIgnoringLeadingSlash } from '../paths/isEqualIgnoringLeadingSlash.js';
5
+ import { isPage } from './isPage.js';
6
+ export var DivisionMatchLevel;
7
+ (function (DivisionMatchLevel) {
8
+ DivisionMatchLevel[DivisionMatchLevel["EXACT"] = 0] = "EXACT";
9
+ DivisionMatchLevel[DivisionMatchLevel["PATH"] = 1] = "PATH";
10
+ DivisionMatchLevel[DivisionMatchLevel["GROUP"] = 2] = "GROUP";
11
+ DivisionMatchLevel[DivisionMatchLevel["DIVISION"] = 3] = "DIVISION";
12
+ DivisionMatchLevel[DivisionMatchLevel["NONE"] = 4] = "NONE";
13
+ })(DivisionMatchLevel || (DivisionMatchLevel = {}));
14
+ const ACCEPTED_BASE_PATHS = ['docs', 'doc', 'documentation', 'help'];
15
+ export function updateFirstHrefInDivision({ type, currentPath, entry, parentGroups, nearestDivisionValue, isActiveGroup, inActiveDivision, currentDivisionValue, allDivisionValues, firstHrefInDivision, navigationDivisions, isHiddenPage, activeGroupNames, }) {
16
+ if (typeof entry !== 'object')
17
+ return;
18
+ if (isPage(entry)) {
19
+ maybeUpdateFirstHrefInDivision(type, entry.href, nearestDivisionValue, isActiveGroup, inActiveDivision, currentPath, currentDivisionValue, allDivisionValues, firstHrefInDivision, isHiddenPage);
20
+ }
21
+ if ('pages' in entry && Array.isArray(entry.pages)) {
22
+ const root = 'root' in entry && entry.root != null && typeof entry.root === 'object'
23
+ ? // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- root is a DecoratedNavigationPage
24
+ entry.root
25
+ : undefined;
26
+ const isRootActive = root !== undefined &&
27
+ isPage(root) &&
28
+ isEqualIgnoringLeadingSlash(root.href, currentPath) &&
29
+ currentDivisionValue === nearestDivisionValue;
30
+ const isActivePages = entry.pages.some((subEntry) => isPage(subEntry) && isEqualIgnoringLeadingSlash(subEntry.href, currentPath)) && currentDivisionValue === nearestDivisionValue;
31
+ if (root !== undefined) {
32
+ updateFirstHrefInDivision({
33
+ type,
34
+ currentPath,
35
+ entry: root,
36
+ parentGroups: parentGroups.length ? parentGroups : entry.pages,
37
+ nearestDivisionValue,
38
+ isActiveGroup: isActiveGroup || isActivePages || isRootActive,
39
+ inActiveDivision,
40
+ currentDivisionValue,
41
+ allDivisionValues,
42
+ firstHrefInDivision,
43
+ navigationDivisions,
44
+ isHiddenPage,
45
+ activeGroupNames,
46
+ });
47
+ }
48
+ for (const page of entry.pages) {
49
+ if (typeof page === 'object') {
50
+ updateFirstHrefInDivision({
51
+ type,
52
+ currentPath,
53
+ entry: page,
54
+ parentGroups: parentGroups.length ? parentGroups : entry.pages,
55
+ nearestDivisionValue,
56
+ isActiveGroup: isActiveGroup || isActivePages || isRootActive,
57
+ inActiveDivision,
58
+ currentDivisionValue,
59
+ allDivisionValues,
60
+ firstHrefInDivision,
61
+ navigationDivisions,
62
+ isHiddenPage,
63
+ activeGroupNames,
64
+ });
65
+ }
66
+ }
67
+ }
68
+ if ('groups' in entry && !isPage(entry)) {
69
+ for (const group of entry.groups) {
70
+ if (typeof group !== 'object')
71
+ continue;
72
+ const groupName = 'group' in group && typeof group.group === 'string' ? group.group : undefined;
73
+ const matchesCurrentDivisionGroup = checkActiveGroup(group, currentPath) && currentDivisionValue === nearestDivisionValue;
74
+ const matchesActiveSiblingGroup = type === 'version' &&
75
+ currentDivisionValue !== nearestDivisionValue &&
76
+ !!groupName &&
77
+ (activeGroupNames === null || activeGroupNames === void 0 ? void 0 : activeGroupNames.has(groupName)) === true;
78
+ const isActiveGroup = matchesCurrentDivisionGroup || matchesActiveSiblingGroup;
79
+ updateFirstHrefInDivision({
80
+ type,
81
+ currentPath,
82
+ entry: group,
83
+ parentGroups: entry.groups,
84
+ nearestDivisionValue,
85
+ isActiveGroup,
86
+ inActiveDivision,
87
+ currentDivisionValue,
88
+ allDivisionValues,
89
+ firstHrefInDivision,
90
+ navigationDivisions,
91
+ isHiddenPage,
92
+ activeGroupNames,
93
+ });
94
+ }
95
+ }
96
+ for (const key of [...divisions, 'groups']) {
97
+ const subDivisions = readObjectArrayProperty(entry, key);
98
+ if (!subDivisions)
99
+ continue;
100
+ let inActiveDivision = false;
101
+ if (allDivisionValues && allDivisionValues.length) {
102
+ if (type === 'version' && key === 'versions') {
103
+ const localDivisionValueCount = navigationDivisions.versions.filter((version) => !version.isGlobal).length;
104
+ inActiveDivision =
105
+ subDivisions.length === localDivisionValueCount &&
106
+ subDivisions.every((subDivision) =>
107
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- TODO: Please fix this violation when you can!
108
+ allDivisionValues.includes(subDivision.version));
109
+ }
110
+ else if (type === 'language' && key === 'languages') {
111
+ const localDivisionValueCount = navigationDivisions.languages.filter((language) => !language.isGlobal).length;
112
+ inActiveDivision =
113
+ subDivisions.length === localDivisionValueCount &&
114
+ subDivisions.every((subDivision) =>
115
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- TODO: Please fix this violation when you can!
116
+ allDivisionValues.includes(subDivision.language));
117
+ }
118
+ }
119
+ let activeGroupsInVersionContext = activeGroupNames;
120
+ if (type === 'version' && key === 'versions' && currentDivisionValue) {
121
+ const currentVersionDivision = subDivisions.find((subDivision) => 'version' in subDivision &&
122
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- TODO: Please fix this violation when you can!
123
+ subDivision.version === currentDivisionValue);
124
+ if (currentVersionDivision) {
125
+ activeGroupsInVersionContext = findActiveGroupNames(
126
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- TODO: Please fix this violation when you can!
127
+ currentVersionDivision, currentPath);
128
+ }
129
+ }
130
+ for (const subDivision of subDivisions) {
131
+ let divisionValue;
132
+ if (type === 'version' && key === 'versions') {
133
+ divisionValue =
134
+ 'version' in subDivision
135
+ ? // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- TODO: Please fix this violation when you can!
136
+ subDivision.version
137
+ : undefined;
138
+ }
139
+ else if (type === 'language' && key === 'languages') {
140
+ divisionValue =
141
+ 'language' in subDivision
142
+ ? // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- TODO: Please fix this violation when you can!
143
+ subDivision.language
144
+ : undefined;
145
+ }
146
+ updateFirstHrefInDivision({
147
+ type,
148
+ currentPath,
149
+ entry: subDivision,
150
+ parentGroups: key === 'groups' && 'groups' in entry
151
+ ? // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
152
+ entry.groups
153
+ : parentGroups,
154
+ nearestDivisionValue: divisionValue !== null && divisionValue !== void 0 ? divisionValue : nearestDivisionValue,
155
+ isActiveGroup,
156
+ inActiveDivision: inActiveDivision,
157
+ currentDivisionValue,
158
+ allDivisionValues,
159
+ firstHrefInDivision,
160
+ navigationDivisions,
161
+ isHiddenPage,
162
+ activeGroupNames: activeGroupsInVersionContext,
163
+ });
164
+ }
165
+ }
166
+ }
167
+ function findActiveGroupNames(entry, currentPath, activeGroupNames = new Set()) {
168
+ if (typeof entry !== 'object')
169
+ return activeGroupNames;
170
+ if ('groups' in entry && !isPage(entry)) {
171
+ for (const group of entry.groups) {
172
+ if (typeof group !== 'object')
173
+ continue;
174
+ if ('group' in group &&
175
+ typeof group.group === 'string' &&
176
+ checkActiveGroup(group, currentPath)) {
177
+ activeGroupNames.add(group.group);
178
+ }
179
+ findActiveGroupNames(group, currentPath, activeGroupNames);
180
+ }
181
+ }
182
+ if ('pages' in entry && Array.isArray(entry.pages)) {
183
+ if ('root' in entry && typeof entry.root === 'object') {
184
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- TODO: Please fix this violation when you can!
185
+ findActiveGroupNames(entry.root, currentPath, activeGroupNames);
186
+ }
187
+ for (const page of entry.pages) {
188
+ if (typeof page === 'object') {
189
+ findActiveGroupNames(page, currentPath, activeGroupNames);
190
+ }
191
+ }
192
+ }
193
+ for (const key of divisions) {
194
+ const subDivisions = readObjectArrayProperty(entry, key);
195
+ if (!subDivisions)
196
+ continue;
197
+ for (const subDivision of subDivisions) {
198
+ findActiveGroupNames(subDivision, currentPath, activeGroupNames);
199
+ }
200
+ }
201
+ return activeGroupNames;
202
+ }
203
+ function parseLanguagePath(segments) {
204
+ let index = 0;
205
+ let locale;
206
+ let hasDocsBase = false;
207
+ const firstSegment = segments[0];
208
+ const firstIsDocsBase = !!firstSegment && ACCEPTED_BASE_PATHS.includes(firstSegment);
209
+ const firstIsLocale = !!firstSegment &&
210
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- TODO: Please fix this violation when you can!
211
+ locales.includes(firstSegment);
212
+ if (firstIsDocsBase) {
213
+ hasDocsBase = true;
214
+ index = 1;
215
+ const maybeLocale = segments[index];
216
+ if (maybeLocale &&
217
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- TODO: Please fix this violation when you can!
218
+ locales.includes(maybeLocale)) {
219
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- TODO: Please fix this violation when you can!
220
+ locale = maybeLocale;
221
+ index++;
222
+ }
223
+ }
224
+ else if (firstIsLocale) {
225
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- TODO: Please fix this violation when you can!
226
+ locale = firstSegment;
227
+ index = 1;
228
+ const maybeDocsBase = segments[index];
229
+ if (maybeDocsBase && ACCEPTED_BASE_PATHS.includes(maybeDocsBase)) {
230
+ hasDocsBase = true;
231
+ index++;
232
+ }
233
+ }
234
+ let contentSegments = segments.slice(index);
235
+ if (contentSegments.at(-1) === 'index') {
236
+ contentSegments = contentSegments.slice(0, -1);
237
+ }
238
+ return { hasDocsBase, locale, contentSegments };
239
+ }
240
+ /**
241
+ * This function attempts to maintain some context when switching versions by following these rules:
242
+ * 1. stay on the active page, if it is in the new version (unversioned)
243
+ * 2. navigate to the first page that is in the new version AND in the active group, if one exists
244
+ * 3. navigate to the first page that is in the new version
245
+ *
246
+ * @param href The href of the page being processed
247
+ * @param finalVersion The version of the page being processed
248
+ * @param inActiveGroup Whether the page being processed is in the same group as the active page
249
+ * @param currentPath The path of the active page
250
+ * @param currentVersion The version of the active page
251
+ * @param versionStrings If defined, the array of version strings
252
+ * @param firstHrefInDivision A map from version strings to the href that should be navigated to when switching to that version
253
+ */
254
+ function maybeUpdateFirstHrefInDivision(type, href, finalVersion, inActiveGroup, inActiveDivision, currentPath, currentVersion, versionStrings, firstHrefInDivision, isHiddenPage) {
255
+ const versionsToUpdate = finalVersion !== undefined ? [finalVersion] : (versionStrings !== null && versionStrings !== void 0 ? versionStrings : []);
256
+ // now that we support index.mdx, the href might empty string
257
+ // router.push cannot take empty string as url
258
+ href = href || '/';
259
+ // always use the current page if the current page is unversioned
260
+ if (href === currentPath) {
261
+ for (const version of versionsToUpdate) {
262
+ firstHrefInDivision.set(version, { href, matchLevel: DivisionMatchLevel.EXACT });
263
+ }
264
+ return;
265
+ }
266
+ // if the page is hidden, assign the current path to the current version with EXACT match level
267
+ if (isHiddenPage && currentVersion !== undefined) {
268
+ firstHrefInDivision.set(currentVersion, {
269
+ href: currentPath,
270
+ matchLevel: DivisionMatchLevel.EXACT,
271
+ });
272
+ }
273
+ // if currentPath and href differ by exactly one path segment, and it's not the last,
274
+ // we make the BOLD assumption that href is a different version of the same page
275
+ if (currentVersion !== undefined && finalVersion !== undefined) {
276
+ const existingRef = firstHrefInDivision.get(finalVersion);
277
+ if ((existingRef === undefined || DivisionMatchLevel.PATH < existingRef.matchLevel) &&
278
+ pathsDifferByOneSegment(href, currentPath, type)) {
279
+ firstHrefInDivision.set(finalVersion, { href, matchLevel: DivisionMatchLevel.PATH });
280
+ }
281
+ }
282
+ if (inActiveGroup) {
283
+ for (const version of versionsToUpdate) {
284
+ const existingHref = firstHrefInDivision.get(version);
285
+ if (existingHref === undefined || DivisionMatchLevel.GROUP < existingHref.matchLevel) {
286
+ firstHrefInDivision.set(version, { href, matchLevel: DivisionMatchLevel.GROUP });
287
+ }
288
+ }
289
+ return;
290
+ }
291
+ if (inActiveDivision) {
292
+ for (const version of versionsToUpdate) {
293
+ const existingHref = firstHrefInDivision.get(version);
294
+ if (existingHref === undefined || DivisionMatchLevel.DIVISION < existingHref.matchLevel) {
295
+ firstHrefInDivision.set(version, { href, matchLevel: DivisionMatchLevel.DIVISION });
296
+ }
297
+ }
298
+ return;
299
+ }
300
+ for (const version of versionsToUpdate) {
301
+ if (!firstHrefInDivision.has(version)) {
302
+ firstHrefInDivision.set(version, { href, matchLevel: DivisionMatchLevel.NONE });
303
+ }
304
+ }
305
+ }
306
+ export function pathsDifferByOneSegment(a, b, type) {
307
+ const aSegments = a.split('/').filter(Boolean);
308
+ const bSegments = b.split('/').filter(Boolean);
309
+ // For language switching, we need to be more strict - paths should be identical except for the language segment
310
+ // once normalized, content segments should be identical and only locale prefix may differ.
311
+ if (type === 'language') {
312
+ const aPath = parseLanguagePath(aSegments);
313
+ const bPath = parseLanguagePath(bSegments);
314
+ if (aPath.hasDocsBase !== bPath.hasDocsBase)
315
+ return false;
316
+ // For language switching, the content parts (including version segments) must be identical.
317
+ if (aPath.contentSegments.length !== bPath.contentSegments.length)
318
+ return false;
319
+ for (let i = 0; i < aPath.contentSegments.length; i++) {
320
+ if (aPath.contentSegments[i] !== bPath.contentSegments[i]) {
321
+ return false;
322
+ }
323
+ }
324
+ // The paths are language variants if locale presence/value differs.
325
+ if (!aPath.locale && !bPath.locale)
326
+ return false;
327
+ return aPath.locale !== bPath.locale;
328
+ }
329
+ const aStartsWithDocs = aSegments[0] && ACCEPTED_BASE_PATHS.includes(aSegments[0]);
330
+ const bStartsWithDocs = bSegments[0] && ACCEPTED_BASE_PATHS.includes(bSegments[0]);
331
+ // Only compare like-for-like paths (both with docs base prefix or both without)
332
+ if (aStartsWithDocs !== bStartsWithDocs)
333
+ return false;
334
+ const aContentSegments = aStartsWithDocs ? aSegments.slice(1) : aSegments;
335
+ const bContentSegments = bStartsWithDocs ? bSegments.slice(1) : bSegments;
336
+ // Existing behavior: same-length paths are version variants if exactly one non-terminal segment differs.
337
+ if (aContentSegments.length === bContentSegments.length &&
338
+ aContentSegments.length >= 2 &&
339
+ aContentSegments.at(-1) === bContentSegments.at(-1)) {
340
+ let mismatchFound = false;
341
+ for (let i = 0; i < aContentSegments.length - 1; i++) {
342
+ if (aContentSegments[i] !== bContentSegments[i]) {
343
+ if (mismatchFound)
344
+ return false;
345
+ mismatchFound = true;
346
+ }
347
+ }
348
+ return mismatchFound;
349
+ }
350
+ // New behavior: handle root-vs-prefixed version paths by allowing one leading segment difference.
351
+ const longerContentSegments = aContentSegments.length > bContentSegments.length ? aContentSegments : bContentSegments;
352
+ const shorterContentSegments = aContentSegments.length > bContentSegments.length ? bContentSegments : aContentSegments;
353
+ if (longerContentSegments.length !== shorterContentSegments.length + 1)
354
+ return false;
355
+ if (shorterContentSegments.length === 0)
356
+ return false;
357
+ for (let i = 0; i < shorterContentSegments.length; i++) {
358
+ if (longerContentSegments[i + 1] !== shorterContentSegments[i]) {
359
+ return false;
360
+ }
361
+ }
362
+ return true;
363
+ }
364
+ function checkActiveGroup(group, currentPath) {
365
+ if (isPage(group)) {
366
+ return isEqualIgnoringLeadingSlash(group.href, currentPath);
367
+ }
368
+ if ('pages' in group) {
369
+ if ('root' in group && typeof group.root === 'object') {
370
+ const isActivePage = checkActiveGroup(group.root, currentPath);
371
+ if (isActivePage) {
372
+ return true;
373
+ }
374
+ }
375
+ for (const page of group.pages) {
376
+ const isActivePage = checkActiveGroup(page, currentPath);
377
+ if (isActivePage) {
378
+ return true;
379
+ }
380
+ }
381
+ }
382
+ return false;
383
+ }
@@ -0,0 +1 @@
1
+ export declare function isEqualIgnoringLeadingSlash(path1: string | undefined, path2: string | undefined): boolean;
@@ -0,0 +1,21 @@
1
+ import { optionallyRemoveLeadingSlash, optionallyRemoveTrailingSlash, } from '../fs/optionallySlash.js';
2
+ import { replaceSlashIndex } from '../slug/replaceSlashIndex.js';
3
+ function normalizeIndexPath(path) {
4
+ if (path === '')
5
+ return 'index';
6
+ if (path === 'index')
7
+ return path;
8
+ if (path.endsWith('/index')) {
9
+ const normalized = replaceSlashIndex(path);
10
+ return normalized === '' ? 'index' : normalized;
11
+ }
12
+ return path;
13
+ }
14
+ export function isEqualIgnoringLeadingSlash(path1, path2) {
15
+ if (path1 == null || path2 == null || typeof path1 !== 'string' || typeof path2 !== 'string') {
16
+ return false;
17
+ }
18
+ const first = optionallyRemoveTrailingSlash(optionallyRemoveLeadingSlash(path1));
19
+ const second = optionallyRemoveTrailingSlash(optionallyRemoveLeadingSlash(path2));
20
+ return normalizeIndexPath(first) === normalizeIndexPath(second);
21
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,43 @@
1
+ import { isEqualIgnoringLeadingSlash } from './isEqualIgnoringLeadingSlash.js';
2
+ describe('isEqualIgnoringLeadingSlash', () => {
3
+ test('false when non-string inputs are passed', () => {
4
+ expect(isEqualIgnoringLeadingSlash({}, {})).toEqual(false);
5
+ expect(isEqualIgnoringLeadingSlash(undefined, '')).toEqual(false);
6
+ expect(isEqualIgnoringLeadingSlash(0, null)).toEqual(false);
7
+ });
8
+ test('true when strings match ignoring leading slash', () => {
9
+ expect(isEqualIgnoringLeadingSlash('', '/')).toEqual(true);
10
+ expect(isEqualIgnoringLeadingSlash('/path/to', 'path/to')).toEqual(true);
11
+ });
12
+ test('handles index paths', () => {
13
+ expect(isEqualIgnoringLeadingSlash('', 'index')).toEqual(true);
14
+ expect(isEqualIgnoringLeadingSlash('/', 'index')).toEqual(true);
15
+ expect(isEqualIgnoringLeadingSlash('path/to/index', 'path/to')).toEqual(true);
16
+ expect(isEqualIgnoringLeadingSlash('/path/to/index', 'path/to')).toEqual(true);
17
+ expect(isEqualIgnoringLeadingSlash('path/to/index', '/path/to')).toEqual(true);
18
+ expect(isEqualIgnoringLeadingSlash('/index', '')).toEqual(true);
19
+ expect(isEqualIgnoringLeadingSlash('/index', '/')).toEqual(true);
20
+ });
21
+ test('handles complex index paths', () => {
22
+ expect(isEqualIgnoringLeadingSlash('/api/v1/index', '/api/v1')).toEqual(true);
23
+ expect(isEqualIgnoringLeadingSlash('indexing/guide', 'ing/guide')).toEqual(false);
24
+ expect(isEqualIgnoringLeadingSlash('reindex/data', 'rein/data')).toEqual(false);
25
+ expect(isEqualIgnoringLeadingSlash('index/subpath/index', 'index/subpath')).toEqual(true);
26
+ expect(isEqualIgnoringLeadingSlash('index/subpath', 'index/subpath/index')).toEqual(true);
27
+ expect(isEqualIgnoringLeadingSlash('/', 'index')).toEqual(true);
28
+ expect(isEqualIgnoringLeadingSlash('/index/index', 'index')).toEqual(true);
29
+ });
30
+ test('normal paths work', () => {
31
+ expect(isEqualIgnoringLeadingSlash('path/to/resource', 'path/to/different')).toEqual(false);
32
+ expect(isEqualIgnoringLeadingSlash('/a/b/c', '/x/y/z')).toEqual(false);
33
+ expect(isEqualIgnoringLeadingSlash('Path/To', 'path/to')).toEqual(false);
34
+ expect(isEqualIgnoringLeadingSlash('INDEX', 'index')).toEqual(false);
35
+ expect(isEqualIgnoringLeadingSlash('path/to', 'path/to')).toEqual(true);
36
+ });
37
+ test('weird cases work', () => {
38
+ expect(isEqualIgnoringLeadingSlash('', 'index')).toEqual(true);
39
+ expect(isEqualIgnoringLeadingSlash('/index', '/index')).toEqual(true);
40
+ expect(isEqualIgnoringLeadingSlash('/index', 'index')).toEqual(true);
41
+ expect(isEqualIgnoringLeadingSlash('/index', '')).toEqual(true);
42
+ });
43
+ });