Merge branch 'main' of https://git.prelude.duckdns.org/monoid/simple-deno-import-gitea
This commit is contained in:
		
						commit
						8a67f4fbdb
					
				
					 2 changed files with 68 additions and 23 deletions
				
			
		
							
								
								
									
										59
									
								
								app.ts
									
										
									
									
									
								
							
							
						
						
									
										59
									
								
								app.ts
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -2,18 +2,27 @@ import { Application, Router, isHttpError } from "https://deno.land/x/oak@v12.1.
 | 
			
		|||
import {
 | 
			
		||||
    searchRepositoryWithTopic,
 | 
			
		||||
    getRepositoryTags,
 | 
			
		||||
    getRepositoryContent
 | 
			
		||||
    getRepositoryContent,
 | 
			
		||||
    GiteaOption
 | 
			
		||||
} from "./gitea.ts";
 | 
			
		||||
import { ContentsResponse } from "./gitea_api.d.ts";
 | 
			
		||||
import { Command } from "https://deno.land/x/cliffy@v0.25.7/mod.ts";
 | 
			
		||||
 | 
			
		||||
// import { load } from "https://deno.land/std@0.181.0/dotenv/mod.ts";
 | 
			
		||||
// const env = await load();
 | 
			
		||||
import { load } from "https://deno.land/std@0.191.0/dotenv/mod.ts";
 | 
			
		||||
const env = await load();
 | 
			
		||||
 | 
			
		||||
