web-csv-toolbox 0.14.0-next-386eebeaafe5857e28c876345c14c9fe5f1a3774 → 0.14.0-next-e45bc4d089f1fb259a7596b9862b3b34e717dab7

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.
@@ -291,6 +291,49 @@ export interface BinaryOptions {
291
291
  * ```
292
292
  */
293
293
  allowExperimentalCompressions?: boolean;
294
+ /**
295
+ * Allow non-standard character encodings not in the common charset list.
296
+ *
297
+ * @remarks
298
+ * When `true`, charset values from Content-Type headers that are not in the
299
+ * default supported list will be passed to the runtime's TextDecoder without
300
+ * validation. This allows using character encodings that may not be universally
301
+ * supported across all environments.
302
+ *
303
+ * ### Default Supported Charsets (commonly used)
304
+ *
305
+ * When `false` (default), only commonly used charsets are allowed, including:
306
+ * - **UTF**: `utf-8`, `utf-16le`, `utf-16be`
307
+ * - **ISO-8859**: `iso-8859-1` through `iso-8859-16`
308
+ * - **Windows**: `windows-1250` through `windows-1258`
309
+ * - **Asian**: `shift_jis`, `euc-jp`, `gb18030`, `euc-kr`, etc.
310
+ *
311
+ * ### Security Considerations
312
+ *
313
+ * **Use with caution**: Enabling this bypasses library validation and relies entirely
314
+ * on runtime error handling. Invalid or malicious charset values could cause:
315
+ * - Runtime exceptions from TextDecoder
316
+ * - Unexpected character decoding behavior
317
+ * - Potential security vulnerabilities
318
+ *
319
+ * It's recommended to validate charset values against your expected inputs before
320
+ * enabling this option.
321
+ *
322
+ * @default false
323
+ *
324
+ * @example
325
+ * ```ts
326
+ * // Safe mode (default): Only commonly supported charsets
327
+ * const response = await fetch('data.csv');
328
+ * await parse(response); // charset must be in SUPPORTED_CHARSETS
329
+ *
330
+ * // Allow non-standard charset
331
+ * const response = await fetch('data.csv'); // Content-Type: text/csv; charset=custom-encoding
332
+ * await parse(response, { allowNonStandardCharsets: true });
333
+ * // ⚠️ May throw error if runtime doesn't support the charset
334
+ * ```
335
+ */
336
+ allowNonStandardCharsets?: boolean;
294
337
  }
295
338
  /**
296
339
  * CSV Lexer Transformer Options.
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Commonly supported character encodings for CSV parsing in Node.js environments.
3
+ *
4
+ * @remarks
5
+ * Node.js 20+ supports the WHATWG Encoding Standard through TextDecoder.
6
+ * This list includes the most commonly used encodings for CSV files.
7
+ *
8
+ * @see {@link https://nodejs.org/api/util.html#class-utiltextdecoder | Node.js TextDecoder}
9
+ * @see {@link https://encoding.spec.whatwg.org/#names-and-labels | WHATWG Encoding Standard}
10
+ */
11
+ export declare const SUPPORTED_CHARSETS: ReadonlySet<string>;
@@ -0,0 +1,53 @@
1
+ const SUPPORTED_CHARSETS = /* @__PURE__ */ new Set([
2
+ // UTF encodings
3
+ "utf-8",
4
+ "utf8",
5
+ "unicode-1-1-utf-8",
6
+ "utf-16le",
7
+ "utf-16be",
8
+ "utf-16",
9
+ // ISO-8859 series (Western European)
10
+ "iso-8859-1",
11
+ "iso-8859-2",
12
+ "iso-8859-3",
13
+ "iso-8859-4",
14
+ "iso-8859-5",
15
+ "iso-8859-6",
16
+ "iso-8859-7",
17
+ "iso-8859-8",
18
+ "iso-8859-9",
19
+ "iso-8859-10",
20
+ "iso-8859-13",
21
+ "iso-8859-14",
22
+ "iso-8859-15",
23
+ "iso-8859-16",
24
+ "latin1",
25
+ // Windows code pages
26
+ "windows-1250",
27
+ "windows-1251",
28
+ "windows-1252",
29
+ "windows-1253",
30
+ "windows-1254",
31
+ "windows-1255",
32
+ "windows-1256",
33
+ "windows-1257",
34
+ "windows-1258",
35
+ // Japanese
36
+ "shift_jis",
37
+ "shift-jis",
38
+ "sjis",
39
+ "euc-jp",
40
+ "iso-2022-jp",
41
+ // Chinese
42
+ "gb18030",
43
+ "gbk",
44
+ "gb2312",
45
+ // Korean
46
+ "euc-kr",
47
+ // Other
48
+ "ascii",
49
+ "us-ascii"
50
+ ]);
51
+
52
+ export { SUPPORTED_CHARSETS };
53
+ //# sourceMappingURL=getCharsetValidation.constants.node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getCharsetValidation.constants.node.js","sources":["../src/getCharsetValidation.constants.node.ts"],"sourcesContent":["/**\n * Commonly supported character encodings for CSV parsing in Node.js environments.\n *\n * @remarks\n * Node.js 20+ supports the WHATWG Encoding Standard through TextDecoder.\n * This list includes the most commonly used encodings for CSV files.\n *\n * @see {@link https://nodejs.org/api/util.html#class-utiltextdecoder | Node.js TextDecoder}\n * @see {@link https://encoding.spec.whatwg.org/#names-and-labels | WHATWG Encoding Standard}\n */\nexport const SUPPORTED_CHARSETS: ReadonlySet<string> = new Set([\n // UTF encodings\n \"utf-8\",\n \"utf8\",\n \"unicode-1-1-utf-8\",\n \"utf-16le\",\n \"utf-16be\",\n \"utf-16\",\n\n // ISO-8859 series (Western European)\n \"iso-8859-1\",\n \"iso-8859-2\",\n \"iso-8859-3\",\n \"iso-8859-4\",\n \"iso-8859-5\",\n \"iso-8859-6\",\n \"iso-8859-7\",\n \"iso-8859-8\",\n \"iso-8859-9\",\n \"iso-8859-10\",\n \"iso-8859-13\",\n \"iso-8859-14\",\n \"iso-8859-15\",\n \"iso-8859-16\",\n \"latin1\",\n\n // Windows code pages\n \"windows-1250\",\n \"windows-1251\",\n \"windows-1252\",\n \"windows-1253\",\n \"windows-1254\",\n \"windows-1255\",\n \"windows-1256\",\n \"windows-1257\",\n \"windows-1258\",\n\n // Japanese\n \"shift_jis\",\n \"shift-jis\",\n \"sjis\",\n \"euc-jp\",\n \"iso-2022-jp\",\n\n // Chinese\n \"gb18030\",\n \"gbk\",\n \"gb2312\",\n\n // Korean\n \"euc-kr\",\n\n // Other\n \"ascii\",\n \"us-ascii\",\n]);\n"],"names":[],"mappings":"AAUO,MAAM,kBAAA,uBAA8C,GAAA,CAAI;AAAA;AAAA,EAE7D,OAAA;AAAA,EACA,MAAA;AAAA,EACA,mBAAA;AAAA,EACA,UAAA;AAAA,EACA,UAAA;AAAA,EACA,QAAA;AAAA;AAAA,EAGA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,QAAA;AAAA;AAAA,EAGA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA;AAAA,EAGA,WAAA;AAAA,EACA,WAAA;AAAA,EACA,MAAA;AAAA,EACA,QAAA;AAAA,EACA,aAAA;AAAA;AAAA,EAGA,SAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA;AAAA,EAGA,QAAA;AAAA;AAAA,EAGA,OAAA;AAAA,EACA;AACF,CAAC;;;;"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Commonly supported character encodings for CSV parsing in browser environments.
3
+ *
4
+ * @remarks
5
+ * This list includes the most commonly used encodings that are supported across
6
+ * all modern browsers. TextDecoder supports additional encodings, but this list
7
+ * focuses on the most widely-used ones for CSV files.
8
+ *
9
+ * ### Common Character Encodings:
10
+ * - **UTF-8**: Universal encoding, recommended for all new content
11
+ * - **UTF-16LE/UTF-16BE**: Unicode encodings with byte order
12
+ * - **ISO-8859-X**: Legacy single-byte encodings for Western European languages
13
+ * - **Windows-125X**: Windows-specific legacy encodings
14
+ * - **Shift_JIS, EUC-JP, ISO-2022-JP**: Japanese encodings
15
+ * - **GB18030, GBK**: Chinese encodings
16
+ * - **EUC-KR**: Korean encoding
17
+ *
18
+ * ### Using Non-Standard Charsets
19
+ *
20
+ * If you need to use a charset not in this list, you can:
21
+ * 1. Set the `allowNonStandardCharsets` option to `true`
22
+ * 2. Be aware that this may cause errors if the browser doesn't support the encoding
23
+ * 3. Consider implementing fallback handling for unsupported charsets
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * // Use non-standard charset (may fail in some browsers)
28
+ * const records = parseResponse(response, {
29
+ * allowNonStandardCharsets: true
30
+ * });
31
+ * ```
32
+ *
33
+ * @see {@link https://encoding.spec.whatwg.org/#names-and-labels | WHATWG Encoding Standard}
34
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder/TextDecoder | TextDecoder}
35
+ */
36
+ export declare const SUPPORTED_CHARSETS: ReadonlySet<string>;
@@ -0,0 +1,53 @@
1
+ const SUPPORTED_CHARSETS = /* @__PURE__ */ new Set([
2
+ // UTF encodings
3
+ "utf-8",
4
+ "utf8",
5
+ "unicode-1-1-utf-8",
6
+ "utf-16le",
7
+ "utf-16be",
8
+ "utf-16",
9
+ // ISO-8859 series (Western European)
10
+ "iso-8859-1",
11
+ "iso-8859-2",
12
+ "iso-8859-3",
13
+ "iso-8859-4",
14
+ "iso-8859-5",
15
+ "iso-8859-6",
16
+ "iso-8859-7",
17
+ "iso-8859-8",
18
+ "iso-8859-9",
19
+ "iso-8859-10",
20
+ "iso-8859-13",
21
+ "iso-8859-14",
22
+ "iso-8859-15",
23
+ "iso-8859-16",
24
+ "latin1",
25
+ // Windows code pages
26
+ "windows-1250",
27
+ "windows-1251",
28
+ "windows-1252",
29
+ "windows-1253",
30
+ "windows-1254",
31
+ "windows-1255",
32
+ "windows-1256",
33
+ "windows-1257",
34
+ "windows-1258",
35
+ // Japanese
36
+ "shift_jis",
37
+ "shift-jis",
38
+ "sjis",
39
+ "euc-jp",
40
+ "iso-2022-jp",
41
+ // Chinese
42
+ "gb18030",
43
+ "gbk",
44
+ "gb2312",
45
+ // Korean
46
+ "euc-kr",
47
+ // Other
48
+ "ascii",
49
+ "us-ascii"
50
+ ]);
51
+
52
+ export { SUPPORTED_CHARSETS };
53
+ //# sourceMappingURL=getCharsetValidation.constants.web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getCharsetValidation.constants.web.js","sources":["../src/getCharsetValidation.constants.web.ts"],"sourcesContent":["/**\n * Commonly supported character encodings for CSV parsing in browser environments.\n *\n * @remarks\n * This list includes the most commonly used encodings that are supported across\n * all modern browsers. TextDecoder supports additional encodings, but this list\n * focuses on the most widely-used ones for CSV files.\n *\n * ### Common Character Encodings:\n * - **UTF-8**: Universal encoding, recommended for all new content\n * - **UTF-16LE/UTF-16BE**: Unicode encodings with byte order\n * - **ISO-8859-X**: Legacy single-byte encodings for Western European languages\n * - **Windows-125X**: Windows-specific legacy encodings\n * - **Shift_JIS, EUC-JP, ISO-2022-JP**: Japanese encodings\n * - **GB18030, GBK**: Chinese encodings\n * - **EUC-KR**: Korean encoding\n *\n * ### Using Non-Standard Charsets\n *\n * If you need to use a charset not in this list, you can:\n * 1. Set the `allowNonStandardCharsets` option to `true`\n * 2. Be aware that this may cause errors if the browser doesn't support the encoding\n * 3. Consider implementing fallback handling for unsupported charsets\n *\n * @example\n * ```typescript\n * // Use non-standard charset (may fail in some browsers)\n * const records = parseResponse(response, {\n * allowNonStandardCharsets: true\n * });\n * ```\n *\n * @see {@link https://encoding.spec.whatwg.org/#names-and-labels | WHATWG Encoding Standard}\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder/TextDecoder | TextDecoder}\n */\nexport const SUPPORTED_CHARSETS: ReadonlySet<string> = new Set([\n // UTF encodings\n \"utf-8\",\n \"utf8\",\n \"unicode-1-1-utf-8\",\n \"utf-16le\",\n \"utf-16be\",\n \"utf-16\",\n\n // ISO-8859 series (Western European)\n \"iso-8859-1\",\n \"iso-8859-2\",\n \"iso-8859-3\",\n \"iso-8859-4\",\n \"iso-8859-5\",\n \"iso-8859-6\",\n \"iso-8859-7\",\n \"iso-8859-8\",\n \"iso-8859-9\",\n \"iso-8859-10\",\n \"iso-8859-13\",\n \"iso-8859-14\",\n \"iso-8859-15\",\n \"iso-8859-16\",\n \"latin1\",\n\n // Windows code pages\n \"windows-1250\",\n \"windows-1251\",\n \"windows-1252\",\n \"windows-1253\",\n \"windows-1254\",\n \"windows-1255\",\n \"windows-1256\",\n \"windows-1257\",\n \"windows-1258\",\n\n // Japanese\n \"shift_jis\",\n \"shift-jis\",\n \"sjis\",\n \"euc-jp\",\n \"iso-2022-jp\",\n\n // Chinese\n \"gb18030\",\n \"gbk\",\n \"gb2312\",\n\n // Korean\n \"euc-kr\",\n\n // Other\n \"ascii\",\n \"us-ascii\",\n]);\n"],"names":[],"mappings":"AAmCO,MAAM,kBAAA,uBAA8C,GAAA,CAAI;AAAA;AAAA,EAE7D,OAAA;AAAA,EACA,MAAA;AAAA,EACA,mBAAA;AAAA,EACA,UAAA;AAAA,EACA,UAAA;AAAA,EACA,QAAA;AAAA;AAAA,EAGA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,QAAA;AAAA;AAAA,EAGA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA;AAAA,EAGA,WAAA;AAAA,EACA,WAAA;AAAA,EACA,MAAA;AAAA,EACA,QAAA;AAAA,EACA,aAAA;AAAA;AAAA,EAGA,SAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA;AAAA,EAGA,QAAA;AAAA;AAAA,EAGA,OAAA;AAAA,EACA;AACF,CAAC;;;;"}
@@ -1,3 +1,4 @@
1
+ import { SUPPORTED_CHARSETS } from './getCharsetValidation.constants.web.js';
1
2
  import { SUPPORTED_COMPRESSIONS } from './getOptionsFromResponse.constants.web.js';
2
3
  import { parseMime } from './utils/parseMime.js';
3
4
 
@@ -29,7 +30,22 @@ function getOptionsFromResponse(response, options = {}) {
29
30
  }
30
31
  }
