diff --git a/bits/47_styxml.js b/bits/47_styxml.js
index 4a671a1..72f20d3 100644
--- a/bits/47_styxml.js
+++ b/bits/47_styxml.js
@@ -163,10 +163,12 @@ function parse_fonts(t, styles, themes, opts) {
/* 18.8.2 b CT_BooleanProperty */
case '': font.bold = 1; break;
+ case '': case '': font.italic = 1; break;
+ case '': case '': font.underline = 1; break;
+ case '': case '': font.strike = 1; break;
+ case '': case '': font.outline = 1; break;
+ case '': case '': font.shadow = 1; break;
+ case '': case '': font.condense = 1; break;
+ case '': case '': font.extend = 1; break;
+ case '': case '': case '': break;
+ case '': case '': case '': case '': break;
+ case '': case '': case '': case '': break;
+ case '': case '': case '': case '': break;
+ case '': case '': case '': case '': break;
+ case '': case '': case '': case '': break;
+ case '': case '': case '': pass = false; break;
+ case '': case '': case '': break;
diff --git a/bits/80_parseods.js b/bits/80_parseods.js
index 688f315..769d88e 100644
--- a/bits/80_parseods.js
+++ b/bits/80_parseods.js
@@ -306,10 +306,18 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
if(rowpeat < 10) for(i = 0; i < rowpeat; ++i) if(row_ol > 0) rowinfo[R + i] = {level: row_ol};
C = -1; break;
case 'covered-table-cell': // 9.1.5
- if(Rn[1] !== '/') ++C;
- if(opts.sheetStubs) {
- if(opts.dense) { if(!ws["!data"][R]) ws["!data"][R] = []; ws["!data"][R][C] = {t:'z'}; }
- else ws[encode_cell({r:R,c:C})] = {t:'z'};
+ if(Rn[1] !== '/') {
+ ++C;
+ ctag = parsexmltag(Rn[0], false);
+ colpeat = parseInt(ctag['number-columns-repeated']||"1",10) || 1;
+ if(opts.sheetStubs) {
+ while(colpeat-- > 0) {
+ if(opts.dense) { if(!ws["!data"][R]) ws["!data"][R] = []; ws["!data"][R][C] = {t:'z'}; }
+ else ws[encode_cell({r:R,c:C})] = {t:'z'};
+ ++C;
+ } --C;
+ }
+ else C += colpeat - 1;
}
textp = ""; textR = [];
break; /* stub */
@@ -317,7 +325,7 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
if(Rn[0].charAt(Rn[0].length-2) === '/') {
++C;
ctag = parsexmltag(Rn[0], false);
- colpeat = parseInt(ctag['number-columns-repeated']||"1", 10);
+ colpeat = parseInt(ctag['number-columns-repeated']||"1", 10)||1;
q = ({t:'z', v:null/*:: , z:null, w:"",c:[]*/}/*:any*/);
if(ctag.formula && opts.cellFormula != false) q.f = ods_to_csf_formula(unescapexml(ctag.formula));
if(ctag["style-name"] && styles[ctag["style-name"]]) q.z = styles[ctag["style-name"]];
@@ -361,10 +369,12 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
q.F = arrayf[i][1];
}
if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
- mR = parseInt(ctag['number-rows-spanned'],10) || 0;
- mC = parseInt(ctag['number-columns-spanned'],10) || 0;
- mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
- merges.push(mrange);
+ mR = parseInt(ctag['number-rows-spanned']||"1",10) || 1;
+ mC = parseInt(ctag['number-columns-spanned']||"1",10) || 1;
+ if(mR * mC > 1) {
+ mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
+ merges.push(mrange);
+ }
}
/* 19.675.2 table:number-columns-repeated */
@@ -796,4 +806,3 @@ function parse_fods(data/*:string*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
wb.bookType = "fods";
return wb;
}
-
diff --git a/bits/83_numbers.js b/bits/83_numbers.js
index fc7b32c..e29f95e 100644
--- a/bits/83_numbers.js
+++ b/bits/83_numbers.js
@@ -1117,7 +1117,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, _j;
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
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;
@@ -1196,6 +1196,38 @@ function parse_TST_TableModelArchive(M, root, ws, opts) {
};
});
}
+ if ((_k = pb[47]) == null ? void 0 : _k[0]) {
+ var merge_owner = parse_shallow(pb[47][0].data);
+ if ((_l = merge_owner[2]) == null ? void 0 : _l[0]) {
+ var formula_store = parse_shallow(merge_owner[2][0].data);
+ if (((_m = formula_store[3]) == null ? void 0 : _m[0]) && !ws["!merges"]) {
+ ws["!merges"] = mappa(formula_store[3], function(u) {
+ var _a2, _b2, _c2, _d2, _e2;
+ var formula_pair = parse_shallow(u);
+ var formula = parse_shallow(formula_pair[2][0].data);
+ var AST_node_array = parse_shallow(formula[1][0].data);
+ if (!((_a2 = AST_node_array[1]) == null ? void 0 : _a2[0]))
+ return;
+ var AST_node0 = parse_shallow(AST_node_array[1][0].data);
+ var AST_node_type = varint_to_i32(AST_node0[1][0].data);
+ if (AST_node_type != 67)
+ return;
+ var AST_colon_tract = parse_shallow(AST_node0[40][0].data);
+ if (!((_b2 = AST_colon_tract[3]) == null ? void 0 : _b2[0]) || !((_c2 = AST_colon_tract[4]) == null ? void 0 : _c2[0]))
+ return;
+ var colrange = parse_shallow(AST_colon_tract[3][0].data);
+ var rowrange = parse_shallow(AST_colon_tract[4][0].data);
+ var c = varint_to_i32(colrange[1][0].data);
+ var C = ((_d2 = colrange[2]) == null ? void 0 : _d2[0]) ? varint_to_i32(colrange[2][0].data) : c;
+ var r = varint_to_i32(rowrange[1][0].data);
+ var R = ((_e2 = rowrange[2]) == null ? void 0 : _e2[0]) ? varint_to_i32(rowrange[2][0].data) : r;
+ return { s: { r: r, c: c }, e: { r: R, c: C } };
+ }).filter(function(x) {
+ return x != null;
+ });
+ }
+ }
+ }
}
function parse_TST_TableInfoArchive(M, root, opts) {
var pb = parse_shallow(root.data);
diff --git a/modules/83_numbers.js b/modules/83_numbers.js
index fc7b32c..e29f95e 100644
--- a/modules/83_numbers.js
+++ b/modules/83_numbers.js
@@ -1117,7 +1117,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, _j;
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
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;
@@ -1196,6 +1196,38 @@ function parse_TST_TableModelArchive(M, root, ws, opts) {
};
});
}
+ if ((_k = pb[47]) == null ? void 0 : _k[0]) {
+ var merge_owner = parse_shallow(pb[47][0].data);
+ if ((_l = merge_owner[2]) == null ? void 0 : _l[0]) {
+ var formula_store = parse_shallow(merge_owner[2][0].data);
+ if (((_m = formula_store[3]) == null ? void 0 : _m[0]) && !ws["!merges"]) {
+ ws["!merges"] = mappa(formula_store[3], function(u) {
+ var _a2, _b2, _c2, _d2, _e2;
+ var formula_pair = parse_shallow(u);
+ var formula = parse_shallow(formula_pair[2][0].data);
+ var AST_node_array = parse_shallow(formula[1][0].data);
+ if (!((_a2 = AST_node_array[1]) == null ? void 0 : _a2[0]))
+ return;
+ var AST_node0 = parse_shallow(AST_node_array[1][0].data);
+ var AST_node_type = varint_to_i32(AST_node0[1][0].data);
+ if (AST_node_type != 67)
+ return;
+ var AST_colon_tract = parse_shallow(AST_node0[40][0].data);
+ if (!((_b2 = AST_colon_tract[3]) == null ? void 0 : _b2[0]) || !((_c2 = AST_colon_tract[4]) == null ? void 0 : _c2[0]))
+ return;
+ var colrange = parse_shallow(AST_colon_tract[3][0].data);
+ var rowrange = parse_shallow(AST_colon_tract[4][0].data);
+ var c = varint_to_i32(colrange[1][0].data);
+ var C = ((_d2 = colrange[2]) == null ? void 0 : _d2[0]) ? varint_to_i32(colrange[2][0].data) : c;
+ var r = varint_to_i32(rowrange[1][0].data);
+ var R = ((_e2 = rowrange[2]) == null ? void 0 : _e2[0]) ? varint_to_i32(rowrange[2][0].data) : r;
+ return { s: { r: r, c: c }, e: { r: R, c: C } };
+ }).filter(function(x) {
+ return x != null;
+ });
+ }
+ }
+ }
}
function parse_TST_TableInfoArchive(M, root, opts) {
var pb = parse_shallow(root.data);
diff --git a/modules/83_numbers.ts b/modules/83_numbers.ts
index 7de5520..188a4e0 100644
--- a/modules/83_numbers.ts
+++ b/modules/83_numbers.ts
@@ -960,6 +960,7 @@ function parse_TST_TableModelArchive(M: MessageSpace, root: IWAMessage, ws: Work
_R += _tile.nrows;
});
+ /* old-style merges */
if(store[13]?.[0]) {
var ref = M[parse_TSP_Reference(store[13][0].data)][0];
var mtype = varint_to_i32(ref.meta[1][0].data);
@@ -976,6 +977,50 @@ function parse_TST_TableModelArchive(M: MessageSpace, root: IWAMessage, ws: Work
};
});
}
+
+ /* new-style merges */
+ if(!ws["!merges"]?.length && pb[47]?.[0]) {
+ // .TST.MergeOwnerArchive
+ var merge_owner = parse_shallow(pb[47][0].data);
+ if(merge_owner[2]?.[0]) {
+ // .TST.FormulaStoreArchive
+ var formula_store = parse_shallow(merge_owner[2][0].data);
+ if(formula_store[3]?.[0]) {
+ ws["!merges"] = mappa(formula_store[3], (u) => {
+ var formula_pair = parse_shallow(u);
+
+ /* TODO: this should eventually use a proper formula parser */
+ // .TSCE.FormulaArchive
+ var formula = parse_shallow(formula_pair[2][0].data);
+
+ // .TSCE.ASTNodeArrayArchive
+ var AST_node_array = parse_shallow(formula[1][0].data);
+
+ // .TSCE.ASTNodeArrayArchive.ASTNodeArchive
+ if(!AST_node_array[1]?.[0]) return;
+ var AST_node0 = parse_shallow(AST_node_array[1][0].data);
+
+ // .TSCE.ASTNodeArrayArchive.ASTNodeType
+ var AST_node_type = varint_to_i32(AST_node0[1][0].data);
+ if(AST_node_type != 67) return; // COLON_TRACT_NODE
+
+ // .TSCE.ASTNodeArrayArchive.ASTColonTractArchive
+ var AST_colon_tract = parse_shallow(AST_node0[40][0].data);
+ if(!AST_colon_tract[3]?.[0] || !AST_colon_tract[4]?.[0]) return;
+
+ // ASTColonTractAbsoluteRangeArchive
+ var colrange = parse_shallow(AST_colon_tract[3][0].data);
+ var rowrange = parse_shallow(AST_colon_tract[4][0].data);
+ var c = varint_to_i32(colrange[1][0].data);
+ var C = colrange[2]?.[0] ? varint_to_i32(colrange[2][0].data) : c;
+ var r = varint_to_i32(rowrange[1][0].data);
+ var R = rowrange[2]?.[0] ? varint_to_i32(rowrange[2][0].data) : r;
+ return { s: { r, c }, e: { r: R, c: C }} as Range;
+ }).filter(x => x != null) as Range[];
+ // .TST.FormulaStoreArchive.FormulaStorePair
+ }
+ }
+ }
}
/** Parse .TST.TableInfoArchive (6000) */
diff --git a/test.mts b/test.mts
index de7c6e3..d6b596c 100644
--- a/test.mts
+++ b/test.mts
@@ -1851,9 +1851,9 @@ describe('roundtrip features', function() {
assert.ok(wb7.Workbook?.WBProps?.date1904);
}); });
- it('should handle numeric NaN and Infinity', function() {[
+ it('should handle numeric NaN and Infinity', function() {([
"xlsx", "xlsm", "xlsb", "xls", "biff5", "biff4", "biff3", "biff2", "xlml", "csv", "txt", "sylk", "html", "rtf", "prn", "eth", "ods", "fods"
- ].forEach(function(ext) {
+ ] as Array).forEach(function(ext) {
var ws: X.DenseWorkSheet = {
"!data": [
[ { t: "s", v: "Inf+" }, { t: "n", v: Infinity } ],
@@ -2630,7 +2630,7 @@ describe('HTML', function() {
});
});
if(domtest) it('should handle numeric NaN and Infinity', function() {
- var ws = {
+ var ws: X.DenseWorkSheet = {
"!data": [
[ { t: "s", v: "Inf+" }, { t: "n", v: Infinity } ],
[ { t: "s", v: "Inf-" }, { t: "n", v: -Infinity } ],
@@ -2717,14 +2717,14 @@ describe('dense mode', function() {
it('read', function() {
ILPaths.forEach(function(p) {
var wb = X.read(fs.readFileSync(p), {type: TYPE, WTF: true});
- var ws = wb.Sheets[wb.SheetNames[0]];
+ var ws: X.WorkSheet = wb.Sheets[wb.SheetNames[0]];
assert.equal(ws["A1"].v, "Link to Sheet2");
assert.ok(!ws["!data"]);
wb = X.read(fs.readFileSync(p), {type: TYPE, WTF: true, dense: true});
ws = wb.Sheets[wb.SheetNames[0]];
assert.ok(!ws["A1"]);
- assert.equal(ws["!data"][0][0].v, "Link to Sheet2");
+ assert.equal(ws["!data"]?.[0][0].v, "Link to Sheet2");
});
if(!browser) artifax.forEach(function(p) {
var wb = X.read(fs.readFileSync(p), {type: TYPE, WTF: true});
@@ -2735,7 +2735,8 @@ describe('dense mode', function() {
wb = X.read(fs.readFileSync(p), {type: TYPE, WTF: true, dense: true});
ws = wb.Sheets[wb.SheetNames[0]];
assert.ok(!ws["A1"]);
- assert.ok(ws["!data"][0][0]);
+ assert.ok(!!ws["!data"]);
+ assert.ok(ws["!data"]?.[0][0]);
});
});
it('aoa_to_sheet', function() {
@@ -2743,28 +2744,28 @@ describe('dense mode', function() {
var sp = X.utils.aoa_to_sheet(aoa); assert.equal(sp["A2"].v, 5433795); assert.ok(!sp["!data"]);
sp = X.utils.aoa_to_sheet(aoa, {}); assert.equal(sp["A2"].v, 5433795); assert.ok(!sp["!data"]);
sp = X.utils.aoa_to_sheet(aoa, {dense: false}); assert.equal(sp["A2"].v, 5433795); assert.ok(!sp["!data"]);
- var ds = X.utils.aoa_to_sheet(aoa, {dense: true}); assert.equal(ds["!data"][1][0].v, 5433795); assert.ok(!ds["A2"]);
+ var ds = X.utils.aoa_to_sheet(aoa, {dense: true}); assert.equal(ds["!data"]?.[1][0].v, 5433795); assert.ok(!ds["A2"]);
});
it('json_to_sheet', function() {
var json = [{"SheetJS": 5433795}];
var sp = X.utils.json_to_sheet(json); assert.equal(sp["A2"].v, 5433795); assert.ok(!sp["!data"]);
sp = X.utils.json_to_sheet(json, {}); assert.equal(sp["A2"].v, 5433795); assert.ok(!sp["!data"]);
sp = X.utils.json_to_sheet(json, {dense: false}); assert.equal(sp["A2"].v, 5433795); assert.ok(!sp["!data"]);
- var ds = X.utils.json_to_sheet(json, {dense: true}); assert.equal(ds["!data"][1][0].v, 5433795); assert.ok(!ds["A2"]);
+ var ds = X.utils.json_to_sheet(json, {dense: true}); assert.equal(ds["!data"]?.[1][0].v, 5433795); assert.ok(!ds["A2"]);
});
it('sheet_add_aoa', function() {
var aoa = [["SheetJS"]];
var sp = X.utils.aoa_to_sheet(aoa); X.utils.sheet_add_aoa(sp, [[5433795]], {origin:-1}); assert.equal(sp["A2"].v, 5433795); assert.ok(!sp["!data"]);
sp = X.utils.aoa_to_sheet(aoa); X.utils.sheet_add_aoa(sp, [[5433795]], {origin:-1, dense: true}); assert.equal(sp["A2"].v, 5433795); assert.ok(!sp["!data"]);
- var ds = X.utils.aoa_to_sheet(aoa, {dense: true}); X.utils.sheet_add_aoa(ds, [[5433795]], {origin:-1}); assert.equal(ds["!data"][1][0].v, 5433795); assert.ok(!ds["A2"]);
- ds = X.utils.aoa_to_sheet(aoa, {dense: true}); X.utils.sheet_add_aoa(ds, [[5433795]], {origin:-1, dense: true}); assert.equal(ds["!data"][1][0].v, 5433795); assert.ok(!ds["A2"]);
+ var ds:X.WorkSheet = X.utils.aoa_to_sheet(aoa, {dense: true}); X.utils.sheet_add_aoa(ds, [[5433795]], {origin:-1}); assert.equal(ds["!data"]?.[1][0].v, 5433795); assert.ok(!ds["A2"]);
+ ds = X.utils.aoa_to_sheet(aoa, {dense: true}); X.utils.sheet_add_aoa(ds, [[5433795]], {origin:-1, dense: true}); assert.equal(ds["!data"]?.[1][0].v, 5433795); assert.ok(!ds["A2"]);
});
it('sheet_add_json', function() {
var aoa = [["SheetJS"]];
- var sp: X.SparseSheet = X.utils.aoa_to_sheet(aoa); X.utils.sheet_add_json(sp, [{X:5433795}], {origin:-1, skipHeader:1}); assert.equal(sp["A2"].v, 5433795); assert.ok(!sp["!data"]);
- sp = X.utils.aoa_to_sheet(aoa); X.utils.sheet_add_json(sp, [{X:5433795}], {origin:-1, skipHeader: 1, dense: true}); assert.equal(sp["A2"].v, 5433795); assert.ok(!sp["!data"]);
- var ds = X.utils.aoa_to_sheet(aoa, {dense: true}); X.utils.sheet_add_json(ds, [{X:5433795}], {origin:-1, skipHeader: 1}); assert.equal(ds["!data"]?.[1][0].v, 5433795); assert.ok(!ds["A2"]);
- ds = X.utils.aoa_to_sheet(aoa, {dense: true}); X.utils.sheet_add_json(ds, [{X:5433795}], {origin:-1, skipHeader: 1, dense: true}); assert.equal(ds["!data"]?.[1][0].v, 5433795); assert.ok(!ds["A2"]);
+ var sp = X.utils.aoa_to_sheet(aoa); X.utils.sheet_add_json(sp, [{X:5433795}], {origin:-1, skipHeader:true}); assert.equal(sp["A2"].v, 5433795); assert.ok(!sp["!data"]);
+ sp = X.utils.aoa_to_sheet(aoa); X.utils.sheet_add_json(sp, [{X:5433795}], {origin:-1, skipHeader: true, dense: true}); assert.equal(sp["A2"].v, 5433795); assert.ok(!sp["!data"]);
+ var ds:X.WorkSheet = X.utils.aoa_to_sheet(aoa, {dense: true}); X.utils.sheet_add_json(ds, [{X:5433795}], {origin:-1, skipHeader: true}); assert.equal(ds["!data"]?.[1][0].v, 5433795); assert.ok(!ds["A2"]);
+ ds = X.utils.aoa_to_sheet(aoa, {dense: true}); X.utils.sheet_add_json(ds, [{X:5433795}], {origin:-1, skipHeader: true, dense: true}); assert.equal(ds["!data"]?.[1][0].v, 5433795); assert.ok(!ds["A2"]);
});
for(var ofmti = 0; ofmti < ofmt.length; ++ofmti) { var f = ofmt[ofmti];
it('write ' + f, function() {
diff --git a/test.ts b/test.ts
index 9447f9f..22ba8c9 100644
--- a/test.ts
+++ b/test.ts
@@ -1851,9 +1851,9 @@ Deno.test('roundtrip features', async function(t) {
assert.assert(wb7.Workbook?.WBProps?.date1904);
}); });
- await t.step('should handle numeric NaN and Infinity', async function(t) {[
+ await t.step('should handle numeric NaN and Infinity', async function(t) {([
"xlsx", "xlsm", "xlsb", "xls", "biff5", "biff4", "biff3", "biff2", "xlml", "csv", "txt", "sylk", "html", "rtf", "prn", "eth", "ods", "fods"
- ].forEach(function(ext) {
+ ] as Array).forEach(function(ext) {
var ws: X.DenseWorkSheet = {
"!data": [
[ { t: "s", v: "Inf+" }, { t: "n", v: Infinity } ],
@@ -2630,7 +2630,7 @@ Deno.test('HTML', async function(t) {
});
});
if(domtest) await t.step('should handle numeric NaN and Infinity', async function(t) {
- var ws = {
+ var ws: X.DenseWorkSheet = {
"!data": [
[ { t: "s", v: "Inf+" }, { t: "n", v: Infinity } ],
[ { t: "s", v: "Inf-" }, { t: "n", v: -Infinity } ],
@@ -2717,14 +2717,14 @@ Deno.test('dense mode', async function(t) {
await t.step('read', async function(t) {
ILPaths.forEach(function(p) {
var wb = X.read(fs.readFileSync(p), {type: TYPE, WTF: true});
- var ws = wb.Sheets[wb.SheetNames[0]];
+ var ws: X.WorkSheet = wb.Sheets[wb.SheetNames[0]];
assert.equal(ws["A1"].v, "Link to Sheet2");
assert.assert(!ws["!data"]);
wb = X.read(fs.readFileSync(p), {type: TYPE, WTF: true, dense: true});
ws = wb.Sheets[wb.SheetNames[0]];
assert.assert(!ws["A1"]);
- assert.equal(ws["!data"][0][0].v, "Link to Sheet2");
+ assert.equal(ws["!data"]?.[0][0].v, "Link to Sheet2");
});
if(!browser) artifax.forEach(function(p) {
var wb = X.read(fs.readFileSync(p), {type: TYPE, WTF: true});
@@ -2735,7 +2735,8 @@ Deno.test('dense mode', async function(t) {
wb = X.read(fs.readFileSync(p), {type: TYPE, WTF: true, dense: true});
ws = wb.Sheets[wb.SheetNames[0]];
assert.assert(!ws["A1"]);
- assert.assert(ws["!data"][0][0]);
+ assert.assert(!!ws["!data"]);
+ assert.assert(ws["!data"]?.[0][0]);
});
});
await t.step('aoa_to_sheet', async function(t) {
@@ -2743,28 +2744,28 @@ Deno.test('dense mode', async function(t) {
var sp = X.utils.aoa_to_sheet(aoa); assert.equal(sp["A2"].v, 5433795); assert.assert(!sp["!data"]);
sp = X.utils.aoa_to_sheet(aoa, {}); assert.equal(sp["A2"].v, 5433795); assert.assert(!sp["!data"]);
sp = X.utils.aoa_to_sheet(aoa, {dense: false}); assert.equal(sp["A2"].v, 5433795); assert.assert(!sp["!data"]);
- var ds = X.utils.aoa_to_sheet(aoa, {dense: true}); assert.equal(ds["!data"][1][0].v, 5433795); assert.assert(!ds["A2"]);
+ var ds = X.utils.aoa_to_sheet(aoa, {dense: true}); assert.equal(ds["!data"]?.[1][0].v, 5433795); assert.assert(!ds["A2"]);
});
await t.step('json_to_sheet', async function(t) {
var json = [{"SheetJS": 5433795}];
var sp = X.utils.json_to_sheet(json); assert.equal(sp["A2"].v, 5433795); assert.assert(!sp["!data"]);
sp = X.utils.json_to_sheet(json, {}); assert.equal(sp["A2"].v, 5433795); assert.assert(!sp["!data"]);
sp = X.utils.json_to_sheet(json, {dense: false}); assert.equal(sp["A2"].v, 5433795); assert.assert(!sp["!data"]);
- var ds = X.utils.json_to_sheet(json, {dense: true}); assert.equal(ds["!data"][1][0].v, 5433795); assert.assert(!ds["A2"]);
+ var ds = X.utils.json_to_sheet(json, {dense: true}); assert.equal(ds["!data"]?.[1][0].v, 5433795); assert.assert(!ds["A2"]);
});
await t.step('sheet_add_aoa', async function(t) {
var aoa = [["SheetJS"]];
var sp = X.utils.aoa_to_sheet(aoa); X.utils.sheet_add_aoa(sp, [[5433795]], {origin:-1}); assert.equal(sp["A2"].v, 5433795); assert.assert(!sp["!data"]);
sp = X.utils.aoa_to_sheet(aoa); X.utils.sheet_add_aoa(sp, [[5433795]], {origin:-1, dense: true}); assert.equal(sp["A2"].v, 5433795); assert.assert(!sp["!data"]);
- var ds = X.utils.aoa_to_sheet(aoa, {dense: true}); X.utils.sheet_add_aoa(ds, [[5433795]], {origin:-1}); assert.equal(ds["!data"][1][0].v, 5433795); assert.assert(!ds["A2"]);
- ds = X.utils.aoa_to_sheet(aoa, {dense: true}); X.utils.sheet_add_aoa(ds, [[5433795]], {origin:-1, dense: true}); assert.equal(ds["!data"][1][0].v, 5433795); assert.assert(!ds["A2"]);
+ var ds:X.WorkSheet = X.utils.aoa_to_sheet(aoa, {dense: true}); X.utils.sheet_add_aoa(ds, [[5433795]], {origin:-1}); assert.equal(ds["!data"]?.[1][0].v, 5433795); assert.assert(!ds["A2"]);
+ ds = X.utils.aoa_to_sheet(aoa, {dense: true}); X.utils.sheet_add_aoa(ds, [[5433795]], {origin:-1, dense: true}); assert.equal(ds["!data"]?.[1][0].v, 5433795); assert.assert(!ds["A2"]);
});
await t.step('sheet_add_json', async function(t) {
var aoa = [["SheetJS"]];
- var sp: X.SparseSheet = X.utils.aoa_to_sheet(aoa); X.utils.sheet_add_json(sp, [{X:5433795}], {origin:-1, skipHeader:1}); assert.equal(sp["A2"].v, 5433795); assert.assert(!sp["!data"]);
- sp = X.utils.aoa_to_sheet(aoa); X.utils.sheet_add_json(sp, [{X:5433795}], {origin:-1, skipHeader: 1, dense: true}); assert.equal(sp["A2"].v, 5433795); assert.assert(!sp["!data"]);
- var ds = X.utils.aoa_to_sheet(aoa, {dense: true}); X.utils.sheet_add_json(ds, [{X:5433795}], {origin:-1, skipHeader: 1}); assert.equal(ds["!data"]?.[1][0].v, 5433795); assert.assert(!ds["A2"]);
- ds = X.utils.aoa_to_sheet(aoa, {dense: true}); X.utils.sheet_add_json(ds, [{X:5433795}], {origin:-1, skipHeader: 1, dense: true}); assert.equal(ds["!data"]?.[1][0].v, 5433795); assert.assert(!ds["A2"]);
+ var sp = X.utils.aoa_to_sheet(aoa); X.utils.sheet_add_json(sp, [{X:5433795}], {origin:-1, skipHeader:true}); assert.equal(sp["A2"].v, 5433795); assert.assert(!sp["!data"]);
+ sp = X.utils.aoa_to_sheet(aoa); X.utils.sheet_add_json(sp, [{X:5433795}], {origin:-1, skipHeader: true, dense: true}); assert.equal(sp["A2"].v, 5433795); assert.assert(!sp["!data"]);
+ var ds:X.WorkSheet = X.utils.aoa_to_sheet(aoa, {dense: true}); X.utils.sheet_add_json(ds, [{X:5433795}], {origin:-1, skipHeader: true}); assert.equal(ds["!data"]?.[1][0].v, 5433795); assert.assert(!ds["A2"]);
+ ds = X.utils.aoa_to_sheet(aoa, {dense: true}); X.utils.sheet_add_json(ds, [{X:5433795}], {origin:-1, skipHeader: true, dense: true}); assert.equal(ds["!data"]?.[1][0].v, 5433795); assert.assert(!ds["A2"]);
});
for(var ofmti = 0; ofmti < ofmt.length; ++ofmti) { var f = ofmt[ofmti];
await t.step('write ' + f, async function(t) {
diff --git a/testnocp.ts b/testnocp.ts
index d494d19..a0f364e 100644
--- a/testnocp.ts
+++ b/testnocp.ts
@@ -387,9 +387,9 @@ Deno.test('should parse test files', async function(t) {
});
function get_cell(ws: X.WorkSheet, addr: string) {
- if(!Array.isArray(ws)) return ws[addr];
+ if(!Array.isArray(ws["!data"])) return ws[addr];
var a = X.utils.decode_cell(addr);
- return (ws[a.r]||[])[a.c];
+ return (ws["!data"][a.r]||[])[a.c];
}
function each_cell(ws: X.WorkSheet, f: (c: X.CellObject) => any) {
@@ -1034,6 +1034,8 @@ Deno.test('parse features', async function(t) {
var wbs: X.WorkBook[] = [], wbs_no_slk: X.WorkBook[] = [];
wbs = CWPaths.map(function(n) { return X.read(fs.readFileSync(n), {type:TYPE, cellStyles:true}); });
wbs_no_slk = wbs.slice(0, 5);
+ /* */
+ var ols = OLPaths.map(function(p) { return X.read(fs.readFileSync(p), {type:TYPE, cellStyles:true}); });
await t.step('should have "!cols"', async function(t) {
wbs.forEach(function(wb) { assert.assert(wb.Sheets["Sheet1"]['!cols']); });
});
@@ -1065,6 +1067,22 @@ Deno.test('parse features', async function(t) {
assert.equal(x?.[7].wpx, 101);
});
});
+ await t.step('should have correct outline levels', async function(t) {
+ ols.map(function(x) { return x.Sheets["Sheet1"]; }).forEach(function(ws) {
+ var cols = ws['!cols'];
+ if(!cols) return; // TODO: ODS!!!
+ for(var i = 0; i < 29; ++i) {
+ var cell = get_cell(ws, X.utils.encode_col(i) + "1");
+ var lvl = (cols[i]||{}).level||0;
+ if(!cell || cell.t == 's') assert.equal(lvl, 0);
+ else if(cell.t == 'n') {
+ if(cell.v === 0) assert.equal(lvl, 0);
+ else assert.equal(lvl, cell.v);
+ }
+ }
+ assert.equal(cols[29].level, 7);
+ });
+ });
});
await t.step('row properties', async function(t) {
@@ -1832,6 +1850,32 @@ Deno.test('roundtrip features', async function(t) {
assert.assert(wb7.Workbook?.WBProps?.date1904);
}); });
+ await t.step('should handle numeric NaN and Infinity', async function(t) {([
+ "xlsx", "xlsm", "xlsb", "xls", "biff5", "biff4", "biff3", "biff2", "xlml", "csv", "txt", "sylk", "html", "rtf", "prn", "eth", "ods", "fods"
+ ] as Array).forEach(function(ext) {
+ var ws: X.DenseWorkSheet = {
+ "!data": [
+ [ { t: "s", v: "Inf+" }, { t: "n", v: Infinity } ],
+ [ { t: "s", v: "Inf-" }, { t: "n", v: -Infinity } ],
+ [ { t: "s", v: "NaN" }, { t: "n", v: NaN } ],
+ ],
+ "!ref": "A1:B3"
+ };
+ var wb = X.utils.book_new(ws, "Sheet1");
+ var buf = X.write(wb, { type: TYPE, bookType: ext, numbers: XLSX_ZAHL });
+ var wb2 = X.read(buf, { type: TYPE, PRN: true });
+ var csv = X.utils.sheet_to_csv(wb2.Sheets.Sheet1).split(/[\r\n]+/);
+ assert.equal(csv.length, 3);
+ assert.equal(csv[0], "Inf+,#DIV/0!");
+ assert.equal(csv[1], "Inf-,#DIV/0!");
+ assert.equal(csv[2], "NaN,#NUM!");
+ assert.equal(wb2.Sheets.Sheet1.B1.t, "e");
+ assert.equal(wb2.Sheets.Sheet1.B2.t, "e");
+ assert.equal(wb2.Sheets.Sheet1.B3.t, "e");
+ assert.equal(wb2.Sheets.Sheet1.B1.v, 0x07);
+ assert.equal(wb2.Sheets.Sheet1.B2.v, 0x07);
+ assert.equal(wb2.Sheets.Sheet1.B3.v, 0x24);
+ }); });
});
//function password_file(x){return x.match(/^password.*\.xls$/); }
@@ -2584,6 +2628,30 @@ Deno.test('HTML', async function(t) {
assert.equal(range.e.c, expectedCellCount - 1);
});
});
+ if(domtest) await t.step('should handle numeric NaN and Infinity', async function(t) {
+ var ws: X.DenseWorkSheet = {
+ "!data": [
+ [ { t: "s", v: "Inf+" }, { t: "n", v: Infinity } ],
+ [ { t: "s", v: "Inf-" }, { t: "n", v: -Infinity } ],
+ [ { t: "s", v: "NaN" }, { t: "n", v: NaN } ],
+ ],
+ "!ref": "A1:B3"
+ };
+ var wb = X.utils.book_new(ws, "Sheet1");
+ var str = X.write(wb, { type: "string", bookType: "html" });
+ var wb2 = X.utils.table_to_book(get_dom_element(str));
+ var csv = X.utils.sheet_to_csv(wb2.Sheets.Sheet1).split(/[\r\n]+/);
+ assert.equal(csv.length, 3);
+ assert.equal(csv[0], "Inf+,#DIV/0!");
+ assert.equal(csv[1], "Inf-,#DIV/0!");
+ assert.equal(csv[2], "NaN,#NUM!");
+ assert.equal(wb2.Sheets.Sheet1.B1.t, "e");
+ assert.equal(wb2.Sheets.Sheet1.B2.t, "e");
+ assert.equal(wb2.Sheets.Sheet1.B3.t, "e");
+ assert.equal(wb2.Sheets.Sheet1.B1.v, 0x07);
+ assert.equal(wb2.Sheets.Sheet1.B2.v, 0x07);
+ assert.equal(wb2.Sheets.Sheet1.B3.v, 0x24);
+ });
});
Deno.test('js -> file -> js', async function(t) {
@@ -2637,6 +2705,99 @@ Deno.test('rtf', async function(t) {
});
});
+Deno.test('dense mode', async function(t) {
+ await t.step('sheet_new', async function(t) {
+ var sp = X.utils.sheet_new(); assert.assert(!sp["!data"]);
+ sp = X.utils.sheet_new({}); assert.assert(!sp["!data"]);
+ sp = X.utils.sheet_new({dense: false}); assert.assert(!sp["!data"]);
+ sp = X.utils.sheet_new({dense: true}); assert.assert(!!sp["!data"]);
+ });
+
+ await t.step('read', async function(t) {
+ ILPaths.forEach(function(p) {
+ var wb = X.read(fs.readFileSync(p), {type: TYPE, WTF: true});
+ var ws: X.WorkSheet = wb.Sheets[wb.SheetNames[0]];
+ assert.equal(ws["A1"].v, "Link to Sheet2");
+ assert.assert(!ws["!data"]);
+
+ wb = X.read(fs.readFileSync(p), {type: TYPE, WTF: true, dense: true});
+ ws = wb.Sheets[wb.SheetNames[0]];
+ assert.assert(!ws["A1"]);
+ assert.equal(ws["!data"]?.[0][0].v, "Link to Sheet2");
+ });
+ if(!browser) artifax.forEach(function(p) {
+ var wb = X.read(fs.readFileSync(p), {type: TYPE, WTF: true});
+ var ws = wb.Sheets[wb.SheetNames[0]];
+ assert.assert(ws["A1"]);
+ assert.assert(!ws["!data"]);
+
+ wb = X.read(fs.readFileSync(p), {type: TYPE, WTF: true, dense: true});
+ ws = wb.Sheets[wb.SheetNames[0]];
+ assert.assert(!ws["A1"]);
+ assert.assert(!!ws["!data"]);
+ assert.assert(ws["!data"]?.[0][0]);
+ });
+ });
+ await t.step('aoa_to_sheet', async function(t) {
+ var aoa = [["SheetJS"],[5433795]];
+ var sp = X.utils.aoa_to_sheet(aoa); assert.equal(sp["A2"].v, 5433795); assert.assert(!sp["!data"]);
+ sp = X.utils.aoa_to_sheet(aoa, {}); assert.equal(sp["A2"].v, 5433795); assert.assert(!sp["!data"]);
+ sp = X.utils.aoa_to_sheet(aoa, {dense: false}); assert.equal(sp["A2"].v, 5433795); assert.assert(!sp["!data"]);
+ var ds = X.utils.aoa_to_sheet(aoa, {dense: true}); assert.equal(ds["!data"]?.[1][0].v, 5433795); assert.assert(!ds["A2"]);
+ });
+ await t.step('json_to_sheet', async function(t) {
+ var json = [{"SheetJS": 5433795}];
+ var sp = X.utils.json_to_sheet(json); assert.equal(sp["A2"].v, 5433795); assert.assert(!sp["!data"]);
+ sp = X.utils.json_to_sheet(json, {}); assert.equal(sp["A2"].v, 5433795); assert.assert(!sp["!data"]);
+ sp = X.utils.json_to_sheet(json, {dense: false}); assert.equal(sp["A2"].v, 5433795); assert.assert(!sp["!data"]);
+ var ds = X.utils.json_to_sheet(json, {dense: true}); assert.equal(ds["!data"]?.[1][0].v, 5433795); assert.assert(!ds["A2"]);
+ });
+ await t.step('sheet_add_aoa', async function(t) {
+ var aoa = [["SheetJS"]];
+ var sp = X.utils.aoa_to_sheet(aoa); X.utils.sheet_add_aoa(sp, [[5433795]], {origin:-1}); assert.equal(sp["A2"].v, 5433795); assert.assert(!sp["!data"]);
+ sp = X.utils.aoa_to_sheet(aoa); X.utils.sheet_add_aoa(sp, [[5433795]], {origin:-1, dense: true}); assert.equal(sp["A2"].v, 5433795); assert.assert(!sp["!data"]);
+ var ds:X.WorkSheet = X.utils.aoa_to_sheet(aoa, {dense: true}); X.utils.sheet_add_aoa(ds, [[5433795]], {origin:-1}); assert.equal(ds["!data"]?.[1][0].v, 5433795); assert.assert(!ds["A2"]);
+ ds = X.utils.aoa_to_sheet(aoa, {dense: true}); X.utils.sheet_add_aoa(ds, [[5433795]], {origin:-1, dense: true}); assert.equal(ds["!data"]?.[1][0].v, 5433795); assert.assert(!ds["A2"]);
+ });
+ await t.step('sheet_add_json', async function(t) {
+ var aoa = [["SheetJS"]];
+ var sp = X.utils.aoa_to_sheet(aoa); X.utils.sheet_add_json(sp, [{X:5433795}], {origin:-1, skipHeader:true}); assert.equal(sp["A2"].v, 5433795); assert.assert(!sp["!data"]);
+ sp = X.utils.aoa_to_sheet(aoa); X.utils.sheet_add_json(sp, [{X:5433795}], {origin:-1, skipHeader: true, dense: true}); assert.equal(sp["A2"].v, 5433795); assert.assert(!sp["!data"]);
+ var ds:X.WorkSheet = X.utils.aoa_to_sheet(aoa, {dense: true}); X.utils.sheet_add_json(ds, [{X:5433795}], {origin:-1, skipHeader: true}); assert.equal(ds["!data"]?.[1][0].v, 5433795); assert.assert(!ds["A2"]);
+ ds = X.utils.aoa_to_sheet(aoa, {dense: true}); X.utils.sheet_add_json(ds, [{X:5433795}], {origin:-1, skipHeader: true, dense: true}); assert.equal(ds["!data"]?.[1][0].v, 5433795); assert.assert(!ds["A2"]);
+ });
+ for(var ofmti = 0; ofmti < ofmt.length; ++ofmti) { var f = ofmt[ofmti];
+ await t.step('write ' + f, async function(t) {
+ var aoa = [["SheetJS"],[5433795]];
+ var wb = X.utils.book_new(X.utils.aoa_to_sheet(aoa));
+ var newwb = X.read(X.write(wb, {type:"binary", bookType:f}), {type:"binary"});
+ assert.equal(get_cell(newwb.Sheets["Sheet1"], "A1").v, "SheetJS");
+ assert.equal(get_cell(newwb.Sheets["Sheet1"], "A2").v, 5433795);
+ }); }
+ await t.step('sheet_to_formulae', async function(t) {
+ var w = ['xlsx', paths.fstxlsx];
+ var wb1 = X.read(fs.readFileSync(w[1]), {type:TYPE, cellFormula:true, WTF:true, dense: false});
+ var wb2 = X.read(fs.readFileSync(w[1]), {type:TYPE, cellFormula:true, WTF:true, dense: true});
+ wb1.SheetNames.forEach(function(n) {
+ assert.equal(
+ X.utils.sheet_to_formulae(wb1.Sheets[n]).sort().join("\n"),
+ X.utils.sheet_to_formulae(wb2.Sheets[n]).sort().join("\n")
+ );
+ });
+ });
+ await t.step('sheet_to_csv', async function(t) {
+ var w = ['xlsx', paths.fstxlsx];
+ var wb1 = X.read(fs.readFileSync(w[1]), {type:TYPE, cellFormula:true, WTF:true, dense: false});
+ var wb2 = X.read(fs.readFileSync(w[1]), {type:TYPE, cellFormula:true, WTF:true, dense: true});
+ wb1.SheetNames.forEach(function(n) {
+ assert.equal(
+ X.utils.sheet_to_csv(wb1.Sheets[n]),
+ X.utils.sheet_to_csv(wb2.Sheets[n])
+ );
+ });
+ });
+});
+
Deno.test('corner cases', async function(t) {
await t.step('output functions', async function(t) {
var ws = X.utils.aoa_to_sheet([