promaster 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/commands/list.js +53 -2
- package/src/download.js +18 -1
package/package.json
CHANGED
package/src/commands/list.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { select, checkbox, confirm } from "@inquirer/prompts";
|
|
1
|
+
import { select, checkbox, confirm, input } from "@inquirer/prompts";
|
|
2
2
|
import { resolve, dirname } from "node:path";
|
|
3
|
+
import { rmSync } from "node:fs";
|
|
4
|
+
import { rm } from "node:fs/promises";
|
|
3
5
|
import { resolveRepo, CATEGORIES } from "../config.js";
|
|
4
6
|
import { listMarkdown, lastCommitDate, fetchRaw, HttpError } from "../github.js";
|
|
5
|
-
import { save, OUTPUT_ROOT } from "../download.js";
|
|
7
|
+
import { save, saveTemp, OUTPUT_ROOT } from "../download.js";
|
|
6
8
|
import { openInBrowser } from "../open.js";
|
|
7
9
|
|
|
8
10
|
const CONCURRENCY = 5;
|
|
@@ -54,6 +56,12 @@ export async function runList() {
|
|
|
54
56
|
return;
|
|
55
57
|
}
|
|
56
58
|
|
|
59
|
+
// books: open immediately, never persist — delete the temp files on exit.
|
|
60
|
+
if (category === "books") {
|
|
61
|
+
await openEphemeral(picked, ctx);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
57
65
|
const saved = [];
|
|
58
66
|
for (const file of picked) {
|
|
59
67
|
const content = await fetchRaw(file.download_url, ctx);
|
|
@@ -73,4 +81,47 @@ export async function runList() {
|
|
|
73
81
|
}
|
|
74
82
|
}
|
|
75
83
|
|
|
84
|
+
// Render picks to OS temp, auto-open in the browser, then delete once the
|
|
85
|
+
// user is done (Enter) or aborts (Ctrl+C). Nothing is left on disk.
|
|
86
|
+
async function openEphemeral(picked, ctx) {
|
|
87
|
+
const dirs = [];
|
|
88
|
+
const cleanup = () => {
|
|
89
|
+
while (dirs.length) {
|
|
90
|
+
try {
|
|
91
|
+
rmSync(dirs.pop(), { recursive: true, force: true });
|
|
92
|
+
} catch {
|
|
93
|
+
/* best effort */
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const onSigint = () => {
|
|
99
|
+
cleanup();
|
|
100
|
+
process.exit(130);
|
|
101
|
+
};
|
|
102
|
+
process.on("SIGINT", onSigint);
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
for (const file of picked) {
|
|
106
|
+
const content = await fetchRaw(file.download_url, ctx);
|
|
107
|
+
const { path, dir } = await saveTemp(file, content);
|
|
108
|
+
dirs.push(dir);
|
|
109
|
+
openInBrowser(path);
|
|
110
|
+
console.log(`Opened in browser: ${file.name}`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
console.log("\nThese are temporary — nothing is saved to disk.");
|
|
114
|
+
await input({
|
|
115
|
+
message: `Press Enter when you're done to delete the temporary file${
|
|
116
|
+
picked.length === 1 ? "" : "s"
|
|
117
|
+
}`,
|
|
118
|
+
});
|
|
119
|
+
} finally {
|
|
120
|
+
process.off("SIGINT", onSigint);
|
|
121
|
+
for (const dir of dirs.splice(0)) {
|
|
122
|
+
await rm(dir, { recursive: true, force: true }).catch(() => {});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
76
127
|
export { HttpError };
|
package/src/download.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { mkdir, writeFile } from "node:fs/promises";
|
|
1
|
+
import { mkdir, mkdtemp, writeFile } from "node:fs/promises";
|
|
2
2
|
import { basename, extname, resolve } from "node:path";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
3
4
|
import { mdToHtml } from "./render.js";
|
|
4
5
|
|
|
5
6
|
export const OUTPUT_ROOT = "promaster-data";
|
|
@@ -40,3 +41,19 @@ export async function save(category, file, content) {
|
|
|
40
41
|
await writeFile(dest, html, "utf8");
|
|
41
42
|
return dest;
|
|
42
43
|
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Render markdown to HTML in a fresh OS temp directory (never under
|
|
47
|
+
* promaster-data). Returns { path, dir } so the caller can delete `dir`
|
|
48
|
+
* once the user is done viewing — nothing is persisted.
|
|
49
|
+
*/
|
|
50
|
+
export async function saveTemp(file, content) {
|
|
51
|
+
const dir = await mkdtemp(resolve(tmpdir(), "promaster-"));
|
|
52
|
+
const base = safeName(file.name);
|
|
53
|
+
const ext = extname(base);
|
|
54
|
+
const title = ext ? base.slice(0, -ext.length) : base;
|
|
55
|
+
const html = mdToHtml(content, { title });
|
|
56
|
+
const path = resolve(dir, htmlName(file.name));
|
|
57
|
+
await writeFile(path, html, "utf8");
|
|
58
|
+
return { path, dir };
|
|
59
|
+
}
|