31
32
  }
32
- const charset = mime.parameters.charset ?? "utf-8";
33
+ const rawCharset = mime.parameters.charset ?? "utf-8";
34
+ const normalizedCharset = rawCharset.trim().toLowerCase();
35
+ let charset;
36
+ if (SUPPORTED_CHARSETS.has(normalizedCharset)) {
37
+ charset = normalizedCharset;
38
+ } else if (normalizedCharset) {
39
+ if (options.allowNonStandardCharsets) {
40
+ charset = normalizedCharset;
41
+ } else {
42
+ throw new TypeError(
43
+ `Unsupported charset: "${rawCharset}". Commonly supported charsets include: utf-8, utf-16le, iso-8859-1, windows-1252, shift_jis, gb18030, euc-kr, etc. To use non-standard charsets, set allowNonStandardCharsets: true`
44
+ );
45
+ }
46
+ } else {
47
+ charset = "utf-8";
48
+ }
33
49
  return {
34
50
  decompression,
35
51
  charset,
@@ -1 +1 @@
1
- {"version":3,"file":"getOptionsFromResponse.js","sources":["../src/getOptionsFromResponse.ts"],"sourcesContent":["import { SUPPORTED_COMPRESSIONS } from \"#getOptionsFromResponse.constants.js\";\nimport type { ParseBinaryOptions } from \"./common/types.ts\";\nimport type { DEFAULT_DELIMITER, DEFAULT_QUOTATION } from \"./constants.ts\";\nimport { parseMime } from \"./utils/parseMime.ts\";\n\n/**\n * Extracts the options from the response object.\n *\n * @param response - The response object from which to extract the options.\n * @param options - The options to merge with the extracted options.\n * @returns The options extracted from the response.\n * @throws {TypeError} - The content type is not supported or the content-encoding is invalid.\n */\nexport function getOptionsFromResponse<\n Header extends ReadonlyArray<string>,\n Delimiter extends string = DEFAULT_DELIMITER,\n Quotation extends string = '\"',\n>(\n response: Response,\n options: ParseBinaryOptions<\n Header,\n Delimiter,\n Quotation\n > = {} as ParseBinaryOptions<Header, Delimiter, Quotation>,\n): ParseBinaryOptions<Header, Delimiter, Quotation> {\n const { headers } = response;\n const contentType = headers.get(\"content-type\") ?? \"text/csv\";\n const mime = parseMime(contentType);\n if (mime.type !== \"text/csv\") {\n throw new TypeError(`Invalid mime type: \"${contentType}\"`);\n }\n\n const contentEncoding = headers.get(\"content-encoding\");\n let decompression: CompressionFormat | undefined;\n\n if (contentEncoding) {\n const normalizedEncoding = contentEncoding.trim().toLowerCase();\n\n if (normalizedEncoding.includes(\",\")) {\n throw new TypeError(\n `Multiple content-encodings are not supported: \"${contentEncoding}\"`,\n );\n }\n\n if (SUPPORTED_COMPRESSIONS.has(normalizedEncoding as CompressionFormat)) {\n decompression = normalizedEncoding as CompressionFormat;\n } else if (normalizedEncoding) {\n // Unknown compression format\n if (options.allowExperimentalCompressions) {\n // Allow runtime to handle experimental/future formats\n decompression = normalizedEncoding as CompressionFormat;\n } else {\n throw new TypeError(\n `Unsupported content-encoding: \"${contentEncoding}\". Supported formats: ${Array.from(SUPPORTED_COMPRESSIONS).join(\", \")}. To use experimental formats, set allowExperimentalCompressions: true`,\n );\n }\n }\n }\n\n const charset = mime.parameters.charset ?? \"utf-8\";\n // TODO: Support header=present and header=absent\n // const header = mime.parameters.header ?? \"present\";\n return {\n decompression,\n charset,\n ...options,\n };\n}\n"],"names":[],"mappings":";;;AAaO,SAAS,sBAAA,CAKd,QAAA,EACA,OAAA,GAII,EAAC,EAC6C;AAClD,EAAA,MAAM,EAAE,SAAQ,GAAI,QAAA;AACpB,EAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,GAAA,CAAI,cAAc,CAAA,IAAK,UAAA;AACnD,EAAA,MAAM,IAAA,GAAO,UAAU,WAAW,CAAA;AAClC,EAAA,IAAI,IAAA,CAAK,SAAS,UAAA,EAAY;AAC5B,IAAA,MAAM,IAAI,SAAA,CAAU,CAAA,oBAAA,EAAuB,WAAW,CAAA,CAAA,CAAG,CAAA;AAAA,EAC3D;AAEA,EAAA,MAAM,eAAA,GAAkB,OAAA,CAAQ,GAAA,CAAI,kBAAkB,CAAA;AACtD,EAAA,IAAI,aAAA;AAEJ,EAAA,IAAI,eAAA,EAAiB;AACnB,IAAA,MAAM,kBAAA,GAAqB,eAAA,CAAgB,IAAA,EAAK,CAAE,WAAA,EAAY;AAE9D,IAAA,IAAI,kBAAA,CAAmB,QAAA,CAAS,GAAG,CAAA,EAAG;AACpC,MAAA,MAAM,IAAI,SAAA;AAAA,QACR,kDAAkD,eAAe,CAAA,CAAA;AAAA,OACnE;AAAA,IACF;AAEA,IAAA,IAAI,sBAAA,CAAuB,GAAA,CAAI,kBAAuC,CAAA,EAAG;AACvE,MAAA,aAAA,GAAgB,kBAAA;AAAA,IAClB,WAAW,kBAAA,EAAoB;AAE7B,MAAA,IAAI,QAAQ,6BAAA,EAA+B;AAEzC,QAAA,aAAA,GAAgB,kBAAA;AAAA,MAClB,CAAA,MAAO;AACL,QAAA,MAAM,IAAI,SAAA;AAAA,UACR,CAAA,+BAAA,EAAkC,eAAe,CAAA,sBAAA,EAAyB,KAAA,CAAM,KAAK,sBAAsB,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA,sEAAA;AAAA,SACzH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,UAAA,CAAW,OAAA,IAAW,OAAA;AAG3C,EAAA,OAAO;AAAA,IACL,aAAA;AAAA,IACA,OAAA;AAAA,IACA,GAAG;AAAA,GACL;AACF;;;;"}
1
+ {"version":3,"file":"getOptionsFromResponse.js","sources":["../src/getOptionsFromResponse.ts"],"sourcesContent":["import { SUPPORTED_CHARSETS } from \"#getCharsetValidation.constants.js\";\nimport { SUPPORTED_COMPRESSIONS } from \"#getOptionsFromResponse.constants.js\";\nimport type { ParseBinaryOptions } from \"./common/types.ts\";\nimport type { DEFAULT_DELIMITER, DEFAULT_QUOTATION } from \"./constants.ts\";\nimport { parseMime } from \"./utils/parseMime.ts\";\n\n/**\n * Extracts the options from the response object.\n *\n * @param response - The response object from which to extract the options.\n * @param options - The options to merge with the extracted options.\n * @returns The options extracted from the response.\n * @throws {TypeError} - The content type is not supported or the content-encoding is invalid.\n */\nexport function getOptionsFromResponse<\n Header extends ReadonlyArray<string>,\n Delimiter extends string = DEFAULT_DELIMITER,\n Quotation extends string = '\"',\n>(\n response: Response,\n options: ParseBinaryOptions<\n Header,\n Delimiter,\n Quotation\n > = {} as ParseBinaryOptions<Header, Delimiter, Quotation>,\n): ParseBinaryOptions<Header, Delimiter, Quotation> {\n const { headers } = response;\n const contentType = headers.get(\"content-type\") ?? \"text/csv\";\n const mime = parseMime(contentType);\n if (mime.type !== \"text/csv\") {\n throw new TypeError(`Invalid mime type: \"${contentType}\"`);\n }\n\n const contentEncoding = headers.get(\"content-encoding\");\n let decompression: CompressionFormat | undefined;\n\n if (contentEncoding) {\n const normalizedEncoding = contentEncoding.trim().toLowerCase();\n\n if (normalizedEncoding.includes(\",\")) {\n throw new TypeError(\n `Multiple content-encodings are not supported: \"${contentEncoding}\"`,\n );\n }\n\n if (SUPPORTED_COMPRESSIONS.has(normalizedEncoding as CompressionFormat)) {\n decompression = normalizedEncoding as CompressionFormat;\n } else if (normalizedEncoding) {\n // Unknown compression format\n if (options.allowExperimentalCompressions) {\n // Allow runtime to handle experimental/future formats\n decompression = normalizedEncoding as CompressionFormat;\n } else {\n throw new TypeError(\n `Unsupported content-encoding: \"${contentEncoding}\". Supported formats: ${Array.from(SUPPORTED_COMPRESSIONS).join(\", \")}. To use experimental formats, set allowExperimentalCompressions: true`,\n );\n }\n }\n }\n\n // Validate and normalize charset\n const rawCharset = mime.parameters.charset ?? \"utf-8\";\n const normalizedCharset = rawCharset.trim().toLowerCase();\n\n let charset: string;\n if (SUPPORTED_CHARSETS.has(normalizedCharset)) {\n charset = normalizedCharset;\n } else if (normalizedCharset) {\n // Unknown charset\n if (options.allowNonStandardCharsets) {\n // Allow runtime to handle non-standard charsets\n charset = normalizedCharset;\n } else {\n throw new TypeError(\n `Unsupported charset: \"${rawCharset}\". Commonly supported charsets include: utf-8, utf-16le, iso-8859-1, windows-1252, shift_jis, gb18030, euc-kr, etc. To use non-standard charsets, set allowNonStandardCharsets: true`,\n );\n }\n } else {\n charset = \"utf-8\";\n }\n\n // TODO: Support header=present and header=absent\n // const header = mime.parameters.header ?? \"present\";\n return {\n decompression,\n charset,\n ...options,\n };\n}\n"],"names":[],"mappings":";;;;AAcO,SAAS,sBAAA,CAKd,QAAA,EACA,OAAA,GAII,EAAC,EAC6C;AAClD,EAAA,MAAM,EAAE,SAAQ,GAAI,QAAA;AACpB,EAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,GAAA,CAAI,cAAc,CAAA,IAAK,UAAA;AACnD,EAAA,MAAM,IAAA,GAAO,UAAU,WAAW,CAAA;AAClC,EAAA,IAAI,IAAA,CAAK,SAAS,UAAA,EAAY;AAC5B,IAAA,MAAM,IAAI,SAAA,CAAU,CAAA,oBAAA,EAAuB,WAAW,CAAA,CAAA,CAAG,CAAA;AAAA,EAC3D;AAEA,EAAA,MAAM,eAAA,GAAkB,OAAA,CAAQ,GAAA,CAAI,kBAAkB,CAAA;AACtD,EAAA,IAAI,aAAA;AAEJ,EAAA,IAAI,eAAA,EAAiB;AACnB,IAAA,MAAM,kBAAA,GAAqB,eAAA,CAAgB,IAAA,EAAK,CAAE,WAAA,EAAY;AAE9D,IAAA,IAAI,kBAAA,CAAmB,QAAA,CAAS,GAAG,CAAA,EAAG;AACpC,MAAA,MAAM,IAAI,SAAA;AAAA,QACR,kDAAkD,eAAe,CAAA,CAAA;AAAA,OACnE;AAAA,IACF;AAEA,IAAA,IAAI,sBAAA,CAAuB,GAAA,CAAI,kBAAuC,CAAA,EAAG;AACvE,MAAA,aAAA,GAAgB,kBAAA;AAAA,IAClB,WAAW,kBAAA,EAAoB;AAE7B,MAAA,IAAI,QAAQ,6BAAA,EAA+B;AAEzC,QAAA,aAAA,GAAgB,kBAAA;AAAA,MAClB,CAAA,MAAO;AACL,QAAA,MAAM,IAAI,SAAA;AAAA,UACR,CAAA,+BAAA,EAAkC,eAAe,CAAA,sBAAA,EAAyB,KAAA,CAAM,KAAK,sBAAsB,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA,sEAAA;AAAA,SACzH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,UAAA,CAAW,OAAA,IAAW,OAAA;AAC9C,EAAA,MAAM,iBAAA,GAAoB,UAAA,CAAW,IAAA,EAAK,CAAE,WAAA,EAAY;AAExD,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI,kBAAA,CAAmB,GAAA,CAAI,iBAAiB,CAAA,EAAG;AAC7C,IAAA,OAAA,GAAU,iBAAA;AAAA,EACZ,WAAW,iBAAA,EAAmB;AAE5B,IAAA,IAAI,QAAQ,wBAAA,EAA0B;AAEpC,MAAA,OAAA,GAAU,iBAAA;AAAA,IACZ,CAAA,MAAO;AACL,MAAA,MAAM,IAAI,SAAA;AAAA,QACR,yBAAyB,UAAU,CAAA,oLAAA;AAAA,OACrC;AAAA,IACF;AAAA,EACF,CAAA,MAAO;AACL,IAAA,OAAA,GAAU,OAAA;AAAA,EACZ;AAIA,EAAA,OAAO;AAAA,IACL,aAAA;AAAA,IACA,OAAA;AAAA,IACA,GAAG;AAAA,GACL;AACF;;;;"}
@@ -11,10 +11,23 @@ function convertBinaryToString(binary, options) {
11
11
  `Binary size (${binary.byteLength} bytes) exceeded maximum allowed size of ${maxBinarySize} bytes`
12
12
  );
13
13
  }
