8000 added useGitHubFolderTree hook · sauravhathi/github-folder-tree@1bf076c · GitHub
[go: up one dir, main page]

Skip to content

Commit 1bf076c

Browse files
committed
added useGitHubFolderTree hook
1 parent e09a2a9 commit 1bf076c

File tree

3 files changed

+242
-0
lines changed

3 files changed

+242
-0
lines changed

package-lock.json

Lines changed: 84 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"name": "github-folder-tree",
3+
"version": "1.0.0",
4+
"description": "github-folder-tree is a React custom hook that allows you to fetch and process the contents of a GitHub folder. It retrieves information about the files and subfolders in the specified folder, including their names, file types, download URLs, SHA hashes, sizes, and paths.",
5+
"main": "useGitHubFolderTree.tsx",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "git+https://github.com/sauravhathi/github-repository-downloader.git"
12+
},
13+
"keywords": [
14+
"github",
15+
"folder",
16+
"tree",
17+
"repository",
18+
"github-api",
19+
"contents",
20+
"fetch",
21+
"download",
22+
"npm",
23+
"package",
24+
"git-api"
25+
],
26+
"author": "Saurav Hathi",
27+
"license": "MIT",
28+
"bugs": {
29+
"url": "https://github.com/sauravhathi/github-repository-downloader/issues"
30+
},
31+
"homepage": "https://github.com/sauravhathi/github-repository-downloader#readme",
32+
"peerDependencies": {
33+
"react": "^18.2.0",
34+
"react-dom": "^18.2.0"
35+
},
36+
"dependencies": {
37+
"typescript": "^5.0.4"
38+
}
39+
}

useGitHubFolderTree.tsx

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import { useState } from 'react';
2+
import axios from 'axios';
3+
4+
interface RepoFile {
5+
url: string;
6+
name: string;
7+
file_type: string;
8+
download_url: string;
9+
sha: string;
10+
size: string;
11+
path: string;
12+
type?: string;
13+
}
14+
15+
const useGitHubFolderTree = (folderUrl: string, apiKey?: string) => {
16+
const [repoFiles, setRepoFiles] = useState<RepoFile[]>([]);
17+
const [error, setError] = useState<string>('');
18+
const [log, setLog] = useState<string>('');
19+
20+
const fetchFolderData = async (folderUrl: string): Promise<any> => {
21+
const contentIndex = folderUrl.indexOf("contents/") + "contents/".length;
22+
const decodedUrl = decodeURIComponent(contentIndex > 0 ? folderUrl.substring(contentIndex) : folderUrl);
23+
setLog(`Fetching data from ${decodedUrl}`);
24+
const options: any = {};
25+
if (apiKey) {
26+
options.headers = {
27+
Authorization: `Bearer ${apiKey}`,
28+
};
29+
}
30+
const { data: response } = await axios.get(folderUrl, options);
31+
setLog(`Data fetched from ${decodedUrl}`);
32+
return response;
33+
};
34+
35+
const processFolderContents = async (folder: RepoFile[]): Promise<(RepoFile | null)[]> => {
36+
const filePromises = folder.map(async (item: RepoFile) => {
37+
if (item.type === 'file') {
38+
setLog(`Processing ${item.name}`);
39+
const extension = item.name.split('.').pop() || 'unknown';
40+
const sizeInKB = Math.round(parseInt(item.size) / 1024);
41+
let size;
42+
if (sizeInKB >= 1024) {
43+
const sizeInMB = (sizeInKB / 1024).toFixed(2);
44+
size = sizeInMB + ' MB';
45+
} else {
46+
size = sizeInKB + ' KB';
47+
}
48+
49+
return {
50+
name: item.name,
51+
file_type: extension,
52+
download_url: item.download_url,
53+
sha: item.sha,
54+
size: size,
55+
path: item.path,
56+
};
57+
} else if (item.type === 'dir') {
58+
setLog(`Processing ${item.name}`);
59+
const subFolder = await fetchFolderData(item.url);
60+
setLog(`Subfolder data fetched from ${item.url}`);
61+
const subFolderFiles = await processFolderContents(subFolder);
62+
setLog(`Processed ${item.name}`);
63+
return subFolderFiles;
64+
}
65+
66+
return null;
67+
});
68+
69+
const files = await Promise.all(filePromises);
70+
const flattenedFiles = files.flat();
71+
72+
setLog('Processing complete');
73+
return flattenedFiles.filter(Boolean) as (RepoFile | null)[];
74+
};
75+
76+
const fetchRepositoryContents = async () => {
77+
try {
78+
const urlRegex = /https:\/\/github.com\/([^\/]+)\/([^\/]+)\/tree\/([^\/]+)\/?(.*)/;
79+
if (!folderUrl) {
80+
setError('Please enter a GitHub folder URL');
81+
return;
82+
}
83+
84+
const matches = folderUrl.match(urlRegex);
85+
86+
if (!matches) {
87+
setError('Invalid GitHub folder URL');
88+
return;
89+
}
90+
91+
const user = matches[1];
92+
const repo = matches[2];
93+
const branch = matches[3];
94+
const dir = matches[4];
95+
console.log(user, repo, branch, dir);
96+
setLog(`Extracted user: ${user}, repo: ${repo}, branch: ${branch}, dir: ${dir}`);
97+
98+
const apiUrl = `https://api.github.com/repos/${user}/${repo}/contents/${dir}?ref=${branch}`;
99+
setLog(`Fetching repository contents from ${apiUrl}`);
100+
const folderData = await fetchFolderData(apiUrl);
101+
setLog('Folder data fetched');
102+
103+
const processedFiles = await processFolderContents(folderData);
104+
setRepoFiles((prevFiles) => [...prevFiles, ...processedFiles].filter(Boolean) as RepoFile[]);
105+
} catch (error: any) {
106+
setError(error.response?.data?.message || 'An error occurred');
107+
console.error(`Error: ${error}`);
108+
}
109+
};
110+
111+
return {
112+
repoFiles,
113+
error,
114+
log,
115+
fetchRepositoryContents,
116+
};
117+
};
118+
119+
export default useGitHubFolderTree;

0 commit comments

Comments
 (0)
0