@cj-tech-master/excelts 4.2.1 → 4.2.2-canary.20260115044841.88820eb

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.
Files changed (331) hide show
  1. package/THIRD_PARTY_NOTICES.md +0 -31
  2. package/dist/browser/index.browser.d.ts +1 -0
  3. package/dist/browser/index.browser.js +12 -0
  4. package/dist/{esm/modules/archive → browser/modules/archive/compression}/compress.base.js +1 -1
  5. package/dist/{types/modules/archive → browser/modules/archive/compression}/compress.browser.d.ts +2 -8
  6. package/dist/browser/modules/archive/{compress.browser.js → compression/compress.browser.js} +3 -11
  7. package/dist/browser/modules/archive/{compress.d.ts → compression/compress.d.ts} +2 -2
  8. package/dist/{esm/modules/archive → browser/modules/archive/compression}/compress.js +1 -1
  9. package/dist/browser/modules/archive/{crc32.browser.d.ts → compression/crc32.browser.d.ts} +1 -1
  10. package/dist/browser/modules/archive/{crc32.d.ts → compression/crc32.d.ts} +1 -1
  11. package/dist/browser/modules/archive/{crc32.js → compression/crc32.js} +1 -1
  12. package/dist/browser/modules/archive/{deflate-fallback.js → compression/deflate-fallback.js} +1 -1
  13. package/dist/browser/modules/archive/{streaming-compress.browser.d.ts → compression/streaming-compress.browser.d.ts} +2 -2
  14. package/dist/browser/modules/archive/{streaming-compress.browser.js → compression/streaming-compress.browser.js} +3 -3
  15. package/dist/browser/modules/archive/{streaming-compress.d.ts → compression/streaming-compress.d.ts} +2 -2
  16. package/dist/browser/modules/archive/{streaming-compress.js → compression/streaming-compress.js} +2 -2
  17. package/dist/browser/modules/archive/defaults.d.ts +1 -0
  18. package/dist/browser/modules/archive/defaults.js +6 -3
  19. package/dist/browser/modules/archive/index.base.d.ts +4 -4
  20. package/dist/browser/modules/archive/index.base.js +3 -6
  21. package/dist/browser/modules/archive/index.browser.d.ts +3 -4
  22. package/dist/browser/modules/archive/index.browser.js +3 -7
  23. package/dist/browser/modules/archive/index.d.ts +3 -4
  24. package/dist/browser/modules/archive/index.js +3 -5
  25. package/dist/browser/modules/archive/internal/byte-queue.d.ts +33 -0
  26. package/dist/browser/modules/archive/internal/byte-queue.js +407 -0
  27. package/dist/browser/modules/archive/io/archive-sink.d.ts +8 -0
  28. package/dist/browser/modules/archive/io/archive-sink.js +45 -0
  29. package/dist/browser/modules/archive/io/archive-source.d.ts +6 -0
  30. package/dist/browser/modules/archive/io/archive-source.js +100 -0
  31. package/dist/browser/modules/archive/{extract.d.ts → unzip/extract.d.ts} +2 -2
  32. package/dist/browser/modules/archive/unzip/index.d.ts +40 -0
  33. package/dist/browser/modules/archive/unzip/index.js +164 -0
  34. package/dist/browser/modules/archive/{parse.base.d.ts → unzip/stream.base.d.ts} +36 -2
  35. package/dist/browser/modules/archive/unzip/stream.base.js +1022 -0
  36. package/dist/browser/modules/archive/{parse.browser.d.ts → unzip/stream.browser.d.ts} +1 -1
  37. package/dist/browser/modules/archive/{parse.browser.js → unzip/stream.browser.js} +371 -110
  38. package/dist/browser/modules/archive/{parse.d.ts → unzip/stream.d.ts} +2 -2
  39. package/dist/{esm/modules/archive/parse.js → browser/modules/archive/unzip/stream.js} +6 -5
  40. package/dist/browser/modules/archive/{zip-parser.d.ts → unzip/zip-parser.d.ts} +1 -1
  41. package/dist/{esm/modules/archive → browser/modules/archive/unzip}/zip-parser.js +38 -24
  42. package/dist/browser/modules/archive/utils/async-queue.d.ts +7 -0
  43. package/dist/browser/modules/archive/utils/async-queue.js +103 -0
  44. package/dist/browser/modules/archive/utils/bytes.js +16 -16
  45. package/dist/browser/modules/archive/utils/compressibility.d.ts +10 -0
  46. package/dist/browser/modules/archive/utils/compressibility.js +57 -0
  47. package/dist/browser/modules/archive/utils/parse-buffer.js +21 -23
  48. package/dist/browser/modules/archive/utils/pattern-scanner.d.ts +21 -0
  49. package/dist/browser/modules/archive/utils/pattern-scanner.js +27 -0
  50. package/dist/browser/modules/archive/utils/timestamps.js +62 -1
  51. package/dist/browser/modules/archive/utils/zip-extra-fields.d.ts +1 -1
  52. package/dist/browser/modules/archive/utils/zip-extra-fields.js +26 -14
  53. package/dist/browser/modules/archive/zip/index.d.ts +42 -0
  54. package/dist/browser/modules/archive/zip/index.js +157 -0
  55. package/dist/browser/modules/archive/{streaming-zip.d.ts → zip/stream.d.ts} +28 -5
  56. package/dist/browser/modules/archive/{streaming-zip.js → zip/stream.js} +192 -48
  57. package/dist/browser/modules/archive/zip/zip-bytes.d.ts +73 -0
  58. package/dist/browser/modules/archive/zip/zip-bytes.js +239 -0
  59. package/dist/{esm/modules/archive → browser/modules/archive/zip}/zip-entry-metadata.js +3 -3
  60. package/dist/browser/modules/archive/{zip-records.d.ts → zip-spec/zip-records.d.ts} +20 -0
  61. package/dist/browser/modules/archive/zip-spec/zip-records.js +126 -0
  62. package/dist/browser/modules/excel/stream/workbook-reader.browser.js +1 -1
  63. package/dist/browser/modules/excel/stream/workbook-writer.browser.d.ts +1 -1
  64. package/dist/browser/modules/excel/stream/workbook-writer.browser.js +1 -1
  65. package/dist/browser/modules/excel/utils/ooxml-validator.d.ts +48 -0
  66. package/dist/browser/modules/excel/utils/ooxml-validator.js +469 -0
  67. package/dist/browser/modules/excel/utils/parse-sax.d.ts +3 -0
  68. package/dist/browser/modules/excel/utils/parse-sax.js +32 -13
  69. package/dist/browser/modules/excel/worksheet.js +5 -2
  70. package/dist/browser/modules/excel/xlsx/xform/core/app-xform.js +3 -3
  71. package/dist/browser/modules/excel/xlsx/xform/core/core-xform.js +56 -68
  72. package/dist/browser/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.d.ts +1 -0
  73. package/dist/browser/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +13 -1
  74. package/dist/browser/modules/excel/xlsx/xform/drawing/sp-xform.d.ts +18 -0
  75. package/dist/browser/modules/excel/xlsx/xform/drawing/sp-xform.js +112 -0
  76. package/dist/browser/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.d.ts +6 -1
  77. package/dist/browser/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +30 -2
  78. package/dist/browser/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +11 -0
  79. package/dist/browser/modules/excel/xlsx/xform/list-xform.js +8 -10
  80. package/dist/browser/modules/excel/xlsx/xform/sheet/page-setup-xform.d.ts +1 -0
  81. package/dist/browser/modules/excel/xlsx/xform/sheet/page-setup-xform.js +16 -2
  82. package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +110 -12
  83. package/dist/browser/modules/excel/xlsx/xform/strings/shared-string-xform.js +2 -3
  84. package/dist/browser/modules/excel/xlsx/xform/strings/text-xform.js +5 -7
  85. package/dist/browser/modules/excel/xlsx/xlsx.browser.js +11 -10
  86. package/dist/browser/modules/excel/xlsx/xlsx.js +1 -1
  87. package/dist/browser/modules/stream/base-transform.d.ts +3 -0
  88. package/dist/browser/modules/stream/base-transform.js +34 -20
  89. package/dist/browser/modules/stream/buffered-stream.d.ts +2 -12
  90. package/dist/browser/modules/stream/chunked-builder.js +4 -4
  91. package/dist/browser/modules/stream/index.browser.d.ts +13 -19
  92. package/dist/browser/modules/stream/index.browser.js +10 -22
  93. package/dist/browser/modules/stream/index.d.ts +18 -41
  94. package/dist/browser/modules/stream/index.js +15 -44
  95. package/dist/browser/modules/stream/internal/event-utils.d.ts +17 -0
  96. package/dist/browser/modules/stream/internal/event-utils.js +40 -0
  97. package/dist/browser/modules/stream/internal/type-guards.d.ts +9 -0
  98. package/dist/browser/modules/stream/internal/type-guards.js +24 -0
  99. package/dist/browser/modules/stream/pull-stream.d.ts +5 -6
  100. package/dist/browser/modules/stream/pull-stream.js +107 -43
  101. package/dist/browser/modules/stream/shared.d.ts +1 -1
  102. package/dist/browser/modules/stream/shared.js +7 -4
  103. package/dist/browser/modules/stream/streams.browser.d.ts +32 -44
  104. package/dist/browser/modules/stream/streams.browser.js +921 -836
  105. package/dist/browser/modules/stream/streams.d.ts +4 -20
  106. package/dist/browser/modules/stream/streams.js +146 -95
  107. package/dist/browser/modules/stream/utils.js +5 -38
  108. package/dist/cjs/modules/archive/{compress.base.js → compression/compress.base.js} +1 -1
  109. package/dist/cjs/modules/archive/{compress.browser.js → compression/compress.browser.js} +3 -11
  110. package/dist/cjs/modules/archive/{compress.js → compression/compress.js} +1 -1
  111. package/dist/cjs/modules/archive/{crc32.js → compression/crc32.js} +1 -1
  112. package/dist/cjs/modules/archive/{deflate-fallback.js → compression/deflate-fallback.js} +1 -1
  113. package/dist/cjs/modules/archive/{streaming-compress.browser.js → compression/streaming-compress.browser.js} +3 -3
  114. package/dist/cjs/modules/archive/{streaming-compress.js → compression/streaming-compress.js} +2 -2
  115. package/dist/cjs/modules/archive/defaults.js +7 -4
  116. package/dist/cjs/modules/archive/index.base.js +9 -19
  117. package/dist/cjs/modules/archive/index.browser.js +4 -10
  118. package/dist/cjs/modules/archive/index.js +4 -8
  119. package/dist/cjs/modules/archive/internal/byte-queue.js +411 -0
  120. package/dist/cjs/modules/archive/io/archive-sink.js +49 -0
  121. package/dist/cjs/modules/archive/io/archive-source.js +105 -0
  122. package/dist/cjs/modules/archive/unzip/index.js +170 -0
  123. package/dist/cjs/modules/archive/unzip/stream.base.js +1044 -0
  124. package/dist/cjs/modules/archive/{parse.browser.js → unzip/stream.browser.js} +372 -111
  125. package/dist/cjs/modules/archive/{parse.js → unzip/stream.js} +9 -8
  126. package/dist/cjs/modules/archive/{zip-parser.js → unzip/zip-parser.js} +47 -33
  127. package/dist/cjs/modules/archive/utils/async-queue.js +106 -0
  128. package/dist/cjs/modules/archive/utils/bytes.js +16 -16
  129. package/dist/cjs/modules/archive/utils/compressibility.js +60 -0
  130. package/dist/cjs/modules/archive/utils/parse-buffer.js +21 -23
  131. package/dist/cjs/modules/archive/utils/pattern-scanner.js +31 -0
  132. package/dist/cjs/modules/archive/utils/timestamps.js +64 -3
  133. package/dist/cjs/modules/archive/utils/zip-extra-fields.js +26 -14
  134. package/dist/cjs/modules/archive/zip/index.js +162 -0
  135. package/dist/cjs/modules/archive/{streaming-zip.js → zip/stream.js} +194 -50
  136. package/dist/cjs/modules/archive/zip/zip-bytes.js +242 -0
  137. package/dist/cjs/modules/archive/{zip-entry-metadata.js → zip/zip-entry-metadata.js} +5 -5
  138. package/dist/cjs/modules/archive/zip-spec/zip-records.js +136 -0
  139. package/dist/cjs/modules/excel/stream/workbook-reader.browser.js +2 -2
  140. package/dist/cjs/modules/excel/stream/workbook-writer.browser.js +4 -4
  141. package/dist/cjs/modules/excel/utils/ooxml-validator.js +475 -0
  142. package/dist/cjs/modules/excel/utils/parse-sax.js +32 -13
  143. package/dist/cjs/modules/excel/worksheet.js +5 -2
  144. package/dist/cjs/modules/excel/xlsx/xform/core/app-xform.js +3 -3
  145. package/dist/cjs/modules/excel/xlsx/xform/core/core-xform.js +56 -68
  146. package/dist/cjs/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +13 -1
  147. package/dist/cjs/modules/excel/xlsx/xform/drawing/sp-xform.js +115 -0
  148. package/dist/cjs/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +30 -2
  149. package/dist/cjs/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +11 -0
  150. package/dist/cjs/modules/excel/xlsx/xform/list-xform.js +8 -10
  151. package/dist/cjs/modules/excel/xlsx/xform/sheet/page-setup-xform.js +16 -2
  152. package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +110 -12
  153. package/dist/cjs/modules/excel/xlsx/xform/strings/shared-string-xform.js +2 -3
  154. package/dist/cjs/modules/excel/xlsx/xform/strings/text-xform.js +5 -7
  155. package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +14 -13
  156. package/dist/cjs/modules/excel/xlsx/xlsx.js +2 -2
  157. package/dist/cjs/modules/stream/base-transform.js +34 -20
  158. package/dist/cjs/modules/stream/chunked-builder.js +4 -4
  159. package/dist/cjs/modules/stream/index.browser.js +10 -17
  160. package/dist/cjs/modules/stream/index.js +15 -39
  161. package/dist/cjs/modules/stream/internal/event-utils.js +43 -0
  162. package/dist/cjs/modules/stream/internal/type-guards.js +30 -0
  163. package/dist/cjs/modules/stream/pull-stream.js +107 -43
  164. package/dist/cjs/modules/stream/shared.js +7 -4
  165. package/dist/cjs/modules/stream/streams.browser.js +927 -847
  166. package/dist/cjs/modules/stream/streams.js +156 -107
  167. package/dist/cjs/modules/stream/utils.js +3 -36
  168. package/dist/esm/index.browser.js +12 -0
  169. package/dist/{browser/modules/archive → esm/modules/archive/compression}/compress.base.js +1 -1
  170. package/dist/esm/modules/archive/{compress.browser.js → compression/compress.browser.js} +3 -11
  171. package/dist/{browser/modules/archive → esm/modules/archive/compression}/compress.js +1 -1
  172. package/dist/esm/modules/archive/{crc32.js → compression/crc32.js} +1 -1
  173. package/dist/esm/modules/archive/{deflate-fallback.js → compression/deflate-fallback.js} +1 -1
  174. package/dist/esm/modules/archive/{streaming-compress.browser.js → compression/streaming-compress.browser.js} +3 -3
  175. package/dist/esm/modules/archive/{streaming-compress.js → compression/streaming-compress.js} +2 -2
  176. package/dist/esm/modules/archive/defaults.js +6 -3
  177. package/dist/esm/modules/archive/index.base.js +3 -6
  178. package/dist/esm/modules/archive/index.browser.js +3 -7
  179. package/dist/esm/modules/archive/index.js +3 -5
  180. package/dist/esm/modules/archive/internal/byte-queue.js +407 -0
  181. package/dist/esm/modules/archive/io/archive-sink.js +45 -0
  182. package/dist/esm/modules/archive/io/archive-source.js +100 -0
  183. package/dist/esm/modules/archive/unzip/index.js +164 -0
  184. package/dist/esm/modules/archive/unzip/stream.base.js +1022 -0
  185. package/dist/esm/modules/archive/{parse.browser.js → unzip/stream.browser.js} +371 -110
  186. package/dist/{browser/modules/archive/parse.js → esm/modules/archive/unzip/stream.js} +6 -5
  187. package/dist/{browser/modules/archive → esm/modules/archive/unzip}/zip-parser.js +38 -24
  188. package/dist/esm/modules/archive/utils/async-queue.js +103 -0
  189. package/dist/esm/modules/archive/utils/bytes.js +16 -16
  190. package/dist/esm/modules/archive/utils/compressibility.js +57 -0
  191. package/dist/esm/modules/archive/utils/parse-buffer.js +21 -23
  192. package/dist/esm/modules/archive/utils/pattern-scanner.js +27 -0
  193. package/dist/esm/modules/archive/utils/timestamps.js +62 -1
  194. package/dist/esm/modules/archive/utils/zip-extra-fields.js +26 -14
  195. package/dist/esm/modules/archive/zip/index.js +157 -0
  196. package/dist/esm/modules/archive/{streaming-zip.js → zip/stream.js} +192 -48
  197. package/dist/esm/modules/archive/zip/zip-bytes.js +239 -0
  198. package/dist/{browser/modules/archive → esm/modules/archive/zip}/zip-entry-metadata.js +3 -3
  199. package/dist/esm/modules/archive/zip-spec/zip-records.js +126 -0
  200. package/dist/esm/modules/excel/stream/workbook-reader.browser.js +1 -1
  201. package/dist/esm/modules/excel/stream/workbook-writer.browser.js +1 -1
  202. package/dist/esm/modules/excel/utils/ooxml-validator.js +469 -0
  203. package/dist/esm/modules/excel/utils/parse-sax.js +32 -13
  204. package/dist/esm/modules/excel/worksheet.js +5 -2
  205. package/dist/esm/modules/excel/xlsx/xform/core/app-xform.js +3 -3
  206. package/dist/esm/modules/excel/xlsx/xform/core/core-xform.js +56 -68
  207. package/dist/esm/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +13 -1
  208. package/dist/esm/modules/excel/xlsx/xform/drawing/sp-xform.js +112 -0
  209. package/dist/esm/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +30 -2
  210. package/dist/esm/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +11 -0
  211. package/dist/esm/modules/excel/xlsx/xform/list-xform.js +8 -10
  212. package/dist/esm/modules/excel/xlsx/xform/sheet/page-setup-xform.js +16 -2
  213. package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +110 -12
  214. package/dist/esm/modules/excel/xlsx/xform/strings/shared-string-xform.js +2 -3
  215. package/dist/esm/modules/excel/xlsx/xform/strings/text-xform.js +5 -7
  216. package/dist/esm/modules/excel/xlsx/xlsx.browser.js +11 -10
  217. package/dist/esm/modules/excel/xlsx/xlsx.js +1 -1
  218. package/dist/esm/modules/stream/base-transform.js +34 -20
  219. package/dist/esm/modules/stream/chunked-builder.js +4 -4
  220. package/dist/esm/modules/stream/index.browser.js +10 -22
  221. package/dist/esm/modules/stream/index.js +15 -44
  222. package/dist/esm/modules/stream/internal/event-utils.js +40 -0
  223. package/dist/esm/modules/stream/internal/type-guards.js +24 -0
  224. package/dist/esm/modules/stream/pull-stream.js +107 -43
  225. package/dist/esm/modules/stream/shared.js +7 -4
  226. package/dist/esm/modules/stream/streams.browser.js +921 -836
  227. package/dist/esm/modules/stream/streams.js +146 -95
  228. package/dist/esm/modules/stream/utils.js +5 -38
  229. package/dist/iife/THIRD_PARTY_NOTICES.md +0 -31
  230. package/dist/iife/excelts.iife.js +6592 -4537
  231. package/dist/iife/excelts.iife.js.map +1 -1
  232. package/dist/iife/excelts.iife.min.js +103 -31
  233. package/dist/types/index.browser.d.ts +1 -0
  234. package/dist/{browser/modules/archive → types/modules/archive/compression}/compress.browser.d.ts +2 -8
  235. package/dist/types/modules/archive/{streaming-compress.browser.d.ts → compression/streaming-compress.browser.d.ts} +1 -1
  236. package/dist/types/modules/archive/defaults.d.ts +1 -0
  237. package/dist/types/modules/archive/index.base.d.ts +4 -4
  238. package/dist/types/modules/archive/index.browser.d.ts +3 -4
  239. package/dist/types/modules/archive/index.d.ts +3 -4
  240. package/dist/types/modules/archive/internal/byte-queue.d.ts +33 -0
  241. package/dist/types/modules/archive/io/archive-sink.d.ts +8 -0
  242. package/dist/types/modules/archive/io/archive-source.d.ts +6 -0
  243. package/dist/types/modules/archive/unzip/index.d.ts +40 -0
  244. package/dist/types/modules/archive/{parse.base.d.ts → unzip/stream.base.d.ts} +38 -4
  245. package/dist/types/modules/archive/{parse.browser.d.ts → unzip/stream.browser.d.ts} +2 -2
  246. package/dist/types/modules/archive/{parse.d.ts → unzip/stream.d.ts} +3 -3
  247. package/dist/types/modules/archive/{zip-parser.d.ts → unzip/zip-parser.d.ts} +1 -1
  248. package/dist/types/modules/archive/utils/async-queue.d.ts +7 -0
  249. package/dist/types/modules/archive/utils/compressibility.d.ts +10 -0
  250. package/dist/types/modules/archive/utils/pattern-scanner.d.ts +21 -0
  251. package/dist/types/modules/archive/utils/zip-extra-fields.d.ts +1 -1
  252. package/dist/types/modules/archive/zip/index.d.ts +42 -0
  253. package/dist/types/modules/archive/{streaming-zip.d.ts → zip/stream.d.ts} +29 -6
  254. package/dist/types/modules/archive/zip/zip-bytes.d.ts +73 -0
  255. package/dist/types/modules/archive/{zip-entry-metadata.d.ts → zip/zip-entry-metadata.d.ts} +1 -1
  256. package/dist/types/modules/archive/{zip-records.d.ts → zip-spec/zip-records.d.ts} +20 -0
  257. package/dist/types/modules/excel/stream/workbook-writer.browser.d.ts +1 -1
  258. package/dist/types/modules/excel/utils/ooxml-validator.d.ts +48 -0
  259. package/dist/types/modules/excel/utils/parse-sax.d.ts +3 -0
  260. package/dist/types/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.d.ts +1 -0
  261. package/dist/types/modules/excel/xlsx/xform/drawing/sp-xform.d.ts +18 -0
  262. package/dist/types/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.d.ts +6 -1
  263. package/dist/types/modules/excel/xlsx/xform/sheet/page-setup-xform.d.ts +1 -0
  264. package/dist/types/modules/stream/base-transform.d.ts +3 -0
  265. package/dist/types/modules/stream/buffered-stream.d.ts +2 -12
  266. package/dist/types/modules/stream/index.browser.d.ts +13 -19
  267. package/dist/types/modules/stream/index.d.ts +18 -41
  268. package/dist/types/modules/stream/internal/event-utils.d.ts +17 -0
  269. package/dist/types/modules/stream/internal/type-guards.d.ts +9 -0
  270. package/dist/types/modules/stream/pull-stream.d.ts +5 -6
  271. package/dist/types/modules/stream/shared.d.ts +1 -1
  272. package/dist/types/modules/stream/streams.browser.d.ts +32 -44
  273. package/dist/types/modules/stream/streams.d.ts +4 -20
  274. package/package.json +14 -10
  275. package/dist/browser/modules/archive/byte-queue.d.ts +0 -18
  276. package/dist/browser/modules/archive/byte-queue.js +0 -125
  277. package/dist/browser/modules/archive/parse.base.js +0 -644
  278. package/dist/browser/modules/archive/utils/zip-extra.d.ts +0 -18
  279. package/dist/browser/modules/archive/utils/zip-extra.js +0 -68
  280. package/dist/browser/modules/archive/zip-builder.d.ts +0 -117
  281. package/dist/browser/modules/archive/zip-builder.js +0 -292
  282. package/dist/browser/modules/archive/zip-constants.d.ts +0 -18
  283. package/dist/browser/modules/archive/zip-constants.js +0 -23
  284. package/dist/browser/modules/archive/zip-records.js +0 -84
  285. package/dist/cjs/modules/archive/byte-queue.js +0 -129
  286. package/dist/cjs/modules/archive/parse.base.js +0 -666
  287. package/dist/cjs/modules/archive/utils/zip-extra.js +0 -74
  288. package/dist/cjs/modules/archive/zip-builder.js +0 -297
  289. package/dist/cjs/modules/archive/zip-constants.js +0 -26
  290. package/dist/cjs/modules/archive/zip-records.js +0 -90
  291. package/dist/esm/modules/archive/byte-queue.js +0 -125
  292. package/dist/esm/modules/archive/parse.base.js +0 -644
  293. package/dist/esm/modules/archive/utils/zip-extra.js +0 -68
  294. package/dist/esm/modules/archive/zip-builder.js +0 -292
  295. package/dist/esm/modules/archive/zip-constants.js +0 -23
  296. package/dist/esm/modules/archive/zip-records.js +0 -84
  297. package/dist/types/modules/archive/byte-queue.d.ts +0 -18
  298. package/dist/types/modules/archive/utils/zip-extra.d.ts +0 -18
  299. package/dist/types/modules/archive/zip-builder.d.ts +0 -117
  300. package/dist/types/modules/archive/zip-constants.d.ts +0 -18
  301. /package/dist/browser/modules/archive/{compress.base.d.ts → compression/compress.base.d.ts} +0 -0
  302. /package/dist/browser/modules/archive/{crc32.base.d.ts → compression/crc32.base.d.ts} +0 -0
  303. /package/dist/browser/modules/archive/{crc32.base.js → compression/crc32.base.js} +0 -0
  304. /package/dist/browser/modules/archive/{crc32.browser.js → compression/crc32.browser.js} +0 -0
  305. /package/dist/browser/modules/archive/{deflate-fallback.d.ts → compression/deflate-fallback.d.ts} +0 -0
  306. /package/dist/browser/modules/archive/{streaming-compress.base.d.ts → compression/streaming-compress.base.d.ts} +0 -0
  307. /package/dist/browser/modules/archive/{streaming-compress.base.js → compression/streaming-compress.base.js} +0 -0
  308. /package/dist/browser/modules/archive/{extract.js → unzip/extract.js} +0 -0
  309. /package/dist/browser/modules/archive/{zip-entry-metadata.d.ts → zip/zip-entry-metadata.d.ts} +0 -0
  310. /package/dist/browser/modules/archive/{zip-entry-info.d.ts → zip-spec/zip-entry-info.d.ts} +0 -0
  311. /package/dist/browser/modules/archive/{zip-entry-info.js → zip-spec/zip-entry-info.js} +0 -0
  312. /package/dist/cjs/modules/archive/{crc32.base.js → compression/crc32.base.js} +0 -0
  313. /package/dist/cjs/modules/archive/{crc32.browser.js → compression/crc32.browser.js} +0 -0
  314. /package/dist/cjs/modules/archive/{streaming-compress.base.js → compression/streaming-compress.base.js} +0 -0
  315. /package/dist/cjs/modules/archive/{extract.js → unzip/extract.js} +0 -0
  316. /package/dist/cjs/modules/archive/{zip-entry-info.js → zip-spec/zip-entry-info.js} +0 -0
  317. /package/dist/esm/modules/archive/{crc32.base.js → compression/crc32.base.js} +0 -0
  318. /package/dist/esm/modules/archive/{crc32.browser.js → compression/crc32.browser.js} +0 -0
  319. /package/dist/esm/modules/archive/{streaming-compress.base.js → compression/streaming-compress.base.js} +0 -0
  320. /package/dist/esm/modules/archive/{extract.js → unzip/extract.js} +0 -0
  321. /package/dist/esm/modules/archive/{zip-entry-info.js → zip-spec/zip-entry-info.js} +0 -0
  322. /package/dist/types/modules/archive/{compress.base.d.ts → compression/compress.base.d.ts} +0 -0
  323. /package/dist/types/modules/archive/{compress.d.ts → compression/compress.d.ts} +0 -0
  324. /package/dist/types/modules/archive/{crc32.base.d.ts → compression/crc32.base.d.ts} +0 -0
  325. /package/dist/types/modules/archive/{crc32.browser.d.ts → compression/crc32.browser.d.ts} +0 -0
  326. /package/dist/types/modules/archive/{crc32.d.ts → compression/crc32.d.ts} +0 -0
  327. /package/dist/types/modules/archive/{deflate-fallback.d.ts → compression/deflate-fallback.d.ts} +0 -0
  328. /package/dist/types/modules/archive/{streaming-compress.base.d.ts → compression/streaming-compress.base.d.ts} +0 -0
  329. /package/dist/types/modules/archive/{streaming-compress.d.ts → compression/streaming-compress.d.ts} +0 -0
  330. /package/dist/types/modules/archive/{extract.d.ts → unzip/extract.d.ts} +0 -0
  331. /package/dist/types/modules/archive/{zip-entry-info.d.ts → zip-spec/zip-entry-info.d.ts} +0 -0