14
- return new TextDecoder(options?.charset, {
15
- ignoreBOM: options?.ignoreBOM,
16
- fatal: options?.fatal
17
- }).decode(binary instanceof ArrayBuffer ? new Uint8Array(binary) : binary);
14
+ let decoder;
15
+ try {
16
+ decoder = new TextDecoder(options?.charset, {
17
+ ignoreBOM: options?.ignoreBOM,
18
+ fatal: options?.fatal
19
+ });
20
+ } catch (error) {
21
+ if (error instanceof RangeError || error instanceof TypeError) {
22
+ throw new RangeError(
23
+ `Invalid or unsupported charset: "${options?.charset}". Please specify a valid charset or enable allowNonStandardCharsets option.`
24
+ );
25
+ }
26
+ throw error;
27
+ }
28
+ return decoder.decode(
29
+ binary instanceof ArrayBuffer ? new Uint8Array(binary) : binary
30
+ );
18
31
  }
19
32
 
20
33
  export { convertBinaryToString };
@@ -1 +1 @@
1
- {"version":3,"file":"convertBinaryToString.js","sources":["../../src/utils/convertBinaryToString.ts"],"sourcesContent":["import type { BinaryOptions } from \"../common/types.ts\";\n\n/**\n * Default maximum binary size in bytes (100MB).\n */\nconst DEFAULT_MAX_BINARY_SIZE = 100 * 1024 * 1024;\n\n/**\n * Converts a binary string to a string.\n *\n * @param binary - The binary string to convert.\n * @param options - The options for parsing the binary string.\n * @returns The converted string.\n * @throws {RangeError} The given charset is not supported or binary size exceeds the limit.\n * @throws {TypeError} The encoded data was not valid.\n */\nexport function convertBinaryToString(\n binary: Uint8Array | ArrayBuffer,\n options: BinaryOptions,\n): string {\n const maxBinarySize = options?.maxBinarySize ?? DEFAULT_MAX_BINARY_SIZE;\n\n // Validate maxBinarySize\n if (\n !(\n Number.isFinite(maxBinarySize) ||\n maxBinarySize === Number.POSITIVE_INFINITY\n ) ||\n (Number.isFinite(maxBinarySize) && maxBinarySize < 0)\n ) {\n throw new RangeError(\n \"maxBinarySize must be a non-negative number or Number.POSITIVE_INFINITY\",\n );\n }\n\n // Check binary size\n if (Number.isFinite(maxBinarySize) && binary.byteLength > maxBinarySize) {\n throw new RangeError(\n `Binary size (${binary.byteLength} bytes) exceeded maximum allowed size of ${maxBinarySize} bytes`,\n );\n }\n\n return new TextDecoder(options?.charset, {\n ignoreBOM: options?.ignoreBOM,\n fatal: options?.fatal,\n }).decode(binary instanceof ArrayBuffer ? new Uint8Array(binary) : binary);\n}\n"],"names":[],"mappings":"AAKA,MAAM,uBAAA,GAA0B,MAAM,IAAA,GAAO,IAAA;AAWtC,SAAS,qBAAA,CACd,QACA,OAAA,EACQ;AACR,EAAA,MAAM,aAAA,GAAgB,SAAS,aAAA,IAAiB,uBAAA;AAGhD,EAAA,IACE,EACE,MAAA,CAAO,QAAA,CAAS,aAAa,CAAA,IAC7B,aAAA,KAAkB,MAAA,CAAO,iBAAA,CAAA,IAE1B,MAAA,CAAO,QAAA,CAAS,aAAa,CAAA,IAAK,gBAAgB,CAAA,EACnD;AACA,IAAA,MAAM,IAAI,UAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AAGA,EAAA,IAAI,OAAO,QAAA,CAAS,aAAa,CAAA,IAAK,MAAA,CAAO,aAAa,aAAA,EAAe;AACvE,IAAA,MAAM,IAAI,UAAA;AAAA,MACR,CAAA,aAAA,EAAgB,MAAA,CAAO,UAAU,CAAA,yCAAA,EAA4C,aAAa,CAAA,MAAA;AAAA,KAC5F;AAAA,EACF;AAEA,EAAA,OAAO,IAAI,WAAA,CAAY,OAAA,EAAS,OAAA,EAAS;AAAA,IACvC,WAAW,OAAA,EAAS,SAAA;AAAA,IACpB,OAAO,OAAA,EAAS;AAAA,GACjB,EAAE,MAAA,CAAO,MAAA,YAAkB,cAAc,IAAI,UAAA,CAAW,MAAM,CAAA,GAAI,MAAM,CAAA;AAC3E;;;;"}
1
+ {"version":3,"file":"convertBinaryToString.js","sources":["../../src/utils/convertBinaryToString.ts"],"sourcesContent":["import type { BinaryOptions } from \"../common/types.ts\";\n\n/**\n * Default maximum binary size in bytes (100MB).\n */\nconst DEFAULT_MAX_BINARY_SIZE = 100 * 1024 * 1024;\n\n/**\n * Converts a binary string to a string.\n *\n * @param binary - The binary string to convert.\n * @param options - The options for parsing the binary string.\n * @returns The converted string.\n * @throws {RangeError} The given charset is not supported or binary size exceeds the limit.\n * @throws {TypeError} The encoded data was not valid.\n */\nexport function convertBinaryToString(\n binary: Uint8Array | ArrayBuffer,\n options: BinaryOptions,\n): string {\n const maxBinarySize = options?.maxBinarySize ?? DEFAULT_MAX_BINARY_SIZE;\n\n // Validate maxBinarySize\n if (\n !(\n Number.isFinite(maxBinarySize) ||\n maxBinarySize === Number.POSITIVE_INFINITY\n ) ||\n (Number.isFinite(maxBinarySize) && maxBinarySize < 0)\n ) {\n throw new RangeError(\n \"maxBinarySize must be a non-negative number or Number.POSITIVE_INFINITY\",\n );\n }\n\n // Check binary size\n if (Number.isFinite(maxBinarySize) && binary.byteLength > maxBinarySize) {\n throw new RangeError(\n `Binary size (${binary.byteLength} bytes) exceeded maximum allowed size of ${maxBinarySize} bytes`,\n );\n }\n\n // Try to create TextDecoder with error handling for invalid charsets\n let decoder: TextDecoder;\n try {\n decoder = new TextDecoder(options?.charset, {\n ignoreBOM: options?.ignoreBOM,\n fatal: options?.fatal,\n });\n } catch (error) {\n // If charset is invalid, provide clear error message\n if (error instanceof RangeError || error instanceof TypeError) {\n throw new RangeError(\n `Invalid or unsupported charset: \"${options?.charset}\". Please specify a valid charset or enable allowNonStandardCharsets option.`,\n );\n }\n throw error;\n }\n\n return decoder.decode(\n binary instanceof ArrayBuffer ? new Uint8Array(binary) : binary,\n );\n}\n"],"names":[],"mappings":"AAKA,MAAM,uBAAA,GAA0B,MAAM,IAAA,GAAO,IAAA;AAWtC,SAAS,qBAAA,CACd,QACA,OAAA,EACQ;AACR,EAAA,MAAM,aAAA,GAAgB,SAAS,aAAA,IAAiB,uBAAA;AAGhD,EAAA,IACE,EACE,MAAA,CAAO,QAAA,CAAS,aAAa,CAAA,IAC7B,aAAA,KAAkB,MAAA,CAAO,iBAAA,CAAA,IAE1B,MAAA,CAAO,QAAA,CAAS,aAAa,CAAA,IAAK,gBAAgB,CAAA,EACnD;AACA,IAAA,MAAM,IAAI,UAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AAGA,EAAA,IAAI,OAAO,QAAA,CAAS,aAAa,CAAA,IAAK,MAAA,CAAO,aAAa,aAAA,EAAe;AACvE,IAAA,MAAM,IAAI,UAAA;AAAA,MACR,CAAA,aAAA,EAAgB,MAAA,CAAO,UAAU,CAAA,yCAAA,EAA4C,aAAa,CAAA,MAAA;AAAA,KAC5F;AAAA,EACF;AAGA,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI;AACF,IAAA,OAAA,GAAU,IAAI,WAAA,CAAY,OAAA,EAAS,OAAA,EAAS;AAAA,MAC1C,WAAW,OAAA,EAAS,SAAA;AAAA,MACpB,OAAO,OAAA,EAAS;AAAA,KACjB,CAAA;AAAA,EACH,SAAS,KAAA,EAAO;AAEd,IAAA,IAAI,KAAA,YAAiB,UAAA,IAAc,KAAA,YAAiB,SAAA,EAAW;AAC7D,MAAA,MAAM,IAAI,UAAA;AAAA,QACR,CAAA,iCAAA,EAAoC,SAAS,OAAO,CAAA,4EAAA;AAAA,OACtD;AAAA,IACF;AACA,IAAA,MAAM,KAAA;AAAA,EACR;AAEA,EAAA,OAAO,OAAA,CAAQ,MAAA;AAAA,IACb,MAAA,YAAkB,WAAA,GAAc,IAAI,UAAA,CAAW,MAAM,CAAA,GAAI;AAAA,GAC3D;AACF;;;;"}
@@ -6,7 +6,9 @@ function parseMime(contentType) {
6
6
  };
