Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')) {
Expand All @@ -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<typeof p, { name: string }> =>
!!p && typeof p === 'object' && 'name' in p && p.name === 'storybook:vue-docgen-plugin',
)
Expand All @@ -48,7 +48,7 @@ const config = {
}
}

return config
return newConfig
},
} satisfies StorybookConfig

Expand Down
4 changes: 2 additions & 2 deletions app/components/Compare/FacetBarChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,8 @@ const config = computed<VueUiHorizontalBarConfig>(() => {
bold: false,
color: colors.value.fg,
value: {
formatter: ({ config }) => {
return config?.datapoint?.formattedValue ?? '0'
formatter: ({ config: formatterConfig }) => {
return formatterConfig?.datapoint?.formattedValue ?? '0'
},
},
},
Expand Down
2 changes: 1 addition & 1 deletion app/composables/npm/useUserPackages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function useUserPackages(username: MaybeRefOrGetter<string>) {

const asyncData = useLazyAsyncData(
() => `user-packages:${searchProviderValue.value}:${toValue(username)}`,
async ({ $npmRegistry }, { signal }) => {
async (_nuxtApp, { signal }) => {
const user = toValue(username)
if (!user) {
return emptySearchResponse()
Expand Down
1 change: 1 addition & 0 deletions app/composables/useBlogPostBlueskyLink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export function useBlogPostBlueskyLink(slug: MaybeRefOrGetter<string | null | un
// TODO: Will need to remove this console error to satisfy linting scan
// Constellation unavailable or error - fail silently
// But during dev we will get an error
// oxlint-disable-next-line no-console
if (import.meta.dev) console.error('[Bluesky] Constellation error:', error)
}

Expand Down
16 changes: 8 additions & 8 deletions app/composables/useFacetSelection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ export interface FacetInfoWithLabels extends Omit<FacetInfo, 'id'> {
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.
*
Expand Down Expand Up @@ -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)
Expand Down
8 changes: 4 additions & 4 deletions app/composables/useMarkdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,20 +88,20 @@ function parseMarkdown({ text, packageName, plain }: UseMarkdownOptions): string
html = html.replace(/~~(.+?)~~/g, '<del>$1</del>')

// Links: [text](url) - only allow https, mailto
html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_match, text, url) => {
html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_match, textGroup, url) => {
// In plain mode, just render the link text without the anchor
if (plain) {
return text
return textGroup
}
const decodedUrl = url.replace(/&amp;/g, '&')
try {
const { protocol, href } = new URL(decodedUrl)
if (['https:', 'mailto:'].includes(protocol)) {
const safeUrl = href.replace(/"/g, '&quot;')
return `<a href="${safeUrl}" rel="nofollow noreferrer noopener" target="_blank">${text}</a>`
return `<a href="${safeUrl}" rel="nofollow noreferrer noopener" target="_blank">${textGroup}</a>`
}
} catch {}
return `${text} (${url})`
return `${textGroup} (${url})`
})

return html
Expand Down
8 changes: 4 additions & 4 deletions app/pages/search.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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<HTMLElement>('[data-suggestion-index]'))
.filter(isVisible)
.sort((a, b) => {
Expand Down Expand Up @@ -435,7 +435,7 @@ async function navigateToPackage(packageName: string) {
const pendingEnterQuery = shallowRef<string | null>(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)
Expand All @@ -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,
Expand Down
6 changes: 3 additions & 3 deletions app/pages/settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
</script>

Expand Down
2 changes: 1 addition & 1 deletion app/utils/download-anomalies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export function applyBlocklistCorrection(opts: {
if (!anomalies.length) return data

// Clone to avoid mutation
const result = (data as Array<Record<string, any>>).map(d => ({ ...d }))
const result = (data as Array<Record<string, any>>).map(d => Object.assign({}, d))

for (const anomaly of anomalies) {
// Find indices of affected points
Expand Down
18 changes: 9 additions & 9 deletions cli/src/mock-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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). */
Expand Down
11 changes: 5 additions & 6 deletions config/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -358,9 +358,9 @@ const locales: (LocaleObjectData | (Omit<LocaleObjectData, 'code'> & { 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,
Expand Down Expand Up @@ -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] = {
Expand Down
20 changes: 12 additions & 8 deletions lunaria/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(localizationItem => localizationItem.lang === lang)

if (!localization || localization.status === 'missing') return false
if (file.type === 'dictionary')
Expand Down Expand Up @@ -150,7 +150,7 @@ export const LocaleDetails = (
<ul>
${missingFiles.map(file => {
const localization = file.localizations.find(
localization => localization.lang === lang,
localizationItem => localizationItem.lang === lang,
)!
return html`
<li>
Expand Down Expand Up @@ -182,7 +182,9 @@ export const OutdatedFiles = (
<h3 class="capitalize">Outdated</h3>
<ul>
${outdatedFiles.map(file => {
const localization = file.localizations.find(localization => localization.lang === lang)!
const localization = file.localizations.find(
localizationItem => localizationItem.lang === lang,
)!

const isMissingKeys =
localization.status !== 'missing' &&
Expand Down Expand Up @@ -265,7 +267,7 @@ export const TableContentStatus = (
lunaria: LunariaInstance,
fileType?: string,
): string => {
const localization = localizations.find(localization => localization.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",
Expand All @@ -292,7 +294,9 @@ export const ContentDetailsLinks = (
lang: string,
lunaria: LunariaInstance,
): string => {
const localization = fileStatus.localizations.find(localization => localization.lang === lang)!
const localization = fileStatus.localizations.find(
localizationItem => localizationItem.lang === lang,
)!
const isMissingKeys =
localization.status !== 'missing' &&
'missingKeys' in localization &&
Expand Down Expand Up @@ -361,9 +365,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`<div class="${type}-bar"></div>`)
}
return items
Expand Down Expand Up @@ -425,7 +429,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(localizationItem => localizationItem.lang === lang)
if (!localization || localization.status === 'missing') {
return false
} else if (file.type === 'dictionary') {
Expand Down
2 changes: 1 addition & 1 deletion server/api/atproto/bluesky-author-profiles.get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand All @@ -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

Expand Down
2 changes: 1 addition & 1 deletion server/api/registry/compare-file/[...pkg].get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ export default defineCachedEventHandler(
defaultColor: 'dark',
})
const html = raw.match(/<code[^>]*>([\s\S]*?)<\/code>/)?.[1]
return html ? { ...seg, html } : seg
return html ? Object.assign({}, seg, { html }) : seg
} catch {
return seg
}
Expand Down
34 changes: 17 additions & 17 deletions server/plugins/payload-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
// -------------------------------------------------------------------------
Expand Down
Loading
Loading