@@ -0,0 +1,469 @@
1
+ import path from "node:path";
2
+ import { extractAll } from "../../archive/unzip/extract.js";
3
+ import { parseSax } from "./parse-sax.js";
4
+ function pushProblem(problems, problem, maxProblems) {
5
+ if (maxProblems !== undefined && problems.length >= maxProblems) {
6
+ return;
7
+ }
8
+ problems.push(problem);
9
+ }
10
+ function stripLeadingSlash(p) {
11
+ return p.startsWith("/") ? p.slice(1) : p;
12
+ }
13
+ function isXmlLike(pathName) {
14
+ return pathName.endsWith(".xml") || pathName.endsWith(".rels") || pathName.endsWith(".vml");
15
+ }
16
+ function getRelsSourceDir(relsPath) {
17
+ // In OPC, relationship targets are resolved relative to the SOURCE part directory,
18
+ // not the .rels part directory.
19
+ //
20
+ // Examples:
21
+ // - _rels/.rels -> base "" (package root)
22
+ // - xl/_rels/workbook.xml.rels -> base "xl"
23
+ // - xl/worksheets/_rels/sheet1.xml.rels -> base "xl/worksheets"
24
+ if (relsPath === "_rels/.rels") {
25
+ return "";
26
+ }
27
+ const relsMarker = "/_rels/";
28
+ const idx = relsPath.indexOf(relsMarker);
29
+ if (idx === -1) {
30
+ return relsPath.includes("/") ? relsPath.slice(0, relsPath.lastIndexOf("/")) : "";
31
+ }
32
+ return relsPath.slice(0, idx);
33
+ }
34
+ function resolveRelTarget(relsPath, target) {
35
+ const baseDir = getRelsSourceDir(relsPath);
36
+ const resolved = path.posix.normalize(path.posix.join(baseDir, target));
37
+ return resolved.replace(/^\//, "");
38
+ }
39
+ function isSafeResolvedPath(resolved) {
40
+ // Prevent path traversal out of package root.
41
+ // `normalize()` can produce paths starting with "../".
42
+ return !(resolved === ".." || resolved.startsWith("../") || resolved.includes("/../"));
43
+ }
44
+ async function assertXmlWellFormed(xmlText) {
45
+ // parseSax throws on malformed XML.
46
+ for await (const _events of parseSax([xmlText])) {
47
+ // no-op
48
+ }
49
+ }
50
+ function parseContentTypes(xml) {
51
+ const defaults = [];
52
+ const overrides = [];
53
+ const defaultRe = /<Default\s+[^>]*Extension="([^"]+)"[^>]*ContentType="([^"]+)"[^>]*\/>/g;
54
+ const overrideRe = /<Override\s+[^>]*PartName="([^"]+)"[^>]*ContentType="([^"]+)"[^>]*\/>/g;
55
+ for (let match = defaultRe.exec(xml); match; match = defaultRe.exec(xml)) {
56
+ defaults.push({ extension: match[1], contentType: match[2] });
57
+ }
58
+ for (let match = overrideRe.exec(xml); match; match = overrideRe.exec(xml)) {
59
+ overrides.push({ partName: match[1], contentType: match[2] });
60
+ }
61
+ const parseOk = xml.includes("<Types") && (defaults.length > 0 || overrides.length > 0);
62
+ return { defaults, overrides, parseOk };
63
+ }
64
+ function getExtension(p) {
65
+ const base = path.posix.basename(p);
66
+ const idx = base.lastIndexOf(".");
67
+ return idx === -1 ? "" : base.slice(idx + 1);
68
+ }
69
+ function isPackagePart(pathName) {
70
+ // Exclude directories and the [Content_Types].xml pseudo-root.
71
+ return pathName !== "" && pathName !== "[Content_Types].xml";
72
+ }
73
+ function parseRelationships(xml) {
74
+ // Ensure the rels XML itself is parseable.
75
+ // We still use regex to extract rels for speed/portability.
76
+ const relRe = /<Relationship\s+[^>]*Id="([^"]+)"[^>]*Type="([^"]+)"[^>]*Target="([^"]*)"(?:[^>]*TargetMode="([^"]+)")?[^>]*\/>/g;
77
+ const rels = [];
78
+ for (let match = relRe.exec(xml); match; match = relRe.exec(xml)) {
79
+ rels.push({ id: match[1], type: match[2], target: match[3], targetMode: match[4] });
80
+ }
81
+ // Basic sanity: should have <Relationships ...> root.
82
+ const parseOk = xml.includes("<Relationships") && xml.includes("Relationship");
83
+ return { rels, parseOk };
84
+ }
85
+ export async function validateXlsxBuffer(xlsxBuffer, options = {}) {
86
+ const { checkXmlWellFormed = true, checkRelationshipTargets = true, checkContentTypesOverrides = true, checkWorksheetControlWiring = true, maxProblems } = options;
87
+ const problems = [];
88
+ const entries = await extractAll(xlsxBuffer);
89
+ const has = (p) => entries.has(p);
90
+ const mustExist = [
91
+ "[Content_Types].xml",
92
+ "_rels/.rels",
93
+ "xl/workbook.xml",
94
+ "xl/_rels/workbook.xml.rels"
95
+ ];
96
+ for (const p of mustExist) {
97
+ if (!has(p)) {
98
+ pushProblem(problems, { kind: "missing-part", file: p, message: `Missing required part: ${p}` }, maxProblems);
99
+ }
100
+ }
101
+ // XML well-formedness for all XML-like parts.
102
+ if (checkXmlWellFormed) {
103
+ for (const [p, entry] of entries) {
104
+ if (maxProblems !== undefined && problems.length >= maxProblems) {
105
+ break;
106
+ }
107
+ if (entry.isDirectory || !isXmlLike(p)) {
108
+ continue;
109
+ }
110
+ const xml = new TextDecoder().decode(entry.data);
111
+ try {
112
+ await assertXmlWellFormed(xml);
113
+ }
114
+ catch (err) {
115
+ pushProblem(problems, {
116
+ kind: "xml-malformed",
117
+ file: p,
118
+ message: `Malformed XML: ${err?.message || String(err)}`
119
+ }, maxProblems);
120
+ }
121
+ }
122
+ }
123
+ // Content types overrides must point to existing parts.
124
+ if (checkContentTypesOverrides && has("[Content_Types].xml")) {
125
+ const ctXml = new TextDecoder().decode(entries.get("[Content_Types].xml").data);
126
+ const { defaults, overrides, parseOk } = parseContentTypes(ctXml);
127
+ if (!parseOk) {
128
+ pushProblem(problems, {
129
+ kind: "content-types-malformed",
130
+ file: "[Content_Types].xml",
131
+ message: "Content types XML missing expected root/entries"
132
+ }, maxProblems);
133
+ }
134
+ const defaultByExt = new Map(defaults.map(d => [d.extension.toLowerCase(), d.contentType]));
135
+ const overrideByPart = new Map();
136
+ for (const ov of overrides) {
137
+ const key = stripLeadingSlash(ov.partName);
138
+ if (overrideByPart.has(key)) {
139
+ pushProblem(problems, {
140
+ kind: "content-types-duplicate-override",
141
+ file: "[Content_Types].xml",
142
+ message: `Duplicate Override PartName: ${ov.partName}`
143
+ }, maxProblems);
144
+ }
145
+ overrideByPart.set(key, ov.contentType);
146
+ }
147
+ // RFC: .rels and .xml defaults are expected in valid packages.
148
+ const relsDefault = defaultByExt.get("rels");
149
+ if (relsDefault !== "application/vnd.openxmlformats-package.relationships+xml") {
150
+ pushProblem(problems, {
151
+ kind: "content-types-missing-default",
152
+ file: "[Content_Types].xml",
153
+ message: "Missing/incorrect Default for .rels (expected application/vnd.openxmlformats-package.relationships+xml)"
154
+ }, maxProblems);
155
+ }
156
+ const xmlDefault = defaultByExt.get("xml");
157
+ if (xmlDefault !== "application/xml") {
158
+ pushProblem(problems, {
159
+ kind: "content-types-missing-default",
160
+ file: "[Content_Types].xml",
161
+ message: "Missing/incorrect Default for .xml (expected application/xml)"
162
+ }, maxProblems);
163
+ }
164
+ for (const ov of overrides) {
165
+ if (maxProblems !== undefined && problems.length >= maxProblems) {
166
+ break;
167
+ }
168
+ const zipPath = stripLeadingSlash(ov.partName);
169
+ if (!has(zipPath)) {
170
+ pushProblem(problems, {
171
+ kind: "content-types-missing",
172
+ file: "[Content_Types].xml",
173
+ message: `Override PartName points to missing file: ${ov.partName}`
174
+ }, maxProblems);
175
+ }
176
+ }
177
+ // Strong check: every part in the zip should have a content type via Default or Override.
178
+ for (const [p, entry] of entries) {
179
+ if (maxProblems !== undefined && problems.length >= maxProblems) {
180
+ break;
181
+ }
182
+ if (entry.isDirectory || !isPackagePart(p)) {
183
+ continue;
184
+ }
185
+ const overrideType = overrideByPart.get(p);
186
+ if (overrideType) {
187
+ continue;
188
+ }
189
+ const ext = getExtension(p).toLowerCase();
190
+ if (!ext) {
191
+ pushProblem(problems, {
192
+ kind: "content-types-missing-for-part",
193
+ file: "[Content_Types].xml",
194
+ message: `No content type for part without extension: ${p}`
195
+ }, maxProblems);
196
+ continue;
197
+ }
198
+ if (!defaultByExt.has(ext)) {
199
+ pushProblem(problems, {
200
+ kind: "content-types-missing-for-part",
201
+ file: "[Content_Types].xml",
202
+ message: `No Default/Override content type for part: ${p} (extension .${ext})`
203
+ }, maxProblems);
204
+ }
205
+ }
206
+ }
207
+ // Root relationships must point to the workbook (OPC officeDocument).
208
+ if (has("_rels/.rels")) {
209
+ const rootRelsXml = new TextDecoder().decode(entries.get("_rels/.rels").data);
210
+ const { rels } = parseRelationships(rootRelsXml);
211
+ const hasOfficeDocument = rels.some(r => r.type.includes("/relationships/officeDocument") && r.target === "xl/workbook.xml");
212
+ if (!hasOfficeDocument) {
213
+ pushProblem(problems, {
214
+ kind: "root-rels-missing-officeDocument",
215
+ file: "_rels/.rels",
216
+ message: "Missing officeDocument relationship to xl/workbook.xml"
217
+ }, maxProblems);
218
+ }
219
+ }
220
+ // Relationships: validate target existence and basic ID uniqueness.
221
+ if (checkRelationshipTargets) {
222
+ for (const [p, entry] of entries) {
223
+ if (maxProblems !== undefined && problems.length >= maxProblems) {
224
+ break;
225
+ }
226
+ if (entry.isDirectory || !p.endsWith(".rels")) {
227
+ continue;
228
+ }
229
+ const relsXml = new TextDecoder().decode(entry.data);
230
+ const { rels, parseOk } = parseRelationships(relsXml);
231
+ if (!parseOk) {
232
+ pushProblem(problems, {
233
+ kind: "rels-malformed",
234
+ file: p,
235
+ message: "Relationships XML missing expected root/entries"
236
+ }, maxProblems);
237
+ }
238
+ const ids = new Set();
239
+ for (const rel of rels) {
240
+ if (maxProblems !== undefined && problems.length >= maxProblems) {
241
+ break;
242
+ }
243
+ if (ids.has(rel.id)) {
244
+ pushProblem(problems, {
245
+ kind: "rels-duplicate-id",
246
+ file: p,
247
+ message: `Duplicate relationship Id: ${rel.id}`
248
+ }, maxProblems);
249
+ }
250
+ ids.add(rel.id);
251
+ if (rel.targetMode === "External") {
252
+ continue;
253
+ }
254
+ if (!rel.target) {
255
+ pushProblem(problems, {
256
+ kind: "rels-empty-target",
257
+ file: p,
258
+ message: `Relationship ${rel.id} (${rel.type}) has empty Target`
259
+ }, maxProblems);
260
+ continue;
261
+ }
262
+ const resolvedTarget = resolveRelTarget(p, rel.target);
263
+ if (!isSafeResolvedPath(resolvedTarget)) {
264
+ pushProblem(problems, {
265
+ kind: "rels-invalid-target-path",
266
+ file: p,
267
+ message: `Rel ${rel.id} (${rel.type}) target escapes package root: ${rel.target} -> ${resolvedTarget}`
268
+ }, maxProblems);
269
+ continue;
270
+ }
271
+ if (!has(resolvedTarget)) {
272
+ pushProblem(problems, {
273
+ kind: "rels-missing-target",
274
+ file: p,
275
+ message: `Rel ${rel.id} (${rel.type}) target missing: ${rel.target} -> ${resolvedTarget}`
276
+ }, maxProblems);
277
+ }
278
+ }
279
+ // Optional: ensure the source part exists for non-root rels.
280
+ if (p !== "_rels/.rels") {
281
+ // Convert: xl/_rels/workbook.xml.rels -> xl/workbook.xml
282
+ // Convert: xl/worksheets/_rels/sheet1.xml.rels -> xl/worksheets/sheet1.xml
283
+ const srcDir = getRelsSourceDir(p);
284
+ const relsBaseName = path.posix.basename(p);
285
+ const sourceName = relsBaseName.replace(/\.rels$/, "");
286
+ const sourcePath = srcDir ? `${srcDir}/${sourceName}` : sourceName;
287
+ if (!has(sourcePath)) {
288
+ pushProblem(problems, {
289
+ kind: "rels-source-missing",
290
+ file: p,
291
+ message: `Relationships part has no corresponding source part: ${sourcePath}`
292
+ }, maxProblems);
293
+ }
294
+ }
295
+ }
296
+ }
297
+ // Workbook -> worksheets wiring.
298
+ if (has("xl/workbook.xml") && has("xl/_rels/workbook.xml.rels")) {
299
+ const workbookXml = new TextDecoder().decode(entries.get("xl/workbook.xml").data);
300
+ const workbookRelsXml = new TextDecoder().decode(entries.get("xl/_rels/workbook.xml.rels").data);
301
+ const { rels: wbRels } = parseRelationships(workbookRelsXml);
302
+ const wbById = new Map(wbRels.map(r => [r.id, r]));
303
+ // Uniqueness checks: sheetId and r:id should not be duplicated.
304
+ const sheetIdRe = /<sheet\b[^>]*\bsheetId="(\d+)"[^>]*\/>/g;
305
+ const seenSheetIds = new Set();
306
+ for (let match = sheetIdRe.exec(workbookXml); match; match = sheetIdRe.exec(workbookXml)) {
307
+ const id = match[1];
308
+ if (seenSheetIds.has(id)) {
309
+ pushProblem(problems, {
310
+ kind: "workbook-duplicate-sheetId",
311
+ file: "xl/workbook.xml",
312
+ message: `Duplicate sheetId in workbook: ${id}`
313
+ }, maxProblems);
314
+ }
315
+ seenSheetIds.add(id);
316
+ }
317
+ const sheetRidSeen = new Set();
318
+ const sheetRidRe = /<sheet\b[^>]*\br:id="(rId\d+)"[^>]*\/>/g;
319
+ for (let match = sheetRidRe.exec(workbookXml); match; match = sheetRidRe.exec(workbookXml)) {
320
+ if (maxProblems !== undefined && problems.length >= maxProblems) {
321
+ break;
322
+ }
323
+ const rid = match[1];
324
+ if (sheetRidSeen.has(rid)) {
325
+ pushProblem(problems, {
326
+ kind: "workbook-duplicate-sheet-rid",
327
+ file: "xl/workbook.xml",
328
+ message: `Duplicate sheet r:id in workbook: ${rid}`
329
+ }, maxProblems);
330
+ }
331
+ sheetRidSeen.add(rid);
332
+ const rel = wbById.get(rid);
333
+ if (!rel) {
334
+ pushProblem(problems, {
335
+ kind: "workbook-sheet-missing-rel",
336
+ file: "xl/workbook.xml",
337
+ message: `Workbook <sheet> references missing relationship: ${rid} (in xl/_rels/workbook.xml.rels)`
338
+ }, maxProblems);
339
+ continue;
340
+ }
341
+ if (!rel.type.includes("/relationships/worksheet")) {
342
+ pushProblem(problems, {
343
+ kind: "workbook-sheet-wrong-rel-type",
344
+ file: "xl/workbook.xml",
345
+ message: `Workbook <sheet> ${rid} relationship is not worksheet: ${rel.type}`
346
+ }, maxProblems);
347
+ }
348
+ }
349
+ }
350
+ // Worksheet <controls>/<legacyDrawing> wiring.
351
+ if (checkWorksheetControlWiring) {
352
+ for (const [p, entry] of entries) {
353
+ if (maxProblems !== undefined && problems.length >= maxProblems) {
354
+ break;
355
+ }
356
+ if (entry.isDirectory || !p.startsWith("xl/worksheets/sheet") || !p.endsWith(".xml")) {
357
+ continue;
358
+ }
359
+ const sheetXml = new TextDecoder().decode(entry.data);
360
+ const relsPath = `xl/worksheets/_rels/${path.posix.basename(p)}.rels`;
361
+ // Excel is sensitive to worksheet child element ordering. In particular,
362
+ // legacyDrawing must come before controls when both are present.
363
+ const legacyDrawingIdx = sheetXml.indexOf("<legacyDrawing");
364
+ const controlsIdx = sheetXml.indexOf("<controls");
365
+ if (legacyDrawingIdx !== -1 && controlsIdx !== -1 && legacyDrawingIdx > controlsIdx) {
366
+ pushProblem(problems, {
367
+ kind: "sheet-legacyDrawing-after-controls",
368
+ file: p,
369
+ message: "Worksheet has <legacyDrawing> after <controls>; Excel may repair or reject this sheet"
370
+ }, maxProblems);
371
+ }
372
+ // Match <control ...> elements (not necessarily self-closing).
373
+ const controlRidRe = /<control\b[^>]*\br:id="(rId\d+)"[^>]*>/g;
374
+ const controlRids = [];
375
+ for (let match = controlRidRe.exec(sheetXml); match; match = controlRidRe.exec(sheetXml)) {
376
+ controlRids.push(match[1]);
377
+ }
378
+ // Excel Online / strict Excel builds may reject or "repair" legacy form controls
379
+ // if the sheet doesn't also have a DrawingML <drawing> part.
380
+ if (controlRids.length > 0 && sheetXml.indexOf("<drawing") === -1) {
381
+ pushProblem(problems, {
382
+ kind: "sheet-controls-missing-drawing",
383
+ file: p,
384
+ message: "Worksheet has legacy <controls> but no <drawing>; Excel may repair/reject legacy form controls"
385
+ }, maxProblems);
386
+ }
387
+ const legacyDrawingRidRe = /<legacyDrawing\b[^>]*\br:id="(rId\d+)"[^>]*\/>/g;
388
+ const legacyDrawingRids = [];
389
+ for (let match = legacyDrawingRidRe.exec(sheetXml); match; match = legacyDrawingRidRe.exec(sheetXml)) {
390
+ legacyDrawingRids.push(match[1]);
391
+ }
392
+ if ((controlRids.length > 0 || legacyDrawingRids.length > 0) && !has(relsPath)) {
393
+ pushProblem(problems, {
394
+ kind: "sheet-missing-rels",
395
+ file: p,
396
+ message: `Worksheet has controls/legacyDrawing but missing rels part: ${relsPath}`
397
+ }, maxProblems);
398
+ continue;
399
+ }
400
+ if (!has(relsPath)) {
401
+ continue;
402
+ }
403
+ const sheetRelsXml = new TextDecoder().decode(entries.get(relsPath).data);
404
+ const { rels: sheetRels } = parseRelationships(sheetRelsXml);
405
+ const byId = new Map(sheetRels.map(r => [r.id, r]));
406
+ const assertRidType = (rid, expectedTypeIncludes, kindMissing, kindWrong, nodeLabel) => {
407
+ const rel = byId.get(rid);
408
+ if (!rel) {
409
+ pushProblem(problems, {
410
+ kind: kindMissing,
411
+ file: p,
412
+ message: `Sheet ${nodeLabel} references missing relationship: ${rid} (in ${relsPath})`
413
+ }, maxProblems);
414
+ return;
415
+ }
416
+ if (!rel.type.includes(expectedTypeIncludes)) {
417
+ pushProblem(problems, {
418
+ kind: kindWrong,
419
+ file: p,
420
+ message: `Sheet ${nodeLabel} ${rid} relationship is not ${expectedTypeIncludes}: ${rel.type}`
421
+ }, maxProblems);
422
+ }
423
+ };
424
+ for (const rid of controlRids) {
425
+ if (maxProblems !== undefined && problems.length >= maxProblems) {
426
+ break;
427
+ }
428
+ assertRidType(rid, "/relationships/ctrlProp", "sheet-control-missing-rel", "sheet-control-wrong-rel-type", "<control>");
429
+ }
430
+ for (const rid of legacyDrawingRids) {
431
+ if (maxProblems !== undefined && problems.length >= maxProblems) {
432
+ break;
433
+ }
434
+ assertRidType(rid, "/relationships/vmlDrawing", "sheet-legacyDrawing-missing-rel", "sheet-legacyDrawing-wrong-rel-type", "<legacyDrawing>");
435
+ }
436
+ // Common worksheet nodes that are wired via r:id
437
+ // - <drawing r:id="..."/> -> drawing
438
+ // - <comments r:id="..."/> -> comments
439
+ // - <tableParts><tablePart r:id="..."/></tableParts> -> table
440
+ // - <hyperlink r:id="..."/> -> hyperlink
441
+ const drawingRidRe = /<drawing\b[^>]*\br:id="(rId\d+)"[^>]*\/>/g;
442
+ for (let match = drawingRidRe.exec(sheetXml); match; match = drawingRidRe.exec(sheetXml)) {
443
+ assertRidType(match[1], "/relationships/drawing", "sheet-drawing-missing-rel", "sheet-drawing-wrong-rel-type", "<drawing>");
444
+ }
445
+ const commentsRidRe = /<comments\b[^>]*\br:id="(rId\d+)"[^>]*\/>/g;
446
+ for (let match = commentsRidRe.exec(sheetXml); match; match = commentsRidRe.exec(sheetXml)) {
447
+ assertRidType(match[1], "/relationships/comments", "sheet-comments-missing-rel", "sheet-comments-wrong-rel-type", "<comments>");
448
+ }
449
+ const tablePartRidRe = /<tablePart\b[^>]*\br:id="(rId\d+)"[^>]*\/>/g;
450
+ for (let match = tablePartRidRe.exec(sheetXml); match; match = tablePartRidRe.exec(sheetXml)) {
451
+ assertRidType(match[1], "/relationships/table", "sheet-tablePart-missing-rel", "sheet-tablePart-wrong-rel-type", "<tablePart>");
452
+ }
453
+ const hyperlinkRidRe = /<hyperlink\b[^>]*\br:id="(rId\d+)"[^>]*\/>/g;
454
+ for (let match = hyperlinkRidRe.exec(sheetXml); match; match = hyperlinkRidRe.exec(sheetXml)) {
455
+ assertRidType(match[1], "/relationships/hyperlink", "sheet-hyperlink-missing-rel", "sheet-hyperlink-wrong-rel-type", "<hyperlink>");
456
+ }
457
+ }
458
+ }
459
+ const stats = {
460
+ entryCount: entries.size,
461
+ xmlLikeCount: [...entries.values()].filter((f) => !f.isDirectory && isXmlLike(f.path)).length,
462
+ relsCount: [...entries.values()].filter((f) => !f.isDirectory && f.path.endsWith(".rels")).length
463
+ };
464
+ return {
465
+ ok: problems.length === 0,
466
+ problems,
467
+ stats
468
+ };
469
+ }
@@ -54,6 +54,7 @@ export declare class SaxesParser {
54
54
  private positionAtNewLine;
55
55
  private chunkPosition;
56
56
  ENTITIES: Record<string, string>;
57
+ private nsPrefix;
57
58
  private textHandler?;
58
59
  private openTagHandler?;
59
60
  private closeTagHandler?;
@@ -62,6 +63,7 @@ export declare class SaxesParser {
62
63
  get closed(): boolean;
63
64
  get position(): number;
64
65
  private _init;
66
+ private stripNsPrefix;
65
67
  on(name: "text", handler: TextHandler): void;
66
68
  on(name: "opentag", handler: OpenTagHandler): void;
67
69
  on(name: "closetag", handler: CloseTagHandler): void;
@@ -106,6 +108,7 @@ export declare class SaxesParser {
106
108
  private skipSpaces;
107
109
  private openTag;
108
110
  private openSelfClosingTag;
111
+ private processAttributes;
109
112
  private closeTag;
110
113
  private end;
111
114
  }
@@ -142,6 +142,12 @@ const XML_ENTITIES = {
142
142
  quot: '"',
143
143
  apos: "'"
144
144
  };
145
+ // HAN CELL namespace prefix normalization
146
+ // HAN CELL uses non-standard namespace prefixes (ep:, cp:, dc:, etc.)
147
+ // The x: prefix for spreadsheetml is detected dynamically from xmlns declarations
148
+ // See: https://github.com/exceljs/exceljs/issues/3014
149
+ const HAN_CELL_PREFIXES = /^(ep|cp|dc|dcterms|dcmitype|vt):/;
150
+ const SPREADSHEETML_NS = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
145
151
  // ============================================================================
146
152
  // Parser States
147
153
  // ============================================================================
@@ -202,6 +208,8 @@ export class SaxesParser {
202
208
  this.chunkPosition = 0;
203
209
  // Entity storage
204
210
  this.ENTITIES = { ...XML_ENTITIES };
211
+ // HAN CELL compatibility: spreadsheetml namespace prefix (e.g., "x")
212
+ this.nsPrefix = null;
205
213
  this.trackPosition = opt?.position !== false;
206
214
  this.fileName = opt?.fileName;
207
215
  this.fragment = opt?.fragment ?? false;
@@ -236,6 +244,14 @@ export class SaxesParser {
236
244
  this.chunk = "";
237
245
  this.i = 0;
238
246
  this.prevI = 0;
247
+ this.nsPrefix = null;
248
+ }
249
+ // Strip HAN CELL namespace prefixes from element names
250
+ stripNsPrefix(name) {
251
+ const n = name.replace(HAN_CELL_PREFIXES, "");
252
+ return this.nsPrefix && n.startsWith(this.nsPrefix + ":")
253
+ ? n.slice(this.nsPrefix.length + 1)
254
+ : n;
239
255
  }
240
256
  on(name, handler) {
241
257
  switch (name) {
@@ -651,9 +667,8 @@ export class SaxesParser {
651
667
  this.name += charFromCode(c);
652
668
  return;
653
669
  }
654
- // Tag name complete
655
670
  this.tag = {
656
- name: this.name,
671
+ name: this.stripNsPrefix(this.name),
657
672
  attributes: Object.create(null),
658
673
  isSelfClosing: false
659
674
  };
@@ -1092,11 +1107,7 @@ export class SaxesParser {
1092
1107
  openTag() {
1093
1108
  const tag = this.tag;
1094
1109
  tag.isSelfClosing = false;
1095
- // Copy attributes from list to object
1096
- for (const { name, value } of this.attribList) {
1097
- tag.attributes[name] = value;
1098
- }
1099
- this.attribList = [];
1110
+ this.processAttributes(tag);
1100
1111
  this.openTagHandler?.(tag);
1101
1112
  this.tags.push(tag);
1102
1113
  this.name = "";
@@ -1105,11 +1116,7 @@ export class SaxesParser {
1105
1116
  openSelfClosingTag() {
1106
1117
  const tag = this.tag;
1107
1118
  tag.isSelfClosing = true;
1108
- // Copy attributes from list to object
1109
- for (const { name, value } of this.attribList) {
1110
- tag.attributes[name] = value;
1111
- }
1112
- this.attribList = [];
1119
+ this.processAttributes(tag);
1113
1120
  this.openTagHandler?.(tag);
1114
1121
  this.closeTagHandler?.(tag);
1115
1122
  if (this.tags.length === 0) {
@@ -1118,8 +1125,20 @@ export class SaxesParser {
1118
1125
  this.name = "";
1119
1126
  this.state = S_TEXT;
1120
1127
  }
1128
+ // Process attributes and detect spreadsheetml namespace prefix
1129
+ processAttributes(tag) {
1130
+ for (const { name, value } of this.attribList) {
1131
+ tag.attributes[name] = value;
1132
+ if (name.startsWith("xmlns:") && value === SPREADSHEETML_NS) {
1133
+ this.nsPrefix = name.slice(6);
1134
+ tag.name = this.stripNsPrefix(tag.name);
1135
+ }
1136
+ }
1137
+ this.attribList = [];
1138
+ }
1121
1139
  closeTag() {
1122
- const { tags, name } = this;
1140
+ const { tags } = this;
1141
+ const name = this.stripNsPrefix(this.name);
1123
1142
  this.state = S_TEXT;
1124
1143
  this.name = "";
1125
1144
  if (name === "") {
@@ -49,8 +49,11 @@ class Worksheet {
49
49
  this.pageSetup = Object.assign({}, {
50
50
  margins: { left: 0.7, right: 0.7, top: 0.75, bottom: 0.75, header: 0.3, footer: 0.3 },
51
51
  orientation: "portrait",
52
- horizontalDpi: 4294967295,
53
- verticalDpi: 4294967295,
52
+ // Excel does not normally write these unless explicitly set.
53
+ // Historically we used 4294967295 as a sentinel when parsing, but emitting it
54
+ // can cause strict Excel parsers to treat the workbook as corrupted.
55
+ horizontalDpi: undefined,
56
+ verticalDpi: undefined,
54
57
  fitToPage: !!(options.pageSetup &&
55
58
  (options.pageSetup.fitToWidth || options.pageSetup.fitToHeight) &&
56
59
  !options.pageSetup.scale),
@@ -10,7 +10,7 @@ class AppXform extends BaseXform {
10
10
  Company: new StringXform({ tag: "Company" }),
11
11
  Manager: new StringXform({ tag: "Manager" }),
12
12
  HeadingPairs: new AppHeadingPairsXform(),
13
- TitleOfParts: new AppTitlesOfPartsXform()
13
+ TitlesOfParts: new AppTitlesOfPartsXform()
14
14
  };
15
15
  }
16
16
  render(xmlStream, model) {
@@ -20,7 +20,7 @@ class AppXform extends BaseXform {
20
20
  xmlStream.leafNode("DocSecurity", undefined, "0");
21
21
  xmlStream.leafNode("ScaleCrop", undefined, "false");
22
22
  this.map.HeadingPairs.render(xmlStream, model.worksheets);
23
- this.map.TitleOfParts.render(xmlStream, model.worksheets);
23
+ this.map.TitlesOfParts.render(xmlStream, model.worksheets);
24
24
  this.map.Company.render(xmlStream, model.company || "");
25
25
  this.map.Manager.render(xmlStream, model.manager);
26
26
  xmlStream.leafNode("LinksUpToDate", undefined, "false");
@@ -62,7 +62,7 @@ class AppXform extends BaseXform {
62
62
  switch (name) {
63
63
  case "Properties":
64
64
  this.model = {
65
- worksheets: this.map.TitleOfParts.model,
65
+ worksheets: this.map.TitlesOfParts.model,
66
66
  company: this.map.Company.model,
67
67
  manager: this.map.Manager.model
68
68
  };