#183 render package README.md if exist

This commit is contained in:
neil 2023-02-09 14:28:55 +08:00
parent 6c490fd16c
commit a33cb2396d
8 changed files with 139 additions and 37 deletions

View file

@ -71,6 +71,7 @@
"dependencies": {
"@electron/asar": "^3.2.3",
"@types/bcryptjs": "^2.4.2",
"@types/js-yaml": "^4.0.5",
"@vitest/coverage-c8": "^0.27.1",
"axios": "^1.3.2",
"bcryptjs": "^2.4.3",
@ -87,7 +88,8 @@
"semver": "^7.3.8",
"svelte-markdown": "^0.2.3",
"svelte-watch-resize": "^1.0.3",
"upath": "^2.0.1"
"upath": "^2.0.1",
"yaml": "^2.2.1"
},
"pnpm": {
"onlyBuiltDependencies": [

View file

@ -0,0 +1,35 @@
import axios from 'axios';
const yaml = window.require('yaml');
export async function getGithubOwnerRepo(
pkgYamlUrl: string
): Promise<{ owner: string; repo: string }> {
// https://github.com/teaxyz/pantry.core/blob/main/projects/sqlite.org/package.yml
// https://raw.githubusercontent.com/teaxyz/pantry.core/main/projects/sqlite.org/package.yml
let owner = '';
let repo = '';
const url = pkgYamlUrl.replace('/github.com', '/raw.githubusercontent.com').replace('/blob', '');
const { data: rawYaml } = await axios.get(url);
const data = await yaml.parse(rawYaml);
if (data?.versions?.github) {
[owner, repo] = data.versions.github.split('/').filter((b: string) => b);
}
return {
owner,
repo
};
}
export async function getReadme(owner: string, repo: string): Promise<string> {
let readme = '';
const req = await axios.get(`https://api.github.com/repos/${owner}/${repo}/readme`);
if (req.data?.download_url) {
const reqDl = await axios.get(req.data.download_url);
readme = reqDl.data;
}
return readme;
}

View file

@ -2,10 +2,13 @@ import { writable } from 'svelte/store';
import type { GUIPackage } from '../types';
import { getPackages } from '@api';
import Fuse from 'fuse.js';
import { getPackageBottles } from '@api';
import { getGithubOwnerRepo, getReadme } from '$libs/github';
export default function initPackagesStore() {
let initialized = false;
const { subscribe, set } = writable<GUIPackage[]>([]);
const { subscribe, set, update } = writable<GUIPackage[]>([]);
const packages: GUIPackage[] = [];
let packagesIndex: Fuse<GUIPackage>;
@ -21,6 +24,19 @@ export default function initPackagesStore() {
subscribe((v) => packages.push(...v));
const updatePackageProp = (full_name: string, props: Partial<GUIPackage>) => {
update((pkgs) => {
const i = pkgs.findIndex((pkg) => pkg.full_name === full_name);
if (i >= 0) {
pkgs[i] = {
...pkgs[i],
...props
};
}
return pkgs;
});
};
return {
packages,
subscribe,
@ -31,6 +47,44 @@ export default function initPackagesStore() {
const res = packagesIndex.search(term, { limit });
const matchingPackages: GUIPackage[] = res.map((v) => v.item);
return matchingPackages;
},
subscribeToPackage: (slug: string, cb: (pkg: GUIPackage) => void) => {
subscribe((pkgs) => {
const foundPackage = pkgs.find((p) => p.slug === slug) as GUIPackage;
if (foundPackage) cb(foundPackage);
// get readme
// get contributors
// get github last modified
// subscribe((pkgs) => cb(pkgs[pkg]));
// console.log('f:', foundPackage);
// getReadmeRaw('');
if (!foundPackage.bottles) {
getPackageBottles(foundPackage.full_name).then((bottles) => {
updatePackageProp(foundPackage.full_name, { bottles });
});
}
console.log(foundPackage);
if (!foundPackage.readme_md && foundPackage.package_yml_url) {
getGithubOwnerRepo(foundPackage.package_yml_url).then(async ({ owner, repo }) => {
if (owner && repo) {
const readme_md = await getReadme(owner, repo);
console.log(readme_md);
updatePackageProp(foundPackage.full_name, { readme_md });
}
});
}
});
}
};
}
async function getReadmeRaw(owner: string, repo: string): Promise<string> {
// const rep = await getRepo('oven-sh', 'bun');
// const repo = await octokit.request('GET /repos/{owner}/{repo}', {
// owner: '',
// repo: '',
// });
return '';
}

View file

@ -26,37 +26,16 @@
let reviews: Review[];
let bottles: Bottle[] = [];
let versions: string[] = [];
let readme: string;
let tabs: Tab[] = [];
const setPkg = (pkgs: Package[]) => {
const foundPackage = pkgs.find(({ slug }) => slug === data?.slug) as Package;
if (!pkg && foundPackage) {
pkg = foundPackage;
tabs.push({
label: 'details',
component: Markdown,
props: { pkg }
});
}
if (!reviews && pkg) {
packagesReviewStore.subscribe(pkg.full_name, (updatedReviews) => {
reviews = updatedReviews;
});
}
};
packagesStore.subscribe(setPkg);
featuredPackages.subscribe(setPkg);
onMount(async () => {
try {
const newBottles = await getPackageBottles(pkg.full_name);
const newVersion = newBottles.map((b) => b.version);
packagesStore.subscribeToPackage(data?.slug, (p) => {
pkg = p;
if (!bottles.length && pkg.bottles) {
const newVersion = pkg.bottles.map((b) => b.version);
versions = [...new Set(newVersion)];
bottles.push(...newBottles);
bottles.push(...pkg.bottles);
tabs = [
...tabs,
{
@ -67,10 +46,21 @@
}
}
];
} catch (err) {
console.error(err);
}
if (!readme && pkg.readme_md) {
readme = pkg.readme_md;
tabs = [
{
label: 'details',
component: Markdown,
props: { pkg, source: readme }
},
...tabs,
];
}
});
</script>
<div>

View file

@ -5,7 +5,7 @@
import './styles.css';
// TODO: rm sample
import { md } from './sample';
// import { md } from './sample';
export let source: string;
@ -15,5 +15,5 @@
</script>
<section class="markdown-body p-4">
<SvelteMarkdown source={source || md} {renderers} />
<SvelteMarkdown {source} {renderers} />
</section>

View file

@ -1,6 +1,6 @@
<script lang="ts">
import type { Tab } from '../types';
import { onMount } from 'svelte';
import { onMount, afterUpdate } from 'svelte';
let clazz = '';
@ -12,8 +12,8 @@
let active: string;
onMount(() => {
if (tabs.length) {
afterUpdate(() => {
if (tabs.length && !active) {
active = tabs[0].label;
}
});

View file

@ -19,6 +19,7 @@ export interface Package {
dl_count: number;
installs: number;
reviews?: Review[];
package_yml_url?: string;
// metas
full_description?: string; // probably markdown
bottles?: Bottle[];
@ -26,8 +27,9 @@ export interface Package {
size_bytes?: number;
documentation_url?: string;
github_repository_url?: string;
owners?: Partial<Developer>[];
categories?: string[];
contributors?: Contributor[];
readme_md?: string;
}
export type AirtablePost = {
@ -94,3 +96,9 @@ export type Snippet = {
comment: string;
}[];
};
export type Contributor = Pick<Developer, 'avatar_url' | 'login' | 'name'> & {
github_id: number;
developer_id?: string;
contributions: number;
};

View file

@ -19,6 +19,7 @@ importers:
'@testing-library/jest-dom': ^5.16.5
'@testing-library/svelte': ^3.2.2
'@types/bcryptjs': ^2.4.2
'@types/js-yaml': ^4.0.5
'@types/testing-library__jest-dom': ^5.14.5
'@typescript-eslint/eslint-plugin': ^5.27.0
'@typescript-eslint/parser': ^5.27.0
@ -62,9 +63,11 @@ importers:
upath: ^2.0.1
vite: ^4.0.0
vitest: ^0.28.3
yaml: ^2.2.1
dependencies:
'@electron/asar': 3.2.3
'@types/bcryptjs': 2.4.2
'@types/js-yaml': 4.0.5
'@vitest/coverage-c8': 0.27.1_jsdom@21.0.0
axios: 1.3.2
bcryptjs: 2.4.3
@ -82,6 +85,7 @@ importers:
svelte-markdown: 0.2.3_svelte@3.55.1
svelte-watch-resize: 1.0.3
upath: 2.0.1
yaml: 2.2.1
devDependencies:
'@electron/notarize': 1.2.3
'@playwright/experimental-ct-svelte': 1.29.2_svelte@3.55.1
@ -4624,6 +4628,10 @@ packages:
pretty-format: 29.3.1
dev: true
/@types/js-yaml/4.0.5:
resolution: {integrity: sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==}
dev: false
/@types/json-schema/7.0.11:
resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
dev: true
@ -13586,6 +13594,11 @@ packages:
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
engines: {node: '>= 6'}
/yaml/2.2.1:
resolution: {integrity: sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==}
engines: {node: '>= 14'}
dev: false
/yargs-parser/20.2.9:
resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==}
engines: {node: '>=10'}