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

visgl / loaders.gl / 24153816851

08 Apr 2026 07:17PM UTC coverage: 53.247% (-12.1%) from 65.319%
24153816851

push

github

web-flow
chore: Move from tape to vitest (#3351)

8651 of 17291 branches covered (50.03%)

Branch coverage included in aggregate %.

7 of 7 new or added lines in 1 file covered. (100.0%)

2031 existing lines in 296 files now uncovered.

17563 of 31940 relevant lines covered (54.99%)

5279.54 hits per line

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

54.79
/modules/zip/src/parse-zip/readable-file-utils.ts
1
// loaders.gl
2
// SPDX-License-Identifier: MIT
3
// Copyright (c) vis.gl contributors
4

5
import {copyToArrayBuffer, type ReadableFile, type Stat} from '@loaders.gl/loader-utils';
6

7
function toBigInt(value: number | bigint): bigint {
8
  return typeof value === 'bigint' ? value : BigInt(value);
510!
9
}
10

11
function toNumber(value: number | bigint): number {
12
  const numberValue = Number(value);
434✔
13
  if (!Number.isFinite(numberValue)) {
434!
UNCOV
14
    throw new Error('Offset is out of bounds');
×
15
  }
16
  return numberValue;
434✔
17
}
18

19
function normalizeOffset(offset: number, size: number): number {
20
  if (offset < 0) {
388!
UNCOV
21
    return Math.max(size + offset, 0);
×
22
  }
23
  return Math.min(offset, size);
388✔
24
}
25

26
/**
27
 * Read a byte range from a readable file.
28
 * @param file readable file handle
29
 * @param start inclusive start offset
30
 * @param end exclusive end offset
31
 * @returns requested slice
32
 */
33
export async function readRange(
34
  file: ReadableFile,
35
  start: number | bigint,
36
  end: number | bigint
37
): Promise<ArrayBuffer> {
38
  const startOffset = toBigInt(start);
240✔
39
  const endOffset = toBigInt(end);
240✔
40
  const length = endOffset - startOffset;
240✔
41
  if (length < 0) {
240!
42
    throw new Error('Invalid range requested');
×
43
  }
44
  return await file.read(startOffset, toNumber(length));
240✔
45
}
46

47
export async function readDataView(
48
  file: ReadableFile,
49
  start: number | bigint,
50
  end: number | bigint
51
): Promise<DataView> {
52
  const arrayBuffer = await readRange(file, start, end);
85✔
53
  return new DataView(arrayBuffer);
85✔
54
}
55

56
export async function readUint8(file: ReadableFile, offset: number | bigint): Promise<number> {
UNCOV
57
  const dataView = await readDataView(file, offset, toBigInt(offset) + 1n);
×
UNCOV
58
  return dataView.getUint8(0);
×
59
}
60

61
export async function readUint16(file: ReadableFile, offset: number | bigint): Promise<number> {
62
  const dataView = await readDataView(file, offset, toBigInt(offset) + 2n);
10✔
63
  return dataView.getUint16(0, true);
10✔
64
}
65

66
export async function readUint32(file: ReadableFile, offset: number | bigint): Promise<number> {
67
  const dataView = await readDataView(file, offset, toBigInt(offset) + 4n);
20✔
68
  return dataView.getUint32(0, true);
20✔
69
}
70

71
export async function readBigUint64(file: ReadableFile, offset: number | bigint): Promise<bigint> {
UNCOV
72
  const dataView = await readDataView(file, offset, toBigInt(offset) + 8n);
×
UNCOV
73
  return dataView.getBigUint64(0, true);
×
74
}
75

76
/**
77
 * Resolve the size of a readable file.
78
 * @param file readable file handle
79
 * @returns file size as bigint
80
 */
81
export async function getReadableFileSize(file: ReadableFile): Promise<bigint> {
82
  if (file.bigsize > 0n) {
54!
83
    return file.bigsize;
54✔
84
  }
UNCOV
85
  if (file.size > 0) {
×
UNCOV
86
    return BigInt(file.size);
×
87
  }
88
  if (file.stat) {
×
89
    const stats: Stat = await file.stat();
×
90
    if (stats?.bigsize !== undefined) {
×
91
      return stats.bigsize;
×
92
    }
UNCOV
93
    if (stats?.size !== undefined) {
×
UNCOV
94
      return BigInt(stats.size);
×
95
    }
96
  }
UNCOV
97
  return 0n;
×
98
}
99

100
/**
101
 * Minimal readable file backed by a DataView.
102
 */
103
export class DataViewReadableFile implements ReadableFile {
104
  readonly handle: DataView;
105
  readonly size: number;
106
  readonly bigsize: bigint;
107
  readonly url: string;
108

109
  constructor(dataView: DataView, url: string = '') {
28✔
110
    this.handle = dataView;
28✔
111
    this.size = dataView.byteLength;
28✔
112
    this.bigsize = BigInt(dataView.byteLength);
28✔
113
    this.url = url;
28✔
114
  }
115

116
  async close(): Promise<void> {}
117

118
  async stat(): Promise<Stat> {
119
    return {size: this.size, bigsize: this.bigsize, isDirectory: false};
×
120
  }
121

122
  async read(start: number | bigint = 0, length?: number): Promise<ArrayBuffer> {
194✔
123
    const offset = toNumber(start);
194✔
124
    const end = length ? offset + length : this.size;
194!
125
    const normalizedStart = normalizeOffset(offset, this.size);
194✔
126
    const normalizedEnd = normalizeOffset(end, this.size);
194✔
127
    const clampedEnd = Math.max(normalizedEnd, normalizedStart);
194✔
128
    const lengthToRead = clampedEnd - normalizedStart;
194✔
129
    if (lengthToRead <= 0) {
194!
130
      return new ArrayBuffer(0);
×
131
    }
132
    return copyToArrayBuffer(this.handle.buffer, normalizedStart, lengthToRead);
194✔
133
  }
134
}
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