aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/index.ts31
-rw-r--r--src/scraper.test.ts12
-rw-r--r--src/scraper.ts11
3 files changed, 45 insertions, 9 deletions
diff --git a/src/index.ts b/src/index.ts
index 388b1e0..51e8cf2 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,10 +1,11 @@
import { createAdaptorServer, serve } from "@hono/node-server";
import { serveStatic } from "@hono/node-server/serve-static";
import { Eta } from "eta";
-import { Hono } from "hono";
+import { type Context, Hono } from "hono";
+import type { StatusCode } from "hono/utils/http-status";
import path from "node:path";
import url from "node:url";
-import { getGitHubBlob, getGitHubRepo, getGitHubTree } from "./scraper.ts";
+import { getGitHubBlob, getGitHubRepo, getGitHubTree, GitHubHTTPError } from "./scraper.ts";
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
@@ -17,22 +18,36 @@ app.get("/", async (c) => {
return c.html(await eta.renderAsync("home.eta", {}));
});
+async function tryRender<T extends object>(c: Context, template: string, promise: Promise<T>) {
+ let data: T;
+ try {
+ data = await promise;
+ } catch (e) {
+ if (e instanceof GitHubHTTPError) {
+ c.status(e.status as StatusCode);
+ const message = `GitHub responded with HTTP ${e.status} ${e.message}`;
+ return c.html(await eta.renderAsync("error.eta", { title: e.message, message }));
+ } else {
+ c.status(500);
+ return c.html(await eta.renderAsync("error.eta", { message: "" + e }));
+ }
+ }
+ return c.html(await eta.renderAsync(template, data));
+}
+
app.get("/:owner/:repo", async (c) => {
const { owner, repo } = c.req.param();
- const data = await getGitHubRepo(owner, repo);
- return c.html(await eta.renderAsync("repo.eta", data));
+ return tryRender(c, "repo.eta", getGitHubRepo(owner, repo));
});
app.get("/:owner/:repo/tree/:branch/:path{.*}?", async (c) => {
const { owner, repo, branch, path = "" } = c.req.param();
- const data = await getGitHubTree(owner, repo, branch, path);
- return c.html(await eta.renderAsync("tree.eta", data));
+ return tryRender(c, "tree.eta", getGitHubTree(owner, repo, branch, path));
});
app.get("/:owner/:repo/blob/:branch/:path{.*}", async (c) => {
const { owner, repo, branch, path } = c.req.param();
- const data = await getGitHubBlob(owner, repo, branch, path);
- return c.html(await eta.renderAsync("blob.eta", data));
+ return tryRender(c, "blob.eta", getGitHubBlob(owner, repo, branch, path));
});
app.get("/:owner/:repo/raw/:branch/:path{.*}", async (c) => {
diff --git a/src/scraper.test.ts b/src/scraper.test.ts
index 3784190..adf70ae 100644
--- a/src/scraper.test.ts
+++ b/src/scraper.test.ts
@@ -1,6 +1,6 @@
import assert from "node:assert";
import { describe, it } from "node:test";
-import { getGitHubBlob, getGitHubRepo, getGitHubTree } from "./scraper.ts";
+import { getGitHubBlob, getGitHubRepo, getGitHubTree, GitHubHTTPError } from "./scraper.ts";
describe("GitHub scraper", () => {
describe("actions/deploy-pages repository", () => {
@@ -67,4 +67,14 @@ describe("GitHub scraper", () => {
assert.match(data.content, /^MIT License\n\n/);
});
});
+
+ describe("error handling", () => {
+ it("should throw for non-existent repository", async () => {
+ await assert.rejects(getGitHubRepo("nosuchowner", "nosuchrepo"), (err) => {
+ assert(err instanceof GitHubHTTPError, "error should be an HTTPError");
+ assert.strictEqual(err.status, 404);
+ return true;
+ });
+ });
+ });
});
diff --git a/src/scraper.ts b/src/scraper.ts
index 4feda73..b76f8c8 100644
--- a/src/scraper.ts
+++ b/src/scraper.ts
@@ -1,3 +1,13 @@
+export class GitHubHTTPError extends Error {
+ status: number;
+
+ constructor(status: number, message: string) {
+ super(message);
+ this.name = "GitHubHTTPError";
+ this.status = status;
+ }
+}
+
interface TreeItem {
contentType: "directory" | "file";
name: string;
@@ -78,6 +88,7 @@ async function fetchGitHubPage(path: string): Promise<string> {
"Accept-Language": "en-US,en;q=0.5",
};
const response = await fetch(`https://github.com/${path}`, { headers });
+ if (!response.ok) throw new GitHubHTTPError(response.status, response.statusText);
return response.text();
}