Compare commits

...

448 Commits

Author SHA1 Message Date
dependabot[bot] 4f4015a4f7 chore(deps-dev): bump karma from 6.3.8 to 6.3.14
Bumps [karma](https://github.com/karma-runner/karma) from 6.3.8 to 6.3.14.
- [Release notes](https://github.com/karma-runner/karma/releases)
- [Changelog](https://github.com/karma-runner/karma/blob/master/CHANGELOG.md)
- [Commits](https://github.com/karma-runner/karma/compare/v6.3.8...v6.3.14)

---
updated-dependencies:
- dependency-name: karma
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-11 11:38:38 -05:00
dependabot[bot] b73ce7bd2e chore(deps): bump log4js from 6.3.0 to 6.4.0
Bumps [log4js](https://github.com/log4js-node/log4js-node) from 6.3.0 to 6.4.0.
- [Release notes](https://github.com/log4js-node/log4js-node/releases)
- [Changelog](https://github.com/log4js-node/log4js-node/blob/master/CHANGELOG.md)
- [Commits](https://github.com/log4js-node/log4js-node/compare/v6.3.0...v6.4.0)

---
updated-dependencies:
- dependency-name: log4js
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-21 15:51:57 -05:00
David Humphrey 3279c2d65a Release 1.4.1 2021-11-15 18:13:39 -05:00
Ben Heidemann e135305f25
Fix Issue 790 and 791 (#795)
* fix: distribute shims and webpack folders to NPM

* docs: update README.md
2021-11-15 18:09:46 -05:00
David Humphrey 0b26979839 Release 1.4.0 2021-11-15 11:12:05 -05:00
Ben Heidemann 7efc4cdc1d
Fix Issue #790 (#793)
* fix: make wepback plugin available from filer/webpack

* deprecate accessing FilerWebpackPlugin through index.js

* docs: update documentation to reflect changes to FilerWebpackPlugin

* docs: fix typo
2021-11-15 11:05:39 -05:00
David Humphrey 4112d072b5 Release 1.3.1 2021-11-13 08:53:11 -05:00
David Humphrey ee26394ead Update dev deps 2021-11-13 08:48:53 -05:00
David Humphrey 9f8804f716 Update actions/setup-node to 2.4.1, fix matrix syntax 2021-10-19 16:58:00 -04:00
David Humphrey 621b6567e0 Update node matrix to 14, 16 2021-10-19 16:49:44 -04:00
David Humphrey 4acd064a2b Release 1.3.0 2021-10-19 16:44:10 -04:00
David Humphrey b283023286 Update deps 2021-10-19 16:40:38 -04:00
Arun Bose 24697a3ed9 fix: rename across directories working 2021-10-19 16:16:31 -04:00
dependabot[bot] 5f872f0f24 chore(deps): bump trim-newlines from 3.0.0 to 3.0.1
Bumps [trim-newlines](https://github.com/sindresorhus/trim-newlines) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/sindresorhus/trim-newlines/releases)
- [Commits](https://github.com/sindresorhus/trim-newlines/commits)

---
updated-dependencies:
- dependency-name: trim-newlines
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-08 11:10:49 -04:00
bcheidemann 77abca991a docs: format fs.readdir documentation section 2021-06-05 13:45:41 -04:00
bcheidemann 49ace4b2fb docs: add documentation for the options in fs.readdir 2021-06-05 13:45:41 -04:00
bcheidemann d055d8042e test: update tests for issue #775 2021-06-05 13:45:41 -04:00
bcheidemann 576831370f fix: handle withFileTypes options in readdir 2021-06-05 13:45:41 -04:00
bcheidemann 594ab2621f fix: mkdir accepts encoding options 2021-06-05 13:45:41 -04:00
Ben Heidemann 75a2cc86cf test: skip this until we have a fix 2021-06-05 13:45:41 -04:00
Ben Heidemann a4b3726520 test(#775): add regression test for issue #775 2021-06-05 13:45:41 -04:00
Ben Heidemann 21e7a4750a test: skip test for issue #776 until fix is finished 2021-05-26 09:55:26 -04:00
Ben Heidemann aa2df3a17c test(#776): add regression test for issue #776 2021-05-26 09:55:26 -04:00
Ben Heidemann bd15462f6e test: skip test for issue #776 until fix is finished 2021-05-26 09:55:26 -04:00
Ben Heidemann 78ae19fbad test(#776): add regression test for issue #776 2021-05-26 09:55:26 -04:00
Ben Heidemann b3caddcfec refactor: make fs shim a commonjs module to match node.js fs module 2021-05-26 09:54:38 -04:00
Ben Heidemann 11e05e131b fix: make fs proxy return undefined for keys which do not exist on the file system instance 2021-05-26 09:54:38 -04:00
Ben Heidemann fb100b165a refactor: use Object.assign instead of Object.create for cloning nodePath
because Object.keys omits many of the methods on the filerPath module when using Object.create
2021-05-26 09:54:38 -04:00
Ben Heidemann e94543471b test: rename webpack plugin test 2021-05-26 09:54:38 -04:00
Ben Heidemann 20d4d5e720 chore: remove path dependency 2021-05-26 09:54:38 -04:00
Ben Heidemann 0295d19a7f refactor: rename plugin.js to index.js 2021-05-26 09:54:38 -04:00
Ben Heidemann 365a7d23a3 test: remove describe.only 2021-05-26 09:54:38 -04:00
Ben Heidemann ea5e48b48b style: fix linting issues 2021-05-26 09:54:38 -04:00
Ben Heidemann e82374ae2b test: add spec for webpack plugin 2021-05-26 09:54:38 -04:00
Ben Heidemann 5bd05287d4 test: add mock function create helper to utils 2021-05-26 09:54:38 -04:00
Ben Heidemann 1c34abf009 style: add missing indents in switch 2021-05-26 09:54:38 -04:00
Ben Heidemann 8b4b0a6140 fix: when cwd is root and the <rootDir> tag is replaced, the resulting path should not begin with // 2021-05-26 09:54:38 -04:00
Ben Heidemann e489409b9c test: remove buffer shim spec test 2021-05-26 09:54:38 -04:00
Ben Heidemann 0db08e31bb docs: remove buffer shim docs and replace with info on why it's not provided 2021-05-26 09:54:38 -04:00
Ben Heidemann 1f02edf5b3 refactor: remove buffer shim option from filer webpack plugin 2021-05-26 09:54:38 -04:00
Ben Heidemann 708c84fc63 refactor: remove buffer shim 2021-05-26 09:54:38 -04:00
Ben Heidemann 4e45701b51 test: update path shim test to not use broken import 2021-05-26 09:54:38 -04:00
Ben Heidemann fe9ed6a648 fix: fix shim path export 2021-05-26 09:54:38 -04:00
Ben Heidemann 81ab65b95c docs: update and replace README.md section on using regular node.js imports 2021-05-26 09:54:38 -04:00
Ben Heidemann 582352f754 refactor: add missing import for path in processors 2021-05-26 09:54:38 -04:00
Ben Heidemann 3b9fafc53e style: fix linting issues in webpack plugin 2021-05-26 09:54:38 -04:00
Ben Heidemann bfb50bf608 docs: fix typo in README.md 2021-05-26 09:54:38 -04:00
Ben Heidemann ce56539190 docs: fix typo in webpack plugin docs 2021-05-26 09:54:38 -04:00
Ben Heidemann 0f812fc6a0 refactor: remove typo in webpack plugin 2021-05-26 09:54:38 -04:00
Ben Heidemann 767c83706b docs: add missing filer import in webpack.config.js code snippet 2021-05-26 09:54:38 -04:00
Ben Heidemann 6a20ac2c3f docs: replace alias documentation with docs for FilerWebpackPlugin 2021-05-26 09:54:38 -04:00
Ben Heidemann 2bcf7e560b refactor: export filer webpack plugin in index.js 2021-05-26 09:54:38 -04:00
Ben Heidemann d040763a73 feat: add filer webpack plugin 2021-05-26 09:54:38 -04:00
Ben Heidemann fd90f32d4c chore: add path and schema-utils as dependancies 2021-05-26 09:54:38 -04:00
dependabot[bot] e18104a60d chore(deps): bump browserslist from 4.11.1 to 4.16.6
Bumps [browserslist](https://github.com/browserslist/browserslist) from 4.11.1 to 4.16.6.
- [Release notes](https://github.com/browserslist/browserslist/releases)
- [Changelog](https://github.com/browserslist/browserslist/blob/main/CHANGELOG.md)
- [Commits](https://github.com/browserslist/browserslist/compare/4.11.1...4.16.6)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-26 09:46:18 -04:00
Ben Heidemann 7bd6e5f4e1 fix: handle case data = 0 in writeFile 2021-04-18 11:44:39 -04:00
Ben Heidemann 90db749ee5 fix: handle case data = 0 in writeFile 2021-04-18 11:44:39 -04:00
Ben Heidemann f9c5473c49 test: add missing space in issue 773 regression test 2021-04-18 11:44:39 -04:00
Ben Heidemann f5ad682fd7 fix: allow encodings other that utf8 when using writeFile 2021-04-18 11:44:39 -04:00
Ben Heidemann 7b1c3e85ce fix(#773): use utf8 encoding when reading file when encoding not specified by options 2021-04-18 11:44:39 -04:00
Ben Heidemann 51afeeaf54 test: simplify regression test for issue773 2021-04-18 11:44:39 -04:00
Ben Heidemann cef6adfc37 style: fix linting issues and invoke done with error if error is captured 2021-04-18 11:44:39 -04:00
Ben Heidemann 6590cb79bd test: add regression test for issue 773 2021-04-18 11:44:39 -04:00
Ben Heidemann 3e88aeca92
Fix issue #766: Remove describe.only from shim tests (#767)
* test: replace describe.only in shim tests with describes so all tests run

* test: move require chai to top of file for consistency with other tests

* chore: npm install

* test: replace describe.only in shim tests with describes so all tests run

* test: move require chai to top of file for consistency with other tests

* chore: npm install

* Revert "chore: npm install"

This reverts commit cddeef421b.

* Revert "test: move require chai to top of file for consistency with other tests"

This reverts commit 40df7912fb.
2021-03-21 13:57:34 -04:00
Ben Heidemann f8c9732be9 docs: correct error in buffer shim documentation 2021-03-20 11:54:36 -04:00
David Humphrey 200171d2a5 Use node-version vs. node_version 2021-03-20 11:48:00 -04:00
David Humphrey 095f78498f Change node version definition in node-js-ci 2021-03-20 11:39:37 -04:00
David Humphrey 5cf2495079 Update node-js-ci workflow to fix broken npm installs 2021-03-20 11:32:38 -04:00
David Humphrey aacc8061cf
Merge pull request #762 from medayo/resolvePackageJSONConflicts
Using filer with webpack
2021-03-07 10:53:40 -05:00
Ben Heidemann c378288819
Merge branch 'master' into resolvePackageJSONConflicts 2021-03-07 15:36:28 +00:00
Ben Heidemann d1054753a6
Merge pull request #3 from medayo/fixTypo
docs: fix buffer import example in README.md
2021-03-07 15:26:31 +00:00
bcheidemann 887ed9318a docs: fix buffer import example in README.md 2021-03-07 15:25:52 +00:00
Ben Heidemann ce076729f6
Merge pull request #2 from medayo/shimTests
Shim tests and buffer shim/docs
2021-03-07 15:23:45 +00:00
bcheidemann a2151cab25 test: add spec for path shim 2021-03-07 15:21:39 +00:00
bcheidemann 3a8a59d362 test: add spec for buffer shim 2021-03-07 15:21:28 +00:00
bcheidemann 15be384940 test: run tests for path and buffer 2021-03-07 15:21:11 +00:00
bcheidemann 6027376efa refactor: use correct import for Buffer in buffer shim 2021-03-07 15:20:58 +00:00
bcheidemann 8b57d299f4 test: add test for fs shim 2021-03-07 15:05:18 +00:00
bcheidemann d6b29226aa refactor: return result of fn when wrapping in utils.shimIndexDB 2021-03-07 15:02:29 +00:00
bcheidemann da65e06e3c test: run fs shim spec test 2021-03-07 15:01:51 +00:00
bcheidemann aa152955b5 refactor: use correct path import in shim 2021-03-07 15:01:05 +00:00
bcheidemann d264113e0d docs: add documentation for use of buffer shim to README.md 2021-03-07 14:58:35 +00:00
bcheidemann ce809c4ac9 feat: add buffer shim 2021-03-07 14:58:09 +00:00
dependabot[bot] 3061328459 Bump ini from 1.3.5 to 1.3.8
Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.8.
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.8)

Signed-off-by: dependabot[bot] <support@github.com>
2021-02-24 15:24:13 -05:00
David Humphrey c0a41d67ff Add .gitattributes and define eol style as lf 2021-02-24 12:35:38 -05:00
David Humphrey 4941d10e13 Remove 16.x from GitHub Actions node build matrix 2021-02-24 12:07:57 -05:00
David Humphrey 07a00a3f77 Update deps, add GitHub Actions CI 2021-02-24 12:04:39 -05:00
bcheidemann 0f5fe64ae8 chore: npm install regenerator-runtime 2021-02-21 10:25:43 +00:00
bcheidemann 7ec1fed51f chore: use regenerator runtime in tests for async/await 2021-02-21 10:21:03 +00:00
bcheidemann a2f7ee044b chore: show console logs when running tests 2021-02-21 10:18:57 +00:00
bcheidemann 7415e45867 docs: fix typo in README.md
replace 'alternative file sytem' with 'alternative file system provider'
2021-02-21 00:24:19 +00:00
bcheidemann 986ad37597 refactor: get reference to error in catch block
fixes red squigle for unexpected {
2021-02-21 00:21:20 +00:00
bcheidemann 9c669564b2 refactor: change fsprovider to fsProvider 2021-02-21 00:19:17 +00:00
bcheidemann 9d03788c1c docs: add own name to authors file 2021-02-20 04:14:24 +00:00
Ben Heidemann a60d2b4cfc
Merge pull request #1 from medayo/feat/shims
Feat/shims
2021-02-20 04:09:06 +00:00
bcheidemann 417a4e97dd docs: 2021-02-20 04:04:37 +00:00
bcheidemann 4d4b6bf3f3 docs: add recommendation to use fsprovider alias in README.md 2021-02-20 03:54:01 +00:00
bcheidemann f12f01dca0 feat: add path shim 2021-02-20 03:38:52 +00:00
bcheidemann 128e10dc13 docs: add webpack section to README.md 2021-02-20 03:36:34 +00:00
bcheidemann ceed84f377 feat: add shim for fs 2021-02-20 02:43:21 +00:00
bcheidemann 2a581726c6 feat: add shims for file system providers 2021-02-20 02:38:43 +00:00
David Humphrey 75f2a70c7b Fix tag and release naming for release-it update 2020-04-13 13:03:11 -04:00
David Humphrey 9db879374d Release 1.2.0 2020-04-13 12:55:50 -04:00
David Humphrey 98683fe261 Update deps, fix new eslint issues, update release-it config 2020-04-13 12:32:17 -04:00
SillyFreak f1fc53d88f resolve relative paths, add two test cases 2020-04-13 11:49:46 -04:00
Rachael Scotchmer 4aae53839a Issue 627 (#746)
* added test to fs.readlink.spec.js

* added test for fs.write() to try and write a file opened without the O_WRITE flag

* added test to fs.write() that attempts to write with a buffer that is too small

* added a test to fs.write() to try and write to a file that doesn't exist

* added more specific summary of test for writing to buffer when length is too long, check the type of error that a test returns

* Adjusted the message on line 69 to be more clear
2019-03-12 15:12:38 -04:00
dcoull 94d5ff8795 Addressed Issue #703 (#711)
* update from var to let and const

* Update from var to let and const

* Update times.spec.js from var to let and const

* Strict mode addition, migrated let usage to const

* Revert changes to package-lock.json
2019-03-05 15:46:23 -05:00
Charles M Drani ee56794601 add test for fs.open with wx flag for existing file (#745)
* add test for fs.open with wx flag for existing file

* update implementation and open spec to throw EEXIST
2019-02-27 11:56:11 -05:00
rscotchmer 914ba8b473 added test to fs.readlink.spec.js 2019-02-26 12:06:41 -05:00
Oleksii Polovyi 2a4fa0f0fd fixed #738: consolidated stats into stat tests (#743)
* fixed #738: consolidated stats into stat tests

* fix for newline and import spacing
2019-02-23 16:42:51 -05:00
ApolllonDev 9d3f220d92 increase test timeout to 10 seconds from 5 seconds 2019-02-23 16:42:03 -05:00
Abdirahman Guled 3d10d6431c Fix #710: updated let to const. 2019-02-15 15:04:04 -05:00
Adel El Masery 7ab6f5e7c6 Update fs.read.spec.js (#741)
* Update fs.read.spec.js

* Update fs.read.spec.js
2019-02-12 16:44:21 -05:00
kwchan19 9487e8ecc6 Issue 728: Updated 'filer/tests/spec/fs.shell.spec.js' to use 'const/let' instead of 'var' (#730)
* Fixes for review comments

* Fixes for review comments

* Fixes for review comments

* Fixes for review comments

* Fixes for review comments
2019-02-12 14:50:57 -05:00
hoaianhkhang e6f8ef2251 Issue #715 Update fs.lstat.spec.js to have proper const and let instead of var and added 'use strict' (#727)
* Update fs.lstat.spec.js

* Update fs.lstat.spec.js

* Update fs.lstat.spec.js

* Update fs.lstat.spec.js

* Update fs.lstat.spec.js

* Update fs.lstat.spec.js

* Update fs.lstat.spec.js
2019-02-12 14:49:20 -05:00
Paul Moon f2201e7a74 Update fs.spec.js to use strict mode and changed var to let (#693)
* Update fs.spec.js

* Update fs.spec.js

Changed global variables

* Update fs.spec.js

changed let to const
2019-02-12 14:46:56 -05:00
otkach 3447ec9c8a Updated file for issue #714 (#732)
* Updated file for issue 714

* Updated file due to review requirements
2019-02-08 15:00:45 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca fe17870a8f Merge branch 'issue-734' 2019-02-08 14:52:57 -05:00
David Humphrey f4e0dce8d3
Merge pull request #733 from PriyankaCodes99/issue-685
issue-685 fix: replaced "var" with "let" in fs.unlink.spec.js
2019-02-08 14:42:53 -05:00
Priyanka Dhiman 34e5580a66 changes made as requested 2019-02-08 11:32:27 -05:00
Aqeel Parpia c515865fb3 [Issue 734] 2019-02-08 05:46:54 -05:00
Aqeel Parpia 4887cc725f issue 734 2019-02-08 05:36:55 -05:00
Aqeel Parpia 3471848b39 [issue-734] 2019-02-08 05:25:26 -05:00
David Humphrey 9b3e567dd1 Release 1.1.2 2019-02-07 22:54:40 -05:00
David Humphrey bf18093661 fs.lstat should return a Stats object including mode 2019-02-07 22:51:52 -05:00
David Humphrey fa3186d322 Release 1.1.1 2019-02-07 16:38:32 -05:00
David Humphrey 8a2e64f9ea Fix #736: use ms vs. s resolution on all times 2019-02-07 16:36:17 -05:00
Alvin Valdez 0ec51a198d Fix for issue-670: Changed var to const (#687)
* Changed var to const

* Added 'use strict' to top of file

* Update stats.js

* Update stats.js
2019-02-05 14:38:59 -05:00
Oleksii Polovyi 317cee5636 Fix issue #672 : Refactor "filer/tests/spec/fs.mkdir.spec.js" to follow ES6 syntax with "const/let" instead of "var" (#722)
* Solution for issue-672

* Removed extra 'use strict';
2019-02-05 14:20:48 -05:00
cmchumak 3c51bbb24f Issue-686 - rfs.mkdtemp.spec.js (#717)
* Replaced 'var' with 'const' where applicable

* Issue-686 - replacing 'var' with 'const', added 'use strict' fs.mkdtemp.spec.js

*  Issue-686 - replacing 'var' with 'const', updated 'use strict' fs.mkdtemp.spec.js
2019-02-05 13:58:01 -05:00
Arash N 9d4b264479 Update errors.spec.js (#718)
* Update errors.spec.js

Updating errors.spec.js to use const/let appropriately instead of var.

* Update errors.spec.js

- Changed corrected 'using' to 'use'.
- Changed 'let' to 'const' becuase the're not being changed during the function scope.
2019-02-05 13:51:29 -05:00
Sahib Arora b5e1d9a82b 'Use strict' @top and updated the file with const/let [issue-702] (#726)
* filer.spec.js var changed to const/let

* let changed to const for a local variable, which is constant through out
2019-02-05 13:46:58 -05:00
Jacob Adach da1aad5667 fixes issue #667 (#678)
* fixes issue 667: Update code in tests/some/fs.write.spec.js to use const/let AND strict mode

* fixes issue 667: Update code in tests/some/fs.write.spec.js to use const/let AND strict mode

* changed let to const for variables pointing to required function

* switched a few variable lets to const in file fs.write.spec.js

* switched a few variable lets to const in file fs.write.spec.js

* added package-lock.json file

* changed variables let to const
2019-02-01 20:53:12 -05:00
Violet-XiaoWeiHuang 05057c45d2 Fix ssue #692: Update code in filer/tests/spec/time-flags.spec.js (#696)
* installed npm

* modified time-flags.spec.js

* Update code to use const/let instead of var

* update the variable type from let to const

* add Strict mode

* review fixed
2019-02-01 15:04:15 -05:00
Rachael Scotchmer 4ba9eded4c Fix Issue 684: Replace var with const, let in filer/tests/spec/filer.buffer.spec.js (#697)
* refactored code in tests/spec/filer.buffer.spec.js

* reverted changes to package-lock.json which shouldn't have been changed

* updated package-lock.json

* trying to fix bug

* roll back changes to package-lock.json, change lets to consts in filer.buffer.spec.js, added new line at the end of filer.buffer.spec.js
2019-02-01 12:45:54 -05:00
Woosle Park 8eaaeeed17 Fix issue #681: Updated filer/tests/spec/filer.filesystem.spec.js (#695)
* issue 681 fix

* issue 681 revision

* issue 681 revision v2
2019-01-31 20:23:57 -05:00
Brandon Wissmann 3b4bf42604 Fixes #662: exchange var for const of require statements in src/filesystem/interface.js (#668)
* exchange var for const of require statements

Changed decleration of import files from var to const in interface.js

* Fixed all areas where var was used as well as use destructing assignment for  CONST imports.

* Fixed import const statement

* Added changes from let to const in certain lines
2019-01-31 20:22:46 -05:00
Harsh Patel 701849eb5a Fixed #707 Replaced var with const and let and added strict mode (#712)
* Fixed #707 Replaced var with const and let and added strict mode

* Fixed src/fs-watcher.js and changed remaining var to let

* Changed src/fs-watcher.js file to use const instead of let at line 52 and 57
2019-01-31 20:20:56 -05:00
DavidLi119 87513997a2 Fixed #708: Added 'use strict' and replaced var with let/const in fs.appendFile.spec.js (#713)
* Add files via upload

* Add files via upload

* Revert "Add files via upload"

This reverts commit 214977d8bf.

* Update fs.appendFile.spec.js

* s

* Revert "s"

This reverts commit 8aa5cbbbd6.

* Changed all `let` to `const`

As informed, all variables will not change at all in this file, therefore all `let` declarations have been changed to `const`
2019-01-31 18:42:50 -05:00
bonbon12 1e660a9d07 Fixed #699 Replacing var with let/const and adding strict mode (#706)
* Updated File to use let/const and strict mode

* Update path-resolution.spec.js

* Updated path-resolution.spec.js

Upon review and further inspection, there was a realization that there was need for the "let" variable as all variable were not modified.
Instead, "const" was used.
2019-01-31 16:42:38 -05:00
Iryna Thompson 3f619fdcb8 Fixed #665: Replaced var with let or const and added strict mode fs.a… (#688)
* Fixed #665: Replaced var with let or const and added strict mode fs.access.spec.js

* Replaced let with const

* Replaced all let with const
2019-01-31 16:08:19 -05:00
Vincent Logozzo 43bba422d9 fixed Issue-689 indexedDB.js (#700)
* CRLF replaced with LF

* package changes to run tests

* updated local varriables to use let and const instead of var

* reverted dependency changes
2019-01-31 15:40:09 -05:00
Priyam Brahmbhatt 7e46fcde8f updated environment.js to use const insted of var for constant property (#709)
* updated environment.js to use const insted of var for constant property

* Added use strict
2019-01-31 15:32:57 -05:00
OlenaVyshnevska fc545ee3c7 code refactoring, added strict mode (#704) 2019-01-31 15:25:57 -05:00
Yuansheng Lu e5481efa9b Fix issue #660: Updated the code to replace var with let, const in strict mode (#694)
* Modify the test file to fix issue-660

* change let to const
2019-01-31 15:11:07 -05:00
Vladimir Rozin 5918cf6ae7 changed fs.watch.spec.js according to filed issue-666 (#680) 2019-01-31 14:12:08 -05:00
jatinkumar 0380a8153c Fixed #667: Replaced var with const and added strict mode in fs.readdir.spec.js (#675)
* Replaced var with either const or let and added strict mode in fs.readdir.spec.js

* Replaced let with const
2019-01-31 14:07:31 -05:00
Nathaniel Ngo 4a39dcc2f0 Fixes Issue#674: Refactored var declarations to const or let declarations to address i… (#676)
* Refactored var declarations to const or let declarations to address issue#674

* refactored let to const when variable does not change values
2019-01-31 14:00:48 -05:00
andrewkoung 4de0bbfafd Fixes #661: replaced var with const (#669)
* replaced var with const for the most part

* Update fs.symlink.spec.js

fixed line 93 and added strict mode
2019-01-31 13:52:39 -05:00
Priyanka Dhiman 7cdef6d963 replaced var with let 2019-01-30 22:27:11 -05:00
David Humphrey 26b47ee094
Remove src/encodings.js, use Buffer methods instead (#657) 2019-01-03 10:46:31 -05:00
David Humphrey 5f10cc2fde Add test API to shim indexedDB when necessary for better coverage 2019-01-03 00:08:22 -05:00
David Humphrey 4e9593f5e8 Bump license date to reflect 2019 activity 2019-01-02 23:20:41 -05:00
David Humphrey 01d76ba0df Update keywords to remove WebSQL 2019-01-02 23:20:19 -05:00
David Humphrey dd7536827b Release 1.1.0 2019-01-02 23:12:19 -05:00
David Humphrey c6e1d51612 Reorder method order to match node's lib/fs.js, document missing 2019-01-02 23:09:47 -05:00
David Humphrey c0acdb97d6 Match node's layout for access modes on fs, with tests 2019-01-02 22:23:58 -05:00
David Humphrey f4ff2e9ed9
Add Filer.fs to support creating a filesystem like node.js (#651)
* Add Filer.fs to support

* Update README code examples, add tests, also expose Path as path
2019-01-02 21:21:25 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca 85a8c21dc1 Support file:// URLs and Buffers for path args, throw when invalid 2019-01-02 19:46:36 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca 9c13a2d248 Update package-lock.json 2019-01-02 18:08:27 -05:00
David Humphrey 1ad81f9bae Remove WebSQL provider (last supported in v0.0.44) 2019-01-02 13:22:51 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca bc861bfd4a Move open files to its own module, properly close fds in tests 2018-12-29 15:11:39 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca 11c91acdcf Move device name off fs and onto context 2018-12-29 15:11:39 -05:00
David Humphrey ace4222a82 Update npm deps 2018-12-22 17:24:10 -05:00
David Humphrey 7301024382 Fix #646: add tools/get-filer-version.js to find old Filer versions 2018-12-22 01:02:04 -05:00
David Humphrey 6ec8cd6191 Fix #612: add way to run tests in node, fix docs on running tests 2018-12-21 23:44:59 -05:00
David Humphrey 52baa2523d Release 1.0.2 2018-12-21 23:09:29 -05:00
David Humphrey d4bfcd71c2 Fix #602: fix mode masking issues, correct X_OK case in fs.access 2018-12-21 23:07:33 -05:00
David Humphrey 4f427ed8d7 Update package-lock.json 2018-12-21 22:04:07 -05:00
David Humphrey 22731267a9 Update README for changes in 1.0.x 2018-12-21 15:28:58 -05:00
David Humphrey 9cb4ff7c0a Release 1.0.1 2018-12-21 14:47:00 -05:00
David Humphrey 3dea503289 Include src/ and lib/ in npm package 2018-12-21 14:45:15 -05:00
David Humphrey 909a66efd7 Release 1.0.0 2018-12-21 14:33:38 -05:00
David Humphrey ea236cf43b Fix what we ship in dist/ to match current build 2018-12-21 14:22:25 -05:00
David Humphrey f053c738b8 Fixes to release-it config and npm files 2018-12-21 14:15:45 -05:00
David Humphrey 3afbcca8b3 Fix env.sample format 2018-12-21 13:56:29 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca b4c3d1f1ae Remove old config/ dir used by grunt 2018-12-21 13:32:29 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca 3f400d17bf Add release-it, config, docs, remove gruntfile.js 2018-12-21 13:32:29 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca 1f3b9e79bf Add .npmignore to slim down npm package 2018-12-21 13:32:29 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca bfe4385a83 Fix #633: fix test failure in coverage run 2018-12-20 19:00:39 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca 5cc21c72fb Fix #639: run tests on Linux and Mac 2018-12-20 18:17:34 -05:00
Julia Yatsenko 9f7f93776e fix #635: added test for fs.ftruncate() 2018-12-20 15:07:17 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca 69758613db Stop npm from spamming on test failures 2018-12-18 11:24:41 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca 1ae7a220b4 Run migration tests by default after browser tests 2018-12-18 11:04:13 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca b5fe85caaa Fixes to pass 0.43 migration test 2018-12-18 11:04:13 -05:00
David Humphrey d0178539f5 Refactor Node to support layout changes with backwad compatibility 2018-12-18 11:04:13 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca f738cbc17d Fix #605: add migration tests for Filer 0.43 2018-12-17 21:29:53 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca b7312bfa1e Fix how mode gets processed when building images (only use permission bits). 2018-12-17 20:03:23 -05:00
Vince b0809272a1 Included unwatchFile in test index.js
Co-authored-by: David Humphrey <david.humphrey@senecacollege.ca>
2018-12-17 16:39:44 -05:00
Vince fb76c0ec1e Fix #445 test cases for fs.unwatchFile 2018-12-17 16:39:44 -05:00
qwang135 9a7d3514d8 Fix #514: add test for fsPromises.lstat with directory
Co-authored-by: David Humphrey <david.humphrey@senecacollege.ca>
2018-12-17 16:30:21 -05:00
Yuecheng Wu 848cc7d3de Adding more tests for fs.copyFile
Co-authored-by: David Humphrey <david.humphrey@senecacollege.ca>
2018-12-17 16:18:06 -05:00
David Humphrey ba188169d6 Review fixes, skip copyFile test for now 2018-12-17 16:06:24 -05:00
mordax 62cbe11a93 Fixed lint issues in copyFile test 2018-12-17 15:56:55 -05:00
mordax ef80713c33 Added tests for future fs.copyFile implementation and adjusted index.js to run it. 2018-12-17 15:56:55 -05:00
Alexei Kozachenko 0eb7066a86 Added mkdtemp method (issue #441)
Added/fixed mkdtemp method (issue 441)

Added/fixed mkdtemp method (issue 441)

Added/fixed mkdtemp method (issue 441)

fixed a typo

Added mkdtemp method description to readme

Unit tests for mkdtemp method added (issue #394)

Added generateRandom(), randomChars() to shared.js. Corrections in README. Fixes for mkdtemp method

cleaned up mkdtemp()

fixed regex

Fix for failing test (humphd)
2018-12-15 00:39:09 -05:00
David Humphrey 158f6241b6 Fixes from #504 to pass lint, travis 2018-12-15 00:17:43 -05:00
Dan Lin 4a5d8c1222 Fix #456 - add test for fs.write() with undefined path 2018-12-15 00:14:13 -05:00
kwkofler 443b582038 Issue #86: Added support for Unix Timestamps
Co-authored-by: David Humphrey <david.humphrey@senecacollege.ca>
2018-12-14 23:58:42 -05:00
David Humphrey 83bd64fd58 Fix lint issues in #521 2018-12-14 22:18:25 -05:00
imedqq 783e7a9e67 Added newline at end of file 2018-12-14 22:18:25 -05:00
imedqq 2aa6cf2b5f Added promise-based test cases for rmdir 2018-12-14 22:18:25 -05:00
David Humphrey acef2c93b0 Update https://github.com/filerjs/filer/pull/485 to master, add tests + fix. 2018-12-14 22:05:51 -05:00
Deepanjali Gerangal 94fd5ba829 Fix#418-updated method 2018-12-14 19:24:55 -05:00
Deepanjali Gerangal e3a285ae54 fix #418 test for fsPromises.truncate(path[, len]) to test when length is negative 2018-12-14 19:24:19 -05:00
Petr Bouianov 1775c24d37 Fixes issue 75
As the array flags were already reflected in the README documentation
and example, this only required a test
2018-12-14 17:31:31 -05:00
chen yuzhou 3d7ff3e08d Store and reuse the file path 2018-12-12 22:24:11 -05:00
chen yuzhou 1e1c704f7e fix the callers in src/node.js to the correct versio 2018-12-12 22:24:11 -05:00
chen yuzhou e1124993ba Remove duplicate stat.h constants defined in constants.js 2018-12-12 22:24:11 -05:00
David Humphrey 97d2d1bfe3 Fix bug uncovered by new invalid flags test: missing return 2018-12-12 22:09:41 -05:00
David Humphrey 2841b2eba7 Fixes from review 2018-12-12 22:09:41 -05:00
Mera-Gangapersaud 0352dad66c Corrected Travis CI error for issue 500 2018-12-12 22:09:41 -05:00
David Humphrey 307fc3e32c Fix security issue with parcel, update to 1.10.3 2018-12-12 21:53:00 -05:00
David Humphrey 33339b81d7 Fix review issues 2018-12-12 21:38:16 -05:00
Adam 7e941bb304 Update fs.symlink.spec.js 2018-12-12 21:38:16 -05:00
Adam db237e617b update fs.symlink.spec.js based on code review
white spaces , comments added, Promises.Open used
2018-12-12 21:38:16 -05:00
Adam bb9dd2e67c Update README.md 2018-12-12 21:38:16 -05:00
Pooch11 0a1aa0fecc Added tests for symlink using promises api 2018-12-12 21:38:16 -05:00
Pooch11 d894a4cf16 readme dummy changes 2018-12-12 21:38:16 -05:00
David Humphrey 16e6b3e1c9 Fix review issues 2018-12-12 21:31:27 -05:00
Dragomegak af3815c54b Removes Symbolic Link check & Fixing Mixing Callbacks and Promises (Basically the fs.link test though) 2018-12-12 21:27:13 -05:00
Dragomegak 0748951ca8 Changed code to reflect promise syntax 2018-12-12 21:27:13 -05:00
Dragomegak 265f0b1d0d Added fsPromises.link() tests 2018-12-12 21:27:13 -05:00
David Humphrey 1c450ae8e7 Fix review nits, move contents to earlier scope and reuse. 2018-12-12 21:08:30 -05:00
PopeSpaceous 0395c4beae Fix issue-447: Added test to append numbers in fs.appendFile function 2018-12-12 21:08:30 -05:00
jagmeetb 1abcb0369b Fix #431: add test for fsPromises.unlink
add newline at end

implemented suggestions

formatting fixes
2018-12-12 20:59:41 -05:00
David Humphrey d1dd5fef61 Finishing work in #401 2018-12-10 23:57:10 -05:00
Josh Mayers e85880dc8b Fix Issue #399 - added test cases for appendFile with promises 2018-12-10 23:57:10 -05:00
David Humphrey 97a6004091
Fix #604: cli for buidling JSON image from folder (#613)
* Fix #604: cli for buidling JSON image from folder

* Allow passing --filer to specify a filer module to use (different version)

* Deal with fs.chown not existing on older versions of Filer

* Tidy up some loose ends

* Make fs-image.js executable
2018-12-06 22:22:18 -05:00
chen yuzhou 0e75661b4b Remove fs.exists() console spam 2018-12-05 16:23:11 -05:00
David Humphrey 5218057d80 Follow-up from #603, rename ImportExportProvider to SerializableMemoryProvider 2018-12-05 10:18:31 -05:00
David Humphrey 61a1f5e020 Fix #603: add import/export provider to work with JSON fs images 2018-12-04 22:54:29 -05:00
Deepanjali Gerangal 0f93a04e40 Fix for issue #561 - Extend fs.access to support R_OK, W_OK, and X_OK (#601)
* added extended test for fs.access

* making requested changes
2018-12-03 23:08:40 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca 0f94c476e7 Fix #597: use built-in path-browserify via Parcel vs. our own path.js 2018-12-03 16:39:04 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca 0ed97864ec Add karma summary reporter 2018-12-02 10:25:25 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca f5678ebe20 Rebase and rework test, skip() for now, see #594 2018-12-02 10:19:43 -05:00
kwkofler 97fb82769a Issue #158 - Added test to ensure that watchers monitoring hardlinks are notified when the original file is updated 2018-12-02 10:19:43 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca 7d196763f8 Update docs, fix test failure 2018-12-02 00:05:57 -05:00
kwkofler 6a5d9073f3 Issue 87 - Added fs.fsync() as a no-op, and added tests. Modified documentation.
Made requested changes to tests, functionality; reverted doc changes
2018-12-02 00:05:57 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca a107fe21d7 Fix #337: Pick up sedge's changes from 3c49743559 2018-12-01 22:20:09 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca d7945d745d Fix #577: deal with promise exceptions and test console spam 2018-12-01 22:07:24 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca 923b999e89 Fix #547: update Buffer use, docs, tests to match node.js v11.3.0 2018-12-01 20:05:05 -05:00
David Humphrey 9acedc2beb (no bug) Update CONTRIBUTING.md to reflect test changes 2018-12-01 12:50:04 -05:00
David Humphrey 395406609d Add Headless Firefox test support, fix failing truncate test in Firefox 2018-12-01 12:38:39 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca cc6e3f7edf Increase coverage: check for non-int with chown/fchown 2018-11-29 22:47:26 -05:00
David Humphrey 43d2632069 Improve coverage: add test for rel paths with symlink 2018-11-29 16:57:06 -05:00
David Humphrey 7ab229a64c Fix #572: remove lib/nodash.js, use builtins instead 2018-11-28 22:54:31 -05:00
yatsenko-julia f57c7330d3 fix #556: added tests for fs.ftruncate method (#557)
* fix #556: added tests for fs.ftruncate method

* Update fs.ftruncate.spec.js
2018-11-28 22:42:17 -05:00
David Humphrey 89cfef0f07 Remove dead code in src/shared.js u8toArray() 2018-11-28 22:23:51 -05:00
David Humphrey d1cf1286cb Fix #576: remove unnecessary methods from fs.promises, adjust tests to match 2018-11-28 19:42:32 -05:00
David Humphrey 2135ee17e9 Update fs.stat.spec.js to not have uncaught exception on promise 2018-11-28 19:41:46 -05:00
David Humphrey 725bfbf30c
Fixes #422: Add nyc lcov-based code coverage for tests (#565)
* Add nyc lcov-based code coverage for tests

* Add codecov to travis

* Add codecov badge to README
2018-11-28 19:24:03 -05:00
yuzhouChen 89626107cc Fix #568: switch all stats.type checks in tests/ to use is*() methods (#581)
* Fix Issue#568

* Fix issue 568: two more file changes

* Fix issue 568: more changes in tests/spec/shell/ls.spec.js
2018-11-28 13:54:20 -05:00
Susan Truong a25d71b524 Fix #435: add a test for fsPromise.unlink() to delete a file that does not exist
Make changes to `fsPromises.unlink()` to be more promise-friendly

Added a newline to the end of the file

Made a change to fsPromises.unlink() to be more friendly

Changed the description of the promises test
2018-11-27 13:18:39 -05:00
Alan K d1afe9719d
Merge pull request #476 from steaward/issue-420
Fixes #420
2018-11-22 01:46:52 -05:00
Deepanjali Gerangal 400b2c3c88 Fix #558 - Implementing fs.access() method (#560)
* Implementing fs.access() method

* added new line to access.js

* updated requested changes

* updated README.md with fs.access

* fixing truncate error

* updated README.md

* changed access.js to access.spec.js
2018-11-17 15:31:20 -05:00
David Humphrey ea95badc5b Update dist/ built versions of Filer 2018-10-30 14:35:33 -04:00
Rikku-x a5fc0e699a #541 Grammatical error (#554) 2018-10-20 17:00:03 -04:00
Alexander Ponomaroff ce030b91fa Fix issue #398 - Add testing for promises to all test cases in fs.writeFile-readFile.spec.js file (#402)
* Fix issue #398 - Add testing for promises to all test cases in fs.writeFile-readFile.spec.js file

* Fix issue #398 - Add testing for promises to all test cases in fs.writeFile-readFile.spec.js file

* Fixed requested issues

* Further Improvement
2018-10-20 16:59:26 -04:00
Deepanjali Gerangal 5568c27bec fix for #542 for fsPromises.symlink(target, path[, type]) (#543)
* updating fs.symlink for promises

* updated the requested changes

* fix#542 added a newline at end
2018-10-20 16:57:45 -04:00
Volodymyr Klymenko bfcb5a6a94 Added tests for Promises version of mkdir (#415) 2018-10-16 19:27:12 -04:00
ThomasNolte 3bbabfcb4a added tests for fs.promises.chown() closes #465 (#471)
* added tests for fs.promises.chown() for check if function exists and updating gid/uid for a file

* update to pass lint tests

* cleaned up code. replaced all callbacks with promises in new test.

* Revert "lint tests fix"

This reverts commit 3c256124cf, reversing
changes made to 71a6f514fc.

* Revert "cleaned up code. replaced all callbacks with promises in new test."

This reverts commit 71a6f514fc.

* Made requested changes.
2018-10-16 11:43:59 -04:00
Shawn Pang 1eab5f0ffd Fix#461 - Added test for fs.read when attempting to read a file that does not exist (#472)
* Added test for fs.read when attempting to read a file that does not exist

* Added test for fs.read when attempting to read a file that does not exist

* Modified read test for non-existent file to act more similar to earlier tests

* Added check in read test for error code
2018-10-16 11:22:54 -04:00
yatsenko-julia 73f0f19bb9 Fix #523: added tests for fs.ftruncate() (#524)
* Fix #523: added tests for fs.ftruncate()

* fix #523: moved a function from truncate to ftruncate and made a few minor changes

* Fixed indentation
2018-10-16 11:21:49 -04:00
bblarney 707d404db0 Issue 417 - Added test for fs.promises.rename to rename existing directory (#460)
* test added

* working so far

* done

* cleaned up a catch

* made some requested changes
2018-10-16 11:07:10 -04:00
VictorKubrak a447b2dd45 rename() should be able to rename an existing file to the same filename (#502)
* rename should not change name to itself

* new test expects failure

* should rename an existing file to itself

* should rename an existing file to itself

* Update tests/spec/fs.rename.spec.js

* add .skip to the test
2018-10-16 09:43:44 -04:00
AHKol 8aa8dda4d6 Fix #411: Tests if event is thrown when calling rename (#478)
* Fix #411: Tests if event is thrown when calling rename

* npm run lint:fix

* Added comment explaining lack of 'rename' event check
2018-10-15 16:33:47 -04:00
Stephen Ward 08b0b3001e removed pre-existing comment about open() 2018-10-10 22:48:13 -04:00
Stephen Ward 675773b92a re-added the newline, as well as another test case to make sure mode is still set to default value when a new file is opened 2018-10-10 15:10:34 -04:00
Janice 41510e7da4 Fix issue 529 (#530)
* Fix issue 529

* Fix Issue 529

* Fix issue 529 and some indentations

* fix arrow function instead of function expression

* Fix issue529

* Fix issue529

* Saving files before refreshing line endings

* done

* push again

* change sth

* changed
2018-10-09 21:17:25 -04:00
jrkong b1c4f04f83 Removed outdated about permission functions in README.md (#513) 2018-10-09 20:53:32 -04:00
Stephen Ward ee67cb39de rolled back the package-lock.json to master's version 2018-10-09 20:34:09 -04:00
Stephen Ward e11c101600 forgot a semicolon 2018-10-09 20:28:46 -04:00
Stephen Ward 7a6a4160e6 made changes as per thomas's and dave's PR review 2018-10-09 20:25:19 -04:00
pynnl c33f22b464 Issue 396 - Add a test for fs.promises.stat() when the path does not exist (#406)
* test non exist path for promise

* fix new line at the end

* fix missing semicolon 113:26

* follow 'Testing promise codes' on guidline
2018-10-09 17:40:35 -04:00
Julia McGeoghan 389dedd3c0 Fix #421 - Add test for fs.promises.link to ensure it returns a Promise (#462)
* Add test

* Move location of describe block

* Remove comment

* Have test check returnValue and not obj

* Override package-lock.json with one from master branch

* Improve naming of fsPromise variable to be more clear
2018-10-09 17:35:28 -04:00
yuzhouChen 8504cc7e2a Issue497 Add test for fs.chmod when the path is invalid (#525)
* Fix #497 Add test for fs.chmod when the path is invalid

* Fix #497 All test passed
2018-10-09 17:30:36 -04:00
yevseytsev 27659d45da 491 (#501)
* mkdir - restricted symbols('?' only)

* FINAL
2018-10-09 17:28:14 -04:00
Stephen Truong 934ef8bfa7 Fix #419: Add test for fsPromises.open() when the path does not exist (#455)
* Fix #419: Add test for fsPromises.open() when the path does not exist

* Update package.json

* Fix #419: Add test for fsPromises.open() when the path does not exist

Removed some unnecessary code based on reviews

* Update fs.open.spec.js
2018-10-09 16:00:56 -04:00
Ruihui Yan c7ea45a18b Fix issue #475 - Add test for fs.exits() when resulting path of a symbolic link is not found (#519)
* add test for exits when resulting path of a symbolic link is not found

* fixed style nit
2018-10-09 14:31:15 -04:00
Sean 009821290f Fixes #499: Update functionality for fs.truncate (#533)
* Fixes #499: Update functionality for fs.truncate

This change to fs.truncate()'s functionality throws an error when the
length to truncate by is a non-numeric string.

* Refactor numeric type validation

As node implements a helper function to validate numeric values, let's
replicate the same logic to use throughout Filer.
2018-10-09 13:53:26 -04:00
Thanh Nguyen 2f3c384868 Add test for fsPromises.rmdir() when dir not empty and dir is a file, Fix Issue 474 (#510)
* Saving files before refreshing line endings

* Adding test case for returning an error if the path is not a directory

* Add return for fsPromises, and few other small fixes

* Fix promises, and few done parameter

* Update fs.rmdir.spec.js
2018-10-09 13:51:19 -04:00
giantpanpan beea03dbae Add test for fs.writeFile-readFile.spec to write a file in non-existing path (#486) 2018-10-09 13:48:51 -04:00
ywpark1 3e0da99040 Fix issue-426: Add the test for fsPromises.readdir when the path exists, and is a directory (#452) 2018-10-09 13:32:09 -04:00
dleung25 02bd6d8a62 Issue#518 fix: Add test for fsPromises.unlink() should be a function (#526)
* issue518 fix

* changed back to original package.json

* add newline to end of file
2018-10-09 13:27:22 -04:00
Jeffrey Espiritu 7e27c8be2c Fix Issue #400 - add test for passing file to fs.promise.readdir() (#409)
* Fix Issue #400 - add test for passing file to fs.promise.readdir()

This adds a test to ensure that `fs.promise.readdir()` throws an error when passing in a file.

* Made changes to `fsPromises.readdir` to be more promise-friendly
2018-10-09 13:04:19 -04:00
Casva e77361107e Issue 427 - Add tests to fsPromises.rmdir when directory doesn't exist and when trying to delete root directory (#457)
* Fix #427 - Fixed indentation and ENOENT -> EBUSY on line 120

* Deleted extra line at the end of document

* Fix #427 - Added tests for fsPromises.rmdir when trying to remove a nonexistent directory and when trying to remove root directory
2018-10-09 13:02:01 -04:00
Daniel Bogomazov 87230ce1e3 Fix #405 - Added tests for chmod and fchmod using Promises (#458)
* Added tests for chmod and fchmod using Promises

* Remove unrelated files from pull request

* Fixed spelling mistake

* Removed redundant catch blocks
2018-10-09 12:59:17 -04:00
Huda Al Dallal 2e2e2f9d64 Fixed issue#480 using promises to test fs.truncate when path does not exist (#516)
* added a test for issue#480 using promises to test fs.truncate

* Fixed issue#480 tesing fs.truncate using promises when path does not exist
2018-10-09 12:56:20 -04:00
rdittrich97 0354c7e13e Fix #423: added proimse support for fs.stat (#432)
* added promise support to fs.stat

* restored package lock

* fixed lint issues

* made tests more promise freindly

* removed .catch statement from promise and fixed style issues

* removed .catch statement from promise and fixed style issues
2018-10-09 12:54:40 -04:00
y2s82 1156f420c4 Fixed #424 - implement fs.promises.read tests (#429)
* implemented first two tests of fs.promises.read

* simplified the 2nd fs.promises.read test

* implemented test on file position update for fs.promises.read

* implemented directory read failure test for fs.promises.read

* implemented test to check the return type to be a Promise in fs.promises.read

* fixed indentation and also fixed a catch statement to allow all code to be reachable

* made tests more promise-friendly

* applied some style changes and test changes as per @rdittrich97 suggestions

* removed lines that are unnecessary for promise-based testing and syntactically simplified some function definitions

* removed more unnecessary check lines in directory check fail test
2018-10-09 12:51:59 -04:00
Nick Skuybeda 86b6b2a907 Fixed Issue #483 for a test done for fs.mknod promise (#509)
* test done for fs.mknod promise

* fixing whitespaces
2018-10-09 12:43:45 -04:00
Chaya Danzinger a8759b1e38 Add tests for fs.promises utimes function #527 (#540)
* first two promise tests initial commit

* implemented existing tests but with promises

* add final tests

* add return statement for remaining tests

* fix function call error
2018-10-09 12:39:18 -04:00
David Humphrey c84dd14f5e
Merge pull request #395 from humphd/issue-393
Fix #393: add test for truncate with length undefined
2018-10-03 18:13:08 -04:00
rhayes2 31b3c40d74 Line ending fix 2018-09-25 00:35:46 -04:00
rhayes2 7a716e033b Add chmod --test for chmode mode value 2018-09-25 00:31:49 -04:00
rhayes2 395de63751 aDD Chmod --test for chmod 2018-09-25 00:29:33 -04:00
rhayes2 7f155a0f40 Add chmod test with incorrect mode value 2018-09-25 00:27:31 -04:00
rhayes2 294685d6cb Style fix 2018-09-25 00:15:07 -04:00
Stephen Ward 62b85d1442 i did it again...forgot to remove an unused variable so travis-ci test failed. 2018-09-24 23:32:11 -04:00
Stephen Ward 30752c9109 added a test: open a new file for writing, and set a mode for that file 2018-09-24 23:28:56 -04:00
Stephen Ward f3a7170133 removed an unused variable, because I was using it for those console.logs which I just deleted 2018-09-24 19:17:19 -04:00
Stephen Ward 833ac62c45 removed some console.logs because travis-ci complained 2018-09-24 19:14:08 -04:00
Stephen Ward 78b3452d5d added the addition of an optional mode when opening a file, removed my test because it was broken. Seemingly passes all the other tests still. STILL TO DO: add a proper test which makes sure the mode is set. 2018-09-24 19:10:09 -04:00
Stephen Ward e7811eb53b fixed lint spaces/indentation errors 2018-09-24 17:46:01 -04:00
rhayes2 546b4567d2 Added Test for CHMODE 2018-09-24 14:16:16 -04:00
Corey James e3a1187ef9 Fixed the fs.read() example in doc. The error checking statements were using the wrong variable name (#449) 2018-09-24 14:08:49 -04:00
rhayes2 499c72daaf saving for lineending dumbness 2018-09-23 21:19:57 -04:00
Stephen Ward add00ce563 testing out the validateAndMask() function, with console.log's... 2018-09-23 13:49:00 -04:00
David Humphrey (:humph) david.humphrey@senecacollege.ca 5e4de6b698 Fix #393: add test for truncate with length undefined 2018-09-17 18:30:09 -04:00
0xazure fd3de6be2c Update karma dev dependency
Resolves `npm audit` warnings about 1 low, 5
moderate vulnerabilities related to versions before
karma@3.0.0.

Closes #384.
2018-09-12 21:43:58 -04:00
Dmytro 353290a08f Adding support for promises. Closes #379, #382 (#380)
* adding promise-based filedescriptor

* fixing promisify dep

* promisifying shell

* deprecating 'exists' method on fs

* adding docs

* fixing docs

* removing redundant code.
2018-08-27 19:50:41 -04:00
Alan K de45918cbc
Merge pull request #378 from humphd/karma
Automate tests using Headless Chrome + Karma runner
2018-08-21 14:54:48 -04:00
David Humphrey 53f5b0c50b Fix script names in package.json 2018-07-27 11:23:27 -04:00
David Humphrey 7798b1cb87 Fix lint issues in implementation.js 2018-07-27 11:23:06 -04:00
David Humphrey 0da0e60194 Fix lint issues in interface.js 2018-07-27 11:17:45 -04:00
David Humphrey dc8fa4cb96 Fix lint issues in node.js 2018-07-27 11:17:03 -04:00
David Humphrey 3a44c1756a Fix lint issues in src/path.js 2018-07-27 11:16:30 -04:00
David Humphrey 8d553b78e0 Fix lint issues in indexeddb.js provider 2018-07-27 11:14:08 -04:00
David Humphrey b92151cdc5 Fix lint issues in websql.js provider 2018-07-27 11:13:40 -04:00
David Humphrey bcf4d9834a Don't build source map for karma test bundle 2018-07-27 11:12:25 -04:00
David Humphrey ed11b01234 Fix lint issues in shell.js 2018-07-27 11:12:06 -04:00
David Humphrey 0980ec4608 Fix lint issues in issue258.js 2018-07-27 11:09:45 -04:00
David Humphrey a31044cc8d Fix lint issues in issue267.js 2018-07-27 11:08:40 -04:00
David Humphrey 454d5bc801 Fix lint issues in ls-depth-bug.js 2018-07-27 11:07:17 -04:00
David Humphrey d41885e9d0 Fix lint issue in tests/lib/indexeddb.js 2018-07-27 11:03:43 -04:00
David Humphrey 0e00af661a Fix lint issues in fs.appendFile.spec.js 2018-07-27 11:02:42 -04:00
David Humphrey f89b616fdc Fix issues in fs.chmod.spec.js 2018-07-27 11:01:47 -04:00
David Humphrey cbcddee3be Fix lint issues in fs.chown.spec.js 2018-07-27 11:01:26 -04:00
David Humphrey 1a738dd2bb Fix lint issues in fs.close.spec.js, fs.link.spec.js 2018-07-27 11:00:48 -04:00
David Humphrey 9e08d96c96 Fix lint issues in fs.lstat.spec.js 2018-07-27 10:44:42 -04:00
David Humphrey 980d5d0917 Fix lint issues in fs.lseek.spec.js 2018-07-27 10:43:51 -04:00
David Humphrey a8e373e4b9 Fix lint issues in fs.mknod.spec.js 2018-07-27 10:39:34 -04:00
David Humphrey 86e57d60db Fix lint issues in fs.open.spec.js 2018-07-27 10:38:44 -04:00
David Humphrey 054094c852 Fix lint issues in fs.read.spec.js, fix test failure in fs.stats.spec.js 2018-07-27 10:37:45 -04:00
David Humphrey cafff52c3a Fix lint issues in fs.rename.spec.js 2018-07-27 10:34:21 -04:00
David Humphrey 1c7b40c895 Fix lint issues in fs.stats.spec.js 2018-07-26 18:17:05 -04:00
David Humphrey 7258a2913e Fix lint issues in fs.truncate.spec.js 2018-07-26 18:07:50 -04:00
David Humphrey bb8743eda1 Fix lint issues in fs.unlink.spec.js 2018-07-26 18:02:16 -04:00
David Humphrey 94e6a98cb8 Fix lint issues in fs.utimes.spec.js 2018-07-26 18:01:21 -04:00
David Humphrey ee8e2a665a Fix lint issues in fs.writeFile-readFile.spec.js 2018-07-26 18:01:07 -04:00
David Humphrey a93ae13c99 Fix lint issues in fs.xattr.spec.js 2018-07-26 17:56:54 -04:00
David Humphrey ab87c7f14a Fix lint issues in tests-fs-watch.js 2018-07-26 17:54:26 -04:00
David Humphrey 49931722cc Fix lint issues in path-resolution.spec.js 2018-07-26 17:53:02 -04:00
David Humphrey 3e1c3deb51 Fix lint issues in providers.base.js 2018-07-26 17:50:32 -04:00
David Humphrey a8c3fa85db Fix lint issues in exec.spec.js 2018-07-26 17:44:27 -04:00
David Humphrey 51c81edb5b Fix lint issues in touch.spec.js 2018-07-26 17:41:35 -04:00
David Humphrey 8e900a3a88 Fix lint issues in time-flags.spec.js 2018-07-26 17:39:19 -04:00
David Humphrey 4a066064f4 Fix lint issues in times.spec.js 2018-07-26 17:37:26 -04:00
David Humphrey e5b6026b91 Add docs for running eslint/lint scripts 2018-07-15 13:28:04 -04:00
David Humphrey a900d8df6d Add eslint --fix scripts, fix first round of lint errors 2018-07-15 13:25:35 -04:00
David Humphrey 2ad0d0eb8b Automate tests using Headless Chrome + Karma runner 2018-07-15 13:08:56 -04:00
Alan K 04f9c57cd8
Merge pull request #374 from humphd/parceljs
Switch to parceljs for bundling, eslint for linting, drop grunt
2018-07-14 12:49:55 -04:00
David Humphrey e155c2d1a0 Remove unneeded requirejs dep 2018-07-14 11:25:17 -04:00
David Humphrey 9832807dd1 Rebase and update to changes on develop 2018-07-14 11:21:34 -04:00
David Humphrey (:humph) david.humphrey@senecacollege.ca 65bbc17ccb Update package.json + tests/ to support browser property for bundlers, delete old useless tests for AMD 2018-07-14 10:53:23 -04:00
David Humphrey (:humph) david.humphrey@senecacollege.ca c15145cc03 Fix tests so they work and pass with Parcel.js, updated outdated, remove .babelrc 2018-07-14 10:50:43 -04:00
David Humphrey (:humph) david.humphrey@senecacollege.ca d61c61aab8 Switch to parceljs for bundling, eslint for linting, drop grunt 2018-07-14 10:50:22 -04:00
Alan K 2e90fdae0c
Merge pull request #373 from humphd/9p-filer
Update Filer to support Plan 9 virtio filesystem API in v86
2018-07-14 10:21:35 -04:00
David Humphrey 9ded3ea1eb Fixup comment that got removed 2018-07-14 10:02:29 -04:00
David Humphrey 3da99f0133 Update README with new info about additional APIs 2018-07-14 10:02:29 -04:00
David Humphrey 31cd579682 Add updated dist/ built files 2018-07-14 10:02:29 -04:00
David Humphrey b7ecae4af1 Fix typos and clean up for review 2018-07-14 10:02:29 -04:00
David Humphrey 46698f30e2 Add package-lock.json 2018-07-14 10:02:29 -04:00
David Humphrey c71a91f72f Update dist/ with newest stuff 2018-07-14 10:02:29 -04:00
David Humphrey eee8200e23 Remove FirefoxOS hack for https://github.com/humphd/next/issues/59 2018-07-14 10:02:29 -04:00
David Humphrey 1087371fc4 Deal with file type bits in mode when setting permissions via chmod 2018-07-14 10:02:29 -04:00
David Humphrey 4e73ef8d9b Allow relpaths for symlink targets (needed by P9vfs), get rid of path info in Node 2018-07-14 10:02:29 -04:00
David Humphrey 9508833b37 Add chown, fchown, chmod, fchmod and tests. 2018-07-14 10:02:29 -04:00
David Humphrey e77a8bacd3 Add fs.constants and file mode permissions 2018-07-14 10:02:29 -04:00
David Humphrey bf1d0e41d6 Fix bug with stats.name generated from fd, add tests 2018-07-14 10:02:29 -04:00
David Humphrey c526445a43 Fix mode, fs.link, fix other bugs and cleanup 2018-07-14 10:02:29 -04:00
David Humphrey 0aaaeacd1a Update sh.ls and stats to remove bits I don't need, add what I do. 2018-07-14 10:02:29 -04:00
David Humphrey ee412d4abe Restructure layout of node 2018-07-14 10:02:29 -04:00
David Humphrey 9244e9be6e Switch from .mode to .type on nodes 2018-07-14 10:02:29 -04:00
David Humphrey 2efb956411 Switch from MODE_* to NODE_TYPE_* 2018-07-14 10:02:29 -04:00
David Humphrey 93633da622 All basic operations now working in Linux 9P mounted fs 2018-07-14 10:02:29 -04:00
David Humphrey 2e627cfe5b Update Filer for things needed for Plan 9 sharing 2018-07-14 10:02:29 -04:00
Alan K b026537f09
Merge pull request #377 from filerjs/travis-node-update
Changes Node version to 8.11.3
2018-07-13 23:56:47 -04:00
Alan K f771f48e8b Changes Node version to 8.11.3 2018-07-13 23:52:01 -04:00
David Humphrey 2a4674d11f Merge pull request #370 from humphd/fix-indexeddb-transactions
Use transaction per operation in indexeddb.js, fix broken async tests in fs.stats.spec.js
2017-05-25 10:08:54 -04:00
David Humphrey (:humph) david.humphrey@senecacollege.ca 18a470e264 Update dist/ with updated built scripts for code changes 2017-05-25 10:05:32 -04:00
David Humphrey (:humph) david.humphrey@senecacollege.ca 3650b798ed Use transaction per operation in indexeddb.js, fix broken async tests in fs.stats.spec.js
Fixing for review comments

Switch to RW or RO transaction per get/put/delete/clear, better error handling for try/catch cases

Switch back to transaction-per-context for better atomic fs operations.

Move _getObjectStore onto prototype
2017-05-25 10:04:20 -04:00
David Humphrey 6d3cec89ee Merge pull request #369 from bryant1410/develop
Fix broken headings in Markdown files
2017-04-18 10:42:33 -04:00
Santiago Castro 68cbd54524 Fix broken Markdown headings 2017-04-18 02:34:52 -03:00
David Humphrey c8f217fbcd Merge pull request #367 from orthographic-pedant/spell_check/conjunction
Fix typographical error(s)
2015-10-07 14:55:23 -04:00
orthographic-pedant 3ddb877276 Fix typographical error(s)
Changed conjuction to conjunction in README.
2015-10-07 14:47:53 -04:00
Alan K 525e11f203 Suppress console.error message in test case 2015-08-16 13:18:26 -04:00
Alan K ddc41f49a5 Fixed default provider when no query string is passed 2015-08-16 13:14:31 -04:00
Alan K 9f625c0d0f Merge branch 'develop' of github.com:filerjs/filer into develop 2015-08-16 13:03:10 -04:00
Alan K 8325b5a9d7 Add a new 'default' provider option so we can force the memory provider
for testing
2015-08-16 13:02:39 -04:00
Alan K d66114e20c v0.0.44 2015-07-21 14:40:33 -04:00
Kieran Sedgwick 9101db2344 Fixed #360 - Added newly exposed internal modules to release commits 2015-07-21 11:47:17 -04:00
Alan K 4de8bc4b81 v0.0.43 2015-07-16 17:56:12 -04:00
Alan K 047536c013 v0.0.42 2015-07-16 17:51:55 -04:00
David Humphrey 6549a98b6a Merge pull request #359 from humphd/issue357
Fix #357 - Path.resolve() should not crash with missing Path.relative()
2015-06-29 13:05:27 -04:00
David Humphrey (:humph) david.humphrey@senecacollege.ca 03896eef05 Update package.json for node 12.5, browserify, uglify, and build dist/ 2015-06-29 12:29:46 -04:00
David Humphrey (:humph) david.humphrey@senecacollege.ca c85fa1851f Fix #357 - Path.resolve() should not crash with missing Path.relative() 2015-06-29 11:38:51 -04:00
Kieran Sedgwick f338991ace Fixed #352 - Removed `process` from browserified version of filer 2015-06-01 16:42:05 -04:00
Kieran Sedgwick 1df35e1834 Fixed #354 - Add standalone Path and filer-buffer modules 2015-06-01 15:08:23 -04:00
David Humphrey (:humph) david.humphrey@senecacollege.ca a13297449d New built versions of filer for fs.rename() fix 2015-05-12 15:44:26 -04:00
David Humphrey f143ea0ce7 Merge pull request #351 from humphd/rename-dir-trailing-slash
fs.rename() should normalize paths before using, dir vs. dir/
2015-05-12 15:27:05 -04:00
David Humphrey (:humph) david.humphrey@senecacollege.ca 17fb8993c3 fs.rename() should normalize paths before using, dir vs. dir/ 2015-05-12 15:16:32 -04:00
Gideon Thomas e9c4cb6d7a Fix #340 - Set provider type for unit tests in the browser 2015-03-30 10:30:50 -04:00
Alan K 78f9ce824d Merge pull request #347 from sedge/issue313-buildDocs
Fix #313: Update docs to include build tasks
2015-02-05 18:22:37 -05:00
Kieran Sedgwick 4dc2bce59d Update gruntfile to match documentation 2015-01-20 14:59:36 -05:00
Kieran Sedgwick 0f63c0988c First revision complete 2015-01-20 14:56:10 -05:00
Kieran Sedgwick af0698a859 Initial commit 2015-01-16 19:09:45 -05:00
Alan K db4274f1d2 Merge pull request #344 from sedge/issue321-updateVersionNo
Fixed #321 - Make grunt-git point upstream
2015-01-13 11:51:07 -05:00
Kieran Sedgwick 4b01317189 Fixed #321 - Make grunt-git point upstream 2015-01-13 09:54:03 -05:00
Alan K 28e981c0c1 Merge pull request #341 from gideonthomas/issue339
Fix #339 - fs.rename tests fail on the browser
2014-12-17 17:13:09 -05:00
Gideon Thomas 67dba10d49 Fix #339 - fs.rename tests fail on the browser 2014-12-17 15:08:13 -05:00
Alan K 841360de71 Merge pull request #335 from gideonthomas/issue334
Fix #334 - Do not allow fs.link on directories
2014-12-17 14:22:40 -05:00
Gideon Thomas 8c4de99a98 Fix #334 - Do not allow fs.link on directories 2014-12-17 13:30:31 -05:00
Alan K 2347e12db2 v0.0.41 2014-12-17 02:52:53 -05:00
Alan K fbb55c86e6 gitrm can't handle directories :/ 2014-12-17 02:52:20 -05:00
Alan K db23ae2bd2 v0.0.40 2014-12-17 02:48:27 -05:00
Alan K ef9df89517 force rm on tests/ and perf/ for gh-pages 2014-12-17 02:47:48 -05:00
Alan K 4e31547270 v0.0.39 2014-12-17 02:46:41 -05:00
Alan K 830c6adde6 v0.0.38 2014-12-17 02:43:18 -05:00
Alan K 8c0f8eaac8 add tests/ and perf/ to gh-pages update 2014-12-17 02:42:40 -05:00
Alan K 2b6d54cbf4 v0.0.37 2014-12-17 02:35:01 -05:00
Alan K 5798beb99f Merge pull request #338 from filerjs/perf
fix up perf tests
2014-12-17 02:34:18 -05:00
Alan K 9e3f48d783 fix up perf tests 2014-12-16 18:53:29 -05:00
Alan K f812ad406d Merge pull request #333 from yoavgurevich/issue303
Issue #303: Performance Test Fix-up
2014-12-16 01:09:04 -05:00
Alan K 68070d0768 Merge pull request #309 from gideonthomas/issue308
Fix #308 - fs.rename does not work on directories
2014-12-08 14:04:21 -05:00
gideonthomas d28100c422 Fix #308 - fs.rename does not work on directories 2014-12-06 16:34:36 -05:00
yoavgurevich 32265e92d7 PR corrections 2014-12-04 09:23:38 -05:00
yoavgurevich d720f65d23 logic thus far 2014-12-03 18:33:07 -05:00
yoavgurevich b4efa7d2a4 Initial work 2014-12-03 17:25:30 -05:00
Alan K e39129a7f4 Merge pull request #326 from gideonthomas/issue297
Fix #297 - Provide better initialization errors
2014-12-03 00:30:39 -05:00
Alan K f160f540a0 v0.0.36 2014-12-02 13:45:21 -05:00
Alan K d6c77abfa0 Merge pull request #331 from humphd/issue329
Fix #329 - Implement Shell.find()
2014-12-02 11:23:43 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca 21b602ef66 Fix #329 - Implement Shell.find() 2014-11-28 15:05:47 -05:00
Alan K 76d256f744 Merge pull request #330 from humphd/cleanup-callback
Ensure test providers deal with missing callback early
2014-11-27 11:20:50 -05:00
David Humphrey (:humph) david.humphrey@senecacollege.ca 4cdcca1a8d Ensure test providers deal with missing callback early 2014-11-27 10:31:49 -05:00
Gideon Thomas 286074f519 Fix #297 - Provide better initialization errors 2014-11-22 12:47:42 -05:00
Alan K b1cf2d7dfb Merge pull request #325 from gideonthomas/issue256
Fix #256 - fs.read() for dir paths should fail
2014-11-20 12:32:33 -05:00
Gideon Thomas 91f7bf0319 Fix #256 - fs.read() for dir paths should fail 2014-11-16 00:12:53 -05:00
Alan K 1283535d75 Merge pull request #322 from sedge/issue208-dontTorchGhPages
Fix #208 - Prevent grunt publish from destroying the gh-pages branch
2014-11-14 16:07:58 -05:00
Kieran Sedgwick 63f5fdeb6c Fix #208 - Prevent grunt publish from destroying the gh-pages branch 2014-11-14 12:18:36 -05:00
Kieran Sedgwick 0d4110ff6f Fixed #323 - Updated references to "fs.Shell" in the docs and test suite 2014-11-14 12:04:51 -05:00
Alan K f8ca6e8208 Merge pull request #315 from sedge/issue312-bundleTests
Fix #312 - Bundle filer-test.js with gh-pages branch only
2014-11-11 16:39:35 -05:00
Alan K 9612cbcbdc Merge pull request #310 from sedge/issue245-ShellConstructor
Fix #245 - Forced the user to manually instantiate FileSystemShell objec...
2014-11-11 16:36:06 -05:00
Kieran Sedgwick 483d3fef72 Fix #312 - Bundle filer-test.js with gh-pages branch only 2014-11-06 11:24:02 -05:00
Kieran Sedgwick a05faf0b2a Review fixes 2014-11-06 10:31:45 -05:00
Kieran Sedgwick 3178ad9a45 Review fixes 2014-11-04 13:03:49 -05:00
Kieran Sedgwick c4c13c1535 Fix #245 - Forced the user to manually instantiate FileSystemShell objects 2014-11-04 13:03:49 -05:00
211 changed files with 49966 additions and 25057 deletions

1
.eslintignore Normal file
View File

@ -0,0 +1 @@
tests/dist/

36
.eslintrc.json Normal file
View File

@ -0,0 +1,36 @@
{
"env": {
"browser": true,
"commonjs": true,
"es6": true,
"mocha": true,
"node": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 2017,
"sourceType": "module"
},
"rules": {
"indent": [
"error",
2
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
],
"eqeqeq": [
"error",
"always"
]
}
}

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
* text=auto eol=lf

27
.github/workflows/node-js-ci.yml vendored Normal file
View File

@ -0,0 +1,27 @@
name: node-js-ci
on:
pull_request:
branches:
- master
push:
branches:
- master
jobs:
build:
runs-on: ${{matrix.os}}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node: ['14', '16']
name: Node ${{ matrix.node }} on ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- name: Test
uses: actions/setup-node@v2.4.1
with:
node-version: ${{ matrix.node }}
- run: npm install
- run: npm test

12
.gitignore vendored
View File

@ -1,5 +1,13 @@
node_modules node_modules
bower_components
.env .env
*~ *~
dist/filer-issue225.js .vscode
.idea
# Parcel build dirs
.cache
tests/dist
# nyc code coverage
.nyc_output
coverage

1
.npmrc Normal file
View File

@ -0,0 +1 @@
loglevel=silent

17
.release-it.json Normal file
View File

@ -0,0 +1,17 @@
{
"hooks": {
"before:init": ["npm run test"],
"before:bump": ["npm run build"]
},
"git": {
"pushRepo": "git@github.com:filerjs/filer.git",
"tagName": "v${version}"
},
"npm": {
"publish": true
},
"github": {
"pushRepo": "git@github.com:filerjs/filer.git",
"release": true
}
}

View File

@ -1,9 +1,32 @@
sudo: false
language: node_js language: node_js
node_js: node_js:
- "0.10" - "lts/*"
before_install: npm install -g grunt-cli
cache:
directories:
- "node_modules"
os:
- linux
- osx
# Setup headless Firefox and Chrome support
# https://docs.travis-ci.com/user/gui-and-headless-browsers/#Using-the-Chrome-addon-in-the-headless-mode
env:
- MOZ_HEADLESS=1
addons:
chrome: stable
firefox: latest
before_install:
- google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost &
after_success:
- npm install -g codecov
- npm run coverage
- codecov
notifications: notifications:
email: false email: false
irc: "irc.mozilla.org#filer" irc: "irc.mozilla.org#filer"
env:
- "FILER_UPSTREAM_URI=\"default\" FILER_UPSTREAM_BRANCH=\"default\" FILER_UPSTREAM_REMOTE_NAME=\"default\""

View File

@ -5,3 +5,5 @@ Barry Tulchinsky <barry.tulchinsky@gmail.com> (@btulchinsky)
Kieran Sedgwick <kieran.sedgwick@gmail.com> (@sedge) Kieran Sedgwick <kieran.sedgwick@gmail.com> (@sedge)
Yoav Gurevich <ygurevich@ymail.com> Yoav Gurevich <ygurevich@ymail.com>
Gideon Thomas <r.gideonthomas@gmail.com> Gideon Thomas <r.gideonthomas@gmail.com>
Abdirahman Guled <aguled2@myseneca.ca>
Ben Heidemann <ben@heidemann.co.uk>

View File

@ -9,78 +9,67 @@ message and I'll update it.
## Setup ## Setup
The Filer build system is based on [grunt](http://gruntjs.com/). To get a working build system To get a working build system do the following:
do the following:
``` ```
npm install npm install
npm install -g grunt-cli
``` ```
You can now run the following grunt tasks: Next, make sure you have installed Chrome and Firefox, which are needed for
* `grunt jshint` will run [JSHint](http://www.jshint.com/) on your code (do this before submitting a pull request) to catch errors running headless versions of the tests with `npm test`.
* `grunt develop` will create a single file version of the library for testing in `dist/idbfs.js`
* `grunt release` like `develop` but will also create a minified version of the library in `dist/idbfs.min.js`
* `grunt test` or `grunt test-node` will run [JSHint](http://www.jshint.com/) on your code and the test suite in the context of `nodejs`
* `grunt test-browser` will run [JSHint](http://www.jshint.com/) and start a localhost server on port `1234`. Navigating to `localhost:1234/tests/index.html` will run the test suite in the context of the browser. **NOTE:** When finished, you will have to manually shut off the server by pressing `cmd/ctrl`+`c` in the same terminal session you ran `grunt test-browser`.
Once you've done some hacking and you'd like to have your work merged, you'll need to
make a pull request. If you're patch includes code, make sure to check that all the
unit tests pass, including any new tests you wrote. Finally, make sure you add yourself
to the `AUTHORS` file.
=======
### Releasing a new version
=======
`grunt publish` will:
* Run the `grunt release` task
* Bump `bower.json` & `package.json` version numbers according to a [Semver](http://semver.org/) compatible scheme (see ["How to Publish"](#how-to-publish) below)
* Create a git tag at the new version number
* Create a release commit including `dist/filer.js`, `dist/filer.min.js`, `bower.json` and `package.json`
* Push tag & commit to `origin/develop`
* Update the `gh-pages` branch with the contents of the `develop` branch
* Force push the `gh-pages` branch to `origin/gh-pages`
* Publish the new version of the module to NPM
#### How to configure
1. Copy `env.sample` to `.env`
2. Modify as needed, or leave alone for defaults
#### How to Publish
`grunt publish` can be run in four ways:
1. `grunt publish` - does a patch (x.x.X) bump
2. `grunt publish:patch` - also does a patch (x.x.X) bump
3. `grunt publish:minor` - does a minor (x.X.x) bump
4. `grunt publish:major` - does a major (X.x.x) bump
The user *must* be on their local `develop` branch before running any form of `grunt publish`, or else the task will fail loudly.
=======
## Tests ## Tests
Tests are writting using [Mocha](http://visionmedia.github.io/mocha/) and [Chai](http://chaijs.com/api/bdd/). Tests are written using [Mocha](https://mochajs.org/) and [Chai](http://chaijs.com/api/bdd/).
You can run the tests in your browser by running `grunt test-browser` and opening the `tests` directory @ `http://localhost:1234/tests`, or in a nodejs context by running `grunt test`. There are a number of ways to run the tests. The preferred way is:
```
npm test
```
This will do a build, run the linting, start a server, and load the tests into
headless versions of Chrome and Firefox.
If you want more control over how tests are run, you can use other scripts:
* Linting is done via `npm run lint` or `npm run eslint`, both of which will run `eslint` on the `src` and `tests` directories. You can also use `npm run lint:fix` or `npm run eslint:fix`, which will run `eslint` with `--fix` on the `src` and `tests` directories, automatically fixing minor issues. Linting is run by default as part of `npm test`
* In headless versions of Chrome and Firefox using `npm test`. A report at the end will tell you what happened with each browser. Browser tests are preferred because they also test our providers (e.g., IndexedDB). They do take longer to run. You can also use `npm run karma-mocha-firefox` or `npm run karma-mocha-chrome` to run the tests in only one of the two headless browsers.
* In node.js using the Memory provider using `npm run test:node`. These run much faster, but don't run all tests (e.g., providers, watches).
* If you need to debug browser tests, or want to run them in a different browser, use `npm run test:manual`, which will start a server and you can point your browser to [http://localhost:1234](http://localhost:1234). Running the tests this way will also automatically watch your files, and hot-reload your code and tests, which is useful for debugging and trial/error testing.
* If you need to debug node.js test runs, you can do so using `npm run test:node-debug`. Then, open Chrome and browse to [chrome://inspect](chrome://inspect) and click on your tests in the inspector. The easiest way to get a breakpoint is to manually add a `debugger` keyword to your test code where you want the tests to stop.
> Tip: you can add `skip()` to any `it()` or `describe()` in Mocha to skip a test, or `only()` to have only that test run. For example: `describe.skip(...)` or `it.only(...)`.
* If you want to run migration tests separate from unit tests, use `npm run test:migrations`. Migration tests run at the end of a typical `npm test` run. If you need to create a new migration test, see [`tools/fs-image.js`](tools/fs-image.js) for details on how to generate a filesystem image, and [tests/filesystems/images/README.md](tests/filesystems/images/README.md) for more docs.
* If you want to manually generate coverage info for the tests, use `npm run coverage`. This is done automatically in Travis, so you shouldn't need to do it. You can see [https://codecov.io/gh/filerjs/filer](https://codecov.io/gh/filerjs/filer) for detailed reports.
There are a number of configurable options for the test suite, which are set via query string params. There are a number of configurable options for the test suite, which are set via query string params.
First, you can choose which filer source to use (i.e., src/, dist/filer-test.js, dist/filer.js or dist/filer.min.js). First, you can choose which filer source to use (i.e., src/, dist/filer-test.js, dist/filer.js or dist/filer.min.js). The default is to use what is in /dist/filer-test.js, and you can switch to other versions like so:
The default is to use what is in /dist/filer-test.js, and you can switch to other versions like so:
* tests/index.html?filer-dist/filer.js * tests/index.html?filer-dist/filer.js
* tests/index.html?filer-dist/filer.min.js * tests/index.html?filer-dist/filer.min.js
* tests/index.html?filer-src/filer.js (from src) * tests/index.html?filer-src/filer.js (from src)
Second, you can specify which provider to use for all non-provider specific tests (i.e., most of the tests). Second, you can specify which provider to use for all non-provider specific tests (i.e., most of the tests).
The default provider is `Memory`, and you can switch it like so: The default provider is `Memory`, and you can switch it like so:
* tests/index.html?filer-provider=memory * tests/index.html?filer-provider=memory
* tests/index.html?filer-provider=indexeddb * tests/index.html?filer-provider=indexeddb
* tests/index.html?filer-provider=websql
If you're writing tests, make sure you write them in the same style as existing tests, which are If you're writing tests, make sure you write them in the same style as existing tests, which are
provider agnostic. See `tests/lib/test-utils.js` and how it gets used in various tests as provider agnostic. See [`tests/lib/test-utils.js`](tests/lib/test-utils.js) and how it gets used
an example. in various tests as an example.
## Communication ## Releases
If you'd like to talk to someone about the project, you can reach us on irc.mozilla.org in the #filer or #mofodev channel. Look for "ack" or "humph". In order to perform a release, you'll need commit access to the main Filer repo,
as well as access to publish to Filer's npm module. To do a release:
1. Make sure you have a .env file, with your `GITHUB_TOKEN` included. See [`env.sample`](env.sample) for more info on how to create one.
1. Login to the `npm` registry if you haven't already using `npm login`
1. Run `npm run release`. Releases are done interactively using [release-it](https://www.npmjs.com/package/release-it), and our config is defined in [`.release-it.json`](.release-it.json).

View File

@ -1,4 +1,4 @@
Copyright (c) 2013, Alan Kligman Copyright (c) 2013 - 2019 Alan Kligman and the Filer contributors
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

591
README.md
View File

@ -1,26 +1,26 @@
[![NPM](https://nodei.co/npm/filer.png?downloads=true&stars=true)](https://nodei.co/npm/filer/) [![NPM](https://nodei.co/npm/filer.png?downloads=true&stars=true)](https://nodei.co/npm/filer/)
[![Build Status](https://secure.travis-ci.org/filerjs/filer.png?branch=develop)](http://travis-ci.org/filerjs/filer) [![Build Status](https://secure.travis-ci.org/filerjs/filer.png?branch=develop)](http://travis-ci.org/filerjs/filer) [![codecov](https://codecov.io/gh/filerjs/filer/branch/master/graph/badge.svg)](https://codecov.io/gh/filerjs/filer)
###Filer ### Filer
Filer is a POSIX-like file system interface for node.js and browser-based JavaScript. Filer is a drop-in replacement for node's `fs` module, a POSIX-like file system
for browsers.
###Compatibility ### Compatibility
Filer is known to work in the following browsers/versions, with the specified [Storage Providers](#providers): Filer uses [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API)
and is [known to work in the following browsers/versions](https://caniuse.com/#feat=indexeddb):
* node.js: v0.10.*+ * node.js: v0.10.*+
* IE: 10+ (IndexedDB) * IE: 10+
* Firefox: 26+ (IndexedDB) * Edge: 12+
* Chrome: 31+ (IndexedDB, WebSQL) * Firefox: 10+
* Safari: 7.0+ (WebSQL) * Chrome: 23+
* Opera: 19+ (IndexedDB, WebSQL) * Safari: 10+
* iOS: 3.2+ (WebSQL) * Opera: 15+
* Android Browser: 2.1-4.4 (WebSQL), 4.4+ (IndexedDB) * iOS: 10+
* Android Browser: 4.4+
NOTE: if you're interested in maximum compatibility, use the `Fallback` provider instead of `Default`.
See the section on [Storage Providers](#providers).
### Contributing ### Contributing
@ -30,16 +30,15 @@ Want to join the fun? We'd love to have you! See [CONTRIBUTING](https://github.c
Filer can be obtained in a number of ways: Filer can be obtained in a number of ways:
1. npm - `npm install filer` 1. Via npm: `npm install filer`
2. bower - `bower install filer` 1. Via unpkg: `<script src="https://unpkg.com/filer"></script>` or specify a version directly, for example: [https://unpkg.com/filer@1.0.1/dist/filer.min.js](https://unpkg.com/filer@1.0.1/dist/filer.min.js)
3. download pre-built versions: [filer.js](https://raw.github.com/filerjs/filer/develop/dist/filer.js), [filer.min.js](https://raw.github.com/filerjs/filer/develop/dist/filer.min.js)
### Loading and Usage ### Loading and Usage
Filer is built as a UMD module and can therefore be loaded as a CommonJS or AMD module, or used via the global. Filer is built as a UMD module and can therefore be loaded as a CommonJS or AMD module, or used via the global.
```javascript ```javascript
// Option 1: Filer loaded via require() in node/browserify // Option 1: Filer loaded via require()
var Filer = require('filer'); var Filer = require('filer');
// Option 2: Filer loaded via RequireJS // Option 2: Filer loaded via RequireJS
@ -55,13 +54,84 @@ requirejs(['filer'], function(Filer) {...}
var Filer = window.Filer; var Filer = window.Filer;
``` ```
### Webpack Plugin
Filer can be used as a drop-in replacement for the node.js [fs](http://nodejs.org/api/fs.html) and
[path](http://nodejs.org/api/path.html) modules. For convenience, filer provides a webpack plugin which
will shim the desired node.js functionality. This plugin can be used by inserting the following into
your webpack config:
```javascript
// webpack.config.js
var { FilerWebpackPlugin } = require('filer/webpack');
module.exports = {
plugins: [
new FilerWebpackPlugin(),
],
}
```
---
**NOTE**
Previously it was recommended to access the `FilerWebpackPlugin` class by importing the main filer module. This was depracated due [this issue](https://github.com/filerjs/filer/issues/790). For anyone using ***filer version 1.4.0 or earlier***, please import the plugin class like this:
```javascript
var FilerWebpackPlugin = require('filer/src/webpack-plugin');
```
---
You can then import the node.js [fs](http://nodejs.org/api/fs.html) and [path](http://nodejs.org/api/path.html)
modules as normal and `FilerWebpackPlugin` will ensure that webpack will resolve references to these modules to
the appropriate filer shims. You will then be able to use these modules as normal (with the exception of the
synchronous fs methods e.g. `mkdirSync()`).
```javascript
import fs from 'fs';
import path from 'path';
```
The filer webpack plugin will, by default, shim the [fs](http://nodejs.org/api/fs.html) and
[path](http://nodejs.org/api/path.html) modules. However, it's behaviour can be customised by passing an
options object.
```javascript
// webpack.config.js
module.exports = {
plugins: [
new FilerWebpackPlugin({
// Options
}),
],
}
```
The following options can be passed to the filer webpack plugin:
| Option | Type | Optional | Default | Description |
|---------------|---------|----------|--------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------|
| filerDir | string | yes | '\<rootDir\>/node_modules/filer' | The directory in which filer is installed. |
| shimsDir | string | yes | '\<rootDir\>/node_modules/filer/shims' | The directory in which the shims are installed. |
| fsProviderDir | string | yes | '\<rootDir\>/node_modules/filer/shims/providers' | The directory in which the shims are located. This option is required when using a custom provider. |
| shimFs | boolean | yes | true | Should the fs module be shimmed. |
| shimPath | boolean | yes | true | Should the path module be shimmed. |
| fsProvider | string | yes | 'default' | The file system provider to use. Should be one of 'default', 'indexeddb', 'memory', 'custom'. The 'default' option is equivalent to 'indexeddb'. |
NOTE: '\<rootDir\>' will be resolved to the current working directory.
Though filer also exposes the Buffer object, it is left up to the user to shim this as appropriate. This is because filer offers
no custom implementation. Currently, filer uses the [node-libs-browser](https://github.com/webpack/node-libs-browser) Buffer implementation
internally, though any faithful implementation of the [node.js Buffer object](http://nodejs.org/api/buffer.html) should play nicely
with filer.
### Getting Started ### Getting Started
Filer is as close to the node.js [fs module](http://nodejs.org/api/fs.html) as possible, Filer is as close to the node.js [fs module](http://nodejs.org/api/fs.html) as possible,
with the following differences: with the following differences:
* No synchronous versions of methods (e.g., `mkdir()` but not `mkdirSync()`). * No synchronous versions of methods (e.g., `mkdir()` but not `mkdirSync()`).
* No permissions (e.g., no `chown()`, `chmod()`, etc.).
* No support for stream-based operations (e.g., `fs.ReadStream`, `fs.WriteStream`). * No support for stream-based operations (e.g., `fs.ReadStream`, `fs.WriteStream`).
Filer has other features lacking in node.js (e.g., swappable backend Filer has other features lacking in node.js (e.g., swappable backend
@ -78,18 +148,32 @@ they are invoked. Ensure proper ordering by chaining operations in callbacks.
To create a new file system or open an existing one, create a new `FileSystem` To create a new file system or open an existing one, create a new `FileSystem`
instance. By default, a new [IndexedDB](https://developer.mozilla.org/en/docs/IndexedDB) instance. By default, a new [IndexedDB](https://developer.mozilla.org/en/docs/IndexedDB)
database is created for each file system. The file system can also use other database is created for each file system. The file system can also use other
backend storage providers, for example [WebSQL](http://en.wikipedia.org/wiki/Web_SQL_Database) backend storage providers, for example `Memory`. See the section on [Storage Providers](#providers).
or even RAM (i.e., for temporary storage). See the section on [Storage Providers](#providers).
```javascript <a name="overviewExample"></a>
var fs = new Filer.FileSystem();
fs.open('/myfile', 'w+', function(err, fd) { ```js
if (err) throw err; const { fs, path } = require('filer');
fs.close(fd, function(err) {
if (err) throw err; fs.mkdir('/docs', (err) => {
fs.stat('/myfile', function(err, stats) { if (err) {
if (err) throw err; return console.error('Unable to create /docs dir', err);
console.log('stats: ' + JSON.stringify(stats)); }
const filename = path.join('/docs', 'first.txt');
const data = 'Hello World!\n';
fs.writeFile(filename, data, (err) => {
if (err) {
return console.error('Unable to write /docs/first.txt', err);
}
fs.stat(filename, (err, stats) => {
if (err) {
return console.error('Unable to stat /docs/first.txt', err);
}
console.log('Stats for /docs/first.txt:', stats);
}); });
}); });
}); });
@ -98,7 +182,7 @@ fs.open('/myfile', 'w+', function(err, fd) {
For a complete list of `FileSystem` methods and examples, see the [FileSystem Instance Methods](#FileSystemMethods) For a complete list of `FileSystem` methods and examples, see the [FileSystem Instance Methods](#FileSystemMethods)
section below. section below.
Filer also supports node's Path module. See the [Filer.Path](#FilerPath) section below. Filer also includes node's `path` and `Buffer` modules. See the [Filer.Path](#FilerPath) and [Filer.Buffer](#FilerBuffer) sections below.
In addition, common shell operations (e.g., rm, touch, cat, etc.) are supported via the In addition, common shell operations (e.g., rm, touch, cat, etc.) are supported via the
`FileSystemShell` object, which can be obtained from, and used with a `FileSystem`. `FileSystemShell` object, which can be obtained from, and used with a `FileSystem`.
@ -110,11 +194,29 @@ Like node.js, callbacks for methods that accept them are optional but suggested
you omit the callback, errors will be thrown as exceptions). The first callback parameter is you omit the callback, errors will be thrown as exceptions). The first callback parameter is
reserved for passing errors. It will be `null` if no errors occurred and should always be checked. reserved for passing errors. It will be `null` if no errors occurred and should always be checked.
#### Support for Promises
The Promise based API mimics the way node [implements](https://nodejs.org/api/fs.html#fs_fs_promises_api) them. Both `Shell` and `FileSystem` now have a `promises` property, which gives access to Promise based versions of methods in addition to the regular callback style methods. Method names are identical to their callback counterparts with the difference that instead of receiving a final argument as a callback, they return a Promise that is resolved or rejected based on the success of method execution.
See example below:
```javascript
const fs = new Filer.FileSystem().promises;
fs.writeFile('/myfile', 'some data')
.then(() => fs.stat('/myfile'))
.then(stats => { console.log(`stats: ${JSON.stringify(stats)}`); })
.catch(err => { console.error(err); });
```
#### Filer.FileSystem(options, callback) constructor #### Filer.FileSystem(options, callback) constructor
File system constructor, invoked to open an existing file system or create a new one. In most cases, using `Filer.fs` will be sufficient, and provide a working filesystem.
Accepts two arguments: an `options` object, and an optional `callback`. The `options` However, if you need more control over the filesystem, you can also use the `FileSystem`
object can specify a number of optional arguments, including: constructor, invoked to open an existing file system or create a new one.
`Filer.FileSystem()` It accepts two arguments: an `options` object, and an optional
`callback` function. The `options` object can specify a number of optional arguments,
including:
* `name`: the name of the file system, defaults to `'"local'` * `name`: the name of the file system, defaults to `'"local'`
* `flags`: an Array of one or more flags to use when creating/opening the file system: * `flags`: an Array of one or more flags to use when creating/opening the file system:
@ -147,17 +249,19 @@ NOTE: if the optional callback argument is not passed to the `FileSystem` constr
operations done on the resulting file system will be queued and run in sequence when operations done on the resulting file system will be queued and run in sequence when
it becomes ready. it becomes ready.
####Filer.FileSystem.providers - Storage Providers<a name="providers"></a> #### Filer.FileSystem.providers - Storage Providers<a name="providers"></a>
Filer can be configured to use a number of different storage providers. The provider object encapsulates all aspects Filer can be configured to use a number of different storage providers. The provider object encapsulates all aspects of data access, making it possible to swap in different backend storage options. There are currently 2 providers to choose from:
of data access, making it possible to swap in different backend storage options. There are currently 4 different
providers to choose from:
* `FileSystem.providers.IndexedDB()` - uses IndexedDB * `FileSystem.providers.IndexedDB()` - uses IndexedDB
* `FileSystem.providers.WebSQL()` - uses WebSQL if necessary
* `FileSystem.providers.Fallback()` - attempts to use IndexedDB if possible, falling-back to WebSQL if necessary
* `FileSystem.providers.Memory()` - uses memory (not suitable for data that needs to survive the current session) * `FileSystem.providers.Memory()` - uses memory (not suitable for data that needs to survive the current session)
**NOTE**: previous versions of Filer also supported `FileSystem.providers.WebSQL()` and
`FileSystem.providers.Fallback()`, which could be used in browsers that supported
WebSQL but not IndexedDB. [WebSQL has been deprecated](https://www.w3.org/TR/webdatabase/),
and this functionality was removed in `v1.0.0`. If for some reason you still need it, use [`v0.0.44`](https://github.com/filerjs/filer/releases/tag/v0.0.44).
You can choose your provider when creating a `FileSystem`: You can choose your provider when creating a `FileSystem`:
```javascript ```javascript
@ -167,45 +271,62 @@ var providers = FileSystem.providers;
// Example 1: Use the default provider (currently IndexedDB) // Example 1: Use the default provider (currently IndexedDB)
var fs1 = new FileSystem(); var fs1 = new FileSystem();
// Example 2: Explicitly use IndexedDB // Example 2: Use the Memory provider
var fs2 = new FileSystem({ provider: new providers.IndexedDB() }); var fs2 = new FileSystem({ provider: new providers.Memory() });
// Example 3: Use one of IndexedDB or WebSQL, whichever is supported
var fs3 = new FileSystem({ provider: new providers.Fallback() });
``` ```
Every provider has an `isSupported()` method, which returns `true` if the browser supports this provider: Every provider has an `isSupported()` method, which returns `true` if the browser supports this provider:
```javascript ```javascript
if( Filer.FileSystem.providers.WebSQL.isSupported() ) { if( Filer.FileSystem.providers.IndexedDB.isSupported() ) {
// WebSQL provider will work in current environment... // IndexedDB provider will work in current environment...
} }
``` ```
You can also write your own provider if you need a different backend. See the code in `src/providers` for details. You can also write your own provider if you need a different backend. See the code in `src/providers` for details.
A number of other providers have been written, including: #### Filer.Buffer<a name="FilerBuffer"></a>
* node.js fs provider: https://github.com/humphd/filer-fs
* node.js Amazon S3 provider: https://github.com/alicoding/filer-s3
####Filer.Buffer<a name="FilerBuffer"></a>
When reading and writing data, Filer follows node.js and uses [`Buffer`](http://nodejs.org/api/buffer.html). When reading and writing data, Filer follows node.js and uses [`Buffer`](http://nodejs.org/api/buffer.html).
When in a node.js environment, native `Buffer`s can be used, or Filer.Buffer, which is a shortcut When in a node.js environment, native `Buffer`s can be used, or Filer.Buffer, which is a shortcut
to node's `Buffer`. In a browser, you can use also use `Filer.Buffer`. to node's `Buffer`. In a browser, you can use also use `Filer.Buffer`.
NOTE: a `Filer.Buffer` in a browser is really an augmented `Uint8Array` (i.e., the node `Buffer` api NOTE: a `Filer.Buffer` in a browser is really an augmented `Uint8Array` (i.e., the node `Buffer` api
methods are added to the instance). See https://github.com/feross/buffer for more details. Additionally, unlike native `Buffer`, `Filer.Buffer`'s constructor can accept `ArrayBuffer` objects, which will be interpreted as `Uint8Array`s. methods are added to the instance). See https://github.com/feross/buffer for more details.
####Filer.Path<a name="FilerPath"></a> NOTE: `Filer.Buffer` currently includes the older, deprecated [constructor functions](https://nodejs.org/api/buffer.html#buffer_new_buffer_array), but these will be removed
at some point. You are encouraged to switch to use the newer class methods `Buffer.from()`
and `Buffer.alloc()`. See the [node.js Buffer docs](https://nodejs.org/api/buffer.html).
The node.js [path module](http://nodejs.org/api/path.html) is available via the `Filer.Path` object. It is ```js
identical to the node.js version with the following differences: /* Deprecated - see https://nodejs.org/api/buffer.html#buffer_new_buffer_array */
* No notion of a current working directory in `resolve` (the root dir is used instead) new Buffer(array)
new Buffer(arrayBuffer[, byteOffset[, length]])
new Buffer(buffer)
new Buffer(string[, encoding])
new Buffer(size)
/* Use Instead */
Buffer.from(array)
Buffer.from(arrayBuffer[, byteOffset[, length]])
Buffer.from(buffer)
Buffer.from(string[, encoding])
Buffer.alloc(size)
Buffer.allocUnsafe(size)
```
#### Filer.Path<a name="FilerPath"></a>
The node.js [path module](http://nodejs.org/api/path.html) is available via `Filer.path` or
`Filer.Path` (both are supported for historical reasons, and to match node). The Filer `path`
module is identical to the node.js version (see [https://github.com/browserify/path-browserify](https://github.com/browserify/path-browserify)), with the following differences:
* The CWD always defaults to `/`
* No support for Windows style paths (assume you are on a POSIX system)
* Additional utility methods (see below)
```javascript ```javascript
var path = Filer.Path; var path = Filer.path;
var dir = path.dirname('/foo/bar/baz/asdf/quux'); var dir = path.dirname('/foo/bar/baz/asdf/quux');
// dir is now '/foo/bar/baz/asdf' // dir is now '/foo/bar/baz/asdf'
@ -220,17 +341,38 @@ var newpath = path.join('/foo', 'bar', 'baz/asdf', 'quux', '..');
``` ```
For more info see the docs in the [path module](http://nodejs.org/api/path.html) for a particular method: For more info see the docs in the [path module](http://nodejs.org/api/path.html) for a particular method:
* `path.normalize(p)` * `path.normalize(p)` - NOTE: Filer.Path.normalize does *not* add a trailing slash
* `path.join([path1], [path2], [...])` * `path.join([path1], [path2], [...])`
* `path.resolve([from ...], to)` * `path.resolve([from ...], to)`
* `path.relative(from, to)` * `path.relative(from, to)`
* `path.dirname(p)` * `path.dirname(p)`
* `path.basename(p, [ext])` * `path.basename(p, [ext])` - NOTE: Filer.Path.basename will return `'/'` vs. `''`
* `path.extname(p)` * `path.extname(p)`
* `path.sep` * `path.sep`
* `path.delimiter` * `path.delimiter`
####Filer.Errors<a name="Errors"></a> Filer.Path also includes the following extra methods:
* `isNull(p)` returns `true` or `false` if the path contains a null character (`'\u0000'`)
* `addTrailing(p)` returns the path `p` with a single trailing slash added
* `removeTrailing(p)` returns the path `p` with trailing slash(es) removed
[As with node.js](https://nodejs.org/api/fs.html#fs_file_paths), all methods below that
accept a `path` argument as a `String` can also take a [`file://` URL](https://nodejs.org/api/fs.html#fs_url_object_support)
or a `Buffer`. For example, all of the following cases will work the same way with Filer:
```js
// 1. path as a String
fs.writeFile('/dir/file.txt', 'data', function(err) {...});
// 2. path as a URL
fs.writeFile(new URL('file:///dir/file.txt'), 'data', function(err) {...});
// 3. path as a Buffer
fs.writeFile(Buffer.from('/dir/file.txt'), 'data', function(err) {...});
```
#### Filer.Errors<a name="Errors"></a>
The error objects used internally by Filer are also exposed via the `Filer.Errors` object. As much as possible The error objects used internally by Filer are also exposed via the `Filer.Errors` object. As much as possible
these match their node.js counterparts, with a few Filer-specifc additions. these match their node.js counterparts, with a few Filer-specifc additions.
@ -266,13 +408,17 @@ function callback(err) {
console.log(err.message); console.log(err.message);
``` ```
###FileSystem Instance Methods<a name="FileSystemMethods"></a> ### FileSystem Instance Methods<a name="FileSystemMethods"></a>
Once a `FileSystem` is created, it has the following methods. NOTE: code examples below assume Once a `FileSystem` is created, it has the following methods. NOTE: code examples below assume
a `FileSystem` instance named `fs` has been created like so: a `FileSystem` instance named `fs` has been created like so:
```javascript ```javascript
var fs = new Filer.FileSystem(); // 1. Using Filer.fs for a default filesystem
const { fs } = require('filer');
// 2. Or via the FileSystem constructor with specified options
const fs = new Filer.FileSystem(options, callback);
``` ```
* [fs.rename(oldPath, newPath, callback)](#rename) * [fs.rename(oldPath, newPath, callback)](#rename)
@ -290,10 +436,16 @@ var fs = new Filer.FileSystem();
* [fs.mknod(path, mode, callback)](#mknod) * [fs.mknod(path, mode, callback)](#mknod)
* [fs.rmdir(path, callback)](#rmdir) * [fs.rmdir(path, callback)](#rmdir)
* [fs.mkdir(path, [mode], callback)](#mkdir) * [fs.mkdir(path, [mode], callback)](#mkdir)
* [fs.access(path, [mode], callback)](#access)
* [fs.mkdtemp(path, [options], callback)](#mkdtemp)
* [fs.readdir(path, callback)](#readdir) * [fs.readdir(path, callback)](#readdir)
* [fs.close(fd, callback)](#close) * [fs.close(fd, callback)](#close)
* [fs.open(path, flags, [mode], callback)](#open) * [fs.open(path, flags, [mode], callback)](#open)
* [fs.utimes(path, atime, mtime, callback)](#utimes) * [fs.utimes(path, atime, mtime, callback)](#utimes)
* [fs.chown(path, uid, gid, callback)](#chown)
* [fs.fchown(fd, uid, gid, callback)](#fchown)
* [fs.chmod(path, mode, callback)](#chmod)
* [fs.fchmod(fd, mode, callback)](#fchmod)
* [fs.futimes(fd, atime, mtime, callback)](#fsutimes) * [fs.futimes(fd, atime, mtime, callback)](#fsutimes)
* [fs.fsync(fd, callback)](#fsync) * [fs.fsync(fd, callback)](#fsync)
* [fs.write(fd, buffer, offset, length, position, callback)](#write) * [fs.write(fd, buffer, offset, length, position, callback)](#write)
@ -335,7 +487,7 @@ Example:
```javascript ```javascript
// Create a file, shrink it, expand it. // Create a file, shrink it, expand it.
var buffer = new Filer.Buffer([1, 2, 3, 4, 5, 6, 7, 8]); var buffer = Filer.Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]);
fs.open('/myfile', 'w', function(err, fd) { fs.open('/myfile', 'w', function(err, fd) {
if(err) throw error; if(err) throw error;
@ -366,7 +518,7 @@ Example:
```javascript ```javascript
// Create a file, shrink it, expand it. // Create a file, shrink it, expand it.
var buffer = new Filer.Buffer([1, 2, 3, 4, 5, 6, 7, 8]); var buffer = Filer.Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]);
fs.open('/myfile', 'w', function(err, fd) { fs.open('/myfile', 'w', function(err, fd) {
if(err) throw error; if(err) throw error;
@ -397,14 +549,22 @@ Callback gets `(error, stats)`, where `stats` is an object with the following pr
``` ```
{ {
node: <string> // internal node id (unique) node: <string> // internal node id (unique)
dev: <string> // file system name dev: <string> // file system name
size: <number> // file size in bytes name: <string> // the entry's name (basename)
nlinks: <number> // number of links size: <number> // file size in bytes
atime: <number> // last access time nlinks: <number> // number of links
mtime: <number> // last modified time atime: <date> // last access time as JS Date Object
ctime: <number> // creation time mtime: <date> // last modified time as JS Date Object
type: <string> // file type (FILE, DIRECTORY, SYMLINK) ctime: <date> // creation time as JS Date Object
atimeMs: <number> // last access time as Unix Timestamp
mtimeMs: <number> // last modified time as Unix Timestamp
ctimeMs: <number> // creation time as Unix Timestamp
type: <string> // file type (FILE, DIRECTORY, SYMLINK),
gid: <number> // group name
uid: <number> // owner name
mode: <number> // permissions
version: <number> // version of the node
} }
``` ```
@ -536,10 +696,12 @@ Create a symbolic link to the file at `dstPath` containing the path `srcPath`. A
Symbolic links are files that point to other paths. Symbolic links are files that point to other paths.
NOTE: Filer allows for, but ignores the optional `type` parameter used in node.js. NOTE: Filer allows for, but ignores the optional `type` parameter used in node.js.
The `srcPath` may be a relative path, which will be resolved relative to `dstPath`
Example: Example:
```javascript ```javascript
// Absolute path
fs.symlink('/logs/august.log', '/logs/current', function(err) { fs.symlink('/logs/august.log', '/logs/current', function(err) {
if(err) throw err; if(err) throw err;
fs.readFile('/logs/current', 'utf8', function(err, data) { fs.readFile('/logs/current', 'utf8', function(err, data) {
@ -547,11 +709,21 @@ fs.symlink('/logs/august.log', '/logs/current', function(err) {
var currentLog = data; var currentLog = data;
}); });
}); });
// Relative path
fs.symlink('../file', '/dir/symlink', function(err) {
if(err) throw err;
// The /dir/symlink file is now a symlink to /file
});
``` ```
#### fs.readlink(path, callback)<a name="readlink"></a> #### fs.readlink(path, callback)<a name="readlink"></a>
Reads the contents of a symbolic link. Asynchronous [readlink(2)](http://pubs.opengroup.org/onlinepubs/009695399/functions/readlink.html). Callback gets `(error, linkContents)`, where `linkContents` is a string containing the symbolic link's link path. Reads the contents of a symbolic link. Asynchronous [readlink(2)](http://pubs.opengroup.org/onlinepubs/009695399/functions/readlink.html).
Callback gets `(error, linkContents)`, where `linkContents` is a string
containing the symbolic link's link path. If the original `srcPath` given
to `symlink()` was a relative path, it will be fully resolved relative
to `dstPath` when returned by `readlink()`.
Example: Example:
@ -648,7 +820,47 @@ fs.mkdir('/home', function(err) {
}); });
``` ```
#### fs.readdir(path, callback)<a name="readdir"></a> #### fs.access(path, [mode], callback)<a name="access"></a>
Tests a user's permissions for the file or directory supplied in `path` argument. Asynchronous [access(2)](http://pubs.opengroup.org/onlinepubs/009695399/functions/access.html). Callback gets no additional arguments. The `mode` argument can be one of the following (constants are available on `fs.constants` and `fs`):
* `F_OK`: Test for existence of file.
* `R_OK`: Test whether the file exists and grants read permission.
* `W_OK`: Test whether the file exists and grants write permission.
* `X_OK`: Test whether the file exists and grants execute permission.
NOTE: you can also create a mask consisting of the bitwise OR of two or more values (e.g. `fs.constants.W_OK | fs.constants.R_OK`).
Example:
```javascript
// Check if the file exists in the current directory.
fs.access(file, fs.F_OK, function(err) {
console.log(`${file} ${err ? 'does not exist' : 'exists'}`);
});
```
#### fs.mkdtemp(prefix, options, callback)<a name="mkdtemp"></a>
Makes a temporary directory with prefix supplied in `path` argument. Method will append six random characters directly to the prefix. Asynchronous. Callback gets `(error, path)`, where path is the path to the created directory.
NOTE: Filer allows for, but ignores the optional `options` argument used in node.js.
Example:
```javascript
// Create tmp directory with prefix foo
fs.mkdtemp("/foo-", function (error, path) {
// A new folder foo-xxxxxx will be created. Path contains a path to created folder.
});
fs.mkdtemp("/myDir/tmp", function (error, path) {
// Will create a new folder tmpxxxxxx inside myDir directory.
// Will throw error if myDir does not exist
});
```
#### fs.readdir(path, [options], callback)<a name="readdir"></a>
Reads the contents of a directory. Asynchronous [readdir(3)](http://pubs.opengroup.org/onlinepubs/009695399/functions/readdir.html). Reads the contents of a directory. Asynchronous [readdir(3)](http://pubs.opengroup.org/onlinepubs/009695399/functions/readdir.html).
Callback gets `(error, files)`, where `files` is an array containing the names of each directory entry (i.e., file, directory, link) in the directory, excluding `.` and `..`. Callback gets `(error, files)`, where `files` is an array containing the names of each directory entry (i.e., file, directory, link) in the directory, excluding `.` and `..`.
@ -669,6 +881,12 @@ fs.readdir('/docs', function(err, files) {
}); });
``` ```
Optionally accepts an options parameter, which can be either an encoding (e.g. "utf8") or an object with optional properties `encoding` and `withFileTypes`.
The `encoding` property is a `string` which will determine the character encoding to use for the names of each directory entry. The `withFileTypes` property is a `boolean` which defaults to `false`. If `true`, this method will return an array of [fs.Dirent](https://nodejs.org/api/fs.html#fs_class_fs_dirent) objects.
The `name` property on the [fs.Dirent](https://nodejs.org/api/fs.html#fs_class_fs_dirent) objects will be encoded using the specified character encoding.
#### fs.close(fd, callback)<a name="close"></a> #### fs.close(fd, callback)<a name="close"></a>
Closes a file descriptor. Asynchronous [close(2)](http://pubs.opengroup.org/onlinepubs/009695399/functions/close.html). Closes a file descriptor. Asynchronous [close(2)](http://pubs.opengroup.org/onlinepubs/009695399/functions/close.html).
@ -716,7 +934,7 @@ fs.open('/myfile', 'w', function(err, fd) {
#### fs.utimes(path, atime, mtime, callback)<a name="utimes"></a> #### fs.utimes(path, atime, mtime, callback)<a name="utimes"></a>
Changes the file timestamps for the file given at path `path`. Asynchronous [utimes(2)](http://pubs.opengroup.org/onlinepubs/009695399/functions/utimes.html). Callback gets no additional arguments. Both `atime` (access time) and `mtime` (modified time) arguments should be a JavaScript Date. Changes the file timestamps for the file given at path `path`. Asynchronous [utimes(2)](http://pubs.opengroup.org/onlinepubs/009695399/functions/utimes.html). Callback gets no additional arguments. Both `atime` (access time) and `mtime` (modified time) arguments should be a JavaScript Date or Number.
Example: Example:
@ -730,7 +948,7 @@ fs.utimes('/myfile.txt', now, now, function(err) {
#### fs.futimes(fd, atime, mtime, callback)<a name="futimes"></a> #### fs.futimes(fd, atime, mtime, callback)<a name="futimes"></a>
Changes the file timestamps for the open file represented by the file descriptor `fd`. Asynchronous [utimes(2)](http://pubs.opengroup.org/onlinepubs/009695399/functions/utimes.html). Callback gets no additional arguments. Both `atime` (access time) and `mtime` (modified time) arguments should be a JavaScript Date. Changes the file timestamps for the open file represented by the file descriptor `fd`. Asynchronous [utimes(2)](http://pubs.opengroup.org/onlinepubs/009695399/functions/utimes.html). Callback gets no additional arguments. Both `atime` (access time) and `mtime` (modified time) arguments should be a JavaScript Date or Number.
Example: Example:
@ -749,9 +967,107 @@ fs.open('/myfile.txt', function(err, fd) {
}); });
``` ```
#### fs.chown(path, uid, gid, callback)<a name="chown"></a>
Changes the owner and group of a file. Asynchronous [chown(2)](http://pubs.opengroup.org/onlinepubs/009695399/functions/chown.html). Callback gets no additional arguments. Both `uid` (user id) and `gid` (group id) arguments should be a JavaScript Number. By default, `0x0` is used (i.e., `root:root` ownership).
Example:
```javascript
fs.chown('/myfile.txt', 500, 500, function(err) {
if(err) throw err;
// /myfile.txt is now owned by user with id 500, group 500
});
```
#### fs.fchown(fd, uid, gid, callback)<a name="fchown"></a>
Changes the owner and group of a file. Asynchronous [chown(2)](http://pubs.opengroup.org/onlinepubs/009695399/functions/chown.html). Callback gets no additional arguments. Both `uid` (user id) and `gid` (group id) arguments should be a JavaScript Number. By default, `0x0` is used (i.e., `root:root` ownership).
Example:
```javascript
fs.open('/myfile.txt', function(err, fd) {
if(err) throw err;
fs.fchown(fd, 500, 500, function(err) {
if(err) throw err;
// /myfile.txt is now owned by user with id 500, group 500
fs.close(fd);
});
});
```
#### fs.chmod(path, mode, callback)<a name="chmod"></a>
Changes the mode of a file. Asynchronous [chmod(2)](http://pubs.opengroup.org/onlinepubs/009695399/functions/chmod.html). Callback gets no additional arguments. The `mode` argument should be a JavaScript Number, which combines file type and permission information. Here are a list of common values useful for setting the `mode`:
* File type `S_IFREG=0x8000`
* Dir type `S_IFDIR=0x4000`
* Link type `S_IFLNK=0xA000`
* Permissions `755=0x1ED`
* Permissions `644=0x1A4`
* Permissions `777=0x1FF`
* Permissions `666=0x1B6`
By default, directories use `(0x4000 | 0x1ED)` and files use `(0x8000 | 0x1A4)`.
Example:
```javascript
// S_IFREG | 0o777
var mode = 0x8000 | 0x1FF
fs.chmod('/myfile.txt', mode, function(err) {
if(err) throw err;
// /myfile.txt is a regular file with permissions 777
});
```
#### fs.fchmod(fd, mode, callback)<a name="fchmod"></a>
Changes the mode of a file. Asynchronous [chmod(2)](http://pubs.opengroup.org/onlinepubs/009695399/functions/chmod.html). Callback gets no additional arguments. The `mode` argument should be a JavaScript Number, which combines file type and permission information. By default, `755` (dir) and `644` (file) are used.
Example:
```javascript
fs.open('/myfile.txt', function(err, fd) {
if(err) throw err;
// S_IFREG | 0o777
var mode = 0x8000 | 0x1FF
fs.fchmod(fd, mode, function(err) {
if(err) throw err;
// /myfile.txt is a regular file with permissions 777
fs.close(fd);
});
});
```
#### fs.fsync(fd, callback)<a name="fsync"></a> #### fs.fsync(fd, callback)<a name="fsync"></a>
NOTE: Not yet implemented, see https://github.com/filerjs/filer/issues/87 Synchronize the data and metadata for the file referred to by `fd` to disk.
Asynchronous [fsync(2)](http://man7.org/linux/man-pages/man2/fsync.2.html).
The callback gets `(error)`.
```js
fs.open('/myfile', 'r', function(error, fd) {
if(err) throw err;
// Use fd, then sync
fs.fsync(fd, function(error) {
if(err) throw err;
fs.close(fd, done);
});
});
```
#### fs.write(fd, buffer, offset, length, position, callback)<a name="write"></a> #### fs.write(fd, buffer, offset, length, position, callback)<a name="write"></a>
@ -763,7 +1079,7 @@ Example:
```javascript ```javascript
// Create a file with the following bytes. // Create a file with the following bytes.
var buffer = new Filer.Buffer([1, 2, 3, 4, 5, 6, 7, 8]); var buffer = Filer.Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]);
fs.open('/myfile', 'w', function(err, fd) { fs.open('/myfile', 'w', function(err, fd) {
if(err) throw error; if(err) throw error;
@ -800,22 +1116,22 @@ Example:
```javascript ```javascript
fs.open('/myfile', 'r', function(err, fd) { fs.open('/myfile', 'r', function(err, fd) {
if(err) throw error; if(err) throw err;
// Determine size of file // Determine size of file
fs.fstat(fd, function(err, stats) { fs.fstat(fd, function(err, stats) {
if(err) throw error; if(err) throw err;
// Create a buffer large enough to hold the file's contents // Create a buffer large enough to hold the file's contents
var nbytes = expected = stats.size; var nbytes = expected = stats.size;
var buffer = new Filer.Buffer(nbytes); var buffer = Filer.Buffer.alloc(nbytes);
var read = 0; var read = 0;
function readBytes(offset, position, length) { function readBytes(offset, position, length) {
length = length || buffer.length - read; length = length || buffer.length - read;
fs.read(fd, buffer, offset, length, position, function(err, nbytes) { fs.read(fd, buffer, offset, length, position, function(err, nbytes) {
if(err) throw error; if(err) throw err;
// nbytes is now the number of bytes read, between 0 and buffer.length. // nbytes is now the number of bytes read, between 0 and buffer.length.
// See if we still have more bytes to read. // See if we still have more bytes to read.
@ -866,7 +1182,7 @@ fs.writeFile('/myfile.txt', "...data...", function (err) {
}); });
// Write binary file // Write binary file
var buffer = new Filer.Buffer([1, 2, 3, 4, 5, 6, 7, 8]); var buffer = Filer.Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]);
fs.writeFile('/myfile', buffer, function (err) { fs.writeFile('/myfile', buffer, function (err) {
if (err) throw err; if (err) throw err;
}); });
@ -889,8 +1205,8 @@ fs.appendFile('/myfile.txt', "Data...", function (err) {
// '/myfile.txt' would now read out 'More...Data...' // '/myfile.txt' would now read out 'More...Data...'
// Append binary file // Append binary file
var data = new Filer.Buffer([1, 2, 3, 4]); var data = Filer.Buffer.from([1, 2, 3, 4]);
var more = new Filer.Buffer([5, 6, 7, 8]); var more = Filer.Buffer.from([5, 6, 7, 8]);
fs.writeFile('/myfile', data, function (err) { fs.writeFile('/myfile', data, function (err) {
if (err) throw err; if (err) throw err;
@ -1088,20 +1404,31 @@ fs.writeFile('/data/subdir/file', 'data');
### FileSystemShell<a name="FileSystemShell"></a> ### FileSystemShell<a name="FileSystemShell"></a>
Many common file system shell operations are available by using a `FileSystemShell` object. Many common file system shell operations are available by using a `FileSystemShell` object.
The `FileSystemShell` is obtained from, and used in conjuction with a `FileSystem`, The `FileSystemShell` is used in conjunction with a `FileSystem`,
and provides augmented features. Many separate `FileSystemShell` objects can exist per and provides augmented features. Many separate `FileSystemShell` objects can exist per
`FileSystem`, but each `FileSystemShell` is bound to a single instance of a `FileSystem` `FileSystem`, but each `FileSystemShell` is bound to a single instance of a `FileSystem`
for its lifetime. for its lifetime.
A `FileSystemShell` is created using the `FileSystem.Shell()` function: A `FileSystemShell` is created by instantiating `Filer.FileSystem().Shell`:
```javascript ```javascript
var fs = new Filer.FileSystem(); var fs = new Filer.FileSystem();
var sh = fs.Shell(options); var sh = new fs.Shell(options);
var sh2 = fs.Shell(options); var sh2 = new fs.Shell(options);
// sh and sh2 are two separate shells, each bound to fs // sh and sh2 are two separate shells, each bound to fs
``` ```
In addition, the constructor function can be accessed through `Filer`:
```javascript
var fs = new Filer.FileSystem();
var sh = new fs.Shell();
Filer.Shell.prototype.newFunction = ...;
sh.newFunction();
```
The `FileSystemShell` can take an optional `options` object. The `options` object The `FileSystemShell` can take an optional `options` object. The `options` object
can include `env`, which is a set of environment variables. Currently supported variables can include `env`, which is a set of environment variables. Currently supported variables
include `TMP` (the path to the temporary directory), and `PATH` (the list of known paths) and include `TMP` (the path to the temporary directory), and `PATH` (the list of known paths) and
@ -1109,7 +1436,7 @@ others may be added in the future. You can also add your own, or update existing
```javascript ```javascript
var fs = new Filer.FileSystem(); var fs = new Filer.FileSystem();
var sh = fs.Shell({ var sh = new fs.Shell({
env: { env: {
TMP: '/tempdir', TMP: '/tempdir',
PATH: '/one:/two' PATH: '/one:/two'
@ -1135,7 +1462,7 @@ Example:
```javascript ```javascript
var fs = new Filer.FileSystem(); var fs = new Filer.FileSystem();
var sh = fs.Shell(); var sh = new fs.Shell();
var p = sh.env.get('PATH'); var p = sh.env.get('PATH');
// Store the current location // Store the current location
@ -1155,11 +1482,12 @@ examples below assume a `FileSystemShell` instance named `sh` has been created l
```javascript ```javascript
var fs = new Filer.FileSystem(); var fs = new Filer.FileSystem();
var sh = fs.Shell(); var sh = new fs.Shell();
``` ```
* [sh.cd(path, callback)](#cd) * [sh.cd(path, callback)](#cd)
* [sh.pwd()](#pwd) * [sh.pwd()](#pwd)
* [sh.find(dir, [options], callback)](#find)
* [sh.ls(dir, [options], callback)](#ls) * [sh.ls(dir, [options], callback)](#ls)
* [sh.exec(path, [args], callback)](#exec) * [sh.exec(path, [args], callback)](#exec)
* [sh.touch(path, [options], callback)](#touch) * [sh.touch(path, [options], callback)](#touch)
@ -1188,20 +1516,71 @@ sh.cd('/dir1', function(err) {
Returns the shell's current working directory. See [sh.cd()](#cd). Returns the shell's current working directory. See [sh.cd()](#cd).
#### sh.find(dir, [options], callback)<a name="find"></a>
Recursively walk a directory tree, reporting back all paths that were
found along the way. Asynchronous [find(1)](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/find.html
)
If given no options, `find` walks the given dir path
and the callback gives `function(err, found)`, where `found` is an array of
all paths discovered during a depth-first walk.
Valid options include a `regex` for pattern matching paths, allowing paths
to be ignored (e.g., ```regex: /\.bak$/``` to find all `.bak` files). You can
also use `name` and `path` to provide a [match pattern](https://github.com/isaacs/minimatch) for the basename and
dirname respectively (e.g., `{name: '*.js'}` to find all JavaScript files or
`{path: '*-modules'}` to only look in folders named `base-modules`, `foo-modules`, etc.).
Finally, you can also provide an `exec` function of the form `function(path, next)` where
`path` is the current path that was found and matches any provided `regex`
(NOTE: dir paths have an '/' appended), and `next` is a callback to call
when you are done processing the path.
Example:
```javascript
function processPath(path, next) {
// Process the path somehow, in this case we print it.
// Dir paths end with /
if(path.endsWith('/')) {
console.log('Found dir: ' + path);
} else {
console.log('Found file: ' + path);
}
// All done, let the process continue by invoking second arg:
next();
}
// Get every path (NOTE: no name or regex provided) below the root, depth first
sh.find('/', {exec: processPath}, function(err, found) {
/* find command is finished, `found` contains the flattened list as an Array */
});
// Find all files that look like map201.jpg, map202.jpg in the /data dir
sh.find('/data', {regex: /map20\d\.jpg$/, exec: processPath}, function(err) {
/* find command is finished */
});
// Find and delete all *.bak files under /app/user
sh.find('/app/user', {
name: '*.bak',
exec: function(path, next) {
sh.rm(path, next);
}
}, function callback(err, found) {
if(err) throw err;
if(found.length) {
console.log('Deleted the following ' + found.length + ' files: ', found);
}
});
```
#### sh.ls(dir, [options], callback)<a name="ls"></a> #### sh.ls(dir, [options], callback)<a name="ls"></a>
Get the listing of a directory, returning an array of directory entries Get the listing of a directory, returning an array of directory entries
in the following form: in the same form as [fs.stat()](#stat), with the exception that a new Array named
``` `contents` is added for directory entries, containing child entries.
{
path: <String> the basename of the directory entry
links: <Number> the number of links to the entry
size: <Number> the size in bytes of the entry
modified: <Number> the last modified date/time
type: <String> the type of the entry
contents: <Array> an optional array of child entries, if this entry is itself a directory
}
```
By default `sh.ls()` gives a shallow listing. If you want to follow By default `sh.ls()` gives a shallow listing. If you want to follow
directories as they are encountered, use the `recursive=true` option. NOTE: directories as they are encountered, use the `recursive=true` option. NOTE:

View File

@ -1,15 +0,0 @@
{
"name": "filer",
"version": "0.0.35",
"main": "dist/filer.js",
"ignore": [
"build",
"examples",
"package.json",
"tests",
"gruntfile.js",
"node_modules",
"src",
"tools"
]
}

View File

@ -1,5 +0,0 @@
module.exports = (function() {
var habitat = require('habitat');
habitat.load();
return new habitat();
})();

16656
dist/filer-test.js vendored

File diff suppressed because it is too large Load Diff

24657
dist/filer.js vendored

File diff suppressed because it is too large Load Diff

1
dist/filer.js.map vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/filer.map vendored Normal file

File diff suppressed because one or more lines are too long

253
dist/filer.min.js vendored

File diff suppressed because one or more lines are too long

1
dist/filer.min.js.map vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/filer.min.map vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,14 +1,9 @@
### ###
# Dev ENVIRONMENT file # Dev ENVIRONMENT file
# #
# Copy to .env to use defaults # Copy to .env to use defaults when releasing via `npm release`
### ###
# GIT (upstream) url to publish to # GitHub Personal Access Token (to push releases)
export FILER_UPSTREAM_URI="git@github.com:js-platform/filer.git" # https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/
GITHUB_TOKEN=
# GIT (upstream) branch to publish to
export FILER_UPSTREAM_BRANCH="develop"
# Remote name for upstream repo
export FILER_UPSTREAM_REMOTE_NAME="origin"

View File

@ -1,231 +0,0 @@
var semver = require('semver'),
fs = require('fs'),
currentVersion = JSON.parse(fs.readFileSync('./package.json', 'utf8')).version,
env = require('./config/environment');
// Globals
var PROMPT_CONFIRM_CONFIG = 'confirmation',
GIT_BRANCH = env.get('FILER_UPSTREAM_BRANCH'),
GIT_REMOTE = env.get('FILER_UPSTREAM_REMOTE_NAME'),
GIT_FULL_REMOTE = env.get('FILER_UPSTREAM_URI') + ' ' + GIT_BRANCH;
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
clean: ['dist/filer-test.js', 'dist/filer-issue225.js'],
uglify: {
options: {
banner: '/*! <%= pkg.name %> <%= pkg.version %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
},
develop: {
src: 'dist/filer.js',
dest: 'dist/filer.min.js'
}
},
jshint: {
// Don't bother with src/path.js
all: [
'gruntfile.js',
'config/environment.js',
'src/constants.js',
'src/errors.js',
'src/fs.js',
'src/index.js',
'src/shared.js',
'src/shell.js',
'src/fswatcher.js',
'src/environment.js',
'src/providers/**/*.js',
'src/adapters/**/*.js',
'src/directory-entry.js',
'src/open-file-description.js',
'src/super-node.js',
'src/node.js',
'src/stats.js',
'src/filesystem/**/*.js'
]
},
browserify: {
filerDist: {
src: "./src/index.js",
dest: "./dist/filer.js",
options: {
browserifyOptions: {
commondir: false
},
bundleOptions: {
standalone: 'Filer'
},
exclude: ["./node_modules/request/index.js"]
}
},
filerTest: {
src: "./tests/index.js",
dest: "./dist/filer-test.js"
},
// See tests/bugs/issue225.js
filerIssue225: {
src: "./src/index.js",
dest: "./dist/filer-issue225.js",
options: {
browserifyOptions: {
commondir: false
},
bundleOptions: {
standalone: 'Filer'
}
}
}
},
shell: {
mocha: {
// Run all tests (e.g., tests require()'ed in tests/index.js) and also tests/bugs/issue225.js
// separately, since it can't be included in a browserify build.
command: '"./node_modules/.bin/mocha" --reporter list tests/index.js && "./node_modules/.bin/mocha" --reporter list tests/bugs/issue225.js'
}
},
bump: {
options: {
files: ['package.json', 'bower.json'],
commit: true,
commitMessage: 'v%VERSION%',
commitFiles: ['package.json', 'bower.json', './dist/filer.js', './dist/filer.min.js', './dist/filer-test.js'],
createTag: true,
tagName: 'v%VERSION%',
tagMessage: 'v%VERSION%',
push: true,
pushTo: GIT_FULL_REMOTE
}
},
'npm-checkBranch': {
options: {
branch: GIT_BRANCH
}
},
'npm-publish': {
options: {
abortIfDirty: false
}
},
prompt: {
confirm: {
options: {
questions: [
{
config: PROMPT_CONFIRM_CONFIG,
type: 'confirm',
message: 'Bump version from ' + (currentVersion).cyan +
' to ' + semver.inc(currentVersion, "patch").yellow + '?',
default: false
}
],
then: function(results) {
if (!results[PROMPT_CONFIRM_CONFIG]) {
return grunt.fatal('User aborted...');
}
}
}
}
},
gitcheckout: {
publish: {
options: {
branch: 'gh-pages',
overwrite: true
}
},
revert: {
options: {
branch: GIT_BRANCH
}
}
},
gitpush: {
publish: {
options: {
remote: GIT_REMOTE,
branch: 'gh-pages',
force: true
},
}
},
connect: {
serverForNode: {
options: {
port: 1234,
base: '.'
}
},
serverForBrowser: {
options: {
port: 1234,
base: '.',
keepalive: true
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-bump');
grunt.loadNpmTasks('grunt-npm');
grunt.loadNpmTasks('grunt-git');
grunt.loadNpmTasks('grunt-prompt');
grunt.loadNpmTasks('grunt-shell');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-browserify');
grunt.registerTask('develop', ['clean', 'browserify']);
grunt.registerTask('build-tests', ['clean', 'browserify:filerTest']);
grunt.registerTask('release', ['test', 'develop', 'uglify']);
grunt.registerTask('publish', 'Publish filer as a new version to NPM, bower and github.', function(patchLevel) {
var allLevels = ['patch', 'minor', 'major'];
// No level specified defaults to 'patch'
patchLevel = (patchLevel || 'patch').toLowerCase();
// Fail out if the patch level isn't recognized
if (allLevels.filter(function(el) { return el == patchLevel; }).length === 0) {
return grunt.fatal('Patch level not recognized! "Patch", "minor" or "major" only.');
}
// Set prompt message
var promptOpts = grunt.config('prompt.confirm.options');
promptOpts.questions[0].message = 'Bump version from ' + (currentVersion).cyan +
' to ' + semver.inc(currentVersion, patchLevel).yellow + '?';
grunt.config('prompt.confirm.options', promptOpts);
grunt.task.run([
'prompt:confirm',
'checkBranch',
'release',
'bump:' + patchLevel,
'gitcheckout:publish',
'gitpush:publish',
'gitcheckout:revert',
'npm-publish'
]);
});
grunt.registerTask('test-node', ['jshint', 'browserify:filerIssue225', 'connect:serverForNode', 'shell:mocha']);
grunt.registerTask('test-browser', ['jshint', 'build-tests', 'connect:serverForBrowser']);
grunt.registerTask('test', ['clean', 'test-node']);
grunt.registerTask('default', ['test']);
};

28
karma.conf.js Normal file
View File

@ -0,0 +1,28 @@
module.exports = function(config) {
config.set({
singleRun: true,
basePath: '',
files: [
'node_modules/regenerator-runtime/runtime.js',
'tests/dist/index.js'
],
frameworks: ['mocha', 'chai'],
reporters: ['mocha', 'summary'],
client: {
captureConsole: true,
mocha: {
ui: 'bdd',
timeout: 5000,
slow: 250
}
},
summaryReporter: {
// 'failed', 'skipped' or 'all'
show: 'failed',
// Limit the spec label to this length
specLength: 50,
// Show an 'all' column as a summary
overviewColumn: true
}
});
};

View File

@ -1,97 +0,0 @@
// Cherry-picked bits of underscore.js, lodash.js
/**
* Lo-Dash 2.4.0 <http://lodash.com/>
* Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.5.2 <http://underscorejs.org/LICENSE>
* Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <http://lodash.com/license>
*/
var ArrayProto = Array.prototype;
var nativeForEach = ArrayProto.forEach;
var nativeIndexOf = ArrayProto.indexOf;
var nativeSome = ArrayProto.some;
var ObjProto = Object.prototype;
var hasOwnProperty = ObjProto.hasOwnProperty;
var nativeKeys = Object.keys;
var breaker = {};
function has(obj, key) {
return hasOwnProperty.call(obj, key);
}
var keys = nativeKeys || function(obj) {
if (obj !== Object(obj)) throw new TypeError('Invalid object');
var keys = [];
for (var key in obj) if (has(obj, key)) keys.push(key);
return keys;
};
function size(obj) {
if (obj == null) return 0;
return (obj.length === +obj.length) ? obj.length : keys(obj).length;
}
function identity(value) {
return value;
}
function each(obj, iterator, context) {
var i, length;
if (obj == null) return;
if (nativeForEach && obj.forEach === nativeForEach) {
obj.forEach(iterator, context);
} else if (obj.length === +obj.length) {
for (i = 0, length = obj.length; i < length; i++) {
if (iterator.call(context, obj[i], i, obj) === breaker) return;
}
} else {
var keys = keys(obj);
for (i = 0, length = keys.length; i < length; i++) {
if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
}
}
};
function any(obj, iterator, context) {
iterator || (iterator = identity);
var result = false;
if (obj == null) return result;
if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
each(obj, function(value, index, list) {
if (result || (result = iterator.call(context, value, index, list))) return breaker;
});
return !!result;
};
function contains(obj, target) {
if (obj == null) return false;
if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
return any(obj, function(value) {
return value === target;
});
};
function Wrapped(value) {
this.value = value;
}
Wrapped.prototype.has = function(key) {
return has(this.value, key);
};
Wrapped.prototype.contains = function(target) {
return contains(this.value, target);
};
Wrapped.prototype.size = function() {
return size(this.value);
};
function nodash(value) {
// don't wrap if already wrapped, even if wrapped by a different `lodash` constructor
return (value && typeof value == 'object' && !Array.isArray(value) && hasOwnProperty.call(value, '__wrapped__'))
? value
: new Wrapped(value);
}
module.exports = nodash;

13903
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -5,48 +5,91 @@
"fs", "fs",
"node", "node",
"file", "file",
"system", "filesystem",
"browser", "browser",
"indexeddb", "indexeddb",
"idb", "idb"
"websql"
], ],
"version": "0.0.35", "version": "1.4.1",
"author": "Alan K <ack@modeswitch.org> (http://blog.modeswitch.org)", "author": "Alan K <ack@modeswitch.org> (http://blog.modeswitch.org)",
"homepage": "http://filerjs.github.io/filer", "homepage": "http://filerjs.github.io/filer",
"bugs": "https://github.com/filerjs/filer/issues", "bugs": "https://github.com/filerjs/filer/issues",
"license": "BSD", "license": "BSD-2-Clause",
"scripts": { "scripts": {
"test": "grunt test" "eslint": "npm run lint",
"eslint:fix": "npm run lint:fix",
"lint": "eslint src tests",
"lint:fix": "eslint --fix src tests",
"test:node": "mocha --timeout 5000 tests",
"pretest:node-debug": "echo \"Open Chrome to chrome://inspect to debug tests...\"",
"test:node-debug": "mocha --timeout 5000 --inspect-brk tests",
"test:manual": "parcel tests/index.html --out-dir tests/dist",
"test:migrations": "mocha tests/filesystems/migrations",
"pretest": "npm run lint",
"test": "npm run karma-mocha",
"posttest": "npm run test:migrations",
"prebuild": "parcel build --global Filer src/index.js --no-minify --out-file filer.js",
"build": "parcel build --global Filer src/index.js --out-file filer.min.js --detailed-report",
"build-tests": "parcel build tests/index.js --no-source-maps --out-dir tests/dist",
"prekarma-mocha-firefox": "npm run build-tests",
"karma-mocha-firefox": "karma start karma.conf.js --browsers FirefoxHeadless",
"prekarma-mocha-chrome": "npm run build-tests",
"karma-mocha-chrome": "karma start karma.conf.js --browsers ChromeHeadless",
"prekarma-mocha": "npm run build-tests",
"karma-mocha": "karma start karma.conf.js --browsers ChromeHeadless,FirefoxHeadless",
"coverage": "nyc mocha tests/index.js",
"release": "run.env release-it"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/filerjs/filer.git" "url": "https://github.com/filerjs/filer.git"
}, },
"dependencies": { "dependencies": {
"bower": "~1.3.8", "es6-promisify": "^7.0.0",
"base64-arraybuffer": "^0.1.2" "minimatch": "^3.0.4",
"schema-utils": "^3.1.1"
}, },
"devDependencies": { "devDependencies": {
"chai": "~1.9.1", "regenerator-runtime": "^0.13.9",
"grunt": "~0.4.0", "chai": "^4.3.4",
"grunt-browserify": "^2.1.0", "chai-datetime": "^1.8.0",
"grunt-bump": "0.0.13", "eslint": "^7.32.0",
"grunt-contrib-clean": "~0.4.0", "fake-indexeddb": "^3.1.7",
"grunt-contrib-compress": "~0.4.1", "karma": "^6.3.8",
"grunt-contrib-concat": "~0.1.3", "karma-chai": "^0.1.0",
"grunt-contrib-connect": "^0.7.1", "karma-chrome-launcher": "^3.1.0",
"grunt-contrib-jshint": "~0.7.1", "karma-firefox-launcher": "^2.1.2",
"grunt-contrib-uglify": "~0.1.2", "karma-mocha": "^2.0.1",
"grunt-contrib-watch": "~0.3.1", "karma-mocha-reporter": "^2.2.5",
"grunt-git": "0.2.10", "karma-summary-reporter": "^3.0.0",
"grunt-npm": "git://github.com/sedge/grunt-npm.git#branchcheck", "meow": "^10.0.1",
"grunt-prompt": "^1.1.0", "mocha": "^9.1.3",
"grunt-shell": "~0.7.0", "nyc": "^15.1.0",
"habitat": "^1.1.0", "parcel-bundler": "^1.12.5",
"mocha": "~1.18.2", "pretty-bytes": "^5.6.0",
"semver": "^2.3.0", "release-it": "^14.11.6",
"requirejs": "^2.1.14" "run.env": "^1.1.0",
"unused-filename": "^3.0.1",
"walk": "^2.3.15"
}, },
"main": "./src/index.js" "main": "./src/index.js",
"browser": "./dist/filer.min.js",
"files": [
"src",
"lib",
"dist",
"shims",
"webpack"
],
"nyc": {
"exclude": [
"tests/**/*.js",
"lib/**/*.js",
"src/providers/**/*.js"
],
"reporter": [
"lcov",
"text"
]
}
} }

13
perf/index.html Normal file
View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<progress id="progress" value=0></progress>
<div id="output"></div>
<div id="stderr"></div>
</body>
<script type="text/javascript" src="simple-statistics/src/simple_statistics.js"></script>
<script src="../dist/filer-perf.js"></script>
</html>

119
perf/index.js Normal file
View File

@ -0,0 +1,119 @@
var util = require('../tests/lib/test-utils.js');
function setImmediate(cb) {
setTimeout(cb, 0);
}
function parse_query() {
var query = window.location.search.substring(1);
var parsed = {};
query.split('&').forEach(function(pair) {
pair = pair.split('=');
var key = decodeURIComponent(pair[0]);
var value = decodeURIComponent(pair[1]);
parsed[key] = value;
});
return parsed;
}
var query = parse_query();
function time(test, cb) {
var start = performance.now();
function done() {
var end = performance.now();
cb(end - start);
}
test(done);
}
var random_data = new Buffer(1024); // 1kB buffer
var read_buffer = new Buffer(1024);
function run(iter) {
iter = (undefined == iter) ? 0 : iter;
function before() {
util.setup(function() {
setImmediate(during);
});
}
function during() {
var fs = util.fs();
window.crypto.getRandomValues(random_data);
time(function(done) {
fs.mkdir('/tmp', function(err) {
fs.stat('/tmp', function(err, stats) {
fs.open('/tmp/test', 'w', function(err, fd) {
fs.write(fd, random_data, null, null, null, function(err, nbytes) {
fs.close(fd, function(err) {
fs.stat('/tmp/test', function(err, stats) {
fs.open('/tmp/test', 'r', function(err, fd) {
fs.read(fd, read_buffer, null, null, null, function(err, nbytes) {
fs.close(fd, function(err) {
fs.unlink('/tmp/test', function(err) {
done();
});});});});});});});});});});
}, after);
}
function after(dt) {
util.cleanup(complete.bind(null, iter, dt));
}
before();
}
var results = [];
function complete(iter, result) {
results.push(result);
if(++iter < iterations) {
setImmediate(run.bind(null, iter));
} else {
do_stats();
}
progress.value = iter;
}
function do_stats() {
var output = document.getElementById("output");
var stats = {
mean: ss.mean(results) + " ms",
min: ss.min(results),
max: ss.max(results),
med_abs_dev: ss.median_absolute_deviation(results),
};
var t = document.createElement("table");
var tbody = document.createElement("tbody");
var keys = Object.keys(stats);
keys.forEach(function(key) {
var row = document.createElement("tr");
var key_cell = document.createElement("td");
var key_cell_text = document.createTextNode(key);
key_cell.appendChild(key_cell_text);
row.appendChild(key_cell);
var val_cell = document.createElement("td");
var val_cell_text = document.createTextNode(stats[key]);
val_cell.appendChild(val_cell_text);
row.appendChild(val_cell);
tbody.appendChild(row);
});
t.appendChild(tbody);
output.appendChild(t);
}
var query = parse_query();
var iterations = query.iterations || 10;
var progress = document.getElementById("progress");
progress.max = iterations;
run();

3
perf/simple-statistics/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
components
build
node_modules

View File

@ -0,0 +1,8 @@
{
"indent": 4,
"undef": true,
"unused": true,
"globals": {
"require": true
}
}

View File

@ -0,0 +1,7 @@
language: node_js
node_js:
- 0.10
script:
- npm install
- npm test
- npm run cov

View File

@ -0,0 +1,242 @@
Basic contracts of functions:
* Functions do not modify their arguments e.g. change their order
* Invalid input, like empty lists to functions that need 1+ items to work, will cause functions to return `null`.
# Basic Array Operations
### .mixin(array)
_Optionally_ mix in the following functions into the `Array` prototype. Otherwise
you can use them off of the simple-statistics object itself.
If given a particular array instance as an argument, this adds the functions
only to that array rather than the global `Array.prototype`. Without an argument,
it runs on the global `Array.prototype`.
### .mean(x)
Mean of a single-dimensional Array of numbers. _Also available as `.average(x)`_
### .sum(x)
Sum of a single-dimensional Array of numbers.
### .mode(x)
Returns the number that appears most frequently in a single-dimensional Array
of numbers. If there are multiple modes, the one that appears last
is returned.
### .variance(x)
[Variance](http://en.wikipedia.org/wiki/Variance) of a single-dimensional Array of numbers.
### .standard_deviation(x)
[Standard Deviation](http://en.wikipedia.org/wiki/Standard_deviation) of a single-dimensional Array of numbers.
### .sample(array, n)
Return a [simple random sample](http://en.wikipedia.org/wiki/Simple_random_sample)
of the given array. The sampling is _without replacement_, and uses a Fisher-Yates
sample to randomize.
### .median_absolute_deviation(x)
The Median Absolute Deviation (MAD) is a robust measure of statistical
dispersion. It is more resilient to outliers than the standard deviation.
Accepts a single-dimensional array of numbers and returns a dispersion value.
Also aliased to `.mad(x)` for brevity.
### .median(x)
[Median](http://en.wikipedia.org/wiki/Median) of a single-dimensional array of numbers.
### .geometric_mean(x)
[Geometric mean](http://en.wikipedia.org/wiki/Geometric_mean) of a single-dimensional array of **positive** numbers.
### .harmonic_mean(x)
[Harmonic mean](http://en.wikipedia.org/wiki/Harmonic_mean) of a single-dimensional array of **positive** numbers.
### .root_mean_square(x)
[Root mean square (RMS)](http://en.wikipedia.org/wiki/Root_mean_square) of a single-dimensional array of numbers.
Also aliased to `.rms(x)` for brevity.
### .min(x)
Finds the minimum of a single-dimensional array of numbers. This runs in linear `O(n)` time.
### .max(x)
Finds the maximum of a single-dimensional array of numbers. This runs in linear `O(n)` time.
### .t_test(sample, x)
Does a [student's t-test](http://en.wikipedia.org/wiki/Student's_t-test) of a dataset `sample`, represented by a single-dimensional array of numbers. `x` is the known value, and the result is a measure of [statistical significance](http://en.wikipedia.org/wiki/Statistical_significance).
### .t_test_two_sample(sample_x, sample_y, difference)
The two-sample t-test is used to compare samples from two populations or groups,
confirming or denying the suspicion (null hypothesis) that the populations are
the same. It returns a t-value that you can then look up to give certain
judgements of confidence based on a t distribution table.
This implementation expects the samples `sample_x` and `sample_y` to be given
as one-dimensional arrays of more than one number each.
### .sample_variance(x)
Produces [sample variance](http://mathworld.wolfram.com/SampleVariance.html)
of a single-dimensional array of numbers.
### .sample_covariance(a, b)
Produces [sample covariance](http://en.wikipedia.org/wiki/Sample_mean_and_sample_covariance)
of two single-dimensional arrays of numbers.
### .sample_correlation(a, b)
Produces [sample correlation](http://en.wikipedia.org/wiki/Correlation_and_dependence)
of two single-dimensional arrays of numbers.
### .quantile(sample, p)
Does a [quantile](http://en.wikipedia.org/wiki/Quantile) of a dataset `sample`,
at p. For those familiary with the `k/q` syntax, `p == k/q`. `sample` must
be a single-dimensional array of numbers. p must be a number greater than or equal to
than zero and less or equal to than one, or an array of numbers following that rule.
If an array is given, an array of results will be returned instead of a single
number.
### .chunk(sample, chunkSize)
Given a `sample` array, and a positive integer `chunkSize`, splits an array
into chunks of `chunkSize` size and returns an array of those chunks. This
does not change the input value. If the length of `sample` is not divisible
by `chunkSize`, the last array will be shorter than the rest.
### .shuffle(sample)
Given a `sample` array (with any type of contents), return a random permutation
of that array, using the [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle)
algorithm.
### .shuffle_in_place(sample)
Given a `sample` array (with any type of contents), return a random permutation
of that array, using the [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle)
algorithm.
This changes the input array in-place, as well as returns it - unlike `.shuffle()`,
it does not create a shallow copy of the array.
### .quantile_sorted(sample, p)
Does a [quantile](http://en.wikipedia.org/wiki/Quantile) of a dataset `sample`,
at p. `sample` must be a one-dimensional _sorted_ array of numbers, and
`p` must be a single number from zero to one.
### .iqr(sample)
Calculates the [Interquartile range](http://en.wikipedia.org/wiki/Interquartile_range) of
a sample - the difference between the upper and lower quartiles. Useful
as a measure of dispersion.
_Also available as `.interquartile_range(x)`_
### .sample_skewness(sample)
Calculates the [skewness](http://en.wikipedia.org/wiki/Skewness) of
a sample, a measure of the extent to which a probability distribution of a
real-valued random variable "leans" to one side of the mean.
The skewness value can be positive or negative, or even undefined.
This implementation uses the [Fisher-Pearson standardized moment coefficient](http://en.wikipedia.org/wiki/Skewness#Pearson.27s_skewness_coefficients),
which means that it behaves the same as Excel, Minitab, SAS, and SPSS.
Skewness is only valid for samples of over three values.
### .jenks(data, number_of_classes)
Find the [Jenks Natural Breaks](http://en.wikipedia.org/wiki/Jenks_natural_breaks_optimization) for
a single-dimensional array of numbers as input and a desired `number_of_classes`.
The result is a single-dimensional with class breaks, including the minimum
and maximum of the input array.
### .r_squared(data, function)
Find the [r-squared](http://en.wikipedia.org/wiki/Coefficient_of_determination) value of a particular dataset, expressed as a two-dimensional `Array` of numbers, against a `Function`.
var r_squared = ss.r_squared([[1, 1]], function(x) { return x * 2; });
### .cumulative_std_normal_probability(z)
Look up the given `z` value in a [standard normal table](http://en.wikipedia.org/wiki/Standard_normal_table)
to calculate the probability of a random variable appearing with a given value.
### .z_score(x, mean, standard_deviation)
The standard score is the number of standard deviations an observation
or datum is above or below the mean.
### .standard_normal_table
A [standard normal table](http://en.wikipedia.org/wiki/Standard_normal_table) from
which to pull values of Φ (phi).
## Regression
### .linear_regression()
Create a new linear regression solver.
#### .data([[1, 1], [2, 2]])
Set the data of a linear regression. The input is a two-dimensional array of numbers, which are treated as coordinates, like `[[x, y], [x1, y1]]`.
#### .line()
Get the linear regression line: this returns a function that you can
give `x` values and it will return `y` values. Internally, this uses the `m()`
and `b()` values and the classic `y = mx + b` equation.
var linear_regression_line = ss.linear_regression()
.data([[0, 1], [2, 2], [3, 3]]).line();
linear_regression_line(5);
#### .m()
Just get the slope of the fitted regression line, the `m` component of the full
line equation. Returns a number.
#### .b()
Just get the y-intercept of the fitted regression line, the `b` component
of the line equation. Returns a number.
## Classification
### .bayesian()
Create a naïve bayesian classifier.
### .train(item, category)
Train the classifier to classify a certain item, given as an object with keys,
to be in a certain category, given as a string.
### .score(item)
Get the classifications of a certain item, given as an object of
`category -> score` mappings.
var bayes = ss.bayesian();
bayes.train({ species: 'Cat' }, 'animal');
bayes.score({ species: 'Cat' });
// { animal: 1 }

View File

@ -0,0 +1,60 @@
# CHANGELOG
## 0.9.0
* Adds `.sample` for simple random sampling
* Adds `.shuffle` and `.shuffle_in_place` for random permutations
* Adds `.chunk` for splitting arrays into chunked subsets
## 0.8.1
* fixes a bug in `mode` that favored the last new number
## 0.8.0
* `mixin` can now take an array in order to mixin functions into a single array
instance rather than the global Array prototype.
## 0.7.0
* Adds `simple_statistics.harmonic_mean` thanks to [jseppi](https://github.com/jseppi)
## 0.6.0
* Adds `simple_statistics.quantile_sorted` thanks to [rluta](http://github.com/rluta)
* `simple_statistics.quantile` now accepts a sorted list of quantiles as a second argument
* Improved test coverage
## 0.5.0
* Adds `simple_statistics.cumulative_std_normal_probability` by [doronlinder](https://github.com/doronlinder)
* Adds `simple_statistics.z_score` by doronlinder
* Adds `simple_statistics.standard_normal_table`
## 0.4.0
* Adds `simple_statistics.median_absolute_deviation()` by siculars
* Adds `simple_statistics.iqr()` by siculars
* Adds `simple_statistics.skewness()` by Doron Linder
* Lower-level accessors for linear regression allow users to do the line
equation themselves
## 0.3.0
* Adds `simple_statistics.jenks()`
* Adds `simple_statistics.jenksMatrices()`
* Improves test coverage and validation
## 0.2.0
* Adds `simple_statistics.quantile()`
* Adds `simple_statistics.mixin()`
* Adds `simple_statistics.geometric_mean()`
* Adds `simple_statistics.sample_variance()`
* Adds `simple_statistics.sample_covariance()`
## 0.1.0
* Adds `simple_statistics.t_test()`
* Adds `simple_statistics.min()`
* Adds `simple_statistics.max()`

View File

@ -0,0 +1,99 @@
# Contributing to simple-statistics
Simple statistics is a statistics library that can be both used and read.
It should help programmers learn statistics and statisticians learn programming.
In order to achieve this goal, it must be **simple** and **explanatory**.
## Simple
`simple-statistics` is written in a subset of JavaScript. Unused features
include:
* [Conditional Operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator)
* [ES5 Array methods](http://ie.microsoft.com/TestDrive/HTML5/ECMAScript5Array/Default.html)
* `with`, `eval`, and other forms of `eval`
* Most micro-optimizations, like [alternative for loop forms](http://jsperf.com/loops/70)
* [Shortcut branching](http://javascriptweblog.wordpress.com/2010/07/26/no-more-ifs-alternatives-to-statement-branching-in-javascript/)
## Explanatory
Example:
```js
// # harmonic mean
//
// a mean function typically used to find the average of rates
//
// this is the reciprocal of the arithmetic mean of the reciprocals
// of the input numbers
//
// This runs on `O(n)`, linear time in respect to the array
```
`simple-statistics` tries to stay away from speaking only in the language of math:
for instance, while JavaScript supports UTF8 characters like π, they are not used
in the source:
* UTF8 in JavaScript on pages without specific meta-tag or Content-Type encodings will fail
* UTF8 can be hard to type, since users need to memorize key combinations or code points
* Mathematical symbols have meanings that are often better communicated by words:
in the form of code, we do not run out of space on the paper, and can afford
to call a variable `reciprocal_sum` instead of `r`.
Every function has a comment that ideally includes:
* The English, long-form name of the method
* What the method does
* What purpose the method typically serves
* A link to a longer description on Wikipedia, Mathematica, or another
web-accessible, non-paywalled source
* The efficiency of the function in terms of Big-O notation, if appropriate
* If the function depends on another function in the library, a note of this, like
`depends on mean()`
## Tests
`simple-statistics` has a testsuite located in `test/spec/`. Each test file
covers a specific topic and tries to test against known values:
* Values produced by trusted statistics software like R or scipy
* Common-sense results
Tests can be run in [node.js](http://nodejs.org/) and are run on every commit
to GitHub by Travis-CI.
To run tests:
```sh
npm install
npm test
```
## Documentation
While the code is meant to readable, it is not documentation. We maintain
documentation in `API.md`, which has the simple form:
```md
### .geometric_mean(x)
[Geometric mean](http://en.wikipedia.org/wiki/Geometric_mean) of a single-dimensional array of **positive** numbers.
```
This file is written in [Markdown](https://daringfireball.net/projects/markdown/) and
specifies which functions are available, what type of arguments they receive,
what they compute, and what type of answer they return.
## Code Style
We use the [Airbnb style for Javascript](https://github.com/airbnb/javascript) with
only one difference:
**4 space soft tabs always for Javascript, not 2.**
No aligned `=`, no aligned arguments, spaces are either indents or the 1
space between expressions. No hard tabs.
* All comparisons should be as strict and obvious as possible: prefer `(foo === 0)` to
`(!foo)`.
* Straightforward code is more important than most optimizations.

View File

@ -0,0 +1,13 @@
Copyright (c) 2014, Tom MacWright
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.

View File

@ -0,0 +1,7 @@
docs:
docco src/*.js
test:
mocha -R spec test/spec/*.js
.PHONY: docs test

View File

@ -0,0 +1,337 @@
[![Build Status](https://secure.travis-ci.org/tmcw/simple-statistics.png?branch=master)](http://travis-ci.org/tmcw/simple-statistics) [![Coverage Status](https://coveralls.io/repos/tmcw/simple-statistics/badge.png)](https://coveralls.io/r/tmcw/simple-statistics)
A JavaScript implementation of descriptive, regression, and inference statistics.
Implemented in literate JavaScript with no dependencies, designed to work
in all modern browsers (including IE) as well as in node.js.
## [API Documentation](API.md)
---
Basic contracts of functions:
* Functions do not modify their arguments e.g. change their order
* Invalid input, like empty lists to functions that need 1+ items to work, will cause functions to return `null`.
# Basic Array Operations
### .mixin(array)
_Optionally_ mix in the following functions into the `Array` prototype. Otherwise
you can use them off of the simple-statistics object itself.
If given a particular array instance as an argument, this adds the functions
only to that array rather than the global `Array.prototype`. Without an argument,
it runs on the global `Array.prototype`.
### .mean(x)
Mean of a single-dimensional Array of numbers. _Also available as `.average(x)`_
### .sum(x)
Sum of a single-dimensional Array of numbers.
### .mode(x)
Returns the number that appears most frequently in a single-dimensional Array
of numbers. If there are multiple modes, the one that appears last
is returned.
### .variance(x)
[Variance](http://en.wikipedia.org/wiki/Variance) of a single-dimensional Array of numbers.
### .standard_deviation(x)
[Standard Deviation](http://en.wikipedia.org/wiki/Standard_deviation) of a single-dimensional Array of numbers.
### .median_absolute_deviation(x)
The Median Absolute Deviation (MAD) is a robust measure of statistical
dispersion. It is more resilient to outliers than the standard deviation.
Accepts a single-dimensional array of numbers and returns a dispersion value.
Also aliased to `.mad(x)` for brevity.
### .median(x)
[Median](http://en.wikipedia.org/wiki/Median) of a single-dimensional array of numbers.
### .geometric_mean(x)
[Geometric mean](http://en.wikipedia.org/wiki/Geometric_mean) of a single-dimensional array of **positive** numbers.
### .harmonic_mean(x)
[Harmonic mean](http://en.wikipedia.org/wiki/Harmonic_mean) of a single-dimensional array of **positive** numbers.
### .root_mean_square(x)
[Root mean square (RMS)](http://en.wikipedia.org/wiki/Root_mean_square) of a single-dimensional array of numbers.
### .min(x)
Finds the minimum of a single-dimensional array of numbers. This runs in linear `O(n)` time.
### .max(x)
Finds the maximum of a single-dimensional array of numbers. This runs in linear `O(n)` time.
### .t_test(sample, x)
Does a [student's t-test](http://en.wikipedia.org/wiki/Student's_t-test) of a dataset `sample`, represented by a single-dimensional array of numbers. `x` is the known value, and the result is a measure of [statistical significance](http://en.wikipedia.org/wiki/Statistical_significance).
### .t_test_two_sample(sample_x, sample_y, difference)
The two-sample t-test is used to compare samples from two populations or groups,
confirming or denying the suspicion (null hypothesis) that the populations are
the same. It returns a t-value that you can then look up to give certain
judgements of confidence based on a t distribution table.
This implementation expects the samples `sample_x` and `sample_y` to be given
as one-dimensional arrays of more than one number each.
### .sample_variance(x)
Produces [sample variance](http://mathworld.wolfram.com/SampleVariance.html)
of a single-dimensional array of numbers.
### .sample_covariance(a, b)
Produces [sample covariance](http://en.wikipedia.org/wiki/Sample_mean_and_sample_covariance)
of two single-dimensional arrays of numbers.
### .sample_correlation(a, b)
Produces [sample correlation](http://en.wikipedia.org/wiki/Correlation_and_dependence)
of two single-dimensional arrays of numbers.
### .quantile(sample, p)
Does a [quantile](http://en.wikipedia.org/wiki/Quantile) of a dataset `sample`,
at p. For those familiary with the `k/q` syntax, `p == k/q`. `sample` must
be a single-dimensional array of numbers. p must be a number greater than or equal to zero and less than or equal to one, or an array of numbers following that rule.
If an array is given, an array of results will be returned instead of a single
number.
### .chunk(sample, chunkSize)
Given a `sample` array, and a positive integer `chunkSize`, splits an array
into chunks of `chunkSize` size and returns an array of those chunks. This
does not change the input value. If the length of `sample` is not divisible
by `chunkSize`, the last array will be shorter than the rest.
### .quantile_sorted(sample, p)
Does a [quantile](http://en.wikipedia.org/wiki/Quantile) of a dataset `sample`,
at p. `sample` must be a one-dimensional _sorted_ array of numbers, and
`p` must be a single number greater than or equal to zero and less than or equal to one.
### .iqr(sample)
Calculates the [Interquartile range](http://en.wikipedia.org/wiki/Interquartile_range) of
a sample - the difference between the upper and lower quartiles. Useful
as a measure of dispersion.
_Also available as `.interquartile_range(x)`_
### .sample_skewness(sample)
Calculates the [skewness](http://en.wikipedia.org/wiki/Skewness) of
a sample, a measure of the extent to which a probability distribution of a
real-valued random variable "leans" to one side of the mean.
The skewness value can be positive or negative, or even undefined.
This implementation uses the [Fisher-Pearson standardized moment coefficient](http://en.wikipedia.org/wiki/Skewness#Pearson.27s_skewness_coefficients),
which means that it behaves the same as Excel, Minitab, SAS, and SPSS.
Skewness is only valid for samples of over three values.
### .jenks(data, number_of_classes)
Find the [Jenks Natural Breaks](http://en.wikipedia.org/wiki/Jenks_natural_breaks_optimization) for
a single-dimensional array of numbers as input and a desired `number_of_classes`.
The result is a single-dimensional with class breaks, including the minimum
and maximum of the input array.
### .r_squared(data, function)
Find the [r-squared](http://en.wikipedia.org/wiki/Coefficient_of_determination) value of a particular dataset, expressed as a two-dimensional `Array` of numbers, against a `Function`.
var r_squared = ss.r_squared([[1, 1]], function(x) { return x * 2; });
### .cumulative_std_normal_probability(z)
Look up the given `z` value in a [standard normal table](http://en.wikipedia.org/wiki/Standard_normal_table)
to calculate the probability of a random variable appearing with a given value.
### .z_score(x, mean, standard_deviation)
The standard score is the number of standard deviations an observation
or datum is above or below the mean.
### .standard_normal_table
A [standard normal table](http://en.wikipedia.org/wiki/Standard_normal_table) from
which to pull values of Φ (phi).
## Regression
### .linear_regression()
Create a new linear regression solver.
#### .data([[1, 1], [2, 2]])
Set the data of a linear regression. The input is a two-dimensional array of numbers, which are treated as coordinates, like `[[x, y], [x1, y1]]`.
#### .line()
Get the linear regression line: this returns a function that you can
give `x` values and it will return `y` values. Internally, this uses the `m()`
and `b()` values and the classic `y = mx + b` equation.
var linear_regression_line = ss.linear_regression()
.data([[0, 1], [2, 2], [3, 3]]).line();
linear_regression_line(5);
#### .m()
Just get the slope of the fitted regression line, the `m` component of the full
line equation. Returns a number.
#### .b()
Just get the y-intercept of the fitted regression line, the `b` component
of the line equation. Returns a number.
## Classification
### .bayesian()
Create a naïve bayesian classifier.
### .train(item, category)
Train the classifier to classify a certain item, given as an object with keys,
to be in a certain category, given as a string.
### .score(item)
Get the classifications of a certain item, given as an object of
`category -> score` mappings.
var bayes = ss.bayesian();
bayes.train({ species: 'Cat' }, 'animal');
bayes.score({ species: 'Cat' });
// { animal: 1 }
---
## [Literate Source](http://macwright.org/simple-statistics/)
## Usage
To use it in browsers, grab [simple_statistics.js](https://raw.github.com/tmcw/simple-statistics/master/src/simple_statistics.js).
To use it in node, install it with [npm](https://npmjs.org/) or add it to your package.json.
npm install simple-statistics
To use it with [component](https://github.com/component/component),
component install tmcw/simple-statistics
To use it with [bower](http://bower.io/),
bower install simple-statistics
## Basic Descriptive Statistics
```javascript
// Require simple statistics
var ss = require('simple-statistics');
// The input is a simple array
var list = [1, 2, 3];
// Many different descriptive statistics are supported
var sum = ss.sum(list),
mean = ss.mean(list),
min = ss.min(list),
geometric_mean = ss.geometric_mean(list),
max = ss.max(list),
quantile = ss.quantile(0.25);
```
## Linear Regression
```javascript
// For a linear regression, it's a two-dimensional array
var data = [ [1, 2], [2, 3] ];
// simple-statistics can produce a linear regression and return
// a friendly javascript function for the line.
var line = ss.linear_regression()
.data(data)
.line();
// get a point along the line function
line(0);
var line = ss.linear_regression()
// Get the r-squared value of the line estimation
ss.r_squared(data, line);
```
### Bayesian Classifier
```javascript
var bayes = ss.bayesian();
bayes.train({ species: 'Cat' }, 'animal');
bayes.score({ species: 'Cat' });
// { animal: 1 }
```
### Mixin Style
_This is **optional** and not used by default. You can opt-in to mixins
with `ss.mixin()`._
This mixes `simple-statistics` methods into the Array prototype - note that
[extending native objects](http://perfectionkills.com/extending-native-builtins/) is a
tricky move.
This will _only work_ if `defineProperty` is available, which means modern browsers
and nodejs - on IE8 and below, calling `ss.mixin()` will throw an exception.
```javascript
// mixin to Array class
ss.mixin();
// The input is a simple array
var list = [1, 2, 3];
// The same descriptive techniques as above, but in a simpler style
var sum = list.sum(),
mean = list.mean(),
min = list.min(),
max = list.max(),
quantile = list.quantile(0.25);
```
## Examples
* [Linear regression with simple-statistics and d3js](http://bl.ocks.org/3931800)
* [Jenks Natural Breaks with a choropleth map with d3js](http://bl.ocks.org/tmcw/4969184)
# Contributors
* Tom MacWright
* [Matt Sacks](https://github.com/mattsacks)
* Doron Linder
* [Alexander Sicular](https://github.com/siculars)

View File

@ -0,0 +1,157 @@
[![Build Status](https://secure.travis-ci.org/tmcw/simple-statistics.png?branch=master)](http://travis-ci.org/tmcw/simple-statistics)
A JavaScript implementation of descriptive, regression, and inference statistics.
Implemented in literate JavaScript with no dependencies, designed to work
in all modern browsers (including IE) as well as in node.js.
# [API](API.md)
[Full documentation](API.md)
---
```
Basic Array Operations
.mixin()
.mean(x)
.sum(x)
.variance(x)
.standard_deviation(x)
.median_absolute_deviation(x)
.median(x)
.geometric_mean(x)
.harmonic_mean(x)
.root_mean_square(x)
.min(x)
.max(x)
.t_test(sample, x)
.t_test_two_sample(sample_x, sample_y, difference)
.sample_variance(x)
.sample_covariance(x)
.sample_correlation(x)
.quantile(sample, p)
.iqr(sample)
.sample_skewness(sample)
.jenks(data, number_of_classes)
.r_squared(data, function)
.cumulative_std_normal_probability(z)
.z_score(x, mean, standard_deviation)
.standard_normal_table
Regression
.linear_regression()
.data([[1, 1], [2, 2]])
.line()
.m()
.b()
Classification
.bayesian()
.train(item, category)
.score(item)
```
---
# [Literate Source](http://macwright.org/simple-statistics/)
## Usage
To use it in browsers, grab [simple_statistics.js](https://raw.github.com/tmcw/simple-statistics/master/src/simple_statistics.js).
To use it in node, install it with [npm](https://npmjs.org/) or add it to your package.json.
npm install simple-statistics
To use it with [component](https://github.com/component/component),
component install tmcw/simple-statistics
To use it with [bower](http://bower.io/),
bower install simple-statistics
## Basic Descriptive Statistics
```javascript
// Require simple statistics
var ss = require('simple-statistics');
// The input is a simple array
var list = [1, 2, 3];
// Many different descriptive statistics are supported
var sum = ss.sum(list),
mean = ss.mean(list),
min = ss.min(list),
geometric_mean = ss.geometric_mean(list),
max = ss.max(list),
quantile = ss.quantile(0.25);
```
## Linear Regression
```javascript
// For a linear regression, it's a two-dimensional array
var data = [ [1, 2], [2, 3] ];
// simple-statistics can produce a linear regression and return
// a friendly javascript function for the line.
var line = ss.linear_regression()
.data(data)
.line();
// get a point along the line function
line(0);
var line = ss.linear_regression()
// Get the r-squared value of the line estimation
ss.r_squared(data, line);
```
### Bayesian Classifier
```javascript
var bayes = ss.bayesian();
bayes.train({ species: 'Cat' }, 'animal');
bayes.score({ species: 'Cat' });
// { animal: 1 }
```
### Mixin Style
_This is **optional** and not used by default. You can opt-in to mixins
with `ss.mixin()`._
This mixes `simple-statistics` methods into the Array prototype - note that
[extending native objects](http://perfectionkills.com/extending-built-in-native-objects-evil-or-not/) is a
tricky move.
This will _only work_ if `defineProperty` is available, which means modern browsers
and nodejs - on IE8 and below, calling `ss.mixin()` will throw an exception.
```javascript
// mixin to Array class
ss.mixin();
// The input is a simple array
var list = [1, 2, 3];
// The same descriptive techniques as above, but in a simpler style
var sum = list.sum(),
mean = list.mean(),
min = list.min(),
max = list.max(),
quantile = list.quantile(0.25);
```
## Examples
* [Linear regression with simple-statistics and d3js](http://bl.ocks.org/3931800)
* [Jenks Natural Breaks with a choropleth map with d3js](http://bl.ocks.org/tmcw/4969184)
# Contributors
* Tom MacWright
* [Matt Sacks](https://github.com/mattsacks)
* Doron Linder
* [Alexander Sicular](https://github.com/siculars)

View File

@ -0,0 +1,23 @@
## See Also
* [stream-statistics](https://github.com/tmcw/stream-statistics), a sister project that implements
many of the same measures for streaming data - as online algorithms
### Javascript
* [science.js](https://github.com/jasondavies/science.js)
* [atoll.js](https://github.com/nsfmc/atoll.js)
* [descriptive_statistics](https://github.com/thirtysixthspan/descriptive_statistics)
* [jStat](http://www.jstat.org/)
* [classifier](https://github.com/harthur/classifier) is a naive bayesian classifier (though specialized for the words-spam case)
* [underscore.math](https://github.com/syntagmatic/underscore.math/blob/master/underscore.math.js)
### Python
* [Pandas](http://pandas.pydata.org/)
* [SciPy](http://www.scipy.org/)
### Their Own Language
* [Julia Language](http://julialang.org/)
* [R language](http://www.r-project.org/)

View File

@ -0,0 +1,20 @@
var fs = require('fs');
var readme = fs.readFileSync('README.md', 'utf8')
.split('\n');
var a = true, b = true;
fs.writeFileSync('README.md', readme.filter(function(f) {
if (f === '---') {
a = !a;
return true;
}
return a;
}).map(function(f) {
if (f === '---' && b) {
f = f + '\n\n' + fs.readFileSync('API.md', 'utf8') + '\n\n';
b = false;
}
return f;
}).join('\n'));

View File

@ -0,0 +1,11 @@
{
"name": "simple-statistics",
"version": "0.9.0",
"description": "Simple Statistics",
"repo": "tmcw/simple-statistics",
"keywords": [],
"license": "ISC",
"dependencies": {},
"development": {},
"main": "src/simple_statistics.js"
}

View File

@ -0,0 +1,13 @@
{
"name": "simple-statistics",
"version": "0.9.0",
"description": "Simple Statistics",
"repo": "tmcw/simple-statistics",
"keywords": [],
"license": "ISC",
"dependencies": {},
"development": {},
"scripts": [
"src/simple_statistics.js"
]
}

View File

@ -0,0 +1,506 @@
/*--------------------- Typography ----------------------------*/
@font-face {
font-family: 'aller-light';
src: url('public/fonts/aller-light.eot');
src: url('public/fonts/aller-light.eot?#iefix') format('embedded-opentype'),
url('public/fonts/aller-light.woff') format('woff'),
url('public/fonts/aller-light.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'aller-bold';
src: url('public/fonts/aller-bold.eot');
src: url('public/fonts/aller-bold.eot?#iefix') format('embedded-opentype'),
url('public/fonts/aller-bold.woff') format('woff'),
url('public/fonts/aller-bold.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'novecento-bold';
src: url('public/fonts/novecento-bold.eot');
src: url('public/fonts/novecento-bold.eot?#iefix') format('embedded-opentype'),
url('public/fonts/novecento-bold.woff') format('woff'),
url('public/fonts/novecento-bold.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
/*--------------------- Layout ----------------------------*/
html { height: 100%; }
body {
font-family: "aller-light";
font-size: 14px;
line-height: 18px;
color: #30404f;
margin: 0; padding: 0;
height:100%;
}
#container { min-height: 100%; }
a {
color: #000;
}
b, strong {
font-weight: normal;
font-family: "aller-bold";
}
p {
margin: 15px 0 0px;
}
.annotation ul, .annotation ol {
margin: 25px 0;
}
.annotation ul li, .annotation ol li {
font-size: 14px;
line-height: 18px;
margin: 10px 0;
}
h1, h2, h3, h4, h5, h6 {
color: #112233;
line-height: 1em;
font-weight: normal;
font-family: "novecento-bold";
text-transform: uppercase;
margin: 30px 0 15px 0;
}
h1 {
margin-top: 40px;
}
hr {
border: 0;
background: 1px #ddd;
height: 1px;
margin: 20px 0;
}
pre, tt, code {
font-size: 12px; line-height: 16px;
font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace;
margin: 0; padding: 0;
}
.annotation pre {
display: block;
margin: 0;
padding: 7px 10px;
background: #fcfcfc;
-moz-box-shadow: inset 0 0 10px rgba(0,0,0,0.1);
-webkit-box-shadow: inset 0 0 10px rgba(0,0,0,0.1);
box-shadow: inset 0 0 10px rgba(0,0,0,0.1);
overflow-x: auto;
}
.annotation pre code {
border: 0;
padding: 0;
background: transparent;
}
blockquote {
border-left: 5px solid #ccc;
margin: 0;
padding: 1px 0 1px 1em;
}
.sections blockquote p {
font-family: Menlo, Consolas, Monaco, monospace;
font-size: 12px; line-height: 16px;
color: #999;
margin: 10px 0 0;
white-space: pre-wrap;
}
ul.sections {
list-style: none;
padding:0 0 5px 0;;
margin:0;
}
/*
Force border-box so that % widths fit the parent
container without overlap because of margin/padding.
More Info : http://www.quirksmode.org/css/box.html
*/
ul.sections > li > div {
-moz-box-sizing: border-box; /* firefox */
-ms-box-sizing: border-box; /* ie */
-webkit-box-sizing: border-box; /* webkit */
-khtml-box-sizing: border-box; /* konqueror */
box-sizing: border-box; /* css3 */
}
/*---------------------- Jump Page -----------------------------*/
#jump_to, #jump_page {
margin: 0;
background: white;
-webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777;
-webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px;
font: 16px Arial;
cursor: pointer;
text-align: right;
list-style: none;
}
#jump_to a {
text-decoration: none;
}
#jump_to a.large {
display: none;
}
#jump_to a.small {
font-size: 22px;
font-weight: bold;
color: #676767;
}
#jump_to, #jump_wrapper {
position: fixed;
right: 0; top: 0;
padding: 10px 15px;
margin:0;
}
#jump_wrapper {
display: none;
padding:0;
}
#jump_to:hover #jump_wrapper {
display: block;
}
#jump_page {
padding: 5px 0 3px;
margin: 0 0 25px 25px;
}
#jump_page .source {
display: block;
padding: 15px;
text-decoration: none;
border-top: 1px solid #eee;
}
#jump_page .source:hover {
background: #f5f5ff;
}
#jump_page .source:first-child {
}
/*---------------------- Low resolutions (> 320px) ---------------------*/
@media only screen and (min-width: 320px) {
.pilwrap { display: none; }
ul.sections > li > div {
display: block;
padding:5px 10px 0 10px;
}
ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol {
padding-left: 30px;
}
ul.sections > li > div.content {
overflow-x:auto;
-webkit-box-shadow: inset 0 0 5px #e5e5ee;
box-shadow: inset 0 0 5px #e5e5ee;
border: 1px solid #dedede;
margin:5px 10px 5px 10px;
padding-bottom: 5px;
}
ul.sections > li > div.annotation pre {
margin: 7px 0 7px;
padding-left: 15px;
}
ul.sections > li > div.annotation p tt, .annotation code {
background: #f8f8ff;
border: 1px solid #dedede;
font-size: 12px;
padding: 0 0.2em;
}
}
/*---------------------- (> 481px) ---------------------*/
@media only screen and (min-width: 481px) {
#container {
position: relative;
}
body {
background-color: #F5F5FF;
font-size: 15px;
line-height: 21px;
}
pre, tt, code {
line-height: 18px;
}
p, ul, ol {
margin: 0 0 15px;
}
#jump_to {
padding: 5px 10px;
}
#jump_wrapper {
padding: 0;
}
#jump_to, #jump_page {
font: 10px Arial;
text-transform: uppercase;
}
#jump_page .source {
padding: 5px 10px;
}
#jump_to a.large {
display: inline-block;
}
#jump_to a.small {
display: none;
}
#background {
position: absolute;
top: 0; bottom: 0;
width: 350px;
background: #fff;
border-right: 1px solid #e5e5ee;
z-index: -1;
}
ul.sections > li > div.annotation ul, ul.sections > li > div.annotation ol {
padding-left: 40px;
}
ul.sections > li {
white-space: nowrap;
}
ul.sections > li > div {
display: inline-block;
}
ul.sections > li > div.annotation {
max-width: 350px;
min-width: 350px;
min-height: 5px;
padding: 13px;
overflow-x: hidden;
white-space: normal;
vertical-align: top;
text-align: left;
}
ul.sections > li > div.annotation pre {
margin: 15px 0 15px;
padding-left: 15px;
}
ul.sections > li > div.content {
padding: 13px;
vertical-align: top;
border: none;
-webkit-box-shadow: none;
box-shadow: none;
}
.pilwrap {
position: relative;
display: inline;
}
.pilcrow {
font: 12px Arial;
text-decoration: none;
color: #454545;
position: absolute;
top: 3px; left: -20px;
padding: 1px 2px;
opacity: 0;
-webkit-transition: opacity 0.2s linear;
}
.for-h1 .pilcrow {
top: 47px;
}
.for-h2 .pilcrow, .for-h3 .pilcrow, .for-h4 .pilcrow {
top: 35px;
}
ul.sections > li > div.annotation:hover .pilcrow {
opacity: 1;
}
}
/*---------------------- (> 1025px) ---------------------*/
@media only screen and (min-width: 1025px) {
body {
font-size: 16px;
line-height: 24px;
}
#background {
width: 525px;
}
ul.sections > li > div.annotation {
max-width: 525px;
min-width: 525px;
padding: 10px 25px 1px 50px;
}
ul.sections > li > div.content {
padding: 9px 15px 16px 25px;
}
}
/*---------------------- Syntax Highlighting -----------------------------*/
td.linenos { background-color: #f0f0f0; padding-right: 10px; }
span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
/*
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
*/
pre code {
display: block; padding: 0.5em;
color: #000;
background: #f8f8ff
}
pre .hljs-comment,
pre .hljs-template_comment,
pre .hljs-diff .hljs-header,
pre .hljs-javadoc {
color: #408080;
font-style: italic
}
pre .hljs-keyword,
pre .hljs-assignment,
pre .hljs-literal,
pre .hljs-css .hljs-rule .hljs-keyword,
pre .hljs-winutils,
pre .hljs-javascript .hljs-title,
pre .hljs-lisp .hljs-title,
pre .hljs-subst {
color: #954121;
/*font-weight: bold*/
}
pre .hljs-number,
pre .hljs-hexcolor {
color: #40a070
}
pre .hljs-string,
pre .hljs-tag .hljs-value,
pre .hljs-phpdoc,
pre .hljs-tex .hljs-formula {
color: #219161;
}
pre .hljs-title,
pre .hljs-id {
color: #19469D;
}
pre .hljs-params {
color: #00F;
}
pre .hljs-javascript .hljs-title,
pre .hljs-lisp .hljs-title,
pre .hljs-subst {
font-weight: normal
}
pre .hljs-class .hljs-title,
pre .hljs-haskell .hljs-label,
pre .hljs-tex .hljs-command {
color: #458;
font-weight: bold
}
pre .hljs-tag,
pre .hljs-tag .hljs-title,
pre .hljs-rules .hljs-property,
pre .hljs-django .hljs-tag .hljs-keyword {
color: #000080;
font-weight: normal
}
pre .hljs-attribute,
pre .hljs-variable,
pre .hljs-instancevar,
pre .hljs-lisp .hljs-body {
color: #008080
}
pre .hljs-regexp {
color: #B68
}
pre .hljs-class {
color: #458;
font-weight: bold
}
pre .hljs-symbol,
pre .hljs-ruby .hljs-symbol .hljs-string,
pre .hljs-ruby .hljs-symbol .hljs-keyword,
pre .hljs-ruby .hljs-symbol .hljs-keymethods,
pre .hljs-lisp .hljs-keyword,
pre .hljs-tex .hljs-special,
pre .hljs-input_number {
color: #990073
}
pre .hljs-builtin,
pre .hljs-constructor,
pre .hljs-built_in,
pre .hljs-lisp .hljs-title {
color: #0086b3
}
pre .hljs-preprocessor,
pre .hljs-pi,
pre .hljs-doctype,
pre .hljs-shebang,
pre .hljs-cdata {
color: #999;
font-weight: bold
}
pre .hljs-deletion {
background: #fdd
}
pre .hljs-addition {
background: #dfd
}
pre .hljs-diff .hljs-change {
background: #0086b3
}
pre .hljs-chunk {
color: #aaa
}
pre .hljs-tex .hljs-formula {
opacity: 0.5;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
<meta http-equiv="refresh" content="0;URL='docs/simple_statistics.html'">

View File

@ -0,0 +1,28 @@
{
"name": "simple-statistics",
"version": "0.9.0",
"description": "Simple Statistics",
"author": "Tom MacWright <tom@macwright.org> (http://macwright.org/)",
"repository": {
"type": "git",
"url": "git://github.com/tmcw/simple-statistics.git"
},
"dependencies": {},
"devDependencies": {
"jshint": "2.5.3",
"coveralls": "~2.11.1",
"istanbul": "~0.3.0",
"tape": "~2.14.0",
"random-js": "~1.0.4"
},
"scripts": {
"test": "tape test/*.js",
"cov": "istanbul cover ./node_modules/.bin/tape test/*.js && coveralls < ./coverage/lcov.info",
"api": "node api.js"
},
"main": "src/simple_statistics.js",
"engines": {
"node": "*"
},
"license": "ISC"
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,114 @@
var ss = require('../');
var test = require('tape');
test('bayes', function(t) {
test('makes an easy call with one training round', function(t) {
var bayes = ss.bayesian();
bayes.train({
species: 'Cat'
}, 'animal');
t.deepEqual(bayes.score({
species: 'Cat'
}), {
animal: 1
});
t.end();
});
test('makes fify-fifty call', function(t) {
var bayes = ss.bayesian();
bayes.train({
species: 'Cat'
}, 'animal');
bayes.train({
species: 'Cat'
}, 'chair');
t.deepEqual(bayes.score({
species: 'Cat'
}), {
animal: 0.5,
chair: 0.5
});
t.end();
});
test('makes seventy-five/twenty-five call', function(t) {
var bayes = ss.bayesian();
bayes.train({
species: 'Cat'
}, 'animal');
bayes.train({
species: 'Cat'
}, 'animal');
bayes.train({
species: 'Cat'
}, 'animal');
bayes.train({
species: 'Cat'
}, 'chair');
t.deepEqual(bayes.score({
species: 'Cat'
}), {
animal: 0.75,
chair: 0.25
});
t.end();
});
test('tests multiple properties', function(t) {
var bayes = ss.bayesian();
bayes.train({
species: 'Cat'
}, 'animal');
bayes.train({
species: 'Cat'
}, 'animal');
bayes.train({
species: 'Cat'
}, 'animal');
bayes.train({
species: 'Cat'
}, 'chair');
bayes.train({
species: 'Cat',
color: 'white'
}, 'chair');
t.deepEqual(bayes.score({
color: 'white'
}), {
animal: 0,
chair: 0.2
});
t.end();
});
test('classifies multiple things', function(t) {
var bayes = ss.bayesian();
bayes.train({
species: 'Cat'
}, 'animal');
bayes.train({
species: 'Dog'
}, 'animal');
bayes.train({
species: 'Dog'
}, 'animal');
bayes.train({
species: 'Cat'
}, 'chair');
t.deepEqual(bayes.score({
species: 'Cat'
}), {
animal: 0.25,
chair: 0.25
});
t.deepEqual(bayes.score({
species: 'Dog'
}), {
animal: 0.5,
chair: 0
});
t.end();
});
t.end();
});

View File

@ -0,0 +1,17 @@
var test = require('tape');
var ss = require('../');
test('bernoulli_distribution', function(t) {
test('can return generate probability and cumulative probability distributions for p = 0.3', function(t) {
t.equal('object', typeof ss.bernoulli_distribution(0.3));
t.equal(ss.bernoulli_distribution(0.3)[0], 0.7, ss.epsilon);
t.equal(ss.bernoulli_distribution(0.3)[1], 0.3, ss.epsilon);
t.end();
});
test('can return null when p is not a valid probability', function(t) {
t.equal(null, ss.bernoulli_distribution(-0.01), 'p should be greater than 0.0');
t.equal(null, ss.bernoulli_distribution(1.5), 'p should be less than 1.0');
t.end();
});
t.end();
});

View File

@ -0,0 +1,31 @@
var test = require('tape');
var ss = require('../');
function rnd(n) {
return parseFloat(n.toFixed(4));
}
test('binomial_distribution', function(t) {
// Data given in the [Wikipedia example](http://en.wikipedia.org/wiki/Binomial_distribution#Example) retrieved 29 Mar 2014
// Cumulative probabilities worked by hand to mitigate accumulated rounding errors.
test('can return generate probability and cumulative probability distributions for n = 6, p = 0.3', function(t) {
t.equal('object', typeof ss.binomial_distribution(6, 0.3));
t.equal(rnd(ss.binomial_distribution(6, 0.3)[0]), 0.1176, ss.epsilon);
t.equal(rnd(ss.binomial_distribution(6, 0.3)[1]), 0.3025, ss.epsilon);
t.equal(rnd(ss.binomial_distribution(6, 0.3)[2]), 0.3241, ss.epsilon);
t.equal(rnd(ss.binomial_distribution(6, 0.3)[3]), 0.1852, ss.epsilon);
t.equal(rnd(ss.binomial_distribution(6, 0.3)[4]), 0.0595, ss.epsilon);
t.equal(rnd(ss.binomial_distribution(6, 0.3)[5]), 0.0102, ss.epsilon);
t.equal(rnd(ss.binomial_distribution(6, 0.3)[6]), 0.0007, ss.epsilon);
t.end();
});
test('can return null when p or n are not valid parameters', function(t) {
t.equal(null, ss.binomial_distribution(0, 0.5), 'n should be strictly positive');
t.equal(null, ss.binomial_distribution(1.5, 0.5), 'n should be an integer');
t.equal(null, ss.binomial_distribution(2, -0.01), 'p should be greater than 0.0');
t.equal(null, ss.binomial_distribution(2, 1.5), 'p should be less than 1.0');
t.end();
});
t.end();
});

View File

@ -0,0 +1,23 @@
var test = require('tape');
var ss = require('../');
// Data from Poisson goodness-of-fit example 10-19 in William W. Hines & Douglas C. Montgomery,
// "Probability and Statistics in Engineering and Management Science", Wiley (1980).
var data_10_19 = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3
];
test('chi_squared_goodness_of_fit', function(t) {
test('can reject the null hypothesis with level of confidence specified at 0.05', function(t) {
t.equal(false, ss.chi_squared_goodness_of_fit(data_10_19, ss.poisson_distribution, 0.05));
t.end();
});
test('can accept the null hypothesis with level of confidence specified at 0.10', function(t) {
t.equal(true, ss.chi_squared_goodness_of_fit(data_10_19, ss.poisson_distribution, 0.10));
t.end();
});
t.end();
});

View File

@ -0,0 +1,18 @@
var test = require('tape');
var ss = require('../');
test('chunks', function(t) {
test('can get chunks of an array', function(t) {
t.deepEqual(ss.chunk([1, 2], 1), [[1], [2]]);
t.deepEqual(ss.chunk([1, 2], 2), [[1, 2]]);
t.deepEqual(ss.chunk([1, 2, 3, 4], 4), [[1, 2, 3, 4]]);
t.deepEqual(ss.chunk([1, 2, 3, 4], 2), [[1, 2], [3, 4]]);
t.deepEqual(ss.chunk([1, 2, 3, 4], 3), [[1, 2, 3], [4]]);
t.deepEqual(ss.chunk([1, 2, 3, 4, 5, 6, 7], 2), [[1, 2], [3, 4], [5, 6], [7]]);
t.deepEqual(ss.chunk([], 2), []);
t.deepEqual(ss.chunk([], 0), null);
t.deepEqual(ss.chunk([1, 2], 0), null);
t.end();
});
t.end();
});

View File

@ -0,0 +1,13 @@
var test = require('tape');
var ss = require('../');
test('cumulative_std_normal_probability', function(t) {
// https://en.wikipedia.org/wiki/Standard_normal_table#Examples_of_use
test('wikipedia test example works', function(t) {
for (var i = 0; i < ss.standard_normal_table.length; i++) {
t.equal(ss.cumulative_std_normal_probability(0.4), 0.6554);
}
t.end();
});
t.end();
});

View File

@ -0,0 +1,22 @@
var test = require('tape');
var ss = require('../');
test('factorial', function(t) {
test('can return null given a negative number', function(t) {
t.equal(null, ss.factorial(-1));
t.end();
});
test('can calculate 0! = 1', function(t) {
t.equal(ss.factorial(0), 1);
t.end();
});
test('can calculate 1! = 1', function(t) {
t.equal(ss.factorial(1), 1);
t.end();
});
test('can calculate 100! = 1', function(t) {
t.equal(ss.factorial(100), 9.33262154439441e+157);
t.end();
});
t.end();
});

View File

@ -0,0 +1,23 @@
var test = require('tape');
var ss = require('../');
test('geometric mean', function(t) {
// From http://en.wikipedia.org/wiki/Geometric_mean
test('can get the mean of two numbers', function(t) {
t.equal(ss.geometric_mean([2, 8]), 4);
t.equal(ss.geometric_mean([4, 1, 1 / 32]), 0.5);
t.equal(Math.round(ss.geometric_mean([2, 32, 1])), 4);
t.end();
});
test('returns null for empty lists', function(t) {
t.equal(ss.geometric_mean([]), null);
t.end();
});
test('returns null for lists with negative numbers', function(t) {
t.equal(ss.geometric_mean([-1]), null);
t.end();
});
t.end();
});

View File

@ -0,0 +1,27 @@
var test = require('tape');
var ss = require('../');
function rnd(x) {
return Math.round(x * 1000) / 1000;
}
test('harmonic_mean', function(t) {
// From http://en.wikipedia.org/wiki/Harmonic_mean
test('can get the mean of two or more numbers', function(t) {
t.equal(ss.harmonic_mean([1, 1]), 1);
t.equal(rnd(ss.harmonic_mean([2, 3])), 2.4);
t.equal(ss.harmonic_mean([1, 2, 4]), 12 / 7);
t.end();
});
test('returns null for empty lists', function(t) {
t.equal(ss.harmonic_mean([]), null);
t.end();
});
test('returns null for lists with negative numbers', function(t) {
t.equal(ss.harmonic_mean([-1]), null);
t.end();
});
t.end();
});

View File

@ -0,0 +1,24 @@
var test = require('tape');
var ss = require('../');
test('interquartile range (iqr)', function(t) {
// Data and results from
// [Wikipedia](http://en.wikipedia.org/wiki/Quantile#Quantiles_of_a_population)
test('can get proper iqr of an even-length list', function(t) {
var even = [3, 6, 7, 8, 8, 10, 13, 15, 16, 20];
t.equal(ss.quantile(even, 0.75) - ss.quantile(even, 0.25), ss.iqr(even));
t.end();
});
test('can get proper iqr of an odd-length list', function(t) {
var odd = [3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20];
t.equal(ss.quantile(odd, 0.75) - ss.quantile(odd, 0.25), ss.iqr(odd));
t.end();
});
test('an iqr of a zero-length list produces null', function(t) {
t.equal(ss.iqr([]), null);
t.end();
});
t.end();
});

View File

@ -0,0 +1,14 @@
var test = require('tape');
var ss = require('../');
test('jenks', function(t) {
test('will not try to assign more classes than datapoints', function(t) {
t.equal(ss.jenks([1, 2], 3), null);
t.end();
});
test('assigns correct breaks', function(t) {
t.deepEqual(ss.jenks([1, 2, 4, 5, 7, 9, 10, 20], 3), [1, 2, 5, 20]);
t.end();
});
t.end();
});

View File

@ -0,0 +1,54 @@
var test = require('tape');
var ss = require('../');
test('linear regression', function(t) {
test('correctly generates a line for a 0, 0 to 1, 1 dataset', function(t) {
var l = ss.linear_regression().data([[0, 0], [1, 1]]);
t.equal(l.line()(0), 0);
t.equal(l.line()(0.5), 0.5);
t.equal(l.line()(1), 1);
t.end();
});
test('correctly generates a line for a 0, 0 to 1, 0 dataset', function(t) {
var l = ss.linear_regression().data([[0, 0], [1, 0]]);
t.equal(l.line()(0), 0);
t.equal(l.line()(0.5), 0);
t.equal(l.line()(1), 0);
t.end();
});
test('returns the data assigned to it', function(t) {
var l = ss.linear_regression().data([[0, 0], [1, 0]]);
t.deepEqual(l.data(), [[0, 0], [1, 0]]);
t.end();
});
test('handles a single-point sample', function(t) {
var l = ss.linear_regression().data([[0, 0]]).line();
t.deepEqual(l(10), 0);
t.end();
});
test('a straight line will have a slope of 0', function(t) {
var l = ss.linear_regression().data([[0, 0], [1, 0]]);
t.equal(l.m(), 0);
t.equal(l.b(), 0);
t.end();
});
test('a line at 50% grade', function(t) {
var l = ss.linear_regression().data([[0, 0], [1, 0.5]]);
t.equal(l.m(), 0.5);
t.equal(l.b(), 0);
t.end();
});
test('a line with a high y-intercept', function(t) {
var l = ss.linear_regression().data([[0, 20], [1, 10]]);
t.equal(l.m(), -10);
t.equal(l.b(), 20);
t.end();
});
t.end();
});

View File

@ -0,0 +1,26 @@
var test = require('tape');
var ss = require('../');
test('median absolute deviation (mad)', function(t) {
test('median absolute deviation of an example on wikipedia', function(t) {
t.equal(ss.mad([1, 1, 2, 2, 4, 6, 9]), 1);
t.end();
});
// wolfram alpha: median absolute deviation {0,1,2,3,4,5,6,7,8,9,10}
test('median absolute deviation of 0-10', function(t) {
t.equal(ss.mad([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), 3);
t.end();
});
test('median absolute deviation of one number is zero', function(t) {
t.equal(ss.mad([1]), 0);
t.end();
});
test('zero-length corner case', function(t) {
t.equal(ss.mad([]), null);
t.end();
});
t.end();
});

View File

@ -0,0 +1,18 @@
var test = require('tape');
var ss = require('../');
test('mean', function(t) {
test('can get the mean of two numbers', function(t) {
t.equal(ss.mean([1, 2]), 1.5);
t.end();
});
test('can get the mean of one number', function(t) {
t.equal(ss.mean([1]), 1);
t.end();
});
test('an empty list has no average', function(t) {
t.equal(ss.mean([]), null);
t.end();
});
t.end();
});

View File

@ -0,0 +1,38 @@
var test = require('tape');
var ss = require('../');
test('median', function(t) {
test('can get the median of three numbers', function(t) {
t.equal(ss.median([1, 2, 3]), 2);
t.end();
});
test('can get the median of two numbers', function(t) {
t.equal(ss.median([1, 2]), 1.5);
t.end();
});
test('can get the median of four numbers', function(t) {
t.equal(ss.median([1, 2, 3, 4]), 2.5);
t.end();
});
test('gives null for the median of an empty list', function(t) {
t.equal(ss.median([]), null);
t.end();
});
test('sorts numbers numerically', function(t) {
t.equal(ss.median([8, 9, 10]), 9);
t.end();
});
test('does not change the sorting order of its input', function(t) {
var x = [1, 0];
t.equal(ss.median(x), 0.5);
t.equal(x[0], 1);
t.equal(x[1], 0);
t.end();
});
t.end();
});

View File

@ -0,0 +1,23 @@
var test = require('tape');
var ss = require('../');
test('min', function(t) {
test('can get the minimum of one number', function(t) {
t.equal(ss.min([1]), 1);
t.end();
});
test('can get the minimum of three numbers', function(t) {
t.equal(ss.min([1, 7, -1000]), -1000);
t.end();
});
t.end();
});
test('max', function(t) {
test('can get the maximum of three numbers', function(t) {
t.equal(ss.max([1, 7, -1000]), 7);
t.end();
});
t.end();
});

View File

@ -0,0 +1,34 @@
var test = require('tape');
var ss = require('../');
test('mixin', function(t) {
test('can mix into a single array', function(t) {
var even = ss.mixin([2, 4, 6, 8]);
t.equal(even.sum(), 20);
t.equal(even.mean(), 5);
t.equal(even.max(), 8);
t.equal(even.min(), 2);
t.equal(even.sample_skewness(), 0);
t.end();
});
test('can mix into Array.prototype', function(t) {
ss.mixin();
var even = [2, 4, 6, 8];
t.equal(even.sum(), 20);
t.equal(even.mean(), 5);
t.equal(even.max(), 8);
t.equal(even.min(), 2);
t.equal(even.sample_skewness(), 0);
t.end();
});
test('mixins can take arguments', function(t) {
ss.mixin();
var even = [2, 4, 6, 8];
t.equal(even.quantile(0.2), 2);
t.equal(even.quantile(0.8), 8);
t.end();
});
t.end();
});

View File

@ -0,0 +1,37 @@
var test = require('tape');
var ss = require('../');
test('mode', function(t) {
test('the mode of a single-number array is that one number', function(t) {
t.equal(ss.mode([1]), 1);
t.end();
});
test('the mode of a two-number array is that one number', function(t) {
t.equal(ss.mode([1, 1]), 1);
t.end();
});
test('other cases', function(t) {
t.equal(ss.mode([1, 1, 2]), 1);
t.equal(ss.mode([1, 1, 2, 3]), 1);
t.equal(ss.mode([1, 1, 2, 3, 3]), 1);
t.equal(ss.mode([1, 1, 2, 3, 3, 3]), 3);
t.equal(ss.mode([1, 1, 2, 2, 2, 2, 3, 3, 3]), 2);
t.equal(ss.mode([1, 2, 3, 4, 5]), 1);
t.equal(ss.mode([1, 2, 3, 4, 5, 5]), 5);
t.equal(ss.mode([1, 1, 1, 2, 2, 3, 3, 4, 4]), 1);
t.end();
});
test('the mode of an empty array is null', function(t) {
t.equal(ss.mode([]), null);
t.end();
});
test('the mode of a three-number array with two same numbers is the repeated one', function(t) {
t.equal(ss.mode([1, 2, 2]), 2);
t.end();
});
t.end();
});

View File

@ -0,0 +1,60 @@
var test = require('tape');
var ss = require('../');
test('natural distribution and z-score', function(t) {
test('normal table is exposed in the API', function(t) {
t.equal(ss.standard_normal_table.length, 310);
t.equal(ss.standard_normal_table[0], 0.5);
t.end();
});
test('P(Z <= 0.4) is 0.6554', function(t) {
// Taken from the examples of use in http://en.wikipedia.org/wiki/Standard_normal_table
t.equal(ss.cumulative_std_normal_probability(0.4), 0.6554);
t.end();
});
test('P(Z <= -1.20) is 0.1151', function(t) {
// Taken from the examples of use in http://en.wikipedia.org/wiki/Standard_normal_table
t.equal(ss.cumulative_std_normal_probability(-1.20), 0.1151);
t.end();
});
test('P(X <= 82) when X ~ N (80, 25) is 0.6554', function(t) {
// Taken from the examples of use in http://en.wikipedia.org/wiki/Standard_normal_table
// A professor's exam scores are approximately distributed normally with mean 80 and standard deviation 5.
// What is the probability that a student scores an 82 or less?
t.equal(ss.cumulative_std_normal_probability(ss.z_score(82, 80, 5)), 0.6554);
t.end();
});
test('P(X >= 90) when X ~ N (80, 25) is 0.0228', function(t) {
// Taken from the examples of use in http://en.wikipedia.org/wiki/Standard_normal_table
// A professor's exam scores are approximately distributed normally with mean 80 and standard deviation 5.
// What is the probability that a student scores a 90 or more?
t.equal(+(1 - ss.cumulative_std_normal_probability(ss.z_score(90, 80, 5))).toPrecision(5), 0.0228);
t.end();
});
test('P(X <= 74) when X ~ N (80, 25) is 0.1151', function(t) {
// Taken from the examples of use in http://en.wikipedia.org/wiki/Standard_normal_table
// A professor's exam scores are approximately distributed normally with mean 80 and standard deviation 5.
// What is the probability that a student scores a 74 or less?
t.equal(ss.cumulative_std_normal_probability(ss.z_score(74, 80, 5)), 0.1151);
t.end();
});
test('P(78 <= X <= 88) when X ~ N (80, 25) is 0.6006', function(t) {
// Taken from the examples of use in http://en.wikipedia.org/wiki/Standard_normal_table
// A professor's exam scores are approximately distributed normally with mean 80 and standard deviation 5.
// What is the probability that a student scores between 78 and 88?
var prob88 = ss.cumulative_std_normal_probability(ss.z_score(88, 80, 5)),
prob78 = ss.cumulative_std_normal_probability(ss.z_score(78, 80, 5));
t.equal(+(prob88 - prob78).toPrecision(5), 0.6006);
t.end();
});
t.end();
});

View File

@ -0,0 +1,37 @@
var test = require('tape');
var ss = require('../');
function rnd(n) {
return parseFloat(n.toFixed(4));
}
// expected cumulative probabilities taken from Appendix 1, Table I of William W. Hines & Douglas C.
// Montgomery, "Probability and Statistics in Engineering and Management Science", Wiley (1980).
test('poisson_distribution', function(t) {
test('can return generate probability and cumulative probability distributions for lambda = 3.0', function(t) {
t.equal('object', typeof ss.poisson_distribution(3.0));
t.equal(rnd(ss.poisson_distribution(3.0)[3]), 0.2240, ss.epsilon);
t.end();
});
test('can generate probability and cumulative probability distributions for lambda = 4.0', function(t) {
t.equal('object', typeof ss.poisson_distribution(4.0));
t.equal(rnd(ss.poisson_distribution(4.0)[2]), 0.1465, ss.epsilon);
t.end();
});
test('can generate probability and cumulative probability distributions for lambda = 5.5', function(t) {
t.equal('object', typeof ss.poisson_distribution(5.5));
t.equal(rnd(ss.poisson_distribution(5.5)[7]), 0.1234, ss.epsilon);
t.end();
});
test('can generate probability and cumulative probability distributions for lambda = 9.5', function(t) {
t.equal('object', typeof ss.poisson_distribution(9.5));
t.equal(rnd(ss.poisson_distribution(9.5)[17]), 0.0088, ss.epsilon);
t.end();
});
test('can return null when lambda <= 0', function(t) {
t.equal(null, ss.poisson_distribution(0));
t.equal(null, ss.poisson_distribution(-10));
t.end();
});
t.end();
});

View File

@ -0,0 +1,64 @@
var test = require('tape');
var ss = require('../');
test('quantile', function(t) {
// Data and results from
// [Wikipedia](http://en.wikipedia.org/wiki/Quantile#Quantiles_of_a_population)
test('can get proper quantiles of an even-length list', function(t) {
var even = [3, 6, 7, 8, 8, 10, 13, 15, 16, 20];
t.equal(ss.quantile(even, 0.25), 7);
t.equal(ss.quantile(even, 0.5), 9);
t.equal(ss.quantile(even, 0.75), 15);
t.end();
});
test('can get proper quantiles of an odd-length list', function(t) {
var odd = [3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20];
t.equal(ss.quantile(odd, 0.25), 7);
t.equal(ss.quantile(odd, 0.5), 9);
t.equal(ss.quantile(odd, 0.75), 15);
t.end();
});
test('the median quantile is equal to the median', function(t) {
var rand = [1, 4, 5, 8];
t.equal(ss.quantile(rand, 0.5), ss.median(rand));
var rand2 = [10, 50, 2, 4, 4, 5, 8];
t.equal(ss.quantile(rand2, 0.5), ss.median(rand2));
t.end();
});
test('a zero-length list produces null', function(t) {
t.equal(ss.quantile([], 0.5), null);
t.end();
});
test('test odd-value case', function(t) {
t.equal(ss.quantile([0, 1, 2, 3, 4], 0.2), 1);
t.end();
});
test('bad bounds produce null', function(t) {
t.equal(ss.quantile([1, 2, 3], 1.1), null);
t.equal(ss.quantile([1, 2, 3], -0.5), null);
t.end();
});
test('max quantile is equal to the max', function(t) {
t.equal(ss.quantile([1, 2, 3], 1), ss.max([1, 2, 3]));
t.end();
});
test('min quantile is equal to the min', function(t) {
t.equal(ss.quantile([1, 2, 3], 0), ss.min([1, 2, 3]));
t.end();
});
test('if quantile arg is an array, response is an array of quantiles', function(t) {
var odd = [3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20];
t.deepEqual(ss.quantile(odd, [0, 0.25, 0.5, 0.75, 1]), [3, 7, 9, 15, 20]);
t.deepEqual(ss.quantile(odd, [0.75, 0.5]), [15, 9]);
t.end();
});
t.end();
});

View File

@ -0,0 +1,15 @@
var test = require('tape');
var ss = require('../');
test('quantile_sorted', function(t) {
// Data and results from
// [Wikipedia](http://en.wikipedia.org/wiki/Quantile#Quantiles_of_a_population)
test('can get proper quantiles of an even-length list', function(t) {
var even = [3, 6, 7, 8, 8, 10, 13, 15, 16, 20];
t.equal(ss.quantile_sorted(even, 0.25), 7);
t.equal(ss.quantile_sorted(even, 0.5), 9);
t.equal(ss.quantile_sorted(even, 0.75), 15);
t.end();
});
t.end();
});

View File

@ -0,0 +1,26 @@
var test = require('tape');
var ss = require('../');
test('r-squared', function(t) {
test('says that the r squared of a two-point line is perfect', function(t) {
var d = [[0, 0], [1, 1]];
var l = ss.linear_regression().data(d);
t.equal(ss.r_squared(d, l.line()), 1);
t.end();
});
test('says that the r squared of a three-point line is not perfect', function(t) {
var d = [[0, 0], [0.5, 0.2], [1, 1]];
var l = ss.linear_regression().data(d);
t.notEqual(ss.r_squared(d, l.line()), 1);
t.end();
});
test('r-squared of single sample is 1', function(t) {
var d = [[0, 0]];
var l = ss.linear_regression().data(d);
t.equal(ss.r_squared(d, l.line()), 1);
t.end();
});
t.end();
});

View File

@ -0,0 +1,23 @@
var test = require('tape');
var ss = require('../');
function rnd(x) {
return Math.round(x * 1000) / 1000;
}
test('root_mean_square', function(t) {
// From http://en.wikipedia.org/wiki/Root_mean_square
test('can get the RMS of two or more numbers', function(t) {
t.equal(ss.root_mean_square([1, 1]), 1);
t.equal(rnd(ss.root_mean_square([3, 4, 5])), 4.082);
t.equal(rnd(ss.root_mean_square([-0.1, 5, -2, 10])), 5.679);
t.end();
});
test('returns null for empty lists', function(t) {
t.equal(ss.root_mean_square([]), null);
t.end();
});
t.end();
});

View File

@ -0,0 +1,19 @@
var test = require('tape');
var Random = require('random-js');
var random = new Random(Random.engines.mt19937().seed(0));
var ss = require('../');
function rng() { return random.real(0, 1); }
test('sample', function(t) {
t.deepEqual(ss.sample([], 0, rng), [], 'edge case - zero array');
t.deepEqual(ss.sample([], 2, rng), [], 'edge case - zero array');
t.deepEqual(ss.sample([1,2,3], 0, rng, 0), [], 'edge case - zero array');
t.deepEqual(ss.sample([1,2,3], 1, rng), [1], 'edge case - sample of 1');
t.deepEqual(ss.sample([1,2,3], 1, rng), [2]);
t.deepEqual(ss.sample([1,2,3], 3, rng), [2,3,1]);
t.deepEqual(ss.sample([1,2,3,4], 2, rng), [3,1]);
t.deepEqual(ss.sample([1,2,3,4,6,7,8], 2, rng), [8,7]);
t.deepEqual(ss.sample(['foo', 'bar'], 1, rng), ['foo'], 'non-number contents');
t.end();
});

View File

@ -0,0 +1,29 @@
var test = require('tape');
var ss = require('../');
function rnd(x) {
return Math.round(x * 1000) / 1000;
}
test('sample correlation', function(t) {
test('can get the sample correlation of identical arrays', function(t) {
var data = [1, 2, 3, 4, 5, 6];
t.equal(rnd(ss.sample_correlation(data, data)), 1);
t.end();
});
test('can get the sample correlation of different arrays', function(t) {
var a = [1, 2, 3, 4, 5, 6];
var b = [2, 2, 3, 4, 5, 60];
t.equal(rnd(ss.sample_correlation(a, b)), 0.691);
t.end();
});
test('zero-length corner case', function(t) {
t.equal(rnd(ss.sample_correlation([], [])), 0);
t.end();
});
t.end();
});

View File

@ -0,0 +1,34 @@
var test = require('tape');
var ss = require('../');
function rnd(x) {
return Math.round(x * 1000) / 1000;
}
test('sample covariance', function(t) {
test('can get perfect negative covariance', function(t) {
var x = [1, 2, 3, 4, 5, 6];
var y = [6, 5, 4, 3, 2, 1];
t.equal(rnd(ss.sample_covariance(x, y)), -3.5);
t.end();
});
test('covariance of something with itself is its variance', function(t) {
var x = [1, 2, 3, 4, 5, 6];
t.equal(rnd(ss.sample_covariance(x, x)), 3.5);
t.end();
});
test('covariance is zero for something with no correlation', function(t) {
var x = [1, 2, 3, 4, 5, 6];
var y = [1, 1, 2, 2, 1, 1];
t.equal(rnd(ss.sample_covariance(x, y)), 0);
t.end();
});
test('zero-length corner case', function(t) {
t.equal(rnd(ss.sample_covariance([], [])), 0);
t.end();
});
t.end();
});

View File

@ -0,0 +1,48 @@
var test = require('tape');
var ss = require('../');
test('sample skewness', function(t) {
test('the skewness of an empty sample is null', function(t) {
var data = [];
t.equal(ss.sample_skewness(data), null);
t.end();
});
test('the skewness of an sample with one number is null', function(t) {
var data = [1];
t.equal(ss.sample_skewness(data), null);
t.end();
});
test('the skewness of an sample with two numbers is null', function(t) {
var data = [1, 2];
t.equal(ss.sample_skewness(data), null);
t.end();
});
test('can calculate the skewness of SAS example 1', function(t) {
// Data and answer taken from SKEWNESS function documentation at
// http://support.sas.com/documentation/c../lrdict/64316/HTML/default/viewer.htm#a000245947.htm
var data = [0, 1, 1];
t.equal(+ss.sample_skewness(data).toPrecision(10), -1.732050808);
t.end();
});
test('can calculate the skewness of SAS example 2', function(t) {
// Data and answer taken from SKEWNESS function documentation at
// http://support.sas.com/documentation/c../lrdict/64316/HTML/default/viewer.htm#a000245947.htm
var data = [2, 4, 6, 3, 1];
t.equal(+ss.sample_skewness(data).toPrecision(10), 0.5901286564);
t.end();
});
test('can calculate the skewness of SAS example 3', function(t) {
// Data and answer taken from SKEWNESS function documentation at
// http://support.sas.com/documentation/c../lrdict/64316/HTML/default/viewer.htm#a000245947.htm
var data = [2, 0, 0];
t.equal(+ss.sample_skewness(data).toPrecision(10), 1.732050808);
t.end();
});
t.end();
});

View File

@ -0,0 +1,19 @@
var test = require('tape');
var ss = require('../');
function rnd(x) {
return Math.round(x * 1000) / 1000;
}
test('sample_standard_deviation', function(t) {
test('can get the standard deviation of an example on wikipedia', function(t) {
t.equal(rnd(ss.sample_standard_deviation([2, 4, 4, 4, 5, 5, 7, 9])), 2.138);
t.end();
});
test('zero-length corner case', function(t) {
t.equal(rnd(ss.sample_standard_deviation([])), 0);
t.end();
});
t.end();
});

View File

@ -0,0 +1,38 @@
var test = require('tape');
var ss = require('../');
function rnd(x) {
return Math.round(x * 1000) / 1000;
}
test('sample variance', function(t) {
test('can get the sample variance of a six-sided die', function(t) {
t.equal(rnd(ss.sample_variance([1, 2, 3, 4, 5, 6])), 3.5);
t.end();
});
// confirmed in R
//
// > var(1:10)
// [1] 9.166667
test('can get the sample variance of numbers 1-10', function(t) {
t.equal(rnd(ss.sample_variance([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])), 9.167);
t.end();
});
test('the sample variance of two numbers that are the same is 0', function(t) {
t.equal(rnd(ss.sample_variance([1, 1])), 0);
t.end();
});
test('the sample variance of one number is null', function(t) {
t.equal(ss.sample_variance([1]), null);
t.end();
});
test('the sample variance of no numbers is null', function(t) {
t.equal(ss.sample_variance([]), null);
t.end();
});
t.end();
});

View File

@ -0,0 +1,24 @@
var test = require('tape');
var Random = require('random-js');
var random = new Random(Random.engines.mt19937().seed(0));
var ss = require('../');
function rng() { return random.real(0, 1); }
test('shuffle', function(t) {
var input = [1, 2, 3, 4, 5, 6];
t.deepEqual(ss.shuffle([], rng), []);
t.deepEqual(ss.shuffle(input, rng), [1, 5, 3, 2, 4, 6]);
t.deepEqual(input, [1, 2, 3, 4, 5, 6], 'does not change original array');
t.deepEqual(ss.shuffle(input, rng), [5, 4, 1, 3, 6, 2]);
t.deepEqual(input, [1, 2, 3, 4, 5, 6], 'does not change original array');
t.end();
});
test('shuffle_in_place', function(t) {
var input = [1, 2, 3, 4, 5, 6];
t.deepEqual(ss.shuffle_in_place([], rng), []);
t.deepEqual(ss.shuffle_in_place(input, rng), [6, 1, 5, 2, 4, 3]);
t.deepEqual(input, [6, 1, 5, 2, 4, 3], 'changes original array');
t.end();
});

View File

@ -0,0 +1,39 @@
var test = require('tape');
var ss = require('../');
function rnd(x) {
return Math.round(x * 1000) / 1000;
}
test('standard_deviation', function(t) {
test('can get the standard deviation of an example on wikipedia', function(t) {
t.equal(rnd(ss.standard_deviation([2, 4, 4, 4, 5, 5, 7, 9])), 2);
t.end();
});
// confirmed with numpy
// In [4]: numpy.std([1,2,3])
// Out[4]: 0.81649658092772603
test('can get the standard deviation of 1-3', function(t) {
t.equal(rnd(ss.standard_deviation([1, 2, 3])), 0.816);
t.end();
});
test('zero-length array corner case', function(t) {
t.equal(rnd(ss.standard_deviation([])), 0);
t.end();
});
// In [6]: numpy.std([0,1,2,3,4,5,6,7,8,9,10])
// Out[6]: 3.1622776601683795
test('can get the standard deviation of 1-10', function(t) {
t.equal(rnd(ss.standard_deviation([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])), 3.162);
t.end();
});
test('the standard deviation of one number is zero', function(t) {
t.equal(rnd(ss.standard_deviation([1])), 0);
t.end();
});
t.end();
});

View File

@ -0,0 +1,14 @@
var test = require('tape');
var ss = require('../');
test('standard_normal_table', function(t) {
test('all entries are numeric', function(t) {
for (var i = 0; i < ss.standard_normal_table.length; i++) {
t.equal(typeof ss.standard_normal_table[i], 'number');
t.ok(ss.standard_normal_table[i] >= 0);
t.ok(ss.standard_normal_table[i] <= 1);
}
t.end();
});
t.end();
});

View File

@ -0,0 +1,15 @@
var test = require('tape');
var ss = require('../');
test('sum', function(t) {
test('can get the sum of two numbers', function(t) {
t.equal(ss.sum([1, 2]), 3);
t.end();
});
test('the sum of no numbers is zero', function(t) {
t.equal(ss.sum([]), 0);
t.end();
});
t.end();
});

View File

@ -0,0 +1,38 @@
var test = require('tape'),
ss = require('../');
test('t test', function(t) {
test('can compare a known value to the mean of samples', function(t) {
var res = ss.t_test([1, 2, 3, 4, 5, 6], 3.385);
t.equal(res, 0.1649415480881466);
t.end();
});
test('can test independency of two samples', function(t) {
var res = ss.t_test_two_sample([1, 2, 3, 4], [3, 4, 5, 6], 0);
t.equal(res, -2.1908902300206643);
t.end();
});
test('can test independency of two samples (mu == -2)', function(t) {
var res = ss.t_test_two_sample([1, 2, 3, 4], [3, 4, 5, 6], -2);
t.equal(res, 0);
t.end();
});
test('can test independency of two samples of different lengths', function(t) {
var res = ss.t_test_two_sample([1, 2, 3, 4], [3, 4, 5, 6, 1, 2, 0]);
t.equal(res, -0.4165977904505309);
t.end();
});
test('has an edge case for one sample being of size zero', function(t) {
t.equal(ss.t_test_two_sample([1, 2, 3, 4], []), null);
t.equal(ss.t_test_two_sample([], [1, 2, 3, 4]), null);
t.equal(ss.t_test_two_sample([], []), null);
t.end();
});
t.end();
});

View File

@ -0,0 +1,24 @@
var test = require('tape');
var ss = require('../');
function rnd(x) {
return Math.round(x * 1000) / 1000;
}
test('variance', function(t) {
test('can get the variance of a six-sided die', function(t) {
t.equal(rnd(ss.variance([1, 2, 3, 4, 5, 6])), 2.917);
t.end();
});
test('the variance of one number is zero', function(t) {
t.equal(rnd(ss.variance([1])), 0);
t.end();
});
test('the variance of no numbers is null', function(t) {
t.equal(ss.variance([]), null);
t.end();
});
t.end();
});

65
shims/fs.js Normal file
View File

@ -0,0 +1,65 @@
const { FileSystem } = require('../src/index');
let Provider;
try {
Provider = require('fsProvider');
}
catch (err) {
Provider = require('./providers/default');
}
const provider = new Provider();
let onFsReady;
let onFsError;
let fsReady = new Promise((resolve, reject) => {
onFsReady = resolve;
onFsError = reject;
});
var fsInstance = new FileSystem({ provider }, (err) => {
if (err) {
onFsError(err);
} else {
onFsReady(true);
}
});
function proxyHasProp(target, prop) {
return prop in target;
}
const fsPromises = new Proxy(fsInstance.promises, {
get(target, prop) {
if (!proxyHasProp(target, prop)) {
return;
}
return async (...args) => {
await fsReady;
return await target[prop](...args);
};
},
});
const fs = new Proxy(fsInstance, {
get(target, prop) {
if (!proxyHasProp(target, prop)) {
return;
}
if (prop === 'promises') {
return fsPromises;
}
return (...args) => {
(async () => {
await fsReady;
target[prop](...args);
})();
};
},
});
module.exports = fs;

3
shims/path.js Normal file
View File

@ -0,0 +1,3 @@
const { path } = require('../src/index');
module.exports = path;

View File

@ -0,0 +1,2 @@
const { Default } = require('../../src/providers/index');
module.exports = Default;

View File

@ -0,0 +1,2 @@
const IndexedDB = require('../../src/providers/indexeddb');
module.exports = IndexedDB;

View File

@ -0,0 +1,2 @@
const Memory = require('../../src/providers/memory');
module.exports = Memory;

View File

@ -1,23 +0,0 @@
function FilerBuffer (subject, encoding, nonZero) {
// Automatically turn ArrayBuffer into Uint8Array so that underlying
// Buffer code doesn't just throw away and ignore ArrayBuffer data.
if (subject instanceof ArrayBuffer) {
subject = new Uint8Array(subject);
}
return new Buffer(subject, encoding, nonZero);
};
// Inherit prototype from Buffer
FilerBuffer.prototype = Object.create(Buffer.prototype);
FilerBuffer.prototype.constructor = FilerBuffer;
// Also copy static methods onto FilerBuffer ctor
Object.keys(Buffer).forEach(function (p) {
if (Buffer.hasOwnProperty(p)) {
FilerBuffer[p] = Buffer[p];
}
});
module.exports = FilerBuffer;

View File

@ -15,14 +15,20 @@ module.exports = {
IDB_RO: 'readonly', IDB_RO: 'readonly',
IDB_RW: 'readwrite', IDB_RW: 'readwrite',
WSQL_VERSION: "1", WSQL_VERSION: '1',
WSQL_SIZE: 5 * 1024 * 1024, WSQL_SIZE: 5 * 1024 * 1024,
WSQL_DESC: "FileSystem Storage", WSQL_DESC: 'FileSystem Storage',
MODE_FILE: 'FILE', NODE_TYPE_FILE: 'FILE',
MODE_DIRECTORY: 'DIRECTORY', NODE_TYPE_DIRECTORY: 'DIRECTORY',
MODE_SYMBOLIC_LINK: 'SYMLINK', NODE_TYPE_SYMBOLIC_LINK: 'SYMLINK',
MODE_META: 'META', NODE_TYPE_META: 'META',
DEFAULT_DIR_PERMISSIONS: 0x1ED, // 755
DEFAULT_FILE_PERMISSIONS: 0x1A4, // 644
FULL_READ_WRITE_EXEC_PERMISSIONS: 0x1FF, // 777
READ_WRITE_PERMISSIONS: 0x1B6, /// 666
SYMLOOP_MAX: 10, SYMLOOP_MAX: 10,
@ -76,5 +82,49 @@ module.exports = {
ENVIRONMENT: { ENVIRONMENT: {
TMP: '/tmp', TMP: '/tmp',
PATH: '' PATH: ''
},
// Duplicate Node's fs.constants
fsConstants: {
O_RDONLY: 0,
O_WRONLY: 1,
O_RDWR: 2,
S_IFMT: 61440,
S_IFREG: 32768,
S_IFDIR: 16384,
S_IFCHR: 8192,
S_IFBLK: 24576,
S_IFIFO: 4096,
S_IFLNK: 40960,
S_IFSOCK: 49152,
O_CREAT: 512,
O_EXCL: 2048,
O_NOCTTY: 131072,
O_TRUNC: 1024,
O_APPEND: 8,
O_DIRECTORY: 1048576,
O_NOFOLLOW: 256,
O_SYNC: 128,
O_DSYNC: 4194304,
O_SYMLINK: 2097152,
O_NONBLOCK: 4,
S_IRWXU: 448,
S_IRUSR: 256,
S_IWUSR: 128,
S_IXUSR: 64,
S_IRWXG: 56,
S_IRGRP: 32,
S_IWGRP: 16,
S_IXGRP: 8,
S_IRWXO: 7,
S_IROTH: 4,
S_IWOTH: 2,
S_IXOTH: 1,
F_OK: 0,
R_OK: 4,
W_OK: 2,
X_OK: 1,
UV_FS_COPYFILE_EXCL: 1,
COPYFILE_EXCL: 1
} }
}; };

View File

@ -1,6 +1,6 @@
var MODE_FILE = require('./constants.js').MODE_FILE; var NODE_TYPE_FILE = require('./constants.js').NODE_TYPE_FILE;
module.exports = function DirectoryEntry(id, type) { module.exports = function DirectoryEntry(id, type) {
this.id = id; this.id = id;
this.type = type || MODE_FILE; this.type = type || NODE_TYPE_FILE;
}; };

12
src/dirent.js Normal file
View File

@ -0,0 +1,12 @@
'use strict';
const Stats = require('./stats.js');
function Dirent(path, fileNode, devName) {
this.constructor = Dirent;
Stats.call(this, path, fileNode, devName);
}
Dirent.prototype = Stats.prototype;
module.exports = Dirent;

View File

@ -1,13 +0,0 @@
// Adapt encodings to work with Buffer or Uint8Array, they expect the latter
function decode(buf) {
return buf.toString('utf8');
}
function encode(string) {
return new Buffer(string, 'utf8');
}
module.exports = {
encode: encode,
decode: decode
};

View File

@ -7,7 +7,7 @@ var errors = {};
//'0:OK:success', //'0:OK:success',
//'1:EOF:end of file', //'1:EOF:end of file',
//'2:EADDRINFO:getaddrinfo error', //'2:EADDRINFO:getaddrinfo error',
//'3:EACCES:permission denied', '3:EACCES:permission denied',
//'4:EAGAIN:resource temporarily unavailable', //'4:EAGAIN:resource temporarily unavailable',
//'5:EADDRINUSE:address already in use', //'5:EADDRINUSE:address already in use',
//'6:EADDRNOTAVAIL:address not available', //'6:EADDRNOTAVAIL:address not available',

File diff suppressed because it is too large Load Diff

View File

@ -1,44 +1,111 @@
var _ = require('../../lib/nodash.js'); 'use strict';
var isNullPath = require('../path.js').isNull; const { promisify } = require('es6-promisify');
var nop = require('../shared.js').nop;
var Constants = require('../constants.js'); const Path = require('../path.js');
var FILE_SYSTEM_NAME = Constants.FILE_SYSTEM_NAME;
var FS_FORMAT = Constants.FS_FORMAT;
var FS_READY = Constants.FS_READY;
var FS_PENDING = Constants.FS_PENDING;
var FS_ERROR = Constants.FS_ERROR;
var FS_NODUPEIDCHECK = Constants.FS_NODUPEIDCHECK;
var providers = require('../providers/index.js'); const providers = require('../providers/index.js');
var Shell = require('../shell/shell.js'); const Shell = require('../shell/shell.js');
var Intercom = require('../../lib/intercom.js'); const Intercom = require('../../lib/intercom.js');
var FSWatcher = require('../fs-watcher.js'); const FSWatcher = require('../fs-watcher.js');
var Errors = require('../errors.js'); const Errors = require('../errors.js');
var defaultGuidFn = require('../shared.js').guid; const {
nop,
guid: defaultGuidFn
} = require('../shared.js');
var STDIN = Constants.STDIN; const {
var STDOUT = Constants.STDOUT; fsConstants,
var STDERR = Constants.STDERR; FILE_SYSTEM_NAME,
var FIRST_DESCRIPTOR = Constants.FIRST_DESCRIPTOR; FS_FORMAT,
FS_READY,
FS_PENDING,
FS_ERROR,
FS_NODUPEIDCHECK,
STDIN,
STDOUT,
STDERR
} = require('../constants.js');
// The core fs operations live on impl // The core fs operations live on impl
var impl = require('./implementation.js'); const impl = require('./implementation.js');
// node.js supports a calling pattern that leaves off a callback. // node.js supports a calling pattern that leaves off a callback.
function maybeCallback(callback) { function maybeCallback(callback) {
if(typeof callback === "function") { if (typeof callback === 'function') {
return callback; return callback;
} }
return function(err) { return function (err) {
if(err) { if (err) {
throw err; throw err;
} }
}; };
} }
// Default callback that logs an error if passed in
function defaultCallback(err) {
if (err) {
/* eslint no-console: 0 */
console.error('Filer error: ', err);
}
}
// Get a path (String) from a file:// URL. Support URL() like objects
// https://github.com/nodejs/node/blob/968e901aff38a343b1de4addebf79fd8fa991c59/lib/internal/url.js#L1381
function toPathIfFileURL(fileURLOrPath) {
if (!(fileURLOrPath &&
fileURLOrPath.protocol &&
fileURLOrPath.pathname)) {
return fileURLOrPath;
}
if (fileURLOrPath.protocol !== 'file:') {
throw new Errors.EINVAL('only file: URLs are supported for paths', fileURLOrPath);
}
const pathname = fileURLOrPath.pathname;
for (let n = 0; n < pathname.length; n++) {
if (pathname[n] === '%') {
const third = pathname.codePointAt(n + 2) | 0x20;
if (pathname[n + 1] === '2' && third === 102) {
throw new Errors.EINVAL('file: URLs must not include encoded / characters', fileURLOrPath);
}
}
}
return decodeURIComponent(pathname);
}
// Allow Buffers for paths. Assumes we want UTF8.
function toPathIfBuffer(bufferOrPath) {
return Buffer.isBuffer(bufferOrPath) ? bufferOrPath.toString() : bufferOrPath;
}
function validatePath(path, allowRelative) {
if (!path) {
return new Errors.EINVAL('Path must be a string', path);
} else if (Path.isNull(path)) {
return new Errors.EINVAL('Path must be a string without null bytes.', path);
} else if (!allowRelative && !Path.isAbsolute(path)) {
return new Errors.EINVAL('Path must be absolute.', path);
}
}
function processPathArg(args, idx, allowRelative) {
let path = args[idx];
path = toPathIfFileURL(path);
path = toPathIfBuffer(path);
// Some methods specifically allow for rel paths (eg symlink with srcPath)
let err = validatePath(path, allowRelative);
if (err) {
throw err;
}
// Overwrite path arg with converted and validated path
args[idx] = path;
}
/** /**
* FileSystem * FileSystem
* *
@ -69,16 +136,16 @@ function maybeCallback(callback) {
*/ */
function FileSystem(options, callback) { function FileSystem(options, callback) {
options = options || {}; options = options || {};
callback = callback || nop; callback = callback || defaultCallback;
var flags = options.flags; const flags = options.flags || [];
var guid = options.guid ? options.guid : defaultGuidFn; const guid = options.guid ? options.guid : defaultGuidFn;
var provider = options.provider || new providers.Default(options.name || FILE_SYSTEM_NAME); const provider = options.provider || new providers.Default(options.name || FILE_SYSTEM_NAME);
// If we're given a provider, match its name unless we get an explicit name // If we're given a provider, match its name unless we get an explicit name
var name = options.name || provider.name; const name = options.name || provider.name;
var forceFormatting = _(flags).contains(FS_FORMAT); const forceFormatting = flags.includes(FS_FORMAT);
var fs = this; const fs = this;
fs.readyState = FS_PENDING; fs.readyState = FS_PENDING;
fs.name = name; fs.name = name;
fs.error = null; fs.error = null;
@ -87,30 +154,25 @@ function FileSystem(options, callback) {
fs.stdout = STDOUT; fs.stdout = STDOUT;
fs.stderr = STDERR; fs.stderr = STDERR;
// Safely expose the list of open files and file // Expose Node's fs.constants to users
// descriptor management functions fs.constants = fsConstants;
var openFiles = {}; // Node also forwards the access mode flags onto fs
var nextDescriptor = FIRST_DESCRIPTOR; fs.F_OK = fsConstants.F_OK;
Object.defineProperty(this, "openFiles", { fs.R_OK = fsConstants.R_OK;
get: function() { return openFiles; } fs.W_OK = fsConstants.W_OK;
}); fs.X_OK = fsConstants.X_OK;
this.allocDescriptor = function(openFileDescription) {
var fd = nextDescriptor ++; // Expose Shell constructor
openFiles[fd] = openFileDescription; this.Shell = Shell.bind(undefined, this);
return fd;
};
this.releaseDescriptor = function(fd) {
delete openFiles[fd];
};
// Safely expose the operation queue // Safely expose the operation queue
var queue = []; let queue = [];
this.queueOrRun = function(operation) { this.queueOrRun = function (operation) {
var error; let error;
if(FS_READY == fs.readyState) { if (FS_READY === fs.readyState) {
operation.call(fs); operation.call(fs);
} else if(FS_ERROR == fs.readyState) { } else if (FS_ERROR === fs.readyState) {
error = new Errors.EFILESYSTEMERROR('unknown error'); error = new Errors.EFILESYSTEMERROR('unknown error');
} else { } else {
queue.push(operation); queue.push(operation);
@ -119,25 +181,25 @@ function FileSystem(options, callback) {
return error; return error;
}; };
function runQueued() { function runQueued() {
queue.forEach(function(operation) { queue.forEach(function (operation) {
operation.call(this); operation.call(this);
}.bind(fs)); }.bind(fs));
queue = null; queue = null;
} }
// We support the optional `options` arg from node, but ignore it // We support the optional `options` arg from node, but ignore it
this.watch = function(filename, options, listener) { this.watch = function (filename, options, listener) {
if(isNullPath(filename)) { if (Path.isNull(filename)) {
throw new Error('Path must be a string without null bytes.'); throw new Error('Path must be a string without null bytes.');
} }
if(typeof options === 'function') { if (typeof options === 'function') {
listener = options; listener = options;
options = {}; options = {};
} }
options = options || {}; options = options || {};
listener = listener || nop; listener = listener || nop;
var watcher = new FSWatcher(); const watcher = new FSWatcher();
watcher.start(filename, false, options.recursive); watcher.start(filename, false, options.recursive);
watcher.on('change', listener); watcher.on('change', listener);
@ -146,24 +208,24 @@ function FileSystem(options, callback) {
// Deal with various approaches to node ID creation // Deal with various approaches to node ID creation
function wrappedGuidFn(context) { function wrappedGuidFn(context) {
return function(callback) { return function (callback) {
// Skip the duplicate ID check if asked to // Skip the duplicate ID check if asked to
if(_(flags).contains(FS_NODUPEIDCHECK)) { if (flags.includes(FS_NODUPEIDCHECK)) {
callback(null, guid()); callback(null, guid());
return; return;
} }
// Otherwise (default) make sure this id is unused first // Otherwise (default) make sure this id is unused first
function guidWithCheck(callback) { function guidWithCheck(callback) {
var id = guid(); const id = guid();
context.getObject(id, function(err, value) { context.getObject(id, function (err, value) {
if(err) { if (err) {
callback(err); callback(err);
return; return;
} }
// If this id is unused, use it, otherwise find another // If this id is unused, use it, otherwise find another
if(!value) { if (!value) {
callback(null, id); callback(null, id);
} else { } else {
guidWithCheck(callback); guidWithCheck(callback);
@ -177,27 +239,28 @@ function FileSystem(options, callback) {
// Let other instances (in this or other windows) know about // Let other instances (in this or other windows) know about
// any changes to this fs instance. // any changes to this fs instance.
function broadcastChanges(changes) { function broadcastChanges(changes) {
if(!changes.length) { if (!changes.length) {
return; return;
} }
var intercom = Intercom.getInstance(); const intercom = Intercom.getInstance();
changes.forEach(function(change) { changes.forEach(function (change) {
intercom.emit(change.event, change.path); intercom.emit(change.event, change.path);
}); });
} }
// Open file system storage provider // Open file system storage provider
provider.open(function(err) { provider.open(function (err) {
function complete(error) { function complete(error) {
function wrappedContext(methodName) { function wrappedContext(methodName) {
var context = provider[methodName](); let context = provider[methodName]();
context.name = name;
context.flags = flags; context.flags = flags;
context.changes = []; context.changes = [];
context.guid = wrappedGuidFn(context); context.guid = wrappedGuidFn(context);
// When the context is finished, let the fs deal with any change events // When the context is finished, let the fs deal with any change events
context.close = function() { context.close = function () {
var changes = context.changes; let changes = context.changes;
broadcastChanges(changes); broadcastChanges(changes);
changes.length = 0; changes.length = 0;
}; };
@ -210,15 +273,15 @@ function FileSystem(options, callback) {
// for paths updated during the lifetime of the context). From this // for paths updated during the lifetime of the context). From this
// point forward we won't call open again, so it's safe to drop it. // point forward we won't call open again, so it's safe to drop it.
fs.provider = { fs.provider = {
openReadWriteContext: function() { openReadWriteContext: function () {
return wrappedContext('getReadWriteContext'); return wrappedContext('getReadWriteContext');
}, },
openReadOnlyContext: function() { openReadOnlyContext: function () {
return wrappedContext('getReadOnlyContext'); return wrappedContext('getReadOnlyContext');
} }
}; };
if(error) { if (error) {
fs.readyState = FS_ERROR; fs.readyState = FS_ERROR;
} else { } else {
fs.readyState = FS_READY; fs.readyState = FS_READY;
@ -227,18 +290,18 @@ function FileSystem(options, callback) {
callback(error, fs); callback(error, fs);
} }
if(err) { if (err) {
return complete(err); return complete(err);
} }
var context = provider.getReadWriteContext(); const context = provider.getReadWriteContext();
context.guid = wrappedGuidFn(context); context.guid = wrappedGuidFn(context);
// Mount the filesystem, formatting if necessary // Mount the filesystem, formatting if necessary
if(forceFormatting) { if (forceFormatting) {
// Wipe the storage provider, then write root block // Wipe the storage provider, then write root block
context.clear(function(err) { context.clear(function (err) {
if(err) { if (err) {
return complete(err); return complete(err);
} }
impl.ensureRootDirectory(context, complete); impl.ensureRootDirectory(context, complete);
@ -248,94 +311,128 @@ function FileSystem(options, callback) {
impl.ensureRootDirectory(context, complete); impl.ensureRootDirectory(context, complete);
} }
}); });
FileSystem.prototype.promises = {};
/**
* Public API for FileSystem. All node.js methods that are exposed on fs.promises
* include `promise: true`. We also include our own extra methods, but skip the
* fd versions to match node.js, which puts these on a `FileHandle` object.
* Any method that deals with path argument(s) also includes the position of
* those args in one of `absPathArgs: [...]` or `relPathArgs: [...]`, so they
* can be processed and validated before being passed on to the method.
*/
[
{ name: 'appendFile', promises: true, absPathArgs: [0] },
{ name: 'access', promises: true, absPathArgs: [0] },
{ name: 'chown', promises: true, absPathArgs: [0] },
{ name: 'chmod', promises: true, absPathArgs: [0] },
{ name: 'close' },
// copyFile - https://github.com/filerjs/filer/issues/436
{ name: 'exists', absPathArgs: [0] },
{ name: 'fchown' },
{ name: 'fchmod' },
// fdatasync - https://github.com/filerjs/filer/issues/653
{ name: 'fgetxattr' },
{ name: 'fremovexattr' },
{ name: 'fsetxattr' },
{ name: 'fstat' },
{ name: 'fsync' },
{ name: 'ftruncate' },
{ name: 'futimes' },
{ name: 'getxattr', promises: true, absPathArgs: [0] },
// lchown - https://github.com/filerjs/filer/issues/620
// lchmod - https://github.com/filerjs/filer/issues/619
{ name: 'link', promises: true, absPathArgs: [0, 1] },
{ name: 'lseek' },
{ name: 'lstat', promises: true },
{ name: 'mkdir', promises: true, absPathArgs: [0] },
{ name: 'mkdtemp', promises: true },
{ name: 'mknod', promises: true, absPathArgs: [0] },
{ name: 'open', promises: true, absPathArgs: [0] },
{ name: 'readdir', promises: true, absPathArgs: [0] },
{ name: 'read' },
{ name: 'readFile', promises: true, absPathArgs: [0] },
{ name: 'readlink', promises: true, absPathArgs: [0] },
// realpath - https://github.com/filerjs/filer/issues/85
{ name: 'removexattr', promises: true, absPathArgs: [0] },
{ name: 'rename', promises: true, absPathArgs: [0, 1] },
{ name: 'rmdir', promises: true, absPathArgs: [0] },
{ name: 'setxattr', promises: true, absPathArgs: [0] },
{ name: 'stat', promises: true, absPathArgs: [0] },
{ name: 'symlink', promises: true, relPathArgs: [0], absPathArgs: [1] },
{ name: 'truncate', promises: true, absPathArgs: [0] },
// unwatchFile - https://github.com/filerjs/filer/pull/553
{ name: 'unlink', promises: true, absPathArgs: [0] },
{ name: 'utimes', promises: true, absPathArgs: [0] },
// watch - implemented above in `this.watch`
// watchFile - https://github.com/filerjs/filer/issues/654
{ name: 'writeFile', promises: true, absPathArgs: [0] },
{ name: 'write' }
].forEach(function (method) {
const methodName = method.name;
const shouldPromisify = method.promises === true;
FileSystem.prototype[methodName] = function () {
const fs = this;
const args = Array.prototype.slice.call(arguments, 0);
const lastArgIndex = args.length - 1;
// We may or may not get a callback, and since node.js supports
// fire-and-forget style fs operations, we have to dance a bit here.
const missingCallback = typeof args[lastArgIndex] !== 'function';
const callback = maybeCallback(args[lastArgIndex]);
// Deal with path arguments, validating and normalizing Buffer and file:// URLs
if (method.absPathArgs) {
method.absPathArgs.forEach(pathArg => processPathArg(args, pathArg, false));
}
if (method.relPathArgs) {
method.relPathArgs.forEach(pathArg => processPathArg(args, pathArg, true));
}
const error = fs.queueOrRun(function () {
const context = fs.provider.openReadWriteContext();
// Fail early if the filesystem is in an error state (e.g.,
// provider failed to open.
if (FS_ERROR === fs.readyState) {
const err = new Errors.EFILESYSTEMERROR('filesystem unavailable, operation canceled');
return callback.call(fs, err);
}
// Wrap the callback so we can explicitly close the context
function complete() {
context.close();
callback.apply(fs, arguments);
}
// Either add or replace the callback with our wrapper complete()
if (missingCallback) {
args.push(complete);
} else {
args[lastArgIndex] = complete;
}
// Forward this call to the impl's version, using the following
// call signature, with complete() as the callback/last-arg now:
// fn(fs, context, arg0, arg1, ... , complete);
const fnArgs = [context].concat(args);
impl[methodName].apply(null, fnArgs);
});
if (error) {
callback(error);
}
};
// Add to fs.promises if appropriate
if (shouldPromisify) {
FileSystem.prototype.promises[methodName] = promisify(FileSystem.prototype[methodName].bind(fs));
}
});
} }
// Expose storage providers on FileSystem constructor // Expose storage providers on FileSystem constructor
FileSystem.providers = providers; FileSystem.providers = providers;
/**
* Public API for FileSystem
*/
[
'open',
'close',
'mknod',
'mkdir',
'rmdir',
'stat',
'fstat',
'link',
'unlink',
'read',
'readFile',
'write',
'writeFile',
'appendFile',
'exists',
'lseek',
'readdir',
'rename',
'readlink',
'symlink',
'lstat',
'truncate',
'ftruncate',
'utimes',
'futimes',
'setxattr',
'getxattr',
'fsetxattr',
'fgetxattr',
'removexattr',
'fremovexattr'
].forEach(function(methodName) {
FileSystem.prototype[methodName] = function() {
var fs = this;
var args = Array.prototype.slice.call(arguments, 0);
var lastArgIndex = args.length - 1;
// We may or may not get a callback, and since node.js supports
// fire-and-forget style fs operations, we have to dance a bit here.
var missingCallback = typeof args[lastArgIndex] !== 'function';
var callback = maybeCallback(args[lastArgIndex]);
var error = fs.queueOrRun(function() {
var context = fs.provider.openReadWriteContext();
// Fail early if the filesystem is in an error state (e.g.,
// provider failed to open.
if(FS_ERROR === fs.readyState) {
var err = new Errors.EFILESYSTEMERROR('filesystem unavailable, operation canceled');
return callback.call(fs, err);
}
// Wrap the callback so we can explicitly close the context
function complete() {
context.close();
callback.apply(fs, arguments);
}
// Either add or replace the callback with our wrapper complete()
if(missingCallback) {
args.push(complete);
} else {
args[lastArgIndex] = complete;
}
// Forward this call to the impl's version, using the following
// call signature, with complete() as the callback/last-arg now:
// fn(fs, context, arg0, arg1, ... , complete);
var fnArgs = [fs, context].concat(args);
impl[methodName].apply(null, fnArgs);
});
if(error) {
callback(error);
}
};
});
FileSystem.prototype.Shell = function(options) {
return new Shell(this, options);
};
module.exports = FileSystem; module.exports = FileSystem;

View File

@ -1,6 +1,8 @@
var EventEmitter = require('../lib/eventemitter.js'); 'using strict';
var Path = require('./path.js');
var Intercom = require('../lib/intercom.js'); const EventEmitter = require('../lib/eventemitter.js');
const Path = require('./path.js');
const Intercom = require('../lib/intercom.js');
/** /**
* FSWatcher based on node.js' FSWatcher * FSWatcher based on node.js' FSWatcher
@ -8,10 +10,10 @@ var Intercom = require('../lib/intercom.js');
*/ */
function FSWatcher() { function FSWatcher() {
EventEmitter.call(this); EventEmitter.call(this);
var self = this; const self = this;
var recursive = false; let recursive = false;
var recursivePathPrefix; let recursivePathPrefix;
var filename; let filename;
function onchange(path) { function onchange(path) {
// Watch for exact filename, or parent path when recursive is true. // Watch for exact filename, or parent path when recursive is true.
@ -46,12 +48,12 @@ function FSWatcher() {
recursivePathPrefix = filename === '/' ? '/' : filename + '/'; recursivePathPrefix = filename === '/' ? '/' : filename + '/';
} }
var intercom = Intercom.getInstance(); const intercom = Intercom.getInstance();
intercom.on('change', onchange); intercom.on('change', onchange);
}; };
self.close = function() { self.close = function() {
var intercom = Intercom.getInstance(); const intercom = Intercom.getInstance();
intercom.off('change', onchange); intercom.off('change', onchange);
self.removeAllListeners('change'); self.removeAllListeners('change');
}; };

View File

@ -1,6 +1,34 @@
module.exports = { let fs = null;
let Filer = null;
module.exports = Filer = {
FileSystem: require('./filesystem/interface.js'), FileSystem: require('./filesystem/interface.js'),
Buffer: require('./buffer.js'), Buffer: Buffer,
// We previously called this Path, but node calls it path. Do both
Path: require('./path.js'), Path: require('./path.js'),
Errors: require('./errors.js') path: require('./path.js'),
Errors: require('./errors.js'),
Shell: require('./shell/shell.js'),
/**
* @deprecated Importing filer from your webpack config is not recommended.
*
* The filer `FilerWebpackPlugin` class is exposed directly.
*
* ```
* const { FilerWebpackPlugin } = require('filer/webpack');
* ```
*/
FilerWebpackPlugin: require('./webpack-plugin'),
}; };
// Add a getter for the `fs` instance, which returns
// a Filer FileSystem instance, using the default provider/flags.
Object.defineProperty(Filer, 'fs', {
enumerable: true,
get() {
if(!fs) {
fs = new Filer.FileSystem();
}
return fs;
}
});

View File

@ -1,53 +1,135 @@
var MODE_FILE = require('./constants.js').MODE_FILE; const {
NODE_TYPE_FILE,
NODE_TYPE_DIRECTORY,
NODE_TYPE_SYMBOLIC_LINK,
DEFAULT_FILE_PERMISSIONS,
DEFAULT_DIR_PERMISSIONS
} = require('./constants');
const {
S_IFREG,
S_IFDIR,
S_IFLNK
} = require('./constants').fsConstants;
function Node(options) { /**
var now = Date.now(); * Make sure the options object has an id on property,
* either from caller or one we generate using supplied guid fn.
this.id = options.id; */
this.mode = options.mode || MODE_FILE; // node type (file, directory, etc)
this.size = options.size || 0; // size (bytes for files, entries for directories)
this.atime = options.atime || now; // access time (will mirror ctime after creation)
this.ctime = options.ctime || now; // creation/change time
this.mtime = options.mtime || now; // modified time
this.flags = options.flags || []; // file flags
this.xattrs = options.xattrs || {}; // extended attributes
this.nlinks = options.nlinks || 0; // links count
this.version = options.version || 0; // node version
this.blksize = undefined; // block size
this.nblocks = 1; // blocks count
this.data = options.data; // id for data object
}
// Make sure the options object has an id on property,
// either from caller or one we generate using supplied guid fn.
function ensureID(options, prop, callback) { function ensureID(options, prop, callback) {
if(options[prop]) { if(options[prop]) {
callback(null); return callback();
} else { }
options.guid(function(err, id) {
options[prop] = id; options.guid(function(err, id) {
callback(err); if(err) {
}); return callback(err);
}
options[prop] = id;
callback();
});
}
/**
* Generate a POSIX mode (integer) for the node type and permissions.
* Use default permissions if we aren't passed any.
*/
function generateMode(nodeType, modePermissions) {
switch(nodeType) {
case NODE_TYPE_DIRECTORY:
return (modePermissions || DEFAULT_DIR_PERMISSIONS) | S_IFDIR;
case NODE_TYPE_SYMBOLIC_LINK:
return (modePermissions || DEFAULT_FILE_PERMISSIONS) | S_IFLNK;
case NODE_TYPE_FILE:
// falls through
default:
return (modePermissions || DEFAULT_FILE_PERMISSIONS) | S_IFREG;
} }
} }
Node.create = function(options, callback) { /**
* Common properties for the layout of a Node
*/
class Node {
constructor(options) {
var now = Date.now();
this.id = options.id;
this.data = options.data; // id for data object
this.size = options.size || 0; // size (bytes for files, entries for directories)
this.atime = options.atime || now; // access time (will mirror ctime after creation)
this.ctime = options.ctime || now; // creation/change time
this.mtime = options.mtime || now; // modified time
this.flags = options.flags || []; // file flags
this.xattrs = options.xattrs || {}; // extended attributes
this.nlinks = options.nlinks || 0; // links count
// Historically, Filer's node layout has referred to the
// node type as `mode`, and done so using a String. In
// a POSIX filesystem, the mode is a number that combines
// both node type and permission bits. Internal we use `type`,
// but store it in the database as `mode` for backward
// compatibility.
if(typeof options.type === 'string') {
this.type = options.type;
} else if(typeof options.mode === 'string') {
this.type = options.mode;
} else {
this.type = NODE_TYPE_FILE;
}
// Extra mode permissions and ownership info
this.permissions = options.permissions || generateMode(this.type);
this.uid = options.uid || 0x0; // owner name
this.gid = options.gid || 0x0; // group name
}
/**
* Serialize a Node to JSON. Everything is as expected except
* that we use `mode` for `type` to maintain backward compatibility.
*/
toJSON() {
return {
id: this.id,
data: this.data,
size: this.size,
atime: this.atime,
ctime: this.ctime,
mtime: this.ctime,
flags: this.flags,
xattrs: this.xattrs,
nlinks: this.nlinks,
// Use `mode` for `type` to keep backward compatibility
mode: this.type,
permissions: this.permissions,
uid: this.uid,
gid: this.gid
};
}
// Return complete POSIX `mode` for node type + permissions. See:
// http://man7.org/linux/man-pages/man2/chmod.2.html
get mode() {
return generateMode(this.type, this.permissions);
}
// When setting the `mode` we assume permissions bits only (not changing type)
set mode(value) {
this.permissions = value;
}
}
module.exports.create = function create(options, callback) {
// We expect both options.id and options.data to be provided/generated. // We expect both options.id and options.data to be provided/generated.
ensureID(options, 'id', function(err) { ensureID(options, 'id', function(err) {
if(err) { if(err) {
callback(err); return callback(err);
return;
} }
ensureID(options, 'data', function(err) { ensureID(options, 'data', function(err) {
if(err) { if(err) {
callback(err); return callback(err);
return;
} }
callback(null, new Node(options)); callback(null, new Node(options));
}); });
}); });
}; };
module.exports = Node;

Some files were not shown because too many files have changed in this diff Show More