@@ -8,92 +8,111 @@ import { Input } from "@/components/ui/input"
8
8
import { Card , CardContent , CardHeader , CardTitle } from "@/components/ui/card"
9
9
import { Loader2 , Download , Github } from 'lucide-react'
10
10
11
+ // Define types for TreeItem and ValidationError
11
12
interface TreeItem {
12
13
path : string
13
14
type : string
14
15
}
15
16
16
17
interface ValidationError {
17
- message : string ;
18
- isError : boolean ;
18
+ message : string
19
+ isError : boolean
19
20
}
20
21
22
+ // Define a recursive type for the directory map structure
23
+ type DirectoryMap = Map < string , DirectoryMap | { type : 'file' } >
24
+
21
25
export default function GitHubProjectStructure ( ) {
22
26
const [ repoUrl , setRepoUrl ] = useState ( '' )
23
27
const [ structure , setStructure ] = useState ( '' )
24
28
const [ loading , setLoading ] = useState ( false )
25
29
const [ validation , setValidation ] = useState < ValidationError > ( { message : '' , isError : false } )
26
30
31
+ // Function to validate GitHub repository URL
27
32
const validateUrl = ( url : string ) : boolean => {
28
- const githubUrlPattern = / ^ h t t p s ? : \/ \/ g i t h u b \. c o m \/ [ \w - ] + \/ [ \w . - ] + \/ ? $ / ;
29
- return githubUrlPattern . test ( url ) ;
33
+ const githubUrlPattern = / ^ h t t p s ? : \/ \/ g i t h u b \. c o m \/ [ \w - ] + \/ [ \w . - ] + \/ ? $ /
34
+ return githubUrlPattern . test ( url )
30
35
}
31
36
37
+ // Handle URL input change and validation
32
38
const handleUrlChange = ( e : React . ChangeEvent < HTMLInputElement > ) => {
33
- const url = e . target . value ;
34
- setRepoUrl ( url ) ;
35
-
39
+ const url = e . target . value
40
+ setRepoUrl ( url )
41
+
36
42
if ( ! url ) {
37
- setValidation ( { message : 'GitHub URL is required' , isError : true } ) ;
43
+ setValidation ( { message : 'GitHub URL is required' , isError : true } )
38
44
} else if ( ! validateUrl ( url ) ) {
39
- setValidation ( { message : 'Enter a valid GitHub URL' , isError : true } ) ;
45
+ setValidation ( { message : 'Enter a valid GitHub URL' , isError : true } )
40
46
} else {
41
- setValidation ( { message : '' , isError : false } ) ;
47
+ setValidation ( { message : '' , isError : false } )
42
48
}
43
49
}
44
50
51
+ // Function to fetch project structure from GitHub
45
52
const fetchProjectStructure = async ( ) => {
46
53
if ( ! repoUrl ) {
47
- setValidation ( { message : 'GitHub URL is required' , isError : true } ) ;
48
- return ;
54
+ setValidation ( { message : 'GitHub URL is required' , isError : true } )
55
+ return
49
56
}
50
57
51
58
if ( ! validateUrl ( repoUrl ) ) {
52
- setValidation ( { message : 'Enter a valid GitHub URL' , isError : true } ) ;
53
- return ;
59
+ setValidation ( { message : 'Enter a valid GitHub URL' , isError : true } )
60
+ return
54
61
}
55
62
56
- setLoading ( true ) ;
63
+ setLoading ( true )
57
64
try {
58
- const [ owner , repo ] = repoUrl . split ( '/' ) . slice ( - 2 ) ;
65
+ const [ owner , repo ] = repoUrl . split ( '/' ) . slice ( - 2 )
59
66
60
- // Fetch the default branch name (either 'main', 'master', or another branch)
61
- const { data : repoData } = await new Octokit ( ) . rest . repos . get ( { owner, repo } ) ;
62
- const defaultBranch = repoData . default_branch ;
67
+ // Fetch the default branch name
68
+ const { data : repoData } = await new Octokit ( ) . rest . repos . get ( { owner, repo } )
69
+ const defaultBranch = repoData . default_branch
63
70
64
71
// Fetch the project structure from the default branch
65
- const { data } = await new Octokit ( ) . rest . git . getTree ( { owner, repo, tree_sha : defaultBranch , recursive : 'true' } ) ;
66
- setStructure ( generateStructure ( data . tree as TreeItem [ ] ) ) ;
67
- setValidation ( { message : '' , isError : false } ) ;
72
+ const { data } = await new Octokit ( ) . rest . git . getTree ( {
73
+ owner,
74
+ repo,
75
+ tree_sha : defaultBranch ,
76
+ recursive : 'true' ,
77
+ } )
78
+
79
+ setStructure ( generateStructure ( data . tree as TreeItem [ ] ) )
80
+ setValidation ( { message : '' , isError : false } )
68
81
} catch ( err ) {
69
- console . error ( err ) ;
70
- setStructure ( 'Error fetching repository structure. Please check the URL and try again.' ) ;
71
- setValidation ( { message : 'Failed to fetch repository structure' , isError : true } ) ;
82
+ console . error ( err )
83
+ setStructure ( 'Error fetching repository structure. Please check the URL and try again.' )
84
+ setValidation ( { message : 'Failed to fetch repository structure' , isError : true } )
72
85
}
73
- setLoading ( false ) ;
86
+ setLoading ( false )
74
87
}
75
88
89
+ // Generate the ASCII directory structure
76
90
const generateStructure = ( tree : TreeItem [ ] ) : string => {
77
- const structureMap = new Map < string , Map < string , any > > ( )
91
+ const structureMap : DirectoryMap = new Map < string , DirectoryMap | { type : 'file' } > ( )
78
92
tree . forEach ( ( item : TreeItem ) => {
79
93
const parts = item . path . split ( '/' )
80
- let currentLevel : Map < string , any > = structureMap
94
+ let currentLevel : DirectoryMap | { type : 'file' } = structureMap
95
+
81
96
parts . forEach ( ( part : string , index : number ) => {
97
+ if ( ! ( currentLevel instanceof Map ) ) return
82
98
if ( ! currentLevel . has ( part ) ) currentLevel . set ( part , new Map ( ) )
83
- if ( index === parts . length - 1 && item . type === 'blob' ) currentLevel . get ( part ) ! . set ( 'type' , 'file' )
99
+ if ( index === parts . length - 1 && item . type === 'blob' ) {
100
+ currentLevel . set ( part , { type : 'file' } )
101
+ }
84
102
currentLevel = currentLevel . get ( part ) !
85
103
} )
86
104
} )
87
105
return buildStructureString ( structureMap )
88
106
}
89
107
90
- const buildStructureString = ( map : Map < string , any > , prefix = '' ) : string => {
108
+ // Build the structure string for display
109
+ const buildStructureString = ( map : DirectoryMap , prefix = '' ) : string => {
91
110
let result = ''
92
111
for ( const [ key , value ] of map . entries ( ) ) {
93
112
if ( key === 'type' ) continue
94
113
result += `${ prefix } ├── ${ key } \n`
95
- if ( value . size > 0 && value . get ( 'type' ) !== 'file' ) {
96
- result += buildStructureString ( value , prefix + ' │ ' )
114
+ if ( value instanceof Map ) {
115
+ result += buildStructureString ( value , ` ${ prefix } │ ` )
97
116
}
98
117
}
99
118
return result
@@ -102,7 +121,9 @@ export default function GitHubProjectStructure() {
102
121
return (
103
122
< Card className = "w-full max-w-4xl mx-auto p-6 md:p-8" id = "generator" >
104
123
< CardHeader >
105
- < CardTitle className = "text-xl font-bold text-center" > Generate Your Repo< span className = "text-blue-600 font-bold" > Tree</ span > </ CardTitle >
124
+ < CardTitle className = "text-xl font-bold text-center" >
125
+ Generate Your Repo< span className = "text-blue-600 font-bold" > Tree</ span >
126
+ </ CardTitle >
106
127
< p className = "text-center text-gray-600" >
107
128
Convert GitHub repository structure into a clean ASCII format, perfect for documentation and sharing.
108
129
</ p >
@@ -158,5 +179,5 @@ export default function GitHubProjectStructure() {
158
179
</ div >
159
180
</ CardContent >
160
181
</ Card >
161
- ) ;
182
+ )
162
183
}
0 commit comments