@flun/mailer 2.1.24 → 2.1.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -45,8 +45,8 @@ const defaultMimeType = 'application/octet-stream', defaultExtension = 'bin',
45
45
  };
46
46
 
47
47
  /**
48
- * 检查值是否为纯文本字符串(仅使用可打印的7位字符)
49
- * 允许的控制字符:\x09(制表符)、\x0a(换行符)、\x0d(回车符)、可打印ASCII(\x20-\x7e)
48
+ * 检查值是否为纯文本字符串(仅使用可打印的7位字符)
49
+ * 允许的控制字符:\x09(制表符)、\x0a(换行符)、\x0d(回车符)、可打印ASCII(\x20-\x7e)
50
50
  * 排除: 其他控制字符和DEL,非ASCII字符
51
51
  * >查看定义:@see {@link isPlainText}
52
52
  * @param {String} value 要测试的字符串
@@ -54,16 +54,16 @@ const defaultMimeType = 'application/octet-stream', defaultExtension = 'bin',
54
54
  * @returns {Boolean} 如果是纯文本字符串则返回true
55
55
  */
56
56
  const isPlainText = (value, isParam) => {
57
- // 如果是参数,则允许双引号,否则不允许
57
+ // 如果是参数,则允许双引号,否则不允许
58
58
  const re = isParam ? regexs.PARAM_PLAIN_TEXT : regexs.PLAIN_TEXT;
59
59
  return typeof value === 'string' && !re.test(value);
60
60
  },
61
61
 
62
62
  /**
63
- * 拆分MIME编码的字符串。用于将MIME字分成更小的块
63
+ * 拆分MIME编码的字符串;用于将MIME字分成更小的块
64
64
  *
65
65
  * @param {String} str 要拆分的MIME编码字符串
66
- * @param {Number} maxlen 一个部分的最大字符长度(最小12)
66
+ * @param {Number} maxlen 一个部分的最大字符长度(最小12)
67
67
  * @return {Array} 拆分后的字符串
68
68
  */
