forked from sheetjs/sheetjs
		
	flow typing and cleanup
This commit is contained in:
		
							parent
							
								
									097f026d03
								
							
						
					
					
						commit
						695452bffb
					
				
							
								
								
									
										29
									
								
								.flowconfig
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										29
									
								
								.flowconfig
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| [ignore] | ||||
| .*/node_modules/.* | ||||
| .*/dist/.* | ||||
| .*/test/bits/.* | ||||
| .*/test/.* | ||||
| .*/ssf.js | ||||
| .*/ssf_lc.js | ||||
| 
 | ||||
| .*/bits/.* | ||||
| .*/ctest/.* | ||||
| .*/misc/.* | ||||
| .*/perf/.* | ||||
| .*/tmp/.* | ||||
| .*/tmp/.* | ||||
| 
 | ||||
| .*/demo/browser.js | ||||
| .*/shim.js | ||||
| 
 | ||||
| [include] | ||||
| ssf.js | ||||
| .*/bin/.*.njs | ||||
| 
 | ||||
| [libs] | ||||
| misc/flow.js | ||||
| misc/flowdeps.js | ||||
| 
 | ||||
| [options] | ||||
| module.file_ext=.js | ||||
| module.file_ext=.njs | ||||
| @ -1,9 +1,16 @@ | ||||
| language: node_js | ||||
| node_js: | ||||
|   - "7" | ||||
|   - "6" | ||||
|   - "5" | ||||
|   - "4" | ||||
|   - "0.12" | ||||
|   - "0.10" | ||||
|   - "0.9" | ||||
|   - "0.8" | ||||
| before_install: | ||||
|   - "npm install -g mocha" | ||||
|   - "npm install -g npm@4.3.0" | ||||
|   - "npm install -g mocha@2.x voc" | ||||
|   - "npm install blanket" | ||||
|   - "npm install coveralls mocha-lcov-reporter" | ||||
| after_success: | ||||
|  | ||||
							
								
								
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							| @ -1,4 +1,4 @@ | ||||
| Copyright (C) 2013-2014   SheetJS | ||||
| Copyright (C) 2013-present  SheetJS | ||||
| 
 | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|  | ||||
							
								
								
									
										59
									
								
								Makefile
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										59
									
								
								Makefile
									
									
									
									
									
								
							| @ -1,35 +1,64 @@ | ||||
| .PHONY: test ssf | ||||
| SHELL=/bin/bash | ||||
| LIB=ssf | ||||
| CMDS=bin/ssf.njs | ||||
| HTMLLINT= | ||||
| 
 | ||||
| ULIB=$(shell echo $(LIB) | tr a-z A-Z) | ||||
| TARGET=$(LIB).js | ||||
| 
 | ||||
| ## Main Targets
 | ||||
| 
 | ||||
| 
 | ||||
| .PHONY: ssf | ||||
| ssf: ssf.md | ||||
| 	voc ssf.md | ||||
| 
 | ||||
| test: | ||||
| ## Testing
 | ||||
| 
 | ||||
| .PHONY: test mocha | ||||
| test mocha: ## Run test suite
 | ||||
| 	npm test | ||||
| 
 | ||||
| test_min: | ||||
| 	MINTEST=1 npm test | ||||
| 
 | ||||
| .PHONY: lint | ||||
| lint: | ||||
| 	jshint ssf.js test/ | ||||
| 	jscs ssf.js | ||||
| ## Code Checking
 | ||||
| 
 | ||||
| .PHONY: perf | ||||
| perf: | ||||
| 	bash misc/perf.sh | ||||
| .PHONY: lint | ||||
| lint: ## Run jshint and jscs checks
 | ||||
| 	@jshint --show-non-errors $(TARGET) test/ | ||||
| 	@jshint --show-non-errors $(CMDS) | ||||
| 	@jshint --show-non-errors package.json | ||||
| 	@jshint --show-non-errors --extract=always $(HTMLLINT) | ||||
| 	@jscs $(TARGET) | ||||
| 
 | ||||
| .PHONY: flow | ||||
| flow: lint ## Run flow checker
 | ||||
| 	@flow check --all --show-all-errors | ||||
| 
 | ||||
| .PHONY: cov | ||||
| cov: tmp/coverage.html | ||||
| 
 | ||||
| tmp/coverage.html: ssf | ||||
| 	mocha --require blanket -R html-cov > tmp/coverage.html | ||||
| cov: tmp/coverage.html ## Run coverage test
 | ||||
| 
 | ||||
| .PHONY: cov_min | ||||
| cov_min: | ||||
| 	MINTEST=1 make cov | ||||
| 
 | ||||
| .PHONY: coveralls full_coveralls | ||||
| tmp/coverage.html: ssf | ||||
| 	mocha --require blanket -R html-cov -t 20000 > $@ | ||||
| 
 | ||||
| .PHONY: full_coveralls | ||||
| full_coveralls: | ||||
| 	mocha --require blanket --reporter mocha-lcov-reporter | ./node_modules/coveralls/bin/coveralls.js | ||||
| 
 | ||||
| coveralls: | ||||
| .PHONY: coveralls | ||||
| coveralls: ## Coverage Test + Send to coveralls.io
 | ||||
| 	MINTEST=1 make full_coveralls | ||||
| 
 | ||||
| 
 | ||||
| .PHONY: help | ||||
| help: | ||||
| 	@grep -hE '(^[a-zA-Z_-][ a-zA-Z_-]*:.*?|^#[#*])' $(MAKEFILE_LIST) | bash misc/help.sh | ||||
| 
 | ||||
| #* To show a spinner, append "-spin" to any target e.g. cov-spin
 | ||||
| %-spin: | ||||
| 	@make $* & bash misc/spin.sh $$! | ||||
|  | ||||
							
								
								
									
										97
									
								
								README.md
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										97
									
								
								README.md
									
									
									
									
									
								
							| @ -1,59 +1,98 @@ | ||||
| # SSF | ||||
| 
 | ||||
| SpreadSheet Format (SSF) is a pure-JS library to format data using ECMA-376  | ||||
| spreadsheet format codes (like those used in Microsoft Excel) | ||||
| ssf (SpreadSheet Format) is a pure-JS library to format data using ECMA-376 | ||||
| spreadsheet format codes (used in popular spreadsheet software packages). | ||||
| 
 | ||||
