Compare commits

..

No commits in common. "master" and "v0.20.3" have entirely different histories.

43 changed files with 176 additions and 383 deletions

2
.gitignore vendored

@ -39,5 +39,3 @@ tmp
*.sheetjs
*.exe
*.img
test_files.zip
test_files/

4
.gitmodules vendored

@ -0,0 +1,4 @@
[submodule "test_files"]
path = test_files
url = https://github.com/SheetJS/test_files
ignore = dirty

@ -4,11 +4,6 @@ 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.
* Sheet Visibility for ODS / FODS (h/t @edemaine)
* HTML DOM ingress support formulae (`data-f`)
* Proper handling of XLSX encoded entities (h/t @inreoh)
* Proper handling of invalid DIF sheets that match heuristics (h/t @lowkeyfish)
## v0.20.3
* Correct parsing of NUMBERS and ODS merge cells (h/t @s-ashwin)

@ -1,74 +1,69 @@
# Contributing
SheetJS CE should be free and clear to use in your projects. To ensure that
remains true, each contributor must be vigilant and each contribution must be
carefully scrutinized from a technical and legal perspective.
The SheetJS Libraries should be free and clear to use in your projects. In
order to maintain that, every contributor must be vigilant.
Many commercial products and open source projects have been very lax regarding
licensing. They are ticking timebombs that no commercial product should use.
There have been many projects in the past that have been very lax regarding
licensing. We are of the opinion that those are ticking timebombs and that no
commercial product should depend on them.
## Required Reading
# Required Reading
These are pretty short reads and emphasize the importance of proper licensing:
- https://web.archive.org/web/20200916173942/https://github.com/jazzband/tablib/issues/114
- https://github.com/jazzband/tablib/issues/114 (discussion of other tools)
- https://web.archive.org/web/20240909210554/https://github.com/stephen-hardy/xlsx.js/issues/8
- https://web.archive.org/web/20120615223756/http://www.codinghorror.com/blog/2007/04/pick-a-license-any-license.html
## Raising Issues
# Raising Issues
Issues should generally be accompanied by test files. It is strongly recommended
to use the [issue tracker](https://git.sheetjs.com/sheetjs/sheetjs/issues).
Issues should generally be accompanied by test files. Since github does not
support attachments, the best method is to send files to <sheetjs@gmail.com>
(subject line should contain issue number or message) or to share using some
storage service. Unless expressly permitted, any attachments will not be
shared or included in a test suite (although I will ask :)
If they cannot be shared publicly, please send files to <oss@sheetjs.com>
(subject line should contain issue number or message) or share links to files
hosted on a storage service. Unless expressly permitted, attachments will not be
shared outside of SheetJS LLC or included in a test suite.
If sending email to a gmail account is problematic, the <dev@sheetjs.com> email
inbox is self-hosted.
If a NDA is required, please send an email to <oss@sheetjs.com> with subject
line "Non-Disclosure Agreemeant Request".
# Opening Pull Requests
[Squash commits](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History)
before opening a pull request, If the pull request addresses documentation or
demos, add `[ci skip]` in the body or title of the commit message to skip tests.
## Opening Pull Requests
Please raise an issue before opening pull requests. It is easy to solve a
specific problem without considering the full context or implications.
## Pre-Contribution Checklist
# Pre-Contribution Checklist
Before thinking about contributing, make sure that:
- You are not, nor have ever been, an employee of Microsoft Corporation.
- You have not signed any NDAs or Shared Source Agreements with Microsoft
Corporation or a subsidiary.
Corporation or a subsidiary
- You have not consulted any existing relevant codebase (if you have, please
take note of which codebases were consulted).
If you cannot attest to each of these items, the best approach is to raise an
issue. If it is a particularly high-priority issue, please drop an email to
<support@sheetjs.com> and it will be prioritized.
issue. If it is a particularly high-priority issue, please drop an email to
<sheetjs@gmail.com> and it will be prioritized.
## Intra-Contribution
# Intra-Contribution
Keep these in mind as you work:
- Your contributions are your original work. Take note of any resources you
- Your contributions are your original work. Take note of any resources you
consult in the process. Be extra careful not to use unlicensed code on the
Internet or code generated by a large language model or other AI tool.
- You are working on your own time. Unless they explicitly grant permission,
- You are working on your own time. Unless they explicitly grant permission,
your employer may be the ultimate owner of your IP
# Post-Contribution
## Post-Contribution
Before certain contributions are merged, you will receive an email (at the
address associated with the git commit) and will be asked to confirm the
aforementioned items. Ensure that the email addresses associated with the
commits are valid.
Before contributions are merged, you will receive an email (at the address
associated with the git commit) and will be asked to confirm the aforementioned
items. Ensure that the email addresses associated with the commits are valid.

@ -151,10 +151,6 @@ test-esm: test.mjs ## Run Node ESM test suite
test.ts: test.mts
node -pe 'var data = fs.readFileSync("'$<'", "utf8"); data.split("\n").map(function(l) { return l.replace(/^describe\((.*?)function\(\)/, "Deno.test($$1async function(t)").replace(/\b(?:it|describe)\((.*?)function\(\)/g, "await t.step($$1async function(t)").replace("assert.ok", "assert.assert"); }).join("\n")' > $@
# NOTE: `bun test test.mjs` does not actually run the tests, hence test.test.mjs
test.test.mjs: test.mjs
cp $< $@
.PHONY: test-bun
test-bun: test.test.mjs ## Run Bun test suite
bun test $<

@ -31,6 +31,9 @@ encodings for XLS and other legacy spreadsheet formats
- [`dta`](packages/dta): Stata DTA file processor
- [`test_files`](https://github.com/sheetjs/test_files): Test files and various
plaintext baselines.
## License
Please consult the attached LICENSE file for details. All rights not explicitly

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

@ -421,11 +421,7 @@ function hashq(str/*:string*/)/*:string*/ {
}
return o;
}
function rnd(val/*:number*/, d/*:number*/)/*:string*/ {
var sgn = val < 0 ? -1 : 1;
var dd = Math.pow(10,d);
return ""+sgn*(Math.round(sgn * val * dd)/dd);
}
function rnd(val/*:number*/, d/*:number*/)/*:string*/ { var dd = Math.pow(10,d); return ""+(Math.round(val * dd)/dd); }
function dec(val/*:number*/, d/*:number*/)/*:number*/ {
var _frac = val - Math.floor(val), dd = Math.pow(10,d);
if (d < ('' + Math.round(_frac * dd)).length) return 0;

@ -67,7 +67,7 @@ var rencoding = /*#__PURE__*/evert(encodings);
// TODO: CP remap (need to read file version to determine OS)
var unescapexml/*:StringConv*/ = /*#__PURE__*/(function() {
/* 22.4.2.4 bstr (Basic String) */
var encregex = /&(?:quot|apos|gt|lt|amp|#x?([\da-fA-F]+));/ig, coderegex = /_x([\da-fA-F]{4})_/g;
var encregex = /&(?:quot|apos|gt|lt|amp|#x?([\da-fA-F]+));/ig, coderegex = /_x([\da-fA-F]{4})_/ig;
function raw_unescapexml(text/*:string*/)/*:string*/ {
var s = text + '', i = s.indexOf("<![CDATA[");
if(i == -1) return s.replace(encregex, function($$, $1) { return encodings[$$]||String.fromCharCode(parseInt($1,$$.indexOf("x")>-1?16:10))||$$; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));});
@ -153,13 +153,7 @@ function utf8readb(data) {
function utf8readc(data) { return Buffer_from(data, 'binary').toString('utf8'); }
var utf8corpus = "foo bar baz\u00e2\u0098\u0083\u00f0\u009f\u008d\u00a3";
var utf8read = /*#__PURE__*/(function() {
if(has_buf) {
if(utf8readc(utf8corpus) == utf8reada(utf8corpus)) return utf8readc;
if(utf8readb(utf8corpus) == utf8reada(utf8corpus)) return utf8readb;
}
return utf8reada;
})();
var utf8read = has_buf && (/*#__PURE__*/utf8readc(utf8corpus) == /*#__PURE__*/utf8reada(utf8corpus) && utf8readc || /*#__PURE__*/utf8readb(utf8corpus) == /*#__PURE__*/utf8reada(utf8corpus) && utf8readb) || utf8reada;
var utf8write/*:StringConv*/ = has_buf ? function(data) { return Buffer_from(data, 'utf8').toString("binary"); } : function(orig/*:string*/)/*:string*/ {
var out/*:Array<string>*/ = [], i = 0, c = 0, d = 0;

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

@ -1138,17 +1138,3 @@ function read_wb_ID(d, opts) {
}
}
function read_wb_TABL(d, opts) {
var o = opts || {}, OLD_WTF = !!o.WTF; o.WTF = true;
try {
var out = DIF.to_workbook(d, o);
if(!out || !out.Sheets) throw "DIF bad workbook";
var ws = out.Sheets[out.SheetNames[0]];
if(!ws || !ws["!ref"]) throw "DIF empty worksheet";
o.WTF = OLD_WTF;
return out;
} catch(e) {
o.WTF = OLD_WTF;
return PRN.to_workbook(d, opts);
}
}

@ -52,10 +52,6 @@ function parse_xlmeta_bin(data, name, _opts) {
var metatype = 2;
recordhopper(data, function(val, R, RT) {
switch (RT) {
case 58:
break;
case 59:
break;
case 335:
out.Types.push({ name: val.name });
break;

@ -35,7 +35,6 @@ function parse_xlink_bin(data, rel, name/*:string*/, _opts) {
case 0x0249: /* 'BrtSupNameFmla' */
case 0x024A: /* 'BrtSupNameBits' */
case 0x024B: /* 'BrtSupNameEnd' */
case 0x13F4: /* 'BrtExternalLinksAlternateUrls' */
break;
case 0x0023: /* 'BrtFRTBegin' */

@ -23,10 +23,9 @@ var rc_to_a1 = /*#__PURE__*/(function(){
};
})();
/* TODO: check if engines support \b */
var crefregex = /(^|[^._A-Za-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;
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-Za-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;
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*/) {

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

@ -505,7 +505,7 @@ function parse_BrtDVal(/*data, length, opts*/) {
}
function parse_BrtDVal14(/*data, length, opts*/) {
}
/* [MS-XLSB] 2.1.7.62 Worksheet */
/* [MS-XLSB] 2.1.7.61 Worksheet */
function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/*:Worksheet*/ {
if(!data) return data;
var opts = _opts || {};

@ -627,14 +627,14 @@ function parse_xls_props(cfb/*:CFBContainer*/, props, o) {
if(DSI && DSI.size > 0) try {
var DocSummary = parse_PropertySetStream(DSI, DocSummaryPIDDSI, PSCLSID.DSI);
for(var d in DocSummary) props[d] = DocSummary[d];
} catch(e) {if(o.WTF) console.error(e && e.message || e);}
} catch(e) {if(o.WTF) throw e;/* empty */}
/* [MS-OSHARED] 2.3.3.2.1 Summary Information Property Set*/
var SI = CFB.find(cfb, '/!SummaryInformation');
if(SI && SI.size > 0) try {
var Summary = parse_PropertySetStream(SI, SummaryPIDSI, PSCLSID.SI);
for(var s in Summary) if(props[s] == null) props[s] = Summary[s];
} catch(e) {if(o.WTF) console.error(e && e.message || e);}
} catch(e) {if(o.WTF) throw e;/* empty */}
if(props.HeadingPairs && props.TitlesOfParts) {
load_props_pairs(props.HeadingPairs, props.TitlesOfParts, props, o);

@ -856,25 +856,6 @@ var XLSBRecordEnum = {
0x13E8: { /* n:"BrtEndCalcFeatures", */ T:-1 },
0x13E9: { /* n:"BrtCalcFeature" */ },
0x13EB: { /* n:"BrtExternalLinksPr" */ },
0x13EC: { /* n:"BrtPivotCacheImplicitMeasureSupport" */ },
0x13ED: { /* n:"BrtPivotFieldIgnorableAfter" */ },
0x13EE: { /* n:"BrtPivotHierarchyIgnorableAfter" */ },
0x13EF: { /* n:"BrtPivotDataFieldFutureData" */ },
0x13F1: { /* n:"BrtPivotCacheRichData" */ },
0x13F4: { /* n:"BrtExternalLinksAlternateUrls" */ },
0x13F5: { /* n:"BrtBeginPivotVersionInfo" */ },
0x13F6: { /* n:"BrtEndPivotVersionInfo" */ },
0x13F7: { /* n:"BrtBeginCacheVersionInfo" */ },
0x13F8: { /* n:"BrtEndCacheVersionInfo" */ },
0x13F9: { /* n:"BrtPivotRequiredFeature" */ },
0x13FA: { /* n:"BrtPivotLastUsedFeature" */ },
0x13FD: { /* n:"BrtExternalCodeService" */ },
0x1407: { /* n:"BrtShowDataTypeIcons" */ },
0x140A: { /* n:"BrtSXDIAggregation" */ },
0x140B: { /* n:"BrtPivotFieldFeatureSupportInfo" */ },
0x140C: { /* n:"BrtPivotCacheAutoRefresh" */ },
0x140E: { /* n:"BrtShowDataTypeIconsUserShView" */ },
0x140F: { /* n:"BrtWorkbookCompatibilityVersion" */ },
0xFFFF: { n:"" }
};

@ -431,54 +431,8 @@ function write_FMTS_biff8(ba, NF/*:?SSFTable*/, opts) {
});
}
function write_ws_protect_biff8(sp) {
/* SheetProtection */
var flags = 0x0000;
[
["objects", false, 0x0001], // fObjects - Bit 0 (Edit objects)
["scenarios", false, 0x0002], // fScenarios - Bit 1 (Edit scenarios)
["formatCells", true, 0x0004], // fFormatCells - Bit 2 (Change cell formatting)
["formatColumns", true, 0x0008], // fFormatColumns - Bit 3 (Change column formatting)
["formatRows", true, 0x0010], // fFormatRows - Bit 4 (Change row formatting)
["insertColumns", true, 0x0020], // fInsertColumns - Bit 5 (Insert columns)
["insertRows", true, 0x0040], // fInsertRows - Bit 6 (Insert rows)
["insertHyperlinks", true, 0x0080], // fInsertHyperlinks - Bit Bit 7 (Insert hyperlinks)
["deleteColumns", true, 0x0100], // fDeleteColumns - Bit 8 (Delete columns)
["deleteRows", true, 0x0200], // fDeleteRows - Bit 9 (Delete rows)
["selectLockedCells", false, 0x0400], // fSelLockedCells - Bit 10 (Select locked cells)
["sort", true, 0x0800], // fSort - Bit 11 (Sort a cell range)
["autoFilter", true, 0x1000], // fAutoFilter - Bit 12 (Edit auto filters)
["pivotTables", true, 0x2000], // fPivotTables - Bit 13 (Edit PivotTables)
["selectUnlockedCells", false, 0x4000] // fSelUnlockedCells - Bit 14 (Select unlocked cells)
].forEach(function(n) {
if(n[1]) flags |= sp[n[0]] != null && !sp[n[0]] ? n[2] : 0x0000;
else flags |= sp[n[0]] != null && sp[n[0]] ? 0x0000 : n[2];
});
/* [MS-XLS] 2.4.112 */
var featHdr = new_buf(23);
/* [MS-XLS] 2.5.135 */
featHdr.write_shift(2, 0x0867);
featHdr.write_shift(2, 0x0000);
featHdr.write_shift(4, 0x00000000);
featHdr.write_shift(4, 0x00000000);
/* [MS-XLS] 2.5.237 */
featHdr.write_shift(2, 0x0002); // SharedFeatureType ISFPROTECTION
/* Reserved byte */
featHdr.write_shift(1, 0x01);
/* cbHdrData */
featHdr.write_shift(4, 0xffffffff);
/* [MS-XLS] 2.5.104 */
featHdr.write_shift(4, flags);
return featHdr;
}
function write_FEAT(ba, ws) {
/* [MS-XLS] 2.4.112 */
/* ISFPROTECTION */
if(ws['!protect']) write_biff_rec(ba, 0x0867 /* FeatHdr */, write_ws_protect_biff8(ws['!protect']));
/* ISFFEC2 */
var o = new_buf(19);
o.write_shift(4, 0x867); o.write_shift(4, 0); o.write_shift(4, 0);
o.write_shift(2, 3); o.write_shift(1, 1); o.write_shift(4, 0);
@ -583,14 +537,6 @@ function write_ws_biff8(idx/*:number*/, opts, wb/*:Workbook*/) {
/* Footer (string) */
write_biff_rec(ba, 0x0083 /* HCenter */, writebool(false));
write_biff_rec(ba, 0x0084 /* VCenter */, writebool(false));
/* PROTECTION */
if(ws['!protect']){
var sp = ws['!protect'];
/* [MS-XLS] 2.4.207 */
write_biff_rec(ba, 0x0012 /* Protect */, writeuint16(1));
/* [MS-XLS] 2.4.191 */
if(sp.password) write_biff_rec(ba, 0x0013 /* Password */, writeuint16(crypto_CreatePasswordVerifier_Method1(sp.password)));
}
/* ... */
if(b8) write_ws_cols_biff8(ba, ws["!cols"]);
/* ... */

@ -92,7 +92,6 @@ function make_html_row(ws/*:Worksheet*/, r/*:Range*/, R/*:number*/, o/*:Sheet2HT
// note: data-v is unaffected by the timezone interpretation
if(cell.v != null) sp["data-v"] = escapehtml(cell.v instanceof Date ? cell.v.toISOString() : cell.v);
if(cell.z != null) sp["data-z"] = cell.z;
if(cell.f != null) sp["data-f"] = escapehtml(cell.f);
if(cell.l && (cell.l.Target || "#").charAt(0) != "#") w = '<a href="' + escapehtml(cell.l.Target) +'">' + w + '</a>';
}
sp.id = (o.id || "sjs") + "-" + coord;
@ -137,6 +136,12 @@ function sheet_to_html(ws/*:Worksheet*/, opts/*:?Sheet2HTMLOpts*//*, wb:?Workboo
}
function sheet_add_dom(ws/*:Worksheet*/, table/*:HTMLElement*/, _opts/*:?any*/)/*:Worksheet*/ {
var rows/*:HTMLCollection<HTMLTableRowElement>*/ = table.rows;
if(!rows) {
/* not an HTML TABLE */
throw "Unsupported origin when " + table.tagName + " is not a TABLE";
}
var opts = _opts || {};
var dense = ws["!data"] != null;
var or_R = 0, or_C = 0;
@ -148,6 +153,7 @@ function sheet_add_dom(ws/*:Worksheet*/, table/*:HTMLElement*/, _opts/*:?any*/)/
}
}
var sheetRows = Math.min(opts.sheetRows||10000000, rows.length);
var range/*:Range*/ = {s:{r:0,c:0},e:{r:or_R,c:or_C}};
if(ws["!ref"]) {
var _range/*:Range*/ = decode_range(ws["!ref"]);
@ -157,15 +163,6 @@ function sheet_add_dom(ws/*:Worksheet*/, table/*:HTMLElement*/, _opts/*:?any*/)/
range.e.c = Math.max(range.e.c, _range.e.c);
if(or_R == -1) range.e.r = or_R = _range.e.r + 1;
}
var rows/*:HTMLCollection<HTMLTableRowElement>*/ = table.rows;
if(!rows) {
/* not an HTML TABLE */
throw "Unsupported origin when " + table.tagName + " is not a TABLE";
}
var sheetRows = Math.min(opts.sheetRows||10000000, rows.length);
var merges/*:Array<Range>*/ = [], midx = 0;
var rowinfo/*:Array<RowInfo>*/ = ws["!rows"] || (ws["!rows"] = []);
var _R = 0, R = 0, _C = 0, C = 0, RS = 0, CS = 0;
@ -182,16 +179,13 @@ function sheet_add_dom(ws/*:Worksheet*/, table/*:HTMLElement*/, _opts/*:?any*/)/
if (opts.display && is_dom_element_hidden(elt)) continue;
var v/*:?string*/ = elt.hasAttribute('data-v') ? elt.getAttribute('data-v') : elt.hasAttribute('v') ? elt.getAttribute('v') : htmldecode(elt.innerHTML);
var z/*:?string*/ = elt.getAttribute('data-z') || elt.getAttribute('z');
var f/*:?string*/ = elt.hasAttribute('data-f') ? elt.getAttribute('data-f') : elt.hasAttribute('f') ? elt.getAttribute('f') : null;
for(midx = 0; midx < merges.length; ++midx) {
var m/*:Range*/ = merges[midx];
if(m.s.c == C + or_C && m.s.r < R + or_R && R + or_R <= m.e.r) { C = m.e.c+1 - or_C; midx = -1; }
}
/* TODO: figure out how to extract nonstandard mso- style */
CS = +elt.getAttribute("colspan") || 1;
if( ((RS = (+elt.getAttribute("rowspan") || 1)))>1 || CS>1) {
merges.push({s:{r:R + or_R,c:C + or_C},e:{r:R + or_R + (RS||1) - 1, c:C + or_C + (CS||1) - 1}});
}
if( ((RS = (+elt.getAttribute("rowspan") || 1)))>1 || CS>1) merges.push({s:{r:R + or_R,c:C + or_C},e:{r:R + or_R + (RS||1) - 1, c:C + or_C + (CS||1) - 1}});
var o/*:Cell*/ = {t:'s', v:v};
var _t/*:string*/ = elt.getAttribute("data-t") || elt.getAttribute("t") || "";
if(v != null) {
@ -216,7 +210,6 @@ function sheet_add_dom(ws/*:Worksheet*/, table/*:HTMLElement*/, _opts/*:?any*/)/
l = Aelts[Aelti].getAttribute("href"); if(l.charAt(0) != "#") break;
}
if(l && l.charAt(0) != "#" && l.slice(0, 11).toLowerCase() != 'javascript:') o.l = ({ Target: l });
if(f != null) o.f = f;
if(dense) { if(!ws["!data"][R + or_R]) ws["!data"][R + or_R] = []; ws["!data"][R + or_R][C + or_C] = o; }
else ws[encode_cell({c:C + or_C, r:R + or_R})] = o;
if(range.e.c < C + or_C) range.e.c = C + or_C;

@ -205,7 +205,7 @@ function parse_ods_styles(d/*:string*/, _opts, _nfm) {
// TODO: handle more complex maps
y = parsexmltag(Rn[0], false);
if(unescapexml(y["condition"]) == "value()>=0") NF = number_format_map[y["apply-style-name"]] + ";" + NF;
else if(_opts && _opts.WTF) console.error("ODS number format may be incorrect: " + y["condition"]);
else console.error("ODS number format may be incorrect: " + y["condition"]);
break;
case 'number': // <number:number> 16.29.3
@ -252,11 +252,11 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
var textR = [], oldtextR = [];
var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
var row_ol = 0;
var number_format_map = _nfm || {}, styles = {}, tstyles = {};
var number_format_map = _nfm || {}, styles = {};
var merges/*:Array<Range>*/ = [], mrange = {}, mR = 0, mC = 0;
var rowinfo/*:Array<RowInfo>*/ = [], rowpeat = 1, colpeat = 1;
var arrayf/*:Array<[Range, string]>*/ = [];
var WB = {Names:[], WBProps:{}, Sheets:[]};
var WB = {Names:[], WBProps:{}};
var atag = ({}/*:any*/);
var _Ref/*:[string, string]*/ = ["", ""];
var comments/*:Array<Comment>*/ = [], comment/*:Comment*/ = ({}/*:any*/);
@ -282,10 +282,6 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
if(typeof JSON !== 'undefined') JSON.stringify(sheetag);
SheetNames.push(sheetag.name);
Sheets[sheetag.name] = ws;
WB.Sheets.push({
/* TODO: CodeName */
Hidden: (tstyles[sheetag["style-name"]] && tstyles[sheetag["style-name"]]["display"] ? (parsexmlbool(tstyles[sheetag["style-name"]]["display"]) ? 0 : 1) : 0)
});
intable = false;
}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
@ -533,16 +529,12 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
case 'style': { // 16.2 <style:style>
var styletag = parsexmltag(Rn[0], false);
if(styletag["family"] == "table-cell" && number_format_map[styletag["data-style-name"]]) styles[styletag["name"]] = number_format_map[styletag["data-style-name"]];
else if(styletag["family"] == "table") tstyles[styletag["name"]] = styletag;
} break;
case 'map': break; // 16.3 <style:map>
case 'font-face': break; // 16.21 <style:font-face>
case 'paragraph-properties': break; // 17.6 <style:paragraph-properties>
case 'table-properties': { // 17.15 <style:table-properties>
var proptag = parsexmltag(Rn[0], false);
if(styletag && styletag.family == "table") styletag.display = proptag.display;
} break;
case 'table-properties': break; // 17.15 <style:table-properties>
case 'table-column-properties': break; // 17.16 <style:table-column-properties>
case 'table-row-properties': break; // 17.17 <style:table-row-properties>
case 'table-cell-properties': break; // 17.18 <style:table-cell-properties>
@ -764,10 +756,6 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
_Ref = ods_to_csf_3D(atag.Target.slice(1));
atag.Target = "#" + _Ref[0] + "!" + _Ref[1];
} else if(atag.Target.match(/^\.\.[\\\/]/)) atag.Target = atag.Target.slice(3);
/* Appendix D.2 Hyperlink Titles */
if(atag.title) {
atag.Tooltip = unescapexml(atag.title); delete atag.title;
}
}
break;

@ -214,9 +214,7 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function
var write_ws = function(ws, wb/*:Workbook*/, i/*:number*/, opts, nfs, date1904)/*:string*/ {
/* Section 9 Tables */
var o/*:Array<string>*/ = [];
var tstyle = "ta1";
if(((((wb||{}).Workbook||{}).Sheets||[])[i]||{}).Hidden) tstyle = "ta2";
o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '" table:style-name="' + tstyle + '">\n');
o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '" table:style-name="ta1">\n');
var R=0,C=0, range = decode_range(ws['!ref']||"A1");
var marr/*:Array<Range>*/ = ws['!merges'] || [], mi = 0;
var dense = ws["!data"] != null;
@ -364,9 +362,6 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function
o.push(' <style:style style:name="ta1" style:family="table" style:master-page-name="mp1">\n');
o.push(' <style:table-properties table:display="true" style:writing-mode="lr-tb"/>\n');
o.push(' </style:style>\n');
o.push(' <style:style style:name="ta2" style:family="table" style:master-page-name="mp1">\n');
o.push(' <style:table-properties table:display="false" style:writing-mode="lr-tb"/>\n');
o.push(' </style:style>\n');
o.push(' <number:date-style style:name="N37" number:automatic-order="true">\n');
o.push(' <number:month number:style="long"/>\n');

@ -99,7 +99,7 @@ function readSync(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
if(n[1] === 0x49 && n[2] === 0x2a && n[3] === 0x00) throw new Error("TIFF Image File is not a spreadsheet");
if(n[1] === 0x44) return read_wb_ID(d, o);
break;
case 0x54: if(n[1] === 0x41 && n[2] === 0x42 && n[3] === 0x4C) return read_wb_TABL(d, o); break;
case 0x54: if(n[1] === 0x41 && n[2] === 0x42 && n[3] === 0x4C) return DIF.to_workbook(d, o); break;
case 0x50: return (n[1] === 0x4B && n[2] < 0x09 && n[3] < 0x09) ? read_zip(d, o) : read_prn(data, d, o, str);
case 0xEF: return n[3] === 0x3C ? parse_xlml(d, o) : read_prn(data, d, o, str);
case 0xFF:

@ -111,7 +111,7 @@ function write_binary_type(out, opts/*:WriteOpts*/)/*:any*/ {
function writeSyncXLSX(wb/*:Workbook*/, opts/*:?WriteOpts*/) {
reset_cp();
if(!opts || !opts.unsafe) check_wb(wb);
check_wb(wb);
var o = dup(opts||{});
if(o.cellStyles) { o.cellNF = true; o.sheetStubs = true; }
if(o.type == "array") { o.type = "binary"; var out/*:string*/ = (writeSyncXLSX(wb, o)/*:any*/); o.type = "array"; return s2ab(out); }
@ -120,7 +120,7 @@ function writeSyncXLSX(wb/*:Workbook*/, opts/*:?WriteOpts*/) {
function writeSync(wb/*:Workbook*/, opts/*:?WriteOpts*/) {
reset_cp();
if(!opts || !opts.unsafe) check_wb(wb);
check_wb(wb);
var o = dup(opts||{});
if(o.cellStyles) { o.cellNF = true; o.sheetStubs = true; }
if(o.type == "array") { o.type = "binary"; var out/*:string*/ = (writeSync(wb, o)/*:any*/); o.type = "array"; return s2ab(out); }

@ -24,7 +24,7 @@ function make_json_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Ar
switch(val.t){
case 'z': if(v == null) break; continue;
case 'e': v = (v == 0 ? null : void 0); break;
case 's': case 'b': break;
case 's': case 'b':
case 'n': if(!val.z || !fmt_is_date(val.z)) break;
v = numdate(v); // TODO: date1904 setting should also be stored in worksheet object
if(typeof v == "number") break;
@ -116,7 +116,7 @@ function make_csv_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Arr
else if(val.v != null) {
isempty = false;
txt = ''+(o.rawNumbers && val.t == "n" ? val.v : format_cell(val, null, o));
for(var i = 0, cc = 0; i !== txt.length; ++i) if((cc = txt.charCodeAt(i)) === fs || cc === rs || cc === 10 ||cc === 13 || cc === 34 || o.forceQuotes) {txt = "\"" + txt.replace(qreg, '""') + "\""; break; }
for(var i = 0, cc = 0; i !== txt.length; ++i) if((cc = txt.charCodeAt(i)) === fs || cc === rs || cc === 34 || o.forceQuotes) {txt = "\"" + txt.replace(qreg, '""') + "\""; break; }
if(txt == "ID" && w == 0 && row.length == 0) txt = '"ID"';
} else if(val.f != null && !val.F) {
isempty = false;

@ -103,10 +103,7 @@ function write_json_stream(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) {
R = r.s.r + offset;
stream._read = function() {
while(R <= r.e.r) {
if ((rowinfo[R]||{}).hidden) {
++R;
continue;
};
if ((rowinfo[R-1]||{}).hidden) continue;
var row = make_json_row(sheet, r, R, cols, header, hdr, o);
++R;
if((row.isempty === false) || (header === 1 ? o.blankrows !== false : !!o.blankrows)) {

@ -52,10 +52,6 @@ function parse_xlmeta_bin(data, name, _opts) {
var metatype = 2;
recordhopper(data, function(val, R, RT) {
switch (RT) {
case 58:
break;
case 59:
break;
case 335:
out.Types.push({ name: val.name });
break;

@ -73,37 +73,15 @@ function parse_xlmeta_bin(data: RawData, name: string, _opts?: ParseXLMetaOption
// case 0x014D: /* BrtEndMetadata */
// case 0x014E: /* BrtBeginEsmdtinfo */
// case 0x0150: /* BrtEndEsmdtinfo */
// case 0x0151: /* BrtBeginEsmdb */
// case 0x0152: /* BrtEndEsmdb */
// case 0x0153: /* BrtBeginEsfmd */
// case 0x0154: /* BrtEndEsfmd */
// case 0x0174: /* BrtBeginEsmdx */
// case 0x0175: /* BrtEndEsmdx */
// case 0x0176: /* BrtBeginMdxSet */
// case 0x0177: /* BrtEndMdxSet */
// case 0x0178: /* BrtBeginMdxMbrProp */
// case 0x0179: /* BrtEndMdxMbrProp */
// case 0x017A: /* BrtBeginMdxKPI */
// case 0x017B: /* BrtEndMdxKPI */
// case 0x017C: /* BrtBeginEsstr */
// case 0x017D: /* BrtEndEsstr */
// case 0x0034: /* BrtBeginFmd */
// case 0x0035: /* BrtEndFmd */
// case 0x0036: /* BrtBeginMdx */
// case 0x0037: /* BrtEndMdx */
// case 0x0038: /* BrtBeginMdxTuple */
// case 0x0039: /* BrtEndMdxTuple */
// case 0x1000: /* BrtBeginDynamicArrayPr */
// case 0x1001: /* BrtEndDynamicArrayPr */
// case 0x138A: /* BrtBeginRichValueBlock */
// case 0x138B: /* BrtEndRichValueBlock */
case 0x003A: /* BrtMdxMbrIstr */
break;
case 0x003B: /* BrtStr */
break;
case 0x014F: /* BrtMdtinfo */
out.Types.push({name: (val as BrtMdtinfo).name}); break;

@ -4,7 +4,7 @@
/* these are type imports and do not show up in the generated JS */
import { CFB$Container, CFB$Entry } from 'cfb';
import { WorkBook, WorkSheet, Range, CellObject, ParsingOptions, WritingOptions, DenseWorkSheet, Comments } from '../';
import type { utils, NumberFormat, DenseSheetData } from "../";
import type { utils, NumberFormat } from "../";
declare var encode_col: typeof utils.encode_col;
declare var encode_row: typeof utils.encode_row;
@ -1697,7 +1697,7 @@ function write_numbers_tma(cfb: CFB$Container, deps: Dependents, ws: WorkSheet,
if(trunc) console.error(`Truncating to ${encode_range(range)}`);
/* preprocess data and build up shared string table */
var data: DenseSheetData = [];
var data: CellObject[][] = [];
if(ws["!data"]) data = ws["!data"];
else {
var colstr: string[] = [];
@ -1708,7 +1708,7 @@ function write_numbers_tma(cfb: CFB$Container, deps: Dependents, ws: WorkSheet,
for(_C = 0; _C <= range.e.c; ++_C) {
var _cell = ws[colstr[_C] + _R];
if(!_cell) continue;
data[R_]![_C] = _cell;
data[R_][_C] = _cell;
}
}
}

@ -142,7 +142,10 @@
"url": "https://git.sheetjs.com/SheetJS/sheetjs"
},
"scripts": {
"test": "make travis",
"pretest": "npm run lint",
"test": "npm run tests-only",
"pretest-only": "git submodule init && git submodule update",
"tests-only": "make travis",
"build": "make",
"lint": "make fullint",
"dtslint": "dtslint types"

@ -13,8 +13,8 @@ a { text-decoration: none }
<pre>
<b><a href="http://sheetjs.com">SSF (Spreadsheet Number Format) Live Demo</a></b>
<a href="https://git.sheetjs.com/sheetjs/sheetjs/src/branch/master/packages/ssf">Source Code Repo</a>
<a href="https://git.sheetjs.com/SheetJS/sheetjs/issues">Issues? Something look weird? Click here and report an issue</a>
<a href="https://github.com/SheetJS/ssf">Source Code Repo</a>
<a href="https://github.com/SheetJS/ssf/issues">Issues? Something look weird? Click here and report an issue</a>
</pre>
<table>
<tr><td><b>Format code:</b></td><td><input type="text" id="fmt" value="General"></td></tr>

@ -1446,7 +1446,7 @@ SSF.load_table = function load_table(tbl/*:{[n:number]:string}*/) { for(var i=0;
## Fraction Library
The implementation is from [our frac library](https://git.sheetjs.com/SheetJS/frac/):
The implementation is from [our frac library](https://github.com/SheetJS/frac/):
```js>bits/30_frac.js
function frac(x, D, mixed) {

13
test.js

@ -1772,8 +1772,8 @@ describe('roundtrip features', function() {
['xlsx', paths.svxlsx],
['xlsb', paths.svxlsb],
['xls', paths.svxls],
['biff5', paths.svxls5],
['ods', paths.svods]
['biff5', paths.svxls5]
// ['ods', paths.svods]
].forEach(function(w) {
it(w[0], function() {
var wb1 = X.read(fs.readFileSync(w[1]), {type:TYPE});
@ -1783,9 +1783,7 @@ describe('roundtrip features', function() {
assert.equal(wbs1.length, wbs2.length);
for(var i = 0; i < wbs1.length; ++i) {
assert.equal(wbs1[i].name, wbs2[i].name);
/* NOTE: ODS does not support the equivalent of "Very Hidden" */
if(w[0] != "ods") assert.equal(wbs1[i].Hidden, wbs2[i].Hidden);
else assert.equal(!!wbs1[i].Hidden, !!wbs2[i].Hidden);
assert.equal(wbs1[i].Hidden, wbs2[i].Hidden);
}
});
});
@ -3104,11 +3102,6 @@ describe('corner cases', function() {
}
});
});
(fs.existsSync(dir + 'shared_formula.xlsx') ? it : it.skip)('should properly handle defined names in shared formulae', function() {
var wb = X.read(fs.readFileSync(dir + 'shared_formula.xlsx'), {type:TYPE});
var formulae = X.utils.sheet_to_formulae(wb.Sheets[wb.SheetNames[0]]);
assert.equal(formulae[4], 'A5=nvRTX6090');
});
});
describe('encryption', function() {

5
test.mjs generated

@ -3103,11 +3103,6 @@ describe('corner cases', function() {
}
});
});
(fs.existsSync(dir + 'shared_formula.xlsx') ? it : it.skip)('should properly handle defined names in shared formulae', function() {
var wb = X.read(fs.readFileSync(dir + 'shared_formula.xlsx'), {type:TYPE});
var formulae = X.utils.sheet_to_formulae(wb.Sheets[wb.SheetNames[0]]);
assert.equal(formulae[4], 'A5=nvRTX6090');
});
});
describe('encryption', function() {

@ -9,10 +9,10 @@ declare type EmptyFunc = (() => void) | null;
declare var afterEach:(test:EmptyFunc)=>void;
declare var cptable: any;
*/
import * as assert_ from 'https://deno.land/std@0.169.0/testing/asserts.ts';
import * as base64_ from 'https://deno.land/std@0.169.0/encoding/base64.ts';
import * as assert_ from 'https://deno.land/std/testing/asserts.ts';
import * as base64_ from 'https://deno.land/std/encoding/base64.ts';
const assert: any = {...assert_};
assert.throws = function(f: () => void) { assert.assertThrows(function() { try { f(); } catch(e) { throw e instanceof Error ? e : new Error(e as string); }})};
assert.throws = function(f: () => void) { assert.assertThrows(function() { try { f(); } catch(e) { throw e instanceof Error ? e : new Error(e); }})};
assert.doesNotThrow = function(f: ()=>void) { f(); };
assert.equal = assert.assertEquals;
assert.notEqual = assert.assertNotEquals;
@ -36,7 +36,7 @@ function readFileSync2(x: string, e?: ShEncoding): Uint8Array | string {
if(!e) return u8;
switch(e) {
case 'utf-8': return new TextDecoder().decode(u8);
case 'base64': return base64_.encode(u8 as any);
case 'base64': return base64_.encode(u8);
case 'buffer': return u8;
case 'binary': return Array.from({length: u8.length}, (_,i) => String.fromCharCode(u8[i])).join("");
}
@ -2724,7 +2724,7 @@ 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.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});
@ -2736,7 +2736,7 @@ describe('dense mode', function() {
ws = wb.Sheets[wb.SheetNames[0]];
assert.ok(!ws["A1"]);
assert.ok(!!ws["!data"]);
assert.ok(ws["!data"]?.[0]![0]);
assert.ok(ws["!data"]?.[0][0]);
});
});
it('aoa_to_sheet', function() {
@ -2744,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.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"]);
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.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"]);
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() {
@ -3022,11 +3022,6 @@ describe('corner cases', function() {
}
});
});
if(fs.existsSync(dir + 'shared_formula.xlsx')) it('should properly handle defined names in shared formulae', function() {
var wb = X.read(fs.readFileSync(dir + 'shared_formula.xlsx'), {type:TYPE});
var formulae = X.utils.sheet_to_formulae(wb.Sheets[wb.SheetNames[0]]);
assert.equal(formulae[4], 'A5=nvRTX6090');
});
});
describe('encryption', function() {
@ -3038,14 +3033,14 @@ describe('encryption', function() {
X.read(fs.readFileSync(dir + x), {type:TYPE,password:'Password',WTF:opts.WTF});
throw new Error("incorrect password was accepted");
} catch(e) {
if((e as any).message != "Password is incorrect") throw e;
if(e.message != "Password is incorrect") throw e;
}
});
it('should recognize correct password', function() {
try {
X.read(fs.readFileSync(dir + x), {type:TYPE,password:'password',WTF:opts.WTF});
} catch(e) {
if((e as any).message == "Password is incorrect") throw e;
if(e.message == "Password is incorrect") throw e;
}
});
if(false) it('should decrypt file', function() {

19
test.sh

@ -2,12 +2,8 @@
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)
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
if [ -e datetest.js ]; then
nvm use 20
# sudo n 20;
sudo n 20;
for TZ in ${TZONES[@]}; do
echo "$TZ"
env TZ="$TZ" mocha -R dot datetest.js
@ -15,22 +11,19 @@ if [ -e datetest.js ]; then
fi
# min test
for n in 20 10 0.8 0.10 0.12 4 6 8 12 14 16 18 22 24; do
nvm use $n
# sudo n $n
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
nvm use $n
sudo n $n
env WTF=1 TZ="$TZ" make testdot_misc
done
done
# full test
for n in 24 16 0.12; do
for n in 20 10 0.12; do
for TZ in America/New_York Asia/Seoul Asia/Kolkata Europe/Paris; do
# sudo n $n
nvm use $n
sudo n $n
env WTF=1 TZ="$TZ" make testdot
done
done

5
test.test.mjs generated

@ -3103,11 +3103,6 @@ describe('corner cases', function() {
}
});
});
(fs.existsSync(dir + 'shared_formula.xlsx') ? it : it.skip)('should properly handle defined names in shared formulae', function() {
var wb = X.read(fs.readFileSync(dir + 'shared_formula.xlsx'), {type:TYPE});
var formulae = X.utils.sheet_to_formulae(wb.Sheets[wb.SheetNames[0]]);
assert.equal(formulae[4], 'A5=nvRTX6090');
});
});
describe('encryption', function() {

33
test.ts

@ -9,10 +9,10 @@ declare type EmptyFunc = (() => void) | null;
declare var afterEach:(test:EmptyFunc)=>void;
declare var cptable: any;
*/
import * as assert_ from 'https://deno.land/std@0.169.0/testing/asserts.ts';
import * as base64_ from 'https://deno.land/std@0.169.0/encoding/base64.ts';
import * as assert_ from 'https://deno.land/std/testing/asserts.ts';
import * as base64_ from 'https://deno.land/std/encoding/base64.ts';
const assert: any = {...assert_};
assert.throws = function(f: () => void) { assert.assertThrows(function() { try { f(); } catch(e) { throw e instanceof Error ? e : new Error(e as string); }})};
assert.throws = function(f: () => void) { assert.assertThrows(function() { try { f(); } catch(e) { throw e instanceof Error ? e : new Error(e); }})};
assert.doesNotThrow = function(f: ()=>void) { f(); };
assert.equal = assert.assertEquals;
assert.notEqual = assert.assertNotEquals;
@ -36,7 +36,7 @@ function readFileSync2(x: string, e?: ShEncoding): Uint8Array | string {
if(!e) return u8;
switch(e) {
case 'utf-8': return new TextDecoder().decode(u8);
case 'base64': return base64_.encode(u8 as any);
case 'base64': return base64_.encode(u8);
case 'buffer': return u8;
case 'binary': return Array.from({length: u8.length}, (_,i) => String.fromCharCode(u8[i])).join("");
}
@ -2724,7 +2724,7 @@ 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.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});
@ -2736,7 +2736,7 @@ Deno.test('dense mode', async function(t) {
ws = wb.Sheets[wb.SheetNames[0]];
assert.assert(!ws["A1"]);
assert.assert(!!ws["!data"]);
assert.assert(ws["!data"]?.[0]![0]);
assert.assert(ws["!data"]?.[0][0]);
});
});
await t.step('aoa_to_sheet', async function(t) {
@ -2744,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.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"]);
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"]);
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) {
@ -3022,11 +3022,6 @@ Deno.test('corner cases', async function(t) {
}
});
});
if(fs.existsSync(dir + 'shared_formula.xlsx')) await t.step('should properly handle defined names in shared formulae', async function(t) {
var wb = X.read(fs.readFileSync(dir + 'shared_formula.xlsx'), {type:TYPE});
var formulae = X.utils.sheet_to_formulae(wb.Sheets[wb.SheetNames[0]]);
assert.equal(formulae[4], 'A5=nvRTX6090');
});
});
Deno.test('encryption', async function(t) {
@ -3038,14 +3033,14 @@ Deno.test('encryption', async function(t) {
X.read(fs.readFileSync(dir + x), {type:TYPE,password:'Password',WTF:opts.WTF});
throw new Error("incorrect password was accepted");
} catch(e) {
if((e as any).message != "Password is incorrect") throw e;
if(e.message != "Password is incorrect") throw e;
}
});
await t.step('should recognize correct password', async function(t) {
try {
X.read(fs.readFileSync(dir + x), {type:TYPE,password:'password',WTF:opts.WTF});
} catch(e) {
if((e as any).message == "Password is incorrect") throw e;
if(e.message == "Password is incorrect") throw e;
}
});
if(false) await t.step('should decrypt file', async function(t) {

1
test_files Submodule

@ -0,0 +1 @@
Subproject commit 1ea05a3eee0a746c102dea42e729b31e4ebfca35

@ -9,10 +9,10 @@ declare type EmptyFunc = (() => void) | null;
declare var afterEach:(test:EmptyFunc)=>void;
declare var cptable: any;
*/
import * as assert_ from 'https://deno.land/std@0.169.0/testing/asserts.ts';
import * as base64_ from 'https://deno.land/std@0.169.0/encoding/base64.ts';
import * as assert_ from 'https://deno.land/std/testing/asserts.ts';
import * as base64_ from 'https://deno.land/std/encoding/base64.ts';
const assert: any = {...assert_};
assert.throws = function(f: () => void) { assert.assertThrows(function() { try { f(); } catch(e) { throw e instanceof Error ? e : new Error(e as string); }})};
assert.throws = function(f: () => void) { assert.assertThrows(function() { try { f(); } catch(e) { throw e instanceof Error ? e : new Error(e); }})};
assert.doesNotThrow = function(f: ()=>void) { f(); };
assert.equal = assert.assertEquals;
assert.notEqual = assert.assertNotEquals;
@ -35,7 +35,7 @@ function readFileSync2(x: string, e?: ShEncoding): Uint8Array | string {
if(!e) return u8;
switch(e) {
case 'utf-8': return new TextDecoder().decode(u8);
case 'base64': return base64_.encode(u8 as any);
case 'base64': return base64_.encode(u8);
case 'buffer': return u8;
case 'binary': return Array.from({length: u8.length}, (_,i) => String.fromCharCode(u8[i])).join("");
}
@ -2723,7 +2723,7 @@ 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.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,7 @@ Deno.test('dense mode', async function(t) {
ws = wb.Sheets[wb.SheetNames[0]];
assert.assert(!ws["A1"]);
assert.assert(!!ws["!data"]);
assert.assert(ws["!data"]?.[0]![0]);
assert.assert(ws["!data"]?.[0][0]);
});
});
await t.step('aoa_to_sheet', async function(t) {
@ -2743,28 +2743,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.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"]);
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"]);
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) {
@ -3021,11 +3021,6 @@ Deno.test('corner cases', async function(t) {
}
});
});
if(fs.existsSync(dir + 'shared_formula.xlsx')) await t.step('should properly handle defined names in shared formulae', async function(t) {
var wb = X.read(fs.readFileSync(dir + 'shared_formula.xlsx'), {type:TYPE});
var formulae = X.utils.sheet_to_formulae(wb.Sheets[wb.SheetNames[0]]);
assert.equal(formulae[4], 'A5=nvRTX6090');
});
});
Deno.test('encryption', async function(t) {
@ -3037,14 +3032,14 @@ Deno.test('encryption', async function(t) {
X.read(fs.readFileSync(dir + x), {type:TYPE,password:'Password',WTF:opts.WTF});
throw new Error("incorrect password was accepted");
} catch(e) {
if((e as any).message != "Password is incorrect") throw e;
if(e.message != "Password is incorrect") throw e;
}
});
await t.step('should recognize correct password', async function(t) {
try {
X.read(fs.readFileSync(dir + x), {type:TYPE,password:'password',WTF:opts.WTF});
} catch(e) {
if((e as any).message == "Password is incorrect") throw e;
if(e.message == "Password is incorrect") throw e;
}
});
if(false) await t.step('should decrypt file', async function(t) {

@ -690,6 +690,7 @@ apachepoi_15573.xls
apachepoi_1904DateWindowing.xls
apachepoi_19599-1.xls
apachepoi_19599-2.xls
apachepoi_22742.xls
apachepoi_24207.xls
apachepoi_24215.xls
apachepoi_25183.xls

5
tests/core.js generated

@ -3102,11 +3102,6 @@ describe('corner cases', function() {
}
});
});
(fs.existsSync(dir + 'shared_formula.xlsx') ? it : it.skip)('should properly handle defined names in shared formulae', function() {
var wb = X.read(fs.readFileSync(dir + 'shared_formula.xlsx'), {type:TYPE});
var formulae = X.utils.sheet_to_formulae(wb.Sheets[wb.SheetNames[0]]);
assert.equal(formulae[4], 'A5=nvRTX6090');
});
});
describe('encryption', function() {

21
types/index.d.ts vendored

@ -317,9 +317,6 @@ export interface WritingOptions extends CommonOptions {
/** Record Separator ("row separator") for CSV / Text output */
RS?: string;
/** Skip certain validity checks (NOTE: generated files may not open in Excel) */
unsafe?: boolean;
}
/** Workbook Object */
@ -578,14 +575,14 @@ export interface Sheet {
* Dense-mode store cells in the '!data' key
* Special keys start with '!'
*/
[cell: string]: CellObject | DenseSheetData | SheetKeys | any;
[cell: string]: CellObject | CellObject[][] | SheetKeys | any;
/**
* Dense-mode worksheets store data in an array of arrays
*
* Cells are accessed with sheet['!data'][R][C] (where R and C are 0-indexed)
*/
'!data'?: DenseSheetData;
'!data'?: CellObject[][];
/** Sheet type */
'!type'?: SheetType;
@ -602,16 +599,15 @@ export interface DenseSheet extends Sheet {
* Special keys start with '!'
* Dense-mode worksheets store data in the '!data' key
*/
[cell: string]: DenseSheetData | SheetKeys | any;
[cell: string]: CellObject[][] | SheetKeys | any;
/**
* Dense-mode worksheets store data in an array of arrays
*
* Cells are accessed with sheet['!data'][R][C] (where R and C are 0-indexed)
*/
'!data': DenseSheetData;
'!data': CellObject[][];
}
export type DenseSheetData = ((CellObject|undefined)[]|undefined)[];
/** General object representing a sparse Sheet (worksheet or chartsheet) */
export interface SparseSheet extends Sheet {
/**
@ -654,7 +650,14 @@ export interface WorkSheet extends Sheet {
'!autofilter'?: AutoFilterInfo;
}
/** Dense Worksheet Object */
export interface DenseWorkSheet extends DenseSheet {}
export interface DenseWorkSheet extends DenseSheet {
/**
* Dense-mode worksheets store data in an array of arrays
*
* Cells are accessed with sheet['!data'][R][C] (where R and C are 0-indexed)
*/
'!data': CellObject[][];
}
/**
* Worksheet Object with CellObject type