7
7
  for (const paramator of parameters) {
8
8
  const [key, value] = paramator.split("=");
9
- result.parameters[key.trim()] = value.trim();
9
+ if (value !== void 0) {
10
+ result.parameters[key.trim()] = value.trim();
11
+ }
10
12
  }
11
13
  return result;
12
14
  }
@@ -1 +1 @@
1
- {"version":3,"file":"parseMime.js","sources":["../../src/utils/parseMime.ts"],"sourcesContent":["export interface ParseMimeResult {\n type: string;\n parameters: {\n [key: string]: string;\n };\n}\n\nexport function parseMime(contentType: string) {\n const [type, ...parameters] = contentType.split(\";\");\n const result: ParseMimeResult = {\n type: type.trim(),\n parameters: {},\n };\n for (const paramator of parameters) {\n const [key, value] = paramator.split(\"=\");\n result.parameters[key.trim()] = value.trim();\n }\n return result;\n}\n"],"names":[],"mappings":"AAOO,SAAS,UAAU,WAAA,EAAqB;AAC7C,EAAA,MAAM,CAAC,IAAA,EAAM,GAAG,UAAU,CAAA,GAAI,WAAA,CAAY,MAAM,GAAG,CAAA;AACnD,EAAA,MAAM,MAAA,GAA0B;AAAA,IAC9B,IAAA,EAAM,KAAK,IAAA,EAAK;AAAA,IAChB,YAAY;AAAC,GACf;AACA,EAAA,KAAA,MAAW,aAAa,UAAA,EAAY;AAClC,IAAA,MAAM,CAAC,GAAA,EAAK,KAAK,CAAA,GAAI,SAAA,CAAU,MAAM,GAAG,CAAA;AACxC,IAAA,MAAA,CAAO,WAAW,GAAA,CAAI,IAAA,EAAM,CAAA,GAAI,MAAM,IAAA,EAAK;AAAA,EAC7C;AACA,EAAA,OAAO,MAAA;AACT;;;;"}
1
+ {"version":3,"file":"parseMime.js","sources":["../../src/utils/parseMime.ts"],"sourcesContent":["export interface ParseMimeResult {\n type: string;\n parameters: {\n [key: string]: string;\n };\n}\n\nexport function parseMime(contentType: string) {\n const [type, ...parameters] = contentType.split(\";\");\n const result: ParseMimeResult = {\n type: type.trim(),\n parameters: {},\n };\n for (const paramator of parameters) {\n const [key, value] = paramator.split(\"=\");\n // Skip parameters without values to prevent undefined.trim() errors\n if (value !== undefined) {\n result.parameters[key.trim()] = value.trim();\n }\n }\n return result;\n}\n"],"names":[],"mappings":"AAOO,SAAS,UAAU,WAAA,EAAqB;AAC7C,EAAA,MAAM,CAAC,IAAA,EAAM,GAAG,UAAU,CAAA,GAAI,WAAA,CAAY,MAAM,GAAG,CAAA;AACnD,EAAA,MAAM,MAAA,GAA0B;AAAA,IAC9B,IAAA,EAAM,KAAK,IAAA,EAAK;AAAA,IAChB,YAAY;AAAC,GACf;AACA,EAAA,KAAA,MAAW,aAAa,UAAA,EAAY;AAClC,IAAA,MAAM,CAAC,GAAA,EAAK,KAAK,CAAA,GAAI,SAAA,CAAU,MAAM,GAAG,CAAA;AAExC,IAAA,IAAI,UAAU,MAAA,EAAW;AACvB,MAAA,MAAA,CAAO,WAAW,GAAA,CAAI,IAAA,EAAM,CAAA,GAAI,MAAM,IAAA,EAAK;AAAA,IAC7C;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "web-csv-toolbox",
3
- "version": "0.14.0-next-386eebeaafe5857e28c876345c14c9fe5f1a3774",
3
+ "version": "0.14.0-next-e45bc4d089f1fb259a7596b9862b3b34e717dab7",
4
4
  "description": "A CSV Toolbox utilizing Web Standard APIs.",
5
5
  "type": "module",
6
6
  "module": "dist/web-csv-toolbox.js",
@@ -56,6 +56,12 @@
56
56
  "browser": "./dist/getOptionsFromResponse.constants.web.js",
57
57
  "default": "./dist/getOptionsFromResponse.constants.web.js"
58
58
  },
59
+ "#getCharsetValidation.constants.js": {
60
+ "types": "./dist/getCharsetValidation.constants.d.ts",
61
+ "node": "./dist/getCharsetValidation.constants.node.js",
62
+ "browser": "./dist/getCharsetValidation.constants.web.js",
63
+ "default": "./dist/getCharsetValidation.constants.web.js"
64
+ },
59
65
  "#execution/worker/parseStringInWorker.js": {
60
66
  "types": "./dist/execution/worker/parseStringInWorker.d.ts",
61
67
  "node": "./dist/execution/worker/parseStringInWorker.node.js",