diff --git a/.jscs.json b/.jscs.json new file mode 100644 index 0000000..5965004 --- /dev/null +++ b/.jscs.json @@ -0,0 +1,6 @@ +{ + "requireCommaBeforeLineBreak": true, + "disallowTrailingWhitespace": true, + "disallowTrailingComma": true +} + diff --git a/Makefile b/Makefile index 39395a8..52dab07 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,7 @@ test_min: .PHONY: lint lint: jshint ssf.js test/ + jscs ssf.js .PHONY: cov cov: tmp/coverage.html diff --git a/package.json b/package.json index c00e508..c07ad86 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ssf", - "version": "0.7.0", + "version": "0.7.1", "author": "SheetJS", "description": "pure-JS library to format data using ECMA-376 spreadsheet Format Codes", "keywords": [ "format", "sprintf", "spreadsheet" ], diff --git a/ssf.js b/ssf.js index 2961016..4263ca1 100644 --- a/ssf.js +++ b/ssf.js @@ -5,7 +5,7 @@ var _strrev = function(x) { return String(x).split("").reverse().join("");}; function fill(c,l) { return new Array(l+1).join(c); } function pad(v,d,c){var t=String(v);return t.length>=d?t:(fill(c||0,d-t.length)+t);} function rpad(v,d,c){var t=String(v);return t.length>=d?t:(t+fill(c||0,d-t.length));} -SSF.version = '0.7.0'; +SSF.version = '0.7.1'; /* Options */ var opts_fmt = { date1904:0, @@ -252,7 +252,10 @@ var write_num = function(type, fmt, val) { } if(fmt.match(/^#+0+$/)) fmt = fmt.replace(/#/g,""); if(fmt.match(/^00+$/)) return (val<0?"-":"")+pad(Math.round(aval),fmt.length); - if(fmt.match(/^[#?]+$/)) return String(Math.round(val)).replace(/^0$/,""); + if(fmt.match(/^[#?]+$/)) { + o = String(Math.round(val)).replace(/^0$/,""); + return o.length > fmt.length ? o : fmt.substr(0,fmt.length-o.length).replace(/#/g,"").replace(/[?]/g," ") + o; + } if((r = fmt.match(/^#*0*\.(0+)/))) { o = Math.round(val * Math.pow(10,r[1].length)); rr = String(o/Math.pow(10,r[1].length)).replace(/^([^\.]+)$/,"$1."+r[1]).replace(/\.$/,"."+r[1]).replace(/\.([0-9]*)$/,function($$, $1) { return "." + $1 + fill("0", r[1].length-$1.length); }); @@ -278,20 +281,32 @@ var write_num = function(type, fmt, val) { ff = write_num(type, "##########", val); return "(" + ff.substr(0,3) + ") " + ff.substr(3, 3) + "-" + ff.substr(6); } - if((r = fmt.match(/^([?]+)([ ]?)\/([ ]?)([?]+)/))) { - rr = Math.min(Math.max(r[1].length, r[4].length),7); + var oa = ""; + if((r = fmt.match(/^([#0?]+)([ ]?)\/([ ]?)([#0?]+)/))) { + o=""; + rr = Math.min(r[4].length,7); ff = frac(aval, Math.pow(10,rr)-1, false); - return sign + (ff[0]||(ff[1] ? "" : "0")) + (ff[1] ? pad(ff[1],rr," ") + r[2] + "/" + r[3] + rpad(ff[2],rr," "): fill(" ", 2*rr+1 + r[2].length + r[3].length)); + 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; + o += r[2]; + o += "/"; + o += r[3]; + oa = rpad(ff[2],rr," "); + if(oa.length < r[4].length) oa = r[4].substr(r[4].length-oa.length).replace(/[?]/g," ").replace(/#/g,"") + oa; + o += oa; + return o; } - if((r = fmt.match(/^# ([?]+)([ ]?)\/([ ]?)([?]+)/))) { + if((r = fmt.match(/^# ([#0?]+)([ ]?)\/([ ]?)([#0?]+)/))) { rr = Math.min(Math.max(r[1].length, r[4].length),7); ff = frac(aval, Math.pow(10,rr)-1, true); return sign + (ff[0]||(ff[1] ? "" : "0")) + " " + (ff[1] ? pad(ff[1],rr," ") + r[2] + "/" + r[3] + rpad(ff[2],rr," "): fill(" ", 2*rr+1 + r[2].length + r[3].length)); } - if((r = fmt.match(/^[#0]+$/))) { + if((r = fmt.match(/^[#0?]+$/))) { o = "" + Math.round(val); if(fmt.length <= o.length) return o; - return fmt.substr(0,fmt.length - o.length).replace(/#/g,"") + o; + return fmt.substr(0,fmt.length-o.length).replace(/#/g,"").replace(/\?/g," ") + o; } if((r = fmt.match(/^([#0]+)\.([#0]+)$/))) { o = "" + val.toFixed(Math.min(r[2].length,10)).replace(/([^0])0+$/,"$1"); @@ -507,7 +522,9 @@ function eval_fmt(fmt, v, opts, flen) { out[i].v = write_num(out[i].t, out[i].v, (flen >1 && v < 0 && i>0 && out[i-1].v == "-" ? -v:v)); out[i].t = 't'; } - return out.map(function(x){return x.v;}).join(""); + var retval = ""; + for(i=0; i != out.length; ++i) if(out[i]) retval += out[i].v; + return retval; } SSF._eval = eval_fmt; function choose_fmt(fmt, v, o) { diff --git a/ssf.md b/ssf.md index 758c0ca..ec6420f 100644 --- a/ssf.md +++ b/ssf.md @@ -452,7 +452,10 @@ A few special general cases can be handled in a very dumb manner: ``` if(fmt.match(/^#+0+$/)) fmt = fmt.replace(/#/g,""); if(fmt.match(/^00+$/)) return (val<0?"-":"")+pad(Math.round(aval),fmt.length); - if(fmt.match(/^[#?]+$/)) return String(Math.round(val)).replace(/^0$/,""); + if(fmt.match(/^[#?]+$/)) { + o = String(Math.round(val)).replace(/^0$/,""); + return o.length > fmt.length ? o : fmt.substr(0,fmt.length-o.length).replace(/#/g,"").replace(/[?]/g," ") + o; + } if((r = fmt.match(/^#*0*\.(0+)/))) { o = Math.round(val * Math.pow(10,r[1].length)); rr = String(o/Math.pow(10,r[1].length)).replace(/^([^\.]+)$/,"$1."+r[1]).replace(/\.$/,"."+r[1]).replace(/\.([0-9]*)$/,function($$, $1) { return "." + $1 + fill("0", r[1].length-$1.length); }); @@ -499,25 +502,37 @@ of first drawing the digits, but this selection allows for more nuance: The frac helper function is used for fraction formats (defined below). ``` - if((r = fmt.match(/^([?]+)([ ]?)\/([ ]?)([?]+)/))) { - rr = Math.min(Math.max(r[1].length, r[4].length),7); + var oa = ""; + if((r = fmt.match(/^([#0?]+)([ ]?)\/([ ]?)([#0?]+)/))) { + o=""; + rr = Math.min(r[4].length,7); ff = frac(aval, Math.pow(10,rr)-1, false); - return sign + (ff[0]||(ff[1] ? "" : "0")) + (ff[1] ? pad(ff[1],rr," ") + r[2] + "/" + r[3] + rpad(ff[2],rr," "): fill(" ", 2*rr+1 + r[2].length + r[3].length)); + 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; + o += r[2]; + o += "/"; + o += r[3]; + oa = rpad(ff[2],rr," "); + if(oa.length < r[4].length) oa = r[4].substr(r[4].length-oa.length).replace(/[?]/g," ").replace(/#/g,"") + oa; + o += oa; + return o; } - if((r = fmt.match(/^# ([?]+)([ ]?)\/([ ]?)([?]+)/))) { + if((r = fmt.match(/^# ([#0?]+)([ ]?)\/([ ]?)([#0?]+)/))) { rr = Math.min(Math.max(r[1].length, r[4].length),7); ff = frac(aval, Math.pow(10,rr)-1, true); return sign + (ff[0]||(ff[1] ? "" : "0")) + " " + (ff[1] ? pad(ff[1],rr," ") + r[2] + "/" + r[3] + rpad(ff[2],rr," "): fill(" ", 2*rr+1 + r[2].length + r[3].length)); } ``` -The general class `/^[#0]+$/` treats the unconsumed '0' as literal, '#' as noop: +The general class `/^[#0?]+$/` treats the '0' as literal, '#' as noop, '?' as space: ``` - if((r = fmt.match(/^[#0]+$/))) { + if((r = fmt.match(/^[#0?]+$/))) { o = "" + Math.round(val); if(fmt.length <= o.length) return o; - return fmt.substr(0,fmt.length - o.length).replace(/#/g,"") + o; + return fmt.substr(0,fmt.length-o.length).replace(/#/g,"").replace(/\?/g," ") + o; } if((r = fmt.match(/^([#0]+)\.([#0]+)$/))) { o = "" + val.toFixed(Math.min(r[2].length,10)).replace(/([^0])0+$/,"$1"); @@ -896,7 +911,9 @@ positive when there is an explicit hyphen before it (e.g. `#,##0.0;-#,##0.0`): Now we just need to combine the elements ``` - return out.map(function(x){return x.v;}).join(""); + var retval = ""; + for(i=0; i != out.length; ++i) if(out[i]) retval += out[i].v; + return retval; } SSF._eval = eval_fmt; ``` @@ -1212,6 +1229,7 @@ test_min: .PHONY: lint lint: jshint ssf.js test/ + jscs ssf.js ``` Coverage tests use [blanket](http://npm.im/blanket): @@ -1245,7 +1263,7 @@ coveralls: ```json>package.json { "name": "ssf", - "version": "0.7.0", + "version": "0.7.1", "author": "SheetJS", "description": "pure-JS library to format data using ECMA-376 spreadsheet Format Codes", "keywords": [ "format", "sprintf", "spreadsheet" ], diff --git a/test/oddities.json b/test/oddities.json index 08074a9..2252be1 100644 --- a/test/oddities.json +++ b/test/oddities.json @@ -118,6 +118,10 @@ ["000-00-0000", [123456789, "123-45-6789"]], ["00000\\-0000", [941051630, "94105-1630"]], ["000\\-00\\-0000", [123456789, "123-45-6789"]], + ["??/??", [12.3456789, "1000/81"], [0.00001, " 0/1 "]], + ["# ??/??", [12.3456789, "12 28/81"]], + ["#??/??", [12.3456789, "1000/81"]], + ["#0#00??/??", [12.3456789, "01000/81"]], ["[<=9999999]###-####;(###) ###-####", [8675309, "867-5309"],[2813308004, "(281) 330-8004"]], ["[<=9999999]###\\-####;(###) ###\\-####", [8675309, "867-5309"],[2813308004, "(281) 330-8004"]], ["[Red][<-25]General;[Blue][>25]General;[Green]General;[Yellow]General", [50, "50"],[26, "26"],[25,"25"],[1,"1"],[0,"0"],[-1,"-1"],[-25,"-25"],[-26,"26","#"],[-50,"50","#"], ["foo","foo"],["bar","bar"]],