Merge branch 'master' into types

This commit is contained in:
lionel-rowe 2023-12-10 10:53:42 +00:00
commit c9b78b6563
46 changed files with 1585 additions and 608 deletions

@ -4,6 +4,18 @@ This log is intended to keep track of backwards-incompatible changes, including
but not limited to API changes and file location changes. Minor behavioral
changes may not be included if they are not expected to break existing code.
## v0.20.1
* `init` use packaged test files to work around GitHub breaking changes
* SSF date code rounding to 15 decimal digits (h/t @davidtamaki)
* `sheet_to_json` force UTC interpretation for formatted strings (h/t @Blanay)
* QPW extract result of string formula
* XLSX parse non-compliant merge cell expressions
* NUMBERS correctly handle rows omitted from official exports
* DBF parse empty logical field (h/t @Roman91)
* `dense` option added to types
* package.json add mini and core scripts to export map (h/t @stof)
## v0.20.0
* Use UTC interpretation of Date objects for date cells (potentially breaking)

@ -67,10 +67,9 @@ clean-data:
.PHONY: init
init: ## Initial setup for development
git submodule init
git submodule update
#git submodule foreach git pull origin master
git submodule foreach make all
rm -rf test_files
if [ ! -e test_files.zip ]; then curl -LO https://test-files.sheetjs.com/test_files.zip; fi
unzip test_files.zip
mkdir -p tmp
DISTHDR=misc/suppress_export.js

