version bump 0.9.0: is_date helper

This commit is contained in:
SheetJS 2017-03-21 03:45:12 -04:00
parent 4fd36de071
commit 354f2bce4f
31 changed files with 2976 additions and 773 deletions

2
.gitignore vendored

@ -1,5 +1,5 @@
node_modules/ node_modules/
tmp/ misc/coverage.html
.vocrc .vocrc
v8.log v8.log
perf.log perf.log

@ -1,7 +1,17 @@
test/*.tsv test/
misc/
node_modules/ node_modules/
tmp/ misc/coverage.html
.gitignore .gitignore
.jshintrc
Makefile
.npmignore
.jscs.json
.gitmodules
.travis.yml
.flowconfig
bits/
.vocrc .vocrc
v8.log v8.log
perf.log perf.log
ssf*.tgz

@ -4,33 +4,57 @@ CMDS=bin/ssf.njs
HTMLLINT= HTMLLINT=
ULIB=$(shell echo $(LIB) | tr a-z A-Z) ULIB=$(shell echo $(LIB) | tr a-z A-Z)
DEPS=$(sort $(wildcard bits/*.js))
TARGET=$(LIB).js TARGET=$(LIB).js
FLOWTARGET=$(LIB).flow.js
FLOWAUX=$(patsubst %.js,%.flow.js,$(AUXTARGETS))
AUXSCPTS=
FLOWTGTS=$(TARGET) $(AUXTARGETS) $(AUXSCPTS)
UGLIFYOPTS=--support-ie8
## Main Targets ## Main Targets
.PHONY: all
all: $(TARGET) $(AUXTARGETS) $(AUXSCPTS) ## Build library and auxiliary scripts
$(FLOWTGTS): %.js : %.flow.js
node -e 'process.stdout.write(require("fs").readFileSync("$<","utf8").replace(/^[ \t]*\/\*[:#][^*]*\*\/\s*(\n)?/gm,"").replace(/\/\*[:#][^*]*\*\//gm,""))' > $@
$(FLOWTARGET): $(DEPS)
cat $^ | tr -d '\15\32' > $@
bits/01_version.js: package.json
echo "$(ULIB).version = '"`grep version package.json | awk '{gsub(/[^0-9a-z\.-]/,"",$$2); print $$2}'`"';" > $@
.PHONY: clean
clean: ## Remove targets and build artifacts
rm -f $(TARGET) $(FLOWTARGET)
.PHONY: ssf
ssf: ssf.md
voc ssf.md
## Testing ## Testing
.PHONY: test mocha .PHONY: test mocha
test mocha: ## Run test suite test mocha: ## Run test suite
npm test mocha -R spec
.PHONY: test_min
test_min: test_min:
MINTEST=1 npm test MINTEST=1 npm test
.PHONY: travis
travis: ## Run test suite with minimal output
mocha -R dot -t 30000
## Code Checking ## Code Checking
.PHONY: lint .PHONY: lint
lint: ## Run jshint and jscs checks lint: $(TARGET) $(AUXTARGETS) ## Run jshint and jscs checks
@jshint --show-non-errors $(TARGET) test/ @jshint --show-non-errors $(TARGET) $(AUXTARGETS)
@jshint --show-non-errors test/
@jshint --show-non-errors $(CMDS) @jshint --show-non-errors $(CMDS)
@jshint --show-non-errors package.json @jshint --show-non-errors package.json
@jshint --show-non-errors --extract=always $(HTMLLINT) @jshint --show-non-errors --extract=always $(HTMLLINT)
@jscs $(TARGET) @jscs $(TARGET) $(AUXTARGETS)
.PHONY: flow .PHONY: flow
flow: lint ## Run flow checker flow: lint ## Run flow checker
@ -43,7 +67,7 @@ cov: tmp/coverage.html ## Run coverage test
cov_min: cov_min:
MINTEST=1 make cov MINTEST=1 make cov
tmp/coverage.html: ssf misc/coverage.html: $(TARGET)
mocha --require blanket -R html-cov -t 20000 > $@ mocha --require blanket -R html-cov -t 20000 > $@
.PHONY: full_coveralls .PHONY: full_coveralls

@ -70,6 +70,7 @@ type SSFDate = {
} }
``` ```
`SSF.is_date(fmt:string):boolean` returns `true` if `fmt` encodes a date format.
## License ## License

4
bits/00_header.js Normal file

@ -0,0 +1,4 @@
/* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */
/*jshint -W041 */
var SSF = {};
var make_ssf = function make_ssf(SSF){

1
bits/01_version.js Normal file

@ -0,0 +1 @@
SSF.version = '0.9.0';

10
bits/02_utilities.js Normal file

@ -0,0 +1,10 @@
function _strrev(x/*:string*/)/*:string*/ { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; }
function fill(c/*:string*/,l/*:number*/)/*:string*/ { var o = ""; while(o.length < l) o+=c; return o; }
function pad0(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
function pad_(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v;return t.length>=d?t:fill(' ',d-t.length)+t;}
function rpad_(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:t+fill(' ',d-t.length);}
function pad0r1(v/*:any*/,d/*:number*/)/*:string*/{var t=""+Math.round(v); return t.length>=d?t:fill('0',d-t.length)+t;}
function pad0r2(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
var p2_32 = Math.pow(2,32);
function pad0r(v/*:any*/,d/*:number*/)/*:string*/{if(v>p2_32||v<-p2_32) return pad0r1(v,d); var i = Math.round(v); return pad0r2(i,d); }
function isgeneral(s/*:string*/, i/*:?number*/)/*:boolean*/ { i = i || 0; return s.length >= 7 + i && (s.charCodeAt(i)|32) === 103 && (s.charCodeAt(i+1)|32) === 101 && (s.charCodeAt(i+2)|32) === 110 && (s.charCodeAt(i+3)|32) === 101 && (s.charCodeAt(i+4)|32) === 114 && (s.charCodeAt(i+5)|32) === 97 && (s.charCodeAt(i+6)|32) === 108; }

10
bits/10_opts.js Normal file

@ -0,0 +1,10 @@
/* Options */
var opts_fmt/*:Array<Array<any> >*/ = [
["date1904", 0],
["output", ""],
["WTF", false]
];
function fixopts(o){
for(var y = 0; y != opts_fmt.length; ++y) if(o[opts_fmt[y][0]]===undefined) o[opts_fmt[y][0]]=opts_fmt[y][1];
}
SSF.opts = opts_fmt;

55
bits/20_consts.js Normal file

@ -0,0 +1,55 @@
var table_fmt = {
/*::[*/0/*::]*/: 'General',
/*::[*/1/*::]*/: '0',
/*::[*/2/*::]*/: '0.00',
/*::[*/3/*::]*/: '#,##0',
/*::[*/4/*::]*/: '#,##0.00',
/*::[*/9/*::]*/: '0%',
/*::[*/10/*::]*/: '0.00%',
/*::[*/11/*::]*/: '0.00E+00',
/*::[*/12/*::]*/: '# ?/?',
/*::[*/13/*::]*/: '# ??/??',
/*::[*/14/*::]*/: 'm/d/yy',
/*::[*/15/*::]*/: 'd-mmm-yy',
/*::[*/16/*::]*/: 'd-mmm',
/*::[*/17/*::]*/: 'mmm-yy',
/*::[*/18/*::]*/: 'h:mm AM/PM',
/*::[*/19/*::]*/: 'h:mm:ss AM/PM',
/*::[*/20/*::]*/: 'h:mm',
/*::[*/21/*::]*/: 'h:mm:ss',
/*::[*/22/*::]*/: 'm/d/yy h:mm',
/*::[*/37/*::]*/: '#,##0 ;(#,##0)',
/*::[*/38/*::]*/: '#,##0 ;[Red](#,##0)',
/*::[*/39/*::]*/: '#,##0.00;(#,##0.00)',
/*::[*/40/*::]*/: '#,##0.00;[Red](#,##0.00)',
/*::[*/45/*::]*/: 'mm:ss',
/*::[*/46/*::]*/: '[h]:mm:ss',
/*::[*/47/*::]*/: 'mmss.0',
/*::[*/48/*::]*/: '##0.0E+0',
/*::[*/49/*::]*/: '@',
/*::[*/56/*::]*/: '"上午/下午 "hh"時"mm"分"ss"秒 "',
/*::[*/65535/*::]*/: 'General'
};
var days/*:Array<Array<string> >*/ = [
['Sun', 'Sunday'],
['Mon', 'Monday'],
['Tue', 'Tuesday'],
['Wed', 'Wednesday'],
['Thu', 'Thursday'],
['Fri', 'Friday'],
['Sat', 'Saturday']
];
var months/*:Array<Array<string> >*/ = [
['J', 'Jan', 'January'],
['F', 'Feb', 'February'],
['M', 'Mar', 'March'],
['A', 'Apr', 'April'],
['M', 'May', 'May'],
['J', 'Jun', 'June'],
['J', 'Jul', 'July'],
['A', 'Aug', 'August'],
['S', 'Sep', 'September'],
['O', 'Oct', 'October'],
['N', 'Nov', 'November'],
['D', 'Dec', 'December']
];

22
bits/30_frac.js Normal file

@ -0,0 +1,22 @@
function frac(x, D, mixed) {
var sgn = x < 0 ? -1 : 1;
var B = x * sgn;
var P_2 = 0, P_1 = 1, P = 0;
var Q_2 = 1, Q_1 = 0, Q = 0;
var A = Math.floor(B);
while(Q_1 < D) {
A = Math.floor(B);
P = A * P_1 + P_2;
Q = A * Q_1 + Q_2;
if((B - A) < 0.0000000005) break;
B = 1 / (B - A);
P_2 = P_1; P_1 = P;
Q_2 = Q_1; Q_1 = Q;
}
if(Q > D) { Q = Q_1; P = P_1; }
if(Q > D) { Q = Q_2; P = P_2; }
if(!mixed) return [0, sgn * P, Q];
if(Q===0) throw "Unexpected state: "+P+" "+P_1+" "+P_2+" "+Q+" "+Q_1+" "+Q_2;
var q = Math.floor(sgn * P/Q);
return [q, sgn*P - q*Q, Q];
}

42
bits/40_general.js Normal file

@ -0,0 +1,42 @@
function general_fmt_int(v/*:number*/, opts/*:?any*/)/*:string*/ { return ""+v; }
SSF._general_int = general_fmt_int;
var general_fmt_num = (function make_general_fmt_num() {
var gnr1 = /\.(\d*[1-9])0+$/, gnr2 = /\.0*$/, gnr4 = /\.(\d*[1-9])0+/, gnr5 = /\.0*[Ee]/, gnr6 = /(E[+-])(\d)$/;
function gfn2(v) {
var w = (v<0?12:11);
var o = gfn5(v.toFixed(12)); if(o.length <= w) return o;
o = v.toPrecision(10); if(o.length <= w) return o;
return v.toExponential(5);
}
function gfn3(v) {
var o = v.toFixed(11).replace(gnr1,".$1");
if(o.length > (v<0?12:11)) o = v.toPrecision(6);
return o;
}
function gfn4(o) {
for(var i = 0; i != o.length; ++i) if((o.charCodeAt(i) | 0x20) === 101) return o.replace(gnr4,".$1").replace(gnr5,"E").replace("e","E").replace(gnr6,"$10$2");
return o;
}
function gfn5(o) {
//for(var i = 0; i != o.length; ++i) if(o.charCodeAt(i) === 46) return o.replace(gnr2,"").replace(gnr1,".$1");
//return o;
return o.indexOf(".") > -1 ? o.replace(gnr2,"").replace(gnr1,".$1") : o;
}
return function general_fmt_num(v/*:number*/, opts/*:?any*/)/*:string*/ {
var V = Math.floor(Math.log(Math.abs(v))*Math.LOG10E), o;
if(V >= -4 && V <= -1) o = v.toPrecision(10+V);
else if(Math.abs(V) <= 9) o = gfn2(v);
else if(V === 10) o = v.toFixed(10).substr(0,12);
else o = gfn3(v);
return gfn5(gfn4(o));
};})();
SSF._general_num = general_fmt_num;
function general_fmt(v/*:any*/, opts/*:?any*/) {
switch(typeof v) {
case 'string': return v;
case 'boolean': return v ? "TRUE" : "FALSE";
case 'number': return (v|0) === v ? general_fmt_int(v, opts) : general_fmt_num(v, opts);
}
throw new Error("unsupported value in General format: " + v);
}
SSF._general = general_fmt;

1
bits/45_hijri.js Normal file

@ -0,0 +1 @@
function fix_hijri(date, o) { return 0; }

103
bits/50_date.js Normal file

@ -0,0 +1,103 @@
function parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) {
if(v > 2958465 || v < 0) return null;
var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
var dout=[];
var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
if(Math.abs(out.u) < 1e-6) out.u = 0;
fixopts(opts != null ? opts : (opts=[]));
if(opts.date1904) date += 1462;
if(out.u > 0.999) {
out.u = 0;
if(++time == 86400) { time = 0; ++date; }
}
if(date === 60) {dout = b2 ? [1317,10,29] : [1900,2,29]; dow=3;}
else if(date === 0) {dout = b2 ? [1317,8,29] : [1900,1,0]; dow=6;}
else {
if(date > 60) --date;
/* 1 = Jan 1 1900 in Gregorian */
var d = new Date(1900, 0, 1);
d.setDate(d.getDate() + date - 1);
dout = [d.getFullYear(), d.getMonth()+1,d.getDate()];
dow = d.getDay();
if(date < 60) dow = (dow + 6) % 7;
if(b2) dow = fix_hijri(d, dout);
}
out.y = dout[0]; out.m = dout[1]; out.d = dout[2];
out.S = time % 60; time = Math.floor(time / 60);
out.M = time % 60; time = Math.floor(time / 60);
out.H = time;
out.q = dow;
return out;
}
SSF.parse_date_code = parse_date_code;
/*jshint -W086 */
function write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*:string*/ {
var o="", ss=0, tt=0, y = val.y, out, outl = 0;
switch(type) {
case 98: /* 'b' buddhist year */
y = val.y + 543;
/* falls through */
case 121: /* 'y' year */
switch(fmt.length) {
case 1: case 2: out = y % 100; outl = 2; break;
default: out = y % 10000; outl = 4; break;
} break;
case 109: /* 'm' month */
switch(fmt.length) {
case 1: case 2: out = val.m; outl = fmt.length; break;
case 3: return months[val.m-1][1];
case 5: return months[val.m-1][0];
default: return months[val.m-1][2];
} break;
case 100: /* 'd' day */
switch(fmt.length) {
case 1: case 2: out = val.d; outl = fmt.length; break;
case 3: return days[val.q][0];
default: return days[val.q][1];
} break;
case 104: /* 'h' 12-hour */
switch(fmt.length) {
case 1: case 2: out = 1+(val.H+11)%12; outl = fmt.length; break;
default: throw 'bad hour format: ' + fmt;
} break;
case 72: /* 'H' 24-hour */
switch(fmt.length) {
case 1: case 2: out = val.H; outl = fmt.length; break;
default: throw 'bad hour format: ' + fmt;
} break;
case 77: /* 'M' minutes */
switch(fmt.length) {
case 1: case 2: out = val.M; outl = fmt.length; break;
default: throw 'bad minute format: ' + fmt;
} break;
case 115: /* 's' seconds */
if(val.u === 0) switch(fmt) {
case 's': case 'ss': return pad0(val.S, fmt.length);
case '.0': case '.00': case '.000':
}
switch(fmt) {
case 's': case 'ss': case '.0': case '.00': case '.000':
/*::if(!ss0) ss0 = 0; */
if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100;
else tt = ss0 === 1 ? 10 : 1;
ss = Math.round((tt)*(val.S + val.u));
if(ss >= 60*tt) ss = 0;
if(fmt === 's') return ss === 0 ? "0" : ""+ss/tt;
o = pad0(ss,2 + ss0);
if(fmt === 'ss') return o.substr(0,2);
return "." + o.substr(2,fmt.length-1);
default: throw 'bad second format: ' + fmt;
}
case 90: /* 'Z' absolute time */
switch(fmt) {
case '[h]': case '[hh]': out = val.D*24+val.H; break;
case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break;
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
default: throw 'bad abstime format: ' + fmt;
} outl = fmt.length === 3 ? 1 : 2; break;
case 101: /* 'e' era */
out = y; outl = 1;
}
if(outl > 0) return pad0(out, outl); else return "";
}
/*jshint +W086 */

6
bits/56_commaify.js Normal file

@ -0,0 +1,6 @@
function commaify(s/*:string*/)/*:string*/ {
if(s.length <= 3) return s;
var j = (s.length % 3), o = s.substr(0,j);
for(; j!=s.length; j+=3) o+=(o.length > 0 ? "," : "") + s.substr(j,3);
return o;
}

1
bits/57_numhead.js Normal file

@ -0,0 +1 @@
var write_num = (function make_write_num(){

5
bits/59_numhelp.js Normal file

@ -0,0 +1,5 @@
var pct1 = /%/g;
function write_num_pct(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{
var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
return write_num(type, sfmt, val * Math.pow(10,2*mul)) + fill("%",mul);
}

265
bits/60_number.js Normal file

@ -0,0 +1,265 @@
function write_num_cm(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{
var idx = fmt.length - 1;
while(fmt.charCodeAt(idx-1) === 44) --idx;
return write_num(type, fmt.substr(0,idx), val / Math.pow(10,3*(fmt.length-idx)));
}
function write_num_exp(fmt/*:string*/, val/*:number*/)/*:string*/{
var o/*:string*/;
var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
if(fmt.match(/^#+0.0E\+0$/)) {
var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
var ee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E)%period;
if(ee < 0) ee += period;
o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
if(o.indexOf("e") === -1) {
var fakee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E);
if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
else o += "E+" + (fakee - ee);
while(o.substr(0,2) === "0.") {
o = o.charAt(0) + o.substr(2,period) + "." + o.substr(2+period);
o = o.replace(/^0+([1-9])/,"$1").replace(/^0+\./,"0.");
}
o = o.replace(/\+-/,"-");
}
o = o.replace(/^([+-]?)(\d*)\.(\d*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,(period+ee)%period) + "." + $3.substr(ee) + "E"; });
} else o = val.toExponential(idx);
if(fmt.match(/E\+00$/) && o.match(/e[+-]\d$/)) o = o.substr(0,o.length-1) + "0" + o.charAt(o.length-1);
if(fmt.match(/E\-/) && o.match(/e\+/)) o = o.replace(/e\+/,"e");
return o.replace("e","E");
}
var frac1 = /# (\?+)( ?)\/( ?)(\d+)/;
function write_num_f1(r/*:Array<string>*/, aval/*:number*/, sign/*:string*/)/*:string*/ {
var den = parseInt(r[4],10), rr = Math.round(aval * den), base = Math.floor(rr/den);
var myn = (rr - base*den), myd = den;
return sign + (base === 0 ? "" : ""+base) + " " + (myn === 0 ? fill(" ", r[1].length + 1 + r[4].length) : pad_(myn,r[1].length) + r[2] + "/" + r[3] + pad0(myd,r[4].length));
}
function write_num_f2(r/*:Array<string>*/, aval/*:number*/, sign/*:string*/)/*:string*/ {
return sign + (aval === 0 ? "" : ""+aval) + fill(" ", r[1].length + 2 + r[4].length);
}
var dec1 = /^#*0*\.(0+)/;
var closeparen = /\).*[0#]/;
var phone = /\(###\) ###\\?-####/;
function hashq(str/*:string*/)/*:string*/ {
var o = "", cc;
for(var i = 0; i != str.length; ++i) switch((cc=str.charCodeAt(i))) {
case 35: break;
case 63: o+= " "; break;
case 48: o+= "0"; break;
default: o+= String.fromCharCode(cc);
}
return o;
}
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*/ {
if (d < ('' + Math.round((val-Math.floor(val))*Math.pow(10,d))).length) {
return 0;
}
return Math.round((val-Math.floor(val))*Math.pow(10,d));
}
function carry(val/*:number*/, d/*:number*/)/*:number*/ {
if (d < ('' + Math.round((val-Math.floor(val))*Math.pow(10,d))).length) {
return 1;
}
return 0;
}
function flr(val/*:number*/)/*:string*/ { if(val < 2147483647 && val > -2147483648) return ""+(val >= 0 ? (val|0) : (val-1|0)); return ""+Math.floor(val); }
function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/ {
if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) {
var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");
if(val >= 0) return write_num_flt('n', ffmt, val);
return '(' + write_num_flt('n', ffmt, -val) + ')';
}
if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm(type, fmt, val);
if(fmt.indexOf('%') !== -1) return write_num_pct(type, fmt, val);
if(fmt.indexOf('E') !== -1) return write_num_exp(fmt, val);
if(fmt.charCodeAt(0) === 36) return "$"+write_num_flt(type,fmt.substr(fmt[1]==' '?2:1),val);
var o;
var r/*:?Array<string>*/, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
if(fmt.match(/^00+$/)) return sign + pad0r(aval,fmt.length);
if(fmt.match(/^[#?]+$/)) {
o = pad0r(val,0); if(o === "0") o = "";
return o.length > fmt.length ? o : hashq(fmt.substr(0,fmt.length-o.length)) + o;
}
if((r = fmt.match(frac1))) return write_num_f1(r, aval, sign);
if(fmt.match(/^#+0+$/)) return sign + pad0r(aval,fmt.length - fmt.indexOf("0"));
if((r = fmt.match(dec1))) {
// $FlowIgnore
o = rnd(val, r[1].length).replace(/^([^\.]+)$/,"$1."+r[1]).replace(/\.$/,"."+r[1]).replace(/\.(\d*)$/,function($$, $1) { return "." + $1 + fill("0", /*::(*/r/*::||[""])*/[1].length-$1.length); });
return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,".");
}
fmt = fmt.replace(/^#+([0.])/, "$1");
if((r = fmt.match(/^(0*)\.(#*)$/))) {
return sign + rnd(aval, r[2].length).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
}
if((r = fmt.match(/^#,##0(\.?)$/))) return sign + commaify(pad0r(aval,0));
if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
return val < 0 ? "-" + write_num_flt(type, fmt, -val) : commaify(""+(Math.floor(val) + carry(val, r[1].length))) + "." + pad0(dec(val, r[1].length),r[1].length);
}
if((r = fmt.match(/^#,#*,#0/))) return write_num_flt(type,fmt.replace(/^#,#*,/,""),val);
if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
o = _strrev(write_num_flt(type, fmt.replace(/[\\-]/g,""), val));
ri = 0;
return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o[ri++]:x==='0'?'0':"";}));
}
if(fmt.match(phone)) {
o = write_num_flt(type, "##########", val);
return "(" + o.substr(0,3) + ") " + o.substr(3, 3) + "-" + o.substr(6);
}
var oa = "";
if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) {
ri = Math.min(/*::String(*/r[4]/*::)*/.length,7);
ff = frac(aval, Math.pow(10,ri)-1, false);
o = "" + sign;
oa = write_num("n", /*::String(*/r[1]/*::)*/, ff[1]);
if(oa[oa.length-1] == " ") oa = oa.substr(0,oa.length-1) + "0";
o += oa + /*::String(*/r[2]/*::)*/ + "/" + /*::String(*/r[3]/*::)*/;
oa = rpad_(ff[2],ri);
if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
o += oa;
return o;
}
if((r = fmt.match(/^# ([#0?]+)( ?)\/( ?)([#0?]+)/))) {
ri = Math.min(Math.max(r[1].length, r[4].length),7);
ff = frac(aval, Math.pow(10,ri)-1, true);
return sign + (ff[0]||(ff[1] ? "" : "0")) + " " + (ff[1] ? pad_(ff[1],ri) + r[2] + "/" + r[3] + rpad_(ff[2],ri): fill(" ", 2*ri+1 + r[2].length + r[3].length));
}
if((r = fmt.match(/^[#0?]+$/))) {
o = pad0r(val, 0);
if(fmt.length <= o.length) return o;
return hashq(fmt.substr(0,fmt.length-o.length)) + o;
}
if((r = fmt.match(/^([#0?]+)\.([#0]+)$/))) {
o = "" + val.toFixed(Math.min(r[2].length,10)).replace(/([^0])0+$/,"$1");
ri = o.indexOf(".");
var lres = fmt.indexOf(".") - ri, rres = fmt.length - o.length - lres;
return hashq(fmt.substr(0,lres) + o + fmt.substr(fmt.length-rres));
}
if((r = fmt.match(/^00,000\.([#0]*0)$/))) {
ri = dec(val, r[1].length);
return val < 0 ? "-" + write_num_flt(type, fmt, -val) : commaify(flr(val)).replace(/^\d,\d{3}$/,"0$&").replace(/^\d*$/,function($$) { return "00," + ($$.length < 3 ? pad0(0,3-$$.length) : "") + $$; }) + "." + pad0(ri,r[1].length);
}
switch(fmt) {
case "#,###": var x = commaify(pad0r(aval,0)); return x !== "0" ? sign + x : "";
default:
}
throw new Error("unsupported format |" + fmt + "|");
}
function write_num_cm2(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{
var idx = fmt.length - 1;
while(fmt.charCodeAt(idx-1) === 44) --idx;
return write_num(type, fmt.substr(0,idx), val / Math.pow(10,3*(fmt.length-idx)));
}
function write_num_pct2(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{
var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
return write_num(type, sfmt, val * Math.pow(10,2*mul)) + fill("%",mul);
}
function write_num_exp2(fmt/*:string*/, val/*:number*/)/*:string*/{
var o/*:string*/;
var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
if(fmt.match(/^#+0.0E\+0$/)) {
var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
var ee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E)%period;
if(ee < 0) ee += period;
o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
if(!o.match(/[Ee]/)) {
var fakee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E);
if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
else o += "E+" + (fakee - ee);
o = o.replace(/\+-/,"-");
}
o = o.replace(/^([+-]?)(\d*)\.(\d*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,(period+ee)%period) + "." + $3.substr(ee) + "E"; });
} else o = val.toExponential(idx);
if(fmt.match(/E\+00$/) && o.match(/e[+-]\d$/)) o = o.substr(0,o.length-1) + "0" + o.charAt(o.length-1);
if(fmt.match(/E\-/) && o.match(/e\+/)) o = o.replace(/e\+/,"e");
return o.replace("e","E");
}
function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/ {
if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) {
var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");
if(val >= 0) return write_num_int('n', ffmt, val);
return '(' + write_num_int('n', ffmt, -val) + ')';
}
if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm2(type, fmt, val);
if(fmt.indexOf('%') !== -1) return write_num_pct2(type, fmt, val);
if(fmt.indexOf('E') !== -1) return write_num_exp2(fmt, val);
if(fmt.charCodeAt(0) === 36) return "$"+write_num_int(type,fmt.substr(fmt[1]==' '?2:1),val);
var o;
var r, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
if(fmt.match(/^00+$/)) return sign + pad0(aval,fmt.length);
if(fmt.match(/^[#?]+$/)) {
o = (""+val); if(val === 0) o = "";
return o.length > fmt.length ? o : hashq(fmt.substr(0,fmt.length-o.length)) + o;
}
if((r = fmt.match(frac1))) return write_num_f2(r, aval, sign);
if(fmt.match(/^#+0+$/)) return sign + pad0(aval,fmt.length - fmt.indexOf("0"));
if((r = fmt.match(dec1))) {
/*:: if(!Array.isArray(r)) throw "unreachable"; */
// $FlowIgnore
o = (""+val).replace(/^([^\.]+)$/,"$1."+r[1]).replace(/\.$/,"."+r[1]);
// $FlowIgnore
o = o.replace(/\.(\d*)$/,function($$, $1) {
/*:: if(!Array.isArray(r)) throw "unreachable"; */
// $FlowIgnore
return "." + $1 + fill("0", r[1].length-$1.length); });
// $FlowIgnore
return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,".");
}
fmt = fmt.replace(/^#+([0.])/, "$1");
if((r = fmt.match(/^(0*)\.(#*)$/))) {
return sign + (""+aval).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
}
if((r = fmt.match(/^#,##0(\.?)$/))) return sign + commaify((""+aval));
if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
return val < 0 ? "-" + write_num_int(type, fmt, -val) : commaify((""+val)) + "." + fill('0',r[1].length);
}
if((r = fmt.match(/^#,#*,#0/))) return write_num_int(type,fmt.replace(/^#,#*,/,""),val);
if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
o = _strrev(write_num_int(type, fmt.replace(/[\\-]/g,""), val));
ri = 0;
return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o[ri++]:x==='0'?'0':"";}));
}
if(fmt.match(phone)) {
o = write_num_int(type, "##########", val);
return "(" + o.substr(0,3) + ") " + o.substr(3, 3) + "-" + o.substr(6);
}
var oa = "";
if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) {
ri = Math.min(r[4].length,7);
ff = frac(aval, Math.pow(10,ri)-1, false);
o = "" + sign;
oa = write_num("n", r[1], ff[1]);
if(oa[oa.length-1] == " ") oa = oa.substr(0,oa.length-1) + "0";
o += oa + r[2] + "/" + r[3];
oa = rpad_(ff[2],ri);
if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
o += oa;
return o;
}
if((r = fmt.match(/^# ([#0?]+)( ?)\/( ?)([#0?]+)/))) {
ri = Math.min(Math.max(r[1].length, r[4].length),7);
ff = frac(aval, Math.pow(10,ri)-1, true);
return sign + (ff[0]||(ff[1] ? "" : "0")) + " " + (ff[1] ? pad_(ff[1],ri) + r[2] + "/" + r[3] + rpad_(ff[2],ri): fill(" ", 2*ri+1 + r[2].length + r[3].length));
}
if((r = fmt.match(/^[#0?]+$/))) {
o = "" + val;
if(fmt.length <= o.length) return o;
return hashq(fmt.substr(0,fmt.length-o.length)) + o;
}
if((r = fmt.match(/^([#0]+)\.([#0]+)$/))) {
o = "" + val.toFixed(Math.min(r[2].length,10)).replace(/([^0])0+$/,"$1");
ri = o.indexOf(".");
var lres = fmt.indexOf(".") - ri, rres = fmt.length - o.length - lres;
return hashq(fmt.substr(0,lres) + o + fmt.substr(fmt.length-rres));
}
if((r = fmt.match(/^00,000\.([#0]*0)$/))) {
return val < 0 ? "-" + write_num_int(type, fmt, -val) : commaify(""+val).replace(/^\d,\d{3}$/,"0$&").replace(/^\d*$/,function($$) { return "00," + ($$.length < 3 ? pad0(0,3-$$.length) : "") + $$; }) + "." + pad0(0,r[1].length);
}
switch(fmt) {
case "#,###": var x = commaify(""+aval); return x !== "0" ? sign + x : "";
default:
}
throw new Error("unsupported format |" + fmt + "|");
}
return function write_num(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/ {
return (val|0) === val ? write_num_int(type, fmt, val) : write_num_flt(type, fmt, val);
};})();

17
bits/80_split.js Normal file

@ -0,0 +1,17 @@
function split_fmt(fmt/*:string*/)/*:Array<string>*/ {
var out/*:Array<string>*/ = [];
var in_str = false, cc;
for(var i = 0, j = 0; i < fmt.length; ++i) switch((cc=fmt.charCodeAt(i))) {
case 34: /* '"' */
in_str = !in_str; break;
case 95: case 42: case 92: /* '_' '*' '\\' */
++i; break;
case 59: /* ';' */
out[out.length] = fmt.substr(j,i-j);
j = i+1;
}
out[out.length] = fmt.substr(j);
if(in_str === true) throw new Error("Format |" + fmt + "| unterminated string ");
return out;
}
SSF._split = split_fmt;

42
bits/81_fmttype.js Normal file

@ -0,0 +1,42 @@
var abstime = /\[[HhMmSs]*\]/;
function fmt_is_date(fmt/*:string*/)/*:boolean*/ {
var i = 0, cc = 0, c = "", o = "";
while(i < fmt.length) {
switch((c = fmt.charAt(i))) {
case 'G': if(isgeneral(fmt, i)) i+= 6; i++; break;
case '"': for(;(cc=fmt.charCodeAt(++i)) !== 34 && i < fmt.length;) ++i; ++i; break;
case '\\': i+=2; break;
case '_': i+=2; break;
case '@': ++i; break;
case 'B': case 'b':
if(fmt.charAt(i+1) === "1" || fmt.charAt(i+1) === "2") return true;
/* falls through */
case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E':
/* falls through */
case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g': return true;
case 'A':
if(fmt.substr(i, 3) === "A/P") return true;
if(fmt.substr(i, 5) === "AM/PM") return true;
++i; break;
case '[':
o = c;
while(fmt.charAt(i++) !== ']' && i < fmt.length) o += fmt.charAt(i);
if(o.match(abstime)) return true;
break;
case '.':
/* falls through */
case '0': case '#':
while(i < fmt.length && ("0#?.,E+-%".indexOf(c=fmt.charAt(++i)) > -1 || c=='\\' && fmt.charAt(i+1) == "-" && "0#".indexOf(fmt.charAt(i+2))>-1));
break;
case '?': while(fmt.charAt(++i) === c); break;
case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break;
case '(': case ')': ++i; break;
case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1); break;
case ' ': ++i; break;
default: ++i; break;
}
}
return false;
}
SSF.is_date = fmt_is_date;

189
bits/82_eval.js Normal file

@ -0,0 +1,189 @@
function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
var out = [], o = "", i = 0, c = "", lst='t', q, dt, j, cc;
var hr='H';
/* Tokenize */
while(i < fmt.length) {
switch((c = fmt.charAt(i))) {
case 'G': /* General */
if(!isgeneral(fmt, i)) throw new Error('unrecognized character ' + c + ' in ' +fmt);
out[out.length] = {t:'G', v:'General'}; i+=7; break;
case '"': /* Literal text */
for(o="";(cc=fmt.charCodeAt(++i)) !== 34 && i < fmt.length;) o += String.fromCharCode(cc);
out[out.length] = {t:'t', v:o}; ++i; break;
case '\\': var w = fmt.charAt(++i), t = (w === "(" || w === ")") ? w : 't';
out[out.length] = {t:t, v:w}; ++i; break;
case '_': out[out.length] = {t:'t', v:" "}; i+=2; break;
case '@': /* Text Placeholder */
out[out.length] = {t:'T', v:v}; ++i; break;
case 'B': case 'b':
if(fmt.charAt(i+1) === "1" || fmt.charAt(i+1) === "2") {
if(dt==null) { dt=parse_date_code(v, opts, fmt.charAt(i+1) === "2"); if(dt==null) return ""; }
out[out.length] = {t:'X', v:fmt.substr(i,2)}; lst = c; i+=2; break;
}
/* falls through */
case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E':
c = c.toLowerCase();
/* falls through */
case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g':
if(v < 0) return "";
if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
o = c; while(++i<fmt.length && fmt.charAt(i).toLowerCase() === c) o+=c;
if(c === 'm' && lst.toLowerCase() === 'h') c = 'M'; /* m = minute */
if(c === 'h') c = hr;
out[out.length] = {t:c, v:o}; lst = c; break;
case 'A':
q={t:c, v:"A"};
if(dt==null) dt=parse_date_code(v, opts);
if(fmt.substr(i, 3) === "A/P") { if(dt!=null) q.v = dt.H >= 12 ? "P" : "A"; q.t = 'T'; hr='h';i+=3;}
else if(fmt.substr(i,5) === "AM/PM") { if(dt!=null) q.v = dt.H >= 12 ? "PM" : "AM"; q.t = 'T'; i+=5; hr='h'; }
else { q.t = "t"; ++i; }
if(dt==null && q.t === 'T') return "";
out[out.length] = q; lst = c; break;
case '[':
o = c;
while(fmt.charAt(i++) !== ']' && i < fmt.length) o += fmt.charAt(i);
if(o.slice(-1) !== ']') throw 'unterminated "[" block: |' + o + '|';
if(o.match(abstime)) {
if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
out[out.length] = {t:'Z', v:o.toLowerCase()};
} else { o=""; }
break;
/* Numbers */
case '.':
if(dt != null) {
o = c; while((c=fmt.charAt(++i)) === "0") o += c;
out[out.length] = {t:'s', v:o}; break;
}
/* falls through */
case '0': case '#':
o = c; while(++i < fmt.length && "0#?.,E+-%".indexOf(c=fmt.charAt(i)) > -1 || c=='\\' && fmt.charAt(i+1) == "-" && "0#".indexOf(fmt.charAt(i+2))>-1) o += c;
out[out.length] = {t:'n', v:o}; break;
case '?':
o = c; while(fmt.charAt(++i) === c) o+=c;
q={t:c, v:o}; out[out.length] = q; lst = c; break;
case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break; // **
case '(': case ')': out[out.length] = {t:(flen===1?'t':c), v:c}; ++i; break;
case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
o = c; while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1) o+=fmt.charAt(i);
out[out.length] = {t:'D', v:o}; break;
case ' ': out[out.length] = {t:c, v:c}; ++i; break;
default:
if(",$-+/():!^&'~{}<>=€acfijklopqrtuvwxz".indexOf(c) === -1) throw new Error('unrecognized character ' + c + ' in ' + fmt);
out[out.length] = {t:'t', v:c}; ++i; break;
}
}
var bt = 0, ss0 = 0, ssm;
for(i=out.length-1, lst='t'; i >= 0; --i) {
switch(out[i].t) {
case 'h': case 'H': out[i].t = hr; lst='h'; if(bt < 1) bt = 1; break;
case 's':
if((ssm=out[i].v.match(/\.0+$/))) ss0=Math.max(ss0,ssm[0].length-1);
if(bt < 3) bt = 3;
/* falls through */
case 'd': case 'y': case 'M': case 'e': lst=out[i].t; break;
case 'm': if(lst === 's') { out[i].t = 'M'; if(bt < 2) bt = 2; } break;
case 'X': if(out[i].v === "B2");
break;
case 'Z':
if(bt < 1 && out[i].v.match(/[Hh]/)) bt = 1;
if(bt < 2 && out[i].v.match(/[Mm]/)) bt = 2;
if(bt < 3 && out[i].v.match(/[Ss]/)) bt = 3;
}
}
switch(bt) {
case 0: break;
case 1:
/*::if(!dt) break;*/
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
break;
case 2:
/*::if(!dt) break;*/
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
break;
}
/* replace fields */
var nstr = "", jj;
for(i=0; i < out.length; ++i) {
switch(out[i].t) {
case 't': case 'T': case ' ': case 'D': break;
case 'X': out[i].v = ""; out[i].t = ";"; break;
case 'd': case 'm': case 'y': case 'h': case 'H': case 'M': case 's': case 'e': case 'b': case 'Z':
/*::if(!dt) throw "unreachable"; */
out[i].v = write_date(out[i].t.charCodeAt(0), out[i].v, dt, ss0);
out[i].t = 't'; break;
case 'n': case '(': case '?':
jj = i+1;
while(out[jj] != null && (
(c=out[jj].t) === "?" || c === "D" ||
(c === " " || c === "t") && out[jj+1] != null && (out[jj+1].t === '?' || out[jj+1].t === "t" && out[jj+1].v === '/') ||
out[i].t === '(' && (c === ' ' || c === 'n' || c === ')') ||
c === 't' && (out[jj].v === '/' || '$€'.indexOf(out[jj].v) > -1 || out[jj].v === ' ' && out[jj+1] != null && out[jj+1].t == '?')
)) {
out[i].v += out[jj].v;
out[jj] = {v:"", t:";"}; ++jj;
}
nstr += out[i].v;
i = jj-1; break;
case 'G': out[i].t = 't'; out[i].v = general_fmt(v,opts); break;
}
}
var vv = "", myv, ostr;
if(nstr.length > 0) {
myv = (v<0&&nstr.charCodeAt(0) === 45 ? -v : v); /* '-' */
ostr = write_num(nstr.charCodeAt(0) === 40 ? '(' : 'n', nstr, myv); /* '(' */
jj=ostr.length-1;
var decpt = out.length;
for(i=0; i < out.length; ++i) if(out[i] != null && out[i].v.indexOf(".") > -1) { decpt = i; break; }
var lasti=out.length;
if(decpt === out.length && ostr.indexOf("E") === -1) {
for(i=out.length-1; i>= 0;--i) {
if(out[i] == null || 'n?('.indexOf(out[i].t) === -1) continue;
if(jj>=out[i].v.length-1) { jj -= out[i].v.length; out[i].v = ostr.substr(jj+1, out[i].v.length); }
else if(jj < 0) out[i].v = "";
else { out[i].v = ostr.substr(0, jj+1); jj = -1; }
out[i].t = 't';
lasti = i;
}
if(jj>=0 && lasti<out.length) out[lasti].v = ostr.substr(0,jj+1) + out[lasti].v;
}
else if(decpt !== out.length && ostr.indexOf("E") === -1) {
jj = ostr.indexOf(".")-1;
for(i=decpt; i>= 0; --i) {
if(out[i] == null || 'n?('.indexOf(out[i].t) === -1) continue;
j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")-1:out[i].v.length-1;
vv = out[i].v.substr(j+1);
for(; j>=0; --j) {
if(jj>=0 && (out[i].v[j] === "0" || out[i].v[j] === "#")) vv = ostr[jj--] + vv;
}
out[i].v = vv;
out[i].t = 't';
lasti = i;
}
if(jj>=0 && lasti<out.length) out[lasti].v = ostr.substr(0,jj+1) + out[lasti].v;
jj = ostr.indexOf(".")+1;
for(i=decpt; i<out.length; ++i) {
if(out[i] == null || 'n?('.indexOf(out[i].t) === -1 && i !== decpt ) continue;
j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")+1:0;
vv = out[i].v.substr(0,j);
for(; j<out[i].v.length; ++j) {
if(jj<ostr.length) vv += ostr[jj++];
}
out[i].v = vv;
out[i].t = 't';
lasti = i;
}
}
}
for(i=0; i<out.length; ++i) if(out[i] != null && 'n(?'.indexOf(out[i].t)>-1) {
myv = (flen >1 && v < 0 && i>0 && out[i-1].v === "-" ? -v:v);
out[i].v = write_num(out[i].t, out[i].v, myv);
out[i].t = 't';
}
var retval = "";
for(i=0; i !== out.length; ++i) if(out[i] != null) retval += out[i].v;
return retval;
}
SSF._eval = eval_fmt;

15
bits/88_cond.js Normal file

@ -0,0 +1,15 @@
var cfregex = /\[[=<>]/;
var cfregex2 = /\[([=<>]*)(-?\d+\.?\d*)\]/;
function chkcond(v, rr) {
if(rr == null) return false;
var thresh = parseFloat(rr[2]);
switch(rr[1]) {
case "=": if(v == thresh) return true; break;
case ">": if(v > thresh) return true; break;
case "<": if(v < thresh) return true; break;
case "<>": if(v != thresh) return true; break;
case ">=": if(v >= thresh) return true; break;
case "<=": if(v <= thresh) return true; break;
}
return false;
}

35
bits/90_main.js Normal file

@ -0,0 +1,35 @@
function choose_fmt(f/*:string*/, v) {
var fmt = split_fmt(f);
var l = fmt.length, lat = fmt[l-1].indexOf("@");
if(l<4 && lat>-1) --l;
if(fmt.length > 4) throw new Error("cannot find right format for |" + fmt.join("|") + "|");
if(typeof v !== "number") return [4, fmt.length === 4 || lat>-1?fmt[fmt.length-1]:"@"];
switch(fmt.length) {
case 1: fmt = lat>-1 ? ["General", "General", "General", fmt[0]] : [fmt[0], fmt[0], fmt[0], "@"]; break;
case 2: fmt = lat>-1 ? [fmt[0], fmt[0], fmt[0], fmt[1]] : [fmt[0], fmt[1], fmt[0], "@"]; break;
case 3: fmt = lat>-1 ? [fmt[0], fmt[1], fmt[0], fmt[2]] : [fmt[0], fmt[1], fmt[2], "@"]; break;
case 4: break;
}
var ff = v > 0 ? fmt[0] : v < 0 ? fmt[1] : fmt[2];
if(fmt[0].indexOf("[") === -1 && fmt[1].indexOf("[") === -1) return [l, ff];
if(fmt[0].match(cfregex) != null || fmt[1].match(cfregex) != null) {
var m1 = fmt[0].match(cfregex2);
var m2 = fmt[1].match(cfregex2);
return chkcond(v, m1) ? [l, fmt[0]] : chkcond(v, m2) ? [l, fmt[1]] : [l, fmt[m1 != null && m2 != null ? 2 : 1]];
}
return [l, ff];
}
function format(fmt/*:string|number*/,v/*:any*/,o/*:?any*/) {
fixopts(o != null ? o : (o=[]));
var sfmt = "";
switch(typeof fmt) {
case "string": sfmt = fmt; break;
case "number": sfmt = (o.table != null ? (o.table/*:any*/) : table_fmt)[fmt]; break;
}
if(isgeneral(sfmt,0)) return general_fmt(v, o);
var f = choose_fmt(sfmt, v);
if(isgeneral(f[1])) return general_fmt(v, o);
if(v === true) v = "TRUE"; else if(v === false) v = "FALSE";
else if(v === "" || v == null) return "";
return eval_fmt(f[1], v, o, f[0]);
}

5
bits/98_exports.js Normal file

@ -0,0 +1,5 @@
SSF._table = table_fmt;
SSF.load = function load_entry(fmt/*:string*/, idx/*:number*/) { table_fmt[idx] = fmt; };
SSF.format = format;
SSF.get_table = function get_table() { return table_fmt; };
SSF.load_table = function load_table(tbl/*:{[n:number]:string}*/) { for(var i=0; i!=0x0188; ++i) if(tbl[i] !== undefined) SSF.load(tbl[i], i); };

5
bits/99_footer.js Normal file

@ -0,0 +1,5 @@
};
make_ssf(SSF);
/*global module */
/*:: declare var DO_NOT_EXPORT_SSF: any; */
if(typeof module !== 'undefined' && typeof DO_NOT_EXPORT_SSF === 'undefined') module.exports = SSF;

@ -3,6 +3,7 @@
type SSFModule = { type SSFModule = {
format(fmt:string|number, v:any, o:any):string; format(fmt:string|number, v:any, o:any):string;
is_date(fmt:string):boolean;
}; };
*/ */

@ -1,31 +1,33 @@
{ {
"name": "ssf", "name": "ssf",
"version": "0.8.1", "version": "0.9.0",
"author": "SheetJS", "author": "SheetJS",
"description": "Format data using ECMA-376 spreadsheet Format Codes", "description": "Format data using ECMA-376 spreadsheet Format Codes",
"keywords": [ "format", "sprintf", "spreadsheet" ], "keywords": [ "format", "sprintf", "spreadsheet" ],
"main": "ssf.js", "bin": {
"dependencies": { "ssf": "./bin/ssf.njs"
"voc":"", },
"colors":"0.6.2", "main": "./ssf",
"frac":"0.3.1" "dependencies": {
}, "voc":"",
"devDependencies": { "colors":"0.6.2",
"mocha":"" "frac":"0.3.1"
}, },
"repository": { "type":"git", "url":"git://github.com/SheetJS/ssf.git" }, "devDependencies": {
"scripts": { "mocha":"",
"test": "mocha -R spec" "uglify-js":""
}, },
"bin": { "repository": { "type":"git", "url":"git://github.com/SheetJS/ssf.git" },
"ssf": "./bin/ssf.njs" "scripts": {
}, "test": "make test"
"config": { },
"blanket": { "config": {
"pattern": "ssf.js" "blanket": {
} "pattern": "ssf.js"
}, }
"bugs": { "url": "https://github.com/SheetJS/ssf/issues" }, },
"license": "Apache-2.0", "homepage": "https://oss.sheetjs.com/ssf",
"engines": { "node": ">=0.8" } "bugs": { "url": "https://github.com/SheetJS/ssf/issues" },
"license": "Apache-2.0",
"engines": { "node": ">=0.8" }
} }

833
ssf.flow.js Normal file

@ -0,0 +1,833 @@
/* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */
/*jshint -W041 */
var SSF = {};
var make_ssf = function make_ssf(SSF){
SSF.version = '0.9.0';
function _strrev(x/*:string*/)/*:string*/ { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; }
function fill(c/*:string*/,l/*:number*/)/*:string*/ { var o = ""; while(o.length < l) o+=c; return o; }
function pad0(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
function pad_(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v;return t.length>=d?t:fill(' ',d-t.length)+t;}
function rpad_(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:t+fill(' ',d-t.length);}
function pad0r1(v/*:any*/,d/*:number*/)/*:string*/{var t=""+Math.round(v); return t.length>=d?t:fill('0',d-t.length)+t;}
function pad0r2(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
var p2_32 = Math.pow(2,32);
function pad0r(v/*:any*/,d/*:number*/)/*:string*/{if(v>p2_32||v<-p2_32) return pad0r1(v,d); var i = Math.round(v); return pad0r2(i,d); }
function isgeneral(s/*:string*/, i/*:?number*/)/*:boolean*/ { i = i || 0; return s.length >= 7 + i && (s.charCodeAt(i)|32) === 103 && (s.charCodeAt(i+1)|32) === 101 && (s.charCodeAt(i+2)|32) === 110 && (s.charCodeAt(i+3)|32) === 101 && (s.charCodeAt(i+4)|32) === 114 && (s.charCodeAt(i+5)|32) === 97 && (s.charCodeAt(i+6)|32) === 108; }
/* Options */
var opts_fmt/*:Array<Array<any> >*/ = [
["date1904", 0],
["output", ""],
["WTF", false]
];
function fixopts(o){
for(var y = 0; y != opts_fmt.length; ++y) if(o[opts_fmt[y][0]]===undefined) o[opts_fmt[y][0]]=opts_fmt[y][1];
}
SSF.opts = opts_fmt;
var table_fmt = {
/*::[*/0/*::]*/: 'General',
/*::[*/1/*::]*/: '0',
/*::[*/2/*::]*/: '0.00',
/*::[*/3/*::]*/: '#,##0',
/*::[*/4/*::]*/: '#,##0.00',
/*::[*/9/*::]*/: '0%',
/*::[*/10/*::]*/: '0.00%',
/*::[*/11/*::]*/: '0.00E+00',
/*::[*/12/*::]*/: '# ?/?',
/*::[*/13/*::]*/: '# ??/??',
/*::[*/14/*::]*/: 'm/d/yy',
/*::[*/15/*::]*/: 'd-mmm-yy',
/*::[*/16/*::]*/: 'd-mmm',
/*::[*/17/*::]*/: 'mmm-yy',
/*::[*/18/*::]*/: 'h:mm AM/PM',
/*::[*/19/*::]*/: 'h:mm:ss AM/PM',
/*::[*/20/*::]*/: 'h:mm',
/*::[*/21/*::]*/: 'h:mm:ss',
/*::[*/22/*::]*/: 'm/d/yy h:mm',
/*::[*/37/*::]*/: '#,##0 ;(#,##0)',
/*::[*/38/*::]*/: '#,##0 ;[Red](#,##0)',
/*::[*/39/*::]*/: '#,##0.00;(#,##0.00)',
/*::[*/40/*::]*/: '#,##0.00;[Red](#,##0.00)',
/*::[*/45/*::]*/: 'mm:ss',
/*::[*/46/*::]*/: '[h]:mm:ss',
/*::[*/47/*::]*/: 'mmss.0',
/*::[*/48/*::]*/: '##0.0E+0',
/*::[*/49/*::]*/: '@',
/*::[*/56/*::]*/: '"上午/下午 "hh"時"mm"分"ss"秒 "',
/*::[*/65535/*::]*/: 'General'
};
var days/*:Array<Array<string> >*/ = [
['Sun', 'Sunday'],
['Mon', 'Monday'],
['Tue', 'Tuesday'],
['Wed', 'Wednesday'],
['Thu', 'Thursday'],
['Fri', 'Friday'],
['Sat', 'Saturday']
];
var months/*:Array<Array<string> >*/ = [
['J', 'Jan', 'January'],
['F', 'Feb', 'February'],
['M', 'Mar', 'March'],
['A', 'Apr', 'April'],
['M', 'May', 'May'],
['J', 'Jun', 'June'],
['J', 'Jul', 'July'],
['A', 'Aug', 'August'],
['S', 'Sep', 'September'],
['O', 'Oct', 'October'],
['N', 'Nov', 'November'],
['D', 'Dec', 'December']
];
function frac(x, D, mixed) {
var sgn = x < 0 ? -1 : 1;
var B = x * sgn;
var P_2 = 0, P_1 = 1, P = 0;
var Q_2 = 1, Q_1 = 0, Q = 0;
var A = Math.floor(B);
while(Q_1 < D) {
A = Math.floor(B);
P = A * P_1 + P_2;
Q = A * Q_1 + Q_2;
if((B - A) < 0.0000000005) break;
B = 1 / (B - A);
P_2 = P_1; P_1 = P;
Q_2 = Q_1; Q_1 = Q;
}
if(Q > D) { Q = Q_1; P = P_1; }
if(Q > D) { Q = Q_2; P = P_2; }
if(!mixed) return [0, sgn * P, Q];
if(Q===0) throw "Unexpected state: "+P+" "+P_1+" "+P_2+" "+Q+" "+Q_1+" "+Q_2;
var q = Math.floor(sgn * P/Q);
return [q, sgn*P - q*Q, Q];
}
function general_fmt_int(v/*:number*/, opts/*:?any*/)/*:string*/ { return ""+v; }
SSF._general_int = general_fmt_int;
var general_fmt_num = (function make_general_fmt_num() {
var gnr1 = /\.(\d*[1-9])0+$/, gnr2 = /\.0*$/, gnr4 = /\.(\d*[1-9])0+/, gnr5 = /\.0*[Ee]/, gnr6 = /(E[+-])(\d)$/;
function gfn2(v) {
var w = (v<0?12:11);
var o = gfn5(v.toFixed(12)); if(o.length <= w) return o;
o = v.toPrecision(10); if(o.length <= w) return o;
return v.toExponential(5);
}
function gfn3(v) {
var o = v.toFixed(11).replace(gnr1,".$1");
if(o.length > (v<0?12:11)) o = v.toPrecision(6);
return o;
}
function gfn4(o) {
for(var i = 0; i != o.length; ++i) if((o.charCodeAt(i) | 0x20) === 101) return o.replace(gnr4,".$1").replace(gnr5,"E").replace("e","E").replace(gnr6,"$10$2");
return o;
}
function gfn5(o) {
//for(var i = 0; i != o.length; ++i) if(o.charCodeAt(i) === 46) return o.replace(gnr2,"").replace(gnr1,".$1");
//return o;
return o.indexOf(".") > -1 ? o.replace(gnr2,"").replace(gnr1,".$1") : o;
}
return function general_fmt_num(v/*:number*/, opts/*:?any*/)/*:string*/ {
var V = Math.floor(Math.log(Math.abs(v))*Math.LOG10E), o;
if(V >= -4 && V <= -1) o = v.toPrecision(10+V);
else if(Math.abs(V) <= 9) o = gfn2(v);
else if(V === 10) o = v.toFixed(10).substr(0,12);
else o = gfn3(v);
return gfn5(gfn4(o));
};})();
SSF._general_num = general_fmt_num;
function general_fmt(v/*:any*/, opts/*:?any*/) {
switch(typeof v) {
case 'string': return v;
case 'boolean': return v ? "TRUE" : "FALSE";
case 'number': return (v|0) === v ? general_fmt_int(v, opts) : general_fmt_num(v, opts);
}
throw new Error("unsupported value in General format: " + v);
}
SSF._general = general_fmt;
function fix_hijri(date, o) { return 0; }
function parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) {
if(v > 2958465 || v < 0) return null;
var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
var dout=[];
var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
if(Math.abs(out.u) < 1e-6) out.u = 0;
fixopts(opts != null ? opts : (opts=[]));
if(opts.date1904) date += 1462;
if(out.u > 0.999) {
out.u = 0;
if(++time == 86400) { time = 0; ++date; }
}
if(date === 60) {dout = b2 ? [1317,10,29] : [1900,2,29]; dow=3;}
else if(date === 0) {dout = b2 ? [1317,8,29] : [1900,1,0]; dow=6;}
else {
if(date > 60) --date;
/* 1 = Jan 1 1900 in Gregorian */
var d = new Date(1900, 0, 1);
d.setDate(d.getDate() + date - 1);
dout = [d.getFullYear(), d.getMonth()+1,d.getDate()];
dow = d.getDay();
if(date < 60) dow = (dow + 6) % 7;
if(b2) dow = fix_hijri(d, dout);
}
out.y = dout[0]; out.m = dout[1]; out.d = dout[2];
out.S = time % 60; time = Math.floor(time / 60);
out.M = time % 60; time = Math.floor(time / 60);
out.H = time;
out.q = dow;
return out;
}
SSF.parse_date_code = parse_date_code;
/*jshint -W086 */
function write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*:string*/ {
var o="", ss=0, tt=0, y = val.y, out, outl = 0;
switch(type) {
case 98: /* 'b' buddhist year */
y = val.y + 543;
/* falls through */
case 121: /* 'y' year */
switch(fmt.length) {
case 1: case 2: out = y % 100; outl = 2; break;
default: out = y % 10000; outl = 4; break;
} break;
case 109: /* 'm' month */
switch(fmt.length) {
case 1: case 2: out = val.m; outl = fmt.length; break;
case 3: return months[val.m-1][1];
case 5: return months[val.m-1][0];
default: return months[val.m-1][2];
} break;
case 100: /* 'd' day */
switch(fmt.length) {
case 1: case 2: out = val.d; outl = fmt.length; break;
case 3: return days[val.q][0];
default: return days[val.q][1];
} break;
case 104: /* 'h' 12-hour */
switch(fmt.length) {
case 1: case 2: out = 1+(val.H+11)%12; outl = fmt.length; break;
default: throw 'bad hour format: ' + fmt;
} break;
case 72: /* 'H' 24-hour */
switch(fmt.length) {
case 1: case 2: out = val.H; outl = fmt.length; break;
default: throw 'bad hour format: ' + fmt;
} break;
case 77: /* 'M' minutes */
switch(fmt.length) {
case 1: case 2: out = val.M; outl = fmt.length; break;
default: throw 'bad minute format: ' + fmt;
} break;
case 115: /* 's' seconds */
if(val.u === 0) switch(fmt) {
case 's': case 'ss': return pad0(val.S, fmt.length);
case '.0': case '.00': case '.000':
}
switch(fmt) {
case 's': case 'ss': case '.0': case '.00': case '.000':
/*::if(!ss0) ss0 = 0; */
if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100;
else tt = ss0 === 1 ? 10 : 1;
ss = Math.round((tt)*(val.S + val.u));
if(ss >= 60*tt) ss = 0;
if(fmt === 's') return ss === 0 ? "0" : ""+ss/tt;
o = pad0(ss,2 + ss0);
if(fmt === 'ss') return o.substr(0,2);
return "." + o.substr(2,fmt.length-1);
default: throw 'bad second format: ' + fmt;
}
case 90: /* 'Z' absolute time */
switch(fmt) {
case '[h]': case '[hh]': out = val.D*24+val.H; break;
case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break;
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
default: throw 'bad abstime format: ' + fmt;
} outl = fmt.length === 3 ? 1 : 2; break;
case 101: /* 'e' era */
out = y; outl = 1;
}
if(outl > 0) return pad0(out, outl); else return "";
}
/*jshint +W086 */
function commaify(s/*:string*/)/*:string*/ {
if(s.length <= 3) return s;
var j = (s.length % 3), o = s.substr(0,j);
for(; j!=s.length; j+=3) o+=(o.length > 0 ? "," : "") + s.substr(j,3);
return o;
}
var write_num = (function make_write_num(){
var pct1 = /%/g;
function write_num_pct(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{
var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
return write_num(type, sfmt, val * Math.pow(10,2*mul)) + fill("%",mul);
}
function write_num_cm(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{
var idx = fmt.length - 1;
while(fmt.charCodeAt(idx-1) === 44) --idx;
return write_num(type, fmt.substr(0,idx), val / Math.pow(10,3*(fmt.length-idx)));
}
function write_num_exp(fmt/*:string*/, val/*:number*/)/*:string*/{
var o/*:string*/;
var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
if(fmt.match(/^#+0.0E\+0$/)) {
var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
var ee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E)%period;
if(ee < 0) ee += period;
o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
if(o.indexOf("e") === -1) {
var fakee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E);
if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
else o += "E+" + (fakee - ee);
while(o.substr(0,2) === "0.") {
o = o.charAt(0) + o.substr(2,period) + "." + o.substr(2+period);
o = o.replace(/^0+([1-9])/,"$1").replace(/^0+\./,"0.");
}
o = o.replace(/\+-/,"-");
}
o = o.replace(/^([+-]?)(\d*)\.(\d*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,(period+ee)%period) + "." + $3.substr(ee) + "E"; });
} else o = val.toExponential(idx);
if(fmt.match(/E\+00$/) && o.match(/e[+-]\d$/)) o = o.substr(0,o.length-1) + "0" + o.charAt(o.length-1);
if(fmt.match(/E\-/) && o.match(/e\+/)) o = o.replace(/e\+/,"e");
return o.replace("e","E");
}
var frac1 = /# (\?+)( ?)\/( ?)(\d+)/;
function write_num_f1(r/*:Array<string>*/, aval/*:number*/, sign/*:string*/)/*:string*/ {
var den = parseInt(r[4],10), rr = Math.round(aval * den), base = Math.floor(rr/den);
var myn = (rr - base*den), myd = den;
return sign + (base === 0 ? "" : ""+base) + " " + (myn === 0 ? fill(" ", r[1].length + 1 + r[4].length) : pad_(myn,r[1].length) + r[2] + "/" + r[3] + pad0(myd,r[4].length));
}
function write_num_f2(r/*:Array<string>*/, aval/*:number*/, sign/*:string*/)/*:string*/ {
return sign + (aval === 0 ? "" : ""+aval) + fill(" ", r[1].length + 2 + r[4].length);
}
var dec1 = /^#*0*\.(0+)/;
var closeparen = /\).*[0#]/;
var phone = /\(###\) ###\\?-####/;
function hashq(str/*:string*/)/*:string*/ {
var o = "", cc;
for(var i = 0; i != str.length; ++i) switch((cc=str.charCodeAt(i))) {
case 35: break;
case 63: o+= " "; break;
case 48: o+= "0"; break;
default: o+= String.fromCharCode(cc);
}
return o;
}
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*/ {
if (d < ('' + Math.round((val-Math.floor(val))*Math.pow(10,d))).length) {
return 0;
}
return Math.round((val-Math.floor(val))*Math.pow(10,d));
}
function carry(val/*:number*/, d/*:number*/)/*:number*/ {
if (d < ('' + Math.round((val-Math.floor(val))*Math.pow(10,d))).length) {
return 1;
}
return 0;
}
function flr(val/*:number*/)/*:string*/ { if(val < 2147483647 && val > -2147483648) return ""+(val >= 0 ? (val|0) : (val-1|0)); return ""+Math.floor(val); }
function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/ {
if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) {
var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");
if(val >= 0) return write_num_flt('n', ffmt, val);
return '(' + write_num_flt('n', ffmt, -val) + ')';
}
if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm(type, fmt, val);
if(fmt.indexOf('%') !== -1) return write_num_pct(type, fmt, val);
if(fmt.indexOf('E') !== -1) return write_num_exp(fmt, val);
if(fmt.charCodeAt(0) === 36) return "$"+write_num_flt(type,fmt.substr(fmt[1]==' '?2:1),val);
var o;
var r/*:?Array<string>*/, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
if(fmt.match(/^00+$/)) return sign + pad0r(aval,fmt.length);
if(fmt.match(/^[#?]+$/)) {
o = pad0r(val,0); if(o === "0") o = "";
return o.length > fmt.length ? o : hashq(fmt.substr(0,fmt.length-o.length)) + o;
}
if((r = fmt.match(frac1))) return write_num_f1(r, aval, sign);
if(fmt.match(/^#+0+$/)) return sign + pad0r(aval,fmt.length - fmt.indexOf("0"));
if((r = fmt.match(dec1))) {
// $FlowIgnore
o = rnd(val, r[1].length).replace(/^([^\.]+)$/,"$1."+r[1]).replace(/\.$/,"."+r[1]).replace(/\.(\d*)$/,function($$, $1) { return "." + $1 + fill("0", /*::(*/r/*::||[""])*/[1].length-$1.length); });
return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,".");
}
fmt = fmt.replace(/^#+([0.])/, "$1");
if((r = fmt.match(/^(0*)\.(#*)$/))) {
return sign + rnd(aval, r[2].length).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
}
if((r = fmt.match(/^#,##0(\.?)$/))) return sign + commaify(pad0r(aval,0));
if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
return val < 0 ? "-" + write_num_flt(type, fmt, -val) : commaify(""+(Math.floor(val) + carry(val, r[1].length))) + "." + pad0(dec(val, r[1].length),r[1].length);
}
if((r = fmt.match(/^#,#*,#0/))) return write_num_flt(type,fmt.replace(/^#,#*,/,""),val);
if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
o = _strrev(write_num_flt(type, fmt.replace(/[\\-]/g,""), val));
ri = 0;
return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o[ri++]:x==='0'?'0':"";}));
}
if(fmt.match(phone)) {
o = write_num_flt(type, "##########", val);
return "(" + o.substr(0,3) + ") " + o.substr(3, 3) + "-" + o.substr(6);
}
var oa = "";
if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) {
ri = Math.min(/*::String(*/r[4]/*::)*/.length,7);
ff = frac(aval, Math.pow(10,ri)-1, false);
o = "" + sign;
oa = write_num("n", /*::String(*/r[1]/*::)*/, ff[1]);
if(oa[oa.length-1] == " ") oa = oa.substr(0,oa.length-1) + "0";
o += oa + /*::String(*/r[2]/*::)*/ + "/" + /*::String(*/r[3]/*::)*/;
oa = rpad_(ff[2],ri);
if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
o += oa;
return o;
}
if((r = fmt.match(/^# ([#0?]+)( ?)\/( ?)([#0?]+)/))) {
ri = Math.min(Math.max(r[1].length, r[4].length),7);
ff = frac(aval, Math.pow(10,ri)-1, true);
return sign + (ff[0]||(ff[1] ? "" : "0")) + " " + (ff[1] ? pad_(ff[1],ri) + r[2] + "/" + r[3] + rpad_(ff[2],ri): fill(" ", 2*ri+1 + r[2].length + r[3].length));
}
if((r = fmt.match(/^[#0?]+$/))) {
o = pad0r(val, 0);
if(fmt.length <= o.length) return o;
return hashq(fmt.substr(0,fmt.length-o.length)) + o;
}
if((r = fmt.match(/^([#0?]+)\.([#0]+)$/))) {
o = "" + val.toFixed(Math.min(r[2].length,10)).replace(/([^0])0+$/,"$1");
ri = o.indexOf(".");
var lres = fmt.indexOf(".") - ri, rres = fmt.length - o.length - lres;
return hashq(fmt.substr(0,lres) + o + fmt.substr(fmt.length-rres));
}
if((r = fmt.match(/^00,000\.([#0]*0)$/))) {
ri = dec(val, r[1].length);
return val < 0 ? "-" + write_num_flt(type, fmt, -val) : commaify(flr(val)).replace(/^\d,\d{3}$/,"0$&").replace(/^\d*$/,function($$) { return "00," + ($$.length < 3 ? pad0(0,3-$$.length) : "") + $$; }) + "." + pad0(ri,r[1].length);
}
switch(fmt) {
case "#,###": var x = commaify(pad0r(aval,0)); return x !== "0" ? sign + x : "";
default:
}
throw new Error("unsupported format |" + fmt + "|");
}
function write_num_cm2(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{
var idx = fmt.length - 1;
while(fmt.charCodeAt(idx-1) === 44) --idx;
return write_num(type, fmt.substr(0,idx), val / Math.pow(10,3*(fmt.length-idx)));
}
function write_num_pct2(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{
var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
return write_num(type, sfmt, val * Math.pow(10,2*mul)) + fill("%",mul);
}
function write_num_exp2(fmt/*:string*/, val/*:number*/)/*:string*/{
var o/*:string*/;
var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
if(fmt.match(/^#+0.0E\+0$/)) {
var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
var ee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E)%period;
if(ee < 0) ee += period;
o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
if(!o.match(/[Ee]/)) {
var fakee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E);
if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
else o += "E+" + (fakee - ee);
o = o.replace(/\+-/,"-");
}
o = o.replace(/^([+-]?)(\d*)\.(\d*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,(period+ee)%period) + "." + $3.substr(ee) + "E"; });
} else o = val.toExponential(idx);
if(fmt.match(/E\+00$/) && o.match(/e[+-]\d$/)) o = o.substr(0,o.length-1) + "0" + o.charAt(o.length-1);
if(fmt.match(/E\-/) && o.match(/e\+/)) o = o.replace(/e\+/,"e");
return o.replace("e","E");
}
function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/ {
if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) {
var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");
if(val >= 0) return write_num_int('n', ffmt, val);
return '(' + write_num_int('n', ffmt, -val) + ')';
}
if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm2(type, fmt, val);
if(fmt.indexOf('%') !== -1) return write_num_pct2(type, fmt, val);
if(fmt.indexOf('E') !== -1) return write_num_exp2(fmt, val);
if(fmt.charCodeAt(0) === 36) return "$"+write_num_int(type,fmt.substr(fmt[1]==' '?2:1),val);
var o;
var r, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
if(fmt.match(/^00+$/)) return sign + pad0(aval,fmt.length);
if(fmt.match(/^[#?]+$/)) {
o = (""+val); if(val === 0) o = "";
return o.length > fmt.length ? o : hashq(fmt.substr(0,fmt.length-o.length)) + o;
}
if((r = fmt.match(frac1))) return write_num_f2(r, aval, sign);
if(fmt.match(/^#+0+$/)) return sign + pad0(aval,fmt.length - fmt.indexOf("0"));
if((r = fmt.match(dec1))) {
/*:: if(!Array.isArray(r)) throw "unreachable"; */
// $FlowIgnore
o = (""+val).replace(/^([^\.]+)$/,"$1."+r[1]).replace(/\.$/,"."+r[1]);
// $FlowIgnore
o = o.replace(/\.(\d*)$/,function($$, $1) {
/*:: if(!Array.isArray(r)) throw "unreachable"; */
// $FlowIgnore
return "." + $1 + fill("0", r[1].length-$1.length); });
// $FlowIgnore
return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,".");
}
fmt = fmt.replace(/^#+([0.])/, "$1");
if((r = fmt.match(/^(0*)\.(#*)$/))) {
return sign + (""+aval).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
}
if((r = fmt.match(/^#,##0(\.?)$/))) return sign + commaify((""+aval));
if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
return val < 0 ? "-" + write_num_int(type, fmt, -val) : commaify((""+val)) + "." + fill('0',r[1].length);
}
if((r = fmt.match(/^#,#*,#0/))) return write_num_int(type,fmt.replace(/^#,#*,/,""),val);
if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
o = _strrev(write_num_int(type, fmt.replace(/[\\-]/g,""), val));
ri = 0;
return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o[ri++]:x==='0'?'0':"";}));
}
if(fmt.match(phone)) {
o = write_num_int(type, "##########", val);
return "(" + o.substr(0,3) + ") " + o.substr(3, 3) + "-" + o.substr(6);
}
var oa = "";
if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) {
ri = Math.min(r[4].length,7);
ff = frac(aval, Math.pow(10,ri)-1, false);
o = "" + sign;
oa = write_num("n", r[1], ff[1]);
if(oa[oa.length-1] == " ") oa = oa.substr(0,oa.length-1) + "0";
o += oa + r[2] + "/" + r[3];
oa = rpad_(ff[2],ri);
if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
o += oa;
return o;
}
if((r = fmt.match(/^# ([#0?]+)( ?)\/( ?)([#0?]+)/))) {
ri = Math.min(Math.max(r[1].length, r[4].length),7);
ff = frac(aval, Math.pow(10,ri)-1, true);
return sign + (ff[0]||(ff[1] ? "" : "0")) + " " + (ff[1] ? pad_(ff[1],ri) + r[2] + "/" + r[3] + rpad_(ff[2],ri): fill(" ", 2*ri+1 + r[2].length + r[3].length));
}
if((r = fmt.match(/^[#0?]+$/))) {
o = "" + val;
if(fmt.length <= o.length) return o;
return hashq(fmt.substr(0,fmt.length-o.length)) + o;
}
if((r = fmt.match(/^([#0]+)\.([#0]+)$/))) {
o = "" + val.toFixed(Math.min(r[2].length,10)).replace(/([^0])0+$/,"$1");
ri = o.indexOf(".");
var lres = fmt.indexOf(".") - ri, rres = fmt.length - o.length - lres;
return hashq(fmt.substr(0,lres) + o + fmt.substr(fmt.length-rres));
}
if((r = fmt.match(/^00,000\.([#0]*0)$/))) {
return val < 0 ? "-" + write_num_int(type, fmt, -val) : commaify(""+val).replace(/^\d,\d{3}$/,"0$&").replace(/^\d*$/,function($$) { return "00," + ($$.length < 3 ? pad0(0,3-$$.length) : "") + $$; }) + "." + pad0(0,r[1].length);
}
switch(fmt) {
case "#,###": var x = commaify(""+aval); return x !== "0" ? sign + x : "";
default:
}
throw new Error("unsupported format |" + fmt + "|");
}
return function write_num(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/ {
return (val|0) === val ? write_num_int(type, fmt, val) : write_num_flt(type, fmt, val);
};})();
function split_fmt(fmt/*:string*/)/*:Array<string>*/ {
var out/*:Array<string>*/ = [];
var in_str = false, cc;
for(var i = 0, j = 0; i < fmt.length; ++i) switch((cc=fmt.charCodeAt(i))) {
case 34: /* '"' */
in_str = !in_str; break;
case 95: case 42: case 92: /* '_' '*' '\\' */
++i; break;
case 59: /* ';' */
out[out.length] = fmt.substr(j,i-j);
j = i+1;
}
out[out.length] = fmt.substr(j);
if(in_str === true) throw new Error("Format |" + fmt + "| unterminated string ");
return out;
}
SSF._split = split_fmt;
var abstime = /\[[HhMmSs]*\]/;
function fmt_is_date(fmt/*:string*/)/*:boolean*/ {
var i = 0, cc = 0, c = "", o = "";
while(i < fmt.length) {
switch((c = fmt.charAt(i))) {
case 'G': if(isgeneral(fmt, i)) i+= 6; i++; break;
case '"': for(;(cc=fmt.charCodeAt(++i)) !== 34 && i < fmt.length;) ++i; ++i; break;
case '\\': i+=2; break;
case '_': i+=2; break;
case '@': ++i; break;
case 'B': case 'b':
if(fmt.charAt(i+1) === "1" || fmt.charAt(i+1) === "2") return true;
/* falls through */
case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E':
/* falls through */
case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g': return true;
case 'A':
if(fmt.substr(i, 3) === "A/P") return true;
if(fmt.substr(i, 5) === "AM/PM") return true;
++i; break;
case '[':
o = c;
while(fmt.charAt(i++) !== ']' && i < fmt.length) o += fmt.charAt(i);
if(o.match(abstime)) return true;
break;
case '.':
/* falls through */
case '0': case '#':
while(i < fmt.length && ("0#?.,E+-%".indexOf(c=fmt.charAt(++i)) > -1 || c=='\\' && fmt.charAt(i+1) == "-" && "0#".indexOf(fmt.charAt(i+2))>-1));
break;
case '?': while(fmt.charAt(++i) === c); break;
case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break;
case '(': case ')': ++i; break;
case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1); break;
case ' ': ++i; break;
default: ++i; break;
}
}
return false;
}
SSF.is_date = fmt_is_date;
function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
var out = [], o = "", i = 0, c = "", lst='t', q, dt, j, cc;
var hr='H';
/* Tokenize */
while(i < fmt.length) {
switch((c = fmt.charAt(i))) {
case 'G': /* General */
if(!isgeneral(fmt, i)) throw new Error('unrecognized character ' + c + ' in ' +fmt);
out[out.length] = {t:'G', v:'General'}; i+=7; break;
case '"': /* Literal text */
for(o="";(cc=fmt.charCodeAt(++i)) !== 34 && i < fmt.length;) o += String.fromCharCode(cc);
out[out.length] = {t:'t', v:o}; ++i; break;
case '\\': var w = fmt.charAt(++i), t = (w === "(" || w === ")") ? w : 't';
out[out.length] = {t:t, v:w}; ++i; break;
case '_': out[out.length] = {t:'t', v:" "}; i+=2; break;
case '@': /* Text Placeholder */
out[out.length] = {t:'T', v:v}; ++i; break;
case 'B': case 'b':
if(fmt.charAt(i+1) === "1" || fmt.charAt(i+1) === "2") {
if(dt==null) { dt=parse_date_code(v, opts, fmt.charAt(i+1) === "2"); if(dt==null) return ""; }
out[out.length] = {t:'X', v:fmt.substr(i,2)}; lst = c; i+=2; break;
}
/* falls through */
case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E':
c = c.toLowerCase();
/* falls through */
case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g':
if(v < 0) return "";
if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
o = c; while(++i<fmt.length && fmt.charAt(i).toLowerCase() === c) o+=c;
if(c === 'm' && lst.toLowerCase() === 'h') c = 'M'; /* m = minute */
if(c === 'h') c = hr;
out[out.length] = {t:c, v:o}; lst = c; break;
case 'A':
q={t:c, v:"A"};
if(dt==null) dt=parse_date_code(v, opts);
if(fmt.substr(i, 3) === "A/P") { if(dt!=null) q.v = dt.H >= 12 ? "P" : "A"; q.t = 'T'; hr='h';i+=3;}
else if(fmt.substr(i,5) === "AM/PM") { if(dt!=null) q.v = dt.H >= 12 ? "PM" : "AM"; q.t = 'T'; i+=5; hr='h'; }
else { q.t = "t"; ++i; }
if(dt==null && q.t === 'T') return "";
out[out.length] = q; lst = c; break;
case '[':
o = c;
while(fmt.charAt(i++) !== ']' && i < fmt.length) o += fmt.charAt(i);
if(o.slice(-1) !== ']') throw 'unterminated "[" block: |' + o + '|';
if(o.match(abstime)) {
if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
out[out.length] = {t:'Z', v:o.toLowerCase()};
} else { o=""; }
break;
/* Numbers */
case '.':
if(dt != null) {
o = c; while((c=fmt.charAt(++i)) === "0") o += c;
out[out.length] = {t:'s', v:o}; break;
}
/* falls through */
case '0': case '#':
o = c; while(++i < fmt.length && "0#?.,E+-%".indexOf(c=fmt.charAt(i)) > -1 || c=='\\' && fmt.charAt(i+1) == "-" && "0#".indexOf(fmt.charAt(i+2))>-1) o += c;
out[out.length] = {t:'n', v:o}; break;
case '?':
o = c; while(fmt.charAt(++i) === c) o+=c;
q={t:c, v:o}; out[out.length] = q; lst = c; break;
case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break; // **
case '(': case ')': out[out.length] = {t:(flen===1?'t':c), v:c}; ++i; break;
case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
o = c; while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1) o+=fmt.charAt(i);
out[out.length] = {t:'D', v:o}; break;
case ' ': out[out.length] = {t:c, v:c}; ++i; break;
default:
if(",$-+/():!^&'~{}<>=€acfijklopqrtuvwxz".indexOf(c) === -1) throw new Error('unrecognized character ' + c + ' in ' + fmt);
out[out.length] = {t:'t', v:c}; ++i; break;
}
}
var bt = 0, ss0 = 0, ssm;
for(i=out.length-1, lst='t'; i >= 0; --i) {
switch(out[i].t) {
case 'h': case 'H': out[i].t = hr; lst='h'; if(bt < 1) bt = 1; break;
case 's':
if((ssm=out[i].v.match(/\.0+$/))) ss0=Math.max(ss0,ssm[0].length-1);
if(bt < 3) bt = 3;
/* falls through */
case 'd': case 'y': case 'M': case 'e': lst=out[i].t; break;
case 'm': if(lst === 's') { out[i].t = 'M'; if(bt < 2) bt = 2; } break;
case 'X': if(out[i].v === "B2");
break;
case 'Z':
if(bt < 1 && out[i].v.match(/[Hh]/)) bt = 1;
if(bt < 2 && out[i].v.match(/[Mm]/)) bt = 2;
if(bt < 3 && out[i].v.match(/[Ss]/)) bt = 3;
}
}
switch(bt) {
case 0: break;
case 1:
/*::if(!dt) break;*/
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
break;
case 2:
/*::if(!dt) break;*/
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
break;
}
/* replace fields */
var nstr = "", jj;
for(i=0; i < out.length; ++i) {
switch(out[i].t) {
case 't': case 'T': case ' ': case 'D': break;
case 'X': out[i].v = ""; out[i].t = ";"; break;
case 'd': case 'm': case 'y': case 'h': case 'H': case 'M': case 's': case 'e': case 'b': case 'Z':
/*::if(!dt) throw "unreachable"; */
out[i].v = write_date(out[i].t.charCodeAt(0), out[i].v, dt, ss0);
out[i].t = 't'; break;
case 'n': case '(': case '?':
jj = i+1;
while(out[jj] != null && (
(c=out[jj].t) === "?" || c === "D" ||
(c === " " || c === "t") && out[jj+1] != null && (out[jj+1].t === '?' || out[jj+1].t === "t" && out[jj+1].v === '/') ||
out[i].t === '(' && (c === ' ' || c === 'n' || c === ')') ||
c === 't' && (out[jj].v === '/' || '$€'.indexOf(out[jj].v) > -1 || out[jj].v === ' ' && out[jj+1] != null && out[jj+1].t == '?')
)) {
out[i].v += out[jj].v;
out[jj] = {v:"", t:";"}; ++jj;
}
nstr += out[i].v;
i = jj-1; break;
case 'G': out[i].t = 't'; out[i].v = general_fmt(v,opts); break;
}
}
var vv = "", myv, ostr;
if(nstr.length > 0) {
myv = (v<0&&nstr.charCodeAt(0) === 45 ? -v : v); /* '-' */
ostr = write_num(nstr.charCodeAt(0) === 40 ? '(' : 'n', nstr, myv); /* '(' */
jj=ostr.length-1;
var decpt = out.length;
for(i=0; i < out.length; ++i) if(out[i] != null && out[i].v.indexOf(".") > -1) { decpt = i; break; }
var lasti=out.length;
if(decpt === out.length && ostr.indexOf("E") === -1) {
for(i=out.length-1; i>= 0;--i) {
if(out[i] == null || 'n?('.indexOf(out[i].t) === -1) continue;
if(jj>=out[i].v.length-1) { jj -= out[i].v.length; out[i].v = ostr.substr(jj+1, out[i].v.length); }
else if(jj < 0) out[i].v = "";
else { out[i].v = ostr.substr(0, jj+1); jj = -1; }
out[i].t = 't';
lasti = i;
}
if(jj>=0 && lasti<out.length) out[lasti].v = ostr.substr(0,jj+1) + out[lasti].v;
}
else if(decpt !== out.length && ostr.indexOf("E") === -1) {
jj = ostr.indexOf(".")-1;
for(i=decpt; i>= 0; --i) {
if(out[i] == null || 'n?('.indexOf(out[i].t) === -1) continue;
j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")-1:out[i].v.length-1;
vv = out[i].v.substr(j+1);
for(; j>=0; --j) {
if(jj>=0 && (out[i].v[j] === "0" || out[i].v[j] === "#")) vv = ostr[jj--] + vv;
}
out[i].v = vv;
out[i].t = 't';
lasti = i;
}
if(jj>=0 && lasti<out.length) out[lasti].v = ostr.substr(0,jj+1) + out[lasti].v;
jj = ostr.indexOf(".")+1;
for(i=decpt; i<out.length; ++i) {
if(out[i] == null || 'n?('.indexOf(out[i].t) === -1 && i !== decpt ) continue;
j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")+1:0;
vv = out[i].v.substr(0,j);
for(; j<out[i].v.length; ++j) {
if(jj<ostr.length) vv += ostr[jj++];
}
out[i].v = vv;
out[i].t = 't';
lasti = i;
}
}
}
for(i=0; i<out.length; ++i) if(out[i] != null && 'n(?'.indexOf(out[i].t)>-1) {
myv = (flen >1 && v < 0 && i>0 && out[i-1].v === "-" ? -v:v);
out[i].v = write_num(out[i].t, out[i].v, myv);
out[i].t = 't';
}
var retval = "";
for(i=0; i !== out.length; ++i) if(out[i] != null) retval += out[i].v;
return retval;
}
SSF._eval = eval_fmt;
var cfregex = /\[[=<>]/;
var cfregex2 = /\[([=<>]*)(-?\d+\.?\d*)\]/;
function chkcond(v, rr) {
if(rr == null) return false;
var thresh = parseFloat(rr[2]);
switch(rr[1]) {
case "=": if(v == thresh) return true; break;
case ">": if(v > thresh) return true; break;
case "<": if(v < thresh) return true; break;
case "<>": if(v != thresh) return true; break;
case ">=": if(v >= thresh) return true; break;
case "<=": if(v <= thresh) return true; break;
}
return false;
}
function choose_fmt(f/*:string*/, v) {
var fmt = split_fmt(f);
var l = fmt.length, lat = fmt[l-1].indexOf("@");
if(l<4 && lat>-1) --l;
if(fmt.length > 4) throw new Error("cannot find right format for |" + fmt.join("|") + "|");
if(typeof v !== "number") return [4, fmt.length === 4 || lat>-1?fmt[fmt.length-1]:"@"];
switch(fmt.length) {
case 1: fmt = lat>-1 ? ["General", "General", "General", fmt[0]] : [fmt[0], fmt[0], fmt[0], "@"]; break;
case 2: fmt = lat>-1 ? [fmt[0], fmt[0], fmt[0], fmt[1]] : [fmt[0], fmt[1], fmt[0], "@"]; break;
case 3: fmt = lat>-1 ? [fmt[0], fmt[1], fmt[0], fmt[2]] : [fmt[0], fmt[1], fmt[2], "@"]; break;
case 4: break;
}
var ff = v > 0 ? fmt[0] : v < 0 ? fmt[1] : fmt[2];
if(fmt[0].indexOf("[") === -1 && fmt[1].indexOf("[") === -1) return [l, ff];
if(fmt[0].match(cfregex) != null || fmt[1].match(cfregex) != null) {
var m1 = fmt[0].match(cfregex2);
var m2 = fmt[1].match(cfregex2);
return chkcond(v, m1) ? [l, fmt[0]] : chkcond(v, m2) ? [l, fmt[1]] : [l, fmt[m1 != null && m2 != null ? 2 : 1]];
}
return [l, ff];
}
function format(fmt/*:string|number*/,v/*:any*/,o/*:?any*/) {
fixopts(o != null ? o : (o=[]));
var sfmt = "";
switch(typeof fmt) {
case "string": sfmt = fmt; break;
case "number": sfmt = (o.table != null ? (o.table/*:any*/) : table_fmt)[fmt]; break;
}
if(isgeneral(sfmt,0)) return general_fmt(v, o);
var f = choose_fmt(sfmt, v);
if(isgeneral(f[1])) return general_fmt(v, o);
if(v === true) v = "TRUE"; else if(v === false) v = "FALSE";
else if(v === "" || v == null) return "";
return eval_fmt(f[1], v, o, f[0]);
}
SSF._table = table_fmt;
SSF.load = function load_entry(fmt/*:string*/, idx/*:number*/) { table_fmt[idx] = fmt; };
SSF.format = format;
SSF.get_table = function get_table() { return table_fmt; };
SSF.load_table = function load_table(tbl/*:{[n:number]:string}*/) { for(var i=0; i!=0x0188; ++i) if(tbl[i] !== undefined) SSF.load(tbl[i], i); };
};
make_ssf(SSF);
/*global module */
/*:: declare var DO_NOT_EXPORT_SSF: any; */
if(typeof module !== 'undefined' && typeof DO_NOT_EXPORT_SSF === 'undefined') module.exports = SSF;

1455
ssf.js

File diff suppressed because it is too large Load Diff

52
ssf.md

@ -8,7 +8,7 @@ spreadsheet format codes.
The various API functions take an `opts` argument which control parsing. The The various API functions take an `opts` argument which control parsing. The
default options are described below: default options are described below:
```js>tmp/10_opts.js ```js>bits/10_opts.js
/* Options */ /* Options */
var opts_fmt/*:Array<Array<any> >*/ = [ var opts_fmt/*:Array<Array<any> >*/ = [
``` ```
@ -59,7 +59,7 @@ numbers, zero values, and text, in that order.
Semicolons can be escaped with the `\` character, so we need to split on those Semicolons can be escaped with the `\` character, so we need to split on those
semicolons that aren't prefaced by a slash or within a quoted string: semicolons that aren't prefaced by a slash or within a quoted string:
```js>tmp/80_split.js ```js>bits/80_split.js
function split_fmt(fmt/*:string*/)/*:Array<string>*/ { function split_fmt(fmt/*:string*/)/*:Array<string>*/ {
var out/*:Array<string>*/ = []; var out/*:Array<string>*/ = [];
var in_str = false, cc; var in_str = false, cc;
@ -116,7 +116,7 @@ as the last format.
## Utility Functions ## Utility Functions
```js>tmp/02_utilities.js ```js>bits/02_utilities.js
function _strrev(x/*:string*/)/*:string*/ { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; } function _strrev(x/*:string*/)/*:string*/ { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; }
function fill(c/*:string*/,l/*:number*/)/*:string*/ { var o = ""; while(o.length < l) o+=c; return o; } function fill(c/*:string*/,l/*:number*/)/*:string*/ { var o = ""; while(o.length < l) o+=c; return o; }
``` ```
@ -148,7 +148,7 @@ of its abilities given the knowledge.
First: 32-bit integers in base 10 are shorter than 11 characters, so they will First: 32-bit integers in base 10 are shorter than 11 characters, so they will
always be written in full: always be written in full:
```js>tmp/40_general.js ```js>bits/40_general.js
function general_fmt_int(v/*:number*/, opts/*:?any*/)/*:string*/ { return ""+v; } function general_fmt_int(v/*:number*/, opts/*:?any*/)/*:string*/ { return ""+v; }
SSF._general_int = general_fmt_int; SSF._general_int = general_fmt_int;
``` ```
@ -191,7 +191,7 @@ SSF._general_num = general_fmt_num;
Finally Finally
```js>tmp/40_general.js ```js>bits/40_general.js
function general_fmt(v/*:any*/, opts/*:?any*/) { function general_fmt(v/*:any*/, opts/*:?any*/) {
switch(typeof v) { switch(typeof v) {
``` ```
@ -228,7 +228,7 @@ SSF._general = general_fmt;
These are the commonly-used formats that have a special implied code. These are the commonly-used formats that have a special implied code.
None of the international formats are included here. None of the international formats are included here.
```js>tmp/20_consts.js ```js>bits/20_consts.js
var table_fmt = { var table_fmt = {
/*::[*/0/*::]*/: 'General', /*::[*/0/*::]*/: 'General',
/*::[*/1/*::]*/: '0', /*::[*/1/*::]*/: '0',
@ -285,7 +285,7 @@ some writers erroneously emit 65535 for general:
The code `ddd` displays short day-of-week and `dddd` shows long day-of-week: The code `ddd` displays short day-of-week and `dddd` shows long day-of-week:
```js>tmp/20_consts.js ```js>bits/20_consts.js
var days = [ var days = [
['Sun', 'Sunday'], ['Sun', 'Sunday'],
['Mon', 'Monday'], ['Mon', 'Monday'],
@ -325,7 +325,7 @@ portion of a 24 hour day).
Excel supports the alternative Hijri calendar (indicated with `b2`): Excel supports the alternative Hijri calendar (indicated with `b2`):
```js>tmp/50_date.js ```js>bits/50_date.js
function parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) { function parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) {
``` ```
@ -417,7 +417,7 @@ SSF.parse_date_code = parse_date_code;
TODO: suitable hijri correction TODO: suitable hijri correction
```js>tmp/45_hijri.js ```js>bits/45_hijri.js
function fix_hijri(date, o) { return 0; } function fix_hijri(date, o) { return 0; }
``` ```
@ -425,7 +425,7 @@ function fix_hijri(date, o) { return 0; }
The utility `commaify` adds commas to integers: The utility `commaify` adds commas to integers:
```js>tmp/56_commaify.js ```js>bits/56_commaify.js
function commaify(s/*:string*/)/*:string*/ { function commaify(s/*:string*/)/*:string*/ {
if(s.length <= 3) return s; if(s.length <= 3) return s;
var j = (s.length % 3), o = s.substr(0,j); var j = (s.length % 3), o = s.substr(0,j);
@ -436,7 +436,7 @@ function commaify(s/*:string*/)/*:string*/ {
`write_num` is broken into sub-functions to help with optimization: `write_num` is broken into sub-functions to help with optimization:
```js>tmp/57_numhead.js ```js>bits/57_numhead.js
var write_num = (function make_write_num(){ var write_num = (function make_write_num(){
``` ```
@ -444,7 +444,7 @@ var write_num = (function make_write_num(){
The underlying number for the percentages should be physically shifted: The underlying number for the percentages should be physically shifted:
```js>tmp/59_numhelp.js ```js>bits/59_numhelp.js
var pct1 = /%/g; var pct1 = /%/g;
function write_num_pct(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{ function write_num_pct(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{
var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length; var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
@ -457,7 +457,7 @@ function write_num_pct(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
Formats with multiple commas after the decimal point should be shifted by the Formats with multiple commas after the decimal point should be shifted by the
appropiate multiple of 1000 (more magic): appropiate multiple of 1000 (more magic):
```js>tmp/60_number.js ```js>bits/60_number.js
function write_num_cm(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{ function write_num_cm(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{
var idx = fmt.length - 1; var idx = fmt.length - 1;
while(fmt.charCodeAt(idx-1) === 44) --idx; while(fmt.charCodeAt(idx-1) === 44) --idx;
@ -562,7 +562,7 @@ function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
For parentheses, explicitly resolve the sign issue: For parentheses, explicitly resolve the sign issue:
```js>tmp/60_number.js ```js>bits/60_number.js
if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) { if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) {
var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,""); var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");
if(val >= 0) return write_num_flt('n', ffmt, val); if(val >= 0) return write_num_flt('n', ffmt, val);
@ -575,7 +575,7 @@ Helpers are used for:
- Trailing commas - Trailing commas
- Exponentials - Exponentials
```js>tmp/60_number.js ```js>bits/60_number.js
if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm(type, fmt, val); if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm(type, fmt, val);
if(fmt.indexOf('%') !== -1) return write_num_pct(type, fmt, val); if(fmt.indexOf('%') !== -1) return write_num_pct(type, fmt, val);
if(fmt.indexOf('E') !== -1) return write_num_exp(fmt, val); if(fmt.indexOf('E') !== -1) return write_num_exp(fmt, val);
@ -691,7 +691,7 @@ The general class `/^[#0?]+$/` treats the '0' as literal, '#' as noop, '?' as sp
The default cases are hard-coded. TODO: actually parse them The default cases are hard-coded. TODO: actually parse them
```js>tmp/60_number.js ```js>bits/60_number.js
if((r = fmt.match(/^00,000\.([#0]*0)$/))) { if((r = fmt.match(/^00,000\.([#0]*0)$/))) {
ri = dec(val, r[1].length); ri = dec(val, r[1].length);
``` ```
@ -707,7 +707,7 @@ Note that this is technically incorrect
For now, the default case is an error: For now, the default case is an error:
```js>tmp/60_number.js ```js>bits/60_number.js
default: default:
} }
throw new Error("unsupported format |" + fmt + "|"); throw new Error("unsupported format |" + fmt + "|");
@ -839,7 +839,7 @@ return function write_num(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:str
## Evaluating Format Strings ## Evaluating Format Strings
```js>tmp/82_eval.js ```js>bits/82_eval.js
var abstime = /\[[HhMmSs]*\]/; var abstime = /\[[HhMmSs]*\]/;
function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) { function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
var out = [], o = "", i = 0, c = "", lst='t', q, dt, j, cc; var out = [], o = "", i = 0, c = "", lst='t', q, dt, j, cc;
@ -1197,7 +1197,7 @@ There is some overloading of the `m` character. According to the spec:
hours) or immediately before the "ss" code (for seconds), the application shall hours) or immediately before the "ss" code (for seconds), the application shall
display minutes instead of the month. display minutes instead of the month.
```js>tmp/50_date.js ```js>bits/50_date.js
/*jshint -W086 */ /*jshint -W086 */
function write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*:string*/ { function write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*:string*/ {
var o="", ss=0, tt=0, y = val.y, out, outl = 0; var o="", ss=0, tt=0, y = val.y, out, outl = 0;
@ -1322,7 +1322,7 @@ it is not exported and is only called when the type is in `ymdhHMsZe`
Based on the value, `choose_fmt` picks the right format string. If formats have Based on the value, `choose_fmt` picks the right format string. If formats have
explicit negative specifications, those values should be passed as positive: explicit negative specifications, those values should be passed as positive:
```js>tmp/90_main.js ```js>bits/90_main.js
function choose_fmt(f/*:string*/, v) { function choose_fmt(f/*:string*/, v) {
var fmt = split_fmt(f); var fmt = split_fmt(f);
var l = fmt.length, lat = fmt[l-1].indexOf("@"); var l = fmt.length, lat = fmt[l-1].indexOf("@");
@ -1357,7 +1357,7 @@ it is treated as the text format
Here we have to scan for conditions. Note that the grammar precludes decimals Here we have to scan for conditions. Note that the grammar precludes decimals
but in practice they are fair game: but in practice they are fair game:
```js>tmp/88_cond.js ```js>bits/88_cond.js
var cfregex = /\[[=<>]/; var cfregex = /\[[=<>]/;
var cfregex2 = /\[([=<>]*)(-?\d+\.?\d*)\]/; var cfregex2 = /\[([=<>]*)(-?\d+\.?\d*)\]/;
function chkcond(v, rr) { function chkcond(v, rr) {
@ -1377,7 +1377,7 @@ function chkcond(v, rr) {
The main function checks for conditional operators and acts accordingly: The main function checks for conditional operators and acts accordingly:
```js>tmp/90_main.js ```js>bits/90_main.js
var ff = v > 0 ? fmt[0] : v < 0 ? fmt[1] : fmt[2]; var ff = v > 0 ? fmt[0] : v < 0 ? fmt[1] : fmt[2];
if(fmt[0].indexOf("[") === -1 && fmt[1].indexOf("[") === -1) return [l, ff]; if(fmt[0].indexOf("[") === -1 && fmt[1].indexOf("[") === -1) return [l, ff];
if(fmt[0].match(cfregex) != null || fmt[1].match(cfregex) != null) { if(fmt[0].match(cfregex) != null || fmt[1].match(cfregex) != null) {
@ -1431,7 +1431,7 @@ Empty string should always emit empty, even if there are other characters:
The methods beginning with an underscore are subject to change and should not be The methods beginning with an underscore are subject to change and should not be
used directly in programs. used directly in programs.
```js>tmp/98_exports.js ```js>bits/98_exports.js
SSF._table = table_fmt; SSF._table = table_fmt;
SSF.load = function load_entry(fmt/*:string*/, idx/*:number*/) { table_fmt[idx] = fmt; }; SSF.load = function load_entry(fmt/*:string*/, idx/*:number*/) { table_fmt[idx] = fmt; };
SSF.format = format; SSF.format = format;
@ -1448,7 +1448,7 @@ SSF.load_table = function load_table(tbl/*:{[n:number]:string}*/) { for(var i=0;
The implementation is from [our frac library](https://github.com/SheetJS/frac/): The implementation is from [our frac library](https://github.com/SheetJS/frac/):
```js>tmp/30_frac.js ```js>bits/30_frac.js
function frac(x, D, mixed) { function frac(x, D, mixed) {
var sgn = x < 0 ? -1 : 1; var sgn = x < 0 ? -1 : 1;
var B = x * sgn; var B = x * sgn;
@ -1475,14 +1475,14 @@ function frac(x, D, mixed) {
## JS Boilerplate ## JS Boilerplate
```js>tmp/00_header.js ```js>bits/00_header.js
/* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */ /* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */
/*jshint -W041 */ /*jshint -W041 */
var SSF = {}; var SSF = {};
var make_ssf = function make_ssf(SSF){ var make_ssf = function make_ssf(SSF){
``` ```
```js>tmp/99_footer.js ```js>bits/99_footer.js
}; };
make_ssf(SSF); make_ssf(SSF);
/*global module */ /*global module */

447
test/is_date.json Normal file

@ -0,0 +1,447 @@
[
["General", false],
["yyyy", true],
["\" Excellent\"", false],
["\" Fair\"", false],
["\" Good\"", false],
["\" Poor\"", false],
["\" Very Good\"", false],
["\"$\"#,##0", false],
["\"$\"#,##0.00", false],
["\"$\"#,##0.00_);[Red]\\(\"$\"#,##0.00\\)", false],
["\"$\"#,##0.00_);\\(\"$\"#,##0.00\\)", false],
["\"$\"#,##0;[Red]\\-\"$\"#,##0", false],
["\"$\"#,##0_);[Red]\\(\"$\"#,##0\\)", false],
["\"$\"#,##0_);\\(\"$\"#,##0\\)", false],
["\"Haha!\"\\ @\\ \"Yeah!\"", false],
["\"TRUE\";\"TRUE\";\"FALSE\"", false],
["\"True\";\"True\";\"False\";@", false],
["\"Years: \"0", false],
["\"Yes\";\"Yes\";\"No\";@", false],
["\"kl \"hh:mm:ss;@", false],
["\"£\"#,##0.00", false],
["\"£\"#,##0;[Red]\\-\"£\"#,##0", false],
["\"€\"#,##0.00", false],
["\"€\"\\ #,##0.00_-", false],
["\"上午/下午 \"hh\"時\"mm\"分\"ss\"秒 \"", true],
["\"¥\"#,##0.00;\"¥\"\\-#,##0.00", false],
["#", false],
["# ?/?", false],
["# ??/??", false],
["#\" \"?/?", false],
["#\" \"??/??", false],
["#\"abded\"\\ ??/??", false],
["###0.00;-###0.00", false],
["###0;-###0", false],
["##0.0E+0", false],
["#,##0", false],
["#,##0 ;(#,##0)", false],
["#,##0 ;[Red](#,##0)", false],
["#,##0\"р.\";[Red]\\-#,##0\"р.\"", false],
["#,##0.0", false],
["#,##0.00", false],
["#,##0.00 \"<22>\"", false],
["#,##0.00 €;-#,##0.00 €", false],
["#,##0.00\"р.\";[Red]\\-#,##0.00\"р.\"", false],
["#,##0.000", false],
["#,##0.0000", false],
["#,##0.00000", false],
["#,##0.000000", false],
["#,##0.0000000", false],
["#,##0.00000000", false],
["#,##0.000000000", false],
["#,##0.00000000;[Red]#,##0.00000000", false],
["#,##0.0000_ ", false],
["#,##0.000_ ", false],
["#,##0.000_);\\(#,##0.000\\)", false],
["#,##0.00;(#,##0.00)", false],
["#,##0.00;(#,##0.00);0.00", false],
["#,##0.00;[Red](#,##0.00)", false],
["#,##0.00;[Red]\\(#,##0.00\\)", false],
["#,##0.00;\\(#,##0.00\\)", false],
["#,##0.00[$₹-449]_);\\(#,##0.00[$₹-449]\\)", false],
["#,##0.00\\ \"р.\"", false],
["#,##0.00\\ \"р.\";[Red]\\-#,##0.00\\ \"р.\"", false],
["#,##0.00\\ [$€-407]", false],
["#,##0.00\\ [$€-40C]", false],
["#,##0.00_);\\(#,##0.00\\)", false],
["#,##0.00_р_.;[Red]\\-#,##0.00_р_.", false],
["#,##0.00_р_.;\\-#,##0.00_р_.", false],
["#,##0.0;[Red]#,##0.0", false],
["#,##0.0_ ;\\-#,##0.0\\ ", false],
["#,##0.0_);[Red]\\(#,##0.0\\)", false],
["#,##0.0_);\\(#,##0.0\\)", false],
["#,##0;\\-#,##0;0", false],
["#,##0\\ \"р.\";[Red]\\-#,##0\\ \"р.\"", false],
["#,##0\\ \"р.\";\\-#,##0\\ \"р.\"", false],
["#,##0\\ ;[Red]\\(#,##0\\)", false],
["#,##0\\ ;\\(#,##0\\)", false],
["#,##0_ ", false],
["#,##0_ ;[Red]\\-#,##0\\ ", false],
["#,##0_);[Red]\\(#,##0\\)", false],
["#,##0_р_.;[Red]\\-#,##0_р_.", false],
["#,##0_р_.;\\-#,##0_р_.", false],
["#.0000,,", false],
["#0", false],
["#0.00", false],
["#0.0000", false],
["#\\ ?/10", false],
["#\\ ?/2", false],
["#\\ ?/4", false],
["#\\ ?/8", false],
["#\\ ?/?", false],
["#\\ ??/100", false],
["#\\ ??/100;[Red]\\(#\\ ??/16\\)", false],
["#\\ ??/16", false],
["#\\ ??/??", false],
["#\\ ??/?????????", false],
["#\\ ???/???", false],
["**\\ #,###,#00,000.00,**", false],
["0", false],
["0\"abde\".0\"??\"000E+00", false],
["0%", false],
["0.0", false],
["0.0%", false],
["0.00", false],
["0.00\"°\"", false],
["0.00%", false],
["0.000", false],
["0.000%", false],
["0.0000", false],
["0.000000", false],
["0.00000000", false],
["0.000000000", false],
["0.000000000%", false],
["0.00000000000", false],
["0.000000000000000", false],
["0.00000000E+00", false],
["0.0000E+00", false],
["0.00;[Red]0.00", false],
["0.00E+00", false],
["0.00_);[Red]\\(0.00\\)", false],
["0.00_);\\(0.00\\)", false],
["0.0_ ", false],
["00.00.00.000", false],
["00.000%", false],
["0000", false],
["00000", false],
["00000000", false],
["000000000", false],
["00000\\-0000", false],
["00000\\-00000", false],
["000\\-00\\-0000", false],
["0;[Red]0", false],
["0\\-00000\\-00000\\-0", false],
["0_);[Red]\\(0\\)", false],
["0_);\\(0\\)", false],
["@", false],
["A/P", true],
["AM/PM", true],
["AM/PMh\"時\"mm\"分\"ss\"秒\";@", true],
["D", true],
["DD", true],
["DD/MM/YY;@", true],
["DD/MM/YYYY", true],
["DD/MM/YYYY;@", true],
["DDD", true],
["DDDD", true],
["DDDD\", \"MMMM\\ DD\", \"YYYY", true],
["GENERAL", false],
["General", false],
["H", true],
["H:MM:SS\\ AM/PM", true],
["HH:MM", true],
["HH:MM:SS\\ AM/PM", true],
["HHM", true],
["HHMM", true],
["HH[MM]", true],
["HH[M]", true],
["M/D/YYYY", true],
["M/D/YYYY\\ H:MM", true],
["MM/DD/YY", true],
["S", true],
["SS", true],
["YY", true],
["YYM", true],
["YYMM", true],
["YYMMM", true],
["YYMMMM", true],
["YYMMMMM", true],
["YYYY", true],
["YYYY-MM-DD HH:MM:SS", true],
["YYYY\\-MM\\-DD", true],
["[$$-409]#,##0", false],
["[$$-409]#,##0.00", false],
["[$$-409]#,##0.00_);[Red]\\([$$-409]#,##0.00\\)", false],
["[$$-C09]#,##0.00", false],
["[$-100042A]h:mm:ss\\ AM/PM;@", true],
["[$-1010409]0.000%", false],
["[$-1010409]General", false],
["[$-1010409]d/m/yyyy\\ h:mm\\ AM/PM;@", true],
["[$-1010409]dddd, mmmm dd, yyyy", true],
["[$-1010409]m/d/yyyy", true],
["[$-1409]h:mm:ss\\ AM/PM;@", true],
["[$-2000000]h:mm:ss;@", true],
["[$-2010401]d/mm/yyyy\\ h:mm\\ AM/PM;@", true],
["[$-4000439]h:mm:ss\\ AM/PM;@", true],
["[$-4010439]d/m/yyyy\\ h:mm\\ AM/PM;@", true],
["[$-409]AM/PM\\ hh:mm:ss;@", true],
["[$-409]d/m/yyyy\\ hh:mm;@", true],
["[$-409]d\\-mmm;@", true],
["[$-409]d\\-mmm\\-yy;@", true],
["[$-409]d\\-mmm\\-yyyy;@", true],
["[$-409]dd/mm/yyyy\\ hh:mm;@", true],
["[$-409]dd\\-mmm\\-yy;@", true],
["[$-409]h:mm:ss\\ AM/PM;@", true],
["[$-409]h:mm\\ AM/PM;@", true],
["[$-409]m/d/yy\\ h:mm\\ AM/PM;@", true],
["[$-409]mmm\\-yy;@", true],
["[$-409]mmmm\\ d\\,\\ yyyy;@", true],
["[$-409]mmmm\\-yy;@", true],
["[$-409]mmmmm;@", true],
["[$-409]mmmmm\\-yy;@", true],
["[$-40E]h\\ \"óra\"\\ m\\ \"perckor\"\\ AM/PM;@", true],
["[$-412]AM/PM\\ h\"시\"\\ mm\"분\"\\ ss\"초\";@", true],
["[$-41C]h:mm:ss\\.AM/PM;@", true],
["[$-449]hh:mm:ss\\ AM/PM;@", true],
["[$-44E]hh:mm:ss\\ AM/PM;@", true],
["[$-44F]hh:mm:ss\\ AM/PM;@", true],
["[$-D000409]h:mm\\ AM/PM;@", true],
["[$-D010000]d/mm/yyyy\\ h:mm\\ \"น.\";@", true],
["[$-F400]h:mm:ss\\ AM/PM", true],
["[$-F800]dddd\\,\\ mmmm\\ dd\\,\\ yyyy", true],
["[$AUD]\\ #,##0.00", false],
["[$RD$-1C0A]#,##0.00;[Red]\\-[$RD$-1C0A]#,##0.00", false],
["[$SFr.-810]\\ #,##0.00_);[Red]\\([$SFr.-810]\\ #,##0.00\\)", false],
["[$£-809]#,##0.00;[Red][$£-809]#,##0.00", false],
["[$¥-411]#,##0.00", false],
["[$¥-804]#,##0.00", false],
["[<0]\"\";0%", false],
["[<=9999999]###\\-####;\\(###\\)\\ ###\\-####", false],
["[=0]?;#,##0.00", false],
["[=0]?;0%", false],
["[=0]?;[<4.16666666666667][hh]:mm:ss;[hh]:mm", true],
["[>999999]#,,\"M\";[>999]#,\"K\";#", false],
["[>999999]#.000,,\"M\";[>999]#.000,\"K\";#.000", false],
["[>=100000]0.000\\ \\\";[Red]0.000\\ \\<\\ \\>\\ \\\"\\ \\&\\ \\'\\ ", false],
["[>=100000]0.000\\ \\<;[Red]0.000\\ \\>", false],
["[BLACK]@", false],
["[BLUE]GENERAL", false],
["[Black]@", false],
["[Blue]General", false],
["[CYAN]@", false],
["[Cyan]@", false],
["[DBNum1][$-804]AM/PMh\"时\"mm\"分\";@", true],
["[DBNum1][$-804]General", false],
["[DBNum1][$-804]h\"时\"mm\"分\";@", true],
["[ENG][$-1004]dddd\\,\\ d\\ mmmm\\,\\ yyyy;@", true],
["[ENG][$-101040D]d\\ mmmm\\ yyyy;@", true],
["[ENG][$-101042A]d\\ mmmm\\ yyyy;@", true],
["[ENG][$-140C]dddd\\ \"YeahWoo!\"\\ ddd\\ mmmm\\ yyyy;@", true],
["[ENG][$-2C0A]dddd\\ d\" de \"mmmm\" de \"yyyy;@", true],
["[ENG][$-402]dd\\ mmmm\\ yyyy\\ \"г.\";@", true],
["[ENG][$-403]dddd\\,\\ d\" / \"mmmm\" / \"yyyy;@", true],
["[ENG][$-405]d\\.\\ mmmm\\ yyyy;@", true],
["[ENG][$-408]d\\ mmmm\\ yyyy;@", true],
["[ENG][$-409]d\\-mmm;@", true],
["[ENG][$-409]d\\-mmm\\-yy;@", true],
["[ENG][$-409]d\\-mmm\\-yyyy;@", true],
["[ENG][$-409]dd\\-mmm\\-yy;@", true],
["[ENG][$-409]mmm\\-yy;@", true],
["[ENG][$-409]mmmm\\ d\\,\\ yyyy;@", true],
["[ENG][$-409]mmmm\\-yy;@", true],
["[ENG][$-40B]d\\.\\ mmmm\\t\\a\\ yyyy;@", true],
["[ENG][$-40C]d/mmm/yyyy;@", true],
["[ENG][$-40E]yyyy/\\ mmmm\\ d\\.;@", true],
["[ENG][$-40F]dd\\.\\ mmmm\\ yyyy;@", true],
["[ENG][$-410]d\\ mmmm\\ yyyy;@", true],
["[ENG][$-415]d\\ mmmm\\ yyyy;@", true],
["[ENG][$-416]d\\ \\ mmmm\\,\\ yyyy;@", true],
["[ENG][$-418]d\\ mmmm\\ yyyy;@", true],
["[ENG][$-41A]d\\.\\ mmmm\\ yyyy\\.;@", true],
["[ENG][$-41B]d\\.\\ mmmm\\ yyyy;@", true],
["[ENG][$-41D]\"den \"\\ d\\ mmmm\\ yyyy;@", true],
["[ENG][$-420]dddd\\,\\ dd\\ mmmm\\,\\ yyyy;@", true],
["[ENG][$-421]dd\\ mmmm\\ yyyy;@", true],
["[ENG][$-424]dddd\\,\\ d\\.\\ mmmm\\ yyyy;@", true],
["[ENG][$-425]dddd\\,\\ d\\.\\ mmmm\\ yyyy;@", true],
["[ENG][$-426]dddd\\,\\ yyyy\". gada \"d\\.\\ mmmm;@", true],
["[ENG][$-427]yyyy\\ \"m.\"\\ mmmm\\ d\\ \"d.\";@", true],
["[ENG][$-42B]dddd\\,\\ d\\ mmmm\\ yyyy;@", true],
["[ENG][$-42C]d\\ mmmm\\ yyyy;@", true],
["[ENG][$-42D]yyyy\"(e)ko\"\\ mmmm\"ren\"\\ d\"a\";@", true],
["[ENG][$-42F]dddd\\,\\ dd\\ mmmm\\ yyyy;@", true],
["[ENG][$-437]yyyy\\ \\წ\\ლ\\ი\\ს\\ dd\\ mm\\,\\ dddd;@", true],
["[ENG][$-438]d\\.\\ mmmm\\ yyyy;@", true],
["[ENG][$-43F]d\\ mmmm\\ yyyy\\ \"ж.\";@", true],
["[ENG][$-444]d\\ mmmm\\ yyyy;@", true],
["[ENG][$-449]dd\\ mmmm\\ yyyy;@", true],
["[ENG][$-44E]d\\ mmmm\\ yyyy;@", true],
["[ENG][$-44F]dd\\ mmmm\\ yyyy\\ dddd;@", true],
["[ENG][$-457]dd\\ mmmm\\ yyyy;@", true],
["[ENG][$-813]dddd\\ d\\ mmmm\\ yyyy;@", true],
["[ENG][$-81A]dddd\\,\\ d\\.\\ mmmm\\ yyyy;@", true],
["[ENG][$-82C]d\\ mmmm\\ yyyy;@", true],
["[ENG][$-843]yyyy\\ \"й\"\"и\"\"л\"\\ d/mmmm;@", true],
["[ENG][$-C07]dddd\\,\\ dd\\.\\ mmmm\\ yyyy;@", true],
["[ENG][$-FC19]yyyy\\,\\ dd\\ mmmm;@", true],
["[ENG][$-FC22]d\\ mmmm\\ yyyy\" р.\";@", true],
["[ENG][$-FC23]d\\ mmmm\\ yyyy;@", true],
["[GREEN]#,###", false],
["[Green]#,###", false],
["[HH]", true],
["[HIJ][$-2060401]d/mm/yyyy\\ h:mm\\ AM/PM;@", true],
["[HIJ][$-2060401]d\\ mmmm\\ yyyy;@", true],
["[H]", true],
["[JPN][$-411]gggyy\"年\"m\"月\"d\"日\"\\ dddd;@", true],
["[MAGENTA]0.00", false],
["[Magenta]0.00", false],
["[RED]#.##", false],
["[Red]#.##", false],
["[Red][<-25]General;[Blue][>25]General;[Green]General;[Yellow]General\\ ", false],
["[Red][<=-25]General;[Blue][>=25]General;[Green]General;[Yellow]General", false],
["[Red][<>50]General;[Blue]000", false],
["[Red][=50]General;[Blue]000", false],
["[SS]", true],
["[S]", true],
["[TWN][DBNum1][$-404]y\"年\"m\"月\"d\"日\";@", true],
["[WHITE]0.0", false],
["[White]0.0", false],
["[YELLOW]@", false],
["[Yellow]@", false],
["[h]", true],
["[h]:mm:ss", true],
["[h]:mm:ss;@", true],
["[h]\\.mm\" Uhr \";@", true],
["[hh]", true],
["[s]", true],
["[ss]", true],
["\\#\\r\\e\\c", false],
["\\$#,##0_);[Red]\\\"($\\\"#,##0\\)", false],
["\\$0.00", false],
["\\C\\O\\B\\ \\o\\n\\ @", false],
["\\C\\R\\O\\N\\T\\A\\B\\ \\o\\n\\ @", false],
["\\R\\e\\s\\u\\l\\t\\ \\o\\n\\ @", false],
["\\S\\Q\\L\\ \\:\\ @", false],
["\\S\\Q\\L\\ \\R\\e\\q\\u\\e\\s\\t\\ \\f\\o\\r\\ @", false],
["\\c\\c\\c?????0\"aaaa\"0\"bbbb\"000000.00%", false],
["\\u\\n\\t\\i\\l\\ h:mm;@", true],
["_ * #,##0.00_)[$﷼-429]_ ;_ * \\(#,##0.00\\)[$﷼-429]_ ;_ * \"-\"??_)[$﷼-429]_ ;_ @_ ", false],
["_ * #,##0_ ;_ * \\-#,##0_ ;[Red]_ * \"-\"_ ;_ @_ ", false],
["_(\"$\"* #,##0.00_);_(\"$\"* \\(#,##0.00\\);_(\"$\"* \"-\"??_);_(@_)", false],
["_(\"$\"* #,##0_);_(\"$\"* \\(#,##0\\);_(\"$\"* \"-\"??_);_(@_)", false],
["_(\"$\"* #,##0_);_(\"$\"* \\(#,##0\\);_(\"$\"* \"-\"_);_(@_)", false],
["_(* #,##0.0000_);_(* \\(#,##0.0000\\);_(* \"-\"??_);_(@_)", false],
["_(* #,##0.000_);_(* \\(#,##0.000\\);_(* \"-\"??_);_(@_)", false],
["_(* #,##0.00_);_(* \\(#,##0.00\\);_(* \"-\"??_);_(@_)", false],
["_(* #,##0.0_);_(* \\(#,##0.0\\);_(* \"-\"??_);_(@_)", false],
["_(* #,##0_);_(* \\(#,##0\\);_(* \"-\"??_);_(@_)", false],
["_(* #,##0_);_(* \\(#,##0\\);_(* \"-\"_);_(@_)", false],
["_([$ANG]\\ * #,##0.0_);_([$ANG]\\ * \\(#,##0.0\\);_([$ANG]\\ * \"-\"?_);_(@_)", false],
["_-\"€\"\\ * #,##0.00_-;_-\"€\"\\ * #,##0.00\\-;_-\"€\"\\ * \"-\"??_-;_-@_-", false],
["_-* #,##0.00\" TL\"_-;\\-* #,##0.00\" TL\"_-;_-* \\-??\" TL\"_-;_-@_-", false],
["_-* #,##0.00\" €\"_-;\\-* #,##0.00\" €\"_-;_-* \\-??\" €\"_-;_-@_-", false],
["_-* #,##0.00\\ \"р.\"_-;\\-* #,##0.00\\ \"р.\"_-;_-* \"-\"??\\ \"р.\"_-;_-@_-", false],
["_-* #,##0.00\\ \"€\"_-;\\-* #,##0.00\\ \"€\"_-;_-* \"-\"??\\ \"€\"_-;_-@_-", false],
["_-* #,##0.00\\ [$€-407]_-;\\-* #,##0.00\\ [$€-407]_-;_-* \\-??\\ [$€-407]_-;_-@_-", false],
["_-* #,##0.0\\ _F_-;\\-* #,##0.0\\ _F_-;_-* \"-\"??\\ _F_-;_-@_-", false],
["_-* #,##0\\ \"€\"_-;\\-* #,##0\\ \"€\"_-;_-* \"-\"\\ \"€\"_-;_-@_-", false],
["_-* #,##0_-;\\-* #,##0_-;_-* \"-\"??_-;_-@_-", false],
["_-\\$* #,##0.0_ ;_-\\$* \\-#,##0.0\\ ;_-\\$* \"-\"?_ ;_-@_ ", false],
["d", true],
["d-mmm", true],
["d-mmm-yy", true],
["d/m", true],
["d/m/yy;@", true],
["d/m/yyyy;@", true],
["d/mm/yy;@", true],
["d/mm/yyyy;@", true],
["d\\-mmm", true],
["d\\-mmm\\-yyyy", true],
["dd", true],
["dd\"-\"mmm\"-\"yyyy", true],
["dd/m/yyyy", true],
["dd/mm/yy", true],
["dd/mm/yy;@", true],
["dd/mm/yy\\ hh:mm", true],
["dd/mm/yyyy", true],
["dd/mm/yyyy\\ hh:mm:ss", true],
["dd/mmm", true],
["dd\\-mm\\-yy", true],
["dd\\-mmm\\-yy", true],
["dd\\-mmm\\-yyyy\\ hh:mm:ss.000", true],
["dd\/mm\/yy", true],
["dd\/mm\/yyyy", true],
["ddd", true],
["dddd", true],
["dddd, mmmm dd, yyyy", true],
["h", true],
["h\"时\"mm\"分\"ss\"秒\";@", true],
["h\"時\"mm\"分\"ss\"秒\";@", true],
["h:mm", true],
["h:mm AM/PM", true],
["h:mm:ss", true],
["h:mm:ss AM/PM", true],
["h:mm:ss;@", true],
["h:mm;@", true],
["h\\.mm\" Uhr \";@", true],
["h\\.mm\" h\";@", true],
["h\\.mm\" u.\";@", true],
["hh\":\"mm AM/PM", true],
["hh:mm:ss", true],
["hh:mm:ss\\ AM/PM", true],
["hh\\.mm\" h\";@", true],
["hhm", true],
["hhmm", true],
["m\"月\"d\"日\"", true],
["m/d/yy", true],
["m/d/yy h:mm", true],
["m/d/yy;@", true],
["m/d/yy\\ h:mm", true],
["m/d/yy\\ h:mm;@", true],
["m/d/yyyy", true],
["m/d/yyyy;@", true],
["m/d/yyyy\\ h:mm:ss;@", true],
["m/d;@", true],
["m\/d\/yyyy", true],
["mm/dd", true],
["mm/dd/yy", true],
["mm/dd/yy;@", true],
["mm/dd/yyyy", true],
["mm:ss", true],
["mm:ss.0;@", true],
["mmm d, yyyy", true],
["mmm\" \"d\", \"yyyy", true],
["mmm-yy", true],
["mmm-yy;@", true],
["mmm/yy", true],
["mmm\\-yy", true],
["mmm\\-yy;@", true],
["mmm\\-yyyy", true],
["mmmm\\ d\\,\\ yyyy", true],
["mmmm\\ yyyy", true],
["mmss.0", true],
["s", true],
["ss", true],
["yy", true],
["yy/mm/dd", true],
["yy\\.mm\\.dd", true],
["yym", true],
["yymm", true],
["yymmm", true],
["yymmmm", true],
["yymmmmm", true],
["yyyy", true],
["yyyy\"년\"\\ m\"월\"\\ d\"일\";@", true],
["yyyy-m-d h:mm AM/PM", true],
["yyyy-mm-dd", true],
["yyyy/mm/dd", true],
["yyyy\\-m\\-d\\ hh:mm:ss", true],
["yyyy\\-mm\\-dd", true],
["yyyy\\-mm\\-dd;@", true],
["yyyy\\-mm\\-dd\\ h:mm", true],
["yyyy\\-mm\\-dd\\Thh:mm", true],
["yyyy\\-mm\\-dd\\Thhmmss.000", true],
["###,##0", false],
["#,###.00", false]
]

11
test/utilities.js Normal file

@ -0,0 +1,11 @@
/* vim: set ts=2: */
/*jshint loopfunc:true, mocha:true, node:true */
var SSF = require('../');
var fs = require('fs'), assert = require('assert');
var is_date = JSON.parse(fs.readFileSync('./test/is_date.json','utf8'));
var skip = [];
describe('utilities', function() {
it('correctly determines if formats are dates', function() {
is_date.forEach(function(d) { assert.equal(SSF.is_date(d[0]), d[1], d[0]); });
});
});