function getGiteaOptions(): GiteaOption | undefined {
 | 
			
		||||
    const token = env.TOKEN;
 | 
			
		||||
    if (token === undefined) {
 | 
			
		||||
        return undefined
 | 
			
		||||
    }
 | 
			
		||||
    return { token: token };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const app = new Application();
 | 
			
		||||
const router = new Router();
 | 
			
		||||
 | 
			
		||||
const RelativeTopic = "denolib";
 | 
			
		||||
const RelativeTopic = env.tag ?? "denolib";
 | 
			
		||||
 | 
			
		||||
export interface CompletionList {
 | 
			
		||||
    /** The list (or partial list) of completion items. */
 | 
			
		||||
| 
						 | 
				
			
			@ -37,7 +46,7 @@ router.get("/.well-known/deno-import-intellisense.json", (ctx) => {
 | 
			
		|||
                "variables": [
 | 
			
		||||
                    {
 | 
			
		||||
                        "key": "package",
 | 
			
		||||
                    //    "documentation": "/docs/packages/${package}",
 | 
			
		||||
                        //    "documentation": "/docs/packages/${package}",
 | 
			
		||||
                        "url": "/packages/${package}"
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
| 
						 | 
				
			
			@ -46,7 +55,7 @@ router.get("/.well-known/deno-import-intellisense.json", (ctx) => {
 | 
			
		|||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        "key": "path",
 | 
			
		||||
                    //    "documentation": "/docs/packages/${package}/${{version}}/paths/${path}",
 | 
			
		||||
                        //    "documentation": "/docs/packages/${package}/${{version}}/paths/${path}",
 | 
			
		||||
                        "url": "/packages/${package}/${{version}}/paths/${path}"
 | 
			
		||||
                    }
 | 
			
		||||
                ]
 | 
			
		||||
| 
						 | 
				
			
			@ -58,10 +67,11 @@ router.get("/.well-known/deno-import-intellisense.json", (ctx) => {
 | 
			
		|||
router.get("/packages/:package", async (ctx) => {
 | 
			
		||||
    const packageName = ctx.params.package;
 | 
			
		||||
    console.log(`searchRepositoryWithTopic: ${packageName}`);
 | 
			
		||||
    const repositories = await searchRepositoryWithTopic(RelativeTopic);
 | 
			
		||||
    const options = getGiteaOptions();
 | 
			
		||||
    const repositories = await searchRepositoryWithTopic(RelativeTopic, options);
 | 
			
		||||
    const repo_name = repositories.data?.map((repo) => repo.full_name)
 | 
			
		||||
        .filter(x => x !== undefined)
 | 
			
		||||
        .map(x=> x?.replace("/","@")) ?? [];
 | 
			
		||||
        .map(x => x?.replace("/", "@")) ?? [];
 | 
			
		||||
    const completionList: CompletionList = {
 | 
			
		||||
        items: repo_name as string[],
 | 
			
		||||
        isIncomplete: true, // TODO: check if there are more than max results
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +85,8 @@ router.get("/packages/:package/versions", async (ctx) => {
 | 
			
		|||
    const packageName = ctx.params.package;
 | 
			
		||||
    const [owner, repo] = packageName.split("@");
 | 
			
		||||
    console.log(`getTags: owner: ${owner}, repo: ${repo}`);
 | 
			
		||||
    const tags = await getRepositoryTags(owner, repo);
 | 
			
		||||
    const options = getGiteaOptions();
 | 
			
		||||
    const tags = await getRepositoryTags(owner, repo, options);
 | 
			
		||||
    const candidate = ["main", ...tags.map((tag) => tag.name) as string[]]
 | 
			
		||||
    const completionList: CompletionList = {
 | 
			
		||||
        items: candidate,
 | 
			
		||||
| 
						 | 
				
			
			@ -92,7 +103,8 @@ router.get("/packages/:package/:version/paths/:path*", async (ctx) => {
 | 
			
		|||
    const path = ctx.params.path;
 | 
			
		||||
    const [owner, repo] = packageName.split("@");
 | 
			
		||||
    console.log(`getFilesEntry: owner: ${owner}, repo: ${repo}, path: ${path}, version: ${version}`);
 | 
			
		||||
    const entries = await getRepositoryContent(owner, repo, path ?? "", version) as ContentsResponse[];
 | 
			
		||||
    const options = getGiteaOptions();
 | 
			
		||||
    const entries = await getRepositoryContent(owner, repo, path ?? "", version, options) as ContentsResponse[];
 | 
			
		||||
    const completionList: CompletionList = {
 | 
			
		||||
        items: entries.map((entry) => entry.name) as string[],
 | 
			
		||||
        isIncomplete: false,
 | 
			
		||||
| 
						 | 
				
			
			@ -108,13 +120,14 @@ router.get("/:package([a-z0-9_]*@[a-z0-9_]*)/:version?/:path*", async (ctx) => {
 | 
			
		|||
    const version = ctx.params.version;
 | 
			
		||||
    const path = ctx.params.path;
 | 
			
		||||
    console.log(`getFiles: owner: ${owner}, repo: ${repo}, path: ${path}, version: ${version}`);
 | 
			
		||||
    const entries = await getRepositoryContent(owner, repo, path ?? "", version);
 | 
			
		||||
    const options = getGiteaOptions();
 | 
			
		||||
    const entries = await getRepositoryContent(owner, repo, path ?? "", version, options);
 | 
			
		||||
    if (entries instanceof Array) {
 | 
			
		||||
        ctx.response.type = "application/json";
 | 
			
		||||
        ctx.response.body = entries;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        if ("errors" in entries){
 | 
			
		||||
        if ("errors" in entries) {
 | 
			
		||||
            ctx.throw(404);
 | 
			
		||||
        }
 | 
			
		||||
        // TODO: check if the file is text file or not (e.g. image)
 | 
			
		||||
| 
						 | 
				
			
			@ -123,11 +136,28 @@ router.get("/:package([a-z0-9_]*@[a-z0-9_]*)/:version?/:path*", async (ctx) => {
 | 
			
		|||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
app.use(async (ctx, next) => {
 | 
			
		||||
    try {
 | 
			
		||||
        await next();
 | 
			
		||||
    }
 | 
			
		||||
    catch (err) {
 | 
			
		||||
        if (isHttpError(err)) {
 | 
			
		||||
            console.log(err);
 | 
			
		||||
            ctx.response.status = err.status;
 | 
			
		||||
            const { message, status, stack } = err;
 | 
			
		||||
            ctx.response.body = { message, status, stack };
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            throw err;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
app.use(router.routes());
 | 
			
		||||
app.use(router.allowedMethods());
 | 
			
		||||
 | 
			
		||||
app.use(async (ctx, next) => {
 | 
			
		||||
    try{
 | 
			
		||||
    try {
 | 
			
		||||
        await next();
 | 
			
		||||
    }
 | 
			
		||||
    catch (err) {
 | 
			
		||||
| 
						 | 
				
			
			@ -137,7 +167,8 @@ app.use(async (ctx, next) => {
 | 
			
		|||
            const { message, status, stack } = err;
 | 
			
		||||
            ctx.response.body = { message, status, stack };
 | 
			
		||||
        }
 | 
			
		||||
        else {                                                                                                   throw err;
 | 
			
		||||
        else {
 | 
			
		||||
            throw err;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										32
									
								
								gitea.ts
									
										
									
									
									
								
							
							
						
						
									
										32
									
								
								gitea.ts
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -2,29 +2,43 @@ import { SearchResults, Tag, ContentsResponse } from "./gitea_api.d.ts";
 | 
			
		|||
 | 
			
		||||
const ENDPOINT_URL = "https://git.prelude.duckdns.org/api/v1/";
 | 
			
		||||
 | 
			
		||||
export async function searchRepositoryWithTopic(topic: string): Promise<SearchResults> {
 | 
			
		||||
export interface GiteaOption{
 | 
			
		||||
    token: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function fetchFromGitea(url: string | URL, giteaOption? :GiteaOption): Promise<any> {
 | 
			
		||||
    const headers = new Headers();
 | 
			
		||||
    if (giteaOption) {
 | 
			
		||||
        headers.append("Authorization", "token " + giteaOption.token);
 | 
			
		||||
    }
 | 
			
		||||
    const response = await fetch(url, {
 | 
			
		||||
        headers: headers
 | 
			
		||||
    }
 | 
			
		||||
    );
 | 
			
		||||
    const data = await response.json();
 | 
			
		||||
    return data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function searchRepositoryWithTopic(topic: string, giteaOption? :GiteaOption): Promise<SearchResults> {
 | 
			
		||||
    const url = new URL(ENDPOINT_URL+ "repos/search");
 | 
			
		||||
    url.searchParams.append("q", topic);
 | 
			
		||||
    url.searchParams.append("topic", "true");
 | 
			
		||||
    const response = await fetch(url);
 | 
			
		||||
    const data = await response.json();
 | 
			
		||||
    const data = await fetchFromGitea(url,giteaOption);
 | 
			
		||||
    return data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function getRepositoryTags(owner:string,
 | 
			
		||||
    repo:string): Promise<Tag[]>{
 | 
			
		||||
    repo:string, giteaOption? :GiteaOption): Promise<Tag[]>{
 | 
			
		||||
    const url = new URL(ENDPOINT_URL+ "repos/"+owner+"/"+repo+"/tags");
 | 
			
		||||
    const response = await fetch(url);
 | 
			
		||||
    const data = await response.json();
 | 
			
		||||
    const data = await fetchFromGitea(url,giteaOption);
 | 
			
		||||
    return data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function getRepositoryContent(owner:string,
 | 
			
		||||
    repo:string, path:string, ref:string): Promise<ContentsResponse[] | ContentsResponse>{
 | 
			
		||||
    repo:string, path:string, ref:string, giteaOption? :GiteaOption): Promise<ContentsResponse[] | ContentsResponse>{
 | 
			
		||||
    const url = new URL(ENDPOINT_URL+ "repos/"+owner+"/"+repo+"/contents/"+path);
 | 
			
		||||
    url.searchParams.append("ref", ref);
 | 
			
		||||
    const response = await fetch(url);
 | 
			
		||||
    const data = await response.json();
 | 
			
		||||
    const data = await fetchFromGitea(url,giteaOption);
 | 
			
		||||
    return data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue