-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.ts
More file actions
156 lines (143 loc) · 4.48 KB
/
utils.ts
File metadata and controls
156 lines (143 loc) · 4.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/**
* Format a file size in bytes to human-readable string
*/
export function formatBytes(bytes: number, decimals = 2): string {
if (bytes === 0) return '0 B'
const k = 1024
const sizes = ['B', 'KB', 'MB', 'GB', 'TB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(decimals))} ${sizes[i]}`
}
/**
* Format a duration in milliseconds to human-readable string
*/
export function formatDuration(ms: number): string {
if (ms < 1000) return `${ms}ms`
if (ms < 60000) return `${(ms / 1000).toFixed(2)}s`
const mins = Math.floor(ms / 60000)
const secs = ((ms % 60000) / 1000).toFixed(1)
return `${mins}m ${secs}s`
}
/**
* Format a date to human-readable string
*/
export function formatDate(date: Date | string): string {
const d = typeof date === 'string' ? new Date(date) : date
return d.toLocaleString()
}
/**
* Get relative time string (e.g., "2 hours ago")
*/
export function getRelativeTime(date: Date | string): string {
const d = typeof date === 'string' ? new Date(date) : date
const now = new Date()
const diff = now.getTime() - d.getTime()
const seconds = Math.floor(diff / 1000)
const minutes = Math.floor(seconds / 60)
const hours = Math.floor(minutes / 60)
const days = Math.floor(hours / 24)
if (days > 0) return `${days} day${days > 1 ? 's' : ''} ago`
if (hours > 0) return `${hours} hour${hours > 1 ? 's' : ''} ago`
if (minutes > 0) return `${minutes} minute${minutes > 1 ? 's' : ''} ago`
return 'just now'
}
/**
* Truncate a string with ellipsis
*/
export function truncate(str: string, maxLength: number): string {
if (str.length <= maxLength) return str
return str.slice(0, maxLength - 3) + '...'
}
/**
* Copy text to clipboard
*/
export async function copyToClipboard(text: string): Promise<boolean> {
try {
await navigator.clipboard.writeText(text)
return true
} catch {
return false
}
}
/**
* Build a JSON path string
*/
export function buildPath(basePath: string, key: string | number): string {
if (basePath === '') {
return typeof key === 'number' ? `[${key}]` : key
}
if (typeof key === 'number') {
return `${basePath}[${key}]`
}
// Use bracket notation for keys with special characters
if (/[^a-zA-Z0-9_$]/.test(key)) {
return `${basePath}["${key}"]`
}
return `${basePath}.${key}`
}
/**
* Get a nested value from an object by path
*/
export function getValueByPath(obj: unknown, path: string): unknown {
if (!path) return obj
const parts = path.match(/[^.[\]]+|\[\d+\]/g) || []
let current: unknown = obj
for (const part of parts) {
if (current === null || current === undefined) return undefined
const key = part.startsWith('[') ? parseInt(part.slice(1, -1)) : part
current = (current as Record<string, unknown>)[key]
}
return current
}
/**
* Get preview text for a value
*/
export function getPreviewText(value: unknown, maxLength = 50): string {
if (value === null) return 'null'
if (value === undefined) return 'undefined'
if (typeof value === 'boolean') return String(value)
if (typeof value === 'number') return String(value)
if (typeof value === 'string') return truncate(`"${value}"`, maxLength)
if (Array.isArray(value)) {
if (value.length === 0) return '[]'
return `Array(${value.length})`
}
if (typeof value === 'object') {
const keys = Object.keys(value)
if (keys.length === 0) return '{}'
return `{${keys.slice(0, 3).join(', ')}${keys.length > 3 ? ', ...' : ''}}`
}
return String(value)
}
/**
* Detect MIME type category
*/
export function getMimeCategory(mimeType: string): 'image' | 'text' | 'json' | 'binary' {
if (mimeType.startsWith('image/')) return 'image'
if (mimeType.includes('json')) return 'json'
if (mimeType.startsWith('text/') || mimeType.includes('xml')) return 'text'
return 'binary'
}
/**
* Get HTTP status category
*/
export function getHttpStatusCategory(status: number): 'info' | 'success' | 'redirect' | 'client-error' | 'server-error' {
if (status < 200) return 'info'
if (status < 300) return 'success'
if (status < 400) return 'redirect'
if (status < 500) return 'client-error'
return 'server-error'
}
/**
* Get color for HTTP status
*/
export function getHttpStatusColor(status: number): string {
const category = getHttpStatusCategory(status)
switch (category) {
case 'success': return 'positive'
case 'redirect': return 'info'
case 'client-error': return 'warning'
case 'server-error': return 'negative'
default: return 'grey'
}
}