Skip to content

Commit 525d289

Browse files
committed
Fix
1 parent 9edb8a8 commit 525d289

File tree

3 files changed

+84
-95
lines changed

3 files changed

+84
-95
lines changed

packages/gitbook-v2/src/lib/links.ts

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -66,49 +66,62 @@ export function createLinker(
6666

6767
/** The base path of the site */
6868
siteBasePath: string;
69-
}
69+
},
70+
linkerOptions: {
71+
alwaysAbsolute?: boolean;
72+
} = {}
7073
): GitBookLinker {
7174
warnOnce(!servedOn.host, 'No host provided to createLinker. It can lead to issues with links.');
7275

76+
const alwaysAbsolute = linkerOptions.alwaysAbsolute ?? false;
77+
7378
const siteBasePath = withTrailingSlash(withLeadingSlash(servedOn.siteBasePath));
7479
const spaceBasePath = withTrailingSlash(withLeadingSlash(servedOn.spaceBasePath));
7580

81+
function wrapInAbsolute(str: string): string {
82+
return alwaysAbsolute ? toAbsoluteURL(str) : str;
83+
}
84+
85+
function toAbsoluteURL(absolutePath: string): string {
86+
// If the path is already a full URL, we return it as is.
87+
if (URL.canParse(absolutePath)) {
88+
return absolutePath;
89+
}
90+
91+
if (!servedOn.host) {
92+
return absolutePath;
93+
}
94+
95+
return `${servedOn.protocol ?? 'https:'}//${joinPaths(servedOn.host, absolutePath)}`;
96+
}
97+
7698
const linker: GitBookLinker = {
7799
toPathInSpace(relativePath: string): string {
78-
return joinPaths(spaceBasePath, relativePath);
100+
return wrapInAbsolute(joinPaths(spaceBasePath, relativePath));
79101
},
80102

81103
toPathInSite(relativePath: string): string {
82-
return joinPaths(siteBasePath, relativePath);
104+
return wrapInAbsolute(joinPaths(siteBasePath, relativePath));
83105
},
84106

85107
toRelativePathInSite(absolutePath: string): string {
86108
const normalizedPath = withLeadingSlash(absolutePath);
87109

88110
if (!normalizedPath.startsWith(servedOn.siteBasePath)) {
89-
return normalizedPath;
90-
}
91-
92-
return normalizedPath.slice(servedOn.siteBasePath.length);
93-
},
94-
95-
toAbsoluteURL(absolutePath: string): string {
96-
// If the path is already a full URL, we return it as is.
97-
if (URL.canParse(absolutePath)) {
98-
return absolutePath;
111+
return wrapInAbsolute(normalizedPath);
99112
}
100113

101-
if (!servedOn.host) {
102-
return absolutePath;
103-
}
104-
105-
return `${servedOn.protocol ?? 'https:'}//${joinPaths(servedOn.host, absolutePath)}`;
114+
return wrapInAbsolute(normalizedPath.slice(servedOn.siteBasePath.length));
106115
},
107116

108117
toPathForPage({ pages, page, anchor }) {
109118
return linker.toPathInSpace(getPagePath(pages, page)) + (anchor ? `#${anchor}` : '');
110119
},
111120

121+
toAbsoluteURL(absolutePath: string): string {
122+
return toAbsoluteURL(absolutePath);
123+
},
124+
112125
toLinkForContent(rawURL: string): string {
113126
const url = new URL(rawURL);
114127

packages/gitbook/src/components/DocumentView/ReusableContent.tsx

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import type { DocumentBlockReusableContent } from '@gitbook/api';
22

3-
import { resolveContentRef } from '@/lib/references';
3+
import { createLinkerForSpace, resolveContentRef } from '@/lib/references';
44

55
import type { GitBookSpaceContext } from '@v2/lib/context';
66
import { getDataOrNull } from '@v2/lib/data';
7+
import { assert } from 'ts-essentials';
78
import type { BlockProps } from './Block';
89
import { UnwrappedBlocks } from './Blocks';
910

@@ -46,23 +47,35 @@ export async function ReusableContent(props: BlockProps<DocumentBlockReusableCon
4647
// Create a new context for reusable content block, including
4748
// the data fetcher with the token from the block meta and the correct
4849
// space and revision pointers.
49-
const reusableContentContext: GitBookSpaceContext =
50-
context.contentContext.space.id === reusableContent.space.id
51-
? context.contentContext
52-
: {
53-
...context.contentContext,
54-
dataFetcher,
55-
space: reusableContent.space,
56-
// When the reusable content is in a different space, we don't resolve relative links to pages
57-
// as this space might not be part of the current site.
58-
// In the future, we might expand the logic to look up the space from the list of all spaces in the site
59-
// and adapt the relative links to point to the correct variant.
60-
revision: {
61-
...reusableContent.revision,
62-
pages: [], // TODO: check with Steven
63-
},
64-
shareKey: undefined,
65-
};
50+
const reusableContentContext: GitBookSpaceContext = await (async () => {
51+
assert(context.contentContext);
52+
53+
// Reusable Content in the same space resolves the same as any other reference.
54+
if (context.contentContext.space.id === reusableContent.space.id) {
55+
return context.contentContext;
56+
}
57+
58+
// Reusable Content in a different space needs to resolve the space context and linker.
59+
const ctx = await createLinkerForSpace(reusableContent.space.id, context.contentContext);
60+
61+
if (!ctx) {
62+
throw new Error(`Could not create context for space ${reusableContent.space.id}`);
63+
}
64+
65+
return {
66+
...context.contentContext,
67+
...ctx.spaceContext,
68+
dataFetcher,
69+
space: ctx.space,
70+
linker: ctx.linker,
71+
// When the reusable content is in a different space, we don't resolve relative links to pages
72+
// as this space might not be part of the current site.
73+
// In the future, we might expand the logic to look up the space from the list of all spaces in the site
74+
// and adapt the relative links to point to the correct variant.
75+
revision: reusableContent.revision,
76+
shareKey: undefined,
77+
};
78+
})();
6679

6780
return (
6881
<UnwrappedBlocks

packages/gitbook/src/lib/references.tsx

Lines changed: 22 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import type {
22
ContentRef,
33
Revision,
44
RevisionFile,
5-
RevisionPage,
65
RevisionPageDocument,
76
RevisionReusableContent,
87
SiteSpace,
@@ -74,12 +73,6 @@ export interface ResolveContentRefOptions {
7473
* Styles to apply to the icon.
7574
*/
7675
iconStyle?: ClassValue;
77-
78-
/**
79-
* Resolve the content URL as absolute.
80-
* @default false
81-
*/
82-
resolveAsAbsoluteURL?: boolean;
8376
}
8477

8578
/**
@@ -123,50 +116,23 @@ export async function resolveContentRef(
123116
return resolveContentRefInSpace(contentRef.space, context, contentRef);
124117
}
125118

126-
let resolveAsAbsoluteURL = options.resolveAsAbsoluteURL ?? false;
127-
let linker = context.linker;
128-
129-
const pages: RevisionPage[] = await (async () => {
130-
if (context.pages.length) {
131-
return context.pages;
132-
}
133-
134-
const pages = await getDataOrNull(
135-
dataFetcher.getRevision({
136-
spaceId: space.id,
137-
revisionId,
138-
metadata: false,
139-
})
140-
);
141-
142-
const ctx = await createLinkerForSpace(space.id, context);
143-
144-
if (!ctx) {
145-
return [];
146-
}
147-
148-
resolveAsAbsoluteURL = true;
149-
linker = ctx.linker;
150-
return pages?.pages ?? [];
151-
})();
152-
119+
// console.log(`resolve`, contentRef);
120+
// console.log(`context`, context);
153121
const resolvePageResult =
154122
!contentRef.page || contentRef.page === activePage?.id
155123
? activePage
156124
? { page: activePage, ancestors: [] }
157125
: undefined
158126
: resolvePageId(revision.pages, contentRef.page);
159127

128+
// console.log(`resolvePageResult`, resolvePageResult);
129+
160130
const page = resolvePageResult?.page;
161131
const ancestors =
162132
resolvePageResult?.ancestors.map((ancestor) => ({
163133
label: ancestor.title,
164134
icon: <PageIcon page={ancestor} style={iconStyle} />,
165-
href: resolveAsAbsoluteURL
166-
? linker.toAbsoluteURL(
167-
linker.toPathForPage({ page: ancestor, pages: revision.pages })
168-
)
169-
: linker.toPathForPage({ page: ancestor, pages: revision.pages }),
135+
href: linker.toPathForPage({ page: ancestor, pages: revision.pages }),
170136
})) ?? [];
171137
if (!page) {
172138
return null;
@@ -186,7 +152,7 @@ export async function resolveContentRef(
186152
ancestors.push({
187153
label: page.title,
188154
icon: <PageIcon page={page} style={iconStyle} />,
189-
href: resolveAsAbsoluteURL ? linker.toAbsoluteURL(href) : href,
155+
href,
190156
});
191157

192158
if (resolveAnchorText) {
@@ -211,7 +177,7 @@ export async function resolveContentRef(
211177
}
212178

213179
return {
214-
href: resolveAsAbsoluteURL ? linker.toAbsoluteURL(href) : href,
180+
href,
215181
text,
216182
subText: page.description,
217183
ancestors: ancestors,
@@ -398,18 +364,11 @@ async function resolveContentRefInSpace(
398364
return null;
399365
}
400366

401-
const resolved = await resolveContentRef(
402-
contentRef,
403-
{
404-
...ctx.spaceContext,
405-
space: ctx.space,
406-
linker: ctx.linker,
407-
},
408-
{
409-
// Resolve pages as absolute URLs as we are in a different site.
410-
resolveAsAbsoluteURL: true,
411-
}
412-
);
367+
const resolved = await resolveContentRef(contentRef, {
368+
...ctx.spaceContext,
369+
space: ctx.space,
370+
linker: ctx.linker,
371+
});
413372

414373
if (!resolved) {
415374
return null;
@@ -427,7 +386,7 @@ async function resolveContentRefInSpace(
427386
};
428387
}
429388

430-
async function createLinkerForSpace(
389+
export async function createLinkerForSpace(
431390
spaceId: string,
432391
context: GitBookAnyContext
433392
): Promise<{
@@ -457,11 +416,15 @@ async function createLinkerForSpace(
457416
const baseURL = new URL(
458417
bestTargetSpace?.siteSpace?.urls.published ?? space.urls.published ?? space.urls.app
459418
);
460-
const linker = createLinker({
461-
host: baseURL.host,
462-
spaceBasePath: baseURL.pathname,
463-
siteBasePath: baseURL.pathname,
464-
});
419+
const linker = createLinker(
420+
{
421+
host: baseURL.host,
422+
spaceBasePath: baseURL.pathname,
423+
siteBasePath: baseURL.pathname,
424+
},
425+
// Resolve pages as absolute URLs as we are in a different site.
426+
{ alwaysAbsolute: true }
427+
);
465428

466429
return {
467430
spaceContext,

0 commit comments

Comments
 (0)