pulling ssf into main project [ci skip]
This commit is contained in:
commit
b738e5d3f1
1
packages/ssf-cli/.gitignore
vendored
Normal file
1
packages/ssf-cli/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
node_modules/
|
1
packages/ssf-cli/.npmignore
Normal file
1
packages/ssf-cli/.npmignore
Normal file
@ -0,0 +1 @@
|
||||
*.tgz
|
48
packages/ssf-cli/README.md
Normal file
48
packages/ssf-cli/README.md
Normal file
@ -0,0 +1,48 @@
|
||||
# [SSF Command-Line Interface](http://sheetjs.com)
|
||||
|
||||
ssf (SpreadSheet Format) is a pure JS library to format data using ECMA-376
|
||||
spreadsheet format codes (used in popular spreadsheet software packages).
|
||||
|
||||
This CLI tool formats numbers from shell scripts and other command-line tools.
|
||||
|
||||
## Installation
|
||||
|
||||
With [npm](https://www.npmjs.org/package/ssf-cli):
|
||||
|
||||
```bash
|
||||
$ npm install -g ssf-cli
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
`ssf-cli` takes two arguments: the format string and the value to be formatted.
|
||||
|
||||
The value is formatted twice, once interpreting the value as a string and once
|
||||
interpreting the value as a number, and both results are printed to standard
|
||||
output, with a pipe character `|` after each value:
|
||||
|
||||
```bash
|
||||
$ bin/ssf.njs "#,##0.00" 12345
|
||||
12345|12,345.00|
|
||||
$ bin/ssf.njs "0;0;0;:@:" 12345
|
||||
:12345:|12345|
|
||||
```
|
||||
|
||||
Extracting the values in a pipeline is straightforward with AWK:
|
||||
|
||||
```bash
|
||||
$ bin/ssf.njs "#,##0.00" 12345 | awk -F\| '{print $2}'
|
||||
12,345.00
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
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.
|
||||
|
||||
## Credits
|
||||
|
||||
Special thanks to [Garrett Luu](https://garrettluu.com/) for spinning off the
|
||||
command from the SSF module.
|
||||
|
||||
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/ssf?pixel)](https://github.com/SheetJS/ssf)
|
8
packages/ssf-cli/bin/ssf.njs
Executable file
8
packages/ssf-cli/bin/ssf.njs
Executable file
@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env node
|
||||
/* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env node */
|
||||
/* eslint no-console:0 */
|
||||
/*jshint node:true */
|
||||
var cli = require('../');
|
||||
|
||||
cli();
|
16
packages/ssf-cli/index.js
Normal file
16
packages/ssf-cli/index.js
Normal file
@ -0,0 +1,16 @@
|
||||
/* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env node */
|
||||
/* eslint no-console:0 */
|
||||
/*jshint node:true */
|
||||
var X = require('ssf');
|
||||
function run() {
|
||||
var argv = process.argv.slice(2);
|
||||
if (argv.length < 2 || argv[0] == "-h" || argv[0] == "--help") {
|
||||
console.error("usage: ssf-cli <format> <value>");
|
||||
console.error("output: format_as_string|format_as_number|");
|
||||
process.exit(0);
|
||||
}
|
||||
console.log(X.format(argv[0], argv[1]) + "|" + X.format(argv[0], +(argv[1])) + "|");
|
||||
}
|
||||
|
||||
module.exports = run;
|
31
packages/ssf-cli/package.json
Normal file
31
packages/ssf-cli/package.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "ssf-cli",
|
||||
"version": "1.1.0",
|
||||
"author": "sheetjs",
|
||||
"description": "Command-line interface for ssf",
|
||||
"keywords": [
|
||||
"format",
|
||||
"sprintf",
|
||||
"spreadsheet"
|
||||
],
|
||||
"main": "index.js",
|
||||
"bin": {
|
||||
"ssf-cli": "bin/ssf.njs"
|
||||
},
|
||||
"dependencies": {
|
||||
"ssf": "^0.11.2"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/SheetJS/sheetjs.git",
|
||||
"directory": "packages/ssf-cli"
|
||||
},
|
||||
"homepage": "http://sheetjs.com/",
|
||||
"bugs": {
|
||||
"url": "https://github.com/SheetJS/sheetjs/issues"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
}
|
24
packages/ssf/.eslintrc
Normal file
24
packages/ssf/.eslintrc
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"env": { "shared-node-browser":true },
|
||||
"globals": {},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 3
|
||||
},
|
||||
"plugins": [ "html", "json" ],
|
||||
"extends": "eslint:recommended",
|
||||
"rules": {
|
||||
"comma-style": [ 2, "last" ],
|
||||
"comma-dangle": [ 2, "never" ],
|
||||
"curly": 0,
|
||||
"no-bitwise": 0,
|
||||
"no-console": 0,
|
||||
"no-control-regex": 0,
|
||||
"no-empty": 0,
|
||||
"no-trailing-spaces": 2,
|
||||
"no-use-before-define": [ 1, {
|
||||
"functions":false, "classes":true, "variables":false
|
||||
}],
|
||||
"no-useless-escape": 0,
|
||||
"semi": [ 2, "always" ]
|
||||
}
|
||||
}
|
31
packages/ssf/.flowconfig
Normal file
31
packages/ssf/.flowconfig
Normal file
@ -0,0 +1,31 @@
|
||||
[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.flow.js
|
||||
.*/bin/.*.njs
|
||||
|
||||
[libs]
|
||||
misc/flow.js
|
||||
misc/flowdeps.js
|
||||
|
||||
[options]
|
||||
module.file_ext=.js
|
||||
module.file_ext=.njs
|
||||
module.ignore_non_literal_requires=true
|
||||
suppress_comment= \\(.\\|\n\\)*\\$FlowIgnore
|
28
packages/ssf/.gitignore
vendored
Normal file
28
packages/ssf/.gitignore
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
node_modules
|
||||
misc/coverage.html
|
||||
.vocrc
|
||||
v8.log
|
||||
tmp
|
||||
*.tgz
|
||||
*.[tT][xX][tT]
|
||||
*.[cC][sS][vV]
|
||||
*.[dD][iIbB][fF]
|
||||
*.[pP][rR][nN]
|
||||
*.[sS][lL][kK]
|
||||
*.socialcalc
|
||||
*.[xX][lL][sSwWcC]
|
||||
*.[xX][lL][sS][xXmMbB]
|
||||
*.[oO][dD][sS]
|
||||
*.[fF][oO][dD][sS]
|
||||
*.[xX][mM][lL]
|
||||
*.[uU][oO][sS]
|
||||
*.[wW][kKqQbB][S1234567890]
|
||||
*.[qQ][pP][wW]
|
||||
*.123
|
||||
*.htm
|
||||
*.html
|
||||
*.sheetjs
|
||||
*.exe
|
||||
perf.log
|
||||
ctest/test.js
|
||||
ctest/sauce*
|
6
packages/ssf/.jscs.json
Normal file
6
packages/ssf/.jscs.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"requireCommaBeforeLineBreak": true,
|
||||
"disallowTrailingWhitespace": true,
|
||||
"disallowTrailingComma": true
|
||||
}
|
||||
|
51
packages/ssf/.npmignore
Normal file
51
packages/ssf/.npmignore
Normal file
@ -0,0 +1,51 @@
|
||||
test/
|
||||
ctest/
|
||||
index.html
|
||||
misc/
|
||||
packages/
|
||||
node_modules
|
||||
*.tgz
|
||||
_book
|
||||
book.json
|
||||
tmp
|
||||
mocha.js
|
||||
*.[tT][xX][tT]
|
||||
*.[cC][sS][vV]
|
||||
*.[dD][iIbB][fF]
|
||||
*.[pP][rR][nN]
|
||||
*.[sS][lL][kK]
|
||||
*.socialcalc
|
||||
*.[xX][lL][sSwWcCaAtTmM]
|
||||
*.[xX][lL][sSaAtT][xXmMbB]
|
||||
*.[oO][dD][sS]
|
||||
*.[fF][oO][dD][sS]
|
||||
*.[xX][mM][lL]
|
||||
*.[uU][oO][sS]
|
||||
*.[wW][kKqQbB][S1234567890]
|
||||
*.[qQ][pP][wW]
|
||||
*.[bB][iI][fF][fF][23458]
|
||||
*.[rR][tT][fF]
|
||||
*.[eE][tT][hH]
|
||||
*.123
|
||||
*.htm
|
||||
*.html
|
||||
*.sheetjs
|
||||
*.exe
|
||||
*.img
|
||||
.gitignore
|
||||
.gitattributes
|
||||
.fossaignore
|
||||
.spelling
|
||||
.eslintrc
|
||||
.jshintrc
|
||||
Makefile
|
||||
.npmignore
|
||||
.jscs.json
|
||||
.gitmodules
|
||||
.travis.yml
|
||||
.flowconfig
|
||||
bits/
|
||||
.vocrc
|
||||
v8.log
|
||||
perf.log
|
||||
ssf.md
|
9
packages/ssf/.spelling
Normal file
9
packages/ssf/.spelling
Normal file
@ -0,0 +1,9 @@
|
||||
# ssf.js (C) 2013-present SheetJS -- http://sheetjs.com
|
||||
SheetJS
|
||||
ssf
|
||||
|
||||
ECMA-376
|
||||
xls
|
||||
xlsb
|
||||
|
||||
npm
|
45
packages/ssf/.travis.yml
Normal file
45
packages/ssf/.travis.yml
Normal file
@ -0,0 +1,45 @@
|
||||
language: node_js
|
||||
dist: xenial
|
||||
node_js:
|
||||
- "14"
|
||||
- "13"
|
||||
- "12"
|
||||
- "11"
|
||||
- "10"
|
||||
- "9"
|
||||
- "8"
|
||||
- "7"
|
||||
- "6"
|
||||
- "5"
|
||||
- "4"
|
||||
- "0.12"
|
||||
- "0.10"
|
||||
- "0.8"
|
||||
matrix:
|
||||
include:
|
||||
- node_js: "14"
|
||||
env: TZ="America/New_York"
|
||||
- node_js: "12"
|
||||
env: TZ="America/Los_Angeles"
|
||||
- node_js: "10"
|
||||
env: TZ="Europe/London"
|
||||
- node_js: "8"
|
||||
env: TZ="Europe/Berlin"
|
||||
- node_js: "6"
|
||||
env: TZ="Asia/Kolkata"
|
||||
- node_js: "4"
|
||||
env: TZ="Asia/Shanghai"
|
||||
- node_js: "0.12"
|
||||
env: TZ="Asia/Seoul"
|
||||
|
||||
before_install:
|
||||
- "npm config set strict-ssl false"
|
||||
- "./misc/node_version.sh"
|
||||
- "npm install -g mocha@2.x voc"
|
||||
- "npm install blanket"
|
||||
- "npm install word"
|
||||
- "npm install coveralls mocha-lcov-reporter"
|
||||
install:
|
||||
- npm install
|
||||
after_success:
|
||||
- "make coveralls"
|
201
packages/ssf/LICENSE
Normal file
201
packages/ssf/LICENSE
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright (C) 2013-present SheetJS LLC
|
||||
|
||||
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.
|
124
packages/ssf/Makefile
Executable file
124
packages/ssf/Makefile
Executable file
@ -0,0 +1,124 @@
|
||||
SHELL=/bin/bash
|
||||
LIB=ssf
|
||||
REQS=
|
||||
ADDONS=
|
||||
AUXTARGETS=
|
||||
CMDS=bin/ssf.njs
|
||||
HTMLLINT=index.html
|
||||
|
||||
ULIB=$(shell echo $(LIB) | tr a-z A-Z)
|
||||
DEPS=$(sort $(wildcard bits/*.js))
|
||||
TARGET=$(LIB).js
|
||||
FLOWTARGET=$(LIB).flow.js
|
||||
FLOWAUX=$(patsubst %.js,%.flow.js,$(AUXTARGETS))
|
||||
AUXSCPTS=
|
||||
FLOWTGTS=$(TARGET) $(AUXTARGETS) $(AUXSCPTS)
|
||||
UGLIFYOPTS=--support-ie8
|
||||
CLOSURE=/usr/local/lib/node_modules/google-closure-compiler/compiler.jar
|
||||
|
||||
## Main Targets
|
||||
|
||||
.PHONY: all
|
||||
all: $(TARGET) $(AUXTARGETS) $(AUXSCPTS) ## Build library and auxiliary scripts
|
||||
|
||||
$(FLOWTGTS): %.js : %.flow.js
|
||||
node -e 'process.stdout.write(require("fs").readFileSync("$<","utf8").replace(/^[ \t]*\/\*[:#][^*]*\*\/\s*(\n)?/gm,"").replace(/\/\*[:#][^*]*\*\//gm,""))' > $@
|
||||
|
||||
$(FLOWTARGET): $(DEPS)
|
||||
cat $^ | tr -d '\15\32' > $@
|
||||
|
||||
bits/01_version.js: package.json
|
||||
echo "$(ULIB).version = '"`grep version package.json | awk '{gsub(/[^0-9a-z\.-]/,"",$$2); print $$2}'`"';" > $@
|
||||
|
||||
.PHONY: clean
|
||||
clean: ## Remove targets and build artifacts
|
||||
rm -f $(TARGET) $(FLOWTARGET)
|
||||
|
||||
.PHONY: git
|
||||
git: ## show version string
|
||||
@echo "$$(node -pe 'require("./package.json").version') (ssf)"
|
||||
|
||||
|
||||
## Testing
|
||||
|
||||
.PHONY: test mocha
|
||||
test mocha: ## Run test suite
|
||||
mocha -R spec -t 30000
|
||||
|
||||
.PHONY: test_misc
|
||||
test_misc:
|
||||
MINTEST=1 mocha -R spec -t 30000
|
||||
|
||||
.PHONY: travis
|
||||
travis: ## Run test suite with minimal output
|
||||
mocha -R dot -t 30000
|
||||
|
||||
.PHONY: ctest
|
||||
ctest: ## Build browser test fixtures
|
||||
browserify -t brfs test/{comma,dateNF,dates,exp,fraction,general,implied,oddities,utilities,valid}.js > ctest/test.js
|
||||
|
||||
.PHONY: ctestserv
|
||||
ctestserv: ## Start a test server on port 8000
|
||||
@cd ctest && python -mSimpleHTTPServer
|
||||
|
||||
|
||||
## Code Checking
|
||||
|
||||
.PHONY: fullint
|
||||
fullint: lint old-lint tslint flow mdlint ## Run all checks
|
||||
|
||||
.PHONY: lint
|
||||
lint: $(TARGET) $(AUXTARGETS) ## Run eslint checks
|
||||
@eslint --ext .js,.njs,.json,.html,.htm $(TARGET) $(AUXTARGETS) $(CMDS) $(HTMLLINT) package.json
|
||||
if [ -e $(CLOSURE) ]; then java -jar $(CLOSURE) $(REQS) $(FLOWTARGET) --jscomp_warning=reportUnknownTypes >/dev/null; fi
|
||||
|
||||
.PHONY: old-lint
|
||||
old-lint: $(TARGET) $(AUXTARGETS) ## Run jshint and jscs checks
|
||||
@jshint --show-non-errors $(TARGET) $(AUXTARGETS)
|
||||
@jshint --show-non-errors $(CMDS)
|
||||
@jshint --show-non-errors package.json test/
|
||||
@jshint --show-non-errors --extract=always $(HTMLLINT)
|
||||
@jscs $(TARGET) $(AUXTARGETS) test/*.js
|
||||
if [ -e $(CLOSURE) ]; then java -jar $(CLOSURE) $(REQS) $(FLOWTARGET) --jscomp_warning=reportUnknownTypes >/dev/null; fi
|
||||
|
||||
.PHONY: tslint
|
||||
tslint: $(TARGET) ## Run typescript checks
|
||||
#@npm install dtslint typescript
|
||||
#@npm run-script dtslint
|
||||
dtslint types
|
||||
|
||||
.PHONY: flow
|
||||
flow: lint ## Run flow checker
|
||||
@flow check --all --show-all-errors
|
||||
|
||||
.PHONY: cov
|
||||
cov: misc/coverage.html ## Run coverage test
|
||||
|
||||
.PHONY: cov_min
|
||||
cov_min:
|
||||
MINTEST=1 make cov
|
||||
|
||||
misc/coverage.html: $(TARGET)
|
||||
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
|
||||
|
||||
.PHONY: coveralls
|
||||
coveralls: ## Coverage Test + Send to coveralls.io
|
||||
MINTEST=1 make full_coveralls
|
||||
|
||||
MDLINT=README.md
|
||||
.PHONY: mdlint
|
||||
mdlint: $(MDLINT) ## Check markdown documents
|
||||
alex $^
|
||||
mdspell -a -n -x -r --en-us $^
|
||||
|
||||
.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 $$!
|
119
packages/ssf/README.md
Normal file
119
packages/ssf/README.md
Normal file
@ -0,0 +1,119 @@
|
||||
# [SheetJS SSF](http://sheetjs.com)
|
||||
|
||||
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 the community version. We also offer a pro version with additional
|
||||
features like international support as well as dedicated support.
|
||||
|
||||
## Installation
|
||||
|
||||
With [npm](https://www.npmjs.org/package/ssf):
|
||||
|
||||
```bash
|
||||
$ npm install ssf
|
||||
```
|
||||
|
||||
In the browser:
|
||||
|
||||
```html
|
||||
<script src="ssf.js"></script>
|
||||
```
|
||||
|
||||
The browser exposes a variable `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 . This is not always
|
||||
desirable. To prevent the behavior, define `DO_NOT_EXPORT_SSF`.
|
||||
|
||||
## Usage
|
||||
|
||||
`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.
|
||||
For a raw numeric format like `000`, the value should be passed as a string.
|
||||
|
||||
Date arguments are interpreted in the local time of the JS client.
|
||||
|
||||
The options argument may contain the following keys:
|
||||
|
||||
| Option Name | Default | Description |
|
||||
| :---------- | :-----: | :--------------------------------------------------- |
|
||||
| `date1904` | false | Use 1904 date system if true, 1900 system if false |
|
||||
|
||||
### Manipulating the Internal Format Table
|
||||
|
||||
Binary spreadsheet formats store cell formats in a table and reference by index.
|
||||
This library uses a global table:
|
||||
|
||||
`SSF._table` is the underlying object, mapping numeric keys to format strings.
|
||||
|
||||
`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`)
|
||||
|
||||
`SSF.get_table()` gets the internal format table (number to format mapping).
|
||||
|
||||
`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 */
|
||||
}
|
||||
```
|
||||
|
||||
`SSF.is_date(fmt:string):boolean` returns `true` if `fmt` encodes a date format.
|
||||
|
||||
## Examples
|
||||
|
||||
- [Basic Demo](http://oss.sheetjs.com/ssf/)
|
||||
- [Custom Formats Builder](https://customformats.com)
|
||||
|
||||
## Related Packages
|
||||
|
||||
[`ssf-cli`](https://www.npmjs.com/package/ssf-cli) is a simple NodeJS command
|
||||
line tool for formatting numbers.
|
||||
|
||||
## License
|
||||
|
||||
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.
|
||||
|
||||
## References
|
||||
|
||||
- `ECMA-376`: Office Open XML File Formats
|
||||
- `MS-XLS`: Excel Binary File Format (.xls) Structure Specification
|
||||
- `MS-XLSB`: Excel (.xlsb) Binary File Format
|
||||
|
||||
## Badges
|
||||
|
||||
[![Sauce Test Status](https://saucelabs.com/browser-matrix/ssfjs.svg)](https://saucelabs.com/u/ssfjs)
|
||||
|
||||
[![Build Status](https://travis-ci.org/SheetJS/ssf.svg?branch=master)](https://travis-ci.org/SheetJS/ssf)
|
||||
|
||||
[![Coverage Status](http://img.shields.io/coveralls/SheetJS/ssf/master.svg)](https://coveralls.io/r/SheetJS/ssf?branch=master)
|
||||
|
||||
[![NPM Downloads](https://img.shields.io/npm/dt/ssf.svg)](https://npmjs.org/package/ssf)
|
||||
|
||||
[![Dependencies Status](https://david-dm.org/sheetjs/ssf/status.svg)](https://david-dm.org/sheetjs/ssf)
|
||||
|
||||
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/ssf?pixel)](https://github.com/SheetJS/ssf)
|
6
packages/ssf/bits/00_header.js
Normal file
6
packages/ssf/bits/00_header.js
Normal file
@ -0,0 +1,6 @@
|
||||
/* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
/*jshint -W041 */
|
||||
/*:: declare var DO_NOT_EXPORT_SSF: any; */
|
||||
var SSF/*:SSFModule*/ = ({}/*:any*/);
|
||||
var make_ssf = function make_ssf(SSF/*:SSFModule*/){
|
1
packages/ssf/bits/01_version.js
Normal file
1
packages/ssf/bits/01_version.js
Normal file
@ -0,0 +1 @@
|
||||
SSF.version = '0.11.2';
|
10
packages/ssf/bits/02_utilities.js
Normal file
10
packages/ssf/bits/02_utilities.js
Normal file
@ -0,0 +1,10 @@
|
||||
function _strrev(x/*:string*/)/*:string*/ { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; }
|
||||
function fill(c/*:string*/,l/*:number*/)/*:string*/ { var o = ""; while(o.length < l) o+=c; return o; }
|
||||
function pad0(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
|
||||
function pad_(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v;return t.length>=d?t:fill(' ',d-t.length)+t;}
|
||||
function rpad_(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:t+fill(' ',d-t.length);}
|
||||
function pad0r1(v/*:any*/,d/*:number*/)/*:string*/{var t=""+Math.round(v); return t.length>=d?t:fill('0',d-t.length)+t;}
|
||||
function pad0r2(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
|
||||
var p2_32 = Math.pow(2,32);
|
||||
function pad0r(v/*:any*/,d/*:number*/)/*:string*/{if(v>p2_32||v<-p2_32) return pad0r1(v,d); var i = Math.round(v); return pad0r2(i,d); }
|
||||
function isgeneral(s/*:string*/, i/*:?number*/)/*:boolean*/ { i = i || 0; return s.length >= 7 + i && (s.charCodeAt(i)|32) === 103 && (s.charCodeAt(i+1)|32) === 101 && (s.charCodeAt(i+2)|32) === 110 && (s.charCodeAt(i+3)|32) === 101 && (s.charCodeAt(i+4)|32) === 114 && (s.charCodeAt(i+5)|32) === 97 && (s.charCodeAt(i+6)|32) === 108; }
|
3
packages/ssf/bits/10_types.js
Normal file
3
packages/ssf/bits/10_types.js
Normal file
@ -0,0 +1,3 @@
|
||||
/*::
|
||||
type SSF_write_num = {(type:string, fmt:string, val:number):string};
|
||||
*/
|
23
packages/ssf/bits/20_consts.js
Normal file
23
packages/ssf/bits/20_consts.js
Normal file
@ -0,0 +1,23 @@
|
||||
var days/*:Array<Array<string> >*/ = [
|
||||
['Sun', 'Sunday'],
|
||||
['Mon', 'Monday'],
|
||||
['Tue', 'Tuesday'],
|
||||
['Wed', 'Wednesday'],
|
||||
['Thu', 'Thursday'],
|
||||
['Fri', 'Friday'],
|
||||
['Sat', 'Saturday']
|
||||
];
|
||||
var months/*:Array<Array<string> >*/ = [
|
||||
['J', 'Jan', 'January'],
|
||||
['F', 'Feb', 'February'],
|
||||
['M', 'Mar', 'March'],
|
||||
['A', 'Apr', 'April'],
|
||||
['M', 'May', 'May'],
|
||||
['J', 'Jun', 'June'],
|
||||
['J', 'Jul', 'July'],
|
||||
['A', 'Aug', 'August'],
|
||||
['S', 'Sep', 'September'],
|
||||
['O', 'Oct', 'October'],
|
||||
['N', 'Nov', 'November'],
|
||||
['D', 'Dec', 'December']
|
||||
];
|
34
packages/ssf/bits/25_table.js
Normal file
34
packages/ssf/bits/25_table.js
Normal file
@ -0,0 +1,34 @@
|
||||
function init_table(t/*:any*/) {
|
||||
t[0]= 'General';
|
||||
t[1]= '0';
|
||||
t[2]= '0.00';
|
||||
t[3]= '#,##0';
|
||||
t[4]= '#,##0.00';
|
||||
t[9]= '0%';
|
||||
t[10]= '0.00%';
|
||||
t[11]= '0.00E+00';
|
||||
t[12]= '# ?/?';
|
||||
t[13]= '# ??/??';
|
||||
t[14]= 'm/d/yy';
|
||||
t[15]= 'd-mmm-yy';
|
||||
t[16]= 'd-mmm';
|
||||
t[17]= 'mmm-yy';
|
||||
t[18]= 'h:mm AM/PM';
|
||||
t[19]= 'h:mm:ss AM/PM';
|
||||
t[20]= 'h:mm';
|
||||
t[21]= 'h:mm:ss';
|
||||
t[22]= 'm/d/yy h:mm';
|
||||
t[37]= '#,##0 ;(#,##0)';
|
||||
t[38]= '#,##0 ;[Red](#,##0)';
|
||||
t[39]= '#,##0.00;(#,##0.00)';
|
||||
t[40]= '#,##0.00;[Red](#,##0.00)';
|
||||
t[45]= 'mm:ss';
|
||||
t[46]= '[h]:mm:ss';
|
||||
t[47]= 'mmss.0';
|
||||
t[48]= '##0.0E+0';
|
||||
t[49]= '@';
|
||||
t[56]= '"上午/下午 "hh"時"mm"分"ss"秒 "';
|
||||
}
|
||||
|
||||
var table_fmt = {};
|
||||
init_table(table_fmt);
|
55
packages/ssf/bits/26_defaults.js
Normal file
55
packages/ssf/bits/26_defaults.js
Normal file
@ -0,0 +1,55 @@
|
||||
/* Defaults determined by systematically testing in Excel 2019 */
|
||||
|
||||
/* These formats appear to default to other formats in the table */
|
||||
var default_map/*:Array<number>*/ = [];
|
||||
var defi = 0;
|
||||
|
||||
// 5 -> 37 ... 8 -> 40
|
||||
for(defi = 5; defi <= 8; ++defi) default_map[defi] = 32 + defi;
|
||||
|
||||
// 23 -> 0 ... 26 -> 0
|
||||
for(defi = 23; defi <= 26; ++defi) default_map[defi] = 0;
|
||||
|
||||
// 27 -> 14 ... 31 -> 14
|
||||
for(defi = 27; defi <= 31; ++defi) default_map[defi] = 14;
|
||||
// 50 -> 14 ... 58 -> 14
|
||||
for(defi = 50; defi <= 58; ++defi) default_map[defi] = 14;
|
||||
|
||||
// 59 -> 1 ... 62 -> 4
|
||||
for(defi = 59; defi <= 62; ++defi) default_map[defi] = defi - 58;
|
||||
// 67 -> 9 ... 68 -> 10
|
||||
for(defi = 67; defi <= 68; ++defi) default_map[defi] = defi - 58;
|
||||
// 72 -> 14 ... 75 -> 17
|
||||
for(defi = 72; defi <= 75; ++defi) default_map[defi] = defi - 58;
|
||||
|
||||
// 69 -> 12 ... 71 -> 14
|
||||
for(defi = 67; defi <= 68; ++defi) default_map[defi] = defi - 57;
|
||||
|
||||
// 76 -> 20 ... 78 -> 22
|
||||
for(defi = 76; defi <= 78; ++defi) default_map[defi] = defi - 56;
|
||||
|
||||
// 79 -> 45 ... 81 -> 47
|
||||
for(defi = 79; defi <= 81; ++defi) default_map[defi] = defi - 34;
|
||||
|
||||
// 82 -> 0 ... 65536 -> 0 (omitted)
|
||||
|
||||
/* These formats technically refer to Accounting formats with no equivalent */
|
||||
var default_str/*:Array<string>*/ = [];
|
||||
|
||||
// 5 -- Currency, 0 decimal, black negative
|
||||
default_str[5] = default_str[63] = '"$"#,##0_);\\("$"#,##0\\)';
|
||||
// 6 -- Currency, 0 decimal, red negative
|
||||
default_str[6] = default_str[64] = '"$"#,##0_);[Red]\\("$"#,##0\\)';
|
||||
// 7 -- Currency, 2 decimal, black negative
|
||||
default_str[7] = default_str[65] = '"$"#,##0.00_);\\("$"#,##0.00\\)';
|
||||
// 8 -- Currency, 2 decimal, red negative
|
||||
default_str[8] = default_str[66] = '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)';
|
||||
|
||||
// 41 -- Accounting, 0 decimal, No Symbol
|
||||
default_str[41] = '_(* #,##0_);_(* \\(#,##0\\);_(* "-"_);_(@_)';
|
||||
// 42 -- Accounting, 0 decimal, $ Symbol
|
||||
default_str[42] = '_("$"* #,##0_);_("$"* \\(#,##0\\);_("$"* "-"_);_(@_)';
|
||||
// 43 -- Accounting, 2 decimal, No Symbol
|
||||
default_str[43] = '_(* #,##0.00_);_(* \\(#,##0.00\\);_(* "-"??_);_(@_)';
|
||||
// 44 -- Accounting, 2 decimal, $ Symbol
|
||||
default_str[44] = '_("$"* #,##0.00_);_("$"* \\(#,##0.00\\);_("$"* "-"??_);_(@_)';
|
20
packages/ssf/bits/30_frac.js
Normal file
20
packages/ssf/bits/30_frac.js
Normal file
@ -0,0 +1,20 @@
|
||||
function frac(x/*:number*/, D/*:number*/, mixed/*:?boolean*/)/*:Array<number>*/ {
|
||||
var sgn = x < 0 ? -1 : 1;
|
||||
var B = x * sgn;
|
||||
var P_2 = 0, P_1 = 1, P = 0;
|
||||
var Q_2 = 1, Q_1 = 0, Q = 0;
|
||||
var A = Math.floor(B);
|
||||
while(Q_1 < D) {
|
||||
A = Math.floor(B);
|
||||
P = A * P_1 + P_2;
|
||||
Q = A * Q_1 + Q_2;
|
||||
if((B - A) < 0.00000005) break;
|
||||
B = 1 / (B - A);
|
||||
P_2 = P_1; P_1 = P;
|
||||
Q_2 = Q_1; Q_1 = Q;
|
||||
}
|
||||
if(Q > D) { if(Q_1 > D) { Q = Q_2; P = P_2; } else { Q = Q_1; P = P_1; } }
|
||||
if(!mixed) return [0, sgn * P, Q];
|
||||
var q = Math.floor(sgn * P/Q);
|
||||
return [q, sgn*P - q*Q, Q];
|
||||
}
|
40
packages/ssf/bits/35_datecode.js
Normal file
40
packages/ssf/bits/35_datecode.js
Normal file
@ -0,0 +1,40 @@
|
||||
function parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) {
|
||||
if(v > 2958465 || v < 0) return null;
|
||||
var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
|
||||
var dout=[];
|
||||
var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
|
||||
if(Math.abs(out.u) < 1e-6) out.u = 0;
|
||||
if(opts && opts.date1904) date += 1462;
|
||||
if(out.u > 0.9999) {
|
||||
out.u = 0;
|
||||
if(++time == 86400) { out.T = time = 0; ++date; ++out.D; }
|
||||
}
|
||||
if(date === 60) {dout = b2 ? [1317,10,29] : [1900,2,29]; dow=3;}
|
||||
else if(date === 0) {dout = b2 ? [1317,8,29] : [1900,1,0]; dow=6;}
|
||||
else {
|
||||
if(date > 60) --date;
|
||||
/* 1 = Jan 1 1900 in Gregorian */
|
||||
var d = new Date(1900, 0, 1);
|
||||
d.setDate(d.getDate() + date - 1);
|
||||
dout = [d.getFullYear(), d.getMonth()+1,d.getDate()];
|
||||
dow = d.getDay();
|
||||
if(date < 60) dow = (dow + 6) % 7;
|
||||
if(b2) dow = fix_hijri(d, dout);
|
||||
}
|
||||
out.y = dout[0]; out.m = dout[1]; out.d = dout[2];
|
||||
out.S = time % 60; time = Math.floor(time / 60);
|
||||
out.M = time % 60; time = Math.floor(time / 60);
|
||||
out.H = time;
|
||||
out.q = dow;
|
||||
return out;
|
||||
}
|
||||
SSF.parse_date_code = parse_date_code;
|
||||
var basedate = new Date(1899, 11, 31, 0, 0, 0);
|
||||
var dnthresh = basedate.getTime();
|
||||
var base1904 = new Date(1900, 2, 1, 0, 0, 0);
|
||||
function datenum_local(v/*:Date*/, date1904/*:?boolean*/)/*:number*/ {
|
||||
var epoch = v.getTime();
|
||||
if(date1904) epoch -= 1461*24*60*60*1000;
|
||||
else if(v >= base1904) epoch += 24*60*60*1000;
|
||||
return (epoch - (dnthresh + (v.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000)) / (24 * 60 * 60 * 1000);
|
||||
}
|
71
packages/ssf/bits/40_general.js
Normal file
71
packages/ssf/bits/40_general.js
Normal file
@ -0,0 +1,71 @@
|
||||
/* The longest 32-bit integer text is "-4294967296", exactly 11 chars */
|
||||
function general_fmt_int(v/*:number*/)/*:string*/ { return v.toString(10); }
|
||||
SSF._general_int = general_fmt_int;
|
||||
|
||||
/* ECMA-376 18.8.30 numFmt*/
|
||||
/* Note: `toPrecision` uses standard form when prec > E and E >= -6 */
|
||||
var general_fmt_num = (function make_general_fmt_num() {
|
||||
var trailing_zeroes_and_decimal = /(?:\.0*|(\.\d*[1-9])0+)$/;
|
||||
function strip_decimal(o/*:string*/)/*:string*/ {
|
||||
return (o.indexOf(".") == -1) ? o : o.replace(trailing_zeroes_and_decimal, "$1");
|
||||
}
|
||||
|
||||
/* General Exponential always shows 2 digits exp and trims the mantissa */
|
||||
var mantissa_zeroes_and_decimal = /(?:\.0*|(\.\d*[1-9])0+)[Ee]/;
|
||||
var exp_with_single_digit = /(E[+-])(\d)$/;
|
||||
function normalize_exp(o/*:string*/)/*:string*/ {
|
||||
if(o.indexOf("E") == -1) return o;
|
||||
return o.replace(mantissa_zeroes_and_decimal,"$1E").replace(exp_with_single_digit,"$10$2");
|
||||
}
|
||||
|
||||
/* exponent >= -9 and <= 9 */
|
||||
function small_exp(v/*:number*/)/*:string*/ {
|
||||
var w = (v<0?12:11);
|
||||
var o = strip_decimal(v.toFixed(12)); if(o.length <= w) return o;
|
||||
o = v.toPrecision(10); if(o.length <= w) return o;
|
||||
return v.toExponential(5);
|
||||
}
|
||||
|
||||
/* exponent >= 11 or <= -10 likely exponential */
|
||||
function large_exp(v/*:number*/)/*:string*/ {
|
||||
var o = strip_decimal(v.toFixed(11));
|
||||
return (o.length > (v<0?12:11) || o === "0" || o === "-0") ? v.toPrecision(6) : o;
|
||||
}
|
||||
|
||||
function general_fmt_num_base(v/*:number*/)/*: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 = small_exp(v);
|
||||
else if(V === 10) o = v.toFixed(10).substr(0,12);
|
||||
else o = large_exp(v);
|
||||
|
||||
return strip_decimal(normalize_exp(o.toUpperCase()));
|
||||
}
|
||||
|
||||
return general_fmt_num_base;
|
||||
})();
|
||||
SSF._general_num = general_fmt_num;
|
||||
|
||||
/*
|
||||
"General" rules:
|
||||
- text is passed through ("@")
|
||||
- booleans are rendered as TRUE/FALSE
|
||||
- "up to 11 characters" displayed for numbers
|
||||
- Default date format (code 14) used for Dates
|
||||
|
||||
TODO: technically the display depends on the width of the cell
|
||||
*/
|
||||
function general_fmt(v/*:any*/, opts/*:any*/) {
|
||||
switch(typeof v) {
|
||||
case 'string': return v;
|
||||
case 'boolean': return v ? "TRUE" : "FALSE";
|
||||
case 'number': return (v|0) === v ? v.toString(10) : general_fmt_num(v);
|
||||
case 'undefined': return "";
|
||||
case 'object':
|
||||
if(v == null) return "";
|
||||
if(v instanceof Date) return format(14, datenum_local(v, opts && opts.date1904), opts);
|
||||
}
|
||||
throw new Error("unsupported value in General format: " + v);
|
||||
}
|
||||
SSF._general = general_fmt;
|
7
packages/ssf/bits/45_hijri.js
Normal file
7
packages/ssf/bits/45_hijri.js
Normal file
@ -0,0 +1,7 @@
|
||||
function fix_hijri(date/*:Date*/, o/*:[number, number, number]*/) {
|
||||
/* TODO: properly adjust y/m/d and */
|
||||
o[0] -= 581;
|
||||
var dow = date.getDay();
|
||||
if(date < 60) dow = (dow + 6) % 7;
|
||||
return dow;
|
||||
}
|
1
packages/ssf/bits/49_thaidigits.js
Normal file
1
packages/ssf/bits/49_thaidigits.js
Normal file
@ -0,0 +1 @@
|
||||
var THAI_DIGITS = "\u0E50\u0E51\u0E52\u0E53\u0E54\u0E55\u0E56\u0E57\u0E58\u0E59".split("");
|
66
packages/ssf/bits/50_date.js
Normal file
66
packages/ssf/bits/50_date.js
Normal file
@ -0,0 +1,66 @@
|
||||
/*jshint -W086 */
|
||||
function write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*:string*/ {
|
||||
var o="", ss=0, tt=0, y = val.y, out, outl = 0;
|
||||
switch(type) {
|
||||
case 98: /* 'b' buddhist year */
|
||||
y = val.y + 543;
|
||||
/* falls through */
|
||||
case 121: /* 'y' year */
|
||||
switch(fmt.length) {
|
||||
case 1: case 2: out = y % 100; outl = 2; break;
|
||||
default: out = y % 10000; outl = 4; break;
|
||||
} break;
|
||||
case 109: /* 'm' month */
|
||||
switch(fmt.length) {
|
||||
case 1: case 2: out = val.m; outl = fmt.length; break;
|
||||
case 3: return months[val.m-1][1];
|
||||
case 5: return months[val.m-1][0];
|
||||
default: return months[val.m-1][2];
|
||||
} break;
|
||||
case 100: /* 'd' day */
|
||||
switch(fmt.length) {
|
||||
case 1: case 2: out = val.d; outl = fmt.length; break;
|
||||
case 3: return days[val.q][0];
|
||||
default: return days[val.q][1];
|
||||
} break;
|
||||
case 104: /* 'h' 12-hour */
|
||||
switch(fmt.length) {
|
||||
case 1: case 2: out = 1+(val.H+11)%12; outl = fmt.length; break;
|
||||
default: throw 'bad hour format: ' + fmt;
|
||||
} break;
|
||||
case 72: /* 'H' 24-hour */
|
||||
switch(fmt.length) {
|
||||
case 1: case 2: out = val.H; outl = fmt.length; break;
|
||||
default: throw 'bad hour format: ' + fmt;
|
||||
} break;
|
||||
case 77: /* 'M' minutes */
|
||||
switch(fmt.length) {
|
||||
case 1: case 2: out = val.M; outl = fmt.length; break;
|
||||
default: throw 'bad minute format: ' + fmt;
|
||||
} break;
|
||||
case 115: /* 's' seconds */
|
||||
if(fmt != 's' && fmt != 'ss' && fmt != '.0' && fmt != '.00' && fmt != '.000') throw 'bad second format: ' + fmt;
|
||||
if(val.u === 0 && (fmt == "s" || fmt == "ss")) return pad0(val.S, fmt.length);
|
||||
/*::if(!ss0) ss0 = 0; */
|
||||
if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100;
|
||||
else tt = ss0 === 1 ? 10 : 1;
|
||||
ss = Math.round((tt)*(val.S + val.u));
|
||||
if(ss >= 60*tt) ss = 0;
|
||||
if(fmt === 's') return ss === 0 ? "0" : ""+ss/tt;
|
||||
o = pad0(ss,2 + ss0);
|
||||
if(fmt === 'ss') return o.substr(0,2);
|
||||
return "." + o.substr(2,fmt.length-1);
|
||||
case 90: /* 'Z' absolute time */
|
||||
switch(fmt) {
|
||||
case '[h]': case '[hh]': out = val.D*24+val.H; break;
|
||||
case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break;
|
||||
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
|
||||
default: throw 'bad abstime format: ' + fmt;
|
||||
} outl = fmt.length === 3 ? 1 : 2; break;
|
||||
case 101: /* 'e' era */
|
||||
out = y; outl = 1; break;
|
||||
}
|
||||
var outstr = outl > 0 ? pad0(out, outl) : "";
|
||||
return outstr;
|
||||
}
|
||||
/*jshint +W086 */
|
7
packages/ssf/bits/56_commaify.js
Normal file
7
packages/ssf/bits/56_commaify.js
Normal file
@ -0,0 +1,7 @@
|
||||
function commaify(s/*:string*/)/*:string*/ {
|
||||
var w = 3;
|
||||
if(s.length <= w) return s;
|
||||
var j = (s.length % w), o = s.substr(0,j);
|
||||
for(; j!=s.length; j+=w) o+=(o.length > 0 ? "," : "") + s.substr(j,w);
|
||||
return o;
|
||||
}
|
1
packages/ssf/bits/57_numhead.js
Normal file
1
packages/ssf/bits/57_numhead.js
Normal file
@ -0,0 +1 @@
|
||||
var write_num/*:SSF_write_num*/ = (function make_write_num(){
|
5
packages/ssf/bits/59_numhelp.js
Normal file
5
packages/ssf/bits/59_numhelp.js
Normal file
@ -0,0 +1,5 @@
|
||||
var pct1 = /%/g;
|
||||
function write_num_pct(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{
|
||||
var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
|
||||
return write_num(type, sfmt, val * Math.pow(10,2*mul)) + fill("%",mul);
|
||||
}
|
69
packages/ssf/bits/60_number.js
Normal file
69
packages/ssf/bits/60_number.js
Normal file
@ -0,0 +1,69 @@
|
||||
function write_num_cm(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{
|
||||
var idx = fmt.length - 1;
|
||||
while(fmt.charCodeAt(idx-1) === 44) --idx;
|
||||
return write_num(type, fmt.substr(0,idx), val / Math.pow(10,3*(fmt.length-idx)));
|
||||
}
|
||||
function write_num_exp(fmt/*:string*/, val/*:number*/)/*:string*/{
|
||||
var o/*:string*/;
|
||||
var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
|
||||
if(fmt.match(/^#+0.0E\+0$/)) {
|
||||
if(val == 0) return "0.0E+0";
|
||||
else if(val < 0) return "-" + write_num_exp(fmt, -val);
|
||||
var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
|
||||
var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
|
||||
if(ee < 0) ee += period;
|
||||
o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
|
||||
if(o.indexOf("e") === -1) {
|
||||
var fakee = Math.floor(Math.log(val)*Math.LOG10E);
|
||||
if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
|
||||
else o += "E+" + (fakee - ee);
|
||||
while(o.substr(0,2) === "0.") {
|
||||
o = o.charAt(0) + o.substr(2,period) + "." + o.substr(2+period);
|
||||
o = o.replace(/^0+([1-9])/,"$1").replace(/^0+\./,"0.");
|
||||
}
|
||||
o = o.replace(/\+-/,"-");
|
||||
}
|
||||
o = o.replace(/^([+-]?)(\d*)\.(\d*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,(period+ee)%period) + "." + $3.substr(ee) + "E"; });
|
||||
} else o = val.toExponential(idx);
|
||||
if(fmt.match(/E\+00$/) && o.match(/e[+-]\d$/)) o = o.substr(0,o.length-1) + "0" + o.charAt(o.length-1);
|
||||
if(fmt.match(/E\-/) && o.match(/e\+/)) o = o.replace(/e\+/,"e");
|
||||
return o.replace("e","E");
|
||||
}
|
||||
var frac1 = /# (\?+)( ?)\/( ?)(\d+)/;
|
||||
function write_num_f1(r/*:Array<string>*/, aval/*:number*/, sign/*:string*/)/*:string*/ {
|
||||
var den = parseInt(r[4],10), rr = Math.round(aval * den), base = Math.floor(rr/den);
|
||||
var myn = (rr - base*den), myd = den;
|
||||
return sign + (base === 0 ? "" : ""+base) + " " + (myn === 0 ? fill(" ", r[1].length + 1 + r[4].length) : pad_(myn,r[1].length) + r[2] + "/" + r[3] + pad0(myd,r[4].length));
|
||||
}
|
||||
function write_num_f2(r/*:Array<string>*/, aval/*:number*/, sign/*:string*/)/*:string*/ {
|
||||
return sign + (aval === 0 ? "" : ""+aval) + fill(" ", r[1].length + 2 + r[4].length);
|
||||
}
|
||||
var dec1 = /^#*0*\.([0#]+)/;
|
||||
var closeparen = /\).*[0#]/;
|
||||
var phone = /\(###\) ###\\?-####/;
|
||||
function hashq(str/*:string*/)/*:string*/ {
|
||||
var o = "", cc;
|
||||
for(var i = 0; i != str.length; ++i) switch((cc=str.charCodeAt(i))) {
|
||||
case 35: break;
|
||||
case 63: o+= " "; break;
|
||||
case 48: o+= "0"; break;
|
||||
default: o+= String.fromCharCode(cc);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
function rnd(val/*:number*/, d/*:number*/)/*:string*/ { var dd = Math.pow(10,d); return ""+(Math.round(val * dd)/dd); }
|
||||
function dec(val/*:number*/, d/*:number*/)/*:number*/ {
|
||||
var _frac = val - Math.floor(val), dd = Math.pow(10,d);
|
||||
if (d < ('' + Math.round(_frac * dd)).length) return 0;
|
||||
return Math.round(_frac * dd);
|
||||
}
|
||||
function carry(val/*:number*/, d/*:number*/)/*:number*/ {
|
||||
if (d < ('' + Math.round((val-Math.floor(val))*Math.pow(10,d))).length) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
function flr(val/*:number*/)/*:string*/ {
|
||||
if(val < 2147483647 && val > -2147483648) return ""+(val >= 0 ? (val|0) : (val-1|0));
|
||||
return ""+Math.floor(val);
|
||||
}
|
85
packages/ssf/bits/63_numflt.js
Normal file
85
packages/ssf/bits/63_numflt.js
Normal file
@ -0,0 +1,85 @@
|
||||
function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/ {
|
||||
if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) {
|
||||
var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");
|
||||
if(val >= 0) return write_num_flt('n', ffmt, val);
|
||||
return '(' + write_num_flt('n', ffmt, -val) + ')';
|
||||
}
|
||||
if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm(type, fmt, val);
|
||||
if(fmt.indexOf('%') !== -1) return write_num_pct(type, fmt, val);
|
||||
if(fmt.indexOf('E') !== -1) return write_num_exp(fmt, val);
|
||||
if(fmt.charCodeAt(0) === 36) return "$"+write_num_flt(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
|
||||
var o;
|
||||
var r/*:?Array<string>*/, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
|
||||
if(fmt.match(/^00+$/)) return sign + pad0r(aval,fmt.length);
|
||||
if(fmt.match(/^[#?]+$/)) {
|
||||
o = pad0r(val,0); if(o === "0") o = "";
|
||||
return o.length > fmt.length ? o : hashq(fmt.substr(0,fmt.length-o.length)) + o;
|
||||
}
|
||||
if((r = fmt.match(frac1))) return write_num_f1(r, aval, sign);
|
||||
if(fmt.match(/^#+0+$/)) return sign + pad0r(aval,fmt.length - fmt.indexOf("0"));
|
||||
if((r = fmt.match(dec1))) {
|
||||
o = rnd(val, r[1].length).replace(/^([^\.]+)$/,"$1."+hashq(r[1])).replace(/\.$/,"."+hashq(r[1])).replace(/\.(\d*)$/,function($$, $1) { return "." + $1 + fill("0", hashq(/*::(*/r/*::||[""])*/[1]).length-$1.length); });
|
||||
return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,".");
|
||||
}
|
||||
fmt = fmt.replace(/^#+([0.])/, "$1");
|
||||
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(/^#{1,3},##0(\.?)$/))) return sign + commaify(pad0r(aval,0));
|
||||
if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
|
||||
return val < 0 ? "-" + write_num_flt(type, fmt, -val) : commaify(""+(Math.floor(val) + carry(val, r[1].length))) + "." + pad0(dec(val, r[1].length),r[1].length);
|
||||
}
|
||||
if((r = fmt.match(/^#,#*,#0/))) return write_num_flt(type,fmt.replace(/^#,#*,/,""),val);
|
||||
if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
|
||||
o = _strrev(write_num_flt(type, fmt.replace(/[\\-]/g,""), val));
|
||||
ri = 0;
|
||||
return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o.charAt(ri++):x==='0'?'0':"";}));
|
||||
}
|
||||
if(fmt.match(phone)) {
|
||||
o = write_num_flt(type, "##########", val);
|
||||
return "(" + o.substr(0,3) + ") " + o.substr(3, 3) + "-" + o.substr(6);
|
||||
}
|
||||
var oa = "";
|
||||
if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) {
|
||||
ri = Math.min(/*::String(*/r[4]/*::)*/.length,7);
|
||||
ff = frac(aval, Math.pow(10,ri)-1, false);
|
||||
o = "" + sign;
|
||||
oa = write_num("n", /*::String(*/r[1]/*::)*/, ff[1]);
|
||||
if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
|
||||
o += oa + /*::String(*/r[2]/*::)*/ + "/" + /*::String(*/r[3]/*::)*/;
|
||||
oa = rpad_(ff[2],ri);
|
||||
if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
|
||||
o += oa;
|
||||
return o;
|
||||
}
|
||||
if((r = fmt.match(/^# ([#0?]+)( ?)\/( ?)([#0?]+)/))) {
|
||||
ri = Math.min(Math.max(r[1].length, r[4].length),7);
|
||||
ff = frac(aval, Math.pow(10,ri)-1, true);
|
||||
return sign + (ff[0]||(ff[1] ? "" : "0")) + " " + (ff[1] ? pad_(ff[1],ri) + r[2] + "/" + r[3] + rpad_(ff[2],ri): fill(" ", 2*ri+1 + r[2].length + r[3].length));
|
||||
}
|
||||
if((r = fmt.match(/^[#0?]+$/))) {
|
||||
o = pad0r(val, 0);
|
||||
if(fmt.length <= o.length) return o;
|
||||
return hashq(fmt.substr(0,fmt.length-o.length)) + o;
|
||||
}
|
||||
if((r = fmt.match(/^([#0?]+)\.([#0]+)$/))) {
|
||||
o = "" + val.toFixed(Math.min(r[2].length,10)).replace(/([^0])0+$/,"$1");
|
||||
ri = o.indexOf(".");
|
||||
var lres = fmt.indexOf(".") - ri, rres = fmt.length - o.length - lres;
|
||||
return hashq(fmt.substr(0,lres) + o + fmt.substr(fmt.length-rres));
|
||||
}
|
||||
if((r = fmt.match(/^00,000\.([#0]*0)$/))) {
|
||||
ri = dec(val, r[1].length);
|
||||
return val < 0 ? "-" + write_num_flt(type, fmt, -val) : commaify(flr(val)).replace(/^\d,\d{3}$/,"0$&").replace(/^\d*$/,function($$) { return "00," + ($$.length < 3 ? pad0(0,3-$$.length) : "") + $$; }) + "." + pad0(ri,r[1].length);
|
||||
}
|
||||
switch(fmt) {
|
||||
case "###,##0.00": return write_num_flt(type, "#,##0.00", val);
|
||||
case "###,###":
|
||||
case "##,###":
|
||||
case "#,###": var x = commaify(pad0r(aval,0)); return x !== "0" ? sign + x : "";
|
||||
case "###,###.00": return write_num_flt(type, "###,##0.00",val).replace(/^0\./,".");
|
||||
case "#,###.00": return write_num_flt(type, "#,##0.00",val).replace(/^0\./,".");
|
||||
default:
|
||||
}
|
||||
throw new Error("unsupported format |" + fmt + "|");
|
||||
}
|
31
packages/ssf/bits/65_numinth.js
Normal file
31
packages/ssf/bits/65_numinth.js
Normal file
@ -0,0 +1,31 @@
|
||||
function write_num_cm2(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{
|
||||
var idx = fmt.length - 1;
|
||||
while(fmt.charCodeAt(idx-1) === 44) --idx;
|
||||
return write_num(type, fmt.substr(0,idx), val / Math.pow(10,3*(fmt.length-idx)));
|
||||
}
|
||||
function write_num_pct2(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{
|
||||
var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
|
||||
return write_num(type, sfmt, val * Math.pow(10,2*mul)) + fill("%",mul);
|
||||
}
|
||||
function write_num_exp2(fmt/*:string*/, val/*:number*/)/*:string*/{
|
||||
var o/*:string*/;
|
||||
var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
|
||||
if(fmt.match(/^#+0.0E\+0$/)) {
|
||||
if(val == 0) return "0.0E+0";
|
||||
else if(val < 0) return "-" + write_num_exp2(fmt, -val);
|
||||
var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
|
||||
var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
|
||||
if(ee < 0) ee += period;
|
||||
o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
|
||||
if(!o.match(/[Ee]/)) {
|
||||
var fakee = Math.floor(Math.log(val)*Math |