forked from sheetjs/sheetjs
		
	version bump 0.20.1
This commit is contained in:
		
							parent
							
								
									9199c2600c
								
							
						
					
					
						commit
						29d46c07a8
					
				
							
								
								
									
										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! | ||||
| 
 | ||||
| [](https://git.sheetjs.com/SheetJS/sheetjs) | ||||
| 
 | ||||
| [](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