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

Haixing-Hu / js-common-app / 212a9a35-98c1-4add-953c-8ba48cb4fe1e

19 Feb 2025 06:04PM UTC coverage: 55.795% (+0.02%) from 55.78%
212a9a35-98c1-4add-953c-8ba48cb4fe1e

push

circleci

Haixing-Hu
refactor: refactor

127 of 229 branches covered (55.46%)

Branch coverage included in aggregate %.

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

8 existing lines in 1 file now uncovered.

287 of 513 relevant lines covered (55.95%)

10.48 hits per line

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

19.64
/src/impl/parse-response-data-as-blob.js
1
////////////////////////////////////////////////////////////////////////////////
2
//
3
//    Copyright (c) 2022 - 2025.
4
//    Haixing Hu, Qubit Co. Ltd.
5
//
6
//    All rights reserved.
7
//
8
////////////////////////////////////////////////////////////////////////////////
9
import { Logger } from '@qubit-ltd/logging';
10

11
const BUFFER_SIZE = 1024;
5✔
12

13
const logger = Logger.getLogger('http');
5✔
14

15
/**
16
 * 将 base64 编码的字符串解码为字节数组。
17
 *
18
 * @param {string} base64String
19
 *     base64 编码的字符串。
20
 * @return {Uint8Array[]}
21
 *     解码后的字节数组列表。
22
 * @private
23
 */
24
function decodeBase64ToByteArrays(base64String) {
25
  logger.debug('Starting base64 decoding, input data length:', base64String.length);
×
26
  const byteCharacters = atob(base64String); // 解码 base64 数据
×
27
  logger.debug('Base64 decoded to raw bytes, length:', byteCharacters.length);
×
28
  const byteArrays = [];
×
29
  for (let offset = 0; offset < byteCharacters.length; offset += BUFFER_SIZE) {
×
30
    const slice = byteCharacters.slice(offset, offset + BUFFER_SIZE);
×
31
    const byteNumbers = new Array(slice.length);
×
32
    for (let i = 0; i < slice.length; i++) {
×
33
      byteNumbers[i] = slice.charCodeAt(i);
×
34
    }
35
    byteArrays.push(new Uint8Array(byteNumbers));
×
36
    logger.debug('Processed chunk', byteArrays.length, 'of size:', slice.length, 'bytes');
×
37
  }
38
  logger.debug('Base64 decoding completed, total chunks:', byteArrays.length);
×
39
  return byteArrays;
×
40
}
41

42
/**
43
 * 尝试将 base64 编码的数据转换为 Blob 对象。
44
 *
45
 * @param {string} data
46
 *     要转换的数据。
47
 * @param {string} contentType
48
 *     Blob 对象的 MIME 类型。
49
 * @return {Blob}
50
 *     转换后的 Blob 对象。如果转换失败,则返回包含原始数据的 Blob 对象。
51
 * @private
52
 */
53
function tryConvertBase64ToBlob(data, contentType) {
54
  try {
×
55
    logger.debug('Converting base64 to blob, data length:', data.length);
×
56
    const byteArrays = decodeBase64ToByteArrays(data);
×
57
    logger.debug('Base64 conversion successful, total byte arrays:', byteArrays.length);
×
58
    return new Blob(byteArrays, { type: contentType });
×
59
  } catch (e) {
60
    logger.error('Base64 conversion failed, falling back to plain text. Error:', e);
×
61
    return new Blob([data], { type: contentType });
×
62
  }
63
}
64

65
/**
66
 * 将 HTTP 响应数据解析为 Blob 对象。
67
 *
68
 * @param response
69
 *     HTTP 响应对象。
70
 * @param contentType
71
 *     Blob 对象的 MIME 类型。
72
 * @return {Blob}
73
 *     解析得到的 Blob 对象。
74
 */
75
function parseResponseDataAsBlob(response, contentType) {
76
  const data = response.data;
7✔
77
  if (data === null || data === undefined) {
7!
78
    logger.error('Response data is null or undefined, creating empty blob');
×
79
    return new Blob([], { type: contentType });
×
80
  }
81
  // If data is already a Blob, return it directly
82
  if (data instanceof Blob) {
7!
83
    logger.debug('Data is already a Blob, returning it directly');
7✔
84
    return data;
7✔
85
  }
86
  // Case 1: Binary data
UNCOV
87
  if (typeof data !== 'string') {
×
UNCOV
88
    const dataType = typeof data;
×
UNCOV
89
    const className = data?.constructor?.name ?? 'unknown';
×
UNCOV
90
    logger.debug('Processing binary data - Type: %s, Class: %s, MIME type: %s',
×
91
      dataType,
92
      className,
93
      contentType || 'unknown');
×
94
    return new Blob([data], { type: contentType });
×
95
  }
96

97
  // Case 2: Data URL format
98
  if (data.startsWith('data:')) {
×
99
    logger.debug('Processing Data URL format');
×
100
    const commaIndex = data.indexOf(',');
×
101
    const base64Data = data.substring(commaIndex + 1);
×
UNCOV
102
    logger.debug('Extracted base64 data, length:', base64Data.length);
×
UNCOV
103
    return tryConvertBase64ToBlob(base64Data, contentType);
×
104
  }
105

106
  // // Case 3: Base64 data (quoted)
107
  // if (/^"[A-Za-z0-9+/=]+"$/.test(data)) {
108
  //   logger.debug('Processing base64 encoded data, length:', data.length);
109
  //   const base64Content = data.substring(1, data.length - 1);
110
  //   return tryConvertBase64ToBlob(base64Content, contentType);
111
  // }
112

113
  // // Case 4: Base64 data (unquoted)
114
  // if (/^[A-Za-z0-9+/=]+$/.test(data)) {
115
  //   logger.debug('Processing base64 encoded data, length:', data.length);
116
  //   return tryConvertBase64ToBlob(data, contentType);
117
  // }
118

119
  // Case 5: Plain text
UNCOV
120
  logger.debug('Processing plain text data, length:', data.length);
×
UNCOV
121
  return new Blob([data], { type: contentType });
×
122
}
123

124
export default parseResponseDataAsBlob;
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