-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprocess.ts
More file actions
118 lines (100 loc) · 3.21 KB
/
process.ts
File metadata and controls
118 lines (100 loc) · 3.21 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
import * as fs from "fs";
import * as os from "os";
import {Octokit, RestEndpointMethodTypes} from "@octokit/rest";
import {sleep} from "extra-sleep";
//#region TYPES
/** A gist object. */
type Gist = RestEndpointMethodTypes["gists"]["listPublic"]["response"]["data"][0];
/** Test whether a gist satisfies the condition. */
type GistTestFn = (gist: Gist) => boolean;
//#endregion
//#region HELPERS
/**
* Read a text file.
* @param pth path to the file
* @returns file content
*/
async function readTextFile(pth: string) {
var data = await fs.promises.readFile(pth, "utf8");
return data.replace(/\r\n|\r/g, "\n");
}
/**
* Write a text file.
* @param pth path to the file
* @param text file content
*/
async function writeTextFile(pth: string, text: string) {
var data = text.replace(/\r\n|\r/g, os.EOL);
await fs.promises.writeFile(pth, data);
}
//#endregion
//#region METHODS
/**
* Fetch user's public gists, and filter by filename and description (regex).
* @param octokit github api client
* @param ft filter function (gist) => boolean
* @returns array of matching gists
*/
async function fetchGists(octokit: Octokit, ft: GistTestFn) {
var per_page = 100, page = 0, gists: Gist[] = [];
while (true) {
try { var res = await octokit.gists.list({per_page, page, public: true}); }
catch (e) { continue; }
var filtered = res.data.filter(ft);
console.log(`Page ${page+1}: ${filtered.length} matching gists`);
gists.push(...filtered);
if (res.data.length < per_page) break;
await sleep(1000);
page++;
}
console.log(`Total ${gists.length} matching gists`);
return gists;
}
/**
* Fetch linked gists from a markdown file.
* @param pth path to markdown file
* @returns array of linked gists
*/
async function linkedGists(pth: string) {
var re = /\[([^\]]+)\]\(https:\/\/gist\.github\.com\/[^)]+\)/g;
var text = await readTextFile(pth);
var matches: string[] = [], m: RegExpExecArray | null;
while ((m = re.exec(text)) != null)
matches.push(m[1]);
return matches;
}
/**
* Main function.
*/
async function main() {
var auth = process.env.GITHUB_TOKEN;
var octokit = new Octokit({auth});
var pth = "details/notes.md";
var refilt = /NOTES$/;
var rerepl = /\s+:\s+.*/;
// Fetch all gists (NOTES).
console.log("Fetching gists...");
var ft: GistTestFn = gist => refilt.test(gist.description || "");
var gists = await fetchGists(octokit, ft);
// Fetch already linked gists.
var linked = await linkedGists(pth);
console.log(`Already linked ${linked.length} gists`);
// Find unlinked gists.
var unlinked = gists.filter(gist => !linked.includes(gist.description?.replace(rerepl, "").trim() || "\0"));
console.log(`Unlinked ${unlinked.length} gists`);
if (unlinked.length === 0) return;
// Append unlinked gists.
console.log("Appending unlinked gists...");
var text = await readTextFile(pth);
text += "\n\n";
unlinked.reverse(); // Gists are sorted by recent first
var added = new Set<string>();
for (var gist of unlinked) {
var line = `- [${gist.description?.replace(rerepl, "").trim()}](${gist.html_url})\n`;
if (!added.has(line)) { text += line; added.add(line); }
}
await writeTextFile(pth, text);
console.log("Done\n");
}
main();
//#endregion