diff --git a/denops/gin/git/__snapshots__/hosting_service_test.ts.snap b/denops/gin/git/__snapshots__/hosting_service_test.ts.snap new file mode 100644 index 00000000..8bb72b89 --- /dev/null +++ b/denops/gin/git/__snapshots__/hosting_service_test.ts.snap @@ -0,0 +1,249 @@ +export const snapshot = {}; + +snapshot[`getHostingService 1`] = ` +{ + result: URL { + hash: "", + host: "github.com", + hostname: "github.com", + href: "https://github.com/lambdalisue/gin.vim", + origin: "https://github.com", + password: "", + pathname: "/lambdalisue/gin.vim", + port: "", + protocol: "https:", + search: "", + username: "", + }, + url: URL { + hash: "", + host: "github.com", + hostname: "github.com", + href: "https://github.com/lambdalisue/gin.vim", + origin: "https://github.com", + password: "", + pathname: "/lambdalisue/gin.vim", + port: "", + protocol: "https:", + search: "", + username: "", + }, +} +`; + +snapshot[`getHostingService 2`] = ` +{ + result: URL { + hash: "", + host: "github.com", + hostname: "github.com", + href: "https://github.com/lambdalisue/gin.vim/blob/main/denops/gin/main.ts", + origin: "https://github.com", + password: "", + pathname: "/lambdalisue/gin.vim/blob/main/denops/gin/main.ts", + port: "", + protocol: "https:", + search: "", + username: "", + }, + url: URL { + hash: "", + host: "github.com", + hostname: "github.com", + href: "https://github.com/lambdalisue/gin.vim", + origin: "https://github.com", + password: "", + pathname: "/lambdalisue/gin.vim", + port: "", + protocol: "https:", + search: "", + username: "", + }, +} +`; + +snapshot[`getHostingService 3`] = ` +{ + result: URL { + hash: "#L10", + host: "github.com", + hostname: "github.com", + href: "https://github.com/lambdalisue/gin.vim/blob/main/denops/gin/main.ts?plain=1#L10", + origin: "https://github.com", + password: "", + pathname: "/lambdalisue/gin.vim/blob/main/denops/gin/main.ts", + port: "", + protocol: "https:", + search: "?plain=1", + username: "", + }, + url: URL { + hash: "", + host: "github.com", + hostname: "github.com", + href: "https://github.com/lambdalisue/gin.vim", + origin: "https://github.com", + password: "", + pathname: "/lambdalisue/gin.vim", + port: "", + protocol: "https:", + search: "", + username: "", + }, +} +`; + +snapshot[`getHostingService 4`] = ` +{ + result: URL { + hash: "#L10-L20", + host: "github.com", + hostname: "github.com", + href: "https://github.com/lambdalisue/gin.vim/blob/main/denops/gin/main.ts?plain=1#L10-L20", + origin: "https://github.com", + password: "", + pathname: "/lambdalisue/gin.vim/blob/main/denops/gin/main.ts", + port: "", + protocol: "https:", + search: "?plain=1", + username: "", + }, + url: URL { + hash: "", + host: "github.com", + hostname: "github.com", + href: "https://github.com/lambdalisue/gin.vim", + origin: "https://github.com", + password: "", + pathname: "/lambdalisue/gin.vim", + port: "", + protocol: "https:", + search: "", + username: "", + }, +} +`; + +snapshot[`getHostingService 5`] = ` +{ + result: URL { + hash: "", + host: "github.com", + hostname: "github.com", + href: "https://github.com/lambdalisue/gin.vim", + origin: "https://github.com", + password: "", + pathname: "/lambdalisue/gin.vim", + port: "", + protocol: "https:", + search: "", + username: "", + }, + url: URL { + hash: "", + host: "github.com", + hostname: "github.com", + href: "ssh://git@github.com/lambdalisue/gin.vim", + origin: "null", + password: "", + pathname: "/lambdalisue/gin.vim", + port: "", + protocol: "ssh:", + search: "", + username: "git", + }, +} +`; + +snapshot[`getHostingService 6`] = ` +{ + result: URL { + hash: "", + host: "github.com", + hostname: "github.com", + href: "https://github.com/lambdalisue/gin.vim/blob/main/denops/gin/main.ts", + origin: "https://github.com", + password: "", + pathname: "/lambdalisue/gin.vim/blob/main/denops/gin/main.ts", + port: "", + protocol: "https:", + search: "", + username: "", + }, + url: URL { + hash: "", + host: "github.com", + hostname: "github.com", + href: "ssh://git@github.com/lambdalisue/gin.vim", + origin: "null", + password: "", + pathname: "/lambdalisue/gin.vim", + port: "", + protocol: "ssh:", + search: "", + username: "git", + }, +} +`; + +snapshot[`getHostingService 7`] = ` +{ + result: URL { + hash: "#L10", + host: "github.com", + hostname: "github.com", + href: "https://github.com/lambdalisue/gin.vim/blob/main/denops/gin/main.ts?plain=1#L10", + origin: "https://github.com", + password: "", + pathname: "/lambdalisue/gin.vim/blob/main/denops/gin/main.ts", + port: "", + protocol: "https:", + search: "?plain=1", + username: "", + }, + url: URL { + hash: "", + host: "github.com", + hostname: "github.com", + href: "ssh://git@github.com/lambdalisue/gin.vim", + origin: "null", + password: "", + pathname: "/lambdalisue/gin.vim", + port: "", + protocol: "ssh:", + search: "", + username: "git", + }, +} +`; + +snapshot[`getHostingService 8`] = ` +{ + result: URL { + hash: "#L10-L20", + host: "github.com", + hostname: "github.com", + href: "https://github.com/lambdalisue/gin.vim/blob/main/denops/gin/main.ts?plain=1#L10-L20", + origin: "https://github.com", + password: "", + pathname: "/lambdalisue/gin.vim/blob/main/denops/gin/main.ts", + port: "", + protocol: "https:", + search: "?plain=1", + username: "", + }, + url: URL { + hash: "", + host: "github.com", + hostname: "github.com", + href: "ssh://git@github.com/lambdalisue/gin.vim", + origin: "null", + password: "", + pathname: "/lambdalisue/gin.vim", + port: "", + protocol: "ssh:", + search: "", + username: "git", + }, +} +`; diff --git a/denops/gin/git/hosting_service.ts b/denops/gin/git/hosting_service.ts new file mode 100644 index 00000000..2fd514af --- /dev/null +++ b/denops/gin/git/hosting_service.ts @@ -0,0 +1,18 @@ +export type HostingService = { + getRootURL(): URL; + getBlobURL( + commitish: string, + filename: string, + options?: { lineStart?: number; lineEnd?: number }, + ): URL; +}; + +export async function getHostingService( + url: URL, +): Promise { + const svcName = url.hostname.replace(/\W/g, "_"); + const svc = await import( + new URL(`./hosting_service/${svcName}.ts`, import.meta.url).href + ); + return new svc.Service(url); +} diff --git a/denops/gin/git/hosting_service/github_com.ts b/denops/gin/git/hosting_service/github_com.ts new file mode 100644 index 00000000..d5457781 --- /dev/null +++ b/denops/gin/git/hosting_service/github_com.ts @@ -0,0 +1,34 @@ +import { HostingService } from "../hosting_service.ts"; + +export class Service implements HostingService { + #url: URL; + + constructor(url: URL) { + this.#url = url; + } + + getRootURL(): URL { + const [owner, repo] = this.#url.pathname.split("/").slice(1); + return new URL( + `https://${this.#url.hostname}/${owner}/${repo}`, + ); + } + + getBlobURL( + commitish: string, + filename: string, + { lineStart, lineEnd }: { lineStart?: number; lineEnd?: number } = {}, + ): URL { + const [owner, repo] = this.#url.pathname.split("/").slice(1); + // Note: + // Without `?plain=1`, GitHub shows the rendering result of content (e.g. Markdown) so that we + // cannot specify the line range. + const suffix = lineStart && lineEnd + ? `?plain=1#L${lineStart}-L${lineEnd}` + : lineStart + ? `?plain=1#L${lineStart}` + : ""; + const pathname = `${owner}/${repo}/blob/${commitish}/${filename}${suffix}`; + return new URL(`https://${this.#url.hostname}/${pathname}`); + } +} diff --git a/denops/gin/git/hosting_service_test.ts b/denops/gin/git/hosting_service_test.ts new file mode 100644 index 00000000..f6a3429e --- /dev/null +++ b/denops/gin/git/hosting_service_test.ts @@ -0,0 +1,55 @@ +import { assertSnapshot } from "https://deno.land/std@0.192.0/testing/snapshot.ts"; +import { getHostingService } from "./hosting_service.ts"; + +Deno.test("getHostingService", async (t) => { + const urls = [ + new URL("https://github.com/lambdalisue/gin.vim"), + new URL("ssh://git@github.com/lambdalisue/gin.vim"), + ]; + + for (const url of urls) { + await t.step(`getRootURL for ${url}`, async () => { + const svc = await getHostingService(url); + const result = svc.getRootURL(); + await assertSnapshot(t, { + url, + result, + }); + }); + + await t.step(`getBlobURL for ${url}`, async () => { + const svc = await getHostingService(url); + const result = svc.getBlobURL("main", "denops/gin/main.ts"); + await assertSnapshot(t, { + url, + result, + }); + }); + + await t.step(`getBlobURL with lineStart for ${url}`, async () => { + const svc = await getHostingService(url); + const result = svc.getBlobURL("main", "denops/gin/main.ts", { + lineStart: 10, + }); + await assertSnapshot(t, { + url, + result, + }); + }); + + await t.step( + `getBlobURL with lineStart/lineEnd for ${url}`, + async () => { + const svc = await getHostingService(url); + const result = svc.getBlobURL("main", "denops/gin/main.ts", { + lineStart: 10, + lineEnd: 20, + }); + await assertSnapshot(t, { + url, + result, + }); + }, + ); + } +});