@ -9,29 +9,30 @@ Edit complex templates with ease; let out your inner Picasso with styling; make
custom sheets with images/graphs/PivotTables; evaluate formula expressions and
port calculations to web apps; automate common spreadsheet tasks, and much more!
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/sheetjs?pixel)](https://git.sheetjs.com/SheetJS/sheetjs)
[![Build Status](https://saucelabs.com/browser-matrix/sheetjs.svg)](https://saucelabs.com/u/sheetjs)
## Documentation
- [API and Usage Documentation](https://docs.sheetjs.com)
- [Downloadable Scripts and Modules](https://cdn.sheetjs.com)
## Related Projects
## Constellation
- <https://oss.sheetjs.com/notes/>: File Format Notes
- [`ssf`](packages/ssf): Format data using ECMA-376 spreadsheet format codes
- [`xlsx-cli`](packages/xlsx-cli/): NodeJS command-line tool for processing files
- [`xlsx-cli`](packages/xlsx-cli): NodeJS command-line tool for processing files
- [`test_files`](https://github.com/SheetJS/test_files): Sample spreadsheets
- [`cfb`](https://git.sheetjs.com/SheetJS/js-cfb): Container (OLE/ZIP) file
processing library
- [`cfb`](https://git.sheetjs.com/SheetJS/js-cfb): Container (OLE/ZIP) format library
- [`codepage`](https://git.sheetjs.com/SheetJS/js-codepage): Legacy text
encodings for XLS and other legacy spreadsheet formats
- [`codepage`](https://git.sheetjs.com/SheetJS/js-codepage): Legacy text encodings
- [`dta`](packages/dta): Stata DTA file processor
- [`test_files`](https://github.com/sheetjs/test_files): Test files and various
plaintext baselines.
## License

@ -1 +1 @@
XLSX.version = '0.20.0';
XLSX.version = '0.20.1';

@ -29,7 +29,7 @@ function make_json_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Ar
v = numdate(v); // TODO: date1904 setting should also be stored in worksheet object
if(typeof v == "number") break;
/* falls through */
case 'd': if(!(o && o.UTC)) v = utc_to_local(v); break;
case 'd': if(!(o && (o.UTC||(o.raw === false)))) v = utc_to_local(new Date(v)); break;
default: throw new Error('unrecognized type ' + val.t);
}
if(hdr[C] != null) {

32
dist/xlsx.core.min.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/xlsx.core.min.map generated vendored

File diff suppressed because one or more lines are too long

162
dist/xlsx.extendscript.js generated vendored

@ -160,7 +160,7 @@ var DO_NOT_EXPORT_CODEPAGE = true;
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false, DataView:false, Deno:false, Float32Array:false */
var XLSX = {};
function make_xlsx_lib(XLSX){
XLSX.version = '0.20.0';
XLSX.version = '0.20.1';
var current_codepage = 1200, current_ansi = 1252;
/*global cptable:true, window */
var $cptable;
@ -620,8 +620,20 @@ function SSF_frac(x, D, mixed) {
var q = Math.floor(sgn * P/Q);
return [q, sgn*P - q*Q, Q];
}
function SSF_normalize_xl_unsafe(v) {
var s = v.toPrecision(16);
if(s.indexOf("e") > -1) {
var m = s.slice(0, s.indexOf("e"));
m = m.indexOf(".") > -1 ? m.slice(0, (m.slice(0,2) == "0." ? 17 : 16)) : (m.slice(0,15) + fill("0", m.length - 15));
return m + s.slice(s.indexOf("e"));
}
var n = s.indexOf(".") > -1 ? s.slice(0, (s.slice(0,2) == "0." ? 17 : 16)) : (s.slice(0,15) + fill("0", s.length - 15));
return Number(n);
}
function SSF_parse_date_code(v,opts,b2) {
if(v > 2958465 || v < 0) return null;
v = SSF_normalize_xl_unsafe(v);
var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
var dout=[];
var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
@ -774,7 +786,7 @@ if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100;
switch(fmt) {
case '[h]': case '[hh]': out = val.D*24+val.H; break;
case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break;
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+(ss0 == 0 ? Math.round(val.S+val.u) : val.S); break;
default: throw 'bad abstime format: ' + fmt;
} outl = fmt.length === 3 ? 1 : 2; break;
case 101: /* 'e' era */
@ -1220,10 +1232,11 @@ function eval_fmt(fmt, v, opts, flen) {
switch(out[i].t) {
case 'h': case 'H': out[i].t = hr; lst='h'; if(bt < 1) bt = 1; break;
case 's':
if((ssm=out[i].v.match(/\.0+$/))) ss0=Math.max(ss0,ssm[0].length-1);
if((ssm=out[i].v.match(/\.0+$/))) { ss0=Math.max(ss0,ssm[0].length-1); bt = 4;}
if(bt < 3) bt = 3;
/* falls through */
case 'd': case 'y': case 'M': case 'e': lst=out[i].t; break;
case 'd': case 'y': case 'e': lst=out[i].t; break;
case 'M': lst=out[i].t; if(bt < 2) bt = 2; break;
case 'm': if(lst === 's') { out[i].t = 'M'; if(bt < 2) bt = 2; } break;
case 'X': /*if(out[i].v === "B2");*/
break;
@ -1233,17 +1246,29 @@ function eval_fmt(fmt, v, opts, flen) {
if(bt < 3 && out[i].v.match(/[Ss]/)) bt = 3;
}
}
/* time rounding depends on presence of minute / second / usec fields */
var _dt;
switch(bt) {
case 0: break;
case 1:
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
case 2:
case 3:
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
if(dt.H >= 24) { dt.H = 0; ++dt.D; _dt = SSF_parse_date_code(dt.D); _dt.u = dt.u; _dt.S = dt.S; _dt.M = dt.M; _dt.H = dt.H; dt = _dt; }
break;
case 2:
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
case 4:
switch(ss0) {
case 1: dt.u = Math.round(dt.u * 10)/10; break;
case 2: dt.u = Math.round(dt.u * 100)/100; break;
case 3: dt.u = Math.round(dt.u * 1000)/1000; break;
}
if(dt.u >= 1) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
if(dt.H >= 24) { dt.H = 0; ++dt.D; _dt = SSF_parse_date_code(dt.D); _dt.u = dt.u; _dt.S = dt.S; _dt.M = dt.M; _dt.H = dt.H; dt = _dt; }
break;
}
@ -4503,6 +4528,13 @@ function sheet_to_workbook(sheet, opts) {
return { SheetNames: [n], Sheets: sheets };
}
function sheet_new(opts) {
var out = {};
var o = opts || {};
if(o.dense) out["!data"] = [];
return out;
}
function sheet_add_aoa(_ws, data, opts) {
var o = opts || {};
var dense = _ws ? (_ws["!data"] != null) : o.dense;
@ -8059,7 +8091,7 @@ var fields = [], field = ({});
case 'L': switch(s.trim().toUpperCase()) {
case 'Y': case 'T': out[R][C] = true; break;
case 'N': case 'F': out[R][C] = false; break;
case '': case '?': break;
case '': case '\x00': case '?': break;
default: throw new Error("DBF Unrecognized L:|" + s + "|");
} break;
case 'M': /* TODO: handle memo files */
@ -8121,6 +8153,7 @@ function dbf_to_workbook(buf, opts) {
var _RLEN = { 'B': 8, 'C': 250, 'L': 1, 'D': 8, '?': 0, '': 0 };
function sheet_to_dbf(ws, opts) {
if(!ws["!ref"]) throw new Error("Cannot export empty sheet to DBF");
var o = opts || {};
var old_cp = current_codepage;
if(+o.codepage >= 0) set_cp(+o.codepage);
@ -8278,7 +8311,10 @@ var SYLK = (function() {
"!":161, '"':162, "#":163, "(":164, "%":165, "'":167, "H ":168,
"+":171, ";":187, "<":188, "=":189, ">":190, "?":191, "{":223
});
var sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1") + "|\\|)", "gm");
var sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1").replace("{", "\\{") + "|\\|)", "gm");
try {
sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1") + "|\\|)", "gm");
} catch(e) {}
var sylk_char_fn = function(_, $1){ var o = sylk_escapes[$1]; return typeof o == "number" ? _getansi(o) : o; };
var decode_sylk_char = function($$, $1, $2) { var newcc = (($1.charCodeAt(0) - 0x20)<<4) | ($2.charCodeAt(0) - 0x30); return newcc == 59 ? $$ : _getansi(newcc); };
sylk_escapes["|"] = 254;
@ -8501,7 +8537,7 @@ var SYLK = (function() {
if(!opts) opts = {}; opts._formats = ["General"];
/* TODO: codepage */
var preamble = ["ID;PSheetJS;N;E"], o = [];
var r = safe_decode_range(ws['!ref']), cell;
var r = safe_decode_range(ws['!ref']||"A1"), cell;
var dense = ws["!data"] != null;
var RS = "\r\n";
var d1904 = (((wb||{}).Workbook||{}).WBProps||{}).date1904;
@ -8510,7 +8546,7 @@ var SYLK = (function() {
preamble.push("P;PGeneral");
/* Excel has been inconsistent in comment placement */
var R = r.s.r, C = r.s.c, p = [];
for(R = r.s.r; R <= r.e.r; ++R) {
if(ws["!ref"]) for(R = r.s.r; R <= r.e.r; ++R) {
if(dense && !ws["!data"][R]) continue;
p = [];
for(C = r.s.c; C <= r.e.c; ++C) {
@ -8520,7 +8556,7 @@ var SYLK = (function() {
}
if(p.length) o.push(p.join(RS));
}
for(R = r.s.r; R <= r.e.r; ++R) {
if(ws["!ref"]) for(R = r.s.r; R <= r.e.r; ++R) {
if(dense && !ws["!data"][R]) continue;
p = [];
for(C = r.s.c; C <= r.e.c; ++C) {
@ -8540,7 +8576,7 @@ var SYLK = (function() {
if(ws['!cols']) write_ws_cols_sylk(preamble, ws['!cols']);
if(ws['!rows']) write_ws_rows_sylk(preamble, ws['!rows']);
preamble.push("B;Y" + (r.e.r - r.s.r + 1) + ";X" + (r.e.c - r.s.c + 1) + ";D" + [r.s.c,r.s.r,r.e.c,r.e.r].join(" "));
if(ws["!ref"]) preamble.push("B;Y" + (r.e.r - r.s.r + 1) + ";X" + (r.e.c - r.s.c + 1) + ";D" + [r.s.c,r.s.r,r.e.c,r.e.r].join(" "));
preamble.push("O;L;D;B" + (d1904 ? ";V4" : "") + ";K47;G100 0.001");
delete opts._formats;
@ -8613,6 +8649,7 @@ var DIF = (function() {
function make_value_str(s) { return "1,0\r\n\"" + s.replace(/"/g,'""') + '"'; }
function sheet_to_dif(ws) {
var _DIF_XL = DIF_XL;
if(!ws["!ref"]) throw new Error("Cannot export empty sheet to DIF");
var r = safe_decode_range(ws['!ref']);
var dense = ws["!data"] != null;
var o = [
@ -8950,6 +8987,7 @@ var PRN = (function() {
function sheet_to_prn(ws) {
var o = [];
if(!ws["!ref"]) return "";
var r = safe_decode_range(ws['!ref']), cell;
var dense = ws["!data"] != null;
for(var R = r.s.r; R <= r.e.r; ++R) {
@ -9174,6 +9212,7 @@ var WK_ = (function() {
if(+o.codepage >= 0) set_cp(+o.codepage);
if(o.type == "string") throw new Error("Cannot write WK1 to JS string");
var ba = buf_array();
if(!ws["!ref"]) throw new Error("Cannot export empty sheet to WK1");
var range = safe_decode_range(ws["!ref"]);
var dense = ws["!data"] != null;
var cols = [];
@ -9967,13 +10006,25 @@ var WK_ = (function() {
0x0E: "dd-mmm-yyyy",
0x0F: "mmm-yyyy",
0x22: "0.00",
0x32: "0.00;[Red]0.00",
0x42: "0.00;\(0.00\)",
0x52: "0.00;[Red]\(0.00\)",
162: '"$"#,##0;\\("$"#,##0\\)' // slightly different from SSF 5
/* It is suspected that the the low nybble specifies decimal places */
0x0022: "0.00",
0x0032: "0.00;[Red]0.00",
0x0042: "0.00;\(0.00\)",
0x0052: "0.00;[Red]\(0.00\)",
0x00A2: '"$"#,##0.00;\\("$"#,##0.00\\)',
0x0120: '0%',
0x0130: '0E+00',
0x0140: '# ?/?'
};
function parse_qpw_str(p) {
var cch = p.read_shift(2);
var flags = p.read_shift(1);
/* TODO: find examples with nonzero flags */
if(flags != 0) throw "unsupported QPW string type " + flags.toString(16);
return p.read_shift(cch, "sbcs-cont");
}
/* QPW uses a different set of record types */
function qpw_to_workbook_buf(d, opts) {
prep_blob(d, 0);
@ -10084,7 +10135,11 @@ var WK_ = (function() {
case 4: cell = { t: "n", v: parse_RkNumber(p) }; break;
case 5: cell = { t: "n", v: p.read_shift(8, 'f') }; break;
case 7: cell = { t: "s", v: SST[type = p.read_shift(4) - 1] }; break;
case 8: cell = { t: "n", v: p.read_shift(8, 'f') }; p.l += 2; /* cell.f = formulae[p.read_shift(4)]; */ p.l += 4; break;
case 8:
cell = { t: "n", v: p.read_shift(8, 'f') };
p.l += 2; /* cell.f = formulae[p.read_shift(4)]; */ p.l += 4;
if(isNaN(cell.v)) cell = { t: "e", v: 0x0F }; // #VALUE!
break;
default: throw "Unrecognized QPW cell type " + (flags & 0x1F);
}
if(fmtidx != -1 && (FMTS[fmtidx - 1]||{}).z) cell.z = FMTS[fmtidx-1].z;
@ -10130,6 +10185,17 @@ var WK_ = (function() {
}
} break;
case 0x0C02: { /* String (result of string formula expression) */
C = p.read_shift(2);
R = p.read_shift(4);
var str = parse_qpw_str(p);
/* TODO: QP10 record has an additional unknown character after the string */
if(s["!data"] != null) {
if(!s["!data"][R]) s["!data"][R] = [];
s["!data"][R][C] = { t:"s", v:str };
} else s[encode_col(C) + encode_row(R)] = { t:"s", v:str };
} break;
default: break;
}
d.l += length;
@ -11281,7 +11347,7 @@ function parse_cellXfs(t, styles, opts) {
case '<cellXfs': case '<cellXfs>': case '<cellXfs/>': case '</cellXfs>': break;
/* 18.8.45 xf CT_Xf */
case '<xf': case '<xf/>':
case '<xf': case '<xf/>': case '<xf>':
xf = y;
delete xf[0];
for(i = 0; i < cellXF_uint.length; ++i) if(xf[cellXF_uint[i]])
@ -11295,7 +11361,7 @@ function parse_cellXfs(t, styles, opts) {
case '</xf>': break;
/* 18.8.1 alignment CT_CellAlignment */
case '<alignment': case '<alignment/>':
case '<alignment': case '<alignment/>': case '<alignment>':
var alignment = {};
if(y.vertical) alignment.vertical = y.vertical;
if(y.horizontal) alignment.horizontal = y.horizontal;
@ -11307,12 +11373,12 @@ function parse_cellXfs(t, styles, opts) {
case '</alignment>': break;
/* 18.8.33 protection CT_CellProtection */
case '<protection':
case '<protection': case '<protection>':
break;
case '</protection>': case '<protection/>': break;
/* note: sometimes mc:AlternateContent appears bare */
case '<AlternateContent': pass = true; break;
case '<AlternateContent': case '<AlternateContent>': pass = true; break;
case '</AlternateContent>': pass = false; break;
/* 18.2.10 extLst CT_ExtensionList ? */
@ -12951,7 +13017,10 @@ var rc_to_a1 = (function(){
};
})();
var crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)(10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})(?![_.\(A-Za-z0-9])/g;
var crefregex = /(^|[^._A-Z0-9])(\$?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])(\$?)(\d{1,7})(?![_.\(A-Za-z0-9])/g;
try {
crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)(10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})(?![_.\(A-Za-z0-9])/g;
}catch(e){}
var a1_to_rc = (function(){
return function a1_to_rc(fstr, base) {
return fstr.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
@ -15664,7 +15733,7 @@ function parse_ws_xml_dim(ws, s) {
var d = safe_decode_range(s);
if(d.s.r<=d.e.r && d.s.c<=d.e.c && d.s.r>=0 && d.s.c>=0) ws["!ref"] = encode_range(d);
}
var mergecregex = /<(?:\w:)?mergeCell ref="[A-Z0-9:]+"\s*[\/]?>/g;
var mergecregex = /<(?:\w:)?mergeCell ref=["'][A-Z0-9:]+['"]\s*[\/]?>/g;
var sheetdataregex = /<(?:\w+:)?sheetData[^>]*>([\s\S]*)<\/(?:\w+:)?sheetData>/;
var hlinkregex = /<(?:\w:)?hyperlink [^>]*>/mg;
var dimregex = /"(\w*:\w*)"/;
@ -22507,9 +22576,9 @@ function sheet_to_html(ws, opts/*, wb:?Workbook*/) {
var header = o.header != null ? o.header : HTML_BEGIN;
var footer = o.footer != null ? o.footer : HTML_END;
var out = [header];
var r = decode_range(ws['!ref']);
var r = decode_range(ws['!ref'] || "A1");
out.push(make_html_preamble(ws, r, o));
for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
if(ws["!ref"]) for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
out.push("</table>" + footer);
return out.join("");
}
@ -23268,10 +23337,13 @@ function parse_content_xml(d, _opts, _nfm) {
case 'help-message': break; // 9.4.6 <table:
case 'error-message': break; // 9.4.7 <table:
case 'database-ranges': break; // 9.4.14 <table:database-ranges>
/* 9.5 Filters */
case 'filter': break; // 9.5.2 <table:filter>
case 'filter-and': break; // 9.5.3 <table:filter-and>
case 'filter-or': break; // 9.5.4 <table:filter-or>
case 'filter-condition': break; // 9.5.5 <table:filter-condition>
case 'filter-set-item': break; // 9.5.6 <table:filter-condition>
case 'list-level-style-bullet': break; // 16.31 <text:
case 'list-level-style-number': break; // 16.32 <text:
@ -23788,6 +23860,7 @@ var write_content_ods = /* @__PURE__ */(function() {
wb.SheetNames.map(function(n) { return wb.Sheets[n]; }).forEach(function(ws) {
if(!ws) return;
var dense = (ws["!data"] != null);
if(!ws["!ref"]) return;
var range = decode_range(ws["!ref"]);
for(var R = 0; R <= range.e.r; ++R) for(var C = 0; C <= range.e.c; ++C) {
var c = dense ? (ws["!data"][R]||[])[C] : ws[encode_cell({r:R,c:C})];
@ -25039,7 +25112,7 @@ function s5s_to_iwa_comment(s5s) {
return out;
}
function parse_TST_TableModelArchive(M, root, ws, opts) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
var pb = parse_shallow(root.data);
var range = { s: { r: 0, c: 0 }, e: { r: 0, c: 0 } };
range.e.r = (varint_to_i32(pb[6][0].data) >>> 0) - 1;
@ -25068,7 +25141,17 @@ function parse_TST_TableModelArchive(M, root, ws, opts) {
lut.nfmt = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[22][0].data)][0]);
var tile = parse_shallow(store[3][0].data);
var _R = 0;
tile[1].forEach(function(t) {
if (!((_h = store[9]) == null ? void 0 : _h[0]))
throw "NUMBERS file missing row tree";
var rtt = parse_shallow(store[9][0].data)[1].map(function(p) {
return parse_shallow(p.data);
});
rtt.forEach(function(kv) {
_R = varint_to_i32(kv[1][0].data);
var tidx = varint_to_i32(kv[2][0].data);
var t = tile[1][tidx];
if (!t)
throw "NUMBERS missing tile " + tidx;
var tl = parse_shallow(t.data);
var ref2 = M[parse_TSP_Reference(tl[2][0].data)][0];
var mtype2 = varint_to_i32(ref2.meta[1][0].data);
@ -25091,12 +25174,12 @@ function parse_TST_TableModelArchive(M, root, ws, opts) {
});
_R += _tile.nrows;
});
if ((_h = store[13]) == null ? void 0 : _h[0]) {
if ((_i = store[13]) == null ? void 0 : _i[0]) {
var ref = M[parse_TSP_Reference(store[13][0].data)][0];
var mtype = varint_to_i32(ref.meta[1][0].data);
if (mtype != 6144)
throw new Error("Expected merge type 6144, found ".concat(mtype));
ws["!merges"] = (_i = parse_shallow(ref.data)) == null ? void 0 : _i[1].map(function(pi) {
ws["!merges"] = (_j = parse_shallow(ref.data)) == null ? void 0 : _j[1].map(function(pi) {
var merge = parse_shallow(pi.data);
var origin = u8_to_dataview(parse_shallow(merge[1][0].data)[1][0].data), size = u8_to_dataview(parse_shallow(merge[2][0].data)[1][0].data);
return {
@ -25758,6 +25841,8 @@ function write_numbers_ws(cfb, deps, ws, wsname, sheetidx, rootref) {
}
var USE_WIDE_ROWS = true;
function write_numbers_tma(cfb, deps, ws, tmaroot, tmafile, tmaref) {
if (!ws["!ref"])
throw new Error("Cannot export empty sheet to NUMBERS");
var range = decode_range(ws["!ref"]);
range.s.r = range.s.c = 0;
var trunc = false;
@ -27192,7 +27277,7 @@ function make_json_row(sheet, r, R, cols, header, hdr, o) {
v = numdate(v); // TODO: date1904 setting should also be stored in worksheet object
if(typeof v == "number") break;
/* falls through */
case 'd': if(!(o && o.UTC)) v = utc_to_local(v); break;
case 'd': if(!(o && (o.UTC||(o.raw === false)))) v = utc_to_local(new Date(v)); break;
default: throw new Error('unrecognized type ' + val.t);
}
if(hdr[C] != null) {
@ -27202,7 +27287,7 @@ function make_json_row(sheet, r, R, cols, header, hdr, o) {
else if(raw && v === null) row[hdr[C]] = null;
else continue;
} else {
row[hdr[C]] = raw && (val.t !== "n" || (val.t === "n" && o.rawNumbers !== false)) ? v : format_cell(val,v,o);
row[hdr[C]] = (val.t === 'n' && typeof o.rawNumbers === 'boolean' ? o.rawNumbers : raw) ? v : format_cell(val, v, o);
}
if(v != null) isempty = false;
}
@ -27460,9 +27545,11 @@ function wb_sheet_idx(wb, sh) {
} else throw new Error("Cannot find sheet |" + sh + "|");
}
/* simple blank workbook object */
function book_new() {
return { SheetNames: [], Sheets: {} };
/* simple blank or single-sheet workbook object */
function book_new(ws, wsname) {
var wb = { SheetNames: [], Sheets: {} };
if(ws) book_append_sheet(wb, ws, wsname || "Sheet1");
return wb;
}
/* add a worksheet to the end of a given workbook */
@ -27559,6 +27646,7 @@ var utils = {
decode_cell: decode_cell,
decode_range: decode_range,
format_cell: format_cell,
sheet_new: sheet_new,
sheet_add_aoa: sheet_add_aoa,
sheet_add_json: sheet_add_json,
sheet_add_dom: sheet_add_dom,

34
dist/xlsx.full.min.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/xlsx.full.min.map generated vendored

File diff suppressed because one or more lines are too long

18
dist/xlsx.mini.min.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/xlsx.mini.min.map generated vendored

File diff suppressed because one or more lines are too long

@ -1,6 +1,6 @@
{
"name": "xlsx",
"version": "0.20.0+csv",
"version": "0.20.1",
"author": "sheetjs",
"description": "SheetJS Spreadsheet data parser and writer",
"keywords": [
@ -167,6 +167,12 @@
]
},
"homepage": "https://sheetjs.com/",
"files": [
"CHANGELOG.md", "LICENSE", "README.md", "bower.json", "package.json", "xlsx.js", "xlsx.mjs", "xlsxworker.js",
"bin/xlsx.njs",
"dist/LICENSE", "dist/*.mjs", "dist/*.js", "dist/*.map", "dist/*.d.ts",
"types/index.d.ts", "types/tsconfig.json"
],
"bugs": {
"url": "https://git.sheetjs.com/SheetJS/sheetjs/issues"
},

1
packages/dta/.gitignore vendored Normal file

@ -0,0 +1 @@
misc/

@ -1,5 +1,15 @@
.PHONY: build
build: node browser
build: node browser types
.PHONY: clean
clean:
rm dist/dta.*
## Types
.PHONY: types
types: dta.ts
tsc -d --emitDeclarationOnly --declarationDir types $<
mv types/dta.d.ts types/index.d.ts
## NodeJS target

@ -6,4 +6,58 @@ compatible with the [SheetJS](https://sheetjs.com) library constellation.
DTA datasets can support millions of observations and over 32767 variables.
The codec will truncate data to 1048576 observations and 16384 variables.
<https://docs.sheetjs.com/docs/constellation/dta> includes a live demo.
<https://docs.sheetjs.com/docs/constellation/dta> includes a live demo.
## Installation
Using NodeJS package manager:
```bash
npm install --save https://cdn.sheetjs.com/dta-0.0.1/dta-0.0.1.tgz
```
The standalone script is also hosted on the SheetJS CDN:
```html
<script src="https://cdn.sheetjs.com/dta-0.0.1/package/dist/dta.min.js"></script>
```
## Usage
The `parse` method accepts a `Uint8Array` representing the file data. It returns
a ["Common Spreadsheet Format"](https://docs.sheetjs.com/docs/csf/) workbook
object.
The `set_utils` method accepts a `utils` object from SheetJS CE or a SheetJS
Pro build. `parse` will use methods from the `utils` object.
### NodeJS
```js
const XLSX = require("xlsx"), DTA = require("dta");
DTA.set_utils(XLSX.utils);
const wb = DTA.parse(fs.readFileSync("auto.dta"));
```
### Browser
`dist/dta.min.js` is a standalone build designed to be added with `<script>`.
```html
<script lang="javascript" src="https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"></script>
<script src="dist/dta.min.js"></script>
<div id="out"></div>
<script>
DTA.set_utils(XLSX.utils);
(async() => {
/* fetch file */
const data = await (await fetch("test.dta")).arrayBuffer();
/* parse */
const wb = DTA.parse(new Uint8Array(data));
/* wb is a SheetJS workbook object */
const html = XLSX.utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]);
out.innerHTML = html;
})();
</script>
```

@ -15,5 +15,5 @@ const fs = require("fs");
const buf = fs.readFileSync(process.argv[2]);
const wb = DTA.parse(buf);
// translate stub cells to single blanks
wb.Sheets[wb.SheetNames[0]]["!data"].forEach(row => row.forEach(cell => {if(cell.t == "z") {cell.t = "s"; cell.v = " ";}}));
//wb.Sheets[wb.SheetNames[0]]["!data"].forEach(row => row.forEach(cell => {if(cell.t == "z") {cell.t = "s"; cell.v = " ";}}));
console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));

@ -25,41 +25,95 @@ var __toCommonJS = /* @__PURE__ */ ((cache) => {
var dta_exports = {};
__export(dta_exports, {
parse: () => parse,
set_utils: () => set_utils
set_utils: () => set_utils,
version: () => version
});
var version = "0.0.1";
var _utils;
function set_utils(utils) {
_utils = utils;
}
function u8_to_str(u8) {
return new TextDecoder().decode(u8);
}
function u8_to_latin1(u8) {
return new TextDecoder("latin1").decode(u8);
}
function format_number_dta(value, format, t) {
if (value < 0) {
const res = format_number_dta(-value, format, t);
res.w = "-" + res.w;
return res;
}
const o = { t: "n", v: value };
switch (t) {
case 251:
case 98:
case 65530:
format = "%8.0g";
break;
case 252:
case 105:
case 65529:
format = "%8.0g";
break;
case 253:
case 108:
case 65528:
format = "%12.0g";
break;
case 254:
case 102:
case 65527:
format = "%9.0g";
break;
case 255:
case 100:
case 65526:
format = "%10.0g";
break;
default:
throw t;
}
try {
let w = +(format.match(/%(\d+)/) || [])[1] || 8;
let k = 0;
if (value < 1)
++k;
if (value < 0.1)
++k;
if (value < 0.01)
++k;
if (value < 1e-3)
++k;
const e = value.toExponential();
const exp = e.indexOf("e") == -1 ? 0 : +e.slice(e.indexOf("e") + 1);
let h = w - 2 - exp;
if (h < 0)
h = 0;
var m = format.match(/%\d+\.(\d+)/);
if (m && +m[1])
h = +m[1];
o.w = (Math.round(value * 10 ** h) / 10 ** h).toFixed(h).replace(/^([-]?)0\./, "$1.");
o.w = o.w.slice(0, w + k);
if (o.w.indexOf(".") > -1)
o.w = o.w.replace(/0+$/, "");
o.w = o.w.replace(/\.$/, "");
if (o.w == "")
o.w = "0";
} catch (e) {
}
return o;
}
function u8_to_dataview(array) {
return new DataView(array.buffer, array.byteOffset, array.byteLength);
}
function valid_inc(p, n) {
if (p.str.slice(p.ptr, p.ptr + n.length) != n)
if (u8_to_str(p.raw.slice(p.ptr, p.ptr + n.length)) != n)
return false;
p.ptr += n.length;
return true;
}
function skip_end(p, n) {
const idx = p.str.indexOf(n, p.ptr);
if (idx == -1)
throw new Error(`Expected ${n} after offset ${p.ptr}`);
p.ptr = idx + n.length;
}
function slice_end(p, n) {
const idx = p.str.indexOf(n, p.ptr);
if (idx == -1)
throw new Error(`Expected ${n} after offset ${p.ptr}`);
const raw = p.raw.slice(p.ptr, idx);
const res = {
ptr: 0,
raw,
str: p.str.slice(p.ptr, idx),
dv: u8_to_dataview(raw)
};
p.ptr = idx + n.length;
return res;
}
function read_f64(p, LE) {
p.ptr += 8;
const d = p.dv.getFloat64(p.ptr - 8, LE);
@ -98,15 +152,29 @@ function read_i8(p) {
}
var SUPPORTED_VERSIONS_TAGGED = [
"117",
"118"
"118",
"119",
"120",
"121"
];
var SUPPORTED_VERSIONS_LEGACY = [
102,
103,
104,
105,
108,
110,
111,
112,
113,
114,
115
];
function parse_tagged(raw) {
const err = "Not a DTA file";
const str = new TextDecoder("latin1").decode(raw);
const d = {
ptr: 0,
raw,
str,
dv: u8_to_dataview(raw)
};
let vers = 118;
@ -124,16 +192,22 @@ function parse_tagged(raw) {
{
if (!valid_inc(d, "<release>"))
throw err;
const res = slice_end(d, "</release>");
if (SUPPORTED_VERSIONS_TAGGED.indexOf(res.str) == -1)
throw `Unsupported DTA ${res.str} file`;
vers = +res.str;
const res = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + 3));
d.ptr += 3;
if (!valid_inc(d, "</release>"))
throw err;
if (SUPPORTED_VERSIONS_TAGGED.indexOf(res) == -1)
throw `Unsupported DTA ${res} file`;
vers = +res;
}
{
if (!valid_inc(d, "<byteorder>"))
throw err;
const res = slice_end(d, "</byteorder>");
switch (res.str) {
const res = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + 3));
d.ptr += 3;
if (!valid_inc(d, "</byteorder>"))
throw err;
switch (res) {
case "MSF":
LE = false;
break;
@ -141,48 +215,49 @@ function parse_tagged(raw) {
LE = true;
break;
default:
throw `Unsupported byteorder ${res.str}`;
throw `Unsupported byteorder ${res}`;
}
}
{
if (!valid_inc(d, "<K>"))
throw err;
const res = slice_end(d, "</K>");
nvar = read_u16(res, LE);
nvar = vers === 119 || vers >= 121 ? read_u32(d, LE) : read_u16(d, LE);
if (!valid_inc(d, "</K>"))
throw err;
}
{
if (!valid_inc(d, "<N>"))
throw err;
const res = slice_end(d, "</N>");
if (vers == 117)
nobs = nobs_lo = read_u32(res, LE);
nobs = nobs_lo = read_u32(d, LE);
else {
const lo = read_u32(res, LE), hi = read_u32(res, LE);
const lo = read_u32(d, LE), hi = read_u32(d, LE);
nobs = LE ? (nobs_lo = lo) + (nobs_hi = hi) * Math.pow(2, 32) : (nobs_lo = hi) + (nobs_hi = lo) * Math.pow(2, 32);
}
if (nobs > 1e6)
console.error(`More than 1 million observations -- extra rows will be dropped`);
if (!valid_inc(d, "</N>"))
throw err;
}
{
if (!valid_inc(d, "<label>"))
throw err;
const res = slice_end(d, "</label>");
const w = vers >= 118 ? 2 : 1;
const strlen = w == 1 ? read_u8(res) : read_u16(res, LE);
if (strlen + w != res.str.length)
throw `Expected string length ${strlen} but actual length was ${res.str.length - w}`;
const strlen = w == 1 ? read_u8(d) : read_u16(d, LE);
if (strlen > 0)
label = new TextDecoder().decode(res.raw.slice(w));
label = u8_to_str(d.raw.slice(d.ptr, d.ptr + w));
d.ptr += strlen;
if (!valid_inc(d, "</label>"))
throw err;
}
{
if (!valid_inc(d, "<timestamp>"))
throw err;
const res = slice_end(d, "</timestamp>");
const strlen = read_u8(res);
if (strlen + 1 != res.str.length)
throw `Expected string length ${strlen} but actual length was ${res.str.length - 1}`;
if (strlen > 0)
timestamp = res.str.slice(1);
const strlen = read_u8(d);
timestamp = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + strlen));
d.ptr += strlen;
if (!valid_inc(d, "</timestamp>"))
throw err;
}
if (!valid_inc(d, "</header>"))
throw err;
@ -190,17 +265,16 @@ function parse_tagged(raw) {
{
if (!valid_inc(d, "<map>"))
throw err;
skip_end(d, "</map>");
d.ptr += 8 * 14;
if (!valid_inc(d, "</map>"))
throw err;
}
let stride = 0;
{
if (!valid_inc(d, "<variable_types>"))
throw err;
const res = slice_end(d, "</variable_types>");
if (res.raw.length != 2 * nvar)
throw `Expected variable_types length ${nvar * 2}, found ${res.raw.length}`;
while (res.ptr < res.raw.length) {
const type = read_u16(res, LE);
for (var i = 0; i < nvar; ++i) {
const type = read_u16(d, LE);
var_types.push(type);
if (type >= 1 && type <= 2045)
stride += type;
@ -209,6 +283,9 @@ function parse_tagged(raw) {
case 32768:
stride += 8;
break;
case 65525:
stride += 0;
break;
case 65526:
stride += 8;
break;
@ -228,57 +305,62 @@ function parse_tagged(raw) {
throw `Unsupported field type ${type}`;
}
}
if (!valid_inc(d, "</variable_types>"))
throw err;
}
{
if (!valid_inc(d, "<varnames>"))
throw err;
const res = slice_end(d, "</varnames>");
const w = vers >= 118 ? 129 : 33;
if (res.raw.length != w * nvar)
throw `Expected variable_types length ${nvar * w}, found ${res.raw.length}`;
while (res.ptr < res.raw.length) {
const name = new TextDecoder().decode(res.raw.slice(res.ptr, res.ptr + w));
res.ptr += w;
for (let i2 = 0; i2 < nvar; ++i2) {
const name = u8_to_str(d.raw.slice(d.ptr, d.ptr + w));
d.ptr += w;
var_names.push(name.replace(/\x00[\s\S]*/, ""));
}
if (!valid_inc(d, "</varnames>"))
throw err;
}
{
if (!valid_inc(d, "<sortlist>"))
throw err;
const res = slice_end(d, "</sortlist>");
if (res.raw.length != 2 * nvar + 2)
throw `Expected sortlist length ${nvar * 2 + 2}, found ${res.raw.length}`;
d.ptr += (2 * nvar + 2) * (vers == 119 || vers == 121 ? 2 : 1);
if (!valid_inc(d, "</sortlist>"))
throw err;
}
{
if (!valid_inc(d, "<formats>"))
throw err;
const res = slice_end(d, "</formats>");
const w = vers >= 118 ? 57 : 49;
if (res.raw.length != w * nvar)
throw `Expected formats length ${nvar * w}, found ${res.raw.length}`;
while (res.ptr < res.raw.length) {
const name = new TextDecoder().decode(res.raw.slice(res.ptr, res.ptr + w));
res.ptr += w;
for (let i2 = 0; i2 < nvar; ++i2) {
const name = u8_to_str(d.raw.slice(d.ptr, d.ptr + w));
d.ptr += w;
formats.push(name.replace(/\x00[\s\S]*/, ""));
}
if (!valid_inc(d, "</formats>"))
throw err;
}
const value_label_names = [];
{
if (!valid_inc(d, "<value_label_names>"))
throw err;
const w = vers >= 118 ? 129 : 33;
const res = slice_end(d, "</value_label_names>");
for (let i2 = 0; i2 < nvar; ++i2, d.ptr += w)
value_label_names[i2] = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + w)).replace(/\x00.*$/, "");
if (!valid_inc(d, "</value_label_names>"))
throw err;
}
{
if (!valid_inc(d, "<variable_labels>"))
throw err;
const w = vers >= 118 ? 321 : 81;
const res = slice_end(d, "</variable_labels>");
d.ptr += w * nvar;
if (!valid_inc(d, "</variable_labels>"))
throw err;
}
{
if (!valid_inc(d, "<characteristics>"))
throw err;
while (d.str.slice(d.ptr, d.ptr + 4) == "<ch>") {
d.ptr += 4;
while (valid_inc(d, "<ch>")) {
const len = read_u32(d, LE);
d.ptr += len;
if (!valid_inc(d, "</ch>"))
@ -297,26 +379,29 @@ function parse_tagged(raw) {
for (let C = 0; C < nvar; ++C) {
let t = var_types[C];
if (t >= 1 && t <= 2045) {
let s = new TextDecoder().decode(d.raw.slice(d.ptr, d.ptr + t));
let s = u8_to_str(d.raw.slice(d.ptr, d.ptr + t));
s = s.replace(/\x00[\s\S]*/, "");
row[C] = s;
d.ptr += t;
} else
switch (t) {
case 65526:
row[C] = read_f64(d, LE);
case 65525:
d.ptr += 0;
break;
case 65527:
row[C] = read_f32(d, LE);
break;
case 65528:
row[C] = read_i32(d, LE);
case 65530:
row[C] = read_i8(d);
break;
case 65529:
row[C] = read_i16(d, LE);
break;
case 65530:
row[C] = read_i8(d);
case 65528:
row[C] = read_i32(d, LE);
break;
case 65527:
row[C] = read_f32(d, LE);
break;
case 65526:
row[C] = read_f64(d, LE);
break;
case 32768:
{
@ -328,6 +413,8 @@ function parse_tagged(raw) {
default:
throw `Unsupported field type ${t} for ${var_names[C]}`;
}
if (typeof row[C] == "number" && formats[C])
row[C] = format_number_dta(row[C], formats[C], t);
}
_utils.sheet_add_aoa(ws, [row], { origin: -1, sheetStubs: true });
}
@ -355,15 +442,15 @@ function parse_tagged(raw) {
const len = read_u32(d, LE);
if (!strl_tbl[o])
strl_tbl[o] = [];
let str2 = "";
let str = "";
if (t == 129) {
str2 = new TextDecoder("latin1").decode(d.raw.slice(d.ptr, d.ptr + len));
str = new TextDecoder(vers >= 118 ? "utf8" : "latin1").decode(d.raw.slice(d.ptr, d.ptr + len));
d.ptr += len;
} else {
str2 = new TextDecoder("latin1").decode(d.raw.slice(d.ptr, d.ptr + len)).replace(/\x00$/, "");
str = new TextDecoder(vers >= 118 ? "utf8" : "latin1").decode(d.raw.slice(d.ptr, d.ptr + len)).replace(/\x00$/, "");
d.ptr += len;
}
strl_tbl[o][v] = str2;
strl_tbl[o][v] = str;
}
if (!valid_inc(d, "</strls>"))
throw err;
@ -397,9 +484,41 @@ function parse_tagged(raw) {
});
}
{
const w = vers >= 118 ? 129 : 33;
if (!valid_inc(d, "<value_labels>"))
throw err;
const res = slice_end(d, "</value_labels>");
while (valid_inc(d, "<lbl>")) {
let len = read_u32(d, LE);
const labname = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + w)).replace(/\x00.*$/, "");
d.ptr += w;
d.ptr += 3;
const labels = [];
{
const n = read_u32(d, LE);
const txtlen = read_u32(d, LE);
const off = [], val = [];
for (let i2 = 0; i2 < n; ++i2)
off.push(read_u32(d, LE));
for (let i2 = 0; i2 < n; ++i2)
val.push(read_u32(d, LE));
const str = u8_to_str(d.raw.slice(d.ptr, d.ptr + txtlen));
d.ptr += txtlen;
for (let i2 = 0; i2 < n; ++i2)
labels[val[i2]] = str.slice(off[i2], str.indexOf("\0", off[i2]));
}
const C = value_label_names.indexOf(labname);
if (C == -1)
throw new Error(`unexpected value label |${labname}|`);
for (let R = 1; R < ws["!data"].length; ++R) {
const cell = ws["!data"][R][C];
cell.t = "s";
cell.v = cell.w = labels[cell.v || 0];
}
if (!valid_inc(d, "</lbl>"))
throw err;
}
if (!valid_inc(d, "</value_labels>"))
throw err;
}
if (!valid_inc(d, "</stata_dta>"))
throw err;
@ -409,27 +528,11 @@ function parse_tagged(raw) {
}
function parse_legacy(raw) {
let vers = raw[0];
switch (vers) {
case 102:
case 112:
throw `Unsupported DTA ${vers} file`;
case 103:
case 104:
case 105:
case 108:
case 110:
case 111:
case 113:
case 114:
case 115:
break;
default:
throw new Error("Not a DTA file");
}
if (SUPPORTED_VERSIONS_LEGACY.indexOf(vers) == -1)
throw new Error("Not a DTA file");
const d = {
ptr: 1,
raw,
str: "",
dv: u8_to_dataview(raw)
};
let LE = true;
@ -456,31 +559,34 @@ function parse_legacy(raw) {
d.ptr++;
nvar = read_u16(d, LE);
nobs = read_u32(d, LE);
d.ptr += vers >= 108 ? 81 : 32;
d.ptr += vers >= 108 ? 81 : vers >= 103 ? 32 : 30;
if (vers >= 105)
d.ptr += 18;
}
const value_label_names = [];
{
let C = 0;
for (C = 0; C < nvar; ++C)
var_types.push(read_u8(d));
const w = vers >= 110 ? 33 : 9;
for (C = 0; C < nvar; ++C) {
var_names.push(new TextDecoder().decode(d.raw.slice(d.ptr, d.ptr + w)).replace(/\x00[\s\S]*$/, ""));
var_names.push(u8_to_str(d.raw.slice(d.ptr, d.ptr + w)).replace(/\x00[\s\S]*$/, ""));
d.ptr += w;
}
d.ptr += 2 * (nvar + 1);
const fw = vers >= 114 ? 49 : vers >= 105 ? 12 : 7;
for (C = 0; C < nvar; ++C) {
formats.push(new TextDecoder().decode(d.raw.slice(d.ptr, d.ptr + fw)).replace(/\x00[\s\S]*$/, ""));
formats.push(u8_to_str(d.raw.slice(d.ptr, d.ptr + fw)).replace(/\x00[\s\S]*$/, ""));
d.ptr += fw;
}
d.ptr += (vers >= 110 ? 33 : 9) * nvar;
const lw = vers >= 110 ? 33 : 9;
for (let i = 0; i < nvar; ++i, d.ptr += lw)
value_label_names[i] = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + lw)).replace(/\x00.*$/, "");
}
d.ptr += (vers >= 106 ? 81 : 32) * nvar;
if (vers >= 105)
while (d.ptr < d.raw.length) {
const dt = read_u8(d), len = (vers >= 111 ? read_u32 : read_u16)(d, LE);
const dt = read_u8(d), len = (vers >= 110 ? read_u32 : read_u16)(d, LE);
if (dt == 0 && len == 0)
break;
d.ptr += len;
@ -490,11 +596,16 @@ function parse_legacy(raw) {
const row = [];
for (let C = 0; C < nvar; ++C) {
let t = var_types[C];
if (vers >= 111 && t >= 1 && t <= 244) {
let s = new TextDecoder().decode(d.raw.slice(d.ptr, d.ptr + t));
if ((vers == 111 || vers >= 113) && t >= 1 && t <= 244) {
let s = u8_to_str(d.raw.slice(d.ptr, d.ptr + t));
s = s.replace(/\x00[\s\S]*/, "");
row[C] = s;
d.ptr += t;
} else if ((vers == 112 || vers <= 110) && t >= 128) {
let s = u8_to_str(d.raw.slice(d.ptr, d.ptr + t - 127));
s = s.replace(/\x00[\s\S]*/, "");
row[C] = s;
d.ptr += t - 127;
} else
switch (t) {
case 251:
@ -520,9 +631,41 @@ function parse_legacy(raw) {
default:
throw `Unsupported field type ${t} for ${var_names[C]}`;
}
if (typeof row[C] == "number" && formats[C])
row[C] = format_number_dta(row[C], formats[C], t);
}
_utils.sheet_add_aoa(ws, [row], { origin: -1, sheetStubs: true });
}
if (vers >= 115)
while (d.ptr < d.raw.length) {
const w = 33;
let len = read_u32(d, LE);
const labname = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + w)).replace(/\x00.*$/, "");
d.ptr += w;
d.ptr += 3;
const labels = [];
{
const n = read_u32(d, LE);
const txtlen = read_u32(d, LE);
const off = [], val = [];
for (let i = 0; i < n; ++i)
off.push(read_u32(d, LE));
for (let i = 0; i < n; ++i)
val.push(read_u32(d, LE));
const str = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + txtlen));
d.ptr += txtlen;
for (let i = 0; i < n; ++i)
labels[val[i]] = str.slice(off[i], str.indexOf("\0", off[i]));
}
const C = value_label_names.indexOf(labname);
if (C == -1)
throw new Error(`unexpected value label |${labname}|`);
for (let R = 1; R < ws["!data"].length; ++R) {
const cell = ws["!data"][R][C];
cell.t = "s";
cell.v = cell.w = labels[cell.v || 0];
}
}
const wb = _utils.book_new();
_utils.book_append_sheet(wb, ws, "Sheet1");
return wb;
@ -538,5 +681,6 @@ module.exports = __toCommonJS(dta_exports);
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
parse,
set_utils
set_utils,
version
});

File diff suppressed because one or more lines are too long

7
packages/dta/dist/dta.min.js.map vendored Normal file

File diff suppressed because one or more lines are too long

@ -1,5 +1,7 @@
import { DenseWorkSheet, WorkBook, type utils } from 'xlsx';
export { parse, set_utils };
import { CellObject, DenseWorkSheet, WorkBook, type utils } from 'xlsx';
export { parse, set_utils, version };
const version = "0.0.1";
let _utils: typeof utils;
/** Set internal instance of `utils`
@ -18,6 +20,51 @@ function set_utils(utils: any): void {
_utils = utils;
}
function u8_to_str(u8: Uint8Array): string {
return new TextDecoder().decode(u8);
}
/* sadly the web zealots decided to abandon binary strings */
function u8_to_latin1(u8: Uint8Array): string {
return new TextDecoder("latin1").decode(u8);
}
/* TODO: generalize and map to SSF */
function format_number_dta(value: number, format: string, t: number): CellObject {
if(value < 0) { const res = format_number_dta(-value, format, t); res.w = "-" + res.w; return res; }
const o: CellObject = { t: "n", v: value };
/* NOTE: The Stata CSV exporter appears to ignore the column formats, instead using these defaults */
switch(t) {
case 251: case 0x62: case 65530: format = "%8.0g"; break; // byte
case 252: case 0x69: case 65529: format = "%8.0g"; break; // int
case 253: case 0x6c: case 65528: format = "%12.0g"; break; // long
case 254: case 0x66: case 65527: format = "%9.0g"; break; // float
case 255: case 0x64: case 65526: format = "%10.0g"; break; // double
default: throw t;
}
try {
let w = +((format.match(/%(\d+)/)||[])[1]) || 8;
let k = 0;
if(value < 1) ++k;
if(value < 0.1) ++k;
if(value < 0.01) ++k;
if(value < 0.001) ++k;
const e = value.toExponential();
const exp = e.indexOf("e") == -1 ? 0 : +e.slice(e.indexOf("e")+1);
let h = w - 2 - exp;
if(h < 0) h = 0;
var m = format.match(/%\d+\.(\d+)/);
if(m && +m[1]) h = +m[1];
o.w = (Math.round(value * 10**(h))/10**(h)).toFixed(h).replace(/^([-]?)0\./,"$1.");
o.w = o.w.slice(0, w + k);
if(o.w.indexOf(".") > -1) o.w = o.w.replace(/0+$/,"");
o.w = o.w.replace(/\.$/,"");
if(o.w == "") o.w = "0";
} catch(e) {}
return o;
}
interface Payload {
/** Offset */
ptr: number;
@ -25,39 +72,17 @@ interface Payload {
/** Raw data */
raw: Uint8Array;
/** Latin-1 encoded */
str: string;
/** DataView */
dv: DataView;
}
function u8_to_dataview(array: Uint8Array): DataView { return new DataView(array.buffer, array.byteOffset, array.byteLength); }
function valid_inc(p: Payload, n: string): boolean {
if(p.str.slice(p.ptr, p.ptr + n.length) != n) return false;
if(u8_to_str(p.raw.slice(p.ptr, p.ptr + n.length)) != n) return false;
p.ptr += n.length;
return true;
}
function skip_end(p: Payload, n: string): void {
const idx = p.str.indexOf(n, p.ptr);
if(idx == -1) throw new Error(`Expected ${n} after offset ${p.ptr}`);
p.ptr = idx + n.length;
}
function slice_end(p: Payload, n: string): Payload {
const idx = p.str.indexOf(n, p.ptr);
if(idx == -1) throw new Error(`Expected ${n} after offset ${p.ptr}`);
const raw = p.raw.slice(p.ptr, idx);
const res = {
ptr: 0,
raw,
str: p.str.slice(p.ptr, idx),
dv: u8_to_dataview(raw)
};
p.ptr = idx + n.length;
return res;
}
function read_f64(p: Payload, LE: boolean): number | null {
p.ptr += 8;
const d = p.dv.getFloat64(p.ptr - 8, LE);
@ -96,23 +121,34 @@ function read_i8(p: Payload): number | null {
return u > 100 ? null : u;
}
/* the annotations are from `dtaversion` */
const SUPPORTED_VERSIONS_TAGGED = [
"117", // stata 13
"118", // stata 14-18
// "119", // stata 15/16/17/18 (> 32767 variables)
// "120", // stata 18 (<= 32767, with aliases)
// "121", // stata 18 (> 32767, with aliases)
"119", // stata 15-18 (> 32767 variables)
"120", // stata 18 (<= 32767, with aliases)
"121", // stata 18 (> 32767, with aliases)
];
const SUPPORTED_VERSIONS_LEGACY = [
102, // stata 1
103, // stata 2/3
104, // stata 4
105, // stata 5
108, // stata 6
110, // stata 7
111, // stata 7
112, // stata 8/9
113, // stata 8/9
114, // stata 10/11
115, // stata 12
];
function parse_tagged(raw: Uint8Array): WorkBook {
const err = ("Not a DTA file");
/* sadly the web zealots decided to abandon binary strings */
const str = new TextDecoder('latin1').decode(raw);
const d: Payload = {
ptr: 0,
raw,
str,
dv: u8_to_dataview(raw)
}
@ -134,58 +170,64 @@ function parse_tagged(raw: Uint8Array): WorkBook {
/* <release> */
{
if(!valid_inc(d, "<release>")) throw err;
const res = slice_end(d, "</release>");
if(SUPPORTED_VERSIONS_TAGGED.indexOf(res.str) == -1) throw (`Unsupported DTA ${res.str} file`);
vers = +res.str;
/* NOTE: this assumes the version is 3 characters wide */
const res = u8_to_latin1(d.raw.slice(d.ptr, d.ptr+3));
d.ptr += 3;
if(!valid_inc(d, "</release>")) throw err;
if(SUPPORTED_VERSIONS_TAGGED.indexOf(res) == -1) throw (`Unsupported DTA ${res} file`);
vers = +res;
}
/* <byteorder> */
{
if(!valid_inc(d, "<byteorder>")) throw err;
const res = slice_end(d, "</byteorder>");
switch(res.str) {
/* NOTE: this assumes the byte order is 3 characters wide */
const res = u8_to_latin1(d.raw.slice(d.ptr, d.ptr+3));
d.ptr += 3;
if(!valid_inc(d, "</byteorder>")) throw err;
switch(res) {
case "MSF": LE = false; break;
case "LSF": LE = true; break;
default: throw (`Unsupported byteorder ${res.str}`);
default: throw (`Unsupported byteorder ${res}`);
}
}
/* <K> */
{
if(!valid_inc(d, "<K>")) throw err;
const res = slice_end(d, "</K>");
nvar = read_u16(res, LE);
nvar = (vers === 119 || vers >= 121) ? read_u32(d, LE) : read_u16(d, LE);
if(!valid_inc(d, "</K>")) throw err;
}
/* <N> */
{
if(!valid_inc(d, "<N>")) throw err;
const res = slice_end(d, "</N>");
if(vers == 117) nobs = nobs_lo = read_u32(res, LE);
if(vers == 117) nobs = nobs_lo = read_u32(d, LE);
else {
const lo = read_u32(res, LE), hi = read_u32(res, LE);
const lo = read_u32(d, LE), hi = read_u32(d, LE);
nobs = LE ? ((nobs_lo = lo) + (nobs_hi = hi) * Math.pow(2,32)) : ((nobs_lo = hi) + (nobs_hi = lo) * Math.pow(2,32));
}
if(nobs > 1e6) console.error(`More than 1 million observations -- extra rows will be dropped`);
if(!valid_inc(d, "</N>")) throw err;
}
/* <label> */
{
if(!valid_inc(d, "<label>")) throw err;
const res = slice_end(d, "</label>");
const w = vers >= 118 ? 2 : 1;
const strlen = w == 1 ? read_u8(res) : read_u16(res, LE);
if(strlen + w != res.str.length) throw (`Expected string length ${strlen} but actual length was ${res.str.length - w}`);
if(strlen > 0) label = new TextDecoder().decode(res.raw.slice(w));
const strlen = w == 1 ? read_u8(d) : read_u16(d, LE);
if(strlen > 0) label = u8_to_str(d.raw.slice(d.ptr, d.ptr + w));
d.ptr += strlen;
if(!valid_inc(d, "</label>")) throw err;
}
/* <timestamp> */
{
if(!valid_inc(d, "<timestamp>")) throw err;
const res = slice_end(d, "</timestamp>");
const strlen = read_u8(res);
if(strlen + 1 != res.str.length) throw (`Expected string length ${strlen} but actual length was ${res.str.length - 1}`);
if(strlen > 0) timestamp = res.str.slice(1);
const strlen = read_u8(d);
timestamp = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + strlen));
d.ptr += strlen;
if(!valid_inc(d, "</timestamp>")) throw err;
}
if(!valid_inc(d, "</header>")) throw err;
@ -211,21 +253,21 @@ function parse_tagged(raw: Uint8Array): WorkBook {
</stata_data>
EOF
*/
skip_end(d, "</map>");
d.ptr += 8 * 14;
if(!valid_inc(d, "</map>")) throw err;
}
let stride = 0;
/* 5.3 Variable types <variable_types> */
{
if(!valid_inc(d, "<variable_types>")) throw err;
const res = slice_end(d, "</variable_types>");
if(res.raw.length != 2 * nvar) throw (`Expected variable_types length ${nvar * 2}, found ${res.raw.length}`);
while(res.ptr < res.raw.length) {
const type = read_u16(res, LE);
for(var i = 0; i < nvar; ++i) {
const type = read_u16(d, LE);
var_types.push(type);
if(type >= 1 && type <= 2045) stride += type;
else switch(type) {
case 32768: stride += 8; break;
case 65525: stride += 0; break; // alias
case 65526: stride += 8; break;
case 65527: stride += 4; break;
case 65528: stride += 4; break;
@ -234,61 +276,62 @@ function parse_tagged(raw: Uint8Array): WorkBook {
default: throw (`Unsupported field type ${type}`);
}
}
if(!valid_inc(d, "</variable_types>")) throw err;
}
/* 5.4 Variable names <varnames> */
{
if(!valid_inc(d, "<varnames>")) throw err;
const res = slice_end(d, "</varnames>");
const w = vers >= 118 ? 129 : 33;
if(res.raw.length != w * nvar) throw (`Expected variable_types length ${nvar * w}, found ${res.raw.length}`);
while(res.ptr < res.raw.length) {
const name = new TextDecoder().decode(res.raw.slice(res.ptr, res.ptr + w));
res.ptr += w;
for(let i = 0; i < nvar; ++i) {
const name = u8_to_str(d.raw.slice(d.ptr, d.ptr + w));
d.ptr += w;
var_names.push(name.replace(/\x00[\s\S]*/,""));
}
if(!valid_inc(d, "</varnames>")) throw err;
}
/* 5.5 Sort order of observations <sortlist> */
{
/* TODO: check sort list? */
if(!valid_inc(d, "<sortlist>")) throw err;
const res = slice_end(d, "</sortlist>");
if(res.raw.length != 2 * nvar + 2) throw (`Expected sortlist length ${nvar * 2 + 2}, found ${res.raw.length}`);
d.ptr += (2 * nvar + 2) * ((vers == 119 || vers == 121) ? 2 : 1);
if(!valid_inc(d, "</sortlist>")) throw err;
}
/* 5.6 Display formats <formats> */
{
if(!valid_inc(d, "<formats>")) throw err;
const res = slice_end(d, "</formats>");
const w = vers >= 118 ? 57 : 49;
if(res.raw.length != w * nvar) throw (`Expected formats length ${nvar * w}, found ${res.raw.length}`);
while(res.ptr < res.raw.length) {
const name = new TextDecoder().decode(res.raw.slice(res.ptr, res.ptr + w));
res.ptr += w;
for(let i = 0; i < nvar; ++i) {
const name = u8_to_str(d.raw.slice(d.ptr, d.ptr + w));
d.ptr += w;
formats.push(name.replace(/\x00[\s\S]*/,""));
}
if(!valid_inc(d, "</formats>")) throw err;
}
const value_label_names: string[] = [];
/* TODO: <value_label_names> */
{
if(!valid_inc(d, "<value_label_names>")) throw err;
const w = vers >= 118 ? 129 : 33;
const res = slice_end(d, "</value_label_names>");
for(let i = 0; i < nvar; ++i, d.ptr += w) value_label_names[i] = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + w)).replace(/\x00.*$/,"");
if(!valid_inc(d, "</value_label_names>")) throw err;
}
/* TODO: <variable_labels> */
{
if(!valid_inc(d, "<variable_labels>")) throw err;
const w = vers >= 118 ? 321 : 81;
const res = slice_end(d, "</variable_labels>");
d.ptr += w * nvar;
if(!valid_inc(d, "</variable_labels>")) throw err;
}
/* 5.9 Characteristics <characteristics> */
{
if(!valid_inc(d, "<characteristics>")) throw err;
while(d.str.slice(d.ptr, d.ptr + 4) == "<ch>") {
d.ptr += 4;
while(valid_inc(d, "<ch>")) {
const len = read_u32(d, LE);
d.ptr += len;
if(!valid_inc(d, "</ch>")) throw err;
@ -296,7 +339,7 @@ function parse_tagged(raw: Uint8Array): WorkBook {
if(!valid_inc(d, "</characteristics>")) throw err;
}
const ws: DenseWorkSheet = (_utils.aoa_to_sheet([var_names], {dense: true}) as DenseWorkSheet);
const ws: DenseWorkSheet = (_utils.aoa_to_sheet([var_names], {dense: true} as any) as DenseWorkSheet);
var ptrs: Array<[number, number, Uint8Array]> = []
/* 5.10 Data <data> */
@ -309,16 +352,17 @@ function parse_tagged(raw: Uint8Array): WorkBook {
// TODO: formats, dta_12{0,1} aliases?
if(t >= 1 && t <= 2045) {
/* NOTE: dta_117 restricts strf to ASCII */
let s = new TextDecoder().decode(d.raw.slice(d.ptr, d.ptr + t));
let s = u8_to_str(d.raw.slice(d.ptr, d.ptr + t));
s = s.replace(/\x00[\s\S]*/,"");
row[C] = s;
d.ptr += t;
} else switch(t) {
case 65526: row[C] = read_f64(d, LE); break;
case 65527: row[C] = read_f32(d, LE); break;
case 65528: row[C] = read_i32(d, LE); break;
case 65529: row[C] = read_i16(d, LE); break;
case 65530: row[C] = read_i8(d); break;
case 65525: d.ptr += 0; break; // alias
case 65530: row[C] = read_i8(d); break; // byte
case 65529: row[C] = read_i16(d, LE); break; // int
case 65528: row[C] = read_i32(d, LE); break; // long
case 65527: row[C] = read_f32(d, LE); break; // float
case 65526: row[C] = read_f64(d, LE); break; // double
case 32768: {
row[C] = "##SheetJStrL##";
ptrs.push([R+1,C, d.raw.slice(d.ptr, d.ptr + 8)]);
@ -326,6 +370,7 @@ function parse_tagged(raw: Uint8Array): WorkBook {
} break;
default: throw (`Unsupported field type ${t} for ${var_names[C]}`);
}
if(typeof row[C] == "number" && formats[C]) row[C] = format_number_dta(row[C], formats[C], t);
}
_utils.sheet_add_aoa(ws, [row], {origin: -1, sheetStubs: true});
}
@ -352,11 +397,11 @@ function parse_tagged(raw: Uint8Array): WorkBook {
if(!strl_tbl[o]) strl_tbl[o] = [];
let str = "";
if(t == 129) {
// TODO: codepage
str = new TextDecoder("latin1").decode(d.raw.slice(d.ptr, d.ptr + len));
// TODO: dta_117 codepage
str = new TextDecoder(vers >= 118 ? "utf8" : "latin1").decode(d.raw.slice(d.ptr, d.ptr + len));
d.ptr += len;
} else {
str = new TextDecoder("latin1").decode(d.raw.slice(d.ptr, d.ptr + len)).replace(/\x00$/,"");
str = new TextDecoder(vers >= 118 ? "utf8" : "latin1").decode(d.raw.slice(d.ptr, d.ptr + len)).replace(/\x00$/,"");
d.ptr += len;
}
strl_tbl[o][v] = str;
@ -391,12 +436,37 @@ function parse_tagged(raw: Uint8Array): WorkBook {
/* 5.12 Value labels <value_labels> */
{
const w = vers >= 118 ? 129 : 33;
if(!valid_inc(d, "<value_labels>")) throw err;
const res = slice_end(d, "</value_labels>");
while(valid_inc(d, "<lbl>")) {
let len = read_u32(d, LE);
const labname = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + w)).replace(/\x00.*$/,"");
d.ptr += w;
d.ptr += 3; // padding
const labels: string[] = [];
{
const n = read_u32(d, LE);
const txtlen = read_u32(d, LE);
const off: number[] = [], val: number[] = [];
for(let i = 0; i < n; ++i) off.push(read_u32(d, LE));
for(let i = 0; i < n; ++i) val.push(read_u32(d, LE));
const str = u8_to_str(d.raw.slice(d.ptr, d.ptr + txtlen));
d.ptr += txtlen;
for(let i = 0; i < n; ++i) labels[val[i]] = str.slice(off[i], str.indexOf("\x00", off[i]));
}
const C = value_label_names.indexOf(labname);
if(C == -1) throw new Error(`unexpected value label |${labname}|`);
for(let R = 1; R < ws["!data"].length; ++R) {
const cell = ws["!data"][R][C];
cell.t = "s"; cell.v = cell.w = labels[(cell.v as number)||0];
}
//d.ptr += len; // value_label_table
if(!valid_inc(d, "</lbl>")) throw err;
}
if(!valid_inc(d, "</value_labels>")) throw err;
}
if(!valid_inc(d, "</stata_dta>")) throw err;
const wb = _utils.book_new();
_utils.book_append_sheet(wb, ws, "Sheet1");
return wb;
@ -404,29 +474,11 @@ function parse_tagged(raw: Uint8Array): WorkBook {
function parse_legacy(raw: Uint8Array): WorkBook {
let vers: number = raw[0];
switch(vers) {
case 102: // stata 1
case 112: // stata 8/9
throw (`Unsupported DTA ${vers} file`);
case 103: // stata 2/3
case 104: // stata 4
case 105: // stata 5
case 108: // stata 6
case 110: // stata 7
case 111: // stata 7
case 113: // stata 8/9
case 114: // stata 10/11
case 115: // stata 12
break;
default: throw new Error("Not a DTA file");
}
if(SUPPORTED_VERSIONS_LEGACY.indexOf(vers) == -1) throw new Error("Not a DTA file");
const d: Payload = {
ptr: 1,
raw,
str:"",
dv: u8_to_dataview(raw)
}
@ -453,11 +505,12 @@ function parse_legacy(raw: Uint8Array): WorkBook {
d.ptr++; // "unused"
nvar = read_u16(d, LE);
nobs = read_u32(d, LE);
d.ptr += (vers >= 108 ? 81 : 32); // TODO: data_label
d.ptr += (vers >= 108 ? 81 : vers >= 103 ? 32 : 30); // TODO: data_label
if(vers >= 105) d.ptr += 18; // TODO: time_stamp
}
/* 5.2 Descriptors */
const value_label_names: string[] = [];
{
let C = 0;
@ -467,7 +520,7 @@ function parse_legacy(raw: Uint8Array): WorkBook {
// varlist
const w = vers >= 110 ? 33 : 9;
for(C = 0; C < nvar; ++C) {
var_names.push(new TextDecoder().decode(d.raw.slice(d.ptr, d.ptr + w)).replace(/\x00[\s\S]*$/,""));
var_names.push(u8_to_str(d.raw.slice(d.ptr, d.ptr + w)).replace(/\x00[\s\S]*$/,""));
d.ptr += w;
}
@ -477,12 +530,12 @@ function parse_legacy(raw: Uint8Array): WorkBook {
// fmtlist
const fw = (vers >= 114 ? 49 : vers >= 105 ? 12 : 7);
for(C = 0; C < nvar; ++C) {
formats.push(new TextDecoder().decode(d.raw.slice(d.ptr, d.ptr + fw)).replace(/\x00[\s\S]*$/,""));
formats.push(u8_to_str(d.raw.slice(d.ptr, d.ptr + fw)).replace(/\x00[\s\S]*$/,""));
d.ptr += fw;
}
// lbllist
d.ptr += (vers >= 110 ? 33 : 9) * nvar;
const lw = vers >= 110 ? 33 : 9;
for(let i = 0; i < nvar; ++i, d.ptr += lw) value_label_names[i] = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + lw)).replace(/\x00.*$/,"");
}
/* 5.3 Variable labels */
@ -491,12 +544,12 @@ function parse_legacy(raw: Uint8Array): WorkBook {
/* 5.4 Expansion fields */
if(vers >= 105) while(d.ptr < d.raw.length) {
const dt = read_u8(d), len = (vers >= 111 ? read_u32 : read_u16)(d, LE);
const dt = read_u8(d), len = (vers >= 110 ? read_u32 : read_u16)(d, LE);
if(dt == 0 && len == 0) break;
d.ptr += len;
}
const ws: DenseWorkSheet = (_utils.aoa_to_sheet([var_names], {dense: true}) as DenseWorkSheet);
const ws: DenseWorkSheet = (_utils.aoa_to_sheet([var_names], {dense: true} as any) as DenseWorkSheet);
/* 5.5 Data */
for(let R = 0; R < nobs; ++R) {
@ -504,12 +557,18 @@ function parse_legacy(raw: Uint8Array): WorkBook {
for(let C = 0; C < nvar; ++C) {
let t = var_types[C];
// TODO: data type processing
if(vers >= 111 && t >= 1 && t <= 244) {
if((vers == 111 || vers >= 113) && t >= 1 && t <= 244) {
/* NOTE: dta_117 restricts strf to ASCII */
let s = new TextDecoder().decode(d.raw.slice(d.ptr, d.ptr + t));
let s = u8_to_str(d.raw.slice(d.ptr, d.ptr + t));
s = s.replace(/\x00[\s\S]*/,"");
row[C] = s;
d.ptr += t;
} else if((vers == 112 || vers <= 110) && t >= 0x80) {
/* NOTE: dta_105 restricts strf to ASCII */
let s = u8_to_str(d.raw.slice(d.ptr, d.ptr + t - 0x7F));
s = s.replace(/\x00[\s\S]*/,"");
row[C] = s;
d.ptr += t - 0x7F;
} else switch(t) {
case 251: case 0x62: row[C] = read_i8(d); break; // byte
case 252: case 0x69: row[C] = read_i16(d, LE); break; // int
@ -518,12 +577,38 @@ function parse_legacy(raw: Uint8Array): WorkBook {
case 255: case 0x64: row[C] = read_f64(d, LE); break; // double
default: throw (`Unsupported field type ${t} for ${var_names[C]}`);
}
if(typeof row[C] == "number" && formats[C]) row[C] = format_number_dta(row[C], formats[C], t);
}
_utils.sheet_add_aoa(ws, [row], {origin: -1, sheetStubs: true});
}
/* 5.6 Value labels */
// EOF or labels
// TODO: < 115
if(vers >= 115) while(d.ptr < d.raw.length) {
const w = 33;
let len = read_u32(d, LE);
const labname = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + w)).replace(/\x00.*$/,"");
d.ptr += w;
d.ptr += 3; // padding
const labels: string[] = [];
{
const n = read_u32(d, LE);
const txtlen = read_u32(d, LE);
const off: number[] = [], val: number[] = [];
for(let i = 0; i < n; ++i) off.push(read_u32(d, LE));
for(let i = 0; i < n; ++i) val.push(read_u32(d, LE));
const str = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + txtlen));
d.ptr += txtlen;
for(let i = 0; i < n; ++i) labels[val[i]] = str.slice(off[i], str.indexOf("\x00", off[i]));
}
const C = value_label_names.indexOf(labname);
if(C == -1) throw new Error(`unexpected value label |${labname}|`);
for(let R = 1; R < ws["!data"].length; ++R) {
const cell = ws["!data"][R][C];
cell.t = "s"; cell.v = cell.w = labels[(cell.v as number)||0];
}
}
const wb: WorkBook = _utils.book_new();
_utils.book_append_sheet(wb, ws, "Sheet1");

@ -9,7 +9,9 @@
"main": "dist/dta.js",
"types": "types",
"files": [
"dist/"
"bin/",
"dist/",
"types/"
],
"repository": {
"type": "git",

@ -16,7 +16,7 @@ for(let tF of test_folders) describe(tF, () => {
const wb = DTA.parse(buf);
assert(wb.SheetNames.length > 0);
/* stata will represent unspecified values as single spaces */
wb.Sheets[wb.SheetNames[0]]["!data"].forEach(row => row.forEach(cell => {if(cell.t == "z") {cell.t = "s"; cell.v = " ";}}));
//wb.Sheets[wb.SheetNames[0]]["!data"].forEach(row => row.forEach(cell => {if(cell.t == "z") {cell.t = "s"; cell.v = " ";}}));
const csvstr = XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]);
const baseline = fs.readFileSync(`${tF}/${tf}`, "utf8").replace(/[\r\n]+/g,"\n");
assert.equal(csvstr.trim(), baseline.trim());

@ -1,5 +1,6 @@
import type { WorkBook } from "xlsx";
import { WorkBook } from 'xlsx';
export { parse, set_utils, version };
declare const version = "0.0.1";
/** Set internal instance of `utils`
*
* Usage:
@ -12,12 +13,11 @@ import type { WorkBook } from "xlsx";
*
* @param utils utils object
*/
export function set_utils(utils: any): void;
declare function set_utils(utils: any): void;
/** Parse DTA file
*
* NOTE: In NodeJS, `Buffer` extends `Uint8Array`
*
* @param {Uint8Array} data File data
*/
export function parse(data: Uint8Array): WorkBook
declare function parse(data: Uint8Array): WorkBook;

@ -0,0 +1,20 @@
function normalize_xl_unsafe(v/*:number*/)/*:number*/ {
if(v == 0) return 0;
var s = v.toPrecision(17);
if(s.indexOf("e") > -1) {
var m = s.slice(0, s.indexOf("e"));
if(m.indexOf(".") > -1) {
var tail = m.charAt(0) + m.slice(2, 17);
m = m.slice(0, 16);
if(tail.length == 16) {
m = String(Math.round(Number(tail.slice(0,15) + "." + tail.slice(15))));
if(m.length == 16) m = m.slice(0,2) + "." + m.slice(2);
else m = m.charAt(0) + "." + m.slice(1);
}
}
else m = m.slice(0,15) + fill("0", m.length - 15);
return Number(m + s.slice(s.indexOf("e")));
}
var n = s.indexOf(".") > -1 ? s.slice(0, (s.slice(0,2) == "0." ? 17 : 16)) : (s.slice(0,15) + fill("0", s.length - 15));
return Number(n);
}

@ -1,17 +1,5 @@
function normalize_xl_unsafe(v/*:number*/)/*:number*/ {
var s = v.toPrecision(16);
if(s.indexOf("e") > -1) {
var m = s.slice(0, s.indexOf("e"));
m = m.indexOf(".") > -1 ? m.slice(0, (m.slice(0,2) == "0." ? 17 : 16)) : (m.slice(0,15) + fill("0", m.length - 15));
return m + s.slice(s.indexOf("e"));
}
var n = s.indexOf(".") > -1 ? s.slice(0, (s.slice(0,2) == "0." ? 17 : 16)) : (s.slice(0,15) + fill("0", s.length - 15));
return Number(n);
}
function parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) {
if(v > 2958465 || v < 0) return null;
v = normalize_xl_unsafe(v);
var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
var dout=[];
var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};

@ -1,4 +1,5 @@
function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
if(typeof v == "number") v = normalize_xl_unsafe(v);
var out = [], o = "", i = 0, c = "", lst='t', dt, j, cc;
var hr='H';
/* Tokenize */

@ -19,7 +19,8 @@
"blanket": "~1.2.3",
"dtslint": "^0.1.2",
"mocha": "~2.5.3",
"typescript": "2.2.0"
"typescript": "2.2.0",
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.0/xlsx-0.20.0.tgz"
},
"repository": {
"type": "git",

@ -141,6 +141,26 @@ var default_str = {
44: '_("$"* #,##0.00_);_("$"* \\(#,##0.00\\);_("$"* "-"??_);_(@_)'
};
function normalize_xl_unsafe(v/*:number*/)/*:number*/ {
if(v == 0) return 0;
var s = v.toPrecision(17);
if(s.indexOf("e") > -1) {
var m = s.slice(0, s.indexOf("e"));
if(m.indexOf(".") > -1) {
var tail = m.charAt(0) + m.slice(2, 17);
m = m.slice(0, 16);
if(tail.length == 16) {
m = String(Math.round(Number(tail.slice(0,15) + "." + tail.slice(15))));
if(m.length == 16) m = m.slice(0,2) + "." + m.slice(2);
else m = m.charAt(0) + "." + m.slice(1);
}
}
else m = m.slice(0,15) + fill("0", m.length - 15);
return Number(m + s.slice(s.indexOf("e")));
}
var n = s.indexOf(".") > -1 ? s.slice(0, (s.slice(0,2) == "0." ? 17 : 16)) : (s.slice(0,15) + fill("0", s.length - 15));
return Number(n);
}
function frac(x/*:number*/, D/*:number*/, mixed/*:?boolean*/)/*:Array<number>*/ {
var sgn = x < 0 ? -1 : 1;
var B = x * sgn;
@ -161,20 +181,8 @@ function frac(x/*:number*/, D/*:number*/, mixed/*:?boolean*/)/*:Array<number>*/
var q = Math.floor(sgn * P/Q);
return [q, sgn*P - q*Q, Q];
}
function normalize_xl_unsafe(v/*:number*/)/*:number*/ {
var s = v.toPrecision(16);
if(s.indexOf("e") > -1) {
var m = s.slice(0, s.indexOf("e"));
m = m.indexOf(".") > -1 ? m.slice(0, (m.slice(0,2) == "0." ? 17 : 16)) : (m.slice(0,15) + fill("0", m.length - 15));
return m + s.slice(s.indexOf("e"));
}
var n = s.indexOf(".") > -1 ? s.slice(0, (s.slice(0,2) == "0." ? 17 : 16)) : (s.slice(0,15) + fill("0", s.length - 15));
return Number(n);
}
function parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) {
if(v > 2958465 || v < 0) return null;
v = normalize_xl_unsafe(v);
var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
var dout=[];
var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
@ -703,6 +711,7 @@ function fmt_is_date(fmt/*:string*/)/*:boolean*/ {
}
SSF.is_date = fmt_is_date;
function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
if(typeof v == "number") v = normalize_xl_unsafe(v);
var out = [], o = "", i = 0, c = "", lst='t', dt, j, cc;
var hr='H';
/* Tokenize */

@ -137,6 +137,26 @@ var default_str = {
44: '_("$"* #,##0.00_);_("$"* \\(#,##0.00\\);_("$"* "-"??_);_(@_)'
};
function normalize_xl_unsafe(v) {
if(v == 0) return 0;
var s = v.toPrecision(17);
if(s.indexOf("e") > -1) {
var m = s.slice(0, s.indexOf("e"));
if(m.indexOf(".") > -1) {
var tail = m.charAt(0) + m.slice(2, 17);
m = m.slice(0, 16);
if(tail.length == 16) {
m = String(Math.round(Number(tail.slice(0,15) + "." + tail.slice(15))));
if(m.length == 16) m = m.slice(0,2) + "." + m.slice(2);
else m = m.charAt(0) + "." + m.slice(1);
}
}
else m = m.slice(0,15) + fill("0", m.length - 15);
return Number(m + s.slice(s.indexOf("e")));
}
var n = s.indexOf(".") > -1 ? s.slice(0, (s.slice(0,2) == "0." ? 17 : 16)) : (s.slice(0,15) + fill("0", s.length - 15));
return Number(n);
}
function frac(x, D, mixed) {
var sgn = x < 0 ? -1 : 1;
var B = x * sgn;
@ -157,20 +177,8 @@ function frac(x, D, mixed) {
var q = Math.floor(sgn * P/Q);
return [q, sgn*P - q*Q, Q];
}
function normalize_xl_unsafe(v) {
var s = v.toPrecision(16);
if(s.indexOf("e") > -1) {
var m = s.slice(0, s.indexOf("e"));
m = m.indexOf(".") > -1 ? m.slice(0, (m.slice(0,2) == "0." ? 17 : 16)) : (m.slice(0,15) + fill("0", m.length - 15));
return m + s.slice(s.indexOf("e"));
}
var n = s.indexOf(".") > -1 ? s.slice(0, (s.slice(0,2) == "0." ? 17 : 16)) : (s.slice(0,15) + fill("0", s.length - 15));
return Number(n);
}
function parse_date_code(v,opts,b2) {
if(v > 2958465 || v < 0) return null;
v = normalize_xl_unsafe(v);
var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
var dout=[];
var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
@ -696,6 +704,7 @@ function fmt_is_date(fmt) {
}
SSF.is_date = fmt_is_date;
function eval_fmt(fmt, v, opts, flen) {
if(typeof v == "number") v = normalize_xl_unsafe(v);
var out = [], o = "", i = 0, c = "", lst='t', dt, j, cc;
var hr='H';
/* Tokenize */

@ -0,0 +1,38 @@
/* vim: set ts=2: */
/*jshint loopfunc:true, mocha:true, node:true */
/*eslint-env node, mocha */
var XLSX = require("xlsx"), SSF = require("../");
describe('rounding', function() {
it('number', function() {
var wb = XLSX.readFile("./test/rounding.xlsx", {cellNF: true, dense: true});
var data = wb.Sheets.number["!data"];
data.slice(1).forEach(function(r,R) {
var val = data[R+1][0].v;
var raw = parseFloat(data[R+1][1].v);
r.slice(2).forEach(function(cell, C) {
var fmt = data[0][C+2].v;
var w = SSF.format(fmt, val);
if(w != cell.v) throw ([R, C, val, fmt, cell.v, w].join("|"));
var W = SSF.format(fmt, raw);
if(W != cell.v) throw ([R, C, val, fmt, cell.v, W, "!!"].join("|"));
});
});
});
it('date', function() {
var wb = XLSX.readFile("./test/rounding.xlsx", {cellNF: true, dense: true});
var data = wb.Sheets.date["!data"];
data.slice(1).forEach(function(r,R) {
var val = data[R+1][0].v;
r.slice(1).forEach(function(cell, C) {
var fmt = data[0][C+1].v;
if(fmt == 'yyyy-mm-dd [hh]:mm:ss') return; // Format broken in excel 2007 - present
var w = SSF.format(fmt, val);
if(w != cell.v) throw([R, C, val, fmt, cell.v, w].join("|"));
});
});
});
});

Binary file not shown.

@ -5,6 +5,6 @@ var fs = require('fs'), assert = require('assert');
var is_date = JSON.parse(fs.readFileSync('./test/is_date.json','utf8'));
describe('utilities', function() {
it('correctly determines if formats are dates', function() {
is_date.forEach(function(d) { assert.equal(SSF.is_date(d[0]), d[1], d[0]); });
is_date.forEach(function(d) { assert.equal(SSF.is_date(d[0]), d[1], d[0]); });
});
});

@ -2128,6 +2128,15 @@ describe('json output', function() {
}
});
});
it('should force UTC in formatted strings', function() {
var ws = { "!ref": "A1", "A1": { t: 'd', v: new Date(Date.UTC(2002, 11, 24, 0, 0, 0, 0)) } };
assert.equal(X.utils.sheet_to_json(ws, {header: 1, UTC: true, raw: false, dateNF: 'd"/"m"/"yyyy'})[0][0], "24/12/2002");
delete ws.A1.w;
assert.equal(X.utils.sheet_to_json(ws, {header: 1, UTC: false, raw: false, dateNF: 'd"/"m"/"yyyy'})[0][0], "24/12/2002");
assert.equal(X.utils.sheet_to_json(ws, {header: 1, UTC: true, raw: true, dateNF: 'd"/"m"/"yyyy'})[0][0].valueOf(), 1040688000000);
assert.equal(X.utils.sheet_to_json(ws, {header: 1, UTC: false, raw: true, dateNF: 'd"/"m"/"yyyy'})[0][0].valueOf(), 1040688000000 + new Date("2002-12-24T00:00:00.000Z").getTimezoneOffset()*60000);
});
});

30
test.mjs generated

@ -1406,13 +1406,16 @@ describe('parse features', function() {
].forEach(function(m) { it(m[0], function() {
var wb = X.read(fs.readFileSync(m[1]), {type: TYPE, cellDates: true});
var ws = wb.Sheets[wb.SheetNames[0]];
var data = X.utils.sheet_to_json(ws, { header: 1, raw: true, rawNumbers: false });
assert.ok(data[0][1] instanceof Date);
assert.ok(data[1][1] instanceof Date);
assert.equal(data[2][1], '$123.00');
assert.equal(data[3][1], '98.76%');
assert.equal(data[4][1], '456.00');
assert.equal(data[5][1], '7,890');
var data1 = X.utils.sheet_to_json(ws, { header: 1, raw: true, rawNumbers: false });
var data2 = X.utils.sheet_to_json(ws, { header: 1, raw: false, rawNumbers: true });
assert.ok(data1[0][1] instanceof Date);
assert.ok(data1[1][1] instanceof Date);
assert.equal(data1[2][1], '$123.00');
assert.equal(data1[3][1], '98.76%');
assert.equal(data1[4][1], '456.00');
assert.equal(data1[5][1], '7,890');
assert.equal(data2[0][1], '7/23/2020');
assert.equal(data2[5][1], 7890);
}); }); });
it('date system', function() {[
@ -1558,7 +1561,7 @@ describe('write features', function() {
["String", "123"],
["Number", 123],
["Boolean", true],
["Date", new Date()],
["Date", new Date()]
], { cellDates: true });
ws["B2"].t = ws["B3"].t = ws["B4"].t = "s"
var wb = X.utils.book_new();
@ -2129,6 +2132,15 @@ describe('json output', function() {
}
});
});
it('should force UTC in formatted strings', function() {
var ws = { "!ref": "A1", "A1": { t: 'd', v: new Date(Date.UTC(2002, 11, 24, 0, 0, 0, 0)) } };
assert.equal(X.utils.sheet_to_json(ws, {header: 1, UTC: true, raw: false, dateNF: 'd"/"m"/"yyyy'})[0][0], "24/12/2002");
delete ws.A1.w;
assert.equal(X.utils.sheet_to_json(ws, {header: 1, UTC: false, raw: false, dateNF: 'd"/"m"/"yyyy'})[0][0], "24/12/2002");
assert.equal(X.utils.sheet_to_json(ws, {header: 1, UTC: true, raw: true, dateNF: 'd"/"m"/"yyyy'})[0][0].valueOf(), 1040688000000);
assert.equal(X.utils.sheet_to_json(ws, {header: 1, UTC: false, raw: true, dateNF: 'd"/"m"/"yyyy'})[0][0].valueOf(), 1040688000000 + new Date("2002-12-24T00:00:00.000Z").getTimezoneOffset()*60000);
});
});
@ -2478,7 +2490,7 @@ describe('dbf', function() {
var wstrue = wbstrue[1][1].Sheets["Sheet1"];
[
["E2", "v", Date.UTC(1917,1,19,0,0,0,0)], ["E2", "w", "19170219"],
["F2", "v", Date.UTC(1917,1,19,0,0,0,0)], ["F2", "w", "19170219"],
["F2", "v", Date.UTC(1917,1,19,0,0,0,0)], ["F2", "w", "19170219"]
].forEach(function(r) {
assert.equal(get_cell(wstrue, r[0])[r[1]].valueOf(), r[2].valueOf());
});

@ -1367,17 +1367,20 @@ describe('parse features', function() {
});
describe('data types formats', function() {var dtf = [
['xlsx', paths.dtfxlsx],
['xlsx', paths.dtfxlsx]
]; for(var j = 0; j < dtf.length; ++j) { var m = dtf[j]; it(m[0], function() {
var wb = X.read(fs.readFileSync(m[1]), {type: TYPE, cellDates: true});
var ws = wb.Sheets[wb.SheetNames[0]];
var data = X.utils.sheet_to_json<any>(ws, { header: 1, raw: true, rawNumbers: false });
assert.ok(data[0][1] instanceof Date);
assert.ok(data[1][1] instanceof Date);
assert.equal(data[2][1], '$123.00');
assert.equal(data[3][1], '98.76%');
assert.equal(data[4][1], '456.00');
assert.equal(data[5][1], '7,890');
var data1 = X.utils.sheet_to_json<any>(ws, { header: 1, raw: true, rawNumbers: false });
var data2 = X.utils.sheet_to_json<any>(ws, { header: 1, raw: false, rawNumbers: true });
assert.ok(data1[0][1] instanceof Date);
assert.ok(data1[1][1] instanceof Date);
assert.equal(data1[2][1], '$123.00');
assert.equal(data1[3][1], '98.76%');
assert.equal(data1[4][1], '456.00');
assert.equal(data1[5][1], '7,890');
assert.equal(data2[0][1], '7/23/2020');
assert.equal(data2[5][1], 7890);
}); } });
it('date system', function() {[
@ -2085,6 +2088,15 @@ describe('json output', function() {
}
});
});
it('should force UTC in formatted strings', function() {
var ws: X.WorkSheet = { "!ref": "A1", "A1": { t: 'd', v: new Date(Date.UTC(2002, 11, 24, 0, 0, 0, 0)) } };
assert.equal(X.utils.sheet_to_json<string[]>(ws, {header: 1, UTC: true, raw: false, dateNF: 'd"/"m"/"yyyy'})[0][0], "24/12/2002");
delete ws.A1.w;
assert.equal(X.utils.sheet_to_json<string[]>(ws, {header: 1, UTC: false, raw: false, dateNF: 'd"/"m"/"yyyy'})[0][0], "24/12/2002");
assert.equal(X.utils.sheet_to_json<number[]>(ws, {header: 1, UTC: true, raw: true, dateNF: 'd"/"m"/"yyyy'})[0][0].valueOf(), 1040688000000);
assert.equal(X.utils.sheet_to_json<number[]>(ws, {header: 1, UTC: false, raw: true, dateNF: 'd"/"m"/"yyyy'})[0][0].valueOf(), 1040688000000 + new Date("2002-12-24T00:00:00.000Z").getTimezoneOffset()*60000);
});
});

44
test.sh Executable file

@ -0,0 +1,44 @@
#!/bin/bash
set -euxo pipefail
TZONES=(America/New_York Europe/London Asia/Seoul America/Los_Angeles Europe/Berlin Asia/Kolkata Asia/Shanghai America/Cancun America/Anchorage America/Barbados Asia/Tokyo America/Cayman Pacific/Honolulu America/Mexico_City Asia/Hong_Kong Europe/Paris Atlantic/Azores)
if [ -e datetest.js ]; then
sudo n 20;
for TZ in ${TZONES[@]}; do
echo "$TZ"
env TZ="$TZ" mocha -R dot datetest.js
done
fi
# min test
for n in 20 10 0.8 0.10 0.12 4 6 8 12 14 16 18; do
sudo n $n
env WTF=1 make testdot_misc
for TZ in ${TZONES[@]}; do
sudo n $n
env WTF=1 TZ="$TZ" make testdot_misc
done
done
# full test
for n in 20 10 0.12; do
for TZ in America/New_York Asia/Seoul Asia/Kolkata Europe/Paris; do
sudo n $n
env WTF=1 TZ="$TZ" make testdot
done
done
# bun
for TZ in ${TZONES[@]}; do
echo "$TZ";
env TZ="$TZ" WTF=1 make test-bun_misc;
done
# deno
for TZ in ${TZONES[@]}; do
echo "$TZ";
env TZ="$TZ" WTF=1 make test-deno_misc;
env TZ="$TZ" WTF=1 make test-denocp_misc;
done

28
test.ts

@ -1367,17 +1367,20 @@ Deno.test('parse features', async function(t) {
});
await t.step('data types formats', async function(t) {var dtf = [
['xlsx', paths.dtfxlsx],
['xlsx', paths.dtfxlsx]
]; for(var j = 0; j < dtf.length; ++j) { var m = dtf[j]; await t.step(m[0], async function(t) {
var wb = X.read(fs.readFileSync(m[1]), {type: TYPE, cellDates: true});
var ws = wb.Sheets[wb.SheetNames[0]];
var data = X.utils.sheet_to_json<any>(ws, { header: 1, raw: true, rawNumbers: false });
assert.assert(data[0][1] instanceof Date);
assert.assert(data[1][1] instanceof Date);
assert.equal(data[2][1], '$123.00');
assert.equal(data[3][1], '98.76%');
assert.equal(data[4][1], '456.00');
assert.equal(data[5][1], '7,890');
var data1 = X.utils.sheet_to_json<any>(ws, { header: 1, raw: true, rawNumbers: false });
var data2 = X.utils.sheet_to_json<any>(ws, { header: 1, raw: false, rawNumbers: true });
assert.assert(data1[0][1] instanceof Date);
assert.assert(data1[1][1] instanceof Date);
assert.equal(data1[2][1], '$123.00');
assert.equal(data1[3][1], '98.76%');
assert.equal(data1[4][1], '456.00');
assert.equal(data1[5][1], '7,890');
assert.equal(data2[0][1], '7/23/2020');
assert.equal(data2[5][1], 7890);
}); } });
await t.step('date system', async function(t) {[
@ -2085,6 +2088,15 @@ Deno.test('json output', async function(t) {
}
});
});
await t.step('should force UTC in formatted strings', async function(t) {
var ws: X.WorkSheet = { "!ref": "A1", "A1": { t: 'd', v: new Date(Date.UTC(2002, 11, 24, 0, 0, 0, 0)) } };
assert.equal(X.utils.sheet_to_json<string[]>(ws, {header: 1, UTC: true, raw: false, dateNF: 'd"/"m"/"yyyy'})[0][0], "24/12/2002");
delete ws.A1.w;
assert.equal(X.utils.sheet_to_json<string[]>(ws, {header: 1, UTC: false, raw: false, dateNF: 'd"/"m"/"yyyy'})[0][0], "24/12/2002");
assert.equal(X.utils.sheet_to_json<number[]>(ws, {header: 1, UTC: true, raw: true, dateNF: 'd"/"m"/"yyyy'})[0][0].valueOf(), 1040688000000);
assert.equal(X.utils.sheet_to_json<number[]>(ws, {header: 1, UTC: false, raw: true, dateNF: 'd"/"m"/"yyyy'})[0][0].valueOf(), 1040688000000 + new Date("2002-12-24T00:00:00.000Z").getTimezoneOffset()*60000);
});
});

93
testbun.mjs generated

@ -65,6 +65,8 @@ if(!browser) {
for(var _fileAi = 0; _fileAi < _fileA.length; ++_fileAi) if(test_file(_fileA[_fileAi])) fileA.push(_fileA[_fileAi]);
}
var can_write_numbers = typeof Set !== "undefined" && typeof Array.prototype.findIndex == "function" && typeof Uint8Array !== "undefined" && typeof Uint8Array.prototype.indexOf == "function";
/* Excel enforces 31 character sheet limit, although technical file limit is 255 */
function fixsheetname(x/*:string*/)/*:string*/ { return x.substr(0,31); }
@ -581,7 +583,7 @@ describe('parse options', function() {
it('sheetRows n=10', function() { FSTPaths.forEach(function(p) {
checkcells(X.read(fs.readFileSync(p), {type:TYPE, sheetRows:10}), false, false, false, true);
}); });
if(false) it('sheetRows n=1', function() { ofmt.forEach(function(fmt) {
it('sheetRows n=1', function() { ofmt.forEach(function(fmt) {
[TYPE, "buffer", "buffer", "array"].forEach(function(ot) {
var data = [[1,2],[3,4],[5,6]];
var ws = X.utils.aoa_to_sheet(data);
@ -676,7 +678,7 @@ describe('parse options', function() {
it('should not generate VBA by default', function() { NFPaths.forEach(function(p) {
var wb = X.read(fs.readFileSync(p), {type:TYPE}); assert.ok(typeof wb.vbaraw === 'undefined');
}); });
if(false) it('bookVBA should generate vbaraw', function() { NFVBA.forEach(function(p) {
it('bookVBA should generate vbaraw', function() { NFVBA.forEach(function(p) {
var wb = X.read(fs.readFileSync(p),{type: TYPE, bookVBA: true});
assert.ok(wb.vbaraw);
var cfb = X.CFB.read(wb.vbaraw, {type: 'array'});
@ -714,7 +716,7 @@ describe('input formats', function() {
((browser || typeof Buffer === 'undefined') ? it.skip : it)('should read Buffers', function() { artifax.forEach(function(p) {
X.read(fs.readFileSync(p), {type: 'buffer'});
}); });
if(false) if(typeof Uint8Array !== 'undefined') it('should read ArrayBuffer / Uint8Array', function() { artifax.forEach(function(p) {
if(typeof Uint8Array !== 'undefined') it('should read ArrayBuffer / Uint8Array', function() { artifax.forEach(function(p) {
var payload = fs.readFileSync(p, browser ? 'buffer' : null);
var ab = new ArrayBuffer(payload.length), vu = new Uint8Array(ab);
for(var i = 0; i < payload.length; ++i) vu[i] = payload[i];
@ -726,13 +728,13 @@ describe('input formats', function() {
}); });
var T = browser ? 'base64' : 'buffer';
if(false) it('should default to "' + T + '" type', function() { artifax.forEach(function(p) {
it('should default to "' + T + '" type', function() { artifax.forEach(function(p) {
X.read(fs.readFileSync.apply(fs, browser ? [p, 'base64'] : [p]));
}); });
if(!browser) it('should read files', function() { artifax.forEach(function(p) { X.readFile(p); }); });
});
if(false) describe('output formats', function() {
describe('output formats', function() {
var fmts = [
/* fmt unicode str */
["xlsx", true, false],
@ -962,7 +964,7 @@ describe('parse features', function() {
}); });
});
if(false) describe('should parse core properties and custom properties', function() {
describe('should parse core properties and custom properties', function() {
var wbs=[];
var bef = (function() {
wbs = [
@ -1031,7 +1033,7 @@ describe('parse features', function() {
});
});
if(false) describe('column properties', function() {
describe('column properties', function() {
var wbs = [], wbs_no_slk = [];
var bef = (function() {
wbs = CWPaths.map(function(n) { return X.read(fs.readFileSync(n), {type:TYPE, cellStyles:true}); });
@ -1072,7 +1074,7 @@ describe('parse features', function() {
});
});
if(false) describe('row properties', function() {
describe('row properties', function() {
var wbs = [], ols = [];
var ol = fs.existsSync(paths.olxls);
var bef = (function() {
@ -1145,15 +1147,15 @@ describe('parse features', function() {
if(typeof before != 'undefined') before(bef);
else it('before', bef);
['xlsx', 'xlsb', /* 'xls', 'xml'*/].forEach(function(x, i) {
['xlsx', 'xlsb', 'xls', 'xml'].forEach(function(x, i) {
it(x + " external", function() { hlink1(wb1[i].Sheets["Sheet1"]); });
});
['xlsx', 'xlsb', /* 'xls', 'xml', 'ods'*/].forEach(function(x, i) {
['xlsx', 'xlsb', 'xls', 'xml', 'ods'].forEach(function(x, i) {
it(x + " internal", function() { hlink2(wb2[i].Sheets["Sheet1"]); });
});
});
if(false) describe('should parse cells with date type (XLSX/XLSM)', function() {
describe('should parse cells with date type (XLSX/XLSM)', function() {
it('Must have read the date', function() {
var wb, ws;
var sheetName = 'Sheet1';
@ -1220,7 +1222,7 @@ describe('parse features', function() {
assert.equal(names[i].Ref, "Sheet1!$A$2");
}); }); });
if(false) describe('defined names unicode', function() {[
describe('defined names unicode', function() {[
/* desc path RT */
['xlsx', paths.dnuxlsx, true],
['xlsb', paths.dnuxlsb, true],
@ -1254,7 +1256,7 @@ describe('parse features', function() {
}); });
}); }); });
if(false) describe('workbook codename unicode', function() {
describe('workbook codename unicode', function() {
var ws, wb;
var bef = (function() {
wb = X.utils.book_new();
@ -1307,7 +1309,7 @@ describe('parse features', function() {
}); });
});
if(false) describe('page margins', function() {
describe('page margins', function() {
var wbs=[];
var bef = (function() {
if(!fs.existsSync(paths.pmxls)) return;
@ -1407,20 +1409,23 @@ describe('parse features', function() {
});
describe('data types formats', function() {[
['xlsx', paths.dtfxlsx],
['xlsx', paths.dtfxlsx]
].forEach(function(m) { it(m[0], function() {
var wb = X.read(fs.readFileSync(m[1]), {type: TYPE, cellDates: true});
var ws = wb.Sheets[wb.SheetNames[0]];
var data = X.utils.sheet_to_json(ws, { header: 1, raw: true, rawNumbers: false });
assert.ok(data[0][1] instanceof Date);
assert.ok(data[1][1] instanceof Date);
assert.equal(data[2][1], '$123.00');
assert.equal(data[3][1], '98.76%');
assert.equal(data[4][1], '456.00');
assert.equal(data[5][1], '7,890');
var data1 = X.utils.sheet_to_json(ws, { header: 1, raw: true, rawNumbers: false });
var data2 = X.utils.sheet_to_json(ws, { header: 1, raw: false, rawNumbers: true });
assert.ok(data1[0][1] instanceof Date);
assert.ok(data1[1][1] instanceof Date);
assert.equal(data1[2][1], '$123.00');
assert.equal(data1[3][1], '98.76%');
assert.equal(data1[4][1], '456.00');
assert.equal(data1[5][1], '7,890');
assert.equal(data2[0][1], '7/23/2020');
assert.equal(data2[5][1], 7890);
}); }); });
if(false) it('date system', function() {[
it('date system', function() {[
"biff5", "ods", "slk", "xls", "xlsb", "xlsx", "xml"
].forEach(function(ext) {
// TODO: verify actual date values
@ -1445,18 +1450,18 @@ describe('parse features', function() {
].join("\n"));
}); });
if(false) it('bookType metadata', function() {
it('bookType metadata', function() {
[
// TODO: keep in sync with BookType, support other formats
"xlsx"/*, "xlsm" */, "xlsb"/* xls / xla / biff# */, "xlml", "ods", "fods"/*, "csv", "txt", */, "sylk", "html", "dif", "rtf"/*, "prn", "eth"*/, "dbf", "numbers"
].forEach(function(r) {
if(r == "numbers" && !can_write_numbers) return;
var ws = X.utils.aoa_to_sheet([ ["a", "b", "c"], [1, 2, 3] ]);
var wb = X.utils.book_new(); X.utils.book_append_sheet(wb, ws, "Sheet1");
var data = X.write(wb, {type: TYPE, bookType: r, WTF: true, numbers:XLSX_ZAHL });
assert.equal(X.read(data, {type: TYPE, WTF: true}).bookType, r);
}); });
});
console.log(`${fails} FAILED ${passes} PASSED`); process.exit(fails > 0);
describe('write features', function() {
describe('props', function() {
@ -1563,7 +1568,7 @@ describe('write features', function() {
["String", "123"],
["Number", 123],
["Boolean", true],
["Date", new Date()],
["Date", new Date()]
], { cellDates: true });
ws["B2"].t = ws["B3"].t = ws["B4"].t = "s"
var wb = X.utils.book_new();
@ -1608,7 +1613,7 @@ function parseDate(str/*:string*/, date1904/*:boolean*/)/*:Date*/ {
var fixdate = browser ? parseDate("2014-02-19T14:30:00.000Z") : new Date("2014-02-19T14:30Z");
describe('roundtrip features', function() {
if(false) describe('roundtrip features', function() {
describe('should preserve core properties', function() { [
['xls', paths.cpxls],
['xlml', paths.cpxml],
@ -1639,6 +1644,7 @@ describe('roundtrip features', function() {
describe('should preserve merge cells', function() {
["xlsx", "xlsb", "xlml", "ods", "biff8", "numbers"].forEach(function(f) { it(f, function() {
if(f == "numbers" && !can_write_numbers) return;
var wb1 = X.read(fs.readFileSync(paths.mcxlsx), {type:TYPE});
var wb2 = X.read(X.write(wb1,{bookType:f,type:'binary',numbers:XLSX_ZAHL}),{type:'binary'});
var m1 = wb1.Sheets["Merge"]['!merges'].map(X.utils.encode_range);
@ -1882,7 +1888,7 @@ var password_files = [
"password_2002_40_xor.xls"
];
describe('invalid files', function() {
describe('parse', function() { [
if(false) describe('parse', function() { [
['KEY files', 'numbers/Untitled.key'],
['PAGES files', 'numbers/Untitled.pages'],
['password', 'apachepoi_password.xls'],
@ -2133,6 +2139,15 @@ describe('json output', function() {
}
});
});
it('should force UTC in formatted strings', function() {
var ws = { "!ref": "A1", "A1": { t: 'd', v: new Date(Date.UTC(2002, 11, 24, 0, 0, 0, 0)) } };
assert.equal(X.utils.sheet_to_json(ws, {header: 1, UTC: true, raw: false, dateNF: 'd"/"m"/"yyyy'})[0][0], "24/12/2002");
delete ws.A1.w;
assert.equal(X.utils.sheet_to_json(ws, {header: 1, UTC: false, raw: false, dateNF: 'd"/"m"/"yyyy'})[0][0], "24/12/2002");
assert.equal(X.utils.sheet_to_json(ws, {header: 1, UTC: true, raw: true, dateNF: 'd"/"m"/"yyyy'})[0][0].valueOf(), 1040688000000);
assert.equal(X.utils.sheet_to_json(ws, {header: 1, UTC: false, raw: true, dateNF: 'd"/"m"/"yyyy'})[0][0].valueOf(), 1040688000000 + new Date("2002-12-24T00:00:00.000Z").getTimezoneOffset()*60000);
});
});
@ -2172,6 +2187,9 @@ var html_bstr = make_html_str(1), html_str = make_html_str(0);
var csv_bstr = make_csv_str(1), csv_str = make_csv_str(0);
// WTF=1 make test-bun_misc in bun 1.0.15 reached this point
console.log(`${fails} FAILED ${passes} PASSED`); process.exit(+!!(fails > 0));
describe('CSV', function() {
describe('input', function(){
var b = "1,2,3,\nTRUE,FALSE,,sheetjs\nfoo,bar,2/19/14,0.3\n,,,\nbaz,,qux,\n";
@ -2297,6 +2315,23 @@ describe('CSV', function() {
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getUTCHours(), 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getUTCHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
});
});
describe('output', function(){
@ -2424,7 +2459,7 @@ describe('numbers', function() {
assert.equal(get_cell(ws, "B11").v, true);
assert.equal(get_cell(ws, "B13").v, 50);
});
it('should cap cols at 1000 (ALL)', function() {
if(can_write_numbers) it('should cap cols at 1000 (ALL)', function() {
var aoa = [[1], [], []]; aoa[1][999] = 2; aoa[2][1000] = 3;
var ws1 = X.utils.aoa_to_sheet(aoa);
var wb1 = X.utils.book_new(); X.utils.book_append_sheet(wb1, ws1, "Sheet1");

@ -1366,17 +1366,20 @@ Deno.test('parse features', async function(t) {
});
await t.step('data types formats', async function(t) {var dtf = [
['xlsx', paths.dtfxlsx],
['xlsx', paths.dtfxlsx]
]; for(var j = 0; j < dtf.length; ++j) { var m = dtf[j]; await t.step(m[0], async function(t) {
var wb = X.read(fs.readFileSync(m[1]), {type: TYPE, cellDates: true});
var ws = wb.Sheets[wb.SheetNames[0]];
var data = X.utils.sheet_to_json<any>(ws, { header: 1, raw: true, rawNumbers: false });
assert.assert(data[0][1] instanceof Date);
assert.assert(data[1][1] instanceof Date);
assert.equal(data[2][1], '$123.00');
assert.equal(data[3][1], '98.76%');
assert.equal(data[4][1], '456.00');
assert.equal(data[5][1], '7,890');
var data1 = X.utils.sheet_to_json<any>(ws, { header: 1, raw: true, rawNumbers: false });
var data2 = X.utils.sheet_to_json<any>(ws, { header: 1, raw: false, rawNumbers: true });
assert.assert(data1[0][1] instanceof Date);
assert.assert(data1[1][1] instanceof Date);
assert.equal(data1[2][1], '$123.00');
assert.equal(data1[3][1], '98.76%');
assert.equal(data1[4][1], '456.00');
assert.equal(data1[5][1], '7,890');
assert.equal(data2[0][1], '7/23/2020');
assert.equal(data2[5][1], 7890);
}); } });
await t.step('date system', async function(t) {[
@ -2084,6 +2087,15 @@ Deno.test('json output', async function(t) {
}
});
});
await t.step('should force UTC in formatted strings', async function(t) {
var ws: X.WorkSheet = { "!ref": "A1", "A1": { t: 'd', v: new Date(Date.UTC(2002, 11, 24, 0, 0, 0, 0)) } };
assert.equal(X.utils.sheet_to_json<string[]>(ws, {header: 1, UTC: true, raw: false, dateNF: 'd"/"m"/"yyyy'})[0][0], "24/12/2002");
delete ws.A1.w;
assert.equal(X.utils.sheet_to_json<string[]>(ws, {header: 1, UTC: false, raw: false, dateNF: 'd"/"m"/"yyyy'})[0][0], "24/12/2002");
assert.equal(X.utils.sheet_to_json<number[]>(ws, {header: 1, UTC: true, raw: true, dateNF: 'd"/"m"/"yyyy'})[0][0].valueOf(), 1040688000000);
assert.equal(X.utils.sheet_to_json<number[]>(ws, {header: 1, UTC: false, raw: true, dateNF: 'd"/"m"/"yyyy'})[0][0].valueOf(), 1040688000000 + new Date("2002-12-24T00:00:00.000Z").getTimezoneOffset()*60000);
});
});

26
tests/core.js generated

@ -1402,13 +1402,16 @@ describe('parse features', function() {
].forEach(function(m) { it(m[0], function() {
var wb = X.read(fs.readFileSync(m[1]), {type: TYPE, cellDates: true});
var ws = wb.Sheets[wb.SheetNames[0]];
var data = X.utils.sheet_to_json(ws, { header: 1, raw: true, rawNumbers: false });
assert.ok(data[0][1] instanceof Date);
assert.ok(data[1][1] instanceof Date);
assert.equal(data[2][1], '$123.00');
assert.equal(data[3][1], '98.76%');
assert.equal(data[4][1], '456.00');
assert.equal(data[5][1], '7,890');
var data1 = X.utils.sheet_to_json(ws, { header: 1, raw: true, rawNumbers: false });
var data2 = X.utils.sheet_to_json(ws, { header: 1, raw: false, rawNumbers: true });
assert.ok(data1[0][1] instanceof Date);
assert.ok(data1[1][1] instanceof Date);
assert.equal(data1[2][1], '$123.00');
assert.equal(data1[3][1], '98.76%');
assert.equal(data1[4][1], '456.00');
assert.equal(data1[5][1], '7,890');
assert.equal(data2[0][1], '7/23/2020');
assert.equal(data2[5][1], 7890);
}); }); });
it('date system', function() {[
@ -2125,6 +2128,15 @@ describe('json output', function() {
}
});
});
it('should force UTC in formatted strings', function() {
var ws = { "!ref": "A1", "A1": { t: 'd', v: new Date(Date.UTC(2002, 11, 24, 0, 0, 0, 0)) } };
assert.equal(X.utils.sheet_to_json(ws, {header: 1, UTC: true, raw: false, dateNF: 'd"/"m"/"yyyy'})[0][0], "24/12/2002");
delete ws.A1.w;
assert.equal(X.utils.sheet_to_json(ws, {header: 1, UTC: false, raw: false, dateNF: 'd"/"m"/"yyyy'})[0][0], "24/12/2002");
assert.equal(X.utils.sheet_to_json(ws, {header: 1, UTC: true, raw: true, dateNF: 'd"/"m"/"yyyy'})[0][0].valueOf(), 1040688000000);
assert.equal(X.utils.sheet_to_json(ws, {header: 1, UTC: false, raw: true, dateNF: 'd"/"m"/"yyyy'})[0][0].valueOf(), 1040688000000 + new Date("2002-12-24T00:00:00.000Z").getTimezoneOffset()*60000);
});
});

@ -4,7 +4,7 @@
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false, DataView:false, Deno:false, Float32Array:false */
var XLSX = {};
function make_xlsx_lib(XLSX){
XLSX.version = '0.20.0';
XLSX.version = '0.20.1';
var current_codepage = 1200, current_ansi = 1252;
/*:: declare var cptable:any; */
/*global cptable:true, window */
@ -484,8 +484,20 @@ function SSF_frac(x/*:number*/, D/*:number*/, mixed/*:?boolean*/)/*:Array<number
var q = Math.floor(sgn * P/Q);
return [q, sgn*P - q*Q, Q];
}
function SSF_normalize_xl_unsafe(v/*:number*/)/*:number*/ {
var s = v.toPrecision(16);
if(s.indexOf("e") > -1) {
var m = s.slice(0, s.indexOf("e"));
m = m.indexOf(".") > -1 ? m.slice(0, (m.slice(0,2) == "0." ? 17 : 16)) : (m.slice(0,15) + fill("0", m.length - 15));
return m + s.slice(s.indexOf("e"));
}
var n = s.indexOf(".") > -1 ? s.slice(0, (s.slice(0,2) == "0." ? 17 : 16)) : (s.slice(0,15) + fill("0", s.length - 15));
return Number(n);
}
function SSF_parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) {
if(v > 2958465 || v < 0) return null;
v = SSF_normalize_xl_unsafe(v);
var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
var dout=[];
var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
@ -639,7 +651,7 @@ function SSF_write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*
switch(fmt) {
case '[h]': case '[hh]': out = val.D*24+val.H; break;
case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break;
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+(ss0 == 0 ? Math.round(val.S+val.u) : val.S); break;
default: throw 'bad abstime format: ' + fmt;
} outl = fmt.length === 3 ? 1 : 2; break;
case 101: /* 'e' era */
@ -1087,10 +1099,11 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
switch(out[i].t) {
case 'h': case 'H': out[i].t = hr; lst='h'; if(bt < 1) bt = 1; break;
case 's':
if((ssm=out[i].v.match(/\.0+$/))) ss0=Math.max(ss0,ssm[0].length-1);
if((ssm=out[i].v.match(/\.0+$/))) { ss0=Math.max(ss0,ssm[0].length-1); bt = 4;}
if(bt < 3) bt = 3;
/* falls through */
case 'd': case 'y': case 'M': case 'e': lst=out[i].t; break;
case 'd': case 'y': case 'e': lst=out[i].t; break;
case 'M': lst=out[i].t; if(bt < 2) bt = 2; break;
case 'm': if(lst === 's') { out[i].t = 'M'; if(bt < 2) bt = 2; } break;
case 'X': /*if(out[i].v === "B2");*/
break;
@ -1100,19 +1113,29 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
if(bt < 3 && out[i].v.match(/[Ss]/)) bt = 3;
}
}
/* time rounding depends on presence of minute / second / usec fields */
var _dt;
switch(bt) {
case 0: break;
case 1:
/*::if(!dt) break;*/
case 2:
case 3:
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
if(dt.H >= 24) { dt.H = 0; ++dt.D; _dt = SSF_parse_date_code(dt.D); _dt.u = dt.u; _dt.S = dt.S; _dt.M = dt.M; _dt.H = dt.H; dt = _dt; }
break;
case 2:
/*::if(!dt) break;*/
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
case 4:
switch(ss0) {
case 1: dt.u = Math.round(dt.u * 10)/10; break;
case 2: dt.u = Math.round(dt.u * 100)/100; break;
case 3: dt.u = Math.round(dt.u * 1000)/1000; break;
}
if(dt.u >= 1) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
if(dt.H >= 24) { dt.H = 0; ++dt.D; _dt = SSF_parse_date_code(dt.D); _dt.u = dt.u; _dt.S = dt.S; _dt.M = dt.M; _dt.H = dt.H; dt = _dt; }
break;
}
@ -4431,6 +4454,13 @@ function sheet_to_workbook(sheet/*:Worksheet*/, opts)/*:Workbook*/ {
return { SheetNames: [n], Sheets: sheets };
}
function sheet_new(opts) {
var out = {};
var o = opts || {};
if(o.dense) out["!data"] = [];
return out;
}
function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ {
var o = opts || {};
var dense = _ws ? (_ws["!data"] != null) : o.dense;
@ -7992,7 +8022,7 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ {
case 'L': switch(s.trim().toUpperCase()) {
case 'Y': case 'T': out[R][C] = true; break;
case 'N': case 'F': out[R][C] = false; break;
case '': case '?': break;
case '': case '\x00': case '?': break;
default: throw new Error("DBF Unrecognized L:|" + s + "|");
} break;
case 'M': /* TODO: handle memo files */
@ -8054,6 +8084,7 @@ function dbf_to_workbook(buf, opts)/*:Workbook*/ {
var _RLEN = { 'B': 8, 'C': 250, 'L': 1, 'D': 8, '?': 0, '': 0 };
function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) {
if(!ws["!ref"]) throw new Error("Cannot export empty sheet to DBF");
var o = opts || {};
var old_cp = current_codepage;
if(+o.codepage >= 0) set_cp(+o.codepage);
@ -8211,7 +8242,10 @@ var SYLK = /*#__PURE__*/(function() {
"!":161, '"':162, "#":163, "(":164, "%":165, "'":167, "H ":168,
"+":171, ";":187, "<":188, "=":189, ">":190, "?":191, "{":223
}/*:any*/);
var sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1") + "|\\|)", "gm");
var sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1").replace("{", "\\{") + "|\\|)", "gm");
try {
sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1") + "|\\|)", "gm");
} catch(e) {}
var sylk_char_fn = function(_, $1){ var o = sylk_escapes[$1]; return typeof o == "number" ? _getansi(o) : o; };
var decode_sylk_char = function($$, $1, $2) { var newcc = (($1.charCodeAt(0) - 0x20)<<4) | ($2.charCodeAt(0) - 0x30); return newcc == 59 ? $$ : _getansi(newcc); };
sylk_escapes["|"] = 254;
@ -8434,7 +8468,7 @@ var SYLK = /*#__PURE__*/(function() {
if(!opts) opts = {}; opts._formats = ["General"];
/* TODO: codepage */
var preamble/*:Array<string>*/ = ["ID;PSheetJS;N;E"], o/*:Array<string>*/ = [];
var r = safe_decode_range(ws['!ref']), cell/*:Cell*/;
var r = safe_decode_range(ws['!ref']||"A1"), cell/*:Cell*/;
var dense = ws["!data"] != null;
var RS = "\r\n";
var d1904 = (((wb||{}).Workbook||{}).WBProps||{}).date1904;
@ -8443,7 +8477,7 @@ var SYLK = /*#__PURE__*/(function() {
preamble.push("P;PGeneral");
/* Excel has been inconsistent in comment placement */
var R = r.s.r, C = r.s.c, p = [];
for(R = r.s.r; R <= r.e.r; ++R) {
if(ws["!ref"]) for(R = r.s.r; R <= r.e.r; ++R) {
if(dense && !ws["!data"][R]) continue;
p = [];
for(C = r.s.c; C <= r.e.c; ++C) {
@ -8453,7 +8487,7 @@ var SYLK = /*#__PURE__*/(function() {
}
if(p.length) o.push(p.join(RS));
}
for(R = r.s.r; R <= r.e.r; ++R) {
if(ws["!ref"]) for(R = r.s.r; R <= r.e.r; ++R) {
if(dense && !ws["!data"][R]) continue;
p = [];
for(C = r.s.c; C <= r.e.c; ++C) {
@ -8473,7 +8507,7 @@ var SYLK = /*#__PURE__*/(function() {
if(ws['!cols']) write_ws_cols_sylk(preamble, ws['!cols']);
if(ws['!rows']) write_ws_rows_sylk(preamble, ws['!rows']);
preamble.push("B;Y" + (r.e.r - r.s.r + 1) + ";X" + (r.e.c - r.s.c + 1) + ";D" + [r.s.c,r.s.r,r.e.c,r.e.r].join(" "));
if(ws["!ref"]) preamble.push("B;Y" + (r.e.r - r.s.r + 1) + ";X" + (r.e.c - r.s.c + 1) + ";D" + [r.s.c,r.s.r,r.e.c,r.e.r].join(" "));
preamble.push("O;L;D;B" + (d1904 ? ";V4" : "") + ";K47;G100 0.001");
delete opts._formats;
@ -8546,6 +8580,7 @@ var DIF = /*#__PURE__*/(function() {
function make_value_str(s/*:string*/)/*:string*/ { return "1,0\r\n\"" + s.replace(/"/g,'""') + '"'; }
function sheet_to_dif(ws/*:Worksheet*//*::, opts:?any*/)/*:string*/ {
var _DIF_XL = DIF_XL;
if(!ws["!ref"]) throw new Error("Cannot export empty sheet to DIF");
var r = safe_decode_range(ws['!ref']);
var dense = ws["!data"] != null;
var o/*:Array<string>*/ = [
@ -8883,6 +8918,7 @@ var PRN = /*#__PURE__*/(function() {
function sheet_to_prn(ws/*:Worksheet*//*::, opts:?any*/)/*:string*/ {
var o/*:Array<string>*/ = [];
if(!ws["!ref"]) return "";
var r = safe_decode_range(ws['!ref']), cell/*:Cell*/;
var dense = ws["!data"] != null;
for(var R = r.s.r; R <= r.e.r; ++R) {
@ -9107,6 +9143,7 @@ var WK_ = /*#__PURE__*/(function() {
if(+o.codepage >= 0) set_cp(+o.codepage);
if(o.type == "string") throw new Error("Cannot write WK1 to JS string");
var ba = buf_array();
if(!ws["!ref"]) throw new Error("Cannot export empty sheet to WK1");
var range = safe_decode_range(ws["!ref"]);
var dense = ws["!data"] != null;
var cols = [];
@ -9900,13 +9937,25 @@ var WK_ = /*#__PURE__*/(function() {
/*::[*/0x0E/*::*/: "dd-mmm-yyyy",
/*::[*/0x0F/*::*/: "mmm-yyyy",
/*::[*/0x22/*::*/: "0.00",
/*::[*/0x32/*::*/: "0.00;[Red]0.00",
/*::[*/0x42/*::*/: "0.00;\(0.00\)",
/*::[*/0x52/*::*/: "0.00;[Red]\(0.00\)",
/*::[*/162/*::*/: '"$"#,##0;\\("$"#,##0\\)' // slightly different from SSF 5
/* It is suspected that the the low nybble specifies decimal places */
/*::[*/0x0022/*::*/: "0.00",
/*::[*/0x0032/*::*/: "0.00;[Red]0.00",
/*::[*/0x0042/*::*/: "0.00;\(0.00\)",
/*::[*/0x0052/*::*/: "0.00;[Red]\(0.00\)",
/*::[*/0x00A2/*::*/: '"$"#,##0.00;\\("$"#,##0.00\\)',
/*::[*/0x0120/*::*/: '0%',
/*::[*/0x0130/*::*/: '0E+00',
/*::[*/0x0140/*::*/: '# ?/?'
};
function parse_qpw_str(p) {
var cch = p.read_shift(2);
var flags = p.read_shift(1);
/* TODO: find examples with nonzero flags */
if(flags != 0) throw "unsupported QPW string type " + flags.toString(16);
return p.read_shift(cch, "sbcs-cont");
}
/* QPW uses a different set of record types */
function qpw_to_workbook_buf(d, opts)/*:Workbook*/ {
prep_blob(d, 0);
@ -10017,7 +10066,11 @@ var WK_ = /*#__PURE__*/(function() {
case 4: cell = { t: "n", v: parse_RkNumber(p) }; break;
case 5: cell = { t: "n", v: p.read_shift(8, 'f') }; break;
case 7: cell = { t: "s", v: SST[type = p.read_shift(4) - 1] }; break;
case 8: cell = { t: "n", v: p.read_shift(8, 'f') }; p.l += 2; /* cell.f = formulae[p.read_shift(4)]; */ p.l += 4; break;
case 8:
cell = { t: "n", v: p.read_shift(8, 'f') };
p.l += 2; /* cell.f = formulae[p.read_shift(4)]; */ p.l += 4;
if(isNaN(cell.v)) cell = { t: "e", v: 0x0F }; // #VALUE!
break;
default: throw "Unrecognized QPW cell type " + (flags & 0x1F);
}
if(fmtidx != -1 && (FMTS[fmtidx - 1]||{}).z) cell.z = FMTS[fmtidx-1].z;
@ -10063,6 +10116,17 @@ var WK_ = /*#__PURE__*/(function() {
}
} break;
case 0x0C02: { /* String (result of string formula expression) */
C = p.read_shift(2);
R = p.read_shift(4);
var str = parse_qpw_str(p);
/* TODO: QP10 record has an additional unknown character after the string */
if(s["!data"] != null) {
if(!s["!data"][R]) s["!data"][R] = [];
s["!data"][R][C] = { t:"s", v:str };
} else s[encode_col(C) + encode_row(R)] = { t:"s", v:str };
} break;
default: break;
}
d.l += length;
@ -11215,7 +11279,7 @@ function parse_cellXfs(t, styles, opts) {
case '<cellXfs': case '<cellXfs>': case '<cellXfs/>': case '</cellXfs>': break;
/* 18.8.45 xf CT_Xf */
case '<xf': case '<xf/>':
case '<xf': case '<xf/>': case '<xf>':
xf = y;
delete xf[0];
for(i = 0; i < cellXF_uint.length; ++i) if(xf[cellXF_uint[i]])
@ -11229,7 +11293,7 @@ function parse_cellXfs(t, styles, opts) {
case '</xf>': break;
/* 18.8.1 alignment CT_CellAlignment */
case '<alignment': case '<alignment/>':
case '<alignment': case '<alignment/>': case '<alignment>':
var alignment = {};
if(y.vertical) alignment.vertical = y.vertical;
if(y.horizontal) alignment.horizontal = y.horizontal;
@ -11241,12 +11305,12 @@ function parse_cellXfs(t, styles, opts) {
case '</alignment>': break;
/* 18.8.33 protection CT_CellProtection */
case '<protection':
case '<protection': case '<protection>':
break;
case '</protection>': case '<protection/>': break;
/* note: sometimes mc:AlternateContent appears bare */
case '<AlternateContent': pass = true; break;
case '<AlternateContent': case '<AlternateContent>': pass = true; break;
case '</AlternateContent>': pass = false; break;
/* 18.2.10 extLst CT_ExtensionList ? */
@ -12887,7 +12951,10 @@ var rc_to_a1 = /*#__PURE__*/(function(){
};
})();
var crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)(10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})(?![_.\(A-Za-z0-9])/g;
var crefregex = /(^|[^._A-Z0-9])(\$?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])(\$?)(\d{1,7})(?![_.\(A-Za-z0-9])/g;
try {
crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)(10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})(?![_.\(A-Za-z0-9])/g;
}catch(e){}
var a1_to_rc = /*#__PURE__*/(function(){
return function a1_to_rc(fstr/*:string*/, base/*:CellAddress*/) {
return fstr.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
@ -15601,7 +15668,7 @@ function parse_ws_xml_dim(ws/*:Worksheet*/, s/*:string*/) {
var d = safe_decode_range(s);
if(d.s.r<=d.e.r && d.s.c<=d.e.c && d.s.r>=0 && d.s.c>=0) ws["!ref"] = encode_range(d);
}
var mergecregex = /<(?:\w:)?mergeCell ref="[A-Z0-9:]+"\s*[\/]?>/g;
var mergecregex = /<(?:\w:)?mergeCell ref=["'][A-Z0-9:]+['"]\s*[\/]?>/g;
var sheetdataregex = /<(?:\w+:)?sheetData[^>]*>([\s\S]*)<\/(?:\w+:)?sheetData>/;
var hlinkregex = /<(?:\w:)?hyperlink [^>]*>/mg;
var dimregex = /"(\w*:\w*)"/;
@ -22460,9 +22527,9 @@ function sheet_to_html(ws/*:Worksheet*/, opts/*:?Sheet2HTMLOpts*//*, wb:?Workboo
var header = o.header != null ? o.header : HTML_BEGIN;
var footer = o.footer != null ? o.footer : HTML_END;
var out/*:Array<string>*/ = [header];
var r = decode_range(ws['!ref']);
var r = decode_range(ws['!ref'] || "A1");
out.push(make_html_preamble(ws, r, o));
for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
if(ws["!ref"]) for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
out.push("</table>" + footer);
return out.join("");
}
@ -23221,10 +23288,13 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
case 'help-message': break; // 9.4.6 <table:
case 'error-message': break; // 9.4.7 <table:
case 'database-ranges': break; // 9.4.14 <table:database-ranges>
/* 9.5 Filters */
case 'filter': break; // 9.5.2 <table:filter>
case 'filter-and': break; // 9.5.3 <table:filter-and>
case 'filter-or': break; // 9.5.4 <table:filter-or>
case 'filter-condition': break; // 9.5.5 <table:filter-condition>
case 'filter-set-item': break; // 9.5.6 <table:filter-condition>
case 'list-level-style-bullet': break; // 16.31 <text:
case 'list-level-style-number': break; // 16.32 <text:
@ -23741,6 +23811,7 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function
wb.SheetNames.map(function(n) { return wb.Sheets[n]; }).forEach(function(ws) {
if(!ws) return;
var dense = (ws["!data"] != null);
if(!ws["!ref"]) return;
var range = decode_range(ws["!ref"]);
for(var R = 0; R <= range.e.r; ++R) for(var C = 0; C <= range.e.c; ++C) {
var c = dense ? (ws["!data"][R]||[])[C] : ws[encode_cell({r:R,c:C})];
@ -24992,7 +25063,7 @@ function s5s_to_iwa_comment(s5s) {
return out;
}
function parse_TST_TableModelArchive(M, root, ws, opts) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
var pb = parse_shallow(root.data);
var range = { s: { r: 0, c: 0 }, e: { r: 0, c: 0 } };
range.e.r = (varint_to_i32(pb[6][0].data) >>> 0) - 1;
@ -25021,7 +25092,17 @@ function parse_TST_TableModelArchive(M, root, ws, opts) {
lut.nfmt = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[22][0].data)][0]);
var tile = parse_shallow(store[3][0].data);
var _R = 0;
tile[1].forEach(function(t) {
if (!((_h = store[9]) == null ? void 0 : _h[0]))
throw "NUMBERS file missing row tree";
var rtt = parse_shallow(store[9][0].data)[1].map(function(p) {
return parse_shallow(p.data);
});
rtt.forEach(function(kv) {
_R = varint_to_i32(kv[1][0].data);
var tidx = varint_to_i32(kv[2][0].data);
var t = tile[1][tidx];
if (!t)
throw "NUMBERS missing tile " + tidx;
var tl = parse_shallow(t.data);
var ref2 = M[parse_TSP_Reference(tl[2][0].data)][0];
var mtype2 = varint_to_i32(ref2.meta[1][0].data);
@ -25044,12 +25125,12 @@ function parse_TST_TableModelArchive(M, root, ws, opts) {
});
_R += _tile.nrows;
});
if ((_h = store[13]) == null ? void 0 : _h[0]) {
if ((_i = store[13]) == null ? void 0 : _i[0]) {
var ref = M[parse_TSP_Reference(store[13][0].data)][0];
var mtype = varint_to_i32(ref.meta[1][0].data);
if (mtype != 6144)
throw new Error("Expected merge type 6144, found ".concat(mtype));
ws["!merges"] = (_i = parse_shallow(ref.data)) == null ? void 0 : _i[1].map(function(pi) {
ws["!merges"] = (_j = parse_shallow(ref.data)) == null ? void 0 : _j[1].map(function(pi) {
var merge = parse_shallow(pi.data);
var origin = u8_to_dataview(parse_shallow(merge[1][0].data)[1][0].data), size = u8_to_dataview(parse_shallow(merge[2][0].data)[1][0].data);
return {
@ -25711,6 +25792,8 @@ function write_numbers_ws(cfb, deps, ws, wsname, sheetidx, rootref) {
}
var USE_WIDE_ROWS = true;
function write_numbers_tma(cfb, deps, ws, tmaroot, tmafile, tmaref) {
if (!ws["!ref"])
throw new Error("Cannot export empty sheet to NUMBERS");
var range = decode_range(ws["!ref"]);
range.s.r = range.s.c = 0;
var trunc = false;
@ -27156,7 +27239,7 @@ function make_json_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Ar
v = numdate(v); // TODO: date1904 setting should also be stored in worksheet object
if(typeof v == "number") break;
/* falls through */
case 'd': if(!(o && o.UTC)) v = utc_to_local(v); break;
case 'd': if(!(o && (o.UTC||(o.raw === false)))) v = utc_to_local(new Date(v)); break;
default: throw new Error('unrecognized type ' + val.t);
}
if(hdr[C] != null) {
@ -27166,7 +27249,7 @@ function make_json_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Ar
else if(raw && v === null) row[hdr[C]] = null;
else continue;
} else {
row[hdr[C]] = raw && (val.t !== "n" || (val.t === "n" && o.rawNumbers !== false)) ? v : format_cell(val,v,o);
row[hdr[C]] = (val.t === 'n' && typeof o.rawNumbers === 'boolean' ? o.rawNumbers : raw) ? v : format_cell(val, v, o);
}
if(v != null) isempty = false;
}
@ -27424,9 +27507,11 @@ function wb_sheet_idx(wb/*:Workbook*/, sh/*:number|string*/) {
} else throw new Error("Cannot find sheet |" + sh + "|");
}
/* simple blank workbook object */
function book_new()/*:Workbook*/ {
return { SheetNames: [], Sheets: {} };
/* simple blank or single-sheet workbook object */
function book_new(ws/*:?Worksheet*/, wsname/*:?string*/)/*:Workbook*/ {
var wb = { SheetNames: [], Sheets: {} };
if(ws) book_append_sheet(wb, ws, wsname || "Sheet1");
return wb;
}
/* add a worksheet to the end of a given workbook */
@ -27523,6 +27608,7 @@ var utils/*:any*/ = {
decode_cell: decode_cell,
decode_range: decode_range,
format_cell: format_cell,
sheet_new: sheet_new,
sheet_add_aoa: sheet_add_aoa,
sheet_add_json: sheet_add_json,
sheet_add_dom: sheet_add_dom,

162
xlsx.js generated

@ -4,7 +4,7 @@
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false, DataView:false, Deno:false, Float32Array:false */
var XLSX = {};
function make_xlsx_lib(XLSX){
XLSX.version = '0.20.0';
XLSX.version = '0.20.1';
var current_codepage = 1200, current_ansi = 1252;
/*global cptable:true, window */
var $cptable;
@ -464,8 +464,20 @@ function SSF_frac(x, D, mixed) {
var q = Math.floor(sgn * P/Q);
return [q, sgn*P - q*Q, Q];
}
function SSF_normalize_xl_unsafe(v) {
var s = v.toPrecision(16);
if(s.indexOf("e") > -1) {
var m = s.slice(0, s.indexOf("e"));
m = m.indexOf(".") > -1 ? m.slice(0, (m.slice(0,2) == "0." ? 17 : 16)) : (m.slice(0,15) + fill("0", m.length - 15));
return m + s.slice(s.indexOf("e"));
}
var n = s.indexOf(".") > -1 ? s.slice(0, (s.slice(0,2) == "0." ? 17 : 16)) : (s.slice(0,15) + fill("0", s.length - 15));
return Number(n);
}
function SSF_parse_date_code(v,opts,b2) {
if(v > 2958465 || v < 0) return null;
v = SSF_normalize_xl_unsafe(v);
var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
var dout=[];
var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
@ -618,7 +630,7 @@ if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100;
switch(fmt) {
case '[h]': case '[hh]': out = val.D*24+val.H; break;
case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break;
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+(ss0 == 0 ? Math.round(val.S+val.u) : val.S); break;
default: throw 'bad abstime format: ' + fmt;
} outl = fmt.length === 3 ? 1 : 2; break;
case 101: /* 'e' era */
@ -1064,10 +1076,11 @@ function eval_fmt(fmt, v, opts, flen) {
switch(out[i].t) {
case 'h': case 'H': out[i].t = hr; lst='h'; if(bt < 1) bt = 1; break;
case 's':
if((ssm=out[i].v.match(/\.0+$/))) ss0=Math.max(ss0,ssm[0].length-1);
if((ssm=out[i].v.match(/\.0+$/))) { ss0=Math.max(ss0,ssm[0].length-1); bt = 4;}
if(bt < 3) bt = 3;
/* falls through */
case 'd': case 'y': case 'M': case 'e': lst=out[i].t; break;
case 'd': case 'y': case 'e': lst=out[i].t; break;
case 'M': lst=out[i].t; if(bt < 2) bt = 2; break;
case 'm': if(lst === 's') { out[i].t = 'M'; if(bt < 2) bt = 2; } break;
case 'X': /*if(out[i].v === "B2");*/
break;
@ -1077,17 +1090,29 @@ function eval_fmt(fmt, v, opts, flen) {
if(bt < 3 && out[i].v.match(/[Ss]/)) bt = 3;
}
}
/* time rounding depends on presence of minute / second / usec fields */
var _dt;
switch(bt) {
case 0: break;
case 1:
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
case 2:
case 3:
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
if(dt.H >= 24) { dt.H = 0; ++dt.D; _dt = SSF_parse_date_code(dt.D); _dt.u = dt.u; _dt.S = dt.S; _dt.M = dt.M; _dt.H = dt.H; dt = _dt; }
break;
case 2:
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
case 4:
switch(ss0) {
case 1: dt.u = Math.round(dt.u * 10)/10; break;
case 2: dt.u = Math.round(dt.u * 100)/100; break;
case 3: dt.u = Math.round(dt.u * 1000)/1000; break;
}
if(dt.u >= 1) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
if(dt.H >= 24) { dt.H = 0; ++dt.D; _dt = SSF_parse_date_code(dt.D); _dt.u = dt.u; _dt.S = dt.S; _dt.M = dt.M; _dt.H = dt.H; dt = _dt; }
break;
}
@ -4347,6 +4372,13 @@ function sheet_to_workbook(sheet, opts) {
return { SheetNames: [n], Sheets: sheets };
}
function sheet_new(opts) {
var out = {};
var o = opts || {};
if(o.dense) out["!data"] = [];
return out;
}
function sheet_add_aoa(_ws, data, opts) {
var o = opts || {};
var dense = _ws ? (_ws["!data"] != null) : o.dense;
@ -7903,7 +7935,7 @@ var fields = [], field = ({});
case 'L': switch(s.trim().toUpperCase()) {
case 'Y': case 'T': out[R][C] = true; break;
case 'N': case 'F': out[R][C] = false; break;
case '': case '?': break;
case '': case '\x00': case '?': break;
default: throw new Error("DBF Unrecognized L:|" + s + "|");
} break;
case 'M': /* TODO: handle memo files */
@ -7965,6 +7997,7 @@ function dbf_to_workbook(buf, opts) {
var _RLEN = { 'B': 8, 'C': 250, 'L': 1, 'D': 8, '?': 0, '': 0 };
function sheet_to_dbf(ws, opts) {
if(!ws["!ref"]) throw new Error("Cannot export empty sheet to DBF");
var o = opts || {};
var old_cp = current_codepage;
if(+o.codepage >= 0) set_cp(+o.codepage);
@ -8122,7 +8155,10 @@ var SYLK = (function() {
"!":161, '"':162, "#":163, "(":164, "%":165, "'":167, "H ":168,
"+":171, ";":187, "<":188, "=":189, ">":190, "?":191, "{":223
});
var sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1") + "|\\|)", "gm");
var sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1").replace("{", "\\{") + "|\\|)", "gm");
try {
sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1") + "|\\|)", "gm");
} catch(e) {}
var sylk_char_fn = function(_, $1){ var o = sylk_escapes[$1]; return typeof o == "number" ? _getansi(o) : o; };
var decode_sylk_char = function($$, $1, $2) { var newcc = (($1.charCodeAt(0) - 0x20)<<4) | ($2.charCodeAt(0) - 0x30); return newcc == 59 ? $$ : _getansi(newcc); };
sylk_escapes["|"] = 254;
@ -8345,7 +8381,7 @@ var SYLK = (function() {
if(!opts) opts = {}; opts._formats = ["General"];
/* TODO: codepage */
var preamble = ["ID;PSheetJS;N;E"], o = [];
var r = safe_decode_range(ws['!ref']), cell;
var r = safe_decode_range(ws['!ref']||"A1"), cell;
var dense = ws["!data"] != null;
var RS = "\r\n";
var d1904 = (((wb||{}).Workbook||{}).WBProps||{}).date1904;
@ -8354,7 +8390,7 @@ var SYLK = (function() {
preamble.push("P;PGeneral");
/* Excel has been inconsistent in comment placement */
var R = r.s.r, C = r.s.c, p = [];
for(R = r.s.r; R <= r.e.r; ++R) {
if(ws["!ref"]) for(R = r.s.r; R <= r.e.r; ++R) {
if(dense && !ws["!data"][R]) continue;
p = [];
for(C = r.s.c; C <= r.e.c; ++C) {
@ -8364,7 +8400,7 @@ var SYLK = (function() {
}
if(p.length) o.push(p.join(RS));
}
for(R = r.s.r; R <= r.e.r; ++R) {
if(ws["!ref"]) for(R = r.s.r; R <= r.e.r; ++R) {
if(dense && !ws["!data"][R]) continue;
p = [];
for(C = r.s.c; C <= r.e.c; ++C) {
@ -8384,7 +8420,7 @@ var SYLK = (function() {
if(ws['!cols']) write_ws_cols_sylk(preamble, ws['!cols']);
if(ws['!rows']) write_ws_rows_sylk(preamble, ws['!rows']);
preamble.push("B;Y" + (r.e.r - r.s.r + 1) + ";X" + (r.e.c - r.s.c + 1) + ";D" + [r.s.c,r.s.r,r.e.c,r.e.r].join(" "));
if(ws["!ref"]) preamble.push("B;Y" + (r.e.r - r.s.r + 1) + ";X" + (r.e.c - r.s.c + 1) + ";D" + [r.s.c,r.s.r,r.e.c,r.e.r].join(" "));
preamble.push("O;L;D;B" + (d1904 ? ";V4" : "") + ";K47;G100 0.001");
delete opts._formats;
@ -8457,6 +8493,7 @@ var DIF = (function() {
function make_value_str(s) { return "1,0\r\n\"" + s.replace(/"/g,'""') + '"'; }
function sheet_to_dif(ws) {
var _DIF_XL = DIF_XL;
if(!ws["!ref"]) throw new Error("Cannot export empty sheet to DIF");
var r = safe_decode_range(ws['!ref']);
var dense = ws["!data"] != null;
var o = [
@ -8794,6 +8831,7 @@ var PRN = (function() {
function sheet_to_prn(ws) {
var o = [];
if(!ws["!ref"]) return "";
var r = safe_decode_range(ws['!ref']), cell;
var dense = ws["!data"] != null;
for(var R = r.s.r; R <= r.e.r; ++R) {
@ -9018,6 +9056,7 @@ var WK_ = (function() {
if(+o.codepage >= 0) set_cp(+o.codepage);
if(o.type == "string") throw new Error("Cannot write WK1 to JS string");
var ba = buf_array();
if(!ws["!ref"]) throw new Error("Cannot export empty sheet to WK1");
var range = safe_decode_range(ws["!ref"]);
var dense = ws["!data"] != null;
var cols = [];
@ -9811,13 +9850,25 @@ var WK_ = (function() {
0x0E: "dd-mmm-yyyy",
0x0F: "mmm-yyyy",
0x22: "0.00",
0x32: "0.00;[Red]0.00",
0x42: "0.00;\(0.00\)",
0x52: "0.00;[Red]\(0.00\)",
162: '"$"#,##0;\\("$"#,##0\\)' // slightly different from SSF 5
/* It is suspected that the the low nybble specifies decimal places */
0x0022: "0.00",
0x0032: "0.00;[Red]0.00",
0x0042: "0.00;\(0.00\)",
0x0052: "0.00;[Red]\(0.00\)",
0x00A2: '"$"#,##0.00;\\("$"#,##0.00\\)',
0x0120: '0%',
0x0130: '0E+00',
0x0140: '# ?/?'
};
function parse_qpw_str(p) {
var cch = p.read_shift(2);
var flags = p.read_shift(1);
/* TODO: find examples with nonzero flags */
if(flags != 0) throw "unsupported QPW string type " + flags.toString(16);
return p.read_shift(cch, "sbcs-cont");
}
/* QPW uses a different set of record types */
function qpw_to_workbook_buf(d, opts) {
prep_blob(d, 0);
@ -9928,7 +9979,11 @@ var WK_ = (function() {
case 4: cell = { t: "n", v: parse_RkNumber(p) }; break;
case 5: cell = { t: "n", v: p.read_shift(8, 'f') }; break;
case 7: cell = { t: "s", v: SST[type = p.read_shift(4) - 1] }; break;
case 8: cell = { t: "n", v: p.read_shift(8, 'f') }; p.l += 2; /* cell.f = formulae[p.read_shift(4)]; */ p.l += 4; break;
case 8:
cell = { t: "n", v: p.read_shift(8, 'f') };
p.l += 2; /* cell.f = formulae[p.read_shift(4)]; */ p.l += 4;
if(isNaN(cell.v)) cell = { t: "e", v: 0x0F }; // #VALUE!
break;
default: throw "Unrecognized QPW cell type " + (flags & 0x1F);
}
if(fmtidx != -1 && (FMTS[fmtidx - 1]||{}).z) cell.z = FMTS[fmtidx-1].z;
@ -9974,6 +10029,17 @@ var WK_ = (function() {
}
} break;
case 0x0C02: { /* String (result of string formula expression) */
C = p.read_shift(2);
R = p.read_shift(4);
var str = parse_qpw_str(p);
/* TODO: QP10 record has an additional unknown character after the string */
if(s["!data"] != null) {
if(!s["!data"][R]) s["!data"][R] = [];
s["!data"][R][C] = { t:"s", v:str };
} else s[encode_col(C) + encode_row(R)] = { t:"s", v:str };
} break;
default: break;
}
d.l += length;
@ -11125,7 +11191,7 @@ function parse_cellXfs(t, styles, opts) {
case '<cellXfs': case '<cellXfs>': case '<cellXfs/>': case '</cellXfs>': break;
/* 18.8.45 xf CT_Xf */
case '<xf': case '<xf/>':
case '<xf': case '<xf/>': case '<xf>':
xf = y;
delete xf[0];
for(i = 0; i < cellXF_uint.length; ++i) if(xf[cellXF_uint[i]])
@ -11139,7 +11205,7 @@ function parse_cellXfs(t, styles, opts) {
case '</xf>': break;
/* 18.8.1 alignment CT_CellAlignment */
case '<alignment': case '<alignment/>':
case '<alignment': case '<alignment/>': case '<alignment>':
var alignment = {};
if(y.vertical) alignment.vertical = y.vertical;
if(y.horizontal) alignment.horizontal = y.horizontal;
@ -11151,12 +11217,12 @@ function parse_cellXfs(t, styles, opts) {
case '</alignment>': break;
/* 18.8.33 protection CT_CellProtection */
case '<protection':
case '<protection': case '<protection>':
break;
case '</protection>': case '<protection/>': break;
/* note: sometimes mc:AlternateContent appears bare */
case '<AlternateContent': pass = true; break;
case '<AlternateContent': case '<AlternateContent>': pass = true; break;
case '</AlternateContent>': pass = false; break;
/* 18.2.10 extLst CT_ExtensionList ? */
@ -12795,7 +12861,10 @@ var rc_to_a1 = (function(){
};
})();
var crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)(10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})(?![_.\(A-Za-z0-9])/g;
var crefregex = /(^|[^._A-Z0-9])(\$?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])(\$?)(\d{1,7})(?![_.\(A-Za-z0-9])/g;
try {
crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)(10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})(?![_.\(A-Za-z0-9])/g;
}catch(e){}
var a1_to_rc = (function(){
return function a1_to_rc(fstr, base) {
return fstr.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
@ -15508,7 +15577,7 @@ function parse_ws_xml_dim(ws, s) {
var d = safe_decode_range(s);
if(d.s.r<=d.e.r && d.s.c<=d.e.c && d.s.r>=0 && d.s.c>=0) ws["!ref"] = encode_range(d);
}
var mergecregex = /<(?:\w:)?mergeCell ref="[A-Z0-9:]+"\s*[\/]?>/g;
var mergecregex = /<(?:\w:)?mergeCell ref=["'][A-Z0-9:]+['"]\s*[\/]?>/g;
var sheetdataregex = /<(?:\w+:)?sheetData[^>]*>([\s\S]*)<\/(?:\w+:)?sheetData>/;
var hlinkregex = /<(?:\w:)?hyperlink [^>]*>/mg;
var dimregex = /"(\w*:\w*)"/;
@ -22351,9 +22420,9 @@ function sheet_to_html(ws, opts/*, wb:?Workbook*/) {
var header = o.header != null ? o.header : HTML_BEGIN;
var footer = o.footer != null ? o.footer : HTML_END;
var out = [header];
var r = decode_range(ws['!ref']);
var r = decode_range(ws['!ref'] || "A1");
out.push(make_html_preamble(ws, r, o));
for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
if(ws["!ref"]) for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
out.push("</table>" + footer);
return out.join("");
}
@ -23112,10 +23181,13 @@ function parse_content_xml(d, _opts, _nfm) {
case 'help-message': break; // 9.4.6 <table:
case 'error-message': break; // 9.4.7 <table:
case 'database-ranges': break; // 9.4.14 <table:database-ranges>
/* 9.5 Filters */
case 'filter': break; // 9.5.2 <table:filter>
case 'filter-and': break; // 9.5.3 <table:filter-and>
case 'filter-or': break; // 9.5.4 <table:filter-or>
case 'filter-condition': break; // 9.5.5 <table:filter-condition>
case 'filter-set-item': break; // 9.5.6 <table:filter-condition>
case 'list-level-style-bullet': break; // 16.31 <text:
case 'list-level-style-number': break; // 16.32 <text:
@ -23632,6 +23704,7 @@ var write_content_ods = /* @__PURE__ */(function() {
wb.SheetNames.map(function(n) { return wb.Sheets[n]; }).forEach(function(ws) {
if(!ws) return;
var dense = (ws["!data"] != null);
if(!ws["!ref"]) return;
var range = decode_range(ws["!ref"]);
for(var R = 0; R <= range.e.r; ++R) for(var C = 0; C <= range.e.c; ++C) {
var c = dense ? (ws["!data"][R]||[])[C] : ws[encode_cell({r:R,c:C})];
@ -24883,7 +24956,7 @@ function s5s_to_iwa_comment(s5s) {
return out;
}
function parse_TST_TableModelArchive(M, root, ws, opts) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
var pb = parse_shallow(root.data);
var range = { s: { r: 0, c: 0 }, e: { r: 0, c: 0 } };
range.e.r = (varint_to_i32(pb[6][0].data) >>> 0) - 1;
@ -24912,7 +24985,17 @@ function parse_TST_TableModelArchive(M, root, ws, opts) {
lut.nfmt = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[22][0].data)][0]);
var tile = parse_shallow(store[3][0].data);
var _R = 0;
tile[1].forEach(function(t) {
if (!((_h = store[9]) == null ? void 0 : _h[0]))
throw "NUMBERS file missing row tree";
var rtt = parse_shallow(store[9][0].data)[1].map(function(p) {
return parse_shallow(p.data);
});
rtt.forEach(function(kv) {
_R = varint_to_i32(kv[1][0].data);
var tidx = varint_to_i32(kv[2][0].data);
var t = tile[1][tidx];
if (!t)
throw "NUMBERS missing tile " + tidx;
var tl = parse_shallow(t.data);
var ref2 = M[parse_TSP_Reference(tl[2][0].data)][0];
var mtype2 = varint_to_i32(ref2.meta[1][0].data);
@ -24935,12 +25018,12 @@ function parse_TST_TableModelArchive(M, root, ws, opts) {
});
_R += _tile.nrows;
});
if ((_h = store[13]) == null ? void 0 : _h[0]) {
if ((_i = store[13]) == null ? void 0 : _i[0]) {
var ref = M[parse_TSP_Reference(store[13][0].data)][0];
var mtype = varint_to_i32(ref.meta[1][0].data);
if (mtype != 6144)
throw new Error("Expected merge type 6144, found ".concat(mtype));
ws["!merges"] = (_i = parse_shallow(ref.data)) == null ? void 0 : _i[1].map(function(pi) {
ws["!merges"] = (_j = parse_shallow(ref.data)) == null ? void 0 : _j[1].map(function(pi) {
var merge = parse_shallow(pi.data);
var origin = u8_to_dataview(parse_shallow(merge[1][0].data)[1][0].data), size = u8_to_dataview(parse_shallow(merge[2][0].data)[1][0].data);
return {
@ -25602,6 +25685,8 @@ function write_numbers_ws(cfb, deps, ws, wsname, sheetidx, rootref) {
}
var USE_WIDE_ROWS = true;
function write_numbers_tma(cfb, deps, ws, tmaroot, tmafile, tmaref) {
if (!ws["!ref"])
throw new Error("Cannot export empty sheet to NUMBERS");
var range = decode_range(ws["!ref"]);
range.s.r = range.s.c = 0;
var trunc = false;
@ -27036,7 +27121,7 @@ function make_json_row(sheet, r, R, cols, header, hdr, o) {
v = numdate(v); // TODO: date1904 setting should also be stored in worksheet object
if(typeof v == "number") break;
/* falls through */
case 'd': if(!(o && o.UTC)) v = utc_to_local(v); break;
case 'd': if(!(o && (o.UTC||(o.raw === false)))) v = utc_to_local(new Date(v)); break;
default: throw new Error('unrecognized type ' + val.t);
}
if(hdr[C] != null) {
@ -27046,7 +27131,7 @@ function make_json_row(sheet, r, R, cols, header, hdr, o) {
else if(raw && v === null) row[hdr[C]] = null;
else continue;
} else {
row[hdr[C]] = raw && (val.t !== "n" || (val.t === "n" && o.rawNumbers !== false)) ? v : format_cell(val,v,o);
row[hdr[C]] = (val.t === 'n' && typeof o.rawNumbers === 'boolean' ? o.rawNumbers : raw) ? v : format_cell(val, v, o);
}
if(v != null) isempty = false;
}
@ -27304,9 +27389,11 @@ function wb_sheet_idx(wb, sh) {
} else throw new Error("Cannot find sheet |" + sh + "|");
}
/* simple blank workbook object */
function book_new() {
return { SheetNames: [], Sheets: {} };
/* simple blank or single-sheet workbook object */
function book_new(ws, wsname) {
var wb = { SheetNames: [], Sheets: {} };
if(ws) book_append_sheet(wb, ws, wsname || "Sheet1");
return wb;
}
/* add a worksheet to the end of a given workbook */
@ -27403,6 +27490,7 @@ var utils = {
decode_cell: decode_cell,
decode_range: decode_range,
format_cell: format_cell,
sheet_new: sheet_new,
sheet_add_aoa: sheet_add_aoa,
sheet_add_json: sheet_add_json,
sheet_add_dom: sheet_add_dom,

@ -4,7 +4,7 @@
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false, DataView:false, Deno:false, Float32Array:false */
var XLSX = {};
function make_xlsx_lib(XLSX){
XLSX.version = '0.20.0';
XLSX.version = '0.20.1';
var current_codepage = 1200, current_ansi = 1252;
/*:: declare var cptable:any; */
/*global cptable:true, window */
@ -484,8 +484,20 @@ function SSF_frac(x/*:number*/, D/*:number*/, mixed/*:?boolean*/)/*:Array<number
var q = Math.floor(sgn * P/Q);
return [q, sgn*P - q*Q, Q];
}
function SSF_normalize_xl_unsafe(v/*:number*/)/*:number*/ {
var s = v.toPrecision(16);
if(s.indexOf("e") > -1) {
var m = s.slice(0, s.indexOf("e"));
m = m.indexOf(".") > -1 ? m.slice(0, (m.slice(0,2) == "0." ? 17 : 16)) : (m.slice(0,15) + fill("0", m.length - 15));
return m + s.slice(s.indexOf("e"));
}
var n = s.indexOf(".") > -1 ? s.slice(0, (s.slice(0,2) == "0." ? 17 : 16)) : (s.slice(0,15) + fill("0", s.length - 15));
return Number(n);
}
function SSF_parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) {
if(v > 2958465 || v < 0) return null;
v = SSF_normalize_xl_unsafe(v);
var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
var dout=[];
var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
@ -639,7 +651,7 @@ function SSF_write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*
switch(fmt) {
case '[h]': case '[hh]': out = val.D*24+val.H; break;
case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break;
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+(ss0 == 0 ? Math.round(val.S+val.u) : val.S); break;
default: throw 'bad abstime format: ' + fmt;
} outl = fmt.length === 3 ? 1 : 2; break;
case 101: /* 'e' era */
@ -1087,10 +1099,11 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
switch(out[i].t) {
case 'h': case 'H': out[i].t = hr; lst='h'; if(bt < 1) bt = 1; break;
case 's':
if((ssm=out[i].v.match(/\.0+$/))) ss0=Math.max(ss0,ssm[0].length-1);
if((ssm=out[i].v.match(/\.0+$/))) { ss0=Math.max(ss0,ssm[0].length-1); bt = 4;}
if(bt < 3) bt = 3;
/* falls through */
case 'd': case 'y': case 'M': case 'e': lst=out[i].t; break;
case 'd': case 'y': case 'e': lst=out[i].t; break;
case 'M': lst=out[i].t; if(bt < 2) bt = 2; break;
case 'm': if(lst === 's') { out[i].t = 'M'; if(bt < 2) bt = 2; } break;
case 'X': /*if(out[i].v === "B2");*/
break;
@ -1100,19 +1113,29 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
if(bt < 3 && out[i].v.match(/[Ss]/)) bt = 3;
}
}
/* time rounding depends on presence of minute / second / usec fields */
var _dt;
switch(bt) {
case 0: break;
case 1:
/*::if(!dt) break;*/
case 2:
case 3:
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
if(dt.H >= 24) { dt.H = 0; ++dt.D; _dt = SSF_parse_date_code(dt.D); _dt.u = dt.u; _dt.S = dt.S; _dt.M = dt.M; _dt.H = dt.H; dt = _dt; }
break;
case 2:
/*::if(!dt) break;*/
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
case 4:
switch(ss0) {
case 1: dt.u = Math.round(dt.u * 10)/10; break;
case 2: dt.u = Math.round(dt.u * 100)/100; break;
case 3: dt.u = Math.round(dt.u * 1000)/1000; break;
}
if(dt.u >= 1) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
if(dt.H >= 24) { dt.H = 0; ++dt.D; _dt = SSF_parse_date_code(dt.D); _dt.u = dt.u; _dt.S = dt.S; _dt.M = dt.M; _dt.H = dt.H; dt = _dt; }
break;
}
@ -4427,6 +4450,13 @@ function sheet_to_workbook(sheet/*:Worksheet*/, opts)/*:Workbook*/ {
return { SheetNames: [n], Sheets: sheets };
}
function sheet_new(opts) {
var out = {};
var o = opts || {};
if(o.dense) out["!data"] = [];
return out;
}
function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ {
var o = opts || {};
var dense = _ws ? (_ws["!data"] != null) : o.dense;
@ -5759,7 +5789,7 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ {
case 'L': switch(s.trim().toUpperCase()) {
case 'Y': case 'T': out[R][C] = true; break;
case 'N': case 'F': out[R][C] = false; break;
case '': case '?': break;
case '': case '\x00': case '?': break;
default: throw new Error("DBF Unrecognized L:|" + s + "|");
} break;
case 'M': /* TODO: handle memo files */
@ -5821,6 +5851,7 @@ function dbf_to_workbook(buf, opts)/*:Workbook*/ {
var _RLEN = { 'B': 8, 'C': 250, 'L': 1, 'D': 8, '?': 0, '': 0 };
function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) {
if(!ws["!ref"]) throw new Error("Cannot export empty sheet to DBF");
var o = opts || {};
var old_cp = current_codepage;
if(+o.codepage >= 0) set_cp(+o.codepage);
@ -5978,7 +6009,10 @@ var SYLK = /*#__PURE__*/(function() {
"!":161, '"':162, "#":163, "(":164, "%":165, "'":167, "H ":168,
"+":171, ";":187, "<":188, "=":189, ">":190, "?":191, "{":223
}/*:any*/);
var sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1") + "|\\|)", "gm");
var sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1").replace("{", "\\{") + "|\\|)", "gm");
try {
sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1") + "|\\|)", "gm");
} catch(e) {}
var sylk_char_fn = function(_, $1){ var o = sylk_escapes[$1]; return typeof o == "number" ? _getansi(o) : o; };
var decode_sylk_char = function($$, $1, $2) { var newcc = (($1.charCodeAt(0) - 0x20)<<4) | ($2.charCodeAt(0) - 0x30); return newcc == 59 ? $$ : _getansi(newcc); };
sylk_escapes["|"] = 254;
@ -6201,7 +6235,7 @@ var SYLK = /*#__PURE__*/(function() {
if(!opts) opts = {}; opts._formats = ["General"];
/* TODO: codepage */
var preamble/*:Array<string>*/ = ["ID;PSheetJS;N;E"], o/*:Array<string>*/ = [];
var r = safe_decode_range(ws['!ref']), cell/*:Cell*/;
var r = safe_decode_range(ws['!ref']||"A1"), cell/*:Cell*/;
var dense = ws["!data"] != null;
var RS = "\r\n";
var d1904 = (((wb||{}).Workbook||{}).WBProps||{}).date1904;
@ -6210,7 +6244,7 @@ var SYLK = /*#__PURE__*/(function() {
preamble.push("P;PGeneral");
/* Excel has been inconsistent in comment placement */
var R = r.s.r, C = r.s.c, p = [];
for(R = r.s.r; R <= r.e.r; ++R) {
if(ws["!ref"]) for(R = r.s.r; R <= r.e.r; ++R) {
if(dense && !ws["!data"][R]) continue;
p = [];
for(C = r.s.c; C <= r.e.c; ++C) {
@ -6220,7 +6254,7 @@ var SYLK = /*#__PURE__*/(function() {
}
if(p.length) o.push(p.join(RS));
}
for(R = r.s.r; R <= r.e.r; ++R) {
if(ws["!ref"]) for(R = r.s.r; R <= r.e.r; ++R) {
if(dense && !ws["!data"][R]) continue;
p = [];
for(C = r.s.c; C <= r.e.c; ++C) {
@ -6240,7 +6274,7 @@ var SYLK = /*#__PURE__*/(function() {
if(ws['!cols']) write_ws_cols_sylk(preamble, ws['!cols']);
if(ws['!rows']) write_ws_rows_sylk(preamble, ws['!rows']);
preamble.push("B;Y" + (r.e.r - r.s.r + 1) + ";X" + (r.e.c - r.s.c + 1) + ";D" + [r.s.c,r.s.r,r.e.c,r.e.r].join(" "));
if(ws["!ref"]) preamble.push("B;Y" + (r.e.r - r.s.r + 1) + ";X" + (r.e.c - r.s.c + 1) + ";D" + [r.s.c,r.s.r,r.e.c,r.e.r].join(" "));
preamble.push("O;L;D;B" + (d1904 ? ";V4" : "") + ";K47;G100 0.001");
delete opts._formats;
@ -6313,6 +6347,7 @@ var DIF = /*#__PURE__*/(function() {
function make_value_str(s/*:string*/)/*:string*/ { return "1,0\r\n\"" + s.replace(/"/g,'""') + '"'; }
function sheet_to_dif(ws/*:Worksheet*//*::, opts:?any*/)/*:string*/ {
var _DIF_XL = DIF_XL;
if(!ws["!ref"]) throw new Error("Cannot export empty sheet to DIF");
var r = safe_decode_range(ws['!ref']);
var dense = ws["!data"] != null;
var o/*:Array<string>*/ = [
@ -6650,6 +6685,7 @@ var PRN = /*#__PURE__*/(function() {
function sheet_to_prn(ws/*:Worksheet*//*::, opts:?any*/)/*:string*/ {
var o/*:Array<string>*/ = [];
if(!ws["!ref"]) return "";
var r = safe_decode_range(ws['!ref']), cell/*:Cell*/;
var dense = ws["!data"] != null;
for(var R = r.s.r; R <= r.e.r; ++R) {
@ -7360,7 +7396,7 @@ function parse_cellXfs(t, styles, opts) {
case '<cellXfs': case '<cellXfs>': case '<cellXfs/>': case '</cellXfs>': break;
/* 18.8.45 xf CT_Xf */
case '<xf': case '<xf/>':
case '<xf': case '<xf/>': case '<xf>':
xf = y;
delete xf[0];
for(i = 0; i < cellXF_uint.length; ++i) if(xf[cellXF_uint[i]])
@ -7374,7 +7410,7 @@ function parse_cellXfs(t, styles, opts) {
case '</xf>': break;
/* 18.8.1 alignment CT_CellAlignment */
case '<alignment': case '<alignment/>':
case '<alignment': case '<alignment/>': case '<alignment>':
var alignment = {};
if(y.vertical) alignment.vertical = y.vertical;
if(y.horizontal) alignment.horizontal = y.horizontal;
@ -7386,12 +7422,12 @@ function parse_cellXfs(t, styles, opts) {
case '</alignment>': break;
/* 18.8.33 protection CT_CellProtection */
case '<protection':
case '<protection': case '<protection>':
break;
case '</protection>': case '<protection/>': break;
/* note: sometimes mc:AlternateContent appears bare */
case '<AlternateContent': pass = true; break;
case '<AlternateContent': case '<AlternateContent>': pass = true; break;
case '</AlternateContent>': pass = false; break;
/* 18.2.10 extLst CT_ExtensionList ? */
@ -8281,7 +8317,10 @@ var rc_to_a1 = /*#__PURE__*/(function(){
};
})();
var crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)(10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})(?![_.\(A-Za-z0-9])/g;
var crefregex = /(^|[^._A-Z0-9])(\$?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])(\$?)(\d{1,7})(?![_.\(A-Za-z0-9])/g;
try {
crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)(10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})(?![_.\(A-Za-z0-9])/g;
}catch(e){}
var a1_to_rc = /*#__PURE__*/(function(){
return function a1_to_rc(fstr/*:string*/, base/*:CellAddress*/) {
return fstr.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
@ -8484,7 +8523,7 @@ function parse_ws_xml_dim(ws/*:Worksheet*/, s/*:string*/) {
var d = safe_decode_range(s);
if(d.s.r<=d.e.r && d.s.c<=d.e.c && d.s.r>=0 && d.s.c>=0) ws["!ref"] = encode_range(d);
}
var mergecregex = /<(?:\w:)?mergeCell ref="[A-Z0-9:]+"\s*[\/]?>/g;
var mergecregex = /<(?:\w:)?mergeCell ref=["'][A-Z0-9:]+['"]\s*[\/]?>/g;
var sheetdataregex = /<(?:\w+:)?sheetData[^>]*>([\s\S]*)<\/(?:\w+:)?sheetData>/;
var hlinkregex = /<(?:\w:)?hyperlink [^>]*>/mg;
var dimregex = /"(\w*:\w*)"/;
@ -9828,9 +9867,9 @@ function sheet_to_html(ws/*:Worksheet*/, opts/*:?Sheet2HTMLOpts*//*, wb:?Workboo
var header = o.header != null ? o.header : HTML_BEGIN;
var footer = o.footer != null ? o.footer : HTML_END;
var out/*:Array<string>*/ = [header];
var r = decode_range(ws['!ref']);
var r = decode_range(ws['!ref'] || "A1");
out.push(make_html_preamble(ws, r, o));
for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
if(ws["!ref"]) for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
out.push("</table>" + footer);
return out.join("");
}
@ -10589,10 +10628,13 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
case 'help-message': break; // 9.4.6 <table:
case 'error-message': break; // 9.4.7 <table:
case 'database-ranges': break; // 9.4.14 <table:database-ranges>
/* 9.5 Filters */
case 'filter': break; // 9.5.2 <table:filter>
case 'filter-and': break; // 9.5.3 <table:filter-and>
case 'filter-or': break; // 9.5.4 <table:filter-or>
case 'filter-condition': break; // 9.5.5 <table:filter-condition>
case 'filter-set-item': break; // 9.5.6 <table:filter-condition>
case 'list-level-style-bullet': break; // 16.31 <text:
case 'list-level-style-number': break; // 16.32 <text:
@ -11109,6 +11151,7 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function
wb.SheetNames.map(function(n) { return wb.Sheets[n]; }).forEach(function(ws) {
if(!ws) return;
var dense = (ws["!data"] != null);
if(!ws["!ref"]) return;
var range = decode_range(ws["!ref"]);
for(var R = 0; R <= range.e.r; ++R) for(var C = 0; C <= range.e.c; ++C) {
var c = dense ? (ws["!data"][R]||[])[C] : ws[encode_cell({r:R,c:C})];
@ -12272,7 +12315,7 @@ function make_json_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Ar
v = numdate(v); // TODO: date1904 setting should also be stored in worksheet object
if(typeof v == "number") break;
/* falls through */
case 'd': if(!(o && o.UTC)) v = utc_to_local(v); break;
case 'd': if(!(o && (o.UTC||(o.raw === false)))) v = utc_to_local(new Date(v)); break;
default: throw new Error('unrecognized type ' + val.t);
}
if(hdr[C] != null) {
@ -12282,7 +12325,7 @@ function make_json_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Ar
else if(raw && v === null) row[hdr[C]] = null;
else continue;
} else {
row[hdr[C]] = raw && (val.t !== "n" || (val.t === "n" && o.rawNumbers !== false)) ? v : format_cell(val,v,o);
row[hdr[C]] = (val.t === 'n' && typeof o.rawNumbers === 'boolean' ? o.rawNumbers : raw) ? v : format_cell(val, v, o);
}
if(v != null) isempty = false;
}
@ -12540,9 +12583,11 @@ function wb_sheet_idx(wb/*:Workbook*/, sh/*:number|string*/) {
} else throw new Error("Cannot find sheet |" + sh + "|");
}
/* simple blank workbook object */
function book_new()/*:Workbook*/ {
return { SheetNames: [], Sheets: {} };
/* simple blank or single-sheet workbook object */
function book_new(ws/*:?Worksheet*/, wsname/*:?string*/)/*:Workbook*/ {
var wb = { SheetNames: [], Sheets: {} };
if(ws) book_append_sheet(wb, ws, wsname || "Sheet1");
return wb;
}
/* add a worksheet to the end of a given workbook */
@ -12639,6 +12684,7 @@ var utils/*:any*/ = {
decode_cell: decode_cell,
decode_range: decode_range,
format_cell: format_cell,
sheet_new: sheet_new,
sheet_add_aoa: sheet_add_aoa,
sheet_add_json: sheet_add_json,
sheet_add_dom: sheet_add_dom,

@ -4,7 +4,7 @@
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false, DataView:false, Deno:false, Float32Array:false */
var XLSX = {};
function make_xlsx_lib(XLSX){
XLSX.version = '0.20.0';
XLSX.version = '0.20.1';
var current_codepage = 1200, current_ansi = 1252;
/*global cptable:true, window */
var $cptable;
@ -464,8 +464,20 @@ function SSF_frac(x, D, mixed) {
var q = Math.floor(sgn * P/Q);
return [q, sgn*P - q*Q, Q];
}
function SSF_normalize_xl_unsafe(v) {
var s = v.toPrecision(16);
if(s.indexOf("e") > -1) {
var m = s.slice(0, s.indexOf("e"));
m = m.indexOf(".") > -1 ? m.slice(0, (m.slice(0,2) == "0." ? 17 : 16)) : (m.slice(0,15) + fill("0", m.length - 15));
return m + s.slice(s.indexOf("e"));
}
var n = s.indexOf(".") > -1 ? s.slice(0, (s.slice(0,2) == "0." ? 17 : 16)) : (s.slice(0,15) + fill("0", s.length - 15));
return Number(n);
}
function SSF_parse_date_code(v,opts,b2) {
if(v > 2958465 || v < 0) return null;
v = SSF_normalize_xl_unsafe(v);
var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
var dout=[];
var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
@ -618,7 +630,7 @@ if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100;
switch(fmt) {
case '[h]': case '[hh]': out = val.D*24+val.H; break;
case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break;
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+(ss0 == 0 ? Math.round(val.S+val.u) : val.S); break;
default: throw 'bad abstime format: ' + fmt;
} outl = fmt.length === 3 ? 1 : 2; break;
case 101: /* 'e' era */
@ -1064,10 +1076,11 @@ function eval_fmt(fmt, v, opts, flen) {
switch(out[i].t) {
case 'h': case 'H': out[i].t = hr; lst='h'; if(bt < 1) bt = 1; break;
case 's':
if((ssm=out[i].v.match(/\.0+$/))) ss0=Math.max(ss0,ssm[0].length-1);
if((ssm=out[i].v.match(/\.0+$/))) { ss0=Math.max(ss0,ssm[0].length-1); bt = 4;}
if(bt < 3) bt = 3;
/* falls through */
case 'd': case 'y': case 'M': case 'e': lst=out[i].t; break;
case 'd': case 'y': case 'e': lst=out[i].t; break;
case 'M': lst=out[i].t; if(bt < 2) bt = 2; break;
case 'm': if(lst === 's') { out[i].t = 'M'; if(bt < 2) bt = 2; } break;
case 'X': /*if(out[i].v === "B2");*/
break;
@ -1077,17 +1090,29 @@ function eval_fmt(fmt, v, opts, flen) {
if(bt < 3 && out[i].v.match(/[Ss]/)) bt = 3;
}
}
/* time rounding depends on presence of minute / second / usec fields */
var _dt;
switch(bt) {
case 0: break;
case 1:
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
case 2:
case 3:
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
if(dt.H >= 24) { dt.H = 0; ++dt.D; _dt = SSF_parse_date_code(dt.D); _dt.u = dt.u; _dt.S = dt.S; _dt.M = dt.M; _dt.H = dt.H; dt = _dt; }
break;
case 2:
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
case 4:
switch(ss0) {
case 1: dt.u = Math.round(dt.u * 10)/10; break;
case 2: dt.u = Math.round(dt.u * 100)/100; break;
case 3: dt.u = Math.round(dt.u * 1000)/1000; break;
}
if(dt.u >= 1) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
if(dt.H >= 24) { dt.H = 0; ++dt.D; _dt = SSF_parse_date_code(dt.D); _dt.u = dt.u; _dt.S = dt.S; _dt.M = dt.M; _dt.H = dt.H; dt = _dt; }
break;
}
@ -4343,6 +4368,13 @@ function sheet_to_workbook(sheet, opts) {
return { SheetNames: [n], Sheets: sheets };
}
function sheet_new(opts) {
var out = {};
var o = opts || {};
if(o.dense) out["!data"] = [];
return out;
}
function sheet_add_aoa(_ws, data, opts) {
var o = opts || {};
var dense = _ws ? (_ws["!data"] != null) : o.dense;
@ -5674,7 +5706,7 @@ var fields = [], field = ({});
case 'L': switch(s.trim().toUpperCase()) {
case 'Y': case 'T': out[R][C] = true; break;
case 'N': case 'F': out[R][C] = false; break;
case '': case '?': break;
case '': case '\x00': case '?': break;
default: throw new Error("DBF Unrecognized L:|" + s + "|");
} break;
case 'M': /* TODO: handle memo files */
@ -5736,6 +5768,7 @@ function dbf_to_workbook(buf, opts) {
var _RLEN = { 'B': 8, 'C': 250, 'L': 1, 'D': 8, '?': 0, '': 0 };
function sheet_to_dbf(ws, opts) {
if(!ws["!ref"]) throw new Error("Cannot export empty sheet to DBF");
var o = opts || {};
var old_cp = current_codepage;
if(+o.codepage >= 0) set_cp(+o.codepage);
@ -5893,7 +5926,10 @@ var SYLK = (function() {
"!":161, '"':162, "#":163, "(":164, "%":165, "'":167, "H ":168,
"+":171, ";":187, "<":188, "=":189, ">":190, "?":191, "{":223
});
var sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1") + "|\\|)", "gm");
var sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1").replace("{", "\\{") + "|\\|)", "gm");
try {
sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1") + "|\\|)", "gm");
} catch(e) {}
var sylk_char_fn = function(_, $1){ var o = sylk_escapes[$1]; return typeof o == "number" ? _getansi(o) : o; };
var decode_sylk_char = function($$, $1, $2) { var newcc = (($1.charCodeAt(0) - 0x20)<<4) | ($2.charCodeAt(0) - 0x30); return newcc == 59 ? $$ : _getansi(newcc); };
sylk_escapes["|"] = 254;
@ -6116,7 +6152,7 @@ var SYLK = (function() {
if(!opts) opts = {}; opts._formats = ["General"];
/* TODO: codepage */
var preamble = ["ID;PSheetJS;N;E"], o = [];
var r = safe_decode_range(ws['!ref']), cell;
var r = safe_decode_range(ws['!ref']||"A1"), cell;
var dense = ws["!data"] != null;
var RS = "\r\n";
var d1904 = (((wb||{}).Workbook||{}).WBProps||{}).date1904;
@ -6125,7 +6161,7 @@ var SYLK = (function() {
preamble.push("P;PGeneral");
/* Excel has been inconsistent in comment placement */
var R = r.s.r, C = r.s.c, p = [];
for(R = r.s.r; R <= r.e.r; ++R) {
if(ws["!ref"]) for(R = r.s.r; R <= r.e.r; ++R) {
if(dense && !ws["!data"][R]) continue;
p = [];
for(C = r.s.c; C <= r.e.c; ++C) {
@ -6135,7 +6171,7 @@ var SYLK = (function() {
}
if(p.length) o.push(p.join(RS));
}
for(R = r.s.r; R <= r.e.r; ++R) {
if(ws["!ref"]) for(R = r.s.r; R <= r.e.r; ++R) {
if(dense && !ws["!data"][R]) continue;
p = [];
for(C = r.s.c; C <= r.e.c; ++C) {
@ -6155,7 +6191,7 @@ var SYLK = (function() {
if(ws['!cols']) write_ws_cols_sylk(preamble, ws['!cols']);
if(ws['!rows']) write_ws_rows_sylk(preamble, ws['!rows']);
preamble.push("B;Y" + (r.e.r - r.s.r + 1) + ";X" + (r.e.c - r.s.c + 1) + ";D" + [r.s.c,r.s.r,r.e.c,r.e.r].join(" "));
if(ws["!ref"]) preamble.push("B;Y" + (r.e.r - r.s.r + 1) + ";X" + (r.e.c - r.s.c + 1) + ";D" + [r.s.c,r.s.r,r.e.c,r.e.r].join(" "));
preamble.push("O;L;D;B" + (d1904 ? ";V4" : "") + ";K47;G100 0.001");
delete opts._formats;
@ -6228,6 +6264,7 @@ var DIF = (function() {
function make_value_str(s) { return "1,0\r\n\"" + s.replace(/"/g,'""') + '"'; }
function sheet_to_dif(ws) {
var _DIF_XL = DIF_XL;
if(!ws["!ref"]) throw new Error("Cannot export empty sheet to DIF");
var r = safe_decode_range(ws['!ref']);
var dense = ws["!data"] != null;
var o = [
@ -6565,6 +6602,7 @@ var PRN = (function() {
function sheet_to_prn(ws) {
var o = [];
if(!ws["!ref"]) return "";
var r = safe_decode_range(ws['!ref']), cell;
var dense = ws["!data"] != null;
for(var R = r.s.r; R <= r.e.r; ++R) {
@ -7275,7 +7313,7 @@ function parse_cellXfs(t, styles, opts) {
case '<cellXfs': case '<cellXfs>': case '<cellXfs/>': case '</cellXfs>': break;
/* 18.8.45 xf CT_Xf */
case '<xf': case '<xf/>':
case '<xf': case '<xf/>': case '<xf>':
xf = y;
delete xf[0];
for(i = 0; i < cellXF_uint.length; ++i) if(xf[cellXF_uint[i]])
@ -7289,7 +7327,7 @@ function parse_cellXfs(t, styles, opts) {
case '</xf>': break;
/* 18.8.1 alignment CT_CellAlignment */
case '<alignment': case '<alignment/>':
case '<alignment': case '<alignment/>': case '<alignment>':
var alignment = {};
if(y.vertical) alignment.vertical = y.vertical;
if(y.horizontal) alignment.horizontal = y.horizontal;
@ -7301,12 +7339,12 @@ function parse_cellXfs(t, styles, opts) {
case '</alignment>': break;
/* 18.8.33 protection CT_CellProtection */
case '<protection':
case '<protection': case '<protection>':
break;
case '</protection>': case '<protection/>': break;
/* note: sometimes mc:AlternateContent appears bare */
case '<AlternateContent': pass = true; break;
case '<AlternateContent': case '<AlternateContent>': pass = true; break;
case '</AlternateContent>': pass = false; break;
/* 18.2.10 extLst CT_ExtensionList ? */
@ -8196,7 +8234,10 @@ var rc_to_a1 = (function(){
};
})();
var crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)(10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})(?![_.\(A-Za-z0-9])/g;
var crefregex = /(^|[^._A-Z0-9])(\$?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])(\$?)(\d{1,7})(?![_.\(A-Za-z0-9])/g;
try {
crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)(10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})(?![_.\(A-Za-z0-9])/g;
}catch(e){}
var a1_to_rc = (function(){
return function a1_to_rc(fstr, base) {
return fstr.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
@ -8399,7 +8440,7 @@ function parse_ws_xml_dim(ws, s) {
var d = safe_decode_range(s);
if(d.s.r<=d.e.r && d.s.c<=d.e.c && d.s.r>=0 && d.s.c>=0) ws["!ref"] = encode_range(d);
}
var mergecregex = /<(?:\w:)?mergeCell ref="[A-Z0-9:]+"\s*[\/]?>/g;
var mergecregex = /<(?:\w:)?mergeCell ref=["'][A-Z0-9:]+['"]\s*[\/]?>/g;
var sheetdataregex = /<(?:\w+:)?sheetData[^>]*>([\s\S]*)<\/(?:\w+:)?sheetData>/;
var hlinkregex = /<(?:\w:)?hyperlink [^>]*>/mg;
var dimregex = /"(\w*:\w*)"/;
@ -9741,9 +9782,9 @@ function sheet_to_html(ws, opts/*, wb:?Workbook*/) {
var header = o.header != null ? o.header : HTML_BEGIN;
var footer = o.footer != null ? o.footer : HTML_END;
var out = [header];
var r = decode_range(ws['!ref']);
var r = decode_range(ws['!ref'] || "A1");
out.push(make_html_preamble(ws, r, o));
for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
if(ws["!ref"]) for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
out.push("</table>" + footer);
return out.join("");
}
@ -10502,10 +10543,13 @@ function parse_content_xml(d, _opts, _nfm) {
case 'help-message': break; // 9.4.6 <table:
case 'error-message': break; // 9.4.7 <table:
case 'database-ranges': break; // 9.4.14 <table:database-ranges>
/* 9.5 Filters */
case 'filter': break; // 9.5.2 <table:filter>
case 'filter-and': break; // 9.5.3 <table:filter-and>
case 'filter-or': break; // 9.5.4 <table:filter-or>
case 'filter-condition': break; // 9.5.5 <table:filter-condition>
case 'filter-set-item': break; // 9.5.6 <table:filter-condition>
case 'list-level-style-bullet': break; // 16.31 <text:
case 'list-level-style-number': break; // 16.32 <text:
@ -11022,6 +11066,7 @@ var write_content_ods = /* @__PURE__ */(function() {
wb.SheetNames.map(function(n) { return wb.Sheets[n]; }).forEach(function(ws) {
if(!ws) return;
var dense = (ws["!data"] != null);
if(!ws["!ref"]) return;
var range = decode_range(ws["!ref"]);
for(var R = 0; R <= range.e.r; ++R) for(var C = 0; C <= range.e.c; ++C) {
var c = dense ? (ws["!data"][R]||[])[C] : ws[encode_cell({r:R,c:C})];
@ -12174,7 +12219,7 @@ function make_json_row(sheet, r, R, cols, header, hdr, o) {
v = numdate(v); // TODO: date1904 setting should also be stored in worksheet object
if(typeof v == "number") break;
/* falls through */
case 'd': if(!(o && o.UTC)) v = utc_to_local(v); break;
case 'd': if(!(o && (o.UTC||(o.raw === false)))) v = utc_to_local(new Date(v)); break;
default: throw new Error('unrecognized type ' + val.t);
}
if(hdr[C] != null) {
@ -12184,7 +12229,7 @@ function make_json_row(sheet, r, R, cols, header, hdr, o) {
else if(raw && v === null) row[hdr[C]] = null;
else continue;
} else {
row[hdr[C]] = raw && (val.t !== "n" || (val.t === "n" && o.rawNumbers !== false)) ? v : format_cell(val,v,o);
row[hdr[C]] = (val.t === 'n' && typeof o.rawNumbers === 'boolean' ? o.rawNumbers : raw) ? v : format_cell(val, v, o);
}
if(v != null) isempty = false;
}
@ -12442,9 +12487,11 @@ function wb_sheet_idx(wb, sh) {
} else throw new Error("Cannot find sheet |" + sh + "|");
}
/* simple blank workbook object */
function book_new() {
return { SheetNames: [], Sheets: {} };
/* simple blank or single-sheet workbook object */
function book_new(ws, wsname) {
var wb = { SheetNames: [], Sheets: {} };
if(ws) book_append_sheet(wb, ws, wsname || "Sheet1");
return wb;
}
/* add a worksheet to the end of a given workbook */
@ -12541,6 +12588,7 @@ var utils = {
decode_cell: decode_cell,
decode_range: decode_range,
format_cell: format_cell,
sheet_new: sheet_new,
sheet_add_aoa: sheet_add_aoa,
sheet_add_json: sheet_add_json,
sheet_add_dom: sheet_add_dom,

162
xlsx.mjs generated

@ -3,7 +3,7 @@
/*exported XLSX */
/*global process:false, Buffer:false, ArrayBuffer:false, DataView:false, Deno:false */
var XLSX = {};
XLSX.version = '0.20.0';
XLSX.version = '0.20.1';
var current_codepage = 1200, current_ansi = 1252;
/*:: declare var cptable:any; */
/*global cptable:true, window */
@ -483,8 +483,20 @@ function SSF_frac(x/*:number*/, D/*:number*/, mixed/*:?boolean*/)/*:Array<number
var q = Math.floor(sgn * P/Q);
return [q, sgn*P - q*Q, Q];
}
function SSF_normalize_xl_unsafe(v/*:number*/)/*:number*/ {
var s = v.toPrecision(16);
if(s.indexOf("e") > -1) {
var m = s.slice(0, s.indexOf("e"));
m = m.indexOf(".") > -1 ? m.slice(0, (m.slice(0,2) == "0." ? 17 : 16)) : (m.slice(0,15) + fill("0", m.length - 15));
return m + s.slice(s.indexOf("e"));
}
var n = s.indexOf(".") > -1 ? s.slice(0, (s.slice(0,2) == "0." ? 17 : 16)) : (s.slice(0,15) + fill("0", s.length - 15));
return Number(n);
}
function SSF_parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) {
if(v > 2958465 || v < 0) return null;
v = SSF_normalize_xl_unsafe(v);
var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
var dout=[];
var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
@ -638,7 +650,7 @@ function SSF_write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*
switch(fmt) {
case '[h]': case '[hh]': out = val.D*24+val.H; break;
case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break;
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+(ss0 == 0 ? Math.round(val.S+val.u) : val.S); break;
default: throw 'bad abstime format: ' + fmt;
} outl = fmt.length === 3 ? 1 : 2; break;
case 101: /* 'e' era */
@ -1086,10 +1098,11 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
switch(out[i].t) {
case 'h': case 'H': out[i].t = hr; lst='h'; if(bt < 1) bt = 1; break;
case 's':
if((ssm=out[i].v.match(/\.0+$/))) ss0=Math.max(ss0,ssm[0].length-1);
if((ssm=out[i].v.match(/\.0+$/))) { ss0=Math.max(ss0,ssm[0].length-1); bt = 4;}
if(bt < 3) bt = 3;
/* falls through */
case 'd': case 'y': case 'M': case 'e': lst=out[i].t; break;
case 'd': case 'y': case 'e': lst=out[i].t; break;
case 'M': lst=out[i].t; if(bt < 2) bt = 2; break;
case 'm': if(lst === 's') { out[i].t = 'M'; if(bt < 2) bt = 2; } break;
case 'X': /*if(out[i].v === "B2");*/
break;
@ -1099,19 +1112,29 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
if(bt < 3 && out[i].v.match(/[Ss]/)) bt = 3;
}
}
/* time rounding depends on presence of minute / second / usec fields */
var _dt;
switch(bt) {
case 0: break;
case 1:
/*::if(!dt) break;*/
case 2:
case 3:
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
if(dt.H >= 24) { dt.H = 0; ++dt.D; _dt = SSF_parse_date_code(dt.D); _dt.u = dt.u; _dt.S = dt.S; _dt.M = dt.M; _dt.H = dt.H; dt = _dt; }
break;
case 2:
/*::if(!dt) break;*/
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
case 4:
switch(ss0) {
case 1: dt.u = Math.round(dt.u * 10)/10; break;
case 2: dt.u = Math.round(dt.u * 100)/100; break;
case 3: dt.u = Math.round(dt.u * 1000)/1000; break;
}
if(dt.u >= 1) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
if(dt.H >= 24) { dt.H = 0; ++dt.D; _dt = SSF_parse_date_code(dt.D); _dt.u = dt.u; _dt.S = dt.S; _dt.M = dt.M; _dt.H = dt.H; dt = _dt; }
break;
}
@ -4426,6 +4449,13 @@ function sheet_to_workbook(sheet/*:Worksheet*/, opts)/*:Workbook*/ {
return { SheetNames: [n], Sheets: sheets };
}
function sheet_new(opts) {
var out = {};
var o = opts || {};
if(o.dense) out["!data"] = [];
return out;
}
function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ {
var o = opts || {};
var dense = _ws ? (_ws["!data"] != null) : o.dense;
@ -7987,7 +8017,7 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ {
case 'L': switch(s.trim().toUpperCase()) {
case 'Y': case 'T': out[R][C] = true; break;
case 'N': case 'F': out[R][C] = false; break;
case '': case '?': break;
case '': case '\x00': case '?': break;
default: throw new Error("DBF Unrecognized L:|" + s + "|");
} break;
case 'M': /* TODO: handle memo files */
@ -8049,6 +8079,7 @@ function dbf_to_workbook(buf, opts)/*:Workbook*/ {
var _RLEN = { 'B': 8, 'C': 250, 'L': 1, 'D': 8, '?': 0, '': 0 };
function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) {
if(!ws["!ref"]) throw new Error("Cannot export empty sheet to DBF");
var o = opts || {};
var old_cp = current_codepage;
if(+o.codepage >= 0) set_cp(+o.codepage);
@ -8206,7 +8237,10 @@ var SYLK = /*#__PURE__*/(function() {
"!":161, '"':162, "#":163, "(":164, "%":165, "'":167, "H ":168,
"+":171, ";":187, "<":188, "=":189, ">":190, "?":191, "{":223
}/*:any*/);
var sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1") + "|\\|)", "gm");
var sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1").replace("{", "\\{") + "|\\|)", "gm");
try {
sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1") + "|\\|)", "gm");
} catch(e) {}
var sylk_char_fn = function(_, $1){ var o = sylk_escapes[$1]; return typeof o == "number" ? _getansi(o) : o; };
var decode_sylk_char = function($$, $1, $2) { var newcc = (($1.charCodeAt(0) - 0x20)<<4) | ($2.charCodeAt(0) - 0x30); return newcc == 59 ? $$ : _getansi(newcc); };
sylk_escapes["|"] = 254;
@ -8429,7 +8463,7 @@ var SYLK = /*#__PURE__*/(function() {
if(!opts) opts = {}; opts._formats = ["General"];
/* TODO: codepage */
var preamble/*:Array<string>*/ = ["ID;PSheetJS;N;E"], o/*:Array<string>*/ = [];
var r = safe_decode_range(ws['!ref']), cell/*:Cell*/;
var r = safe_decode_range(ws['!ref']||"A1"), cell/*:Cell*/;
var dense = ws["!data"] != null;
var RS = "\r\n";
var d1904 = (((wb||{}).Workbook||{}).WBProps||{}).date1904;
@ -8438,7 +8472,7 @@ var SYLK = /*#__PURE__*/(function() {
preamble.push("P;PGeneral");
/* Excel has been inconsistent in comment placement */
var R = r.s.r, C = r.s.c, p = [];
for(R = r.s.r; R <= r.e.r; ++R) {
if(ws["!ref"]) for(R = r.s.r; R <= r.e.r; ++R) {
if(dense && !ws["!data"][R]) continue;
p = [];
for(C = r.s.c; C <= r.e.c; ++C) {
@ -8448,7 +8482,7 @@ var SYLK = /*#__PURE__*/(function() {
}
if(p.length) o.push(p.join(RS));
}
for(R = r.s.r; R <= r.e.r; ++R) {
if(ws["!ref"]) for(R = r.s.r; R <= r.e.r; ++R) {
if(dense && !ws["!data"][R]) continue;
p = [];
for(C = r.s.c; C <= r.e.c; ++C) {
@ -8468,7 +8502,7 @@ var SYLK = /*#__PURE__*/(function() {
if(ws['!cols']) write_ws_cols_sylk(preamble, ws['!cols']);
if(ws['!rows']) write_ws_rows_sylk(preamble, ws['!rows']);
preamble.push("B;Y" + (r.e.r - r.s.r + 1) + ";X" + (r.e.c - r.s.c + 1) + ";D" + [r.s.c,r.s.r,r.e.c,r.e.r].join(" "));
if(ws["!ref"]) preamble.push("B;Y" + (r.e.r - r.s.r + 1) + ";X" + (r.e.c - r.s.c + 1) + ";D" + [r.s.c,r.s.r,r.e.c,r.e.r].join(" "));
preamble.push("O;L;D;B" + (d1904 ? ";V4" : "") + ";K47;G100 0.001");
delete opts._formats;
@ -8541,6 +8575,7 @@ var DIF = /*#__PURE__*/(function() {
function make_value_str(s/*:string*/)/*:string*/ { return "1,0\r\n\"" + s.replace(/"/g,'""') + '"'; }
function sheet_to_dif(ws/*:Worksheet*//*::, opts:?any*/)/*:string*/ {
var _DIF_XL = DIF_XL;
if(!ws["!ref"]) throw new Error("Cannot export empty sheet to DIF");
var r = safe_decode_range(ws['!ref']);
var dense = ws["!data"] != null;
var o/*:Array<string>*/ = [
@ -8878,6 +8913,7 @@ var PRN = /*#__PURE__*/(function() {
function sheet_to_prn(ws/*:Worksheet*//*::, opts:?any*/)/*:string*/ {
var o/*:Array<string>*/ = [];
if(!ws["!ref"]) return "";
var r = safe_decode_range(ws['!ref']), cell/*:Cell*/;
var dense = ws["!data"] != null;
for(var R = r.s.r; R <= r.e.r; ++R) {
@ -9102,6 +9138,7 @@ var WK_ = /*#__PURE__*/(function() {
if(+o.codepage >= 0) set_cp(+o.codepage);
if(o.type == "string") throw new Error("Cannot write WK1 to JS string");
var ba = buf_array();
if(!ws["!ref"]) throw new Error("Cannot export empty sheet to WK1");
var range = safe_decode_range(ws["!ref"]);
var dense = ws["!data"] != null;
var cols = [];
@ -9895,13 +9932,25 @@ var WK_ = /*#__PURE__*/(function() {
/*::[*/0x0E/*::*/: "dd-mmm-yyyy",
/*::[*/0x0F/*::*/: "mmm-yyyy",
/*::[*/0x22/*::*/: "0.00",
/*::[*/0x32/*::*/: "0.00;[Red]0.00",
/*::[*/0x42/*::*/: "0.00;\(0.00\)",
/*::[*/0x52/*::*/: "0.00;[Red]\(0.00\)",
/*::[*/162/*::*/: '"$"#,##0;\\("$"#,##0\\)' // slightly different from SSF 5
/* It is suspected that the the low nybble specifies decimal places */
/*::[*/0x0022/*::*/: "0.00",
/*::[*/0x0032/*::*/: "0.00;[Red]0.00",
/*::[*/0x0042/*::*/: "0.00;\(0.00\)",
/*::[*/0x0052/*::*/: "0.00;[Red]\(0.00\)",
/*::[*/0x00A2/*::*/: '"$"#,##0.00;\\("$"#,##0.00\\)',
/*::[*/0x0120/*::*/: '0%',
/*::[*/0x0130/*::*/: '0E+00',
/*::[*/0x0140/*::*/: '# ?/?'
};
function parse_qpw_str(p) {
var cch = p.read_shift(2);
var flags = p.read_shift(1);
/* TODO: find examples with nonzero flags */
if(flags != 0) throw "unsupported QPW string type " + flags.toString(16);
return p.read_shift(cch, "sbcs-cont");
}
/* QPW uses a different set of record types */
function qpw_to_workbook_buf(d, opts)/*:Workbook*/ {
prep_blob(d, 0);
@ -10012,7 +10061,11 @@ var WK_ = /*#__PURE__*/(function() {
case 4: cell = { t: "n", v: parse_RkNumber(p) }; break;
case 5: cell = { t: "n", v: p.read_shift(8, 'f') }; break;
case 7: cell = { t: "s", v: SST[type = p.read_shift(4) - 1] }; break;
case 8: cell = { t: "n", v: p.read_shift(8, 'f') }; p.l += 2; /* cell.f = formulae[p.read_shift(4)]; */ p.l += 4; break;
case 8:
cell = { t: "n", v: p.read_shift(8, 'f') };
p.l += 2; /* cell.f = formulae[p.read_shift(4)]; */ p.l += 4;
if(isNaN(cell.v)) cell = { t: "e", v: 0x0F }; // #VALUE!
break;
default: throw "Unrecognized QPW cell type " + (flags & 0x1F);
}
if(fmtidx != -1 && (FMTS[fmtidx - 1]||{}).z) cell.z = FMTS[fmtidx-1].z;
@ -10058,6 +10111,17 @@ var WK_ = /*#__PURE__*/(function() {
}
} break;
case 0x0C02: { /* String (result of string formula expression) */
C = p.read_shift(2);
R = p.read_shift(4);
var str = parse_qpw_str(p);
/* TODO: QP10 record has an additional unknown character after the string */
if(s["!data"] != null) {
if(!s["!data"][R]) s["!data"][R] = [];
s["!data"][R][C] = { t:"s", v:str };
} else s[encode_col(C) + encode_row(R)] = { t:"s", v:str };
} break;
default: break;
}
d.l += length;
@ -11210,7 +11274,7 @@ function parse_cellXfs(t, styles, opts) {
case '<cellXfs': case '<cellXfs>': case '<cellXfs/>': case '</cellXfs>': break;
/* 18.8.45 xf CT_Xf */
case '<xf': case '<xf/>':
case '<xf': case '<xf/>': case '<xf>':
xf = y;
delete xf[0];
for(i = 0; i < cellXF_uint.length; ++i) if(xf[cellXF_uint[i]])
@ -11224,7 +11288,7 @@ function parse_cellXfs(t, styles, opts) {
case '</xf>': break;
/* 18.8.1 alignment CT_CellAlignment */
case '<alignment': case '<alignment/>':
case '<alignment': case '<alignment/>': case '<alignment>':
var alignment = {};
if(y.vertical) alignment.vertical = y.vertical;
if(y.horizontal) alignment.horizontal = y.horizontal;
@ -11236,12 +11300,12 @@ function parse_cellXfs(t, styles, opts) {
case '</alignment>': break;
/* 18.8.33 protection CT_CellProtection */
case '<protection':
case '<protection': case '<protection>':
break;
case '</protection>': case '<protection/>': break;
/* note: sometimes mc:AlternateContent appears bare */
case '<AlternateContent': pass = true; break;
case '<AlternateContent': case '<AlternateContent>': pass = true; break;
case '</AlternateContent>': pass = false; break;
/* 18.2.10 extLst CT_ExtensionList ? */
@ -12882,7 +12946,10 @@ var rc_to_a1 = /*#__PURE__*/(function(){
};
})();
var crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)(10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})(?![_.\(A-Za-z0-9])/g;
var crefregex = /(^|[^._A-Z0-9])(\$?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])(\$?)(\d{1,7})(?![_.\(A-Za-z0-9])/g;
try {
crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)(10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})(?![_.\(A-Za-z0-9])/g;
}catch(e){}
var a1_to_rc = /*#__PURE__*/(function(){
return function a1_to_rc(fstr/*:string*/, base/*:CellAddress*/) {
return fstr.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
@ -15596,7 +15663,7 @@ function parse_ws_xml_dim(ws/*:Worksheet*/, s/*:string*/) {
var d = safe_decode_range(s);
if(d.s.r<=d.e.r && d.s.c<=d.e.c && d.s.r>=0 && d.s.c>=0) ws["!ref"] = encode_range(d);
}
var mergecregex = /<(?:\w:)?mergeCell ref="[A-Z0-9:]+"\s*[\/]?>/g;
var mergecregex = /<(?:\w:)?mergeCell ref=["'][A-Z0-9:]+['"]\s*[\/]?>/g;
var sheetdataregex = /<(?:\w+:)?sheetData[^>]*>([\s\S]*)<\/(?:\w+:)?sheetData>/;
var hlinkregex = /<(?:\w:)?hyperlink [^>]*>/mg;
var dimregex = /"(\w*:\w*)"/;
@ -22455,9 +22522,9 @@ function sheet_to_html(ws/*:Worksheet*/, opts/*:?Sheet2HTMLOpts*//*, wb:?Workboo
var header = o.header != null ? o.header : HTML_BEGIN;
var footer = o.footer != null ? o.footer : HTML_END;
var out/*:Array<string>*/ = [header];
var r = decode_range(ws['!ref']);
var r = decode_range(ws['!ref'] || "A1");
out.push(make_html_preamble(ws, r, o));
for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
if(ws["!ref"]) for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
out.push("</table>" + footer);
return out.join("");
}
@ -23216,10 +23283,13 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
case 'help-message': break; // 9.4.6 <table:
case 'error-message': break; // 9.4.7 <table:
case 'database-ranges': break; // 9.4.14 <table:database-ranges>
/* 9.5 Filters */
case 'filter': break; // 9.5.2 <table:filter>
case 'filter-and': break; // 9.5.3 <table:filter-and>
case 'filter-or': break; // 9.5.4 <table:filter-or>
case 'filter-condition': break; // 9.5.5 <table:filter-condition>
case 'filter-set-item': break; // 9.5.6 <table:filter-condition>
case 'list-level-style-bullet': break; // 16.31 <text:
case 'list-level-style-number': break; // 16.32 <text:
@ -23736,6 +23806,7 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function
wb.SheetNames.map(function(n) { return wb.Sheets[n]; }).forEach(function(ws) {
if(!ws) return;
var dense = (ws["!data"] != null);
if(!ws["!ref"]) return;
var range = decode_range(ws["!ref"]);
for(var R = 0; R <= range.e.r; ++R) for(var C = 0; C <= range.e.c; ++C) {
var c = dense ? (ws["!data"][R]||[])[C] : ws[encode_cell({r:R,c:C})];
@ -24987,7 +25058,7 @@ function s5s_to_iwa_comment(s5s) {
return out;
}
function parse_TST_TableModelArchive(M, root, ws, opts) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
var pb = parse_shallow(root.data);
var range = { s: { r: 0, c: 0 }, e: { r: 0, c: 0 } };
range.e.r = (varint_to_i32(pb[6][0].data) >>> 0) - 1;
@ -25016,7 +25087,17 @@ function parse_TST_TableModelArchive(M, root, ws, opts) {
lut.nfmt = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[22][0].data)][0]);
var tile = parse_shallow(store[3][0].data);
var _R = 0;
tile[1].forEach(function(t) {
if (!((_h = store[9]) == null ? void 0 : _h[0]))
throw "NUMBERS file missing row tree";
var rtt = parse_shallow(store[9][0].data)[1].map(function(p) {
return parse_shallow(p.data);
});
rtt.forEach(function(kv) {
_R = varint_to_i32(kv[1][0].data);
var tidx = varint_to_i32(kv[2][0].data);
var t = tile[1][tidx];
if (!t)
throw "NUMBERS missing tile " + tidx;
var tl = parse_shallow(t.data);
var ref2 = M[parse_TSP_Reference(tl[2][0].data)][0];
var mtype2 = varint_to_i32(ref2.meta[1][0].data);
@ -25039,12 +25120,12 @@ function parse_TST_TableModelArchive(M, root, ws, opts) {
});
_R += _tile.nrows;
});
if ((_h = store[13]) == null ? void 0 : _h[0]) {
if ((_i = store[13]) == null ? void 0 : _i[0]) {
var ref = M[parse_TSP_Reference(store[13][0].data)][0];
var mtype = varint_to_i32(ref.meta[1][0].data);
if (mtype != 6144)
throw new Error("Expected merge type 6144, found ".concat(mtype));
ws["!merges"] = (_i = parse_shallow(ref.data)) == null ? void 0 : _i[1].map(function(pi) {
ws["!merges"] = (_j = parse_shallow(ref.data)) == null ? void 0 : _j[1].map(function(pi) {
var merge = parse_shallow(pi.data);
var origin = u8_to_dataview(parse_shallow(merge[1][0].data)[1][0].data), size = u8_to_dataview(parse_shallow(merge[2][0].data)[1][0].data);
return {
@ -25706,6 +25787,8 @@ function write_numbers_ws(cfb, deps, ws, wsname, sheetidx, rootref) {
}
var USE_WIDE_ROWS = true;
function write_numbers_tma(cfb, deps, ws, tmaroot, tmafile, tmaref) {
if (!ws["!ref"])
throw new Error("Cannot export empty sheet to NUMBERS");
var range = decode_range(ws["!ref"]);
range.s.r = range.s.c = 0;
var trunc = false;
@ -27151,7 +27234,7 @@ function make_json_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Ar
v = numdate(v); // TODO: date1904 setting should also be stored in worksheet object
if(typeof v == "number") break;
/* falls through */
case 'd': if(!(o && o.UTC)) v = utc_to_local(v); break;
case 'd': if(!(o && (o.UTC||(o.raw === false)))) v = utc_to_local(new Date(v)); break;
default: throw new Error('unrecognized type ' + val.t);
}
if(hdr[C] != null) {
@ -27161,7 +27244,7 @@ function make_json_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Ar
else if(raw && v === null) row[hdr[C]] = null;
else continue;
} else {
row[hdr[C]] = raw && (val.t !== "n" || (val.t === "n" && o.rawNumbers !== false)) ? v : format_cell(val,v,o);
row[hdr[C]] = (val.t === 'n' && typeof o.rawNumbers === 'boolean' ? o.rawNumbers : raw) ? v : format_cell(val, v, o);
}
if(v != null) isempty = false;
}
@ -27419,9 +27502,11 @@ function wb_sheet_idx(wb/*:Workbook*/, sh/*:number|string*/) {
} else throw new Error("Cannot find sheet |" + sh + "|");
}
/* simple blank workbook object */
function book_new()/*:Workbook*/ {
return { SheetNames: [], Sheets: {} };
/* simple blank or single-sheet workbook object */
function book_new(ws/*:?Worksheet*/, wsname/*:?string*/)/*:Workbook*/ {
var wb = { SheetNames: [], Sheets: {} };
if(ws) book_append_sheet(wb, ws, wsname || "Sheet1");
return wb;
}
/* add a worksheet to the end of a given workbook */
@ -27518,6 +27603,7 @@ var utils/*:any*/ = {
decode_cell: decode_cell,
decode_range: decode_range,
format_cell: format_cell,
sheet_new: sheet_new,
sheet_add_aoa: sheet_add_aoa,
sheet_add_json: sheet_add_json,
sheet_add_dom: sheet_add_dom,