吕君喜 před 3 roky
rodič
revize
e8b3c1ac64
100 změnil soubory, kde provedl 7412 přidání a 1826 odebrání
  1. 16 0
      base64id/CHANGELOG.md
  2. 12 0
      date-format/.eslintrc
  3. 6 0
      date-format/.travis.yml
  4. 20 0
      date-format/LICENSE
  5. 58 0
      date-format/README.md
  6. 219 0
      date-format/lib/index.js
  7. 64 0
      date-format/package.json
  8. 61 0
      date-format/test/date_format-test.js
  9. 220 0
      date-format/test/parse-test.js
  10. 10 9
      debug/LICENSE
  11. 229 63
      debug/README.md
  12. 53 42
      debug/package.json
  13. 194 110
      debug/src/browser.js
  14. 274 0
      debug/src/common.js
  15. 4 4
      debug/src/index.js
  16. 180 165
      debug/src/node.js
  17. 50 0
      engine.io-client/CHANGELOG.md
  18. 9 0
      engine.io-client/lib/globalThis.browser.js
  19. 1 0
      engine.io-client/lib/globalThis.js
  20. 1 0
      engine.io-parser/CHANGELOG.md
  21. 29 0
      engine.io/CHANGELOG.md
  22. 912 0
      engine.io/node_modules/debug/dist/debug.js
  23. 152 0
      engine.io/node_modules/debug/node_modules/ms/index.js
  24. 21 0
      engine.io/node_modules/debug/node_modules/ms/license.md
  25. 69 0
      engine.io/node_modules/debug/node_modules/ms/package.json
  26. 51 0
      engine.io/node_modules/debug/node_modules/ms/readme.md
  27. 266 0
      engine.io/node_modules/debug/src/common.js
  28. 162 0
      engine.io/node_modules/ms/index.js
  29. 21 0
      engine.io/node_modules/ms/license.md
  30. 70 0
      engine.io/node_modules/ms/package.json
  31. 59 0
      engine.io/node_modules/ms/readme.md
  32. 8 0
      flatted/.github/FUNDING.yml
  33. 15 0
      flatted/LICENSE
  34. 65 0
      flatted/README.md
  35. 94 0
      flatted/SPECS.md
  36. 114 0
      flatted/cjs/index.js
  37. 116 0
      flatted/esm/index.js
  38. 113 0
      flatted/index.js
  39. 2 0
      flatted/min.js
  40. 71 0
      flatted/package.json
  41. 19 0
      flatted/types.d.ts
  42. 330 19
      fs-extra/CHANGELOG.md
  43. 1 1
      fs-extra/LICENSE
  44. 89 416
      fs-extra/README.md
  45. 151 35
      fs-extra/lib/copy-sync/copy-sync.js
  46. 2 0
      fs-extra/lib/copy-sync/index.js
  47. 204 36
      fs-extra/lib/copy/copy.js
  48. 4 1
      fs-extra/lib/copy/index.js
  49. 17 16
      fs-extra/lib/empty/index.js
  50. 22 16
      fs-extra/lib/ensure/file.js
  51. 5 3
      fs-extra/lib/ensure/index.js
  52. 21 18
      fs-extra/lib/ensure/link.js
  53. 16 14
      fs-extra/lib/ensure/symlink-paths.js
  54. 9 5
      fs-extra/lib/ensure/symlink-type.js
  55. 31 30
      fs-extra/lib/ensure/symlink.js
  56. 109 0
      fs-extra/lib/fs/index.js
  57. 26 35
      fs-extra/lib/index.js
  58. 11 4
      fs-extra/lib/json/index.js
  59. 7 9
      fs-extra/lib/json/jsonfile.js
  60. 7 5
      fs-extra/lib/json/output-json-sync.js
  61. 10 7
      fs-extra/lib/json/output-json.js
  62. 11 6
      fs-extra/lib/mkdirs/index.js
  63. 23 26
      fs-extra/lib/mkdirs/mkdirs-sync.js
  64. 12 10
      fs-extra/lib/mkdirs/mkdirs.js
  65. 7 6
      fs-extra/lib/mkdirs/win32.js
  66. 5 0
      fs-extra/lib/move-sync/index.js
  67. 47 0
      fs-extra/lib/move-sync/move-sync.js
  68. 3 158
      fs-extra/lib/move/index.js
  69. 65 0
      fs-extra/lib/move/move.js
  70. 17 12
      fs-extra/lib/output/index.js
  71. 12 0
      fs-extra/lib/path-exists/index.js
  72. 5 10
      fs-extra/lib/remove/index.js
  73. 314 0
      fs-extra/lib/remove/rimraf.js
  74. 12 0
      fs-extra/lib/util/buffer.js
  75. 172 0
      fs-extra/lib/util/stat.js
  76. 31 21
      fs-extra/lib/util/utimes.js
  77. 35 27
      fs-extra/package.json
  78. 11 1
      graceful-fs/README.md
  79. 5 1
      graceful-fs/clone.js
  80. 236 86
      graceful-fs/graceful-fs.js
  81. 16 16
      graceful-fs/package.json
  82. 41 24
      graceful-fs/polyfills.js
  83. 20 1
      jsonfile/CHANGELOG.md
  84. 39 33
      jsonfile/README.md
  85. 26 25
      jsonfile/index.js
  86. 15 13
      jsonfile/package.json
  87. 126 0
      log4js/CHANGELOG.md
  88. 13 0
      log4js/LICENSE
  89. 78 100
      log4js/README.md
  90. 80 0
      log4js/lib/LoggingEvent.js
  91. 44 0
      log4js/lib/appenders/adapters.js
  92. 19 0
      log4js/lib/appenders/categoryFilter.js
  93. 9 12
      log4js/lib/appenders/console.js
  94. 47 35
      log4js/lib/appenders/dateFile.js
  95. 81 56
      log4js/lib/appenders/file.js
  96. 208 0
      log4js/lib/appenders/fileSync.js
  97. 131 0
      log4js/lib/appenders/index.js
  98. 10 14
      log4js/lib/appenders/logLevelFilter.js
  99. 83 0
      log4js/lib/appenders/multiFile.js
  100. 121 70
      log4js/lib/appenders/multiprocess.js

+ 16 - 0
base64id/CHANGELOG.md

@@ -0,0 +1,16 @@
+# [2.0.0](https://github.com/faeldt/base64id/compare/1.0.0...2.0.0) (2019-05-27)
+
+
+### Code Refactoring
+
+* **buffer:** replace deprecated Buffer constructor usage ([#11](https://github.com/faeldt/base64id/issues/11)) ([ccfba54](https://github.com/faeldt/base64id/commit/ccfba54))
+
+
+### BREAKING CHANGES
+
+* **buffer:** drop support for Node.js ≤ 4.4.x and 5.0.0 - 5.9.x
+
+See: https://nodejs.org/en/docs/guides/buffer-constructor-deprecation/
+
+
+

+ 12 - 0
date-format/.eslintrc

@@ -0,0 +1,12 @@
+{
+  "extends": [
+    "eslint:recommended"
+  ],
+  "env": {
+    "node": true,
+    "mocha": true
+  },
+  "plugins": [
+      "mocha"
+  ]
+}

+ 6 - 0
date-format/.travis.yml

@@ -0,0 +1,6 @@
+language: node_js
+sudo: false
+node_js:
+  - "10"
+  - "8"
+  - "6"

+ 20 - 0
date-format/LICENSE

@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Gareth Jones
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 58 - 0
date-format/README.md

@@ -0,0 +1,58 @@
+date-format
+===========
+
+node.js formatting of Date objects as strings. Probably exactly the same as some other library out there.
+
+```sh
+npm install date-format
+```
+
+usage
+=====
+
+Formatting dates as strings
+----
+
+```javascript
+var format = require('date-format');
+format.asString(); //defaults to ISO8601 format and current date.
+format.asString(new Date()); //defaults to ISO8601 format
+format.asString('hh:mm:ss.SSS', new Date()); //just the time
+```
+
+or
+
+```javascript
+var format = require('date-format');
+format(); //defaults to ISO8601 format and current date.
+format(new Date());
+format('hh:mm:ss.SSS', new Date());
+```
+
+Format string can be anything, but the following letters will be replaced (and leading zeroes added if necessary):
+* dd - `date.getDate()`
+* MM - `date.getMonth() + 1`
+* yy - `date.getFullYear().toString().substring(2, 4)`
+* yyyy - `date.getFullYear()`
+* hh - `date.getHours()`
+* mm - `date.getMinutes()`
+* ss - `date.getSeconds()`
+* SSS - `date.getMilliseconds()`
+* O - timezone offset in +hm format (note that time will be in UTC if displaying offset)
+
+Built-in formats:
+* `format.ISO8601_FORMAT` - `2017-03-14T14:10:20.391` (local time used)
+* `format.ISO8601_WITH_TZ_OFFSET_FORMAT` - `2017-03-14T03:10:20.391+1100` (UTC + TZ used)
+* `format.DATETIME_FORMAT` - `14 03 2017 14:10:20.391` (local time used)
+* `format.ABSOLUTETIME_FORMAT` - `14:10:20.391` (local time used)
+
+Parsing strings as dates
+----
+The date format library has limited ability to parse strings into dates. It can convert strings created using date format patterns (as above), but if you're looking for anything more sophisticated than that you should probably look for a better library ([momentjs](https://momentjs.com) does pretty much everything).
+
+```javascript
+var format = require('date-format');
+// pass in the format of the string as first argument
+format.parse(format.ISO8601_FORMAT, '2017-03-14T14:10:20.391');
+// returns Date
+```

+ 219 - 0
date-format/lib/index.js

@@ -0,0 +1,219 @@
+"use strict";
+
+function padWithZeros(vNumber, width) {
+  var numAsString = vNumber.toString();
+  while (numAsString.length < width) {
+    numAsString = "0" + numAsString;
+  }
+  return numAsString;
+}
+
+function addZero(vNumber) {
+  return padWithZeros(vNumber, 2);
+}
+
+/**
+ * Formats the TimeOffset
+ * Thanks to http://www.svendtofte.com/code/date_format/
+ * @private
+ */
+function offset(timezoneOffset) {
+  var os = Math.abs(timezoneOffset);
+  var h = String(Math.floor(os / 60));
+  var m = String(os % 60);
+  if (h.length === 1) {
+    h = "0" + h;
+  }
+  if (m.length === 1) {
+    m = "0" + m;
+  }
+  return timezoneOffset < 0 ? "+" + h + m : "-" + h + m;
+}
+
+function asString(format, date) {
+  if (typeof format !== "string") {
+    date = format;
+    format = module.exports.ISO8601_FORMAT;
+  }
+  if (!date) {
+    date = module.exports.now();
+  }
+
+  // Issue # 14 - Per ISO8601 standard, the time string should be local time
+  // with timezone info.
+  // See https://en.wikipedia.org/wiki/ISO_8601 section "Time offsets from UTC"
+
+  var vDay = addZero(date.getDate());
+  var vMonth = addZero(date.getMonth() + 1);
+  var vYearLong = addZero(date.getFullYear());
+  var vYearShort = addZero(vYearLong.substring(2, 4));
+  var vYear = format.indexOf("yyyy") > -1 ? vYearLong : vYearShort;
+  var vHour = addZero(date.getHours());
+  var vMinute = addZero(date.getMinutes());
+  var vSecond = addZero(date.getSeconds());
+  var vMillisecond = padWithZeros(date.getMilliseconds(), 3);
+  var vTimeZone = offset(date.getTimezoneOffset());
+  var formatted = format
+    .replace(/dd/g, vDay)
+    .replace(/MM/g, vMonth)
+    .replace(/y{1,4}/g, vYear)
+    .replace(/hh/g, vHour)
+    .replace(/mm/g, vMinute)
+    .replace(/ss/g, vSecond)
+    .replace(/SSS/g, vMillisecond)
+    .replace(/O/g, vTimeZone);
+  return formatted;
+}
+
+function setDatePart(date, part, value, local) {
+  date['set' + (local ? '' : 'UTC') + part](value);
+}
+
+function extractDateParts(pattern, str, missingValuesDate) {
+  // Javascript Date object doesn't support custom timezone.  Sets all felds as
+  // GMT based to begin with.  If the timezone offset is provided, then adjust
+  // it using provided timezone, otherwise, adjust it with the system timezone.
+  var local = pattern.indexOf('O') < 0;
+  var matchers = [
+    {
+      pattern: /y{1,4}/,
+      regexp: "\\d{1,4}",
+      fn: function(date, value) {
+        setDatePart(date, 'FullYear', value, local);
+      }
+    },
+    {
+      pattern: /MM/,
+      regexp: "\\d{1,2}",
+      fn: function(date, value) {
+        setDatePart(date, 'Month', (value - 1), local);
+      }
+    },
+    {
+      pattern: /dd/,
+      regexp: "\\d{1,2}",
+      fn: function(date, value) {
+        setDatePart(date, 'Date', value, local);
+      }
+    },
+    {
+      pattern: /hh/,
+      regexp: "\\d{1,2}",
+      fn: function(date, value) {
+        setDatePart(date, 'Hours', value, local);
+      }
+    },
+    {
+      pattern: /mm/,
+      regexp: "\\d\\d",
+      fn: function(date, value) {
+        setDatePart(date, 'Minutes', value, local);
+      }
+    },
+    {
+      pattern: /ss/,
+      regexp: "\\d\\d",
+      fn: function(date, value) {
+        setDatePart(date, 'Seconds', value, local);
+      }
+    },
+    {
+      pattern: /SSS/,
+      regexp: "\\d\\d\\d",
+      fn: function(date, value) {
+        setDatePart(date, 'Milliseconds', value, local);
+      }
+    },
+    {
+      pattern: /O/,
+      regexp: "[+-]\\d{3,4}|Z",
+      fn: function(date, value) {
+        if (value === "Z") {
+          value = 0;
+        }
+        var offset = Math.abs(value);
+        var timezoneOffset = (value > 0 ? -1 :  1 ) * ((offset % 100) + Math.floor(offset / 100) * 60);
+        // Per ISO8601 standard: UTC = local time - offset
+        //
+        // For example, 2000-01-01T01:00:00-0700
+        //   local time: 2000-01-01T01:00:00
+        //   ==> UTC   : 2000-01-01T08:00:00 ( 01 - (-7) = 8 )
+        //
+        // To make it even more confusing, the date.getTimezoneOffset() is
+        // opposite sign of offset string in the ISO8601 standard.  So if offset
+        // is '-0700' the getTimezoneOffset() would be (+)420. The line above
+        // calculates timezoneOffset to matche Javascript's behavior.
+        //
+        // The date/time of the input is actually the local time, so the date
+        // object that was constructed is actually local time even thought the
+        // UTC setters are used.  This means the date object's internal UTC
+        // representation was wrong.  It needs to be fixed by substracting the
+        // offset (or adding the offset minutes as they are opposite sign).
+        //
+        // Note: the time zone has to be processed after all other fileds are
+        // set.  The result would be incorrect if the offset was calculated
+        // first then overriden by the other filed setters.
+        date.setUTCMinutes(date.getUTCMinutes() + timezoneOffset);
+      }
+    }
+  ];
+
+  var parsedPattern = matchers.reduce(
+    function(p, m) {
+      if (m.pattern.test(p.regexp)) {
+        m.index = p.regexp.match(m.pattern).index;
+        p.regexp = p.regexp.replace(m.pattern, "(" + m.regexp + ")");
+      } else {
+        m.index = -1;
+      }
+      return p;
+    },
+    { regexp: pattern, index: [] }
+  );
+
+  var dateFns = matchers.filter(function(m) {
+    return m.index > -1;
+  });
+  dateFns.sort(function(a, b) {
+    return a.index - b.index;
+  });
+
+  var matcher = new RegExp(parsedPattern.regexp);
+  var matches = matcher.exec(str);
+  if (matches) {
+    var date = missingValuesDate || module.exports.now();
+    dateFns.forEach(function(f, i) {
+      f.fn(date, matches[i + 1]);
+    });
+
+    return date;
+  }
+
+  throw new Error(
+    "String '" + str + "' could not be parsed as '" + pattern + "'"
+  );
+}
+
+function parse(pattern, str, missingValuesDate) {
+  if (!pattern) {
+    throw new Error("pattern must be supplied");
+  }
+
+  return extractDateParts(pattern, str, missingValuesDate);
+}
+
+/**
+ * Used for testing - replace this function with a fixed date.
+ */
+function now() {
+  return new Date();
+}
+
+module.exports = asString;
+module.exports.asString = asString;
+module.exports.parse = parse;
+module.exports.now = now;
+module.exports.ISO8601_FORMAT = "yyyy-MM-ddThh:mm:ss.SSS";
+module.exports.ISO8601_WITH_TZ_OFFSET_FORMAT = "yyyy-MM-ddThh:mm:ss.SSSO";
+module.exports.DATETIME_FORMAT = "dd MM yyyy hh:mm:ss.SSS";
+module.exports.ABSOLUTETIME_FORMAT = "hh:mm:ss.SSS";

+ 64 - 0
date-format/package.json

@@ -0,0 +1,64 @@
+{
+  "_from": "date-format@^3.0.0",
+  "_id": "date-format@3.0.0",
+  "_inBundle": false,
+  "_integrity": "sha1-64eANlx9KxURB4+0keZHl4DzrZU=",
+  "_location": "/date-format",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "date-format@^3.0.0",
+    "name": "date-format",
+    "escapedName": "date-format",
+    "rawSpec": "^3.0.0",
+    "saveSpec": null,
+    "fetchSpec": "^3.0.0"
+  },
+  "_requiredBy": [
+    "/log4js"
+  ],
+  "_resolved": "https://registry.npm.taobao.org/date-format/download/date-format-3.0.0.tgz",
+  "_shasum": "eb8780365c7d2b1511078fb491e6479780f3ad95",
+  "_spec": "date-format@^3.0.0",
+  "_where": "D:\\project\\server\\logtest\\node_modules\\log4js",
+  "author": {
+    "name": "Gareth Jones",
+    "email": "gareth.nomiddlename@gmail.com"
+  },
+  "bugs": {
+    "url": "https://github.com/nomiddlename/date-format/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "Formatting Date objects as strings since 2013",
+  "devDependencies": {
+    "eslint": "^5.16.0",
+    "eslint-plugin-mocha": "^5.3.0",
+    "mocha": "^5.2.0",
+    "should": "^13.2.3"
+  },
+  "engines": {
+    "node": ">=4.0"
+  },
+  "gitHead": "bf59015ab6c9e86454b179374f29debbdb403522",
+  "homepage": "https://github.com/nomiddlename/date-format#readme",
+  "keywords": [
+    "date",
+    "format",
+    "string"
+  ],
+  "license": "MIT",
+  "main": "lib/index.js",
+  "name": "date-format",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/nomiddlename/date-format.git"
+  },
+  "scripts": {
+    "lint": "eslint lib/* test/*",
+    "pretest": "eslint lib/* test/*",
+    "test": "mocha"
+  },
+  "version": "3.0.0"
+}

+ 61 - 0
date-format/test/date_format-test.js

@@ -0,0 +1,61 @@
+'use strict';
+
+require('should');
+
+var dateFormat = require('../lib');
+
+function createFixedDate() {
+    return new Date(2010, 0, 11, 14, 31, 30, 5);
+}
+
+describe('date_format', function() {
+    var date = createFixedDate();
+
+    it('should default to now when a date is not provided', function() {
+        dateFormat.asString(dateFormat.DATETIME_FORMAT).should.not.be.empty();
+    });
+
+    it('should be usable directly without calling asString', function() {
+        dateFormat(dateFormat.DATETIME_FORMAT, date).should.eql('11 01 2010 14:31:30.005');
+    });
+
+    it('should format a date as string using a pattern', function() {
+        dateFormat.asString(dateFormat.DATETIME_FORMAT, date).should.eql('11 01 2010 14:31:30.005');
+    });
+
+    it('should default to the ISO8601 format', function() {
+        dateFormat.asString(date).should.eql('2010-01-11T14:31:30.005');
+    });
+
+    it('should provide a ISO8601 with timezone offset format', function() {
+        var tzDate = createFixedDate();
+        tzDate.getTimezoneOffset = function () {
+            return -660;
+        };
+
+        // when tz offset is in the pattern, the date should be in local time
+        dateFormat.asString(dateFormat.ISO8601_WITH_TZ_OFFSET_FORMAT, tzDate)
+            .should.eql('2010-01-11T14:31:30.005+1100');
+
+        tzDate = createFixedDate();
+        tzDate.getTimezoneOffset = function () {
+            return 120;
+        };
+
+        dateFormat.asString(dateFormat.ISO8601_WITH_TZ_OFFSET_FORMAT, tzDate)
+            .should.eql('2010-01-11T14:31:30.005-0200');
+    });
+
+    it('should provide a just-the-time format', function() {
+        dateFormat.asString(dateFormat.ABSOLUTETIME_FORMAT, date).should.eql('14:31:30.005');
+    });
+
+    it('should provide a custom format', function() {
+        var customDate = createFixedDate();
+        customDate.getTimezoneOffset = function () {
+            return 120;
+        };
+
+        dateFormat.asString('O.SSS.ss.mm.hh.dd.MM.yy', customDate).should.eql('-0200.005.30.31.14.11.01.10');
+    });
+});

+ 220 - 0
date-format/test/parse-test.js

@@ -0,0 +1,220 @@
+"use strict";
+
+require("should");
+var dateFormat = require("../lib");
+
+describe("dateFormat.parse", function() {
+  it("should require a pattern", function() {
+    (function() {
+      dateFormat.parse();
+    }.should.throw(/pattern must be supplied/));
+    (function() {
+      dateFormat.parse(null);
+    }.should.throw(/pattern must be supplied/));
+    (function() {
+      dateFormat.parse("");
+    }.should.throw(/pattern must be supplied/));
+  });
+
+  describe("with a pattern that has no replacements", function() {
+    it("should return a new date when the string matches", function() {
+      dateFormat.parse("cheese", "cheese").should.be.a.Date();
+    });
+
+    it("should throw if the string does not match", function() {
+      (function() {
+        dateFormat.parse("cheese", "biscuits");
+      }.should.throw(/String 'biscuits' could not be parsed as 'cheese'/));
+    });
+  });
+
+  describe("with a full pattern", function() {
+    var pattern = "yyyy-MM-dd hh:mm:ss.SSSO";
+
+    it("should return the correct date if the string matches", function() {
+      var testDate = new Date();
+      testDate.setUTCFullYear(2018);
+      testDate.setUTCMonth(8);
+      testDate.setUTCDate(13);
+      testDate.setUTCHours(18);
+      testDate.setUTCMinutes(10);
+      testDate.setUTCSeconds(12);
+      testDate.setUTCMilliseconds(392);
+
+      dateFormat
+        .parse(pattern, "2018-09-14 04:10:12.392+1000")
+        .getTime()
+        .should.eql(testDate.getTime())
+        ;
+    });
+
+    it("should throw if the string does not match", function() {
+      (function() {
+        dateFormat.parse(pattern, "biscuits");
+      }.should.throw(
+        /String 'biscuits' could not be parsed as 'yyyy-MM-dd hh:mm:ss.SSSO'/
+      ));
+    });
+  });
+
+  describe("with a partial pattern", function() {
+    var testDate = new Date();
+    dateFormat.now = function() {
+      return testDate;
+    };
+
+    /**
+     * If there's no timezone in the format, then we verify against the local date
+     */
+    function verifyLocalDate(actual, expected) {
+      actual.getFullYear().should.eql(expected.year || testDate.getFullYear());
+      actual.getMonth().should.eql(expected.month || testDate.getMonth());
+      actual.getDate().should.eql(expected.day || testDate.getDate());
+      actual.getHours().should.eql(expected.hours || testDate.getHours());
+      actual.getMinutes().should.eql(expected.minutes || testDate.getMinutes());
+      actual.getSeconds().should.eql(expected.seconds || testDate.getSeconds());
+      actual
+        .getMilliseconds()
+        .should.eql(expected.milliseconds || testDate.getMilliseconds());
+    }
+
+    /**
+     * If a timezone is specified, let's verify against the UTC time it is supposed to be
+     */
+    function verifyDate(actual, expected) {
+      actual.getUTCFullYear().should.eql(expected.year || testDate.getUTCFullYear());
+      actual.getUTCMonth().should.eql(expected.month || testDate.getUTCMonth());
+      actual.getUTCDate().should.eql(expected.day || testDate.getUTCDate());
+      actual.getUTCHours().should.eql(expected.hours || testDate.getUTCHours());
+      actual.getUTCMinutes().should.eql(expected.minutes || testDate.getUTCMinutes());
+      actual.getUTCSeconds().should.eql(expected.seconds || testDate.getUTCSeconds());
+      actual
+        .getMilliseconds()
+        .should.eql(expected.milliseconds || testDate.getMilliseconds());
+    }
+
+    it("should return a date with missing values defaulting to current time", function() {
+      var date = dateFormat.parse("yyyy-MM", "2015-09");
+      verifyLocalDate(date, { year: 2015, month: 8 });
+    });
+
+    it("should use a passed in date for missing values", function() {
+      var missingValueDate = new Date(2010, 1, 8, 22, 30, 12, 100);
+      var date = dateFormat.parse("yyyy-MM", "2015-09", missingValueDate);
+      verifyLocalDate(date, {
+        year: 2015,
+        month: 8,
+        day: 8,
+        hours: 22,
+        minutes: 30,
+        seconds: 12,
+        milliseconds: 100
+      });
+    });
+
+    it("should handle variations on the same pattern", function() {
+      var date = dateFormat.parse("MM-yyyy", "09-2015");
+      verifyLocalDate(date, { year: 2015, month: 8 });
+
+      date = dateFormat.parse("yyyy MM", "2015 09");
+      verifyLocalDate(date, { year: 2015, month: 8 });
+
+      date = dateFormat.parse("MM, yyyy.", "09, 2015.");
+      verifyLocalDate(date, { year: 2015, month: 8 });
+    });
+
+    describe("should match all the date parts", function() {
+      it("works with dd", function() {
+        var date = dateFormat.parse("dd", "21");
+        verifyLocalDate(date, { day: 21 });
+      });
+
+      it("works with hh", function() {
+        var date = dateFormat.parse("hh", "12");
+        verifyLocalDate(date, { hours: 12 });
+      });
+
+      it("works with mm", function() {
+        var date = dateFormat.parse("mm", "34");
+        verifyLocalDate(date, { minutes: 34 });
+      });
+
+      it("works with ss", function() {
+        var date = dateFormat.parse("ss", "59");
+        verifyLocalDate(date, { seconds: 59 });
+      });
+
+      it("works with ss.SSS", function() {
+        var date = dateFormat.parse("ss.SSS", "23.452");
+        verifyLocalDate(date, { seconds: 23, milliseconds: 452 });
+      });
+
+      it("works with hh:mm O (+1000)", function() {
+        var date = dateFormat.parse("hh:mm O", "05:23 +1000");
+        verifyDate(date, { hours: 19, minutes: 23 });
+      });
+
+      it("works with hh:mm O (-200)", function() {
+        var date = dateFormat.parse("hh:mm O", "05:23 -200");
+        verifyDate(date, { hours: 7, minutes: 23 });
+      });
+
+      it("works with hh:mm O (+0930)", function() {
+        var date = dateFormat.parse("hh:mm O", "05:23 +0930");
+        verifyDate(date, { hours: 19, minutes: 53 });
+      });
+    });
+  });
+
+  describe("with a date formatted by this library", function() {
+    describe("should format and then parse back to the same date", function() {
+      function testDateInitWithUTC() {
+        var td = new Date();
+        td.setUTCFullYear(2018);
+        td.setUTCMonth(8);
+        td.setUTCDate(13);
+        td.setUTCHours(18);
+        td.setUTCMinutes(10);
+        td.setUTCSeconds(12);
+        td.setUTCMilliseconds(392);
+        return td;
+      }
+
+      it("works with ISO8601_WITH_TZ_OFFSET_FORMAT", function() {
+        // For this test case to work, the date object must be initialized with
+        // UTC timezone
+        var td = testDateInitWithUTC();
+        var d = dateFormat(dateFormat.ISO8601_WITH_TZ_OFFSET_FORMAT, td);
+        dateFormat.parse(dateFormat.ISO8601_WITH_TZ_OFFSET_FORMAT, d)
+          .should.eql(td);
+      });
+
+      it("works with ISO8601_FORMAT", function() {
+        var td = new Date();
+        var d = dateFormat(dateFormat.ISO8601_FORMAT, td);
+        var actual = dateFormat.parse(dateFormat.ISO8601_FORMAT, d);
+        actual.should.eql(td);
+      });
+
+      it("works with DATETIME_FORMAT", function() {
+        var testDate = new Date();
+        dateFormat
+        .parse(
+          dateFormat.DATETIME_FORMAT,
+          dateFormat(dateFormat.DATETIME_FORMAT, testDate)
+        )
+        .should.eql(testDate);
+      });
+
+      it("works with ABSOLUTETIME_FORMAT", function() {
+        var testDate = new Date();
+        dateFormat
+        .parse(
+          dateFormat.ABSOLUTETIME_FORMAT,
+          dateFormat(dateFormat.ABSOLUTETIME_FORMAT, testDate)
+        )
+        .should.eql(testDate);
+      });
+    });
+  });
+});

+ 10 - 9
debug/LICENSE

@@ -1,19 +1,20 @@
 (The MIT License)
 
-Copyright (c) 2014 TJ Holowaychuk <tj@vision-media.ca>
+Copyright (c) 2014-2017 TJ Holowaychuk <tj@vision-media.ca>
+Copyright (c) 2018-2021 Josh Junon
 
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
-and associated documentation files (the 'Software'), to deal in the Software without restriction, 
-including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+and associated documentation files (the 'Software'), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
 and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
 subject to the following conditions:
 
-The above copyright notice and this permission notice shall be included in all copies or substantial 
+The above copyright notice and this permission notice shall be included in all copies or substantial
 portions of the Software.
 
-THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 
-LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
-WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 

+ 229 - 63
debug/README.md

@@ -1,12 +1,11 @@
 # debug
-[![Build Status](https://travis-ci.org/visionmedia/debug.svg?branch=master)](https://travis-ci.org/visionmedia/debug)  [![Coverage Status](https://coveralls.io/repos/github/visionmedia/debug/badge.svg?branch=master)](https://coveralls.io/github/visionmedia/debug?branch=master)  [![Slack](https://visionmedia-community-slackin.now.sh/badge.svg)](https://visionmedia-community-slackin.now.sh/) [![OpenCollective](https://opencollective.com/debug/backers/badge.svg)](#backers) 
+[![Build Status](https://travis-ci.org/debug-js/debug.svg?branch=master)](https://travis-ci.org/debug-js/debug)  [![Coverage Status](https://coveralls.io/repos/github/debug-js/debug/badge.svg?branch=master)](https://coveralls.io/github/debug-js/debug?branch=master)  [![Slack](https://visionmedia-community-slackin.now.sh/badge.svg)](https://visionmedia-community-slackin.now.sh/) [![OpenCollective](https://opencollective.com/debug/backers/badge.svg)](#backers)
 [![OpenCollective](https://opencollective.com/debug/sponsors/badge.svg)](#sponsors)
 
+<img width="647" src="https://user-images.githubusercontent.com/71256/29091486-fa38524c-7c37-11e7-895f-e7ec8e1039b6.png">
 
-
-A tiny node.js debugging utility modelled after node core's debugging technique.
-
-**Discussion around the V3 API is under way [here](https://github.com/visionmedia/debug/issues/370)**
+A tiny JavaScript debugging utility modelled after Node.js core's debugging
+technique. Works in Node.js and web browsers.
 
 ## Installation
 
@@ -18,7 +17,7 @@ $ npm install debug
 
 `debug` exposes a function; simply pass this function the name of your module, and it will return a decorated version of `console.error` for you to pass debug statements to. This will allow you to toggle the debug output for different parts of your module as well as the module as a whole.
 
-Example _app.js_:
+Example [_app.js_](./examples/node/app.js):
 
 ```js
 var debug = require('debug')('http')
@@ -27,7 +26,7 @@ var debug = require('debug')('http')
 
 // fake app
 
-debug('booting %s', name);
+debug('booting %o', name);
 
 http.createServer(function(req, res){
   debug(req.method + ' ' + req.url);
@@ -41,81 +40,148 @@ http.createServer(function(req, res){
 require('./worker');
 ```
 
-Example _worker.js_:
+Example [_worker.js_](./examples/node/worker.js):
 
 ```js
-var debug = require('debug')('worker');
+var a = require('debug')('worker:a')
+  , b = require('debug')('worker:b');
 
-setInterval(function(){
-  debug('doing some work');
-}, 1000);
+function work() {
+  a('doing lots of uninteresting work');
+  setTimeout(work, Math.random() * 1000);
+}
+
+work();
+
+function workb() {
+  b('doing some work');
+  setTimeout(workb, Math.random() * 2000);
+}
+
+workb();
 ```
 
- The __DEBUG__ environment variable is then used to enable these based on space or comma-delimited names. Here are some examples:
+The `DEBUG` environment variable is then used to enable these based on space or
+comma-delimited names.
 
-  ![debug http and worker](http://f.cl.ly/items/18471z1H402O24072r1J/Screenshot.png)
+Here are some examples:
 
-  ![debug worker](http://f.cl.ly/items/1X413v1a3M0d3C2c1E0i/Screenshot.png)
+<img width="647" alt="screen shot 2017-08-08 at 12 53 04 pm" src="https://user-images.githubusercontent.com/71256/29091703-a6302cdc-7c38-11e7-8304-7c0b3bc600cd.png">
+<img width="647" alt="screen shot 2017-08-08 at 12 53 38 pm" src="https://user-images.githubusercontent.com/71256/29091700-a62a6888-7c38-11e7-800b-db911291ca2b.png">
+<img width="647" alt="screen shot 2017-08-08 at 12 53 25 pm" src="https://user-images.githubusercontent.com/71256/29091701-a62ea114-7c38-11e7-826a-2692bedca740.png">
 
-#### Windows note
+#### Windows command prompt notes
 
- On Windows the environment variable is set using the `set` command.
+##### CMD
 
- ```cmd
- set DEBUG=*,-not_this
- ```
+On Windows the environment variable is set using the `set` command.
 
- Note that PowerShell uses different syntax to set environment variables.
+```cmd
+set DEBUG=*,-not_this
+```
+
+Example:
+
+```cmd
+set DEBUG=* & node app.js
+```
+
+##### PowerShell (VS Code default)
 
- ```cmd
- $env:DEBUG = "*,-not_this"
-  ```
+PowerShell uses different syntax to set environment variables.
+
+```cmd
+$env:DEBUG = "*,-not_this"
+```
+
+Example:
+
+```cmd
+$env:DEBUG='app';node app.js
+```
 
 Then, run the program to be debugged as usual.
 
+npm script example:
+```js
+  "windowsDebug": "@powershell -Command $env:DEBUG='*';node app.js",
+```
+
+## Namespace Colors
+
+Every debug instance has a color generated for it based on its namespace name.
+This helps when visually parsing the debug output to identify which debug instance
+a debug line belongs to.
+
+#### Node.js
+
+In Node.js, colors are enabled when stderr is a TTY. You also _should_ install
+the [`supports-color`](https://npmjs.org/supports-color) module alongside debug,
+otherwise debug will only use a small handful of basic colors.
+
+<img width="521" src="https://user-images.githubusercontent.com/71256/29092181-47f6a9e6-7c3a-11e7-9a14-1928d8a711cd.png">
+
+#### Web Browser
+
+Colors are also enabled on "Web Inspectors" that understand the `%c` formatting
+option. These are WebKit web inspectors, Firefox ([since version
+31](https://hacks.mozilla.org/2014/05/editable-box-model-multiple-selection-sublime-text-keys-much-more-firefox-developer-tools-episode-31/))
+and the Firebug plugin for Firefox (any version).
+
+<img width="524" src="https://user-images.githubusercontent.com/71256/29092033-b65f9f2e-7c39-11e7-8e32-f6f0d8e865c1.png">
+
+
 ## Millisecond diff
 
-  When actively developing an application it can be useful to see when the time spent between one `debug()` call and the next. Suppose for example you invoke `debug()` before requesting a resource, and after as well, the "+NNNms" will show you how much time was spent between calls.
+When actively developing an application it can be useful to see when the time spent between one `debug()` call and the next. Suppose for example you invoke `debug()` before requesting a resource, and after as well, the "+NNNms" will show you how much time was spent between calls.
+
+<img width="647" src="https://user-images.githubusercontent.com/71256/29091486-fa38524c-7c37-11e7-895f-e7ec8e1039b6.png">
 
-  ![](http://f.cl.ly/items/2i3h1d3t121M2Z1A3Q0N/Screenshot.png)
+When stdout is not a TTY, `Date#toISOString()` is used, making it more useful for logging the debug information as shown below:
 
-  When stdout is not a TTY, `Date#toUTCString()` is used, making it more useful for logging the debug information as shown below:
+<img width="647" src="https://user-images.githubusercontent.com/71256/29091956-6bd78372-7c39-11e7-8c55-c948396d6edd.png">
 
-  ![](http://f.cl.ly/items/112H3i0e0o0P0a2Q2r11/Screenshot.png)
 
 ## Conventions
 
-  If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use ":" to separate features. For example "bodyParser" from Connect would then be "connect:bodyParser".
+If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use ":" to separate features. For example "bodyParser" from Connect would then be "connect:bodyParser".  If you append a "*" to the end of your name, it will always be enabled regardless of the setting of the DEBUG environment variable.  You can then use it for normal output as well as debug output.
 
 ## Wildcards
 
-  The `*` character may be used as a wildcard. Suppose for example your library has debuggers named "connect:bodyParser", "connect:compress", "connect:session", instead of listing all three with `DEBUG=connect:bodyParser,connect:compress,connect:session`, you may simply do `DEBUG=connect:*`, or to run everything using this module simply use `DEBUG=*`.
+The `*` character may be used as a wildcard. Suppose for example your library has
+debuggers named "connect:bodyParser", "connect:compress", "connect:session",
+instead of listing all three with
+`DEBUG=connect:bodyParser,connect:compress,connect:session`, you may simply do
+`DEBUG=connect:*`, or to run everything using this module simply use `DEBUG=*`.
 
-  You can also exclude specific debuggers by prefixing them with a "-" character.  For example, `DEBUG=*,-connect:*` would include all debuggers except those starting with "connect:".
+You can also exclude specific debuggers by prefixing them with a "-" character.
+For example, `DEBUG=*,-connect:*` would include all debuggers except those
+starting with "connect:".
 
 ## Environment Variables
 
-  When running through Node.js, you can set a few environment variables that will
-  change the behavior of the debug logging:
+When running through Node.js, you can set a few environment variables that will
+change the behavior of the debug logging:
 
 | Name      | Purpose                                         |
 |-----------|-------------------------------------------------|
 | `DEBUG`   | Enables/disables specific debugging namespaces. |
+| `DEBUG_HIDE_DATE` | Hide date from debug output (non-TTY).  |
 | `DEBUG_COLORS`| Whether or not to use colors in the debug output. |
-| `DEBUG_DEPTH` | Object inspection depth. |
+| `DEBUG_DEPTH` | Object inspection depth.                    |
 | `DEBUG_SHOW_HIDDEN` | Shows hidden properties on inspected objects. |
 
 
-  __Note:__ The environment variables beginning with `DEBUG_` end up being
-  converted into an Options object that gets used with `%o`/`%O` formatters.
-  See the Node.js documentation for
-  [`util.inspect()`](https://nodejs.org/api/util.html#util_util_inspect_object_options)
-  for the complete list.
+__Note:__ The environment variables beginning with `DEBUG_` end up being
+converted into an Options object that gets used with `%o`/`%O` formatters.
+See the Node.js documentation for
+[`util.inspect()`](https://nodejs.org/api/util.html#util_util_inspect_object_options)
+for the complete list.
 
 ## Formatters
 
-
-  Debug uses [printf-style](https://wikipedia.org/wiki/Printf_format_string) formatting. Below are the officially supported formatters:
+Debug uses [printf-style](https://wikipedia.org/wiki/Printf_format_string) formatting.
+Below are the officially supported formatters:
 
 | Formatter | Representation |
 |-----------|----------------|
@@ -126,9 +192,12 @@ Then, run the program to be debugged as usual.
 | `%j`      | JSON. Replaced with the string '[Circular]' if the argument contains circular references. |
 | `%%`      | Single percent sign ('%'). This does not consume an argument. |
 
+
 ### Custom formatters
 
-  You can add custom formatters by extending the `debug.formatters` object. For example, if you wanted to add support for rendering a Buffer as hex with `%h`, you could do something like:
+You can add custom formatters by extending the `debug.formatters` object.
+For example, if you wanted to add support for rendering a Buffer as hex with
+`%h`, you could do something like:
 
 ```js
 const createDebug = require('debug')
@@ -142,14 +211,16 @@ debug('this is hex: %h', new Buffer('hello world'))
 //   foo this is hex: 68656c6c6f20776f726c6421 +0ms
 ```
 
-## Browser support
-  You can build a browser-ready script using [browserify](https://github.com/substack/node-browserify),
-  or just use the [browserify-as-a-service](https://wzrd.in/) [build](https://wzrd.in/standalone/debug@latest),
-  if you don't want to build it yourself.
 
-  Debug's enable state is currently persisted by `localStorage`.
-  Consider the situation shown below where you have `worker:a` and `worker:b`,
-  and wish to debug both. You can enable this using `localStorage.debug`:
+## Browser Support
+
+You can build a browser-ready script using [browserify](https://github.com/substack/node-browserify),
+or just use the [browserify-as-a-service](https://wzrd.in/) [build](https://wzrd.in/standalone/debug@latest),
+if you don't want to build it yourself.
+
+Debug's enable state is currently persisted by `localStorage`.
+Consider the situation shown below where you have `worker:a` and `worker:b`,
+and wish to debug both. You can enable this using `localStorage.debug`:
 
 ```js
 localStorage.debug = 'worker:*'
@@ -170,23 +241,12 @@ setInterval(function(){
 }, 1200);
 ```
 
-#### Web Inspector Colors
-
-  Colors are also enabled on "Web Inspectors" that understand the `%c` formatting
-  option. These are WebKit web inspectors, Firefox ([since version
-  31](https://hacks.mozilla.org/2014/05/editable-box-model-multiple-selection-sublime-text-keys-much-more-firefox-developer-tools-episode-31/))
-  and the Firebug plugin for Firefox (any version).
-
-  Colored output looks something like:
-
-  ![](https://cloud.githubusercontent.com/assets/71256/3139768/b98c5fd8-e8ef-11e3-862a-f7253b6f47c6.png)
-
 
 ## Output streams
 
   By default `debug` will log to stderr, however this can be configured per-namespace by overriding the `log` method:
 
-Example _stdout.js_:
+Example [_stdout.js_](./examples/node/stdout.js):
 
 ```js
 var debug = require('debug');
@@ -208,13 +268,118 @@ error('now goes to stdout via console.info');
 log('still goes to stdout, but via console.info now');
 ```
 
+## Extend
+You can simply extend debugger 
+```js
+const log = require('debug')('auth');
+
+//creates new debug instance with extended namespace
+const logSign = log.extend('sign');
+const logLogin = log.extend('login');
+
+log('hello'); // auth hello
+logSign('hello'); //auth:sign hello
+logLogin('hello'); //auth:login hello
+```
+
+## Set dynamically
+
+You can also enable debug dynamically by calling the `enable()` method :
+
+```js
+let debug = require('debug');
+
+console.log(1, debug.enabled('test'));
+
+debug.enable('test');
+console.log(2, debug.enabled('test'));
+
+debug.disable();
+console.log(3, debug.enabled('test'));
+
+```
+
+print :   
+```
+1 false
+2 true
+3 false
+```
+
+Usage :  
+`enable(namespaces)`  
+`namespaces` can include modes separated by a colon and wildcards.
+   
+Note that calling `enable()` completely overrides previously set DEBUG variable : 
+
+```
+$ DEBUG=foo node -e 'var dbg = require("debug"); dbg.enable("bar"); console.log(dbg.enabled("foo"))'
+=> false
+```
+
+`disable()`
+
+Will disable all namespaces. The functions returns the namespaces currently
+enabled (and skipped). This can be useful if you want to disable debugging
+temporarily without knowing what was enabled to begin with.
+
+For example:
+
+```js
+let debug = require('debug');
+debug.enable('foo:*,-foo:bar');
+let namespaces = debug.disable();
+debug.enable(namespaces);
+```
+
+Note: There is no guarantee that the string will be identical to the initial
+enable string, but semantically they will be identical.
+
+## Checking whether a debug target is enabled
+
+After you've created a debug instance, you can determine whether or not it is
+enabled by checking the `enabled` property:
+
+```javascript
+const debug = require('debug')('http');
+
+if (debug.enabled) {
+  // do stuff...
+}
+```
+
+You can also manually toggle this property to force the debug instance to be
+enabled or disabled.
+
+## Usage in child processes
+
+Due to the way `debug` detects if the output is a TTY or not, colors are not shown in child processes when `stderr` is piped. A solution is to pass the `DEBUG_COLORS=1` environment variable to the child process.  
+For example:
+
+```javascript
+worker = fork(WORKER_WRAP_PATH, [workerPath], {
+  stdio: [
+    /* stdin: */ 0,
+    /* stdout: */ 'pipe',
+    /* stderr: */ 'pipe',
+    'ipc',
+  ],
+  env: Object.assign({}, process.env, {
+    DEBUG_COLORS: 1 // without this settings, colors won't be shown
+  }),
+});
+
+worker.stderr.pipe(process.stderr, { end: false });
+```
+
 
 ## Authors
 
  - TJ Holowaychuk
  - Nathan Rajlich
  - Andrew Rhyne
- 
+ - Josh Junon
+
 ## Backers
 
 Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/debug#backer)]
@@ -290,7 +455,8 @@ Become a sponsor and get your logo on our README on Github with a link to your s
 
 (The MIT License)
 
-Copyright (c) 2014-2016 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
+Copyright (c) 2014-2017 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
+Copyright (c) 2018-2021 Josh Junon
 
 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the

+ 53 - 42
debug/package.json

@@ -1,46 +1,42 @@
 {
-  "_from": "debug@2.6.9",
-  "_id": "debug@2.6.9",
+  "_from": "debug@^4.1.1",
+  "_id": "debug@4.3.3",
   "_inBundle": false,
-  "_integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
+  "_integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
   "_location": "/debug",
   "_phantomChildren": {},
   "_requested": {
-    "type": "version",
+    "type": "range",
     "registry": true,
-    "raw": "debug@2.6.9",
+    "raw": "debug@^4.1.1",
     "name": "debug",
     "escapedName": "debug",
-    "rawSpec": "2.6.9",
+    "rawSpec": "^4.1.1",
     "saveSpec": null,
-    "fetchSpec": "2.6.9"
+    "fetchSpec": "^4.1.1"
   },
   "_requiredBy": [
-    "/body-parser",
-    "/express",
-    "/finalhandler",
-    "/send"
+    "/log4js",
+    "/streamroller"
   ],
-  "_resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz",
-  "_shasum": "5d128515df134ff327e90a4c93f4e077a536341f",
-  "_spec": "debug@2.6.9",
-  "_where": "E:\\dev\\007\\node_module\\node10\\node_modules\\express",
+  "_resolved": "https://registry.npmmirror.com/debug/download/debug-4.3.3.tgz",
+  "_shasum": "04266e0b70a98d4462e6e288e38259213332b664",
+  "_spec": "debug@^4.1.1",
+  "_where": "D:\\project\\server\\logtest\\node_modules\\log4js",
   "author": {
-    "name": "TJ Holowaychuk",
-    "email": "tj@vision-media.ca"
+    "name": "Josh Junon",
+    "email": "josh.junon@protonmail.com"
   },
   "browser": "./src/browser.js",
   "bugs": {
-    "url": "https://github.com/visionmedia/debug/issues"
+    "url": "https://github.com/debug-js/debug/issues"
   },
   "bundleDependencies": false,
-  "component": {
-    "scripts": {
-      "debug/index.js": "browser.js",
-      "debug/debug.js": "debug.js"
-    }
-  },
   "contributors": [
+    {
+      "name": "TJ Holowaychuk",
+      "email": "tj@vision-media.ca"
+    },
     {
       "name": "Nathan Rajlich",
       "email": "nathan@tootallnate.net",
@@ -52,29 +48,32 @@
     }
   ],
   "dependencies": {
-    "ms": "2.0.0"
+    "ms": "2.1.2"
   },
   "deprecated": false,
-  "description": "small debugging utility",
+  "description": "Lightweight debugging utility for Node.js and the browser",
   "devDependencies": {
-    "browserify": "9.0.3",
-    "chai": "^3.5.0",
-    "concurrently": "^3.1.0",
-    "coveralls": "^2.11.15",
-    "eslint": "^3.12.1",
+    "brfs": "^2.0.1",
+    "browserify": "^16.2.3",
+    "coveralls": "^3.0.2",
     "istanbul": "^0.4.5",
-    "karma": "^1.3.0",
-    "karma-chai": "^0.1.0",
+    "karma": "^3.1.4",
+    "karma-browserify": "^6.0.0",
+    "karma-chrome-launcher": "^2.2.0",
     "karma-mocha": "^1.3.0",
-    "karma-phantomjs-launcher": "^1.0.2",
-    "karma-sinon": "^1.0.5",
-    "mocha": "^3.2.0",
+    "mocha": "^5.2.0",
     "mocha-lcov-reporter": "^1.2.0",
-    "rimraf": "^2.5.4",
-    "sinon": "^1.17.6",
-    "sinon-chai": "^2.8.0"
+    "xo": "^0.23.0"
+  },
+  "engines": {
+    "node": ">=6.0"
   },
-  "homepage": "https://github.com/visionmedia/debug#readme",
+  "files": [
+    "src",
+    "LICENSE",
+    "README.md"
+  ],
+  "homepage": "https://github.com/debug-js/debug#readme",
   "keywords": [
     "debug",
     "log",
@@ -83,9 +82,21 @@
   "license": "MIT",
   "main": "./src/index.js",
   "name": "debug",
+  "peerDependenciesMeta": {
+    "supports-color": {
+      "optional": true
+    }
+  },
   "repository": {
     "type": "git",
-    "url": "git://github.com/visionmedia/debug.git"
+    "url": "git://github.com/debug-js/debug.git"
+  },
+  "scripts": {
+    "lint": "xo",
+    "test": "npm run test:node && npm run test:browser && npm run lint",
+    "test:browser": "karma start --single-run",
+    "test:coverage": "cat ./coverage/lcov.info | coveralls",
+    "test:node": "istanbul cover _mocha -- test.js"
   },
-  "version": "2.6.9"
+  "version": "4.3.3"
 }

+ 194 - 110
debug/src/browser.js

@@ -1,31 +1,106 @@
+/* eslint-env browser */
+
 /**
  * This is the web browser implementation of `debug()`.
- *
- * Expose `debug()` as the module.
  */
 
-exports = module.exports = require('./debug');
-exports.log = log;
 exports.formatArgs = formatArgs;
 exports.save = save;
 exports.load = load;
 exports.useColors = useColors;
-exports.storage = 'undefined' != typeof chrome
-               && 'undefined' != typeof chrome.storage
-                  ? chrome.storage.local
-                  : localstorage();
+exports.storage = localstorage();
+exports.destroy = (() => {
+	let warned = false;
+
+	return () => {
+		if (!warned) {
+			warned = true;
+			console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');
+		}
+	};
+})();
 
 /**
  * Colors.
  */
 
 exports.colors = [
-  'lightseagreen',
-  'forestgreen',
-  'goldenrod',
-  'dodgerblue',
-  'darkorchid',
-  'crimson'
+	'#0000CC',
+	'#0000FF',
+	'#0033CC',
+	'#0033FF',
+	'#0066CC',
+	'#0066FF',
+	'#0099CC',
+	'#0099FF',
+	'#00CC00',
+	'#00CC33',
+	'#00CC66',
+	'#00CC99',
+	'#00CCCC',
+	'#00CCFF',
+	'#3300CC',
+	'#3300FF',
+	'#3333CC',
+	'#3333FF',
+	'#3366CC',
+	'#3366FF',
+	'#3399CC',
+	'#3399FF',
+	'#33CC00',
+	'#33CC33',
+	'#33CC66',
+	'#33CC99',
+	'#33CCCC',
+	'#33CCFF',
+	'#6600CC',
+	'#6600FF',
+	'#6633CC',
+	'#6633FF',
+	'#66CC00',
+	'#66CC33',
+	'#9900CC',
+	'#9900FF',
+	'#9933CC',
+	'#9933FF',
+	'#99CC00',
+	'#99CC33',
+	'#CC0000',
+	'#CC0033',
+	'#CC0066',
+	'#CC0099',
+	'#CC00CC',
+	'#CC00FF',
+	'#CC3300',
+	'#CC3333',
+	'#CC3366',
+	'#CC3399',
+	'#CC33CC',
+	'#CC33FF',
+	'#CC6600',
+	'#CC6633',
+	'#CC9900',
+	'#CC9933',
+	'#CCCC00',
+	'#CCCC33',
+	'#FF0000',
+	'#FF0033',
+	'#FF0066',
+	'#FF0099',
+	'#FF00CC',
+	'#FF00FF',
+	'#FF3300',
+	'#FF3333',
+	'#FF3366',
+	'#FF3399',
+	'#FF33CC',
+	'#FF33FF',
+	'#FF6600',
+	'#FF6633',
+	'#FF9900',
+	'#FF9933',
+	'#FFCC00',
+	'#FFCC33'
 ];
 
 /**
@@ -36,38 +111,31 @@ exports.colors = [
  * TODO: add a `localStorage` variable to explicitly enable/disable colors
  */
 
+// eslint-disable-next-line complexity
 function useColors() {
-  // NB: In an Electron preload script, document will be defined but not fully
-  // initialized. Since we know we're in Chrome, we'll just detect this case
-  // explicitly
-  if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') {
-    return true;
-  }
-
-  // is webkit? http://stackoverflow.com/a/16459606/376773
-  // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
-  return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||
-    // is firebug? http://stackoverflow.com/a/398120/376773
-    (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||
-    // is firefox >= v31?
-    // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
-    (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) ||
-    // double check webkit in userAgent just in case we are in a worker
-    (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/));
-}
+	// NB: In an Electron preload script, document will be defined but not fully
+	// initialized. Since we know we're in Chrome, we'll just detect this case
+	// explicitly
+	if (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) {
+		return true;
+	}
 
-/**
- * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
- */
-
-exports.formatters.j = function(v) {
-  try {
-    return JSON.stringify(v);
-  } catch (err) {
-    return '[UnexpectedJSONParseError]: ' + err.message;
-  }
-};
+	// Internet Explorer and Edge do not support colors.
+	if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) {
+		return false;
+	}
 
+	// Is webkit? http://stackoverflow.com/a/16459606/376773
+	// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
+	return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||
+		// Is firebug? http://stackoverflow.com/a/398120/376773
+		(typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||
+		// Is firefox >= v31?
+		// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
+		(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) ||
+		// Double check webkit in userAgent just in case we are in a worker
+		(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/));
+}
 
 /**
  * Colorize log arguments if enabled.
@@ -76,52 +144,49 @@ exports.formatters.j = function(v) {
  */
 
 function formatArgs(args) {
-  var useColors = this.useColors;
-
-  args[0] = (useColors ? '%c' : '')
-    + this.namespace
-    + (useColors ? ' %c' : ' ')
-    + args[0]
-    + (useColors ? '%c ' : ' ')
-    + '+' + exports.humanize(this.diff);
-
-  if (!useColors) return;
-
-  var c = 'color: ' + this.color;
-  args.splice(1, 0, c, 'color: inherit')
-
-  // the final "%c" is somewhat tricky, because there could be other
-  // arguments passed either before or after the %c, so we need to
-  // figure out the correct index to insert the CSS into
-  var index = 0;
-  var lastC = 0;
-  args[0].replace(/%[a-zA-Z%]/g, function(match) {
-    if ('%%' === match) return;
-    index++;
-    if ('%c' === match) {
-      // we only are interested in the *last* %c
-      // (the user may have provided their own)
-      lastC = index;
-    }
-  });
-
-  args.splice(lastC, 0, c);
+	args[0] = (this.useColors ? '%c' : '') +
+		this.namespace +
+		(this.useColors ? ' %c' : ' ') +
+		args[0] +
+		(this.useColors ? '%c ' : ' ') +
+		'+' + module.exports.humanize(this.diff);
+
+	if (!this.useColors) {
+		return;
+	}
+
+	const c = 'color: ' + this.color;
+	args.splice(1, 0, c, 'color: inherit');
+
+	// The final "%c" is somewhat tricky, because there could be other
+	// arguments passed either before or after the %c, so we need to
+	// figure out the correct index to insert the CSS into
+	let index = 0;
+	let lastC = 0;
+	args[0].replace(/%[a-zA-Z%]/g, match => {
+		if (match === '%%') {
+			return;
+		}
+		index++;
+		if (match === '%c') {
+			// We only are interested in the *last* %c
+			// (the user may have provided their own)
+			lastC = index;
+		}
+	});
+
+	args.splice(lastC, 0, c);
 }
 
 /**
- * Invokes `console.log()` when available.
- * No-op when `console.log` is not a "function".
+ * Invokes `console.debug()` when available.
+ * No-op when `console.debug` is not a "function".
+ * If `console.debug` is not available, falls back
+ * to `console.log`.
  *
  * @api public
  */
-
-function log() {
-  // this hackery is required for IE8/9, where
-  // the `console.log` function doesn't have 'apply'
-  return 'object' === typeof console
-    && console.log
-    && Function.prototype.apply.call(console.log, console, arguments);
-}
+exports.log = console.debug || console.log || (() => {});
 
 /**
  * Save `namespaces`.
@@ -129,15 +194,17 @@ function log() {
  * @param {String} namespaces
  * @api private
  */
-
 function save(namespaces) {
-  try {
-    if (null == namespaces) {
-      exports.storage.removeItem('debug');
-    } else {
-      exports.storage.debug = namespaces;
-    }
-  } catch(e) {}
+	try {
+		if (namespaces) {
+			exports.storage.setItem('debug', namespaces);
+		} else {
+			exports.storage.removeItem('debug');
+		}
+	} catch (error) {
+		// Swallow
+		// XXX (@Qix-) should we be logging these?
+	}
 }
 
 /**
@@ -146,27 +213,23 @@ function save(namespaces) {
  * @return {String} returns the previously persisted debug modes
  * @api private
  */
-
 function load() {
-  var r;
-  try {
-    r = exports.storage.debug;
-  } catch(e) {}
+	let r;
+	try {
+		r = exports.storage.getItem('debug');
+	} catch (error) {
+		// Swallow
+		// XXX (@Qix-) should we be logging these?
+	}
 
-  // If debug isn't set in LS, and we're in Electron, try to load $DEBUG
-  if (!r && typeof process !== 'undefined' && 'env' in process) {
-    r = process.env.DEBUG;
-  }
+	// If debug isn't set in LS, and we're in Electron, try to load $DEBUG
+	if (!r && typeof process !== 'undefined' && 'env' in process) {
+		r = process.env.DEBUG;
+	}
 
-  return r;
+	return r;
 }
 
-/**
- * Enable namespaces listed in `localStorage.debug` initially.
- */
-
-exports.enable(load());
-
 /**
  * Localstorage attempts to return the localstorage.
  *
@@ -179,7 +242,28 @@ exports.enable(load());
  */
 
 function localstorage() {
-  try {
-    return window.localStorage;
-  } catch (e) {}
+	try {
+		// TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context
+		// The Browser also has localStorage in the global context.
+		return localStorage;
+	} catch (error) {
+		// Swallow
+		// XXX (@Qix-) should we be logging these?
+	}
 }
+
+module.exports = require('./common')(exports);
+
+const {formatters} = module.exports;
+
+/**
+ * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
+ */
+
+formatters.j = function (v) {
+	try {
+		return JSON.stringify(v);
+	} catch (error) {
+		return '[UnexpectedJSONParseError]: ' + error.message;
+	}
+};

+ 274 - 0
debug/src/common.js

@@ -0,0 +1,274 @@
+
+/**
+ * This is the common logic for both the Node.js and web browser
+ * implementations of `debug()`.
+ */
+
+function setup(env) {
+	createDebug.debug = createDebug;
+	createDebug.default = createDebug;
+	createDebug.coerce = coerce;
+	createDebug.disable = disable;
+	createDebug.enable = enable;
+	createDebug.enabled = enabled;
+	createDebug.humanize = require('ms');
+	createDebug.destroy = destroy;
+
+	Object.keys(env).forEach(key => {
+		createDebug[key] = env[key];
+	});
+
+	/**
+	* The currently active debug mode names, and names to skip.
+	*/
+
+	createDebug.names = [];
+	createDebug.skips = [];
+
+	/**
+	* Map of special "%n" handling functions, for the debug "format" argument.
+	*
+	* Valid key names are a single, lower or upper-case letter, i.e. "n" and "N".
+	*/
+	createDebug.formatters = {};
+
+	/**
+	* Selects a color for a debug namespace
+	* @param {String} namespace The namespace string for the debug instance to be colored
+	* @return {Number|String} An ANSI color code for the given namespace
+	* @api private
+	*/
+	function selectColor(namespace) {
+		let hash = 0;
+
+		for (let i = 0; i < namespace.length; i++) {
+			hash = ((hash << 5) - hash) + namespace.charCodeAt(i);
+			hash |= 0; // Convert to 32bit integer
+		}
+
+		return createDebug.colors[Math.abs(hash) % createDebug.colors.length];
+	}
+	createDebug.selectColor = selectColor;
+
+	/**
+	* Create a debugger with the given `namespace`.
+	*
+	* @param {String} namespace
+	* @return {Function}
+	* @api public
+	*/
+	function createDebug(namespace) {
+		let prevTime;
+		let enableOverride = null;
+		let namespacesCache;
+		let enabledCache;
+
+		function debug(...args) {
+			// Disabled?
+			if (!debug.enabled) {
+				return;
+			}
+
+			const self = debug;
+
+			// Set `diff` timestamp
+			const curr = Number(new Date());
+			const ms = curr - (prevTime || curr);
+			self.diff = ms;
+			self.prev = prevTime;
+			self.curr = curr;
+			prevTime = curr;
+
+			args[0] = createDebug.coerce(args[0]);
+
+			if (typeof args[0] !== 'string') {
+				// Anything else let's inspect with %O
+				args.unshift('%O');
+			}
+
+			// Apply any `formatters` transformations
+			let index = 0;
+			args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {
+				// If we encounter an escaped % then don't increase the array index
+				if (match === '%%') {
+					return '%';
+				}
+				index++;
+				const formatter = createDebug.formatters[format];
+				if (typeof formatter === 'function') {
+					const val = args[index];
+					match = formatter.call(self, val);
+
+					// Now we need to remove `args[index]` since it's inlined in the `format`
+					args.splice(index, 1);
+					index--;
+				}
+				return match;
+			});
+
+			// Apply env-specific formatting (colors, etc.)
+			createDebug.formatArgs.call(self, args);
+
+			const logFn = self.log || createDebug.log;
+			logFn.apply(self, args);
+		}
+
+		debug.namespace = namespace;
+		debug.useColors = createDebug.useColors();
+		debug.color = createDebug.selectColor(namespace);
+		debug.extend = extend;
+		debug.destroy = createDebug.destroy; // XXX Temporary. Will be removed in the next major release.
+
+		Object.defineProperty(debug, 'enabled', {
+			enumerable: true,
+			configurable: false,
+			get: () => {
+				if (enableOverride !== null) {
+					return enableOverride;
+				}
+				if (namespacesCache !== createDebug.namespaces) {
+					namespacesCache = createDebug.namespaces;
+					enabledCache = createDebug.enabled(namespace);
+				}
+
+				return enabledCache;
+			},
+			set: v => {
+				enableOverride = v;
+			}
+		});
+
+		// Env-specific initialization logic for debug instances
+		if (typeof createDebug.init === 'function') {
+			createDebug.init(debug);
+		}
+
+		return debug;
+	}
+
+	function extend(namespace, delimiter) {
+		const newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace);
+		newDebug.log = this.log;
+		return newDebug;
+	}
+
+	/**
+	* Enables a debug mode by namespaces. This can include modes
+	* separated by a colon and wildcards.
+	*
+	* @param {String} namespaces
+	* @api public
+	*/
+	function enable(namespaces) {
+		createDebug.save(namespaces);
+		createDebug.namespaces = namespaces;
+
+		createDebug.names = [];
+		createDebug.skips = [];
+
+		let i;
+		const split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
+		const len = split.length;
+
+		for (i = 0; i < len; i++) {
+			if (!split[i]) {
+				// ignore empty strings
+				continue;
+			}
+
+			namespaces = split[i].replace(/\*/g, '.*?');
+
+			if (namespaces[0] === '-') {
+				createDebug.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
+			} else {
+				createDebug.names.push(new RegExp('^' + namespaces + '$'));
+			}
+		}
+	}
+
+	/**
+	* Disable debug output.
+	*
+	* @return {String} namespaces
+	* @api public
+	*/
+	function disable() {
+		const namespaces = [
+			...createDebug.names.map(toNamespace),
+			...createDebug.skips.map(toNamespace).map(namespace => '-' + namespace)
+		].join(',');
+		createDebug.enable('');
+		return namespaces;
+	}
+
+	/**
+	* Returns true if the given mode name is enabled, false otherwise.
+	*
+	* @param {String} name
+	* @return {Boolean}
+	* @api public
+	*/
+	function enabled(name) {
+		if (name[name.length - 1] === '*') {
+			return true;
+		}
+
+		let i;
+		let len;
+
+		for (i = 0, len = createDebug.skips.length; i < len; i++) {
+			if (createDebug.skips[i].test(name)) {
+				return false;
+			}
+		}
+
+		for (i = 0, len = createDebug.names.length; i < len; i++) {
+			if (createDebug.names[i].test(name)) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	* Convert regexp to namespace
+	*
+	* @param {RegExp} regxep
+	* @return {String} namespace
+	* @api private
+	*/
+	function toNamespace(regexp) {
+		return regexp.toString()
+			.substring(2, regexp.toString().length - 2)
+			.replace(/\.\*\?$/, '*');
+	}
+
+	/**
+	* Coerce `val`.
+	*
+	* @param {Mixed} val
+	* @return {Mixed}
+	* @api private
+	*/
+	function coerce(val) {
+		if (val instanceof Error) {
+			return val.stack || val.message;
+		}
+		return val;
+	}
+
+	/**
+	* XXX DO NOT USE. This is a temporary stub function.
+	* XXX It WILL be removed in the next major release.
+	*/
+	function destroy() {
+		console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');
+	}
+
+	createDebug.enable(createDebug.load());
+
+	return createDebug;
+}
+
+module.exports = setup;

+ 4 - 4
debug/src/index.js

@@ -1,10 +1,10 @@
 /**
- * Detect Electron renderer process, which is node, but we should
+ * Detect Electron renderer / nwjs process, which is node, but we should
  * treat as a browser.
  */
 
-if (typeof process !== 'undefined' && process.type === 'renderer') {
-  module.exports = require('./browser.js');
+if (typeof process === 'undefined' || process.type === 'renderer' || process.browser === true || process.__nwjs) {
+	module.exports = require('./browser.js');
 } else {
-  module.exports = require('./node.js');
+	module.exports = require('./node.js');
 }

+ 180 - 165
debug/src/node.js

@@ -2,22 +2,23 @@
  * Module dependencies.
  */
 
-var tty = require('tty');
-var util = require('util');
+const tty = require('tty');
+const util = require('util');
 
 /**
  * This is the Node.js implementation of `debug()`.
- *
- * Expose `debug()` as the module.
  */
 
-exports = module.exports = require('./debug');
 exports.init = init;
 exports.log = log;
 exports.formatArgs = formatArgs;
 exports.save = save;
 exports.load = load;
 exports.useColors = useColors;
+exports.destroy = util.deprecate(
+	() => {},
+	'Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.'
+);
 
 /**
  * Colors.
@@ -25,80 +26,138 @@ exports.useColors = useColors;
 
 exports.colors = [6, 2, 3, 4, 5, 1];
 
+try {
+	// Optional dependency (as in, doesn't need to be installed, NOT like optionalDependencies in package.json)
+	// eslint-disable-next-line import/no-extraneous-dependencies
+	const supportsColor = require('supports-color');
+
+	if (supportsColor && (supportsColor.stderr || supportsColor).level >= 2) {
+		exports.colors = [
+			20,
+			21,
+			26,
+			27,
+			32,
+			33,
+			38,
+			39,
+			40,
+			41,
+			42,
+			43,
+			44,
+			45,
+			56,
+			57,
+			62,
+			63,
+			68,
+			69,
+			74,
+			75,
+			76,
+			77,
+			78,
+			79,
+			80,
+			81,
+			92,
+			93,
+			98,
+			99,
+			112,
+			113,
+			128,
+			129,
+			134,
+			135,
+			148,
+			149,
+			160,
+			161,
+			162,
+			163,
+			164,
+			165,
+			166,
+			167,
+			168,
+			169,
+			170,
+			171,
+			172,
+			173,
+			178,
+			179,
+			184,
+			185,
+			196,
+			197,
+			198,
+			199,
+			200,
+			201,
+			202,
+			203,
+			204,
+			205,
+			206,
+			207,
+			208,
+			209,
+			214,
+			215,
+			220,
+			221
+		];
+	}
+} catch (error) {
+	// Swallow - we only care if `supports-color` is available; it doesn't have to be.
+}
+
 /**
  * Build up the default `inspectOpts` object from the environment variables.
  *
  *   $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js
  */
 
-exports.inspectOpts = Object.keys(process.env).filter(function (key) {
-  return /^debug_/i.test(key);
-}).reduce(function (obj, key) {
-  // camel-case
-  var prop = key
-    .substring(6)
-    .toLowerCase()
-    .replace(/_([a-z])/g, function (_, k) { return k.toUpperCase() });
-
-  // coerce string value into JS value
-  var val = process.env[key];
-  if (/^(yes|on|true|enabled)$/i.test(val)) val = true;
-  else if (/^(no|off|false|disabled)$/i.test(val)) val = false;
-  else if (val === 'null') val = null;
-  else val = Number(val);
-
-  obj[prop] = val;
-  return obj;
+exports.inspectOpts = Object.keys(process.env).filter(key => {
+	return /^debug_/i.test(key);
+}).reduce((obj, key) => {
+	// Camel-case
+	const prop = key
+		.substring(6)
+		.toLowerCase()
+		.replace(/_([a-z])/g, (_, k) => {
+			return k.toUpperCase();
+		});
+
+	// Coerce string value into JS value
+	let val = process.env[key];
+	if (/^(yes|on|true|enabled)$/i.test(val)) {
+		val = true;
+	} else if (/^(no|off|false|disabled)$/i.test(val)) {
+		val = false;
+	} else if (val === 'null') {
+		val = null;
+	} else {
+		val = Number(val);
+	}
+
+	obj[prop] = val;
+	return obj;
 }, {});
 
-/**
- * The file descriptor to write the `debug()` calls to.
- * Set the `DEBUG_FD` env variable to override with another value. i.e.:
- *
- *   $ DEBUG_FD=3 node script.js 3>debug.log
- */
-
-var fd = parseInt(process.env.DEBUG_FD, 10) || 2;
-
-if (1 !== fd && 2 !== fd) {
-  util.deprecate(function(){}, 'except for stderr(2) and stdout(1), any other usage of DEBUG_FD is deprecated. Override debug.log if you want to use a different log function (https://git.io/debug_fd)')()
-}
-
-var stream = 1 === fd ? process.stdout :
-             2 === fd ? process.stderr :
-             createWritableStdioStream(fd);
-
 /**
  * Is stdout a TTY? Colored output is enabled when `true`.
  */
 
 function useColors() {
-  return 'colors' in exports.inspectOpts
-    ? Boolean(exports.inspectOpts.colors)
-    : tty.isatty(fd);
+	return 'colors' in exports.inspectOpts ?
+		Boolean(exports.inspectOpts.colors) :
+		tty.isatty(process.stderr.fd);
 }
 
-/**
- * Map %o to `util.inspect()`, all on a single line.
- */
-
-exports.formatters.o = function(v) {
-  this.inspectOpts.colors = this.useColors;
-  return util.inspect(v, this.inspectOpts)
-    .split('\n').map(function(str) {
-      return str.trim()
-    }).join(' ');
-};
-
-/**
- * Map %o to `util.inspect()`, allowing multiple lines if needed.
- */
-
-exports.formatters.O = function(v) {
-  this.inspectOpts.colors = this.useColors;
-  return util.inspect(v, this.inspectOpts);
-};
-
 /**
  * Adds ANSI color escape codes if enabled.
  *
@@ -106,27 +165,33 @@ exports.formatters.O = function(v) {
  */
 
 function formatArgs(args) {
-  var name = this.namespace;
-  var useColors = this.useColors;
-
-  if (useColors) {
-    var c = this.color;
-    var prefix = '  \u001b[3' + c + ';1m' + name + ' ' + '\u001b[0m';
-
-    args[0] = prefix + args[0].split('\n').join('\n' + prefix);
-    args.push('\u001b[3' + c + 'm+' + exports.humanize(this.diff) + '\u001b[0m');
-  } else {
-    args[0] = new Date().toUTCString()
-      + ' ' + name + ' ' + args[0];
-  }
+	const {namespace: name, useColors} = this;
+
+	if (useColors) {
+		const c = this.color;
+		const colorCode = '\u001B[3' + (c < 8 ? c : '8;5;' + c);
+		const prefix = `  ${colorCode};1m${name} \u001B[0m`;
+
+		args[0] = prefix + args[0].split('\n').join('\n' + prefix);
+		args.push(colorCode + 'm+' + module.exports.humanize(this.diff) + '\u001B[0m');
+	} else {
+		args[0] = getDate() + name + ' ' + args[0];
+	}
+}
+
+function getDate() {
+	if (exports.inspectOpts.hideDate) {
+		return '';
+	}
+	return new Date().toISOString() + ' ';
 }
 
 /**
- * Invokes `util.format()` with the specified arguments and writes to `stream`.
+ * Invokes `util.format()` with the specified arguments and writes to stderr.
  */
 
-function log() {
-  return stream.write(util.format.apply(util, arguments) + '\n');
+function log(...args) {
+	return process.stderr.write(util.format(...args) + '\n');
 }
 
 /**
@@ -135,15 +200,14 @@ function log() {
  * @param {String} namespaces
  * @api private
  */
-
 function save(namespaces) {
-  if (null == namespaces) {
-    // If you set a process.env field to null or undefined, it gets cast to the
-    // string 'null' or 'undefined'. Just delete instead.
-    delete process.env.DEBUG;
-  } else {
-    process.env.DEBUG = namespaces;
-  }
+	if (namespaces) {
+		process.env.DEBUG = namespaces;
+	} else {
+		// If you set a process.env field to null or undefined, it gets cast to the
+		// string 'null' or 'undefined'. Just delete instead.
+		delete process.env.DEBUG;
+	}
 }
 
 /**
@@ -154,75 +218,7 @@ function save(namespaces) {
  */
 
 function load() {
-  return process.env.DEBUG;
-}
-
-/**
- * Copied from `node/src/node.js`.
- *
- * XXX: It's lame that node doesn't expose this API out-of-the-box. It also
- * relies on the undocumented `tty_wrap.guessHandleType()` which is also lame.
- */
-
-function createWritableStdioStream (fd) {
-  var stream;
-  var tty_wrap = process.binding('tty_wrap');
-
-  // Note stream._type is used for test-module-load-list.js
-
-  switch (tty_wrap.guessHandleType(fd)) {
-    case 'TTY':
-      stream = new tty.WriteStream(fd);
-      stream._type = 'tty';
-
-      // Hack to have stream not keep the event loop alive.
-      // See https://github.com/joyent/node/issues/1726
-      if (stream._handle && stream._handle.unref) {
-        stream._handle.unref();
-      }
-      break;
-
-    case 'FILE':
-      var fs = require('fs');
-      stream = new fs.SyncWriteStream(fd, { autoClose: false });
-      stream._type = 'fs';
-      break;
-
-    case 'PIPE':
-    case 'TCP':
-      var net = require('net');
-      stream = new net.Socket({
-        fd: fd,
-        readable: false,
-        writable: true
-      });
-
-      // FIXME Should probably have an option in net.Socket to create a
-      // stream from an existing fd which is writable only. But for now
-      // we'll just add this hack and set the `readable` member to false.
-      // Test: ./node test/fixtures/echo.js < /etc/passwd
-      stream.readable = false;
-      stream.read = null;
-      stream._type = 'pipe';
-
-      // FIXME Hack to have stream not keep the event loop alive.
-      // See https://github.com/joyent/node/issues/1726
-      if (stream._handle && stream._handle.unref) {
-        stream._handle.unref();
-      }
-      break;
-
-    default:
-      // Probably an error on in uv_guess_handle()
-      throw new Error('Implement me. Unknown stream file type!');
-  }
-
-  // For supporting legacy API we put the FD here.
-  stream.fd = fd;
-
-  stream._isStdio = true;
-
-  return stream;
+	return process.env.DEBUG;
 }
 
 /**
@@ -232,17 +228,36 @@ function createWritableStdioStream (fd) {
  * differently for a particular `debug` instance.
  */
 
-function init (debug) {
-  debug.inspectOpts = {};
+function init(debug) {
+	debug.inspectOpts = {};
 
-  var keys = Object.keys(exports.inspectOpts);
-  for (var i = 0; i < keys.length; i++) {
-    debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]];
-  }
+	const keys = Object.keys(exports.inspectOpts);
+	for (let i = 0; i < keys.length; i++) {
+		debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]];
+	}
 }
 
+module.exports = require('./common')(exports);
+
+const {formatters} = module.exports;
+
+/**
+ * Map %o to `util.inspect()`, all on a single line.
+ */
+
+formatters.o = function (v) {
+	this.inspectOpts.colors = this.useColors;
+	return util.inspect(v, this.inspectOpts)
+		.split('\n')
+		.map(str => str.trim())
+		.join(' ');
+};
+
 /**
- * Enable namespaces listed in `process.env.DEBUG` initially.
+ * Map %O to `util.inspect()`, allowing multiple lines if needed.
  */
 
-exports.enable(load());
+formatters.O = function (v) {
+	this.inspectOpts.colors = this.useColors;
+	return util.inspect(v, this.inspectOpts);
+};

+ 50 - 0
engine.io-client/CHANGELOG.md

@@ -0,0 +1,50 @@
+## [3.5.2](https://github.com/socketio/engine.io-client/compare/3.5.1...3.5.2) (2021-05-05)
+
+This release only contains a bump of `xmlhttprequest-ssl`, in order to fix the following vulnerability: https://www.npmjs.com/advisories/1665.
+
+Please note that `engine.io-client` was not directly impacted by this vulnerability, since we are always using `async: true`.
+
+
+## [3.5.1](https://github.com/socketio/engine.io-client/compare/3.5.0...3.5.1) (2021-03-02)
+
+
+### Bug Fixes
+
+* replace default nulls in SSL options with undefineds ([d0c551c](https://github.com/socketio/engine.io-client/commit/d0c551cca1e37301e8b28843c8f6e7ad5cf561d3))
+
+
+# [3.5.0](https://github.com/socketio/engine.io-client/compare/3.4.4...3.5.0) (2020-12-30)
+
+
+### Bug Fixes
+
+* check the type of the initial packet ([8750356](https://github.com/socketio/engine.io-client/commit/8750356dba5409ba0e1d3a27da6d214118702b3e))
+
+
+
+## [3.4.4](https://github.com/socketio/engine.io-client/compare/3.4.3...3.4.4) (2020-09-30)
+
+
+
+## [3.4.3](https://github.com/socketio/engine.io-client/compare/3.4.2...3.4.3) (2020-06-04)
+
+
+### Bug Fixes
+
+* **react-native:** restrict the list of options for the WebSocket object ([e5bc106](https://github.com/socketio/engine.io-client/commit/e5bc1063cc90a7b6262146c7b5338ffff1ff9e5b))
+
+
+
+## [3.4.2](https://github.com/socketio/engine.io-client/compare/3.4.1...3.4.2) (2020-05-13)
+
+
+
+## [3.4.1](https://github.com/socketio/engine.io-client/compare/3.4.0...3.4.1) (2020-04-17)
+
+
+### Bug Fixes
+
+* use globalThis polyfill instead of self/global ([357f01d](https://github.com/socketio/engine.io-client/commit/357f01d90448d8565b650377bc7cabb351d991bd))
+
+
+

+ 9 - 0
engine.io-client/lib/globalThis.browser.js

@@ -0,0 +1,9 @@
+module.exports = (function () {
+  if (typeof self !== 'undefined') {
+    return self;
+  } else if (typeof window !== 'undefined') {
+    return window;
+  } else {
+    return Function('return this')(); // eslint-disable-line no-new-func
+  }
+})();

+ 1 - 0
engine.io-client/lib/globalThis.js

@@ -0,0 +1 @@
+module.exports = global;

+ 1 - 0
engine.io-parser/CHANGELOG.md

@@ -0,0 +1 @@
+## [2.2.1](https://github.com/socketio/engine.io-parser/compare/2.2.0...2.2.1) (2020-09-30)

+ 29 - 0
engine.io/CHANGELOG.md

@@ -0,0 +1,29 @@
+# [3.5.0](https://github.com/socketio/engine.io/compare/3.4.2...3.5.0) (2020-12-30)
+
+
+### Features
+
+* add support for all cookie options ([19cc582](https://github.com/socketio/engine.io/commit/19cc58264a06dca47ed401fbaca32dcdb80a903b)), closes [/github.com/jshttp/cookie#options-1](https://github.com//github.com/jshttp/cookie/issues/options-1)
+* disable perMessageDeflate by default ([5ad2736](https://github.com/socketio/engine.io/commit/5ad273601eb66c7b318542f87026837bf9dddd21))
+
+
+
+## [3.4.2](https://github.com/socketio/engine.io/compare/3.4.1...3.4.2) (2020-06-04)
+
+
+### Bug Fixes
+
+* remove explicit require of uws ([85e544a](https://github.com/socketio/engine.io/commit/85e544afd95a5890761a613263a5eba0c9a18a93))
+
+
+
+## [3.4.1](https://github.com/socketio/engine.io/compare/3.4.0...3.4.1) (2020-04-17)
+
+
+### Bug Fixes
+
+* ignore errors when forcefully closing the socket ([da851ec](https://github.com/socketio/engine.io/commit/da851ec4ec89d96df2ee5c711f328b5d795423e9))
+* use SameSite=Strict by default ([001ca62](https://github.com/socketio/engine.io/commit/001ca62cc4a8f511f3b2fbd9e4493ad274a6a0e5))
+
+
+

+ 912 - 0
engine.io/node_modules/debug/dist/debug.js

@@ -0,0 +1,912 @@
+"use strict";
+
+function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }
+
+function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); }
+
+function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); }
+
+function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }
+
+function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
+
+(function (f) {
+  if ((typeof exports === "undefined" ? "undefined" : _typeof(exports)) === "object" && typeof module !== "undefined") {
+    module.exports = f();
+  } else if (typeof define === "function" && define.amd) {
+    define([], f);
+  } else {
+    var g;
+
+    if (typeof window !== "undefined") {
+      g = window;
+    } else if (typeof global !== "undefined") {
+      g = global;
+    } else if (typeof self !== "undefined") {
+      g = self;
+    } else {
+      g = this;
+    }
+
+    g.debug = f();
+  }
+})(function () {
+  var define, module, exports;
+  return function () {
+    function r(e, n, t) {
+      function o(i, f) {
+        if (!n[i]) {
+          if (!e[i]) {
+            var c = "function" == typeof require && require;
+            if (!f && c) return c(i, !0);
+            if (u) return u(i, !0);
+            var a = new Error("Cannot find module '" + i + "'");
+            throw a.code = "MODULE_NOT_FOUND", a;
+          }
+
+          var p = n[i] = {
+            exports: {}
+          };
+          e[i][0].call(p.exports, function (r) {
+            var n = e[i][1][r];
+            return o(n || r);
+          }, p, p.exports, r, e, n, t);
+        }
+
+        return n[i].exports;
+      }
+
+      for (var u = "function" == typeof require && require, i = 0; i < t.length; i++) {
+        o(t[i]);
+      }
+
+      return o;
+    }
+
+    return r;
+  }()({
+    1: [function (require, module, exports) {
+      /**
+       * Helpers.
+       */
+      var s = 1000;
+      var m = s * 60;
+      var h = m * 60;
+      var d = h * 24;
+      var w = d * 7;
+      var y = d * 365.25;
+      /**
+       * Parse or format the given `val`.
+       *
+       * Options:
+       *
+       *  - `long` verbose formatting [false]
+       *
+       * @param {String|Number} val
+       * @param {Object} [options]
+       * @throws {Error} throw an error if val is not a non-empty string or a number
+       * @return {String|Number}
+       * @api public
+       */
+
+      module.exports = function (val, options) {
+        options = options || {};
+
+        var type = _typeof(val);
+
+        if (type === 'string' && val.length > 0) {
+          return parse(val);
+        } else if (type === 'number' && isNaN(val) === false) {
+          return options.long ? fmtLong(val) : fmtShort(val);
+        }
+
+        throw new Error('val is not a non-empty string or a valid number. val=' + JSON.stringify(val));
+      };
+      /**
+       * Parse the given `str` and return milliseconds.
+       *
+       * @param {String} str
+       * @return {Number}
+       * @api private
+       */
+
+
+      function parse(str) {
+        str = String(str);
+
+        if (str.length > 100) {
+          return;
+        }
+
+        var match = /^((?:\d+)?\-?\d?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(str);
+
+        if (!match) {
+          return;
+        }
+
+        var n = parseFloat(match[1]);
+        var type = (match[2] || 'ms').toLowerCase();
+
+        switch (type) {
+          case 'years':
+          case 'year':
+          case 'yrs':
+          case 'yr':
+          case 'y':
+            return n * y;
+
+          case 'weeks':
+          case 'week':
+          case 'w':
+            return n * w;
+
+          case 'days':
+          case 'day':
+          case 'd':
+            return n * d;
+
+          case 'hours':
+          case 'hour':
+          case 'hrs':
+          case 'hr':
+          case 'h':
+            return n * h;
+
+          case 'minutes':
+          case 'minute':
+          case 'mins':
+          case 'min':
+          case 'm':
+            return n * m;
+
+          case 'seconds':
+          case 'second':
+          case 'secs':
+          case 'sec':
+          case 's':
+            return n * s;
+
+          case 'milliseconds':
+          case 'millisecond':
+          case 'msecs':
+          case 'msec':
+          case 'ms':
+            return n;
+
+          default:
+            return undefined;
+        }
+      }
+      /**
+       * Short format for `ms`.
+       *
+       * @param {Number} ms
+       * @return {String}
+       * @api private
+       */
+
+
+      function fmtShort(ms) {
+        var msAbs = Math.abs(ms);
+
+        if (msAbs >= d) {
+          return Math.round(ms / d) + 'd';
+        }
+
+        if (msAbs >= h) {
+          return Math.round(ms / h) + 'h';
+        }
+
+        if (msAbs >= m) {
+          return Math.round(ms / m) + 'm';
+        }
+
+        if (msAbs >= s) {
+          return Math.round(ms / s) + 's';
+        }
+
+        return ms + 'ms';
+      }
+      /**
+       * Long format for `ms`.
+       *
+       * @param {Number} ms
+       * @return {String}
+       * @api private
+       */
+
+
+      function fmtLong(ms) {
+        var msAbs = Math.abs(ms);
+
+        if (msAbs >= d) {
+          return plural(ms, msAbs, d, 'day');
+        }
+
+        if (msAbs >= h) {
+          return plural(ms, msAbs, h, 'hour');
+        }
+
+        if (msAbs >= m) {
+          return plural(ms, msAbs, m, 'minute');
+        }
+
+        if (msAbs >= s) {
+          return plural(ms, msAbs, s, 'second');
+        }
+
+        return ms + ' ms';
+      }
+      /**
+       * Pluralization helper.
+       */
+
+
+      function plural(ms, msAbs, n, name) {
+        var isPlural = msAbs >= n * 1.5;
+        return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');
+      }
+    }, {}],
+    2: [function (require, module, exports) {
+      // shim for using process in browser
+      var process = module.exports = {}; // cached from whatever global is present so that test runners that stub it
+      // don't break things.  But we need to wrap it in a try catch in case it is
+      // wrapped in strict mode code which doesn't define any globals.  It's inside a
+      // function because try/catches deoptimize in certain engines.
+
+      var cachedSetTimeout;
+      var cachedClearTimeout;
+
+      function defaultSetTimout() {
+        throw new Error('setTimeout has not been defined');
+      }
+
+      function defaultClearTimeout() {
+        throw new Error('clearTimeout has not been defined');
+      }
+
+      (function () {
+        try {
+          if (typeof setTimeout === 'function') {
+            cachedSetTimeout = setTimeout;
+          } else {
+            cachedSetTimeout = defaultSetTimout;
+          }
+        } catch (e) {
+          cachedSetTimeout = defaultSetTimout;
+        }
+
+        try {
+          if (typeof clearTimeout === 'function') {
+            cachedClearTimeout = clearTimeout;
+          } else {
+            cachedClearTimeout = defaultClearTimeout;
+          }
+        } catch (e) {
+          cachedClearTimeout = defaultClearTimeout;
+        }
+      })();
+
+      function runTimeout(fun) {
+        if (cachedSetTimeout === setTimeout) {
+          //normal enviroments in sane situations
+          return setTimeout(fun, 0);
+        } // if setTimeout wasn't available but was latter defined
+
+
+        if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
+          cachedSetTimeout = setTimeout;
+          return setTimeout(fun, 0);
+        }
+
+        try {
+          // when when somebody has screwed with setTimeout but no I.E. maddness
+          return cachedSetTimeout(fun, 0);
+        } catch (e) {
+          try {
+            // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
+            return cachedSetTimeout.call(null, fun, 0);
+          } catch (e) {
+            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
+            return cachedSetTimeout.call(this, fun, 0);
+          }
+        }
+      }
+
+      function runClearTimeout(marker) {
+        if (cachedClearTimeout === clearTimeout) {
+          //normal enviroments in sane situations
+          return clearTimeout(marker);
+        } // if clearTimeout wasn't available but was latter defined
+
+
+        if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
+          cachedClearTimeout = clearTimeout;
+          return clearTimeout(marker);
+        }
+
+        try {
+          // when when somebody has screwed with setTimeout but no I.E. maddness
+          return cachedClearTimeout(marker);
+        } catch (e) {
+          try {
+            // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally
+            return cachedClearTimeout.call(null, marker);
+          } catch (e) {
+            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
+            // Some versions of I.E. have different rules for clearTimeout vs setTimeout
+            return cachedClearTimeout.call(this, marker);
+          }
+        }
+      }
+
+      var queue = [];
+      var draining = false;
+      var currentQueue;
+      var queueIndex = -1;
+
+      function cleanUpNextTick() {
+        if (!draining || !currentQueue) {
+          return;
+        }
+
+        draining = false;
+
+        if (currentQueue.length) {
+          queue = currentQueue.concat(queue);
+        } else {
+          queueIndex = -1;
+        }
+
+        if (queue.length) {
+          drainQueue();
+        }
+      }
+
+      function drainQueue() {
+        if (draining) {
+          return;
+        }
+
+        var timeout = runTimeout(cleanUpNextTick);
+        draining = true;
+        var len = queue.length;
+
+        while (len) {
+          currentQueue = queue;
+          queue = [];
+
+          while (++queueIndex < len) {
+            if (currentQueue) {
+              currentQueue[queueIndex].run();
+            }
+          }
+
+          queueIndex = -1;
+          len = queue.length;
+        }
+
+        currentQueue = null;
+        draining = false;
+        runClearTimeout(timeout);
+      }
+
+      process.nextTick = function (fun) {
+        var args = new Array(arguments.length - 1);
+
+        if (arguments.length > 1) {
+          for (var i = 1; i < arguments.length; i++) {
+            args[i - 1] = arguments[i];
+          }
+        }
+
+        queue.push(new Item(fun, args));
+
+        if (queue.length === 1 && !draining) {
+          runTimeout(drainQueue);
+        }
+      }; // v8 likes predictible objects
+
+
+      function Item(fun, array) {
+        this.fun = fun;
+        this.array = array;
+      }
+
+      Item.prototype.run = function () {
+        this.fun.apply(null, this.array);
+      };
+
+      process.title = 'browser';
+      process.browser = true;
+      process.env = {};
+      process.argv = [];
+      process.version = ''; // empty string to avoid regexp issues
+
+      process.versions = {};
+
+      function noop() {}
+
+      process.on = noop;
+      process.addListener = noop;
+      process.once = noop;
+      process.off = noop;
+      process.removeListener = noop;
+      process.removeAllListeners = noop;
+      process.emit = noop;
+      process.prependListener = noop;
+      process.prependOnceListener = noop;
+
+      process.listeners = function (name) {
+        return [];
+      };
+
+      process.binding = function (name) {
+        throw new Error('process.binding is not supported');
+      };
+
+      process.cwd = function () {
+        return '/';
+      };
+
+      process.chdir = function (dir) {
+        throw new Error('process.chdir is not supported');
+      };
+
+      process.umask = function () {
+        return 0;
+      };
+    }, {}],
+    3: [function (require, module, exports) {
+      /**
+       * This is the common logic for both the Node.js and web browser
+       * implementations of `debug()`.
+       */
+      function setup(env) {
+        createDebug.debug = createDebug;
+        createDebug.default = createDebug;
+        createDebug.coerce = coerce;
+        createDebug.disable = disable;
+        createDebug.enable = enable;
+        createDebug.enabled = enabled;
+        createDebug.humanize = require('ms');
+        Object.keys(env).forEach(function (key) {
+          createDebug[key] = env[key];
+        });
+        /**
+        * Active `debug` instances.
+        */
+
+        createDebug.instances = [];
+        /**
+        * The currently active debug mode names, and names to skip.
+        */
+
+        createDebug.names = [];
+        createDebug.skips = [];
+        /**
+        * Map of special "%n" handling functions, for the debug "format" argument.
+        *
+        * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N".
+        */
+
+        createDebug.formatters = {};
+        /**
+        * Selects a color for a debug namespace
+        * @param {String} namespace The namespace string for the for the debug instance to be colored
+        * @return {Number|String} An ANSI color code for the given namespace
+        * @api private
+        */
+
+        function selectColor(namespace) {
+          var hash = 0;
+
+          for (var i = 0; i < namespace.length; i++) {
+            hash = (hash << 5) - hash + namespace.charCodeAt(i);
+            hash |= 0; // Convert to 32bit integer
+          }
+
+          return createDebug.colors[Math.abs(hash) % createDebug.colors.length];
+        }
+
+        createDebug.selectColor = selectColor;
+        /**
+        * Create a debugger with the given `namespace`.
+        *
+        * @param {String} namespace
+        * @return {Function}
+        * @api public
+        */
+
+        function createDebug(namespace) {
+          var prevTime;
+
+          function debug() {
+            for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
+              args[_key] = arguments[_key];
+            }
+
+            // Disabled?
+            if (!debug.enabled) {
+              return;
+            }
+
+            var self = debug; // Set `diff` timestamp
+
+            var curr = Number(new Date());
+            var ms = curr - (prevTime || curr);
+            self.diff = ms;
+            self.prev = prevTime;
+            self.curr = curr;
+            prevTime = curr;
+            args[0] = createDebug.coerce(args[0]);
+
+            if (typeof args[0] !== 'string') {
+              // Anything else let's inspect with %O
+              args.unshift('%O');
+            } // Apply any `formatters` transformations
+
+
+            var index = 0;
+            args[0] = args[0].replace(/%([a-zA-Z%])/g, function (match, format) {
+              // If we encounter an escaped % then don't increase the array index
+              if (match === '%%') {
+                return match;
+              }
+
+              index++;
+              var formatter = createDebug.formatters[format];
+
+              if (typeof formatter === 'function') {
+                var val = args[index];
+                match = formatter.call(self, val); // Now we need to remove `args[index]` since it's inlined in the `format`
+
+                args.splice(index, 1);
+                index--;
+              }
+
+              return match;
+            }); // Apply env-specific formatting (colors, etc.)
+
+            createDebug.formatArgs.call(self, args);
+            var logFn = self.log || createDebug.log;
+            logFn.apply(self, args);
+          }
+
+          debug.namespace = namespace;
+          debug.enabled = createDebug.enabled(namespace);
+          debug.useColors = createDebug.useColors();
+          debug.color = selectColor(namespace);
+          debug.destroy = destroy;
+          debug.extend = extend; // Debug.formatArgs = formatArgs;
+          // debug.rawLog = rawLog;
+          // env-specific initialization logic for debug instances
+
+          if (typeof createDebug.init === 'function') {
+            createDebug.init(debug);
+          }
+
+          createDebug.instances.push(debug);
+          return debug;
+        }
+
+        function destroy() {
+          var index = createDebug.instances.indexOf(this);
+
+          if (index !== -1) {
+            createDebug.instances.splice(index, 1);
+            return true;
+          }
+
+          return false;
+        }
+
+        function extend(namespace, delimiter) {
+          var newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace);
+          newDebug.log = this.log;
+          return newDebug;
+        }
+        /**
+        * Enables a debug mode by namespaces. This can include modes
+        * separated by a colon and wildcards.
+        *
+        * @param {String} namespaces
+        * @api public
+        */
+
+
+        function enable(namespaces) {
+          createDebug.save(namespaces);
+          createDebug.names = [];
+          createDebug.skips = [];
+          var i;
+          var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
+          var len = split.length;
+
+          for (i = 0; i < len; i++) {
+            if (!split[i]) {
+              // ignore empty strings
+              continue;
+            }
+
+            namespaces = split[i].replace(/\*/g, '.*?');
+
+            if (namespaces[0] === '-') {
+              createDebug.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
+            } else {
+              createDebug.names.push(new RegExp('^' + namespaces + '$'));
+            }
+          }
+
+          for (i = 0; i < createDebug.instances.length; i++) {
+            var instance = createDebug.instances[i];
+            instance.enabled = createDebug.enabled(instance.namespace);
+          }
+        }
+        /**
+        * Disable debug output.
+        *
+        * @return {String} namespaces
+        * @api public
+        */
+
+
+        function disable() {
+          var namespaces = [].concat(_toConsumableArray(createDebug.names.map(toNamespace)), _toConsumableArray(createDebug.skips.map(toNamespace).map(function (namespace) {
+            return '-' + namespace;
+          }))).join(',');
+          createDebug.enable('');
+          return namespaces;
+        }
+        /**
+        * Returns true if the given mode name is enabled, false otherwise.
+        *
+        * @param {String} name
+        * @return {Boolean}
+        * @api public
+        */
+
+
+        function enabled(name) {
+          if (name[name.length - 1] === '*') {
+            return true;
+          }
+
+          var i;
+          var len;
+
+          for (i = 0, len = createDebug.skips.length; i < len; i++) {
+            if (createDebug.skips[i].test(name)) {
+              return false;
+            }
+          }
+
+          for (i = 0, len = createDebug.names.length; i < len; i++) {
+            if (createDebug.names[i].test(name)) {
+              return true;
+            }
+          }
+
+          return false;
+        }
+        /**
+        * Convert regexp to namespace
+        *
+        * @param {RegExp} regxep
+        * @return {String} namespace
+        * @api private
+        */
+
+
+        function toNamespace(regexp) {
+          return regexp.toString().substring(2, regexp.toString().length - 2).replace(/\.\*\?$/, '*');
+        }
+        /**
+        * Coerce `val`.
+        *
+        * @param {Mixed} val
+        * @return {Mixed}
+        * @api private
+        */
+
+
+        function coerce(val) {
+          if (val instanceof Error) {
+            return val.stack || val.message;
+          }
+
+          return val;
+        }
+
+        createDebug.enable(createDebug.load());
+        return createDebug;
+      }
+
+      module.exports = setup;
+    }, {
+      "ms": 1
+    }],
+    4: [function (require, module, exports) {
+      (function (process) {
+        /* eslint-env browser */
+
+        /**
+         * This is the web browser implementation of `debug()`.
+         */
+        exports.log = log;
+        exports.formatArgs = formatArgs;
+        exports.save = save;
+        exports.load = load;
+        exports.useColors = useColors;
+        exports.storage = localstorage();
+        /**
+         * Colors.
+         */
+
+        exports.colors = ['#0000CC', '#0000FF', '#0033CC', '#0033FF', '#0066CC', '#0066FF', '#0099CC', '#0099FF', '#00CC00', '#00CC33', '#00CC66', '#00CC99', '#00CCCC', '#00CCFF', '#3300CC', '#3300FF', '#3333CC', '#3333FF', '#3366CC', '#3366FF', '#3399CC', '#3399FF', '#33CC00', '#33CC33', '#33CC66', '#33CC99', '#33CCCC', '#33CCFF', '#6600CC', '#6600FF', '#6633CC', '#6633FF', '#66CC00', '#66CC33', '#9900CC', '#9900FF', '#9933CC', '#9933FF', '#99CC00', '#99CC33', '#CC0000', '#CC0033', '#CC0066', '#CC0099', '#CC00CC', '#CC00FF', '#CC3300', '#CC3333', '#CC3366', '#CC3399', '#CC33CC', '#CC33FF', '#CC6600', '#CC6633', '#CC9900', '#CC9933', '#CCCC00', '#CCCC33', '#FF0000', '#FF0033', '#FF0066', '#FF0099', '#FF00CC', '#FF00FF', '#FF3300', '#FF3333', '#FF3366', '#FF3399', '#FF33CC', '#FF33FF', '#FF6600', '#FF6633', '#FF9900', '#FF9933', '#FFCC00', '#FFCC33'];
+        /**
+         * Currently only WebKit-based Web Inspectors, Firefox >= v31,
+         * and the Firebug extension (any Firefox version) are known
+         * to support "%c" CSS customizations.
+         *
+         * TODO: add a `localStorage` variable to explicitly enable/disable colors
+         */
+        // eslint-disable-next-line complexity
+
+        function useColors() {
+          // NB: In an Electron preload script, document will be defined but not fully
+          // initialized. Since we know we're in Chrome, we'll just detect this case
+          // explicitly
+          if (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) {
+            return true;
+          } // Internet Explorer and Edge do not support colors.
+
+
+          if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) {
+            return false;
+          } // Is webkit? http://stackoverflow.com/a/16459606/376773
+          // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
+
+
+          return typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance || // Is firebug? http://stackoverflow.com/a/398120/376773
+          typeof window !== 'undefined' && window.console && (window.console.firebug || window.console.exception && window.console.table) || // Is firefox >= v31?
+          // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
+          typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31 || // Double check webkit in userAgent just in case we are in a worker
+          typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/);
+        }
+        /**
+         * Colorize log arguments if enabled.
+         *
+         * @api public
+         */
+
+
+        function formatArgs(args) {
+          args[0] = (this.useColors ? '%c' : '') + this.namespace + (this.useColors ? ' %c' : ' ') + args[0] + (this.useColors ? '%c ' : ' ') + '+' + module.exports.humanize(this.diff);
+
+          if (!this.useColors) {
+            return;
+          }
+
+          var c = 'color: ' + this.color;
+          args.splice(1, 0, c, 'color: inherit'); // The final "%c" is somewhat tricky, because there could be other
+          // arguments passed either before or after the %c, so we need to
+          // figure out the correct index to insert the CSS into
+
+          var index = 0;
+          var lastC = 0;
+          args[0].replace(/%[a-zA-Z%]/g, function (match) {
+            if (match === '%%') {
+              return;
+            }
+
+            index++;
+
+            if (match === '%c') {
+              // We only are interested in the *last* %c
+              // (the user may have provided their own)
+              lastC = index;
+            }
+          });
+          args.splice(lastC, 0, c);
+        }
+        /**
+         * Invokes `console.log()` when available.
+         * No-op when `console.log` is not a "function".
+         *
+         * @api public
+         */
+
+
+        function log() {
+          var _console;
+
+          // This hackery is required for IE8/9, where
+          // the `console.log` function doesn't have 'apply'
+          return (typeof console === "undefined" ? "undefined" : _typeof(console)) === 'object' && console.log && (_console = console).log.apply(_console, arguments);
+        }
+        /**
+         * Save `namespaces`.
+         *
+         * @param {String} namespaces
+         * @api private
+         */
+
+
+        function save(namespaces) {
+          try {
+            if (namespaces) {
+              exports.storage.setItem('debug', namespaces);
+            } else {
+              exports.storage.removeItem('debug');
+            }
+          } catch (error) {// Swallow
+            // XXX (@Qix-) should we be logging these?
+          }
+        }
+        /**
+         * Load `namespaces`.
+         *
+         * @return {String} returns the previously persisted debug modes
+         * @api private
+         */
+
+
+        function load() {
+          var r;
+
+          try {
+            r = exports.storage.getItem('debug');
+          } catch (error) {} // Swallow
+          // XXX (@Qix-) should we be logging these?
+          // If debug isn't set in LS, and we're in Electron, try to load $DEBUG
+
+
+          if (!r && typeof process !== 'undefined' && 'env' in process) {
+            r = process.env.DEBUG;
+          }
+
+          return r;
+        }
+        /**
+         * Localstorage attempts to return the localstorage.
+         *
+         * This is necessary because safari throws
+         * when a user disables cookies/localstorage
+         * and you attempt to access it.
+         *
+         * @return {LocalStorage}
+         * @api private
+         */
+
+
+        function localstorage() {
+          try {
+            // TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context
+            // The Browser also has localStorage in the global context.
+            return localStorage;
+          } catch (error) {// Swallow
+            // XXX (@Qix-) should we be logging these?
+          }
+        }
+
+        module.exports = require('./common')(exports);
+        var formatters = module.exports.formatters;
+        /**
+         * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
+         */
+
+        formatters.j = function (v) {
+          try {
+            return JSON.stringify(v);
+          } catch (error) {
+            return '[UnexpectedJSONParseError]: ' + error.message;
+          }
+        };
+      }).call(this, require('_process'));
+    }, {
+      "./common": 3,
+      "_process": 2
+    }]
+  }, {}, [4])(4);
+});

+ 152 - 0
engine.io/node_modules/debug/node_modules/ms/index.js

@@ -0,0 +1,152 @@
+/**
+ * Helpers.
+ */
+
+var s = 1000;
+var m = s * 60;
+var h = m * 60;
+var d = h * 24;
+var y = d * 365.25;
+
+/**
+ * Parse or format the given `val`.
+ *
+ * Options:
+ *
+ *  - `long` verbose formatting [false]
+ *
+ * @param {String|Number} val
+ * @param {Object} [options]
+ * @throws {Error} throw an error if val is not a non-empty string or a number
+ * @return {String|Number}
+ * @api public
+ */
+
+module.exports = function(val, options) {
+  options = options || {};
+  var type = typeof val;
+  if (type === 'string' && val.length > 0) {
+    return parse(val);
+  } else if (type === 'number' && isNaN(val) === false) {
+    return options.long ? fmtLong(val) : fmtShort(val);
+  }
+  throw new Error(
+    'val is not a non-empty string or a valid number. val=' +
+      JSON.stringify(val)
+  );
+};
+
+/**
+ * Parse the given `str` and return milliseconds.
+ *
+ * @param {String} str
+ * @return {Number}
+ * @api private
+ */
+
+function parse(str) {
+  str = String(str);
+  if (str.length > 100) {
+    return;
+  }
+  var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(
+    str
+  );
+  if (!match) {
+    return;
+  }
+  var n = parseFloat(match[1]);
+  var type = (match[2] || 'ms').toLowerCase();
+  switch (type) {
+    case 'years':
+    case 'year':
+    case 'yrs':
+    case 'yr':
+    case 'y':
+      return n * y;
+    case 'days':
+    case 'day':
+    case 'd':
+      return n * d;
+    case 'hours':
+    case 'hour':
+    case 'hrs':
+    case 'hr':
+    case 'h':
+      return n * h;
+    case 'minutes':
+    case 'minute':
+    case 'mins':
+    case 'min':
+    case 'm':
+      return n * m;
+    case 'seconds':
+    case 'second':
+    case 'secs':
+    case 'sec':
+    case 's':
+      return n * s;
+    case 'milliseconds':
+    case 'millisecond':
+    case 'msecs':
+    case 'msec':
+    case 'ms':
+      return n;
+    default:
+      return undefined;
+  }
+}
+
+/**
+ * Short format for `ms`.
+ *
+ * @param {Number} ms
+ * @return {String}
+ * @api private
+ */
+
+function fmtShort(ms) {
+  if (ms >= d) {
+    return Math.round(ms / d) + 'd';
+  }
+  if (ms >= h) {
+    return Math.round(ms / h) + 'h';
+  }
+  if (ms >= m) {
+    return Math.round(ms / m) + 'm';
+  }
+  if (ms >= s) {
+    return Math.round(ms / s) + 's';
+  }
+  return ms + 'ms';
+}
+
+/**
+ * Long format for `ms`.
+ *
+ * @param {Number} ms
+ * @return {String}
+ * @api private
+ */
+
+function fmtLong(ms) {
+  return plural(ms, d, 'day') ||
+    plural(ms, h, 'hour') ||
+    plural(ms, m, 'minute') ||
+    plural(ms, s, 'second') ||
+    ms + ' ms';
+}
+
+/**
+ * Pluralization helper.
+ */
+
+function plural(ms, n, name) {
+  if (ms < n) {
+    return;
+  }
+  if (ms < n * 1.5) {
+    return Math.floor(ms / n) + ' ' + name;
+  }
+  return Math.ceil(ms / n) + ' ' + name + 's';
+}

+ 21 - 0
engine.io/node_modules/debug/node_modules/ms/license.md

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Zeit, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 69 - 0
engine.io/node_modules/debug/node_modules/ms/package.json

@@ -0,0 +1,69 @@
+{
+  "_from": "ms@2.0.0",
+  "_id": "ms@2.0.0",
+  "_inBundle": false,
+  "_integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+  "_location": "/engine.io/debug/ms",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "version",
+    "registry": true,
+    "raw": "ms@2.0.0",
+    "name": "ms",
+    "escapedName": "ms",
+    "rawSpec": "2.0.0",
+    "saveSpec": null,
+    "fetchSpec": "2.0.0"
+  },
+  "_requiredBy": [
+    "/engine.io/debug"
+  ],
+  "_resolved": "https://registry.npmmirror.com/ms/download/ms-2.0.0.tgz",
+  "_shasum": "5608aeadfc00be6c2901df5f9861788de0d597c8",
+  "_spec": "ms@2.0.0",
+  "_where": "D:\\project\\node_modules\\engine.io\\node_modules\\debug",
+  "bugs": {
+    "url": "https://github.com/zeit/ms/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "Tiny milisecond conversion utility",
+  "devDependencies": {
+    "eslint": "3.19.0",
+    "expect.js": "0.3.1",
+    "husky": "0.13.3",
+    "lint-staged": "3.4.1",
+    "mocha": "3.4.1"
+  },
+  "eslintConfig": {
+    "extends": "eslint:recommended",
+    "env": {
+      "node": true,
+      "es6": true
+    }
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/zeit/ms#readme",
+  "license": "MIT",
+  "lint-staged": {
+    "*.js": [
+      "npm run lint",
+      "prettier --single-quote --write",
+      "git add"
+    ]
+  },
+  "main": "./index",
+  "name": "ms",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/zeit/ms.git"
+  },
+  "scripts": {
+    "lint": "eslint lib/* bin/*",
+    "precommit": "lint-staged",
+    "test": "mocha tests.js"
+  },
+  "version": "2.0.0"
+}

+ 51 - 0
engine.io/node_modules/debug/node_modules/ms/readme.md

@@ -0,0 +1,51 @@
+# ms
+
+[![Build Status](https://travis-ci.org/zeit/ms.svg?branch=master)](https://travis-ci.org/zeit/ms)
+[![Slack Channel](http://zeit-slackin.now.sh/badge.svg)](https://zeit.chat/)
+
+Use this package to easily convert various time formats to milliseconds.
+
+## Examples
+
+```js
+ms('2 days')  // 172800000
+ms('1d')      // 86400000
+ms('10h')     // 36000000
+ms('2.5 hrs') // 9000000
+ms('2h')      // 7200000
+ms('1m')      // 60000
+ms('5s')      // 5000
+ms('1y')      // 31557600000
+ms('100')     // 100
+```
+
+### Convert from milliseconds
+
+```js
+ms(60000)             // "1m"
+ms(2 * 60000)         // "2m"
+ms(ms('10 hours'))    // "10h"
+```
+
+### Time format written-out
+
+```js
+ms(60000, { long: true })             // "1 minute"
+ms(2 * 60000, { long: true })         // "2 minutes"
+ms(ms('10 hours'), { long: true })    // "10 hours"
+```
+
+## Features
+
+- Works both in [node](https://nodejs.org) and in the browser.
+- If a number is supplied to `ms`, a string with a unit is returned.
+- If a string that contains the number is supplied, it returns it as a number (e.g.: it returns `100` for `'100'`).
+- If you pass a string with a number and a valid unit, the number of equivalent ms is returned.
+
+## Caught a bug?
+
+1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device
+2. Link the package to the global module directory: `npm link`
+3. Within the module you want to test your local development instance of ms, just link it to the dependencies: `npm link ms`. Instead of the default one from npm, node will now use your clone of ms!
+
+As always, you can run the tests using: `npm test`

+ 266 - 0
engine.io/node_modules/debug/src/common.js

@@ -0,0 +1,266 @@
+
+/**
+ * This is the common logic for both the Node.js and web browser
+ * implementations of `debug()`.
+ */
+
+function setup(env) {
+	createDebug.debug = createDebug;
+	createDebug.default = createDebug;
+	createDebug.coerce = coerce;
+	createDebug.disable = disable;
+	createDebug.enable = enable;
+	createDebug.enabled = enabled;
+	createDebug.humanize = require('ms');
+
+	Object.keys(env).forEach(key => {
+		createDebug[key] = env[key];
+	});
+
+	/**
+	* Active `debug` instances.
+	*/
+	createDebug.instances = [];
+
+	/**
+	* The currently active debug mode names, and names to skip.
+	*/
+
+	createDebug.names = [];
+	createDebug.skips = [];
+
+	/**
+	* Map of special "%n" handling functions, for the debug "format" argument.
+	*
+	* Valid key names are a single, lower or upper-case letter, i.e. "n" and "N".
+	*/
+	createDebug.formatters = {};
+
+	/**
+	* Selects a color for a debug namespace
+	* @param {String} namespace The namespace string for the for the debug instance to be colored
+	* @return {Number|String} An ANSI color code for the given namespace
+	* @api private
+	*/
+	function selectColor(namespace) {
+		let hash = 0;
+
+		for (let i = 0; i < namespace.length; i++) {
+			hash = ((hash << 5) - hash) + namespace.charCodeAt(i);
+			hash |= 0; // Convert to 32bit integer
+		}
+
+		return createDebug.colors[Math.abs(hash) % createDebug.colors.length];
+	}
+	createDebug.selectColor = selectColor;
+
+	/**
+	* Create a debugger with the given `namespace`.
+	*
+	* @param {String} namespace
+	* @return {Function}
+	* @api public
+	*/
+	function createDebug(namespace) {
+		let prevTime;
+
+		function debug(...args) {
+			// Disabled?
+			if (!debug.enabled) {
+				return;
+			}
+
+			const self = debug;
+
+			// Set `diff` timestamp
+			const curr = Number(new Date());
+			const ms = curr - (prevTime || curr);
+			self.diff = ms;
+			self.prev = prevTime;
+			self.curr = curr;
+			prevTime = curr;
+
+			args[0] = createDebug.coerce(args[0]);
+
+			if (typeof args[0] !== 'string') {
+				// Anything else let's inspect with %O
+				args.unshift('%O');
+			}
+
+			// Apply any `formatters` transformations
+			let index = 0;
+			args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {
+				// If we encounter an escaped % then don't increase the array index
+				if (match === '%%') {
+					return match;
+				}
+				index++;
+				const formatter = createDebug.formatters[format];
+				if (typeof formatter === 'function') {
+					const val = args[index];
+					match = formatter.call(self, val);
+
+					// Now we need to remove `args[index]` since it's inlined in the `format`
+					args.splice(index, 1);
+					index--;
+				}
+				return match;
+			});
+
+			// Apply env-specific formatting (colors, etc.)
+			createDebug.formatArgs.call(self, args);
+
+			const logFn = self.log || createDebug.log;
+			logFn.apply(self, args);
+		}
+
+		debug.namespace = namespace;
+		debug.enabled = createDebug.enabled(namespace);
+		debug.useColors = createDebug.useColors();
+		debug.color = selectColor(namespace);
+		debug.destroy = destroy;
+		debug.extend = extend;
+		// Debug.formatArgs = formatArgs;
+		// debug.rawLog = rawLog;
+
+		// env-specific initialization logic for debug instances
+		if (typeof createDebug.init === 'function') {
+			createDebug.init(debug);
+		}
+
+		createDebug.instances.push(debug);
+
+		return debug;
+	}
+
+	function destroy() {
+		const index = createDebug.instances.indexOf(this);
+		if (index !== -1) {
+			createDebug.instances.splice(index, 1);
+			return true;
+		}
+		return false;
+	}
+
+	function extend(namespace, delimiter) {
+		const newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace);
+		newDebug.log = this.log;
+		return newDebug;
+	}
+
+	/**
+	* Enables a debug mode by namespaces. This can include modes
+	* separated by a colon and wildcards.
+	*
+	* @param {String} namespaces
+	* @api public
+	*/
+	function enable(namespaces) {
+		createDebug.save(namespaces);
+
+		createDebug.names = [];
+		createDebug.skips = [];
+
+		let i;
+		const split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
+		const len = split.length;
+
+		for (i = 0; i < len; i++) {
+			if (!split[i]) {
+				// ignore empty strings
+				continue;
+			}
+
+			namespaces = split[i].replace(/\*/g, '.*?');
+
+			if (namespaces[0] === '-') {
+				createDebug.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
+			} else {
+				createDebug.names.push(new RegExp('^' + namespaces + '$'));
+			}
+		}
+
+		for (i = 0; i < createDebug.instances.length; i++) {
+			const instance = createDebug.instances[i];
+			instance.enabled = createDebug.enabled(instance.namespace);
+		}
+	}
+
+	/**
+	* Disable debug output.
+	*
+	* @return {String} namespaces
+	* @api public
+	*/
+	function disable() {
+		const namespaces = [
+			...createDebug.names.map(toNamespace),
+			...createDebug.skips.map(toNamespace).map(namespace => '-' + namespace)
+		].join(',');
+		createDebug.enable('');
+		return namespaces;
+	}
+
+	/**
+	* Returns true if the given mode name is enabled, false otherwise.
+	*
+	* @param {String} name
+	* @return {Boolean}
+	* @api public
+	*/
+	function enabled(name) {
+		if (name[name.length - 1] === '*') {
+			return true;
+		}
+
+		let i;
+		let len;
+
+		for (i = 0, len = createDebug.skips.length; i < len; i++) {
+			if (createDebug.skips[i].test(name)) {
+				return false;
+			}
+		}
+
+		for (i = 0, len = createDebug.names.length; i < len; i++) {
+			if (createDebug.names[i].test(name)) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	* Convert regexp to namespace
+	*
+	* @param {RegExp} regxep
+	* @return {String} namespace
+	* @api private
+	*/
+	function toNamespace(regexp) {
+		return regexp.toString()
+			.substring(2, regexp.toString().length - 2)
+			.replace(/\.\*\?$/, '*');
+	}
+
+	/**
+	* Coerce `val`.
+	*
+	* @param {Mixed} val
+	* @return {Mixed}
+	* @api private
+	*/
+	function coerce(val) {
+		if (val instanceof Error) {
+			return val.stack || val.message;
+		}
+		return val;
+	}
+
+	createDebug.enable(createDebug.load());
+
+	return createDebug;
+}
+
+module.exports = setup;

+ 162 - 0
engine.io/node_modules/ms/index.js

@@ -0,0 +1,162 @@
+/**
+ * Helpers.
+ */
+
+var s = 1000;
+var m = s * 60;
+var h = m * 60;
+var d = h * 24;
+var w = d * 7;
+var y = d * 365.25;
+
+/**
+ * Parse or format the given `val`.
+ *
+ * Options:
+ *
+ *  - `long` verbose formatting [false]
+ *
+ * @param {String|Number} val
+ * @param {Object} [options]
+ * @throws {Error} throw an error if val is not a non-empty string or a number
+ * @return {String|Number}
+ * @api public
+ */
+
+module.exports = function (val, options) {
+  options = options || {};
+  var type = typeof val;
+  if (type === 'string' && val.length > 0) {
+    return parse(val);
+  } else if (type === 'number' && isFinite(val)) {
+    return options.long ? fmtLong(val) : fmtShort(val);
+  }
+  throw new Error(
+    'val is not a non-empty string or a valid number. val=' +
+      JSON.stringify(val)
+  );
+};
+
+/**
+ * Parse the given `str` and return milliseconds.
+ *
+ * @param {String} str
+ * @return {Number}
+ * @api private
+ */
+
+function parse(str) {
+  str = String(str);
+  if (str.length > 100) {
+    return;
+  }
+  var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
+    str
+  );
+  if (!match) {
+    return;
+  }
+  var n = parseFloat(match[1]);
+  var type = (match[2] || 'ms').toLowerCase();
+  switch (type) {
+    case 'years':
+    case 'year':
+    case 'yrs':
+    case 'yr':
+    case 'y':
+      return n * y;
+    case 'weeks':
+    case 'week':
+    case 'w':
+      return n * w;
+    case 'days':
+    case 'day':
+    case 'd':
+      return n * d;
+    case 'hours':
+    case 'hour':
+    case 'hrs':
+    case 'hr':
+    case 'h':
+      return n * h;
+    case 'minutes':
+    case 'minute':
+    case 'mins':
+    case 'min':
+    case 'm':
+      return n * m;
+    case 'seconds':
+    case 'second':
+    case 'secs':
+    case 'sec':
+    case 's':
+      return n * s;
+    case 'milliseconds':
+    case 'millisecond':
+    case 'msecs':
+    case 'msec':
+    case 'ms':
+      return n;
+    default:
+      return undefined;
+  }
+}
+
+/**
+ * Short format for `ms`.
+ *
+ * @param {Number} ms
+ * @return {String}
+ * @api private
+ */
+
+function fmtShort(ms) {
+  var msAbs = Math.abs(ms);
+  if (msAbs >= d) {
+    return Math.round(ms / d) + 'd';
+  }
+  if (msAbs >= h) {
+    return Math.round(ms / h) + 'h';
+  }
+  if (msAbs >= m) {
+    return Math.round(ms / m) + 'm';
+  }
+  if (msAbs >= s) {
+    return Math.round(ms / s) + 's';
+  }
+  return ms + 'ms';
+}
+
+/**
+ * Long format for `ms`.
+ *
+ * @param {Number} ms
+ * @return {String}
+ * @api private
+ */
+
+function fmtLong(ms) {
+  var msAbs = Math.abs(ms);
+  if (msAbs >= d) {
+    return plural(ms, msAbs, d, 'day');
+  }
+  if (msAbs >= h) {
+    return plural(ms, msAbs, h, 'hour');
+  }
+  if (msAbs >= m) {
+    return plural(ms, msAbs, m, 'minute');
+  }
+  if (msAbs >= s) {
+    return plural(ms, msAbs, s, 'second');
+  }
+  return ms + ' ms';
+}
+
+/**
+ * Pluralization helper.
+ */
+
+function plural(ms, msAbs, n, name) {
+  var isPlural = msAbs >= n * 1.5;
+  return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');
+}

+ 21 - 0
engine.io/node_modules/ms/license.md

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2020 Vercel, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 70 - 0
engine.io/node_modules/ms/package.json

@@ -0,0 +1,70 @@
+{
+  "_from": "ms@^2.1.1",
+  "_id": "ms@2.1.3",
+  "_inBundle": false,
+  "_integrity": "sha1-V0yBOM4dK1hh8LRFedut1gxmFbI=",
+  "_location": "/engine.io/ms",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "ms@^2.1.1",
+    "name": "ms",
+    "escapedName": "ms",
+    "rawSpec": "^2.1.1",
+    "saveSpec": null,
+    "fetchSpec": "^2.1.1"
+  },
+  "_requiredBy": [
+    "/engine.io/debug"
+  ],
+  "_resolved": "https://registry.npmmirror.com/ms/download/ms-2.1.3.tgz",
+  "_shasum": "574c8138ce1d2b5861f0b44579dbadd60c6615b2",
+  "_spec": "ms@^2.1.1",
+  "_where": "D:\\project\\server\\build\\node_modules\\engine.io\\node_modules\\debug",
+  "bugs": {
+    "url": "https://github.com/vercel/ms/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "Tiny millisecond conversion utility",
+  "devDependencies": {
+    "eslint": "4.18.2",
+    "expect.js": "0.3.1",
+    "husky": "0.14.3",
+    "lint-staged": "5.0.0",
+    "mocha": "4.0.1",
+    "prettier": "2.0.5"
+  },
+  "eslintConfig": {
+    "extends": "eslint:recommended",
+    "env": {
+      "node": true,
+      "es6": true
+    }
+  },
+  "files": [
+    "index.js"
+  ],
+  "homepage": "https://github.com/vercel/ms#readme",
+  "license": "MIT",
+  "lint-staged": {
+    "*.js": [
+      "npm run lint",
+      "prettier --single-quote --write",
+      "git add"
+    ]
+  },
+  "main": "./index",
+  "name": "ms",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vercel/ms.git"
+  },
+  "scripts": {
+    "lint": "eslint lib/* bin/*",
+    "precommit": "lint-staged",
+    "test": "mocha tests.js"
+  },
+  "version": "2.1.3"
+}

+ 59 - 0
engine.io/node_modules/ms/readme.md

@@ -0,0 +1,59 @@
+# ms
+
+![CI](https://github.com/vercel/ms/workflows/CI/badge.svg)
+
+Use this package to easily convert various time formats to milliseconds.
+
+## Examples
+
+```js
+ms('2 days')  // 172800000
+ms('1d')      // 86400000
+ms('10h')     // 36000000
+ms('2.5 hrs') // 9000000
+ms('2h')      // 7200000
+ms('1m')      // 60000
+ms('5s')      // 5000
+ms('1y')      // 31557600000
+ms('100')     // 100
+ms('-3 days') // -259200000
+ms('-1h')     // -3600000
+ms('-200')    // -200
+```
+
+### Convert from Milliseconds
+
+```js
+ms(60000)             // "1m"
+ms(2 * 60000)         // "2m"
+ms(-3 * 60000)        // "-3m"
+ms(ms('10 hours'))    // "10h"
+```
+
+### Time Format Written-Out
+
+```js
+ms(60000, { long: true })             // "1 minute"
+ms(2 * 60000, { long: true })         // "2 minutes"
+ms(-3 * 60000, { long: true })        // "-3 minutes"
+ms(ms('10 hours'), { long: true })    // "10 hours"
+```
+
+## Features
+
+- Works both in [Node.js](https://nodejs.org) and in the browser
+- If a number is supplied to `ms`, a string with a unit is returned
+- If a string that contains the number is supplied, it returns it as a number (e.g.: it returns `100` for `'100'`)
+- If you pass a string with a number and a valid unit, the number of equivalent milliseconds is returned
+
+## Related Packages
+
+- [ms.macro](https://github.com/knpwrs/ms.macro) - Run `ms` as a macro at build-time.
+
+## Caught a Bug?
+
+1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device
+2. Link the package to the global module directory: `npm link`
+3. Within the module you want to test your local development instance of ms, just link it to the dependencies: `npm link ms`. Instead of the default one from npm, Node.js will now use your clone of ms!
+
+As always, you can run the tests using: `npm test`

+ 8 - 0
flatted/.github/FUNDING.yml

@@ -0,0 +1,8 @@
+# These are supported funding model platforms
+
+github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
+patreon: # not working due missing www.
+open_collective: #
+ko_fi: # Replace with a single Ko-fi username
+tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
+custom: https://www.patreon.com/webreflection

+ 15 - 0
flatted/LICENSE

@@ -0,0 +1,15 @@
+ISC License
+
+Copyright (c) 2018, Andrea Giammarchi, @WebReflection
+
+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.

+ 65 - 0
flatted/README.md

@@ -0,0 +1,65 @@
+# flatted
+
+![Downloads](https://img.shields.io/npm/dm/flatted.svg) [![Coverage Status](https://coveralls.io/repos/github/WebReflection/flatted/badge.svg?branch=master)](https://coveralls.io/github/WebReflection/flatted?branch=master) [![Build Status](https://travis-ci.org/WebReflection/flatted.svg?branch=master)](https://travis-ci.org/WebReflection/flatted) [![License: ISC](https://img.shields.io/badge/License-ISC-yellow.svg)](https://opensource.org/licenses/ISC) ![WebReflection status](https://offline.report/status/webreflection.svg)
+
+A super light (0.5K) and fast circular JSON parser, directly from the creator of [CircularJSON](https://github.com/WebReflection/circular-json/#circularjson).
+
+```js
+npm i flatted
+```
+
+Usable via [CDN](https://unpkg.com/flatted) or as regular module.
+
+```js
+// ESM
+import {parse, stringify} from 'flatted/esm';
+
+// CJS
+const {parse, stringify} = require('flatted/cjs');
+
+const a = [{}];
+a[0].a = a;
+a.push(a);
+
+stringify(a); // [["1","0"],{"a":"0"}]
+```
+
+## Flatted VS JSON
+
+As it is for every other specialized format capable of serializing and deserializing circular data, you should never `JSON.parse(Flatted.stringify(data))`, and you should never `Flatted.parse(JSON.stringify(data))`.
+
+The only way this could work is to `Flatted.parse(Flatted.stringify(data))`, as it is also for _CircularJSON_ or any other, otherwise there's no granted data integrity.
+
+Also please note this project serializes and deserializes only data compatible with JSON, so that sockets, or anything else with internal classes different from those allowed by JSON standard, won't be serialized and unserialized as expected.
+
+
+### New in V1: Exact same JSON API
+
+  * Added a [reviver](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Syntax) parameter to `.parse(string, reviver)` and revive your own objects.
+  * Added a [replacer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#Syntax) and a `space` parameter to `.stringify(object, replacer, space)` for feature parity with JSON signature.
+
+
+### Compatibility
+All ECMAScript engines compatible with `Map`, `Set`, `Object.keys`, and `Array.prototype.reduce` will work, even if polyfilled.
+
+
+### How does it work ?
+While stringifying, all Objects, including Arrays, and strings, are flattened out and replaced as unique index. `*`
+
+Once parsed, all indexes will be replaced through the flattened collection.
+
+<sup><sub>`*` represented as string to avoid conflicts with numbers</sub></sup>
+
+```js
+// logic example
+var a = [{one: 1}, {two: '2'}];
+a[0].a = a;
+// a is the main object, will be at index '0'
+// {one: 1} is the second object, index '1'
+// {two: '2'} the third, in '2', and it has a string
+// which will be found at index '3'
+
+Flatted.stringify(a);
+// [["1","2"],{"one":1,"a":"0"},{"two":"3"},"2"]
+// a[one,two]    {one: 1, a}    {two: '2'}  '2'
+```

+ 94 - 0
flatted/SPECS.md

@@ -0,0 +1,94 @@
+# Flatted Specifications
+
+This document describes operations performed to produce, or parse, the flatted output.
+
+## stringify(any) => flattedString
+
+The output is always an `Array` that contains at index `0` the given value.
+
+If the value is an `Array` or an `Object`, per each property value passed through the callback, return the value as is if it's not an `Array`, an `Object`, or a `string`.
+
+In case it's an `Array`, an `Object`, or a `string`, return the index as `string`, associated through a `Map`.
+
+Giving the following example:
+
+```js
+flatted.stringify('a');                     // ["a"]
+flatted.stringify(['a']);                   // [["1"],"a"]
+flatted.stringify(['a', 1, 'b']);           // [["1",1,"2"],"a","b"]
+```
+
+There is an `input` containing `[array, "a", "b"]`, where the `array` has indexes `"1"` and `"2"` as strings, indexes that point respectively at `"a"` and `"b"` within the input `[array, "a", "b"]`.
+
+The exact same happens for objects.
+
+```js
+flatted.stringify('a');                     // ["a"]
+flatted.stringify({a: 'a'});                // [{"a":"1"},"a"]
+flatted.stringify({a: 'a', n: 1, b: 'b'});  // [{"a":"1","n":1,"b":"2"},"a","b"]
+```
+
+Every object, string, or array, encountered during serialization will be stored once as stringified index.
+
+```js
+// per each property/value of the object/array
+if (any == null || !/object|string/.test(typeof any))
+  return any;
+if (!map.has(any)) {
+  const index = String(arr.length);
+  arr.push(any);
+  map.set(any, index);
+}
+return map.get(any);
+```
+
+This, performed before going through all properties, grants unique indexes per reference.
+
+The stringified indexes ensure there won't be conflicts with regularly stored numbers.
+
+## parse(flattedString) => any
+
+Everything that is a `string` is wrapped as `new String`, but strings in the array, from index `1` on, is kept as regular `string`.
+
+```js
+const input = JSON.parse('[{"a":"1"},"b"]', Strings).map(strings);
+// convert strings primitives into String instances
+function Strings(key, value) {
+  return typeof value === 'string' ? new String(value) : value;
+}
+// converts String instances into strings primitives
+function strings(value) {
+  return value instanceof String ? String(value) : value;
+}
+```
+
+The `input` array will have a regular `string` at index `1`, but its object at index `0` will have an `instanceof String` as `.a` property.
+
+That is the key to place back values from the rest of the array, so that per each property of the object at index `0`, if the value is an `instanceof` String, something not serializable via JSON, it means it can be used to retrieve the position of its value from the `input` array.
+
+If such `value` is an object and it hasn't been parsed yet, add it as parsed and go through all its properties/values.
+
+```js
+// outside any loop ...
+const parsed = new Set;
+
+// ... per each property/value ...
+if (value instanceof Primitive) {
+  const tmp = input[parseInt(value)];
+  if (typeof tmp === 'object' && !parsed.has(tmp)) {
+    parsed.add(tmp);
+    output[key] = tmp;
+    if (typeof tmp === 'object' && tmp != null) {
+      // perform this same logic per
+      // each nested property/value ...
+    }
+  } else {
+    output[key] = tmp;
+  }
+} else
+  output[key] = tmp;
+```
+
+As summary, the whole logic is based on polluting the de-serialization with a kind of variable that is unexpected, hence secure to use as directive to retrieve an index with a value.
+
+The usage of a `Map` and a `Set` to flag known references/strings as visited/stored makes **flatted** a rock solid, fast, and compact, solution.

+ 114 - 0
flatted/cjs/index.js

@@ -0,0 +1,114 @@
+var Flatted = (function (Primitive, primitive) {
+
+  /*!
+   * ISC License
+   *
+   * Copyright (c) 2018, Andrea Giammarchi, @WebReflection
+   *
+   * 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.
+   */
+
+  var Flatted = {
+
+    parse: function parse(text, reviver) {
+      var input = JSON.parse(text, Primitives).map(primitives);
+      var value = input[0];
+      var $ = reviver || noop;
+      var tmp = typeof value === 'object' && value ?
+                  revive(input, new Set, value, $) :
+                  value;
+      return $.call({'': tmp}, '', tmp);
+    },
+
+    stringify: function stringify(value, replacer, space) {
+      for (var
+        firstRun,
+        known = new Map,
+        input = [],
+        output = [],
+        $ = replacer && typeof replacer === typeof input ?
+              function (k, v) {
+                if (k === '' || -1 < replacer.indexOf(k)) return v;
+              } :
+              (replacer || noop),
+        i = +set(known, input, $.call({'': value}, '', value)),
+        replace = function (key, value) {
+          if (firstRun) {
+            firstRun = !firstRun;
+            return value;
+          }
+          var after = $.call(this, key, value);
+          switch (typeof after) {
+            case 'object':
+              if (after === null) return after;
+            case primitive:
+              return known.get(after) || set(known, input, after);
+          }
+          return after;
+        };
+        i < input.length; i++
+      ) {
+        firstRun = true;
+        output[i] = JSON.stringify(input[i], replace, space);
+      }
+      return '[' + output.join(',') + ']';
+    }
+
+  };
+
+  return Flatted;
+
+  function noop(key, value) {
+    return value;
+  }
+
+  function revive(input, parsed, output, $) {
+    return Object.keys(output).reduce(
+      function (output, key) {
+        var value = output[key];
+        if (value instanceof Primitive) {
+          var tmp = input[value];
+          if (typeof tmp === 'object' && !parsed.has(tmp)) {
+            parsed.add(tmp);
+            output[key] = $.call(output, key, revive(input, parsed, tmp, $));
+          } else {
+            output[key] = $.call(output, key, tmp);
+          }
+        } else
+          output[key] = $.call(output, key, value);
+        return output;
+      },
+      output
+    );
+  }
+
+  function set(known, input, value) {
+    var index = Primitive(input.push(value) - 1);
+    known.set(value, index);
+    return index;
+  }
+
+  // the two kinds of primitives
+  //  1. the real one
+  //  2. the wrapped one
+
+  function primitives(value) {
+    return value instanceof Primitive ? Primitive(value) : value;
+  }
+
+  function Primitives(key, value) {
+    return typeof value === primitive ? new Primitive(value) : value;
+  }
+
+}(String, 'string'));
+module.exports = Flatted;

+ 116 - 0
flatted/esm/index.js

@@ -0,0 +1,116 @@
+var Flatted = (function (Primitive, primitive) {
+
+  /*!
+   * ISC License
+   *
+   * Copyright (c) 2018, Andrea Giammarchi, @WebReflection
+   *
+   * 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.
+   */
+
+  var Flatted = {
+
+    parse: function parse(text, reviver) {
+      var input = JSON.parse(text, Primitives).map(primitives);
+      var value = input[0];
+      var $ = reviver || noop;
+      var tmp = typeof value === 'object' && value ?
+                  revive(input, new Set, value, $) :
+                  value;
+      return $.call({'': tmp}, '', tmp);
+    },
+
+    stringify: function stringify(value, replacer, space) {
+      for (var
+        firstRun,
+        known = new Map,
+        input = [],
+        output = [],
+        $ = replacer && typeof replacer === typeof input ?
+              function (k, v) {
+                if (k === '' || -1 < replacer.indexOf(k)) return v;
+              } :
+              (replacer || noop),
+        i = +set(known, input, $.call({'': value}, '', value)),
+        replace = function (key, value) {
+          if (firstRun) {
+            firstRun = !firstRun;
+            return value;
+          }
+          var after = $.call(this, key, value);
+          switch (typeof after) {
+            case 'object':
+              if (after === null) return after;
+            case primitive:
+              return known.get(after) || set(known, input, after);
+          }
+          return after;
+        };
+        i < input.length; i++
+      ) {
+        firstRun = true;
+        output[i] = JSON.stringify(input[i], replace, space);
+      }
+      return '[' + output.join(',') + ']';
+    }
+
+  };
+
+  return Flatted;
+
+  function noop(key, value) {
+    return value;
+  }
+
+  function revive(input, parsed, output, $) {
+    return Object.keys(output).reduce(
+      function (output, key) {
+        var value = output[key];
+        if (value instanceof Primitive) {
+          var tmp = input[value];
+          if (typeof tmp === 'object' && !parsed.has(tmp)) {
+            parsed.add(tmp);
+            output[key] = $.call(output, key, revive(input, parsed, tmp, $));
+          } else {
+            output[key] = $.call(output, key, tmp);
+          }
+        } else
+          output[key] = $.call(output, key, value);
+        return output;
+      },
+      output
+    );
+  }
+
+  function set(known, input, value) {
+    var index = Primitive(input.push(value) - 1);
+    known.set(value, index);
+    return index;
+  }
+
+  // the two kinds of primitives
+  //  1. the real one
+  //  2. the wrapped one
+
+  function primitives(value) {
+    return value instanceof Primitive ? Primitive(value) : value;
+  }
+
+  function Primitives(key, value) {
+    return typeof value === primitive ? new Primitive(value) : value;
+  }
+
+}(String, 'string'));
+export default Flatted;
+export var parse = Flatted.parse;
+export var stringify = Flatted.stringify;

+ 113 - 0
flatted/index.js

@@ -0,0 +1,113 @@
+var Flatted = (function (Primitive, primitive) {
+
+  /*!
+   * ISC License
+   *
+   * Copyright (c) 2018, Andrea Giammarchi, @WebReflection
+   *
+   * 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.
+   */
+
+  var Flatted = {
+
+    parse: function parse(text, reviver) {
+      var input = JSON.parse(text, Primitives).map(primitives);
+      var value = input[0];
+      var $ = reviver || noop;
+      var tmp = typeof value === 'object' && value ?
+                  revive(input, new Set, value, $) :
+                  value;
+      return $.call({'': tmp}, '', tmp);
+    },
+
+    stringify: function stringify(value, replacer, space) {
+      for (var
+        firstRun,
+        known = new Map,
+        input = [],
+        output = [],
+        $ = replacer && typeof replacer === typeof input ?
+              function (k, v) {
+                if (k === '' || -1 < replacer.indexOf(k)) return v;
+              } :
+              (replacer || noop),
+        i = +set(known, input, $.call({'': value}, '', value)),
+        replace = function (key, value) {
+          if (firstRun) {
+            firstRun = !firstRun;
+            return value;
+          }
+          var after = $.call(this, key, value);
+          switch (typeof after) {
+            case 'object':
+              if (after === null) return after;
+            case primitive:
+              return known.get(after) || set(known, input, after);
+          }
+          return after;
+        };
+        i < input.length; i++
+      ) {
+        firstRun = true;
+        output[i] = JSON.stringify(input[i], replace, space);
+      }
+      return '[' + output.join(',') + ']';
+    }
+
+  };
+
+  return Flatted;
+
+  function noop(key, value) {
+    return value;
+  }
+
+  function revive(input, parsed, output, $) {
+    return Object.keys(output).reduce(
+      function (output, key) {
+        var value = output[key];
+        if (value instanceof Primitive) {
+          var tmp = input[value];
+          if (typeof tmp === 'object' && !parsed.has(tmp)) {
+            parsed.add(tmp);
+            output[key] = $.call(output, key, revive(input, parsed, tmp, $));
+          } else {
+            output[key] = $.call(output, key, tmp);
+          }
+        } else
+          output[key] = $.call(output, key, value);
+        return output;
+      },
+      output
+    );
+  }
+
+  function set(known, input, value) {
+    var index = Primitive(input.push(value) - 1);
+    known.set(value, index);
+    return index;
+  }
+
+  // the two kinds of primitives
+  //  1. the real one
+  //  2. the wrapped one
+
+  function primitives(value) {
+    return value instanceof Primitive ? Primitive(value) : value;
+  }
+
+  function Primitives(key, value) {
+    return typeof value === primitive ? new Primitive(value) : value;
+  }
+
+}(String, 'string'));

+ 2 - 0
flatted/min.js

@@ -0,0 +1,2 @@
+/*! (c) 2018, Andrea Giammarchi, (ISC) */
+var Flatted=function(a,l){return{parse:function(n,t){var e=JSON.parse(n,i).map(f),r=e[0],u=t||s,c="object"==typeof r&&r?function u(c,f,n,i){return Object.keys(n).reduce(function(n,t){var e=n[t];if(e instanceof a){var r=c[e];"object"!=typeof r||f.has(r)?n[t]=i.call(n,t,r):(f.add(r),n[t]=i.call(n,t,u(c,f,r,i)))}else n[t]=i.call(n,t,e);return n},n)}(e,new Set,r,u):r;return u.call({"":c},"",c)},stringify:function(n,e,t){function r(n,t){if(u)return u=!u,t;var e=a.call(this,n,t);switch(typeof e){case"object":if(null===e)return e;case l:return c.get(e)||p(c,f,e)}return e}for(var u,c=new Map,f=[],i=[],a=e&&typeof e==typeof f?function(n,t){if(""===n||-1<e.indexOf(n))return t}:e||s,o=+p(c,f,a.call({"":n},"",n));o<f.length;o++)u=!0,i[o]=JSON.stringify(f[o],r,t);return"["+i.join(",")+"]"}};function s(n,t){return t}function p(n,t,e){var r=a(t.push(e)-1);return n.set(e,r),r}function f(n){return n instanceof a?a(n):n}function i(n,t){return typeof t==l?new a(t):t}}(String,"string");

+ 71 - 0
flatted/package.json

@@ -0,0 +1,71 @@
+{
+  "_from": "flatted@^2.0.1",
+  "_id": "flatted@2.0.2",
+  "_inBundle": false,
+  "_integrity": "sha1-RXWyHivO50NKqb5mL0t7X5wrUTg=",
+  "_location": "/flatted",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "flatted@^2.0.1",
+    "name": "flatted",
+    "escapedName": "flatted",
+    "rawSpec": "^2.0.1",
+    "saveSpec": null,
+    "fetchSpec": "^2.0.1"
+  },
+  "_requiredBy": [
+    "/log4js"
+  ],
+  "_resolved": "https://registry.npmmirror.com/flatted/download/flatted-2.0.2.tgz?cache=0&sync_timestamp=1636473847692&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fflatted%2Fdownload%2Fflatted-2.0.2.tgz",
+  "_shasum": "4575b21e2bcee7434aa9be662f4b7b5f9c2b5138",
+  "_spec": "flatted@^2.0.1",
+  "_where": "D:\\project\\server\\logtest\\node_modules\\log4js",
+  "author": {
+    "name": "Andrea Giammarchi"
+  },
+  "bugs": {
+    "url": "https://github.com/WebReflection/flatted/issues"
+  },
+  "bundleDependencies": false,
+  "deprecated": false,
+  "description": "A super light and fast circular JSON parser.",
+  "devDependencies": {
+    "circular-json": "^0.5.9",
+    "circular-json-es6": "^2.0.2",
+    "coveralls": "^3.0.11",
+    "jsan": "^3.1.13",
+    "nyc": "^15.0.0",
+    "uglify-js": "^3.8.1"
+  },
+  "homepage": "https://github.com/WebReflection/flatted#readme",
+  "keywords": [
+    "circular",
+    "JSON",
+    "fast",
+    "parser",
+    "minimal"
+  ],
+  "license": "ISC",
+  "main": "cjs/index.js",
+  "module": "esm/index.js",
+  "name": "flatted",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/WebReflection/flatted.git"
+  },
+  "scripts": {
+    "bench": "node test/bench.js",
+    "build": "npm run cjs && npm test && npm run esm && npm run min && npm run size",
+    "cjs": "cp index.js cjs/index.js; echo 'module.exports = Flatted;' >> cjs/index.js",
+    "coveralls": "nyc report --reporter=text-lcov | coveralls",
+    "esm": "cp index.js esm/index.js; echo 'export default Flatted;' >> esm/index.js; echo 'export var parse = Flatted.parse;' >> esm/index.js; echo 'export var stringify = Flatted.stringify;' >> esm/index.js",
+    "min": "echo '/*! (c) 2018, Andrea Giammarchi, (ISC) */'>min.js && uglifyjs index.js --support-ie8 -c -m >> min.js",
+    "size": "cat index.js | wc -c;cat min.js | wc -c;gzip -c9 min.js | wc -c;cat min.js | brotli | wc -c",
+    "test": "nyc node test/index.js"
+  },
+  "types": "types.d.ts",
+  "unpkg": "min.js",
+  "version": "2.0.2"
+}

+ 19 - 0
flatted/types.d.ts

@@ -0,0 +1,19 @@
+/**
+ * Fast and minimal circular JSON parser.
+ * logic example
+```js
+ var a = [{one: 1}, {two: '2'}];
+a[0].a = a;
+// a is the main object, will be at index '0'
+// {one: 1} is the second object, index '1'
+// {two: '2'} the third, in '2', and it has a string
+// which will be found at index '3'
+
+Flatted.stringify(a);
+// [["1","2"],{"one":1,"a":"0"},{"two":"3"},"2"]
+// a[one,two]    {one: 1, a}    {two: '2'}  '2'
+```
+ */
+declare const Flatted: typeof JSON;
+
+export = Flatted;

+ 330 - 19
fs-extra/CHANGELOG.md

@@ -1,3 +1,207 @@
+8.1.0 / 2019-06-28
+------------------
+
+- Add support for promisified `fs.realpath.native` in Node v9.2+ ([#650](https://github.com/jprichardson/node-fs-extra/issues/650), [#682](https://github.com/jprichardson/node-fs-extra/pull/682))
+- Update `graceful-fs` dependency ([#700](https://github.com/jprichardson/node-fs-extra/pull/700))
+- Use `graceful-fs` everywhere ([#700](https://github.com/jprichardson/node-fs-extra/pull/700))
+
+8.0.1 / 2019-05-13
+------------------
+
+- Fix bug `Maximum call stack size exceeded` error in `util/stat` ([#679](https://github.com/jprichardson/node-fs-extra/pull/679))
+
+8.0.0 / 2019-05-11
+------------------
+
+**NOTE:** Node.js v6 support is deprecated, and will be dropped in the next major release.
+
+- Use `renameSync()` under the hood in `moveSync()`
+- Fix bug with bind-mounted directories in `copy*()` ([#613](https://github.com/jprichardson/node-fs-extra/issues/613), [#618](https://github.com/jprichardson/node-fs-extra/pull/618))
+- Fix bug in `move()` with case-insensitive file systems
+- Use `fs.stat()`'s `bigint` option in `copy*()` & `move*()` where possible ([#657](https://github.com/jprichardson/node-fs-extra/issues/657))
+
+7.0.1 / 2018-11-07
+------------------
+
+- Fix `removeSync()` on Windows, in some cases, it would error out with `ENOTEMPTY` ([#646](https://github.com/jprichardson/node-fs-extra/pull/646))
+- Document `mode` option for `ensureDir*()` ([#587](https://github.com/jprichardson/node-fs-extra/pull/587))
+- Don't include documentation files in npm package tarball ([#642](https://github.com/jprichardson/node-fs-extra/issues/642), [#643](https://github.com/jprichardson/node-fs-extra/pull/643))
+
+7.0.0 / 2018-07-16
+------------------
+
+- **BREAKING:** Refine `copy*()` handling of symlinks to properly detect symlinks that point to the same file. ([#582](https://github.com/jprichardson/node-fs-extra/pull/582))
+- Fix bug with copying write-protected directories ([#600](https://github.com/jprichardson/node-fs-extra/pull/600))
+- Universalify `fs.lchmod()` ([#596](https://github.com/jprichardson/node-fs-extra/pull/596))
+- Add `engines` field to `package.json` ([#580](https://github.com/jprichardson/node-fs-extra/pull/580))
+
+6.0.1 / 2018-05-09
+------------------
+
+- Fix `fs.promises` `ExperimentalWarning` on Node v10.1.0 ([#578](https://github.com/jprichardson/node-fs-extra/pull/578))
+
+6.0.0 / 2018-05-01
+------------------
+
+- Drop support for Node.js versions 4, 5, & 7 ([#564](https://github.com/jprichardson/node-fs-extra/pull/564))
+- Rewrite `move` to use `fs.rename` where possible ([#549](https://github.com/jprichardson/node-fs-extra/pull/549))
+- Don't convert relative paths to absolute paths for `filter` ([#554](https://github.com/jprichardson/node-fs-extra/pull/554))
+- `copy*`'s behavior when `preserveTimestamps` is `false` has been OS-dependent since 5.0.0, but that's now explicitly noted in the docs ([#563](https://github.com/jprichardson/node-fs-extra/pull/563))
+- Fix subdirectory detection for `copy*` & `move*` ([#541](https://github.com/jprichardson/node-fs-extra/pull/541))
+- Handle case-insensitive paths correctly in `copy*` ([#568](https://github.com/jprichardson/node-fs-extra/pull/568))
+
+5.0.0 / 2017-12-11
+------------------
+
+Significant refactor of `copy()` & `copySync()`, including breaking changes. No changes to other functions in this release.
+
+Huge thanks to **[@manidlou](https://github.com/manidlou)** for doing most of the work on this release.
+
+- The `filter` option can no longer be a RegExp (must be a function). This was deprecated since fs-extra v1.0.0. [#512](https://github.com/jprichardson/node-fs-extra/pull/512)
+- `copy()`'s `filter` option can now be a function that returns a Promise. [#518](https://github.com/jprichardson/node-fs-extra/pull/518)
+- `copy()` & `copySync()` now use `fs.copyFile()`/`fs.copyFileSync()` in environments that support it (currently Node 8.5.0+). Older Node versions still get the old implementation. [#505](https://github.com/jprichardson/node-fs-extra/pull/505)
+- Don't allow copying a directory into itself. [#83](https://github.com/jprichardson/node-fs-extra/issues/83)
+- Handle copying between identical files. [#198](https://github.com/jprichardson/node-fs-extra/issues/198)
+- Error out when copying an empty folder to a path that already exists. [#464](https://github.com/jprichardson/node-fs-extra/issues/464)
+- Don't create `dest`'s parent if the `filter` function aborts the `copy()` operation. [#517](https://github.com/jprichardson/node-fs-extra/pull/517)
+- Fix `writeStream` not being closed if there was an error in `copy()`. [#516](https://github.com/jprichardson/node-fs-extra/pull/516)
+
+4.0.3 / 2017-12-05
+------------------
+
+- Fix wrong `chmod` values in `fs.remove()` [#501](https://github.com/jprichardson/node-fs-extra/pull/501)
+- Fix `TypeError` on systems that don't have some `fs` operations like `lchown` [#520](https://github.com/jprichardson/node-fs-extra/pull/520)
+
+4.0.2 / 2017-09-12
+------------------
+
+- Added `EOL` option to `writeJson*` & `outputJson*` (via upgrade to jsonfile v4)
+- Added promise support to [`fs.copyFile()`](https://nodejs.org/api/fs.html#fs_fs_copyfile_src_dest_flags_callback) in Node 8.5+
+- Added `.js` extension to `main` field in `package.json` for better tooling compatibility. [#485](https://github.com/jprichardson/node-fs-extra/pull/485)
+
+4.0.1 / 2017-07-31
+------------------
+
+### Fixed
+
+- Previously, `ensureFile()` & `ensureFileSync()` would do nothing if the path was a directory. Now, they error out for consistency with `ensureDir()`. [#465](https://github.com/jprichardson/node-fs-extra/issues/465), [#466](https://github.com/jprichardson/node-fs-extra/pull/466), [#470](https://github.com/jprichardson/node-fs-extra/issues/470)
+
+4.0.0 / 2017-07-14
+------------------
+
+### Changed
+
+- **BREAKING:** The promisified versions of `fs.read()` & `fs.write()` now return objects. See [the docs](docs/fs-read-write.md) for details. [#436](https://github.com/jprichardson/node-fs-extra/issues/436), [#449](https://github.com/jprichardson/node-fs-extra/pull/449)
+- `fs.move()` now errors out when destination is a subdirectory of source. [#458](https://github.com/jprichardson/node-fs-extra/pull/458)
+- Applied upstream fixes from `rimraf` to `fs.remove()` & `fs.removeSync()`. [#459](https://github.com/jprichardson/node-fs-extra/pull/459)
+
+### Fixed
+
+- Got `fs.outputJSONSync()` working again; it was broken due to refactoring. [#428](https://github.com/jprichardson/node-fs-extra/pull/428)
+
+Also clarified the docs in a few places.
+
+3.0.1 / 2017-05-04
+------------------
+
+- Fix bug in `move()` & `moveSync()` when source and destination are the same, and source does not exist. [#415](https://github.com/jprichardson/node-fs-extra/pull/415)
+
+3.0.0 / 2017-04-27
+------------------
+
+### Added
+
+- **BREAKING:** Added Promise support. All asynchronous native fs methods and fs-extra methods now return a promise if the callback is not passed. [#403](https://github.com/jprichardson/node-fs-extra/pull/403)
+- `pathExists()`, a replacement for the deprecated `fs.exists`. `pathExists` has a normal error-first callback signature. Also added `pathExistsSync`, an alias to `fs.existsSync`, for completeness. [#406](https://github.com/jprichardson/node-fs-extra/pull/406)
+
+### Removed
+
+- **BREAKING:** Removed support for setting the default spaces for `writeJson()`, `writeJsonSync()`, `outputJson()`, & `outputJsonSync()`. This was undocumented. [#402](https://github.com/jprichardson/node-fs-extra/pull/402)
+
+### Changed
+
+- Upgraded jsonfile dependency to v3.0.0:
+  - **BREAKING:** Changed behavior of `throws` option for `readJsonSync()`; now does not throw filesystem errors when `throws` is `false`.
+- **BREAKING:** `writeJson()`, `writeJsonSync()`, `outputJson()`, & `outputJsonSync()` now output minified JSON by default for consistency with `JSON.stringify()`; set the `spaces` option to `2` to override this new behavior. [#402](https://github.com/jprichardson/node-fs-extra/pull/402)
+- Use `Buffer.allocUnsafe()` instead of `new Buffer()` in environments that support it. [#394](https://github.com/jprichardson/node-fs-extra/pull/394)
+
+### Fixed
+
+- `removeSync()` silently failed on Windows in some cases. Now throws an `EBUSY` error. [#408](https://github.com/jprichardson/node-fs-extra/pull/408)
+
+2.1.2 / 2017-03-16
+------------------
+
+### Fixed
+
+- Weird windows bug that resulted in `ensureDir()`'s callback being called twice in some cases. This bug may have also affected `remove()`. See [#392](https://github.com/jprichardson/node-fs-extra/issues/392), [#393](https://github.com/jprichardson/node-fs-extra/pull/393)
+
+2.1.1 / 2017-03-15
+------------------
+
+### Fixed
+
+- Reverted [`5597bd`](https://github.com/jprichardson/node-fs-extra/commit/5597bd5b67f7d060f5f5bf26e9635be48330f5d7), this broke compatibility with Node.js versions v4+ but less than `v4.5.0`.
+- Remove `Buffer.alloc()` usage in `moveSync()`.
+
+2.1.0 / 2017-03-15
+------------------
+
+Thanks to [Mani Maghsoudlou (@manidlou)](https://github.com/manidlou) & [Jan Peer Stöcklmair (@JPeer264)](https://github.com/JPeer264) for their extraordinary help with this release!
+
+### Added
+- `moveSync()` See [#309], [#381](https://github.com/jprichardson/node-fs-extra/pull/381). ([@manidlou](https://github.com/manidlou))
+- `copy()` and `copySync()`'s `filter` option now gets the destination path passed as the second parameter. [#366](https://github.com/jprichardson/node-fs-extra/pull/366) ([@manidlou](https://github.com/manidlou))
+
+### Changed
+- Use `Buffer.alloc()` instead of deprecated `new Buffer()` in `copySync()`. [#380](https://github.com/jprichardson/node-fs-extra/pull/380) ([@manidlou](https://github.com/manidlou))
+- Refactored entire codebase to use ES6 features supported by Node.js v4+ [#355](https://github.com/jprichardson/node-fs-extra/issues/355). [(@JPeer264)](https://github.com/JPeer264)
+- Refactored docs. ([@manidlou](https://github.com/manidlou))
+
+### Fixed
+
+- `move()` shouldn't error out when source and dest are the same. [#377](https://github.com/jprichardson/node-fs-extra/issues/377), [#378](https://github.com/jprichardson/node-fs-extra/pull/378) ([@jdalton](https://github.com/jdalton))
+
+2.0.0 / 2017-01-16
+------------------
+
+### Removed
+- **BREAKING:** Removed support for Node `v0.12`. The Node foundation stopped officially supporting it
+on Jan 1st, 2017.
+- **BREAKING:** Remove `walk()` and `walkSync()`. `walkSync()` was only part of `fs-extra` for a little
+over two months. Use [klaw](https://github.com/jprichardson/node-klaw) instead of `walk()`, in fact, `walk()` was just
+an alias to klaw. For `walkSync()` use [klaw-sync](https://github.com/mawni/node-klaw-sync). See: [#338], [#339]
+
+### Changed
+- **BREAKING:** Renamed `clobber` to `overwrite`. This affects `copy()`, `copySync()`, and `move()`. [#330], [#333]
+- Moved docs, to `docs/`. [#340]
+
+### Fixed
+- Apply filters to directories in `copySync()` like in `copy()`. [#324]
+- A specific condition when disk is under heavy use, `copy()` can fail. [#326]
+
+
+1.0.0 / 2016-11-01
+------------------
+
+After five years of development, we finally have reach the 1.0.0 milestone! Big thanks goes
+to [Ryan Zim](https://github.com/RyanZim) for leading the charge on this release!
+
+### Added
+- `walkSync()`
+
+### Changed
+- **BREAKING**: dropped Node v0.10 support.
+- disabled `rimaf` globbing, wasn't used. [#280]
+- deprecate `copy()/copySync()` option `filter` if it's a `RegExp`. `filter` should now be a function.
+- inline `rimraf`. This is temporary and was done because `rimraf` depended upon the beefy `glob` which `fs-extra` does not use. [#300]
+
+### Fixed
+- bug fix proper closing of file handle on `utimesMillis()` [#271]
+- proper escaping of files with dollar signs [#291]
+- `copySync()` failed if user didn't own file. [#199], [#301]
+
+
 0.30.0 / 2016-04-28
 -------------------
 - Brought back Node v0.10 support. I didn't realize there was still demand. Official support will end **2016-10-01**.
@@ -145,10 +349,10 @@ this package had both `fs.readJsonFile` and `fs.readJson` that were aliases to e
 
 0.16.0 / 2015-01-28
 -------------------
-- bugfix `fs.move()` into itself. Closes #104
-- bugfix `fs.move()` moving directory across device. Closes #108
+- bugfix `fs.move()` into itself. Closes [#104]
+- bugfix `fs.move()` moving directory across device. Closes [#108]
 - added coveralls support
-- bugfix: nasty multiple callback `fs.copy()` bug. Closes #98
+- bugfix: nasty multiple callback `fs.copy()` bug. Closes [#98]
 - misc fs.copy code cleanups
 
 0.15.0 / 2015-01-21
@@ -185,7 +389,7 @@ see https://github.com/jprichardson/node-jsonfile#readfilesyncfilename-options f
 0.10.0 / 2014-06-29
 ------------------
 * bugfix: upgaded `"jsonfile": "~1.1.0"` to `"jsonfile": "^1.2.0"`, bumped minor because of `jsonfile` dep change
-from `~` to `^`. #67
+from `~` to `^`. [#67]
 
 0.9.1 / 2014-05-22
 ------------------
@@ -193,31 +397,31 @@ from `~` to `^`. #67
 
 0.9.0 / 2014-05-22
 ------------------
-* upgraded `ncp` from `~0.4.2` to `^0.5.1`, #58
+* upgraded `ncp` from `~0.4.2` to `^0.5.1`, [#58]
 * upgraded `rimraf` from `~2.2.6` to `^2.2.8`
 * upgraded `mkdirp` from `0.3.x` to `^0.5.0`
 * added methods `ensureFile()`, `ensureFileSync()`
-* added methods `ensureDir()`, `ensureDirSync()` #31
+* added methods `ensureDir()`, `ensureDirSync()` [#31]
 * added `move()` method. From: https://github.com/andrewrk/node-mv
 
 
 0.8.1 / 2013-10-24
 ------------------
-* copy failed to return an error to the callback if a file doesn't exist (ulikoehler #38, #39)
+* copy failed to return an error to the callback if a file doesn't exist (ulikoehler [#38], [#39])
 
 0.8.0 / 2013-10-14
 ------------------
-* `filter` implemented on `copy()` and `copySync()`. (Srirangan / #36)
+* `filter` implemented on `copy()` and `copySync()`. (Srirangan / [#36])
 
 0.7.1 / 2013-10-12
 ------------------
-* `copySync()` implemented (Srirangan / #33)
-* updated to the latest `jsonfile` version `1.1.0` which gives `options` params for the JSON methods. Closes #32
+* `copySync()` implemented (Srirangan / [#33])
+* updated to the latest `jsonfile` version `1.1.0` which gives `options` params for the JSON methods. Closes [#32]
 
 0.7.0 / 2013-10-07
 ------------------
 * update readme conventions
-* `copy()` now works if destination directory does not exist. Closes #29
+* `copy()` now works if destination directory does not exist. Closes [#29]
 
 0.6.4 / 2013-09-05
 ------------------
@@ -231,19 +435,19 @@ from `~` to `^`. #67
 
 0.6.2 / 2013-06-28
 ------------------
-* added .npmignore, #25
+* added .npmignore, [#25]
 
 0.6.1 / 2013-05-14
 ------------------
-* modified for `strict` mode, closes #24
-* added `outputJson()/outputJsonSync()`, closes #23
+* modified for `strict` mode, closes [#24]
+* added `outputJson()/outputJsonSync()`, closes [#23]
 
 0.6.0 / 2013-03-18
 ------------------
 * removed node 0.6 support
 * added node 0.10 support
 * upgraded to latest `ncp` and `rimraf`.
-* optional `graceful-fs` support. Closes #17
+* optional `graceful-fs` support. Closes [#17]
 
 
 0.5.0 / 2013-02-03
@@ -281,7 +485,7 @@ from `~` to `^`. #67
 0.2.0 / 2012-09-10
 ------------------
 * Rewrote module into JavaScript. (Must still rewrite tests into JavaScript)
-* Added all methods of [jsonfile][https://github.com/jprichardson/node-jsonfile]
+* Added all methods of [jsonfile](https://github.com/jprichardson/node-jsonfile)
 * Added Travis-CI.
 
 0.1.3 / 2012-08-13
@@ -314,6 +518,113 @@ from `~` to `^`. #67
 * Added methods rmrf and rmrfSync
 * Moved tests from Jasmine to Mocha
 
+
+[#344]: https://github.com/jprichardson/node-fs-extra/issues/344    "Licence Year"
+[#343]: https://github.com/jprichardson/node-fs-extra/pull/343      "Add klaw-sync link to readme"
+[#342]: https://github.com/jprichardson/node-fs-extra/pull/342      "allow preserveTimestamps when use move"
+[#341]: https://github.com/jprichardson/node-fs-extra/issues/341    "mkdirp(path.dirname(dest) in move() logic needs cleaning up [question]"
+[#340]: https://github.com/jprichardson/node-fs-extra/pull/340      "Move docs to seperate docs folder [documentation]"
+[#339]: https://github.com/jprichardson/node-fs-extra/pull/339      "Remove walk() & walkSync() [feature-walk]"
+[#338]: https://github.com/jprichardson/node-fs-extra/issues/338    "Remove walk() and walkSync() [feature-walk]"
+[#337]: https://github.com/jprichardson/node-fs-extra/issues/337    "copy doesn't return a yieldable value"
+[#336]: https://github.com/jprichardson/node-fs-extra/pull/336      "Docs enhanced walk sync [documentation, feature-walk]"
+[#335]: https://github.com/jprichardson/node-fs-extra/pull/335      "Refactor move() tests [feature-move]"
+[#334]: https://github.com/jprichardson/node-fs-extra/pull/334      "Cleanup lib/move/index.js [feature-move]"
+[#333]: https://github.com/jprichardson/node-fs-extra/pull/333      "Rename clobber to overwrite [feature-copy, feature-move]"
+[#332]: https://github.com/jprichardson/node-fs-extra/pull/332      "BREAKING: Drop Node v0.12 & io.js support"
+[#331]: https://github.com/jprichardson/node-fs-extra/issues/331    "Add support for chmodr [enhancement, future]"
+[#330]: https://github.com/jprichardson/node-fs-extra/pull/330      "BREAKING: Do not error when copy destination exists & clobber: false [feature-copy]"
+[#329]: https://github.com/jprichardson/node-fs-extra/issues/329    "Does .walk() scale to large directories? [question]"
+[#328]: https://github.com/jprichardson/node-fs-extra/issues/328    "Copying files corrupts [feature-copy, needs-confirmed]"
+[#327]: https://github.com/jprichardson/node-fs-extra/pull/327      "Use writeStream 'finish' event instead of 'close' [bug, feature-copy]"
+[#326]: https://github.com/jprichardson/node-fs-extra/issues/326    "fs.copy fails with chmod error when disk under heavy use [bug, feature-copy]"
+[#325]: https://github.com/jprichardson/node-fs-extra/issues/325    "ensureDir is difficult to promisify [enhancement]"
+[#324]: https://github.com/jprichardson/node-fs-extra/pull/324      "copySync() should apply filter to directories like copy() [bug, feature-copy]"
+[#323]: https://github.com/jprichardson/node-fs-extra/issues/323    "Support for `dest` being a directory when using `copy*()`?"
+[#322]: https://github.com/jprichardson/node-fs-extra/pull/322      "Add fs-promise as fs-extra-promise alternative"
+[#321]: https://github.com/jprichardson/node-fs-extra/issues/321    "fs.copy() with clobber set to false return EEXIST error [feature-copy]"
+[#320]: https://github.com/jprichardson/node-fs-extra/issues/320    "fs.copySync: Error: EPERM: operation not permitted, unlink "
+[#319]: https://github.com/jprichardson/node-fs-extra/issues/319    "Create directory if not exists"
+[#318]: https://github.com/jprichardson/node-fs-extra/issues/318    "Support glob patterns [enhancement, future]"
+[#317]: https://github.com/jprichardson/node-fs-extra/pull/317      "Adding copy sync test for src file without write perms"
+[#316]: https://github.com/jprichardson/node-fs-extra/pull/316      "Remove move()'s broken limit option [feature-move]"
+[#315]: https://github.com/jprichardson/node-fs-extra/pull/315      "Fix move clobber tests to work around graceful-fs bug."
+[#314]: https://github.com/jprichardson/node-fs-extra/issues/314    "move() limit option [documentation, enhancement, feature-move]"
+[#313]: https://github.com/jprichardson/node-fs-extra/pull/313      "Test that remove() ignores glob characters."
+[#312]: https://github.com/jprichardson/node-fs-extra/pull/312      "Enhance walkSync() to return items with path and stats [feature-walk]"
+[#311]: https://github.com/jprichardson/node-fs-extra/issues/311    "move() not work when dest name not provided [feature-move]"
+[#310]: https://github.com/jprichardson/node-fs-extra/issues/310    "Edit walkSync to return items like what walk emits [documentation, enhancement, feature-walk]"
+[#309]: https://github.com/jprichardson/node-fs-extra/issues/309    "moveSync support [enhancement, feature-move]"
+[#308]: https://github.com/jprichardson/node-fs-extra/pull/308      "Fix incorrect anchor link"
+[#307]: https://github.com/jprichardson/node-fs-extra/pull/307      "Fix coverage"
+[#306]: https://github.com/jprichardson/node-fs-extra/pull/306      "Update devDeps, fix lint error"
+[#305]: https://github.com/jprichardson/node-fs-extra/pull/305      "Re-add Coveralls"
+[#304]: https://github.com/jprichardson/node-fs-extra/pull/304      "Remove path-is-absolute [enhancement]"
+[#303]: https://github.com/jprichardson/node-fs-extra/pull/303      "Document copySync filter inconsistency [documentation, feature-copy]"
+[#302]: https://github.com/jprichardson/node-fs-extra/pull/302      "fix(console): depreciated -> deprecated"
+[#301]: https://github.com/jprichardson/node-fs-extra/pull/301      "Remove chmod call from copySync [feature-copy]"
+[#300]: https://github.com/jprichardson/node-fs-extra/pull/300      "Inline Rimraf [enhancement, feature-move, feature-remove]"
+[#299]: https://github.com/jprichardson/node-fs-extra/pull/299      "Warn when filter is a RegExp [feature-copy]"
+[#298]: https://github.com/jprichardson/node-fs-extra/issues/298    "API Docs [documentation]"
+[#297]: https://github.com/jprichardson/node-fs-extra/pull/297      "Warn about using preserveTimestamps on 32-bit node"
+[#296]: https://github.com/jprichardson/node-fs-extra/pull/296      "Improve EEXIST error message for copySync [enhancement]"
+[#295]: https://github.com/jprichardson/node-fs-extra/pull/295      "Depreciate using regular expressions for copy's filter option [documentation]"
+[#294]: https://github.com/jprichardson/node-fs-extra/pull/294      "BREAKING: Refactor lib/copy/ncp.js [feature-copy]"
+[#293]: https://github.com/jprichardson/node-fs-extra/pull/293      "Update CI configs"
+[#292]: https://github.com/jprichardson/node-fs-extra/issues/292    "Rewrite lib/copy/ncp.js [enhancement, feature-copy]"
+[#291]: https://github.com/jprichardson/node-fs-extra/pull/291      "Escape '$' in replacement string for async file copying"
+[#290]: https://github.com/jprichardson/node-fs-extra/issues/290    "Exclude files pattern while copying using copy.config.js [question]"
+[#289]: https://github.com/jprichardson/node-fs-extra/pull/289      "(Closes #271) lib/util/utimes: properly close file descriptors in the event of an error"
+[#288]: https://github.com/jprichardson/node-fs-extra/pull/288      "(Closes #271) lib/util/utimes: properly close file descriptors in the event of an error"
+[#287]: https://github.com/jprichardson/node-fs-extra/issues/287    "emptyDir() callback arguments are inconsistent [enhancement, feature-remove]"
+[#286]: https://github.com/jprichardson/node-fs-extra/pull/286      "Added walkSync function"
+[#285]: https://github.com/jprichardson/node-fs-extra/issues/285    "CITGM test failing on s390"
+[#284]: https://github.com/jprichardson/node-fs-extra/issues/284    "outputFile method is missing a check to determine if existing item is a folder or not"
+[#283]: https://github.com/jprichardson/node-fs-extra/pull/283      "Apply filter also on directories and symlinks for copySync()"
+[#282]: https://github.com/jprichardson/node-fs-extra/pull/282      "Apply filter also on directories and symlinks for copySync()"
+[#281]: https://github.com/jprichardson/node-fs-extra/issues/281    "remove function executes 'successfully' but doesn't do anything?"
+[#280]: https://github.com/jprichardson/node-fs-extra/pull/280      "Disable rimraf globbing"
+[#279]: https://github.com/jprichardson/node-fs-extra/issues/279    "Some code is vendored instead of included [awaiting-reply]"
+[#278]: https://github.com/jprichardson/node-fs-extra/issues/278    "copy() does not preserve file/directory ownership"
+[#277]: https://github.com/jprichardson/node-fs-extra/pull/277      "Mention defaults for clobber and dereference options"
+[#276]: https://github.com/jprichardson/node-fs-extra/issues/276    "Cannot connect to Shared Folder [awaiting-reply]"
+[#275]: https://github.com/jprichardson/node-fs-extra/issues/275    "EMFILE, too many open files on Mac OS with JSON API"
+[#274]: https://github.com/jprichardson/node-fs-extra/issues/274    "Use with memory-fs? [enhancement, future]"
+[#273]: https://github.com/jprichardson/node-fs-extra/pull/273      "tests: rename `remote.test.js` to `remove.test.js`"
+[#272]: https://github.com/jprichardson/node-fs-extra/issues/272    "Copy clobber flag never err even when true [bug, feature-copy]"
+[#271]: https://github.com/jprichardson/node-fs-extra/issues/271    "Unclosed file handle on futimes error"
+[#270]: https://github.com/jprichardson/node-fs-extra/issues/270    "copy not working as desired on Windows [feature-copy, platform-windows]"
+[#269]: https://github.com/jprichardson/node-fs-extra/issues/269    "Copying with preserveTimeStamps: true is inaccurate using 32bit node [feature-copy]"
+[#268]: https://github.com/jprichardson/node-fs-extra/pull/268      "port fix for mkdirp issue #111"
+[#267]: https://github.com/jprichardson/node-fs-extra/issues/267    "WARN deprecated wrench@1.5.9: wrench.js is deprecated!"
+[#266]: https://github.com/jprichardson/node-fs-extra/issues/266    "fs-extra"
+[#265]: https://github.com/jprichardson/node-fs-extra/issues/265    "Link the `fs.stat fs.exists` etc. methods for replace the `fs` module forever?"
+[#264]: https://github.com/jprichardson/node-fs-extra/issues/264    "Renaming a file using move fails when a file inside is open (at least on windows) [wont-fix]"
+[#263]: https://github.com/jprichardson/node-fs-extra/issues/263    "ENOSYS: function not implemented, link [needs-confirmed]"
+[#262]: https://github.com/jprichardson/node-fs-extra/issues/262    "Add .exists() and .existsSync()"
+[#261]: https://github.com/jprichardson/node-fs-extra/issues/261    "Cannot read property 'prototype' of undefined"
+[#260]: https://github.com/jprichardson/node-fs-extra/pull/260      "use more specific path for method require"
+[#259]: https://github.com/jprichardson/node-fs-extra/issues/259    "Feature Request: isEmpty"
+[#258]: https://github.com/jprichardson/node-fs-extra/issues/258    "copy files does not preserve file timestamp"
+[#257]: https://github.com/jprichardson/node-fs-extra/issues/257    "Copying a file on windows fails"
+[#256]: https://github.com/jprichardson/node-fs-extra/pull/256      "Updated Readme "
+[#255]: https://github.com/jprichardson/node-fs-extra/issues/255    "Update rimraf required version"
+[#254]: https://github.com/jprichardson/node-fs-extra/issues/254    "request for readTree, readTreeSync, walkSync method"
+[#253]: https://github.com/jprichardson/node-fs-extra/issues/253    "outputFile does not touch mtime when file exists"
+[#252]: https://github.com/jprichardson/node-fs-extra/pull/252      "Fixing problem when copying file with no write permission"
+[#251]: https://github.com/jprichardson/node-fs-extra/issues/251    "Just wanted to say thank you"
+[#250]: https://github.com/jprichardson/node-fs-extra/issues/250    "`fs.remove()` not removing files (works with `rm -rf`)"
+[#249]: https://github.com/jprichardson/node-fs-extra/issues/249    "Just a Question ... Remove Servers"
+[#248]: https://github.com/jprichardson/node-fs-extra/issues/248    "Allow option to not preserve permissions for copy"
+[#247]: https://github.com/jprichardson/node-fs-extra/issues/247    "Add TypeScript typing directly in the fs-extra package"
+[#246]: https://github.com/jprichardson/node-fs-extra/issues/246    "fse.remove() && fse.removeSync() don't throw error on ENOENT file"
+[#245]: https://github.com/jprichardson/node-fs-extra/issues/245    "filter for empty dir [enhancement]"
+[#244]: https://github.com/jprichardson/node-fs-extra/issues/244    "copySync doesn't apply the filter to directories"
+[#243]: https://github.com/jprichardson/node-fs-extra/issues/243    "Can I request fs.walk() to be synchronous?"
+[#242]: https://github.com/jprichardson/node-fs-extra/issues/242    "Accidentally truncates file names ending with $$ [bug, feature-copy]"
+[#241]: https://github.com/jprichardson/node-fs-extra/pull/241      "Remove link to createOutputStream"
+[#240]: https://github.com/jprichardson/node-fs-extra/issues/240    "walkSync request"
+[#239]: https://github.com/jprichardson/node-fs-extra/issues/239    "Depreciate regular expressions for copy's filter [documentation, feature-copy]"
 [#238]: https://github.com/jprichardson/node-fs-extra/issues/238    "Can't write to files while in a worker thread."
 [#237]: https://github.com/jprichardson/node-fs-extra/issues/237    ".ensureDir(..) fails silently when passed an invalid path..."
 [#236]: https://github.com/jprichardson/node-fs-extra/issues/236    "[Removed] Filed under wrong repo"
@@ -493,7 +804,7 @@ from `~` to `^`. #67
 [#62]: https://github.com/jprichardson/node-fs-extra/issues/62      "npm install fs-extra doesn't work"
 [#61]: https://github.com/jprichardson/node-fs-extra/issues/61      "No longer supports node 0.8 due to use of `^` in package.json dependencies"
 [#60]: https://github.com/jprichardson/node-fs-extra/issues/60      "chmod & chown for mkdirs"
-[#59]: https://github.com/jprichardson/node-fs-extra/issues/59      "Consider including mkdirp and making fs-extra "--use_strict" safe [question]"
+[#59]: https://github.com/jprichardson/node-fs-extra/issues/59      "Consider including mkdirp and making fs-extra '--use_strict' safe [question]"
 [#58]: https://github.com/jprichardson/node-fs-extra/issues/58      "Stack trace not included in fs.copy error"
 [#57]: https://github.com/jprichardson/node-fs-extra/issues/57      "Possible to include wildcards in delete?"
 [#56]: https://github.com/jprichardson/node-fs-extra/issues/56      "Crash when have no access to write to destination file in copy "
@@ -505,7 +816,7 @@ from `~` to `^`. #67
 [#50]: https://github.com/jprichardson/node-fs-extra/issues/50      "Replace mechanism in createFile"
 [#49]: https://github.com/jprichardson/node-fs-extra/pull/49        "update rimraf to v2.2.6"
 [#48]: https://github.com/jprichardson/node-fs-extra/issues/48      "fs.copy issue [bug]"
-[#47]: https://github.com/jprichardson/node-fs-extra/issues/47      "Bug in copy - callback called on readStream "close" - Fixed in ncp 0.5.0"
+[#47]: https://github.com/jprichardson/node-fs-extra/issues/47      "Bug in copy - callback called on readStream 'close' - Fixed in ncp 0.5.0"
 [#46]: https://github.com/jprichardson/node-fs-extra/pull/46        "update copyright year"
 [#45]: https://github.com/jprichardson/node-fs-extra/pull/45        "Added note about fse.outputFile() being the one that overwrites"
 [#44]: https://github.com/jprichardson/node-fs-extra/pull/44        "Proposal: Stream support"
@@ -535,7 +846,7 @@ from `~` to `^`. #67
 [#20]: https://github.com/jprichardson/node-fs-extra/issues/20      "fs.remove yields callback before directory is really deleted"
 [#19]: https://github.com/jprichardson/node-fs-extra/issues/19      "fs.copy err is empty array"
 [#18]: https://github.com/jprichardson/node-fs-extra/pull/18        "Exposed copyFile Function"
-[#17]: https://github.com/jprichardson/node-fs-extra/issues/17      "Use `require("graceful-fs")` if found instead of `require("fs")`"
+[#17]: https://github.com/jprichardson/node-fs-extra/issues/17      "Use `require('graceful-fs')` if found instead of `require('fs')`"
 [#16]: https://github.com/jprichardson/node-fs-extra/pull/16        "Update README.md"
 [#15]: https://github.com/jprichardson/node-fs-extra/issues/15      "Implement cp -r but sync aka copySync. [enhancement]"
 [#14]: https://github.com/jprichardson/node-fs-extra/issues/14      "fs.mkdirSync is broken in 0.3.1"

+ 1 - 1
fs-extra/LICENSE

@@ -1,6 +1,6 @@
 (The MIT License)
 
-Copyright (c) 2011-2016 JP Richardson
+Copyright (c) 2011-2017 JP Richardson
 
 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
 (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,

+ 89 - 416
fs-extra/README.md

@@ -1,18 +1,15 @@
 Node.js: fs-extra
 =================
 
-`fs-extra` adds file system methods that aren't included in the native `fs` module. It is a drop in replacement for `fs`.
+`fs-extra` adds file system methods that aren't included in the native `fs` module and adds promise support to the `fs` methods. It also uses [`graceful-fs`](https://github.com/isaacs/node-graceful-fs) to prevent `EMFILE` errors. It should be a drop in replacement for `fs`.
 
-[![npm Package](https://img.shields.io/npm/v/fs-extra.svg?style=flat-square)](https://www.npmjs.org/package/fs-extra)
-[![build status](https://api.travis-ci.org/jprichardson/node-fs-extra.svg)](http://travis-ci.org/jprichardson/node-fs-extra)
+[![npm Package](https://img.shields.io/npm/v/fs-extra.svg)](https://www.npmjs.org/package/fs-extra)
+[![License](https://img.shields.io/npm/l/express.svg)](https://github.com/jprichardson/node-fs-extra/blob/master/LICENSE)
+[![build status](https://img.shields.io/travis/jprichardson/node-fs-extra/master.svg)](http://travis-ci.org/jprichardson/node-fs-extra)
 [![windows Build status](https://img.shields.io/appveyor/ci/jprichardson/node-fs-extra/master.svg?label=windows%20build)](https://ci.appveyor.com/project/jprichardson/node-fs-extra/branch/master)
 [![downloads per month](http://img.shields.io/npm/dm/fs-extra.svg)](https://www.npmjs.org/package/fs-extra)
-[![Coverage Status](https://img.shields.io/coveralls/jprichardson/node-fs-extra.svg)](https://coveralls.io/r/jprichardson/node-fs-extra)
-
-<a href="https://github.com/feross/standard"><img src="https://cdn.rawgit.com/feross/standard/master/sticker.svg" alt="Standard JavaScript" width="100"></a>
-
-**NOTE (2016-04-28):** Node v0.10 will be unsupported 2016-10-01. Node v0.12 will be unsupported on 2017-04-01.
-
+[![Coverage Status](https://img.shields.io/coveralls/github/jprichardson/node-fs-extra/master.svg)](https://coveralls.io/github/jprichardson/node-fs-extra)
+[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
 
 Why?
 ----
@@ -25,476 +22,154 @@ I got tired of including `mkdirp`, `rimraf`, and `ncp` in most of my projects.
 Installation
 ------------
 
-    npm install --save fs-extra
+    npm install fs-extra
 
 
 
 Usage
 -----
 
-`fs-extra` is a drop in replacement for native `fs`. All methods in `fs` are unmodified and attached to `fs-extra`.
+`fs-extra` is a drop in replacement for native `fs`. All methods in `fs` are attached to `fs-extra`. All `fs` methods return promises if the callback isn't passed.
 
 You don't ever need to include the original `fs` module again:
 
 ```js
-var fs = require('fs') // this is no longer necessary
+const fs = require('fs') // this is no longer necessary
 ```
 
 you can now do this:
 
 ```js
-var fs = require('fs-extra')
+const fs = require('fs-extra')
 ```
 
 or if you prefer to make it clear that you're using `fs-extra` and not `fs`, you may want
 to name your `fs` variable `fse` like so:
 
 ```js
-var fse = require('fs-extra')
+const fse = require('fs-extra')
 ```
 
 you can also keep both, but it's redundant:
 
 ```js
-var fs = require('fs')
-var fse = require('fs-extra')
+const fs = require('fs')
+const fse = require('fs-extra')
 ```
 
-Sync vs Async
+Sync vs Async vs Async/Await
 -------------
-Most methods are async by default (they take a callback with an `Error` as first argument).
+Most methods are async by default. All async methods will return a promise if the callback isn't passed.
 
 Sync methods on the other hand will throw if an error occurs.
 
-Example:
-
-```js
-var fs = require('fs-extra')
-
-fs.copy('/tmp/myfile', '/tmp/mynewfile', function (err) {
-  if (err) return console.error(err)
-  console.log("success!")
-});
-
-try {
-  fs.copySync('/tmp/myfile', '/tmp/mynewfile')
-  console.log("success!")
-} catch (err) {
-  console.error(err)
-}
-```
-
-
-Methods
--------
-- [copy](#copy)
-- [copySync](#copy)
-- [emptyDir](#emptydirdir-callback)
-- [emptyDirSync](#emptydirdir-callback)
-- [ensureFile](#ensurefilefile-callback)
-- [ensureFileSync](#ensurefilefile-callback)
-- [ensureDir](#ensuredirdir-callback)
-- [ensureDirSync](#ensuredirdir-callback)
-- [ensureLink](#ensurelinksrcpath-dstpath-callback)
-- [ensureLinkSync](#ensurelinksrcpath-dstpath-callback)
-- [ensureSymlink](#ensuresymlinksrcpath-dstpath-type-callback)
-- [ensureSymlinkSync](#ensuresymlinksrcpath-dstpath-type-callback)
-- [mkdirs](#mkdirsdir-callback)
-- [mkdirsSync](#mkdirsdir-callback)
-- [move](#movesrc-dest-options-callback)
-- [outputFile](#outputfilefile-data-options-callback)
-- [outputFileSync](#outputfilefile-data-options-callback)
-- [outputJson](#outputjsonfile-data-options-callback)
-- [outputJsonSync](#outputjsonfile-data-options-callback)
-- [readJson](#readjsonfile-options-callback)
-- [readJsonSync](#readjsonfile-options-callback)
-- [remove](#removedir-callback)
-- [removeSync](#removedir-callback)
-- [walk](#walk)
-- [writeJson](#writejsonfile-object-options-callback)
-- [writeJsonSync](#writejsonfile-object-options-callback)
-
-
-**NOTE:** You can still use the native Node.js methods. They are copied over to `fs-extra`.
-
-
-### copy()
-
-**copy(src, dest, [options], callback)**
-
-
-Copy a file or directory. The directory can have contents. Like `cp -r`.
-
-Options:
-- clobber (boolean): overwrite existing file or directory
-- dereference (boolean): dereference symlinks
-- preserveTimestamps (boolean): will set last modification and access times to the ones of the original source files, default is `false`.
-- filter: Function or RegExp to filter copied files. If function, return true to include, false to exclude. If RegExp, same as function, where `filter` is `filter.test`.
-
-Sync: `copySync()`
+Also Async/Await will throw an error if one occurs.
 
 Example:
 
 ```js
-var fs = require('fs-extra')
+const fs = require('fs-extra')
 
-fs.copy('/tmp/myfile', '/tmp/mynewfile', function (err) {
-  if (err) return console.error(err)
-  console.log("success!")
-}) // copies file
+// Async with promises:
+fs.copy('/tmp/myfile', '/tmp/mynewfile')
+  .then(() => console.log('success!'))
+  .catch(err => console.error(err))
 
-fs.copy('/tmp/mydir', '/tmp/mynewdir', function (err) {
+// Async with callbacks:
+fs.copy('/tmp/myfile', '/tmp/mynewfile', err => {
   if (err) return console.error(err)
   console.log('success!')
-}) // copies directory, even if it has subdirectories or files
-```
-
-
-### emptyDir(dir, [callback])
-
-Ensures that a directory is empty. Deletes directory contents if the directory is not empty. If the directory does not exist, it is created. The directory itself is not deleted.
-
-Alias: `emptydir()`
-
-Sync: `emptyDirSync()`, `emptydirSync()`
-
-Example:
-
-```js
-var fs = require('fs-extra')
-
-// assume this directory has a lot of files and folders
-fs.emptyDir('/tmp/some/dir', function (err) {
-  if (!err) console.log('success!')
 })
-```
-
-
-### ensureFile(file, callback)
-
-Ensures that the file exists. If the file that is requested to be created is in directories that do not exist, these directories are created. If the file already exists, it is **NOT MODIFIED**.
-
-Alias: `createFile()`
-
-Sync: `createFileSync()`,`ensureFileSync()`
-
-
-Example:
-
-```js
-var fs = require('fs-extra')
-
-var file = '/tmp/this/path/does/not/exist/file.txt'
-fs.ensureFile(file, function (err) {
-  console.log(err) // => null
-  // file has now been created, including the directory it is to be placed in
-})
-```
-
-
-### ensureDir(dir, callback)
-
-Ensures that the directory exists. If the directory structure does not exist, it is created.
-
-Sync: `ensureDirSync()`
-
-
-Example:
-
-```js
-var fs = require('fs-extra')
-
-var dir = '/tmp/this/path/does/not/exist'
-fs.ensureDir(dir, function (err) {
-  console.log(err) // => null
-  // dir has now been created, including the directory it is to be placed in
-})
-```
-
-
-### ensureLink(srcpath, dstpath, callback)
-
-Ensures that the link exists. If the directory structure does not exist, it is created.
-
-Sync: `ensureLinkSync()`
-
-
-Example:
-
-```js
-var fs = require('fs-extra')
-
-var srcpath = '/tmp/file.txt'
-var dstpath = '/tmp/this/path/does/not/exist/file.txt'
-fs.ensureLink(srcpath, dstpath, function (err) {
-  console.log(err) // => null
-  // link has now been created, including the directory it is to be placed in
-})
-```
-
-
-### ensureSymlink(srcpath, dstpath, [type], callback)
-
-Ensures that the symlink exists. If the directory structure does not exist, it is created.
-
-Sync: `ensureSymlinkSync()`
-
-
-Example:
-
-```js
-var fs = require('fs-extra')
-
-var srcpath = '/tmp/file.txt'
-var dstpath = '/tmp/this/path/does/not/exist/file.txt'
-fs.ensureSymlink(srcpath, dstpath, function (err) {
-  console.log(err) // => null
-  // symlink has now been created, including the directory it is to be placed in
-})
-```
-
-
-### mkdirs(dir, callback)
-
-Creates a directory. If the parent hierarchy doesn't exist, it's created. Like `mkdir -p`.
-
-Alias: `mkdirp()`
-
-Sync: `mkdirsSync()` / `mkdirpSync()`
-
-
-Examples:
-
-```js
-var fs = require('fs-extra')
-
-fs.mkdirs('/tmp/some/long/path/that/prob/doesnt/exist', function (err) {
-  if (err) return console.error(err)
-  console.log("success!")
-})
-
-fs.mkdirsSync('/tmp/another/path')
-```
-
-
-### move(src, dest, [options], callback)
-
-Moves a file or directory, even across devices.
-
-Options:
-- clobber (boolean): overwrite existing file or directory
-- limit (number): number of concurrent moves, see ncp for more information
-
-Example:
-
-```js
-var fs = require('fs-extra')
-
-fs.move('/tmp/somefile', '/tmp/does/not/exist/yet/somefile', function (err) {
-  if (err) return console.error(err)
-  console.log("success!")
-})
-```
-
-
-### outputFile(file, data, [options], callback)
-
-Almost the same as `writeFile` (i.e. it [overwrites](http://pages.citebite.com/v2o5n8l2f5reb)), except that if the parent directory does not exist, it's created. `options` are what you'd pass to [`fs.writeFile()`](https://nodejs.org/api/fs.html#fs_fs_writefile_file_data_options_callback).
-
-Sync: `outputFileSync()`
-
-
-Example:
-
-```js
-var fs = require('fs-extra')
-var file = '/tmp/this/path/does/not/exist/file.txt'
-
-fs.outputFile(file, 'hello!', function (err) {
-  console.log(err) // => null
-
-  fs.readFile(file, 'utf8', function (err, data) {
-    console.log(data) // => hello!
-  })
-})
-```
-
-
-
-### outputJson(file, data, [options], callback)
-
-Almost the same as `writeJson`, except that if the directory does not exist, it's created.
-`options` are what you'd pass to [`jsonFile.writeFile()`](https://github.com/jprichardson/node-jsonfile#writefilefilename-options-callback).
-
-Alias: `outputJSON()`
-
-Sync: `outputJsonSync()`, `outputJSONSync()`
-
-
-Example:
-
-```js
-var fs = require('fs-extra')
-var file = '/tmp/this/path/does/not/exist/file.txt'
-
-fs.outputJson(file, {name: 'JP'}, function (err) {
-  console.log(err) // => null
-
-  fs.readJson(file, function(err, data) {
-    console.log(data.name) // => JP
-  })
-})
-```
-
-
-
-### readJson(file, [options], callback)
-
-Reads a JSON file and then parses it into an object. `options` are the same
-that you'd pass to [`jsonFile.readFile`](https://github.com/jprichardson/node-jsonfile#readfilefilename-options-callback).
-
-Alias: `readJSON()`
-
-Sync: `readJsonSync()`, `readJSONSync()`
-
-
-Example:
-
-```js
-var fs = require('fs-extra')
-
-fs.readJson('./package.json', function (err, packageObj) {
-  console.log(packageObj.version) // => 0.1.3
-})
-```
-
-`readJsonSync()` can take a `throws` option set to `false` and it won't throw if the JSON is invalid. Example:
-
-```js
-var fs = require('fs-extra')
-var file = path.join('/tmp/some-invalid.json')
-var data = '{not valid JSON'
-fs.writeFileSync(file, data)
-
-var obj = fs.readJsonSync(file, {throws: false})
-console.log(obj) // => null
-```
-
-
-### remove(dir, callback)
-
-Removes a file or directory. The directory can have contents. Like `rm -rf`.
-
-Sync: `removeSync()`
-
-
-Examples:
-
-```js
-var fs = require('fs-extra')
-
-fs.remove('/tmp/myfile', function (err) {
-  if (err) return console.error(err)
 
+// Sync:
+try {
+  fs.copySync('/tmp/myfile', '/tmp/mynewfile')
   console.log('success!')
-})
-
-fs.removeSync('/home/jprichardson') //I just deleted my entire HOME directory.
-```
-
-### walk()
-
-**walk(dir, [streamOptions])**
-
-The function `walk()` from the module [`klaw`](https://github.com/jprichardson/node-klaw).
-
-Returns a [Readable stream](https://nodejs.org/api/stream.html#stream_class_stream_readable) that iterates
-through every file and directory starting with `dir` as the root. Every `read()` or `data` event
-returns an object with two properties: `path` and `stats`. `path` is the full path of the file and
-`stats` is an instance of [fs.Stats](https://nodejs.org/api/fs.html#fs_class_fs_stats).
-
-Streams 1 (push) example:
-
-```js
-var items = [] // files, directories, symlinks, etc
-fse.walk(TEST_DIR)
-  .on('data', function (item) {
-    items.push(item.path)
-  })
-  .on('end', function () {
-    console.dir(items) // => [ ... array of files]
-  })
-```
+} catch (err) {
+  console.error(err)
+}
 
-Streams 2 & 3 (pull) example:
+// Async/Await:
+async function copyFiles () {
+  try {
+    await fs.copy('/tmp/myfile', '/tmp/mynewfile')
+    console.log('success!')
+  } catch (err) {
+    console.error(err)
+  }
+}
 
-```js
-var items = [] // files, directories, symlinks, etc
-fse.walk(TEST_DIR)
-  .on('readable', function () {
-    var item
-    while ((item = this.read())) {
-      items.push(item.path)
-    }
-  })
-  .on('end', function () {
-    console.dir(items) // => [ ... array of files]
-  })
+copyFiles()
 ```
 
-If you're not sure of the differences on Node.js streams 1, 2, 3 then I'd
-recommend this resource as a good starting point: https://strongloop.com/strongblog/whats-new-io-js-beta-streams3/.
-
-**See [`klaw` documentation](https://github.com/jprichardson/node-klaw) for more detailed usage.**
 
+Methods
+-------
 
-### writeJson(file, object, [options], callback)
-
-Writes an object to a JSON file. `options` are the same that
-you'd pass to [`jsonFile.writeFile()`](https://github.com/jprichardson/node-jsonfile#writefilefilename-options-callback).
-
-Alias: `writeJSON()`
-
-Sync: `writeJsonSync()`, `writeJSONSync()`
-
-Example:
-
-```js
-var fs = require('fs-extra')
-fs.writeJson('./package.json', {name: 'fs-extra'}, function (err) {
-  console.log(err)
-})
-```
+### Async
+
+- [copy](docs/copy.md)
+- [emptyDir](docs/emptyDir.md)
+- [ensureFile](docs/ensureFile.md)
+- [ensureDir](docs/ensureDir.md)
+- [ensureLink](docs/ensureLink.md)
+- [ensureSymlink](docs/ensureSymlink.md)
+- [mkdirp](docs/ensureDir.md)
+- [mkdirs](docs/ensureDir.md)
+- [move](docs/move.md)
+- [outputFile](docs/outputFile.md)
+- [outputJson](docs/outputJson.md)
+- [pathExists](docs/pathExists.md)
+- [readJson](docs/readJson.md)
+- [remove](docs/remove.md)
+- [writeJson](docs/writeJson.md)
+
+### Sync
+
+- [copySync](docs/copy-sync.md)
+- [emptyDirSync](docs/emptyDir-sync.md)
+- [ensureFileSync](docs/ensureFile-sync.md)
+- [ensureDirSync](docs/ensureDir-sync.md)
+- [ensureLinkSync](docs/ensureLink-sync.md)
+- [ensureSymlinkSync](docs/ensureSymlink-sync.md)
+- [mkdirpSync](docs/ensureDir-sync.md)
+- [mkdirsSync](docs/ensureDir-sync.md)
+- [moveSync](docs/move-sync.md)
+- [outputFileSync](docs/outputFile-sync.md)
+- [outputJsonSync](docs/outputJson-sync.md)
+- [pathExistsSync](docs/pathExists-sync.md)
+- [readJsonSync](docs/readJson-sync.md)
+- [removeSync](docs/remove-sync.md)
+- [writeJsonSync](docs/writeJson-sync.md)
+
+
+**NOTE:** You can still use the native Node.js methods. They are promisified and copied over to `fs-extra`. See [notes on `fs.read()` & `fs.write()`](docs/fs-read-write.md)
+
+### What happened to `walk()` and `walkSync()`?
+
+They were removed from `fs-extra` in v2.0.0. If you need the functionality, `walk` and `walkSync` are available as separate packages, [`klaw`](https://github.com/jprichardson/node-klaw) and [`klaw-sync`](https://github.com/manidlou/node-klaw-sync).
 
 
 Third Party
 -----------
 
-### Promises
-
-Use [Bluebird](https://github.com/petkaantonov/bluebird). See https://github.com/petkaantonov/bluebird/blob/master/API.md#promisification. `fs-extra` is
-explicitly listed as supported.
-
-```js
-var Promise = require('bluebird')
-var fs = Promise.promisifyAll(require('fs-extra'))
-```
-
-Or you can use the package [`fs-extra-promise`](https://github.com/overlookmotel/fs-extra-promise) that marries the two together.
-
 
 ### TypeScript
 
-If you like TypeScript, you can use `fs-extra` with it: https://github.com/borisyankov/DefinitelyTyped/tree/master/fs-extra
+If you like TypeScript, you can use `fs-extra` with it: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/fs-extra
 
 
 ### File / Directory Watching
 
 If you want to watch for changes to files or directories, then you should use [chokidar](https://github.com/paulmillr/chokidar).
 
+### Obtain Filesystem (Devices, Partitions) Information
+
+[fs-filesystem](https://github.com/arthurintelligence/node-fs-filesystem) allows you to read the state of the filesystem of the host on which it is run. It returns information about both the devices and the partitions (volumes) of the system.
 
 ### Misc.
 
+- [fs-extra-debug](https://github.com/jdxcode/fs-extra-debug) - Send your fs-extra calls to [debug](https://npmjs.org/package/debug).
 - [mfs](https://github.com/cadorn/mfs) - Monitor your fs-extra calls.
 
 
@@ -512,8 +187,6 @@ What's needed?
 - First, take a look at existing issues. Those are probably going to be where the priority lies.
 - More tests for edge cases. Specifically on different platforms. There can never be enough tests.
 - Improve test coverage. See coveralls output for more info.
-- After the directory walker is integrated, any function that needs to traverse directories like
-`copy`, `remove`, or `mkdirs` should be built on top of it.
 
 Note: If you make any big changes, **you should definitely file an issue for discussion first.**
 
@@ -580,7 +253,7 @@ License
 
 Licensed under MIT
 
-Copyright (c) 2011-2016 [JP Richardson](https://github.com/jprichardson)
+Copyright (c) 2011-2017 [JP Richardson](https://github.com/jprichardson)
 
 [1]: http://nodejs.org/docs/latest/api/fs.html
 

+ 151 - 35
fs-extra/lib/copy-sync/copy-sync.js

@@ -1,48 +1,164 @@
-var fs = require('graceful-fs')
-var path = require('path')
-var copyFileSync = require('./copy-file-sync')
-var mkdir = require('../mkdirs')
+'use strict'
 
-function copySync (src, dest, options) {
-  if (typeof options === 'function' || options instanceof RegExp) {
-    options = {filter: options}
+const fs = require('graceful-fs')
+const path = require('path')
+const mkdirpSync = require('../mkdirs').mkdirsSync
+const utimesSync = require('../util/utimes.js').utimesMillisSync
+const stat = require('../util/stat')
+
+function copySync (src, dest, opts) {
+  if (typeof opts === 'function') {
+    opts = { filter: opts }
   }
 
-  options = options || {}
-  options.recursive = !!options.recursive
+  opts = opts || {}
+  opts.clobber = 'clobber' in opts ? !!opts.clobber : true // default to true for now
+  opts.overwrite = 'overwrite' in opts ? !!opts.overwrite : opts.clobber // overwrite falls back to clobber
+
+  // Warn about using preserveTimestamps on 32-bit node
+  if (opts.preserveTimestamps && process.arch === 'ia32') {
+    console.warn(`fs-extra: Using the preserveTimestamps option in 32-bit node is not recommended;\n
+    see https://github.com/jprichardson/node-fs-extra/issues/269`)
+  }
 
-  // default to true for now
-  options.clobber = 'clobber' in options ? !!options.clobber : true
-  options.dereference = 'dereference' in options ? !!options.dereference : false
-  options.preserveTimestamps = 'preserveTimestamps' in options ? !!options.preserveTimestamps : false
+  const { srcStat, destStat } = stat.checkPathsSync(src, dest, 'copy')
+  stat.checkParentPathsSync(src, srcStat, dest, 'copy')
+  return handleFilterAndCopy(destStat, src, dest, opts)
+}
 
-  options.filter = options.filter || function () { return true }
+function handleFilterAndCopy (destStat, src, dest, opts) {
+  if (opts.filter && !opts.filter(src, dest)) return
+  const destParent = path.dirname(dest)
+  if (!fs.existsSync(destParent)) mkdirpSync(destParent)
+  return startCopy(destStat, src, dest, opts)
+}
 
-  var stats = (options.recursive && !options.dereference) ? fs.lstatSync(src) : fs.statSync(src)
-  var destFolder = path.dirname(dest)
-  var destFolderExists = fs.existsSync(destFolder)
-  var performCopy = false
+function startCopy (destStat, src, dest, opts) {
+  if (opts.filter && !opts.filter(src, dest)) return
+  return getStats(destStat, src, dest, opts)
+}
 
-  if (stats.isFile()) {
-    if (options.filter instanceof RegExp) performCopy = options.filter.test(src)
-    else if (typeof options.filter === 'function') performCopy = options.filter(src)
+function getStats (destStat, src, dest, opts) {
+  const statSync = opts.dereference ? fs.statSync : fs.lstatSync
+  const srcStat = statSync(src)
 
-    if (performCopy) {
-      if (!destFolderExists) mkdir.mkdirsSync(destFolder)
-      copyFileSync(src, dest, {clobber: options.clobber, preserveTimestamps: options.preserveTimestamps})
+  if (srcStat.isDirectory()) return onDir(srcStat, destStat, src, dest, opts)
+  else if (srcStat.isFile() ||
+           srcStat.isCharacterDevice() ||
+           srcStat.isBlockDevice()) return onFile(srcStat, destStat, src, dest, opts)
+  else if (srcStat.isSymbolicLink()) return onLink(destStat, src, dest, opts)
+}
+
+function onFile (srcStat, destStat, src, dest, opts) {
+  if (!destStat) return copyFile(srcStat, src, dest, opts)
+  return mayCopyFile(srcStat, src, dest, opts)
+}
+
+function mayCopyFile (srcStat, src, dest, opts) {
+  if (opts.overwrite) {
+    fs.unlinkSync(dest)
+    return copyFile(srcStat, src, dest, opts)
+  } else if (opts.errorOnExist) {
+    throw new Error(`'${dest}' already exists`)
+  }
+}
+
+function copyFile (srcStat, src, dest, opts) {
+  if (typeof fs.copyFileSync === 'function') {
+    fs.copyFileSync(src, dest)
+    fs.chmodSync(dest, srcStat.mode)
+    if (opts.preserveTimestamps) {
+      return utimesSync(dest, srcStat.atime, srcStat.mtime)
     }
-  } else if (stats.isDirectory()) {
-    if (!fs.existsSync(dest)) mkdir.mkdirsSync(dest)
-    var contents = fs.readdirSync(src)
-    contents.forEach(function (content) {
-      var opts = options
-      opts.recursive = true
-      copySync(path.join(src, content), path.join(dest, content), opts)
-    })
-  } else if (options.recursive && stats.isSymbolicLink()) {
-    var srcPath = fs.readlinkSync(src)
-    fs.symlinkSync(srcPath, dest)
+    return
+  }
+  return copyFileFallback(srcStat, src, dest, opts)
+}
+
+function copyFileFallback (srcStat, src, dest, opts) {
+  const BUF_LENGTH = 64 * 1024
+  const _buff = require('../util/buffer')(BUF_LENGTH)
+
+  const fdr = fs.openSync(src, 'r')
+  const fdw = fs.openSync(dest, 'w', srcStat.mode)
+  let pos = 0
+
+  while (pos < srcStat.size) {
+    const bytesRead = fs.readSync(fdr, _buff, 0, BUF_LENGTH, pos)
+    fs.writeSync(fdw, _buff, 0, bytesRead)
+    pos += bytesRead
   }
+
+  if (opts.preserveTimestamps) fs.futimesSync(fdw, srcStat.atime, srcStat.mtime)
+
+  fs.closeSync(fdr)
+  fs.closeSync(fdw)
+}
+
+function onDir (srcStat, destStat, src, dest, opts) {
+  if (!destStat) return mkDirAndCopy(srcStat, src, dest, opts)
+  if (destStat && !destStat.isDirectory()) {
+    throw new Error(`Cannot overwrite non-directory '${dest}' with directory '${src}'.`)
+  }
+  return copyDir(src, dest, opts)
+}
+
+function mkDirAndCopy (srcStat, src, dest, opts) {
+  fs.mkdirSync(dest)
+  copyDir(src, dest, opts)
+  return fs.chmodSync(dest, srcStat.mode)
+}
+
+function copyDir (src, dest, opts) {
+  fs.readdirSync(src).forEach(item => copyDirItem(item, src, dest, opts))
+}
+
+function copyDirItem (item, src, dest, opts) {
+  const srcItem = path.join(src, item)
+  const destItem = path.join(dest, item)
+  const { destStat } = stat.checkPathsSync(srcItem, destItem, 'copy')
+  return startCopy(destStat, srcItem, destItem, opts)
+}
+
+function onLink (destStat, src, dest, opts) {
+  let resolvedSrc = fs.readlinkSync(src)
+  if (opts.dereference) {
+    resolvedSrc = path.resolve(process.cwd(), resolvedSrc)
+  }
+
+  if (!destStat) {
+    return fs.symlinkSync(resolvedSrc, dest)
+  } else {
+    let resolvedDest
+    try {
+      resolvedDest = fs.readlinkSync(dest)
+    } catch (err) {
+      // dest exists and is a regular file or directory,
+      // Windows may throw UNKNOWN error. If dest already exists,
+      // fs throws error anyway, so no need to guard against it here.
+      if (err.code === 'EINVAL' || err.code === 'UNKNOWN') return fs.symlinkSync(resolvedSrc, dest)
+      throw err
+    }
+    if (opts.dereference) {
+      resolvedDest = path.resolve(process.cwd(), resolvedDest)
+    }
+    if (stat.isSrcSubdir(resolvedSrc, resolvedDest)) {
+      throw new Error(`Cannot copy '${resolvedSrc}' to a subdirectory of itself, '${resolvedDest}'.`)
+    }
+
+    // prevent copy if src is a subdir of dest since unlinking
+    // dest in this case would result in removing src contents
+    // and therefore a broken symlink would be created.
+    if (fs.statSync(dest).isDirectory() && stat.isSrcSubdir(resolvedDest, resolvedSrc)) {
+      throw new Error(`Cannot overwrite '${resolvedDest}' with '${resolvedSrc}'.`)
+    }
+    return copyLink(resolvedSrc, dest)
+  }
+}
+
+function copyLink (resolvedSrc, dest) {
+  fs.unlinkSync(dest)
+  return fs.symlinkSync(resolvedSrc, dest)
 }
 
 module.exports = copySync

+ 2 - 0
fs-extra/lib/copy-sync/index.js

@@ -1,3 +1,5 @@
+'use strict'
+
 module.exports = {
   copySync: require('./copy-sync')
 }

+ 204 - 36
fs-extra/lib/copy/copy.js

@@ -1,44 +1,212 @@
-var fs = require('graceful-fs')
-var path = require('path')
-var ncp = require('./ncp')
-var mkdir = require('../mkdirs')
-
-function copy (src, dest, options, callback) {
-  if (typeof options === 'function' && !callback) {
-    callback = options
-    options = {}
-  } else if (typeof options === 'function' || options instanceof RegExp) {
-    options = {filter: options}
+'use strict'
+
+const fs = require('graceful-fs')
+const path = require('path')
+const mkdirp = require('../mkdirs').mkdirs
+const pathExists = require('../path-exists').pathExists
+const utimes = require('../util/utimes').utimesMillis
+const stat = require('../util/stat')
+
+function copy (src, dest, opts, cb) {
+  if (typeof opts === 'function' && !cb) {
+    cb = opts
+    opts = {}
+  } else if (typeof opts === 'function') {
+    opts = { filter: opts }
   }
-  callback = callback || function () {}
-  options = options || {}
-
-  // don't allow src and dest to be the same
-  var basePath = process.cwd()
-  var currentPath = path.resolve(basePath, src)
-  var targetPath = path.resolve(basePath, dest)
-  if (currentPath === targetPath) return callback(new Error('Source and destination must not be the same.'))
-
-  fs.lstat(src, function (err, stats) {
-    if (err) return callback(err)
-
-    var dir = null
-    if (stats.isDirectory()) {
-      var parts = dest.split(path.sep)
-      parts.pop()
-      dir = parts.join(path.sep)
-    } else {
-      dir = path.dirname(dest)
+
+  cb = cb || function () {}
+  opts = opts || {}
+
+  opts.clobber = 'clobber' in opts ? !!opts.clobber : true // default to true for now
+  opts.overwrite = 'overwrite' in opts ? !!opts.overwrite : opts.clobber // overwrite falls back to clobber
+
+  // Warn about using preserveTimestamps on 32-bit node
+  if (opts.preserveTimestamps && process.arch === 'ia32') {
+    console.warn(`fs-extra: Using the preserveTimestamps option in 32-bit node is not recommended;\n
+    see https://github.com/jprichardson/node-fs-extra/issues/269`)
+  }
+
+  stat.checkPaths(src, dest, 'copy', (err, stats) => {
+    if (err) return cb(err)
+    const { srcStat, destStat } = stats
+    stat.checkParentPaths(src, srcStat, dest, 'copy', err => {
+      if (err) return cb(err)
+      if (opts.filter) return handleFilter(checkParentDir, destStat, src, dest, opts, cb)
+      return checkParentDir(destStat, src, dest, opts, cb)
+    })
+  })
+}
+
+function checkParentDir (destStat, src, dest, opts, cb) {
+  const destParent = path.dirname(dest)
+  pathExists(destParent, (err, dirExists) => {
+    if (err) return cb(err)
+    if (dirExists) return startCopy(destStat, src, dest, opts, cb)
+    mkdirp(destParent, err => {
+      if (err) return cb(err)
+      return startCopy(destStat, src, dest, opts, cb)
+    })
+  })
+}
+
+function handleFilter (onInclude, destStat, src, dest, opts, cb) {
+  Promise.resolve(opts.filter(src, dest)).then(include => {
+    if (include) return onInclude(destStat, src, dest, opts, cb)
+    return cb()
+  }, error => cb(error))
+}
+
+function startCopy (destStat, src, dest, opts, cb) {
+  if (opts.filter) return handleFilter(getStats, destStat, src, dest, opts, cb)
+  return getStats(destStat, src, dest, opts, cb)
+}
+
+function getStats (destStat, src, dest, opts, cb) {
+  const stat = opts.dereference ? fs.stat : fs.lstat
+  stat(src, (err, srcStat) => {
+    if (err) return cb(err)
+
+    if (srcStat.isDirectory()) return onDir(srcStat, destStat, src, dest, opts, cb)
+    else if (srcStat.isFile() ||
+             srcStat.isCharacterDevice() ||
+             srcStat.isBlockDevice()) return onFile(srcStat, destStat, src, dest, opts, cb)
+    else if (srcStat.isSymbolicLink()) return onLink(destStat, src, dest, opts, cb)
+  })
+}
+
+function onFile (srcStat, destStat, src, dest, opts, cb) {
+  if (!destStat) return copyFile(srcStat, src, dest, opts, cb)
+  return mayCopyFile(srcStat, src, dest, opts, cb)
+}
+
+function mayCopyFile (srcStat, src, dest, opts, cb) {
+  if (opts.overwrite) {
+    fs.unlink(dest, err => {
+      if (err) return cb(err)
+      return copyFile(srcStat, src, dest, opts, cb)
+    })
+  } else if (opts.errorOnExist) {
+    return cb(new Error(`'${dest}' already exists`))
+  } else return cb()
+}
+
+function copyFile (srcStat, src, dest, opts, cb) {
+  if (typeof fs.copyFile === 'function') {
+    return fs.copyFile(src, dest, err => {
+      if (err) return cb(err)
+      return setDestModeAndTimestamps(srcStat, dest, opts, cb)
+    })
+  }
+  return copyFileFallback(srcStat, src, dest, opts, cb)
+}
+
+function copyFileFallback (srcStat, src, dest, opts, cb) {
+  const rs = fs.createReadStream(src)
+  rs.on('error', err => cb(err)).once('open', () => {
+    const ws = fs.createWriteStream(dest, { mode: srcStat.mode })
+    ws.on('error', err => cb(err))
+      .on('open', () => rs.pipe(ws))
+      .once('close', () => setDestModeAndTimestamps(srcStat, dest, opts, cb))
+  })
+}
+
+function setDestModeAndTimestamps (srcStat, dest, opts, cb) {
+  fs.chmod(dest, srcStat.mode, err => {
+    if (err) return cb(err)
+    if (opts.preserveTimestamps) {
+      return utimes(dest, srcStat.atime, srcStat.mtime, cb)
     }
+    return cb()
+  })
+}
 
-    fs.exists(dir, function (dirExists) {
-      if (dirExists) return ncp(src, dest, options, callback)
-      mkdir.mkdirs(dir, function (err) {
-        if (err) return callback(err)
-        ncp(src, dest, options, callback)
-      })
+function onDir (srcStat, destStat, src, dest, opts, cb) {
+  if (!destStat) return mkDirAndCopy(srcStat, src, dest, opts, cb)
+  if (destStat && !destStat.isDirectory()) {
+    return cb(new Error(`Cannot overwrite non-directory '${dest}' with directory '${src}'.`))
+  }
+  return copyDir(src, dest, opts, cb)
+}
+
+function mkDirAndCopy (srcStat, src, dest, opts, cb) {
+  fs.mkdir(dest, err => {
+    if (err) return cb(err)
+    copyDir(src, dest, opts, err => {
+      if (err) return cb(err)
+      return fs.chmod(dest, srcStat.mode, cb)
     })
   })
 }
 
+function copyDir (src, dest, opts, cb) {
+  fs.readdir(src, (err, items) => {
+    if (err) return cb(err)
+    return copyDirItems(items, src, dest, opts, cb)
+  })
+}
+
+function copyDirItems (items, src, dest, opts, cb) {
+  const item = items.pop()
+  if (!item) return cb()
+  return copyDirItem(items, item, src, dest, opts, cb)
+}
+
+function copyDirItem (items, item, src, dest, opts, cb) {
+  const srcItem = path.join(src, item)
+  const destItem = path.join(dest, item)
+  stat.checkPaths(srcItem, destItem, 'copy', (err, stats) => {
+    if (err) return cb(err)
+    const { destStat } = stats
+    startCopy(destStat, srcItem, destItem, opts, err => {
+      if (err) return cb(err)
+      return copyDirItems(items, src, dest, opts, cb)
+    })
+  })
+}
+
+function onLink (destStat, src, dest, opts, cb) {
+  fs.readlink(src, (err, resolvedSrc) => {
+    if (err) return cb(err)
+    if (opts.dereference) {
+      resolvedSrc = path.resolve(process.cwd(), resolvedSrc)
+    }
+
+    if (!destStat) {
+      return fs.symlink(resolvedSrc, dest, cb)
+    } else {
+      fs.readlink(dest, (err, resolvedDest) => {
+        if (err) {
+          // dest exists and is a regular file or directory,
+          // Windows may throw UNKNOWN error. If dest already exists,
+          // fs throws error anyway, so no need to guard against it here.
+          if (err.code === 'EINVAL' || err.code === 'UNKNOWN') return fs.symlink(resolvedSrc, dest, cb)
+          return cb(err)
+        }
+        if (opts.dereference) {
+          resolvedDest = path.resolve(process.cwd(), resolvedDest)
+        }
+        if (stat.isSrcSubdir(resolvedSrc, resolvedDest)) {
+          return cb(new Error(`Cannot copy '${resolvedSrc}' to a subdirectory of itself, '${resolvedDest}'.`))
+        }
+
+        // do not copy if src is a subdir of dest since unlinking
+        // dest in this case would result in removing src contents
+        // and therefore a broken symlink would be created.
+        if (destStat.isDirectory() && stat.isSrcSubdir(resolvedDest, resolvedSrc)) {
+          return cb(new Error(`Cannot overwrite '${resolvedDest}' with '${resolvedSrc}'.`))
+        }
+        return copyLink(resolvedSrc, dest, cb)
+      })
+    }
+  })
+}
+
+function copyLink (resolvedSrc, dest, cb) {
+  fs.unlink(dest, err => {
+    if (err) return cb(err)
+    return fs.symlink(resolvedSrc, dest, cb)
+  })
+}
+
 module.exports = copy

+ 4 - 1
fs-extra/lib/copy/index.js

@@ -1,3 +1,6 @@
+'use strict'
+
+const u = require('universalify').fromCallback
 module.exports = {
-  copy: require('./copy')
+  copy: u(require('./copy'))
 }

+ 17 - 16
fs-extra/lib/empty/index.js

@@ -1,47 +1,48 @@
-var fs = require('fs')
-var path = require('path')
-var mkdir = require('../mkdirs')
-var remove = require('../remove')
+'use strict'
 
-function emptyDir (dir, callback) {
+const u = require('universalify').fromCallback
+const fs = require('graceful-fs')
+const path = require('path')
+const mkdir = require('../mkdirs')
+const remove = require('../remove')
+
+const emptyDir = u(function emptyDir (dir, callback) {
   callback = callback || function () {}
-  fs.readdir(dir, function (err, items) {
+  fs.readdir(dir, (err, items) => {
     if (err) return mkdir.mkdirs(dir, callback)
 
-    items = items.map(function (item) {
-      return path.join(dir, item)
-    })
+    items = items.map(item => path.join(dir, item))
 
     deleteItem()
 
     function deleteItem () {
-      var item = items.pop()
+      const item = items.pop()
       if (!item) return callback()
-      remove.remove(item, function (err) {
+      remove.remove(item, err => {
         if (err) return callback(err)
         deleteItem()
       })
     }
   })
-}
+})
 
 function emptyDirSync (dir) {
-  var items
+  let items
   try {
     items = fs.readdirSync(dir)
   } catch (err) {
     return mkdir.mkdirsSync(dir)
   }
 
-  items.forEach(function (item) {
+  items.forEach(item => {
     item = path.join(dir, item)
     remove.removeSync(item)
   })
 }
 
 module.exports = {
-  emptyDirSync: emptyDirSync,
+  emptyDirSync,
   emptydirSync: emptyDirSync,
-  emptyDir: emptyDir,
+  emptyDir,
   emptydir: emptyDir
 }

+ 22 - 16
fs-extra/lib/ensure/file.js

@@ -1,21 +1,26 @@
-var path = require('path')
-var fs = require('graceful-fs')
-var mkdir = require('../mkdirs')
+'use strict'
+
+const u = require('universalify').fromCallback
+const path = require('path')
+const fs = require('graceful-fs')
+const mkdir = require('../mkdirs')
+const pathExists = require('../path-exists').pathExists
 
 function createFile (file, callback) {
   function makeFile () {
-    fs.writeFile(file, '', function (err) {
+    fs.writeFile(file, '', err => {
       if (err) return callback(err)
       callback()
     })
   }
 
-  fs.exists(file, function (fileExists) {
-    if (fileExists) return callback()
-    var dir = path.dirname(file)
-    fs.exists(dir, function (dirExists) {
+  fs.stat(file, (err, stats) => { // eslint-disable-line handle-callback-err
+    if (!err && stats.isFile()) return callback()
+    const dir = path.dirname(file)
+    pathExists(dir, (err, dirExists) => {
+      if (err) return callback(err)
       if (dirExists) return makeFile()
-      mkdir.mkdirs(dir, function (err) {
+      mkdir.mkdirs(dir, err => {
         if (err) return callback(err)
         makeFile()
       })
@@ -24,9 +29,13 @@ function createFile (file, callback) {
 }
 
 function createFileSync (file) {
-  if (fs.existsSync(file)) return
+  let stats
+  try {
+    stats = fs.statSync(file)
+  } catch (e) {}
+  if (stats && stats.isFile()) return
 
-  var dir = path.dirname(file)
+  const dir = path.dirname(file)
   if (!fs.existsSync(dir)) {
     mkdir.mkdirsSync(dir)
   }
@@ -35,9 +44,6 @@ function createFileSync (file) {
 }
 
 module.exports = {
-  createFile: createFile,
-  createFileSync: createFileSync,
-  // alias
-  ensureFile: createFile,
-  ensureFileSync: createFileSync
+  createFile: u(createFile),
+  createFileSync
 }

+ 5 - 3
fs-extra/lib/ensure/index.js

@@ -1,6 +1,8 @@
-var file = require('./file')
-var link = require('./link')
-var symlink = require('./symlink')
+'use strict'
+
+const file = require('./file')
+const link = require('./link')
+const symlink = require('./symlink')
 
 module.exports = {
   // file

+ 21 - 18
fs-extra/lib/ensure/link.js

@@ -1,27 +1,33 @@
-var path = require('path')
-var fs = require('graceful-fs')
-var mkdir = require('../mkdirs')
+'use strict'
+
+const u = require('universalify').fromCallback
+const path = require('path')
+const fs = require('graceful-fs')
+const mkdir = require('../mkdirs')
+const pathExists = require('../path-exists').pathExists
 
 function createLink (srcpath, dstpath, callback) {
   function makeLink (srcpath, dstpath) {
-    fs.link(srcpath, dstpath, function (err) {
+    fs.link(srcpath, dstpath, err => {
       if (err) return callback(err)
       callback(null)
     })
   }
 
-  fs.exists(dstpath, function (destinationExists) {
+  pathExists(dstpath, (err, destinationExists) => {
+    if (err) return callback(err)
     if (destinationExists) return callback(null)
-    fs.lstat(srcpath, function (err, stat) {
+    fs.lstat(srcpath, (err) => {
       if (err) {
         err.message = err.message.replace('lstat', 'ensureLink')
         return callback(err)
       }
 
-      var dir = path.dirname(dstpath)
-      fs.exists(dir, function (dirExists) {
+      const dir = path.dirname(dstpath)
+      pathExists(dir, (err, dirExists) => {
+        if (err) return callback(err)
         if (dirExists) return makeLink(srcpath, dstpath)
-        mkdir.mkdirs(dir, function (err) {
+        mkdir.mkdirs(dir, err => {
           if (err) return callback(err)
           makeLink(srcpath, dstpath)
         })
@@ -30,8 +36,8 @@ function createLink (srcpath, dstpath, callback) {
   })
 }
 
-function createLinkSync (srcpath, dstpath, callback) {
-  var destinationExists = fs.existsSync(dstpath)
+function createLinkSync (srcpath, dstpath) {
+  const destinationExists = fs.existsSync(dstpath)
   if (destinationExists) return undefined
 
   try {
@@ -41,8 +47,8 @@ function createLinkSync (srcpath, dstpath, callback) {
     throw err
   }
 
-  var dir = path.dirname(dstpath)
-  var dirExists = fs.existsSync(dir)
+  const dir = path.dirname(dstpath)
+  const dirExists = fs.existsSync(dir)
   if (dirExists) return fs.linkSync(srcpath, dstpath)
   mkdir.mkdirsSync(dir)
 
@@ -50,9 +56,6 @@ function createLinkSync (srcpath, dstpath, callback) {
 }
 
 module.exports = {
-  createLink: createLink,
-  createLinkSync: createLinkSync,
-  // alias
-  ensureLink: createLink,
-  ensureLinkSync: createLinkSync
+  createLink: u(createLink),
+  createLinkSync
 }

+ 16 - 14
fs-extra/lib/ensure/symlink-paths.js

@@ -1,7 +1,8 @@
-var path = require('path')
-// path.isAbsolute shim for Node.js 0.10 support
-path.isAbsolute = (path.isAbsolute) ? path.isAbsolute : require('path-is-absolute')
-var fs = require('graceful-fs')
+'use strict'
+
+const path = require('path')
+const fs = require('graceful-fs')
+const pathExists = require('../path-exists').pathExists
 
 /**
  * Function that returns two types of paths, one relative to symlink, and one
@@ -27,7 +28,7 @@ var fs = require('graceful-fs')
 
 function symlinkPaths (srcpath, dstpath, callback) {
   if (path.isAbsolute(srcpath)) {
-    return fs.lstat(srcpath, function (err, stat) {
+    return fs.lstat(srcpath, (err) => {
       if (err) {
         err.message = err.message.replace('lstat', 'ensureSymlink')
         return callback(err)
@@ -38,16 +39,17 @@ function symlinkPaths (srcpath, dstpath, callback) {
       })
     })
   } else {
-    var dstdir = path.dirname(dstpath)
-    var relativeToDst = path.join(dstdir, srcpath)
-    return fs.exists(relativeToDst, function (exists) {
+    const dstdir = path.dirname(dstpath)
+    const relativeToDst = path.join(dstdir, srcpath)
+    return pathExists(relativeToDst, (err, exists) => {
+      if (err) return callback(err)
       if (exists) {
         return callback(null, {
           'toCwd': relativeToDst,
           'toDst': srcpath
         })
       } else {
-        return fs.lstat(srcpath, function (err, stat) {
+        return fs.lstat(srcpath, (err) => {
           if (err) {
             err.message = err.message.replace('lstat', 'ensureSymlink')
             return callback(err)
@@ -63,7 +65,7 @@ function symlinkPaths (srcpath, dstpath, callback) {
 }
 
 function symlinkPathsSync (srcpath, dstpath) {
-  var exists
+  let exists
   if (path.isAbsolute(srcpath)) {
     exists = fs.existsSync(srcpath)
     if (!exists) throw new Error('absolute srcpath does not exist')
@@ -72,8 +74,8 @@ function symlinkPathsSync (srcpath, dstpath) {
       'toDst': srcpath
     }
   } else {
-    var dstdir = path.dirname(dstpath)
-    var relativeToDst = path.join(dstdir, srcpath)
+    const dstdir = path.dirname(dstpath)
+    const relativeToDst = path.join(dstdir, srcpath)
     exists = fs.existsSync(relativeToDst)
     if (exists) {
       return {
@@ -92,6 +94,6 @@ function symlinkPathsSync (srcpath, dstpath) {
 }
 
 module.exports = {
-  'symlinkPaths': symlinkPaths,
-  'symlinkPathsSync': symlinkPathsSync
+  symlinkPaths,
+  symlinkPathsSync
 }

+ 9 - 5
fs-extra/lib/ensure/symlink-type.js

@@ -1,10 +1,12 @@
-var fs = require('graceful-fs')
+'use strict'
+
+const fs = require('graceful-fs')
 
 function symlinkType (srcpath, type, callback) {
   callback = (typeof type === 'function') ? type : callback
   type = (typeof type === 'function') ? false : type
   if (type) return callback(null, type)
-  fs.lstat(srcpath, function (err, stats) {
+  fs.lstat(srcpath, (err, stats) => {
     if (err) return callback(null, 'file')
     type = (stats && stats.isDirectory()) ? 'dir' : 'file'
     callback(null, type)
@@ -12,9 +14,11 @@ function symlinkType (srcpath, type, callback) {
 }
 
 function symlinkTypeSync (srcpath, type) {
+  let stats
+
   if (type) return type
   try {
-    var stats = fs.lstatSync(srcpath)
+    stats = fs.lstatSync(srcpath)
   } catch (e) {
     return 'file'
   }
@@ -22,6 +26,6 @@ function symlinkTypeSync (srcpath, type) {
 }
 
 module.exports = {
-  symlinkType: symlinkType,
-  symlinkTypeSync: symlinkTypeSync
+  symlinkType,
+  symlinkTypeSync
 }

+ 31 - 30
fs-extra/lib/ensure/symlink.js

@@ -1,32 +1,39 @@
-var path = require('path')
-var fs = require('graceful-fs')
-var _mkdirs = require('../mkdirs')
-var mkdirs = _mkdirs.mkdirs
-var mkdirsSync = _mkdirs.mkdirsSync
+'use strict'
 
-var _symlinkPaths = require('./symlink-paths')
-var symlinkPaths = _symlinkPaths.symlinkPaths
-var symlinkPathsSync = _symlinkPaths.symlinkPathsSync
+const u = require('universalify').fromCallback
+const path = require('path')
+const fs = require('graceful-fs')
+const _mkdirs = require('../mkdirs')
+const mkdirs = _mkdirs.mkdirs
+const mkdirsSync = _mkdirs.mkdirsSync
 
-var _symlinkType = require('./symlink-type')
-var symlinkType = _symlinkType.symlinkType
-var symlinkTypeSync = _symlinkType.symlinkTypeSync
+const _symlinkPaths = require('./symlink-paths')
+const symlinkPaths = _symlinkPaths.symlinkPaths
+const symlinkPathsSync = _symlinkPaths.symlinkPathsSync
+
+const _symlinkType = require('./symlink-type')
+const symlinkType = _symlinkType.symlinkType
+const symlinkTypeSync = _symlinkType.symlinkTypeSync
+
+const pathExists = require('../path-exists').pathExists
 
 function createSymlink (srcpath, dstpath, type, callback) {
   callback = (typeof type === 'function') ? type : callback
   type = (typeof type === 'function') ? false : type
 
-  fs.exists(dstpath, function (destinationExists) {
+  pathExists(dstpath, (err, destinationExists) => {
+    if (err) return callback(err)
     if (destinationExists) return callback(null)
-    symlinkPaths(srcpath, dstpath, function (err, relative) {
+    symlinkPaths(srcpath, dstpath, (err, relative) => {
       if (err) return callback(err)
       srcpath = relative.toDst
-      symlinkType(relative.toCwd, type, function (err, type) {
+      symlinkType(relative.toCwd, type, (err, type) => {
         if (err) return callback(err)
-        var dir = path.dirname(dstpath)
-        fs.exists(dir, function (dirExists) {
+        const dir = path.dirname(dstpath)
+        pathExists(dir, (err, dirExists) => {
+          if (err) return callback(err)
           if (dirExists) return fs.symlink(srcpath, dstpath, type, callback)
-          mkdirs(dir, function (err) {
+          mkdirs(dir, err => {
             if (err) return callback(err)
             fs.symlink(srcpath, dstpath, type, callback)
           })
@@ -36,27 +43,21 @@ function createSymlink (srcpath, dstpath, type, callback) {
   })
 }
 
-function createSymlinkSync (srcpath, dstpath, type, callback) {
-  callback = (typeof type === 'function') ? type : callback
-  type = (typeof type === 'function') ? false : type
-
-  var destinationExists = fs.existsSync(dstpath)
+function createSymlinkSync (srcpath, dstpath, type) {
+  const destinationExists = fs.existsSync(dstpath)
   if (destinationExists) return undefined
 
-  var relative = symlinkPathsSync(srcpath, dstpath)
+  const relative = symlinkPathsSync(srcpath, dstpath)
   srcpath = relative.toDst
   type = symlinkTypeSync(relative.toCwd, type)
-  var dir = path.dirname(dstpath)
-  var exists = fs.existsSync(dir)
+  const dir = path.dirname(dstpath)
+  const exists = fs.existsSync(dir)
   if (exists) return fs.symlinkSync(srcpath, dstpath, type)
   mkdirsSync(dir)
   return fs.symlinkSync(srcpath, dstpath, type)
 }
 
 module.exports = {
-  createSymlink: createSymlink,
-  createSymlinkSync: createSymlinkSync,
-  // alias
-  ensureSymlink: createSymlink,
-  ensureSymlinkSync: createSymlinkSync
+  createSymlink: u(createSymlink),
+  createSymlinkSync
 }

+ 109 - 0
fs-extra/lib/fs/index.js

@@ -0,0 +1,109 @@
+'use strict'
+// This is adapted from https://github.com/normalize/mz
+// Copyright (c) 2014-2016 Jonathan Ong me@jongleberry.com and Contributors
+const u = require('universalify').fromCallback
+const fs = require('graceful-fs')
+
+const api = [
+  'access',
+  'appendFile',
+  'chmod',
+  'chown',
+  'close',
+  'copyFile',
+  'fchmod',
+  'fchown',
+  'fdatasync',
+  'fstat',
+  'fsync',
+  'ftruncate',
+  'futimes',
+  'lchown',
+  'lchmod',
+  'link',
+  'lstat',
+  'mkdir',
+  'mkdtemp',
+  'open',
+  'readFile',
+  'readdir',
+  'readlink',
+  'realpath',
+  'rename',
+  'rmdir',
+  'stat',
+  'symlink',
+  'truncate',
+  'unlink',
+  'utimes',
+  'writeFile'
+].filter(key => {
+  // Some commands are not available on some systems. Ex:
+  // fs.copyFile was added in Node.js v8.5.0
+  // fs.mkdtemp was added in Node.js v5.10.0
+  // fs.lchown is not available on at least some Linux
+  return typeof fs[key] === 'function'
+})
+
+// Export all keys:
+Object.keys(fs).forEach(key => {
+  if (key === 'promises') {
+    // fs.promises is a getter property that triggers ExperimentalWarning
+    // Don't re-export it here, the getter is defined in "lib/index.js"
+    return
+  }
+  exports[key] = fs[key]
+})
+
+// Universalify async methods:
+api.forEach(method => {
+  exports[method] = u(fs[method])
+})
+
+// We differ from mz/fs in that we still ship the old, broken, fs.exists()
+// since we are a drop-in replacement for the native module
+exports.exists = function (filename, callback) {
+  if (typeof callback === 'function') {
+    return fs.exists(filename, callback)
+  }
+  return new Promise(resolve => {
+    return fs.exists(filename, resolve)
+  })
+}
+
+// fs.read() & fs.write need special treatment due to multiple callback args
+
+exports.read = function (fd, buffer, offset, length, position, callback) {
+  if (typeof callback === 'function') {
+    return fs.read(fd, buffer, offset, length, position, callback)
+  }
+  return new Promise((resolve, reject) => {
+    fs.read(fd, buffer, offset, length, position, (err, bytesRead, buffer) => {
+      if (err) return reject(err)
+      resolve({ bytesRead, buffer })
+    })
+  })
+}
+
+// Function signature can be
+// fs.write(fd, buffer[, offset[, length[, position]]], callback)
+// OR
+// fs.write(fd, string[, position[, encoding]], callback)
+// We need to handle both cases, so we use ...args
+exports.write = function (fd, buffer, ...args) {
+  if (typeof args[args.length - 1] === 'function') {
+    return fs.write(fd, buffer, ...args)
+  }
+
+  return new Promise((resolve, reject) => {
+    fs.write(fd, buffer, ...args, (err, bytesWritten, buffer) => {
+      if (err) return reject(err)
+      resolve({ bytesWritten, buffer })
+    })
+  })
+}
+
+// fs.realpath.native only available in Node v9.2+
+if (typeof fs.realpath.native === 'function') {
+  exports.realpath.native = u(fs.realpath.native)
+}

+ 26 - 35
fs-extra/lib/index.js

@@ -1,37 +1,28 @@
-var assign = require('./util/assign')
+'use strict'
 
-var fse = {}
-var gfs = require('graceful-fs')
+module.exports = Object.assign(
+  {},
+  // Export promiseified graceful-fs:
+  require('./fs'),
+  // Export extra methods:
+  require('./copy-sync'),
+  require('./copy'),
+  require('./empty'),
+  require('./ensure'),
+  require('./json'),
+  require('./mkdirs'),
+  require('./move-sync'),
+  require('./move'),
+  require('./output'),
+  require('./path-exists'),
+  require('./remove')
+)
 
-// attach fs methods to fse
-Object.keys(gfs).forEach(function (key) {
-  fse[key] = gfs[key]
-})
-
-var fs = fse
-
-assign(fs, require('./copy'))
-assign(fs, require('./copy-sync'))
-assign(fs, require('./mkdirs'))
-assign(fs, require('./remove'))
-assign(fs, require('./json'))
-assign(fs, require('./move'))
-assign(fs, require('./empty'))
-assign(fs, require('./ensure'))
-assign(fs, require('./output'))
-assign(fs, require('./walk'))
-
-module.exports = fs
-
-// maintain backwards compatibility for awhile
-var jsonfile = {}
-Object.defineProperty(jsonfile, 'spaces', {
-  get: function () {
-    return fs.spaces // found in ./json
-  },
-  set: function (val) {
-    fs.spaces = val
-  }
-})
-
-module.exports.jsonfile = jsonfile // so users of fs-extra can modify jsonFile.spaces
+// Export fs.promises as a getter property so that we don't trigger
+// ExperimentalWarning before fs.promises is actually accessed.
+const fs = require('fs')
+if (Object.getOwnPropertyDescriptor(fs, 'promises')) {
+  Object.defineProperty(module.exports, 'promises', {
+    get () { return fs.promises }
+  })
+}

+ 11 - 4
fs-extra/lib/json/index.js

@@ -1,9 +1,16 @@
-var jsonFile = require('./jsonfile')
+'use strict'
 
+const u = require('universalify').fromCallback
+const jsonFile = require('./jsonfile')
+
+jsonFile.outputJson = u(require('./output-json'))
 jsonFile.outputJsonSync = require('./output-json-sync')
-jsonFile.outputJson = require('./output-json')
 // aliases
-jsonFile.outputJSONSync = require('./output-json-sync')
-jsonFile.outputJSON = require('./output-json')
+jsonFile.outputJSON = jsonFile.outputJson
+jsonFile.outputJSONSync = jsonFile.outputJsonSync
+jsonFile.writeJSON = jsonFile.writeJson
+jsonFile.writeJSONSync = jsonFile.writeJsonSync
+jsonFile.readJSON = jsonFile.readJson
+jsonFile.readJSONSync = jsonFile.readJsonSync
 
 module.exports = jsonFile

+ 7 - 9
fs-extra/lib/json/jsonfile.js

@@ -1,14 +1,12 @@
-var jsonFile = require('jsonfile')
+'use strict'
+
+const u = require('universalify').fromCallback
+const jsonFile = require('jsonfile')
 
 module.exports = {
   // jsonfile exports
-  readJson: jsonFile.readFile,
-  readJSON: jsonFile.readFile,
+  readJson: u(jsonFile.readFile),
   readJsonSync: jsonFile.readFileSync,
-  readJSONSync: jsonFile.readFileSync,
-  writeJson: jsonFile.writeFile,
-  writeJSON: jsonFile.writeFile,
-  writeJsonSync: jsonFile.writeFileSync,
-  writeJSONSync: jsonFile.writeFileSync,
-  spaces: 2 // default in fs-extra
+  writeJson: u(jsonFile.writeFile),
+  writeJsonSync: jsonFile.writeFileSync
 }

+ 7 - 5
fs-extra/lib/json/output-json-sync.js

@@ -1,10 +1,12 @@
-var fs = require('graceful-fs')
-var path = require('path')
-var jsonFile = require('./jsonfile')
-var mkdir = require('../mkdirs')
+'use strict'
+
+const fs = require('graceful-fs')
+const path = require('path')
+const mkdir = require('../mkdirs')
+const jsonFile = require('./jsonfile')
 
 function outputJsonSync (file, data, options) {
-  var dir = path.dirname(file)
+  const dir = path.dirname(file)
 
   if (!fs.existsSync(dir)) {
     mkdir.mkdirsSync(dir)

+ 10 - 7
fs-extra/lib/json/output-json.js

@@ -1,7 +1,9 @@
-var fs = require('graceful-fs')
-var path = require('path')
-var jsonFile = require('./jsonfile')
-var mkdir = require('../mkdirs')
+'use strict'
+
+const path = require('path')
+const mkdir = require('../mkdirs')
+const pathExists = require('../path-exists').pathExists
+const jsonFile = require('./jsonfile')
 
 function outputJson (file, data, options, callback) {
   if (typeof options === 'function') {
@@ -9,12 +11,13 @@ function outputJson (file, data, options, callback) {
     options = {}
   }
 
-  var dir = path.dirname(file)
+  const dir = path.dirname(file)
 
-  fs.exists(dir, function (itDoes) {
+  pathExists(dir, (err, itDoes) => {
+    if (err) return callback(err)
     if (itDoes) return jsonFile.writeJson(file, data, options, callback)
 
-    mkdir.mkdirs(dir, function (err) {
+    mkdir.mkdirs(dir, err => {
       if (err) return callback(err)
       jsonFile.writeJson(file, data, options, callback)
     })

+ 11 - 6
fs-extra/lib/mkdirs/index.js

@@ -1,9 +1,14 @@
+'use strict'
+const u = require('universalify').fromCallback
+const mkdirs = u(require('./mkdirs'))
+const mkdirsSync = require('./mkdirs-sync')
+
 module.exports = {
-  mkdirs: require('./mkdirs'),
-  mkdirsSync: require('./mkdirs-sync'),
+  mkdirs,
+  mkdirsSync,
   // alias
-  mkdirp: require('./mkdirs'),
-  mkdirpSync: require('./mkdirs-sync'),
-  ensureDir: require('./mkdirs'),
-  ensureDirSync: require('./mkdirs-sync')
+  mkdirp: mkdirs,
+  mkdirpSync: mkdirsSync,
+  ensureDir: mkdirs,
+  ensureDirSync: mkdirsSync
 }

+ 23 - 26
fs-extra/lib/mkdirs/mkdirs-sync.js

@@ -1,19 +1,21 @@
-var fs = require('graceful-fs')
-var path = require('path')
-var invalidWin32Path = require('./win32').invalidWin32Path
+'use strict'
 
-var o777 = parseInt('0777', 8)
+const fs = require('graceful-fs')
+const path = require('path')
+const invalidWin32Path = require('./win32').invalidWin32Path
+
+const o777 = parseInt('0777', 8)
 
 function mkdirsSync (p, opts, made) {
   if (!opts || typeof opts !== 'object') {
     opts = { mode: opts }
   }
 
-  var mode = opts.mode
-  var xfs = opts.fs || fs
+  let mode = opts.mode
+  const xfs = opts.fs || fs
 
   if (process.platform === 'win32' && invalidWin32Path(p)) {
-    var errInval = new Error(p + ' contains invalid WIN32 path characters.')
+    const errInval = new Error(p + ' contains invalid WIN32 path characters.')
     errInval.code = 'EINVAL'
     throw errInval
   }
@@ -29,25 +31,20 @@ function mkdirsSync (p, opts, made) {
     xfs.mkdirSync(p, mode)
     made = made || p
   } catch (err0) {
-    switch (err0.code) {
-      case 'ENOENT':
-        if (path.dirname(p) === p) throw err0
-        made = mkdirsSync(path.dirname(p), opts, made)
-        mkdirsSync(p, opts, made)
-        break
-
-      // In the case of any other error, just see if there's a dir
-      // there already.  If so, then hooray!  If not, then something
-      // is borked.
-      default:
-        var stat
-        try {
-          stat = xfs.statSync(p)
-        } catch (err1) {
-          throw err0
-        }
-        if (!stat.isDirectory()) throw err0
-        break
+    if (err0.code === 'ENOENT') {
+      if (path.dirname(p) === p) throw err0
+      made = mkdirsSync(path.dirname(p), opts, made)
+      mkdirsSync(p, opts, made)
+    } else {
+      // In the case of any other error, just see if there's a dir there
+      // already. If so, then hooray!  If not, then something is borked.
+      let stat
+      try {
+        stat = xfs.statSync(p)
+      } catch (err1) {
+        throw err0
+      }
+      if (!stat.isDirectory()) throw err0
     }
   }
 

+ 12 - 10
fs-extra/lib/mkdirs/mkdirs.js

@@ -1,8 +1,10 @@
-var fs = require('graceful-fs')
-var path = require('path')
-var invalidWin32Path = require('./win32').invalidWin32Path
+'use strict'
 
-var o777 = parseInt('0777', 8)
+const fs = require('graceful-fs')
+const path = require('path')
+const invalidWin32Path = require('./win32').invalidWin32Path
+
+const o777 = parseInt('0777', 8)
 
 function mkdirs (p, opts, callback, made) {
   if (typeof opts === 'function') {
@@ -13,13 +15,13 @@ function mkdirs (p, opts, callback, made) {
   }
 
   if (process.platform === 'win32' && invalidWin32Path(p)) {
-    var errInval = new Error(p + ' contains invalid WIN32 path characters.')
+    const errInval = new Error(p + ' contains invalid WIN32 path characters.')
     errInval.code = 'EINVAL'
     return callback(errInval)
   }
 
-  var mode = opts.mode
-  var xfs = opts.fs || fs
+  let mode = opts.mode
+  const xfs = opts.fs || fs
 
   if (mode === undefined) {
     mode = o777 & (~process.umask())
@@ -29,7 +31,7 @@ function mkdirs (p, opts, callback, made) {
   callback = callback || function () {}
   p = path.resolve(p)
 
-  xfs.mkdir(p, mode, function (er) {
+  xfs.mkdir(p, mode, er => {
     if (!er) {
       made = made || p
       return callback(null, made)
@@ -37,7 +39,7 @@ function mkdirs (p, opts, callback, made) {
     switch (er.code) {
       case 'ENOENT':
         if (path.dirname(p) === p) return callback(er)
-        mkdirs(path.dirname(p), opts, function (er, made) {
+        mkdirs(path.dirname(p), opts, (er, made) => {
           if (er) callback(er, made)
           else mkdirs(p, opts, callback, made)
         })
@@ -47,7 +49,7 @@ function mkdirs (p, opts, callback, made) {
       // there already.  If so, then hooray!  If not, then something
       // is borked.
       default:
-        xfs.stat(p, function (er2, stat) {
+        xfs.stat(p, (er2, stat) => {
           // if the stat fails, then that's super weird.
           // let the original error be the failure reason.
           if (er2 || !stat.isDirectory()) callback(er, made)

+ 7 - 6
fs-extra/lib/mkdirs/win32.js

@@ -1,24 +1,25 @@
 'use strict'
-var path = require('path')
+
+const path = require('path')
 
 // get drive on windows
 function getRootPath (p) {
   p = path.normalize(path.resolve(p)).split(path.sep)
   if (p.length > 0) return p[0]
-  else return null
+  return null
 }
 
 // http://stackoverflow.com/a/62888/10333 contains more accurate
 // TODO: expand to include the rest
-var INVALID_PATH_CHARS = /[<>:"|?*]/
+const INVALID_PATH_CHARS = /[<>:"|?*]/
 
 function invalidWin32Path (p) {
-  var rp = getRootPath(p)
+  const rp = getRootPath(p)
   p = p.replace(rp, '')
   return INVALID_PATH_CHARS.test(p)
 }
 
 module.exports = {
-  getRootPath: getRootPath,
-  invalidWin32Path: invalidWin32Path
+  getRootPath,
+  invalidWin32Path
 }

+ 5 - 0
fs-extra/lib/move-sync/index.js

@@ -0,0 +1,5 @@
+'use strict'
+
+module.exports = {
+  moveSync: require('./move-sync')
+}

+ 47 - 0
fs-extra/lib/move-sync/move-sync.js

@@ -0,0 +1,47 @@
+'use strict'
+
+const fs = require('graceful-fs')
+const path = require('path')
+const copySync = require('../copy-sync').copySync
+const removeSync = require('../remove').removeSync
+const mkdirpSync = require('../mkdirs').mkdirpSync
+const stat = require('../util/stat')
+
+function moveSync (src, dest, opts) {
+  opts = opts || {}
+  const overwrite = opts.overwrite || opts.clobber || false
+
+  const { srcStat } = stat.checkPathsSync(src, dest, 'move')
+  stat.checkParentPathsSync(src, srcStat, dest, 'move')
+  mkdirpSync(path.dirname(dest))
+  return doRename(src, dest, overwrite)
+}
+
+function doRename (src, dest, overwrite) {
+  if (overwrite) {
+    removeSync(dest)
+    return rename(src, dest, overwrite)
+  }
+  if (fs.existsSync(dest)) throw new Error('dest already exists.')
+  return rename(src, dest, overwrite)
+}
+
+function rename (src, dest, overwrite) {
+  try {
+    fs.renameSync(src, dest)
+  } catch (err) {
+    if (err.code !== 'EXDEV') throw err
+    return moveAcrossDevice(src, dest, overwrite)
+  }
+}
+
+function moveAcrossDevice (src, dest, overwrite) {
+  const opts = {
+    overwrite,
+    errorOnExist: true
+  }
+  copySync(src, dest, opts)
+  return removeSync(src)
+}
+
+module.exports = moveSync

+ 3 - 158
fs-extra/lib/move/index.js

@@ -1,161 +1,6 @@
-// most of this code was written by Andrew Kelley
-// licensed under the BSD license: see
-// https://github.com/andrewrk/node-mv/blob/master/package.json
-
-// this needs a cleanup
-
-var fs = require('graceful-fs')
-var ncp = require('../copy/ncp')
-var path = require('path')
-var rimraf = require('rimraf')
-var mkdirp = require('../mkdirs').mkdirs
-
-function mv (source, dest, options, callback) {
-  if (typeof options === 'function') {
-    callback = options
-    options = {}
-  }
-
-  var shouldMkdirp = ('mkdirp' in options) ? options.mkdirp : true
-  var clobber = ('clobber' in options) ? options.clobber : false
-
-  var limit = options.limit || 16
-
-  if (shouldMkdirp) {
-    mkdirs()
-  } else {
-    doRename()
-  }
-
-  function mkdirs () {
-    mkdirp(path.dirname(dest), function (err) {
-      if (err) return callback(err)
-      doRename()
-    })
-  }
-
-  function doRename () {
-    if (clobber) {
-      fs.rename(source, dest, function (err) {
-        if (!err) return callback()
-
-        if (err.code === 'ENOTEMPTY' || err.code === 'EEXIST') {
-          rimraf(dest, function (err) {
-            if (err) return callback(err)
-            options.clobber = false // just clobbered it, no need to do it again
-            mv(source, dest, options, callback)
-          })
-          return
-        }
-
-        // weird Windows shit
-        if (err.code === 'EPERM') {
-          setTimeout(function () {
-            rimraf(dest, function (err) {
-              if (err) return callback(err)
-              options.clobber = false
-              mv(source, dest, options, callback)
-            })
-          }, 200)
-          return
-        }
-
-        if (err.code !== 'EXDEV') return callback(err)
-        moveAcrossDevice(source, dest, clobber, limit, callback)
-      })
-    } else {
-      fs.link(source, dest, function (err) {
-        if (err) {
-          if (err.code === 'EXDEV' || err.code === 'EISDIR' || err.code === 'EPERM') {
-            moveAcrossDevice(source, dest, clobber, limit, callback)
-            return
-          }
-          callback(err)
-          return
-        }
-        fs.unlink(source, callback)
-      })
-    }
-  }
-}
-
-function moveAcrossDevice (source, dest, clobber, limit, callback) {
-  fs.stat(source, function (err, stat) {
-    if (err) {
-      callback(err)
-      return
-    }
-
-    if (stat.isDirectory()) {
-      moveDirAcrossDevice(source, dest, clobber, limit, callback)
-    } else {
-      moveFileAcrossDevice(source, dest, clobber, limit, callback)
-    }
-  })
-}
-
-function moveFileAcrossDevice (source, dest, clobber, limit, callback) {
-  var outFlags = clobber ? 'w' : 'wx'
-  var ins = fs.createReadStream(source)
-  var outs = fs.createWriteStream(dest, {flags: outFlags})
-
-  ins.on('error', function (err) {
-    ins.destroy()
-    outs.destroy()
-    outs.removeListener('close', onClose)
-
-    // may want to create a directory but `out` line above
-    // creates an empty file for us: See #108
-    // don't care about error here
-    fs.unlink(dest, function () {
-      // note: `err` here is from the input stream errror
-      if (err.code === 'EISDIR' || err.code === 'EPERM') {
-        moveDirAcrossDevice(source, dest, clobber, limit, callback)
-      } else {
-        callback(err)
-      }
-    })
-  })
-
-  outs.on('error', function (err) {
-    ins.destroy()
-    outs.destroy()
-    outs.removeListener('close', onClose)
-    callback(err)
-  })
-
-  outs.once('close', onClose)
-  ins.pipe(outs)
-
-  function onClose () {
-    fs.unlink(source, callback)
-  }
-}
-
-function moveDirAcrossDevice (source, dest, clobber, limit, callback) {
-  var options = {
-    stopOnErr: true,
-    clobber: false,
-    limit: limit
-  }
-
-  function startNcp () {
-    ncp(source, dest, options, function (errList) {
-      if (errList) return callback(errList[0])
-      rimraf(source, callback)
-    })
-  }
-
-  if (clobber) {
-    rimraf(dest, function (err) {
-      if (err) return callback(err)
-      startNcp()
-    })
-  } else {
-    startNcp()
-  }
-}
+'use strict'
 
+const u = require('universalify').fromCallback
 module.exports = {
-  move: mv
+  move: u(require('./move'))
 }

+ 65 - 0
fs-extra/lib/move/move.js

@@ -0,0 +1,65 @@
+'use strict'
+
+const fs = require('graceful-fs')
+const path = require('path')
+const copy = require('../copy').copy
+const remove = require('../remove').remove
+const mkdirp = require('../mkdirs').mkdirp
+const pathExists = require('../path-exists').pathExists
+const stat = require('../util/stat')
+
+function move (src, dest, opts, cb) {
+  if (typeof opts === 'function') {
+    cb = opts
+    opts = {}
+  }
+
+  const overwrite = opts.overwrite || opts.clobber || false
+
+  stat.checkPaths(src, dest, 'move', (err, stats) => {
+    if (err) return cb(err)
+    const { srcStat } = stats
+    stat.checkParentPaths(src, srcStat, dest, 'move', err => {
+      if (err) return cb(err)
+      mkdirp(path.dirname(dest), err => {
+        if (err) return cb(err)
+        return doRename(src, dest, overwrite, cb)
+      })
+    })
+  })
+}
+
+function doRename (src, dest, overwrite, cb) {
+  if (overwrite) {
+    return remove(dest, err => {
+      if (err) return cb(err)
+      return rename(src, dest, overwrite, cb)
+    })
+  }
+  pathExists(dest, (err, destExists) => {
+    if (err) return cb(err)
+    if (destExists) return cb(new Error('dest already exists.'))
+    return rename(src, dest, overwrite, cb)
+  })
+}
+
+function rename (src, dest, overwrite, cb) {
+  fs.rename(src, dest, err => {
+    if (!err) return cb()
+    if (err.code !== 'EXDEV') return cb(err)
+    return moveAcrossDevice(src, dest, overwrite, cb)
+  })
+}
+
+function moveAcrossDevice (src, dest, overwrite, cb) {
+  const opts = {
+    overwrite,
+    errorOnExist: true
+  }
+  copy(src, dest, opts, err => {
+    if (err) return cb(err)
+    return remove(src, cb)
+  })
+}
+
+module.exports = move

+ 17 - 12
fs-extra/lib/output/index.js

@@ -1,6 +1,10 @@
-var path = require('path')
-var fs = require('graceful-fs')
-var mkdir = require('../mkdirs')
+'use strict'
+
+const u = require('universalify').fromCallback
+const fs = require('graceful-fs')
+const path = require('path')
+const mkdir = require('../mkdirs')
+const pathExists = require('../path-exists').pathExists
 
 function outputFile (file, data, encoding, callback) {
   if (typeof encoding === 'function') {
@@ -8,11 +12,12 @@ function outputFile (file, data, encoding, callback) {
     encoding = 'utf8'
   }
 
-  var dir = path.dirname(file)
-  fs.exists(dir, function (itDoes) {
+  const dir = path.dirname(file)
+  pathExists(dir, (err, itDoes) => {
+    if (err) return callback(err)
     if (itDoes) return fs.writeFile(file, data, encoding, callback)
 
-    mkdir.mkdirs(dir, function (err) {
+    mkdir.mkdirs(dir, err => {
       if (err) return callback(err)
 
       fs.writeFile(file, data, encoding, callback)
@@ -20,16 +25,16 @@ function outputFile (file, data, encoding, callback) {
   })
 }
 
-function outputFileSync (file, data, encoding) {
-  var dir = path.dirname(file)
+function outputFileSync (file, ...args) {
+  const dir = path.dirname(file)
   if (fs.existsSync(dir)) {
-    return fs.writeFileSync.apply(fs, arguments)
+    return fs.writeFileSync(file, ...args)
   }
   mkdir.mkdirsSync(dir)
-  fs.writeFileSync.apply(fs, arguments)
+  fs.writeFileSync(file, ...args)
 }
 
 module.exports = {
-  outputFile: outputFile,
-  outputFileSync: outputFileSync
+  outputFile: u(outputFile),
+  outputFileSync
 }

+ 12 - 0
fs-extra/lib/path-exists/index.js

@@ -0,0 +1,12 @@
+'use strict'
+const u = require('universalify').fromPromise
+const fs = require('../fs')
+
+function pathExists (path) {
+  return fs.access(path).then(() => true).catch(() => false)
+}
+
+module.exports = {
+  pathExists: u(pathExists),
+  pathExistsSync: fs.existsSync
+}

+ 5 - 10
fs-extra/lib/remove/index.js

@@ -1,14 +1,9 @@
-var rimraf = require('rimraf')
+'use strict'
 
-function removeSync (dir) {
-  return rimraf.sync(dir)
-}
-
-function remove (dir, callback) {
-  return callback ? rimraf(dir, callback) : rimraf(dir, function () {})
-}
+const u = require('universalify').fromCallback
+const rimraf = require('./rimraf')
 
 module.exports = {
-  remove: remove,
-  removeSync: removeSync
+  remove: u(rimraf),
+  removeSync: rimraf.sync
 }

+ 314 - 0
fs-extra/lib/remove/rimraf.js

@@ -0,0 +1,314 @@
+'use strict'
+
+const fs = require('graceful-fs')
+const path = require('path')
+const assert = require('assert')
+
+const isWindows = (process.platform === 'win32')
+
+function defaults (options) {
+  const methods = [
+    'unlink',
+    'chmod',
+    'stat',
+    'lstat',
+    'rmdir',
+    'readdir'
+  ]
+  methods.forEach(m => {
+    options[m] = options[m] || fs[m]
+    m = m + 'Sync'
+    options[m] = options[m] || fs[m]
+  })
+
+  options.maxBusyTries = options.maxBusyTries || 3
+}
+
+function rimraf (p, options, cb) {
+  let busyTries = 0
+
+  if (typeof options === 'function') {
+    cb = options
+    options = {}
+  }
+
+  assert(p, 'rimraf: missing path')
+  assert.strictEqual(typeof p, 'string', 'rimraf: path should be a string')
+  assert.strictEqual(typeof cb, 'function', 'rimraf: callback function required')
+  assert(options, 'rimraf: invalid options argument provided')
+  assert.strictEqual(typeof options, 'object', 'rimraf: options should be object')
+
+  defaults(options)
+
+  rimraf_(p, options, function CB (er) {
+    if (er) {
+      if ((er.code === 'EBUSY' || er.code === 'ENOTEMPTY' || er.code === 'EPERM') &&
+          busyTries < options.maxBusyTries) {
+        busyTries++
+        const time = busyTries * 100
+        // try again, with the same exact callback as this one.
+        return setTimeout(() => rimraf_(p, options, CB), time)
+      }
+
+      // already gone
+      if (er.code === 'ENOENT') er = null
+    }
+
+    cb(er)
+  })
+}
+
+// Two possible strategies.
+// 1. Assume it's a file.  unlink it, then do the dir stuff on EPERM or EISDIR
+// 2. Assume it's a directory.  readdir, then do the file stuff on ENOTDIR
+//
+// Both result in an extra syscall when you guess wrong.  However, there
+// are likely far more normal files in the world than directories.  This
+// is based on the assumption that a the average number of files per
+// directory is >= 1.
+//
+// If anyone ever complains about this, then I guess the strategy could
+// be made configurable somehow.  But until then, YAGNI.
+function rimraf_ (p, options, cb) {
+  assert(p)
+  assert(options)
+  assert(typeof cb === 'function')
+
+  // sunos lets the root user unlink directories, which is... weird.
+  // so we have to lstat here and make sure it's not a dir.
+  options.lstat(p, (er, st) => {
+    if (er && er.code === 'ENOENT') {
+      return cb(null)
+    }
+
+    // Windows can EPERM on stat.  Life is suffering.
+    if (er && er.code === 'EPERM' && isWindows) {
+      return fixWinEPERM(p, options, er, cb)
+    }
+
+    if (st && st.isDirectory()) {
+      return rmdir(p, options, er, cb)
+    }
+
+    options.unlink(p, er => {
+      if (er) {
+        if (er.code === 'ENOENT') {
+          return cb(null)
+        }
+        if (er.code === 'EPERM') {
+          return (isWindows)
+            ? fixWinEPERM(p, options, er, cb)
+            : rmdir(p, options, er, cb)
+        }
+        if (er.code === 'EISDIR') {
+          return rmdir(p, options, er, cb)
+        }
+      }
+      return cb(er)
+    })
+  })
+}
+
+function fixWinEPERM (p, options, er, cb) {
+  assert(p)
+  assert(options)
+  assert(typeof cb === 'function')
+  if (er) {
+    assert(er instanceof Error)
+  }
+
+  options.chmod(p, 0o666, er2 => {
+    if (er2) {
+      cb(er2.code === 'ENOENT' ? null : er)
+    } else {
+      options.stat(p, (er3, stats) => {
+        if (er3) {
+          cb(er3.code === 'ENOENT' ? null : er)
+        } else if (stats.isDirectory()) {
+          rmdir(p, options, er, cb)
+        } else {
+          options.unlink(p, cb)
+        }
+      })
+    }
+  })
+}
+
+function fixWinEPERMSync (p, options, er) {
+  let stats
+
+  assert(p)
+  assert(options)
+  if (er) {
+    assert(er instanceof Error)
+  }
+
+  try {
+    options.chmodSync(p, 0o666)
+  } catch (er2) {
+    if (er2.code === 'ENOENT') {
+      return
+    } else {
+      throw er
+    }
+  }
+
+  try {
+    stats = options.statSync(p)
+  } catch (er3) {
+    if (er3.code === 'ENOENT') {
+      return
+    } else {
+      throw er
+    }
+  }
+
+  if (stats.isDirectory()) {
+    rmdirSync(p, options, er)
+  } else {
+    options.unlinkSync(p)
+  }
+}
+
+function rmdir (p, options, originalEr, cb) {
+  assert(p)
+  assert(options)
+  if (originalEr) {
+    assert(originalEr instanceof Error)
+  }
+  assert(typeof cb === 'function')
+
+  // try to rmdir first, and only readdir on ENOTEMPTY or EEXIST (SunOS)
+  // if we guessed wrong, and it's not a directory, then
+  // raise the original error.
+  options.rmdir(p, er => {
+    if (er && (er.code === 'ENOTEMPTY' || er.code === 'EEXIST' || er.code === 'EPERM')) {
+      rmkids(p, options, cb)
+    } else if (er && er.code === 'ENOTDIR') {
+      cb(originalEr)
+    } else {
+      cb(er)
+    }
+  })
+}
+
+function rmkids (p, options, cb) {
+  assert(p)
+  assert(options)
+  assert(typeof cb === 'function')
+
+  options.readdir(p, (er, files) => {
+    if (er) return cb(er)
+
+    let n = files.length
+    let errState
+
+    if (n === 0) return options.rmdir(p, cb)
+
+    files.forEach(f => {
+      rimraf(path.join(p, f), options, er => {
+        if (errState) {
+          return
+        }
+        if (er) return cb(errState = er)
+        if (--n === 0) {
+          options.rmdir(p, cb)
+        }
+      })
+    })
+  })
+}
+
+// this looks simpler, and is strictly *faster*, but will
+// tie up the JavaScript thread and fail on excessively
+// deep directory trees.
+function rimrafSync (p, options) {
+  let st
+
+  options = options || {}
+  defaults(options)
+
+  assert(p, 'rimraf: missing path')
+  assert.strictEqual(typeof p, 'string', 'rimraf: path should be a string')
+  assert(options, 'rimraf: missing options')
+  assert.strictEqual(typeof options, 'object', 'rimraf: options should be object')
+
+  try {
+    st = options.lstatSync(p)
+  } catch (er) {
+    if (er.code === 'ENOENT') {
+      return
+    }
+
+    // Windows can EPERM on stat.  Life is suffering.
+    if (er.code === 'EPERM' && isWindows) {
+      fixWinEPERMSync(p, options, er)
+    }
+  }
+
+  try {
+    // sunos lets the root user unlink directories, which is... weird.
+    if (st && st.isDirectory()) {
+      rmdirSync(p, options, null)
+    } else {
+      options.unlinkSync(p)
+    }
+  } catch (er) {
+    if (er.code === 'ENOENT') {
+      return
+    } else if (er.code === 'EPERM') {
+      return isWindows ? fixWinEPERMSync(p, options, er) : rmdirSync(p, options, er)
+    } else if (er.code !== 'EISDIR') {
+      throw er
+    }
+    rmdirSync(p, options, er)
+  }
+}
+
+function rmdirSync (p, options, originalEr) {
+  assert(p)
+  assert(options)
+  if (originalEr) {
+    assert(originalEr instanceof Error)
+  }
+
+  try {
+    options.rmdirSync(p)
+  } catch (er) {
+    if (er.code === 'ENOTDIR') {
+      throw originalEr
+    } else if (er.code === 'ENOTEMPTY' || er.code === 'EEXIST' || er.code === 'EPERM') {
+      rmkidsSync(p, options)
+    } else if (er.code !== 'ENOENT') {
+      throw er
+    }
+  }
+}
+
+function rmkidsSync (p, options) {
+  assert(p)
+  assert(options)
+  options.readdirSync(p).forEach(f => rimrafSync(path.join(p, f), options))
+
+  if (isWindows) {
+    // We only end up here once we got ENOTEMPTY at least once, and
+    // at this point, we are guaranteed to have removed all the kids.
+    // So, we know that it won't be ENOENT or ENOTDIR or anything else.
+    // try really hard to delete stuff on windows, because it has a
+    // PROFOUNDLY annoying habit of not closing handles promptly when
+    // files are deleted, resulting in spurious ENOTEMPTY errors.
+    const startTime = Date.now()
+    do {
+      try {
+        const ret = options.rmdirSync(p, options)
+        return ret
+      } catch (er) { }
+    } while (Date.now() - startTime < 500) // give up after 500ms
+  } else {
+    const ret = options.rmdirSync(p, options)
+    return ret
+  }
+}
+
+module.exports = rimraf
+rimraf.sync = rimrafSync

+ 12 - 0
fs-extra/lib/util/buffer.js

@@ -0,0 +1,12 @@
+'use strict'
+/* eslint-disable node/no-deprecated-api */
+module.exports = function (size) {
+  if (typeof Buffer.allocUnsafe === 'function') {
+    try {
+      return Buffer.allocUnsafe(size)
+    } catch (e) {
+      return new Buffer(size)
+    }
+  }
+  return new Buffer(size)
+}

+ 172 - 0
fs-extra/lib/util/stat.js

@@ -0,0 +1,172 @@
+'use strict'
+
+const fs = require('graceful-fs')
+const path = require('path')
+
+const NODE_VERSION_MAJOR_WITH_BIGINT = 10
+const NODE_VERSION_MINOR_WITH_BIGINT = 5
+const NODE_VERSION_PATCH_WITH_BIGINT = 0
+const nodeVersion = process.versions.node.split('.')
+const nodeVersionMajor = Number.parseInt(nodeVersion[0], 10)
+const nodeVersionMinor = Number.parseInt(nodeVersion[1], 10)
+const nodeVersionPatch = Number.parseInt(nodeVersion[2], 10)
+
+function nodeSupportsBigInt () {
+  if (nodeVersionMajor > NODE_VERSION_MAJOR_WITH_BIGINT) {
+    return true
+  } else if (nodeVersionMajor === NODE_VERSION_MAJOR_WITH_BIGINT) {
+    if (nodeVersionMinor > NODE_VERSION_MINOR_WITH_BIGINT) {
+      return true
+    } else if (nodeVersionMinor === NODE_VERSION_MINOR_WITH_BIGINT) {
+      if (nodeVersionPatch >= NODE_VERSION_PATCH_WITH_BIGINT) {
+        return true
+      }
+    }
+  }
+  return false
+}
+
+function getStats (src, dest, cb) {
+  if (nodeSupportsBigInt()) {
+    fs.stat(src, { bigint: true }, (err, srcStat) => {
+      if (err) return cb(err)
+      fs.stat(dest, { bigint: true }, (err, destStat) => {
+        if (err) {
+          if (err.code === 'ENOENT') return cb(null, { srcStat, destStat: null })
+          return cb(err)
+        }
+        return cb(null, { srcStat, destStat })
+      })
+    })
+  } else {
+    fs.stat(src, (err, srcStat) => {
+      if (err) return cb(err)
+      fs.stat(dest, (err, destStat) => {
+        if (err) {
+          if (err.code === 'ENOENT') return cb(null, { srcStat, destStat: null })
+          return cb(err)
+        }
+        return cb(null, { srcStat, destStat })
+      })
+    })
+  }
+}
+
+function getStatsSync (src, dest) {
+  let srcStat, destStat
+  if (nodeSupportsBigInt()) {
+    srcStat = fs.statSync(src, { bigint: true })
+  } else {
+    srcStat = fs.statSync(src)
+  }
+  try {
+    if (nodeSupportsBigInt()) {
+      destStat = fs.statSync(dest, { bigint: true })
+    } else {
+      destStat = fs.statSync(dest)
+    }
+  } catch (err) {
+    if (err.code === 'ENOENT') return { srcStat, destStat: null }
+    throw err
+  }
+  return { srcStat, destStat }
+}
+
+function checkPaths (src, dest, funcName, cb) {
+  getStats(src, dest, (err, stats) => {
+    if (err) return cb(err)
+    const { srcStat, destStat } = stats
+    if (destStat && destStat.ino && destStat.dev && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev) {
+      return cb(new Error('Source and destination must not be the same.'))
+    }
+    if (srcStat.isDirectory() && isSrcSubdir(src, dest)) {
+      return cb(new Error(errMsg(src, dest, funcName)))
+    }
+    return cb(null, { srcStat, destStat })
+  })
+}
+
+function checkPathsSync (src, dest, funcName) {
+  const { srcStat, destStat } = getStatsSync(src, dest)
+  if (destStat && destStat.ino && destStat.dev && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev) {
+    throw new Error('Source and destination must not be the same.')
+  }
+  if (srcStat.isDirectory() && isSrcSubdir(src, dest)) {
+    throw new Error(errMsg(src, dest, funcName))
+  }
+  return { srcStat, destStat }
+}
+
+// recursively check if dest parent is a subdirectory of src.
+// It works for all file types including symlinks since it
+// checks the src and dest inodes. It starts from the deepest
+// parent and stops once it reaches the src parent or the root path.
+function checkParentPaths (src, srcStat, dest, funcName, cb) {
+  const srcParent = path.resolve(path.dirname(src))
+  const destParent = path.resolve(path.dirname(dest))
+  if (destParent === srcParent || destParent === path.parse(destParent).root) return cb()
+  if (nodeSupportsBigInt()) {
+    fs.stat(destParent, { bigint: true }, (err, destStat) => {
+      if (err) {
+        if (err.code === 'ENOENT') return cb()
+        return cb(err)
+      }
+      if (destStat.ino && destStat.dev && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev) {
+        return cb(new Error(errMsg(src, dest, funcName)))
+      }
+      return checkParentPaths(src, srcStat, destParent, funcName, cb)
+    })
+  } else {
+    fs.stat(destParent, (err, destStat) => {
+      if (err) {
+        if (err.code === 'ENOENT') return cb()
+        return cb(err)
+      }
+      if (destStat.ino && destStat.dev && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev) {
+        return cb(new Error(errMsg(src, dest, funcName)))
+      }
+      return checkParentPaths(src, srcStat, destParent, funcName, cb)
+    })
+  }
+}
+
+function checkParentPathsSync (src, srcStat, dest, funcName) {
+  const srcParent = path.resolve(path.dirname(src))
+  const destParent = path.resolve(path.dirname(dest))
+  if (destParent === srcParent || destParent === path.parse(destParent).root) return
+  let destStat
+  try {
+    if (nodeSupportsBigInt()) {
+      destStat = fs.statSync(destParent, { bigint: true })
+    } else {
+      destStat = fs.statSync(destParent)
+    }
+  } catch (err) {
+    if (err.code === 'ENOENT') return
+    throw err
+  }
+  if (destStat.ino && destStat.dev && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev) {
+    throw new Error(errMsg(src, dest, funcName))
+  }
+  return checkParentPathsSync(src, srcStat, destParent, funcName)
+}
+
+// return true if dest is a subdir of src, otherwise false.
+// It only checks the path strings.
+function isSrcSubdir (src, dest) {
+  const srcArr = path.resolve(src).split(path.sep).filter(i => i)
+  const destArr = path.resolve(dest).split(path.sep).filter(i => i)
+  return srcArr.reduce((acc, cur, i) => acc && destArr[i] === cur, true)
+}
+
+function errMsg (src, dest, funcName) {
+  return `Cannot ${funcName} '${src}' to a subdirectory of itself, '${dest}'.`
+}
+
+module.exports = {
+  checkPaths,
+  checkPathsSync,
+  checkParentPaths,
+  checkParentPathsSync,
+  isSrcSubdir
+}

+ 31 - 21
fs-extra/lib/util/utimes.js

@@ -1,36 +1,38 @@
-var fs = require('graceful-fs')
-var path = require('path')
-var os = require('os')
+'use strict'
+
+const fs = require('graceful-fs')
+const os = require('os')
+const path = require('path')
 
 // HFS, ext{2,3}, FAT do not, Node.js v0.10 does not
 function hasMillisResSync () {
-  var tmpfile = path.join('millis-test-sync' + Date.now().toString() + Math.random().toString().slice(2))
+  let tmpfile = path.join('millis-test-sync' + Date.now().toString() + Math.random().toString().slice(2))
   tmpfile = path.join(os.tmpdir(), tmpfile)
 
   // 550 millis past UNIX epoch
-  var d = new Date(1435410243862)
+  const d = new Date(1435410243862)
   fs.writeFileSync(tmpfile, 'https://github.com/jprichardson/node-fs-extra/pull/141')
-  var fd = fs.openSync(tmpfile, 'r+')
+  const fd = fs.openSync(tmpfile, 'r+')
   fs.futimesSync(fd, d, d)
   fs.closeSync(fd)
   return fs.statSync(tmpfile).mtime > 1435410243000
 }
 
 function hasMillisRes (callback) {
-  var tmpfile = path.join('millis-test' + Date.now().toString() + Math.random().toString().slice(2))
+  let tmpfile = path.join('millis-test' + Date.now().toString() + Math.random().toString().slice(2))
   tmpfile = path.join(os.tmpdir(), tmpfile)
 
   // 550 millis past UNIX epoch
-  var d = new Date(1435410243862)
-  fs.writeFile(tmpfile, 'https://github.com/jprichardson/node-fs-extra/pull/141', function (err) {
+  const d = new Date(1435410243862)
+  fs.writeFile(tmpfile, 'https://github.com/jprichardson/node-fs-extra/pull/141', err => {
     if (err) return callback(err)
-    fs.open(tmpfile, 'r+', function (err, fd) {
+    fs.open(tmpfile, 'r+', (err, fd) => {
       if (err) return callback(err)
-      fs.futimes(fd, d, d, function (err) {
+      fs.futimes(fd, d, d, err => {
         if (err) return callback(err)
-        fs.close(fd, function (err) {
+        fs.close(fd, err => {
           if (err) return callback(err)
-          fs.stat(tmpfile, function (err, stats) {
+          fs.stat(tmpfile, (err, stats) => {
             if (err) return callback(err)
             callback(null, stats.mtime > 1435410243000)
           })
@@ -52,18 +54,26 @@ function timeRemoveMillis (timestamp) {
 
 function utimesMillis (path, atime, mtime, callback) {
   // if (!HAS_MILLIS_RES) return fs.utimes(path, atime, mtime, callback)
-  fs.open(path, 'r+', function (err, fd) {
+  fs.open(path, 'r+', (err, fd) => {
     if (err) return callback(err)
-    fs.futimes(fd, atime, mtime, function (err) {
-      if (err) return callback(err)
-      fs.close(fd, callback)
+    fs.futimes(fd, atime, mtime, futimesErr => {
+      fs.close(fd, closeErr => {
+        if (callback) callback(futimesErr || closeErr)
+      })
     })
   })
 }
 
+function utimesMillisSync (path, atime, mtime) {
+  const fd = fs.openSync(path, 'r+')
+  fs.futimesSync(fd, atime, mtime)
+  return fs.closeSync(fd)
+}
+
 module.exports = {
-  hasMillisRes: hasMillisRes,
-  hasMillisResSync: hasMillisResSync,
-  timeRemoveMillis: timeRemoveMillis,
-  utimesMillis: utimesMillis
+  hasMillisRes,
+  hasMillisResSync,
+  timeRemoveMillis,
+  utimesMillis,
+  utimesMillisSync
 }

+ 35 - 27
fs-extra/package.json

@@ -1,27 +1,27 @@
 {
-  "_from": "fs-extra@0.30.0",
-  "_id": "fs-extra@0.30.0",
+  "_from": "fs-extra@^8.1.0",
+  "_id": "fs-extra@8.1.0",
   "_inBundle": false,
-  "_integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=",
+  "_integrity": "sha1-SdQ8RaiM2Wd2aMt74bRu/bjS4cA=",
   "_location": "/fs-extra",
   "_phantomChildren": {},
   "_requested": {
-    "type": "version",
+    "type": "range",
     "registry": true,
-    "raw": "fs-extra@0.30.0",
+    "raw": "fs-extra@^8.1.0",
     "name": "fs-extra",
     "escapedName": "fs-extra",
-    "rawSpec": "0.30.0",
+    "rawSpec": "^8.1.0",
     "saveSpec": null,
-    "fetchSpec": "0.30.0"
+    "fetchSpec": "^8.1.0"
   },
   "_requiredBy": [
-    "/waterline-utils"
+    "/streamroller"
   ],
-  "_resolved": "http://registry.npm.taobao.org/fs-extra/download/fs-extra-0.30.0.tgz",
-  "_shasum": "f233ffcc08d4da7d432daa449776989db1df93f0",
-  "_spec": "fs-extra@0.30.0",
-  "_where": "E:\\dev\\007\\node_module\\node10\\node_modules\\waterline-utils",
+  "_resolved": "https://registry.nlark.com/fs-extra/download/fs-extra-8.1.0.tgz",
+  "_shasum": "49d43c45a88cd9677668cb7be1b46efdb8d2e1c0",
+  "_spec": "fs-extra@^8.1.0",
+  "_where": "D:\\project\\server\\logtest\\node_modules\\streamroller",
   "author": {
     "name": "JP Richardson",
     "email": "jprichardson@gmail.com"
@@ -31,24 +31,31 @@
   },
   "bundleDependencies": false,
   "dependencies": {
-    "graceful-fs": "^4.1.2",
-    "jsonfile": "^2.1.0",
-    "klaw": "^1.0.0",
-    "path-is-absolute": "^1.0.0",
-    "rimraf": "^2.2.8"
+    "graceful-fs": "^4.2.0",
+    "jsonfile": "^4.0.0",
+    "universalify": "^0.1.0"
   },
   "deprecated": false,
   "description": "fs-extra contains methods that aren't included in the vanilla Node.js fs package. Such as mkdir -p, cp -r, and rm -rf.",
   "devDependencies": {
-    "coveralls": "^2.11.2",
-    "istanbul": "^0.3.5",
+    "coveralls": "^3.0.0",
+    "istanbul": "^0.4.5",
+    "klaw": "^2.1.1",
+    "klaw-sync": "^3.0.2",
     "minimist": "^1.1.1",
-    "mocha": "^2.1.0",
+    "mocha": "^5.0.5",
+    "proxyquire": "^2.0.1",
     "read-dir-files": "^0.1.1",
-    "secure-random": "^1.1.1",
-    "semver": "^4.3.6",
-    "standard": "^7.0.0-beta.0"
+    "semver": "^5.3.0",
+    "standard": "^12.0.1"
   },
+  "engines": {
+    "node": ">=6 <7 || >=8"
+  },
+  "files": [
+    "lib/",
+    "!lib/**/__tests__/"
+  ],
   "homepage": "https://github.com/jprichardson/node-fs-extra",
   "keywords": [
     "fs",
@@ -74,19 +81,20 @@
     "move"
   ],
   "license": "MIT",
-  "main": "./lib/index",
+  "main": "./lib/index.js",
   "name": "fs-extra",
   "repository": {
     "type": "git",
     "url": "git+https://github.com/jprichardson/node-fs-extra.git"
   },
   "scripts": {
-    "coverage": "istanbul cover test.js",
-    "coveralls": "npm run coverage && coveralls < coverage/lcov.info",
+    "coverage": "istanbul cover -i 'lib/**' -x '**/__tests__/**' test.js",
+    "coveralls": "coveralls < coverage/lcov.info",
+    "full-ci": "npm run lint && npm run coverage",
     "lint": "standard",
     "test": "npm run lint && npm run unit",
     "test-find": "find ./lib/**/__tests__ -name *.test.js | xargs mocha",
     "unit": "node test.js"
   },
-  "version": "0.30.0"
+  "version": "8.1.0"
 }

+ 11 - 1
graceful-fs/README.md

@@ -30,9 +30,19 @@ the directory.
 var fs = require('graceful-fs')
 
 // now go and do stuff with it...
-fs.readFileSync('some-file-or-whatever')
+fs.readFile('some-file-or-whatever', (err, data) => {
+  // Do stuff here.
+})
 ```
 
+## Sync methods
+
+This module cannot intercept or handle `EMFILE` or `ENFILE` errors from sync
+methods.  If you use sync methods which open file descriptors then you are
+responsible for dealing with any errors.
+
+This is a known limitation, not a bug.
+
 ## Global Patching
 
 If you want to patch the global fs module (or any other fs-like

+ 5 - 1
graceful-fs/clone.js

@@ -2,12 +2,16 @@
 
 module.exports = clone
 
+var getPrototypeOf = Object.getPrototypeOf || function (obj) {
+  return obj.__proto__
+}
+
 function clone (obj) {
   if (obj === null || typeof obj !== 'object')
     return obj
 
   if (obj instanceof Object)
-    var copy = { __proto__: obj.__proto__ }
+    var copy = { __proto__: getPrototypeOf(obj) }
   else
     var copy = Object.create(null)
 

+ 236 - 86
graceful-fs/graceful-fs.js

@@ -3,12 +3,32 @@ var polyfills = require('./polyfills.js')
 var legacy = require('./legacy-streams.js')
 var clone = require('./clone.js')
 
-var queue = []
-
 var util = require('util')
 
+/* istanbul ignore next - node 0.x polyfill */
+var gracefulQueue
+var previousSymbol
+
+/* istanbul ignore else - node 0.x polyfill */
+if (typeof Symbol === 'function' && typeof Symbol.for === 'function') {
+  gracefulQueue = Symbol.for('graceful-fs.queue')
+  // This is used in testing by future versions
+  previousSymbol = Symbol.for('graceful-fs.previous')
+} else {
+  gracefulQueue = '___graceful-fs.queue'
+  previousSymbol = '___graceful-fs.previous'
+}
+
 function noop () {}
 
+function publishQueue(context, queue) {
+  Object.defineProperty(context, gracefulQueue, {
+    get: function() {
+      return queue
+    }
+  })
+}
+
 var debug = noop
 if (util.debuglog)
   debug = util.debuglog('gfs4')
@@ -19,11 +39,58 @@ else if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || ''))
     console.error(m)
   }
 
-if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) {
-  process.on('exit', function() {
-    debug(queue)
-    require('assert').equal(queue.length, 0)
-  })
+// Once time initialization
+if (!fs[gracefulQueue]) {
+  // This queue can be shared by multiple loaded instances
+  var queue = global[gracefulQueue] || []
+  publishQueue(fs, queue)
+
+  // Patch fs.close/closeSync to shared queue version, because we need
+  // to retry() whenever a close happens *anywhere* in the program.
+  // This is essential when multiple graceful-fs instances are
+  // in play at the same time.
+  fs.close = (function (fs$close) {
+    function close (fd, cb) {
+      return fs$close.call(fs, fd, function (err) {
+        // This function uses the graceful-fs shared queue
+        if (!err) {
+          resetQueue()
+        }
+
+        if (typeof cb === 'function')
+          cb.apply(this, arguments)
+      })
+    }
+
+    Object.defineProperty(close, previousSymbol, {
+      value: fs$close
+    })
+    return close
+  })(fs.close)
+
+  fs.closeSync = (function (fs$closeSync) {
+    function closeSync (fd) {
+      // This function uses the graceful-fs shared queue
+      fs$closeSync.apply(fs, arguments)
+      resetQueue()
+    }
+
+    Object.defineProperty(closeSync, previousSymbol, {
+      value: fs$closeSync
+    })
+    return closeSync
+  })(fs.closeSync)
+
+  if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) {
+    process.on('exit', function() {
+      debug(fs[gracefulQueue])
+      require('assert').equal(fs[gracefulQueue].length, 0)
+    })
+  }
+}
+
+if (!global[gracefulQueue]) {
+  publishQueue(global, fs[gracefulQueue]);
 }
 
 module.exports = patch(clone(fs))
@@ -32,45 +99,11 @@ if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs.__patched) {
     fs.__patched = true;
 }
 
-// Always patch fs.close/closeSync, because we want to
-// retry() whenever a close happens *anywhere* in the program.
-// This is essential when multiple graceful-fs instances are
-// in play at the same time.
-module.exports.close = (function (fs$close) { return function (fd, cb) {
-  return fs$close.call(fs, fd, function (err) {
-    if (!err)
-      retry()
-
-    if (typeof cb === 'function')
-      cb.apply(this, arguments)
-  })
-}})(fs.close)
-
-module.exports.closeSync = (function (fs$closeSync) { return function (fd) {
-  // Note that graceful-fs also retries when fs.closeSync() fails.
-  // Looks like a bug to me, although it's probably a harmless one.
-  var rval = fs$closeSync.apply(fs, arguments)
-  retry()
-  return rval
-}})(fs.closeSync)
-
-// Only patch fs once, otherwise we'll run into a memory leak if
-// graceful-fs is loaded multiple times, such as in test environments that
-// reset the loaded modules between tests.
-// We look for the string `graceful-fs` from the comment above. This
-// way we are not adding any extra properties and it will detect if older
-// versions of graceful-fs are installed.
-if (!/\bgraceful-fs\b/.test(fs.closeSync.toString())) {
-  fs.closeSync = module.exports.closeSync;
-  fs.close = module.exports.close;
-}
-
 function patch (fs) {
   // Everything that references the open() function needs to be in here
   polyfills(fs)
   fs.gracefulify = patch
-  fs.FileReadStream = ReadStream;  // Legacy name.
-  fs.FileWriteStream = WriteStream;  // Legacy name.
+
   fs.createReadStream = createReadStream
   fs.createWriteStream = createWriteStream
   var fs$readFile = fs.readFile
@@ -81,14 +114,13 @@ function patch (fs) {
 
     return go$readFile(path, options, cb)
 
-    function go$readFile (path, options, cb) {
+    function go$readFile (path, options, cb, startTime) {
       return fs$readFile(path, options, function (err) {
         if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
-          enqueue([go$readFile, [path, options, cb]])
+          enqueue([go$readFile, [path, options, cb], err, startTime || Date.now(), Date.now()])
         else {
           if (typeof cb === 'function')
             cb.apply(this, arguments)
-          retry()
         }
       })
     }
@@ -102,14 +134,13 @@ function patch (fs) {
 
     return go$writeFile(path, data, options, cb)
 
-    function go$writeFile (path, data, options, cb) {
+    function go$writeFile (path, data, options, cb, startTime) {
       return fs$writeFile(path, data, options, function (err) {
         if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
-          enqueue([go$writeFile, [path, data, options, cb]])
+          enqueue([go$writeFile, [path, data, options, cb], err, startTime || Date.now(), Date.now()])
         else {
           if (typeof cb === 'function')
             cb.apply(this, arguments)
-          retry()
         }
       })
     }
@@ -124,14 +155,35 @@ function patch (fs) {
 
     return go$appendFile(path, data, options, cb)
 
-    function go$appendFile (path, data, options, cb) {
+    function go$appendFile (path, data, options, cb, startTime) {
       return fs$appendFile(path, data, options, function (err) {
         if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
-          enqueue([go$appendFile, [path, data, options, cb]])
+          enqueue([go$appendFile, [path, data, options, cb], err, startTime || Date.now(), Date.now()])
+        else {
+          if (typeof cb === 'function')
+            cb.apply(this, arguments)
+        }
+      })
+    }
+  }
+
+  var fs$copyFile = fs.copyFile
+  if (fs$copyFile)
+    fs.copyFile = copyFile
+  function copyFile (src, dest, flags, cb) {
+    if (typeof flags === 'function') {
+      cb = flags
+      flags = 0
+    }
+    return go$copyFile(src, dest, flags, cb)
+
+    function go$copyFile (src, dest, flags, cb, startTime) {
+      return fs$copyFile(src, dest, flags, function (err) {
+        if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
+          enqueue([go$copyFile, [src, dest, flags, cb], err, startTime || Date.now(), Date.now()])
         else {
           if (typeof cb === 'function')
             cb.apply(this, arguments)
-          retry()
         }
       })
     }
@@ -140,35 +192,26 @@ function patch (fs) {
   var fs$readdir = fs.readdir
   fs.readdir = readdir
   function readdir (path, options, cb) {
-    var args = [path]
-    if (typeof options !== 'function') {
-      args.push(options)
-    } else {
-      cb = options
-    }
-    args.push(go$readdir$cb)
-
-    return go$readdir(args)
+    if (typeof options === 'function')
+      cb = options, options = null
 
-    function go$readdir$cb (err, files) {
-      if (files && files.sort)
-        files.sort()
+    return go$readdir(path, options, cb)
 
-      if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
-        enqueue([go$readdir, [args]])
+    function go$readdir (path, options, cb, startTime) {
+      return fs$readdir(path, options, function (err, files) {
+        if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
+          enqueue([go$readdir, [path, options, cb], err, startTime || Date.now(), Date.now()])
+        else {
+          if (files && files.sort)
+            files.sort()
 
-      else {
-        if (typeof cb === 'function')
-          cb.apply(this, arguments)
-        retry()
-      }
+          if (typeof cb === 'function')
+            cb.call(this, err, files)
+        }
+      })
     }
   }
 
-  function go$readdir (args) {
-    return fs$readdir.apply(fs, args)
-  }
-
   if (process.version.substr(0, 4) === 'v0.8') {
     var legStreams = legacy(fs)
     ReadStream = legStreams.ReadStream
@@ -187,8 +230,50 @@ function patch (fs) {
     WriteStream.prototype.open = WriteStream$open
   }
 
-  fs.ReadStream = ReadStream
-  fs.WriteStream = WriteStream
+  Object.defineProperty(fs, 'ReadStream', {
+    get: function () {
+      return ReadStream
+    },
+    set: function (val) {
+      ReadStream = val
+    },
+    enumerable: true,
+    configurable: true
+  })
+  Object.defineProperty(fs, 'WriteStream', {
+    get: function () {
+      return WriteStream
+    },
+    set: function (val) {
+      WriteStream = val
+    },
+    enumerable: true,
+    configurable: true
+  })
+
+  // legacy names
+  var FileReadStream = ReadStream
+  Object.defineProperty(fs, 'FileReadStream', {
+    get: function () {
+      return FileReadStream
+    },
+    set: function (val) {
+      FileReadStream = val
+    },
+    enumerable: true,
+    configurable: true
+  })
+  var FileWriteStream = WriteStream
+  Object.defineProperty(fs, 'FileWriteStream', {
+    get: function () {
+      return FileWriteStream
+    },
+    set: function (val) {
+      FileWriteStream = val
+    },
+    enumerable: true,
+    configurable: true
+  })
 
   function ReadStream (path, options) {
     if (this instanceof ReadStream)
@@ -234,11 +319,11 @@ function patch (fs) {
   }
 
   function createReadStream (path, options) {
-    return new ReadStream(path, options)
+    return new fs.ReadStream(path, options)
   }
 
   function createWriteStream (path, options) {
-    return new WriteStream(path, options)
+    return new fs.WriteStream(path, options)
   }
 
   var fs$open = fs.open
@@ -249,14 +334,13 @@ function patch (fs) {
 
     return go$open(path, flags, mode, cb)
 
-    function go$open (path, flags, mode, cb) {
+    function go$open (path, flags, mode, cb, startTime) {
       return fs$open(path, flags, mode, function (err, fd) {
         if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
-          enqueue([go$open, [path, flags, mode, cb]])
+          enqueue([go$open, [path, flags, mode, cb], err, startTime || Date.now(), Date.now()])
         else {
           if (typeof cb === 'function')
             cb.apply(this, arguments)
-          retry()
         }
       })
     }
@@ -267,13 +351,79 @@ function patch (fs) {
 
 function enqueue (elem) {
   debug('ENQUEUE', elem[0].name, elem[1])
-  queue.push(elem)
+  fs[gracefulQueue].push(elem)
+  retry()
+}
+
+// keep track of the timeout between retry() calls
+var retryTimer
+
+// reset the startTime and lastTime to now
+// this resets the start of the 60 second overall timeout as well as the
+// delay between attempts so that we'll retry these jobs sooner
+function resetQueue () {
+  var now = Date.now()
+  for (var i = 0; i < fs[gracefulQueue].length; ++i) {
+    // entries that are only a length of 2 are from an older version, don't
+    // bother modifying those since they'll be retried anyway.
+    if (fs[gracefulQueue][i].length > 2) {
+      fs[gracefulQueue][i][3] = now // startTime
+      fs[gracefulQueue][i][4] = now // lastTime
+    }
+  }
+  // call retry to make sure we're actively processing the queue
+  retry()
 }
 
 function retry () {
-  var elem = queue.shift()
-  if (elem) {
-    debug('RETRY', elem[0].name, elem[1])
-    elem[0].apply(null, elem[1])
+  // clear the timer and remove it to help prevent unintended concurrency
+  clearTimeout(retryTimer)
+  retryTimer = undefined
+
+  if (fs[gracefulQueue].length === 0)
+    return
+
+  var elem = fs[gracefulQueue].shift()
+  var fn = elem[0]
+  var args = elem[1]
+  // these items may be unset if they were added by an older graceful-fs
+  var err = elem[2]
+  var startTime = elem[3]
+  var lastTime = elem[4]
+
+  // if we don't have a startTime we have no way of knowing if we've waited
+  // long enough, so go ahead and retry this item now
+  if (startTime === undefined) {
+    debug('RETRY', fn.name, args)
+    fn.apply(null, args)
+  } else if (Date.now() - startTime >= 60000) {
+    // it's been more than 60 seconds total, bail now
+    debug('TIMEOUT', fn.name, args)
+    var cb = args.pop()
+    if (typeof cb === 'function')
+      cb.call(null, err)
+  } else {
+    // the amount of time between the last attempt and right now
+    var sinceAttempt = Date.now() - lastTime
+    // the amount of time between when we first tried, and when we last tried
+    // rounded up to at least 1
+    var sinceStart = Math.max(lastTime - startTime, 1)
+    // backoff. wait longer than the total time we've been retrying, but only
+    // up to a maximum of 100ms
+    var desiredDelay = Math.min(sinceStart * 1.2, 100)
+    // it's been long enough since the last retry, do it again
+    if (sinceAttempt >= desiredDelay) {
+      debug('RETRY', fn.name, args)
+      fn.apply(null, args.concat([startTime]))
+    } else {
+      // if we can't do this job yet, push it to the end of the queue
+      // and let the next iteration check again
+      fs[gracefulQueue].push(elem)
+    }
+  }
+
+  // schedule our next run if one isn't already scheduled
+  if (retryTimer === undefined) {
+    retryTimer = setTimeout(retry, 0)
   }
 }

+ 16 - 16
graceful-fs/package.json

@@ -1,29 +1,28 @@
 {
-  "_from": "graceful-fs@^4.1.2",
-  "_id": "graceful-fs@4.1.15",
+  "_from": "graceful-fs@^4.2.0",
+  "_id": "graceful-fs@4.2.8",
   "_inBundle": false,
-  "_integrity": "sha1-/7cD4QZuig7qpMi4C6klPu77+wA=",
+  "_integrity": "sha1-5BK40z9eAGWTy9PO5t+fLOu+gCo=",
   "_location": "/graceful-fs",
   "_phantomChildren": {},
   "_requested": {
     "type": "range",
     "registry": true,
-    "raw": "graceful-fs@^4.1.2",
+    "raw": "graceful-fs@^4.2.0",
     "name": "graceful-fs",
     "escapedName": "graceful-fs",
-    "rawSpec": "^4.1.2",
+    "rawSpec": "^4.2.0",
     "saveSpec": null,
-    "fetchSpec": "^4.1.2"
+    "fetchSpec": "^4.2.0"
   },
   "_requiredBy": [
     "/fs-extra",
-    "/jsonfile",
-    "/klaw"
+    "/jsonfile"
   ],
-  "_resolved": "http://registry.npm.taobao.org/graceful-fs/download/graceful-fs-4.1.15.tgz",
-  "_shasum": "ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00",
-  "_spec": "graceful-fs@^4.1.2",
-  "_where": "E:\\dev\\007\\node_module\\node10\\node_modules\\fs-extra",
+  "_resolved": "https://registry.npmmirror.com/graceful-fs/download/graceful-fs-4.2.8.tgz",
+  "_shasum": "e412b8d33f5e006593cbd3cee6df9f2cebbe802a",
+  "_spec": "graceful-fs@^4.2.0",
+  "_where": "D:\\project\\server\\logtest\\node_modules\\fs-extra",
   "bugs": {
     "url": "https://github.com/isaacs/node-graceful-fs/issues"
   },
@@ -34,7 +33,7 @@
     "import-fresh": "^2.0.0",
     "mkdirp": "^0.5.0",
     "rimraf": "^2.2.8",
-    "tap": "^12.0.1"
+    "tap": "^12.7.0"
   },
   "directories": {
     "test": "test"
@@ -71,10 +70,11 @@
     "url": "git+https://github.com/isaacs/node-graceful-fs.git"
   },
   "scripts": {
-    "postpublish": "git push origin --all; git push origin --tags",
+    "postpublish": "git push origin --follow-tags",
+    "posttest": "nyc report",
     "postversion": "npm publish",
     "preversion": "npm test",
-    "test": "node test.js | tap -"
+    "test": "nyc --silent node test.js | tap -c -"
   },
-  "version": "4.1.15"
+  "version": "4.2.8"
 }

+ 41 - 24
graceful-fs/polyfills.js

@@ -14,10 +14,14 @@ try {
   process.cwd()
 } catch (er) {}
 
-var chdir = process.chdir
-process.chdir = function(d) {
-  cwd = null
-  chdir.call(process, d)
+// This check is needed until node.js 12 is required
+if (typeof process.chdir === 'function') {
+  var chdir = process.chdir
+  process.chdir = function (d) {
+    cwd = null
+    chdir.call(process, d)
+  }
+  if (Object.setPrototypeOf) Object.setPrototypeOf(process.chdir, chdir)
 }
 
 module.exports = patch
@@ -115,20 +119,26 @@ function patch (fs) {
   }
 
   // if read() returns EAGAIN, then just try it again.
-  fs.read = (function (fs$read) { return function (fd, buffer, offset, length, position, callback_) {
-    var callback
-    if (callback_ && typeof callback_ === 'function') {
-      var eagCounter = 0
-      callback = function (er, _, __) {
-        if (er && er.code === 'EAGAIN' && eagCounter < 10) {
-          eagCounter ++
-          return fs$read.call(fs, fd, buffer, offset, length, position, callback)
+  fs.read = (function (fs$read) {
+    function read (fd, buffer, offset, length, position, callback_) {
+      var callback
+      if (callback_ && typeof callback_ === 'function') {
+        var eagCounter = 0
+        callback = function (er, _, __) {
+          if (er && er.code === 'EAGAIN' && eagCounter < 10) {
+            eagCounter ++
+            return fs$read.call(fs, fd, buffer, offset, length, position, callback)
+          }
+          callback_.apply(this, arguments)
         }
-        callback_.apply(this, arguments)
       }
+      return fs$read.call(fs, fd, buffer, offset, length, position, callback)
     }
-    return fs$read.call(fs, fd, buffer, offset, length, position, callback)
-  }})(fs.read)
+
+    // This ensures `util.promisify` works as it does for native `fs.read`.
+    if (Object.setPrototypeOf) Object.setPrototypeOf(read, fs$read)
+    return read
+  })(fs.read)
 
   fs.readSync = (function (fs$readSync) { return function (fd, buffer, offset, length, position) {
     var eagCounter = 0
@@ -272,18 +282,24 @@ function patch (fs) {
     }
   }
 
-
   function statFix (orig) {
     if (!orig) return orig
     // Older versions of Node erroneously returned signed integers for
     // uid + gid.
-    return function (target, cb) {
-      return orig.call(fs, target, function (er, stats) {
-        if (!stats) return cb.apply(this, arguments)
-        if (stats.uid < 0) stats.uid += 0x100000000
-        if (stats.gid < 0) stats.gid += 0x100000000
+    return function (target, options, cb) {
+      if (typeof options === 'function') {
+        cb = options
+        options = null
+      }
+      function callback (er, stats) {
+        if (stats) {
+          if (stats.uid < 0) stats.uid += 0x100000000
+          if (stats.gid < 0) stats.gid += 0x100000000
+        }
         if (cb) cb.apply(this, arguments)
-      })
+      }
+      return options ? orig.call(fs, target, options, callback)
+        : orig.call(fs, target, callback)
     }
   }
 
@@ -291,8 +307,9 @@ function patch (fs) {
     if (!orig) return orig
     // Older versions of Node erroneously returned signed integers for
     // uid + gid.
-    return function (target) {
-      var stats = orig.call(fs, target)
+    return function (target, options) {
+      var stats = options ? orig.call(fs, target, options)
+        : orig.call(fs, target)
       if (stats.uid < 0) stats.uid += 0x100000000
       if (stats.gid < 0) stats.gid += 0x100000000
       return stats;

+ 20 - 1
jsonfile/CHANGELOG.md

@@ -1,3 +1,21 @@
+4.0.0 / 2017-07-12
+------------------
+
+- **BREAKING:** Remove global `spaces` option.
+- **BREAKING:** Drop support for Node 0.10, 0.12, and io.js.
+- Remove undocumented `passParsingErrors` option.
+- Added `EOL` override option to `writeFile` when using `spaces`. [#89]
+
+3.0.1 / 2017-07-05
+------------------
+
+- Fixed bug in `writeFile` when there was a serialization error & no callback was passed. In previous versions, an empty file would be written; now no file is written.
+
+3.0.0 / 2017-04-25
+------------------
+
+- Changed behavior of `throws` option for `readFileSync`; now does not throw filesystem errors when `throws` is `false`
+
 2.4.0 / 2016-09-15
 ------------------
 ### Changed
@@ -79,12 +97,13 @@ changes it according to docs. [#12][#12]
 ------------------
 * Initial release.
 
+[#89]: https://github.com/jprichardson/node-jsonfile/pull/89
 [#45]: https://github.com/jprichardson/node-jsonfile/issues/45    "Reading of UTF8-encoded (w/ BOM) files fails"
 [#44]: https://github.com/jprichardson/node-jsonfile/issues/44    "Extra characters in written file"
 [#43]: https://github.com/jprichardson/node-jsonfile/issues/43    "Prettyfy json when written to file"
 [#42]: https://github.com/jprichardson/node-jsonfile/pull/42      "Moved fs.readFileSync within the try/catch"
 [#41]: https://github.com/jprichardson/node-jsonfile/issues/41    "Linux: Hidden file not working"
-[#40]: https://github.com/jprichardson/node-jsonfile/issues/40    "autocreate folder doesnt work from Path-value"
+[#40]: https://github.com/jprichardson/node-jsonfile/issues/40    "autocreate folder doesn't work from Path-value"
 [#39]: https://github.com/jprichardson/node-jsonfile/pull/39      "Add `throws` option for readFile (async)"
 [#38]: https://github.com/jprichardson/node-jsonfile/pull/38      "Update README.md writeFile[Sync] signature"
 [#37]: https://github.com/jprichardson/node-jsonfile/pull/37      "support append file"

+ 39 - 33
jsonfile/README.md

@@ -44,9 +44,8 @@ jsonfile.readFile(file, function(err, obj) {
 
 ### readFileSync(filename, [options])
 
-`options` (`object`, default `undefined`): Pass in any `fs.readFileSync` options or set `reviver` for a [JSON reviver](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse). 
-- `throws` (`boolean`, default: `true`). If `JSON.parse` throws an error, throw the error.
-If `false`, returns `null` for the object.
+`options` (`object`, default `undefined`): Pass in any `fs.readFileSync` options or set `reviver` for a [JSON reviver](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse).
+- `throws` (`boolean`, default: `true`). If an error is encountered reading or parsing the file, throw the error. If `false`, returns `null` for the object.
 
 ```js
 var jsonfile = require('jsonfile')
@@ -58,7 +57,7 @@ console.dir(jsonfile.readFileSync(file))
 
 ### writeFile(filename, obj, [options], callback)
 
-`options`: Pass in any `fs.writeFile` options or set `replacer` for a [JSON replacer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify). Can also pass in `spaces`.
+`options`: Pass in any `fs.writeFile` options or set `replacer` for a [JSON replacer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify). Can also pass in `spaces` and override `EOL` string.
 
 
 ```js
@@ -85,10 +84,7 @@ jsonfile.writeFile(file, obj, {spaces: 2}, function(err) {
 })
 ```
 
-
-### writeFileSync(filename, obj, [options])
-
-`options`: Pass in any `fs.writeFileSync` options or set `replacer` for a [JSON replacer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify). Can also pass in `spaces`.
+**overriding EOL:**
 
 ```js
 var jsonfile = require('jsonfile')
@@ -96,63 +92,73 @@ var jsonfile = require('jsonfile')
 var file = '/tmp/data.json'
 var obj = {name: 'JP'}
 
-jsonfile.writeFileSync(file, obj)
+jsonfile.writeFile(file, obj, {spaces: 2, EOL: '\r\n'}, function(err) {
+  console.error(err)
+})
 ```
 
-**formatting with spaces:**
+**appending to an existing JSON file:**
+
+You can use `fs.writeFile` option `{flag: 'a'}` to achieve this.
 
 ```js
 var jsonfile = require('jsonfile')
 
-var file = '/tmp/data.json'
+var file = '/tmp/mayAlreadyExistedData.json'
 var obj = {name: 'JP'}
 
-jsonfile.writeFileSync(file, obj, {spaces: 2})
+jsonfile.writeFile(file, obj, {flag: 'a'}, function (err) {
+  console.error(err)
+})
 ```
 
+### writeFileSync(filename, obj, [options])
 
+`options`: Pass in any `fs.writeFileSync` options or set `replacer` for a [JSON replacer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify). Can also pass in `spaces` and override `EOL` string.
 
-### spaces
+```js
+var jsonfile = require('jsonfile')
 
-Global configuration to set spaces to indent JSON files.
+var file = '/tmp/data.json'
+var obj = {name: 'JP'}
 
-**default:** `null`
+jsonfile.writeFileSync(file, obj)
+```
+
+**formatting with spaces:**
 
 ```js
 var jsonfile = require('jsonfile')
 
-jsonfile.spaces = 4
-
 var file = '/tmp/data.json'
 var obj = {name: 'JP'}
 
-// json file has four space indenting now
-jsonfile.writeFile(file, obj, function (err) {
-  console.error(err)
-})
+jsonfile.writeFileSync(file, obj, {spaces: 2})
 ```
 
-Note, it's bound to `this.spaces`. So, if you do this:
+**overriding EOL:**
 
 ```js
-var myObj = {}
-myObj.writeJsonSync = jsonfile.writeFileSync
-// => this.spaces = null
+var jsonfile = require('jsonfile')
+
+var file = '/tmp/data.json'
+var obj = {name: 'JP'}
+
+jsonfile.writeFileSync(file, obj, {spaces: 2, EOL: '\r\n'})
 ```
 
-Could do the following:
+**appending to an existing JSON file:**
+
+You can use `fs.writeFileSync` option `{flag: 'a'}` to achieve this.
 
 ```js
 var jsonfile = require('jsonfile')
-jsonfile.spaces = 4
-jsonfile.writeFileSync(file, obj) // will have 4 spaces indentation
 
-var myCrazyObj = {spaces: 32}
-myCrazyObj.writeJsonSync = jsonfile.writeFileSync
-myCrazyObj.writeJsonSync(file, obj) // will have 32 space indentation
-myCrazyObj.writeJsonSync(file, obj, {spaces: 2}) // will have only 2
-```
+var file = '/tmp/mayAlreadyExistedData.json'
+var obj = {name: 'JP'}
 
+jsonfile.writeFileSync(file, obj, {flag: 'a'})
+```
 
 License
 -------

+ 26 - 25
jsonfile/index.js

@@ -19,10 +19,7 @@ function readFile (file, options, callback) {
   var fs = options.fs || _fs
 
   var shouldThrow = true
-  // DO NOT USE 'passParsingErrors' THE NAME WILL CHANGE!!!, use 'throws' instead
-  if ('passParsingErrors' in options) {
-    shouldThrow = options.passParsingErrors
-  } else if ('throws' in options) {
+  if ('throws' in options) {
     shouldThrow = options.throws
   }
 
@@ -56,17 +53,13 @@ function readFileSync (file, options) {
   var fs = options.fs || _fs
 
   var shouldThrow = true
-  // DO NOT USE 'passParsingErrors' THE NAME WILL CHANGE!!!, use 'throws' instead
-  if ('passParsingErrors' in options) {
-    shouldThrow = options.passParsingErrors
-  } else if ('throws' in options) {
+  if ('throws' in options) {
     shouldThrow = options.throws
   }
 
-  var content = fs.readFileSync(file, options)
-  content = stripBom(content)
-
   try {
+    var content = fs.readFileSync(file, options)
+    content = stripBom(content)
     return JSON.parse(content, options.reviver)
   } catch (err) {
     if (shouldThrow) {
@@ -78,6 +71,23 @@ function readFileSync (file, options) {
   }
 }
 
+function stringify (obj, options) {
+  var spaces
+  var EOL = '\n'
+  if (typeof options === 'object' && options !== null) {
+    if (options.spaces) {
+      spaces = options.spaces
+    }
+    if (options.EOL) {
+      EOL = options.EOL
+    }
+  }
+
+  var str = JSON.stringify(obj, options ? options.replacer : null, spaces)
+
+  return str.replace(/\n/g, EOL) + EOL
+}
+
 function writeFile (file, obj, options, callback) {
   if (callback == null) {
     callback = options
@@ -86,16 +96,13 @@ function writeFile (file, obj, options, callback) {
   options = options || {}
   var fs = options.fs || _fs
 
-  var spaces = typeof options === 'object' && options !== null
-    ? 'spaces' in options
-    ? options.spaces : this.spaces
-    : this.spaces
-
   var str = ''
   try {
-    str = JSON.stringify(obj, options ? options.replacer : null, spaces) + '\n'
+    str = stringify(obj, options)
   } catch (err) {
-    if (callback) return callback(err, null)
+    // Need to return whether a callback was passed or not
+    if (callback) callback(err, null)
+    return
   }
 
   fs.writeFile(file, str, options, callback)
@@ -105,12 +112,7 @@ function writeFileSync (file, obj, options) {
   options = options || {}
   var fs = options.fs || _fs
 
-  var spaces = typeof options === 'object' && options !== null
-    ? 'spaces' in options
-    ? options.spaces : this.spaces
-    : this.spaces
-
-  var str = JSON.stringify(obj, options.replacer, spaces) + '\n'
+  var str = stringify(obj, options)
   // not sure if fs.writeFileSync returns anything, but just in case
   return fs.writeFileSync(file, str, options)
 }
@@ -123,7 +125,6 @@ function stripBom (content) {
 }
 
 var jsonfile = {
-  spaces: null,
   readFile: readFile,
   readFileSync: readFileSync,
   writeFile: writeFile,

+ 15 - 13
jsonfile/package.json

@@ -1,27 +1,27 @@
 {
-  "_from": "jsonfile@^2.1.0",
-  "_id": "jsonfile@2.4.0",
+  "_from": "jsonfile@^4.0.0",
+  "_id": "jsonfile@4.0.0",
   "_inBundle": false,
-  "_integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
+  "_integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
   "_location": "/jsonfile",
   "_phantomChildren": {},
   "_requested": {
     "type": "range",
     "registry": true,
-    "raw": "jsonfile@^2.1.0",
+    "raw": "jsonfile@^4.0.0",
     "name": "jsonfile",
     "escapedName": "jsonfile",
-    "rawSpec": "^2.1.0",
+    "rawSpec": "^4.0.0",
     "saveSpec": null,
-    "fetchSpec": "^2.1.0"
+    "fetchSpec": "^4.0.0"
   },
   "_requiredBy": [
     "/fs-extra"
   ],
-  "_resolved": "http://registry.npm.taobao.org/jsonfile/download/jsonfile-2.4.0.tgz",
-  "_shasum": "3736a2b428b87bbda0cc83b53fa3d633a35c2ae8",
-  "_spec": "jsonfile@^2.1.0",
-  "_where": "E:\\dev\\007\\node_module\\node10\\node_modules\\fs-extra",
+  "_resolved": "https://registry.nlark.com/jsonfile/download/jsonfile-4.0.0.tgz",
+  "_shasum": "8771aae0799b64076b76640fca058f9c10e33ecb",
+  "_spec": "jsonfile@^4.0.0",
+  "_where": "D:\\project\\server\\logtest\\node_modules\\fs-extra",
   "author": {
     "name": "JP Richardson",
     "email": "jprichardson@gmail.com"
@@ -37,10 +37,12 @@
   "description": "Easily read/write JSON files.",
   "devDependencies": {
     "mocha": "2.x",
-    "mock-fs": "^3.8.0",
     "rimraf": "^2.4.0",
-    "standard": "^6.0.8"
+    "standard": "^10.0.3"
   },
+  "files": [
+    "index.js"
+  ],
   "homepage": "https://github.com/jprichardson/node-jsonfile#readme",
   "keywords": [
     "read",
@@ -65,5 +67,5 @@
     "test": "npm run lint && npm run unit",
     "unit": "mocha"
   },
-  "version": "2.4.0"
+  "version": "4.0.0"
 }

+ 126 - 0
log4js/CHANGELOG.md

@@ -0,0 +1,126 @@
+# log4js-node changelog
+
+## 6.3.0
+
+- [Add option to file appender to remove ANSI colours](https://github.com/log4js-node/log4js-node/pull/1001) - thanks [@BlueCocoa](https://github.com/BlueCocoa)
+- [Do not create appender if no categories use it](https://github.com/log4js-node/log4js-node/pull/1002) - thanks [@rnd-debug](https://github.com/rnd-debug)
+- [Docs: better categories inheritance description](https://github.com/log4js-node/log4js-node/pull/1003) - thanks [@rnd-debug](https://github.com/rnd-debug)
+- [Better jsdoc docs](https://github.com/log4js-node/log4js-node/pull/1004) - thanks [@wataash](https://github.com/wataash)
+- [Typescript: access category field in Logger](https://github.com/log4js-node/log4js-node/pull/1006) - thanks [@rtvd](https://github.com/rtvd)
+- [Docs: influxdb appender](https://github.com/log4js-node/log4js-node/pull/1014) - thanks [@rnd-debug](https://github.com/rnd-debug)
+- [Support for fileSync appender in webpack](https://github.com/log4js-node/log4js-node/pull/1015) - thanks [@lauren-li](https://github.com/lauren-li)
+- [Docs: UDP appender](https://github.com/log4js-node/log4js-node/pull/1018) - thanks [@iassasin](https://github.com/iassasin)
+- [Style: spaces and tabs](https://github.com/log4js-node/log4js-node/pull/1016) - thanks [@abetomo](https://github.com/abetomo)
+
+## 6.2.1
+
+- [Update streamroller to 2.2.4 to fix incorrect filename matching during log rotation](https://github.com/log4js-node/log4js-node/pull/996)
+
+## 6.2.0
+
+- [Add custom message end token to TCP appender](https://github.com/log4js-node/log4js-node/pull/994) - thanks [@rnd-debug](https://github.com/rnd-debug)
+- [Update acorn (dev dep of a dep)](https://github.com/log4js-node/log4js-node/pull/992) - thanks Github Robots.
+
+## 6.1.2
+
+- [Handle out-of-order appender loading](https://github.com/log4js-node/log4js-node/pull/986) - thanks [@mvastola](https://github.com/mvastola)
+
+## 6.1.1
+
+- [Add guards for undefined shutdown callback](https://github.com/log4js-node/log4js-node/pull/972) - thanks [@aaron-edwards](https://github.com/aaron-edwards)
+- [Ignore .bob files](https://github.com/log4js-node/log4js-node/pull/975) - thanks [@cesine](https://github.com/cesine)
+- [Add mark method to type definitions](https://github.com/log4js-node/log4js-node/pull/984) - thanks [@techmunk](https://github.com/techmunk)
+
+## 6.1.0
+
+- [Add pause event to dateFile appender](https://github.com/log4js-node/log4js-node/pull/965) - thanks [@shayantabatabaee](https://github.com/shayantabatabaee)
+- [Add pause event to file appender](https://github.com/log4js-node/log4js-node/pull/938) - thanks [@shayantabatabaee](https://github.com/shayantabatabaee)
+- [Add pause/resume event to docs](https://github.com/log4js-node/log4js-node/pull/966)
+
+## 6.0.0
+
+- [Update streamroller to fix unhandled promise rejection](https://github.com/log4js-node/log4js-node/pull/962)
+- [Updated date-format library](https://github.com/log4js-node/log4js-node/pull/960)
+
+## 5.3.0
+
+- [Padding and truncation changes](https://github.com/log4js-node/log4js-node/pull/956)
+
+## 5.2.2
+
+- [Update streamroller to fix overwriting old files when using date rolling](https://github.com/log4js-node/log4js-node/pull/951)
+
+## 5.2.1
+
+- [Update streamroller to fix numToKeep not working with dateFile pattern that is all digits](https://github.com/log4js-node/log4js-node/pull/949)
+
+## 5.2.0
+
+- [Update streamroller to 2.2.0 (copy and truncate when file is busy)](https://github.com/log4js-node/log4js-node/pull/948)
+
+## 5.1.0
+
+- [Update streamroller to 2.1.0 (windows fixes)](https://github.com/log4js-node/log4js-node/pull/933)
+
+## 5.0.0
+
+- [Update streamroller to 2.0.0 (remove support for node v6)](https://github.com/log4js-node/log4js-node/pull/922)
+- [Update dependencies (mostly dev deps)](https://github.com/log4js-node/log4js-node/pull/923)
+- [Fix error when cluster not available](https://github.com/log4js-node/log4js-node/pull/930)
+- [Test coverage improvements](https://github.com/log4js-node/log4js-node/pull/925)
+
+## 4.5.1
+
+- [Update streamroller 1.0.5 -> 1.0.6 (to fix overwriting old backup log files)](https://github.com/log4js-node/log4js-node/pull/918)
+- [Dependency update: lodash 4.17.4 (dependency of a dependency, not log4js)](https://github.com/log4js-node/log4js-node/pull/917) - thanks Github Automated Security Thing.
+- [Dependency update: lodash 4.4.0 -> 4.5.0 (dependency of a dependency, not log4js)](https://github.com/log4js-node/log4js-node/pull/915) - thanks Github Automated Security Thing.
+
+## 4.5.0
+
+- [Override call stack parsing](https://github.com/log4js-node/log4js-node/pull/914) - thanks [@rommni](https://github.com/rommni)
+- [patternLayout filename depth token](https://github.com/log4js-node/log4js-node/pull/913) - thanks [@rommni](https://github.com/rommni)
+
+## 4.4.0
+
+- [Add option to pass appender module in config](https://github.com/log4js-node/log4js-node/pull/833) - thanks [@kaxelson](https://github.com/kaxelson)
+- [Added docs for passing appender module](https://github.com/log4js-node/log4js-node/pull/904)
+- [Updated dependencies](https://github.com/log4js-node/log4js-node/pull/900)
+
+## 4.3.2
+
+- [Types for enableCallStack](https://github.com/log4js-node/log4js-node/pull/897) - thanks [@citrusjunoss](https://github.com/citrusjunoss)
+
+## 4.3.1
+
+- [Fix for maxLogSize in dateFile appender](https://github.com/log4js-node/log4js-node/pull/889)
+
+## 4.3.0
+
+- [Feature: line number support](https://github.com/log4js-node/log4js-node/pull/879) - thanks [@victor0801x](https://github.com/victor0801x)
+- [Fix for missing core appenders in webpack](https://github.com/log4js-node/log4js-node/pull/882)
+
+## 4.2.0
+
+- [Feature: add appender and level inheritance](https://github.com/log4js-node/log4js-node/pull/863) - thanks [@pharapiak](https://github.com/pharapiak)
+- [Feature: add response to context for connectLogger](https://github.com/log4js-node/log4js-node/pull/862) - thanks [@leak4mk0](https://github.com/leak4mk0)
+- [Fix for broken sighup handler](https://github.com/log4js-node/log4js-node/pull/873)
+- [Add missing types for Level](https://github.com/log4js-node/log4js-node/pull/872) - thanks [@Ivkaa](https://github.com/Ivkaa)
+- [Typescript fixes for connect logger context](https://github.com/log4js-node/log4js-node/pull/876) - thanks [@leak4mk0](https://github.com/leak4mk0)
+- [Upgrade to streamroller-1.0.5 to fix log rotation bug](https://github.com/log4js-node/log4js-node/pull/878)
+
+## 4.1.1
+
+- [Various test fixes for node v12](https://github.com/log4js-node/log4js-node/pull/870)
+- [Fix layout problem in node v12](https://github.com/log4js-node/log4js-node/pull/860) - thanks [@bjornstar](https://github.com/bjornstar)
+- [Add missing types for addLevels](https://github.com/log4js-node/log4js-node/pull/867) - thanks [@Ivkaa](https://github.com/Ivkaa)
+- [Allow any return type for layout function](https://github.com/log4js-node/log4js-node/pull/845) - thanks [@xinbenlv](https://github.com/xinbenlv)
+
+## 4.1.0
+
+- Updated streamroller to 1.0.4, to fix a bug where the inital size of an existing file was ignored when appending
+- [Updated streamroller to 1.0.3](https://github.com/log4js-node/log4js-node/pull/841), to fix a crash bug if the date pattern was all digits.
+- [Updated dependencies](https://github.com/log4js-node/log4js-node/pull/840)
+
+## Previous versions
+
+Change information for older versions can be found by looking at the milestones in github.

+ 13 - 0
log4js/LICENSE

@@ -0,0 +1,13 @@
+Copyright 2015 Gareth Jones (with contributions from many other people)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.

+ 78 - 100
log4js/README.md

@@ -1,140 +1,118 @@
-# log4js-node [![Build Status](https://secure.travis-ci.org/nomiddlename/log4js-node.png?branch=master)](http://travis-ci.org/nomiddlename/log4js-node)
+# log4js-node [![Build Status](https://secure.travis-ci.org/log4js-node/log4js-node.png?branch=master)](http://travis-ci.org/log4js-node/log4js-node) [![codecov](https://codecov.io/gh/log4js-node/log4js-node/branch/master/graph/badge.svg)](https://codecov.io/gh/log4js-node/log4js-node)
 
+[![NPM](https://nodei.co/npm/log4js.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/log4js/)
 
-This is a conversion of the [log4js](http://log4js.berlios.de/index.html)
-framework to work with [node](http://nodejs.org). I've mainly stripped out the browser-specific code and tidied up some of the javascript. 
+This is a conversion of the [log4js](https://github.com/stritti/log4js)
+framework to work with [node](http://nodejs.org). I started out just stripping out the browser-specific code and tidying up some of the javascript to work better in node. It grew from there. Although it's got a similar name to the Java library [log4j](https://logging.apache.org/log4j/2.x/), thinking that it will behave the same way will only bring you sorrow and confusion.
+
+The full documentation is available [here](https://log4js-node.github.io/log4js-node/).
+
+[Changes in version 3.x](https://log4js-node.github.io/log4js-node/v3-changes.md)
+
+There have been a few changes between log4js 1.x and 2.x (and 0.x too). You should probably read this [migration guide](https://log4js-node.github.io/log4js-node/migration-guide.html) if things aren't working.
 
 Out of the box it supports the following features:
 
-* coloured console logging
-* replacement of node's console.log functions (optional)
-* file appender, with log rolling based on file size
-* SMTP appender
-* GELF appender
-* hook.io appender
-* multiprocess appender (useful when you've got worker processes)
-* a logger for connect/express servers
-* configurable log message layout/patterns
-* different log levels for different log categories (make some parts of your app log as DEBUG, others only ERRORS, etc.)
+- coloured console logging to stdout or stderr
+- file appender, with configurable log rolling based on file size or date
+- a logger for connect/express servers
+- configurable log message layout/patterns
+- different log levels for different log categories (make some parts of your app log as DEBUG, others only ERRORS, etc.)
 
-NOTE: from log4js 0.5 onwards you'll need to explicitly enable replacement of node's console.log functions. Do this either by calling `log4js.replaceConsole()` or configuring with an object or json file like this:
+Optional appenders are available:
 
-```javascript
-{
-  appenders: [
-    { type: "console" }
-  ],
-  replaceConsole: true
-}
-```
+- [SMTP](https://github.com/log4js-node/smtp)
+- [GELF](https://github.com/log4js-node/gelf)
+- [Loggly](https://github.com/log4js-node/loggly)
+- Logstash ([UDP](https://github.com/log4js-node/logstashUDP) and [HTTP](https://github.com/log4js-node/logstashHTTP))
+- logFaces ([UDP](https://github.com/log4js-node/logFaces-UDP) and [HTTP](https://github.com/log4js-node/logFaces-HTTP))
+- [RabbitMQ](https://github.com/log4js-node/rabbitmq)
+- [Redis](https://github.com/log4js-node/redis)
+- [Hipchat](https://github.com/log4js-node/hipchat)
+- [Slack](https://github.com/log4js-node/slack)
+- [mailgun](https://github.com/log4js-node/mailgun)
+- [InfluxDB](https://github.com/rnd-debug/log4js-influxdb-appender)
+
+## Getting help
+
+Having problems? Jump on the [slack](https://join.slack.com/t/log4js-node/shared_invite/enQtODkzMDQ3MzExMDczLWUzZmY0MmI0YWI1ZjFhODY0YjI0YmU1N2U5ZTRkOTYyYzg3MjY5NWI4M2FjZThjYjdiOGM0NjU2NzBmYTJjOGI) channel, or create an issue. If you want to help out with the development, the slack channel is a good place to go as well.
 
 ## installation
 
+```bash
 npm install log4js
-
+```
 
 ## usage
 
 Minimalist version:
+
 ```javascript
-var log4js = require('log4js');
+var log4js = require("log4js");
 var logger = log4js.getLogger();
+logger.level = "debug";
 logger.debug("Some debug messages");
 ```
-By default, log4js outputs to stdout with the coloured layout (thanks to [masylum](http://github.com/masylum)), so for the above you would see:
+
+By default, log4js will not output any logs (so that it can safely be used in libraries). The `level` for the `default` category is set to `OFF`. To enable logs, set the level (as in the example). This will then output to stdout with the coloured layout (thanks to [masylum](http://github.com/masylum)), so for the above you would see:
+
 ```bash
 [2010-01-17 11:43:37.987] [DEBUG] [default] - Some debug messages
 ```
-See example.js for a full example, but here's a snippet (also in fromreadme.js):
+
+See example.js for a full example, but here's a snippet (also in `examples/fromreadme.js`):
+
 ```javascript
-var log4js = require('log4js'); 
-//console log is loaded by default, so you won't normally need to do this
-//log4js.loadAppender('console');
-log4js.loadAppender('file');
-//log4js.addAppender(log4js.appenders.console());
-log4js.addAppender(log4js.appenders.file('logs/cheese.log'), 'cheese');
-
-var logger = log4js.getLogger('cheese');
-logger.setLevel('ERROR');
-
-logger.trace('Entering cheese testing');
-logger.debug('Got cheese.');
-logger.info('Cheese is Gouda.');
-logger.warn('Cheese is quite smelly.');
-logger.error('Cheese is too ripe!');
-logger.fatal('Cheese was breeding ground for listeria.');
+const log4js = require("log4js");
+log4js.configure({
+  appenders: { cheese: { type: "file", filename: "cheese.log" } },
+  categories: { default: { appenders: ["cheese"], level: "error" } }
+});
+
+const logger = log4js.getLogger("cheese");
+logger.trace("Entering cheese testing");
+logger.debug("Got cheese.");
+logger.info("Cheese is Comté.");
+logger.warn("Cheese is quite smelly.");
+logger.error("Cheese is too ripe!");
+logger.fatal("Cheese was breeding ground for listeria.");
 ```
-Output:
+
+Output (in `cheese.log`):
+
 ```bash
 [2010-01-17 11:43:37.987] [ERROR] cheese - Cheese is too ripe!
 [2010-01-17 11:43:37.990] [FATAL] cheese - Cheese was breeding ground for listeria.
-```    
-The first 5 lines of the code above could also be written as:
-```javascript
-var log4js = require('log4js');
-log4js.configure({
-  appenders: [
-    { type: 'console' },
-    { type: 'file', filename: 'logs/cheese.log', category: 'cheese' }
-  ]
-});
 ```
 
-## configuration
+## Note for library makers
 
-You can configure the appenders and log levels manually (as above), or provide a
-configuration file (`log4js.configure('path/to/file.json')`), or a configuration object. The 
-configuration file location may also be specified via the environment variable 
-LOG4JS_CONFIG (`export LOG4JS_CONFIG=path/to/file.json`). 
-An example file can be found in `test/log4js.json`. An example config file with log rolling is in `test/with-log-rolling.json`.
-By default, the configuration file is checked for changes every 60 seconds, and if changed, reloaded. This allows changes to logging levels to occur without restarting the application.
+If you're writing a library and would like to include support for log4js, without introducing a dependency headache for your users, take a look at [log4js-api](https://github.com/log4js-node/log4js-api).
 
-To turn off configuration file change checking, configure with:
+## Documentation
 
-```javascript
-var log4js = require('log4js');
-log4js.configure('my_log4js_configuration.json', {});
-```
-To specify a different period:
+Available [here](https://log4js-node.github.io/log4js-node/).
 
-```javascript
-log4js.configure('file.json', { reloadSecs: 300 });
-```
-For FileAppender you can also pass the path to the log directory as an option where all your log files would be stored.
+There's also [an example application](https://github.com/log4js-node/log4js-example).
 
-```javascript
-log4js.configure('my_log4js_configuration.json', { cwd: '/absolute/path/to/log/dir' });
-```
-If you have already defined an absolute path for one of the FileAppenders in the configuration file, you could add a "absolute": true to the particular FileAppender to override the cwd option passed. Here is an example configuration file:
-```json
-#### my_log4js_configuration.json ####
-{
-  "appenders": [
-    {
-      "type": "file",
-      "filename": "relative/path/to/log_file.log",
-      "maxLogSize": 20480,
-      "backups": 3,
-      "category": "relative-logger"
-    },
-    {
-      "type": "file",
-      "absolute": true,
-      "filename": "/absolute/path/to/log_file.log",
-      "maxLogSize": 20480,
-      "backups": 10,
-      "category": "absolute-logger"          
-    }
-  ]
-}
-```    
-Documentation for most of the core appenders can be found on the [wiki](https://github.com/nomiddlename/log4js-node/wiki/Appenders), otherwise take a look at the tests and the examples.
+## TypeScript
 
-## Documentation
-See the [wiki](https://github.com/nomiddlename/log4js-node/wiki). Improve the [wiki](https://github.com/nomiddlename/log4js-node/wiki), please.
+```ts
+import { configure, getLogger } from "log4js";
+configure("./filename");
+const logger = getLogger();
+logger.level = "debug";
+logger.debug("Some debug messages");
+
+configure({
+  appenders: { cheese: { type: "file", filename: "cheese.log" } },
+  categories: { default: { appenders: ["cheese"], level: "error" } }
+});
+```
 
 ## Contributing
-Contributions welcome, but take a look at the [rules](https://github.com/nomiddlename/log4js-node/wiki/Contributing) first.
+
+We're always looking for people to help out. Jump on [slack](https://join.slack.com/t/log4js-node/shared_invite/enQtODkzMDQ3MzExMDczLWUzZmY0MmI0YWI1ZjFhODY0YjI0YmU1N2U5ZTRkOTYyYzg3MjY5NWI4M2FjZThjYjdiOGM0NjU2NzBmYTJjOGI) and discuss what you want to do. Also, take a look at the [rules](https://log4js-node.github.io/log4js-node/contrib-guidelines.html) before submitting a pull request.
 
 ## License
 

+ 80 - 0
log4js/lib/LoggingEvent.js

@@ -0,0 +1,80 @@
+const flatted = require('flatted');
+const levels = require('./levels');
+
+/**
+ * @name LoggingEvent
+ * @namespace Log4js
+ */
+class LoggingEvent {
+  /**
+   * Models a logging event.
+   * @constructor
+   * @param {string} categoryName name of category
+   * @param {Log4js.Level} level level of message
+   * @param {Array} data objects to log
+   * @author Seth Chisamore
+   */
+  constructor(categoryName, level, data, context, location) {
+    this.startTime = new Date();
+    this.categoryName = categoryName;
+    this.data = data;
+    this.level = level;
+    this.context = Object.assign({}, context);
+    this.pid = process.pid;
+
+    if (location) {
+      this.functionName = location.functionName;
+      this.fileName = location.fileName;
+      this.lineNumber = location.lineNumber;
+      this.columnNumber = location.columnNumber;
+      this.callStack = location.callStack;
+    }
+  }
+
+  serialise() {
+    const logData = this.data.map((e) => {
+      // JSON.stringify(new Error('test')) returns {}, which is not really useful for us.
+      // The following allows us to serialize errors correctly.
+      if (e && e.message && e.stack) {
+        e = Object.assign({ message: e.message, stack: e.stack }, e);
+      }
+      return e;
+    });
+    this.data = logData;
+    return flatted.stringify(this);
+  }
+
+  static deserialise(serialised) {
+    let event;
+    try {
+      const rehydratedEvent = flatted.parse(serialised);
+      rehydratedEvent.data = rehydratedEvent.data.map((e) => {
+        if (e && e.message && e.stack) {
+          const fakeError = new Error(e);
+          Object.keys(e).forEach((key) => { fakeError[key] = e[key]; });
+          e = fakeError;
+        }
+        return e;
+      });
+      event = new LoggingEvent(
+        rehydratedEvent.categoryName,
+        levels.getLevel(rehydratedEvent.level.levelStr),
+        rehydratedEvent.data,
+        rehydratedEvent.context
+      );
+      event.startTime = new Date(rehydratedEvent.startTime);
+      event.pid = rehydratedEvent.pid;
+      event.cluster = rehydratedEvent.cluster;
+    } catch (e) {
+      event = new LoggingEvent(
+        'log4js',
+        levels.ERROR,
+        ['Unable to parse log:', serialised, 'because: ', e]
+      );
+    }
+
+    return event;
+  }
+}
+
+module.exports = LoggingEvent;

+ 44 - 0
log4js/lib/appenders/adapters.js

@@ -0,0 +1,44 @@
+function maxFileSizeUnitTransform(maxLogSize) {
+  if (typeof maxLogSize === 'number' && Number.isInteger(maxLogSize)) {
+    return maxLogSize;
+  }
+
+  const units = {
+    K: 1024,
+    M: 1024 * 1024,
+    G: 1024 * 1024 * 1024,
+  };
+  const validUnit = Object.keys(units);
+  const unit = maxLogSize.substr(maxLogSize.length - 1).toLocaleUpperCase();
+  const value = maxLogSize.substring(0, maxLogSize.length - 1).trim();
+
+  if (validUnit.indexOf(unit) < 0 || !Number.isInteger(Number(value))) {
+    throw Error(`maxLogSize: "${maxLogSize}" is invalid`);
+  } else {
+    return value * units[unit];
+  }
+}
+
+function adapter(configAdapter, config) {
+  const newConfig = Object.assign({}, config);
+  Object.keys(configAdapter).forEach((key) => {
+    if (newConfig[key]) {
+      newConfig[key] = configAdapter[key](config[key]);
+    }
+  });
+  return newConfig;
+}
+
+function fileAppenderAdapter(config) {
+  const configAdapter = {
+    maxLogSize: maxFileSizeUnitTransform
+  };
+  return adapter(configAdapter, config);
+}
+
+const adapters = {
+  file: fileAppenderAdapter,
+  fileSync: fileAppenderAdapter
+};
+
+module.exports.modifyConfig = config => (adapters[config.type] ? adapters[config.type](config) : config);

+ 19 - 0
log4js/lib/appenders/categoryFilter.js

@@ -0,0 +1,19 @@
+const debug = require('debug')('log4js:categoryFilter');
+
+function categoryFilter(excludes, appender) {
+  if (typeof excludes === 'string') excludes = [excludes];
+  return (logEvent) => {
+    debug(`Checking ${logEvent.categoryName} against ${excludes}`);
+    if (excludes.indexOf(logEvent.categoryName) === -1) {
+      debug('Not excluded, sending to appender');
+      appender(logEvent);
+    }
+  };
+}
+
+function configure(config, layouts, findAppender) {
+  const appender = findAppender(config.appender);
+  return categoryFilter(config.exclude, appender);
+}
+
+module.exports.configure = configure;

+ 9 - 12
log4js/lib/appenders/console.js

@@ -1,21 +1,18 @@
-"use strict";
-var layouts = require('../layouts')
-, consoleLog = console.log.bind(console);
+// eslint-disable-next-line no-console
+const consoleLog = console.log.bind(console);
 
-function consoleAppender (layout) {
-  layout = layout || layouts.colouredLayout;
-  return function(loggingEvent) {
-    consoleLog(layout(loggingEvent));
+function consoleAppender(layout, timezoneOffset) {
+  return (loggingEvent) => {
+    consoleLog(layout(loggingEvent, timezoneOffset));
   };
 }
 
-function configure(config) {
-  var layout;
+function configure(config, layouts) {
+  let layout = layouts.colouredLayout;
   if (config.layout) {
     layout = layouts.layout(config.layout.type, config.layout);
   }
-  return consoleAppender(layout);
+  return consoleAppender(layout, config.timezoneOffset);
 }
 
-exports.appender = consoleAppender;
-exports.configure = configure;
+module.exports.configure = configure;

+ 47 - 35
log4js/lib/appenders/dateFile.js

@@ -1,17 +1,7 @@
-"use strict";
-var streams = require('../streams')
-, layouts = require('../layouts')
-, path = require('path')
-, os = require('os')
-, eol = os.EOL || '\n'
-, openFiles = [];
-
-//close open files on process exit.
-process.on('exit', function() {
-  openFiles.forEach(function (file) {
-    file.end();
-  });
-});
+const streams = require('streamroller');
+const os = require('os');
+
+const eol = os.EOL;
 
 /**
  * File appender that rolls files according to a date pattern.
@@ -19,40 +9,62 @@ process.on('exit', function() {
  * @pattern the format that will be added to the end of filename when rolling,
  *          also used to check when to roll files - defaults to '.yyyy-MM-dd'
  * @layout layout function for log messages - defaults to basicLayout
+ * @timezoneOffset optional timezone offset in minutes - defaults to system local
  */
-function appender(filename, pattern, alwaysIncludePattern, layout) {
-  layout = layout || layouts.basicLayout;
+function appender(
+  filename,
+  pattern,
+  layout,
+  options,
+  timezoneOffset
+) {
+  // the options for file appender use maxLogSize, but the docs say any file appender
+  // options should work for dateFile as well.
+  options.maxSize = options.maxLogSize;
 
-  var logFile = new streams.DateRollingFileStream(
-    filename, 
-    pattern, 
-    { alwaysIncludePattern: alwaysIncludePattern }
+  const logFile = new streams.DateRollingFileStream(
+    filename,
+    pattern,
+    options
   );
-  openFiles.push(logFile);
-  
-  return function(logEvent) {
-    logFile.write(layout(logEvent) + eol, "utf8");
+
+  logFile.on("drain", () => {
+    process.emit("log4js:pause", false);
+  });
+
+  const app = function (logEvent) {
+    if (!logFile.write(layout(logEvent, timezoneOffset) + eol, "utf8")) {
+      process.emit("log4js:pause", true);
+    }
   };
 
+  app.shutdown = function (complete) {
+    logFile.write('', 'utf-8', () => {
+      logFile.end(complete);
+    });
+  };
+
+  return app;
 }
 
-function configure(config, options) {
-  var layout;
-  
+function configure(config, layouts) {
+  let layout = layouts.basicLayout;
+
   if (config.layout) {
     layout = layouts.layout(config.layout.type, config.layout);
   }
-  
+
   if (!config.alwaysIncludePattern) {
     config.alwaysIncludePattern = false;
   }
-  
-  if (options && options.cwd && !config.absolute) {
-    config.filename = path.join(options.cwd, config.filename);
-  }
 
-  return appender(config.filename, config.pattern, config.alwaysIncludePattern, layout);
+  return appender(
+    config.filename,
+    config.pattern,
+    layout,
+    config,
+    config.timezoneOffset
+  );
 }
 
-exports.appender = appender;
-exports.configure = configure;
+module.exports.configure = configure;

+ 81 - 56
log4js/lib/appenders/file.js

@@ -1,82 +1,107 @@
-"use strict";
-var layouts = require('../layouts')
-, path = require('path')
-, fs = require('fs')
-, streams = require('../streams')
-, os = require('os')
-, eol = os.EOL || '\n'
-, openFiles = [];
+const debug = require('debug')('log4js:file');
+const path = require('path');
+const streams = require('streamroller');
+const os = require('os');
 
-//close open files on process exit.
-process.on('exit', function() {
-  openFiles.forEach(function (file) {
-    file.end();
+const eol = os.EOL;
+
+function openTheStream(file, fileSize, numFiles, options) {
+  const stream = new streams.RollingFileStream(
+    file,
+    fileSize,
+    numFiles,
+    options
+  );
+  stream.on('error', (err) => {
+    console.error('log4js.fileAppender - Writing to file %s, error happened ', file, err); //eslint-disable-line
+  });
+  stream.on('drain', () => {
+    process.emit("log4js:pause", false);
   });
-});
+  return stream;
+}
+
 
 /**
  * File Appender writing the logs to a text file. Supports rolling of logs by size.
  *
  * @param file file log messages will be written to
- * @param layout a function that takes a logevent and returns a string 
+ * @param layout a function that takes a logEvent and returns a string
  *   (defaults to basicLayout).
- * @param logSize - the maximum size (in bytes) for a log file, 
+ * @param logSize - the maximum size (in bytes) for a log file,
  *   if not provided then logs won't be rotated.
- * @param numBackups - the number of log files to keep after logSize 
+ * @param numBackups - the number of log files to keep after logSize
  *   has been reached (default 5)
+ * @param options - options to be passed to the underlying stream
+ * @param timezoneOffset - optional timezone offset in minutes (default system local)
  */
-function fileAppender (file, layout, logSize, numBackups) {
-  var bytesWritten = 0;
+function fileAppender(file, layout, logSize, numBackups, options, timezoneOffset) {
   file = path.normalize(file);
-  layout = layout || layouts.basicLayout;
   numBackups = numBackups === undefined ? 5 : numBackups;
-  //there has to be at least one backup if logSize has been specified
+  // there has to be at least one backup if logSize has been specified
   numBackups = numBackups === 0 ? 1 : numBackups;
 
-  function openTheStream(file, fileSize, numFiles) {
-    var stream;
-    if (fileSize) {
-      stream = new streams.RollingFileStream(
-        file,
-        fileSize,
-        numFiles
-      );
-    } else {
-      stream = fs.createWriteStream(
-        file, 
-        { encoding: "utf8", 
-          mode: parseInt('0644', 8), 
-          flags: 'a' }
-      );
+  debug(
+    'Creating file appender (',
+    file, ', ',
+    logSize, ', ',
+    numBackups, ', ',
+    options, ', ',
+    timezoneOffset, ')'
+  );
+
+  let writer = openTheStream(file, logSize, numBackups, options);
+
+  const app = function (loggingEvent) {
+    if (options.removeColor === true) {
+      // eslint-disable-next-line no-control-regex
+      const regex = /\x1b[[0-9;]*m/g;
+      loggingEvent.data = loggingEvent.data.map(d => {
+        if (typeof d === 'string') return d.replace(regex, '')
+        return d
+      })
     }
-    stream.on("error", function (err) {
-      console.error("log4js.fileAppender - Writing to file %s, error happened ", file, err);
-    });
-    return stream;
-  }
+    if (!writer.write(layout(loggingEvent, timezoneOffset) + eol, "utf8")) {
+      process.emit('log4js:pause', true);
+    }
+  };
 
-  var logFile = openTheStream(file, logSize, numBackups);
-  
-  // push file to the stack of open handlers
-  openFiles.push(logFile);
-  
-  return function(loggingEvent) {
-    logFile.write(layout(loggingEvent) + eol, "utf8");
+  app.reopen = function () {
+    writer.end(() => { writer = openTheStream(file, logSize, numBackups, options); });
   };
+
+  app.sighupHandler = function () {
+    debug('SIGHUP handler called.');
+    app.reopen();
+  };
+
+  app.shutdown = function (complete) {
+    process.removeListener('SIGHUP', app.sighupHandler);
+    writer.end('', 'utf-8', complete);
+  };
+
+  // On SIGHUP, close and reopen all files. This allows this appender to work with
+  // logrotate. Note that if you are using logrotate, you should not set
+  // `logSize`.
+  process.on('SIGHUP', app.sighupHandler);
+
+  return app;
 }
 
-function configure(config, options) {
-  var layout;
+function configure(config, layouts) {
+  let layout = layouts.basicLayout;
   if (config.layout) {
     layout = layouts.layout(config.layout.type, config.layout);
   }
 
-  if (options && options.cwd && !config.absolute) {
-    config.filename = path.join(options.cwd, config.filename);
-  }
-
-  return fileAppender(config.filename, layout, config.maxLogSize, config.backups);
+  return fileAppender(
+    config.filename,
+    layout,
+    config.maxLogSize,
+    config.backups,
+    config,
+    config.timezoneOffset
+  );
 }
 
-exports.appender = fileAppender;
-exports.configure = configure;
+module.exports.configure = configure;

+ 208 - 0
log4js/lib/appenders/fileSync.js

@@ -0,0 +1,208 @@
+const debug = require('debug')('log4js:fileSync');
+const path = require('path');
+const fs = require('fs');
+const os = require('os');
+
+const eol = os.EOL || '\n';
+
+function touchFile(file, options) {
+  // if the file exists, nothing to do
+  if (fs.existsSync(file)) {
+    return;
+  }
+
+  // touch the file to apply flags (like w to truncate the file)
+  const id = fs.openSync(file, options.flags, options.mode);
+  fs.closeSync(id);
+}
+
+class RollingFileSync {
+  constructor(filename, size, backups, options) {
+    debug('In RollingFileStream');
+
+    function throwErrorIfArgumentsAreNotValid() {
+      if (!filename || !size || size <= 0) {
+        throw new Error('You must specify a filename and file size');
+      }
+    }
+
+    throwErrorIfArgumentsAreNotValid();
+
+    this.filename = filename;
+    this.size = size;
+    this.backups = backups || 1;
+    this.options = options;
+    this.currentSize = 0;
+
+    function currentFileSize(file) {
+      let fileSize = 0;
+
+      try {
+        fileSize = fs.statSync(file).size;
+      } catch (e) {
+        // file does not exist
+        touchFile(file, options);
+      }
+      return fileSize;
+    }
+
+    this.currentSize = currentFileSize(this.filename);
+  }
+
+  shouldRoll() {
+    debug('should roll with current size %d, and max size %d', this.currentSize, this.size);
+    return this.currentSize >= this.size;
+  }
+
+  roll(filename) {
+    const that = this;
+    const nameMatcher = new RegExp(`^${path.basename(filename)}`);
+
+    function justTheseFiles(item) {
+      return nameMatcher.test(item);
+    }
+
+    function index(filename_) {
+      return parseInt(filename_.substring((`${path.basename(filename)}.`).length), 10) || 0;
+    }
+
+    function byIndex(a, b) {
+      if (index(a) > index(b)) {
+        return 1;
+      }
+      if (index(a) < index(b)) {
+        return -1;
+      }
+
+      return 0;
+    }
+
+    function increaseFileIndex(fileToRename) {
+      const idx = index(fileToRename);
+      debug(`Index of ${fileToRename} is ${idx}`);
+      if (idx < that.backups) {
+        // on windows, you can get a EEXIST error if you rename a file to an existing file
+        // so, we'll try to delete the file we're renaming to first
+        try {
+          fs.unlinkSync(`${filename}.${idx + 1}`);
+        } catch (e) {
+          // ignore err: if we could not delete, it's most likely that it doesn't exist
+        }
+
+        debug(`Renaming ${fileToRename} -> ${filename}.${idx + 1}`);
+        fs.renameSync(path.join(path.dirname(filename), fileToRename), `${filename}.${idx + 1}`);
+      }
+    }
+
+    function renameTheFiles() {
+      // roll the backups (rename file.n to file.n+1, where n <= numBackups)
+      debug('Renaming the old files');
+
+      const files = fs.readdirSync(path.dirname(filename));
+      files.filter(justTheseFiles).sort(byIndex).reverse().forEach(increaseFileIndex);
+    }
+
+    debug('Rolling, rolling, rolling');
+    renameTheFiles();
+  }
+
+  /* eslint no-unused-vars:0 */
+  write(chunk, encoding) {
+    const that = this;
+
+
+    function writeTheChunk() {
+      debug('writing the chunk to the file');
+      that.currentSize += chunk.length;
+      fs.appendFileSync(that.filename, chunk);
+    }
+
+    debug('in write');
+
+
+    if (this.shouldRoll()) {
+      this.currentSize = 0;
+      this.roll(this.filename);
+    }
+
+    writeTheChunk();
+  }
+}
+
+/**
+ * File Appender writing the logs to a text file. Supports rolling of logs by size.
+ *
+ * @param file file log messages will be written to
+ * @param layout a function that takes a logevent and returns a string
+ *   (defaults to basicLayout).
+ * @param logSize - the maximum size (in bytes) for a log file,
+ *   if not provided then logs won't be rotated.
+ * @param numBackups - the number of log files to keep after logSize
+ *   has been reached (default 5)
+ * @param timezoneOffset - optional timezone offset in minutes
+ *   (default system local)
+ * @param options - passed as is to fs options
+ */
+function fileAppender(file, layout, logSize, numBackups, timezoneOffset, options) {
+  debug('fileSync appender created');
+  file = path.normalize(file);
+  numBackups = numBackups === undefined ? 5 : numBackups;
+  // there has to be at least one backup if logSize has been specified
+  numBackups = numBackups === 0 ? 1 : numBackups;
+
+  function openTheStream(filePath, fileSize, numFiles) {
+    let stream;
+
+    if (fileSize) {
+      stream = new RollingFileSync(
+        filePath,
+        fileSize,
+        numFiles,
+        options
+      );
+    } else {
+      stream = (((f) => {
+        // touch the file to apply flags (like w to truncate the file)
+        touchFile(f, options);
+
+        return {
+          write(data) {
+            fs.appendFileSync(f, data);
+          }
+        };
+      }))(filePath);
+    }
+
+    return stream;
+  }
+
+  const logFile = openTheStream(file, logSize, numBackups);
+
+  return (loggingEvent) => {
+    logFile.write(layout(loggingEvent, timezoneOffset) + eol);
+  };
+}
+
+function configure(config, layouts) {
+  let layout = layouts.basicLayout;
+  if (config.layout) {
+    layout = layouts.layout(config.layout.type, config.layout);
+  }
+
+  const options = {
+    flags: config.flags || 'a',
+    encoding: config.encoding || 'utf8',
+    mode: config.mode || 0o644
+  };
+
+  return fileAppender(
+    config.filename,
+    layout,
+    config.maxLogSize,
+    config.backups,
+    config.timezoneOffset,
+    options
+  );
+}
+
+module.exports.configure = configure;

+ 131 - 0
log4js/lib/appenders/index.js

@@ -0,0 +1,131 @@
+const path = require('path');
+const debug = require('debug')('log4js:appenders');
+const configuration = require('../configuration');
+const clustering = require('../clustering');
+const levels = require('../levels');
+const layouts = require('../layouts');
+const adapters = require('./adapters');
+
+// pre-load the core appenders so that webpack can find them
+const coreAppenders = new Map();
+coreAppenders.set('console', require('./console'));
+coreAppenders.set('stdout', require('./stdout'));
+coreAppenders.set('stderr', require('./stderr'));
+coreAppenders.set('logLevelFilter', require('./logLevelFilter'));
+coreAppenders.set('categoryFilter', require('./categoryFilter'));
+coreAppenders.set('noLogFilter', require('./noLogFilter'));
+coreAppenders.set('file', require('./file'));
+coreAppenders.set('dateFile', require('./dateFile'));
+coreAppenders.set('fileSync', require('./fileSync'));
+
+const appenders = new Map();
+
+const tryLoading = (modulePath, config) => {
+  debug('Loading module from ', modulePath);
+  try {
+    return require(modulePath); //eslint-disable-line
+  } catch (e) {
+    // if the module was found, and we still got an error, then raise it
+    configuration.throwExceptionIf(
+      config,
+      e.code !== 'MODULE_NOT_FOUND',
+      `appender "${modulePath}" could not be loaded (error was: ${e})`
+    );
+    return undefined;
+  }
+};
+
+const loadAppenderModule = (type, config) => coreAppenders.get(type)
+  || tryLoading(`./${type}`, config)
+  || tryLoading(type, config)
+  || (require.main && tryLoading(path.join(path.dirname(require.main.filename), type), config))
+  || tryLoading(path.join(process.cwd(), type), config);
+
+const appendersLoading = new Set();
+
+const getAppender = (name, config) => {
+  if (appenders.has(name)) return appenders.get(name);
+  if (!config.appenders[name]) return false;
+  if (appendersLoading.has(name)) throw new Error(`Dependency loop detected for appender ${name}.`);
+  appendersLoading.add(name);
+
+  debug(`Creating appender ${name}`);
+  // eslint-disable-next-line no-use-before-define
+  const appender = createAppender(name, config);
+  appendersLoading.delete(name);
+  appenders.set(name, appender);
+  return appender;
+};
+
+const createAppender = (name, config) => {
+  const appenderConfig = config.appenders[name];
+  const appenderModule = appenderConfig.type.configure
+    ? appenderConfig.type : loadAppenderModule(appenderConfig.type, config);
+  configuration.throwExceptionIf(
+    config,
+    configuration.not(appenderModule),
+    `appender "${name}" is not valid (type "${appenderConfig.type}" could not be found)`
+  );
+  if (appenderModule.appender) {
+    debug(`DEPRECATION: Appender ${appenderConfig.type} exports an appender function.`);
+  }
+  if (appenderModule.shutdown) {
+    debug(`DEPRECATION: Appender ${appenderConfig.type} exports a shutdown function.`);
+  }
+
+  debug(`${name}: clustering.isMaster ? ${clustering.isMaster()}`);
+  debug(`${name}: appenderModule is ${require('util').inspect(appenderModule)}`); // eslint-disable-line
+  return clustering.onlyOnMaster(() => {
+    debug(`calling appenderModule.configure for ${name} / ${appenderConfig.type}`);
+    return appenderModule.configure(
+      adapters.modifyConfig(appenderConfig),
+      layouts,
+      appender => getAppender(appender, config),
+      levels
+    );
+  }, () => { });
+};
+
+const setup = (config) => {
+  appenders.clear();
+  appendersLoading.clear();
+  const usedAppenders = [];
+  Object.values(config.categories).forEach(category => {
+    usedAppenders.push(...category.appenders)
+  });
+  Object.keys(config.appenders).forEach((name) => {
+    // dodgy hard-coding of special case for tcp-server which may not have
+    // any categories associated with it, but needs to be started up anyway
+    if (usedAppenders.includes(name) || config.appenders[name].type === 'tcp-server') {
+      getAppender(name, config);
+    }
+  });
+};
+
+setup({ appenders: { out: { type: 'stdout' } }, categories: { default: { appenders: ['out'], level: 'trace' } } });
+
+configuration.addListener((config) => {
+  configuration.throwExceptionIf(
+    config,
+    configuration.not(configuration.anObject(config.appenders)),
+    'must have a property "appenders" of type object.'
+  );
+  const appenderNames = Object.keys(config.appenders);
+  configuration.throwExceptionIf(
+    config,
+    configuration.not(appenderNames.length),
+    'must define at least one appender.'
+  );
+
+  appenderNames.forEach((name) => {
+    configuration.throwExceptionIf(
+      config,
+      configuration.not(config.appenders[name].type),
+      `appender "${name}" is not valid (must be an object with property "type")`
+    );
+  });
+});
+
+configuration.addListener(setup);
+
+module.exports = appenders;

+ 10 - 14
log4js/lib/appenders/logLevelFilter.js

@@ -1,21 +1,17 @@
-"use strict";
-var levels = require('../levels')
-, log4js = require('../log4js');
-
-function logLevelFilter (levelString, appender) {
-  var level = levels.toLevel(levelString);
-  return function(logEvent) {
-    if (logEvent.level.isGreaterThanOrEqualTo(level)) {
+function logLevelFilter(minLevelString, maxLevelString, appender, levels) {
+  const minLevel = levels.getLevel(minLevelString);
+  const maxLevel = levels.getLevel(maxLevelString, levels.FATAL);
+  return (logEvent) => {
+    const eventLevel = logEvent.level;
+    if (eventLevel.isGreaterThanOrEqualTo(minLevel) && eventLevel.isLessThanOrEqualTo(maxLevel)) {
       appender(logEvent);
     }
   };
 }
 
-function configure(config) {
-  log4js.loadAppender(config.appender.type);
-  var appender = log4js.appenderMakers[config.appender.type](config.appender);
-  return logLevelFilter(config.level, appender);
+function configure(config, layouts, findAppender, levels) {
+  const appender = findAppender(config.appender);
+  return logLevelFilter(config.level, config.maxLevel, appender, levels);
 }
 
-exports.appender = logLevelFilter;
-exports.configure = configure;
+module.exports.configure = configure;

+ 83 - 0
log4js/lib/appenders/multiFile.js

@@ -0,0 +1,83 @@
+
+
+const debug = require('debug')('log4js:multiFile');
+const path = require('path');
+const fileAppender = require('./file');
+
+const findFileKey = (property, event) => event[property] || event.context[property];
+
+module.exports.configure = (config, layouts) => {
+  debug('Creating a multi-file appender');
+  const files = new Map();
+  const timers = new Map();
+
+  function checkForTimeout(fileKey) {
+    const timer = timers.get(fileKey);
+    const app = files.get(fileKey);
+    if (timer && app) {
+      if (Date.now() - timer.lastUsed > timer.timeout) {
+        debug('%s not used for > %d ms => close', fileKey, timer.timeout);
+        clearInterval(timer.interval);
+        timers.delete(fileKey);
+        files.delete(fileKey);
+        app.shutdown((err) => {
+          if (err) {
+            debug('ignore error on file shutdown: %s', err.message);
+          }
+        });
+      }
+    }
+  }
+
+  const appender = (logEvent) => {
+    const fileKey = findFileKey(config.property, logEvent);
+    debug('fileKey for property ', config.property, ' is ', fileKey);
+    if (fileKey) {
+      let file = files.get(fileKey);
+      debug('existing file appender is ', file);
+      if (!file) {
+        debug('creating new file appender');
+        config.filename = path.join(config.base, fileKey + config.extension);
+        file = fileAppender.configure(config, layouts);
+        files.set(fileKey, file);
+        if (config.timeout) {
+          debug('creating new timer');
+          timers.set(fileKey, {
+            timeout: config.timeout,
+            lastUsed: Date.now(),
+            interval: setInterval(checkForTimeout.bind(null, fileKey), config.timeout)
+          });
+        }
+      } else if (config.timeout) {
+        timers.get(fileKey).lastUsed = Date.now();
+      }
+
+      file(logEvent);
+    } else {
+      debug('No fileKey for logEvent, quietly ignoring this log event');
+    }
+  };
+
+  appender.shutdown = (cb) => {
+    let shutdownFunctions = files.size;
+    if (shutdownFunctions <= 0) {
+      cb();
+    }
+    let error;
+    timers.forEach((timer) => {
+      clearInterval(timer.interval);
+    });
+    files.forEach((app, fileKey) => {
+      debug('calling shutdown for ', fileKey);
+      app.shutdown((err) => {
+        error = error || err;
+        shutdownFunctions -= 1;
+        if (shutdownFunctions <= 0) {
+          cb(error);
+        }
+      });
+    });
+  };
+
+  return appender;
+};

+ 121 - 70
log4js/lib/appenders/multiprocess.js

@@ -1,129 +1,180 @@
-"use strict";
-var log4js = require('../log4js')
-, net = require('net')
-, END_MSG = '__LOG4JS__';
+
+
+const debug = require('debug')('log4js:multiprocess');
+const net = require('net');
+const LoggingEvent = require('../LoggingEvent');
+
+const END_MSG = '__LOG4JS__';
 
 /**
  * Creates a server, listening on config.loggerPort, config.loggerHost.
  * Output goes to config.actualAppender (config.appender is used to
  * set up that appender).
  */
-function logServer(config) {
-  
+function logServer(config, actualAppender, levels) {
   /**
    * Takes a utf-8 string, returns an object with
    * the correct log properties.
    */
   function deserializeLoggingEvent(clientSocket, msg) {
-    var loggingEvent;
-    try {
-      loggingEvent = JSON.parse(msg);
-      loggingEvent.startTime = new Date(loggingEvent.startTime);
-      loggingEvent.level = log4js.levels.toLevel(loggingEvent.level.levelStr);
-    } catch (e) {
-      // JSON.parse failed, just log the contents probably a naughty.
-      loggingEvent = {
-        startTime: new Date(),
-        categoryName: 'log4js',
-        level: log4js.levels.ERROR,
-        data: [ 'Unable to parse log:', msg ]
-      };
-    }
-
+    debug('(master) deserialising log event');
+    const loggingEvent = LoggingEvent.deserialise(msg);
     loggingEvent.remoteAddress = clientSocket.remoteAddress;
     loggingEvent.remotePort = clientSocket.remotePort;
-    
+
     return loggingEvent;
   }
-  
-  var actualAppender = config.actualAppender,
-  server = net.createServer(function serverCreated(clientSocket) {
+
+  /* eslint prefer-arrow-callback:0 */
+  const server = net.createServer(function connectionHandler(clientSocket) {
+    debug('(master) connection received');
     clientSocket.setEncoding('utf8');
-    var logMessage = '';
-    
+    let logMessage = '';
+
     function logTheMessage(msg) {
       if (logMessage.length > 0) {
+        debug('(master) deserialising log event and sending to actual appender');
         actualAppender(deserializeLoggingEvent(clientSocket, msg));
       }
     }
-    
+
     function chunkReceived(chunk) {
-      var event;
+      debug('(master) chunk of data received');
+      let event;
       logMessage += chunk || '';
       if (logMessage.indexOf(END_MSG) > -1) {
         event = logMessage.substring(0, logMessage.indexOf(END_MSG));
         logTheMessage(event);
         logMessage = logMessage.substring(event.length + END_MSG.length) || '';
-        //check for more, maybe it was a big chunk
+        // check for more, maybe it was a big chunk
         chunkReceived();
       }
     }
-    
+
+    function handleError(error) {
+      const loggingEvent = {
+        startTime: new Date(),
+        categoryName: 'log4js',
+        level: levels.ERROR,
+        data: ['A worker log process hung up unexpectedly', error],
+        remoteAddress: clientSocket.remoteAddress,
+        remotePort: clientSocket.remotePort
+      };
+      actualAppender(loggingEvent);
+    }
+
     clientSocket.on('data', chunkReceived);
     clientSocket.on('end', chunkReceived);
+    clientSocket.on('error', handleError);
   });
-  
-  server.listen(config.loggerPort || 5000, config.loggerHost || 'localhost');
-  
-  return actualAppender;
+
+  server.listen(config.loggerPort || 5000, config.loggerHost || 'localhost', function (e) {
+    debug('(master) master server listening, error was ', e);
+    // allow the process to exit, if this is the only socket active
+    server.unref();
+  });
+
+  function app(event) {
+    debug('(master) log event sent directly to actual appender (local event)');
+    return actualAppender(event);
+  }
+
+  app.shutdown = function (cb) {
+    debug('(master) master shutdown called, closing server');
+    server.close(cb);
+  };
+
+  return app;
 }
 
 function workerAppender(config) {
-  var canWrite = false,
-  buffer = [],
-  socket;
-  
-  createSocket();
-  
+  let canWrite = false;
+  const buffer = [];
+  let socket;
+  let shutdownAttempts = 3;
+
+  function write(loggingEvent) {
+    debug('(worker) Writing log event to socket');
+    socket.write(loggingEvent.serialise(), 'utf8');
+    socket.write(END_MSG, 'utf8');
+  }
+
+  function emptyBuffer() {
+    let evt;
+    debug('(worker) emptying worker buffer');
+    /* eslint no-cond-assign:0 */
+    while ((evt = buffer.shift())) {
+      write(evt);
+    }
+  }
+
   function createSocket() {
+    debug(
+      `(worker) worker appender creating socket to ${config.loggerHost || 'localhost'}:${config.loggerPort || 5000}`
+    );
     socket = net.createConnection(config.loggerPort || 5000, config.loggerHost || 'localhost');
-    socket.on('connect', function() {
+    socket.on('connect', () => {
+      debug('(worker) worker socket connected');
       emptyBuffer();
       canWrite = true;
     });
     socket.on('timeout', socket.end.bind(socket));
-    //don't bother listening for 'error', 'close' gets called after that anyway
+    // don't bother listening for 'error', 'close' gets called after that anyway
     socket.on('close', createSocket);
   }
-  
-  function emptyBuffer() {
-    var evt;
-    while ((evt = buffer.shift())) {
-      write(evt);
-    }
-  }
-  
-  function write(loggingEvent) {
-    socket.write(JSON.stringify(loggingEvent), 'utf8');
-    socket.write(END_MSG, 'utf8');
-  }
-  
-  return function log(loggingEvent) {
+
+  createSocket();
+
+  function log(loggingEvent) {
     if (canWrite) {
       write(loggingEvent);
     } else {
+      debug('(worker) worker buffering log event because it cannot write at the moment');
       buffer.push(loggingEvent);
     }
+  }
+  log.shutdown = function (cb) {
+    debug('(worker) worker shutdown called');
+    if (buffer.length && shutdownAttempts) {
+      debug('(worker) worker buffer has items, waiting 100ms to empty');
+      shutdownAttempts -= 1;
+      setTimeout(() => {
+        log.shutdown(cb);
+      }, 100);
+    } else {
+      socket.removeAllListeners('close');
+      socket.end(cb);
+    }
   };
+  return log;
 }
 
-function createAppender(config) {
+function createAppender(config, appender, levels) {
   if (config.mode === 'master') {
-    return logServer(config);
-  } else {
-    return workerAppender(config);
+    debug('Creating master appender');
+    return logServer(config, appender, levels);
   }
+
+  debug('Creating worker appender');
+  return workerAppender(config);
 }
 
-function configure(config, options) {
-  var actualAppender;
-  if (config.appender && config.mode === 'master') {
-    log4js.loadAppender(config.appender.type);
-    actualAppender = log4js.appenderMakers[config.appender.type](config.appender, options);
-    config.actualAppender = actualAppender;
+function configure(config, layouts, findAppender, levels) {
+  let appender;
+  debug(`configure with mode = ${config.mode}`);
+  if (config.mode === 'master') {
+    if (!config.appender) {
+      debug(`no appender found in config ${config}`);
+      throw new Error('multiprocess master must have an "appender" defined');
+    }
+    debug(`actual appender is ${config.appender}`);
+    appender = findAppender(config.appender);
+    if (!appender) {
+      debug(`actual appender "${config.appender}" not found`);
+      throw new Error(`multiprocess master appender "${config.appender}" not defined`);
+    }
   }
-  return createAppender(config);
+  return createAppender(config, appender, levels);
 }
 
-exports.appender = createAppender;
-exports.configure = configure;
+module.exports.configure = configure;

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů