diff --git a/app/components/Translation/StatusByFile.unused.vue b/app/components/Translation/StatusByFile.unused.vue deleted file mode 100644 index c4db80ae99..0000000000 --- a/app/components/Translation/StatusByFile.unused.vue +++ /dev/null @@ -1,132 +0,0 @@ - - - diff --git a/app/composables/usePackageComparison.ts b/app/composables/usePackageComparison.ts index 7d938d69e8..a26e1de515 100644 --- a/app/composables/usePackageComparison.ts +++ b/app/composables/usePackageComparison.ts @@ -8,7 +8,7 @@ export const NO_DEPENDENCY_ID = '__no_dependency__' * Special display values for the "no dependency" column. * These are explicit markers that get special rendering treatment. */ -export const NoDependencyDisplay = { +const NoDependencyDisplay = { /** Display as "–" (en-dash) */ DASH: '__display_dash__', /** Display as "Up to you!" with good status */ diff --git a/app/utils/chart-data-correction.ts b/app/utils/chart-data-correction.ts index 4f94ee5663..2301af8084 100644 --- a/app/utils/chart-data-correction.ts +++ b/app/utils/chart-data-correction.ts @@ -6,7 +6,7 @@ * * @param halfWindow - number of points on each side (0 = disabled) */ -export function movingAverage(data: T[], halfWindow: number): T[] { +function movingAverage(data: T[], halfWindow: number): T[] { if (halfWindow <= 0 || data.length < 3) return data const n = data.length @@ -46,7 +46,7 @@ export function movingAverage(data: T[], halfWindow * * @param tau - time constant (0 = disabled, higher = smoother) */ -export function smoothing(data: T[], tau: number): T[] { +function smoothing(data: T[], tau: number): T[] { if (tau <= 0 || data.length < 3) return data const alpha = 1 / (1 + tau) diff --git a/app/utils/charts.ts b/app/utils/charts.ts index 3ac00eb48c..7ef1da59d1 100644 --- a/app/utils/charts.ts +++ b/app/utils/charts.ts @@ -427,9 +427,9 @@ export type TrendLineDataset = { [key: string]: unknown } | null -export type TrendTranslateKey = number | 'package.trends.y_axis_label' | (string & {}) +type TrendTranslateKey = number | 'package.trends.y_axis_label' | (string & {}) -export type TrendTranslateFunction = { +type TrendTranslateFunction = { (key: TrendTranslateKey): string (key: TrendTranslateKey, named: Record): string (key: TrendTranslateKey, named: Record, options: Record): string @@ -461,7 +461,7 @@ export type FacetBarChartConfig = VueUiHorizontalBarConfig & { $t: TrendTranslateFunction } -export type TimelineSizeDependencyBreakdown = { +type TimelineSizeDependencyBreakdown = { name: string size: number } @@ -473,7 +473,7 @@ export type TimelineSizeCacheValue = { dependencies: TimelineSizeDependencyBreakdown[] } -export type ConvertedTimelineSizeCacheEntry = TimelineSizeCacheValue & { +type ConvertedTimelineSizeCacheEntry = TimelineSizeCacheValue & { name: string } @@ -684,7 +684,7 @@ export async function copyAltTextForVersionsBarChart({ } // Used for FacetBarChart.vue -export function createAltTextForCompareFacetBarChart({ +function createAltTextForCompareFacetBarChart({ dataset, config, }: AltCopyArgs) { @@ -734,7 +734,7 @@ type CompareScatterChartConfig = VueUiScatterConfig & { } // Used for FacetScatterChart.vue -export function createAltTextForCompareScatterChart({ +function createAltTextForCompareScatterChart({ dataset, config, }: AltCopyArgs) { diff --git a/app/utils/download-anomalies.ts b/app/utils/download-anomalies.ts index 8aad2ab646..458efc3a1b 100644 --- a/app/utils/download-anomalies.ts +++ b/app/utils/download-anomalies.ts @@ -1,7 +1,7 @@ import type { ChartTimeGranularity, EvolutionData } from '~/types/chart' import { DOWNLOAD_ANOMALIES } from './download-anomalies.data' -export type DownloadAnomalyBound = { +type DownloadAnomalyBound = { date: string // YYYY-MM-DD weeklyDownloads: number } diff --git a/app/utils/package-name.ts b/app/utils/package-name.ts index f4738938d3..ef0d821500 100644 --- a/app/utils/package-name.ts +++ b/app/utils/package-name.ts @@ -31,7 +31,7 @@ export function normalizePackageName(name: string): string { /** * Calculate similarity between two strings using Levenshtein distance. */ -export function levenshteinDistance(a: string, b: string): number { +function levenshteinDistance(a: string, b: string): number { const matrix: number[][] = [] for (let i = 0; i <= b.length; i++) { diff --git a/app/utils/versions.ts b/app/utils/versions.ts index b848bf3442..d4e7c67c83 100644 --- a/app/utils/versions.ts +++ b/app/utils/versions.ts @@ -48,7 +48,7 @@ export function getPrereleaseChannel(version: string): string { * Lower number = higher priority in display order. * Unknown tags fall back to Infinity and are sorted by publish date descending. */ -export const TAG_PRIORITY: Record = { +const TAG_PRIORITY: Record = { latest: 0, stable: 1, rc: 2, @@ -67,7 +67,7 @@ export const TAG_PRIORITY: Record = { * @param tag - The tag name (e.g., "beta", "v2-legacy") * @returns Numeric priority (lower = higher priority); Infinity for unknown tags */ -export function getTagPriority(tag: string | undefined): number { +function getTagPriority(tag: string | undefined): number { if (!tag) return Infinity for (const [key, priority] of Object.entries(TAG_PRIORITY)) { if (tag.toLowerCase().includes(key)) return priority diff --git a/i18n/locales/ar-EG.json b/i18n/locales/ar-EG.json index 3cdee1ca54..3a669bde78 100644 --- a/i18n/locales/ar-EG.json +++ b/i18n/locales/ar-EG.json @@ -368,18 +368,10 @@ "p2": "نرحّب بمساهماتك في الترجمة.", "guide": "دليل الترجمة", "by_locale": "التقدم حسب اللغة", - "by_file": "التقدم حسب الملف", "complete_text": "مكتمل", "missing_text": "مفقود", "missing_keys": "المفاتيح المفقودة", - "progress_label": "نسبة الاكتمال", - "table": { - "file": "الملف", - "status": "الحالة", - "error": "خطأ", - "empty": "لا توجد بيانات", - "file_link": "رابط الملف" - } + "progress_label": "نسبة الاكتمال" }, "action_bar": { "title": "شريط الإجراءات", diff --git a/i18n/locales/bn-IN.json b/i18n/locales/bn-IN.json index f63f47f2ad..c66a30e719 100644 --- a/i18n/locales/bn-IN.json +++ b/i18n/locales/bn-IN.json @@ -1736,18 +1736,10 @@ "p2": "শুরু করার আগে, অনুগ্রহ করে আমাদের {guide} পড়ুন যাতে অনুবাদ প্রক্রিয়া এবং কীভাবে অংশ নিতে হয় তা জানতে পারেন।", "guide": "লোকালাইজেশন (i18n) গাইড", "by_locale": "লোকেল অনুযায়ী অনুবাদ অগ্রগতি", - "by_file": "ফাইল অনুযায়ী অনুবাদ অগ্রগতি", "complete_text": "এই অনুবাদ সম্পূর্ণ হয়েছে, দারুণ কাজ!", "missing_text": "অনুপস্থিত", "missing_keys": "কোনো অনুবাদ অনুপস্থিত নেই | অনুপস্থিত অনুবাদ | অনুপস্থিত অনুবাদসমূহ", - "progress_label": "{locale}-এর জন্য অগ্রগতির অবস্থা", - "table": { - "file": "ফাইল", - "status": "অবস্থা", - "error": "ফাইল তালিকা লোড করার সময় ত্রুটি হয়েছে।", - "empty": "কোনো ফাইল পাওয়া যায়নি", - "file_link": "{file} ({lang}) GitHub-এ সম্পাদনা করুন" - } + "progress_label": "{locale}-এর জন্য অগ্রগতির অবস্থা" }, "vacations": { "title": "ছুটিতে", diff --git a/i18n/locales/cs-CZ.json b/i18n/locales/cs-CZ.json index a6fa3f887c..efe1e297ec 100644 --- a/i18n/locales/cs-CZ.json +++ b/i18n/locales/cs-CZ.json @@ -1666,18 +1666,10 @@ "p2": "Než začnete, přečtěte si prosím našeho {guide}, abyste se seznámili s naším procesem překladu a zjistili, jak se můžete zapojit.", "guide": "průvodce lokalizací (i18n)", "by_locale": "Pokrok překladu podle jazyka", - "by_file": "Pokrok překladu podle souboru", "complete_text": "Tento překlad je dokončen, skvělá práce!", "missing_text": "chybí", "missing_keys": "{count} chybějící překlad | {count} chybějící překlady | {count} chybějících překladů", - "progress_label": "Pokrok překladu do jazyka {locale}", - "table": { - "file": "Soubor", - "status": "Stav", - "error": "Chyba při načítání seznamu souborů.", - "empty": "Žádné soubory nebyly nalezeny", - "file_link": "Upravit {file} ({lang}) na GitHubu" - } + "progress_label": "Pokrok překladu do jazyka {locale}" }, "vacations": { "title": "na dovolené", diff --git a/i18n/locales/de.json b/i18n/locales/de.json index e0f1fedb21..d24d774fce 100644 --- a/i18n/locales/de.json +++ b/i18n/locales/de.json @@ -1616,18 +1616,10 @@ "p2": "Bevor du beginnst, lies bitte unseren {guide}, um mehr über unseren Übersetzungsprozess zu erfahren und wie du dich beteiligen kannst.", "guide": "Lokalisierungs-Leitfaden (i18n)", "by_locale": "Übersetzungsfortschritt nach Sprache", - "by_file": "Übersetzungsfortschritt nach Datei", "complete_text": "Diese Übersetzung ist vollständig, großartige Arbeit!", "missing_text": "fehlt", "missing_keys": "Keine fehlenden Übersetzungen | Fehlende Übersetzung | Fehlende Übersetzungen", - "progress_label": "Fortschrittsstatus für {locale}", - "table": { - "file": "Datei", - "status": "Status", - "error": "Fehler beim Laden der Dateiliste.", - "empty": "Keine Dateien gefunden", - "file_link": "Bearbeite {file} ({lang}) auf GitHub" - } + "progress_label": "Fortschrittsstatus für {locale}" }, "vacations": { "title": "im urlaub", diff --git a/i18n/locales/en.json b/i18n/locales/en.json index 5217627409..23ba2d5b82 100644 --- a/i18n/locales/en.json +++ b/i18n/locales/en.json @@ -1839,18 +1839,10 @@ "p2": "Before starting, please read our {guide} to learn about our translation process and how you can get involved.", "guide": "localization (i18n) guide", "by_locale": "Translation progress by locale", - "by_file": "Translation progress by file", "complete_text": "This translation is complete, amazing job!", "missing_text": "missing", "missing_keys": "There is no missing translations | Missing translation | Missing translations", - "progress_label": "Progress status for {locale}", - "table": { - "file": "File", - "status": "Status", - "error": "Error while loading file list.", - "empty": "No files found", - "file_link": "Edit {file} ({lang}) on GitHub" - } + "progress_label": "Progress status for {locale}" }, "vacations": { "title": "on vacation", diff --git a/i18n/locales/es.json b/i18n/locales/es.json index 3e63d8fa5f..f8c2d05171 100644 --- a/i18n/locales/es.json +++ b/i18n/locales/es.json @@ -1737,18 +1737,10 @@ "p2": "Antes de comenzar, por favor lee nuestra {guide} para aprender sobre nuestro proceso de traducción y cómo puedes participar.", "guide": "guía de localización (i18n)", "by_locale": "Progreso de traducción por idioma", - "by_file": "Progreso de traducción por archivo", "complete_text": "Esta traducción está completa, ¡gran trabajo!", "missing_text": "faltante", "missing_keys": "No hay traducciones faltantes | Traducción faltante | Traducciones faltantes", - "progress_label": "Estado de progreso para {locale}", - "table": { - "file": "Archivo", - "status": "Estado", - "error": "Error al cargar la lista de archivos.", - "empty": "No se encontraron archivos", - "file_link": "Editar {file} ({lang}) en GitHub" - } + "progress_label": "Estado de progreso para {locale}" }, "vacations": { "title": "de vacaciones", diff --git a/i18n/locales/fr-FR.json b/i18n/locales/fr-FR.json index ca260b5ba7..ea367e8e07 100644 --- a/i18n/locales/fr-FR.json +++ b/i18n/locales/fr-FR.json @@ -1682,18 +1682,10 @@ "p2": "Avant de commencer, veuillez lire notre {guide} pour en savoir plus sur notre processus de traduction et sur la façon de contribuer.", "guide": "guide de localisation (i18n)", "by_locale": "Progression des traductions par langue", - "by_file": "Progression des traductions par fichier", "complete_text": "Cette traduction est complète, bravo !", "missing_text": "manquantes", "missing_keys": "Aucune traduction manquante | Traduction manquante | Traductions manquantes", - "progress_label": "État d'avancement pour {locale}", - "table": { - "file": "Fichier", - "status": "Statut", - "error": "Erreur lors du chargement de la liste des fichiers.", - "empty": "Aucun fichier trouvé", - "file_link": "Modifier {file} ({lang}) sur GitHub" - } + "progress_label": "État d'avancement pour {locale}" }, "vacations": { "title": "en vacances", diff --git a/i18n/locales/hi-IN.json b/i18n/locales/hi-IN.json index 4dbbc73a92..0e3d440933 100644 --- a/i18n/locales/hi-IN.json +++ b/i18n/locales/hi-IN.json @@ -1415,18 +1415,10 @@ "p2": "शुरू करने से पहले, हमारी {guide} पढ़ें ताकि आप हमारी अनुवाद प्रक्रिया और इसमें शामिल होने के तरीकों के बारे में जान सकें।", "guide": "लोकलाइज़ेशन (i18n) गाइड", "by_locale": "locale के अनुसार अनुवाद प्रगति", - "by_file": "फ़ाइल के अनुसार अनुवाद प्रगति", "complete_text": "यह अनुवाद पूरा हो चुका है, शानदार काम!", "missing_text": "गायब", "missing_keys": "कोई अनुवाद गायब नहीं है | अनुवाद गायब है | अनुवाद गायब हैं", - "progress_label": "{locale} के लिए प्रगति स्थिति", - "table": { - "file": "फ़ाइल", - "status": "स्थिति", - "error": "फ़ाइल सूची लोड करते समय त्रुटि।", - "empty": "कोई फ़ाइल नहीं मिली", - "file_link": "GitHub पर {file} ({lang}) संपादित करें" - } + "progress_label": "{locale} के लिए प्रगति स्थिति" }, "vacations": { "title": "छुट्टी पर", diff --git a/i18n/locales/id-ID.json b/i18n/locales/id-ID.json index c8cd4009b6..3693349b92 100644 --- a/i18n/locales/id-ID.json +++ b/i18n/locales/id-ID.json @@ -1437,18 +1437,10 @@ "p2": "Sebelum memulai, silakan baca {guide} kami untuk mempelajari proses penerjemahan dan bagaimana Anda dapat berkontribusi.", "guide": "panduan lokalisasi (i18n)", "by_locale": "Progres terjemahan per locale", - "by_file": "Progres terjemahan per file", "complete_text": "Terjemahan ini sudah lengkap, pekerjaan yang luar biasa!", "missing_text": "tidak ditemukan", "missing_keys": "Tidak ada terjemahan yang hilang | Terjemahan hilang | Terjemahan hilang", - "progress_label": "Status progres untuk {locale}", - "table": { - "file": "File", - "status": "Status", - "error": "Terjadi kesalahan saat memuat daftar file.", - "empty": "Tidak ada file yang ditemukan", - "file_link": "Ubah {file} ({lang}) di GitHub" - } + "progress_label": "Status progres untuk {locale}" }, "vacations": { "title": "sedang liburan", diff --git a/i18n/locales/it-IT.json b/i18n/locales/it-IT.json index a61b78a12c..691db79463 100644 --- a/i18n/locales/it-IT.json +++ b/i18n/locales/it-IT.json @@ -1581,18 +1581,10 @@ "p2": "Prima di iniziare, leggi la nostra {guide} per scoprire il nostro processo di traduzione e come puoi contribuire.", "guide": "guida alla localizzazione (i18n)", "by_locale": "Avanzamento traduzione per lingua", - "by_file": "Avanzamento traduzione per file", "complete_text": "Questa traduzione è completa, ottimo lavoro!", "missing_text": "mancante", "missing_keys": "Non mancano traduzioni | Traduzione mancante | Traduzioni mancanti", - "progress_label": "Stato avanzamento per {locale}", - "table": { - "file": "File", - "status": "Stato", - "error": "Errore durante il caricamento dell'elenco file.", - "empty": "Nessun file trovato", - "file_link": "Modifica {file} ({lang}) su GitHub" - } + "progress_label": "Stato avanzamento per {locale}" }, "vacations": { "title": "in vacanza", diff --git a/i18n/locales/ja-JP.json b/i18n/locales/ja-JP.json index b286a4883b..c1a8fa2765 100644 --- a/i18n/locales/ja-JP.json +++ b/i18n/locales/ja-JP.json @@ -1729,18 +1729,10 @@ "p2": "開始する前に、翻訳プロセスと参加方法について説明した {guide} を読んでください。", "guide": "ローカライズ (i18n) ガイド", "by_locale": "言語別の翻訳進捗", - "by_file": "ファイル別の翻訳進捗", "complete_text": "この言語の翻訳は完了しています。素晴らしい!", "missing_text": "未翻訳", "missing_keys": "未翻訳はありません | 未翻訳 1 件 | 未翻訳 {count} 件", - "progress_label": "{locale} の進捗状況", - "table": { - "file": "ファイル", - "status": "ステータス", - "error": "ファイルリストの読み込み中にエラーが発生しました。", - "empty": "ファイルが見つかりません", - "file_link": "GitHubで {file} ({lang}) を編集" - } + "progress_label": "{locale} の進捗状況" }, "vacations": { "title": "on vacation", diff --git a/i18n/locales/ko-KR.json b/i18n/locales/ko-KR.json index 0cbc273121..b07f4b7c0f 100644 --- a/i18n/locales/ko-KR.json +++ b/i18n/locales/ko-KR.json @@ -1762,18 +1762,10 @@ "p2": "시작하기 전에 번역 프로세스와 참여 방법을 알아보려면 {guide}를 읽어 주세요.", "guide": "현지화(i18n) 가이드", "by_locale": "로케일별 번역 진행률", - "by_file": "파일별 번역 진행률", "complete_text": "이 번역은 완료되었습니다. 훌륭합니다!", "missing_text": "누락", "missing_keys": "누락된 번역이 없습니다 | 누락된 번역 | 누락된 번역", - "progress_label": "{locale} 진행 상태", - "table": { - "file": "파일", - "status": "상태", - "error": "파일 목록을 불러오는 중 에러가 발생했습니다.", - "empty": "파일을 찾을 수 없습니다", - "file_link": "GitHub에서 {file}({lang}) 편집" - } + "progress_label": "{locale} 진행 상태" }, "vacations": { "title": "휴가 중", diff --git a/i18n/locales/mr-IN.json b/i18n/locales/mr-IN.json index d459a87f65..160a40ec53 100644 --- a/i18n/locales/mr-IN.json +++ b/i18n/locales/mr-IN.json @@ -1390,18 +1390,10 @@ "p2": "सुरू करण्यापूर्वी, आमची भाषांतर प्रक्रिया आणि तुम्ही कसे सहभागी होऊ शकता हे जाणून घेण्यासाठी कृपया आमचे {guide} वाचा.", "guide": "स्थानिकीकरण (i18n) मार्गदर्शक", "by_locale": "लोकॅलनुसार भाषांतर प्रगती", - "by_file": "फाइलनुसार भाषांतर प्रगती", "complete_text": "हे भाषांतर पूर्ण झाले आहे, अप्रतिम काम!", "missing_text": "गहाळ", "missing_keys": "एकही भाषांतर गहाळ नाही | गहाळ भाषांतर | गहाळ भाषांतरे", - "progress_label": "{locale} साठी प्रगती स्थिती", - "table": { - "file": "फाइल", - "status": "स्थिती", - "error": "फाइल यादी लोड करताना त्रुटी.", - "empty": "कोणत्याही फाइल्स सापडल्या नाहीत", - "file_link": "GitHub वर {file} ({lang}) संपादित करा" - } + "progress_label": "{locale} साठी प्रगती स्थिती" }, "vacations": { "what": {}, diff --git a/i18n/locales/nb-NO.json b/i18n/locales/nb-NO.json index 4056445877..1d275f8a62 100644 --- a/i18n/locales/nb-NO.json +++ b/i18n/locales/nb-NO.json @@ -1666,18 +1666,10 @@ "p2": "Før du begynner, vennligst les vår {guide} for å lære om oversettelsesprosessen vår og hvordan du kan bli involvert.", "guide": "lokaliseringsguide (i18n)", "by_locale": "Oversettelsesfremdrift etter språk", - "by_file": "Oversettelsesfremdrift etter fil", "complete_text": "Denne oversettelsen er fullført, fantastisk jobb!", "missing_text": "mangler", "missing_keys": "Det er ingen manglende oversettelser | Manglende oversettelse | Manglende oversettelser", - "progress_label": "Fremdriftsstatus for {locale}", - "table": { - "file": "Fil", - "status": "Status", - "error": "Feil ved lasting av filliste.", - "empty": "Ingen filer funnet", - "file_link": "Rediger {file} ({lang}) på GitHub" - } + "progress_label": "Fremdriftsstatus for {locale}" }, "vacations": { "title": "på ferie", diff --git a/i18n/locales/ne-NP.json b/i18n/locales/ne-NP.json index ca9e17f1e2..a5cec7feb7 100644 --- a/i18n/locales/ne-NP.json +++ b/i18n/locales/ne-NP.json @@ -1813,18 +1813,10 @@ "p2": "सुरु गर्नुअघि, हाम्रो अनुवाद प्रक्रिया र सहभागी हुने तरिका जान्न कृपया हाम्रो {guide} पढ्नुहोस्।", "guide": "स्थानीयकरण (i18n) गाइड", "by_locale": "लोकेलअनुसार अनुवाद प्रगति", - "by_file": "फाइलअनुसार अनुवाद प्रगति", "complete_text": "यो अनुवाद पूरा भएको छ, उत्कृष्ट काम!", "missing_text": "बाँकी", "missing_keys": "कुनै अनुवाद छुटेको छैन | छुटेको अनुवाद | छुटेका अनुवादहरू", - "progress_label": "{locale} को प्रगति स्थिति", - "table": { - "file": "फाइल", - "status": "स्थिति", - "error": "फाइल सूची लोड गर्दा त्रुटि भयो।", - "empty": "कुनै फाइल फेला परेन", - "file_link": "GitHub मा {file} ({lang}) सम्पादन गर्नुहोस्" - } + "progress_label": "{locale} को प्रगति स्थिति" }, "vacations": { "title": "बिदामा", diff --git a/i18n/locales/nl.json b/i18n/locales/nl.json index f821a06608..fc98c0404b 100644 --- a/i18n/locales/nl.json +++ b/i18n/locales/nl.json @@ -1809,18 +1809,10 @@ "p2": "Voordat u begint, raden we u aan onze {guide} te lezen om meer te weten te komen over ons vertaalproces en hoe u hieraan kunt bijdragen.", "guide": "Handleiding voor lokalisatie (i18n)", "by_locale": "Voortgang van de vertaling per taal", - "by_file": "Voortgang van de vertaling per bestand", "complete_text": "Deze vertaling is compleet, fantastisch werk!", "missing_text": "ontbrekend", "missing_keys": "Er ontbreken geen vertalingen | Ontbrekende vertaling | Ontbrekende vertalingen", - "progress_label": "Voortgangsstatus voor {locale}", - "table": { - "file": "Bestand", - "status": "Status", - "error": "Fout bij het laden van de bestandslijst.", - "empty": "Geen bestanden gevonden", - "file_link": "Bewerk {file} ({lang}) op GitHub" - } + "progress_label": "Voortgangsstatus voor {locale}" }, "vacations": { "title": "op vakantie", diff --git a/i18n/locales/pt-BR.json b/i18n/locales/pt-BR.json index b05fd70969..ba01a12857 100644 --- a/i18n/locales/pt-BR.json +++ b/i18n/locales/pt-BR.json @@ -1583,18 +1583,10 @@ "p2": "Antes de começar, por favor, leia nosso {guide} para aprender sobre nosso processo de tradução e como você pode contribuir.", "guide": "Guia de tradução (i18n)", "by_locale": "Progresso de tradução por localidade", - "by_file": "Progresso de tradução por arquivo", "complete_text": "Esta tradução está completa, ótimo trabalho!", "missing_text": "faltando", "missing_keys": "Não existem traduções faltando | Tradução faltando | Traduções faltando", - "progress_label": "Status de progresso para {locale}", - "table": { - "file": "Arquivo", - "status": "Status", - "error": "Erro enquanto carregava a lista de arquivos.", - "empty": "Nenhum arquivo encontrado", - "file_link": "Editar {file} ({lang}) no GitHub" - } + "progress_label": "Status de progresso para {locale}" }, "vacations": { "title": "de férias", diff --git a/i18n/locales/pt-PT.json b/i18n/locales/pt-PT.json index e55e915a38..812447bea5 100644 --- a/i18n/locales/pt-PT.json +++ b/i18n/locales/pt-PT.json @@ -1594,18 +1594,10 @@ "p2": "Antes de começar, por favor lê o nosso {guide} para saberes mais sobre o nosso processo de tradução e como podes contribuir.", "guide": "Guia de tradução (i18n)", "by_locale": "Progresso de tradução por locale", - "by_file": "Progresso de tradução por ficheiro", "complete_text": "Esta tradução está completa, ótimo trabalho!", "missing_text": "em falta", "missing_keys": "Não existem traduções em falta | Tradução em falta | Traduções em falta", - "progress_label": "Estado de progresso para {locale}", - "table": { - "file": "Ficheiro", - "status": "Estado", - "error": "Erro ao carregar a lista de ficheiros.", - "empty": "Nenhum ficheiro encontrado", - "file_link": "Editar {file} ({lang}) no GitHub" - } + "progress_label": "Estado de progresso para {locale}" }, "vacations": { "title": "de férias", diff --git a/i18n/locales/ro-RO.json b/i18n/locales/ro-RO.json index 636de1dc39..4d8b727368 100644 --- a/i18n/locales/ro-RO.json +++ b/i18n/locales/ro-RO.json @@ -1602,18 +1602,10 @@ "p2": "Înainte de a începe, te rugăm să citești al nostru {guide} pentru a afla mai multe despre procesul nostru de traducere și despre cum te poți implica.", "guide": "ghid de localizare (i18n)", "by_locale": "Progresul traducerii pe setări de localizare", - "by_file": "Progresul traducerii pe fișier", "complete_text": "Traducerea aceasta este completă, o treabă excelentă!", "missing_text": "lipsește", "missing_keys": "Nu există traduceri care lipsesc | Traducere care lipsește | Traduceri care lipsesc", - "progress_label": "Starea progresului pentru {locale}", - "table": { - "file": "Fișier", - "status": "Statut", - "error": "A apărut o eroare la încărcarea listei de fișiere.", - "empty": "Nu s-au găsit fișiere", - "file_link": "Editează {file} ({lang}) pe GitHub" - } + "progress_label": "Starea progresului pentru {locale}" }, "vacations": { "title": "în vacanță", diff --git a/i18n/locales/ru-RU.json b/i18n/locales/ru-RU.json index 217815923d..6144c112b8 100644 --- a/i18n/locales/ru-RU.json +++ b/i18n/locales/ru-RU.json @@ -1818,18 +1818,10 @@ "p2": "Перед началом прочитайте {guide} — там описан процесс перевода и как присоединиться.", "guide": "руководство по локализации (i18n)", "by_locale": "Прогресс по локалям", - "by_file": "Прогресс по файлам", "complete_text": "Перевод завершён, отличная работа!", "missing_text": "нет", "missing_keys": "Нет пропусков | Нет перевода | Нет переводов", - "progress_label": "Прогресс для {locale}", - "table": { - "file": "Файл", - "status": "Статус", - "error": "Ошибка при загрузке списка файлов.", - "empty": "Файлы не найдены", - "file_link": "Редактировать {file} ({lang}) на GitHub" - } + "progress_label": "Прогресс для {locale}" }, "vacations": { "title": "в отпуске", diff --git a/i18n/locales/sr-Latn-RS.json b/i18n/locales/sr-Latn-RS.json index cde898eeb8..bdfcb74429 100644 --- a/i18n/locales/sr-Latn-RS.json +++ b/i18n/locales/sr-Latn-RS.json @@ -1433,18 +1433,10 @@ "p2": "Pre nego što počnete, pročitajte naš {guide} da biste naučili o našem procesu prevođenja i kako možete da se uključite.", "guide": "vodič za lokalizaciju (i18n)", "by_locale": "Napredak prevoda po lokalitetu", - "by_file": "Napredak prevoda po datoteci", "complete_text": "Ovaj prevod je kompletan, neverovatan posao!", "missing_text": "nedostaje", "missing_keys": "{count} nedostajući prevod | {count} nedostajuća prevoda | {count} nedostajućih prevoda", - "progress_label": "Status napretka za {locale}", - "table": { - "file": "Datoteka", - "status": "Status", - "error": "Greška pri učitavanju liste datoteka.", - "empty": "Nema pronađenih datoteka", - "file_link": "Uredite {file} ({lang}) na GitHub-u" - } + "progress_label": "Status napretka za {locale}" }, "vacations": { "title": "na odmoru", diff --git a/i18n/locales/tr-TR.json b/i18n/locales/tr-TR.json index e2e6a2441e..9f5035b735 100644 --- a/i18n/locales/tr-TR.json +++ b/i18n/locales/tr-TR.json @@ -1610,18 +1610,10 @@ "p2": "Başlamadan önce çeviri sürecimiz ve nasıl katkıda bulunabileceğiniz hakkında bilgi edinmek için {guide} okuyun.", "guide": "yerelleştirme (i18n) rehberi", "by_locale": "Yerel ayara göre çeviri ilerleme durumu", - "by_file": "Dosyaya göre çeviri ilerleme durumu", "complete_text": "Bu çeviri tamamlandı, harika iş!", "missing_text": "eksik", "missing_keys": "Eksik çeviri yok | Eksik çeviri | Eksik çeviri", - "progress_label": "{locale} için ilerleme durumu", - "table": { - "file": "Dosya", - "status": "Durum", - "error": "Dosya listesi yüklenirken hata oluştu.", - "empty": "Dosya bulunamadı", - "file_link": "GitHub'da {file} ({lang}) düzenle" - } + "progress_label": "{locale} için ilerleme durumu" }, "vacations": { "title": "tatilde", diff --git a/i18n/locales/uk-UA.json b/i18n/locales/uk-UA.json index d25ab33873..3009ba45e1 100644 --- a/i18n/locales/uk-UA.json +++ b/i18n/locales/uk-UA.json @@ -1818,18 +1818,10 @@ "p2": "Перед початком, будь ласка, прочитайте наш {guide}, щоб дізнатися про наш процес перекладу та як ви можете долучитися.", "guide": "посібник з локалізації (i18n)", "by_locale": "Прогрес перекладу за мовою", - "by_file": "Прогрес перекладу за файлом", "complete_text": "Цей переклад завершено, чудова робота!", "missing_text": "відсутні", "missing_keys": "Відсутні переклади", - "progress_label": "Статус прогресу для {locale}", - "table": { - "file": "Файл", - "status": "Статус", - "error": "Помилка під час завантаження списку файлів.", - "empty": "Файлів не знайдено", - "file_link": "Редагувати {file} ({lang}) на GitHub" - } + "progress_label": "Статус прогресу для {locale}" }, "vacations": { "title": "у відпустці", diff --git a/i18n/locales/vi-VN.json b/i18n/locales/vi-VN.json index db257c9683..6a69d07785 100644 --- a/i18n/locales/vi-VN.json +++ b/i18n/locales/vi-VN.json @@ -1433,18 +1433,10 @@ "p2": "Trước khi bắt đầu, bạn hãy đọc qua {guide} để hiểu thêm về quy trình dịch và cách đóng góp.", "guide": "Hướng dẫn dịch (i18n)", "by_locale": "Tiến độ dịch theo ngôn ngữ", - "by_file": "Tiến độ dịch theo tệp", "complete_text": "Bản dịch đã hoàn chỉnh, tuyệt vời!", "missing_text": "thiếu", "missing_keys": "Không thiếu bản dịch | Thiếu bản dịch | Thiếu bản dịch", - "progress_label": "Tiến độ cho {locale}", - "table": { - "file": "Tệp", - "status": "Trạng thái", - "error": "Lỗi trong quá trình tải tệp", - "empty": "Không tìm thấy tệp nào", - "file_link": "Chỉnh sửa {file} ({lang}) tại GitHub" - } + "progress_label": "Tiến độ cho {locale}" }, "vacations": { "title": "đang nghỉ lễ", diff --git a/i18n/locales/zh-CN.json b/i18n/locales/zh-CN.json index 09f56bff5e..66f0ed67dd 100644 --- a/i18n/locales/zh-CN.json +++ b/i18n/locales/zh-CN.json @@ -1607,18 +1607,10 @@ "p2": "开始之前,建议先读读我们的{guide},了解一下翻译流程和参与方式。", "guide": "本地化(i18n)指南", "by_locale": "各语言翻译进度", - "by_file": "各文件翻译进度", "complete_text": "这个翻译已经完成,太棒啦!", "missing_text": "待翻译", "missing_keys": "没有遗漏的翻译 | 有 1 处遗漏 | 遗漏了 {count} 处", - "progress_label": "{locale} 的翻译进度", - "table": { - "file": "文件", - "status": "状态", - "error": "加载文件列表时出错", - "empty": "没有找到文件", - "file_link": "去 GitHub 上编辑 {file}({lang})" - } + "progress_label": "{locale} 的翻译进度" }, "vacations": { "title": "休假中", diff --git a/i18n/locales/zh-TW.json b/i18n/locales/zh-TW.json index 8437c7254b..6d6035341e 100644 --- a/i18n/locales/zh-TW.json +++ b/i18n/locales/zh-TW.json @@ -1545,18 +1545,10 @@ "p2": "開始之前,請先閱讀我們的 {guide},瞭解翻譯流程以及參與方式。", "guide": "在地化(i18n)指南", "by_locale": "依語言的翻譯進度", - "by_file": "依檔案的翻譯進度", "complete_text": "這個翻譯已經完成,超棒的!", "missing_text": "缺少", "missing_keys": "沒有缺少的翻譯 | 缺少 1 處翻譯 | 缺少 {count} 處翻譯", - "progress_label": "{locale} 的翻譯進度狀態", - "table": { - "file": "檔案", - "status": "狀態", - "error": "載入檔案清單時發生錯誤。", - "empty": "找不到任何檔案", - "file_link": "在 GitHub 上編輯 {file}({lang})" - } + "progress_label": "{locale} 的翻譯進度狀態" }, "vacations": { "title": "休假中", diff --git a/i18n/schema.json b/i18n/schema.json index db98fada79..c37e533a9d 100644 --- a/i18n/schema.json +++ b/i18n/schema.json @@ -5521,9 +5521,6 @@ "by_locale": { "type": "string" }, - "by_file": { - "type": "string" - }, "complete_text": { "type": "string" }, @@ -5535,27 +5532,6 @@ }, "progress_label": { "type": "string" - }, - "table": { - "type": "object", - "properties": { - "file": { - "type": "string" - }, - "status": { - "type": "string" - }, - "error": { - "type": "string" - }, - "empty": { - "type": "string" - }, - "file_link": { - "type": "string" - } - }, - "additionalProperties": false } }, "additionalProperties": false diff --git a/knip.ts b/knip.ts index 2a2d3c2bbf..e2325bd42c 100644 --- a/knip.ts +++ b/knip.ts @@ -28,7 +28,7 @@ const config: KnipConfig = { }, ignoreDependencies: ['@iconify-json/*', 'puppeteer', 'vite-plugin-pwa', '@vueuse/shared'], ignoreUnresolved: ['#oauth/config'], - ignoreFiles: ['app/components/UserCombobox.vue', '**/*.unused.*'], + ignoreFiles: ['app/components/UserCombobox.vue'], }, 'cli': { project: ['src/**/*.ts!', '!src/mock-*.ts'], diff --git a/package.json b/package.json index f3ffa4cb9d..e90f148df1 100644 --- a/package.json +++ b/package.json @@ -138,7 +138,7 @@ "fast-check": "4.9.0", "h3": "1.15.11", "h3-next": "npm:h3@2.0.1-rc.26", - "knip": "6.38.0", + "knip": "6.42.1", "markdown-it-anchor": "10.0.0", "msw": "catalog:msw", "msw-storybook-addon": "catalog:storybook", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 48d4f1c505..403bc1aebe 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -350,8 +350,8 @@ importers: specifier: npm:h3@2.0.1-rc.26 version: h3@2.0.1-rc.26(crossws@0.4.15) knip: - specifier: 6.38.0 - version: 6.38.0 + specifier: 6.42.1 + version: 6.42.1 markdown-it-anchor: specifier: 10.0.0 version: 10.0.0(@types/markdown-it@14.1.2)(markdown-it@14.3.0) @@ -6996,9 +6996,9 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} - formatly@0.7.0: - resolution: {integrity: sha512-7CXJtIIA0zy/u12StsYk25qVKxvdLA2ep2sTNxK3ov0mGNIIDqIvAXDSgTnAfDJFsPfWjuz0WjfYSdpvnLA5Tg==} - engines: {node: '>=18.3.0'} + formatly@0.11.4: + resolution: {integrity: sha512-TeCC10lP8KCgoX+Fe5lryILIT0/Dy+nP0OSVnsuB5CwXoLuOdqxCYlPFF1inR8S/zTy1ec7TjhS2TeRKWzzImA==} + engines: {node: '>=18.14.0'} hasBin: true forwarded@0.2.0: @@ -7819,8 +7819,8 @@ packages: resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} engines: {node: '>= 8'} - knip@6.38.0: - resolution: {integrity: sha512-umytiMCaZf02MV9SOO1FEDgbDf6h20VZk3ruJE0kh52kkGjYZFRUAXHJWYoLhvhoHGINO/7GXVJmQ2vxTBvl6A==} + knip@6.42.1: + resolution: {integrity: sha512-gKJVsiT4LJQ0lfc8uSHOCzkOY8adAXNFGarIeODZbJOkBnQRVsG3e0UZFnO4LMwjA82A5tBWX/VgoeTYcjdKiQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -9701,8 +9701,8 @@ packages: resolution: {integrity: sha512-RQsvleCbF8cVHEv+xuDGaA4pOizFqJ0GgjtMSRo6oP8pnN7WsigHgVGey6aILRBKv4W2YOMHLqbKdnB6hpB9fw==} engines: {node: '>=20.0.0'} - smol-toml@1.8.0: - resolution: {integrity: sha512-kCZr2V3ch9i00x8zXRhjUNVcjG9ijES5dDudkXvUVCT5QlJNQWElSJdZqyPemffHoLNUYwOcou0Fy+ojN0uHSQ==} + smol-toml@1.9.1: + resolution: {integrity: sha512-j7WyPdf0CJoutMzMoPLF/bVXHtKZIT9Rb4eGeEbWw8X2t5oirjPgpL+OpaENZrILYaXqYwnVH+qgUwVbl+pUJQ==} engines: {node: '>= 18'} socket.io-client@4.8.3: @@ -10149,8 +10149,8 @@ packages: ultramatter@0.0.4: resolution: {integrity: sha512-1f/hO3mR+/Hgue4eInOF/Qm/wzDqwhYha4DxM0hre9YIUyso3fE2XtrAU6B4njLqTC8CM49EZaYgsVSa+dXHGw==} - unbash@4.0.11: - resolution: {integrity: sha512-FoSOKV7NEofQSkAefMVHam4ZPKYMxjAydxiV72UFEDNV/YofxjGfiZ2A9pZjdL/lRJzTjcu4PABo1JYJX8N5iQ==} + unbash@6.0.0: + resolution: {integrity: sha512-vD5CvvFLVQDhXdNyNEPPa/tHPCK3HLySddOine+OZLDYIH1cMImGNgnw9+NkizToaPsFsQlwiyPGMiK+uwtYVw==} engines: {node: '>=14'} unbox-primitive@1.1.0: @@ -18754,7 +18754,7 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - formatly@0.7.0: + formatly@0.11.4: dependencies: fd-package-json: 2.0.0 package-manager-detector: 1.9.0 @@ -19684,19 +19684,18 @@ snapshots: klona@2.0.6: {} - knip@6.38.0: + knip@6.42.1: dependencies: - fdir: 6.5.0(picomatch@4.0.7) - formatly: 0.7.0 + formatly: 0.11.4 get-tsconfig: 4.14.3 jiti: 2.7.0 oxc-parser: 0.144.0 oxc-resolver: 11.24.2 picomatch: 4.0.7 - smol-toml: 1.8.0 + smol-toml: 1.9.1 strip-json-comments: 5.0.3 tinyglobby: 0.2.17 - unbash: 4.0.11 + unbash: 6.0.0 yaml: 2.9.1 zod: 4.6.5 @@ -22583,7 +22582,7 @@ snapshots: smob@1.6.2: {} - smol-toml@1.8.0: {} + smol-toml@1.9.1: {} socket.io-client@4.8.3(supports-color@10.2.2): dependencies: @@ -23064,7 +23063,7 @@ snapshots: ultramatter@0.0.4: {} - unbash@4.0.11: {} + unbash@6.0.0: {} unbox-primitive@1.1.0: dependencies: diff --git a/server/utils/atproto/oauth.ts b/server/utils/atproto/oauth.ts index ae9ba489d2..ad6440b0c5 100644 --- a/server/utils/atproto/oauth.ts +++ b/server/utils/atproto/oauth.ts @@ -20,7 +20,7 @@ export const scope = `atproto ${LIKES_SCOPE} ${PROFILE_SCOPE}` /** * Resolves a did to a handle via DoH or via the http website calls */ -export const handleResolver = new AtprotoDohHandleResolver({ +const handleResolver = new AtprotoDohHandleResolver({ dohEndpoint: 'https://cloudflare-dns.com/dns-query', }) diff --git a/server/utils/code-highlight.ts b/server/utils/code-highlight.ts index e0eb6bb885..c19bf584fe 100644 --- a/server/utils/code-highlight.ts +++ b/server/utils/code-highlight.ts @@ -135,19 +135,19 @@ function getPackageName(specifier: string): string { /** * Resolved dependency info for linking imports to specific versions */ -export interface ResolvedDependency { +interface ResolvedDependency { version: string } /** * Map of package name to resolved version for import linking */ -export type DependencyVersions = Record +type DependencyVersions = Record /** * Function to resolve relative imports to URLs */ -export type RelativeImportResolver = (specifier: string) => string | null +type RelativeImportResolver = (specifier: string) => string | null interface LinkifyOptions { dependencies?: DependencyVersions diff --git a/server/utils/compare.ts b/server/utils/compare.ts index b44c079593..71db811193 100644 --- a/server/utils/compare.ts +++ b/server/utils/compare.ts @@ -26,7 +26,7 @@ function traverse(nodes: PackageFileTree[], callback: (node: PackageFileTree) => } /** Flatten a file tree into a map of path -> node */ -export function flattenTree(tree: PackageFileTree[]): Map { +function flattenTree(tree: PackageFileTree[]): Map { const result = new Map() traverse(tree, node => { @@ -48,7 +48,7 @@ const hasChanged = (fromNode: PackageFileTree, toNode: PackageFileTree): boolean } /** Compare two file trees and return changes */ -export function compareFileTrees( +function compareFileTrees( fromTree: PackageFileTree[], toTree: PackageFileTree[], ): { added: FileChange[]; removed: FileChange[]; modified: FileChange[]; truncated: boolean } { @@ -136,7 +136,7 @@ export function compareFileTrees( } /** Compare dependencies between two package.json files */ -export function compareDependencies( +function compareDependencies( fromPkg: Record | null, toPkg: Record | null, ): DependencyChange[] { @@ -212,7 +212,7 @@ export function compareDependencies( } /** Count total files in a tree */ -export function countFiles(tree: PackageFileTree[]): number { +function countFiles(tree: PackageFileTree[]): number { let count = 0 traverse(tree, node => { diff --git a/server/utils/docs/format.ts b/server/utils/docs/format.ts index 68d30044ac..dfd06af61d 100644 --- a/server/utils/docs/format.ts +++ b/server/utils/docs/format.ts @@ -60,7 +60,7 @@ export function getNodeSignature(node: DenoDocNode): string | null { /** * Format a function parameter. */ -export function formatParam(param: FunctionParam, index = 0): string { +function formatParam(param: FunctionParam, index = 0): string { const name = param.name || `arg_${index}` const optional = param.optional ? '?' : '' const type = formatType(param.tsType) diff --git a/server/utils/embed-downloads-svg.ts b/server/utils/embed-downloads-svg.ts index df9a839612..2cb77660fd 100644 --- a/server/utils/embed-downloads-svg.ts +++ b/server/utils/embed-downloads-svg.ts @@ -24,7 +24,7 @@ type ChartGranularity = 'daily' | 'weekly' | 'monthly' | 'yearly' type Metric = 'downloads' | 'likes' | 'contributors' type QueryParameters = Record -export function parsePackageNames(value: unknown): string[] { +function parsePackageNames(value: unknown): string[] { return String(value ?? '') .split(',') .map(name => name.trim().toLowerCase()) @@ -32,7 +32,7 @@ export function parsePackageNames(value: unknown): string[] { .slice(0, 8) } -export function parseFetchGranularity(value: unknown): FetchGranularity { +function parseFetchGranularity(value: unknown): FetchGranularity { if (value === 'daily' || value === 'day') return 'day' if (value === 'weekly' || value === 'week') return 'week' if (value === 'monthly' || value === 'month') return 'month' @@ -40,7 +40,7 @@ export function parseFetchGranularity(value: unknown): FetchGranularity { return 'week' } -export function toChartGranularity(granularity: FetchGranularity): ChartGranularity { +function toChartGranularity(granularity: FetchGranularity): ChartGranularity { const mapping: Record = { day: 'daily', week: 'weekly', @@ -51,7 +51,7 @@ export function toChartGranularity(granularity: FetchGranularity): ChartGranular return mapping[granularity] } -export function parseLocale(value: unknown): string { +function parseLocale(value: unknown): string { if (typeof value !== 'string') return 'en' try { @@ -61,7 +61,7 @@ export function parseLocale(value: unknown): string { } } -export function parseAccent(value: unknown): string { +function parseAccent(value: unknown): string { if (typeof value !== 'string') { return OKLCH_NEUTRAL_FALLBACK } @@ -83,7 +83,7 @@ export function parseAccent(value: unknown): string { return OKLCH_NEUTRAL_FALLBACK } -export function parseSafeText(value: unknown, fallback = '', maximumLength = 100): string { +function parseSafeText(value: unknown, fallback = '', maximumLength = 100): string { if (typeof value !== 'string') return fallback return ( @@ -96,7 +96,7 @@ export function parseSafeText(value: unknown, fallback = '', maximumLength = 100 ) } -export function parseDateQuery(value: unknown): string | undefined { +function parseDateQuery(value: unknown): string | undefined { if (typeof value !== 'string') return undefined const date = value.trim() @@ -104,12 +104,7 @@ export function parseDateQuery(value: unknown): string | undefined { return /^\d{4}-\d{2}-\d{2}$/.test(date) ? date : undefined } -export function clampNumber( - value: unknown, - minimum: number, - maximum: number, - fallback: number, -): number { +function clampNumber(value: unknown, minimum: number, maximum: number, fallback: number): number { const parsed = Number(value) if (!Number.isFinite(parsed)) { @@ -119,7 +114,7 @@ export function clampNumber( return Math.min(maximum, Math.max(minimum, parsed)) } -export function parseMetric(value: unknown): Metric { +function parseMetric(value: unknown): Metric { if (value === 'likes') return 'likes' if (value === 'contributors') return 'contributors' diff --git a/server/utils/import-resolver.ts b/server/utils/import-resolver.ts index db42226092..b4419fc0c3 100644 --- a/server/utils/import-resolver.ts +++ b/server/utils/import-resolver.ts @@ -177,7 +177,7 @@ export type InternalImportTarget = string | { default?: string; import?: string export type InternalImportsMap = Record -export type PackageExportTarget = +type PackageExportTarget = | string | { default?: string diff --git a/server/utils/likes-leaderboard.ts b/server/utils/likes-leaderboard.ts index d66b96e398..fb1a0d19f2 100644 --- a/server/utils/likes-leaderboard.ts +++ b/server/utils/likes-leaderboard.ts @@ -29,7 +29,7 @@ const NpmDownloadCountSchema = v.object({ downloads: v.number(), }) -export const LIKES_LEADERBOARD_MAX_ENTRIES = 10 +const LIKES_LEADERBOARD_MAX_ENTRIES = 10 export function extractPackageNameFromSubjectRef(subjectRef: string): string | null { const match = /^https:\/\/npmx\.dev\/package\/(.+)$/.exec(subjectRef) diff --git a/server/utils/mdKit.ts b/server/utils/mdKit.ts index 205e3ba7e6..2035a75f70 100644 --- a/server/utils/mdKit.ts +++ b/server/utils/mdKit.ts @@ -198,7 +198,7 @@ export const USER_CONTENT_PREFIX = 'user-content-' // README h1 always becomes h3 // For deeper levels, ensure sequential order // Don't allow jumping more than 1 level deeper than previous -export function calculateSemanticDepth( +function calculateSemanticDepth( depth: number, lastSemanticLevel: number, minSemanticLevel: number, @@ -208,11 +208,11 @@ export function calculateSemanticDepth( return Math.min(depth + minSemanticLevel, maxAllowed) } -export function getHeadingPlainText(text: string): string { +function getHeadingPlainText(text: string): string { return decodeHtmlEntities(stripHtmlTags(text).trim()) } -export function getHeadingSlugSource(text: string): string { +function getHeadingSlugSource(text: string): string { return stripHtmlTags(text).trim() } @@ -284,7 +284,7 @@ export function createHeading(options: { // html // Extract and preserve allowed attributes from HTML heading tags -export function extractHeadingAttrs(attrsString: string): string { +function extractHeadingAttrs(attrsString: string): string { if (!attrsString) return '' const preserved: string[] = [] const alignMatch = /\balign=(["']?)([^"'\s>]+)\1/i.exec(attrsString) @@ -389,7 +389,7 @@ export const ALLOWED_ATTR: Record = { // allow h1-h6, but replace h1-h2 later since we shift README headings down by 2 levels // (page h1 = package name, h2 = "Readme" section, so README h1 → h3) -export const ALLOWED_TAGS = [ +const ALLOWED_TAGS = [ 'h1', 'h2', 'h3', diff --git a/server/utils/npm.ts b/server/utils/npm.ts index 8d26c9b527..47da8dd452 100644 --- a/server/utils/npm.ts +++ b/server/utils/npm.ts @@ -85,7 +85,7 @@ export async function fetchLatestVersionWithFallback(name: string): Promise { diff --git a/server/utils/skills.ts b/server/utils/skills.ts index d9e431ef24..97fbca8830 100644 --- a/server/utils/skills.ts +++ b/server/utils/skills.ts @@ -4,7 +4,7 @@ const MAX_SKILL_FILE_SIZE = 500 * 1024 * Parse YAML frontmatter from SKILL.md content. * Returns { frontmatter, content } where content is the markdown body without frontmatter. */ -export function parseFrontmatter(raw: string): { frontmatter: SkillFrontmatter; content: string } { +function parseFrontmatter(raw: string): { frontmatter: SkillFrontmatter; content: string } { const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/) if (!match) { throw createError({ statusCode: 400, message: 'Invalid SKILL.md: missing YAML frontmatter' }) @@ -85,7 +85,7 @@ const countFilesRecursive = (nodes: PackageFileTree[]): number => /** * Count files in skill subdirectories (scripts, references, assets). */ -export function countSkillFiles(children: PackageFileTree[]): SkillFileCounts | undefined { +function countSkillFiles(children: PackageFileTree[]): SkillFileCounts | undefined { const counts: SkillFileCounts = {} for (const child of children) { @@ -154,7 +154,7 @@ export async function fetchSkillContent( /** * Validate skill frontmatter and return warnings. */ -export function validateSkill(frontmatter: SkillFrontmatter): SkillWarning[] { +function validateSkill(frontmatter: SkillFrontmatter): SkillWarning[] { const warnings: SkillWarning[] = [] if (!frontmatter.license) { warnings.push({ type: 'warning', message: 'No license specified' }) diff --git a/server/utils/version-downloads.ts b/server/utils/version-downloads.ts index 5dfebcfd45..f72d031f5c 100644 --- a/server/utils/version-downloads.ts +++ b/server/utils/version-downloads.ts @@ -11,19 +11,6 @@ interface ProcessedVersion { parsed: SemVer } -/** - * Filter out versions below a usage threshold - * @param versions Array of version download points - * @param thresholdPercent Minimum percentage to include (default: 0.1%) - * @returns Filtered array of versions - */ -export function filterLowUsageVersions( - versions: VersionDownloadPoint[], - thresholdPercent: number = 0.1, -): VersionDownloadPoint[] { - return versions.filter(v => v.percentage >= thresholdPercent) -} - /** * Parse and validate version strings, calculating total downloads * @param rawDownloads Raw download data from npm API @@ -72,7 +59,7 @@ function addPercentages( * @param rawDownloads Raw download data from npm API * @returns Array of version groups sorted by downloads descending */ -export function groupByMajor(rawDownloads: Record): VersionGroupDownloads[] { +function groupByMajor(rawDownloads: Record): VersionGroupDownloads[] { const processed = parseVersions(rawDownloads) const totalDownloads = processed.reduce((sum, v) => sum + v.downloads, 0) @@ -108,7 +95,7 @@ export function groupByMajor(rawDownloads: Record): VersionGroup * @param rawDownloads Raw download data from npm API * @returns Array of version groups sorted by downloads descending */ -export function groupByMinor(rawDownloads: Record): VersionGroupDownloads[] { +function groupByMinor(rawDownloads: Record): VersionGroupDownloads[] { const processed = parseVersions(rawDownloads) const totalDownloads = processed.reduce((sum, v) => sum + v.downloads, 0) diff --git a/shared/types/dependency-analysis.ts b/shared/types/dependency-analysis.ts index 31adbe065b..772cbe3b4f 100644 --- a/shared/types/dependency-analysis.ts +++ b/shared/types/dependency-analysis.ts @@ -18,13 +18,13 @@ export type OsvSeverityLevel = (typeof SEVERITY_LEVELS)[number] | 'unknown' /** * Counts by severity level */ -export type SeverityCounts = Record<(typeof SEVERITY_LEVELS)[number], number> -export type VulnerabilityCounts = SeverityCounts & { total: number } +type SeverityCounts = Record<(typeof SEVERITY_LEVELS)[number], number> +type VulnerabilityCounts = SeverityCounts & { total: number } /** * CVSS severity information from OSV */ -export interface OsvSeverity { +interface OsvSeverity { type: 'CVSS_V3' | 'CVSS_V4' score: string } @@ -32,7 +32,7 @@ export interface OsvSeverity { /** * Reference link for a vulnerability */ -export interface OsvReference { +interface OsvReference { type: 'ADVISORY' | 'WEB' | 'PACKAGE' | 'REPORT' | 'FIX' | 'ARTICLE' | 'DETECTION' | 'EVIDENCE' url: string } @@ -41,7 +41,7 @@ export interface OsvReference { * Version range event from OSV affected data * @see https://ossf.github.io/osv-schema/#affectedrangesevents-fields */ -export interface OsvRangeEvent { +interface OsvRangeEvent { introduced?: string fixed?: string last_affected?: string @@ -100,7 +100,7 @@ export interface OsvQueryResponse { /** * Single result from OSV batch query (minimal info - just ID and modified) */ -export interface OsvBatchVulnRef { +interface OsvBatchVulnRef { id: string modified: string } @@ -108,7 +108,7 @@ export interface OsvBatchVulnRef { /** * Single result in OSV batch response */ -export interface OsvBatchResult { +interface OsvBatchResult { vulns?: OsvBatchVulnRef[] next_page_token?: string } @@ -134,16 +134,6 @@ export interface VulnerabilitySummary { fixedIn?: string } -/** - * Package vulnerability response returned by our API - */ -export interface PackageVulnerabilities { - package: string - version: string - vulnerabilities: VulnerabilitySummary[] - counts: VulnerabilityCounts -} - /** Depth in dependency tree */ export type DependencyDepth = 'root' | 'direct' | 'transitive' diff --git a/shared/types/docs.ts b/shared/types/docs.ts index a59164f811..1da94695c7 100644 --- a/shared/types/docs.ts +++ b/shared/types/docs.ts @@ -1,4 +1,4 @@ -export type DocsStatus = 'ok' | 'missing' | 'error' +type DocsStatus = 'ok' | 'missing' | 'error' export interface DocsResponse { package: string @@ -9,9 +9,3 @@ export interface DocsResponse { status: DocsStatus message?: string } - -export interface DocsSearchResponse { - package: string - version: string - index: Record -} diff --git a/shared/types/i18n-status.ts b/shared/types/i18n-status.ts index c815d32864..5ba50e151a 100644 --- a/shared/types/i18n-status.ts +++ b/shared/types/i18n-status.ts @@ -37,13 +37,3 @@ export interface I18nLocaleStatus { /** GitHub URL to view history of this locale file */ githubHistoryUrl: string } - -export interface FileStatus extends Omit { - file: string - lang: string -} - -export interface FileEntryStatus extends FileStatus { - done: number - missing: number -} diff --git a/shared/types/jsr.ts b/shared/types/jsr.ts index ad3115b275..4dcaff12a9 100644 --- a/shared/types/jsr.ts +++ b/shared/types/jsr.ts @@ -20,7 +20,7 @@ export interface JsrPackageMeta { /** * JSR version metadata (minimal, from meta.json) */ -export interface JsrVersionMeta { +interface JsrVersionMeta { /** If true, the version has been yanked */ yanked?: boolean } diff --git a/shared/types/npm-registry.ts b/shared/types/npm-registry.ts index c1192c3906..bd3519f37a 100644 --- a/shared/types/npm-registry.ts +++ b/shared/types/npm-registry.ts @@ -15,7 +15,6 @@ import type { ReadmeResponse } from './readme' import type { TrustLevelName, TrustStatus } from 'packumeta' // Re-export official npm types for packument/manifest -export type { Manifest, ManifestVersion, PackageJSON } from '@npm/types' type NpmTrustedPublisherEvidence = NpmSearchTrustedPublisher | NpmTrustedPublisher | true @@ -160,7 +159,7 @@ export interface PackageVersionInfo { * Person/contact type extracted from @npm/types Contact interface * Used for maintainers, authors, publishers */ -export interface NpmPerson { +interface NpmPerson { name?: string email?: string url?: string @@ -201,7 +200,7 @@ export interface NpmSearchResult { * Trusted publisher info from search API * Present when package was published via OIDC (e.g., GitHub Actions) */ -export interface NpmSearchTrustedPublisher { +interface NpmSearchTrustedPublisher { /** OIDC provider identifier (e.g., "github", "gitlab") */ id: string /** OIDC config ID */ @@ -211,7 +210,7 @@ export interface NpmSearchTrustedPublisher { /** * Publisher info with optional trusted publisher and actor details */ -export interface NpmSearchPublisher extends NpmPerson { +interface NpmSearchPublisher extends NpmPerson { /** Trusted publisher info (present if published via OIDC) */ trustedPublisher?: NpmSearchTrustedPublisher /** Actor who triggered the publish (for trusted publishing) */ @@ -222,7 +221,7 @@ export interface NpmSearchPublisher extends NpmPerson { } } -export interface NpmSearchPackage { +interface NpmSearchPackage { name: string scope?: string version: string @@ -248,7 +247,7 @@ export interface NpmSearchPackage { * Present when package was published with provenance * Note: Not covered by @npm/types */ -export interface NpmVersionAttestations { +interface NpmVersionAttestations { /** URL to fetch full attestation details */ url: string /** Provenance info */ @@ -311,41 +310,11 @@ export interface NpmDownloadCount { package: string } -export interface NpmDownloadRange { - downloads: Array<{ - downloads: number - day: string - }> - start: string - end: string - package: string -} - -/** - * Organization API types - * These require authentication - * Note: Not covered by @npm/types - */ -export interface NpmOrgMember { - user: string - role: 'developer' | 'admin' | 'owner' -} - -export interface NpmTeam { - name: string - description?: string - members?: string[] -} - -export interface NpmPackageAccess { - permissions: 'read-only' | 'read-write' -} - /** * Trusted Publishing types * Note: Not covered by @npm/types */ -export interface NpmTrustedPublisher { +interface NpmTrustedPublisher { type: 'github-actions' | 'gitlab-ci' // GitHub Actions specific repository?: string @@ -433,19 +402,6 @@ export interface PackageFileContentResponse { markdownHtml?: ReadmeResponse } -/** - * Minimal packument data needed for package cards - */ -export interface MinimalPackument { - 'name': string - 'description'?: string - 'keywords'?: string[] - // `dist-tags` can be missing in some later unpublished packages - 'dist-tags'?: Record - 'time': Record - 'maintainers'?: NpmPerson[] -} - /** * Lightweight package metadata returned by /api/registry/package-meta/. * Contains only the fields needed for search result cards, extracted diff --git a/shared/utils/constants.ts b/shared/utils/constants.ts index 4598b1b23f..402eb41606 100644 --- a/shared/utils/constants.ts +++ b/shared/utils/constants.ts @@ -25,11 +25,7 @@ export const LIKES_LEADERBOARD_API_URL = // Error Messages export const ERROR_PACKAGE_ANALYSIS_FAILED = 'Failed to analyze package.' export const ERROR_PACKAGE_VERSION_AND_FILE_FAILED = 'Version and file path are required.' -export const ERROR_PACKAGE_REQUIREMENTS_FAILED = - 'Package name, version, and file path are required.' export const ERROR_PACKAGE_DETECT_CHANGELOG = 'failed to detect package has changelog' -export const ERROR_BLUESKY_URL_FAILED = - 'Invalid Bluesky URL format. Expected: https://bsky.app/profile/HANDLE/post/POST_ID' export const ERROR_FILE_LIST_FETCH_FAILED = 'Failed to fetch file list.' export const ERROR_CALC_INSTALL_SIZE_FAILED = 'Failed to calculate install size.' export const NPM_MISSING_README_SENTINEL = 'ERROR: No README data found!' @@ -128,6 +124,3 @@ export const FOREGROUND_THEMES = { export const BLUESKY_URL_EXTRACT_REGEX = /profile\/([^/]+)\/post\/([^/]+)/ export const BSKY_POST_AT_URI_REGEX = /^at:\/\/(did:[a-z]+:[\w.:%-]+)\/app\.bsky\.feed\.post\/([a-z0-9]+)$/ -export const BLOG_META_TAG_REGEX = - /]*(?:property|name)=["']([^"']+)["'][^>]*content=["']([^"']+)["'][^>]*>/gi -export const META_TAG_TITLE_REGEX = /([^<]*)<\/title>/i diff --git a/shared/utils/constellation.ts b/shared/utils/constellation.ts index 91993f9fe9..01396e4222 100644 --- a/shared/utils/constellation.ts +++ b/shared/utils/constellation.ts @@ -7,19 +7,19 @@ export type Backlink = { rkey: string } -export type BacklinksResponse = { +type BacklinksResponse = { total: number records: Backlink[] cursor: string | undefined } -export type LinksDistinctDidsResponse = { +type LinksDistinctDidsResponse = { total: number linking_dids: string[] cursor: string | undefined } -export type AllLinksResponse = { +type AllLinksResponse = { links: Record< string, Record< diff --git a/shared/utils/dev-dependency.ts b/shared/utils/dev-dependency.ts index f45449ba52..1572d9af48 100644 --- a/shared/utils/dev-dependency.ts +++ b/shared/utils/dev-dependency.ts @@ -1,4 +1,4 @@ -export type DevDependencySuggestionReason = 'known-package' | 'readme-hint' +type DevDependencySuggestionReason = 'known-package' | 'readme-hint' export interface DevDependencySuggestion { recommended: boolean diff --git a/shared/utils/diff.ts b/shared/utils/diff.ts index a9a4c68627..d1bc288d2b 100644 --- a/shared/utils/diff.ts +++ b/shared/utils/diff.ts @@ -163,10 +163,7 @@ function mergeAdjacentLines(changes: RawChange[], options: ParseOptions): DiffLi return out } -export function parseUnifiedDiff( - diffText: string, - options: Partial<ParseOptions> = {}, -): FileDiff[] { +function parseUnifiedDiff(diffText: string, options: Partial<ParseOptions> = {}): FileDiff[] { const opts = { ...defaultOptions, ...options } const files: FileDiff[] = [] diff --git a/shared/utils/git-providers.ts b/shared/utils/git-providers.ts index a28f727d12..26b5cdd75c 100644 --- a/shared/utils/git-providers.ts +++ b/shared/utils/git-providers.ts @@ -30,7 +30,7 @@ export interface RepositoryInfo extends RepoRef { } /** Known GitLab instances (self-hosted) */ -export const GITLAB_HOSTS = [ +const GITLAB_HOSTS = [ 'gitlab.com', 'gitlab.gnome.org', 'gitlab.freedesktop.org', @@ -44,12 +44,12 @@ export const GITLAB_HOSTS = [ * is effectively user-controlled input that can point at a malicious user-controlled server, this * would put us at risk of Server-Side Request Forgery (SSRF). Thus we only support allowlisted hosts. */ -export const FORGEJO_HOSTS = ['next.forgejo.org', 'try.next.forgejo.org', 'code.haverbeke.berlin'] +const FORGEJO_HOSTS = ['next.forgejo.org', 'try.next.forgejo.org', 'code.haverbeke.berlin'] /** * No open-ended Gitea host detection for the same reason as Forgejo above. */ -export const GITEA_HOSTS = ['gitea.com'] +const GITEA_HOSTS = ['gitea.com'] interface ProviderConfig { id: ProviderId @@ -399,10 +399,6 @@ export function parseRepositoryInfo( } } -export function getProviderConfig(providerId: ProviderId): ProviderConfig | undefined { - return providers.find(p => p.id === providerId) -} - export function convertBlobOrFileToRawUrl(url: string, providerId: ProviderId): string { const provider = providers.find(p => p.id === providerId) let rawUrl = url @@ -415,10 +411,6 @@ export function convertBlobOrFileToRawUrl(url: string, providerId: ProviderId): return rawUrl } -export function isKnownGitProvider(url: string): boolean { - return parseRepoUrl(url) !== null -} - /** * API origins used by each provider for client-side repo metadata fetches. * Self-hosted providers are excluded because their origins can be anything. diff --git a/shared/utils/install-scripts.ts b/shared/utils/install-scripts.ts index 501111de67..ed52d1c9cf 100644 --- a/shared/utils/install-scripts.ts +++ b/shared/utils/install-scripts.ts @@ -26,7 +26,7 @@ const PACKAGE_VERSION_PATTERN = /^(@[\w.-]+\/[\w.-]+|[\w.-]+)(?:@(.+))?$/ * @param scripts - The scripts object from package.json * @returns Record of package name to version (or "latest" if none specified) */ -export function extractNpxDependencies( +function extractNpxDependencies( scripts: Record<string, string> | undefined, ): Record<string, string> { if (!scripts) return {} diff --git a/shared/utils/npm.ts b/shared/utils/npm.ts index c6a0a2929d..f71de75a10 100644 --- a/shared/utils/npm.ts +++ b/shared/utils/npm.ts @@ -3,9 +3,6 @@ import { createError } from 'h3' import validatePackageName from 'validate-npm-package-name' import type { PackumentLicense } from '#shared/types/npm-registry' -const NPM_USERNAME_RE = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i -const NPM_USERNAME_MAX_LENGTH = 50 - /** * Encode package name for URL usage. * Scoped packages need special handling (@scope/name → @scope%2Fname) @@ -50,20 +47,6 @@ export function assertValidPackageName(name: string): void { } } -/** - * Validate an npm username and throw an HTTP error if invalid. - * Uses a regular expression to check against npm naming rules. - */ -export function assertValidUsername(username: string): void { - if (!username || username.length > NPM_USERNAME_MAX_LENGTH || !NPM_USERNAME_RE.test(username)) { - throw createError({ - // TODO: throwing 404 rather than 400 as it's cacheable - statusCode: 404, - message: `Invalid username: ${username}`, - }) - } -} - /** Parsed result of an npm dependency version value */ export interface ParsedDependencyVersion { /** The real package name (different from the dependency key only for aliases) */ diff --git a/shared/utils/package-analysis.ts b/shared/utils/package-analysis.ts index 6807a02499..ad7e0357d5 100644 --- a/shared/utils/package-analysis.ts +++ b/shared/utils/package-analysis.ts @@ -40,7 +40,7 @@ export interface ExtendedPackageJson { repository?: { url?: string; type?: string; directory?: string } | string } -export type PackageExports = string | null | { [key: string]: PackageExports } | PackageExports[] +type PackageExports = string | null | { [key: string]: PackageExports } | PackageExports[] /** * Detect the module format of a package based on package.json fields @@ -180,7 +180,7 @@ function mergeExportsAnalysis(target: ExportsAnalysis, source: ExportsAnalysis): } /** Info about a related package (@types or create-*) */ -export interface RelatedPackageInfo { +interface RelatedPackageInfo { packageName: string deprecated?: string } diff --git a/shared/utils/repository-meta.ts b/shared/utils/repository-meta.ts index 83830e88de..1046136fd4 100644 --- a/shared/utils/repository-meta.ts +++ b/shared/utils/repository-meta.ts @@ -7,7 +7,7 @@ const REPO_META_TTL = 60 * 10 // Other TTLs for known sources const UNGH_REPO_META_TTL = 60 * 60 * 3 // 3 hours (ungh caches 6 hours server-side, but we run it half more frequently) -export type RepoMetaLinks = { +type RepoMetaLinks = { repo: string stars: string forks: string @@ -551,11 +551,6 @@ function getProviderAdapter(ref: RepoRef): ProviderAdapter | null { return providers[ref.provider] ?? null } -export function getRepoMetaLinks(ref: RepoRef): RepoMetaLinks | null { - const adapter = getProviderAdapter(ref) - return adapter?.links(ref) ?? null -} - export async function getRepoMeta( cachedFetch: CachedFetchFunction, ref: RepoRef, diff --git a/shared/utils/spdx.ts b/shared/utils/spdx.ts index f11f09bc5c..f0a731bee0 100644 --- a/shared/utils/spdx.ts +++ b/shared/utils/spdx.ts @@ -7,7 +7,7 @@ import spdxLicenseIds from 'spdx-license-list/spdx-simple.json' * * @see https://spdx.org/licenses/ */ -export const SPDX_LICENSE_IDS: Set<string> = new Set(spdxLicenseIds) +const SPDX_LICENSE_IDS: Set<string> = new Set(spdxLicenseIds) /** * Check if a license identifier is a valid SPDX license. diff --git a/shared/utils/trends-chart.ts b/shared/utils/trends-chart.ts index 6fc591fe62..4a29618ece 100644 --- a/shared/utils/trends-chart.ts +++ b/shared/utils/trends-chart.ts @@ -745,9 +745,9 @@ export function isMissingDownloadValue(value: unknown): boolean { } // This is somehow arbitrary: fixes the threshold above which a package is considered "large", which means any day with 0 downloads must imply a npm recording anomaly. If a package has a median daily downloads above this threshold, the last label on the charts will be the last valid one (see implementations in TrendsChart.vue, SplitSparkline.vue, embed-downloads-svg.ts) -export const LARGE_PACKAGE_DAILY_DOWNLOADS_THRESHOLD = 500 +const LARGE_PACKAGE_DAILY_DOWNLOADS_THRESHOLD = 500 -export const DAYS_PER_GRANULARITY: Record<ChartTimeGranularity, number> = { +const DAYS_PER_GRANULARITY: Record<ChartTimeGranularity, number> = { daily: 1, weekly: 7, monthly: 365.25 / 12, diff --git a/test/unit/a11y-component-coverage.spec.ts b/test/unit/a11y-component-coverage.spec.ts index d6f82a4d62..ac08aae771 100644 --- a/test/unit/a11y-component-coverage.spec.ts +++ b/test/unit/a11y-component-coverage.spec.ts @@ -60,7 +60,6 @@ const SKIPPED_COMPONENTS: Record<string, string> = { 'Button/Group.vue': "Wrapper component, tests wouldn't make much sense here", 'Changelog/Releases.vue': 'Requires API calls & only renders ChangelogCard components in a list', 'Changelog/Markdown.vue': 'Requires API call & mostly renders markdown html', - 'Translation/StatusByFile.unused.vue': 'Unused component, might be needed in the future', 'ColorScheme/Img.vue': 'Image component, basic ui', 'VideoPlayer.vue': 'Atproto video component, basic ui', }