@cj-tech-master/excelts 1.6.3 → 2.0.0-canary.20251228013952.4f2c3c6
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.
- package/README.md +139 -24
- package/README_zh.md +140 -26
- package/dist/browser/excelts.esm.js +18468 -0
- package/dist/browser/excelts.esm.js.map +1 -0
- package/dist/browser/excelts.esm.min.js +125 -0
- package/dist/browser/excelts.iife.js +13107 -47146
- package/dist/browser/excelts.iife.js.map +1 -1
- package/dist/browser/excelts.iife.min.js +24 -106
- package/dist/cjs/csv/csv-core.js +701 -0
- package/dist/cjs/csv/csv-stream.js +646 -0
- package/dist/cjs/csv/csv.base.js +137 -0
- package/dist/cjs/csv/csv.browser.js +68 -0
- package/dist/cjs/csv/csv.js +218 -162
- package/dist/cjs/doc/anchor.js +2 -2
- package/dist/cjs/doc/cell.js +22 -22
- package/dist/cjs/doc/column.js +28 -7
- package/dist/cjs/doc/data-validations.js +3 -3
- package/dist/cjs/doc/defined-names.js +13 -13
- package/dist/cjs/doc/image.js +7 -7
- package/dist/cjs/doc/modelcontainer.js +2 -2
- package/dist/cjs/doc/note.js +2 -2
- package/dist/cjs/doc/pivot-table.js +5 -5
- package/dist/cjs/doc/range.js +11 -11
- package/dist/cjs/doc/row.js +16 -16
- package/dist/cjs/doc/table.js +5 -5
- package/dist/cjs/doc/workbook.base.js +211 -0
- package/dist/cjs/doc/workbook.browser.js +62 -0
- package/dist/cjs/doc/workbook.js +68 -179
- package/dist/cjs/doc/worksheet.js +45 -41
- package/dist/cjs/index.js +49 -32
- package/dist/cjs/stream/xlsx/hyperlink-reader.js +6 -6
- package/dist/cjs/stream/xlsx/sheet-comments-writer.js +12 -12
- package/dist/cjs/stream/xlsx/sheet-rels-writer.js +4 -4
- package/dist/cjs/stream/xlsx/workbook-reader.js +22 -22
- package/dist/cjs/stream/xlsx/workbook-writer.js +38 -38
- package/dist/cjs/stream/xlsx/worksheet-reader.js +17 -17
- package/dist/cjs/stream/xlsx/worksheet-writer.js +67 -60
- package/dist/cjs/utils/browser-buffer.js +75 -0
- package/dist/cjs/utils/cell-format.js +2 -2
- package/dist/cjs/utils/cell-matrix.js +5 -5
- package/dist/cjs/utils/datetime.js +499 -0
- package/dist/cjs/utils/encryptor.browser.js +240 -0
- package/dist/cjs/utils/parse-sax.js +1191 -13
- package/dist/cjs/utils/shared-formula.js +5 -5
- package/dist/cjs/utils/sheet-utils.js +13 -13
- package/dist/cjs/utils/stream-buf.browser.js +355 -0
- package/dist/cjs/utils/stream-buf.js +5 -5
- package/dist/cjs/utils/unzip/extract.js +11 -11
- package/dist/cjs/utils/unzip/index.js +21 -21
- package/dist/cjs/utils/unzip/parse-extra-field.js +3 -3
- package/dist/cjs/utils/unzip/parse.js +16 -16
- package/dist/cjs/utils/unzip/zip-parser.js +14 -3
- package/dist/cjs/utils/utils.base.js +161 -0
- package/dist/cjs/utils/utils.browser.js +89 -0
- package/dist/cjs/utils/utils.js +46 -154
- package/dist/cjs/utils/xml-stream.js +3 -3
- package/dist/cjs/utils/zip/compress.base.js +88 -0
- package/dist/cjs/utils/zip/compress.browser.js +127 -0
- package/dist/cjs/utils/zip/compress.js +18 -198
- package/dist/cjs/utils/zip/crc32.browser.js +88 -0
- package/dist/cjs/utils/zip/deflate-fallback.js +575 -0
- package/dist/cjs/utils/zip/index.js +17 -17
- package/dist/cjs/utils/zip/streaming-zip.js +264 -0
- package/dist/cjs/utils/zip/zip-builder.js +10 -10
- package/dist/cjs/utils/zip-stream.browser.js +135 -0
- package/dist/cjs/utils/zip-stream.js +4 -4
- package/dist/cjs/xlsx/xform/base-xform.js +4 -4
- package/dist/cjs/xlsx/xform/book/defined-name-xform.js +4 -4
- package/dist/cjs/xlsx/xform/book/sheet-xform.js +4 -4
- package/dist/cjs/xlsx/xform/book/workbook-calc-properties-xform.js +2 -2
- package/dist/cjs/xlsx/xform/book/workbook-pivot-cache-xform.js +2 -2
- package/dist/cjs/xlsx/xform/book/workbook-properties-xform.js +2 -2
- package/dist/cjs/xlsx/xform/book/workbook-view-xform.js +2 -2
- package/dist/cjs/xlsx/xform/book/workbook-xform.js +24 -24
- package/dist/cjs/xlsx/xform/comment/comment-xform.js +4 -4
- package/dist/cjs/xlsx/xform/comment/comments-xform.js +6 -6
- package/dist/cjs/xlsx/xform/comment/style/vml-position-xform.js +2 -2
- package/dist/cjs/xlsx/xform/comment/style/vml-protection-xform.js +2 -2
- package/dist/cjs/xlsx/xform/comment/vml-anchor-xform.js +2 -2
- package/dist/cjs/xlsx/xform/comment/vml-client-data-xform.js +10 -10
- package/dist/cjs/xlsx/xform/comment/vml-notes-xform.js +6 -6
- package/dist/cjs/xlsx/xform/comment/vml-shape-xform.js +6 -6
- package/dist/cjs/xlsx/xform/comment/vml-textbox-xform.js +2 -2
- package/dist/cjs/xlsx/xform/composite-xform.js +2 -2
- package/dist/cjs/xlsx/xform/core/app-heading-pairs-xform.js +2 -2
- package/dist/cjs/xlsx/xform/core/app-titles-of-parts-xform.js +2 -2
- package/dist/cjs/xlsx/xform/core/app-xform.js +11 -11
- package/dist/cjs/xlsx/xform/core/content-types-xform.js +4 -4
- package/dist/cjs/xlsx/xform/core/core-xform.js +23 -23
- package/dist/cjs/xlsx/xform/core/relationship-xform.js +2 -2
- package/dist/cjs/xlsx/xform/core/relationships-xform.js +6 -6
- package/dist/cjs/xlsx/xform/drawing/base-cell-anchor-xform.js +2 -2
- package/dist/cjs/xlsx/xform/drawing/blip-fill-xform.js +4 -4
- package/dist/cjs/xlsx/xform/drawing/blip-xform.js +2 -2
- package/dist/cjs/xlsx/xform/drawing/c-nv-pic-pr-xform.js +2 -2
- package/dist/cjs/xlsx/xform/drawing/c-nv-pr-xform.js +6 -6
- package/dist/cjs/xlsx/xform/drawing/cell-position-xform.js +7 -7
- package/dist/cjs/xlsx/xform/drawing/drawing-xform.js +10 -10
- package/dist/cjs/xlsx/xform/drawing/ext-lst-xform.js +2 -2
- package/dist/cjs/xlsx/xform/drawing/ext-xform.js +2 -2
- package/dist/cjs/xlsx/xform/drawing/hlink-click-xform.js +2 -2
- package/dist/cjs/xlsx/xform/drawing/nv-pic-pr-xform.js +6 -6
- package/dist/cjs/xlsx/xform/drawing/one-cell-anchor-xform.js +10 -10
- package/dist/cjs/xlsx/xform/drawing/pic-xform.js +9 -9
- package/dist/cjs/xlsx/xform/drawing/two-cell-anchor-xform.js +9 -9
- package/dist/cjs/xlsx/xform/list-xform.js +2 -2
- package/dist/cjs/xlsx/xform/pivot-table/cache-field-xform.js +5 -5
- package/dist/cjs/xlsx/xform/pivot-table/cache-field.js +3 -3
- package/dist/cjs/xlsx/xform/pivot-table/pivot-cache-definition-xform.js +10 -10
- package/dist/cjs/xlsx/xform/pivot-table/pivot-cache-records-xform.js +9 -9
- package/dist/cjs/xlsx/xform/pivot-table/pivot-table-xform.js +10 -11
- package/dist/cjs/xlsx/xform/sheet/auto-filter-xform.js +4 -4
- package/dist/cjs/xlsx/xform/sheet/cell-xform.js +65 -65
- package/dist/cjs/xlsx/xform/sheet/cf/cf-rule-xform.js +27 -27
- package/dist/cjs/xlsx/xform/sheet/cf/cfvo-xform.js +3 -3
- package/dist/cjs/xlsx/xform/sheet/cf/color-scale-xform.js +6 -6
- package/dist/cjs/xlsx/xform/sheet/cf/conditional-formatting-xform.js +6 -6
- package/dist/cjs/xlsx/xform/sheet/cf/conditional-formattings-xform.js +4 -4
- package/dist/cjs/xlsx/xform/sheet/cf/databar-xform.js +6 -6
- package/dist/cjs/xlsx/xform/sheet/cf/ext-lst-ref-xform.js +5 -5
- package/dist/cjs/xlsx/xform/sheet/cf/formula-xform.js +2 -2
- package/dist/cjs/xlsx/xform/sheet/cf/icon-set-xform.js +11 -11
- package/dist/cjs/xlsx/xform/sheet/cf-ext/cf-icon-ext-xform.js +3 -3
- package/dist/cjs/xlsx/xform/sheet/cf-ext/cf-rule-ext-xform.js +11 -12
- package/dist/cjs/xlsx/xform/sheet/cf-ext/cfvo-ext-xform.js +4 -4
- package/dist/cjs/xlsx/xform/sheet/cf-ext/conditional-formatting-ext-xform.js +8 -8
- package/dist/cjs/xlsx/xform/sheet/cf-ext/conditional-formattings-ext-xform.js +6 -6
- package/dist/cjs/xlsx/xform/sheet/cf-ext/databar-ext-xform.js +26 -26
- package/dist/cjs/xlsx/xform/sheet/cf-ext/f-ext-xform.js +2 -2
- package/dist/cjs/xlsx/xform/sheet/cf-ext/icon-set-ext-xform.js +14 -14
- package/dist/cjs/xlsx/xform/sheet/cf-ext/sqref-ext-xform.js +2 -2
- package/dist/cjs/xlsx/xform/sheet/col-breaks-xform.js +38 -0
- package/dist/cjs/xlsx/xform/sheet/col-xform.js +6 -6
- package/dist/cjs/xlsx/xform/sheet/data-validations-xform.js +18 -18
- package/dist/cjs/xlsx/xform/sheet/dimension-xform.js +2 -2
- package/dist/cjs/xlsx/xform/sheet/drawing-xform.js +2 -2
- package/dist/cjs/xlsx/xform/sheet/ext-lst-xform.js +5 -5
- package/dist/cjs/xlsx/xform/sheet/header-footer-xform.js +2 -2
- package/dist/cjs/xlsx/xform/sheet/hyperlink-xform.js +2 -2
- package/dist/cjs/xlsx/xform/sheet/merge-cell-xform.js +2 -2
- package/dist/cjs/xlsx/xform/sheet/merges.js +8 -8
- package/dist/cjs/xlsx/xform/sheet/outline-properties-xform.js +2 -2
- package/dist/cjs/xlsx/xform/sheet/page-breaks-xform.js +15 -3
- package/dist/cjs/xlsx/xform/sheet/page-margins-xform.js +2 -2
- package/dist/cjs/xlsx/xform/sheet/page-setup-properties-xform.js +2 -2
- package/dist/cjs/xlsx/xform/sheet/page-setup-xform.js +2 -2
- package/dist/cjs/xlsx/xform/sheet/picture-xform.js +2 -2
- package/dist/cjs/xlsx/xform/sheet/print-options-xform.js +2 -2
- package/dist/cjs/xlsx/xform/sheet/row-breaks-xform.js +15 -17
- package/dist/cjs/xlsx/xform/sheet/row-xform.js +11 -11
- package/dist/cjs/xlsx/xform/sheet/sheet-format-properties-xform.js +2 -2
- package/dist/cjs/xlsx/xform/sheet/sheet-properties-xform.js +8 -8
- package/dist/cjs/xlsx/xform/sheet/sheet-protection-xform.js +2 -2
- package/dist/cjs/xlsx/xform/sheet/sheet-view-xform.js +4 -4
- package/dist/cjs/xlsx/xform/sheet/table-part-xform.js +2 -2
- package/dist/cjs/xlsx/xform/sheet/worksheet-xform.js +75 -70
- package/dist/cjs/xlsx/xform/simple/boolean-xform.js +2 -2
- package/dist/cjs/xlsx/xform/simple/date-xform.js +2 -2
- package/dist/cjs/xlsx/xform/simple/float-xform.js +2 -2
- package/dist/cjs/xlsx/xform/simple/integer-xform.js +2 -2
- package/dist/cjs/xlsx/xform/simple/string-xform.js +2 -2
- package/dist/cjs/xlsx/xform/static-xform.js +4 -4
- package/dist/cjs/xlsx/xform/strings/phonetic-text-xform.js +6 -6
- package/dist/cjs/xlsx/xform/strings/rich-text-xform.js +6 -6
- package/dist/cjs/xlsx/xform/strings/shared-string-xform.js +8 -8
- package/dist/cjs/xlsx/xform/strings/shared-strings-xform.js +6 -6
- package/dist/cjs/xlsx/xform/strings/text-xform.js +2 -2
- package/dist/cjs/xlsx/xform/style/alignment-xform.js +8 -8
- package/dist/cjs/xlsx/xform/style/border-xform.js +8 -8
- package/dist/cjs/xlsx/xform/style/color-xform.js +2 -2
- package/dist/cjs/xlsx/xform/style/dxf-xform.js +14 -14
- package/dist/cjs/xlsx/xform/style/fill-xform.js +9 -9
- package/dist/cjs/xlsx/xform/style/font-xform.js +22 -22
- package/dist/cjs/xlsx/xform/style/numfmt-xform.js +5 -5
- package/dist/cjs/xlsx/xform/style/protection-xform.js +2 -2
- package/dist/cjs/xlsx/xform/style/style-xform.js +6 -6
- package/dist/cjs/xlsx/xform/style/styles-xform.js +39 -39
- package/dist/cjs/xlsx/xform/style/underline-xform.js +2 -2
- package/dist/cjs/xlsx/xform/table/auto-filter-xform.js +4 -4
- package/dist/cjs/xlsx/xform/table/custom-filter-xform.js +2 -2
- package/dist/cjs/xlsx/xform/table/filter-column-xform.js +9 -9
- package/dist/cjs/xlsx/xform/table/filter-xform.js +2 -2
- package/dist/cjs/xlsx/xform/table/table-column-xform.js +2 -2
- package/dist/cjs/xlsx/xform/table/table-style-info-xform.js +2 -2
- package/dist/cjs/xlsx/xform/table/table-xform.js +12 -12
- package/dist/cjs/xlsx/xlsx.base.js +742 -0
- package/dist/cjs/xlsx/xlsx.browser.js +162 -0
- package/dist/cjs/xlsx/xlsx.js +118 -892
- package/dist/esm/csv/csv-core.js +694 -0
- package/dist/esm/csv/csv-stream.js +638 -0
- package/dist/esm/csv/csv.base.js +127 -0
- package/dist/esm/csv/csv.browser.js +65 -0
- package/dist/esm/csv/csv.js +181 -159
- package/dist/esm/doc/column.js +21 -0
- package/dist/esm/doc/workbook.base.js +207 -0
- package/dist/esm/doc/workbook.browser.js +59 -0
- package/dist/esm/doc/workbook.js +64 -175
- package/dist/esm/doc/worksheet.js +4 -0
- package/dist/esm/index.browser.js +33 -1
- package/dist/esm/index.js +23 -8
- package/dist/esm/local.js +0 -1
- package/dist/esm/stream/xlsx/workbook-writer.js +1 -1
- package/dist/esm/stream/xlsx/worksheet-writer.js +8 -1
- package/dist/esm/utils/browser-buffer.js +67 -0
- package/dist/esm/utils/datetime.js +493 -0
- package/dist/esm/utils/encryptor.browser.js +237 -0
- package/dist/esm/utils/parse-sax.js +1188 -12
- package/dist/esm/utils/stream-buf.browser.js +352 -0
- package/dist/esm/utils/unzip/zip-parser.js +11 -0
- package/dist/esm/utils/utils.base.js +142 -0
- package/dist/esm/utils/utils.browser.js +68 -0
- package/dist/esm/utils/utils.js +15 -123
- package/dist/esm/utils/zip/compress.base.js +83 -0
- package/dist/esm/utils/zip/compress.browser.js +121 -0
- package/dist/esm/utils/zip/compress.js +16 -164
- package/dist/esm/utils/zip/crc32.browser.js +82 -0
- package/dist/esm/utils/zip/deflate-fallback.js +570 -0
- package/dist/esm/utils/zip/streaming-zip.js +259 -0
- package/dist/esm/utils/zip-stream.browser.js +132 -0
- package/dist/esm/xlsx/xform/pivot-table/pivot-table-xform.js +2 -3
- package/dist/esm/xlsx/xform/sheet/cf-ext/cf-rule-ext-xform.js +2 -3
- package/dist/esm/xlsx/xform/sheet/col-breaks-xform.js +35 -0
- package/dist/esm/xlsx/xform/sheet/page-breaks-xform.js +13 -1
- package/dist/esm/xlsx/xform/sheet/row-breaks-xform.js +11 -13
- package/dist/esm/xlsx/xform/sheet/worksheet-xform.js +7 -2
- package/dist/esm/xlsx/xlsx.base.js +739 -0
- package/dist/esm/xlsx/xlsx.browser.js +159 -0
- package/dist/esm/xlsx/xlsx.js +114 -888
- package/dist/types/csv/csv-core.d.ts +207 -0
- package/dist/types/csv/csv-stream.d.ts +114 -0
- package/dist/types/csv/csv.base.d.ts +62 -0
- package/dist/types/csv/csv.browser.d.ts +33 -0
- package/dist/types/csv/csv.d.ts +97 -71
- package/dist/types/doc/anchor.d.ts +1 -1
- package/dist/types/doc/cell.d.ts +7 -7
- package/dist/types/doc/column.d.ts +9 -3
- package/dist/types/doc/defined-names.d.ts +4 -4
- package/dist/types/doc/image.d.ts +2 -2
- package/dist/types/doc/modelcontainer.d.ts +1 -1
- package/dist/types/doc/pivot-table.d.ts +1 -1
- package/dist/types/doc/range.d.ts +1 -1
- package/dist/types/doc/row.d.ts +3 -3
- package/dist/types/doc/table.d.ts +2 -2
- package/dist/types/doc/workbook.base.d.ts +111 -0
- package/dist/types/doc/workbook.browser.d.ts +38 -0
- package/dist/types/doc/workbook.d.ts +62 -92
- package/dist/types/doc/worksheet.d.ts +12 -10
- package/dist/types/index.browser.d.ts +19 -5
- package/dist/types/index.d.ts +24 -23
- package/dist/types/local.d.ts +0 -1
- package/dist/types/stream/xlsx/hyperlink-reader.d.ts +1 -1
- package/dist/types/stream/xlsx/workbook-reader.d.ts +4 -4
- package/dist/types/stream/xlsx/workbook-writer.d.ts +7 -7
- package/dist/types/stream/xlsx/worksheet-reader.d.ts +5 -5
- package/dist/types/stream/xlsx/worksheet-writer.d.ts +11 -9
- package/dist/types/types.d.ts +6 -0
- package/dist/types/utils/browser-buffer.d.ts +28 -0
- package/dist/types/utils/col-cache.d.ts +1 -1
- package/dist/types/utils/datetime.d.ts +56 -0
- package/dist/types/utils/encryptor.browser.d.ts +28 -0
- package/dist/types/utils/parse-sax.d.ts +108 -1
- package/dist/types/utils/sheet-utils.d.ts +3 -3
- package/dist/types/utils/stream-buf.browser.d.ts +41 -0
- package/dist/types/utils/unzip/extract.d.ts +6 -6
- package/dist/types/utils/unzip/index.d.ts +8 -8
- package/dist/types/utils/unzip/parse.d.ts +3 -3
- package/dist/types/utils/unzip/zip-parser.d.ts +5 -0
- package/dist/types/utils/utils.base.d.ts +29 -0
- package/dist/types/utils/utils.browser.d.ts +29 -0
- package/dist/types/utils/utils.d.ts +6 -25
- package/dist/types/utils/zip/compress.base.d.ts +45 -0
- package/dist/types/utils/zip/compress.browser.d.ts +63 -0
- package/dist/types/utils/zip/compress.d.ts +13 -45
- package/dist/types/utils/zip/crc32.browser.d.ts +52 -0
- package/dist/types/utils/zip/deflate-fallback.d.ts +39 -0
- package/dist/types/utils/zip/index.d.ts +5 -5
- package/dist/types/utils/zip/streaming-zip.d.ts +96 -0
- package/dist/types/utils/zip/zip-builder.d.ts +1 -1
- package/dist/types/utils/zip-stream.browser.d.ts +39 -0
- package/dist/types/xlsx/xform/base-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/book/defined-name-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/book/sheet-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/book/workbook-calc-properties-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/book/workbook-pivot-cache-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/book/workbook-properties-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/book/workbook-view-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/book/workbook-xform.d.ts +2 -2
- package/dist/types/xlsx/xform/comment/comment-xform.d.ts +2 -2
- package/dist/types/xlsx/xform/comment/comments-xform.d.ts +2 -2
- package/dist/types/xlsx/xform/comment/style/vml-position-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/comment/style/vml-protection-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/comment/vml-anchor-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/comment/vml-client-data-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/comment/vml-notes-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/comment/vml-shape-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/comment/vml-textbox-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/composite-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/core/app-heading-pairs-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/core/app-titles-of-parts-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/core/app-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/core/content-types-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/core/core-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/core/relationship-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/core/relationships-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/drawing/base-cell-anchor-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/drawing/blip-fill-xform.d.ts +2 -2
- package/dist/types/xlsx/xform/drawing/blip-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/drawing/c-nv-pic-pr-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/drawing/c-nv-pr-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/drawing/cell-position-xform.d.ts +2 -2
- package/dist/types/xlsx/xform/drawing/drawing-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/drawing/ext-lst-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/drawing/ext-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/drawing/hlink-click-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/drawing/nv-pic-pr-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/drawing/one-cell-anchor-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/drawing/pic-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/drawing/two-cell-anchor-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/list-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/pivot-table/cache-field-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/pivot-table/pivot-cache-definition-xform.d.ts +3 -3
- package/dist/types/xlsx/xform/pivot-table/pivot-cache-records-xform.d.ts +2 -2
- package/dist/types/xlsx/xform/pivot-table/pivot-table-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/auto-filter-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/cell-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/cf/cf-rule-xform.d.ts +6 -6
- package/dist/types/xlsx/xform/sheet/cf/cfvo-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/cf/color-scale-xform.d.ts +3 -3
- package/dist/types/xlsx/xform/sheet/cf/conditional-formatting-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/cf/conditional-formattings-xform.d.ts +2 -2
- package/dist/types/xlsx/xform/sheet/cf/databar-xform.d.ts +3 -3
- package/dist/types/xlsx/xform/sheet/cf/ext-lst-ref-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/cf/formula-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/cf/icon-set-xform.d.ts +2 -2
- package/dist/types/xlsx/xform/sheet/cf-ext/cf-icon-ext-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/cf-ext/cf-rule-ext-xform.d.ts +3 -3
- package/dist/types/xlsx/xform/sheet/cf-ext/cfvo-ext-xform.d.ts +2 -2
- package/dist/types/xlsx/xform/sheet/cf-ext/conditional-formatting-ext-xform.d.ts +3 -3
- package/dist/types/xlsx/xform/sheet/cf-ext/conditional-formattings-ext-xform.d.ts +2 -2
- package/dist/types/xlsx/xform/sheet/cf-ext/databar-ext-xform.d.ts +3 -3
- package/dist/types/xlsx/xform/sheet/cf-ext/f-ext-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/cf-ext/icon-set-ext-xform.d.ts +3 -3
- package/dist/types/xlsx/xform/sheet/cf-ext/sqref-ext-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/col-breaks-xform.d.ts +16 -0
- package/dist/types/xlsx/xform/sheet/col-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/data-validations-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/dimension-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/drawing-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/ext-lst-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/header-footer-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/hyperlink-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/merge-cell-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/outline-properties-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/page-breaks-xform.d.ts +5 -1
- package/dist/types/xlsx/xform/sheet/page-margins-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/page-setup-properties-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/page-setup-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/picture-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/print-options-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/row-breaks-xform.d.ts +5 -1
- package/dist/types/xlsx/xform/sheet/row-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/sheet-format-properties-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/sheet-properties-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/sheet-protection-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/sheet-view-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/table-part-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/worksheet-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/simple/boolean-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/simple/date-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/simple/float-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/simple/integer-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/simple/string-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/static-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/strings/phonetic-text-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/strings/rich-text-xform.d.ts +3 -3
- package/dist/types/xlsx/xform/strings/shared-string-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/strings/shared-strings-xform.d.ts +2 -2
- package/dist/types/xlsx/xform/strings/text-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/style/alignment-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/style/border-xform.d.ts +2 -2
- package/dist/types/xlsx/xform/style/color-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/style/dxf-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/style/fill-xform.d.ts +2 -2
- package/dist/types/xlsx/xform/style/font-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/style/numfmt-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/style/protection-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/style/style-xform.d.ts +3 -3
- package/dist/types/xlsx/xform/style/styles-xform.d.ts +2 -2
- package/dist/types/xlsx/xform/style/underline-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/table/auto-filter-xform.d.ts +2 -2
- package/dist/types/xlsx/xform/table/custom-filter-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/table/filter-column-xform.d.ts +2 -2
- package/dist/types/xlsx/xform/table/filter-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/table/table-column-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/table/table-style-info-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/table/table-xform.d.ts +1 -1
- package/dist/types/xlsx/xlsx.base.d.ts +134 -0
- package/dist/types/xlsx/xlsx.browser.d.ts +31 -0
- package/dist/types/xlsx/xlsx.d.ts +20 -80
- package/package.json +16 -39
|
@@ -0,0 +1,694 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSV Parser and Formatter - RFC 4180 compliant
|
|
3
|
+
*
|
|
4
|
+
* A lightweight, cross-platform CSV implementation that works in both
|
|
5
|
+
* Node.js and Browser environments with zero dependencies.
|
|
6
|
+
*
|
|
7
|
+
* High-performance RFC 4180 compliant CSV parser and formatter.
|
|
8
|
+
*
|
|
9
|
+
* @see https://tools.ietf.org/html/rfc4180
|
|
10
|
+
*/
|
|
11
|
+
// =============================================================================
|
|
12
|
+
// Helper Functions
|
|
13
|
+
// =============================================================================
|
|
14
|
+
/**
|
|
15
|
+
* Escape special regex characters
|
|
16
|
+
*/
|
|
17
|
+
function escapeRegex(str) {
|
|
18
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Check if a transform function is synchronous (1 argument) vs async (2 arguments)
|
|
22
|
+
*/
|
|
23
|
+
export function isSyncTransform(transform) {
|
|
24
|
+
return transform.length === 1;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Check if a validate function is synchronous (1 argument) vs async (2 arguments)
|
|
28
|
+
*/
|
|
29
|
+
export function isSyncValidate(validate) {
|
|
30
|
+
return validate.length === 1;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Check if headers are unique
|
|
34
|
+
*/
|
|
35
|
+
function validateUniqueHeaders(headers) {
|
|
36
|
+
const seen = new Set();
|
|
37
|
+
const duplicates = [];
|
|
38
|
+
for (const header of headers) {
|
|
39
|
+
if (header !== null && header !== undefined) {
|
|
40
|
+
if (seen.has(header)) {
|
|
41
|
+
duplicates.push(header);
|
|
42
|
+
}
|
|
43
|
+
seen.add(header);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (duplicates.length > 0) {
|
|
47
|
+
throw new Error(`Duplicate headers found ${JSON.stringify(duplicates)}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Apply trim options to a field
|
|
52
|
+
*/
|
|
53
|
+
function applyTrim(field, trim, ltrim, rtrim) {
|
|
54
|
+
if (trim) {
|
|
55
|
+
return field.trim();
|
|
56
|
+
}
|
|
57
|
+
let result = field;
|
|
58
|
+
if (ltrim) {
|
|
59
|
+
result = result.trimStart();
|
|
60
|
+
}
|
|
61
|
+
if (rtrim) {
|
|
62
|
+
result = result.trimEnd();
|
|
63
|
+
}
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
// =============================================================================
|
|
67
|
+
// Parse Functions
|
|
68
|
+
// =============================================================================
|
|
69
|
+
/**
|
|
70
|
+
* Parse a CSV string into rows of fields
|
|
71
|
+
*/
|
|
72
|
+
export function parseCsv(input, options = {}) {
|
|
73
|
+
const { delimiter = ",", quote: quoteOption = '"', escape: escapeOption = '"', skipEmptyLines = false, ignoreEmpty = false, trim = false, ltrim = false, rtrim = false, headers = false, renameHeaders = false, comment, maxRows, skipLines = 0, skipRows = 0, strictColumnHandling = false, discardUnmappedColumns = false, transform, validate } = options;
|
|
74
|
+
const shouldSkipEmpty = skipEmptyLines || ignoreEmpty;
|
|
75
|
+
// Handle quote: null/false to disable quoting
|
|
76
|
+
const quoteEnabled = quoteOption !== null && quoteOption !== false;
|
|
77
|
+
const quote = quoteEnabled ? String(quoteOption) : "";
|
|
78
|
+
const escape = escapeOption !== null && escapeOption !== false ? String(escapeOption) : "";
|
|
79
|
+
const rows = [];
|
|
80
|
+
const invalidRows = [];
|
|
81
|
+
let currentRow = [];
|
|
82
|
+
let currentField = "";
|
|
83
|
+
let inQuotes = false;
|
|
84
|
+
let i = 0;
|
|
85
|
+
let lineNumber = 0;
|
|
86
|
+
let dataRowCount = 0;
|
|
87
|
+
let skippedDataRows = 0;
|
|
88
|
+
// Header handling
|
|
89
|
+
let headerRow = null;
|
|
90
|
+
let headersLength = 0;
|
|
91
|
+
let useHeaders = false;
|
|
92
|
+
let headerRowProcessed = false;
|
|
93
|
+
// Determine header mode
|
|
94
|
+
if (headers === true) {
|
|
95
|
+
useHeaders = true;
|
|
96
|
+
}
|
|
97
|
+
else if (Array.isArray(headers)) {
|
|
98
|
+
headerRow = headers;
|
|
99
|
+
headersLength = headers.filter(h => h !== null && h !== undefined).length;
|
|
100
|
+
validateUniqueHeaders(headers);
|
|
101
|
+
useHeaders = true;
|
|
102
|
+
if (!renameHeaders) {
|
|
103
|
+
headerRowProcessed = true; // We already have headers, don't wait for first row
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else if (typeof headers === "function") {
|
|
107
|
+
useHeaders = true;
|
|
108
|
+
}
|
|
109
|
+
// Normalize line endings
|
|
110
|
+
input = input.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
111
|
+
const processRow = (row) => {
|
|
112
|
+
// If we have headers defined and this is the first data row (for headers: true)
|
|
113
|
+
// or we need to validate headers from a function
|
|
114
|
+
if (useHeaders && !headerRowProcessed) {
|
|
115
|
+
// First row is headers
|
|
116
|
+
if (typeof headers === "function") {
|
|
117
|
+
const transformed = headers(row);
|
|
118
|
+
validateUniqueHeaders(transformed);
|
|
119
|
+
headerRow = transformed;
|
|
120
|
+
}
|
|
121
|
+
else if (!Array.isArray(headers)) {
|
|
122
|
+
validateUniqueHeaders(row);
|
|
123
|
+
headerRow = row;
|
|
124
|
+
}
|
|
125
|
+
headersLength = headerRow.filter(h => h !== null && h !== undefined).length;
|
|
126
|
+
headerRowProcessed = true;
|
|
127
|
+
// If renameHeaders and custom headers provided, discard this row
|
|
128
|
+
if (renameHeaders) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
// For headers: true, don't add header row to data
|
|
132
|
+
if (headers === true || typeof headers === "function") {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
// Skip data rows
|
|
138
|
+
if (skippedDataRows < skipRows) {
|
|
139
|
+
skippedDataRows++;
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
// Column validation when using headers
|
|
143
|
+
if (headerRow && headerRow.length > 0) {
|
|
144
|
+
const expectedCols = headersLength;
|
|
145
|
+
const actualCols = row.length;
|
|
146
|
+
if (actualCols > expectedCols) {
|
|
147
|
+
if (strictColumnHandling && !discardUnmappedColumns) {
|
|
148
|
+
// Mark as invalid but continue
|
|
149
|
+
invalidRows.push({
|
|
150
|
+
row,
|
|
151
|
+
reason: `Column header mismatch expected: ${expectedCols} columns got: ${actualCols}`
|
|
152
|
+
});
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
// Default: trim extra columns
|
|
157
|
+
row.length = headerRow.length;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
else if (actualCols < expectedCols) {
|
|
161
|
+
if (strictColumnHandling) {
|
|
162
|
+
invalidRows.push({
|
|
163
|
+
row,
|
|
164
|
+
reason: `Column header mismatch expected: ${expectedCols} columns got: ${actualCols}`
|
|
165
|
+
});
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
// Pad with empty strings
|
|
169
|
+
while (row.length < headerRow.length) {
|
|
170
|
+
row.push("");
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return true;
|
|
175
|
+
};
|
|
176
|
+
while (i < input.length) {
|
|
177
|
+
const char = input[i];
|
|
178
|
+
const nextChar = input[i + 1];
|
|
179
|
+
if (inQuotes && quoteEnabled) {
|
|
180
|
+
// Inside quoted field
|
|
181
|
+
if (escape && char === escape && nextChar === quote) {
|
|
182
|
+
// Escaped quote
|
|
183
|
+
currentField += quote;
|
|
184
|
+
i += 2;
|
|
185
|
+
}
|
|
186
|
+
else if (char === quote) {
|
|
187
|
+
// End of quoted field
|
|
188
|
+
inQuotes = false;
|
|
189
|
+
i++;
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
currentField += char;
|
|
193
|
+
i++;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
// Outside quoted field
|
|
198
|
+
if (quoteEnabled && char === quote && currentField === "") {
|
|
199
|
+
// Start of quoted field
|
|
200
|
+
inQuotes = true;
|
|
201
|
+
i++;
|
|
202
|
+
}
|
|
203
|
+
else if (char === delimiter) {
|
|
204
|
+
// Field separator
|
|
205
|
+
currentRow.push(applyTrim(currentField, trim, ltrim, rtrim));
|
|
206
|
+
currentField = "";
|
|
207
|
+
i++;
|
|
208
|
+
}
|
|
209
|
+
else if (char === "\n") {
|
|
210
|
+
// End of row
|
|
211
|
+
currentRow.push(applyTrim(currentField, trim, ltrim, rtrim));
|
|
212
|
+
currentField = "";
|
|
213
|
+
lineNumber++;
|
|
214
|
+
// Skip lines at beginning
|
|
215
|
+
if (lineNumber <= skipLines) {
|
|
216
|
+
currentRow = [];
|
|
217
|
+
i++;
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
// Skip comment lines
|
|
221
|
+
if (comment && currentRow[0]?.startsWith(comment)) {
|
|
222
|
+
currentRow = [];
|
|
223
|
+
i++;
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
// Skip empty lines
|
|
227
|
+
const isEmpty = currentRow.length === 1 && currentRow[0] === "";
|
|
228
|
+
if (shouldSkipEmpty && isEmpty) {
|
|
229
|
+
currentRow = [];
|
|
230
|
+
i++;
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
// Process row (handles headers, validation)
|
|
234
|
+
if (processRow(currentRow)) {
|
|
235
|
+
rows.push(currentRow);
|
|
236
|
+
dataRowCount++;
|
|
237
|
+
}
|
|
238
|
+
currentRow = [];
|
|
239
|
+
i++;
|
|
240
|
+
// Check max rows - after resetting currentRow
|
|
241
|
+
if (maxRows !== undefined && dataRowCount >= maxRows) {
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
currentField += char;
|
|
247
|
+
i++;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
// Handle last field/row
|
|
252
|
+
if (currentField !== "" || currentRow.length > 0) {
|
|
253
|
+
currentRow.push(applyTrim(currentField, trim, ltrim, rtrim));
|
|
254
|
+
// Skip lines at beginning
|
|
255
|
+
if (lineNumber >= skipLines) {
|
|
256
|
+
// Skip comment lines
|
|
257
|
+
if (!(comment && currentRow[0]?.startsWith(comment))) {
|
|
258
|
+
// Skip empty lines
|
|
259
|
+
const isEmpty = currentRow.length === 1 && currentRow[0] === "";
|
|
260
|
+
if (!(shouldSkipEmpty && isEmpty)) {
|
|
261
|
+
if (!(maxRows !== undefined && dataRowCount >= maxRows)) {
|
|
262
|
+
if (processRow(currentRow)) {
|
|
263
|
+
rows.push(currentRow);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
// Convert to objects if headers enabled
|
|
271
|
+
if (useHeaders && headerRow) {
|
|
272
|
+
let dataRows = rows.map(row => {
|
|
273
|
+
const obj = {};
|
|
274
|
+
headerRow.forEach((header, index) => {
|
|
275
|
+
if (header !== null && header !== undefined) {
|
|
276
|
+
obj[header] = row[index] ?? "";
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
return obj;
|
|
280
|
+
});
|
|
281
|
+
// Apply transform if provided
|
|
282
|
+
if (transform) {
|
|
283
|
+
dataRows = dataRows
|
|
284
|
+
.map(row => transform(row))
|
|
285
|
+
.filter((row) => row !== null && row !== undefined);
|
|
286
|
+
}
|
|
287
|
+
// Apply validate if provided
|
|
288
|
+
if (validate) {
|
|
289
|
+
const validatedRows = [];
|
|
290
|
+
for (const row of dataRows) {
|
|
291
|
+
const result = validate(row);
|
|
292
|
+
if (typeof result === "boolean") {
|
|
293
|
+
if (result) {
|
|
294
|
+
validatedRows.push(row);
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
invalidRows.push({ row: Object.values(row), reason: "Validation failed" });
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
if (result.isValid) {
|
|
302
|
+
validatedRows.push(row);
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
invalidRows.push({
|
|
306
|
+
row: Object.values(row),
|
|
307
|
+
reason: result.reason || "Validation failed"
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
dataRows = validatedRows;
|
|
313
|
+
}
|
|
314
|
+
if ((strictColumnHandling || validate) && invalidRows.length > 0) {
|
|
315
|
+
return {
|
|
316
|
+
headers: headerRow.filter((h) => h !== null && h !== undefined),
|
|
317
|
+
rows: dataRows,
|
|
318
|
+
invalidRows
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
return {
|
|
322
|
+
headers: headerRow.filter((h) => h !== null && h !== undefined),
|
|
323
|
+
rows: dataRows
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
// For array mode (no headers), apply transform and validate
|
|
327
|
+
let resultRows = rows;
|
|
328
|
+
if (transform) {
|
|
329
|
+
resultRows = resultRows
|
|
330
|
+
.map(row => transform(row))
|
|
331
|
+
.filter((row) => row !== null && row !== undefined);
|
|
332
|
+
}
|
|
333
|
+
if (validate) {
|
|
334
|
+
const validatedRows = [];
|
|
335
|
+
const arrayInvalidRows = [];
|
|
336
|
+
for (const row of resultRows) {
|
|
337
|
+
const result = validate(row);
|
|
338
|
+
if (typeof result === "boolean") {
|
|
339
|
+
if (result) {
|
|
340
|
+
validatedRows.push(row);
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
arrayInvalidRows.push({ row, reason: "Validation failed" });
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
if (result.isValid) {
|
|
348
|
+
validatedRows.push(row);
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
arrayInvalidRows.push({ row, reason: result.reason || "Validation failed" });
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
resultRows = validatedRows;
|
|
356
|
+
if (arrayInvalidRows.length > 0) {
|
|
357
|
+
return {
|
|
358
|
+
rows: resultRows,
|
|
359
|
+
invalidRows: arrayInvalidRows
|
|
360
|
+
}; // Return with invalidRows for array mode too
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
return resultRows;
|
|
364
|
+
}
|
|
365
|
+
// =============================================================================
|
|
366
|
+
// Format Functions
|
|
367
|
+
// =============================================================================
|
|
368
|
+
/**
|
|
369
|
+
* Format data as a CSV string
|
|
370
|
+
*/
|
|
371
|
+
export function formatCsv(data, options = {}) {
|
|
372
|
+
const { delimiter = ",", quote: quoteOption = '"', escape: escapeOption, rowDelimiter = "\n", alwaysQuote = false, quoteColumns = false, quoteHeaders = false, headers, writeHeaders: writeHeadersOption, writeBOM = false, includeEndRowDelimiter = false, alwaysWriteHeaders = false, transform } = options;
|
|
373
|
+
// Determine if headers should be written (default: true when headers is provided)
|
|
374
|
+
const shouldWriteHeaders = writeHeadersOption ?? true;
|
|
375
|
+
// If quote is false or null, disable quoting entirely
|
|
376
|
+
const quoteEnabled = quoteOption !== false && quoteOption !== null;
|
|
377
|
+
const quote = quoteEnabled ? String(quoteOption) : "";
|
|
378
|
+
const escape = escapeOption !== undefined && escapeOption !== false && escapeOption !== null
|
|
379
|
+
? String(escapeOption)
|
|
380
|
+
: quote;
|
|
381
|
+
const lines = [];
|
|
382
|
+
const shouldQuoteColumn = (index, header, isHeader = false) => {
|
|
383
|
+
const quoteConfig = isHeader ? quoteHeaders : quoteColumns;
|
|
384
|
+
if (typeof quoteConfig === "boolean") {
|
|
385
|
+
return quoteConfig;
|
|
386
|
+
}
|
|
387
|
+
if (Array.isArray(quoteConfig)) {
|
|
388
|
+
return quoteConfig[index] === true;
|
|
389
|
+
}
|
|
390
|
+
if (typeof quoteConfig === "object" && header) {
|
|
391
|
+
return quoteConfig[header] === true;
|
|
392
|
+
}
|
|
393
|
+
return false;
|
|
394
|
+
};
|
|
395
|
+
const formatField = (value, index, header, isHeader = false) => {
|
|
396
|
+
if (value === null || value === undefined) {
|
|
397
|
+
return "";
|
|
398
|
+
}
|
|
399
|
+
const str = String(value);
|
|
400
|
+
// If quoting is disabled, return raw string
|
|
401
|
+
if (!quoteEnabled) {
|
|
402
|
+
return str;
|
|
403
|
+
}
|
|
404
|
+
// Check if quoting is needed
|
|
405
|
+
const forceQuote = alwaysQuote || shouldQuoteColumn(index, header, isHeader);
|
|
406
|
+
// Check if quoting is needed (contains delimiter, quote, or newline)
|
|
407
|
+
const quoteRegex = new RegExp(`[${escapeRegex(delimiter)}${escapeRegex(quote)}\r\n]`);
|
|
408
|
+
const needsQuote = forceQuote || quoteRegex.test(str);
|
|
409
|
+
if (needsQuote) {
|
|
410
|
+
// Escape quotes
|
|
411
|
+
const escaped = str.replace(new RegExp(escapeRegex(quote), "g"), escape + quote);
|
|
412
|
+
return quote + escaped + quote;
|
|
413
|
+
}
|
|
414
|
+
return str;
|
|
415
|
+
};
|
|
416
|
+
const formatRow = (row, rowHeaders, isHeader = false) => {
|
|
417
|
+
return row
|
|
418
|
+
.map((value, index) => formatField(value, index, rowHeaders?.[index], isHeader))
|
|
419
|
+
.join(delimiter);
|
|
420
|
+
};
|
|
421
|
+
// Determine headers
|
|
422
|
+
let keys = null;
|
|
423
|
+
// Helper to apply transform if provided (sync only)
|
|
424
|
+
const applyTransform = (row) => {
|
|
425
|
+
if (transform) {
|
|
426
|
+
// Check if it's a sync transform (1 argument)
|
|
427
|
+
if (transform.length === 1) {
|
|
428
|
+
return transform(row);
|
|
429
|
+
}
|
|
430
|
+
// For async transform in sync context, just return the row unchanged
|
|
431
|
+
// Async transforms should use streaming API
|
|
432
|
+
return row;
|
|
433
|
+
}
|
|
434
|
+
return row;
|
|
435
|
+
};
|
|
436
|
+
// Handle array of objects
|
|
437
|
+
if (data.length > 0 && !Array.isArray(data[0])) {
|
|
438
|
+
const objects = data;
|
|
439
|
+
keys = headers === true ? Object.keys(objects[0]) : Array.isArray(headers) ? headers : null;
|
|
440
|
+
if (keys && shouldWriteHeaders) {
|
|
441
|
+
// Add header row
|
|
442
|
+
lines.push(formatRow(keys, keys, true));
|
|
443
|
+
}
|
|
444
|
+
// Add data rows
|
|
445
|
+
for (const obj of objects) {
|
|
446
|
+
const transformedObj = applyTransform(obj);
|
|
447
|
+
if (transformedObj === null || transformedObj === undefined) {
|
|
448
|
+
continue; // Skip row if transform returns null
|
|
449
|
+
}
|
|
450
|
+
const row = keys ? keys.map(key => transformedObj[key]) : Object.values(transformedObj);
|
|
451
|
+
lines.push(formatRow(row, keys ?? undefined));
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
else if (data.length > 0) {
|
|
455
|
+
// Handle 2D array with data
|
|
456
|
+
const arrays = data;
|
|
457
|
+
// Add custom headers if provided
|
|
458
|
+
if (Array.isArray(headers)) {
|
|
459
|
+
keys = headers;
|
|
460
|
+
if (shouldWriteHeaders) {
|
|
461
|
+
lines.push(formatRow(headers, headers, true));
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
for (const row of arrays) {
|
|
465
|
+
const transformedRow = applyTransform(row);
|
|
466
|
+
if (transformedRow === null || transformedRow === undefined) {
|
|
467
|
+
continue; // Skip row if transform returns null
|
|
468
|
+
}
|
|
469
|
+
lines.push(formatRow(transformedRow, keys ?? undefined));
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
else if (alwaysWriteHeaders && Array.isArray(headers) && shouldWriteHeaders) {
|
|
473
|
+
// Handle empty data with alwaysWriteHeaders
|
|
474
|
+
lines.push(formatRow(headers, headers, true));
|
|
475
|
+
}
|
|
476
|
+
let result = lines.join(rowDelimiter);
|
|
477
|
+
// Add trailing row delimiter
|
|
478
|
+
if (result.length > 0 && includeEndRowDelimiter) {
|
|
479
|
+
result += rowDelimiter;
|
|
480
|
+
}
|
|
481
|
+
// Add BOM for UTF-8
|
|
482
|
+
if (writeBOM) {
|
|
483
|
+
result = "\uFEFF" + result;
|
|
484
|
+
}
|
|
485
|
+
return result;
|
|
486
|
+
}
|
|
487
|
+
// =============================================================================
|
|
488
|
+
// Streaming Parser
|
|
489
|
+
// =============================================================================
|
|
490
|
+
/**
|
|
491
|
+
* Async CSV parser that yields rows one at a time
|
|
492
|
+
*/
|
|
493
|
+
export async function* parseCsvStream(input, options = {}) {
|
|
494
|
+
const { delimiter = ",", quote: quoteOption = '"', escape: escapeOption = '"', skipEmptyLines = false, ignoreEmpty = false, trim = false, ltrim = false, rtrim = false, headers = false, renameHeaders = false, comment, maxRows, skipLines = 0, skipRows = 0, strictColumnHandling = false, discardUnmappedColumns = false } = options;
|
|
495
|
+
const shouldSkipEmpty = skipEmptyLines || ignoreEmpty;
|
|
496
|
+
// Handle quote: null/false to disable quoting
|
|
497
|
+
const quoteEnabled = quoteOption !== null && quoteOption !== false;
|
|
498
|
+
const quote = quoteEnabled ? String(quoteOption) : "";
|
|
499
|
+
const escape = escapeOption !== null && escapeOption !== false ? String(escapeOption) : "";
|
|
500
|
+
let headerRow = null;
|
|
501
|
+
let headersLength = 0;
|
|
502
|
+
let useHeaders = false;
|
|
503
|
+
let headerRowProcessed = false;
|
|
504
|
+
let buffer = "";
|
|
505
|
+
let currentRow = [];
|
|
506
|
+
let currentField = "";
|
|
507
|
+
let inQuotes = false;
|
|
508
|
+
let lineNumber = 0;
|
|
509
|
+
let dataRowCount = 0;
|
|
510
|
+
let skippedDataRows = 0;
|
|
511
|
+
// Determine header mode
|
|
512
|
+
if (headers === true) {
|
|
513
|
+
useHeaders = true;
|
|
514
|
+
}
|
|
515
|
+
else if (Array.isArray(headers)) {
|
|
516
|
+
headerRow = headers;
|
|
517
|
+
headersLength = headers.filter(h => h !== null && h !== undefined).length;
|
|
518
|
+
validateUniqueHeaders(headers);
|
|
519
|
+
useHeaders = true;
|
|
520
|
+
if (!renameHeaders) {
|
|
521
|
+
headerRowProcessed = true;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
else if (typeof headers === "function") {
|
|
525
|
+
useHeaders = true;
|
|
526
|
+
}
|
|
527
|
+
const processRow = (row) => {
|
|
528
|
+
// Header handling
|
|
529
|
+
if (useHeaders && !headerRowProcessed) {
|
|
530
|
+
if (typeof headers === "function") {
|
|
531
|
+
const transformed = headers(row);
|
|
532
|
+
validateUniqueHeaders(transformed);
|
|
533
|
+
headerRow = transformed;
|
|
534
|
+
}
|
|
535
|
+
else if (!Array.isArray(headers)) {
|
|
536
|
+
validateUniqueHeaders(row);
|
|
537
|
+
headerRow = row;
|
|
538
|
+
}
|
|
539
|
+
headersLength = headerRow.filter(h => h !== null && h !== undefined).length;
|
|
540
|
+
headerRowProcessed = true;
|
|
541
|
+
if (renameHeaders) {
|
|
542
|
+
return { valid: false, row: null };
|
|
543
|
+
}
|
|
544
|
+
if (headers === true || typeof headers === "function") {
|
|
545
|
+
return { valid: false, row: null };
|
|
546
|
+
}
|
|
547
|
+
return { valid: false, row: null };
|
|
548
|
+
}
|
|
549
|
+
// Skip data rows
|
|
550
|
+
if (skippedDataRows < skipRows) {
|
|
551
|
+
skippedDataRows++;
|
|
552
|
+
return { valid: false, row: null };
|
|
553
|
+
}
|
|
554
|
+
// Column validation
|
|
555
|
+
if (headerRow && headerRow.length > 0) {
|
|
556
|
+
const expectedCols = headersLength;
|
|
557
|
+
const actualCols = row.length;
|
|
558
|
+
if (actualCols > expectedCols) {
|
|
559
|
+
if (strictColumnHandling && !discardUnmappedColumns) {
|
|
560
|
+
return { valid: false, row: null };
|
|
561
|
+
}
|
|
562
|
+
else {
|
|
563
|
+
// Default: trim extra columns
|
|
564
|
+
row.length = headerRow.length;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
else if (actualCols < expectedCols) {
|
|
568
|
+
if (strictColumnHandling) {
|
|
569
|
+
return { valid: false, row: null };
|
|
570
|
+
}
|
|
571
|
+
while (row.length < headerRow.length) {
|
|
572
|
+
row.push("");
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
// Convert to object if using headers
|
|
577
|
+
if (useHeaders && headerRow) {
|
|
578
|
+
const obj = {};
|
|
579
|
+
headerRow.forEach((header, index) => {
|
|
580
|
+
if (header !== null && header !== undefined) {
|
|
581
|
+
obj[header] = row[index] ?? "";
|
|
582
|
+
}
|
|
583
|
+
});
|
|
584
|
+
return { valid: true, row: obj };
|
|
585
|
+
}
|
|
586
|
+
return { valid: true, row };
|
|
587
|
+
};
|
|
588
|
+
const processBuffer = function* () {
|
|
589
|
+
let i = 0;
|
|
590
|
+
while (i < buffer.length) {
|
|
591
|
+
const char = buffer[i];
|
|
592
|
+
const nextChar = buffer[i + 1];
|
|
593
|
+
if (inQuotes && quoteEnabled) {
|
|
594
|
+
if (escape && char === escape && nextChar === quote) {
|
|
595
|
+
currentField += quote;
|
|
596
|
+
i += 2;
|
|
597
|
+
}
|
|
598
|
+
else if (char === quote) {
|
|
599
|
+
inQuotes = false;
|
|
600
|
+
i++;
|
|
601
|
+
}
|
|
602
|
+
else if (i === buffer.length - 1) {
|
|
603
|
+
buffer = buffer.slice(i);
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
else {
|
|
607
|
+
currentField += char;
|
|
608
|
+
i++;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
else {
|
|
612
|
+
if (quoteEnabled && char === quote && currentField === "") {
|
|
613
|
+
inQuotes = true;
|
|
614
|
+
i++;
|
|
615
|
+
}
|
|
616
|
+
else if (char === delimiter) {
|
|
617
|
+
currentRow.push(applyTrim(currentField, trim, ltrim, rtrim));
|
|
618
|
+
currentField = "";
|
|
619
|
+
i++;
|
|
620
|
+
}
|
|
621
|
+
else if (char === "\n" || char === "\r") {
|
|
622
|
+
if (char === "\r" && nextChar === "\n") {
|
|
623
|
+
i++;
|
|
624
|
+
}
|
|
625
|
+
currentRow.push(applyTrim(currentField, trim, ltrim, rtrim));
|
|
626
|
+
currentField = "";
|
|
627
|
+
lineNumber++;
|
|
628
|
+
if (lineNumber <= skipLines) {
|
|
629
|
+
currentRow = [];
|
|
630
|
+
i++;
|
|
631
|
+
continue;
|
|
632
|
+
}
|
|
633
|
+
if (comment && currentRow[0]?.startsWith(comment)) {
|
|
634
|
+
currentRow = [];
|
|
635
|
+
i++;
|
|
636
|
+
continue;
|
|
637
|
+
}
|
|
638
|
+
const isEmpty = currentRow.length === 1 && currentRow[0] === "";
|
|
639
|
+
if (shouldSkipEmpty && isEmpty) {
|
|
640
|
+
currentRow = [];
|
|
641
|
+
i++;
|
|
642
|
+
continue;
|
|
643
|
+
}
|
|
644
|
+
const result = processRow(currentRow);
|
|
645
|
+
if (result.valid && result.row) {
|
|
646
|
+
dataRowCount++;
|
|
647
|
+
if (maxRows !== undefined && dataRowCount > maxRows) {
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
yield result.row;
|
|
651
|
+
}
|
|
652
|
+
currentRow = [];
|
|
653
|
+
i++;
|
|
654
|
+
}
|
|
655
|
+
else {
|
|
656
|
+
currentField += char;
|
|
657
|
+
i++;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
buffer = "";
|
|
662
|
+
};
|
|
663
|
+
// Handle string input
|
|
664
|
+
if (typeof input === "string") {
|
|
665
|
+
buffer = input;
|
|
666
|
+
yield* processBuffer();
|
|
667
|
+
// Handle last row
|
|
668
|
+
if (currentField !== "" || currentRow.length > 0) {
|
|
669
|
+
currentRow.push(applyTrim(currentField, trim, ltrim, rtrim));
|
|
670
|
+
if (!(maxRows !== undefined && dataRowCount >= maxRows)) {
|
|
671
|
+
const result = processRow(currentRow);
|
|
672
|
+
if (result.valid && result.row) {
|
|
673
|
+
yield result.row;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
// Handle async iterable
|
|
680
|
+
for await (const chunk of input) {
|
|
681
|
+
buffer += chunk;
|
|
682
|
+
yield* processBuffer();
|
|
683
|
+
}
|
|
684
|
+
// Handle last row
|
|
685
|
+
if (currentField !== "" || currentRow.length > 0) {
|
|
686
|
+
currentRow.push(applyTrim(currentField, trim, ltrim, rtrim));
|
|
687
|
+
if (!(maxRows !== undefined && dataRowCount >= maxRows)) {
|
|
688
|
+
const result = processRow(currentRow);
|
|
689
|
+
if (result.valid && result.row) {
|
|
690
|
+
yield result.row;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
}
|