From aa25491492df4a2f681684eb9f3d4d1a4343768b Mon Sep 17 00:00:00 2001 From: SheetJS Date: Thu, 8 Jun 2017 20:59:13 -0400 Subject: [PATCH] version bump 0.9.4 - correct am/pm to AM/PM and a/p to A/P (h/t @vvaldersteins) - trailing hashes (h/t @kuhu19) --- Makefile | 2 +- bits/01_version.js | 2 +- bits/60_number.js | 2 +- bits/63_numflt.js | 2 +- bits/66_numint.js | 4 ++-- bits/81_fmttype.js | 6 +++--- bits/82_eval.js | 9 ++++----- package.json | 2 +- ssf.flow.js | 26 +++++++++++++------------- ssf.js | 24 +++++++++++------------- test/oddities.json | 21 +++++++++++++++++++-- 11 files changed, 57 insertions(+), 43 deletions(-) diff --git a/Makefile b/Makefile index 9e72bcb..5ffb9b5 100755 --- a/Makefile +++ b/Makefile @@ -80,7 +80,7 @@ flow: lint ## Run flow checker @flow check --all --show-all-errors .PHONY: cov -cov: tmp/coverage.html ## Run coverage test +cov: misc/coverage.html ## Run coverage test .PHONY: cov_min cov_min: diff --git a/bits/01_version.js b/bits/01_version.js index d1260b4..9c32d95 100644 --- a/bits/01_version.js +++ b/bits/01_version.js @@ -1 +1 @@ -SSF.version = '0.9.3'; +SSF.version = '0.9.4'; diff --git a/bits/60_number.js b/bits/60_number.js index c14a2ec..5d13dfc 100644 --- a/bits/60_number.js +++ b/bits/60_number.js @@ -38,7 +38,7 @@ function write_num_f1(r/*:Array*/, aval/*:number*/, sign/*:string*/)/*:s function write_num_f2(r/*:Array*/, aval/*:number*/, sign/*:string*/)/*:string*/ { return sign + (aval === 0 ? "" : ""+aval) + fill(" ", r[1].length + 2 + r[4].length); } -var dec1 = /^#*0*\.(0+)/; +var dec1 = /^#*0*\.([0#]+)/; var closeparen = /\).*[0#]/; var phone = /\(###\) ###\\?-####/; function hashq(str/*:string*/)/*:string*/ { diff --git a/bits/63_numflt.js b/bits/63_numflt.js index 6644977..6ab7870 100644 --- a/bits/63_numflt.js +++ b/bits/63_numflt.js @@ -18,7 +18,7 @@ function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string 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))) { - 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); }); + o = rnd(val, r[1].length).replace(/^([^\.]+)$/,"$1."+hashq(r[1])).replace(/\.$/,"."+hashq(r[1])).replace(/\.(\d*)$/,function($$, $1) { return "." + $1 + fill("0", hashq(/*::(*/r/*::||[""])*/[1]).length-$1.length); }); return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,"."); } fmt = fmt.replace(/^#+([0.])/, "$1"); diff --git a/bits/66_numint.js b/bits/66_numint.js index a543c72..2e3dca3 100644 --- a/bits/66_numint.js +++ b/bits/66_numint.js @@ -19,10 +19,10 @@ function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string if(fmt.match(/^#+0+$/)) return sign + pad0(aval,fmt.length - fmt.indexOf("0")); if((r = fmt.match(dec1))) { /*:: if(!Array.isArray(r)) throw new Error("unreachable"); */ - o = (""+val).replace(/^([^\.]+)$/,"$1."+r[1]).replace(/\.$/,"."+r[1]); + o = (""+val).replace(/^([^\.]+)$/,"$1."+hashq(r[1])).replace(/\.$/,"."+hashq(r[1])); o = o.replace(/\.(\d*)$/,function($$, $1) { /*:: if(!Array.isArray(r)) throw new Error("unreachable"); */ - return "." + $1 + fill("0", r[1].length-$1.length); }); + return "." + $1 + fill("0", hashq(r[1]).length-$1.length); }); return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,"."); } fmt = fmt.replace(/^#+([0.])/, "$1"); diff --git a/bits/81_fmttype.js b/bits/81_fmttype.js index 9337d88..090d1a8 100644 --- a/bits/81_fmttype.js +++ b/bits/81_fmttype.js @@ -14,9 +14,9 @@ function fmt_is_date(fmt/*:string*/)/*:boolean*/ { 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; + case 'A': case 'a': + if(fmt.substr(i, 3).toUpperCase() === "A/P") return true; + if(fmt.substr(i, 5).toUpperCase() === "AM/PM") return true; ++i; break; case '[': o = c; diff --git a/bits/82_eval.js b/bits/82_eval.js index 5657f24..c1e5f30 100644 --- a/bits/82_eval.js +++ b/bits/82_eval.js @@ -32,11 +32,10 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) { if(c === 'h') c = hr; out[out.length] = {t:c, v:o}; lst = c; break; case 'A': case 'a': - q={t:c, v:"A"}; + q={t:c, v:c}; 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 if(fmt.substr(i,5) === 'am/pm') { if(dt!=null) q.v = dt.H >= 12 ? "PM" : "AM"; q.t = 'T'; i+=5; hr='h'; } + if(fmt.substr(i, 3).toUpperCase() === "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).toUpperCase() === "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; @@ -73,7 +72,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) { 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); + if(",$-+/():!^&'~{}<>=€acfijklopqrtuvwxzP".indexOf(c) === -1) throw new Error('unrecognized character ' + c + ' in ' + fmt); out[out.length] = {t:'t', v:c}; ++i; break; } } diff --git a/package.json b/package.json index 63bd210..f0e3cd9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ssf", - "version": "0.9.3", + "version": "0.9.4", "author": "SheetJS", "description": "Format data using ECMA-376 spreadsheet Format Codes", "keywords": [ "format", "sprintf", "spreadsheet" ], diff --git a/ssf.flow.js b/ssf.flow.js index caacba5..7ba1a52 100644 --- a/ssf.flow.js +++ b/ssf.flow.js @@ -2,7 +2,7 @@ /*jshint -W041 */ var SSF = {}; var make_ssf = function make_ssf(SSF){ -SSF.version = '0.9.3'; +SSF.version = '0.9.4'; 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;} @@ -299,7 +299,7 @@ function write_num_f1(r/*:Array*/, aval/*:number*/, sign/*:string*/)/*:s function write_num_f2(r/*:Array*/, aval/*:number*/, sign/*:string*/)/*:string*/ { return sign + (aval === 0 ? "" : ""+aval) + fill(" ", r[1].length + 2 + r[4].length); } -var dec1 = /^#*0*\.(0+)/; +var dec1 = /^#*0*\.([0#]+)/; var closeparen = /\).*[0#]/; var phone = /\(###\) ###\\?-####/; function hashq(str/*:string*/)/*:string*/ { @@ -346,7 +346,7 @@ function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string 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))) { - 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); }); + o = rnd(val, r[1].length).replace(/^([^\.]+)$/,"$1."+hashq(r[1])).replace(/\.$/,"."+hashq(r[1])).replace(/\.(\d*)$/,function($$, $1) { return "." + $1 + fill("0", hashq(/*::(*/r/*::||[""])*/[1]).length-$1.length); }); return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,"."); } fmt = fmt.replace(/^#+([0.])/, "$1"); @@ -463,10 +463,10 @@ function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string if(fmt.match(/^#+0+$/)) return sign + pad0(aval,fmt.length - fmt.indexOf("0")); if((r = fmt.match(dec1))) { /*:: if(!Array.isArray(r)) throw new Error("unreachable"); */ - o = (""+val).replace(/^([^\.]+)$/,"$1."+r[1]).replace(/\.$/,"."+r[1]); + o = (""+val).replace(/^([^\.]+)$/,"$1."+hashq(r[1])).replace(/\.$/,"."+hashq(r[1])); o = o.replace(/\.(\d*)$/,function($$, $1) { /*:: if(!Array.isArray(r)) throw new Error("unreachable"); */ - return "." + $1 + fill("0", r[1].length-$1.length); }); + return "." + $1 + fill("0", hashq(r[1]).length-$1.length); }); return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,"."); } fmt = fmt.replace(/^#+([0.])/, "$1"); @@ -564,9 +564,9 @@ function fmt_is_date(fmt/*:string*/)/*:boolean*/ { 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; + case 'A': case 'a': + if(fmt.substr(i, 3).toUpperCase() === "A/P") return true; + if(fmt.substr(i, 5).toUpperCase() === "AM/PM") return true; ++i; break; case '[': o = c; @@ -623,11 +623,11 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) { if(c === 'm' && lst.toLowerCase() === 'h') c = 'M'; if(c === 'h') c = hr; out[out.length] = {t:c, v:o}; lst = c; break; - case 'A': - q={t:c, v:"A"}; + case 'A': case 'a': + q={t:c, v:c}; 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'; } + if(fmt.substr(i, 3).toUpperCase() === "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).toUpperCase() === "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; @@ -664,7 +664,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) { 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); + if(",$-+/():!^&'~{}<>=€acfijklopqrtuvwxzP".indexOf(c) === -1) throw new Error('unrecognized character ' + c + ' in ' + fmt); out[out.length] = {t:'t', v:c}; ++i; break; } } diff --git a/ssf.js b/ssf.js index 212506e..4c77d22 100644 --- a/ssf.js +++ b/ssf.js @@ -2,7 +2,7 @@ /*jshint -W041 */ var SSF = {}; var make_ssf = function make_ssf(SSF){ -SSF.version = '0.9.3'; +SSF.version = '0.9.4'; function _strrev(x) { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; } function fill(c,l) { var o = ""; while(o.length < l) o+=c; return o; } function pad0(v,d){var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;} @@ -298,7 +298,7 @@ function write_num_f1(r, aval, sign) { function write_num_f2(r, aval, sign) { return sign + (aval === 0 ? "" : ""+aval) + fill(" ", r[1].length + 2 + r[4].length); } -var dec1 = /^#*0*\.(0+)/; +var dec1 = /^#*0*\.([0#]+)/; var closeparen = /\).*[0#]/; var phone = /\(###\) ###\\?-####/; function hashq(str) { @@ -345,7 +345,7 @@ function write_num_flt(type, fmt, val) { 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))) { - 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); }); + o = rnd(val, r[1].length).replace(/^([^\.]+)$/,"$1."+hashq(r[1])).replace(/\.$/,"."+hashq(r[1])).replace(/\.(\d*)$/,function($$, $1) { return "." + $1 + fill("0", hashq(r[1]).length-$1.length); }); return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,"."); } fmt = fmt.replace(/^#+([0.])/, "$1"); @@ -461,9 +461,9 @@ function write_num_int(type, fmt, val) { 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))) { -o = (""+val).replace(/^([^\.]+)$/,"$1."+r[1]).replace(/\.$/,"."+r[1]); +o = (""+val).replace(/^([^\.]+)$/,"$1."+hashq(r[1])).replace(/\.$/,"."+hashq(r[1])); o = o.replace(/\.(\d*)$/,function($$, $1) { -return "." + $1 + fill("0", r[1].length-$1.length); }); +return "." + $1 + fill("0", hashq(r[1]).length-$1.length); }); return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,"."); } fmt = fmt.replace(/^#+([0.])/, "$1"); @@ -562,9 +562,8 @@ function fmt_is_date(fmt) { /* falls through */ case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g': return true; case 'A': case 'a': - if(fmt.substr(i, 3) === "A/P") return true; - if(fmt.substr(i, 5) === "AM/PM") return true; - if(fmt.substr(i, 5) === "am/pm") return true; + if(fmt.substr(i, 3).toUpperCase() === "A/P") return true; + if(fmt.substr(i, 5).toUpperCase() === "AM/PM") return true; ++i; break; case '[': o = c; @@ -622,11 +621,10 @@ function eval_fmt(fmt, v, opts, flen) { if(c === 'h') c = hr; out[out.length] = {t:c, v:o}; lst = c; break; case 'A': case 'a': - q={t:c, v:"A"}; + q={t:c, v:c}; 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 if(fmt.substr(i,5) === 'am/pm') { if(dt!=null) q.v = dt.H >= 12 ? "PM" : "AM"; q.t = 'T'; i+=5; hr='h'; } + if(fmt.substr(i, 3).toUpperCase() === "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).toUpperCase() === "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; @@ -663,7 +661,7 @@ function eval_fmt(fmt, v, opts, flen) { 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); + if(",$-+/():!^&'~{}<>=€acfijklopqrtuvwxzP".indexOf(c) === -1) throw new Error('unrecognized character ' + c + ' in ' + fmt); out[out.length] = {t:'t', v:c}; ++i; break; } } diff --git a/test/oddities.json b/test/oddities.json index 56fb3e1..2cc6a40 100644 --- a/test/oddities.json +++ b/test/oddities.json @@ -125,6 +125,19 @@ [101000000, "1010\\000\\000.00"], [123456789.01, "1234\\567\\890.01"] ], + ["0.0#", + [12345.0, "12345.0"], + [1234.5, "1234.5"], + [123.45, "123.45"], + [12.345, "12.35"], + [1.2345, "1.23"], + [0.12345, "0.12"], + [0.012345, "0.01"], + [0.0012345, "0.0"], + [0.00012345, "0.0"], + [15.04, "15.04"], + [15.06, "15.06"] + ], ["###\\\\###\\\\##\\0", [12345.6789, "\\123\\460"]], ["00000-0000", [941051630, "94105-1630"], [12345.6789, "00001-2346"]], ["000-00-0000", [123456789, "123-45-6789"]], @@ -157,7 +170,11 @@ ["[$-409]mmm\\-yy", [12345, "Oct-33"]], ["\\,##.??;\\(#,###.??\\);0", [15,",15. ","#"], [14.3453453,",14.35","#"], [12.1,",12.1 ","#"], [0,"0","#"], [-15,"(15. )","#"], [-14.3453453,"(14.35)","#"], [-12.1,"(12.1 )","#"], [1,",1. ","#"]], - ["\"£\"#.####;-\"£\"#.####", [3.141592654, "£3.1416"], [-3.141592654, "-£3.1416"]], - ["[h]:mm:ss;@", [2.9999999999999996, "72:00:00"]], + ["\"£\"#.####;-\"£\"#.####", [3.141592654, "£3.1416"], [-3.141592654, "-£3.1416"]], + ["[h]:mm:ss;@", [2.9999999999999996, "72:00:00"]], + ["hh:mm:ss AM/PM", [0.5, "12:00:00 PM"]], + ["hh:mm:ss am/pm", [0.5, "12:00:00 PM"]], + ["hh:mm:ss AM/P", [0.5, "12:00:00 A1/P"]], + ["hh:mm:ss am/p", [0.5, "12:00:00 a1/p"]], ["\"foo\";\"bar\";\"baz\";\"qux\";\"foobar\"", [1], [0], [-1], ["sheetjs"]] ]