Skip to content
Draft
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
7 changes: 4 additions & 3 deletions app/components/Package/SkillsModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@ const installCommand = computed(() => {

const { copied, copy } = useClipboard({ copiedDuring: 2000 })
const copyCommand = () => installCommand.value && copy(installCommand.value)
const translateWarning = useI18nWarning()

function getWarningTooltip(skill: SkillListItem): string | undefined {
if (!skill.warnings?.length) return undefined
return skill.warnings.map(w => w.message).join(', ')
return skill.warnings.map(translateWarning).join(', ')
}
</script>

Expand Down Expand Up @@ -218,10 +219,10 @@ function getWarningTooltip(skill: SkillListItem): string | undefined {
)
}}
</span>
<template v-for="warning in skill.warnings" :key="warning.message">
<template v-for="warning in skill.warnings" :key="warning.key">
<span class="text-amber-500">
<span class="i-lucide:circle-alert size-3 align-[-2px] me-0.5" />{{
warning.message
translateWarning(warning)
}}
</span>
</template>
Expand Down
5 changes: 4 additions & 1 deletion app/components/diff/SidebarPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const fileFilter = defineModel<'all' | 'added' | 'removed' | 'modified'>('fileFi

const sectionOrder = ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies']
const { t } = useI18n()
const translateWarning = useI18nWarning()
const sectionMeta = computed<Record<string, { label: string; icon: string }>>(() => ({
dependencies: { label: t('compare.dependencies'), icon: 'i-lucide:box' },
devDependencies: { label: t('compare.dev_dependencies'), icon: 'i-lucide:wrench' },
Expand Down Expand Up @@ -112,7 +113,9 @@ function handleFileSelect(file: FileChange) {
<div class="flex items-start gap-2">
<span class="i-lucide:triangle-alert w-3.5 h-3.5 text-yellow-500 shrink-0 mt-0.5" />
<div class="text-3xs text-fg-muted">
<p v-for="warning in compare.meta.warnings" :key="warning">{{ warning }}</p>
<p v-for="warning in compare.meta.warnings" :key="warning.key">
{{ translateWarning(warning) }}
</p>
</div>
</div>
</div>
Expand Down
7 changes: 7 additions & 0 deletions app/composables/useI18nWarning.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { WarningMessage } from '#shared/types/warning'

export function useI18nWarning() {
const { t } = useI18n()

return (warning: WarningMessage): string => t(warning.key, warning.data ?? {})
}
9 changes: 8 additions & 1 deletion i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,10 @@
"refs": "{count} ref | {count} refs",
"assets": "{count} asset | {count} assets"
},
"warnings": {
"no_license": "No license specified",
"no_compatibility": "No compatibility info"
},
"view_source": "View source"
},
"links": {
Expand Down Expand Up @@ -1205,7 +1209,10 @@
"files_button": "Files",
"select_file_prompt": "Select a file from the sidebar to view its diff",
"close_files_panel": "Close files panel",
"filter_files_label": "Filter files by change type"
"filter_files_label": "Filter files by change type",
"warnings": {
"files_truncated": "File list truncated to {count} files"
}
},
"pds": {
"title": "npmx.social",
Expand Down
6 changes: 5 additions & 1 deletion i18n/locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,11 @@
"refs": "{count} 个引用 | {count} 个引用",
"assets": "{count} 个资源 | {count} 个资源"
},
"view_source": "查看源代码"
"view_source": "查看源代码",
"warnings": {
"no_compatibility": "无兼容性信息",
"no_license": "未指定许可证"
}
},
"links": {
"repo": "仓库",
Expand Down
21 changes: 21 additions & 0 deletions i18n/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,18 @@
},
"additionalProperties": false
},
"warnings": {
"type": "object",
"properties": {
"no_license": {
"type": "string"
},
"no_compatibility": {
"type": "string"
}
},
"additionalProperties": false
},
"view_source": {
"type": "string"
}
Expand Down Expand Up @@ -3621,6 +3633,15 @@
},
"filter_files_label": {
"type": "string"
},
"warnings": {
"type": "object",
"properties": {
"files_truncated": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
Expand Down
8 changes: 6 additions & 2 deletions server/utils/compare.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { diff as semverDiff } from 'semver'
import type { WarningMessage } from '#shared/types/warning'

/**
* Parse a version range from a URL segment.
Expand Down Expand Up @@ -236,9 +237,12 @@ export function buildCompareResponse(
const fileChanges = compareFileTrees(fromTree, toTree)
const dependencyChanges = compareDependencies(fromPkg, toPkg)

const warnings: string[] = []
const warnings: WarningMessage[] = []
if (fileChanges.truncated) {
warnings.push(`File list truncated to ${MAX_FILES_COMPARE} files`)
warnings.push({
key: 'compare.warnings.files_truncated',
data: { count: String(MAX_FILES_COMPARE) },
})
}

return {
Expand Down
10 changes: 6 additions & 4 deletions server/utils/skills.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { WarningMessage } from '#shared/types/warning'

const MAX_SKILL_FILE_SIZE = 500 * 1024

/**
Expand Down Expand Up @@ -154,13 +156,13 @@ export async function fetchSkillContent(
/**
* Validate skill frontmatter and return warnings.
*/
export function validateSkill(frontmatter: SkillFrontmatter): SkillWarning[] {
const warnings: SkillWarning[] = []
export function validateSkill(frontmatter: SkillFrontmatter): WarningMessage[] {
const warnings: WarningMessage[] = []
if (!frontmatter.license) {
warnings.push({ type: 'warning', message: 'No license specified' })
warnings.push({ key: 'package.skills.warnings.no_license' })
}
if (!frontmatter.compatibility) {
warnings.push({ type: 'warning', message: 'No compatibility info' })
warnings.push({ key: 'package.skills.warnings.no_compatibility' })
}
return warnings
}
Expand Down
4 changes: 3 additions & 1 deletion shared/types/compare.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { WarningMessage } from '#shared/types/warning'

/** A change in a dependency between versions */
export interface DependencyChange {
/** Package name */
Expand Down Expand Up @@ -60,7 +62,7 @@ export interface CompareResponse {
/** Whether file list was truncated due to size */
truncated?: boolean
/** Any warnings during comparison */
warnings?: string[]
warnings?: WarningMessage[]
/** Time taken to compute (ms) */
computeTime?: number
}
Expand Down
9 changes: 3 additions & 6 deletions shared/types/skills.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { WarningMessage } from '#shared/types/warning'

export interface SkillFrontmatter {
name: string
description: string
Expand All @@ -6,11 +8,6 @@ export interface SkillFrontmatter {
metadata?: Record<string, string>
}

export interface SkillWarning {
type: 'error' | 'warning'
message: string
}

export interface SkillFileCounts {
scripts?: number
references?: number
Expand All @@ -23,7 +20,7 @@ export interface SkillListItem {
dirName: string
license?: string
compatibility?: string
warnings?: SkillWarning[]
warnings?: WarningMessage[]
fileCounts?: SkillFileCounts
}

Expand Down
6 changes: 6 additions & 0 deletions shared/types/warning.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface WarningMessage {
/** i18n translation key returned by the API. */
key: string
/** Named interpolation params for the translation key. */
data?: Record<string, string>
}
4 changes: 3 additions & 1 deletion test/nuxt/a11y.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3426,7 +3426,9 @@ describe('component accessibility audits', () => {
it('should have no accessibility violations with warnings', async () => {
const compareWithWarnings = {
...mockCompare,
meta: { warnings: ['Some files were truncated'] },
meta: {
warnings: [{ key: 'compare.warnings.files_truncated', data: { count: '1000' } }],
},
}
const component = await mountSuspended(DiffSidebarPanel, {
props: {
Expand Down
Loading