mirror of
https://github.com/LukeHagar/sveltesociety.dev.git
synced 2025-12-09 20:57:44 +00:00
feat: Add script to get npm package data (#499)
* Add zod schemas for CI validation * Require npm field for components.json * Remove svelte-layout-resizable * Stricter Zod validation * Stricter repository field validation * Implement requested changes * Add back accidentally removed field * Move SvelteStore to templates.json * Update category and tags * Add script to get npm data * Re-run updateNpm.js * Implement initial feedback * Update npm.js * Switch async/await to then/catch Co-authored-by: MacFJA <MacFJA@users.noreply.github.com> * Fix prettier * Run script * Re-run updateNpm * Also read tools.json * Add @types/node * Restructure npm.json output * Display last update on components page * Add to weekly workflow * Clarify updating npm data * Update src/lib/utils/injectNpmData.ts Co-authored-by: MacFJA <MacFJA@users.noreply.github.com> * Smaller date font, add version * Improve error text * Fix property title --------- Co-authored-by: MacFJA <MacFJA@users.noreply.github.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
name: Update stars count
|
||||
name: Fetch latest data
|
||||
|
||||
on:
|
||||
schedule:
|
||||
@@ -19,10 +19,12 @@ jobs:
|
||||
cache: 'pnpm'
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
- name: Run script
|
||||
- name: Update stars
|
||||
uses: ./.github/actions/update-stars
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Update npm data
|
||||
run: node scripts/updateNpm.js
|
||||
- name: Run format
|
||||
run: pnpm run format
|
||||
- name: Create Pull Request
|
||||
@@ -26,6 +26,7 @@
|
||||
"@types/node": "^20.10.4",
|
||||
"@typescript-eslint/eslint-plugin": "^6.14.0",
|
||||
"@typescript-eslint/parser": "^6.14.0",
|
||||
"dayjs": "^1.11.10",
|
||||
"eslint": "^8.55.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-svelte": "^2.35.1",
|
||||
|
||||
7
pnpm-lock.yaml
generated
7
pnpm-lock.yaml
generated
@@ -35,6 +35,9 @@ devDependencies:
|
||||
'@typescript-eslint/parser':
|
||||
specifier: ^6.14.0
|
||||
version: 6.14.0(eslint@8.55.0)(typescript@5.3.3)
|
||||
dayjs:
|
||||
specifier: ^1.11.10
|
||||
version: 1.11.10
|
||||
eslint:
|
||||
specifier: ^8.55.0
|
||||
version: 8.55.0
|
||||
@@ -1169,6 +1172,10 @@ packages:
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/dayjs@1.11.10:
|
||||
resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==}
|
||||
dev: true
|
||||
|
||||
/debug@4.3.4:
|
||||
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
|
||||
engines: {node: '>=6.0'}
|
||||
|
||||
33
scripts/updateNpm.js
Normal file
33
scripts/updateNpm.js
Normal file
@@ -0,0 +1,33 @@
|
||||
// @ts-check
|
||||
|
||||
import { writeFileSync } from 'node:fs';
|
||||
import { promisify } from 'node:util';
|
||||
import { exec } from 'node:child_process';
|
||||
import { componentsSchema, toolsSchema } from '../src/lib/schemas.js';
|
||||
import components from '../src/routes/components/components.json' assert { type: 'json' };
|
||||
import tools from '../src/routes/tools/tools.json' assert { type: 'json' };
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
const data = [...componentsSchema.parse(components), ...toolsSchema.parse(tools)];
|
||||
|
||||
const npm = await Promise.all(
|
||||
data.map((pkg) => processPackage(pkg).catch((error) => console.log(error.message)))
|
||||
).then((values) => {
|
||||
return values.reduce((result, value) => Object.assign(result, value), {});
|
||||
});
|
||||
|
||||
writeFileSync('src/lib/npm.json', JSON.stringify(npm));
|
||||
|
||||
/** @param {ReturnType<typeof data>[0]} pkg */
|
||||
async function processPackage(pkg) {
|
||||
if (!pkg.npm) {
|
||||
throw new Error(`npm field missing from ${pkg.title} (skipping)`);
|
||||
}
|
||||
const { stdout } = await execAsync(`npm view ${pkg.npm} --json`);
|
||||
const data = JSON.parse(stdout.toString());
|
||||
const version = data.version;
|
||||
const date = data.time[version];
|
||||
const support = data.peerDependencies?.svelte ? data.peerDependencies.svelte : 'Unknown';
|
||||
return { [pkg.npm]: { version: version, date: date, support: support } };
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
import Tag from '../Tag.svelte';
|
||||
import { copyToClipboard } from '$lib/utils/clipboard';
|
||||
import { packageManager as manager } from '$stores/packageManager';
|
||||
import { relativeDate } from '$utils/relativeDate';
|
||||
|
||||
export let active = false;
|
||||
export let title = '';
|
||||
@@ -11,6 +12,8 @@
|
||||
export let url = '';
|
||||
export let npm = '';
|
||||
export let repository = undefined;
|
||||
export let date = undefined;
|
||||
export let version = undefined;
|
||||
|
||||
let clipboardCopy = false;
|
||||
|
||||
@@ -33,15 +36,35 @@
|
||||
</script>
|
||||
|
||||
<div class="card" class:active id="component-{title}">
|
||||
<div class="card__top">
|
||||
<div>
|
||||
<h3>
|
||||
<a href="#component-{title}">#</a>
|
||||
{#if url || repository}<a href={url || repository}>{title}</a>{:else}<span>{title}</span>{/if}
|
||||
{#if npm}<Tag
|
||||
{#if url || repository}<a href={url || repository}>{title}</a>{:else}<span>{title}</span
|
||||
>{/if}
|
||||
</h3>
|
||||
</div>
|
||||
<div>
|
||||
{#if (repository || url || '').includes('github')}
|
||||
<a class="repo" title="Go to the source code" href={repository || url}
|
||||
><img style="display:inline" src="/images/github_logo.svg" alt="github logo" /></a
|
||||
>
|
||||
{:else if (repository || url || '').includes('gitlab')}
|
||||
<a class="repo" title="Go to the source code" href={repository || url}
|
||||
><img style="display:inline" src="/images/gitlab_logo.svg" alt="gitlab logo" /></a
|
||||
>
|
||||
<!-- {:else} -->
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if npm}
|
||||
<Tag
|
||||
click={() => copy()}
|
||||
variant="copy"
|
||||
title={clipboardCopy ? 'copied!' : `${packageManagers[$manager]} ${cleanupNpm(npm)}`}
|
||||
/>{/if}
|
||||
</h3>
|
||||
/>
|
||||
{/if}
|
||||
<p class="flex-grow">{description}</p>
|
||||
{#if tags}
|
||||
<div class="card__tags">
|
||||
@@ -51,26 +74,13 @@
|
||||
</div>
|
||||
{/if}
|
||||
<div class="card__bottom">
|
||||
<div>
|
||||
{#if (repository || url || '').includes('github')}
|
||||
<a title="Go to the source code" href={repository || url}
|
||||
><img style="display:inline" src="/images/github_logo.svg" alt="github logo" /></a
|
||||
>
|
||||
{:else if (repository || url || '').includes('gitlab')}
|
||||
<a title="Go to the source code" href={repository || url}
|
||||
><img style="display:inline" src="/images/gitlab_logo.svg" alt="gitlab logo" /></a
|
||||
>
|
||||
<!-- {:else} -->
|
||||
{/if}
|
||||
</div>
|
||||
<div>
|
||||
{#if typeof stars !== 'undefined'}
|
||||
★
|
||||
<code>{stars}</code>
|
||||
{/if}
|
||||
</div>
|
||||
<!-- commenting out dates just cause it is not very updated yet - all the cards show same date. put back in when we have better scraping -->
|
||||
<!-- <datetime value={addedOn}>{new Intl.DateTimeFormat('en-Us').format(Date.parse(addedOn))}</datetime> -->
|
||||
{#if date && version}<span class="date">Updated {relativeDate(date)} ({version})</span>{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -97,6 +107,11 @@
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.card__top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: top;
|
||||
}
|
||||
.card__bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -105,7 +120,7 @@
|
||||
.card__bottom > * {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.card__bottom a {
|
||||
.repo {
|
||||
border-bottom: none;
|
||||
aspect-ratio: 1/1;
|
||||
display: flex;
|
||||
@@ -117,10 +132,12 @@
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
transition: background-color 200ms ease-out;
|
||||
}
|
||||
.card__bottom a:hover {
|
||||
.repo:hover {
|
||||
background-color: rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.date {
|
||||
font-size: 14px;
|
||||
}
|
||||
.flex-grow {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
1451
src/lib/npm.json
Normal file
1451
src/lib/npm.json
Normal file
File diff suppressed because it is too large
Load Diff
12
src/lib/utils/injectNpmData.ts
Normal file
12
src/lib/utils/injectNpmData.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import npm from '$lib/npm.json';
|
||||
import type { z } from 'zod';
|
||||
import type { componentsSchema } from '$lib/schemas';
|
||||
|
||||
export const injectNpmData = (input: z.infer<typeof componentsSchema>) => {
|
||||
const output = [];
|
||||
for (const item of input) {
|
||||
const extra = npm[item.npm] ?? {};
|
||||
output.push({ ...item, ...extra });
|
||||
}
|
||||
return output;
|
||||
};
|
||||
7
src/lib/utils/relativeDate.ts
Normal file
7
src/lib/utils/relativeDate.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import dayjs from 'dayjs';
|
||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||
|
||||
export const relativeDate = (input: string | Date): string => {
|
||||
dayjs.extend(relativeTime);
|
||||
return dayjs(input).fromNow();
|
||||
};
|
||||
@@ -1,11 +1,12 @@
|
||||
<script lang="ts">
|
||||
import components from './components.json';
|
||||
import SearchableJson from '$lib/SearchableJson.svelte';
|
||||
import { injectNpmData } from '$utils/injectNpmData';
|
||||
import { injectStars } from '$utils/stars';
|
||||
</script>
|
||||
|
||||
<SearchableJson
|
||||
data={injectStars(components)}
|
||||
data={injectNpmData(injectStars(components))}
|
||||
displayTitle="Components"
|
||||
displayTitleSingular="component"
|
||||
submittingType="component"
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
<script lang="ts">
|
||||
import tools from '../tools/tools.json';
|
||||
import SearchableJson from '$lib/SearchableJson.svelte';
|
||||
import { injectNpmData } from '$utils/injectNpmData';
|
||||
import { injectStars } from '$utils/stars';
|
||||
</script>
|
||||
|
||||
<SearchableJson
|
||||
data={injectStars(tools)}
|
||||
data={injectNpmData(injectStars(tools))}
|
||||
displayTitle="Tools"
|
||||
displayTitleSingular="tool"
|
||||
submittingType="tool"
|
||||
|
||||
Reference in New Issue
Block a user