youiyoux 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/dist/chunks/{chunk-S7UV34H5.js → chunk-42YJX3W5.js} +1 -3
- package/dist/chunks/{chunk-FUB7B3VK.js → chunk-4BBYLTZX.js} +10 -10
- package/dist/chunks/chunk-52KOKYY6.js +8710 -0
- package/dist/chunks/chunk-FJZFCAL5.js +129 -0
- package/dist/chunks/chunk-FVVL5JCY.js +24 -0
- package/dist/chunks/{chunk-UHPK62Q5.js → chunk-M5XZWCPS.js} +240 -60
- package/dist/chunks/{chunk-ZLRFD5JI.js → chunk-NYDJYMID.js} +263 -16
- package/dist/chunks/{src-7ENJHYG4.js → chunk-RDTHHRZN.js} +319 -165
- package/dist/chunks/{chunk-E4HNK7VF.js → chunk-WNTS7ZO4.js} +1 -1
- package/dist/chunks/chunk-XAEMVEYX.js +188 -0
- package/dist/chunks/{chunk-CLNMVQZJ.js → chunk-YFCMTTXS.js} +708 -494
- package/dist/chunks/chunk-YJ7WMBTT.js +13761 -0
- package/dist/chunks/src-5IP4NGKT.js +115 -0
- package/dist/chunks/src-6CJR547Y.js +124 -0
- package/dist/chunks/{src-WQWYJ6IQ.js → src-BPETAFLW.js} +175 -76
- package/dist/chunks/{src-B742AYFC.js → src-LLV7IY6W.js} +55 -16
- package/dist/chunks/src-RHNZELGE.js +306 -0
- package/dist/chunks/{src-4KFNL3MY.js → src-SFKFERZ2.js} +18 -8
- package/dist/chunks/{src-VEHGMKYV.js → src-VL2ZYO6X.js} +4 -4
- package/dist/hub/assets/Badge-CUJUit4d.js +1 -0
- package/dist/hub/assets/CandidatePanel-CnbK4S0j.js +1 -0
- package/dist/hub/assets/CatalogScreen-B5OVL-AR.js +1 -0
- package/dist/hub/assets/ChangesScreen-GwGqJwxN.js +1 -0
- package/dist/hub/assets/CheatSheet-BLSOq-xa.js +1 -0
- package/dist/hub/assets/CodeBlock-CsiGFgvI.js +1 -0
- package/dist/hub/assets/CommandPalette-CAWQfdXJ.js +1 -0
- package/dist/hub/assets/CopyButton-DE8drl4P.js +1 -0
- package/dist/hub/assets/Disclosure-B1kTgPgk.js +1 -0
- package/dist/hub/assets/DiscoverScreen-Tl_Z6mgY.js +2 -0
- package/dist/hub/assets/DraftEditor-yIDapXTs.js +5 -0
- package/dist/hub/assets/Field-LwrJXoOs.js +1 -0
- package/dist/hub/assets/GapsScreen-DXZAlm6v.js +1 -0
- package/dist/hub/assets/HomeScreen-CEpiVhOa.js +1 -0
- package/dist/hub/assets/InventoryScreen-CEG3Pmw_.js +1 -0
- package/dist/hub/assets/KindIcon-BJ6bz-ny.js +1 -0
- package/dist/hub/assets/LibraryScreen-IaVnxrX9.js +1 -0
- package/dist/hub/assets/LicenceBadge-CLCUMMHE.js +1 -0
- package/dist/hub/assets/Opened-DJyf4Hnj.js +1 -0
- package/dist/hub/assets/Preview-C069zVMP.js +1 -0
- package/dist/hub/assets/RuleDetail-B4g2-TRe.js +3 -0
- package/dist/hub/assets/RulesScreen-CAaXIWjO.js +3 -0
- package/dist/hub/assets/ScreenImage-DcI7_G3O.js +1 -0
- package/dist/hub/assets/ScreensScreen-DwczCjZD.js +1 -0
- package/dist/hub/assets/SearchField-DaCpNAj6.js +1 -0
- package/dist/hub/assets/Section-BTnvUq_W.js +1 -0
- package/dist/hub/assets/Segmented-Dzi1x49S.js +1 -0
- package/dist/hub/assets/ServiceDown-Bv-BPXro.js +1 -0
- package/dist/hub/assets/SpecimenCapture-DlsjshVE.js +1 -0
- package/dist/hub/assets/Specimens-C-lHp7sr.js +2 -0
- package/dist/hub/assets/StackScreen-DkmELsqR.js +1 -0
- package/dist/hub/assets/StubScreens-Bt7lWLVK.js +1 -0
- package/dist/hub/assets/StyleScreen-tq1tbRBo.js +1 -0
- package/dist/hub/assets/Swatch-KDz4qxdM.js +1 -0
- package/dist/hub/assets/Tabs-1QQDS0I6.js +1 -0
- package/dist/hub/assets/TokenDetail-DvCw6GqC.js +1 -0
- package/dist/hub/assets/TokenValue-CsPRc2ai.js +1 -0
- package/dist/hub/assets/TokensScreen-DoENV8Xy.js +1 -0
- package/dist/hub/assets/arrow-right-DcbNDzqs.js +1 -0
- package/dist/hub/assets/bot-B3gC9oUR.js +1 -0
- package/dist/hub/assets/button-6mvMVtpb.js +1 -0
- package/dist/hub/assets/button.demo-DuU0DQbv.js +1 -0
- package/dist/hub/assets/card.demo-CufAxMAA.js +1 -0
- package/dist/hub/assets/chevron-down-CzN07vMi.js +1 -0
- package/dist/hub/assets/circle-alert-DT2LC4yf.js +1 -0
- package/dist/hub/assets/circle-check-DkwBMT62.js +1 -0
- package/dist/hub/assets/client-D7whEyep.js +1 -0
- package/dist/hub/assets/clsx-DB0hHKMi.js +1 -0
- package/dist/hub/assets/compass-BkKOZPYe.js +1 -0
- package/dist/hub/assets/contrast-BkNHUAPa.js +1 -0
- package/dist/hub/assets/createLucideIcon-CGDJWtKO.js +1 -0
- package/dist/hub/assets/discover-XjJEViwk.js +1 -0
- package/dist/hub/assets/dist-BYQYaPBV.js +1 -0
- package/dist/hub/assets/dist-Bk4srtDn.js +41 -0
- package/dist/hub/assets/dist-BogNzeK9.js +1 -0
- package/dist/hub/assets/dist-D0z7Bvsy.js +1 -0
- package/dist/hub/assets/download-BQI-Si9R.js +1 -0
- package/dist/hub/assets/engine-CMmt9yEz.js +1 -0
- package/dist/hub/assets/esm-NPpg23M8.js +1 -0
- package/dist/hub/assets/family-tiles-CyTdy_cP.js +1 -0
- package/dist/hub/assets/format-DxAYNTN_.js +1 -0
- package/dist/hub/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
- package/dist/hub/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
- package/dist/hub/assets/geist-latin-core-vkBVTr4s.woff2 +0 -0
- package/dist/hub/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
- package/dist/hub/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
- package/dist/hub/assets/geist-mono-cyrillic-ext-wght-normal-X_5orZeX.woff2 +0 -0
- package/dist/hub/assets/geist-mono-cyrillic-wght-normal-DiZS0aHC.woff2 +0 -0
- package/dist/hub/assets/geist-mono-latin-core-DccGGzmg.woff2 +0 -0
- package/dist/hub/assets/geist-mono-latin-ext-wght-normal-Bwz-egvJ.woff2 +0 -0
- package/dist/hub/assets/geist-mono-latin-wght-normal-XN7g48iV.woff2 +0 -0
- package/dist/hub/assets/geist-mono-symbols2-wght-normal-CO5SzqOn.woff2 +0 -0
- package/dist/hub/assets/geist-mono-vietnamese-wght-normal-DadHysG0.woff2 +0 -0
- package/dist/hub/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
- package/dist/hub/assets/git-pull-request-arrow-RqUUIRCU.js +1 -0
- package/dist/hub/assets/input.demo-238gqWpz.js +1 -0
- package/dist/hub/assets/inventory-BI8QBdar.js +1 -0
- package/dist/hub/assets/inventory-source-lZYzcA8O.js +1 -0
- package/dist/hub/assets/jsx-runtime-D6zNwnaE.js +9 -0
- package/dist/hub/assets/layers-DfzdK_wG.js +1 -0
- package/dist/hub/assets/layout-grid-xFY9L9Oc.js +1 -0
- package/dist/hub/assets/library-W5R8GwvG.js +1 -0
- package/dist/hub/assets/main-7snyIdoi.css +2 -0
- package/dist/hub/assets/main-B9CIkk5m.js +2 -0
- package/dist/hub/assets/minus-BDifFhOo.js +1 -0
- package/dist/hub/assets/monitor-X_lELkcU.js +1 -0
- package/dist/hub/assets/mouse-pointer-click-CVJ6hWg8.js +1 -0
- package/dist/hub/assets/paintbrush-DOkEgSTO.js +1 -0
- package/dist/hub/assets/plural-BbGQPQKA.js +1 -0
- package/dist/hub/assets/preview-BA8CPsKb.css +2 -0
- package/dist/hub/assets/preview-DUm13vr1.js +3 -0
- package/dist/hub/assets/protocol-caP6umNL.js +1 -0
- package/dist/hub/assets/react-DB-4Zxce.js +1 -0
- package/dist/hub/assets/shield-check-0ka0kQct.js +1 -0
- package/dist/hub/assets/trash-B7aEfJps.js +1 -0
- package/dist/hub/assets/triangle-alert-Dkdi9eDR.js +1 -0
- package/dist/hub/assets/try-live-zX3CSd3P.js +1 -0
- package/dist/hub/assets/utils-BoaXfs8y.js +1 -0
- package/dist/hub/assets/values-DzxR_TlI.js +1 -0
- package/dist/hub/assets/worker-Bh-wSp42.js +1 -0
- package/dist/hub/assets/workflow-jpV8wh-U.js +1 -0
- package/dist/hub/assets/x-MLbFVa4v.js +1 -0
- package/dist/hub/favicon.svg +1 -0
- package/dist/hub/index.html +35 -0
- package/dist/hub/kit/candidates.json +1 -0
- package/dist/hub/kit/chunks/chunk-2NYFUOIV.js +14 -0
- package/dist/hub/kit/chunks/chunk-DCANE7XH.js +1 -0
- package/dist/hub/kit/chunks/chunk-FTGHCY4I.js +14 -0
- package/dist/hub/kit/chunks/chunk-IBF3UTJF.js +33 -0
- package/dist/hub/kit/chunks/chunk-LLXY4VSH.js +1 -0
- package/dist/hub/kit/chunks/chunk-PUPZMW4P.js +14 -0
- package/dist/hub/kit/chunks/chunk-PWLNZQET.js +1 -0
- package/dist/hub/kit/chunks/chunk-ULXWVOKJ.js +1 -0
- package/dist/hub/kit/chunks/chunk-WM4BGGMK.js +1 -0
- package/dist/hub/kit/chunks/chunk-ZQUNRK72.js +1 -0
- package/dist/hub/kit/class-variance-authority.js +1 -0
- package/dist/hub/kit/clsx.js +1 -0
- package/dist/hub/kit/fonts/geist-cyrillic-ext-wght-normal.woff2 +0 -0
- package/dist/hub/kit/fonts/geist-cyrillic-wght-normal.woff2 +0 -0
- package/dist/hub/kit/fonts/geist-latin-ext-wght-normal.woff2 +0 -0
- package/dist/hub/kit/fonts/geist-latin-wght-normal.woff2 +0 -0
- package/dist/hub/kit/fonts/geist-vietnamese-wght-normal.woff2 +0 -0
- package/dist/hub/kit/frame.css.src +73 -0
- package/dist/hub/kit/frame.js +2 -0
- package/dist/hub/kit/lucide-react.js +1878 -0
- package/dist/hub/kit/preview.html +13 -0
- package/dist/hub/kit/radix-ui-react-dialog.js +41 -0
- package/dist/hub/kit/radix-ui-react-label.js +1 -0
- package/dist/hub/kit/radix-ui-react-separator.js +1 -0
- package/dist/hub/kit/radix-ui-react-slot.js +1 -0
- package/dist/hub/kit/radix-ui-react-switch.js +1 -0
- package/dist/hub/kit/radix-ui-react-tabs.js +1 -0
- package/dist/hub/kit/react-dom-client.js +1 -0
- package/dist/hub/kit/react-dom.js +1 -0
- package/dist/hub/kit/react-jsx-runtime.js +1 -0
- package/dist/hub/kit/react.js +1 -0
- package/dist/hub/kit/tailwind-merge.js +1 -0
- package/dist/hub/kit/tailwindcss/index.css +950 -0
- package/dist/hub/kit/tailwindcss/preflight.css +398 -0
- package/dist/hub/kit/tailwindcss/theme.css +510 -0
- package/dist/hub/kit/tailwindcss/utilities.css +1 -0
- package/dist/hub-demo/frame/button.demo.js +1 -0
- package/dist/hub-demo/frame/card.demo.js +1 -0
- package/dist/hub-demo/frame/demos.js +6 -0
- package/dist/hub-demo/frame/frame.css +770 -0
- package/dist/hub-demo/frame/input.demo.js +1 -0
- package/dist/hub-demo/preview/components/button.demo.tsx +47 -0
- package/dist/hub-demo/preview/components/button.tsx +31 -0
- package/dist/hub-demo/preview/components/card.demo.tsx +26 -0
- package/dist/hub-demo/preview/components/card.tsx +20 -0
- package/dist/hub-demo/preview/components/input.demo.tsx +39 -0
- package/dist/hub-demo/preview/components/input.tsx +19 -0
- package/dist/hub-demo/preview/components/utils.ts +5 -0
- package/dist/hub-demo/preview/system.css +161 -0
- package/dist/hub-demo/public/data/demo-app.usage.bedd9c82fe.json +1 -0
- package/dist/hub-demo/public/data/demo.catalog.a605de2281.json +1 -0
- package/dist/hub-demo/public/data/gaps.129a93538d.json +1 -0
- package/dist/hub-demo/public/data/inventory.165a4f6408.json +1 -0
- package/dist/hub-demo/public/data/inventory.console.badge.ad0238784e.json +1 -0
- package/dist/hub-demo/public/data/inventory.console.button.3249daff35.json +1 -0
- package/dist/hub-demo/public/data/inventory.console.card.9ea88708ac.json +1 -0
- package/dist/hub-demo/public/data/inventory.console.dialog.8b6574d93a.json +1 -0
- package/dist/hub-demo/public/data/inventory.console.input.bdffb756a7.json +1 -0
- package/dist/hub-demo/public/data/inventory.console.link-as-button.1ce7faa1f3.json +1 -0
- package/dist/hub-demo/public/data/inventory.console.tabs.813e694c44.json +1 -0
- package/dist/hub-demo/public/data/inventory.extras.e5d06c6ff4.json +1 -0
- package/dist/hub-demo/public/data/inventory.site.badge.047a68f644.json +1 -0
- package/dist/hub-demo/public/data/inventory.site.button.720938384e.json +1 -0
- package/dist/hub-demo/public/data/inventory.site.card.d8df5f6873.json +1 -0
- package/dist/hub-demo/public/data/inventory.site.link-as-button.9c1f8a55bf.json +1 -0
- package/dist/hub-demo/public/data/inventory.site.tabs.59bd0200b9.json +1 -0
- package/dist/hub-demo/public/data/manifest.json +39 -0
- package/dist/hub-demo/public/data/specimens.console.dark.046471907d.css +786 -0
- package/dist/hub-demo/public/data/specimens.console.light.aaffa2d213.css +786 -0
- package/dist/hub-demo/public/data/specimens.site.dark.94a6706908.css +92 -0
- package/dist/hub-demo/public/data/specimens.site.light.3ddbc8d28d.css +92 -0
- package/dist/hub-demo/public/previews/button.dark.webp +0 -0
- package/dist/hub-demo/public/previews/button.light.webp +0 -0
- package/dist/hub-demo/public/previews/card.dark.webp +0 -0
- package/dist/hub-demo/public/previews/card.light.webp +0 -0
- package/dist/hub-demo/public/previews/input.dark.webp +0 -0
- package/dist/hub-demo/public/previews/input.light.webp +0 -0
- package/dist/hub-previews.js +173 -0
- package/dist/hub-server.js +6329 -0
- package/dist/hub-snapshot.js +573 -0
- package/dist/schema/youi.gaps.schema.json +235 -0
- package/dist/schema/youi.request.schema.json +229 -0
- package/dist/tailwind-worker.js +3 -3
- package/dist/youi.js +10 -8
- package/dist/youiyoux.js +10 -8
- package/package.json +4 -4
- package/dist/chunks/chunk-3ZHGONNA.js +0 -21797
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import { createRequire as __youiRequire } from "node:module"; const require = __youiRequire(import.meta.url);
|
|
1
|
+
import { createRequire as __youiRequire } from "node:module"; import { dirname as __youiDir } from "node:path"; import { fileURLToPath as __youiPath } from "node:url"; const require = __youiRequire(import.meta.url); const __youiDirname = __youiDir(__youiPath(import.meta.url));
|
|
2
2
|
import {
|
|
3
3
|
LIBRARY_SOURCE_KINDS,
|
|
4
4
|
LibraryEntry,
|
|
5
5
|
SHAPE_DIMENSIONS,
|
|
6
|
+
copyleft,
|
|
6
7
|
external_exports,
|
|
7
8
|
sha256,
|
|
9
|
+
shortHash,
|
|
8
10
|
writeFileAtomic
|
|
9
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-NYDJYMID.js";
|
|
10
12
|
|
|
11
13
|
// ../discover/src/aliases.ts
|
|
12
14
|
var CONCEPTS = [
|
|
@@ -55,9 +57,6 @@ var CONCEPTS = [
|
|
|
55
57
|
{ id: "marquee", names: ["marquee", "ticker", "scrolling text"], packages: [] }
|
|
56
58
|
];
|
|
57
59
|
var BY_ID = new Map(CONCEPTS.map((c) => [c.id, c]));
|
|
58
|
-
function conceptById(id) {
|
|
59
|
-
return BY_ID.get(id);
|
|
60
|
-
}
|
|
61
60
|
function normalize(text) {
|
|
62
61
|
return text.normalize("NFC").replace(/([a-z0-9])([A-Z])/g, "$1 $2").toLowerCase().replace(/[^\p{L}\p{N}]+/gu, " ").trim();
|
|
63
62
|
}
|
|
@@ -112,7 +111,7 @@ function cleanData(value) {
|
|
|
112
111
|
}
|
|
113
112
|
|
|
114
113
|
// ../discover/src/sources.ts
|
|
115
|
-
var CURATED = ["@coss", "@kibo-ui", "@magicui", "@
|
|
114
|
+
var CURATED = ["@coss", "@kibo-ui", "@magicui", "@aceternity"];
|
|
116
115
|
var SHADCN = {
|
|
117
116
|
name: "@shadcn",
|
|
118
117
|
homepage: "https://ui.shadcn.com",
|
|
@@ -215,7 +214,7 @@ function importedPackages(source) {
|
|
|
215
214
|
const found = /* @__PURE__ */ new Set();
|
|
216
215
|
for (const match of source.matchAll(IMPORT)) {
|
|
217
216
|
const spec = match[1];
|
|
218
|
-
if (/^(\.|\/|@\/|~\/|#|node:)/.test(spec)
|
|
217
|
+
if (/^(\.|\/|@\/|~\/|#|node:)/.test(spec)) continue;
|
|
219
218
|
const parts = spec.split("/");
|
|
220
219
|
const name = spec.startsWith("@") ? parts.slice(0, 2).join("/") : parts[0];
|
|
221
220
|
if (name && !AMBIENT.has(name)) found.add(name);
|
|
@@ -508,7 +507,7 @@ var json = (value) => JSON.stringify(value);
|
|
|
508
507
|
var parse = (value) => typeof value === "string" ? JSON.parse(value) : value;
|
|
509
508
|
var int = (value) => Number(value ?? 0);
|
|
510
509
|
var marks = (n) => Array.from({ length: n }, () => "?").join(", ");
|
|
511
|
-
var
|
|
510
|
+
var batches = (items) => Array.from({ length: Math.ceil(items.length / MAX_PARAMS) }, (_, i) => items.slice(i * MAX_PARAMS, (i + 1) * MAX_PARAMS));
|
|
512
511
|
var SqlStore = class {
|
|
513
512
|
db;
|
|
514
513
|
lock = new Lock();
|
|
@@ -603,10 +602,7 @@ var SqlStore = class {
|
|
|
603
602
|
const update = columns.slice(1).map((c) => `${c} = excluded.${c}`).join(", ");
|
|
604
603
|
await this.insert("discover_items", columns, items.map((i) => [i.id, i.scope, i.ref, i.name, i.title, i.summary, i.kind, i.sourceKind, i.sourceClass, i.registry, i.licence, i.style, i.downloads, i.stars, i.archived ? 1 : 0, i.searchText, json(i.entry), i.builtAt]), `ON CONFLICT (id) DO UPDATE SET ${update}`);
|
|
605
604
|
const ids = items.map((i) => i.id);
|
|
606
|
-
for (
|
|
607
|
-
const batch = ids.slice(i, i + MAX_PARAMS);
|
|
608
|
-
await this.db.run(`DELETE FROM discover_roles WHERE item_id IN (${marks(batch.length)})`, batch);
|
|
609
|
-
}
|
|
605
|
+
for (const batch of batches(ids)) await this.db.run(`DELETE FROM discover_roles WHERE item_id IN (${marks(batch.length)})`, batch);
|
|
610
606
|
await this.insert("discover_roles", ["item_id", "role"], items.flatMap((i) => [...new Set(i.roles)].map((role) => [i.id, role])), "ON CONFLICT (item_id, role) DO NOTHING");
|
|
611
607
|
}
|
|
612
608
|
async replaceDiscoverItems(scope, items) {
|
|
@@ -659,15 +655,14 @@ var SqlStore = class {
|
|
|
659
655
|
);
|
|
660
656
|
const entries = /* @__PURE__ */ new Map();
|
|
661
657
|
const ids = ranked.map((r) => r.id);
|
|
662
|
-
for (
|
|
663
|
-
const batch = ids.slice(i, i + MAX_PARAMS);
|
|
658
|
+
for (const batch of batches(ids)) {
|
|
664
659
|
for (const row of await this.db.all(`SELECT id, entry FROM discover_items WHERE id IN (${marks(batch.length)})`, batch)) entries.set(row.id, row.entry);
|
|
665
660
|
}
|
|
666
661
|
return ranked.map((r) => ({ id: r.id, sourceClass: r.source_class, entry: parse(entries.get(r.id)) }));
|
|
667
662
|
}
|
|
668
663
|
async listDiscover(filter, page = {}) {
|
|
669
664
|
const where = this.filterSql(filter);
|
|
670
|
-
const limit =
|
|
665
|
+
const limit = pageInteger(page.limit, 20);
|
|
671
666
|
const offset = pageInteger(page.offset, 0, 2147483647);
|
|
672
667
|
const rows = await this.db.all(
|
|
673
668
|
`SELECT d.id, d.source_class, d.entry FROM discover_items d WHERE ${where.sql} ORDER BY CASE d.source_class WHEN 'official' THEN 0 ELSE 1 END, COALESCE(d.downloads, -1) DESC, d.id LIMIT ? OFFSET ?`,
|
|
@@ -698,8 +693,7 @@ var SqlStore = class {
|
|
|
698
693
|
}
|
|
699
694
|
async discoverRoles(itemIds) {
|
|
700
695
|
const out = {};
|
|
701
|
-
for (
|
|
702
|
-
const batch = itemIds.slice(i, i + MAX_PARAMS);
|
|
696
|
+
for (const batch of batches(itemIds)) {
|
|
703
697
|
for (const row of await this.db.all(`SELECT item_id, role FROM discover_roles WHERE item_id IN (${marks(batch.length)}) ORDER BY item_id, role`, batch)) (out[row.item_id] ??= []).push(row.role);
|
|
704
698
|
}
|
|
705
699
|
return out;
|
|
@@ -745,7 +739,7 @@ var SqlStore = class {
|
|
|
745
739
|
}
|
|
746
740
|
async history(filter = {}) {
|
|
747
741
|
const where = filter.project ? `WHERE project = ?` : "";
|
|
748
|
-
const rows = await this.db.all(`SELECT * FROM scans ${where} ORDER BY scanned_at DESC, project LIMIT ? OFFSET ?`, [...filter.project ? [filter.project] : [],
|
|
742
|
+
const rows = await this.db.all(`SELECT * FROM scans ${where} ORDER BY scanned_at DESC, project LIMIT ? OFFSET ?`, [...filter.project ? [filter.project] : [], pageInteger(filter.limit, 20), pageInteger(filter.offset, 0, 2147483647)]);
|
|
749
743
|
return rows.map((r) => ({ id: String(r.id), run: String(r.run), source: String(r.source), project: String(r.project), root: String(r.root), commit: r.commit_sha ?? null, scannedAt: String(r.scanned_at), status: String(r.status), files: int(r.files), looks: int(r.looks), families: int(r.families), nearDuplicates: int(r.near_duplicates), roles: parse(r.roles) }));
|
|
750
744
|
}
|
|
751
745
|
async latestRun(source) {
|
|
@@ -758,7 +752,7 @@ var SqlStore = class {
|
|
|
758
752
|
const where = `run = ?${filter.role ? " AND role = ?" : ""}`;
|
|
759
753
|
const params = [run, ...filter.role ? [filter.role] : []];
|
|
760
754
|
const total = int((await this.db.all(`SELECT CAST(COUNT(*) AS INTEGER) AS n FROM families WHERE ${where}`, params))[0]?.n);
|
|
761
|
-
const rows = await this.db.all(`SELECT * FROM families WHERE ${where} ORDER BY role, looks DESC, id LIMIT ? OFFSET ?`, [...params,
|
|
755
|
+
const rows = await this.db.all(`SELECT * FROM families WHERE ${where} ORDER BY role, looks DESC, id LIMIT ? OFFSET ?`, [...params, pageInteger(filter.limit, 50), pageInteger(filter.offset, 0, 2147483647)]);
|
|
762
756
|
return { run, total, rows: rows.map((r) => ({ id: String(r.id), role: String(r.role), looks: int(r.looks), nearDuplicate: int(r.near_duplicate) === 1, projects: parse(r.projects), kits: parse(r.kits), shape: parse(r.shape) })) };
|
|
763
757
|
}
|
|
764
758
|
async looks(filter) {
|
|
@@ -767,7 +761,7 @@ var SqlStore = class {
|
|
|
767
761
|
const where = `run = ?${filter.family ? " AND family = ?" : ""}${filter.role ? " AND role = ?" : ""}`;
|
|
768
762
|
const params = [run, ...filter.family ? [filter.family] : [], ...filter.role ? [filter.role] : []];
|
|
769
763
|
const total = int((await this.db.all(`SELECT CAST(COUNT(*) AS INTEGER) AS n FROM looks WHERE ${where}`, params))[0]?.n);
|
|
770
|
-
const rows = await this.db.all(`SELECT * FROM looks WHERE ${where} ORDER BY project, file, line, col, id LIMIT ? OFFSET ?`, [...params,
|
|
764
|
+
const rows = await this.db.all(`SELECT * FROM looks WHERE ${where} ORDER BY project, file, line, col, id LIMIT ? OFFSET ?`, [...params, pageInteger(filter.limit, 50), pageInteger(filter.offset, 0, 2147483647)]);
|
|
771
765
|
return { run, total, rows: rows.map((r) => ({ id: String(r.id), project: String(r.project), role: String(r.role), file: String(r.file), line: int(r.line), column: int(r.col), tag: String(r.tag), kit: r.kit ?? null, family: r.family ?? null, routes: parse(r.routes), shape: parse(r.shape) })) };
|
|
772
766
|
}
|
|
773
767
|
/* --------------------------------------------------------------------- graph */
|
|
@@ -1108,10 +1102,8 @@ async function openStore(options = {}) {
|
|
|
1108
1102
|
}
|
|
1109
1103
|
|
|
1110
1104
|
// ../store/src/derive.ts
|
|
1111
|
-
import { createHash } from "node:crypto";
|
|
1112
|
-
var short = (text) => createHash("sha256").update(text).digest("hex").slice(0, 12);
|
|
1113
1105
|
var nodeId = {
|
|
1114
|
-
family: (inventory, id, project = "") => `family:${
|
|
1106
|
+
family: (inventory, id, project = "") => `family:${shortHash(inventory)}/${encodeURIComponent(project)}/${id}`,
|
|
1115
1107
|
file: (project, file) => `file:${project}:${file}`,
|
|
1116
1108
|
route: (project, route) => `route:${project}:${route}`,
|
|
1117
1109
|
project: (id) => `project:${id}`,
|
|
@@ -1158,7 +1150,7 @@ function nearDuplicatePairs(families, tolerance) {
|
|
|
1158
1150
|
return pairs;
|
|
1159
1151
|
}
|
|
1160
1152
|
function inventoryRun(report, source) {
|
|
1161
|
-
const run = `${report.generatedAt}#${
|
|
1153
|
+
const run = `${report.generatedAt}#${shortHash(`${source}\0${report.generatedAt}`).slice(0, 8)}`;
|
|
1162
1154
|
const g = new GraphBuilder();
|
|
1163
1155
|
const familyNode = (id, project) => g.node({ id: nodeId.family(source, id, project), kind: "family", ref: id, project });
|
|
1164
1156
|
for (const family of report.families) for (const project of family.projects) familyNode(family.id, project);
|
|
@@ -1266,7 +1258,6 @@ var DiscoverIndex = external_exports.object({
|
|
|
1266
1258
|
categories: external_exports.record(external_exports.string(), external_exports.array(external_exports.string())),
|
|
1267
1259
|
entries: external_exports.array(LibraryEntry)
|
|
1268
1260
|
});
|
|
1269
|
-
var EMPTY_SIGNALS = { npm: {}, github: {}, registryRepos: {} };
|
|
1270
1261
|
async function readJson(file) {
|
|
1271
1262
|
try {
|
|
1272
1263
|
return JSON.parse(await readFile(file, "utf8"));
|
|
@@ -1373,7 +1364,7 @@ function slimResponse(url, body) {
|
|
|
1373
1364
|
}))
|
|
1374
1365
|
})) };
|
|
1375
1366
|
}
|
|
1376
|
-
async function writeHttpCache(cacheDir, cache
|
|
1367
|
+
async function writeHttpCache(cacheDir, cache) {
|
|
1377
1368
|
const keep = /* @__PURE__ */ new Set();
|
|
1378
1369
|
for (const [url, entry] of cache) {
|
|
1379
1370
|
let data;
|
|
@@ -1511,7 +1502,7 @@ var PoliteClient = class {
|
|
|
1511
1502
|
this.stats.cached++;
|
|
1512
1503
|
return { ok: true, url, status: 200, body: cached.body, sha256: cached.sha256, fetchedAt: cached.fetchedAt, revalidated: true, headers: new Headers() };
|
|
1513
1504
|
}
|
|
1514
|
-
const bucket = npm ? "npm" :
|
|
1505
|
+
const bucket = npm ? "npm" : githubBucketFor(parsed);
|
|
1515
1506
|
let host = this.hosts.get(parsed.host);
|
|
1516
1507
|
if (!host) this.hosts.set(parsed.host, host = new Gate(this.options.perHost ?? 2));
|
|
1517
1508
|
const gate = host;
|
|
@@ -1720,6 +1711,9 @@ function playsRole(role, f) {
|
|
|
1720
1711
|
const n = normalize(role);
|
|
1721
1712
|
return hasPhrase(f.name, n) || f.categories.some((c) => hasPhrase(c, n));
|
|
1722
1713
|
}
|
|
1714
|
+
function licenceOf(entry) {
|
|
1715
|
+
return entry.license && entry.license !== "unknown" ? entry.license.spdx : "unknown";
|
|
1716
|
+
}
|
|
1723
1717
|
function hitOf(entry, score, why) {
|
|
1724
1718
|
return {
|
|
1725
1719
|
id: entry.id,
|
|
@@ -1728,7 +1722,7 @@ function hitOf(entry, score, why) {
|
|
|
1728
1722
|
kind: entry.kind,
|
|
1729
1723
|
summary: entry.summary,
|
|
1730
1724
|
source: { kind: entry.source.kind ?? null, name: entry.source.name, ref: entry.source.ref ?? null, url: entry.source.url ?? null },
|
|
1731
|
-
license: entry
|
|
1725
|
+
license: licenceOf(entry),
|
|
1732
1726
|
signals: { ...entry.signals?.via ? { via: entry.signals.via } : {}, weeklyDownloads: entry.signals?.weeklyDownloads ?? null, stars: entry.signals?.stars ?? null, pushedAt: entry.signals?.pushedAt ?? null, archived: entry.signals?.archived ?? null },
|
|
1733
1727
|
install: entry.install ? { command: entry.install.command, npm: entry.install.npm, registryDeps: entry.install.registryDeps, implicitDeps: entry.install.implicitDeps } : null,
|
|
1734
1728
|
score: Math.round(score * 100) / 100,
|
|
@@ -1796,7 +1790,7 @@ function showCandidate(index, query) {
|
|
|
1796
1790
|
|
|
1797
1791
|
// ../discover/src/signals.ts
|
|
1798
1792
|
var HOUR = 36e5;
|
|
1799
|
-
var SIGNAL_TTL = { npmMs: 24 * HOUR, githubMs: 7 * 24 * HOUR, registryRepoMs: 30 * 24 * HOUR };
|
|
1793
|
+
var SIGNAL_TTL = { npmMs: 24 * HOUR, githubMs: 7 * 24 * HOUR, registryRepoMs: 30 * 24 * HOUR, registryRepoMissMs: 24 * HOUR };
|
|
1800
1794
|
function defaultBudgets(token) {
|
|
1801
1795
|
return token ? { npmPackages: 400, githubRepos: 600, githubSearches: 30 } : { npmPackages: 200, githubRepos: 50, githubSearches: 10 };
|
|
1802
1796
|
}
|
|
@@ -1810,18 +1804,39 @@ function registryOf(entry) {
|
|
|
1810
1804
|
return entry.source.ref.slice(0, entry.source.ref.indexOf("/"));
|
|
1811
1805
|
}
|
|
1812
1806
|
var fresh = (at, ttl, now) => Boolean(at) && now.getTime() - Date.parse(at) < ttl;
|
|
1807
|
+
function homeParts(value) {
|
|
1808
|
+
try {
|
|
1809
|
+
const url = new URL(value.includes("://") ? value : `https://${value}`);
|
|
1810
|
+
return { host: url.hostname.replace(/^www\./, "").toLowerCase(), path: url.pathname.replace(/\/+$/, "").toLowerCase() };
|
|
1811
|
+
} catch {
|
|
1812
|
+
return null;
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1813
1815
|
function sameHomepage(a, b) {
|
|
1814
|
-
const key = (value) => {
|
|
1815
|
-
try {
|
|
1816
|
-
const url = new URL(value.includes("://") ? value : `https://${value}`);
|
|
1817
|
-
return `${url.hostname.replace(/^www\./, "")}${url.pathname.replace(/\/+$/, "")}`.toLowerCase();
|
|
1818
|
-
} catch {
|
|
1819
|
-
return null;
|
|
1820
|
-
}
|
|
1821
|
-
};
|
|
1822
1816
|
if (!a || !b) return false;
|
|
1823
|
-
const
|
|
1824
|
-
|
|
1817
|
+
const pa = homeParts(a);
|
|
1818
|
+
const pb = homeParts(b);
|
|
1819
|
+
return pa !== null && pb !== null && `${pa.host}${pa.path}` === `${pb.host}${pb.path}`;
|
|
1820
|
+
}
|
|
1821
|
+
var PATH_TENANTS = /* @__PURE__ */ new Set(["github.com", "gitlab.com", "bitbucket.org", "codeberg.org", "npmjs.com", "codesandbox.io", "stackblitz.com", "gitbook.io", "medium.com", "notion.site"]);
|
|
1822
|
+
function sameSite(repository, registry) {
|
|
1823
|
+
if (!repository || !registry) return false;
|
|
1824
|
+
const repo = homeParts(repository);
|
|
1825
|
+
const home = homeParts(registry);
|
|
1826
|
+
if (!repo || !home || repo.host !== home.host) return false;
|
|
1827
|
+
if (PATH_TENANTS.has(repo.host)) return repo.path === home.path && repo.path !== "";
|
|
1828
|
+
return repo.path === "" || home.path === repo.path || home.path.startsWith(`${repo.path}/`);
|
|
1829
|
+
}
|
|
1830
|
+
var NOT_OWNERS = /* @__PURE__ */ new Set(["about", "apps", "collections", "contact", "enterprise", "explore", "features", "login", "marketplace", "orgs", "pricing", "settings", "site", "sponsors", "topics"]);
|
|
1831
|
+
function linkedRepos(html) {
|
|
1832
|
+
const names = [];
|
|
1833
|
+
for (const match of html.matchAll(/https?:\/\/(?:www\.)?github\.com\/([A-Za-z0-9-]+)\/([A-Za-z0-9_.-]+)/g)) {
|
|
1834
|
+
const owner = match[1];
|
|
1835
|
+
const repo = match[2].replace(/\.git$/, "").replace(/\.+$/, "");
|
|
1836
|
+
if (NOT_OWNERS.has(owner.toLowerCase()) || !repo || repo.startsWith(".")) continue;
|
|
1837
|
+
names.push(`${owner}/${repo}`);
|
|
1838
|
+
}
|
|
1839
|
+
return byUse(names);
|
|
1825
1840
|
}
|
|
1826
1841
|
var GithubRepoBody = external_exports.object({
|
|
1827
1842
|
full_name: external_exports.string(),
|
|
@@ -1886,9 +1901,19 @@ async function refreshSignals(entries, registries, previous, client, now, budget
|
|
|
1886
1901
|
npm[name] = { weeklyDownloads: typeof count2 === "number" ? count2 : null, license: spdxOrNull(meta?.license), repo: githubRepo(typeof repository === "string" ? repository : null), fetchedAt: at };
|
|
1887
1902
|
});
|
|
1888
1903
|
registryRepos[SHADCN.name] = { repo: SHADCN.repo, checkedAt: at };
|
|
1889
|
-
const
|
|
1890
|
-
|
|
1891
|
-
|
|
1904
|
+
const known = (name) => {
|
|
1905
|
+
const prior = registryRepos[name];
|
|
1906
|
+
return fresh(prior?.checkedAt, prior?.repo ? SIGNAL_TTL.registryRepoMs : SIGNAL_TTL.registryRepoMissMs, now);
|
|
1907
|
+
};
|
|
1908
|
+
const unsearched = [...registries].filter((r) => r.name !== SHADCN.name && r.homepage && !known(r.name)).sort((a, b) => b.items - a.items || a.name.localeCompare(b.name));
|
|
1909
|
+
const spend = { repoCalls: budgets.githubRepos };
|
|
1910
|
+
for (const registry of unsearched) {
|
|
1911
|
+
const linked = await homepageRepo(registry.homepage, client, github, at, report, spend);
|
|
1912
|
+
if (linked) {
|
|
1913
|
+
registryRepos[registry.name] = { repo: linked, checkedAt: at };
|
|
1914
|
+
continue;
|
|
1915
|
+
}
|
|
1916
|
+
if (report.github.searches >= budgets.githubSearches || !client.hasBudget("github-search")) continue;
|
|
1892
1917
|
const query = `${sourceSlug(registry.name).replace(/-ui$/, "")} in:name`;
|
|
1893
1918
|
const result = await client.json(`https://api.github.com/search/repositories?q=${encodeURIComponent(query)}&per_page=10`);
|
|
1894
1919
|
report.github.searches++;
|
|
@@ -1915,7 +1940,7 @@ async function refreshSignals(entries, registries, previous, client, now, budget
|
|
|
1915
1940
|
}
|
|
1916
1941
|
return true;
|
|
1917
1942
|
});
|
|
1918
|
-
const repoTodo = repoStale.slice(0,
|
|
1943
|
+
const repoTodo = repoStale.slice(0, spend.repoCalls);
|
|
1919
1944
|
await pool(repoTodo, async (repo) => {
|
|
1920
1945
|
if (!client.hasBudget("github-core")) return;
|
|
1921
1946
|
const result = await client.json(`https://api.github.com/repos/${repo}`);
|
|
@@ -1931,12 +1956,35 @@ async function refreshSignals(entries, registries, previous, client, now, budget
|
|
|
1931
1956
|
report.github.failed++;
|
|
1932
1957
|
return;
|
|
1933
1958
|
}
|
|
1934
|
-
|
|
1935
|
-
github[repo] = { found: true, repo: body.full_name, htmlUrl: body.html_url, stars: body.stargazers_count, pushedAt: body.pushed_at, archived: body.archived, spdx: spdxOrNull(body.license?.spdx_id), fetchedAt: at };
|
|
1959
|
+
github[repo] = githubSignal(parsed.data, at);
|
|
1936
1960
|
});
|
|
1937
1961
|
report.github.leftUnknown = repos.filter((repo) => !github[repo]).length;
|
|
1938
1962
|
return { signals: { npm, github, registryRepos }, report };
|
|
1939
1963
|
}
|
|
1964
|
+
function githubSignal(body, at) {
|
|
1965
|
+
return { found: true, repo: body.full_name, htmlUrl: body.html_url, stars: body.stargazers_count, pushedAt: body.pushed_at, archived: body.archived, spdx: spdxOrNull(body.license?.spdx_id), fetchedAt: at };
|
|
1966
|
+
}
|
|
1967
|
+
var HOMEPAGE_REPOS = 3;
|
|
1968
|
+
async function homepageRepo(homepage, client, github, at, report, spend) {
|
|
1969
|
+
const page = await client.get(homepage, "text/html");
|
|
1970
|
+
client.cache.delete(homepage);
|
|
1971
|
+
if (!page.ok) return null;
|
|
1972
|
+
for (const repo of linkedRepos(page.body).slice(0, HOMEPAGE_REPOS)) {
|
|
1973
|
+
if (spend.repoCalls <= 0 || !client.hasBudget("github-core")) return null;
|
|
1974
|
+
spend.repoCalls--;
|
|
1975
|
+
const result = await client.json(`https://api.github.com/repos/${repo}`);
|
|
1976
|
+
report.github.looked++;
|
|
1977
|
+
if (!result.ok) {
|
|
1978
|
+
if (result.reason === "rate-limited") report.github.rateLimited = true;
|
|
1979
|
+
continue;
|
|
1980
|
+
}
|
|
1981
|
+
const parsed = GithubRepoBody.safeParse(result.value);
|
|
1982
|
+
if (!parsed.success || !sameSite(parsed.data.homepage, homepage)) continue;
|
|
1983
|
+
github[parsed.data.full_name] = githubSignal(parsed.data, at);
|
|
1984
|
+
return parsed.data.full_name;
|
|
1985
|
+
}
|
|
1986
|
+
return null;
|
|
1987
|
+
}
|
|
1940
1988
|
function repoOf(entry, signals) {
|
|
1941
1989
|
const registry = registryOf(entry);
|
|
1942
1990
|
if (registry) return signals.registryRepos[registry]?.repo ?? null;
|
|
@@ -2021,7 +2069,6 @@ async function syncIndex(options) {
|
|
|
2021
2069
|
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
2022
2070
|
const builtAt = now().toISOString();
|
|
2023
2071
|
const cache = await readHttpCache(options.cacheDir);
|
|
2024
|
-
const previousBodies = new Map([...cache].map(([url, c]) => [url, c.sha256]));
|
|
2025
2072
|
const client = new PoliteClient({
|
|
2026
2073
|
...options.fetcher ? { fetcher: options.fetcher } : {},
|
|
2027
2074
|
...options.token ? { token: options.token } : {},
|
|
@@ -2029,7 +2076,6 @@ async function syncIndex(options) {
|
|
|
2029
2076
|
perHost: options.perHost ?? 2,
|
|
2030
2077
|
timeoutMs: options.timeoutMs ?? 15e3,
|
|
2031
2078
|
buckets: githubBuckets(options.token),
|
|
2032
|
-
bucketFor: githubBucketFor,
|
|
2033
2079
|
cache,
|
|
2034
2080
|
now,
|
|
2035
2081
|
...options.sleep ? { sleep: options.sleep } : {}
|
|
@@ -2055,7 +2101,7 @@ async function syncIndex(options) {
|
|
|
2055
2101
|
failure = "could not be parsed";
|
|
2056
2102
|
}
|
|
2057
2103
|
}
|
|
2058
|
-
sources.push(failure === null && result.ok ? { id: `headless:${catalog.id}`, url: catalog.url, outcome: result.revalidated ? "revalidated" : "fetched", reason: null, httpStatus: result.status, items: names.length, health: null } : { id: `headless:${catalog.id}`, url: catalog.url, outcome: "failed", reason: failure, httpStatus: result.
|
|
2104
|
+
sources.push(failure === null && result.ok ? { id: `headless:${catalog.id}`, url: catalog.url, outcome: result.revalidated ? "revalidated" : "fetched", reason: null, httpStatus: result.status, items: names.length, health: null } : { id: `headless:${catalog.id}`, url: catalog.url, outcome: "failed", reason: failure, httpStatus: result.status, items: 0, health: null });
|
|
2059
2105
|
return { id: catalog.id, names };
|
|
2060
2106
|
})
|
|
2061
2107
|
);
|
|
@@ -2086,6 +2132,8 @@ async function syncIndex(options) {
|
|
|
2086
2132
|
else if (options.maxRegistries !== void 0 && toFetch.length >= options.maxRegistries) sources.push({ id: registry.name, url: registryUrl(registry.template), outcome: "skipped", reason: "over --max-registries", httpStatus: null, items: 0, health: healthOf(registry) });
|
|
2087
2133
|
else toFetch.push(registry);
|
|
2088
2134
|
}
|
|
2135
|
+
const missing = directory2.ok ? selected.filter((name) => !listed.some((r) => r.name === name)) : [];
|
|
2136
|
+
for (const name of missing) sources.push({ id: name, url: SHADCN.directory, outcome: "skipped", reason: "not in the registry directory", httpStatus: null, items: 0, health: null });
|
|
2089
2137
|
const community = await Promise.all(
|
|
2090
2138
|
toFetch.map(async (registry) => {
|
|
2091
2139
|
const url = registryUrl(registry.template);
|
|
@@ -2138,7 +2186,7 @@ async function syncIndex(options) {
|
|
|
2138
2186
|
const index = cleanData({ schema: "youi.discover-index/v1", format: 2, builtAt, sources, categories: Object.fromEntries(categories), entries: final });
|
|
2139
2187
|
await writeJson(join3(options.cacheDir, SIGNALS_FILE), signals);
|
|
2140
2188
|
await writeJson(join3(options.cacheDir, HEALTH_FILE), cleanData({ checkedAt: builtAt, sources }));
|
|
2141
|
-
await writeHttpCache(options.cacheDir, client.cache
|
|
2189
|
+
await writeHttpCache(options.cacheDir, client.cache);
|
|
2142
2190
|
await writeJson(join3(options.cacheDir, INDEX_FILE2), index);
|
|
2143
2191
|
const registryStatuses = sources.filter((s) => s.health !== null);
|
|
2144
2192
|
const known = final.filter((e) => e.license && e.license !== "unknown").length;
|
|
@@ -2147,7 +2195,7 @@ async function syncIndex(options) {
|
|
|
2147
2195
|
catalogBytes: await catalogBytes(options.cacheDir),
|
|
2148
2196
|
selectedSources: selected.length,
|
|
2149
2197
|
index: { bytes: Buffer.byteLength(JSON.stringify(index) + "\n"), entries: final.length, mirrorsCollapsed, iconRegistriesSkipped: sources.filter((s) => s.reason === iconReason).length },
|
|
2150
|
-
warnings: client.warnings,
|
|
2198
|
+
warnings: [...client.warnings, ...missing.map((name) => `${name} is chosen but the registry directory no longer lists it: \`youiyoux discover sources remove ${name}\``)],
|
|
2151
2199
|
builtAt,
|
|
2152
2200
|
durationMs: Math.round(performance.now() - started),
|
|
2153
2201
|
entries: { total: final.length, official: final.filter((e) => e.source.ref?.startsWith(`${SHADCN.name}/`)).length, community: final.filter((e) => e.source.kind === "shadcn-registry" && !e.source.ref?.startsWith(`${SHADCN.name}/`)).length, npm: final.filter((e) => e.source.kind === "npm").length },
|
|
@@ -2197,7 +2245,7 @@ async function expandAll(cacheDir, options = {}) {
|
|
|
2197
2245
|
const entries2 = parseRegistryItems(response.value).items.filter(isCandidate).map((item) => registryEntry({ name: r.name, homepage: r.homepage, url, fetchedAt: response.result.fetchedAt, official: false, health: r.health }, item, categories));
|
|
2198
2246
|
return !options.icons && entries2.length && entries2.filter(isIconEntry).length / entries2.length >= 0.8 ? [] : entries2.map((entry) => applySignals(entry, signals));
|
|
2199
2247
|
}));
|
|
2200
|
-
await writeHttpCache(cacheDir, cache
|
|
2248
|
+
await writeHttpCache(cacheDir, cache);
|
|
2201
2249
|
const chosen = new Set(index.entries.map((e) => e.id));
|
|
2202
2250
|
const entries = dedupe([...index.entries, ...extra.flat()]).entries.filter((e) => !chosen.has(e.id));
|
|
2203
2251
|
const next = `${JSON.stringify(cleanData({ schema: index.schema, format: 2, builtAt: index.builtAt, sources: [], categories: index.categories, entries }))}
|
|
@@ -2259,9 +2307,6 @@ function rolesOf(entry) {
|
|
|
2259
2307
|
const f = fieldsOf(entry);
|
|
2260
2308
|
return CONCEPTS.filter((concept) => conceptScore(concept, f, []) > 0).map((c) => c.id);
|
|
2261
2309
|
}
|
|
2262
|
-
function licenceOf(entry) {
|
|
2263
|
-
return entry.license && entry.license !== "unknown" ? entry.license.spdx : "unknown";
|
|
2264
|
-
}
|
|
2265
2310
|
function searchTextOf(entry) {
|
|
2266
2311
|
const f = fieldsOf(entry);
|
|
2267
2312
|
return [f.name, f.name, f.name, f.title, f.title, f.description, ...f.categories, ...f.packages.map(normalize)].filter(Boolean).join(" ");
|
|
@@ -2388,7 +2433,7 @@ function needTerms(need) {
|
|
|
2388
2433
|
}
|
|
2389
2434
|
async function searchCatalog(store, need, options = {}) {
|
|
2390
2435
|
const filter = filterOf(options);
|
|
2391
|
-
const rows = await store.matchDiscover({ ...filter, terms: needTerms(need), perClass:
|
|
2436
|
+
const rows = await store.matchDiscover({ ...filter, terms: needTerms(need), perClass: CANDIDATES_PER_CLASS });
|
|
2392
2437
|
const ranked = rankEntries(rows.map((r) => r.entry), need, options);
|
|
2393
2438
|
const offset = pageInteger(options.offset, 0, 2147483647);
|
|
2394
2439
|
const page = ranked.scored.slice(offset, offset + pageInteger(options.limit, 10));
|
|
@@ -2598,7 +2643,7 @@ async function preparePreview(cacheDir, id, options = {}) {
|
|
|
2598
2643
|
await assertNoLinks(dir, file);
|
|
2599
2644
|
await writeFileAtomic(join6(dir, file), text);
|
|
2600
2645
|
}
|
|
2601
|
-
const packages = [...new Set([...rewritten.values()].flatMap((t) => importedPackages(t)))].
|
|
2646
|
+
const packages = [...new Set([...rewritten.values()].flatMap((t) => importedPackages(t)))].sort();
|
|
2602
2647
|
const declared = [...new Set([...source.dependencies ?? entry.install?.npm ?? [], ...partDeps].map(packageName))].sort();
|
|
2603
2648
|
const sources = [...rewritten.entries()].filter(([f]) => /\.(?:tsx|jsx|ts|js)$/.test(f)).map(([, t]) => t);
|
|
2604
2649
|
return {
|
|
@@ -2618,9 +2663,138 @@ async function preparePreview(cacheDir, id, options = {}) {
|
|
|
2618
2663
|
};
|
|
2619
2664
|
}
|
|
2620
2665
|
|
|
2666
|
+
// ../discover/src/gaps.ts
|
|
2667
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2668
|
+
import { join as join7 } from "node:path";
|
|
2669
|
+
var STANDARD_KIT = ["button", "input", "card", "badge", "dialog", "alert", "drawer", "menu", "popover", "tooltip", "tabs", "avatar", "accordion", "table", "carousel", "slider", "switch", "checkbox", "radio", "select", "otp", "progress", "skeleton", "spinner", "sidebar", "navigation", "breadcrumb", "pagination", "command", "toast", "date-picker", "combobox", "chart"];
|
|
2670
|
+
var ONLY_EXACT = /* @__PURE__ */ new Set(["hint", "tile", "range", "loading", "picker", "tree", "graph", "plot", "editor", "cta", "notice", "steps", "tag", "toggle", "meter", "command", "banner", "popup", "pager", "loader", "navigation", "chip", "pill"]);
|
|
2671
|
+
var ROLE_CONCEPT2 = { button: "button", "link-as-button": "button", input: "input", card: "card", badge: "badge", dialog: "dialog", tabs: "tabs" };
|
|
2672
|
+
var CANDIDATES = 3;
|
|
2673
|
+
var DEFINITIONS_SHOWN = 5;
|
|
2674
|
+
function conceptOfName(name) {
|
|
2675
|
+
const words2 = normalize(name.replace(/\.[a-z]+$/, ""));
|
|
2676
|
+
if (!words2) return void 0;
|
|
2677
|
+
const phrases = CONCEPTS.flatMap((concept) => concept.names.map((n) => ({ concept, name: normalize(n) }))).sort((a, b) => b.name.length - a.name.length);
|
|
2678
|
+
return phrases.find((p) => words2 === p.name || !ONLY_EXACT.has(p.name) && ` ${words2}`.endsWith(` ${p.name}`))?.concept;
|
|
2679
|
+
}
|
|
2680
|
+
function conceptOfPackage(pkg) {
|
|
2681
|
+
const listed = CONCEPTS.find((c) => c.packages.includes(pkg));
|
|
2682
|
+
if (listed) return listed;
|
|
2683
|
+
const last = pkg.split("/").at(-1).replace(/^react-/, "");
|
|
2684
|
+
return conceptForRole(last);
|
|
2685
|
+
}
|
|
2686
|
+
function declaredPackages(roots) {
|
|
2687
|
+
const found = {};
|
|
2688
|
+
for (const [id, root] of roots) {
|
|
2689
|
+
const file = join7(root, "package.json");
|
|
2690
|
+
if (!existsSync(file)) continue;
|
|
2691
|
+
try {
|
|
2692
|
+
const pkg = JSON.parse(readFileSync(file, "utf8"));
|
|
2693
|
+
found[id] = [...Object.keys(pkg.dependencies ?? {}), ...Object.keys(pkg.devDependencies ?? {})].sort();
|
|
2694
|
+
} catch {
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
return found;
|
|
2698
|
+
}
|
|
2699
|
+
var fresh2 = () => ({ system: /* @__PURE__ */ new Set(), packages: /* @__PURE__ */ new Set(), definitions: [], uses: 0, files: /* @__PURE__ */ new Set() });
|
|
2700
|
+
async function candidatesFor(store, concept) {
|
|
2701
|
+
const { hits } = await searchCatalog(store, concept.names[0], { role: concept.id, limit: 12 });
|
|
2702
|
+
return hits.filter((hit) => hit.license !== "unknown").map((hit) => ({ id: hit.id, name: hit.name, source: hit.source.name, licence: hit.license, copyleft: copyleft(hit.license), install: hit.install?.command ?? null })).sort((a, b) => Number(a.copyleft) - Number(b.copyleft)).slice(0, CANDIDATES);
|
|
2703
|
+
}
|
|
2704
|
+
var ORDER = { "hand-built": 0, missing: 1, library: 2, system: 3 };
|
|
2705
|
+
var KIT_ORDER = new Map(STANDARD_KIT.map((id, i) => [id, i]));
|
|
2706
|
+
async function buildGaps(source, store) {
|
|
2707
|
+
const { inventory } = source;
|
|
2708
|
+
const systemByConcept = /* @__PURE__ */ new Map();
|
|
2709
|
+
for (const name of source.system?.components ?? []) {
|
|
2710
|
+
const concept = conceptOfName(name);
|
|
2711
|
+
if (concept) systemByConcept.set(concept.id, [...systemByConcept.get(concept.id) ?? [], name]);
|
|
2712
|
+
}
|
|
2713
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
2714
|
+
const offer = (concept) => {
|
|
2715
|
+
if (!store) return null;
|
|
2716
|
+
let found = candidates.get(concept.id);
|
|
2717
|
+
if (!found) candidates.set(concept.id, found = candidatesFor(store, concept));
|
|
2718
|
+
return found;
|
|
2719
|
+
};
|
|
2720
|
+
const projects = [];
|
|
2721
|
+
for (const project of inventory.projects) {
|
|
2722
|
+
const tallies = /* @__PURE__ */ new Map();
|
|
2723
|
+
const tally2 = (id) => {
|
|
2724
|
+
let t = tallies.get(id);
|
|
2725
|
+
if (!t) tallies.set(id, t = fresh2());
|
|
2726
|
+
return t;
|
|
2727
|
+
};
|
|
2728
|
+
for (const [id, names] of systemByConcept) for (const name of names) tally2(id).system.add(name);
|
|
2729
|
+
for (const primitive of inventory.primitives.filter((p) => p.project === project.id)) {
|
|
2730
|
+
const concept = conceptOfPackage(primitive.package);
|
|
2731
|
+
if (concept) tally2(concept.id).packages.add(primitive.package);
|
|
2732
|
+
}
|
|
2733
|
+
for (const pkg of source.dependencies[project.id] ?? []) {
|
|
2734
|
+
const concept = CONCEPTS.find((c) => c.packages.includes(pkg));
|
|
2735
|
+
if (concept) tally2(concept.id).packages.add(pkg);
|
|
2736
|
+
}
|
|
2737
|
+
const ownConcept = /* @__PURE__ */ new Map();
|
|
2738
|
+
for (const definition of inventory.definitions.filter((d) => d.project === project.id)) {
|
|
2739
|
+
const concept = conceptOfName(definition.name);
|
|
2740
|
+
if (!concept) continue;
|
|
2741
|
+
ownConcept.set(definition.id, concept.id);
|
|
2742
|
+
const t = tally2(concept.id);
|
|
2743
|
+
t.definitions.push({ name: definition.name, file: definition.file, line: definition.line });
|
|
2744
|
+
t.files.add(definition.file);
|
|
2745
|
+
}
|
|
2746
|
+
for (const look of inventory.looks.filter((l) => l.project === project.id && !l.story)) {
|
|
2747
|
+
const id = look.definition ? ownConcept.get(look.definition) : look.source === "intrinsic" ? ROLE_CONCEPT2[look.role] : void 0;
|
|
2748
|
+
if (!id) continue;
|
|
2749
|
+
const t = tally2(id);
|
|
2750
|
+
t.uses += 1;
|
|
2751
|
+
t.files.add(look.file);
|
|
2752
|
+
}
|
|
2753
|
+
const concepts = [];
|
|
2754
|
+
for (const concept of CONCEPTS) {
|
|
2755
|
+
const t = tallies.get(concept.id) ?? fresh2();
|
|
2756
|
+
const hand = t.definitions.length > 0 || t.uses > 0;
|
|
2757
|
+
const status2 = t.system.size ? "system" : t.packages.size ? "library" : hand ? "hand-built" : KIT_ORDER.has(concept.id) ? "missing" : null;
|
|
2758
|
+
if (!status2) continue;
|
|
2759
|
+
const offered = status2 === "hand-built" || status2 === "missing" ? offer(concept) : null;
|
|
2760
|
+
concepts.push({
|
|
2761
|
+
concept: concept.id,
|
|
2762
|
+
name: concept.names[0],
|
|
2763
|
+
status: status2,
|
|
2764
|
+
system: [...t.system].sort(),
|
|
2765
|
+
packages: [...t.packages].sort(),
|
|
2766
|
+
definitions: t.definitions.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line).slice(0, DEFINITIONS_SHOWN),
|
|
2767
|
+
count: t.definitions.length,
|
|
2768
|
+
uses: t.uses,
|
|
2769
|
+
files: t.files.size,
|
|
2770
|
+
candidates: offered ? await offered : status2 === "hand-built" || status2 === "missing" ? null : []
|
|
2771
|
+
});
|
|
2772
|
+
}
|
|
2773
|
+
concepts.sort((a, b) => ORDER[a.status] - ORDER[b.status] || (a.status === "hand-built" ? b.uses - a.uses || b.count - a.count : 0) || (KIT_ORDER.get(a.concept) ?? 99) - (KIT_ORDER.get(b.concept) ?? 99) || a.concept.localeCompare(b.concept));
|
|
2774
|
+
projects.push({ id: project.id, complete: project.status === "complete", dependencies: source.dependencies[project.id] ? "read" : "unread", concepts });
|
|
2775
|
+
}
|
|
2776
|
+
const across = /* @__PURE__ */ new Map();
|
|
2777
|
+
for (const project of projects) {
|
|
2778
|
+
for (const c of project.concepts.filter((c2) => c2.status === "hand-built")) {
|
|
2779
|
+
const entry = across.get(c.concept) ?? { name: c.name, projects: [], uses: 0 };
|
|
2780
|
+
entry.projects.push(project.id);
|
|
2781
|
+
entry.uses += c.uses;
|
|
2782
|
+
across.set(c.concept, entry);
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2785
|
+
return {
|
|
2786
|
+
schema: "youi.gaps/v1",
|
|
2787
|
+
generatedAt: (source.now ?? /* @__PURE__ */ new Date()).toISOString(),
|
|
2788
|
+
system: source.system?.name ?? null,
|
|
2789
|
+
discover: store ? "synced" : "not-synced",
|
|
2790
|
+
kit: [...STANDARD_KIT],
|
|
2791
|
+
projects,
|
|
2792
|
+
across: [...across].filter(([, e]) => e.projects.length > 1).map(([concept, e]) => ({ concept, ...e })).sort((a, b) => b.uses - a.uses || a.concept.localeCompare(b.concept))
|
|
2793
|
+
};
|
|
2794
|
+
}
|
|
2795
|
+
|
|
2621
2796
|
export {
|
|
2622
2797
|
CONCEPTS,
|
|
2623
|
-
conceptById,
|
|
2624
2798
|
normalize,
|
|
2625
2799
|
hasPhrase,
|
|
2626
2800
|
readNeed,
|
|
@@ -2669,7 +2843,6 @@ export {
|
|
|
2669
2843
|
discoverIndexPath,
|
|
2670
2844
|
SourceStatus,
|
|
2671
2845
|
DiscoverIndex,
|
|
2672
|
-
EMPTY_SIGNALS,
|
|
2673
2846
|
writeJson,
|
|
2674
2847
|
MissingIndexError,
|
|
2675
2848
|
readIndex,
|
|
@@ -2696,6 +2869,7 @@ export {
|
|
|
2696
2869
|
registryName,
|
|
2697
2870
|
passes,
|
|
2698
2871
|
playsRole,
|
|
2872
|
+
licenceOf,
|
|
2699
2873
|
hitOf,
|
|
2700
2874
|
isIconEntry,
|
|
2701
2875
|
rankEntries,
|
|
@@ -2706,6 +2880,8 @@ export {
|
|
|
2706
2880
|
keyPackage,
|
|
2707
2881
|
registryOf,
|
|
2708
2882
|
sameHomepage,
|
|
2883
|
+
sameSite,
|
|
2884
|
+
linkedRepos,
|
|
2709
2885
|
refreshSignals,
|
|
2710
2886
|
applySignals,
|
|
2711
2887
|
dedupe,
|
|
@@ -2718,7 +2894,6 @@ export {
|
|
|
2718
2894
|
LINKS_PER_ROLE,
|
|
2719
2895
|
sourceClassOf,
|
|
2720
2896
|
rolesOf,
|
|
2721
|
-
licenceOf,
|
|
2722
2897
|
searchTextOf,
|
|
2723
2898
|
itemOf,
|
|
2724
2899
|
ingestCatalog,
|
|
@@ -2736,5 +2911,10 @@ export {
|
|
|
2736
2911
|
safeRelative,
|
|
2737
2912
|
exportNames,
|
|
2738
2913
|
importedNames,
|
|
2739
|
-
preparePreview
|
|
2914
|
+
preparePreview,
|
|
2915
|
+
STANDARD_KIT,
|
|
2916
|
+
conceptOfName,
|
|
2917
|
+
conceptOfPackage,
|
|
2918
|
+
declaredPackages,
|
|
2919
|
+
buildGaps
|
|
2740
2920
|
};
|