Skip to content

Commit 44e8609

Browse files
committed
fix: small fixes
1 parent 8813003 commit 44e8609

5 files changed

Lines changed: 42 additions & 46 deletions

File tree

app/components/diff/ViewerPanel.vue

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script setup lang="ts">
22
import type { FileDiffResponse, FileChange, DiffHunk } from '#shared/types'
33
import { createDiff, insertSkipBlocks, countDiffStats } from '#shared/utils/diff'
4+
import { onClickOutside } from '@vueuse/core'
45
import { motion } from 'motion-v'
56
67
const props = defineProps<{
@@ -16,6 +17,10 @@ const maxDiffDistance = ref(30)
1617
const inlineMaxCharEdits = ref(2)
1718
const wordWrap = ref(false)
1819
const showOptions = ref(false)
20+
const optionsDropdownRef = useTemplateRef('optionsDropdownRef')
21+
onClickOutside(optionsDropdownRef, () => {
22+
showOptions.value = false
23+
})
1924
const loading = ref(true)
2025
const loadError = ref<Error | null>(null)
2126
const diff = ref<FileDiffResponse | null>(null)
@@ -192,8 +197,8 @@ function getStepMarks(min: number, max: number, step: number): number[] {
192197
return marks
193198
}
194199
195-
const changeRatioMarks = computed(() => getStepMarks(0, 1, 0.01))
196-
const diffDistanceMarks = computed(() => getStepMarks(1, 60, 1))
200+
const changeRatioMarks = computed(() => getStepMarks(0, 1, 0.1))
201+
const diffDistanceMarks = computed(() => getStepMarks(1, 60, 10))
197202
const charEditMarks = computed(() => [] as number[]) // no dots for char edits slider
198203
const changeRatioPercent = computed(() => calcPercent(maxChangeRatio.value, 0, 1))
199204
const diffDistancePercent = computed(() => calcPercent(maxDiffDistance.value, 1, 60))
@@ -260,7 +265,7 @@ function getCodeUrl(version: string): string {
260265

261266
<div class="flex items-center gap-2 shrink-0">
262267
<!-- Options dropdown -->
263-
<div class="relative">
268+
<div ref="optionsDropdownRef" class="relative">
264269
<button
265270
type="button"
266271
class="px-2 py-1 text-xs text-fg-muted hover:text-fg bg-bg-muted border border-border rounded transition-colors flex items-center gap-1.5"
@@ -278,7 +283,7 @@ function getCodeUrl(version: string): string {
278283
<!-- Dropdown menu -->
279284
<motion.div
280285
v-if="showOptions"
281-
class="absolute right-0 top-full mt-2 z-20 p-4 bg-bg-elevated border border-border shadow-2xl overflow-auto"
286+
class="absolute inset-ie-0 top-full mt-2 z-20 p-4 bg-bg-elevated border border-border shadow-2xl overflow-auto"
282287
:style="{
283288
width: mergeModifiedLines
284289
? 'min(420px, calc(100vw - 24px))'

server/api/registry/compare-file/[...pkg].get.ts

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,14 @@ import { PackageFileDiffQuerySchema } from '#shared/schemas/package'
33
import type { FileDiffResponse, DiffHunk } from '#shared/types'
44
import { CACHE_MAX_AGE_ONE_YEAR } from '#shared/utils/constants'
55
import { createDiff, insertSkipBlocks, countDiffStats } from '#server/utils/diff'
6+
import { parseVersionRange } from '#server/utils/compare'
67

78
const CACHE_VERSION = 1
89
const DIFF_TIMEOUT = 15000 // 15 sec
910

1011
/** Maximum file size for diffing (250KB - smaller than viewing since we diff two files) */
1112
const MAX_DIFF_FILE_SIZE = 250 * 1024
1213

13-
/**
14-
* Parse the version range from the URL.
15-
* Supports formats like: "1.0.0...2.0.0" or "1.0.0..2.0.0"
16-
*/
17-
function parseVersionRange(versionRange: string): { from: string; to: string } | null {
18-
// Try triple dot first (GitHub style)
19-
let parts = versionRange.split('...')
20-
if (parts.length === 2) {
21-
return { from: parts[0]!, to: parts[1]! }
22-
}
23-
24-
// Try double dot
25-
parts = versionRange.split('..')
26-
if (parts.length === 2) {
27-
return { from: parts[0]!, to: parts[1]! }
28-
}
29-
30-
return null
31-
}
32-
3314
/**
3415
* Fetch file content from jsDelivr with size check
3516
*/
@@ -241,7 +222,13 @@ export default defineCachedEventHandler(
241222
getKey: event => {
242223
const pkg = getRouterParam(event, 'pkg') ?? ''
243224
const query = getQuery(event)
244-
const optionsKey = `${query.mergeModifiedLines}:${query.maxChangeRatio}:${query.maxDiffDistance}:${query.inlineMaxCharEdits}`
225+
// Normalize option values to prevent cache pollution from arbitrary floats.
226+
// These match the parsing logic used in the handler body.
227+
const merge = query.mergeModifiedLines !== 'false'
228+
const ratio = Math.round((parseFloat(query.maxChangeRatio as string) || 0.45) * 100)
229+
const distance = parseInt(query.maxDiffDistance as string, 10) || 30
230+
const charEdits = parseInt(query.inlineMaxCharEdits as string, 10) || 2
231+
const optionsKey = `${merge}:${ratio}:${distance}:${charEdits}`
245232
return `compare-file:v${CACHE_VERSION}:${pkg.replace(/\/+$/, '').trim()}:${optionsKey}`
246233
},
247234
},

server/api/registry/compare/[...pkg].get.ts

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as v from 'valibot'
22
import { PackageCompareQuerySchema } from '#shared/schemas/package'
33
import type { CompareResponse } from '#shared/types'
44
import { CACHE_MAX_AGE_ONE_YEAR } from '#shared/utils/constants'
5-
import { buildCompareResponse } from '#server/utils/compare'
5+
import { buildCompareResponse, parseVersionRange } from '#server/utils/compare'
66

77
const CACHE_VERSION = 1
88
const COMPARE_TIMEOUT = 8000 // 8 seconds
@@ -25,26 +25,6 @@ async function fetchPackageJson(
2525
}
2626
}
2727

28-
/**
29-
* Parse the version range from the URL.
30-
* Supports formats like: "1.0.0...2.0.0" or "1.0.0..2.0.0"
31-
*/
32-
function parseVersionRange(versionRange: string): { from: string; to: string } | null {
33-
// Try triple dot first (GitHub style)
34-
let parts = versionRange.split('...')
35-
if (parts.length === 2) {
36-
return { from: parts[0]!, to: parts[1]! }
37-
}
38-
39-
// Try double dot
40-
parts = versionRange.split('..')
41-
if (parts.length === 2) {
42-
return { from: parts[0]!, to: parts[1]! }
43-
}
44-
45-
return null
46-
}
47-
4828
/**
4929
* Compare two package versions and return differences.
5030
*

server/utils/compare.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
11
import { diff as semverDiff } from 'semver'
22
import type { PackageFileTree, DependencyChange, FileChange, CompareResponse } from '#shared/types'
33

4+
/**
5+
* Parse a version range from a URL segment.
6+
* Supports formats like: "1.0.0...2.0.0" (triple dot, GitHub style)
7+
*/
8+
export function parseVersionRange(versionRange: string): { from: string; to: string } | null {
9+
const parts = versionRange.split('...')
10+
if (parts.length === 2) {
11+
return { from: parts[0]!, to: parts[1]! }
12+
}
13+
14+
return null
15+
}
16+
417
/** Maximum number of files to include in comparison */
518
const MAX_FILES_COMPARE = 1000
619

shared/utils/diff.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,17 @@ export function countDiffStats(hunks: (DiffHunk | DiffSkipBlock)[]): {
374374
for (const line of hunk.lines) {
375375
if (line.type === 'insert') additions++
376376
else if (line.type === 'delete') deletions++
377+
else if (line.type === 'normal') {
378+
// Merged modified lines have type 'normal' but contain inline
379+
// insert/delete segments. Count them as both an addition and deletion.
380+
const hasInlineChanges = line.content.some(
381+
seg => seg.type === 'insert' || seg.type === 'delete',
382+
)
383+
if (hasInlineChanges) {
384+
additions++
385+
deletions++
386+
}
387+
}
377388
}
378389
}
379390
}

0 commit comments

Comments
 (0)