forked from sheetjs/sheetjs
Merge branch 'master' into types
This commit is contained in:
commit
c9b78b6563
12
CHANGELOG.md
12
CHANGELOG.md
@ -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)
|
||||
|
7
Makefile
7
Makefile
@ -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
|
||||
|
19
README.md
19
README.md
@ -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
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
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
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
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
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
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
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
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]]));
|
372
packages/dta/dist/dta.js
vendored
372
packages/dta/dist/dta.js
vendored
@ -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
|
||||
});
|
||||
|
2
packages/dta/dist/dta.min.js
vendored
2
packages/dta/dist/dta.min.js
vendored
File diff suppressed because one or more lines are too long
7
packages/dta/dist/dta.min.js.map
vendored
Normal file
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());
|
||||
|
10
packages/dta/types/index.d.ts
vendored
10
packages/dta/types/index.d.ts
vendored
@ -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;
|
||||
|
20
packages/ssf/bits/27_normalize.js
Normal file
20
packages/ssf/bits/27_normalize.js
Normal file
@ -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 */
|
||||
|
38
packages/ssf/test/rounding.js
Normal file
38
packages/ssf/test/rounding.js
Normal file
@ -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("|"));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
BIN
packages/ssf/test/rounding.xlsx
Normal file
BIN
packages/ssf/test/rounding.xlsx
Normal file
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]); });
|
||||
});
|
||||
});
|
||||
|
9
test.js
9
test.js
@ -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
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());
|
||||
});
|
||||
|
28
test.mts
28
test.mts
@ -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
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
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
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");
|
||||
|
28
testnocp.ts
28
testnocp.ts
@ -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
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);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
162
xlsx.flow.js
162
xlsx.flow.js
@ -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
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,
|
||||
|
100
xlsx.mini.js
100
xlsx.mini.js
@ -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
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,
|
||||
|
Loading…
Reference in New Issue
Block a user