repos / neovimcraft

website that makes it easy to find neovim plugins
git clone https://github.com/neurosnap/neovimcraft.git

neovimcraft / src
Eric Bower · 27 Nov 22

stht.ts

  1import type { FetchRepoProps, Resp } from "./types.ts";
  2
  3interface SrhtRepo {
  4  id: string;
  5  name: string;
  6  created: string;
  7  updated: string;
  8  readme: string | null;
  9  description: string;
 10  HEAD: { name: string };
 11}
 12
 13interface SrhtRepoResp {
 14  data: {
 15    user: {
 16      repository: SrhtRepo;
 17    };
 18  };
 19}
 20
 21async function fetchReadme(
 22  props: FetchRepoProps,
 23  branch: string,
 24  fpath = "README.md",
 25): Promise<Resp<string>> {
 26  const url =
 27    `https://git.sr.ht/~${props.username}/${props.repo}/blob/${branch}/${fpath}`;
 28  console.log(`Fetching ${url}`);
 29  const resp = await fetch(url);
 30  const readme = await resp.text();
 31  if (!resp.ok) {
 32    return {
 33      ok: false,
 34      data: {
 35        status: resp.status,
 36        error: new Error(`failed to fetch srht readme: ${readme}`),
 37      },
 38    };
 39  }
 40
 41  return { ok: true, data: readme };
 42}
 43
 44async function recurseReadme(
 45  props: FetchRepoProps,
 46  branch: string,
 47  fnames: string[],
 48) {
 49  for (let i = 0; i < fnames.length; i += 1) {
 50    const readme = await fetchReadme(props, branch, fnames[i]);
 51
 52    if (readme.ok) {
 53      return readme.data;
 54    } else {
 55      console.log(`${readme.data.status}: ${readme.data.error.message}`);
 56    }
 57  }
 58
 59  return "";
 60}
 61
 62interface SrhtData {
 63  repo: SrhtRepo;
 64  branch: string;
 65  readme: string;
 66}
 67
 68export async function fetchSrhtData(
 69  props: FetchRepoProps,
 70): Promise<Resp<SrhtData>> {
 71  const query = `\
 72    query {\
 73      user(username: "${props.username}") {\
 74        repository(name: "${props.repo}") {\
 75          id,\
 76          name,\
 77          created,\
 78          updated,\
 79          readme,\
 80          description,\
 81          HEAD { name }\
 82        }\
 83      }\
 84    }`;
 85  const body = { query };
 86
 87  const payload = {
 88    method: "POST",
 89    headers: {
 90      Authorization: `Bearer ${props.token}`,
 91      ["Content-Type"]: "application/json",
 92    },
 93    body: JSON.stringify(body),
 94  };
 95  const url = "https://git.sr.ht/query";
 96  console.log(`Fetching ${url} [${props.username}/${props.repo}]`);
 97  const resp = await fetch(url, payload);
 98
 99  if (!resp.ok) {
100    return {
101      ok: false,
102      data: { status: resp.status, error: new Error("request failed") },
103    };
104  }
105
106  const data: SrhtRepoResp = await resp.json();
107  const repo = data.data.user.repository;
108  const name = repo.HEAD.name;
109  const ref = name.split("/");
110  const branch = ref[ref.length - 1];
111  let readmeData = "";
112  if (repo.readme) {
113    readmeData = repo.readme;
114  } else {
115    // supported readme: https://git.sr.ht/~sircmpwn/scm.sr.ht/tree/83185bf27e1e67ab2ce88851dc7a3f7766075a60/item/scmsrht/formatting.py#L25
116    const fnames = ["README.md", "README.markdown", "README"];
117    readmeData = await recurseReadme(props, branch, fnames);
118  }
119
120  return {
121    ok: true,
122    data: {
123      repo,
124      branch,
125      readme: readmeData,
126    },
127  };
128}