feat(tools): Support for Excel (.xlsx) files (#4668)

This commit is contained in:
Christiaan Arnoldus 2025-06-17 20:12:33 +02:00 committed by GitHub
parent 7b5a1d987d
commit bbbff7344b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 666 additions and 0 deletions

353
pnpm-lock.yaml generated
View file

@ -630,6 +630,9 @@ importers:
diff-match-patch:
specifier: ^1.0.5
version: 1.0.5
exceljs:
specifier: ^4.4.0
version: 4.4.0
fast-deep-equal:
specifier: ^3.1.3
version: 3.1.3
@ -2088,6 +2091,12 @@ packages:
resolution: {integrity: sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@fast-csv/format@4.3.5':
resolution: {integrity: sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A==}
'@fast-csv/parse@4.3.6':
resolution: {integrity: sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==}
'@fastify/busboy@2.1.1':
resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==}
engines: {node: '>=14'}
@ -4225,6 +4234,9 @@ packages:
'@types/node@12.20.55':
resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==}
'@types/node@14.18.63':
resolution: {integrity: sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==}
'@types/node@18.19.100':
resolution: {integrity: sha512-ojmMP8SZBKprc3qGrGk8Ujpo80AXkrP7G2tOT4VWr5jlr5DHjsJF+emXJz+Wm0glmy4Js62oKMdZZ6B9Y+tEcA==}
@ -4573,6 +4585,18 @@ packages:
aproba@2.0.0:
resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==}
archiver-utils@2.1.0:
resolution: {integrity: sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==}
engines: {node: '>= 6'}
archiver-utils@3.0.4:
resolution: {integrity: sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==}
engines: {node: '>= 10'}
archiver@5.3.2:
resolution: {integrity: sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==}
engines: {node: '>= 10'}
arg@5.0.2:
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
@ -4748,6 +4772,10 @@ packages:
better-sqlite3@11.10.0:
resolution: {integrity: sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==}
big-integer@1.6.52:
resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==}
engines: {node: '>=0.6'}
bignumber.js@9.3.0:
resolution: {integrity: sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA==}
@ -4755,9 +4783,15 @@ packages:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'}
binary@0.3.0:
resolution: {integrity: sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==}
bindings@1.5.0:
resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==}
bl@4.1.0:
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
bluebird@3.4.7:
resolution: {integrity: sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==}
@ -4805,9 +4839,17 @@ packages:
buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
buffer-indexof-polyfill@1.0.2:
resolution: {integrity: sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==}
engines: {node: '>=0.10'}
buffer@5.7.1:
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
buffers@0.1.1:
resolution: {integrity: sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==}
engines: {node: '>=0.2.0'}
bundle-name@4.1.0:
resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==}
engines: {node: '>=18'}
@ -4876,6 +4918,9 @@ packages:
resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==}
engines: {node: '>=12'}
chainsaw@0.1.0:
resolution: {integrity: sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==}
chalk@2.4.2:
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
engines: {node: '>=4'}
@ -5092,6 +5137,10 @@ packages:
resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==}
engines: {node: '>= 12'}
compress-commons@4.1.2:
resolution: {integrity: sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==}
engines: {node: '>= 10'}
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
@ -5154,6 +5203,15 @@ packages:
resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==}
engines: {node: '>=10'}
crc-32@1.2.2:
resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==}
engines: {node: '>=0.8'}
hasBin: true
crc32-stream@4.0.3:
resolution: {integrity: sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==}
engines: {node: '>= 10'}
create-jest@29.7.0:
resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@ -5696,6 +5754,9 @@ packages:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
duplexer2@0.1.4:
resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==}
duplexer@0.1.2:
resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
@ -6018,6 +6079,10 @@ packages:
resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==}
engines: {node: '>=18.0.0'}
exceljs@4.4.0:
resolution: {integrity: sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg==}
engines: {node: '>=8.3.0'}
execa@5.1.1:
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
engines: {node: '>=10'}
@ -6081,6 +6146,10 @@ packages:
engines: {node: '>= 10.17.0'}
hasBin: true
fast-csv@4.3.6:
resolution: {integrity: sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==}
engines: {node: '>=10.0.0'}
fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
@ -6267,6 +6336,9 @@ packages:
from@0.1.7:
resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==}
fs-constants@1.0.0:
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
fs-extra@7.0.1:
resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==}
engines: {node: '>=6 <7 || >=8'}
@ -6283,6 +6355,11 @@ packages:
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
fstream@1.0.12:
resolution: {integrity: sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==}
engines: {node: '>=0.6'}
deprecated: This package is no longer supported.
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
@ -7274,6 +7351,10 @@ packages:
layout-base@2.0.1:
resolution: {integrity: sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==}
lazystream@1.0.1:
resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==}
engines: {node: '>= 0.6.3'}
leven@3.1.0:
resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
engines: {node: '>=6'}
@ -7433,6 +7514,9 @@ packages:
engines: {node: '>=20.17'}
hasBin: true
listenercount@1.0.1:
resolution: {integrity: sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==}
listr2@8.3.3:
resolution: {integrity: sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==}
engines: {node: '>=18.0.0'}
@ -7462,15 +7546,40 @@ packages:
lodash.debounce@4.0.8:
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
lodash.defaults@4.2.0:
resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==}
lodash.difference@4.5.0:
resolution: {integrity: sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==}
lodash.escaperegexp@4.1.2:
resolution: {integrity: sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==}
lodash.flatten@4.4.0:
resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==}
lodash.groupby@4.6.0:
resolution: {integrity: sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==}
lodash.includes@4.3.0:
resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==}
lodash.isboolean@3.0.3:
resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==}
lodash.isequal@4.5.0:
resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead.
lodash.isfunction@3.0.9:
resolution: {integrity: sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==}
lodash.isinteger@4.0.4:
resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==}
lodash.isnil@4.0.0:
resolution: {integrity: sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==}
lodash.isnumber@3.0.3:
resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==}
@ -7480,6 +7589,9 @@ packages:
lodash.isstring@4.0.1:
resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==}
lodash.isundefined@3.0.1:
resolution: {integrity: sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==}
lodash.memoize@4.1.2:
resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
@ -7495,6 +7607,12 @@ packages:
lodash.startcase@4.4.0:
resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==}
lodash.union@4.6.0:
resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==}
lodash.uniq@4.5.0:
resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==}
lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
@ -7846,6 +7964,10 @@ packages:
mkdirp-classic@0.5.3:
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
mkdirp@0.5.6:
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
hasBin: true
mkdirp@1.0.4:
resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
engines: {node: '>=10'}
@ -8749,6 +8871,13 @@ packages:
readable-stream@2.3.8:
resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
readable-stream@3.6.2:
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
engines: {node: '>= 6'}
readdir-glob@1.1.3:
resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==}
readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
@ -8872,6 +9001,11 @@ packages:
rfdc@1.4.1:
resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==}
rimraf@2.7.1:
resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==}
deprecated: Rimraf versions prior to v4 are no longer supported
hasBin: true
rimraf@6.0.1:
resolution: {integrity: sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==}
engines: {node: 20 || >=22}
@ -8932,6 +9066,10 @@ packages:
sax@1.4.1:
resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==}
saxes@5.0.1:
resolution: {integrity: sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==}
engines: {node: '>=10'}
saxes@6.0.0:
resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
engines: {node: '>=v12.22.7'}
@ -9411,6 +9549,10 @@ packages:
tar-fs@3.0.9:
resolution: {integrity: sha512-XF4w9Xp+ZQgifKakjZYmFdkLoSWd34VGKcsTCwlNWM7QG3ZbaxnTsaBwnjFZqHRf/rROxaR8rXnbtwdvaDI+lA==}
tar-stream@2.2.0:
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
engines: {node: '>=6'}
tar-stream@3.1.7:
resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==}
@ -9517,6 +9659,9 @@ packages:
resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==}
engines: {node: '>=12'}
traverse@0.3.9:
resolution: {integrity: sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==}
tree-kill@1.2.2:
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
hasBin: true
@ -9818,6 +9963,9 @@ packages:
resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==}
engines: {node: '>=8'}
unzipper@0.10.14:
resolution: {integrity: sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==}
update-browserslist-db@1.1.3:
resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==}
hasBin: true
@ -10278,6 +10426,10 @@ packages:
resolution: {integrity: sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==}
engines: {node: '>=18'}
zip-stream@4.1.1:
resolution: {integrity: sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==}
engines: {node: '>= 10'}
zod-to-json-schema@3.24.5:
resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==}
peerDependencies:
@ -11600,6 +11752,25 @@ snapshots:
'@eslint/core': 0.14.0
levn: 0.4.1
'@fast-csv/format@4.3.5':
dependencies:
'@types/node': 14.18.63
lodash.escaperegexp: 4.1.2
lodash.isboolean: 3.0.3
lodash.isequal: 4.5.0
lodash.isfunction: 3.0.9
lodash.isnil: 4.0.0
'@fast-csv/parse@4.3.6':
dependencies:
'@types/node': 14.18.63
lodash.escaperegexp: 4.1.2
lodash.groupby: 4.6.0
lodash.isfunction: 3.0.9
lodash.isnil: 4.0.0
lodash.isundefined: 3.0.1
lodash.uniq: 4.5.0
'@fastify/busboy@2.1.1': {}
'@floating-ui/core@1.7.0':
@ -13960,6 +14131,8 @@ snapshots:
'@types/node@12.20.55': {}
'@types/node@14.18.63': {}
'@types/node@18.19.100':
dependencies:
undici-types: 5.26.5
@ -14393,6 +14566,42 @@ snapshots:
aproba@2.0.0: {}
archiver-utils@2.1.0:
dependencies:
glob: 7.2.3
graceful-fs: 4.2.11
lazystream: 1.0.1
lodash.defaults: 4.2.0
lodash.difference: 4.5.0
lodash.flatten: 4.4.0
lodash.isplainobject: 4.0.6
lodash.union: 4.6.0
normalize-path: 3.0.0
readable-stream: 2.3.8
archiver-utils@3.0.4:
dependencies:
glob: 7.2.3
graceful-fs: 4.2.11
lazystream: 1.0.1
lodash.defaults: 4.2.0
lodash.difference: 4.5.0
lodash.flatten: 4.4.0
lodash.isplainobject: 4.0.6
lodash.union: 4.6.0
normalize-path: 3.0.0
readable-stream: 3.6.2
archiver@5.3.2:
dependencies:
archiver-utils: 2.1.0
async: 3.2.6
buffer-crc32: 0.2.13
readable-stream: 3.6.2
readdir-glob: 1.1.3
tar-stream: 2.2.0
zip-stream: 4.1.1
arg@5.0.2: {}
argparse@1.0.10:
@ -14622,15 +14831,28 @@ snapshots:
- bare-buffer
optional: true
big-integer@1.6.52: {}
bignumber.js@9.3.0: {}
binary-extensions@2.3.0: {}
binary@0.3.0:
dependencies:
buffers: 0.1.1
chainsaw: 0.1.0
bindings@1.5.0:
dependencies:
file-uri-to-path: 1.0.0
optional: true
bl@4.1.0:
dependencies:
buffer: 5.7.1
inherits: 2.0.4
readable-stream: 3.6.2
bluebird@3.4.7: {}
body-parser@2.2.0:
@ -14687,11 +14909,15 @@ snapshots:
buffer-from@1.1.2: {}
buffer-indexof-polyfill@1.0.2: {}
buffer@5.7.1:
dependencies:
base64-js: 1.5.1
ieee754: 1.2.1
buffers@0.1.1: {}
bundle-name@4.1.0:
dependencies:
run-applescript: 7.0.0
@ -14762,6 +14988,10 @@ snapshots:
loupe: 3.1.3
pathval: 2.0.0
chainsaw@0.1.0:
dependencies:
traverse: 0.3.9
chalk@2.4.2:
dependencies:
ansi-styles: 3.2.1
@ -14985,6 +15215,13 @@ snapshots:
commander@8.3.0: {}
compress-commons@4.1.2:
dependencies:
buffer-crc32: 0.2.13
crc32-stream: 4.0.3
normalize-path: 3.0.0
readable-stream: 3.6.2
concat-map@0.0.1: {}
confbox@0.1.8: {}
@ -15047,6 +15284,13 @@ snapshots:
yaml: 1.10.2
optional: true
crc-32@1.2.2: {}
crc32-stream@4.0.3:
dependencies:
crc-32: 1.2.2
readable-stream: 3.6.2
create-jest@29.7.0(@types/node@20.17.57)(babel-plugin-macros@3.1.0):
dependencies:
'@jest/types': 29.6.3
@ -15515,6 +15759,10 @@ snapshots:
es-errors: 1.3.0
gopd: 1.2.0
duplexer2@0.1.4:
dependencies:
readable-stream: 2.3.8
duplexer@0.1.2: {}
eastasianwidth@0.2.0: {}
@ -16015,6 +16263,18 @@ snapshots:
dependencies:
eventsource-parser: 3.0.2
exceljs@4.4.0:
dependencies:
archiver: 5.3.2
dayjs: 1.11.13
fast-csv: 4.3.6
jszip: 3.10.1
readable-stream: 3.6.2
saxes: 5.0.1
tmp: 0.2.3
unzipper: 0.10.14
uuid: 8.3.2
execa@5.1.1:
dependencies:
cross-spawn: 7.0.6
@ -16144,6 +16404,11 @@ snapshots:
transitivePeerDependencies:
- supports-color
fast-csv@4.3.6:
dependencies:
'@fast-csv/format': 4.3.5
'@fast-csv/parse': 4.3.6
fast-deep-equal@3.1.3: {}
fast-equals@5.2.2: {}
@ -16323,6 +16588,8 @@ snapshots:
from@0.1.7: {}
fs-constants@1.0.0: {}
fs-extra@7.0.1:
dependencies:
graceful-fs: 4.2.11
@ -16340,6 +16607,13 @@ snapshots:
fsevents@2.3.3:
optional: true
fstream@1.0.12:
dependencies:
graceful-fs: 4.2.11
inherits: 2.0.4
mkdirp: 0.5.6
rimraf: 2.7.1
function-bind@1.1.2: {}
function.prototype.name@1.1.8:
@ -17610,6 +17884,10 @@ snapshots:
layout-base@2.0.1: {}
lazystream@1.0.1:
dependencies:
readable-stream: 2.3.8
leven@3.1.0: {}
levn@0.4.1:
@ -17750,6 +18028,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
listenercount@1.0.1: {}
listr2@8.3.3:
dependencies:
cli-truncate: 4.0.0
@ -17781,18 +18061,36 @@ snapshots:
lodash.debounce@4.0.8: {}
lodash.defaults@4.2.0: {}
lodash.difference@4.5.0: {}
lodash.escaperegexp@4.1.2: {}
lodash.flatten@4.4.0: {}
lodash.groupby@4.6.0: {}
lodash.includes@4.3.0: {}
lodash.isboolean@3.0.3: {}
lodash.isequal@4.5.0: {}
lodash.isfunction@3.0.9: {}
lodash.isinteger@4.0.4: {}
lodash.isnil@4.0.0: {}
lodash.isnumber@3.0.3: {}
lodash.isplainobject@4.0.6: {}
lodash.isstring@4.0.1: {}
lodash.isundefined@3.0.1: {}
lodash.memoize@4.1.2: {}
lodash.merge@4.6.2: {}
@ -17803,6 +18101,10 @@ snapshots:
lodash.startcase@4.4.0: {}
lodash.union@4.6.0: {}
lodash.uniq@4.5.0: {}
lodash@4.17.21: {}
log-symbols@4.1.0:
@ -18387,6 +18689,10 @@ snapshots:
mkdirp-classic@0.5.3:
optional: true
mkdirp@0.5.6:
dependencies:
minimist: 1.2.8
mkdirp@1.0.4: {}
mkdirp@3.0.1: {}
@ -19399,6 +19705,16 @@ snapshots:
string_decoder: 1.1.1
util-deprecate: 1.0.2
readable-stream@3.6.2:
dependencies:
inherits: 2.0.4
string_decoder: 1.1.1
util-deprecate: 1.0.2
readdir-glob@1.1.3:
dependencies:
minimatch: 5.1.6
readdirp@3.6.0:
dependencies:
picomatch: 2.3.1
@ -19565,6 +19881,10 @@ snapshots:
rfdc@1.4.1: {}
rimraf@2.7.1:
dependencies:
glob: 7.2.3
rimraf@6.0.1:
dependencies:
glob: 11.0.2
@ -19658,6 +19978,10 @@ snapshots:
sax@1.4.1: {}
saxes@5.0.1:
dependencies:
xmlchars: 2.2.0
saxes@6.0.0:
dependencies:
xmlchars: 2.2.0
@ -20221,6 +20545,14 @@ snapshots:
transitivePeerDependencies:
- bare-buffer
tar-stream@2.2.0:
dependencies:
bl: 4.1.0
end-of-stream: 1.4.4
fs-constants: 1.0.0
inherits: 2.0.4
readable-stream: 3.6.2
tar-stream@3.1.7:
dependencies:
b4a: 1.6.7
@ -20324,6 +20656,8 @@ snapshots:
dependencies:
punycode: 2.3.1
traverse@0.3.9: {}
tree-kill@1.2.2: {}
tree-sitter-wasms@0.1.12: {}
@ -20640,6 +20974,19 @@ snapshots:
untildify@4.0.0: {}
unzipper@0.10.14:
dependencies:
big-integer: 1.6.52
binary: 0.3.0
bluebird: 3.4.7
buffer-indexof-polyfill: 1.0.2
duplexer2: 0.1.4
fstream: 1.0.12
graceful-fs: 4.2.11
listenercount: 1.0.1
readable-stream: 2.3.8
setimmediate: 1.0.5
update-browserslist-db@1.1.3(browserslist@4.24.5):
dependencies:
browserslist: 4.24.5
@ -21264,6 +21611,12 @@ snapshots:
yoctocolors@2.1.1: {}
zip-stream@4.1.1:
dependencies:
archiver-utils: 3.0.4
compress-commons: 4.1.2
readable-stream: 3.6.2
zod-to-json-schema@3.24.5(zod@3.25.61):
dependencies:
zod: 3.25.61

