Skip to content

Commit 1545ac8

Browse files
committed
Fix example file tree fallback
1 parent a2edb12 commit 1545ac8

2 files changed

Lines changed: 354 additions & 69 deletions

File tree

src/utils/documents.server.ts

Lines changed: 119 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,26 @@ function isGitHubFileNodeArray(value: unknown): value is Array<GitHubFileNode> {
759759
return Array.isArray(value) && value.every((item) => isGitHubFileNode(item))
760760
}
761761

762+
function isGitHubFile(value: unknown): value is GitHubFile {
763+
if (!isRecord(value)) {
764+
return false
765+
}
766+
767+
const links = value._links
768+
769+
return (
770+
typeof value.name === 'string' &&
771+
typeof value.path === 'string' &&
772+
typeof value.type === 'string' &&
773+
isRecord(links) &&
774+
typeof links.self === 'string'
775+
)
776+
}
777+
778+
function isGitHubFileArray(value: unknown): value is Array<GitHubFile> {
779+
return Array.isArray(value) && value.every((item) => isGitHubFile(item))
780+
}
781+
762782
function isGitHubTreeEntry(value: unknown): value is GitHubTreeEntry {
763783
if (typeof value !== 'object' || value === null) {
764784
return false
@@ -1036,6 +1056,15 @@ function buildFileTreeFromRecursiveTree(
10361056

10371057
const API_CONTENTS_MAX_DEPTH = 3
10381058

1059+
function encodeGitHubContentsPath(path: string) {
1060+
return removeLeadingSlash(path)
1061+
.replace(/\/+$/g, '')
1062+
.split('/')
1063+
.filter(Boolean)
1064+
.map((segment) => encodeURIComponent(segment))
1065+
.join('/')
1066+
}
1067+
10391068
export function fetchApiContents(
10401069
repoPair: string,
10411070
branch: string,
@@ -1182,11 +1211,98 @@ async function fetchApiContentsRemote(
11821211
branch: string,
11831212
startingPath: string,
11841213
): Promise<Array<GitHubFileNode> | null> {
1185-
const tree = await fetchGitHubRecursiveTree(repo, branch)
1214+
try {
1215+
const tree = await fetchGitHubRecursiveTree(repo, branch)
1216+
1217+
if (tree) {
1218+
const fileTree = buildFileTreeFromRecursiveTree(tree, startingPath)
1219+
1220+
if (fileTree) {
1221+
return fileTree
1222+
}
1223+
}
1224+
} catch (error) {
1225+
if (!isRecoverableGitHubContentError(error)) {
1226+
throw error
1227+
}
1228+
}
1229+
1230+
return fetchApiContentsRemoteFromContentsApi(repo, branch, startingPath)
1231+
}
1232+
1233+
async function fetchGitHubDirectoryContents(
1234+
repo: string,
1235+
branch: string,
1236+
directoryPath: string,
1237+
) {
1238+
const encodedPath = encodeGitHubContentsPath(directoryPath)
1239+
const url = new URL(
1240+
`https://api.github.com/repos/${repo}/contents/${encodedPath}`,
1241+
)
1242+
url.searchParams.set('ref', branch)
1243+
1244+
const response = await fetchGitHubApiJson(url.href)
1245+
1246+
if (response === null) {
1247+
return null
1248+
}
1249+
1250+
if (!isGitHubFileArray(response)) {
1251+
throw new GitHubContentError(
1252+
'invalid-response',
1253+
`Unexpected directory contents response for ${repo}@${branch}:${directoryPath}`,
1254+
)
1255+
}
1256+
1257+
return response.filter((file) => file.type === 'dir' || file.type === 'file')
1258+
}
1259+
1260+
async function fetchApiContentsRemoteFromContentsApi(
1261+
repo: string,
1262+
branch: string,
1263+
startingPath: string,
1264+
): Promise<Array<GitHubFileNode> | null> {
1265+
const data = await fetchGitHubDirectoryContents(repo, branch, startingPath)
11861266

1187-
if (!tree) {
1267+
if (!data || data.length === 0) {
11881268
return null
11891269
}
11901270

1191-
return buildFileTreeFromRecursiveTree(tree, startingPath)
1271+
async function buildFileTree(
1272+
nodes: Array<GitHubFile>,
1273+
depth: number,
1274+
parentPath: string,
1275+
): Promise<Array<GitHubFileNode>> {
1276+
const result: Array<GitHubFileNode> = []
1277+
const sortedNodes = sortApiContents(nodes)
1278+
1279+
for (const node of sortedNodes) {
1280+
const file: GitHubFileNode = {
1281+
...node,
1282+
depth,
1283+
parentPath,
1284+
}
1285+
1286+
if (file.type === 'dir' && depth <= API_CONTENTS_MAX_DEPTH) {
1287+
const directoryFiles = await fetchGitHubDirectoryContents(
1288+
repo,
1289+
branch,
1290+
file.path,
1291+
)
1292+
file.children = directoryFiles
1293+
? await buildFileTree(
1294+
directoryFiles,
1295+
depth + 1,
1296+
`${parentPath}${file.path}/`,
1297+
)
1298+
: []
1299+
}
1300+
1301+
result.push(file)
1302+
}
1303+
1304+
return result
1305+
}
1306+
1307+
return buildFileTree(data, 0, '')
11921308
}

0 commit comments

Comments
 (0)