#!/usr/bin/env -S deno run --allow-net // @deno-types="https://cdn.sheetjs.com/xlsx-latest/package/types/index.d.ts" import { read, stream, Sheet2CSVOpts, WorkSheet } from 'https://cdn.sheetjs.com/xlsx-latest/package/xlsx.mjs'; interface Resumable { resume:()=>void; }; /* Generate row strings from a worksheet */ function sheet_to_csv_cb(ws: WorkSheet, cb:(d:string|null)=>void, opts: Sheet2CSVOpts = {}, batch = 1000): Resumable { stream.set_readable(() => ({ __done: false, // this function will be assigned by the SheetJS stream methods _read: function() { this.__done = true; }, // this function is called by the stream methods push: function(d: string|null) { if(!this.__done) cb(d); if(d == null) this.__done = true; }, resume: function pump() { for(var i = 0; i < batch && !this.__done; ++i) this._read(); if(!this.__done) setTimeout(pump.bind(this), 0); } })); return stream.to_csv(ws, opts) as Resumable; } /* Callback invoked on each row (string) and at the end (null) */ const csv_cb = (d:string|null) => { if(d == null) return; /* The strings include line endings, so raw write ops should be used */ Deno.stdout.write(new TextEncoder().encode(d)); }; /* Fetch https://sheetjs.com/pres.numbers, parse, and get first worksheet */ const ab = await (await fetch("https://sheetjs.com/pres.numbers")).arrayBuffer(); const wb = read(ab, { dense: true }); const ws = wb.Sheets[wb.SheetNames[0]]; /* Create and start CSV stream */ sheet_to_csv_cb(ws, csv_cb).resume();