View file

@ -0,0 +1,221 @@
import ExcelJS from "exceljs"
import { extractTextFromXLSX } from "../extract-text-from-xlsx"
describe("extractTextFromXLSX", () => {
describe("basic functionality", () => {
it("should extract text with proper formatting", async () => {
const workbook = new ExcelJS.Workbook()
const worksheet = workbook.addWorksheet("Sheet1")
worksheet.getCell("A1").value = "Hello"
worksheet.getCell("B1").value = "World"
worksheet.getCell("A2").value = "Test"
worksheet.getCell("B2").value = 123
const result = await extractTextFromXLSX(workbook)
expect(result).toContain("--- Sheet: Sheet1 ---")
expect(result).toContain("Hello\tWorld")
expect(result).toContain("Test\t123")
})
it("should skip rows with no content", async () => {
const workbook = new ExcelJS.Workbook()
const worksheet = workbook.addWorksheet("Sheet1")
worksheet.getCell("A1").value = "Row 1"
// Row 2 is completely empty
worksheet.getCell("A3").value = "Row 3"
const result = await extractTextFromXLSX(workbook)
expect(result).toContain("Row 1")
expect(result).toContain("Row 3")
// Should not contain empty rows
expect(result).not.toMatch(/\n\t*\n/)
})
})
describe("sheet handling", () => {
it("should process multiple sheets", async () => {
const workbook = new ExcelJS.Workbook()
const sheet1 = workbook.addWorksheet("First Sheet")
sheet1.getCell("A1").value = "Sheet 1 Data"
const sheet2 = workbook.addWorksheet("Second Sheet")
sheet2.getCell("A1").value = "Sheet 2 Data"
const result = await extractTextFromXLSX(workbook)
expect(result).toContain("--- Sheet: First Sheet ---")
expect(result).toContain("Sheet 1 Data")
expect(result).toContain("--- Sheet: Second Sheet ---")
expect(result).toContain("Sheet 2 Data")
})
it("should skip hidden sheets", async () => {
const workbook = new ExcelJS.Workbook()
const visibleSheet = workbook.addWorksheet("Visible Sheet")
visibleSheet.getCell("A1").value = "Visible Data"
const hiddenSheet = workbook.addWorksheet("Hidden Sheet")
hiddenSheet.getCell("A1").value = "Hidden Data"
hiddenSheet.state = "hidden"
const result = await extractTextFromXLSX(workbook)
expect(result).toContain("--- Sheet: Visible Sheet ---")
expect(result).toContain("Visible Data")
expect(result).not.toContain("--- Sheet: Hidden Sheet ---")
expect(result).not.toContain("Hidden Data")
})
it("should skip very hidden sheets", async () => {
const workbook = new ExcelJS.Workbook()
const visibleSheet = workbook.addWorksheet("Visible Sheet")
visibleSheet.getCell("A1").value = "Visible Data"
const veryHiddenSheet = workbook.addWorksheet("Very Hidden Sheet")
veryHiddenSheet.getCell("A1").value = "Very Hidden Data"
veryHiddenSheet.state = "veryHidden"
const result = await extractTextFromXLSX(workbook)
expect(result).toContain("--- Sheet: Visible Sheet ---")
expect(result).toContain("Visible Data")
expect(result).not.toContain("--- Sheet: Very Hidden Sheet ---")
expect(result).not.toContain("Very Hidden Data")
})
})
describe("formatCellValue logic", () => {
it("should handle null and undefined values", async () => {
const workbook = new ExcelJS.Workbook()
const worksheet = workbook.addWorksheet("Sheet1")
worksheet.getCell("A1").value = "Before"
worksheet.getCell("A2").value = null
worksheet.getCell("A3").value = undefined
worksheet.getCell("A4").value = "After"
const result = await extractTextFromXLSX(workbook)
expect(result).toContain("Before")
expect(result).toContain("After")
// Should handle null/undefined as empty strings
const lines = result.split("\n")
const dataLines = lines.filter((line) => !line.startsWith("---") && line.trim())
expect(dataLines).toHaveLength(2) // Only 'Before' and 'After' should create content
})
it("should format dates correctly", async () => {
const workbook = new ExcelJS.Workbook()
const worksheet = workbook.addWorksheet("Sheet1")
const testDate = new Date("2023-12-25")
worksheet.getCell("A1").value = testDate
const result = await extractTextFromXLSX(workbook)
expect(result).toContain("2023-12-25")
})
it("should handle error values", async () => {
const workbook = new ExcelJS.Workbook()
const worksheet = workbook.addWorksheet("Sheet1")
worksheet.getCell("A1").value = { error: "#DIV/0!" }
const result = await extractTextFromXLSX(workbook)
expect(result).toContain("[Error: #DIV/0!]")
})
it("should handle rich text", async () => {
const workbook = new ExcelJS.Workbook()
const worksheet = workbook.addWorksheet("Sheet1")
worksheet.getCell("A1").value = {
richText: [{ text: "Hello " }, { text: "World", font: { bold: true } }],
}
const result = await extractTextFromXLSX(workbook)
expect(result).toContain("Hello World")
})
it("should handle hyperlinks", async () => {
const workbook = new ExcelJS.Workbook()
const worksheet = workbook.addWorksheet("Sheet1")
worksheet.getCell("A1").value = {
text: "Roo Code",
hyperlink: "https://roocode.com/",
}
const result = await extractTextFromXLSX(workbook)
expect(result).toContain("Roo Code (https://roocode.com/)")
})
it("should handle formulas with and without results", async () => {
const workbook = new ExcelJS.Workbook()
const worksheet = workbook.addWorksheet("Sheet1")
worksheet.getCell("A1").value = { formula: "A2+A3", result: 30 }
worksheet.getCell("A2").value = { formula: "SUM(B1:B10)" }
const result = await extractTextFromXLSX(workbook)
expect(result).toContain("30") // Formula with result
expect(result).toContain("[Formula: SUM(B1:B10)]") // Formula without result
})
})
describe("edge cases", () => {
it("should handle empty workbook", async () => {
const workbook = new ExcelJS.Workbook()
workbook.addWorksheet("Empty Sheet")
const result = await extractTextFromXLSX(workbook)
expect(result).toContain("--- Sheet: Empty Sheet ---")
expect(result.trim()).toBe("--- Sheet: Empty Sheet ---")
})
it("should handle workbook with only empty cells", async () => {
const workbook = new ExcelJS.Workbook()
const worksheet = workbook.addWorksheet("Sheet1")
// Set cells but leave them empty
worksheet.getCell("A1").value = ""
worksheet.getCell("B1").value = ""
const result = await extractTextFromXLSX(workbook)
expect(result).toContain("--- Sheet: Sheet1 ---")
// Should not contain any data rows since empty strings don't count as content
const lines = result.split("\n").filter((line) => line.trim() && !line.startsWith("---"))
expect(lines).toHaveLength(0)
})
})
describe("function overloads", () => {
it("should work with workbook objects", async () => {
const workbook = new ExcelJS.Workbook()
const worksheet = workbook.addWorksheet("Test")
worksheet.getCell("A1").value = "Test Data"
const result = await extractTextFromXLSX(workbook)
expect(result).toContain("Test Data")
})
it("should reject invalid file paths", async () => {
await expect(extractTextFromXLSX("/non/existent/file.xlsx")).rejects.toThrow()
})
})
})

View file

@ -0,0 +1,89 @@
import ExcelJS from "exceljs"
const ROW_LIMIT = 50000
function formatCellValue(cell: ExcelJS.Cell): string {
const value = cell.value
if (value === null || value === undefined) {
return ""
}
// Handle error values (#DIV/0!, #N/A, etc.)
if (typeof value === "object" && "error" in value) {
return `[Error: ${value.error}]`
}
// Handle dates - ExcelJS can parse them as Date objects
if (value instanceof Date) {
return value.toISOString().split("T")[0]
}
// Handle rich text
if (typeof value === "object" && "richText" in value) {
return value.richText.map((rt) => rt.text).join("")
}
// Handle hyperlinks
if (typeof value === "object" && "text" in value && "hyperlink" in value) {
return `${value.text} (${value.hyperlink})`
}
// Handle formulas - get the calculated result
if (typeof value === "object" && "formula" in value) {
if ("result" in value && value.result !== undefined && value.result !== null) {
return value.result.toString()
} else {
return `[Formula: ${value.formula}]`
}
}
return value.toString()
}
export async function extractTextFromXLSX(filePathOrWorkbook: string | ExcelJS.Workbook): Promise<string> {
let workbook: ExcelJS.Workbook
let excelText = ""
if (typeof filePathOrWorkbook === "string") {
workbook = new ExcelJS.Workbook()
await workbook.xlsx.readFile(filePathOrWorkbook)
} else {
workbook = filePathOrWorkbook
}
workbook.eachSheet((worksheet, sheetId) => {
if (worksheet.state === "hidden" || worksheet.state === "veryHidden") {
return
}
excelText += `--- Sheet: ${worksheet.name} ---\n`
worksheet.eachRow({ includeEmpty: false }, (row, rowNumber) => {
if (rowNumber > ROW_LIMIT) {
excelText += `[... truncated at row ${rowNumber} ...]\n`
return false
}
const rowTexts: string[] = []
let hasContent = false
row.eachCell({ includeEmpty: true }, (cell, colNumber) => {
const cellText = formatCellValue(cell)
if (cellText.trim()) {
hasContent = true
}
rowTexts.push(cellText)
})
if (hasContent) {
excelText += rowTexts.join("\t") + "\n"
}
return true
})
excelText += "\n"
})
return excelText.trim()
}

View file

@ -4,6 +4,7 @@ import pdf from "pdf-parse/lib/pdf-parse"
import mammoth from "mammoth"
import fs from "fs/promises"
import { isBinaryFile } from "isbinaryfile"
import { extractTextFromXLSX } from "./extract-text-from-xlsx"
async function extractTextFromPDF(filePath: string): Promise<string> {
const dataBuffer = await fs.readFile(filePath)
@ -37,6 +38,7 @@ const SUPPORTED_BINARY_FORMATS = {
".pdf": extractTextFromPDF,
".docx": extractTextFromDOCX,
".ipynb": extractTextFromIPYNB,
".xlsx": extractTextFromXLSX,
} as const
/**

View file

@ -387,6 +387,7 @@
"delay": "^6.0.0",
"diff": "^5.2.0",
"diff-match-patch": "^1.0.5",
"exceljs": "^4.4.0",
"fast-deep-equal": "^3.1.3",
"fast-xml-parser": "^5.0.0",
"fastest-levenshtein": "^1.0.16",