From b93739577a037b155a2de09aec47c35cef7e8ad5 Mon Sep 17 00:00:00 2001 From: MatteoGabriele Date: Fri, 13 Mar 2026 16:00:32 +0100 Subject: [PATCH 1/3] refactor: remove linter warnings --- .storybook/main.ts | 10 ++--- app/components/Compare/FacetBarChart.vue | 4 +- app/composables/npm/useUserPackages.ts | 2 +- app/composables/useBlogPostBlueskyLink.ts | 1 + app/composables/useFacetSelection.ts | 16 +++---- app/composables/useMarkdown.ts | 8 ++-- app/pages/search.vue | 8 ++-- app/pages/settings.vue | 6 +-- app/utils/download-anomalies.ts | 2 +- cli/src/mock-state.ts | 18 ++++---- config/i18n.ts | 11 +++-- lunaria/components.ts | 18 ++++---- .../atproto/bluesky-author-profiles.get.ts | 2 +- .../[owner]/[repo].get.ts | 3 +- .../api/registry/compare-file/[...pkg].get.ts | 2 +- server/plugins/payload-cache.ts | 34 +++++++-------- server/utils/compare.ts | 21 +++++----- test/unit/app/utils/charts.spec.ts | 42 +++++++++---------- test/unit/app/utils/publish-security.spec.ts | 22 +++++----- 19 files changed, 114 insertions(+), 116 deletions(-) diff --git a/.storybook/main.ts b/.storybook/main.ts index 45af6e1491..04f806021c 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -8,10 +8,10 @@ const config = { features: { backgrounds: false, }, - async viteFinal(config) { - config.plugins ??= [] + async viteFinal(newConfig) { + newConfig.plugins ??= [] - config.plugins.push({ + newConfig.plugins.push({ name: 'ignore-internals', transform(_, id) { if (id.includes('/app/pages/blog/') && id.endsWith('.md')) { @@ -23,7 +23,7 @@ const config = { // vue-docgen-api can crash on components that import types from other // .vue files (it tries to parse the SFC with @babel/parser as plain TS). // This wrapper catches those errors so the build doesn't fail. - const docgenPlugin = config.plugins?.find( + const docgenPlugin = newConfig.plugins?.find( (p): p is Extract => !!p && typeof p === 'object' && 'name' in p && p.name === 'storybook:vue-docgen-plugin', ) @@ -48,7 +48,7 @@ const config = { } } - return config + return newConfig }, } satisfies StorybookConfig diff --git a/app/components/Compare/FacetBarChart.vue b/app/components/Compare/FacetBarChart.vue index dd1fb37cc2..1e28d23db2 100644 --- a/app/components/Compare/FacetBarChart.vue +++ b/app/components/Compare/FacetBarChart.vue @@ -178,8 +178,8 @@ const config = computed(() => { bold: false, color: colors.value.fg, value: { - formatter: ({ config }) => { - return config?.datapoint?.formattedValue ?? '0' + formatter: ({ config: formatterConfig }) => { + return formatterConfig?.datapoint?.formattedValue ?? '0' }, }, }, diff --git a/app/composables/npm/useUserPackages.ts b/app/composables/npm/useUserPackages.ts index 960c5208c4..def3706f9e 100644 --- a/app/composables/npm/useUserPackages.ts +++ b/app/composables/npm/useUserPackages.ts @@ -47,7 +47,7 @@ export function useUserPackages(username: MaybeRefOrGetter) { const asyncData = useLazyAsyncData( () => `user-packages:${searchProviderValue.value}:${toValue(username)}`, - async ({ $npmRegistry }, { signal }) => { + async (_, { signal }) => { const user = toValue(username) if (!user) { return emptySearchResponse() diff --git a/app/composables/useBlogPostBlueskyLink.ts b/app/composables/useBlogPostBlueskyLink.ts index f5c41906d7..68901ed47a 100644 --- a/app/composables/useBlogPostBlueskyLink.ts +++ b/app/composables/useBlogPostBlueskyLink.ts @@ -72,6 +72,7 @@ export function useBlogPostBlueskyLink(slug: MaybeRefOrGetter { chartable: boolean } +// Get facets in a category (excluding coming soon) +function getFacetsInCategory(category: string): ComparisonFacet[] { + return ALL_FACETS.filter(f => { + const info = FACET_INFO[f] + return info.category === category && !info.comingSoon + }) +} + /** * Composable for managing comparison facet selection with URL sync. * @@ -150,14 +158,6 @@ export function useFacetSelection(queryParam = 'facets') { } } - // Get facets in a category (excluding coming soon) - function getFacetsInCategory(category: string): ComparisonFacet[] { - return ALL_FACETS.filter(f => { - const info = FACET_INFO[f] - return info.category === category && !info.comingSoon - }) - } - // Select all facets in a category function selectCategory(category: string): void { const categoryFacets = getFacetsInCategory(category) diff --git a/app/composables/useMarkdown.ts b/app/composables/useMarkdown.ts index 036c0b2d66..01dc9b1533 100644 --- a/app/composables/useMarkdown.ts +++ b/app/composables/useMarkdown.ts @@ -88,20 +88,20 @@ function parseMarkdown({ text, packageName, plain }: UseMarkdownOptions): string html = html.replace(/~~(.+?)~~/g, '$1') // Links: [text](url) - only allow https, mailto - html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_match, text, url) => { + html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_match, matchedText, url) => { // In plain mode, just render the link text without the anchor if (plain) { - return text + return matchedText } const decodedUrl = url.replace(/&/g, '&') try { const { protocol, href } = new URL(decodedUrl) if (['https:', 'mailto:'].includes(protocol)) { const safeUrl = href.replace(/"/g, '"') - return `${text}` + return `${matchedText}` } } catch {} - return `${text} (${url})` + return `${matchedText} (${url})` }) return html diff --git a/app/pages/search.vue b/app/pages/search.vue index ce503b995b..762a122eb3 100644 --- a/app/pages/search.vue +++ b/app/pages/search.vue @@ -393,12 +393,12 @@ const exactMatchType = computed<'package' | 'org' | 'user' | null>(() => { const suggestionCount = computed(() => validatedSuggestions.value.length) const totalSelectableCount = computed(() => suggestionCount.value + resultCount.value) +const isVisible = (el: HTMLElement) => el.getClientRects().length > 0 + /** * Get all focusable result elements in DOM order (suggestions first, then packages) */ function getFocusableElements(): HTMLElement[] { - const isVisible = (el: HTMLElement) => el.getClientRects().length > 0 - const suggestions = Array.from(document.querySelectorAll('[data-suggestion-index]')) .filter(isVisible) .sort((a, b) => { @@ -435,7 +435,7 @@ async function navigateToPackage(packageName: string) { const pendingEnterQuery = shallowRef(null) // Watch for results to navigate when Enter was pressed before results arrived -watch(displayResults, results => { +watch(displayResults, newResults => { if (!pendingEnterQuery.value) return // Check if input is still focused (user hasn't started navigating or clicked elsewhere) @@ -445,7 +445,7 @@ watch(displayResults, results => { } // Navigate if first result matches the query that was entered - const firstResult = results[0] + const firstResult = newResults[0] // eslint-disable-next-line no-console console.log('[search] watcher fired', { pending: pendingEnterQuery.value, diff --git a/app/pages/settings.vue b/app/pages/settings.vue index 08523f7703..f2fe9db5e0 100644 --- a/app/pages/settings.vue +++ b/app/pages/settings.vue @@ -36,9 +36,9 @@ defineOgImageComponent('Default', { primaryColor: '#60a5fa', }) -const setLocale: typeof setNuxti18nLocale = locale => { - settings.value.selectedLocale = locale - return setNuxti18nLocale(locale) +const setLocale: typeof setNuxti18nLocale = newLocale => { + settings.value.selectedLocale = newLocale + return setNuxti18nLocale(newLocale) } diff --git a/app/utils/download-anomalies.ts b/app/utils/download-anomalies.ts index ae2798d0bd..8aad2ab646 100644 --- a/app/utils/download-anomalies.ts +++ b/app/utils/download-anomalies.ts @@ -98,7 +98,7 @@ export function applyBlocklistCorrection(opts: { if (!anomalies.length) return data // Clone to avoid mutation - const result = (data as Array>).map(d => ({ ...d })) + const result = (data as Array>).map(d => Object.assign({}, d)) for (const anomaly of anomalies) { // Find indices of affected points diff --git a/cli/src/mock-state.ts b/cli/src/mock-state.ts index 829e0ff3c7..3eed20a5ac 100644 --- a/cli/src/mock-state.ts +++ b/cli/src/mock-state.ts @@ -229,10 +229,10 @@ export class MockConnectorStateManager { } approveOperation(id: string): PendingOperation | null { - const op = this.state.operations.find(op => op.id === id) - if (!op || op.status !== 'pending') return null - op.status = 'approved' - return op + const operation = this.state.operations.find(op => op.id === id) + if (!operation || operation.status !== 'pending') return null + operation.status = 'approved' + return operation } approveAll(): number { @@ -247,11 +247,11 @@ export class MockConnectorStateManager { } retryOperation(id: string): PendingOperation | null { - const op = this.state.operations.find(op => op.id === id) - if (!op || op.status !== 'failed') return null - op.status = 'approved' - op.result = undefined - return op + const operation = this.state.operations.find(op => op.id === id) + if (!operation || operation.status !== 'failed') return null + operation.status = 'approved' + operation.result = undefined + return operation } /** Execute all approved operations (mock: instant success unless configured otherwise). */ diff --git a/config/i18n.ts b/config/i18n.ts index 0270ec9c42..aca626d74d 100644 --- a/config/i18n.ts +++ b/config/i18n.ts @@ -358,9 +358,9 @@ const locales: (LocaleObjectData | (Omit & { code: str function buildLocales() { const useLocales = Object.values(locales).reduce((acc, data) => { - const locales = countryLocaleVariants[data.code] - if (locales) { - locales.forEach(l => { + const variants = countryLocaleVariants[data.code] + if (variants) { + variants.forEach(l => { const entry: LocaleObjectData = { ...data, code: l.code, @@ -406,9 +406,8 @@ export const datetimeFormats = Object.values(currentLocales).reduce((acc, data) }, {} as DateTimeFormats) export const numberFormats = Object.values(currentLocales).reduce((acc, data) => { - const numberFormats = data.numberFormats - if (numberFormats) { - acc[data.code] = { ...numberFormats } + if (data.numberFormats) { + acc[data.code] = { ...data.numberFormats } delete data.numberFormats } else { acc[data.code] = { diff --git a/lunaria/components.ts b/lunaria/components.ts index e5545004f8..35d377fe45 100644 --- a/lunaria/components.ts +++ b/lunaria/components.ts @@ -115,7 +115,7 @@ export const LocaleDetails = ( file.localizations.find(localization => localization.lang === lang)?.status === 'missing', ) const outdatedFiles = status.filter(file => { - const localization = file.localizations.find(localization => localization.lang === lang) + const localization = file.localizations.find(l => l.lang === lang) if (!localization || localization.status === 'missing') return false if (file.type === 'dictionary') @@ -149,9 +149,7 @@ export const LocaleDetails = ( ? html`

Missing

    ${missingFiles.map(file => { - const localization = file.localizations.find( - localization => localization.lang === lang, - )! + const localization = file.localizations.find(l => l.lang === lang)! return html`
  • ${Link(links.source(file.source.path), collapsePath(file.source.path))} @@ -182,7 +180,7 @@ export const OutdatedFiles = (

    Outdated

      ${outdatedFiles.map(file => { - const localization = file.localizations.find(localization => localization.lang === lang)! + const localization = file.localizations.find(l => l.lang === lang)! const isMissingKeys = localization.status !== 'missing' && @@ -265,7 +263,7 @@ export const TableContentStatus = ( lunaria: LunariaInstance, fileType?: string, ): string => { - const localization = localizations.find(localization => localization.lang === lang)! + const localization = localizations.find(l => l.lang === lang)! const isMissingKeys = 'missingKeys' in localization && localization.missingKeys.length > 0 // For dictionary files, status is determined solely by key completion: // if there are missing keys it's "outdated", if all keys are present it's "up-to-date", @@ -292,7 +290,7 @@ export const ContentDetailsLinks = ( lang: string, lunaria: LunariaInstance, ): string => { - const localization = fileStatus.localizations.find(localization => localization.lang === lang)! + const localization = fileStatus.localizations.find(l => l.lang === lang)! const isMissingKeys = localization.status !== 'missing' && 'missingKeys' in localization && @@ -361,9 +359,9 @@ export const ProgressBar = ( const missingSize = Math.round((missing / total) * size) const doneSize = size - outdatedSize - missingSize - const getBlocks = (size: number, type: 'missing' | 'outdated' | 'up-to-date') => { + const getBlocks = (blockSize: number, type: 'missing' | 'outdated' | 'up-to-date') => { const items = [] - for (let i = 0; i < size; i++) { + for (let i = 0; i < blockSize; i++) { items.push(html`
      `) } return items @@ -425,7 +423,7 @@ function SvgLocaleSummary( file.localizations.find(localization => localization.lang === lang)?.status === 'missing', ) const outdatedFiles = status.filter(file => { - const localization = file.localizations.find(localization => localization.lang === lang) + const localization = file.localizations.find(l => l.lang === lang) if (!localization || localization.status === 'missing') { return false } else if (file.type === 'dictionary') { diff --git a/server/api/atproto/bluesky-author-profiles.get.ts b/server/api/atproto/bluesky-author-profiles.get.ts index c4b63b2866..d423278f20 100644 --- a/server/api/atproto/bluesky-author-profiles.get.ts +++ b/server/api/atproto/bluesky-author-profiles.get.ts @@ -39,7 +39,7 @@ export default defineCachedEventHandler( return { authors: [] } } - const handles = authors.map(a => a.blueskyHandle).filter(v => v != null) + const handles = authors.map(a => a.blueskyHandle).filter(handle => handle != null) if (handles.length === 0) { return { diff --git a/server/api/github/contributors-evolution/[owner]/[repo].get.ts b/server/api/github/contributors-evolution/[owner]/[repo].get.ts index 3f87d1b73e..24499a53a7 100644 --- a/server/api/github/contributors-evolution/[owner]/[repo].get.ts +++ b/server/api/github/contributors-evolution/[owner]/[repo].get.ts @@ -12,6 +12,8 @@ type GitHubContributorStats = { weeks: GitHubContributorWeek[] } +const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)) + export default defineCachedEventHandler( async event => { const owner = getRouterParam(event, 'owner') @@ -30,7 +32,6 @@ export default defineCachedEventHandler( 'Accept': 'application/vnd.github+json', } - const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)) const maxAttempts = 6 let delayMs = 1000 diff --git a/server/api/registry/compare-file/[...pkg].get.ts b/server/api/registry/compare-file/[...pkg].get.ts index ab22fae418..eb0f03e1ad 100644 --- a/server/api/registry/compare-file/[...pkg].get.ts +++ b/server/api/registry/compare-file/[...pkg].get.ts @@ -200,7 +200,7 @@ export default defineCachedEventHandler( defaultColor: 'dark', }) const html = raw.match(/]*>([\s\S]*?)<\/code>/)?.[1] - return html ? { ...seg, html } : seg + return html ? Object.assign({}, seg, { html }) : seg } catch { return seg } diff --git a/server/plugins/payload-cache.ts b/server/plugins/payload-cache.ts index 7cdb12eb26..bcca9c5a6d 100644 --- a/server/plugins/payload-cache.ts +++ b/server/plugins/payload-cache.ts @@ -35,19 +35,27 @@ interface CachedPayload { buildId: string } +/** + * Get the route path from a _payload.json URL. + * e.g. "/package/vue/v/3.4.0/_payload.json?abc123" → "/package/vue/v/3.4.0" + */ +function getRouteFromPayloadUrl(url: string): string { + const withoutQuery = url.replace(/\?.*$/, '') + return withoutQuery.substring(0, withoutQuery.lastIndexOf('/')) || '/' +} + +/** + * Check if a route has ISR or cache rules enabled. + */ +function isISRRoute(event: H3Event): boolean { + const rules = getRouteRules(event) + return !!(rules.isr || rules.cache) +} + export default defineNitroPlugin(nitroApp => { const storage = useStorage(PAYLOAD_CACHE_STORAGE_KEY) const buildId = useRuntimeConfig().app.buildId as string - /** - * Get the route path from a _payload.json URL. - * e.g. "/package/vue/v/3.4.0/_payload.json?abc123" → "/package/vue/v/3.4.0" - */ - function getRouteFromPayloadUrl(url: string): string { - const withoutQuery = url.replace(/\?.*$/, '') - return withoutQuery.substring(0, withoutQuery.lastIndexOf('/')) || '/' - } - /** * Generate a cache key for a route path. * Includes the build ID to prevent serving stale payloads after deploys. @@ -56,14 +64,6 @@ export default defineNitroPlugin(nitroApp => { return `${buildId}:${routePath}` } - /** - * Check if a route has ISR or cache rules enabled. - */ - function isISRRoute(event: H3Event): boolean { - const rules = getRouteRules(event) - return !!(rules.isr || rules.cache) - } - // ------------------------------------------------------------------------- // render:before — Serve cached payloads, skip full SSR render // ------------------------------------------------------------------------- diff --git a/server/utils/compare.ts b/server/utils/compare.ts index 4a5a1e5732..a71bd34a8b 100644 --- a/server/utils/compare.ts +++ b/server/utils/compare.ts @@ -16,11 +16,11 @@ export function parseVersionRange(versionRange: string): { from: string; to: str /** Maximum number of files to include in comparison */ const MAX_FILES_COMPARE = 1000 -function traverse(nodes: PackageFileTree[], result: Map) { +function traverse(nodes: PackageFileTree[], callback: (node: PackageFileTree) => void) { for (const node of nodes) { - result.set(node.path, node) + callback(node) if (node.children) { - traverse(node.children, result) + traverse(node.children, callback) } } } @@ -29,7 +29,10 @@ function traverse(nodes: PackageFileTree[], result: Map export function flattenTree(tree: PackageFileTree[]): Map { const result = new Map() - traverse(tree, result) + traverse(tree, node => { + result.set(node.path, node) + }) + return result } @@ -212,14 +215,10 @@ export function compareDependencies( export function countFiles(tree: PackageFileTree[]): number { let count = 0 - function traverse(nodes: PackageFileTree[]) { - for (const node of nodes) { - if (node.type === 'file') count++ - if (node.children) traverse(node.children) - } - } + traverse(tree, node => { + if (node.type === 'file') count++ + }) - traverse(tree) return count } diff --git a/test/unit/app/utils/charts.spec.ts b/test/unit/app/utils/charts.spec.ts index 050799c8fa..8cac485de3 100644 --- a/test/unit/app/utils/charts.spec.ts +++ b/test/unit/app/utils/charts.spec.ts @@ -442,30 +442,30 @@ describe('winsorize', () => { }) }) -describe('computeLineChartAnalysis', () => { - const computeBaseTrend = (rSquared: number | null) => { - if (rSquared === null) return 'undefined' as const - if (rSquared > 0.75) return 'strong' as const - if (rSquared > 0.4) return 'weak' as const - return 'none' as const - } +const computeBaseTrend = (rSquared: number | null) => { + if (rSquared === null) return 'undefined' as const + if (rSquared > 0.75) return 'strong' as const + if (rSquared > 0.4) return 'weak' as const + return 'none' as const +} - const buildSeries = (base: number, step: number, noiseAmplitude: number) => { - const values: number[] = [] - for (let i = 0; i < 19; i += 1) { - const noise = - i % 4 === 0 - ? noiseAmplitude - : i % 4 === 1 - ? -noiseAmplitude - : i % 4 === 2 - ? Math.floor(noiseAmplitude / 2) - : -Math.floor(noiseAmplitude / 2) - values.push(base + i * step + noise) - } - return values +const buildSeries = (base: number, step: number, noiseAmplitude: number) => { + const values: number[] = [] + for (let i = 0; i < 19; i += 1) { + const noise = + i % 4 === 0 + ? noiseAmplitude + : i % 4 === 1 + ? -noiseAmplitude + : i % 4 === 2 + ? Math.floor(noiseAmplitude / 2) + : -Math.floor(noiseAmplitude / 2) + values.push(base + i * step + noise) } + return values +} +describe('computeLineChartAnalysis', () => { it('returns undefined interpretations for empty array', () => { const result = computeLineChartAnalysis([]) expect(result.mean).toBe(0) diff --git a/test/unit/app/utils/publish-security.spec.ts b/test/unit/app/utils/publish-security.spec.ts index dae694701e..abbb6a4fe8 100644 --- a/test/unit/app/utils/publish-security.spec.ts +++ b/test/unit/app/utils/publish-security.spec.ts @@ -89,7 +89,7 @@ describe('detectPublishSecurityDowngradeForVersion', () => { }) it('flags ongoing downgraded versions until an upgrade happens', () => { - const versions = [ + const downgradedVersions = [ { version: '2.1.0', time: '2026-01-01T00:00:00.000Z', @@ -122,16 +122,16 @@ describe('detectPublishSecurityDowngradeForVersion', () => { }, ] - expect(detectPublishSecurityDowngradeForVersion(versions, '2.1.1')?.trustedVersion).toBe( - '2.1.0', - ) - expect(detectPublishSecurityDowngradeForVersion(versions, '2.2.0')?.trustedVersion).toBe( - '2.1.0', - ) - expect(detectPublishSecurityDowngradeForVersion(versions, '2.3.0')?.trustedVersion).toBe( - '2.1.0', - ) - expect(detectPublishSecurityDowngradeForVersion(versions, '2.4.0')).toBeNull() + expect( + detectPublishSecurityDowngradeForVersion(downgradedVersions, '2.1.1')?.trustedVersion, + ).toBe('2.1.0') + expect( + detectPublishSecurityDowngradeForVersion(downgradedVersions, '2.2.0')?.trustedVersion, + ).toBe('2.1.0') + expect( + detectPublishSecurityDowngradeForVersion(downgradedVersions, '2.3.0')?.trustedVersion, + ).toBe('2.1.0') + expect(detectPublishSecurityDowngradeForVersion(downgradedVersions, '2.4.0')).toBeNull() }) it('skips deprecated versions when selecting trustedVersion', () => { From 96784827e7378096c0a129f8cdaac4d6441560e2 Mon Sep 17 00:00:00 2001 From: MatteoGabriele Date: Fri, 13 Mar 2026 16:33:31 +0100 Subject: [PATCH 2/3] refactor: review feedback --- app/composables/useMarkdown.ts | 8 ++++---- lunaria/components.ts | 18 ++++++++++++------ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/app/composables/useMarkdown.ts b/app/composables/useMarkdown.ts index 01dc9b1533..cd70bf6529 100644 --- a/app/composables/useMarkdown.ts +++ b/app/composables/useMarkdown.ts @@ -88,20 +88,20 @@ function parseMarkdown({ text, packageName, plain }: UseMarkdownOptions): string html = html.replace(/~~(.+?)~~/g, '$1') // Links: [text](url) - only allow https, mailto - html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_match, matchedText, url) => { + html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_match, textGroup, url) => { // In plain mode, just render the link text without the anchor if (plain) { - return matchedText + return textGroup } const decodedUrl = url.replace(/&/g, '&') try { const { protocol, href } = new URL(decodedUrl) if (['https:', 'mailto:'].includes(protocol)) { const safeUrl = href.replace(/"/g, '"') - return `${matchedText}` + return `${textGroup}` } } catch {} - return `${matchedText} (${url})` + return `${textGroup} (${url})` }) return html diff --git a/lunaria/components.ts b/lunaria/components.ts index 35d377fe45..a8c290727d 100644 --- a/lunaria/components.ts +++ b/lunaria/components.ts @@ -115,7 +115,7 @@ export const LocaleDetails = ( file.localizations.find(localization => localization.lang === lang)?.status === 'missing', ) const outdatedFiles = status.filter(file => { - const localization = file.localizations.find(l => l.lang === lang) + const localization = file.localizations.find(localizationItem => localizationItem.lang === lang) if (!localization || localization.status === 'missing') return false if (file.type === 'dictionary') @@ -149,7 +149,9 @@ export const LocaleDetails = ( ? html`

      Missing

        ${missingFiles.map(file => { - const localization = file.localizations.find(l => l.lang === lang)! + const localization = file.localizations.find( + localizationItem => localizationItem.lang === lang, + )! return html`
      • ${Link(links.source(file.source.path), collapsePath(file.source.path))} @@ -180,7 +182,9 @@ export const OutdatedFiles = (

        Outdated

          ${outdatedFiles.map(file => { - const localization = file.localizations.find(l => l.lang === lang)! + const localization = file.localizations.find( + localizationItem => localizationItem.lang === lang, + )! const isMissingKeys = localization.status !== 'missing' && @@ -263,7 +267,7 @@ export const TableContentStatus = ( lunaria: LunariaInstance, fileType?: string, ): string => { - const localization = localizations.find(l => l.lang === lang)! + const localization = localizations.find(localizationItem => localizationItem.lang === lang)! const isMissingKeys = 'missingKeys' in localization && localization.missingKeys.length > 0 // For dictionary files, status is determined solely by key completion: // if there are missing keys it's "outdated", if all keys are present it's "up-to-date", @@ -290,7 +294,9 @@ export const ContentDetailsLinks = ( lang: string, lunaria: LunariaInstance, ): string => { - const localization = fileStatus.localizations.find(l => l.lang === lang)! + const localization = fileStatus.localizations.find( + localizationItem => localizationItem.lang === lang, + )! const isMissingKeys = localization.status !== 'missing' && 'missingKeys' in localization && @@ -423,7 +429,7 @@ function SvgLocaleSummary( file.localizations.find(localization => localization.lang === lang)?.status === 'missing', ) const outdatedFiles = status.filter(file => { - const localization = file.localizations.find(l => l.lang === lang) + const localization = file.localizations.find(localizationItem => localizationItem.lang === lang) if (!localization || localization.status === 'missing') { return false } else if (file.type === 'dictionary') { From af8d0cf1dbc53315f8aaf6dd38a5e1b93a338803 Mon Sep 17 00:00:00 2001 From: MatteoGabriele Date: Fri, 13 Mar 2026 16:44:58 +0100 Subject: [PATCH 3/3] refactor: use _nuxtApp --- app/composables/npm/useUserPackages.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/composables/npm/useUserPackages.ts b/app/composables/npm/useUserPackages.ts index def3706f9e..59577cefaf 100644 --- a/app/composables/npm/useUserPackages.ts +++ b/app/composables/npm/useUserPackages.ts @@ -47,7 +47,7 @@ export function useUserPackages(username: MaybeRefOrGetter) { const asyncData = useLazyAsyncData( () => `user-packages:${searchProviderValue.value}:${toValue(username)}`, - async (_, { signal }) => { + async (_nuxtApp, { signal }) => { const user = toValue(username) if (!user) { return emptySearchResponse()