Skip to content

Commit 9cfdba4

Browse files
authored
Merge pull request mouredev#7177 from hozlucas28/Solution-45-TypeScript
mouredev#45 - TypeScript
2 parents 0673b84 + 4d678d7 commit 9cfdba4

File tree

1 file changed

+307
-0
lines changed

1 file changed

+307
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
import readline from 'node:readline/promises'
2+
3+
/* -------------------------------------------------------------------------- */
4+
/* TYPES */
5+
/* -------------------------------------------------------------------------- */
6+
7+
interface GitHubAPI {
8+
user: {
9+
avatar_url: string
10+
bio: string
11+
blog: string
12+
company?: string
13+
created_at: string
14+
email?: string
15+
events_url: string
16+
followers_url: string
17+
followers: number
18+
following_url: string
19+
following: number
20+
gists_url: string
21+
gravatar_id: string
22+
hireable: true
23+
html_url: string
24+
id: number
25+
location: string
26+
login: string
27+
name: string
28+
node_id: string
29+
organizations_url: string
30+
public_gists: number
31+
public_repos: number
32+
received_events_url: string
33+
repos_url: string
34+
site_admin: boolean
35+
starred_url: string
36+
subscriptions_url: string
37+
twitter_username: string
38+
type: string
39+
updated_at: string
40+
url: string
41+
user_view_type: string
42+
43+
public_repos_data: {
44+
allow_forking: boolean
45+
archive_url: string
46+
archived: boolean
47+
assignees_url: string
48+
blobs_url: string
49+
branches_url: string
50+
clone_url: string
51+
collaborators_url: string
52+
comments_url: string
53+
commits_url: string
54+
compare_url: string
55+
contents_url: string
56+
contributors_url: string
57+
created_at: string
58+
default_branch: string
59+
deployments_url: string
60+
description: string
61+
disabled: boolean
62+
downloads_url: string
63+
events_url: string
64+
fork: boolean
65+
forks_count: number
66+
forks_url: string
67+
forks: number
68+
full_name: string
69+
git_commits_url: string
70+
git_refs_url: string
71+
git_tags_url: string
72+
git_url: string
73+
has_discussions: boolean
74+
has_downloads: boolean
75+
has_issues: boolean
76+
has_pages: boolean
77+
has_projects: boolean
78+
has_wiki: boolean
79+
homepage: string
80+
hooks_url: string
81+
html_url: string
82+
id: number
83+
is_template: boolean
84+
issue_comment_url: string
85+
issue_events_url: string
86+
issues_url: string
87+
keys_url: string
88+
labels_url: string
89+
language: string
90+
languages_url: string
91+
merges_url: string
92+
milestones_url: string
93+
mirror_url?: string
94+
name: string
95+
node_id: string
96+
notifications_url: string
97+
open_issues_count: number
98+
open_issues: number
99+
private: boolean
100+
pulls_url: string
101+
pushed_at: string
102+
releases_url: string
103+
size: number
104+
ssh_url: string
105+
stargazers_count: number
106+
stargazers_url: string
107+
statuses_url: string
108+
subscribers_url: string
109+
subscription_url: string
110+
svn_url: string
111+
tags_url: string
112+
teams_url: string
113+
trees_url: string
114+
updated_at: string
115+
url: string
116+
visibility: string
117+
watchers_count: number
118+
watchers: number
119+
web_commit_signoff_required: boolean
120+
}[]
121+
122+
stars: {
123+
avatar_url: string
124+
events_url: string
125+
followers_url: string
126+
following_url: string
127+
gists_url: string
128+
gravatar_id: string
129+
html_url: string
130+
id: number
131+
login: string
132+
node_id: string
133+
organizations_url: string
134+
received_events_url: string
135+
repos_url: string
136+
site_admin: boolean
137+
starred_url: string
138+
subscriptions_url: string
139+
type: string
140+
url: string
141+
user_view_type: string
142+
}[]
143+
}
144+
}
145+
146+
/* -------------------------------------------------------------------------- */
147+
/* FUNCTIONS */
148+
/* -------------------------------------------------------------------------- */
149+
150+
interface GetUserInputParams {
151+
message: string
152+
onFail?: (userInput: string) => void
153+
validator?: (userInput: string) => boolean
154+
}
155+
156+
async function getUserInput({
157+
message,
158+
onFail = () => {},
159+
validator = () => true,
160+
}: GetUserInputParams): Promise<string> {
161+
let userInput: string
162+
163+
const rl = readline.createInterface({
164+
input: process.stdin,
165+
output: process.stdout,
166+
})
167+
168+
userInput = await rl.question(message)
169+
170+
while (!validator(userInput)) {
171+
onFail(userInput)
172+
userInput = await rl.question(message)
173+
}
174+
175+
rl.close()
176+
177+
userInput = userInput.trim()
178+
179+
return userInput.trim()
180+
}
181+
182+
/* -------------------------------------------------------------------------- */
183+
/* CLASSES */
184+
/* -------------------------------------------------------------------------- */
185+
186+
interface GitHubUserData {
187+
followers: number
188+
following: number
189+
forks: number
190+
name: string
191+
publicRepositories: number
192+
stars: number
193+
userName: string
194+
}
195+
196+
interface IGitHubService {
197+
fetchUserData: (userName: string) => Promise<GitHubUserData>
198+
}
199+
200+
class GitHubService implements IGitHubService {
201+
public constructor() {}
202+
203+
private userDataAdapter(userData: GitHubAPI['user']): GitHubUserData {
204+
let forks: number = 0
205+
for (const publicRepo of userData.public_repos_data) {
206+
if (publicRepo.fork) forks++
207+
}
208+
209+
return {
210+
followers: userData.followers,
211+
following: userData.following,
212+
forks,
213+
name: userData.name,
214+
publicRepositories: userData.public_repos,
215+
stars: userData.stars.length,
216+
userName: userData.login,
217+
}
218+
}
219+
220+
public async fetchUserData(userName: string): Promise<GitHubUserData> {
221+
let response = await fetch(`https://api.github.com/users/${userName}`)
222+
if (!response.ok)
223+
throw new Error('An error occurred on fetch user data')
224+
225+
const userData = (await response.json()) as GitHubAPI['user']
226+
227+
response = await fetch(
228+
`https://api.github.com/users/${userName}/starred`
229+
)
230+
if (!response.ok)
231+
throw new Error('An error occurred on fetch user data')
232+
233+
const stars = (await response.json()) as GitHubAPI['user']['stars']
234+
userData.stars = stars
235+
236+
response = await fetch(userData.repos_url)
237+
if (!response.ok)
238+
throw new Error('An error occurred on fetch user data')
239+
240+
const publicRepositories =
241+
(await response.json()) as GitHubAPI['user']['public_repos_data']
242+
userData.public_repos_data = publicRepositories
243+
244+
return this.userDataAdapter(userData)
245+
}
246+
}
247+
248+
/* -------------------------------------------------------------------------- */
249+
/* MAIN */
250+
/* -------------------------------------------------------------------------- */
251+
252+
;(async () => {
253+
let userData: GitHubUserData
254+
const githubService: IGitHubService = new GitHubService()
255+
256+
let userInput: string = await getUserInput({
257+
message: '> Enter a GitHub username (-1 to exit): ',
258+
})
259+
260+
while (userInput !== '-1') {
261+
try {
262+
userData = await githubService.fetchUserData(userInput)
263+
264+
console.clear()
265+
266+
console.log('+'.padEnd(55, '-') + '+')
267+
console.log(
268+
'+' + userData.userName.padStart(27, ' ').padEnd(54, ' ') + '+'
269+
)
270+
console.log('+'.padEnd(55, '-') + '+')
271+
272+
console.log(`+ Name: ${userData.name}.`.padEnd(55, ' ') + '+')
273+
console.log(
274+
`+ Public repositories: ${userData.publicRepositories}.`.padEnd(
275+
55,
276+
' '
277+
) + '+'
278+
)
279+
console.log(
280+
`+ Repositories stared: ${userData.stars}.`.padEnd(55, ' ') +
281+
'+'
282+
)
283+
console.log(
284+
`+ Number of repositories forked: ${userData.forks}.`.padEnd(
285+
55,
286+
' '
287+
) + '+'
288+
)
289+
console.log(
290+
`+ Following: ${userData.following}.`.padEnd(55, ' ') + '+'
291+
)
292+
console.log(
293+
`+ Followers: ${userData.followers}.`.padEnd(55, ' ') + '+'
294+
)
295+
296+
console.log('+'.padEnd(55, '-') + '+')
297+
} catch (error) {
298+
console.log(
299+
`\n> An error occurred on fetch "${userInput}" username! Try again...`
300+
)
301+
}
302+
303+
userInput = await getUserInput({
304+
message: '\n> Enter a new GitHub username (-1 to exit): ',
305+
})
306+
}
307+
})()

0 commit comments

Comments
 (0)