• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

flyingsquirrel0419 / layercache / 24609566478

18 Apr 2026 05:03PM UTC coverage: 95.411% (+0.09%) from 95.325%
24609566478

Pull #14

github

web-flow
Merge 6839074ab into 418da5d2a
Pull Request #14: Fix key display formatting and sync docs

1608 of 1729 branches covered (93.0%)

Branch coverage included in aggregate %.

52 of 53 new or added lines in 7 files covered. (98.11%)

1 existing line in 1 file now uncovered.

2862 of 2956 relevant lines covered (96.82%)

261.71 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.09
/src/internal/CacheKeySerialization.ts
1
import type { CacheGetOptions } from '../types'
2

3
export const DANGEROUS_OBJECT_KEYS = new Set(['__proto__', 'prototype', 'constructor'])
12✔
4

5
function isPrimitive(value: unknown): value is string | number | boolean | null | undefined {
6
  return (
47✔
7
    value === null ||
193✔
8
    value === undefined ||
9
    typeof value === 'string' ||
10
    typeof value === 'number' ||
11
    typeof value === 'boolean'
12
  )
13
}
14

15
export function normalizeForSerialization(value: unknown): unknown {
16
  if (isPrimitive(value)) {
23✔
17
    return value
10✔
18
  }
19

20
  if (Array.isArray(value)) {
13✔
21
    const length = value.length
4✔
22
    let changed = false
4✔
23
    const mapped: unknown[] = new Array(length)
4✔
24
    for (let i = 0; i < length; i++) {
4✔
25
      const entry = value[i]
8✔
26
      if (isPrimitive(entry)) {
8✔
27
        mapped[i] = entry
6✔
28
      } else {
29
        changed = true
2✔
30
        mapped[i] = normalizeForSerialization(entry)
2✔
31
      }
32
    }
33
    return changed ? mapped : value
4✔
34
  }
35

36
  if (value && typeof value === 'object') {
9!
37
    const source = value as Record<string, unknown>
9✔
38
    const keys = Object.keys(source)
9✔
39
    const length = keys.length
9✔
40

41
    let needsSort = false
9✔
42
    let needsFilter = false
9✔
43
    let needsRecurse = false
9✔
44

45
    for (let i = 0; i < length; i++) {
9✔
46
      const key = keys[i]
18✔
47
      if (key === undefined) continue
18!
48
      if (DANGEROUS_OBJECT_KEYS.has(key)) {
18✔
49
        needsFilter = true
2✔
50
        continue
2✔
51
      }
52
      if (!isPrimitive(source[key])) {
16✔
53
        needsRecurse = true
3✔
54
      }
55
      const prev = keys[i - 1]
16✔
56
      if (i > 0 && prev !== undefined && prev > key) {
16✔
57
        needsSort = true
4✔
58
      }
59
    }
60

61
    if (!needsSort && !needsFilter && !needsRecurse) {
9✔
62
      return { ...source }
4✔
63
    }
64

65
    return keys.sort().reduce<Record<string, unknown>>((normalized, key) => {
5✔
66
      if (DANGEROUS_OBJECT_KEYS.has(key)) {
12✔
67
        return normalized
2✔
68
      }
69
      normalized[key] = normalizeForSerialization(source[key])
10✔
70
      return normalized
10✔
71
    }, {})
72
  }
73

UNCOV
74
  return value
×
75
}
76

77
export function serializeKeyPart(value: unknown): string {
78
  if (typeof value === 'string') {
13✔
79
    return `s:${value.replace(/%/g, '%25').replace(/:/g, '%3A')}`
2✔
80
  }
81

82
  if (typeof value === 'number') {
11✔
83
    return `n:${value}`
9✔
84
  }
85

86
  if (typeof value === 'boolean') {
2✔
87
    return `b:${value}`
1✔
88
  }
89

90
  return `j:${JSON.stringify(normalizeForSerialization(value))}`
1✔
91
}
92

93
export function serializeOptions(options: CacheGetOptions | undefined): string {
94
  return JSON.stringify(normalizeForSerialization(options) ?? null)
6✔
95
}
96

97
export function createInstanceId(): string {
98
  if (globalThis.crypto?.randomUUID) {
226✔
99
    return globalThis.crypto.randomUUID()
224✔
100
  }
101

102
  if (globalThis.crypto?.getRandomValues) {
2✔
103
    const bytes = new Uint8Array(16)
1✔
104
    globalThis.crypto.getRandomValues(bytes)
1✔
105
    return `layercache-${Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('')}`
16✔
106
  }
107

108
  throw new Error(
1✔
109
    'layercache requires a cryptographic random source. ' +
110
      'Neither crypto.randomUUID nor crypto.getRandomValues is available in this runtime.'
111
  )
112
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc