export nits

- XLSX write dense mode null check (fixes #3261 h/t @mbornstein)
- Use `subarray` for Uint8Array/Buffer ops (h/t @hardonthebeat)
This commit is contained in:
SheetJS 2025-02-22 15:18:51 -05:00
parent 9c3853ba25
commit 0e4eb976e1
5 changed files with 55 additions and 45 deletions

@ -2,6 +2,7 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* eslint-env node */
/* vim: set ts=2 ft=javascript: */
var n = "xlsx";
var X = require('../');
try { X = require('../xlsx.flow'); } catch(e) {}
@ -17,7 +18,7 @@ try { program = require('commander'); } catch(e) {
"For older versions of node, explicitly install `xlsx-cli` globally:",
" $ npm i -g xlsx-cli",
" $ xlsx-cli --help"
].forEach(function(m) { console.error(m); });
].forEach(function (m) { console.error(m); });
process.exit(1);
}
program
@ -65,9 +66,10 @@ program
.option('-F, --field-sep <sep>', 'CSV field separator', ",")
.option('-R, --row-sep <sep>', 'CSV row separator', "\n")
.option('-n, --sheet-rows <num>', 'Number of rows to process (0=all rows)')
.option('--date-format <string>', 'output date format, for example yyyy-mm-dd')
.option('--codepage <cp>', 'default to specified codepage when ambiguous')
.option('--req <module>', 'require module before processing')
.option('--sst', 'generate shared string table for XLS* formats')
.option('-d, --no-dim', 'recalculate worksheet range')
.option('--compress', 'use compression when writing XLSX/M/B and ODS')
.option('--read', 'read but do not generate output')
.option('--book', 'for single-sheet formats, emit a file per worksheet')
@ -102,18 +104,18 @@ var wb_formats_2 = [
program.parse(process.argv);
var filename = '', sheetname = '';
if(program.args[0]) {
if (program.args[0]) {
filename = program.args[0];
if(program.args[1]) sheetname = program.args[1];
if (program.args[1]) sheetname = program.args[1];
}
if(program.sheet) sheetname = program.sheet;
if(program.file) filename = program.file;
if (program.sheet) sheetname = program.sheet;
if (program.file) filename = program.file;
if(!filename) {
if (!filename) {
console.error(n + ": must specify a filename");
process.exit(1);
}
if(!fs.existsSync(filename)) {
if (!fs.existsSync(filename)) {
console.error(n + ": " + filename + ": No such file or directory");
process.exit(2);
}
@ -209,15 +211,15 @@ wb_formats_2.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) {
} });
var target_sheet = sheetname || '';
if(target_sheet === '') {
if(+program.sheetIndex < (wb.SheetNames||[]).length) target_sheet = wb.SheetNames[+program.sheetIndex];
else target_sheet = (wb.SheetNames||[""])[0];
if (target_sheet === '') {
if (+program.sheetIndex < (wb.SheetNames || []).length) target_sheet = wb.SheetNames[+program.sheetIndex];
else target_sheet = (wb.SheetNames || [""])[0];
}
var ws;
try {
ws = wb.Sheets[target_sheet];
if(!ws) {
if (!ws) {
console.error("Sheet " + target_sheet + " cannot be found");
process.exit(3);
}
@ -226,7 +228,7 @@ try {
process.exit(4);
}
if(!program.quiet && !program.book) console.error(target_sheet);
if (!program.quiet && !program.book) console.error(target_sheet);
/* single worksheet file formats */
[
@ -254,21 +256,21 @@ if(!program.quiet && !program.book) console.error(target_sheet);
process.exit(0);
} });
function outit(o, fn) { if(fn) fs.writeFileSync(fn, o); else console.log(o); }
function outit(o, fn) { if (fn) fs.writeFileSync(fn, o); else console.log(o); }
function doit(cb) {
/*:: if(!wb) throw new Error("unreachable"); */
if(program.book) wb.SheetNames.forEach(function(n, i) {
/*:: if(!wb) throw new Error("unreachable"); */
/*:: if (!wb) throw new Error("unreachable"); */
if (program.book) wb.SheetNames.forEach(function (n, i) {
/*:: if (!wb) throw new Error("unreachable"); */
outit(cb(wb.Sheets[n]), (program.output || sheetname || filename) + "." + i);
});
else outit(cb(ws), program.output);
}
var jso = {};
switch(true) {
switch (true) {
case program.formulae:
doit(function(ws) { return X.utils.sheet_to_formulae(ws).join("\n"); });
doit(function (ws) { return X.utils.sheet_to_formulae(ws).join("\n"); });
break;
case program.arrays: jso.header = 1;
@ -276,33 +278,33 @@ switch(true) {
case program.rawJs: jso.raw = true;
/* falls through */
case program.json:
doit(function(ws) { return JSON.stringify(X.utils.sheet_to_json(ws,jso)); });
doit(function (ws) { return JSON.stringify(X.utils.sheet_to_json(ws, jso)); });
break;
default:
if(!program.book) {
var stream = X.stream.to_csv(ws, {FS:program.fieldSep||",", RS:program.rowSep||"\n"});
if(program.output) stream.pipe(fs.createWriteStream(program.output));
if (!program.book) {
var stream = X.stream.to_csv(ws, { FS: program.fieldSep || ",", RS: program.rowSep || "\n" });
if (program.output) stream.pipe(fs.createWriteStream(program.output));
else stream.pipe(process.stdout);
} else doit(function(ws) { return X.utils.sheet_to_csv(ws,{FS:program.fieldSep, RS:program.rowSep}); });
} else doit(function (ws) { return X.utils.sheet_to_csv(ws, { FS: program.fieldSep, RS: program.rowSep }); });
break;
}
function dump_props(wb/*:Workbook*/) {
var propaoa = [];
if(Object.assign && Object.entries) propaoa = Object.entries(Object.assign({}, wb.Props, wb.Custprops));
if (Object.assign && Object.entries) propaoa = Object.entries(Object.assign({}, wb.Props, wb.Custprops));
else {
var Keys/*:: :Array<string> = []*/, pi;
if(wb.Props) {
if (wb.Props) {
Keys = Object.keys(wb.Props);
for(pi = 0; pi < Keys.length; ++pi) {
if(Object.prototype.hasOwnProperty.call(Keys, Keys[pi])) propaoa.push([Keys[pi], Keys[/*::+*/Keys[pi]]]);
for (pi = 0; pi < Keys.length; ++pi) {
if (Object.prototype.hasOwnProperty.call(Keys, Keys[pi])) propaoa.push([Keys[pi], Keys[/*::+*/Keys[pi]]]);
}
}
if(wb.Custprops) {
if (wb.Custprops) {
Keys = Object.keys(wb.Custprops);
for(pi = 0; pi < Keys.length; ++pi) {
if(Object.prototype.hasOwnProperty.call(Keys, Keys[pi])) propaoa.push([Keys[pi], Keys[/*::+*/Keys[pi]]]);
for (pi = 0; pi < Keys.length; ++pi) {
if (Object.prototype.hasOwnProperty.call(Keys, Keys[pi])) propaoa.push([Keys[pi], Keys[/*::+*/Keys[pi]]]);
}
}
}

@ -21,7 +21,8 @@ function recordhopper(data, cb/*:RecordHopperCB*/, opts/*:?any*/) {
/* control buffer usage for fixed-length buffers */
function buf_array()/*:BufArray*/ {
var bufs/*:Array<Block>*/ = [], blksz = has_buf ? 16384 : 2048;
var has_buf_copy = has_buf && (typeof new_buf(blksz).copy == "function");
var has_buf_subarray = has_buf && (typeof new_buf(blksz).subarray == "function");
var newblk = function ba_newblk(sz/*:number*/)/*:Block*/ {
var o/*:Block*/ = (new_buf(sz)/*:any*/);
prep_blob(o, 0);
@ -55,7 +56,10 @@ function buf_array()/*:BufArray*/ {
};
var push = function ba_push(buf) {
endbuf(); curbuf = buf; if(curbuf.l == null) curbuf.l = curbuf.length; next(blksz);
if(curbuf.l > 0) bufs.push(curbuf.slice(0, curbuf.l));
bufs.push(buf);
curbuf = has_buf_subarray ? curbuf.subarray(curbuf.l || 0) : curbuf.slice(curbuf.l || 0);
prep_blob(curbuf, 0);
};
return ({ next:next, push:push, end:end, _bufs:bufs, end2:end2 }/*:any*/);

@ -6,7 +6,7 @@ var mergecregex = /<(?:\w+:)?mergeCell ref=["'][A-Z0-9:]+['"]\s*[\/]?>/g;
var hlinkregex = /<(?:\w+:)?hyperlink [^<>]*>/mg;
var dimregex = /"(\w*:\w*)"/;
var colregex = /<(?:\w+:)?col\b[^<>]*[\/]?>/g;
var afregex = /<(?:\w+:)?autoFilter[^>]*/g;
var afregex = /<(?:\w:)?autoFilter[^>]*([\/]|>([\s\S]*)<\/(?:\w:)?autoFilter)>/g;
var marginregex= /<(?:\w+:)?pageMargins[^<>]*\/>/g;
var sheetprregex = /<(?:\w+:)?sheetPr\b[^<>]*?\/>/;
@ -217,7 +217,7 @@ function write_ws_xml_cols(ws, cols)/*:string*/ {
}
function parse_ws_xml_autofilter(data/*:string*/) {
var o = { ref: (data.match(/ref="([^"]*)"/)||[])[1]};
var o = { ref: (data.match(/ref=["']([^"']*)["']/)||[])[1]};
return o;
}
function write_ws_xml_autofilter(data, ws, wb, idx)/*:string*/ {
@ -529,7 +529,7 @@ function write_ws_xml_data(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook
r = [];
rr = encode_row(R);
var data_R = dense ? data[R] : [];
for(C = range.s.c; C <= range.e.c; ++C) {
if(data_R) for(C = range.s.c; C <= range.e.c; ++C) {
ref = cols[C] + rr;
var _cell = dense ? data_R[C] : ws[ref];
if(_cell === undefined) continue;

@ -137,12 +137,6 @@ function sheet_to_html(ws/*:Worksheet*/, opts/*:?Sheet2HTMLOpts*//*, wb:?Workboo
}
function sheet_add_dom(ws/*:Worksheet*/, table/*:HTMLElement*/, _opts/*:?any*/)/*:Worksheet*/ {
var rows/*:HTMLCollection<HTMLTableRowElement>*/ = table.rows;
if(!rows) {
/* not an HTML TABLE */
throw "Unsupported origin when " + table.tagName + " is not a TABLE";
}
var opts = _opts || {};
var dense = ws["!data"] != null;
var or_R = 0, or_C = 0;
@ -154,7 +148,6 @@ function sheet_add_dom(ws/*:Worksheet*/, table/*:HTMLElement*/, _opts/*:?any*/)/
}
}
var sheetRows = Math.min(opts.sheetRows||10000000, rows.length);
var range/*:Range*/ = {s:{r:0,c:0},e:{r:or_R,c:or_C}};
if(ws["!ref"]) {
var _range/*:Range*/ = decode_range(ws["!ref"]);
@ -164,6 +157,15 @@ function sheet_add_dom(ws/*:Worksheet*/, table/*:HTMLElement*/, _opts/*:?any*/)/
range.e.c = Math.max(range.e.c, _range.e.c);
if(or_R == -1) range.e.r = or_R = _range.e.r + 1;
}
var rows/*:HTMLCollection<HTMLTableRowElement>*/ = table.rows;
if(!rows) {
/* not an HTML TABLE */
throw "Unsupported origin when " + table.tagName + " is not a TABLE";
}
var sheetRows = Math.min(opts.sheetRows||10000000, rows.length);
var merges/*:Array<Range>*/ = [], midx = 0;
var rowinfo/*:Array<RowInfo>*/ = ws["!rows"] || (ws["!rows"] = []);
var _R = 0, R = 0, _C = 0, C = 0, RS = 0, CS = 0;
@ -187,7 +189,9 @@ function sheet_add_dom(ws/*:Worksheet*/, table/*:HTMLElement*/, _opts/*:?any*/)/
}
/* TODO: figure out how to extract nonstandard mso- style */
CS = +elt.getAttribute("colspan") || 1;
if( ((RS = (+elt.getAttribute("rowspan") || 1)))>1 || CS>1) merges.push({s:{r:R + or_R,c:C + or_C},e:{r:R + or_R + (RS||1) - 1, c:C + or_C + (CS||1) - 1}});
if( ((RS = (+elt.getAttribute("rowspan") || 1)))>1 || CS>1) {
merges.push({s:{r:R + or_R,c:C + or_C},e:{r:R + or_R + (RS||1) - 1, c:C + or_C + (CS||1) - 1}});
}
var o/*:Cell*/ = {t:'s', v:v};
var _t/*:string*/ = elt.getAttribute("data-t") || elt.getAttribute("t") || "";
if(v != null) {

@ -24,7 +24,7 @@ function make_json_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Ar
switch(val.t){
case 'z': if(v == null) break; continue;
case 'e': v = (v == 0 ? null : void 0); break;
case 's': case 'b':break;
case 's': case 'b': break;
case 'n': if(!val.z || !fmt_is_date(val.z)) break;
v = numdate(v); // TODO: date1904 setting should also be stored in worksheet object
if(typeof v == "number") break;