69
69
  _splitMimeEncodedString = (str = '', maxlen) => {
@@ -82,7 +82,7 @@ const isPlainText = (value, isParam) => {
82
82
  // 检查是否不在Unicode字符序列的中间
83
83
  if ((match = str.substring(curLine.length).match(regexs.ENCODED_SEQUENCE))) {
84
84
  chr = parseInt(match[1], 16);
85
- // 无效序列,向后移动一个字符并重新检查
85
+ // 无效序列,向后移动一个字符并重新检查
86
86
  if (chr < 0xc2 && chr > 0x7f) curLine = curLine.substring(0, curLine.length - 3), done = false;
87
87
  }
88
88
  }
@@ -95,8 +95,8 @@ const isPlainText = (value, isParam) => {
95
95
  },
96
96
 
97
97
  /**
98
- * 将字符串或Buffer编码为UTF-8参数值连续编码(rfc2231)
99
- * 用于拆分长参数值。
98
+ * 将字符串或Buffer编码为UTF-8参数值连续编码(rfc2231)
99
+ * 用于拆分长参数值;
100
100
  *
101
101
  * 例如
102
102
  * title="unicode string"
@@ -121,19 +121,20 @@ const isPlainText = (value, isParam) => {
121
121
  return '';
122
122
  });
123
123
 
124
- if (encodedStr) list.push({ line: encodedStr }); // 如果最后一个字符串不为空,则将其推送到数组中
124
+ if (encodedStr) list.push({ line: encodedStr }); // 如果最后一个字符串不为空,则将其推送到数组中
125
125
  }
126
- // 否则,如果字符串包含Unicode或特殊字符,则将其拆分为多个块
126
+ // 否则,如果字符串包含Unicode或特殊字符,则将其拆分为多个块
127
127
  else {
128
128
  let chr, i, len, line = "utf-8''", encoded = true, startPos = 0;
129
- // 如果字符串包含代理对,则将其规范化为字符数组
129
+ // 如果字符串包含代理对,则将其规范化为字符数组
130
130
  if (regexs.UTF16_HIGH_SURROGATE.test(encodedStr)) {
131
131
  const encodedStrArr = [];
132
132
  for (i = 0, len = encodedStr.length; i < len; i++) {
133
133
  chr = encodedStr.charAt(i);
134
134
  const ord = chr.charCodeAt(0);
135
- // 如果字符是代理对的第一个字符,则将其与第二个字符一起添加到数组中
136
- if (ord >= 0xd800 && ord <= 0xdbff && i < len - 1) chr += encodedStr.charAt(i + 1), encodedStrArr.push(chr), i++;
135
+ // 如果字符是代理对的第一个字符,则将其与第二个字符一起添加到数组中
136
+ if (ord >= 0xd800 && ord <= 0xdbff && i < len - 1) chr += encodedStr.charAt(i + 1),
137
+ encodedStrArr.push(chr), i++;
137
138
  else encodedStrArr.push(chr); // 否则,将其添加到数组中
138
139
  }
139
140
  encodedStr = encodedStrArr
@@ -143,13 +144,13 @@ const isPlainText = (value, isParam) => {
143
144
  for (i = 0; i < encodedStr.length; i++) {
144
145
  chr = encodedStr[i];
145
146
  const encodedChr = _safeEncodeURIComponent(chr);
146
- if (encoded) chr = encodedChr; // 如果需要编码,则对当前字符进行URL编码
147
+ if (encoded) chr = encodedChr; // 如果需要编码,则对当前字符进行URL编码
147
148
  else {
148
149
  chr = chr === ' ' ? chr : encodedChr; // 尝试对当前字符进行URL编码
149
- // 默认情况下不需要编码行,只有当字符串包含Unicode或特殊字符时才需要
150
+ // 默认情况下不需要编码行,只有当字符串包含Unicode或特殊字符时才需要
150
151
  if (chr !== encodedStr[i]) {
151
152
  // 检查是否可以将编码字符添加到行中
152
- // 如果不能,则没有理由使用此行,只需将其推送到列表,并开始新行处理需要编码的字符
153
+ // 如果不能,则没有理由使用此行,只需将其推送到列表,并开始新行处理需要编码的字符
153
154
  if ((_safeEncodeURIComponent(line) + chr).length >= maxLength)
154
155
  list.push({ line, encoded }), line = '', startPos = i - 1;
155
156
  else {
@@ -159,25 +160,26 @@ const isPlainText = (value, isParam) => {
159
160
  }
160
161
  }
161
162
 
162
- // 如果行已经太长,将其推送到列表并开始新行
163
+ // 如果行已经太长,将其推送到列表并开始新行
163
164
  if ((line + chr).length >= maxLength) {
164
- list.push({ line, encoded }), line = chr = encodedStr[i] === ' ' ? ' ' : _safeEncodeURIComponent(encodedStr[i]);
165
- // 如果添加的字符不需要编码,则将编码设置为false,并继续处理下一个字符;否则设为需要编码
165
+ list.push({ line, encoded }),
166
+ line = chr = encodedStr[i] === ' ' ? ' ' : _safeEncodeURIComponent(encodedStr[i]);
167
+ // 如果添加的字符不需要编码,则将编码设置为false,并继续处理下一个字符;否则设为需要编码
166
168
  chr === encodedStr[i] ? (encoded = false, startPos = i - 1) : encoded = true;
167
169
  }
168
- else line += chr; // 否则,将字符添加到行中
170
+ else line += chr; // 否则,将字符添加到行中
169
171
  }
170
172
 
171
- if (line) list.push({ line, encoded }); // 如果最后一行不为空,则将其推送到列表中
173
+ if (line) list.push({ line, encoded }); // 如果最后一行不为空,则将其推送到列表中
172
174
  }
173
175
 
174
- // 如果任何行需要编码,则第一行(part==0)总是编码的
176
+ // 如果任何行需要编码,则第一行(part==0)总是编码的
175
177
  return list.map((item, i) => ({ key: `${key}*${i}${(item.encoded ? '*' : '')}`, value: item.line }));
176
178
  },
177
179
 
178
180
  /**
179
181
  * 处理 RFC2231 编码的参数
180
- * 将拆分的rfc2231字符串合并到单个键中,并进行解码
182
+ * 将拆分的rfc2231字符串合并到单个键中,并进行解码
181
183
  * @param {Object} params 参数对象
182
184
  */
183
185
  _processRFC2231Params = params => {
@@ -186,7 +188,8 @@ const isPlainText = (value, isParam) => {
186
188
  let match, value;
187
189
  if ((match = key.match(regexs.RFC2231_KEY))) {
188
190
  const actualKey = key.substring(0, match.index), nr = Number(match[2] || match[3]) || 0;
189
- if (!params[actualKey] || typeof params[actualKey] !== 'object') params[actualKey] = { charset: false, values: [] };
191
+ if (!params[actualKey] || typeof params[actualKey] !== 'object')
192
+ params[actualKey] = { charset: false, values: [] };
190
193
 
191
194
  value = params[key];
192
195
  if (nr === 0 && match[0].endsWith('*') && (match = value.match(regexs.CHARSET_LANGUAGE_VALUE)))
@@ -217,7 +220,7 @@ const isPlainText = (value, isParam) => {
217
220
 
218
221
  /**
219
222
  * 检查多行字符串是否包含超过指定长度的行
220
- * 如果值是纯文本但有超过允许长度的行,则使用format=flowed
223
+ * 如果值是纯文本但有超过允许长度的行,则使用format=flowed
221
224
  * >查看定义:@see {@link hasLongerLines}
222
225
  * @param {String} str 要检查的字符串(不检查超过128kB的字符串)
223
226
  * @param {Number} lineLength 要检查的最大行长度
@@ -231,8 +234,8 @@ const hasLongerLines = (str, lineLength) => {
231
234
  * 将字符串或Buffer编码为UTF-8 MIME字(rfc2047)
232
235
  * >查看定义:@see {@link encodeWord}
233
236
  * @param {String|Buffer} data 要编码的字符串
234
- * @param {String} mimeWordEncoding='Q' MIME字的编码,Q或B
235
- * @param {Number} [maxLength=0] 如果设置,根据需要将MIME字拆分为多个块
237
+ * @param {String} mimeWordEncoding='Q' MIME字的编码,Q或B
238
+ * @param {Number} [maxLength=0] 如果设置,根据需要将MIME字拆分为多个块
236
239
  * @return {String} 单个或多个连接在一起的MIME字
237
240
  */
238
241
  const encodeWord = (data, mimeWordEncoding = "Q", maxLength = 0) => {
@@ -242,15 +245,15 @@ const encodeWord = (data, mimeWordEncoding = "Q", maxLength = 0) => {
242
245
  const toCharset = 'UTF-8', offset = 7 + toCharset.length;
243
246
  maxLength && maxLength > offset && (maxLength -= offset);
244
247
 
245
- // 如果mimeWordEncoding为Q,则使用qp编码,否则使用base64编码
248
+ // 如果mimeWordEncoding为Q,则使用qp编码,否则使用base64编码
246
249
  if (newMWE === 'Q') {
247
250
  const rNSC = resetRegex(regexs.NON_SAFE_CHAR);
248
251
  encodedStr = qpEncode(data).replace(rNSC, chr => {
249
252
  const ord = chr.charCodeAt(0).toString(16).toUpperCase(), XX = ord.length === 1 ? `0${ord}` : ord
250
- return chr === ' ' ? '_' : `=${XX}`;// 如果字符是空格,则使用_;否则使用=XX
253
+ return chr === ' ' ? '_' : `=${XX}`;// 如果字符是空格,则使用_;否则使用=XX
251
254
  });
252
255
  }
253
- // 否则如果mimeWordEncoding为B,则使用base64编码
256
+ // 否则如果mimeWordEncoding为B,则使用base64编码
254
257
  else if (newMWE === 'B') {
255
258
  encodedStr = typeof data === 'string' ? data : base64Encode(data);
256
259
  maxLength = maxLength ? Math.max(3, ((maxLength - (maxLength % 4)) / 4) * 3) : 0;
@@ -264,16 +267,16 @@ const encodeWord = (data, mimeWordEncoding = "Q", maxLength = 0) => {
264
267
  let lpart = '';
265
268
  for (let i = 0, len = encodedStr.length; i < len; i++) {
266
269
  let chr = encodedStr.charAt(i);
267
- // 如果字符是emoji,则将下一个字符也添加到字符串中
270
+ // 如果字符是emoji,则将下一个字符也添加到字符串中
268
271
  if (regexs.EMOJI_OR_SURROGATE.test(chr) && i < len - 1) chr += encodedStr.charAt(++i);
269
272
 
270
- // 如果字符串加上当前字符的长度超过最大长度,则将字符串推送到数组中,并开始一个新的字符串
273
+ // 如果字符串加上当前字符的长度超过最大长度,则将字符串推送到数组中,并开始一个新的字符串
271
274
  if (Buffer.byteLength(lpart + chr) <= maxLength || i === 0) lpart += chr;
272
- else parts.push(base64Encode(lpart)), lpart = chr; // 达到长度限制,推送现有字符串并重新开始
275
+ else parts.push(base64Encode(lpart)), lpart = chr; // 达到长度限制,推送现有字符串并重新开始
273
276
  }
274
- if (lpart) parts.push(base64Encode(lpart)); // 如果最后一个字符串不为空,则将其推送到数组中
277
+ if (lpart) parts.push(base64Encode(lpart)); // 如果最后一个字符串不为空,则将其推送到数组中
275
278
 
276
- // 如果有多个字符串,则将它们连接到一起,并用分隔符分隔;否则,如果只有一个字符串,则将其返回
279
+ // 如果有多个字符串,则将它们连接到一起,并用分隔符分隔;否则,如果只有一个字符串,则将其返回
277
280
  encodedStr = parts.length > 1 ? parts.join(delimiter) : parts.join('');
278
281
  }
279
282
  }
@@ -285,20 +288,21 @@ const encodeWord = (data, mimeWordEncoding = "Q", maxLength = 0) => {
285
288
  * 查找包含非ASCII文本的单词序列并将其转换为MIME字
286
289
  * >查看定义:@see {@link encodeWords}
287
290
  * @param {String} value 要编码的字符串
288
- * @param {String} mimeWordEncoding='Q' MIME字的编码,Q或B
289
- * @param {Number} [maxLength=0] 如果设置,根据需要将MIME字拆分为多个块
290
- * @param {Boolean} [encodeAll=false] 如果为true且值需要编码,则编码整个字符串,而不仅仅是最小匹配
291
+ * @param {String} mimeWordEncoding='Q' MIME字的编码,Q或B
292
+ * @param {Number} [maxLength=0] 如果设置,根据需要将MIME字拆分为多个块
293
+ * @param {Boolean} [encodeAll=false] 如果为true且值需要编码,则编码整个字符串,而不仅仅是最小匹配
291
294
  * @return {String} 可能包含MIME字的字符串
292
295
  */
293
296
  const encodeWords = (value, mimeWordEncoding = "Q", maxLength = 0, encodeAll) => {
294
- // 查找第一个和最后一个是否包含不可打印ASCII或特殊符号的单词,如果找不到,则返回原始值
297
+ // 查找第一个和最后一个是否包含不可打印ASCII或特殊符号的单词,如果找不到,则返回原始值
295
298
  const firstMatch = value.match(regexs.FIRST_NON_ASCII_WORD), lastMatch = value.match(regexs.LAST_NON_ASCII_WORD);
296
299
  if (!firstMatch || !lastMatch) return value;
297
- // 如果请求编码所有内容或字符串包含类似编码字的内容,则返回编码后的所有内容
300
+ // 如果请求编码所有内容或字符串包含类似编码字的内容,则返回编码后的所有内容
298
301
  if (encodeAll) return encodeWord(value, mimeWordEncoding, maxLength);
299
302
 
300
303
  const startIndex = firstMatch.index + firstMatch[0].length - firstMatch[0].trimStart().length,
301
- endIndex = lastMatch.index + (lastMatch[1] || '').length, startStr = startIndex ? value.substring(0, startIndex) : '',
304
+ endIndex = lastMatch.index + (lastMatch[1] || '').length,
305
+ startStr = startIndex ? value.substring(0, startIndex) : '',
302
306
  endStr = endIndex < value.length ? value.substring(endIndex) : '',
303
307
  eWord = encodeWords(value.substring(startIndex, endIndex), mimeWordEncoding, maxLength);
304
308
  return `${startStr}${eWord}${endStr}`;
@@ -307,8 +311,8 @@ const encodeWords = (value, mimeWordEncoding = "Q", maxLength = 0, encodeAll) =>
307
311
  /**
308
312
  * 将解析后的头值连接为 'value; param1=value1; param2=value2';
309
313
  * >查看定义:@see {@link buildHeaderValue}
310
- * - 注意:我们遵循RFC 822来维护需要放在引号中的特殊字符列表;
311
- * 参考:https://www.w3.org/Protocols/rfc1341/4_Content-Type.html
314
+ * - 注意:我们遵循RFC 822来维护需要放在引号中的特殊字符列表;
315
+ * 参考:https://www.w3.org/Protocols/rfc1341/4_Content-Type.html
312
316
  * @param {Object} structured 解析后的头值
313
317
  * @return {String} 连接后的头值
314
318
  */
@@ -316,7 +320,7 @@ const buildHeaderValue = structured => {
316
320
  const paramsArray = [];
317
321
  Object.keys(structured.params || {}).forEach(param => {
318
322
  const pValue = structured.params[param];
319
- // 如果值是纯文本字符串,则将其编码为MIME字
323
+ // 如果值是纯文本字符串,则将其编码为MIME字
320
324
  if (!isPlainText(pValue, true) || pValue.length >= 75) {
321
325
  _buildHeaderParam(param, pValue, 50).forEach(encodedParam => {
322
326
  const { key, value } = encodedParam;
@@ -325,7 +329,7 @@ const buildHeaderValue = structured => {
325
329
  else paramsArray.push(`${key}=${JSON.stringify(value)}`); // 否则将参数编码为JSON字符串
326
330
  });
327
331
  }
328
- // 否则如果值是纯文本字符串,则将其编码为JSON字符串
332
+ // 否则如果值是纯文本字符串,则将其编码为JSON字符串
329
333
  else if (regexs.UNSAFE_PARAM_VALUE.test(pValue)) paramsArray.push(`${param}=${JSON.stringify(pValue)}`);
330
334
  else paramsArray.push(`${param}=${pValue}`); // 否则,如果值是安全的,则将其编码为MIME字
331
335
  });
@@ -346,7 +350,7 @@ const buildHeaderValue = structured => {
346
350
  */
347
351
  const parseHeaderValue = str => {
348
352
  const result = { value: '', params: {} };
349
- if (!str || typeof str !== 'string') return result; // 输入验证:如果输入为空或不是字符串,直接返回空结果
353
+ if (!str || typeof str !== 'string') return result; // 输入验证:如果输入为空或不是字符串,直接返回空结果
350
354
 
351
355
  // 当前解析状态,正在解析的参数键名,正在解析的值,引号字符,是否处于转义状态
352
356
  let state = 'value', currentKey = '', currentValue = '', quoteChar = '', escaped = false;
@@ -354,7 +358,7 @@ const parseHeaderValue = str => {
354
358
  for (let i = 0; i < str.length; i++) {
355
359
  const char = str[i];
356
360
 
357
- // 处理转义字符:如果前一个字符是\,当前字符直接加入值,不进行特殊处理
361
+ // 处理转义字符:如果前一个字符是\,当前字符直接加入值,不进行特殊处理
358
362
  if (escaped) {
359
363
  currentValue += char, escaped = false;
360
364
  continue;
@@ -362,16 +366,16 @@ const parseHeaderValue = str => {
362
366
 
363
367
  // 根据当前状态处理字符
364
368
  switch (state) {
365
- case 'value': // 解析主值部分(如:text/plain)
366
- // 如果遇到分号,保存主值(去除前后空格),重置当前值,切换到键解析状态
369
+ case 'value': // 解析主值部分(如:text/plain)
370
+ // 如果遇到分号,保存主值(去除前后空格),重置当前值,切换到键解析状态
367
371
  if (char === ';') result.value = currentValue.trim(), currentValue = '', state = 'key';
368
372
  else if (char === '\\') escaped = true; // 遇到反斜杠设置转义为真
369
- else currentValue += char; // 普通字符:直接添加到当前值
373
+ else currentValue += char; // 普通字符:直接添加到当前值
370
374
  break;
371
- case 'key': // 解析参数键名(如:charset)
375
+ case 'key': // 解析参数键名(如:charset)
372
376
  if (char === '=') currentKey = currentValue.trim().toLowerCase(), currentValue = '', state = 'value';
373
377
  else if (char === ';') {
374
- // 遇到分号但没有等号如:;flag
378
+ // 遇到分号但没有等号如:;flag
375
379
  if (currentValue.trim()) result.params[currentValue.trim().toLowerCase()] = ''; // 保存空值参数
376
380
  currentValue = '';
377
381
  }
@@ -384,11 +388,11 @@ const parseHeaderValue = str => {
384
388
  break;
385
389
  }
386
390
 
387
- // 检查是否需要进入引号状态(不在转义状态下)
391
+ // 检查是否需要进入引号状态(不在转义状态下)
388
392
  if (!escaped && (char === '"' || char === "'") && state !== 'quoted') quoteChar = char, state = 'quoted';
389
393
  }
390
394
 
391
- const finalValue = currentValue.trim(); // 循环结束后,处理最后剩余的值
395
+ const finalValue = currentValue.trim(); // 循环结束后,处理最后剩余的值
392
396
  // 如果最后为值状态且有值
393
397
  if (state === 'value' && finalValue) {
394
398
  if (!result.value && !currentKey) result.value = finalValue; // 如果主值还未设置且没有当前键,设置为主值
@@ -397,7 +401,7 @@ const parseHeaderValue = str => {
397
401
  // 否则,如果最后在为键状态且有值,设置为空参数
398
402
  else if (state === 'key' && finalValue) result.params[finalValue.toLowerCase()] = '';
399
403
 
400
- _processRFC2231Params(result.params); // 处理 RFC2231 编码的参数(用于邮件头编码)
404
+ _processRFC2231Params(result.params); // 处理 RFC2231 编码的参数(用于邮件头编码)
401
405
  return result;
402
406
  };
403
407
 
@@ -408,15 +412,16 @@ const parseHeaderValue = str => {
408
412
  * @returns {string} 检测到的文件扩展名
409
413
  */
410
414
  const detectExtension = (mimeType = '') => {
411
- // 如果MIME类型为空,返回默认扩展名
415
+ // 如果MIME类型为空,返回默认扩展名
412
416
  if (!mimeType) return defaultExtension;
413
417
 
414
- // 处理MIME类型字符串:转换为小写,去除空格,按斜杠分割;获取主类型(如:application、text等)和子类型(处理包含斜杠的情况)
415
- const parts = mimeType.toLowerCase().trim().split('/'), rootType = parts.shift().trim(), subType = parts.join('/').trim(),
418
+ // 处理MIME类型字符串:转换为小写,去除空格,按斜杠分割;获取主类型(如:application、text等)和子类型(处理包含斜杠的情况)
419
+ const parts = mimeType.toLowerCase().trim().split('/'), rootType = parts.shift().trim(),
420
+ subType = parts.join('/').trim(),
416
421
  fullMimeType = `${rootType}/${subType}`; // 重新构建标准化的MIME类型字符串并查找对应的扩展名
417
422
  if (MIME_TYPES.has(fullMimeType)) {
418
423
  const value = MIME_TYPES.get(fullMimeType);
419
- return Array.isArray(value) ? value[0] : value; // 如果值是数组,返回第一个元素
424
+ return Array.isArray(value) ? value[0] : value; // 如果值是数组,返回第一个元素
420
425
  }
421
426
 
422
427
  // 根据主类型返回默认扩展名
@@ -433,15 +438,15 @@ const detectExtension = (mimeType = '') => {
433
438
  * @returns {string} 检测到的MIME类型
434
439
  */
435
440
  const detectMimeType = filename => {
436
- if (!filename) return defaultMimeType; // 如果文件名为空,返回默认MIME类型
441
+ if (!filename) return defaultMimeType; // 如果文件名为空,返回默认MIME类型
437
442
 
438
443
  const { ext, name = '' } = parse(filename), // 解析文件路径获取扩展名
439
- // 提取扩展名(去掉点号),处理查询参数,转换为小写
444
+ // 提取扩展名(去掉点号),处理查询参数,转换为小写
440
445
  extension = (ext.substring(1) || name).split('?').shift().trim().toLowerCase(),
441
446
 
442
- // 如果在扩展名映射表中找到对应项,则使用对应的MIME类型
447
+ // 如果在扩展名映射表中找到对应项,则使用对应的MIME类型
443
448
  value = EXTENSIONS.has(extension) ? EXTENSIONS.get(extension) : defaultMimeType;
444
- return Array.isArray(value) ? value[0] : value; // 如果值是数组,返回第一个元素;否则返回值
449
+ return Array.isArray(value) ? value[0] : value; // 如果值是数组,返回第一个元素;否则返回值
445
450
  };
446
451
 
447
452
  /**
@@ -449,7 +454,7 @@ const detectMimeType = filename => {
449
454
  * >查看定义:@see {@link foldLines}
450
455
  • @param {String} str 要折叠的字符串
451
456
  • @param {Number} [lineLength=76] 一行的最大长度
452
- • @param {Boolean} afterSpace 如果为true,在行尾留一个空格
457
+ • @param {Boolean} afterSpace 如果为true,在行尾留一个空格
453
458
  • @return {String} 带有折叠行的字符串
454
459
  */
455
460
  const foldLines = (str = '', lineLength = 76, afterSpace) => {
@@ -1102,7 +1102,8 @@ const EXTENSIONS = new Map([
1102
1102
  ['bdm', 'application/vnd.syncml.dm+wbxml'],
1103
1103
  ['bed', 'application/vnd.realvnc.bed'],
1104
1104
  ['bh2', 'application/vnd.fujitsu.oasysprs'],
1105
- ['bin', ['application/octet-stream', 'application/mac-binary', 'application/macbinary', 'application/x-macbinary', 'application/x-binary']],
1105
+ ['bin', ['application/octet-stream', 'application/mac-binary', 'application/macbinary', 'application/x-macbinary',
1106
+ 'application/x-binary']],
1106
1107
  ['bm', 'image/bmp'],
1107
1108
  ['bmi', 'application/vnd.bmi'],
1108
1109
  ['bmp', ['image/bmp', 'image/x-windows-bmp']],
@@ -1147,7 +1148,8 @@ const EXTENSIONS = new Map([
1147
1148
  ['cii', 'application/vnd.anser-web-certificate-issue-initiation'],
1148
1149
  ['cil', 'application/vnd.ms-artgalry'],
1149
1150
  ['cla', 'application/vnd.claymore'],
1150
- ['class', ['application/octet-stream', 'application/java', 'application/java-byte-code', 'application/java-vm', 'application/x-java-class']],
1151
+ ['class', ['application/octet-stream', 'application/java', 'application/java-byte-code', 'application/java-vm',
1152
+ 'application/x-java-class']],
1151
1153
  ['clkk', 'application/vnd.crick.clicker.keyboard'],
1152
1154
  ['clkp', 'application/vnd.crick.clicker.palette'],
1153
1155
  ['clkt', 'application/vnd.crick.clicker.template'],
@@ -1407,7 +1409,8 @@ const EXTENSIONS = new Map([
1407
1409
  ['jpgv', 'video/jpeg'],
1408
1410
  ['jpm', 'video/jpm'],
1409
1411
  ['jps', 'image/x-jps'],
1410
- ['js', ['application/javascript', 'application/ecmascript', 'text/javascript', 'text/ecmascript', 'application/x-javascript']],
1412
+ ['js', ['application/javascript', 'application/ecmascript', 'text/javascript', 'text/ecmascript',
1413
+ 'application/x-javascript']],
1411
1414
  ['json', 'application/json'],
1412
1415
  ['jut', 'image/jutvision'],
1413
1416
  ['kar', ['audio/midi', 'music/x-karaoke']],
@@ -1484,7 +1487,8 @@ const EXTENSIONS = new Map([
1484
1487
  ['mgz', 'application/vnd.proteus.magazine'],
1485
1488
  ['mht', 'message/rfc822'],
1486
1489
  ['mhtml', 'message/rfc822'],
1487
- ['mid', ['audio/mid', 'audio/midi', 'music/crescendo', 'x-music/x-midi', 'audio/x-midi', 'application/x-midi', 'audio/x-mid']],
1490
+ ['mid', ['audio/mid', 'audio/midi', 'music/crescendo', 'x-music/x-midi', 'audio/x-midi', 'application/x-midi',
1491
+ 'audio/x-mid']],
1488
1492
  ['midi', ['audio/midi', 'music/crescendo', 'x-music/x-midi', 'audio/x-midi', 'application/x-midi', 'audio/x-mid']],
1489
1493
  ['mif', ['application/vnd.mif', 'application/x-mif', 'application/x-frame']],
1490
1494
  ['mime', ['message/rfc822', 'www/mime']],
@@ -1669,7 +1673,8 @@ const EXTENSIONS = new Map([
1669
1673
  ['pps', ['application/vnd.ms-powerpoint', 'application/mspowerpoint']],
1670
1674
  ['ppsm', 'application/vnd.ms-powerpoint.slideshow.macroenabled.12'],
1671
1675
  ['ppsx', 'application/vnd.openxmlformats-officedocument.presentationml.slideshow'],
1672
- ['ppt', ['application/vnd.ms-powerpoint', 'application/mspowerpoint', 'application/powerpoint', 'application/x-mspowerpoint']],
1676
+ ['ppt', ['application/vnd.ms-powerpoint', 'application/mspowerpoint', 'application/powerpoint',
1677
+ 'application/x-mspowerpoint']],
1673
1678
  ['pptm', 'application/vnd.ms-powerpoint.presentation.macroenabled.12'],
1674
1679
  ['pptx', 'application/vnd.openxmlformats-officedocument.presentationml.presentation'],
1675
1680
  ['ppz', 'application/mspowerpoint'],
@@ -1752,7 +1757,8 @@ const EXTENSIONS = new Map([
1752
1757
  ['sbml', 'application/sbml+xml'],
1753
1758
  ['sc', 'application/vnd.ibm.secure-container'],
1754
1759
  ['scd', 'application/x-msschedule'],
1755
- ['scm', ['application/vnd.lotus-screencam', 'video/x-scm', 'text/x-script.guile', 'application/x-lotusscreencam', 'text/x-script.scheme']],
1760
+ ['scm', ['application/vnd.lotus-screencam', 'video/x-scm', 'text/x-script.guile', 'application/x-lotusscreencam',
1761
+ 'text/x-script.scheme']],
1756
1762
  ['scq', 'application/scvp-cv-request'],
1757
1763
  ['scs', 'application/scvp-cv-response'],
1758
1764
  ['sct', 'text/scriptlet'],