-
Notifications
You must be signed in to change notification settings - Fork 57
Expand file tree
/
Copy pathgist.ts
More file actions
165 lines (148 loc) · 3.9 KB
/
gist.ts
File metadata and controls
165 lines (148 loc) · 3.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/**
* Copyright (c) 2022-present Hengyang Zhang
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
import FIFOCache from "@util/fifo-cache"
import { fetchGet, fetchPost } from "./http"
type BaseFile = {
filename: string
}
export type FileForm = BaseFile & {
content: string
}
export type File = BaseFile & {
type: string
language: string
raw_url: string
content?: string
}
type BaseGist<FileInfo> = {
public: boolean
description: string
files: { [filename: string]: FileInfo | null }
}
export type Gist = BaseGist<File> & {
id: string
}
export type GistForm = BaseGist<FileForm>
const BASE_URL = 'https://api.github.com/gists'
/**
* Cache of get requests
*/
const GET_CACHE = new FIFOCache<unknown>(20)
async function get<T>(token: string, uri: string): Promise<T> {
const cacheKey = uri + token
return await GET_CACHE.getOrSupply(cacheKey, async () => {
const headers = {
"Accept": "application/vnd.github+json",
"Authorization": `token ${token}`
}
const url = BASE_URL + uri
const response = await fetchGet(url, { headers })
return await response.json()
}) as T
}
async function post<T, R>(token: string, uri: string, body?: R): Promise<T> {
const response = await fetchPost<R>(BASE_URL + uri, body, {
headers: {
"Accept": "application/vnd.github+json",
"Authorization": `token ${token}`
}
})
const result = await response.json()
const { status } = response
if (status >= 200 && status < 300) {
// Clear cache if success to request
GET_CACHE.clear()
return result as T
}
throw new Error(JSON.stringify(result))
}
/**
* @param token token
* @param id id
* @returns detail of Gist
*/
export function getGist(token: string, id: string): Promise<Gist> {
return get(token, `/${id}`)
}
/**
* Find the first target gist with predicate
*
* @param token gist token
* @param predicate predicate
* @returns
*/
export async function findTarget(token: string, predicate: (gist: Gist) => boolean): Promise<Gist | null> {
let pageNum = 1
while (true) {
const uri = `?per_page=100&page=${pageNum}`
const gists: Gist[] = await get(token, uri)
if (!gists?.length) {
break
}
const satisfied = gists.find(predicate)
if (satisfied) {
return satisfied
}
pageNum += 1
}
return null
}
/**
* Create one gist
*
* @param token token
* @param gist gist info
* @returns gist info with id
*/
export function createGist(token: string, gist: GistForm): Promise<Gist> {
return post(token, "", gist)
}
/**
* Update gist
*
* @param token token
* @param gist gist
* @returns
*/
export async function updateGist(token: string, id: string, gist: GistForm): Promise<void> {
await post(token, `/${id}`, gist)
}
/**
* Get content of file
*/
export async function getJsonFileContent<T>(file: File): Promise<T | null> {
const content = file.content
if (content) {
try {
return JSON.parse(content)
} catch (e) {
console.warn("Failed to parse content of: " + file.raw_url)
console.warn(e)
}
}
const rawUrl = file.raw_url
if (!rawUrl) {
return null
}
const response = await fetchGet(rawUrl)
return await response.json()
}
/**
* Test token to process gist
*
* @returns errorMsg or null/undefined
*/
export async function testToken(token: string): Promise<string | undefined> {
const response = await fetchGet(BASE_URL + '?per_page=1&page=1', {
headers: {
"Accept": "application/vnd.github+json",
"Authorization": `token ${token}`
}
})
const { status, statusText } = response || {}
return status === 200 ? undefined : statusText || ("ERROR " + status)
}