| This is written in [voc](https://npmjs.org/package/voc) -- see ssf.md for code. | ||||
| 
 | ||||
| To build: `voc ssf.md` | ||||
| ## Installation | ||||
| 
 | ||||
| ## Setup | ||||
| With [npm](https://www.npmjs.org/package/ssf): | ||||
| 
 | ||||
| ```bash | ||||
| $ npm install ssf | ||||
| ``` | ||||
| 
 | ||||
| In the browser: | ||||
| 
 | ||||
|     <script src="ssf.js"></script> | ||||
| ```html | ||||
| <script src="ssf.js"></script> | ||||
| ``` | ||||
| 
 | ||||
| In node: | ||||
| The browser exposes a variable `SSF` | ||||
| 
 | ||||
|     var SSF = require('ssf'); | ||||
| When installed globally, npm installs a script `ssf` that renders the format | ||||
| string with the given arguments.  Running the script with `-h` displays help. | ||||
| 
 | ||||
| The script will manipulate `module.exports` if available (e.g. in a CommonJS  | ||||
| `require` context).  This is not always desirable.  To prevent the behavior,  | ||||
| define `DO_NOT_EXPORT_SSF`: | ||||
| The script will manipulate `module.exports` if available (e.g. in a CommonJS | ||||
| `require` context).  This is not always desirable.  To prevent the behavior, | ||||
| define `DO_NOT_EXPORT_SSF`. | ||||
| 
 | ||||
| ## Usage | ||||
| 
 | ||||
| `.load(fmt, idx)` sets custom formats (generally indices above `164`). | ||||
| `SSF.format(fmt, val, opts)` formats `val` using the format `fmt`.  If `fmt` is | ||||
| a string, it will be parsed and evaluated.  If `fmt` is a `number`, the actual | ||||
| format will be the corresponding entry in the internal format table. | ||||
| 
 | ||||
| `.format(fmt, val, opts)` formats `val` using the format `fmt`.  If `fmt` is of  | ||||
| type `number`, the internal table (and custom formats) will be used.  If `fmt`  | ||||
| is a literal format, then it will be parsed and evaluated. | ||||
| ### Manipulating the Internal Format Table | ||||
| 
 | ||||
| `.parse_date_code(val, opts)` parses `val` as date code and returns object: | ||||
| Binary spreadsheet formats store cell formats in a table and reference by index. | ||||
| This library uses a global table: | ||||
| 
 | ||||
| - `D,T`: Date (`[val]`) Time (`{val}`) | ||||
| - `y,m,d`: Year, Month, Day | ||||
| - `H,M,S,u`: (0-23)Hour, Minute, Second, Sub-second | ||||
| - `q`: Day of Week (0=Sunday, 1=Monday, ..., 5=Friday, 6=Saturday) | ||||
| `SSF._table` is the underlying object, mapping numeric keys to format strings. | ||||
| 
 | ||||
| `.get_table()` gets the internal format table (number to format mapping). | ||||
| `SSF.load(fmt:string, idx:?number):number` assigns the format to the specified | ||||
| index and returns the index.  If the index is not specified, SSF will search the | ||||
| space for an available format slot pick an unused slot.  For compatibility with | ||||
| the XLS and XLSB file formats, custom indices should be in the valid ranges | ||||
| `5-8`, `23-26`, `41-44`, `63-66`, `164-382` (see `[MS-XLSB] 2.4.655 BrtFmt`) | ||||
| 
 | ||||
| `.load_table(table)` sets the internal format table. | ||||
| `SSF.get_table()` gets the internal format table (number to format mapping). | ||||
| 
 | ||||
| ## Notes | ||||
| `SSF.load_table(table)` sets the internal format table. | ||||
| 
 | ||||
| ### Other Utilities | ||||
| 
 | ||||
| `SSF.parse_date_code(val:number, opts:?any)` parses `val`, returning an object: | ||||
| 
 | ||||
| ```typescript | ||||
| type SSFDate = { | ||||
|   D:number; /* number of whole days since relevant epoch, 0 <= D */ | ||||
|   y:number; /* integral year portion, epoch_year <= y */ | ||||
|   m:number; /* integral month portion, 1 <= m <= 12 */ | ||||
|   d:number; /* integral day portion, subject to gregorian YMD constraints */ | ||||
|   q:number; /* integral day of week (0=Sunday .. 6=Saturday) 0 <= q <= 6 */ | ||||
| 
 | ||||
|   T:number; /* number of seconds since midnight, 0 <= T < 86400 */ | ||||
|   H:number; /* integral number of hours since midnight, 0 <= H < 24 */ | ||||
|   M:number; /* integral number of minutes since the last hour, 0 <= M < 60 */ | ||||
|   S:number; /* integral number of seconds since the last minute, 0 <= S < 60 */ | ||||
|   u:number; /* sub-second part of time, 0 <= u < 1 */ | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| Format code 14 in the spec is broken; the correct format is 'mm/dd/yy' (dashes, | ||||
| not spaces) | ||||
| 
 | ||||
| ## License | ||||
| 
 | ||||
| Apache 2.0 | ||||
| Please consult the attached LICENSE file for details.  All rights not explicitly | ||||
| granted by the Apache 2.0 license are reserved by the Original Author. | ||||
| 
 | ||||
| ## Tests | ||||
| ## References | ||||
| 
 | ||||
| - [ECMA-376] Office Open XML File Formats | ||||
| - [MS-XLSB] Excel (.xlsb) Binary File Format | ||||
| 
 | ||||
| ## Badges | ||||
| 
 | ||||
| [](https://saucelabs.com/u/ssfjs) | ||||
| 
 | ||||
| [](https://travis-ci.org/SheetJS/ssf) | ||||
| 
 | ||||
| [](https://coveralls.io/r/SheetJS/ssf?branch=master) | ||||
| [](https://coveralls.io/r/SheetJS/ssf?branch=master) | ||||
| 
 | ||||
| [](http://githalytics.com/SheetJS/ssf) | ||||
| [](https://npmjs.org/package/ssf) | ||||
| 
 | ||||
| [](https://david-dm.org/sheetjs/ssf) | ||||
| 
 | ||||
| [](https://ghit.me/repo/sheetjs/js-xlsx) | ||||
| 
 | ||||
| [](https://github.com/SheetJS/ssf) | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| #!/usr/bin/env node | ||||
| /* ssf.js (C) 2013-2014 SheetJS -- http://sheetjs.com */ | ||||
| /* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */ | ||||
| var SSF = require('../'); | ||||
| var argv = process.argv.slice(2); | ||||
| if(argv.length < 2 || argv[0] == "-h" || argv[0] == "--help") { | ||||
|  | ||||
							
								
								
									
										8
									
								
								misc/flow.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										8
									
								
								misc/flow.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| /*# vim: set ts=2: */ | ||||
| /*:: | ||||
| 
 | ||||
| type SSFModule = { | ||||
| 	format(fmt:string|number, v:any, o:any):string; | ||||
| }; | ||||
| 
 | ||||
| */ | ||||
							
								
								
									
										8
									
								
								misc/flowdeps.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										8
									
								
								misc/flowdeps.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| /*# vim: set ts=2: */ | ||||
| /*:: | ||||
| 
 | ||||
| declare module './' { declare var exports:SSFModule; }; | ||||
| declare module '../' { declare var exports:SSFModule; }; | ||||
| declare module 'ssf' { declare var exports:SSFModule; }; | ||||
| 
 | ||||
| */ | ||||
							
								
								
									
										42
									
								
								misc/help.sh
									
									
									
									
									
										Executable file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										42
									
								
								misc/help.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,42 @@ | ||||
| #!/bin/bash | ||||
| # make_help.sh -- process listing of targets and special items in Makefile | ||||
| # Copyright (C) 2016-present  SheetJS | ||||
| # | ||||
| # usage in makefile: pipe the output of the following command: | ||||
| #     @grep -hE '(^[a-zA-Z_-][ a-zA-Z_-]*:.*?|^#[#*])' $(MAKEFILE_LIST) | ||||
| # | ||||
| # lines starting with "## " are treated as subtitles | ||||
| # lines starting with "#* " are treated as plaintext comments | ||||
| # multiple targets with "## " after the ":" are rendered as separate targets | ||||
| # if the presumed default target is labeled, it will be assigned a unique color | ||||
| 
 | ||||
| awk ' | ||||
| BEGIN{recipes=0;} | ||||
| 	!/#[#*] .*$/ {next;} | ||||
| 	{multi=0; isrecipe=0;} | ||||
| 	/^[^#]*:/ {isrecipe=1; ++recipes;} | ||||
| 	/^[^ :]* .*:/ {multi=1} | ||||
| 	multi==0 && isrecipe>0 { if(recipes > 1) print; else print $0, "[default]"; next} | ||||
| 	isrecipe == 0 {print; next} | ||||
| 	multi>0 { | ||||
| 		k=split($0, msg, "##"); m=split($0, a, ":"); n=split(a[1], b, " "); | ||||
| 		for(i=1; i<=n; ++i) print b[i] ":", "##" msg[2], (recipes==1 && i==1 ? "[default]" : "") | ||||
| 	} | ||||
| END {} | ||||
| ' | if [[ -t 1 ]]; then | ||||
| awk ' | ||||
| BEGIN {FS = ":.*?## "} | ||||
| 	{color=36} | ||||
| 	/\[default\]/ {color=35} | ||||
| 	NF==1 && /^##/ {color=34} | ||||
| 	NF==1 && /^#\*/ {color=20; $1 = substr($1, 4)} | ||||
| 	{printf "\033[" color "m%-20s\033[0m %s\n", $1, $2;} | ||||
| END{}' - | ||||
| else | ||||
| awk ' | ||||
| BEGIN {FS = ":.*?## "} | ||||
| 	/^#\* / {$1 = substr($1, 4)} | ||||
| 	{printf "%-20s %s\n", $1, $2;} | ||||
| END{}' - | ||||
| fi | ||||
| 
 | ||||
							
								
								
									
										14
									
								
								misc/spin.sh
									
									
									
									
									
										Executable file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										14
									
								
								misc/spin.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,14 @@ | ||||
| #!/bin/bash | ||||
| # spin.sh -- show a spinner (for coverage test) | ||||
| # Copyright (C) 2014-present  SheetJS | ||||
| 
 | ||||
| wpid=$1 | ||||
| delay=1 | ||||
| str="|/-\\" | ||||
| while [ $(ps -a|awk '$1=='$wpid' {print $1}') ]; do | ||||
|   t=${str#?} | ||||
|   printf " [%c]" "$str" | ||||
|   str=$t${str%"$t"} | ||||
|   sleep $delay | ||||
|   printf "\b\b\b\b" | ||||
| done | ||||
							
								
								
									
										242
									
								
								ssf.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										242
									
								
								ssf.js
									
									
									
									
									
								
							| @ -1,20 +1,20 @@ | ||||
| /* ssf.js (C) 2013-2014 SheetJS -- http://sheetjs.com */ | ||||
| /* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */ | ||||
| /*jshint -W041 */ | ||||
| var SSF = {}; | ||||
| var make_ssf = function make_ssf(SSF){ | ||||
| SSF.version = '0.8.1'; | ||||
| 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;} | ||||
| function pad_(v,d){var t=""+v;return t.length>=d?t:fill(' ',d-t.length)+t;} | ||||
| function rpad_(v,d){var t=""+v; return t.length>=d?t:t+fill(' ',d-t.length);} | ||||
| function pad0r1(v,d){var t=""+Math.round(v); return t.length>=d?t:fill('0',d-t.length)+t;} | ||||
| function pad0r2(v,d){var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;} | ||||
| 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,d){if(v>p2_32||v<-p2_32) return pad0r1(v,d); var i = Math.round(v); return pad0r2(i,d); } | ||||
| function isgeneral(s, i) { 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; } | ||||
| 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 = [ | ||||
| var opts_fmt/*:Array<Array<any> >*/ = [ | ||||
|   ["date1904", 0], | ||||
|   ["output", ""], | ||||
|   ["WTF", false] | ||||
| @ -24,36 +24,36 @@ function fixopts(o){ | ||||
| } | ||||
| 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' | ||||
|   /*::[*/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 = [ | ||||
|   ['Sun', 'Sunday'], | ||||
| @ -100,7 +100,7 @@ function frac(x, D, mixed) { | ||||
|   var q = Math.floor(sgn * P/Q); | ||||
|   return [q, sgn*P - q*Q, Q]; | ||||
| } | ||||
| function general_fmt_int(v, opts) { return ""+v; } | ||||
| 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)$/; | ||||
| @ -124,7 +124,7 @@ function gfn5(o) { | ||||
|   //return o;
 | ||||
|   return o.indexOf(".") > -1 ? o.replace(gnr2,"").replace(gnr1,".$1") : o; | ||||
| } | ||||
| return function general_fmt_num(v, opts) { | ||||
| 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); | ||||
| @ -133,7 +133,7 @@ return function general_fmt_num(v, opts) { | ||||
|   return gfn5(gfn4(o)); | ||||
| };})(); | ||||
| SSF._general_num = general_fmt_num; | ||||
| function general_fmt(v, opts) { | ||||
| function general_fmt(v/*:any*/, opts/*:?any*/) { | ||||
|   switch(typeof v) { | ||||
|     case 'string': return v; | ||||
|     case 'boolean': return v ? "TRUE" : "FALSE"; | ||||
| @ -143,7 +143,7 @@ function general_fmt(v, opts) { | ||||
| } | ||||
| SSF._general = general_fmt; | ||||
| function fix_hijri(date, o) { return 0; } | ||||
| function parse_date_code(v,opts,b2) { | ||||
| 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=[]; | ||||
| @ -159,8 +159,8 @@ function parse_date_code(v,opts,b2) { | ||||
|   else if(date === 0) {dout = b2 ? [1317,8,29] : [1900,1,0]; dow=6;} | ||||
|   else { | ||||
|     if(date > 60) --date; | ||||
|     /* 1 = Jan 1 1900 */ | ||||
|     var d = new Date(1900,0,1); | ||||
|     /* 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(); | ||||
| @ -176,7 +176,7 @@ function parse_date_code(v,opts,b2) { | ||||
| } | ||||
| SSF.parse_date_code = parse_date_code; | ||||
| /*jshint -W086 */ | ||||
| function write_date(type, fmt, val, ss0) { | ||||
| 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 */ | ||||
| @ -222,6 +222,7 @@ function write_date(type, fmt, val, ss0) { | ||||
|     } | ||||
|     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)); | ||||
| @ -245,7 +246,7 @@ function write_date(type, fmt, val, ss0) { | ||||
|   if(outl > 0) return pad0(out, outl); else return ""; | ||||
| } | ||||
| /*jshint +W086 */ | ||||
| function commaify(s) { | ||||
| 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); | ||||
| @ -253,17 +254,17 @@ function commaify(s) { | ||||
| } | ||||
| var write_num = (function make_write_num(){ | ||||
| var pct1 = /%/g; | ||||
| function write_num_pct(type, fmt, val){ | ||||
| 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, fmt, val){ | ||||
| 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, val){ | ||||
|   var o; | ||||
| 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'); | ||||
| @ -272,33 +273,33 @@ function write_num_exp(fmt, val){ | ||||
|     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[0] + "." + o.substr(1) + "E+" + (fakee - o.length+ee); | ||||
|       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[0] + o.substr(2,period) + "." + o.substr(2+period); | ||||
|         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[o.length-1]; | ||||
|   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, aval, sign) { | ||||
|   var den = parseInt(r[4]), rr = Math.round(aval * den), base = Math.floor(rr/den); | ||||
| 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, aval, sign) { | ||||
| 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) { | ||||
| function hashq(str/*:string*/)/*:string*/ { | ||||
|   var o = "", cc; | ||||
|   for(var i = 0; i != str.length; ++i) switch((cc=str.charCodeAt(i))) { | ||||
|     case 35: break; | ||||
| @ -308,10 +309,10 @@ function hashq(str) { | ||||
|   } | ||||
|   return o; | ||||
| } | ||||
| function rnd(val, d) { var dd = Math.pow(10,d); return ""+(Math.round(val * dd)/dd); } | ||||
| function dec(val, d) { return Math.round((val-Math.floor(val))*Math.pow(10,d)); } | ||||
| function flr(val) { if(val < 2147483647 && val > -2147483648) return ""+(val >= 0 ? (val|0) : (val-1|0)); return ""+Math.floor(val); } | ||||
| function write_num_flt(type, fmt, val) { | ||||
| 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*/ { return Math.round((val-Math.floor(val))*Math.pow(10,d)); } | ||||
| 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); | ||||
| @ -321,67 +322,68 @@ function write_num_flt(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, oo; | ||||
|   var r, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : ""; | ||||
|   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)) !== null) return write_num_f1(r, aval, sign); | ||||
|   if(fmt.match(/^#+0+$/) !== null) return sign + pad0r(aval,fmt.length - fmt.indexOf("0")); | ||||
|   if((r = fmt.match(dec1)) !== null) { | ||||
|   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*)\.(#*)$/)) !== null) { | ||||
|   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(\.?)$/)) !== null) return sign + commaify(pad0r(aval,0)); | ||||
|   if((r = fmt.match(/^#,##0\.([#0]*0)$/)) !== null) { | ||||
|   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))) + "." + pad0(dec(val, r[1].length),r[1].length); | ||||
|   } | ||||
|   if((r = fmt.match(/^#,#*,#0/)) !== null) return write_num_flt(type,fmt.replace(/^#,#*,/,""),val); | ||||
|   if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/)) !== null) { | ||||
|   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) !== null) { | ||||
|   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?]+)/)) !== null) { | ||||
|     ri = Math.min(r[4].length,7); | ||||
|   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", r[1], ff[1]); | ||||
|     oa = write_num("n", /*::String(*/r[1]/*::)*/, ff[1]); | ||||
|     if(oa[oa.length-1] == " ") oa = oa.substr(0,oa.length-1) + "0"; | ||||
|     o += oa + r[2] + "/" + r[3]; | ||||
|     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?]+)/)) !== null) { | ||||
|   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?]+$/)) !== null) { | ||||
|   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]+)$/)) !== null) { | ||||
|   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)$/)) !== null) { | ||||
|   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); | ||||
|   } | ||||
| @ -391,17 +393,17 @@ function write_num_flt(type, fmt, val) { | ||||
|   } | ||||
|   throw new Error("unsupported format |" + fmt + "|"); | ||||
| } | ||||
| function write_num_cm2(type, fmt, val){ | ||||
| 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, fmt, val){ | ||||
| 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, val){ | ||||
|   var o; | ||||
| 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'); | ||||
| @ -410,17 +412,17 @@ function write_num_exp2(fmt, val){ | ||||
|     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[0] + "." + o.substr(1) + "E+" + (fakee - o.length+ee); | ||||
|       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[o.length-1]; | ||||
|   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, fmt, val) { | ||||
| 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); | ||||
| @ -437,32 +439,33 @@ function write_num_int(type, fmt, val) { | ||||
|     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)) !== null) return write_num_f2(r, aval, sign); | ||||
|   if(fmt.match(/^#+0+$/) !== null) return sign + pad0(aval,fmt.length - fmt.indexOf("0")); | ||||
|   if((r = fmt.match(dec1)) !== null) { | ||||
|   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))) { | ||||
|     // $FlowIgnore
 | ||||
|     o = (""+val).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*)\.(#*)$/)) !== null) { | ||||
|   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(\.?)$/)) !== null) return sign + commaify((""+aval)); | ||||
|   if((r = fmt.match(/^#,##0\.([#0]*0)$/)) !== null) { | ||||
|   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/)) !== null) return write_num_int(type,fmt.replace(/^#,#*,/,""),val); | ||||
|   if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/)) !== null) { | ||||
|   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) !== null) { | ||||
|   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?]+)/)) !== null) { | ||||
|   if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) { | ||||
|     ri = Math.min(r[4].length,7); | ||||
|     ff = frac(aval, Math.pow(10,ri)-1, false); | ||||
|     o = "" + sign; | ||||
| @ -474,23 +477,23 @@ function write_num_int(type, fmt, val) { | ||||
|     o += oa; | ||||
|     return o; | ||||
|   } | ||||
|   if((r = fmt.match(/^# ([#0?]+)( ?)\/( ?)([#0?]+)/)) !== null) { | ||||
|   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?]+$/)) !== null) { | ||||
|   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]+)$/)) !== null) { | ||||
|   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)$/)) !== null) { | ||||
|   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) { | ||||
| @ -499,11 +502,11 @@ function write_num_int(type, fmt, val) { | ||||
|   } | ||||
|   throw new Error("unsupported format |" + fmt + "|"); | ||||
| } | ||||
| return function write_num(type, fmt, val) { | ||||
| 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) { | ||||
|   var out = []; | ||||
| 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: /* '"' */ | ||||
| @ -520,12 +523,12 @@ function split_fmt(fmt) { | ||||
| } | ||||
| SSF._split = split_fmt; | ||||
| var abstime = /\[[HhMmSs]*\]/; | ||||
| function eval_fmt(fmt, v, opts, flen) { | ||||
| 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[i])) { | ||||
|     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; | ||||
| @ -615,11 +618,13 @@ function eval_fmt(fmt, v, opts, flen) { | ||||
|   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; | ||||
| @ -629,8 +634,9 @@ function eval_fmt(fmt, v, opts, flen) { | ||||
|   for(i=0; i < out.length; ++i) { | ||||
|     switch(out[i].t) { | ||||
|       case 't': case 'T': case ' ': case 'D': break; | ||||
|       case 'X': out[i] = undefined; 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 '?': | ||||
| @ -642,7 +648,7 @@ function eval_fmt(fmt, v, opts, flen) { | ||||
|           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] = undefined; ++jj; | ||||
|           out[jj] = {v:"", t:";"}; ++jj; | ||||
|         } | ||||
|         nstr += out[i].v; | ||||
|         i = jj-1; break; | ||||
| @ -721,11 +727,11 @@ function chkcond(v, rr) { | ||||
|   } | ||||
|   return false; | ||||
| } | ||||
| function choose_fmt(f, v) { | ||||
| 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 "cannot find right format for |" + fmt + "|"; | ||||
|   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; | ||||
| @ -742,12 +748,12 @@ function choose_fmt(f, v) { | ||||
|   } | ||||
|   return [l, ff]; | ||||
| } | ||||
| function format(fmt,v,o) { | ||||
| 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 : table_fmt)[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); | ||||
| @ -757,10 +763,12 @@ function format(fmt,v,o) { | ||||
|   return eval_fmt(f[1], v, o, f[0]); | ||||
| } | ||||
| SSF._table = table_fmt; | ||||
| SSF.load = function load_entry(fmt, idx) { table_fmt[idx] = 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) { for(var i=0; i!=0x0188; ++i) if(tbl[i] !== undefined) SSF.load(tbl[i], i); }; | ||||
| 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; | ||||
|  | ||||
							
								
								
									
										533
									
								
								ssf.md
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										533
									
								
								ssf.md
									
									
									
									
									
								
							| @ -10,7 +10,7 @@ default options are described below: | ||||
| 
 | ||||
| ```js>tmp/10_opts.js | ||||
| /* Options */ | ||||
| var opts_fmt = [ | ||||
| var opts_fmt/*:Array<Array<any> >*/ = [ | ||||
| ``` | ||||
| 
 | ||||
| There are two commonly-recognized date code formats: | ||||
| @ -60,8 +60,8 @@ 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: | ||||
| 
 | ||||
| ```js>tmp/80_split.js | ||||
| function split_fmt(fmt) { | ||||
|   var out = []; | ||||
| 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: /* '"' */ | ||||
| @ -117,26 +117,26 @@ as the last format. | ||||
| ## Utility Functions | ||||
| 
 | ||||
| ```js>tmp/02_utilities.js | ||||
| 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 _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; } | ||||
| ``` | ||||
| 
 | ||||
| The next few helpers break up the general `pad` function into special cases: | ||||
| 
 | ||||
| ``` | ||||
| function pad0(v,d){var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;} | ||||
| function pad_(v,d){var t=""+v;return t.length>=d?t:fill(' ',d-t.length)+t;} | ||||
| function rpad_(v,d){var t=""+v; return t.length>=d?t:t+fill(' ',d-t.length);} | ||||
| function pad0r1(v,d){var t=""+Math.round(v); return t.length>=d?t:fill('0',d-t.length)+t;} | ||||
| function pad0r2(v,d){var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;} | ||||
| 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,d){if(v>p2_32||v<-p2_32) return pad0r1(v,d); var i = Math.round(v); return pad0r2(i,d); } | ||||
| 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); } | ||||
| ``` | ||||
| 
 | ||||
| Comparing against the string "general" is faster via char codes: | ||||
| 
 | ||||
| ``` | ||||
| function isgeneral(s, i) { 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; } | ||||
| 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; } | ||||
| ``` | ||||
| 
 | ||||
| ## General Number Format | ||||
| @ -149,7 +149,7 @@ First: 32-bit integers in base 10 are shorter than 11 characters, so they will | ||||
| always be written in full: | ||||
| 
 | ||||
| ```js>tmp/40_general.js | ||||
| function general_fmt_int(v, opts) { return ""+v; } | ||||
| function general_fmt_int(v/*:number*/, opts/*:?any*/)/*:string*/ { return ""+v; } | ||||
| SSF._general_int = general_fmt_int; | ||||
| ``` | ||||
| 
 | ||||
| @ -178,7 +178,7 @@ function gfn5(o) { | ||||
|   //return o; | ||||
|   return o.indexOf(".") > -1 ? o.replace(gnr2,"").replace(gnr1,".$1") : o; | ||||
| } | ||||
| return function general_fmt_num(v, opts) { | ||||
| 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); | ||||
| @ -192,7 +192,7 @@ SSF._general_num = general_fmt_num; | ||||
| Finally | ||||
| 
 | ||||
| ```js>tmp/40_general.js | ||||
| function general_fmt(v, opts) { | ||||
| function general_fmt(v/*:any*/, opts/*:?any*/) { | ||||
|   switch(typeof v) { | ||||
| ``` | ||||
| 
 | ||||
| @ -230,16 +230,16 @@ None of the international formats are included here. | ||||
| 
 | ||||
| ```js>tmp/20_consts.js | ||||
| 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: '# ??/??', | ||||
|   /*::[*/0/*::]*/:  'General', | ||||
|   /*::[*/1/*::]*/:  '0', | ||||
|   /*::[*/2/*::]*/:  '0.00', | ||||
|   /*::[*/3/*::]*/:  '#,##0', | ||||
|   /*::[*/4/*::]*/:  '#,##0.00', | ||||
|   /*::[*/9/*::]*/:  '0%', | ||||
|   /*::[*/10/*::]*/: '0.00%', | ||||
|   /*::[*/11/*::]*/: '0.00E+00', | ||||
|   /*::[*/12/*::]*/: '# ?/?', | ||||
|   /*::[*/13/*::]*/: '# ??/??', | ||||
| ``` | ||||
| 
 | ||||
| Now Excel and other formats treat code 14 as `m/d/yy` (with slashes).  Given | ||||
| @ -247,37 +247,37 @@ that the spec gives no internationalization considerations, erring on the side | ||||
| of the applications makes sense here: | ||||
| 
 | ||||
| ``` | ||||
|   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: '@', | ||||
|   /*::[*/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/*::]*/: '@', | ||||
| ``` | ||||
| 
 | ||||
| There are special implicit format codes identified in [ECMA-376] 18.8.30. | ||||
| Assuming zh-tw is the default: | ||||
| 
 | ||||
| ``` | ||||
|   56: '"上午/下午 "hh"時"mm"分"ss"秒 "', | ||||
|   /*::[*/56/*::]*/: '"上午/下午 "hh"時"mm"分"ss"秒 "', | ||||
| ``` | ||||
| 
 | ||||
| some writers erroneously emit 65535 for general: | ||||
| 
 | ||||
| ``` | ||||
|   65535: 'General' | ||||
|   /*::[*/65535/*::]*/: 'General' | ||||
| }; | ||||
| ``` | ||||
| 
 | ||||
| @ -326,7 +326,7 @@ portion of a 24 hour day). | ||||
| Excel supports the alternative Hijri calendar (indicated with `b2`): | ||||
| 
 | ||||
| ```js>tmp/50_date.js | ||||
| function parse_date_code(v,opts,b2) { | ||||
| function parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) { | ||||
| ``` | ||||
| 
 | ||||
| Date codes beyond 12/31/9999 are invalid: | ||||
| @ -378,8 +378,8 @@ For the other dates, using the JS date mechanism suffices. | ||||
| ``` | ||||
|   else { | ||||
|     if(date > 60) --date; | ||||
|     /* 1 = Jan 1 1900 */ | ||||
|     var d = new Date(1900,0,1); | ||||
|     /* 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(); | ||||
| @ -426,7 +426,7 @@ function fix_hijri(date, o) { return 0; } | ||||
| The utility `commaify` adds commas to integers: | ||||
| 
 | ||||
| ```js>tmp/56_commaify.js | ||||
| function commaify(s) { | ||||
| 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); | ||||
| @ -446,7 +446,7 @@ The underlying number for the percentages should be physically shifted: | ||||
| 
 | ||||
| ```js>tmp/59_numhelp.js | ||||
| var pct1 = /%/g; | ||||
| function write_num_pct(type, fmt, val){ | ||||
| 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); | ||||
| } | ||||
| @ -458,7 +458,7 @@ Formats with multiple commas after the decimal point should be shifted by the | ||||
| appropiate multiple of 1000 (more magic): | ||||
| 
 | ||||
| ```js>tmp/60_number.js | ||||
| function write_num_cm(type, fmt, val){ | ||||
| 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))); | ||||
| @ -470,8 +470,8 @@ function write_num_cm(type, fmt, val){ | ||||
| For exponents, get the exponent and mantissa and format them separately: | ||||
| 
 | ||||
| ``` | ||||
| function write_num_exp(fmt, val){ | ||||
|   var o; | ||||
| function write_num_exp(fmt/*:string*/, val/*:number*/)/*:string*/{ | ||||
|   var o/*:string*/; | ||||
|   var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1; | ||||
| ``` | ||||
| 
 | ||||
| @ -490,17 +490,17 @@ TODO: something cleaner | ||||
| 
 | ||||
| ``` | ||||
|       var fakee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E); | ||||
|       if(o.indexOf(".") === -1) o = o[0] + "." + o.substr(1) + "E+" + (fakee - o.length+ee); | ||||
|       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[0] + o.substr(2,period) + "." + o.substr(2+period); | ||||
|         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[o.length-1]; | ||||
|   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"); | ||||
| } | ||||
| @ -510,18 +510,18 @@ TODO: something cleaner | ||||
| 
 | ||||
| ``` | ||||
| var frac1 = /# (\?+)( ?)\/( ?)(\d+)/; | ||||
| function write_num_f1(r, aval, sign) { | ||||
|   var den = parseInt(r[4]), rr = Math.round(aval * den), base = Math.floor(rr/den); | ||||
| 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, aval, sign) { | ||||
| 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) { | ||||
| function hashq(str/*:string*/)/*:string*/ { | ||||
|   var o = "", cc; | ||||
|   for(var i = 0; i != str.length; ++i) switch((cc=str.charCodeAt(i))) { | ||||
|     case 35: break; | ||||
| @ -536,9 +536,9 @@ function hashq(str) { | ||||
| V8 has an annoying habit of deoptimizing round and floor | ||||
| 
 | ||||
| ``` | ||||
| function rnd(val, d) { var dd = Math.pow(10,d); return ""+(Math.round(val * dd)/dd); } | ||||
| function dec(val, d) { return Math.round((val-Math.floor(val))*Math.pow(10,d)); } | ||||
| function flr(val) { if(val < 2147483647 && val > -2147483648) return ""+(val >= 0 ? (val|0) : (val-1|0)); return ""+Math.floor(val); } | ||||
| 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*/ { return Math.round((val-Math.floor(val))*Math.pow(10,d)); } | ||||
| function flr(val/*:number*/)/*:string*/ { if(val < 2147483647 && val > -2147483648) return ""+(val >= 0 ? (val|0) : (val-1|0)); return ""+Math.floor(val); } | ||||
| ``` | ||||
| 
 | ||||
| ### Main Number Writing Function | ||||
| @ -546,7 +546,7 @@ function flr(val) { if(val < 2147483647 && val > -2147483648) return ""+(val >= | ||||
| Finally the body: | ||||
| 
 | ||||
| ``` | ||||
| function write_num_flt(type, fmt, val) { | ||||
| function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/ { | ||||
| ``` | ||||
| 
 | ||||
| For parentheses, explicitly resolve the sign issue: | ||||
| @ -579,8 +579,8 @@ TODO: localize the currency: | ||||
| Some simple cases should be resolved first: | ||||
| 
 | ||||
| ``` | ||||
|   var o, oo; | ||||
|   var r, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : ""; | ||||
|   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 = ""; | ||||
| @ -591,14 +591,15 @@ Some simple cases should be resolved first: | ||||
| Fractions with known denominator are resolved by rounding: | ||||
| 
 | ||||
| ``` | ||||
|   if((r = fmt.match(frac1)) !== null) return write_num_f1(r, aval, sign); | ||||
|   if((r = fmt.match(frac1))) return write_num_f1(r, aval, sign); | ||||
| ``` | ||||
| 
 | ||||
| A few special general cases can be handled in a very dumb manner: | ||||
| 
 | ||||
| ``` | ||||
|   if(fmt.match(/^#+0+$/) !== null) return sign + pad0r(aval,fmt.length - fmt.indexOf("0")); | ||||
|   if((r = fmt.match(dec1)) !== null) { | ||||
|   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\./,"."); | ||||
|   } | ||||
| @ -608,20 +609,20 @@ The next few simplifications ignore leading optional sigils (`#`): | ||||
| 
 | ||||
| ``` | ||||
|   fmt = fmt.replace(/^#+([0.])/, "$1"); | ||||
|   if((r = fmt.match(/^(0*)\.(#*)$/)) !== null) { | ||||
|   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(\.?)$/)) !== null) return sign + commaify(pad0r(aval,0)); | ||||
|   if((r = fmt.match(/^#,##0\.([#0]*0)$/)) !== null) { | ||||
|   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))) + "." + pad0(dec(val, r[1].length),r[1].length); | ||||
|   } | ||||
|   if((r = fmt.match(/^#,#*,#0/)) !== null) return write_num_flt(type,fmt.replace(/^#,#*,/,""),val); | ||||
|   if((r = fmt.match(/^#,#*,#0/))) return write_num_flt(type,fmt.replace(/^#,#*,/,""),val); | ||||
| ``` | ||||
| 
 | ||||
| The `Zip Code + 4` format needs to treat an interstitial hyphen as a character: | ||||
| 
 | ||||
| ``` | ||||
|   if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/)) !== null) { | ||||
|   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':"";})); | ||||
| @ -632,7 +633,7 @@ There's a better way to generalize the phone number and other formats in terms | ||||
| of first drawing the digits, but this selection allows for more nuance: | ||||
| 
 | ||||
| ``` | ||||
|   if(fmt.match(phone) !== null) { | ||||
|   if(fmt.match(phone)) { | ||||
|     o = write_num_flt(type, "##########", val); | ||||
|     return "(" + o.substr(0,3) + ") " + o.substr(3, 3) + "-" + o.substr(6); | ||||
|   } | ||||
| @ -642,19 +643,19 @@ The frac helper function is used for fraction formats (defined below). | ||||
| 
 | ||||
| ``` | ||||
|   var oa = ""; | ||||
|   if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/)) !== null) { | ||||
|     ri = Math.min(r[4].length,7); | ||||
|   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", r[1], ff[1]); | ||||
|     oa = write_num("n", /*::String(*/r[1]/*::)*/, ff[1]); | ||||
|     if(oa[oa.length-1] == " ") oa = oa.substr(0,oa.length-1) + "0"; | ||||
|     o += oa + r[2] + "/" + r[3]; | ||||
|     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?]+)/)) !== null) { | ||||
|   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)); | ||||
| @ -664,12 +665,12 @@ The frac helper function is used for fraction formats (defined below). | ||||
| The general class `/^[#0?]+$/` treats the '0' as literal, '#' as noop, '?' as space: | ||||
| 
 | ||||
| ``` | ||||
|   if((r = fmt.match(/^[#0?]+$/)) !== null) { | ||||
|   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]+)$/)) !== null) { | ||||
|   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; | ||||
| @ -680,7 +681,7 @@ The general class `/^[#0?]+$/` treats the '0' as literal, '#' as noop, '?' as sp | ||||
| The default cases are hard-coded.  TODO: actually parse them | ||||
| 
 | ||||
| ```js>tmp/60_number.js | ||||
|   if((r = fmt.match(/^00,000\.([#0]*0)$/)) !== null) { | ||||
|   if((r = fmt.match(/^00,000\.([#0]*0)$/))) { | ||||
|     ri = dec(val, r[1].length); | ||||
| ``` | ||||
| 
 | ||||
| @ -706,17 +707,17 @@ For now, the default case is an error: | ||||
| ### Integer Optimizations | ||||
| 
 | ||||
| ``` | ||||
| function write_num_cm2(type, fmt, val){ | ||||
| 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, fmt, val){ | ||||
| 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, val){ | ||||
|   var o; | ||||
| 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'); | ||||
| @ -725,17 +726,17 @@ function write_num_exp2(fmt, val){ | ||||
|     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[0] + "." + o.substr(1) + "E+" + (fakee - o.length+ee); | ||||
|       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[o.length-1]; | ||||
|   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, fmt, val) { | ||||
| 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); | ||||
| @ -752,32 +753,33 @@ function write_num_int(type, fmt, val) { | ||||
|     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)) !== null) return write_num_f2(r, aval, sign); | ||||
|   if(fmt.match(/^#+0+$/) !== null) return sign + pad0(aval,fmt.length - fmt.indexOf("0")); | ||||
|   if((r = fmt.match(dec1)) !== null) { | ||||
|   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))) { | ||||
|     // $FlowIgnore | ||||
|     o = (""+val).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*)\.(#*)$/)) !== null) { | ||||
|   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(\.?)$/)) !== null) return sign + commaify((""+aval)); | ||||
|   if((r = fmt.match(/^#,##0\.([#0]*0)$/)) !== null) { | ||||
|   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/)) !== null) return write_num_int(type,fmt.replace(/^#,#*,/,""),val); | ||||
|   if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/)) !== null) { | ||||
|   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) !== null) { | ||||
|   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?]+)/)) !== null) { | ||||
|   if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) { | ||||
|     ri = Math.min(r[4].length,7); | ||||
|     ff = frac(aval, Math.pow(10,ri)-1, false); | ||||
|     o = "" + sign; | ||||
| @ -789,23 +791,23 @@ function write_num_int(type, fmt, val) { | ||||
|     o += oa; | ||||
|     return o; | ||||
|   } | ||||
|   if((r = fmt.match(/^# ([#0?]+)( ?)\/( ?)([#0?]+)/)) !== null) { | ||||
|   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?]+$/)) !== null) { | ||||
|   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]+)$/)) !== null) { | ||||
|   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)$/)) !== null) { | ||||
|   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) { | ||||
| @ -819,7 +821,7 @@ function write_num_int(type, fmt, val) { | ||||
| The final function simply dispatches: | ||||
| 
 | ||||
| ``` | ||||
| return function write_num(type, fmt, val) { | ||||
| 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); | ||||
| };})(); | ||||
| ``` | ||||
| @ -828,12 +830,12 @@ return function write_num(type, fmt, val) { | ||||
| 
 | ||||
| ```js>tmp/82_eval.js | ||||
| var abstime = /\[[HhMmSs]*\]/; | ||||
| function eval_fmt(fmt, v, opts, flen) { | ||||
| 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[i])) { | ||||
|     switch((c = fmt.charAt(i))) { | ||||
| ``` | ||||
| 
 | ||||
| LO Formats sometimes leak "GENERAL" or "General" to stand for general format: | ||||
| @ -1045,11 +1047,13 @@ Having determined the smallest time unit, round appropriately: | ||||
|   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; | ||||
| @ -1065,8 +1069,9 @@ group them together to construct the real number string: | ||||
|   for(i=0; i < out.length; ++i) { | ||||
|     switch(out[i].t) { | ||||
|       case 't': case 'T': case ' ': case 'D': break; | ||||
|       case 'X': out[i] = undefined; 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 '?': | ||||
| @ -1078,7 +1083,7 @@ group them together to construct the real number string: | ||||
|           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] = undefined; ++jj; | ||||
|           out[jj] = {v:"", t:";"}; ++jj; | ||||
|         } | ||||
|         nstr += out[i].v; | ||||
|         i = jj-1; break; | ||||
| @ -1183,7 +1188,7 @@ display minutes instead of the month. | ||||
| 
 | ||||
| ```js>tmp/50_date.js | ||||
| /*jshint -W086 */ | ||||
| function write_date(type, fmt, val, ss0) { | ||||
| 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) { | ||||
| ``` | ||||
| @ -1260,6 +1265,7 @@ terms.  That is passed via the `ss0` parameter: | ||||
|     } | ||||
|     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)); | ||||
| @ -1306,11 +1312,11 @@ Based on the value, `choose_fmt` picks the right format string.  If formats have | ||||
| explicit negative specifications, those values should be passed as positive: | ||||
| 
 | ||||
| ```js>tmp/90_main.js | ||||
| function choose_fmt(f, v) { | ||||
| 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 "cannot find right format for |" + fmt + "|"; | ||||
|   if(fmt.length > 4) throw new Error("cannot find right format for |" + fmt.join("|") + "|"); | ||||
| ``` | ||||
| 
 | ||||
| Short-circuit the string case by using the last format if it has "@": | ||||
| @ -1375,7 +1381,7 @@ The main function checks for conditional operators and acts accordingly: | ||||
| Finally, the format wrapper brings everything together: | ||||
| 
 | ||||
| ``` | ||||
| function format(fmt,v,o) { | ||||
| function format(fmt/*:string|number*/,v/*:any*/,o/*:?any*/) { | ||||
|   fixopts(o != null ? o : (o=[])); | ||||
| ``` | ||||
| 
 | ||||
| @ -1385,7 +1391,7 @@ The string format is saved to a different variable: | ||||
|   var sfmt = ""; | ||||
|   switch(typeof fmt) { | ||||
|     case "string": sfmt = fmt; break; | ||||
|     case "number": sfmt = (o.table != null ? o.table : table_fmt)[fmt]; break; | ||||
|     case "number": sfmt = (o.table != null ? (o.table/*:any*/) : table_fmt)[fmt]; break; | ||||
|   } | ||||
| ``` | ||||
| 
 | ||||
| @ -1416,7 +1422,7 @@ used directly in programs. | ||||
| 
 | ||||
| ```js>tmp/98_exports.js | ||||
| SSF._table = table_fmt; | ||||
| SSF.load = function load_entry(fmt, idx) { table_fmt[idx] = fmt; }; | ||||
| SSF.load = function load_entry(fmt/*:string*/, idx/*:number*/) { table_fmt[idx] = fmt; }; | ||||
| SSF.format = format; | ||||
| ``` | ||||
| 
 | ||||
| @ -1424,7 +1430,7 @@ To support multiple SSF tables: | ||||
| 
 | ||||
| ``` | ||||
| SSF.get_table = function get_table() { return table_fmt; }; | ||||
| SSF.load_table = function load_table(tbl) { for(var i=0; i!=0x0188; ++i) if(tbl[i] !== undefined) SSF.load(tbl[i], i); }; | ||||
| 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); }; | ||||
| ``` | ||||
| 
 | ||||
| ## Fraction Library | ||||
| @ -1459,7 +1465,7 @@ function frac(x, D, mixed) { | ||||
| ## JS Boilerplate | ||||
| 
 | ||||
| ```js>tmp/00_header.js | ||||
| /* ssf.js (C) 2013-2014 SheetJS -- http://sheetjs.com */ | ||||
| /* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */ | ||||
| /*jshint -W041 */ | ||||
| var SSF = {}; | ||||
| var make_ssf = function make_ssf(SSF){ | ||||
| @ -1468,6 +1474,8 @@ var make_ssf = function make_ssf(SSF){ | ||||
| ```js>tmp/99_footer.js | ||||
| }; | ||||
| 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; | ||||
| ``` | ||||
| 
 | ||||
| @ -1486,294 +1494,3 @@ cat tmp/*.js > ssf.js | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| ```>.gitignore | ||||
| node_modules/ | ||||
| tmp/ | ||||
| .vocrc | ||||
| v8.log | ||||
| perf.log | ||||
| ``` | ||||
| 
 | ||||
| ```>.npmignore | ||||
| test/*.tsv | ||||
| node_modules/ | ||||
| tmp/ | ||||
| .gitignore | ||||
| .vocrc | ||||
| v8.log | ||||
| perf.log | ||||
| ``` | ||||
| 
 | ||||
| ```make>Makefile | ||||
| .PHONY: test ssf | ||||
| ssf: ssf.md | ||||
|         voc ssf.md | ||||
| 
 | ||||
| test: | ||||
|         npm test | ||||
| 
 | ||||
| test_min: | ||||
|         MINTEST=1 npm test | ||||
| 
 | ||||
| .PHONY: lint | ||||
| lint: | ||||
|         jshint ssf.js test/ | ||||
|         jscs ssf.js | ||||
| 
 | ||||
| .PHONY: perf | ||||
| perf: | ||||
|         bash misc/perf.sh | ||||
| ``` | ||||
| 
 | ||||
| Coverage tests use [blanket](http://npm.im/blanket): | ||||
| 
 | ||||
| ``` | ||||
| 
 | ||||
| .PHONY: cov | ||||
| cov: tmp/coverage.html | ||||
| 
 | ||||
| tmp/coverage.html: ssf | ||||
|         mocha --require blanket -R html-cov > tmp/coverage.html | ||||
| 
 | ||||
| .PHONY: cov_min | ||||
| cov_min: | ||||
|         MINTEST=1 make cov | ||||
| ``` | ||||
| 
 | ||||
| Coveralls.io support | ||||
| 
 | ||||
| ``` | ||||
| 
 | ||||
| .PHONY: coveralls full_coveralls | ||||
| full_coveralls: | ||||
|         mocha --require blanket --reporter mocha-lcov-reporter | ./node_modules/coveralls/bin/coveralls.js | ||||
| 
 | ||||
| coveralls: | ||||
|         MINTEST=1 make full_coveralls | ||||
| 
 | ||||
| ``` | ||||
| 
 | ||||
| ```json>package.json | ||||
| { | ||||
|   "name": "ssf", | ||||
|   "version": "0.8.1", | ||||
|   "author": "SheetJS", | ||||
|   "description": "Format data using ECMA-376 spreadsheet Format Codes", | ||||
|   "keywords": [ "format", "sprintf", "spreadsheet" ], | ||||
|   "main": "ssf.js", | ||||
|   "dependencies": { | ||||
|     "voc":"", | ||||
|     "colors":"0.6.2", | ||||
|     "frac":"0.3.1" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "mocha":"" | ||||
|   }, | ||||
|   "repository": { "type":"git", "url":"git://github.com/SheetJS/ssf.git" }, | ||||
|   "scripts": { | ||||
|     "test": "mocha -R spec" | ||||
|   }, | ||||
|   "bin": { | ||||
|     "ssf": "./bin/ssf.njs" | ||||
|   }, | ||||
|   "config": { | ||||
|     "blanket": { | ||||
|       "pattern": "ssf.js" | ||||
|     } | ||||
|   }, | ||||
|   "bugs": { "url": "https://github.com/SheetJS/ssf/issues" }, | ||||
|   "license": "Apache-2.0", | ||||
|   "engines": { "node": ">=0.8" } | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| # Test Driver | ||||
| 
 | ||||
| Travis CI is used for node testing: | ||||
| 
 | ||||
| ```>.travis.yml | ||||
| language: node_js | ||||
| node_js: | ||||
|   - "0.10" | ||||
|   - "0.8" | ||||
| before_install: | ||||
|   - "npm install -g mocha" | ||||
|   - "npm install blanket" | ||||
|   - "npm install coveralls mocha-lcov-reporter" | ||||
| after_success: | ||||
|   - "make coveralls" | ||||
| ``` | ||||
| 
 | ||||
| The mocha test driver tests the implied formats: | ||||
| 
 | ||||
| ```js>test/implied.js | ||||
| var SSF = require('../'); | ||||
| var fs = require('fs'), assert = require('assert'); | ||||
| var data = JSON.parse(fs.readFileSync('./test/implied.json','utf8')); | ||||
| var skip = []; | ||||
| function doit(d) { | ||||
|   d[1].forEach(function(r){if(r.length === 2)assert.equal(SSF.format(r[0],d[0]),r[1]);}); | ||||
| } | ||||
| describe('implied formats', function() { | ||||
|   data.forEach(function(d) { | ||||
|     if(d.length == 2) it(d[0], function() { doit(d); }); | ||||
|     else it(d[1]+" for "+d[0], skip.indexOf(d[1]) > -1 ? null : function(){ | ||||
|       assert.equal(SSF.format(d[1], d[0], {}), d[2]); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
| ``` | ||||
| 
 | ||||
| The general test driver tests the General format: | ||||
| 
 | ||||
| ```js>test/general.js | ||||
| /* vim: set ts=2: */ | ||||
| var SSF = require('../'); | ||||
| var fs = require('fs'), assert = require('assert'); | ||||
| var data = JSON.parse(fs.readFileSync('./test/general.json','utf8')); | ||||
| var skip = []; | ||||
| describe('General format', function() { | ||||
|   data.forEach(function(d) { | ||||
|     it(d[1]+" for "+d[0], skip.indexOf(d[1]) > -1 ? null : function(){ | ||||
|       assert.equal(SSF.format(d[1], d[0], {}), d[2]); | ||||
|     }); | ||||
|   }); | ||||
|   it('should fail for undefined and null', function() { | ||||
|     assert.throws(function() { | ||||
|       SSF.format("General", undefined); | ||||
|       SSF.format("General", null); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
| ``` | ||||
| 
 | ||||
| The fraction test driver tests fractional formats: | ||||
| 
 | ||||
| ```js>test/fraction.js | ||||
| /* vim: set ts=2: */ | ||||
| var SSF = require('../'); | ||||
| var fs = require('fs'), assert = require('assert'); | ||||
| var data = JSON.parse(fs.readFileSync('./test/fraction.json','utf8')); | ||||
| var skip = []; | ||||
| describe('fractional formats', function() { | ||||
|   data.forEach(function(d) { | ||||
|     it(d[1]+" for "+d[0], skip.indexOf(d[1]) > -1 ? null : function(){ | ||||
|       var expected = d[2], actual = SSF.format(d[1], d[0], {}); | ||||
|       //var r = actual.match(/(-?)\d* *\d+\/\d+/); | ||||
|       assert.equal(actual, expected); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
| ``` | ||||
| 
 | ||||
| The dates test driver tests the date and time formats: | ||||
| 
 | ||||
| ```js>test/date.js | ||||
| /* vim: set ts=2: */ | ||||
| /*jshint -W041 */ | ||||
| /*jshint loopfunc:true */ | ||||
| var SSF = require('../'); | ||||
| var fs = require('fs'), assert = require('assert'); | ||||
| var dates = fs.readFileSync('./test/dates.tsv','utf8').split("\n"); | ||||
| var date2 = fs.readFileSync('./test/cal.tsv',  'utf8').split("\n"); | ||||
| var times = fs.readFileSync('./test/times.tsv','utf8').split("\n"); | ||||
| function doit(data) { | ||||
|   var step = Math.ceil(data.length/100), i = 1; | ||||
|   var headers = data[0].split("\t"); | ||||
|   for(j=0;j<=100;++j) it(j, function() { | ||||
|     for(var k = 0; k <= step; ++k,++i) { | ||||
|       if(data[i] == null || data[i].length < 3) return; | ||||
|       var d = data[i].replace(/#{255}/g,"").split("\t"); | ||||
|       for(var w = 1; w < headers.length; ++w) { | ||||
|         var expected = d[w], actual = SSF.format(headers[w], parseFloat(d[0]), {}); | ||||
|         if(actual != expected) throw [actual, expected, w, headers[w],d[0],d,i].join("|"); | ||||
|         actual = SSF.format(headers[w].toUpperCase(), parseFloat(d[0]), {}); | ||||
|         if(actual != expected) throw [actual, expected, w, headers[w].toUpperCase(),d[0],d,i].join("|"); | ||||
|       } | ||||
|     } | ||||
|   }); | ||||
| } | ||||
| describe('time formats', function() { | ||||
|   doit(process.env.MINTEST ? times.slice(0,4000) : times); | ||||
| }); | ||||
| describe('date formats', function() { | ||||
|   doit(process.env.MINTEST ? dates.slice(0,4000) : dates); | ||||
|   //doit(process.env.MINTEST ? date2.slice(0,1000) : date2); | ||||
|   it('should fail for bad formats', function() { | ||||
|     var bad = []; | ||||
|     var chk = function(fmt){ return function(){ SSF.format(fmt,0); }; }; | ||||
|     bad.forEach(function(fmt){assert.throws(chk(fmt));}); | ||||
|   }); | ||||
| }); | ||||
| ``` | ||||
| 
 | ||||
| The exponential test driver tests exponential formats (pipe denotes fails) | ||||
| 
 | ||||
| ```js>test/exp.js | ||||
| /* vim: set ts=2: */ | ||||
| /*jshint loopfunc:true */ | ||||
| var SSF = require('../'); | ||||
| var fs = require('fs'), assert = require('assert'); | ||||
| var data = fs.readFileSync('./test/exp.tsv','utf8').split("\n"); | ||||
| function doit(d, headers) { | ||||
|   it(d[0], function() { | ||||
|     for(var w = 1; w < headers.length; ++w) { | ||||
|       var expected = d[w].replace("|", ""), actual; | ||||
|       try { actual = SSF.format(headers[w], parseFloat(d[0]), {}); } catch(e) { } | ||||
|       if(actual != expected && d[w][0] !== "|") throw [actual, expected, w, headers[w],d[0],d].join("|"); | ||||
|     } | ||||
|   }); | ||||
| } | ||||
| describe('exponential formats', function() { | ||||
|   var headers = data[0].split("\t"); | ||||
|   for(var j=1;j<data.length;++j) { | ||||
|     if(!data[j]) return; | ||||
|     doit(data[j].replace(/#{255}/g,"").split("\t"), headers); | ||||
|   } | ||||
| }); | ||||
| ``` | ||||
| 
 | ||||
| The oddities test driver tests random odd formats | ||||
| 
 | ||||
| ```js>test/oddities.js | ||||
| /* vim: set ts=2: */ | ||||
| /*jshint loopfunc:true */ | ||||
| var SSF = require('../'); | ||||
| var fs = require('fs'), assert = require('assert'); | ||||
| var data = JSON.parse(fs.readFileSync('./test/oddities.json','utf8')); | ||||
| describe('oddities', function() { | ||||
|   data.forEach(function(d) { | ||||
|     it(d[0], function(){ | ||||
|       for(var j=1;j<d.length;++j) { | ||||
|         if(d[j].length == 2) { | ||||
|           var expected = d[j][1], actual = SSF.format(d[0], d[j][0], {}); | ||||
|           assert.equal(actual, expected); | ||||
|         } else if(d[j][2] !== "#") assert.throws(function() { SSF.format(d[0], d[j][0]); }); | ||||
|       } | ||||
|     }); | ||||
|   }); | ||||
|   it('should fail for bad formats', function() { | ||||
|     var bad = ['##,##']; | ||||
|     var chk = function(fmt){ return function(){ SSF.format(fmt,0); }; }; | ||||
|     bad.forEach(function(fmt){assert.throws(chk(fmt));}); | ||||
|   }); | ||||
| }); | ||||
| ``` | ||||
| 
 | ||||
| # LICENSE | ||||
| 
 | ||||
| ```>LICENSE | ||||
| Copyright (C) 2013-2014   SheetJS | ||||
| 
 | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
| 
 | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
| 
 | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
| ``` | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| /* vim: set ts=2: */ | ||||
| /*jshint loopfunc:true */ | ||||
| /*jshint loopfunc:true, mocha:true, node:true */ | ||||
| var SSF = require('../'); | ||||
| var fs = require('fs'), assert = require('assert'); | ||||
| var fs = require('fs'); | ||||
| var data = fs.readFileSync('./test/comma.tsv','utf8').split("\n"); | ||||
| 
 | ||||
| function doit(w, headers) { | ||||
| @ -11,7 +11,7 @@ function doit(w, headers) { | ||||
|       var d = data[j].replace(/#{255}/g,"").split("\t"); | ||||
|       var expected = d[w].replace("|", ""), actual; | ||||
|       try { actual = SSF.format(headers[w], Number(d[0]), {}); } catch(e) { } | ||||
|       if(actual != expected && d[w][0] !== "|") throw [actual, expected, w, headers[w],d[0],d].join("|"); | ||||
|       if(actual != expected && d[w][0] !== "|") throw new Error([actual, expected, w, headers[w],d[0],d].join("|")); | ||||
|     } | ||||
|   }); | ||||
| } | ||||
|  | ||||
							
								
								
									
										12
									
								
								test/date.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										12
									
								
								test/date.js
									
									
									
									
									
								
							| @ -1,6 +1,6 @@ | ||||
| /* vim: set ts=2: */ | ||||
| /*jshint -W041 */ | ||||
| /*jshint loopfunc:true */ | ||||
| /*jshint loopfunc:true, mocha:true, node:true */ | ||||
| var SSF = require('../'); | ||||
| var fs = require('fs'), assert = require('assert'); | ||||
| var dates = fs.readFileSync('./test/dates.tsv','utf8').split("\n"); | ||||
| @ -9,25 +9,27 @@ var times = fs.readFileSync('./test/times.tsv','utf8').split("\n"); | ||||
| function doit(data) { | ||||
|   var step = Math.ceil(data.length/100), i = 1; | ||||
|   var headers = data[0].split("\t"); | ||||
|   for(j=0;j<=100;++j) it(j, function() { | ||||
|   for(var j = 0; j <= 100; ++j) it(String(j), function() { | ||||
|     for(var k = 0; k <= step; ++k,++i) { | ||||
|       if(data[i] == null || data[i].length < 3) return; | ||||
|       var d = data[i].replace(/#{255}/g,"").split("\t"); | ||||
|       for(var w = 1; w < headers.length; ++w) { | ||||
|         var expected = d[w], actual = SSF.format(headers[w], parseFloat(d[0]), {}); | ||||
|         if(actual != expected) throw [actual, expected, w, headers[w],d[0],d,i].join("|"); | ||||
|         if(actual != expected) throw new Error([actual, expected, w, headers[w],d[0],d,i].join("|")); | ||||
|         actual = SSF.format(headers[w].toUpperCase(), parseFloat(d[0]), {}); | ||||
|         if(actual != expected) throw [actual, expected, w, headers[w].toUpperCase(),d[0],d,i].join("|"); | ||||
|         if(actual != expected) throw new Error([actual, expected, w, headers[w].toUpperCase(),d[0],d,i].join("|")); | ||||
|       } | ||||
|     } | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| describe('time formats', function() { | ||||
|   doit(process.env.MINTEST ? times.slice(0,4000) : times); | ||||
| }); | ||||
| 
 | ||||
| describe('date formats', function() { | ||||
|   doit(process.env.MINTEST ? dates.slice(0,4000) : dates); | ||||
|   //doit(process.env.MINTEST ? date2.slice(0,1000) : date2);
 | ||||
|   if(0) doit(process.env.MINTEST ? date2.slice(0,1000) : date2); | ||||
|   it('should fail for bad formats', function() { | ||||
|     var bad = []; | ||||
|     var chk = function(fmt){ return function(){ SSF.format(fmt,0); }; }; | ||||
|  | ||||
| @ -1,14 +1,14 @@ | ||||
| /* vim: set ts=2: */ | ||||
| /*jshint loopfunc:true */ | ||||
| /*jshint loopfunc:true, mocha:true, node:true */ | ||||
| var SSF = require('../'); | ||||
| var fs = require('fs'), assert = require('assert'); | ||||
| var fs = require('fs'); | ||||
| var data = fs.readFileSync('./test/exp.tsv','utf8').split("\n"); | ||||
| function doit(d, headers) { | ||||
|   it(d[0], function() { | ||||
|     for(var w = 1; w < headers.length; ++w) { | ||||
|       var expected = d[w].replace("|", ""), actual; | ||||
|       try { actual = SSF.format(headers[w], parseFloat(d[0]), {}); } catch(e) { } | ||||
|       if(actual != expected && d[w][0] !== "|") throw [actual, expected, w, headers[w],d[0],d].join("|"); | ||||
|       if(actual != expected && d[w][0] !== "|") throw new Error([actual, expected, w, headers[w],d[0],d].join("|")); | ||||
|     } | ||||
|   }); | ||||
| } | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| /* vim: set ts=2: */ | ||||
| /*jshint loopfunc:true, mocha:true, node:true */ | ||||
| var SSF = require('../'); | ||||
| var fs = require('fs'), assert = require('assert'); | ||||
| var data = JSON.parse(fs.readFileSync('./test/fraction.json','utf8')); | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| /* vim: set ts=2: */ | ||||
| /*jshint loopfunc:true, mocha:true, node:true */ | ||||
| var SSF = require('../'); | ||||
| var fs = require('fs'), assert = require('assert'); | ||||
| var data = JSON.parse(fs.readFileSync('./test/general.json','utf8')); | ||||
| @ -9,10 +10,9 @@ describe('General format', function() { | ||||
|       assert.equal(SSF.format(d[1], d[0], {}), d[2]); | ||||
|     }); | ||||
|   }); | ||||
|   it('should fail for undefined and null', function() { | ||||
|     assert.throws(function() { | ||||
|       SSF.format("General", undefined); | ||||
|       SSF.format("General", null); | ||||
|     }); | ||||
|   it.skip('should handle special values', function() { | ||||
|     assert.equal(SSF.format("General", true), "TRUE"); | ||||
|     assert.equal(SSF.format("General", undefined), ""); | ||||
|     assert.equal(SSF.format("General", null), ""); | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| @ -1,3 +1,5 @@ | ||||
| /* vim: set ts=2: */ | ||||
| /*jshint loopfunc:true, mocha:true, node:true */ | ||||
| var SSF = require('../'); | ||||
| var fs = require('fs'), assert = require('assert'); | ||||
| var data = JSON.parse(fs.readFileSync('./test/implied.json','utf8')); | ||||
| @ -7,7 +9,7 @@ function doit(d) { | ||||
| } | ||||
| describe('implied formats', function() { | ||||
|   data.forEach(function(d) { | ||||
|     if(d.length == 2) it(d[0], function() { doit(d); }); | ||||
|     if(d.length == 2) it(String(d[0]), function() { doit(d); }); | ||||
|     else it(d[1]+" for "+d[0], skip.indexOf(d[1]) > -1 ? null : function(){ | ||||
|       assert.equal(SSF.format(d[1], d[0], {}), d[2]); | ||||
|     }); | ||||
|  | ||||
| @ -1,11 +1,11 @@ | ||||
| /* vim: set ts=2: */ | ||||
| /*jshint loopfunc:true */ | ||||
| /*jshint loopfunc:true, mocha:true, node:true */ | ||||
| var SSF = require('../'); | ||||
| var fs = require('fs'), assert = require('assert'); | ||||
| var data = JSON.parse(fs.readFileSync('./test/oddities.json','utf8')); | ||||
| describe('oddities', function() { | ||||
|   data.forEach(function(d) { | ||||
|     it(d[0], function(){ | ||||
|     it(String(d[0]), function(){ | ||||
|       for(var j=1;j<d.length;++j) { | ||||
|         if(d[j].length == 2) { | ||||
|           var expected = d[j][1], actual = SSF.format(d[0], d[j][0], {}); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user