diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json index ea33509..6fa51ef 100644 --- a/node_modules/.package-lock.json +++ b/node_modules/.package-lock.json @@ -21,12 +21,12 @@ } }, "node_modules/accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dependencies": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" }, "engines": { "node": ">= 0.6" @@ -61,21 +61,26 @@ "node": ">= 0.8" } }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", "dependencies": { - "bytes": "3.1.0", + "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", "depd": "~1.1.2", - "http-errors": "1.7.2", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" + "qs": "6.9.7", + "raw-body": "2.4.3", + "type-is": "~1.6.18" }, "engines": { "node": ">= 0.8" @@ -91,9 +96,9 @@ } }, "node_modules/bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "engines": { "node": ">= 0.8" } @@ -104,11 +109,11 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "node_modules/content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dependencies": { - "safe-buffer": "5.1.2" + "safe-buffer": "5.2.1" }, "engines": { "node": ">= 0.6" @@ -123,9 +128,9 @@ } }, "node_modules/cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", "engines": { "node": ">= 0.6" } @@ -197,16 +202,16 @@ } }, "node_modules/express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", + "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", "dependencies": { - "accepts": "~1.3.7", + "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", + "body-parser": "1.19.2", + "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.0", + "cookie": "0.4.2", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "~1.1.2", @@ -220,13 +225,13 @@ "on-finished": "~2.3.0", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", + "proxy-addr": "~2.0.7", + "qs": "6.9.7", "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", "statuses": "~1.5.0", "type-is": "~1.6.18", "utils-merge": "1.0.1", @@ -237,12 +242,12 @@ } }, "node_modules/express-handlebars": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/express-handlebars/-/express-handlebars-5.3.4.tgz", - "integrity": "sha512-b36grfkbXZItLLQV6cwzA20o6Zg4Eckke3PjHF4EGQIQLGs5IPMjpAxepdGb45A/bECekXzA9STzNqvEgrdRPw==", + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/express-handlebars/-/express-handlebars-5.3.5.tgz", + "integrity": "sha512-r9pzDc94ZNJ7FVvtsxLfPybmN0eFAUnR61oimNPRpD0D7nkLcezrkpZzoXS5TI75wYHRbflPLTU39B62pwB4DA==", "dependencies": { "glob": "^7.2.0", - "graceful-fs": "^4.2.7", + "graceful-fs": "^4.2.8", "handlebars": "^4.7.7" }, "engines": { @@ -326,9 +331,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" }, "node_modules/handlebars": { "version": "4.7.7", @@ -351,15 +356,15 @@ } }, "node_modules/http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "dependencies": { "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "toidentifier": "1.0.1" }, "engines": { "node": ">= 0.6" @@ -386,9 +391,9 @@ } }, "node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ipaddr.js": { "version": "1.9.1", @@ -431,28 +436,28 @@ } }, "node_modules/mime-db": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", - "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.33", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", - "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dependencies": { - "mime-db": "1.50.0" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" } }, "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -494,9 +499,9 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "node_modules/negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "engines": { "node": ">= 0.6" } @@ -567,11 +572,14 @@ } }, "node_modules/qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", "engines": { "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/range-parser": { @@ -583,12 +591,12 @@ } }, "node_modules/raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", + "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", "dependencies": { - "bytes": "3.1.0", - "http-errors": "1.7.2", + "bytes": "3.1.2", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, @@ -597,9 +605,23 @@ } }, "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/safer-buffer": { "version": "2.1.2", @@ -607,9 +629,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", + "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", "dependencies": { "debug": "2.6.9", "depd": "~1.1.2", @@ -618,9 +640,9 @@ "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "1.8.1", "mime": "1.6.0", - "ms": "2.1.1", + "ms": "2.1.3", "on-finished": "~2.3.0", "range-parser": "~1.2.1", "statuses": "~1.5.0" @@ -630,28 +652,28 @@ } }, "node_modules/send/node_modules/ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", + "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.1" + "send": "0.17.2" }, "engines": { "node": ">= 0.8.0" } }, "node_modules/setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "node_modules/source-map": { "version": "0.6.1", @@ -670,9 +692,9 @@ } }, "node_modules/toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "engines": { "node": ">=0.6" } @@ -698,9 +720,9 @@ } }, "node_modules/uglify-js": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.2.tgz", - "integrity": "sha512-rtPMlmcO4agTUfz10CbgJ1k6UAoXM2gWb3GoMPPZB/+/Ackf8lNWk11K4rYi2D0apgoFRLtQOZhb+/iGNJq26A==", + "version": "3.15.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.3.tgz", + "integrity": "sha512-6iCVm2omGJbsu3JWac+p6kUiOpg3wFO2f8lIXjfEb8RrmLjzog1wTPMmwKB7swfzzqxj9YM+sGUM++u1qN4qJg==", "optional": true, "bin": { "uglifyjs": "bin/uglifyjs" diff --git a/node_modules/accepts/HISTORY.md b/node_modules/accepts/HISTORY.md index 0bf0417..cb5990c 100644 --- a/node_modules/accepts/HISTORY.md +++ b/node_modules/accepts/HISTORY.md @@ -1,3 +1,10 @@ +1.3.8 / 2022-02-02 +================== + + * deps: mime-types@~2.1.34 + - deps: mime-db@~1.51.0 + * deps: negotiator@0.6.3 + 1.3.7 / 2019-04-29 ================== diff --git a/node_modules/accepts/README.md b/node_modules/accepts/README.md index 66a2f54..82680c5 100644 --- a/node_modules/accepts/README.md +++ b/node_modules/accepts/README.md @@ -3,7 +3,7 @@ [![NPM Version][npm-version-image]][npm-url] [![NPM Downloads][npm-downloads-image]][npm-url] [![Node.js Version][node-version-image]][node-version-url] -[![Build Status][travis-image]][travis-url] +[![Build Status][github-actions-ci-image]][github-actions-ci-url] [![Test Coverage][coveralls-image]][coveralls-url] Higher level content negotiation based on [negotiator](https://www.npmjs.com/package/negotiator). @@ -29,8 +29,6 @@ $ npm install accepts ## API - - ```js var accepts = require('accepts') ``` @@ -133,10 +131,10 @@ curl -I -H'Accept: text/html' http://localhost:3000/ [coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/accepts/master [coveralls-url]: https://coveralls.io/r/jshttp/accepts?branch=master +[github-actions-ci-image]: https://badgen.net/github/checks/jshttp/accepts/master?label=ci +[github-actions-ci-url]: https://github.com/jshttp/accepts/actions/workflows/ci.yml [node-version-image]: https://badgen.net/npm/node/accepts [node-version-url]: https://nodejs.org/en/download [npm-downloads-image]: https://badgen.net/npm/dm/accepts [npm-url]: https://npmjs.org/package/accepts [npm-version-image]: https://badgen.net/npm/v/accepts -[travis-image]: https://badgen.net/travis/jshttp/accepts/master -[travis-url]: https://travis-ci.org/jshttp/accepts diff --git a/node_modules/accepts/package.json b/node_modules/accepts/package.json index bc750cf..0f2d15d 100644 --- a/node_modules/accepts/package.json +++ b/node_modules/accepts/package.json @@ -1,7 +1,7 @@ { "name": "accepts", "description": "Higher-level content negotiation", - "version": "1.3.7", + "version": "1.3.8", "contributors": [ "Douglas Christopher Wilson ", "Jonathan Ong (http://jongleberry.com)" @@ -9,20 +9,20 @@ "license": "MIT", "repository": "jshttp/accepts", "dependencies": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" }, "devDependencies": { "deep-equal": "1.0.1", - "eslint": "5.16.0", - "eslint-config-standard": "12.0.0", - "eslint-plugin-import": "2.17.2", - "eslint-plugin-markdown": "1.0.0", - "eslint-plugin-node": "8.0.1", - "eslint-plugin-promise": "4.1.1", - "eslint-plugin-standard": "4.0.0", - "mocha": "6.1.4", - "nyc": "14.0.0" + "eslint": "7.32.0", + "eslint-config-standard": "14.1.1", + "eslint-plugin-import": "2.25.4", + "eslint-plugin-markdown": "2.2.1", + "eslint-plugin-node": "11.1.0", + "eslint-plugin-promise": "4.3.1", + "eslint-plugin-standard": "4.1.0", + "mocha": "9.2.0", + "nyc": "15.1.0" }, "files": [ "LICENSE", @@ -33,10 +33,10 @@ "node": ">= 0.6" }, "scripts": { - "lint": "eslint --plugin markdown --ext js,md .", + "lint": "eslint .", "test": "mocha --reporter spec --check-leaks --bail test/", - "test-cov": "nyc --reporter=html --reporter=text npm test", - "test-travis": "nyc --reporter=text npm test" + "test-ci": "nyc --reporter=lcov --reporter=text npm test", + "test-cov": "nyc --reporter=html --reporter=text npm test" }, "keywords": [ "content", diff --git a/node_modules/basic-auth/node_modules/safe-buffer/LICENSE b/node_modules/basic-auth/node_modules/safe-buffer/LICENSE new file mode 100644 index 0000000..0c068ce --- /dev/null +++ b/node_modules/basic-auth/node_modules/safe-buffer/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Feross Aboukhadijeh + +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. diff --git a/node_modules/basic-auth/node_modules/safe-buffer/README.md b/node_modules/basic-auth/node_modules/safe-buffer/README.md new file mode 100644 index 0000000..e9a81af --- /dev/null +++ b/node_modules/basic-auth/node_modules/safe-buffer/README.md @@ -0,0 +1,584 @@ +# safe-buffer [![travis][travis-image]][travis-url] [![npm][npm-image]][npm-url] [![downloads][downloads-image]][downloads-url] [![javascript style guide][standard-image]][standard-url] + +[travis-image]: https://img.shields.io/travis/feross/safe-buffer/master.svg +[travis-url]: https://travis-ci.org/feross/safe-buffer +[npm-image]: https://img.shields.io/npm/v/safe-buffer.svg +[npm-url]: https://npmjs.org/package/safe-buffer +[downloads-image]: https://img.shields.io/npm/dm/safe-buffer.svg +[downloads-url]: https://npmjs.org/package/safe-buffer +[standard-image]: https://img.shields.io/badge/code_style-standard-brightgreen.svg +[standard-url]: https://standardjs.com + +#### Safer Node.js Buffer API + +**Use the new Node.js Buffer APIs (`Buffer.from`, `Buffer.alloc`, +`Buffer.allocUnsafe`, `Buffer.allocUnsafeSlow`) in all versions of Node.js.** + +**Uses the built-in implementation when available.** + +## install + +``` +npm install safe-buffer +``` + +## usage + +The goal of this package is to provide a safe replacement for the node.js `Buffer`. + +It's a drop-in replacement for `Buffer`. You can use it by adding one `require` line to +the top of your node.js modules: + +```js +var Buffer = require('safe-buffer').Buffer + +// Existing buffer code will continue to work without issues: + +new Buffer('hey', 'utf8') +new Buffer([1, 2, 3], 'utf8') +new Buffer(obj) +new Buffer(16) // create an uninitialized buffer (potentially unsafe) + +// But you can use these new explicit APIs to make clear what you want: + +Buffer.from('hey', 'utf8') // convert from many types to a Buffer +Buffer.alloc(16) // create a zero-filled buffer (safe) +Buffer.allocUnsafe(16) // create an uninitialized buffer (potentially unsafe) +``` + +## api + +### Class Method: Buffer.from(array) + + +* `array` {Array} + +Allocates a new `Buffer` using an `array` of octets. + +```js +const buf = Buffer.from([0x62,0x75,0x66,0x66,0x65,0x72]); + // creates a new Buffer containing ASCII bytes + // ['b','u','f','f','e','r'] +``` + +A `TypeError` will be thrown if `array` is not an `Array`. + +### Class Method: Buffer.from(arrayBuffer[, byteOffset[, length]]) + + +* `arrayBuffer` {ArrayBuffer} The `.buffer` property of a `TypedArray` or + a `new ArrayBuffer()` +* `byteOffset` {Number} Default: `0` +* `length` {Number} Default: `arrayBuffer.length - byteOffset` + +When passed a reference to the `.buffer` property of a `TypedArray` instance, +the newly created `Buffer` will share the same allocated memory as the +TypedArray. + +```js +const arr = new Uint16Array(2); +arr[0] = 5000; +arr[1] = 4000; + +const buf = Buffer.from(arr.buffer); // shares the memory with arr; + +console.log(buf); + // Prints: + +// changing the TypedArray changes the Buffer also +arr[1] = 6000; + +console.log(buf); + // Prints: +``` + +The optional `byteOffset` and `length` arguments specify a memory range within +the `arrayBuffer` that will be shared by the `Buffer`. + +```js +const ab = new ArrayBuffer(10); +const buf = Buffer.from(ab, 0, 2); +console.log(buf.length); + // Prints: 2 +``` + +A `TypeError` will be thrown if `arrayBuffer` is not an `ArrayBuffer`. + +### Class Method: Buffer.from(buffer) + + +* `buffer` {Buffer} + +Copies the passed `buffer` data onto a new `Buffer` instance. + +```js +const buf1 = Buffer.from('buffer'); +const buf2 = Buffer.from(buf1); + +buf1[0] = 0x61; +console.log(buf1.toString()); + // 'auffer' +console.log(buf2.toString()); + // 'buffer' (copy is not changed) +``` + +A `TypeError` will be thrown if `buffer` is not a `Buffer`. + +### Class Method: Buffer.from(str[, encoding]) + + +* `str` {String} String to encode. +* `encoding` {String} Encoding to use, Default: `'utf8'` + +Creates a new `Buffer` containing the given JavaScript string `str`. If +provided, the `encoding` parameter identifies the character encoding. +If not provided, `encoding` defaults to `'utf8'`. + +```js +const buf1 = Buffer.from('this is a tést'); +console.log(buf1.toString()); + // prints: this is a tést +console.log(buf1.toString('ascii')); + // prints: this is a tC)st + +const buf2 = Buffer.from('7468697320697320612074c3a97374', 'hex'); +console.log(buf2.toString()); + // prints: this is a tést +``` + +A `TypeError` will be thrown if `str` is not a string. + +### Class Method: Buffer.alloc(size[, fill[, encoding]]) + + +* `size` {Number} +* `fill` {Value} Default: `undefined` +* `encoding` {String} Default: `utf8` + +Allocates a new `Buffer` of `size` bytes. If `fill` is `undefined`, the +`Buffer` will be *zero-filled*. + +```js +const buf = Buffer.alloc(5); +console.log(buf); + // +``` + +The `size` must be less than or equal to the value of +`require('buffer').kMaxLength` (on 64-bit architectures, `kMaxLength` is +`(2^31)-1`). Otherwise, a [`RangeError`][] is thrown. A zero-length Buffer will +be created if a `size` less than or equal to 0 is specified. + +If `fill` is specified, the allocated `Buffer` will be initialized by calling +`buf.fill(fill)`. See [`buf.fill()`][] for more information. + +```js +const buf = Buffer.alloc(5, 'a'); +console.log(buf); + // +``` + +If both `fill` and `encoding` are specified, the allocated `Buffer` will be +initialized by calling `buf.fill(fill, encoding)`. For example: + +```js +const buf = Buffer.alloc(11, 'aGVsbG8gd29ybGQ=', 'base64'); +console.log(buf); + // +``` + +Calling `Buffer.alloc(size)` can be significantly slower than the alternative +`Buffer.allocUnsafe(size)` but ensures that the newly created `Buffer` instance +contents will *never contain sensitive data*. + +A `TypeError` will be thrown if `size` is not a number. + +### Class Method: Buffer.allocUnsafe(size) + + +* `size` {Number} + +Allocates a new *non-zero-filled* `Buffer` of `size` bytes. The `size` must +be less than or equal to the value of `require('buffer').kMaxLength` (on 64-bit +architectures, `kMaxLength` is `(2^31)-1`). Otherwise, a [`RangeError`][] is +thrown. A zero-length Buffer will be created if a `size` less than or equal to +0 is specified. + +The underlying memory for `Buffer` instances created in this way is *not +initialized*. The contents of the newly created `Buffer` are unknown and +*may contain sensitive data*. Use [`buf.fill(0)`][] to initialize such +`Buffer` instances to zeroes. + +```js +const buf = Buffer.allocUnsafe(5); +console.log(buf); + // + // (octets will be different, every time) +buf.fill(0); +console.log(buf); + // +``` + +A `TypeError` will be thrown if `size` is not a number. + +Note that the `Buffer` module pre-allocates an internal `Buffer` instance of +size `Buffer.poolSize` that is used as a pool for the fast allocation of new +`Buffer` instances created using `Buffer.allocUnsafe(size)` (and the deprecated +`new Buffer(size)` constructor) only when `size` is less than or equal to +`Buffer.poolSize >> 1` (floor of `Buffer.poolSize` divided by two). The default +value of `Buffer.poolSize` is `8192` but can be modified. + +Use of this pre-allocated internal memory pool is a key difference between +calling `Buffer.alloc(size, fill)` vs. `Buffer.allocUnsafe(size).fill(fill)`. +Specifically, `Buffer.alloc(size, fill)` will *never* use the internal Buffer +pool, while `Buffer.allocUnsafe(size).fill(fill)` *will* use the internal +Buffer pool if `size` is less than or equal to half `Buffer.poolSize`. The +difference is subtle but can be important when an application requires the +additional performance that `Buffer.allocUnsafe(size)` provides. + +### Class Method: Buffer.allocUnsafeSlow(size) + + +* `size` {Number} + +Allocates a new *non-zero-filled* and non-pooled `Buffer` of `size` bytes. The +`size` must be less than or equal to the value of +`require('buffer').kMaxLength` (on 64-bit architectures, `kMaxLength` is +`(2^31)-1`). Otherwise, a [`RangeError`][] is thrown. A zero-length Buffer will +be created if a `size` less than or equal to 0 is specified. + +The underlying memory for `Buffer` instances created in this way is *not +initialized*. The contents of the newly created `Buffer` are unknown and +*may contain sensitive data*. Use [`buf.fill(0)`][] to initialize such +`Buffer` instances to zeroes. + +When using `Buffer.allocUnsafe()` to allocate new `Buffer` instances, +allocations under 4KB are, by default, sliced from a single pre-allocated +`Buffer`. This allows applications to avoid the garbage collection overhead of +creating many individually allocated Buffers. This approach improves both +performance and memory usage by eliminating the need to track and cleanup as +many `Persistent` objects. + +However, in the case where a developer may need to retain a small chunk of +memory from a pool for an indeterminate amount of time, it may be appropriate +to create an un-pooled Buffer instance using `Buffer.allocUnsafeSlow()` then +copy out the relevant bits. + +```js +// need to keep around a few small chunks of memory +const store = []; + +socket.on('readable', () => { + const data = socket.read(); + // allocate for retained data + const sb = Buffer.allocUnsafeSlow(10); + // copy the data into the new allocation + data.copy(sb, 0, 0, 10); + store.push(sb); +}); +``` + +Use of `Buffer.allocUnsafeSlow()` should be used only as a last resort *after* +a developer has observed undue memory retention in their applications. + +A `TypeError` will be thrown if `size` is not a number. + +### All the Rest + +The rest of the `Buffer` API is exactly the same as in node.js. +[See the docs](https://nodejs.org/api/buffer.html). + + +## Related links + +- [Node.js issue: Buffer(number) is unsafe](https://github.com/nodejs/node/issues/4660) +- [Node.js Enhancement Proposal: Buffer.from/Buffer.alloc/Buffer.zalloc/Buffer() soft-deprecate](https://github.com/nodejs/node-eps/pull/4) + +## Why is `Buffer` unsafe? + +Today, the node.js `Buffer` constructor is overloaded to handle many different argument +types like `String`, `Array`, `Object`, `TypedArrayView` (`Uint8Array`, etc.), +`ArrayBuffer`, and also `Number`. + +The API is optimized for convenience: you can throw any type at it, and it will try to do +what you want. + +Because the Buffer constructor is so powerful, you often see code like this: + +```js +// Convert UTF-8 strings to hex +function toHex (str) { + return new Buffer(str).toString('hex') +} +``` + +***But what happens if `toHex` is called with a `Number` argument?*** + +### Remote Memory Disclosure + +If an attacker can make your program call the `Buffer` constructor with a `Number` +argument, then they can make it allocate uninitialized memory from the node.js process. +This could potentially disclose TLS private keys, user data, or database passwords. + +When the `Buffer` constructor is passed a `Number` argument, it returns an +**UNINITIALIZED** block of memory of the specified `size`. When you create a `Buffer` like +this, you **MUST** overwrite the contents before returning it to the user. + +From the [node.js docs](https://nodejs.org/api/buffer.html#buffer_new_buffer_size): + +> `new Buffer(size)` +> +> - `size` Number +> +> The underlying memory for `Buffer` instances created in this way is not initialized. +> **The contents of a newly created `Buffer` are unknown and could contain sensitive +> data.** Use `buf.fill(0)` to initialize a Buffer to zeroes. + +(Emphasis our own.) + +Whenever the programmer intended to create an uninitialized `Buffer` you often see code +like this: + +```js +var buf = new Buffer(16) + +// Immediately overwrite the uninitialized buffer with data from another buffer +for (var i = 0; i < buf.length; i++) { + buf[i] = otherBuf[i] +} +``` + + +### Would this ever be a problem in real code? + +Yes. It's surprisingly common to forget to check the type of your variables in a +dynamically-typed language like JavaScript. + +Usually the consequences of assuming the wrong type is that your program crashes with an +uncaught exception. But the failure mode for forgetting to check the type of arguments to +the `Buffer` constructor is more catastrophic. + +Here's an example of a vulnerable service that takes a JSON payload and converts it to +hex: + +```js +// Take a JSON payload {str: "some string"} and convert it to hex +var server = http.createServer(function (req, res) { + var data = '' + req.setEncoding('utf8') + req.on('data', function (chunk) { + data += chunk + }) + req.on('end', function () { + var body = JSON.parse(data) + res.end(new Buffer(body.str).toString('hex')) + }) +}) + +server.listen(8080) +``` + +In this example, an http client just has to send: + +```json +{ + "str": 1000 +} +``` + +and it will get back 1,000 bytes of uninitialized memory from the server. + +This is a very serious bug. It's similar in severity to the +[the Heartbleed bug](http://heartbleed.com/) that allowed disclosure of OpenSSL process +memory by remote attackers. + + +### Which real-world packages were vulnerable? + +#### [`bittorrent-dht`](https://www.npmjs.com/package/bittorrent-dht) + +[Mathias Buus](https://github.com/mafintosh) and I +([Feross Aboukhadijeh](http://feross.org/)) found this issue in one of our own packages, +[`bittorrent-dht`](https://www.npmjs.com/package/bittorrent-dht). The bug would allow +anyone on the internet to send a series of messages to a user of `bittorrent-dht` and get +them to reveal 20 bytes at a time of uninitialized memory from the node.js process. + +Here's +[the commit](https://github.com/feross/bittorrent-dht/commit/6c7da04025d5633699800a99ec3fbadf70ad35b8) +that fixed it. We released a new fixed version, created a +[Node Security Project disclosure](https://nodesecurity.io/advisories/68), and deprecated all +vulnerable versions on npm so users will get a warning to upgrade to a newer version. + +#### [`ws`](https://www.npmjs.com/package/ws) + +That got us wondering if there were other vulnerable packages. Sure enough, within a short +period of time, we found the same issue in [`ws`](https://www.npmjs.com/package/ws), the +most popular WebSocket implementation in node.js. + +If certain APIs were called with `Number` parameters instead of `String` or `Buffer` as +expected, then uninitialized server memory would be disclosed to the remote peer. + +These were the vulnerable methods: + +```js +socket.send(number) +socket.ping(number) +socket.pong(number) +``` + +Here's a vulnerable socket server with some echo functionality: + +```js +server.on('connection', function (socket) { + socket.on('message', function (message) { + message = JSON.parse(message) + if (message.type === 'echo') { + socket.send(message.data) // send back the user's message + } + }) +}) +``` + +`socket.send(number)` called on the server, will disclose server memory. + +Here's [the release](https://github.com/websockets/ws/releases/tag/1.0.1) where the issue +was fixed, with a more detailed explanation. Props to +[Arnout Kazemier](https://github.com/3rd-Eden) for the quick fix. Here's the +[Node Security Project disclosure](https://nodesecurity.io/advisories/67). + + +### What's the solution? + +It's important that node.js offers a fast way to get memory otherwise performance-critical +applications would needlessly get a lot slower. + +But we need a better way to *signal our intent* as programmers. **When we want +uninitialized memory, we should request it explicitly.** + +Sensitive functionality should not be packed into a developer-friendly API that loosely +accepts many different types. This type of API encourages the lazy practice of passing +variables in without checking the type very carefully. + +#### A new API: `Buffer.allocUnsafe(number)` + +The functionality of creating buffers with uninitialized memory should be part of another +API. We propose `Buffer.allocUnsafe(number)`. This way, it's not part of an API that +frequently gets user input of all sorts of different types passed into it. + +```js +var buf = Buffer.allocUnsafe(16) // careful, uninitialized memory! + +// Immediately overwrite the uninitialized buffer with data from another buffer +for (var i = 0; i < buf.length; i++) { + buf[i] = otherBuf[i] +} +``` + + +### How do we fix node.js core? + +We sent [a PR to node.js core](https://github.com/nodejs/node/pull/4514) (merged as +`semver-major`) which defends against one case: + +```js +var str = 16 +new Buffer(str, 'utf8') +``` + +In this situation, it's implied that the programmer intended the first argument to be a +string, since they passed an encoding as a second argument. Today, node.js will allocate +uninitialized memory in the case of `new Buffer(number, encoding)`, which is probably not +what the programmer intended. + +But this is only a partial solution, since if the programmer does `new Buffer(variable)` +(without an `encoding` parameter) there's no way to know what they intended. If `variable` +is sometimes a number, then uninitialized memory will sometimes be returned. + +### What's the real long-term fix? + +We could deprecate and remove `new Buffer(number)` and use `Buffer.allocUnsafe(number)` when +we need uninitialized memory. But that would break 1000s of packages. + +~~We believe the best solution is to:~~ + +~~1. Change `new Buffer(number)` to return safe, zeroed-out memory~~ + +~~2. Create a new API for creating uninitialized Buffers. We propose: `Buffer.allocUnsafe(number)`~~ + +#### Update + +We now support adding three new APIs: + +- `Buffer.from(value)` - convert from any type to a buffer +- `Buffer.alloc(size)` - create a zero-filled buffer +- `Buffer.allocUnsafe(size)` - create an uninitialized buffer with given size + +This solves the core problem that affected `ws` and `bittorrent-dht` which is +`Buffer(variable)` getting tricked into taking a number argument. + +This way, existing code continues working and the impact on the npm ecosystem will be +minimal. Over time, npm maintainers can migrate performance-critical code to use +`Buffer.allocUnsafe(number)` instead of `new Buffer(number)`. + + +### Conclusion + +We think there's a serious design issue with the `Buffer` API as it exists today. It +promotes insecure software by putting high-risk functionality into a convenient API +with friendly "developer ergonomics". + +This wasn't merely a theoretical exercise because we found the issue in some of the +most popular npm packages. + +Fortunately, there's an easy fix that can be applied today. Use `safe-buffer` in place of +`buffer`. + +```js +var Buffer = require('safe-buffer').Buffer +``` + +Eventually, we hope that node.js core can switch to this new, safer behavior. We believe +the impact on the ecosystem would be minimal since it's not a breaking change. +Well-maintained, popular packages would be updated to use `Buffer.alloc` quickly, while +older, insecure packages would magically become safe from this attack vector. + + +## links + +- [Node.js PR: buffer: throw if both length and enc are passed](https://github.com/nodejs/node/pull/4514) +- [Node Security Project disclosure for `ws`](https://nodesecurity.io/advisories/67) +- [Node Security Project disclosure for`bittorrent-dht`](https://nodesecurity.io/advisories/68) + + +## credit + +The original issues in `bittorrent-dht` +([disclosure](https://nodesecurity.io/advisories/68)) and +`ws` ([disclosure](https://nodesecurity.io/advisories/67)) were discovered by +[Mathias Buus](https://github.com/mafintosh) and +[Feross Aboukhadijeh](http://feross.org/). + +Thanks to [Adam Baldwin](https://github.com/evilpacket) for helping disclose these issues +and for his work running the [Node Security Project](https://nodesecurity.io/). + +Thanks to [John Hiesey](https://github.com/jhiesey) for proofreading this README and +auditing the code. + + +## license + +MIT. Copyright (C) [Feross Aboukhadijeh](http://feross.org) diff --git a/node_modules/basic-auth/node_modules/safe-buffer/index.d.ts b/node_modules/basic-auth/node_modules/safe-buffer/index.d.ts new file mode 100644 index 0000000..e9fed80 --- /dev/null +++ b/node_modules/basic-auth/node_modules/safe-buffer/index.d.ts @@ -0,0 +1,187 @@ +declare module "safe-buffer" { + export class Buffer { + length: number + write(string: string, offset?: number, length?: number, encoding?: string): number; + toString(encoding?: string, start?: number, end?: number): string; + toJSON(): { type: 'Buffer', data: any[] }; + equals(otherBuffer: Buffer): boolean; + compare(otherBuffer: Buffer, targetStart?: number, targetEnd?: number, sourceStart?: number, sourceEnd?: number): number; + copy(targetBuffer: Buffer, targetStart?: number, sourceStart?: number, sourceEnd?: number): number; + slice(start?: number, end?: number): Buffer; + writeUIntLE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; + writeUIntBE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; + writeIntLE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; + writeIntBE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; + readUIntLE(offset: number, byteLength: number, noAssert?: boolean): number; + readUIntBE(offset: number, byteLength: number, noAssert?: boolean): number; + readIntLE(offset: number, byteLength: number, noAssert?: boolean): number; + readIntBE(offset: number, byteLength: number, noAssert?: boolean): number; + readUInt8(offset: number, noAssert?: boolean): number; + readUInt16LE(offset: number, noAssert?: boolean): number; + readUInt16BE(offset: number, noAssert?: boolean): number; + readUInt32LE(offset: number, noAssert?: boolean): number; + readUInt32BE(offset: number, noAssert?: boolean): number; + readInt8(offset: number, noAssert?: boolean): number; + readInt16LE(offset: number, noAssert?: boolean): number; + readInt16BE(offset: number, noAssert?: boolean): number; + readInt32LE(offset: number, noAssert?: boolean): number; + readInt32BE(offset: number, noAssert?: boolean): number; + readFloatLE(offset: number, noAssert?: boolean): number; + readFloatBE(offset: number, noAssert?: boolean): number; + readDoubleLE(offset: number, noAssert?: boolean): number; + readDoubleBE(offset: number, noAssert?: boolean): number; + swap16(): Buffer; + swap32(): Buffer; + swap64(): Buffer; + writeUInt8(value: number, offset: number, noAssert?: boolean): number; + writeUInt16LE(value: number, offset: number, noAssert?: boolean): number; + writeUInt16BE(value: number, offset: number, noAssert?: boolean): number; + writeUInt32LE(value: number, offset: number, noAssert?: boolean): number; + writeUInt32BE(value: number, offset: number, noAssert?: boolean): number; + writeInt8(value: number, offset: number, noAssert?: boolean): number; + writeInt16LE(value: number, offset: number, noAssert?: boolean): number; + writeInt16BE(value: number, offset: number, noAssert?: boolean): number; + writeInt32LE(value: number, offset: number, noAssert?: boolean): number; + writeInt32BE(value: number, offset: number, noAssert?: boolean): number; + writeFloatLE(value: number, offset: number, noAssert?: boolean): number; + writeFloatBE(value: number, offset: number, noAssert?: boolean): number; + writeDoubleLE(value: number, offset: number, noAssert?: boolean): number; + writeDoubleBE(value: number, offset: number, noAssert?: boolean): number; + fill(value: any, offset?: number, end?: number): this; + indexOf(value: string | number | Buffer, byteOffset?: number, encoding?: string): number; + lastIndexOf(value: string | number | Buffer, byteOffset?: number, encoding?: string): number; + includes(value: string | number | Buffer, byteOffset?: number, encoding?: string): boolean; + + /** + * Allocates a new buffer containing the given {str}. + * + * @param str String to store in buffer. + * @param encoding encoding to use, optional. Default is 'utf8' + */ + constructor (str: string, encoding?: string); + /** + * Allocates a new buffer of {size} octets. + * + * @param size count of octets to allocate. + */ + constructor (size: number); + /** + * Allocates a new buffer containing the given {array} of octets. + * + * @param array The octets to store. + */ + constructor (array: Uint8Array); + /** + * Produces a Buffer backed by the same allocated memory as + * the given {ArrayBuffer}. + * + * + * @param arrayBuffer The ArrayBuffer with which to share memory. + */ + constructor (arrayBuffer: ArrayBuffer); + /** + * Allocates a new buffer containing the given {array} of octets. + * + * @param array The octets to store. + */ + constructor (array: any[]); + /** + * Copies the passed {buffer} data onto a new {Buffer} instance. + * + * @param buffer The buffer to copy. + */ + constructor (buffer: Buffer); + prototype: Buffer; + /** + * Allocates a new Buffer using an {array} of octets. + * + * @param array + */ + static from(array: any[]): Buffer; + /** + * When passed a reference to the .buffer property of a TypedArray instance, + * the newly created Buffer will share the same allocated memory as the TypedArray. + * The optional {byteOffset} and {length} arguments specify a memory range + * within the {arrayBuffer} that will be shared by the Buffer. + * + * @param arrayBuffer The .buffer property of a TypedArray or a new ArrayBuffer() + * @param byteOffset + * @param length + */ + static from(arrayBuffer: ArrayBuffer, byteOffset?: number, length?: number): Buffer; + /** + * Copies the passed {buffer} data onto a new Buffer instance. + * + * @param buffer + */ + static from(buffer: Buffer): Buffer; + /** + * Creates a new Buffer containing the given JavaScript string {str}. + * If provided, the {encoding} parameter identifies the character encoding. + * If not provided, {encoding} defaults to 'utf8'. + * + * @param str + */ + static from(str: string, encoding?: string): Buffer; + /** + * Returns true if {obj} is a Buffer + * + * @param obj object to test. + */ + static isBuffer(obj: any): obj is Buffer; + /** + * Returns true if {encoding} is a valid encoding argument. + * Valid string encodings in Node 0.12: 'ascii'|'utf8'|'utf16le'|'ucs2'(alias of 'utf16le')|'base64'|'binary'(deprecated)|'hex' + * + * @param encoding string to test. + */ + static isEncoding(encoding: string): boolean; + /** + * Gives the actual byte length of a string. encoding defaults to 'utf8'. + * This is not the same as String.prototype.length since that returns the number of characters in a string. + * + * @param string string to test. + * @param encoding encoding used to evaluate (defaults to 'utf8') + */ + static byteLength(string: string, encoding?: string): number; + /** + * Returns a buffer which is the result of concatenating all the buffers in the list together. + * + * If the list has no items, or if the totalLength is 0, then it returns a zero-length buffer. + * If the list has exactly one item, then the first item of the list is returned. + * If the list has more than one item, then a new Buffer is created. + * + * @param list An array of Buffer objects to concatenate + * @param totalLength Total length of the buffers when concatenated. + * If totalLength is not provided, it is read from the buffers in the list. However, this adds an additional loop to the function, so it is faster to provide the length explicitly. + */ + static concat(list: Buffer[], totalLength?: number): Buffer; + /** + * The same as buf1.compare(buf2). + */ + static compare(buf1: Buffer, buf2: Buffer): number; + /** + * Allocates a new buffer of {size} octets. + * + * @param size count of octets to allocate. + * @param fill if specified, buffer will be initialized by calling buf.fill(fill). + * If parameter is omitted, buffer will be filled with zeros. + * @param encoding encoding used for call to buf.fill while initalizing + */ + static alloc(size: number, fill?: string | Buffer | number, encoding?: string): Buffer; + /** + * Allocates a new buffer of {size} octets, leaving memory not initialized, so the contents + * of the newly created Buffer are unknown and may contain sensitive data. + * + * @param size count of octets to allocate + */ + static allocUnsafe(size: number): Buffer; + /** + * Allocates a new non-pooled buffer of {size} octets, leaving memory not initialized, so the contents + * of the newly created Buffer are unknown and may contain sensitive data. + * + * @param size count of octets to allocate + */ + static allocUnsafeSlow(size: number): Buffer; + } +} \ No newline at end of file diff --git a/node_modules/basic-auth/node_modules/safe-buffer/index.js b/node_modules/basic-auth/node_modules/safe-buffer/index.js new file mode 100644 index 0000000..22438da --- /dev/null +++ b/node_modules/basic-auth/node_modules/safe-buffer/index.js @@ -0,0 +1,62 @@ +/* eslint-disable node/no-deprecated-api */ +var buffer = require('buffer') +var Buffer = buffer.Buffer + +// alternative to using Object.keys for old browsers +function copyProps (src, dst) { + for (var key in src) { + dst[key] = src[key] + } +} +if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) { + module.exports = buffer +} else { + // Copy properties from require('buffer') + copyProps(buffer, exports) + exports.Buffer = SafeBuffer +} + +function SafeBuffer (arg, encodingOrOffset, length) { + return Buffer(arg, encodingOrOffset, length) +} + +// Copy static methods from Buffer +copyProps(Buffer, SafeBuffer) + +SafeBuffer.from = function (arg, encodingOrOffset, length) { + if (typeof arg === 'number') { + throw new TypeError('Argument must not be a number') + } + return Buffer(arg, encodingOrOffset, length) +} + +SafeBuffer.alloc = function (size, fill, encoding) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + var buf = Buffer(size) + if (fill !== undefined) { + if (typeof encoding === 'string') { + buf.fill(fill, encoding) + } else { + buf.fill(fill) + } + } else { + buf.fill(0) + } + return buf +} + +SafeBuffer.allocUnsafe = function (size) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + return Buffer(size) +} + +SafeBuffer.allocUnsafeSlow = function (size) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + return buffer.SlowBuffer(size) +} diff --git a/node_modules/basic-auth/node_modules/safe-buffer/package.json b/node_modules/basic-auth/node_modules/safe-buffer/package.json new file mode 100644 index 0000000..623fbc3 --- /dev/null +++ b/node_modules/basic-auth/node_modules/safe-buffer/package.json @@ -0,0 +1,37 @@ +{ + "name": "safe-buffer", + "description": "Safer Node.js Buffer API", + "version": "5.1.2", + "author": { + "name": "Feross Aboukhadijeh", + "email": "feross@feross.org", + "url": "http://feross.org" + }, + "bugs": { + "url": "https://github.com/feross/safe-buffer/issues" + }, + "devDependencies": { + "standard": "*", + "tape": "^4.0.0" + }, + "homepage": "https://github.com/feross/safe-buffer", + "keywords": [ + "buffer", + "buffer allocate", + "node security", + "safe", + "safe-buffer", + "security", + "uninitialized" + ], + "license": "MIT", + "main": "index.js", + "types": "index.d.ts", + "repository": { + "type": "git", + "url": "git://github.com/feross/safe-buffer.git" + }, + "scripts": { + "test": "standard && tape test/*.js" + } +} diff --git a/node_modules/body-parser/HISTORY.md b/node_modules/body-parser/HISTORY.md index a1d3fbf..622f40c 100644 --- a/node_modules/body-parser/HISTORY.md +++ b/node_modules/body-parser/HISTORY.md @@ -1,3 +1,27 @@ +1.19.2 / 2022-02-15 +=================== + + * deps: bytes@3.1.2 + * deps: qs@6.9.7 + * Fix handling of `__proto__` keys + * deps: raw-body@2.4.3 + - deps: bytes@3.1.2 + +1.19.1 / 2021-12-10 +=================== + + * deps: bytes@3.1.1 + * deps: http-errors@1.8.1 + - deps: inherits@2.0.4 + - deps: toidentifier@1.0.1 + - deps: setprototypeof@1.2.0 + * deps: qs@6.9.6 + * deps: raw-body@2.4.2 + - deps: bytes@3.1.1 + - deps: http-errors@1.8.1 + * deps: safe-buffer@5.2.1 + * deps: type-is@~1.6.18 + 1.19.0 / 2019-04-25 =================== diff --git a/node_modules/body-parser/README.md b/node_modules/body-parser/README.md index aba6297..7d7fa88 100644 --- a/node_modules/body-parser/README.md +++ b/node_modules/body-parser/README.md @@ -2,7 +2,7 @@ [![NPM Version][npm-image]][npm-url] [![NPM Downloads][downloads-image]][downloads-url] -[![Build Status][travis-image]][travis-url] +[![Build Status][github-actions-ci-image]][github-actions-ci-url] [![Test Coverage][coveralls-image]][coveralls-url] Node.js body parsing middleware. @@ -49,8 +49,6 @@ $ npm install body-parser ## API - - ```js var bodyParser = require('body-parser') ``` @@ -281,14 +279,15 @@ encoding of the request. The parsing can be aborted by throwing an error. ## Errors -The middlewares provided by this module create errors depending on the error -condition during parsing. The errors will typically have a `status`/`statusCode` -property that contains the suggested HTTP response code, an `expose` property -to determine if the `message` property should be displayed to the client, a -`type` property to determine the type of error without matching against the -`message`, and a `body` property containing the read body, if available. +The middlewares provided by this module create errors using the +[`http-errors` module](https://www.npmjs.com/package/http-errors). The errors +will typically have a `status`/`statusCode` property that contains the suggested +HTTP response code, an `expose` property to determine if the `message` property +should be displayed to the client, a `type` property to determine the type of +error without matching against the `message`, and a `body` property containing +the read body, if available. -The following are the common errors emitted, though any error can come through +The following are the common errors created, though any error can come through for various reasons. ### content encoding unsupported @@ -299,6 +298,20 @@ contained an encoding but the "inflation" option was set to `false`. The `'encoding.unsupported'`, and the `charset` property will be set to the encoding that is unsupported. +### entity parse failed + +This error will occur when the request contained an entity that could not be +parsed by the middleware. The `status` property is set to `400`, the `type` +property is set to `'entity.parse.failed'`, and the `body` property is set to +the entity value that failed parsing. + +### entity verify failed + +This error will occur when the request contained an entity that could not be +failed verification by the defined `verify` option. The `status` property is +set to `403`, the `type` property is set to `'entity.verify.failed'`, and the +`body` property is set to the entity value that failed verification. + ### request aborted This error will occur when the request is aborted by the client before reading @@ -435,9 +448,9 @@ app.use(bodyParser.text({ type: 'text/html' })) [npm-image]: https://img.shields.io/npm/v/body-parser.svg [npm-url]: https://npmjs.org/package/body-parser -[travis-image]: https://img.shields.io/travis/expressjs/body-parser/master.svg -[travis-url]: https://travis-ci.org/expressjs/body-parser [coveralls-image]: https://img.shields.io/coveralls/expressjs/body-parser/master.svg [coveralls-url]: https://coveralls.io/r/expressjs/body-parser?branch=master [downloads-image]: https://img.shields.io/npm/dm/body-parser.svg [downloads-url]: https://npmjs.org/package/body-parser +[github-actions-ci-image]: https://img.shields.io/github/workflow/status/expressjs/body-parser/ci/master?label=ci +[github-actions-ci-url]: https://github.com/expressjs/body-parser?query=workflow%3Aci diff --git a/node_modules/body-parser/package.json b/node_modules/body-parser/package.json index 269ebf2..b418b45 100644 --- a/node_modules/body-parser/package.json +++ b/node_modules/body-parser/package.json @@ -1,7 +1,7 @@ { "name": "body-parser", "description": "Node.js body parsing middleware", - "version": "1.19.0", + "version": "1.19.2", "contributors": [ "Douglas Christopher Wilson ", "Jonathan Ong (http://jongleberry.com)" @@ -9,30 +9,30 @@ "license": "MIT", "repository": "expressjs/body-parser", "dependencies": { - "bytes": "3.1.0", + "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", "depd": "~1.1.2", - "http-errors": "1.7.2", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" + "qs": "6.9.7", + "raw-body": "2.4.3", + "type-is": "~1.6.18" }, "devDependencies": { - "eslint": "5.16.0", - "eslint-config-standard": "12.0.0", - "eslint-plugin-import": "2.17.2", - "eslint-plugin-markdown": "1.0.0", - "eslint-plugin-node": "8.0.1", - "eslint-plugin-promise": "4.1.1", - "eslint-plugin-standard": "4.0.0", - "istanbul": "0.4.5", + "eslint": "7.32.0", + "eslint-config-standard": "14.1.1", + "eslint-plugin-import": "2.25.4", + "eslint-plugin-markdown": "2.2.1", + "eslint-plugin-node": "11.1.0", + "eslint-plugin-promise": "5.2.0", + "eslint-plugin-standard": "4.1.0", "methods": "1.1.2", - "mocha": "6.1.4", - "safe-buffer": "5.1.2", - "supertest": "4.0.2" + "mocha": "9.2.0", + "nyc": "15.1.0", + "safe-buffer": "5.2.1", + "supertest": "6.2.2" }, "files": [ "lib/", @@ -44,9 +44,9 @@ "node": ">= 0.8" }, "scripts": { - "lint": "eslint --plugin markdown --ext js,md .", + "lint": "eslint .", "test": "mocha --require test/support/env --reporter spec --check-leaks --bail test/", - "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks test/", - "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks test/" + "test-ci": "nyc --reporter=lcov --reporter=text npm test", + "test-cov": "nyc --reporter=html --reporter=text npm test" } } diff --git a/node_modules/bytes/History.md b/node_modules/bytes/History.md index cf6a5bb..d60ce0e 100644 --- a/node_modules/bytes/History.md +++ b/node_modules/bytes/History.md @@ -1,3 +1,13 @@ +3.1.2 / 2022-01-27 +================== + + * Fix return value for un-parsable strings + +3.1.1 / 2021-11-15 +================== + + * Fix "thousandsSeparator" incorrecting formatting fractional part + 3.1.0 / 2019-01-22 ================== diff --git a/node_modules/bytes/Readme.md b/node_modules/bytes/Readme.md index 6ad1ec6..5790e23 100644 --- a/node_modules/bytes/Readme.md +++ b/node_modules/bytes/Readme.md @@ -2,7 +2,7 @@ [![NPM Version][npm-image]][npm-url] [![NPM Downloads][downloads-image]][downloads-url] -[![Build Status][travis-image]][travis-url] +[![Build Status][ci-image]][ci-url] [![Test Coverage][coveralls-image]][coveralls-url] Utility to parse a string bytes (ex: `1TB`) to bytes (`1099511627776`) and vice-versa. @@ -23,6 +23,33 @@ $ npm install bytes var bytes = require('bytes'); ``` +#### bytes(number|string value, [options]): number|string|null + +Default export function. Delegates to either `bytes.format` or `bytes.parse` based on the type of `value`. + +**Arguments** + +| Name | Type | Description | +|---------|----------|--------------------| +| value | `number`|`string` | Number value to format or string value to parse | +| options | `Object` | Conversion options for `format` | + +**Returns** + +| Name | Type | Description | +|---------|------------------|-------------------------------------------------| +| results | `string`|`number`|`null` | Return null upon error. Numeric value in bytes, or string value otherwise. | + +**Example** + +```js +bytes(1024); +// output: '1KB' + +bytes('1KB'); +// output: 1024 +``` + #### bytes.format(number value, [options]): string|null Format the given value in bytes into a string. If the value is negative, it is kept as such. If it is a float, it is @@ -41,7 +68,7 @@ Format the given value in bytes into a string. If the value is negative, it is k |-------------------|--------|-----------------------------------------------------------------------------------------| | decimalPlaces | `number`|`null` | Maximum number of decimal places to include in output. Default value to `2`. | | fixedDecimals | `boolean`|`null` | Whether to always display the maximum number of decimal places. Default value to `false` | -| thousandsSeparator | `string`|`null` | Example of values: `' '`, `','` and `.`... Default value to `''`. | +| thousandsSeparator | `string`|`null` | Example of values: `' '`, `','` and `'.'`... Default value to `''`. | | unit | `string`|`null` | The unit in which the result will be returned (B/KB/MB/GB/TB). Default value to `''` (which means auto detect). | | unitSeparator | `string`|`null` | Separator to use between number and unit. Default value to `''`. | @@ -54,21 +81,20 @@ Format the given value in bytes into a string. If the value is negative, it is k **Example** ```js -bytes(1024); +bytes.format(1024); // output: '1KB' -bytes(1000); +bytes.format(1000); // output: '1000B' -bytes(1000, {thousandsSeparator: ' '}); +bytes.format(1000, {thousandsSeparator: ' '}); // output: '1 000B' -bytes(1024 * 1.7, {decimalPlaces: 0}); +bytes.format(1024 * 1.7, {decimalPlaces: 0}); // output: '2KB' -bytes(1024, {unitSeparator: ' '}); +bytes.format(1024, {unitSeparator: ' '}); // output: '1 KB' - ``` #### bytes.parse(string|number value): number|null @@ -102,25 +128,25 @@ The units are in powers of two, not ten. This means 1kb = 1024b according to thi **Example** ```js -bytes('1KB'); +bytes.parse('1KB'); // output: 1024 -bytes('1024'); +bytes.parse('1024'); // output: 1024 -bytes(1024); -// output: 1KB +bytes.parse(1024); +// output: 1024 ``` -## License +## License [MIT](LICENSE) +[ci-image]: https://badgen.net/github/checks/visionmedia/bytes.js/master?label=ci +[ci-url]: https://github.com/visionmedia/bytes.js/actions?query=workflow%3Aci [coveralls-image]: https://badgen.net/coveralls/c/github/visionmedia/bytes.js/master [coveralls-url]: https://coveralls.io/r/visionmedia/bytes.js?branch=master [downloads-image]: https://badgen.net/npm/dm/bytes [downloads-url]: https://npmjs.org/package/bytes -[npm-image]: https://badgen.net/npm/node/bytes +[npm-image]: https://badgen.net/npm/v/bytes [npm-url]: https://npmjs.org/package/bytes -[travis-image]: https://badgen.net/travis/visionmedia/bytes.js/master -[travis-url]: https://travis-ci.org/visionmedia/bytes.js diff --git a/node_modules/bytes/index.js b/node_modules/bytes/index.js index 4975bfb..6f2d0f8 100644 --- a/node_modules/bytes/index.js +++ b/node_modules/bytes/index.js @@ -117,7 +117,11 @@ function format(value, options) { } if (thousandsSeparator) { - str = str.replace(formatThousandsRegExp, thousandsSeparator); + str = str.split('.').map(function (s, i) { + return i === 0 + ? s.replace(formatThousandsRegExp, thousandsSeparator) + : s + }).join('.'); } return str + unitSeparator + unit; @@ -158,5 +162,9 @@ function parse(val) { unit = results[4].toLowerCase(); } + if (isNaN(floatValue)) { + return null; + } + return Math.floor(map[unit] * floatValue); } diff --git a/node_modules/bytes/package.json b/node_modules/bytes/package.json index 72ee63d..f2b6a8b 100644 --- a/node_modules/bytes/package.json +++ b/node_modules/bytes/package.json @@ -1,7 +1,7 @@ { "name": "bytes", "description": "Utility to parse a string bytes to bytes and vice-versa", - "version": "3.1.0", + "version": "3.1.2", "author": "TJ Holowaychuk (http://tjholowaychuk.com)", "contributors": [ "Jed Watson ", @@ -19,9 +19,10 @@ ], "repository": "visionmedia/bytes.js", "devDependencies": { - "eslint": "5.12.1", - "mocha": "5.2.0", - "nyc": "13.1.0" + "eslint": "7.32.0", + "eslint-plugin-markdown": "2.2.1", + "mocha": "9.2.0", + "nyc": "15.1.0" }, "files": [ "History.md", @@ -35,7 +36,7 @@ "scripts": { "lint": "eslint .", "test": "mocha --check-leaks --reporter spec", - "test-ci": "nyc --reporter=text npm test", + "test-ci": "nyc --reporter=lcov --reporter=text npm test", "test-cov": "nyc --reporter=html --reporter=text npm test" } } diff --git a/node_modules/content-disposition/HISTORY.md b/node_modules/content-disposition/HISTORY.md index 63a3d08..488effa 100644 --- a/node_modules/content-disposition/HISTORY.md +++ b/node_modules/content-disposition/HISTORY.md @@ -1,3 +1,8 @@ +0.5.4 / 2021-12-10 +================== + + * deps: safe-buffer@5.2.1 + 0.5.3 / 2018-12-17 ================== diff --git a/node_modules/content-disposition/README.md b/node_modules/content-disposition/README.md index eebef13..3a0bb05 100644 --- a/node_modules/content-disposition/README.md +++ b/node_modules/content-disposition/README.md @@ -3,7 +3,7 @@ [![NPM Version][npm-image]][npm-url] [![NPM Downloads][downloads-image]][downloads-url] [![Node.js Version][node-version-image]][node-version-url] -[![Build Status][travis-image]][travis-url] +[![Build Status][github-actions-ci-image]][github-actions-ci-url] [![Test Coverage][coveralls-image]][coveralls-url] Create and parse HTTP `Content-Disposition` header @@ -16,8 +16,6 @@ $ npm install content-disposition ## API - - ```js var contentDisposition = require('content-disposition') ``` @@ -28,8 +26,6 @@ Create an attachment `Content-Disposition` header value using the given file nam if supplied. The `filename` is optional and if no file name is desired, but you want to specify `options`, set `filename` to `undefined`. - - ```js res.setHeader('Content-Disposition', contentDisposition('∫ maths.pdf')) ``` @@ -70,8 +66,6 @@ it). The type is normalized to lower-case. ### contentDisposition.parse(string) - - ```js var disposition = contentDisposition.parse('attachment; filename="EURO rates.txt"; filename*=UTF-8\'\'%e2%82%ac%20rates.txt') ``` @@ -140,9 +134,9 @@ $ npm test [npm-url]: https://npmjs.org/package/content-disposition [node-version-image]: https://img.shields.io/node/v/content-disposition.svg [node-version-url]: https://nodejs.org/en/download -[travis-image]: https://img.shields.io/travis/jshttp/content-disposition.svg -[travis-url]: https://travis-ci.org/jshttp/content-disposition [coveralls-image]: https://img.shields.io/coveralls/jshttp/content-disposition.svg [coveralls-url]: https://coveralls.io/r/jshttp/content-disposition?branch=master [downloads-image]: https://img.shields.io/npm/dm/content-disposition.svg [downloads-url]: https://npmjs.org/package/content-disposition +[github-actions-ci-image]: https://img.shields.io/github/workflow/status/jshttp/content-disposition/ci/master?label=ci +[github-actions-ci-url]: https://github.com/jshttp/content-disposition?query=workflow%3Aci diff --git a/node_modules/content-disposition/index.js b/node_modules/content-disposition/index.js index 3092a4d..ecec899 100644 --- a/node_modules/content-disposition/index.js +++ b/node_modules/content-disposition/index.js @@ -255,7 +255,7 @@ function format (obj) { } /** - * Decode a RFC 6987 field value (gracefully). + * Decode a RFC 5987 field value (gracefully). * * @param {string} str * @return {string} diff --git a/node_modules/content-disposition/package.json b/node_modules/content-disposition/package.json index 814f7f3..43c70ce 100644 --- a/node_modules/content-disposition/package.json +++ b/node_modules/content-disposition/package.json @@ -1,7 +1,7 @@ { "name": "content-disposition", "description": "Create and parse Content-Disposition header", - "version": "0.5.3", + "version": "0.5.4", "author": "Douglas Christopher Wilson ", "license": "MIT", "keywords": [ @@ -12,19 +12,19 @@ ], "repository": "jshttp/content-disposition", "dependencies": { - "safe-buffer": "5.1.2" + "safe-buffer": "5.2.1" }, "devDependencies": { "deep-equal": "1.0.1", - "eslint": "5.10.0", - "eslint-config-standard": "12.0.0", - "eslint-plugin-import": "2.14.0", - "eslint-plugin-markdown": "1.0.0-rc.1", - "eslint-plugin-node": "7.0.1", - "eslint-plugin-promise": "4.0.1", - "eslint-plugin-standard": "4.0.0", + "eslint": "7.32.0", + "eslint-config-standard": "13.0.1", + "eslint-plugin-import": "2.25.3", + "eslint-plugin-markdown": "2.2.1", + "eslint-plugin-node": "11.1.0", + "eslint-plugin-promise": "5.2.0", + "eslint-plugin-standard": "4.1.0", "istanbul": "0.4.5", - "mocha": "5.2.0" + "mocha": "9.1.3" }, "files": [ "LICENSE", @@ -36,9 +36,9 @@ "node": ">= 0.6" }, "scripts": { - "lint": "eslint --plugin markdown --ext js,md .", + "lint": "eslint .", "test": "mocha --reporter spec --bail --check-leaks test/", - "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/", - "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/" + "test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/", + "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/" } } diff --git a/node_modules/cookie/HISTORY.md b/node_modules/cookie/HISTORY.md index da2bf24..2d21760 100644 --- a/node_modules/cookie/HISTORY.md +++ b/node_modules/cookie/HISTORY.md @@ -1,3 +1,14 @@ +0.4.2 / 2022-02-02 +================== + + * pref: read value only when assigning in parse + * pref: remove unnecessary regexp in parse + +0.4.1 / 2020-04-21 +================== + + * Fix `maxAge` option to reject invalid values + 0.4.0 / 2019-05-15 ================== diff --git a/node_modules/cookie/README.md b/node_modules/cookie/README.md index 857fb77..e275c70 100644 --- a/node_modules/cookie/README.md +++ b/node_modules/cookie/README.md @@ -3,13 +3,17 @@ [![NPM Version][npm-version-image]][npm-url] [![NPM Downloads][npm-downloads-image]][npm-url] [![Node.js Version][node-version-image]][node-version-url] -[![Build Status][travis-image]][travis-url] +[![Build Status][github-actions-ci-image]][github-actions-ci-url] [![Test Coverage][coveralls-image]][coveralls-url] Basic HTTP cookie parser and serializer for HTTP servers. ## Installation +This is a [Node.js](https://nodejs.org/en/) module available through the +[npm registry](https://www.npmjs.com/). Installation is done using the +[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally): + ```sh $ npm install cookie ``` @@ -194,32 +198,61 @@ $ npm test ``` $ npm run bench -> cookie@0.3.1 bench cookie +> cookie@0.4.1 bench > node benchmark/index.js - http_parser@2.8.0 - node@6.14.2 - v8@5.1.281.111 - uv@1.16.1 + node@16.13.1 + v8@9.4.146.24-node.14 + uv@1.42.0 zlib@1.2.11 - ares@1.10.1-DEV - icu@58.2 - modules@48 - napi@3 - openssl@1.0.2o + brotli@1.0.9 + ares@1.18.1 + modules@93 + nghttp2@1.45.1 + napi@8 + llhttp@6.0.4 + openssl@1.1.1l+quic + cldr@39.0 + icu@69.1 + tz@2021a + unicode@13.0 + ngtcp2@0.1.0-DEV + nghttp3@0.1.0-DEV + +> node benchmark/parse-top.js + + cookie.parse - top sites + + 15 tests completed. + + parse accounts.google.com x 504,358 ops/sec ±6.55% (171 runs sampled) + parse apple.com x 1,369,991 ops/sec ±0.84% (189 runs sampled) + parse cloudflare.com x 360,669 ops/sec ±3.75% (182 runs sampled) + parse docs.google.com x 521,496 ops/sec ±4.90% (180 runs sampled) + parse drive.google.com x 553,514 ops/sec ±0.59% (189 runs sampled) + parse en.wikipedia.org x 286,052 ops/sec ±0.62% (188 runs sampled) + parse linkedin.com x 178,817 ops/sec ±0.61% (192 runs sampled) + parse maps.google.com x 284,585 ops/sec ±0.68% (188 runs sampled) + parse microsoft.com x 161,230 ops/sec ±0.56% (192 runs sampled) + parse play.google.com x 352,144 ops/sec ±1.01% (181 runs sampled) + parse plus.google.com x 275,204 ops/sec ±7.78% (156 runs sampled) + parse support.google.com x 339,493 ops/sec ±1.02% (191 runs sampled) + parse www.google.com x 286,110 ops/sec ±0.90% (191 runs sampled) + parse youtu.be x 548,557 ops/sec ±0.60% (184 runs sampled) + parse youtube.com x 545,293 ops/sec ±0.65% (191 runs sampled) > node benchmark/parse.js - cookie.parse + cookie.parse - generic 6 tests completed. - simple x 1,200,691 ops/sec ±1.12% (189 runs sampled) - decode x 1,012,994 ops/sec ±0.97% (186 runs sampled) - unquote x 1,074,174 ops/sec ±2.43% (186 runs sampled) - duplicates x 438,424 ops/sec ±2.17% (184 runs sampled) - 10 cookies x 147,154 ops/sec ±1.01% (186 runs sampled) - 100 cookies x 14,274 ops/sec ±1.07% (187 runs sampled) + simple x 1,266,646 ops/sec ±0.65% (191 runs sampled) + decode x 838,413 ops/sec ±0.60% (191 runs sampled) + unquote x 877,820 ops/sec ±0.72% (189 runs sampled) + duplicates x 516,680 ops/sec ±0.61% (191 runs sampled) + 10 cookies x 156,874 ops/sec ±0.52% (189 runs sampled) + 100 cookies x 14,663 ops/sec ±0.53% (191 runs sampled) ``` ## References @@ -244,10 +277,10 @@ $ npm run bench [coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/cookie/master [coveralls-url]: https://coveralls.io/r/jshttp/cookie?branch=master +[github-actions-ci-image]: https://img.shields.io/github/workflow/status/jshttp/cookie/ci/master?label=ci +[github-actions-ci-url]: https://github.com/jshttp/cookie/actions/workflows/ci.yml [node-version-image]: https://badgen.net/npm/node/cookie [node-version-url]: https://nodejs.org/en/download [npm-downloads-image]: https://badgen.net/npm/dm/cookie [npm-url]: https://npmjs.org/package/cookie [npm-version-image]: https://badgen.net/npm/v/cookie -[travis-image]: https://badgen.net/travis/jshttp/cookie/master -[travis-url]: https://travis-ci.org/jshttp/cookie diff --git a/node_modules/cookie/index.js b/node_modules/cookie/index.js index 16f56c0..55331d9 100644 --- a/node_modules/cookie/index.js +++ b/node_modules/cookie/index.js @@ -22,7 +22,6 @@ exports.serialize = serialize; var decode = decodeURIComponent; var encode = encodeURIComponent; -var pairSplitRegExp = /; */; /** * RegExp to match field-content in RFC 7230 sec 3.2 @@ -53,28 +52,29 @@ function parse(str, options) { var obj = {} var opt = options || {}; - var pairs = str.split(pairSplitRegExp); + var pairs = str.split(';') var dec = opt.decode || decode; for (var i = 0; i < pairs.length; i++) { var pair = pairs[i]; - var eq_idx = pair.indexOf('='); + var index = pair.indexOf('=') // skip things that don't look like key=value - if (eq_idx < 0) { + if (index < 0) { continue; } - var key = pair.substr(0, eq_idx).trim() - var val = pair.substr(++eq_idx, pair.length).trim(); - - // quoted values - if ('"' == val[0]) { - val = val.slice(1, -1); - } + var key = pair.substring(0, index).trim() // only assign once if (undefined == obj[key]) { + var val = pair.substring(index + 1, pair.length).trim() + + // quoted values + if (val[0] === '"') { + val = val.slice(1, -1) + } + obj[key] = tryDecode(val, dec); } } @@ -120,7 +120,11 @@ function serialize(name, val, options) { if (null != opt.maxAge) { var maxAge = opt.maxAge - 0; - if (isNaN(maxAge)) throw new Error('maxAge should be a Number'); + + if (isNaN(maxAge) || !isFinite(maxAge)) { + throw new TypeError('option maxAge is invalid') + } + str += '; Max-Age=' + Math.floor(maxAge); } diff --git a/node_modules/cookie/package.json b/node_modules/cookie/package.json index 9bfbc47..cd40d0d 100644 --- a/node_modules/cookie/package.json +++ b/node_modules/cookie/package.json @@ -1,7 +1,7 @@ { "name": "cookie", "description": "HTTP server cookie parsing and serialization", - "version": "0.4.0", + "version": "0.4.2", "author": "Roman Shtylman ", "contributors": [ "Douglas Christopher Wilson " @@ -15,10 +15,11 @@ "devDependencies": { "beautify-benchmark": "0.2.4", "benchmark": "2.1.4", - "eslint": "5.16.0", - "eslint-plugin-markdown": "1.0.0", - "istanbul": "0.4.5", - "mocha": "6.1.4" + "eslint": "7.32.0", + "eslint-plugin-markdown": "2.2.1", + "mocha": "9.2.0", + "nyc": "15.1.0", + "top-sites": "1.1.85" }, "files": [ "HISTORY.md", @@ -31,10 +32,11 @@ }, "scripts": { "bench": "node benchmark/index.js", - "lint": "eslint --plugin markdown --ext js,md .", - "test": "mocha --reporter spec --bail --check-leaks test/", - "test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/", - "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/", + "lint": "eslint .", + "test": "mocha --reporter spec --bail --check-leaks --ui qunit test/", + "test-ci": "nyc --reporter=lcov --reporter=text npm test", + "test-cov": "nyc --reporter=html --reporter=text npm test", + "update-bench": "node scripts/update-benchmark.js", "version": "node scripts/version-history.js && git add HISTORY.md" } } diff --git a/node_modules/express-handlebars/CHANGELOG.md b/node_modules/express-handlebars/CHANGELOG.md index 53dc08e..21dccb5 100644 --- a/node_modules/express-handlebars/CHANGELOG.md +++ b/node_modules/express-handlebars/CHANGELOG.md @@ -1,3 +1,10 @@ +## [5.3.5](https://github.com/express-handlebars/express-handlebars/compare/v5.3.4...v5.3.5) (2021-11-13) + + +### Bug Fixes + +* update deps ([b516cff](https://github.com/express-handlebars/express-handlebars/commit/b516cff30ba3de90db02b3a3682c9ffbcfb10091)) + ## [5.3.4](https://github.com/express-handlebars/express-handlebars/compare/v5.3.3...v5.3.4) (2021-09-23) diff --git a/node_modules/express-handlebars/package.json b/node_modules/express-handlebars/package.json index 0595484..91b126b 100644 --- a/node_modules/express-handlebars/package.json +++ b/node_modules/express-handlebars/package.json @@ -1,7 +1,7 @@ { "name": "express-handlebars", "description": "A Handlebars view engine for Express which doesn't suck.", - "version": "5.3.4", + "version": "5.3.5", "homepage": "https://github.com/express-handlebars/express-handlebars", "keywords": [ "express", @@ -25,7 +25,7 @@ }, "dependencies": { "glob": "^7.2.0", - "graceful-fs": "^4.2.7", + "graceful-fs": "^4.2.8", "handlebars": "^4.7.7" }, "main": "index.js", @@ -33,18 +33,18 @@ "example": "examples" }, "devDependencies": { - "@semantic-release/changelog": "^6.0.0", + "@semantic-release/changelog": "^6.0.1", "@semantic-release/commit-analyzer": "^9.0.1", - "@semantic-release/git": "^10.0.0", - "@semantic-release/github": "^8.0.0", - "@semantic-release/npm": "^8.0.0", + "@semantic-release/git": "^10.0.1", + "@semantic-release/github": "^8.0.2", + "@semantic-release/npm": "^8.0.3", "@semantic-release/release-notes-generator": "^10.0.2", "eslint": "^7.32.0", "eslint-config-standard": "^16.0.3", - "eslint-plugin-import": "^2.24.2", + "eslint-plugin-import": "^2.25.3", "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^5.1.0", - "jest-cli": "^27.2.1", + "eslint-plugin-promise": "^5.1.1", + "jest-cli": "^27.3.1", "semantic-release": "^18.0.0" }, "release": { diff --git a/node_modules/express/History.md b/node_modules/express/History.md index 6e62a6d..9f3f876 100644 --- a/node_modules/express/History.md +++ b/node_modules/express/History.md @@ -1,3 +1,51 @@ +4.17.3 / 2022-02-16 +=================== + + * deps: accepts@~1.3.8 + - deps: mime-types@~2.1.34 + - deps: negotiator@0.6.3 + * deps: body-parser@1.19.2 + - deps: bytes@3.1.2 + - deps: qs@6.9.7 + - deps: raw-body@2.4.3 + * deps: cookie@0.4.2 + * deps: qs@6.9.7 + * Fix handling of `__proto__` keys + * pref: remove unnecessary regexp for trust proxy + +4.17.2 / 2021-12-16 +=================== + + * Fix handling of `undefined` in `res.jsonp` + * Fix handling of `undefined` when `"json escape"` is enabled + * Fix incorrect middleware execution with unanchored `RegExp`s + * Fix `res.jsonp(obj, status)` deprecation message + * Fix typo in `res.is` JSDoc + * deps: body-parser@1.19.1 + - deps: bytes@3.1.1 + - deps: http-errors@1.8.1 + - deps: qs@6.9.6 + - deps: raw-body@2.4.2 + - deps: safe-buffer@5.2.1 + - deps: type-is@~1.6.18 + * deps: content-disposition@0.5.4 + - deps: safe-buffer@5.2.1 + * deps: cookie@0.4.1 + - Fix `maxAge` option to reject invalid values + * deps: proxy-addr@~2.0.7 + - Use `req.socket` over deprecated `req.connection` + - deps: forwarded@0.2.0 + - deps: ipaddr.js@1.9.1 + * deps: qs@6.9.6 + * deps: safe-buffer@5.2.1 + * deps: send@0.17.2 + - deps: http-errors@1.8.1 + - deps: ms@2.1.3 + - pref: ignore empty http tokens + * deps: serve-static@1.14.2 + - deps: send@0.17.2 + * deps: setprototypeof@1.2.0 + 4.17.1 / 2019-05-25 =================== diff --git a/node_modules/express/Readme.md b/node_modules/express/Readme.md index 1f91297..b60d588 100644 --- a/node_modules/express/Readme.md +++ b/node_modules/express/Readme.md @@ -4,7 +4,7 @@ [![NPM Version][npm-image]][npm-url] [![NPM Downloads][downloads-image]][downloads-url] - [![Linux Build][travis-image]][travis-url] + [![Linux Build][ci-image]][ci-url] [![Windows Build][appveyor-image]][appveyor-url] [![Test Coverage][coveralls-image]][coveralls-url] @@ -27,6 +27,9 @@ This is a [Node.js](https://nodejs.org/en/) module available through the Before installing, [download and install Node.js](https://nodejs.org/en/download/). Node.js 0.10 or higher is required. +If this is a brand new project, make sure to create a `package.json` first with +the [`npm init` command](https://docs.npmjs.com/creating-a-package-json-file). + Installation is done using the [`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally): @@ -95,7 +98,7 @@ $ npm start ## Philosophy The Express philosophy is to provide small, robust tooling for HTTP servers, making - it a great solution for single page applications, web sites, hybrids, or public + it a great solution for single page applications, websites, hybrids, or public HTTP APIs. Express does not force you to use any specific ORM or template engine. With support for over @@ -143,12 +146,12 @@ The current lead maintainer is [Douglas Christopher Wilson](https://github.com/d [MIT](LICENSE) +[ci-image]: https://img.shields.io/github/workflow/status/expressjs/express/ci/master.svg?label=linux +[ci-url]: https://github.com/expressjs/express/actions?query=workflow%3Aci [npm-image]: https://img.shields.io/npm/v/express.svg [npm-url]: https://npmjs.org/package/express [downloads-image]: https://img.shields.io/npm/dm/express.svg -[downloads-url]: https://npmjs.org/package/express -[travis-image]: https://img.shields.io/travis/expressjs/express/master.svg?label=linux -[travis-url]: https://travis-ci.org/expressjs/express +[downloads-url]: https://npmcharts.com/compare/express?minimal=true [appveyor-image]: https://img.shields.io/appveyor/ci/dougwilson/express/master.svg?label=windows [appveyor-url]: https://ci.appveyor.com/project/dougwilson/express [coveralls-image]: https://img.shields.io/coveralls/expressjs/express/master.svg diff --git a/node_modules/express/lib/application.js b/node_modules/express/lib/application.js index 91f77d2..e65ba58 100644 --- a/node_modules/express/lib/application.js +++ b/node_modules/express/lib/application.js @@ -276,7 +276,7 @@ app.route = function route(path) { * In this case EJS provides a `.renderFile()` method with * the same signature that Express expects: `(path, options, callback)`, * though note that it aliases this method as `ejs.__express` internally - * so if you're using ".ejs" extensions you dont need to do anything. + * so if you're using ".ejs" extensions you don't need to do anything. * * Some template engines do not follow this convention, the * [Consolidate.js](https://github.com/tj/consolidate.js) diff --git a/node_modules/express/lib/request.js b/node_modules/express/lib/request.js index a9400ef..3f1eeca 100644 --- a/node_modules/express/lib/request.js +++ b/node_modules/express/lib/request.js @@ -251,7 +251,7 @@ req.param = function param(name, defaultValue) { /** * Check if the incoming request contains the "Content-Type" - * header field, and it contains the give mime `type`. + * header field, and it contains the given mime `type`. * * Examples: * diff --git a/node_modules/express/lib/response.js b/node_modules/express/lib/response.js index c9f08cd..ba02008 100644 --- a/node_modules/express/lib/response.js +++ b/node_modules/express/lib/response.js @@ -284,9 +284,9 @@ res.jsonp = function jsonp(obj) { // allow status / body if (arguments.length === 2) { - // res.json(body, status) backwards compat + // res.jsonp(body, status) backwards compat if (typeof arguments[1] === 'number') { - deprecate('res.jsonp(obj, status): Use res.status(status).json(obj) instead'); + deprecate('res.jsonp(obj, status): Use res.status(status).jsonp(obj) instead'); this.statusCode = arguments[1]; } else { deprecate('res.jsonp(status, obj): Use res.status(status).jsonp(obj) instead'); @@ -322,10 +322,15 @@ res.jsonp = function jsonp(obj) { // restrict callback charset callback = callback.replace(/[^\[\]\w$.]/g, ''); - // replace chars not allowed in JavaScript that are in JSON - body = body - .replace(/\u2028/g, '\\u2028') - .replace(/\u2029/g, '\\u2029'); + if (body === undefined) { + // empty argument + body = '' + } else if (typeof body === 'string') { + // replace chars not allowed in JavaScript that are in JSON + body = body + .replace(/\u2028/g, '\\u2028') + .replace(/\u2029/g, '\\u2029') + } // the /**/ is a specific security mitigation for "Rosetta Flash JSONP abuse" // the typeof check is just to reduce client error noise @@ -364,7 +369,7 @@ res.sendStatus = function sendStatus(statusCode) { * * Automatically sets the _Content-Type_ response header field. * The callback `callback(err)` is invoked when the transfer is complete - * or when an error occurs. Be sure to check `res.sentHeader` + * or when an error occurs. Be sure to check `res.headersSent` * if you wish to attempt responding, as the header and some data * may have already been transferred. * @@ -446,7 +451,7 @@ res.sendFile = function sendFile(path, options, callback) { * * Automatically sets the _Content-Type_ response header field. * The callback `callback(err)` is invoked when the transfer is complete - * or when an error occurs. Be sure to check `res.sentHeader` + * or when an error occurs. Be sure to check `res.headersSent` * if you wish to attempt responding, as the header and some data * may have already been transferred. * @@ -519,7 +524,7 @@ res.sendfile = deprecate.function(res.sendfile, * Optionally providing an alternate attachment `filename`, * and optional callback `callback(err)`. The callback is invoked * when the data transfer is complete, or when an error has - * ocurred. Be sure to check `res.headersSent` if you plan to respond. + * occurred. Be sure to check `res.headersSent` if you plan to respond. * * Optionally providing an `options` object to use with `res.sendFile()`. * This function will set the `Content-Disposition` header, overriding @@ -623,7 +628,7 @@ res.type = function contentType(type) { * res.send('

hey

'); * }, * - * 'appliation/json': function(){ + * 'application/json': function () { * res.send({ message: 'hey' }); * } * }); @@ -726,7 +731,7 @@ res.append = function append(field, val) { // concat the new and prev vals value = Array.isArray(prev) ? prev.concat(val) : Array.isArray(val) ? [prev].concat(val) - : [prev, val]; + : [prev, val] } return this.set(field, value); @@ -1122,7 +1127,7 @@ function stringify (value, replacer, spaces, escape) { ? JSON.stringify(value, replacer, spaces) : JSON.stringify(value); - if (escape) { + if (escape && typeof json === 'string') { json = json.replace(/[<>&]/g, function (c) { switch (c.charCodeAt(0)) { case 0x3c: diff --git a/node_modules/express/lib/router/index.js b/node_modules/express/lib/router/index.js index 69e6d38..fbe94ac 100644 --- a/node_modules/express/lib/router/index.js +++ b/node_modules/express/lib/router/index.js @@ -287,6 +287,12 @@ proto.handle = function handle(req, res, out) { function trim_prefix(layer, layerError, layerPath, path) { if (layerPath.length !== 0) { + // Validate path is a prefix match + if (layerPath !== path.substr(0, layerPath.length)) { + next(layerError) + return + } + // Validate path breaks on a path separator var c = path[layerPath.length] if (c && c !== '/' && c !== '.') return next(layerError) diff --git a/node_modules/express/lib/utils.js b/node_modules/express/lib/utils.js index bd81ac7..7797b06 100644 --- a/node_modules/express/lib/utils.js +++ b/node_modules/express/lib/utils.js @@ -157,6 +157,7 @@ exports.compileETag = function(val) { switch (val) { case true: + case 'weak': fn = exports.wetag; break; case false: @@ -164,9 +165,6 @@ exports.compileETag = function(val) { case 'strong': fn = exports.etag; break; - case 'weak': - fn = exports.wetag; - break; default: throw new TypeError('unknown value for etag function: ' + val); } @@ -191,6 +189,7 @@ exports.compileQueryParser = function compileQueryParser(val) { switch (val) { case true: + case 'simple': fn = querystring.parse; break; case false: @@ -199,9 +198,6 @@ exports.compileQueryParser = function compileQueryParser(val) { case 'extended': fn = parseExtendedQueryString; break; - case 'simple': - fn = querystring.parse; - break; default: throw new TypeError('unknown value for query parser function: ' + val); } @@ -232,7 +228,8 @@ exports.compileTrust = function(val) { if (typeof val === 'string') { // Support comma-separated values - val = val.split(/ *, */); + val = val.split(',') + .map(function (v) { return v.trim() }) } return proxyaddr.compile(val || []); diff --git a/node_modules/express/package.json b/node_modules/express/package.json index 2979d57..2fb6eba 100644 --- a/node_modules/express/package.json +++ b/node_modules/express/package.json @@ -1,7 +1,7 @@ { "name": "express", "description": "Fast, unopinionated, minimalist web framework", - "version": "4.17.1", + "version": "4.17.3", "author": "TJ Holowaychuk ", "contributors": [ "Aaron Heckmann ", @@ -20,6 +20,7 @@ "framework", "sinatra", "web", + "http", "rest", "restful", "router", @@ -27,12 +28,12 @@ "api" ], "dependencies": { - "accepts": "~1.3.7", + "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", + "body-parser": "1.19.2", + "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.0", + "cookie": "0.4.2", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "~1.1.2", @@ -46,13 +47,13 @@ "on-finished": "~2.3.0", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", + "proxy-addr": "~2.0.7", + "qs": "6.9.7", "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", + "safe-buffer": "5.2.1", + "send": "0.17.2", + "serve-static": "1.14.2", + "setprototypeof": "1.2.0", "statuses": "~1.5.0", "type-is": "~1.6.18", "utils-merge": "1.0.1", @@ -60,22 +61,23 @@ }, "devDependencies": { "after": "0.8.2", - "connect-redis": "3.4.1", - "cookie-parser": "~1.4.4", - "cookie-session": "1.3.3", - "ejs": "2.6.1", - "eslint": "2.13.1", - "express-session": "1.16.1", - "hbs": "4.0.4", - "istanbul": "0.4.5", - "marked": "0.6.2", + "connect-redis": "3.4.2", + "cookie-parser": "1.4.6", + "cookie-session": "2.0.0", + "ejs": "3.1.6", + "eslint": "7.32.0", + "express-session": "1.17.2", + "hbs": "4.2.0", + "marked": "0.7.0", "method-override": "3.0.0", - "mocha": "5.2.0", - "morgan": "1.9.1", - "multiparty": "4.2.1", + "mocha": "9.2.0", + "morgan": "1.10.0", + "multiparty": "4.2.3", + "nyc": "15.1.0", "pbkdf2-password": "1.2.1", + "resolve-path": "1.4.0", "should": "13.2.3", - "supertest": "3.3.0", + "supertest": "6.2.2", "vhost": "~3.0.2" }, "engines": { @@ -91,8 +93,8 @@ "scripts": { "lint": "eslint .", "test": "mocha --require test/support/env --reporter spec --bail --check-leaks test/ test/acceptance/", - "test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks test/ test/acceptance/", - "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks test/ test/acceptance/", + "test-ci": "nyc --reporter=lcovonly --reporter=text npm test", + "test-cov": "nyc --reporter=html --reporter=text npm test", "test-tap": "mocha --require test/support/env --reporter tap --check-leaks test/ test/acceptance/" } } diff --git a/node_modules/graceful-fs/package.json b/node_modules/graceful-fs/package.json index 032c7d0..e1cb584 100644 --- a/node_modules/graceful-fs/package.json +++ b/node_modules/graceful-fs/package.json @@ -1,7 +1,7 @@ { "name": "graceful-fs", "description": "A drop-in replacement for fs, making various improvements.", - "version": "4.2.8", + "version": "4.2.9", "repository": { "type": "git", "url": "https://github.com/isaacs/node-graceful-fs" diff --git a/node_modules/graceful-fs/polyfills.js b/node_modules/graceful-fs/polyfills.js index 1287da1..26804ef 100644 --- a/node_modules/graceful-fs/polyfills.js +++ b/node_modules/graceful-fs/polyfills.js @@ -310,8 +310,10 @@ function patch (fs) { 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 + if (stats) { + if (stats.uid < 0) stats.uid += 0x100000000 + if (stats.gid < 0) stats.gid += 0x100000000 + } return stats; } } diff --git a/node_modules/http-errors/HISTORY.md b/node_modules/http-errors/HISTORY.md index efc2d4c..fd802a5 100644 --- a/node_modules/http-errors/HISTORY.md +++ b/node_modules/http-errors/HISTORY.md @@ -1,3 +1,19 @@ +2021-11-14 / 1.8.1 +================== + + * deps: toidentifier@1.0.1 + +2020-06-29 / 1.8.0 +================== + + * Add `isHttpError` export to determine if value is an HTTP error + * deps: setprototypeof@1.2.0 + +2019-06-24 / 1.7.3 +================== + + * deps: inherits@2.0.4 + 2019-02-18 / 1.7.2 ================== diff --git a/node_modules/http-errors/README.md b/node_modules/http-errors/README.md index 3b25481..42251a3 100644 --- a/node_modules/http-errors/README.md +++ b/node_modules/http-errors/README.md @@ -3,7 +3,7 @@ [![NPM Version][npm-version-image]][npm-url] [![NPM Downloads][npm-downloads-image]][node-url] [![Node.js Version][node-image]][node-url] -[![Build Status][travis-image]][travis-url] +[![Build Status][ci-image]][ci-url] [![Test Coverage][coveralls-image]][coveralls-url] Create HTTP errors for Express, Koa, Connect, etc. with ease. @@ -53,8 +53,6 @@ This is the current API, currently extracted from Koa and subject to change. Create a new error object with the given message `msg`. The error object inherits from `createError.HttpError`. - - ```js var err = createError(404, 'This video does not exist!') ``` @@ -70,7 +68,7 @@ properties. This will not alter the inheritance of the given `error` object, and the modified `error` object is the return value. - + ```js fs.readFile('foo.txt', function (err, buf) { @@ -88,13 +86,19 @@ fs.readFile('foo.txt', function (err, buf) { - `error` - the error object to extend - `properties` - custom properties to attach to the object +### createError.isHttpError(val) + +Determine if the provided `val` is an `HttpError`. This will return `true` +if the error inherits from the `HttpError` constructor of this module or +matches the "duck type" for an error this module creates. All outputs from +the `createError` factory will return `true` for this function, including +if an non-`HttpError` was passed into the factory. + ### new createError\[code || name\](\[msg]\)) Create a new error object with the given message `msg`. The error object inherits from `createError.HttpError`. - - ```js var err = new createError.NotFound() ``` @@ -152,6 +156,8 @@ var err = new createError.NotFound() [MIT](LICENSE) +[ci-image]: https://badgen.net/github/checks/jshttp/http-errors/master?label=ci +[ci-url]: https://github.com/jshttp/http-errors/actions?query=workflow%3Aci [coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/http-errors/master [coveralls-url]: https://coveralls.io/r/jshttp/http-errors?branch=master [node-image]: https://badgen.net/npm/node/http-errors diff --git a/node_modules/http-errors/index.js b/node_modules/http-errors/index.js index 10ca4ad..1a88029 100644 --- a/node_modules/http-errors/index.js +++ b/node_modules/http-errors/index.js @@ -25,6 +25,7 @@ var toIdentifier = require('toidentifier') module.exports = createError module.exports.HttpError = createHttpErrorConstructor() +module.exports.isHttpError = createIsHttpErrorFunction(module.exports.HttpError) // Populate exports for all constructors populateConstructorExports(module.exports, statuses.codes, module.exports.HttpError) @@ -130,7 +131,7 @@ function createHttpErrorConstructor () { */ function createClientErrorConstructor (HttpError, name, code) { - var className = name.match(/Error$/) ? name : name + 'Error' + var className = toClassName(name) function ClientError (message) { // create the error object @@ -172,13 +173,34 @@ function createClientErrorConstructor (HttpError, name, code) { return ClientError } +/** + * Create function to test is a value is a HttpError. + * @private + */ + +function createIsHttpErrorFunction (HttpError) { + return function isHttpError (val) { + if (!val || typeof val !== 'object') { + return false + } + + if (val instanceof HttpError) { + return true + } + + return val instanceof Error && + typeof val.expose === 'boolean' && + typeof val.statusCode === 'number' && val.status === val.statusCode + } +} + /** * Create a constructor for a server error. * @private */ function createServerErrorConstructor (HttpError, name, code) { - var className = name.match(/Error$/) ? name : name + 'Error' + var className = toClassName(name) function ServerError (message) { // create the error object @@ -264,3 +286,14 @@ function populateConstructorExports (exports, codes, HttpError) { exports["I'mateapot"] = deprecate.function(exports.ImATeapot, '"I\'mateapot"; use "ImATeapot" instead') } + +/** + * Get a class name from a name identifier. + * @private + */ + +function toClassName (name) { + return name.substr(-5) !== 'Error' + ? name + 'Error' + : name +} diff --git a/node_modules/http-errors/package.json b/node_modules/http-errors/package.json index 96cd630..df52507 100644 --- a/node_modules/http-errors/package.json +++ b/node_modules/http-errors/package.json @@ -1,7 +1,7 @@ { "name": "http-errors", "description": "Create HTTP error objects", - "version": "1.7.2", + "version": "1.8.1", "author": "Jonathan Ong (http://jongleberry.com)", "contributors": [ "Alan Plum ", @@ -11,30 +11,30 @@ "repository": "jshttp/http-errors", "dependencies": { "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "toidentifier": "1.0.1" }, "devDependencies": { - "eslint": "5.13.0", - "eslint-config-standard": "12.0.0", - "eslint-plugin-import": "2.16.0", - "eslint-plugin-markdown": "1.0.0", - "eslint-plugin-node": "7.0.1", - "eslint-plugin-promise": "4.0.1", - "eslint-plugin-standard": "4.0.0", - "istanbul": "0.4.5", - "mocha": "5.2.0" + "eslint": "7.32.0", + "eslint-config-standard": "14.1.1", + "eslint-plugin-import": "2.25.3", + "eslint-plugin-markdown": "2.2.1", + "eslint-plugin-node": "11.1.0", + "eslint-plugin-promise": "5.1.1", + "eslint-plugin-standard": "4.1.0", + "mocha": "9.1.3", + "nyc": "15.1.0" }, "engines": { "node": ">= 0.6" }, "scripts": { - "lint": "eslint --plugin markdown --ext js,md . && node ./scripts/lint-readme-list.js", + "lint": "eslint . && node ./scripts/lint-readme-list.js", "test": "mocha --reporter spec --bail", - "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot", - "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter dot" + "test-ci": "nyc --reporter=lcov --reporter=text npm test", + "test-cov": "nyc --reporter=html --reporter=text npm test" }, "keywords": [ "http", diff --git a/node_modules/inherits/inherits.js b/node_modules/inherits/inherits.js index 3b94763..f71f2d9 100644 --- a/node_modules/inherits/inherits.js +++ b/node_modules/inherits/inherits.js @@ -1,7 +1,9 @@ try { var util = require('util'); + /* istanbul ignore next */ if (typeof util.inherits !== 'function') throw ''; module.exports = util.inherits; } catch (e) { + /* istanbul ignore next */ module.exports = require('./inherits_browser.js'); } diff --git a/node_modules/inherits/inherits_browser.js b/node_modules/inherits/inherits_browser.js index c1e78a7..86bbb3d 100644 --- a/node_modules/inherits/inherits_browser.js +++ b/node_modules/inherits/inherits_browser.js @@ -1,23 +1,27 @@ if (typeof Object.create === 'function') { // implementation from standard node.js 'util' module module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); + if (superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }) + } }; } else { // old school shim for old browsers module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor + if (superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } } } diff --git a/node_modules/inherits/package.json b/node_modules/inherits/package.json index 7cf62b9..37b4366 100644 --- a/node_modules/inherits/package.json +++ b/node_modules/inherits/package.json @@ -1,7 +1,7 @@ { "name": "inherits", "description": "Browser-friendly inheritance fully compatible with standard node.js inherits()", - "version": "2.0.3", + "version": "2.0.4", "keywords": [ "inheritance", "class", @@ -17,10 +17,10 @@ "repository": "git://github.com/isaacs/inherits", "license": "ISC", "scripts": { - "test": "node test" + "test": "tap" }, "devDependencies": { - "tap": "^7.1.0" + "tap": "^14.2.4" }, "files": [ "inherits.js", diff --git a/node_modules/mime-db/HISTORY.md b/node_modules/mime-db/HISTORY.md index 622adb9..7436f64 100644 --- a/node_modules/mime-db/HISTORY.md +++ b/node_modules/mime-db/HISTORY.md @@ -1,3 +1,18 @@ +1.52.0 / 2022-02-21 +=================== + + * Add extensions from IANA for more `image/*` types + * Add extension `.asc` to `application/pgp-keys` + * Add extensions to various XML types + * Add new upstream MIME types + +1.51.0 / 2021-11-08 +=================== + + * Add new upstream MIME types + * Mark `image/vnd.microsoft.icon` as compressible + * Mark `image/vnd.ms-dds` as compressible + 1.50.0 / 2021-09-15 =================== diff --git a/node_modules/mime-db/LICENSE b/node_modules/mime-db/LICENSE index a7ae8ee..0751cb1 100644 --- a/node_modules/mime-db/LICENSE +++ b/node_modules/mime-db/LICENSE @@ -1,22 +1,23 @@ +(The MIT License) -The MIT License (MIT) +Copyright (c) 2014 Jonathan Ong +Copyright (c) 2015-2022 Douglas Christopher Wilson -Copyright (c) 2014 Jonathan Ong me@jongleberry.com +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: -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 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. +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. diff --git a/node_modules/mime-db/README.md b/node_modules/mime-db/README.md index 41c696a..5a8fcfe 100644 --- a/node_modules/mime-db/README.md +++ b/node_modules/mime-db/README.md @@ -6,7 +6,7 @@ [![Build Status][ci-image]][ci-url] [![Coverage Status][coveralls-image]][coveralls-url] -This is a database of all mime types. +This is a large database of mime types and information about them. It consists of a single, public JSON file and does not include any logic, allowing it to remain as un-opinionated as possible with an API. It aggregates data from the following sources: diff --git a/node_modules/mime-db/db.json b/node_modules/mime-db/db.json index 29786a7..eb9c42c 100644 --- a/node_modules/mime-db/db.json +++ b/node_modules/mime-db/db.json @@ -250,6 +250,10 @@ "application/cfw": { "source": "iana" }, + "application/city+json": { + "source": "iana", + "compressible": true + }, "application/clr": { "source": "iana" }, @@ -293,7 +297,8 @@ }, "application/cpl+xml": { "source": "iana", - "compressible": true + "compressible": true, + "extensions": ["cpl"] }, "application/csrattrs": { "source": "iana" @@ -328,6 +333,11 @@ "compressible": true, "extensions": ["mpd"] }, + "application/dash-patch+xml": { + "source": "iana", + "compressible": true, + "extensions": ["mpp"] + }, "application/dashdelta": { "source": "iana" }, @@ -868,7 +878,8 @@ }, "application/media-policy-dataset+xml": { "source": "iana", - "compressible": true + "compressible": true, + "extensions": ["mpf"] }, "application/media_control+xml": { "source": "iana", @@ -1024,6 +1035,9 @@ "application/oauth-authz-req+jwt": { "source": "iana" }, + "application/oblivious-dns-message": { + "source": "iana" + }, "application/ocsp-request": { "source": "iana" }, @@ -1116,7 +1130,8 @@ "extensions": ["pgp"] }, "application/pgp-keys": { - "source": "iana" + "source": "iana", + "extensions": ["asc"] }, "application/pgp-signature": { "source": "iana", @@ -1536,6 +1551,10 @@ "compressible": true, "extensions": ["srx"] }, + "application/spdx+json": { + "source": "iana", + "compressible": true + }, "application/spirits-event+xml": { "source": "iana", "compressible": true @@ -2017,6 +2036,10 @@ "application/vnd.afpc.modca-pagesegment": { "source": "iana" }, + "application/vnd.age": { + "source": "iana", + "extensions": ["age"] + }, "application/vnd.ah-barcode": { "source": "iana" }, @@ -2639,6 +2662,10 @@ "application/vnd.ecip.rlp": { "source": "iana" }, + "application/vnd.eclipse.ditto+json": { + "source": "iana", + "compressible": true + }, "application/vnd.ecowin.chart": { "source": "iana", "extensions": ["mag"] @@ -2796,6 +2823,10 @@ "application/vnd.etsi.tsl.der": { "source": "iana" }, + "application/vnd.eu.kasparian.car+json": { + "source": "iana", + "compressible": true + }, "application/vnd.eudora.data": { "source": "iana" }, @@ -2826,6 +2857,10 @@ "application/vnd.f-secure.mobile": { "source": "iana" }, + "application/vnd.familysearch.gedcom+zip": { + "source": "iana", + "compressible": false + }, "application/vnd.fastcopy-disk-image": { "source": "iana" }, @@ -3116,6 +3151,16 @@ "source": "iana", "extensions": ["les"] }, + "application/vnd.hl7cda+xml": { + "source": "iana", + "charset": "UTF-8", + "compressible": true + }, + "application/vnd.hl7v2+xml": { + "source": "iana", + "charset": "UTF-8", + "compressible": true + }, "application/vnd.hp-hpgl": { "source": "iana", "extensions": ["hpgl"] @@ -3529,6 +3574,10 @@ "source": "iana", "compressible": true }, + "application/vnd.maxar.archive.3tz+zip": { + "source": "iana", + "compressible": false + }, "application/vnd.maxmind.maxmind-db": { "source": "iana" }, @@ -3858,6 +3907,10 @@ "source": "iana", "extensions": ["taglet"] }, + "application/vnd.nacamar.ybrid+json": { + "source": "iana", + "compressible": true + }, "application/vnd.ncd.control": { "source": "iana" }, @@ -5145,6 +5198,10 @@ "source": "iana", "compressible": true }, + "application/vnd.syft+json": { + "source": "iana", + "compressible": true + }, "application/vnd.symbian.install": { "source": "apache", "extensions": ["sis","sisx"] @@ -5535,7 +5592,8 @@ }, "application/watcherinfo+xml": { "source": "iana", - "compressible": true + "compressible": true, + "extensions": ["wif"] }, "application/webpush-options+json": { "source": "iana", @@ -6955,10 +7013,12 @@ "extensions": ["apng"] }, "image/avci": { - "source": "iana" + "source": "iana", + "extensions": ["avci"] }, "image/avcs": { - "source": "iana" + "source": "iana", + "extensions": ["avcs"] }, "image/avif": { "source": "iana", @@ -7192,6 +7252,7 @@ }, "image/vnd.microsoft.icon": { "source": "iana", + "compressible": true, "extensions": ["ico"] }, "image/vnd.mix": { @@ -7201,6 +7262,7 @@ "source": "iana" }, "image/vnd.ms-dds": { + "compressible": true, "extensions": ["dds"] }, "image/vnd.ms-modi": { @@ -7890,6 +7952,10 @@ "source": "iana", "charset": "UTF-8" }, + "text/vnd.familysearch.gedcom": { + "source": "iana", + "extensions": ["ged"] + }, "text/vnd.ficlab.flt": { "source": "iana" }, diff --git a/node_modules/mime-db/index.js b/node_modules/mime-db/index.js index 551031f..ec2be30 100644 --- a/node_modules/mime-db/index.js +++ b/node_modules/mime-db/index.js @@ -1,6 +1,7 @@ /*! * mime-db * Copyright(c) 2014 Jonathan Ong + * Copyright(c) 2015-2022 Douglas Christopher Wilson * MIT Licensed */ diff --git a/node_modules/mime-db/package.json b/node_modules/mime-db/package.json index b53d3ce..32c14b8 100644 --- a/node_modules/mime-db/package.json +++ b/node_modules/mime-db/package.json @@ -1,7 +1,7 @@ { "name": "mime-db", "description": "Media Type Database", - "version": "1.50.0", + "version": "1.52.0", "contributors": [ "Douglas Christopher Wilson ", "Jonathan Ong (http://jongleberry.com)", @@ -25,15 +25,16 @@ "csv-parse": "4.16.3", "eslint": "7.32.0", "eslint-config-standard": "15.0.1", - "eslint-plugin-import": "2.24.2", + "eslint-plugin-import": "2.25.4", "eslint-plugin-markdown": "2.2.1", "eslint-plugin-node": "11.1.0", - "eslint-plugin-promise": "5.1.0", + "eslint-plugin-promise": "5.1.1", "eslint-plugin-standard": "4.1.0", "gnode": "0.1.2", - "mocha": "9.1.1", + "media-typer": "1.1.0", + "mocha": "9.2.1", "nyc": "15.1.0", - "raw-body": "2.4.1", + "raw-body": "2.5.0", "stream-to-array": "2.3.0" }, "files": [ diff --git a/node_modules/mime-types/HISTORY.md b/node_modules/mime-types/HISTORY.md index d5545c1..c5043b7 100644 --- a/node_modules/mime-types/HISTORY.md +++ b/node_modules/mime-types/HISTORY.md @@ -1,3 +1,18 @@ +2.1.35 / 2022-03-12 +=================== + + * deps: mime-db@1.52.0 + - Add extensions from IANA for more `image/*` types + - Add extension `.asc` to `application/pgp-keys` + - Add extensions to various XML types + - Add new upstream MIME types + +2.1.34 / 2021-11-08 +=================== + + * deps: mime-db@1.51.0 + - Add new upstream MIME types + 2.1.33 / 2021-10-01 =================== @@ -18,7 +33,6 @@ * deps: mime-db@1.48.0 - Add extension `.mvt` to `application/vnd.mapbox-vector-tile` - Add new upstream MIME types - - Mark `text/yaml` as compressible 2.1.30 / 2021-04-02 =================== @@ -96,7 +110,6 @@ - Add extension `.nq` to `application/n-quads` - Add extension `.nt` to `application/n-triples` - Add new upstream MIME types - - Mark `text/less` as compressible 2.1.21 / 2018-10-19 =================== @@ -349,7 +362,6 @@ * deps: mime-db@~1.1.0 - Add new mime types - - Add additional compressible - Update charsets 2.0.1 / 2014-09-07 diff --git a/node_modules/mime-types/README.md b/node_modules/mime-types/README.md index c978ac2..48d2fb4 100644 --- a/node_modules/mime-types/README.md +++ b/node_modules/mime-types/README.md @@ -103,7 +103,7 @@ A map of extensions by content-type. [MIT](LICENSE) [ci-image]: https://badgen.net/github/checks/jshttp/mime-types/master?label=ci -[ci-url]: https://github.com/jshttp/mime-types/actions?query=workflow%3Aci +[ci-url]: https://github.com/jshttp/mime-types/actions/workflows/ci.yml [coveralls-image]: https://badgen.net/coveralls/c/github/jshttp/mime-types/master [coveralls-url]: https://coveralls.io/r/jshttp/mime-types?branch=master [node-version-image]: https://badgen.net/npm/node/mime-types diff --git a/node_modules/mime-types/package.json b/node_modules/mime-types/package.json index 17bddef..bbef696 100644 --- a/node_modules/mime-types/package.json +++ b/node_modules/mime-types/package.json @@ -1,7 +1,7 @@ { "name": "mime-types", "description": "The ultimate javascript content-type utility.", - "version": "2.1.33", + "version": "2.1.35", "contributors": [ "Douglas Christopher Wilson ", "Jeremiah Senkpiel (https://searchbeam.jit.su)", @@ -14,17 +14,17 @@ ], "repository": "jshttp/mime-types", "dependencies": { - "mime-db": "1.50.0" + "mime-db": "1.52.0" }, "devDependencies": { "eslint": "7.32.0", "eslint-config-standard": "14.1.1", - "eslint-plugin-import": "2.24.2", + "eslint-plugin-import": "2.25.4", "eslint-plugin-markdown": "2.2.1", "eslint-plugin-node": "11.1.0", - "eslint-plugin-promise": "5.1.0", + "eslint-plugin-promise": "5.2.0", "eslint-plugin-standard": "4.1.0", - "mocha": "9.1.2", + "mocha": "9.2.2", "nyc": "15.1.0" }, "files": [ diff --git a/node_modules/minimatch/README.md b/node_modules/minimatch/README.md index ad72b81..33ede1d 100644 --- a/node_modules/minimatch/README.md +++ b/node_modules/minimatch/README.md @@ -2,7 +2,7 @@ A minimal matching utility. -[![Build Status](https://secure.travis-ci.org/isaacs/minimatch.svg)](http://travis-ci.org/isaacs/minimatch) +[![Build Status](https://travis-ci.org/isaacs/minimatch.svg?branch=master)](http://travis-ci.org/isaacs/minimatch) This is the matching library used internally by npm. @@ -171,6 +171,27 @@ Suppress the behavior of treating a leading `!` character as negation. Returns from negate expressions the same as if they were not negated. (Ie, true on a hit, false on a miss.) +### partial + +Compare a partial path to a pattern. As long as the parts of the path that +are present are not contradicted by the pattern, it will be treated as a +match. This is useful in applications where you're walking through a +folder structure, and don't yet have the full path, but want to ensure that +you do not walk down paths that can never be a match. + +For example, + +```js +minimatch('/a/b', '/a/*/c/d', { partial: true }) // true, might be /a/b/c/d +minimatch('/a/b', '/**/d', { partial: true }) // true, might be /a/b/.../d +minimatch('/x/y/z', '/a/**/z', { partial: true }) // false, because x !== a +``` + +### allowWindowsEscape + +Windows path separator `\` is by default converted to `/`, which +prohibits the usage of `\` as a escape character. This flag skips that +behavior and allows using the escape character. ## Comparisons to other fnmatch/glob implementations diff --git a/node_modules/minimatch/minimatch.js b/node_modules/minimatch/minimatch.js index 5b5f8cf..fda45ad 100644 --- a/node_modules/minimatch/minimatch.js +++ b/node_modules/minimatch/minimatch.js @@ -1,10 +1,10 @@ module.exports = minimatch minimatch.Minimatch = Minimatch -var path = { sep: '/' } -try { - path = require('path') -} catch (er) {} +var path = (function () { try { return require('path') } catch (e) {}}()) || { + sep: '/' +} +minimatch.sep = path.sep var GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {} var expand = require('brace-expansion') @@ -56,43 +56,64 @@ function filter (pattern, options) { } function ext (a, b) { - a = a || {} b = b || {} var t = {} - Object.keys(b).forEach(function (k) { - t[k] = b[k] - }) Object.keys(a).forEach(function (k) { t[k] = a[k] }) + Object.keys(b).forEach(function (k) { + t[k] = b[k] + }) return t } minimatch.defaults = function (def) { - if (!def || !Object.keys(def).length) return minimatch + if (!def || typeof def !== 'object' || !Object.keys(def).length) { + return minimatch + } var orig = minimatch var m = function minimatch (p, pattern, options) { - return orig.minimatch(p, pattern, ext(def, options)) + return orig(p, pattern, ext(def, options)) } m.Minimatch = function Minimatch (pattern, options) { return new orig.Minimatch(pattern, ext(def, options)) } + m.Minimatch.defaults = function defaults (options) { + return orig.defaults(ext(def, options)).Minimatch + } + + m.filter = function filter (pattern, options) { + return orig.filter(pattern, ext(def, options)) + } + + m.defaults = function defaults (options) { + return orig.defaults(ext(def, options)) + } + + m.makeRe = function makeRe (pattern, options) { + return orig.makeRe(pattern, ext(def, options)) + } + + m.braceExpand = function braceExpand (pattern, options) { + return orig.braceExpand(pattern, ext(def, options)) + } + + m.match = function (list, pattern, options) { + return orig.match(list, pattern, ext(def, options)) + } return m } Minimatch.defaults = function (def) { - if (!def || !Object.keys(def).length) return Minimatch return minimatch.defaults(def).Minimatch } function minimatch (p, pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('glob pattern string required') - } + assertValidPattern(pattern) if (!options) options = {} @@ -101,9 +122,6 @@ function minimatch (p, pattern, options) { return false } - // "" only matches "" - if (pattern.trim() === '') return p === '' - return new Minimatch(pattern, options).match(p) } @@ -112,15 +130,14 @@ function Minimatch (pattern, options) { return new Minimatch(pattern, options) } - if (typeof pattern !== 'string') { - throw new TypeError('glob pattern string required') - } + assertValidPattern(pattern) if (!options) options = {} + pattern = pattern.trim() // windows support: need to use /, not \ - if (path.sep !== '/') { + if (!options.allowWindowsEscape && path.sep !== '/') { pattern = pattern.split(path.sep).join('/') } @@ -131,6 +148,7 @@ function Minimatch (pattern, options) { this.negate = false this.comment = false this.empty = false + this.partial = !!options.partial // make the set of regexps etc. this.make() @@ -140,9 +158,6 @@ Minimatch.prototype.debug = function () {} Minimatch.prototype.make = make function make () { - // don't do it more than once. - if (this._made) return - var pattern = this.pattern var options = this.options @@ -162,7 +177,7 @@ function make () { // step 2: expand braces var set = this.globSet = this.braceExpand() - if (options.debug) this.debug = console.error + if (options.debug) this.debug = function debug() { console.error.apply(console, arguments) } this.debug(this.pattern, set) @@ -242,12 +257,11 @@ function braceExpand (pattern, options) { pattern = typeof pattern === 'undefined' ? this.pattern : pattern - if (typeof pattern === 'undefined') { - throw new TypeError('undefined pattern') - } + assertValidPattern(pattern) - if (options.nobrace || - !pattern.match(/\{.*\}/)) { + // Thanks to Yeting Li for + // improving this regexp to avoid a ReDOS vulnerability. + if (options.nobrace || !/\{(?:(?!\{).)*\}/.test(pattern)) { // shortcut. no need to expand. return [pattern] } @@ -255,6 +269,17 @@ function braceExpand (pattern, options) { return expand(pattern) } +var MAX_PATTERN_LENGTH = 1024 * 64 +var assertValidPattern = function (pattern) { + if (typeof pattern !== 'string') { + throw new TypeError('invalid pattern') + } + + if (pattern.length > MAX_PATTERN_LENGTH) { + throw new TypeError('pattern is too long') + } +} + // parse a component of the expanded set. // At this point, no pattern may contain "/" in it // so we're going to return a 2d array, where each entry is the full @@ -269,14 +294,17 @@ function braceExpand (pattern, options) { Minimatch.prototype.parse = parse var SUBPARSE = {} function parse (pattern, isSub) { - if (pattern.length > 1024 * 64) { - throw new TypeError('pattern is too long') - } + assertValidPattern(pattern) var options = this.options // shortcuts - if (!options.noglobstar && pattern === '**') return GLOBSTAR + if (pattern === '**') { + if (!options.noglobstar) + return GLOBSTAR + else + pattern = '*' + } if (pattern === '') return '' var re = '' @@ -332,10 +360,12 @@ function parse (pattern, isSub) { } switch (c) { - case '/': + /* istanbul ignore next */ + case '/': { // completely not allowed, even escaped. // Should already be path-split by now. return false + } case '\\': clearStateChar() @@ -454,25 +484,23 @@ function parse (pattern, isSub) { // handle the case where we left a class open. // "[z-a]" is valid, equivalent to "\[z-a\]" - if (inClass) { - // split where the last [ was, make sure we don't have - // an invalid re. if so, re-walk the contents of the - // would-be class to re-translate any characters that - // were passed through as-is - // TODO: It would probably be faster to determine this - // without a try/catch and a new RegExp, but it's tricky - // to do safely. For now, this is safe and works. - var cs = pattern.substring(classStart + 1, i) - try { - RegExp('[' + cs + ']') - } catch (er) { - // not a valid class! - var sp = this.parse(cs, SUBPARSE) - re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]' - hasMagic = hasMagic || sp[1] - inClass = false - continue - } + // split where the last [ was, make sure we don't have + // an invalid re. if so, re-walk the contents of the + // would-be class to re-translate any characters that + // were passed through as-is + // TODO: It would probably be faster to determine this + // without a try/catch and a new RegExp, but it's tricky + // to do safely. For now, this is safe and works. + var cs = pattern.substring(classStart + 1, i) + try { + RegExp('[' + cs + ']') + } catch (er) { + // not a valid class! + var sp = this.parse(cs, SUBPARSE) + re = re.substr(0, reClassStart) + '\\[' + sp[0] + '\\]' + hasMagic = hasMagic || sp[1] + inClass = false + continue } // finish up the class. @@ -556,9 +584,7 @@ function parse (pattern, isSub) { // something that could conceivably capture a dot var addPatternStart = false switch (re.charAt(0)) { - case '.': - case '[': - case '(': addPatternStart = true + case '[': case '.': case '(': addPatternStart = true } // Hack to work around lack of negative lookbehind in JS @@ -620,7 +646,7 @@ function parse (pattern, isSub) { var flags = options.nocase ? 'i' : '' try { var regExp = new RegExp('^' + re + '$', flags) - } catch (er) { + } catch (er) /* istanbul ignore next - should be impossible */ { // If it was an invalid regular expression, then it can't match // anything. This trick looks for a character after the end of // the string, which is of course impossible, except in multi-line @@ -678,7 +704,7 @@ function makeRe () { try { this.regexp = new RegExp(re, flags) - } catch (ex) { + } catch (ex) /* istanbul ignore next - should be impossible */ { this.regexp = false } return this.regexp @@ -696,8 +722,8 @@ minimatch.match = function (list, pattern, options) { return list } -Minimatch.prototype.match = match -function match (f, partial) { +Minimatch.prototype.match = function match (f, partial) { + if (typeof partial === 'undefined') partial = this.partial this.debug('match', f, this.pattern) // short-circuit in the case of busted things. // comments, etc. @@ -779,6 +805,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) { // should be impossible. // some invalid regexp stuff in the set. + /* istanbul ignore if */ if (p === false) return false if (p === GLOBSTAR) { @@ -852,6 +879,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) { // no match was found. // However, in partial mode, we can't say this is necessarily over. // If there's more *pattern* left, then + /* istanbul ignore if */ if (partial) { // ran out of file this.debug('\n>>> no match, partial?', file, fr, pattern, pr) @@ -865,11 +893,7 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) { // patterns with magic have been turned into regexps. var hit if (typeof p === 'string') { - if (options.nocase) { - hit = f.toLowerCase() === p.toLowerCase() - } else { - hit = f === p - } + hit = f === p this.debug('string match', p, f, hit) } else { hit = f.match(p) @@ -900,16 +924,16 @@ Minimatch.prototype.matchOne = function (file, pattern, partial) { // this is ok if we're doing the match as part of // a glob fs traversal. return partial - } else if (pi === pl) { + } else /* istanbul ignore else */ if (pi === pl) { // ran out of pattern, still have file left. // this is only acceptable if we're on the very last // empty segment of a file with a trailing slash. // a/* should match a/b/ - var emptyFileEnd = (fi === fl - 1) && (file[fi] === '') - return emptyFileEnd + return (fi === fl - 1) && (file[fi] === '') } // should be unreachable. + /* istanbul ignore next */ throw new Error('wtf?') } diff --git a/node_modules/minimatch/package.json b/node_modules/minimatch/package.json index c4514c8..566efdf 100644 --- a/node_modules/minimatch/package.json +++ b/node_modules/minimatch/package.json @@ -2,14 +2,17 @@ "author": "Isaac Z. Schlueter (http://blog.izs.me)", "name": "minimatch", "description": "a glob matcher in javascript", - "version": "3.0.4", + "version": "3.1.2", + "publishConfig": { + "tag": "v3-legacy" + }, "repository": { "type": "git", "url": "git://github.com/isaacs/minimatch.git" }, "main": "minimatch.js", "scripts": { - "test": "tap test/*.js --cov", + "test": "tap", "preversion": "npm test", "postversion": "npm publish", "postpublish": "git push origin --all; git push origin --tags" @@ -21,7 +24,7 @@ "brace-expansion": "^1.1.7" }, "devDependencies": { - "tap": "^10.3.2" + "tap": "^15.1.6" }, "license": "ISC", "files": [ diff --git a/node_modules/negotiator/HISTORY.md b/node_modules/negotiator/HISTORY.md index 6d06c76..a9a5449 100644 --- a/node_modules/negotiator/HISTORY.md +++ b/node_modules/negotiator/HISTORY.md @@ -1,3 +1,8 @@ +0.6.3 / 2022-01-22 +================== + + * Revert "Lazy-load modules from main entry point" + 0.6.2 / 2019-04-29 ================== diff --git a/node_modules/negotiator/README.md b/node_modules/negotiator/README.md index 04a67ff..82915e5 100644 --- a/node_modules/negotiator/README.md +++ b/node_modules/negotiator/README.md @@ -3,7 +3,7 @@ [![NPM Version][npm-image]][npm-url] [![NPM Downloads][downloads-image]][downloads-url] [![Node.js Version][node-version-image]][node-version-url] -[![Build Status][travis-image]][travis-url] +[![Build Status][github-actions-ci-image]][github-actions-ci-url] [![Test Coverage][coveralls-image]][coveralls-url] An HTTP content negotiator for Node.js @@ -195,9 +195,9 @@ and more. [npm-url]: https://npmjs.org/package/negotiator [node-version-image]: https://img.shields.io/node/v/negotiator.svg [node-version-url]: https://nodejs.org/en/download/ -[travis-image]: https://img.shields.io/travis/jshttp/negotiator/master.svg -[travis-url]: https://travis-ci.org/jshttp/negotiator [coveralls-image]: https://img.shields.io/coveralls/jshttp/negotiator/master.svg [coveralls-url]: https://coveralls.io/r/jshttp/negotiator?branch=master [downloads-image]: https://img.shields.io/npm/dm/negotiator.svg [downloads-url]: https://npmjs.org/package/negotiator +[github-actions-ci-image]: https://img.shields.io/github/workflow/status/jshttp/negotiator/ci/master?label=ci +[github-actions-ci-url]: https://github.com/jshttp/negotiator/actions/workflows/ci.yml diff --git a/node_modules/negotiator/index.js b/node_modules/negotiator/index.js index 8d4f6a2..4788264 100644 --- a/node_modules/negotiator/index.js +++ b/node_modules/negotiator/index.js @@ -8,12 +8,10 @@ 'use strict'; -/** - * Cached loaded submodules. - * @private - */ - -var modules = Object.create(null); +var preferredCharsets = require('./lib/charset') +var preferredEncodings = require('./lib/encoding') +var preferredLanguages = require('./lib/language') +var preferredMediaTypes = require('./lib/mediaType') /** * Module exports. @@ -43,7 +41,6 @@ Negotiator.prototype.charset = function charset(available) { }; Negotiator.prototype.charsets = function charsets(available) { - var preferredCharsets = loadModule('charset').preferredCharsets; return preferredCharsets(this.request.headers['accept-charset'], available); }; @@ -53,7 +50,6 @@ Negotiator.prototype.encoding = function encoding(available) { }; Negotiator.prototype.encodings = function encodings(available) { - var preferredEncodings = loadModule('encoding').preferredEncodings; return preferredEncodings(this.request.headers['accept-encoding'], available); }; @@ -63,7 +59,6 @@ Negotiator.prototype.language = function language(available) { }; Negotiator.prototype.languages = function languages(available) { - var preferredLanguages = loadModule('language').preferredLanguages; return preferredLanguages(this.request.headers['accept-language'], available); }; @@ -73,7 +68,6 @@ Negotiator.prototype.mediaType = function mediaType(available) { }; Negotiator.prototype.mediaTypes = function mediaTypes(available) { - var preferredMediaTypes = loadModule('mediaType').preferredMediaTypes; return preferredMediaTypes(this.request.headers.accept, available); }; @@ -86,39 +80,3 @@ Negotiator.prototype.preferredLanguage = Negotiator.prototype.language; Negotiator.prototype.preferredLanguages = Negotiator.prototype.languages; Negotiator.prototype.preferredMediaType = Negotiator.prototype.mediaType; Negotiator.prototype.preferredMediaTypes = Negotiator.prototype.mediaTypes; - -/** - * Load the given module. - * @private - */ - -function loadModule(moduleName) { - var module = modules[moduleName]; - - if (module !== undefined) { - return module; - } - - // This uses a switch for static require analysis - switch (moduleName) { - case 'charset': - module = require('./lib/charset'); - break; - case 'encoding': - module = require('./lib/encoding'); - break; - case 'language': - module = require('./lib/language'); - break; - case 'mediaType': - module = require('./lib/mediaType'); - break; - default: - throw new Error('Cannot find module \'' + moduleName + '\''); - } - - // Store to prevent invoking require() - modules[moduleName] = module; - - return module; -} diff --git a/node_modules/negotiator/lib/language.js b/node_modules/negotiator/lib/language.js index 62f737f..a231672 100644 --- a/node_modules/negotiator/lib/language.js +++ b/node_modules/negotiator/lib/language.js @@ -54,9 +54,9 @@ function parseLanguage(str, i) { var match = simpleLanguageRegExp.exec(str); if (!match) return null; - var prefix = match[1], - suffix = match[2], - full = prefix; + var prefix = match[1] + var suffix = match[2] + var full = prefix if (suffix) full += "-" + suffix; diff --git a/node_modules/negotiator/package.json b/node_modules/negotiator/package.json index 0c7ff3c..297635f 100644 --- a/node_modules/negotiator/package.json +++ b/node_modules/negotiator/package.json @@ -1,7 +1,7 @@ { "name": "negotiator", "description": "HTTP content negotiation", - "version": "0.6.2", + "version": "0.6.3", "contributors": [ "Douglas Christopher Wilson ", "Federico Romero ", @@ -18,10 +18,10 @@ ], "repository": "jshttp/negotiator", "devDependencies": { - "eslint": "5.16.0", - "eslint-plugin-markdown": "1.0.0", - "mocha": "6.1.4", - "nyc": "14.0.0" + "eslint": "7.32.0", + "eslint-plugin-markdown": "2.2.1", + "mocha": "9.1.3", + "nyc": "15.1.0" }, "files": [ "lib/", @@ -34,9 +34,9 @@ "node": ">= 0.6" }, "scripts": { - "lint": "eslint --plugin markdown --ext js,md .", + "lint": "eslint .", "test": "mocha --reporter spec --check-leaks --bail test/", - "test-cov": "nyc --reporter=html --reporter=text npm test", - "test-travis": "nyc --reporter=text npm test" + "test-ci": "nyc --reporter=lcov --reporter=text npm test", + "test-cov": "nyc --reporter=html --reporter=text npm test" } } diff --git a/node_modules/qs/.editorconfig b/node_modules/qs/.editorconfig index a4893dd..0ea91d9 100644 --- a/node_modules/qs/.editorconfig +++ b/node_modules/qs/.editorconfig @@ -8,10 +8,14 @@ charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true max_line_length = 160 +quote_type = single [test/*] max_line_length = off +[LICENSE.md] +indent_size = off + [*.md] max_line_length = off @@ -28,3 +32,9 @@ indent_size = 2 [LICENSE] indent_size = 2 max_line_length = off + +[coverage/**/*] +indent_size = off +indent_style = off +indent = off +max_line_length = off diff --git a/node_modules/qs/.eslintignore b/node_modules/qs/.eslintignore deleted file mode 100644 index 1521c8b..0000000 --- a/node_modules/qs/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/node_modules/qs/.eslintrc b/node_modules/qs/.eslintrc index e3bde89..6884760 100644 --- a/node_modules/qs/.eslintrc +++ b/node_modules/qs/.eslintrc @@ -3,19 +3,36 @@ "extends": "@ljharb", + "ignorePatterns": [ + "dist/", + ], + "rules": { "complexity": 0, "consistent-return": 1, - "func-name-matching": 0, + "func-name-matching": 0, "id-length": [2, { "min": 1, "max": 25, "properties": "never" }], "indent": [2, 4], "max-lines-per-function": [2, { "max": 150 }], - "max-params": [2, 14], + "max-params": [2, 15], "max-statements": [2, 52], "multiline-comment-style": 0, "no-continue": 1, "no-magic-numbers": 0, "no-restricted-syntax": [2, "BreakStatement", "DebuggerStatement", "ForInStatement", "LabeledStatement", "WithStatement"], - "operator-linebreak": [2, "before"], - } + }, + + "overrides": [ + { + "files": "test/**", + "rules": { + "function-paren-newline": 0, + "max-lines-per-function": 0, + "max-statements": 0, + "no-buffer-constructor": 0, + "no-extend-native": 0, + "no-throw-literal": 0, + } + } + ] } diff --git a/node_modules/qs/.github/FUNDING.yml b/node_modules/qs/.github/FUNDING.yml new file mode 100644 index 0000000..0355f4f --- /dev/null +++ b/node_modules/qs/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: [ljharb] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: npm/qs +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: # Replace with a single custom sponsorship URL diff --git a/node_modules/qs/.nycrc b/node_modules/qs/.nycrc new file mode 100644 index 0000000..1d57cab --- /dev/null +++ b/node_modules/qs/.nycrc @@ -0,0 +1,13 @@ +{ + "all": true, + "check-coverage": false, + "reporter": ["text-summary", "text", "html", "json"], + "lines": 86, + "statements": 85.93, + "functions": 82.43, + "branches": 76.06, + "exclude": [ + "coverage", + "dist" + ] +} diff --git a/node_modules/qs/CHANGELOG.md b/node_modules/qs/CHANGELOG.md index 50505c4..1283465 100644 --- a/node_modules/qs/CHANGELOG.md +++ b/node_modules/qs/CHANGELOG.md @@ -1,3 +1,118 @@ +## **6.9.7** +- [Fix] `parse`: ignore `__proto__` keys (#428) +- [Fix] `stringify`: avoid encoding arrayformat comma when `encodeValuesOnly = true` (#424) +- [Robustness] `stringify`: avoid relying on a global `undefined` (#427) +- [readme] remove travis badge; add github actions/codecov badges; update URLs +- [Docs] add note and links for coercing primitive values (#408) +- [Tests] clean up stringify tests slightly +- [meta] fix README.md (#399) +- Revert "[meta] ignore eclint transitive audit warning" +- [actions] backport actions from main +- [Dev Deps] backport updates from main + +## **6.9.6** +- [Fix] restore `dist` dir; mistakenly removed in d4f6c32 + +## **6.9.5** +- [Fix] `stringify`: do not encode parens for RFC1738 +- [Fix] `stringify`: fix arrayFormat comma with empty array/objects (#350) +- [Refactor] `format`: remove `util.assign` call +- [meta] add "Allow Edits" workflow; update rebase workflow +- [actions] switch Automatic Rebase workflow to `pull_request_target` event +- [Tests] `stringify`: add tests for #378 +- [Tests] migrate tests to Github Actions +- [Tests] run `nyc` on all tests; use `tape` runner +- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `browserify`, `mkdirp`, `object-inspect`, `tape`; add `aud` + +## **6.9.4** +- [Fix] `stringify`: when `arrayFormat` is `comma`, respect `serializeDate` (#364) +- [Refactor] `stringify`: reduce branching (part of #350) +- [Refactor] move `maybeMap` to `utils` +- [Dev Deps] update `browserify`, `tape` + +## **6.9.3** +- [Fix] proper comma parsing of URL-encoded commas (#361) +- [Fix] parses comma delimited array while having percent-encoded comma treated as normal text (#336) + +## **6.9.2** +- [Fix] `parse`: Fix parsing array from object with `comma` true (#359) +- [Fix] `parse`: throw a TypeError instead of an Error for bad charset (#349) +- [meta] ignore eclint transitive audit warning +- [meta] fix indentation in package.json +- [meta] add tidelift marketing copy +- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `object-inspect`, `has-symbols`, `tape`, `mkdirp`, `iconv-lite` +- [actions] add automatic rebasing / merge commit blocking + +## **6.9.1** +- [Fix] `parse`: with comma true, handle field that holds an array of arrays (#335) +- [Fix] `parse`: with comma true, do not split non-string values (#334) +- [meta] add `funding` field +- [Dev Deps] update `eslint`, `@ljharb/eslint-config` +- [Tests] use shared travis-ci config + +## **6.9.0** +- [New] `parse`/`stringify`: Pass extra key/value argument to `decoder` (#333) +- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `evalmd` +- [Tests] `parse`: add passing `arrayFormat` tests +- [Tests] add `posttest` using `npx aud` to run `npm audit` without a lockfile +- [Tests] up to `node` `v12.10`, `v11.15`, `v10.16`, `v8.16` +- [Tests] `Buffer.from` in node v5.0-v5.9 and v4.0-v4.4 requires a TypedArray + +## **6.8.2** +- [Fix] proper comma parsing of URL-encoded commas (#361) +- [Fix] parses comma delimited array while having percent-encoded comma treated as normal text (#336) + +## **6.8.1** +- [Fix] `parse`: Fix parsing array from object with `comma` true (#359) +- [Fix] `parse`: throw a TypeError instead of an Error for bad charset (#349) +- [Fix] `parse`: with comma true, handle field that holds an array of arrays (#335) +- [fix] `parse`: with comma true, do not split non-string values (#334) +- [meta] add tidelift marketing copy +- [meta] add `funding` field +- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `tape`, `safe-publish-latest`, `evalmd`, `has-symbols`, `iconv-lite`, `mkdirp`, `object-inspect` +- [Tests] `parse`: add passing `arrayFormat` tests +- [Tests] use shared travis-ci configs +- [Tests] `Buffer.from` in node v5.0-v5.9 and v4.0-v4.4 requires a TypedArray +- [actions] add automatic rebasing / merge commit blocking + +## **6.8.0** +- [New] add `depth=false` to preserve the original key; [Fix] `depth=0` should preserve the original key (#326) +- [New] [Fix] stringify symbols and bigints +- [Fix] ensure node 0.12 can stringify Symbols +- [Fix] fix for an impossible situation: when the formatter is called with a non-string value +- [Refactor] `formats`: tiny bit of cleanup. +- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `browserify`, `safe-publish-latest`, `iconv-lite`, `tape` +- [Tests] add tests for `depth=0` and `depth=false` behavior, both current and intuitive/intended (#326) +- [Tests] use `eclint` instead of `editorconfig-tools` +- [docs] readme: add security note +- [meta] add github sponsorship +- [meta] add FUNDING.yml +- [meta] Clean up license text so it’s properly detected as BSD-3-Clause + +## **6.7.2** +- [Fix] proper comma parsing of URL-encoded commas (#361) +- [Fix] parses comma delimited array while having percent-encoded comma treated as normal text (#336) + +## **6.7.1** +- [Fix] `parse`: Fix parsing array from object with `comma` true (#359) +- [Fix] `parse`: with comma true, handle field that holds an array of arrays (#335) +- [fix] `parse`: with comma true, do not split non-string values (#334) +- [Fix] `parse`: throw a TypeError instead of an Error for bad charset (#349) +- [Fix] fix for an impossible situation: when the formatter is called with a non-string value +- [Refactor] `formats`: tiny bit of cleanup. +- readme: add security note +- [meta] add tidelift marketing copy +- [meta] add `funding` field +- [meta] add FUNDING.yml +- [meta] Clean up license text so it’s properly detected as BSD-3-Clause +- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `tape`, `safe-publish-latest`, `evalmd`, `iconv-lite`, `mkdirp`, `object-inspect`, `browserify` +- [Tests] `parse`: add passing `arrayFormat` tests +- [Tests] use shared travis-ci configs +- [Tests] `Buffer.from` in node v5.0-v5.9 and v4.0-v4.4 requires a TypedArray +- [Tests] add tests for `depth=0` and `depth=false` behavior, both current and intuitive/intended +- [Tests] use `eclint` instead of `editorconfig-tools` +- [actions] add automatic rebasing / merge commit blocking + ## **6.7.0** - [New] `stringify`/`parse`: add `comma` as an `arrayFormat` option (#276, #219) - [Fix] correctly parse nested arrays (#212) diff --git a/node_modules/qs/LICENSE b/node_modules/qs/LICENSE deleted file mode 100644 index d456948..0000000 --- a/node_modules/qs/LICENSE +++ /dev/null @@ -1,28 +0,0 @@ -Copyright (c) 2014 Nathan LaFreniere and other contributors. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * The names of any contributors may not be used to endorse or promote - products derived from this software without specific prior written - permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - * * * - -The complete list of contributors can be found at: https://github.com/hapijs/qs/graphs/contributors diff --git a/node_modules/qs/LICENSE.md b/node_modules/qs/LICENSE.md new file mode 100644 index 0000000..fecf6b6 --- /dev/null +++ b/node_modules/qs/LICENSE.md @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2014, Nathan LaFreniere and other [contributors](https://github.com/ljharb/qs/graphs/contributors) +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/node_modules/qs/README.md b/node_modules/qs/README.md index 8590cfd..f64de3d 100644 --- a/node_modules/qs/README.md +++ b/node_modules/qs/README.md @@ -1,12 +1,13 @@ # qs [![Version Badge][2]][1] -[![Build Status][3]][4] -[![dependency status][5]][6] -[![dev dependency status][7]][8] +[![github actions][actions-image]][actions-url] +[![coverage][codecov-image]][codecov-url] +[![dependency status][deps-svg]][deps-url] +[![dev dependency status][dev-deps-svg]][dev-deps-url] [![License][license-image]][license-url] [![Downloads][downloads-image]][downloads-url] -[![npm badge][11]][1] +[![npm badge][npm-badge-png]][package-url] A querystring parsing and stringifying library with some added security. @@ -280,6 +281,17 @@ assert.deepEqual(arraysOfObjects, { a: ['b', 'c'] }) ``` (_this cannot convert nested objects, such as `a={b:1},{c:d}`_) +### Parsing primitive/scalar values (numbers, booleans, null, etc) + +By default, all values are parsed as strings. This behavior will not change and is explained in [issue #91](https://github.com/ljharb/qs/issues/91). + +```javascript +var primitiveValues = qs.parse('a=15&b=true&c=null'); +assert.deepEqual(primitiveValues, { a: '15', b: 'true', c: 'null' }); +``` + +If you wish to auto-convert values which look like numbers, booleans, and other values into their primitive counterparts, you can use the [query-types Express JS middleware](https://github.com/xpepermint/query-types) which will auto-convert all request query parameters. + ### Stringifying [](#preventEval) @@ -330,6 +342,30 @@ var decoded = qs.parse('x=z', { decoder: function (str) { }}) ``` +You can encode keys and values using different logic by using the type argument provided to the encoder: + +```javascript +var encoded = qs.stringify({ a: { b: 'c' } }, { encoder: function (str, defaultEncoder, charset, type) { + if (type === 'key') { + return // Encoded key + } else if (type === 'value') { + return // Encoded value + } +}}) +``` + +The type argument is also provided to the decoder: + +```javascript +var decoded = qs.parse('x=z', { decoder: function (str, defaultDecoder, charset, type) { + if (type === 'key') { + return // Decoded key + } else if (type === 'value') { + return // Decoded value + } +}}) +``` + Examples beyond this point will be shown as though the output is not URI encoded for clarity. Please note that the return values in these cases *will* be URI encoded during real usage. When arrays are stringified, by default they are given explicit indices: @@ -553,18 +589,28 @@ assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC3986' }), 'a=b%20c'); assert.equal(qs.stringify({ a: 'b c' }, { format : 'RFC1738' }), 'a=b+c'); ``` -[1]: https://npmjs.org/package/qs -[2]: http://versionbadg.es/ljharb/qs.svg -[3]: https://api.travis-ci.org/ljharb/qs.svg -[4]: https://travis-ci.org/ljharb/qs -[5]: https://david-dm.org/ljharb/qs.svg -[6]: https://david-dm.org/ljharb/qs -[7]: https://david-dm.org/ljharb/qs/dev-status.svg -[8]: https://david-dm.org/ljharb/qs?type=dev -[9]: https://ci.testling.com/ljharb/qs.png -[10]: https://ci.testling.com/ljharb/qs -[11]: https://nodei.co/npm/qs.png?downloads=true&stars=true -[license-image]: http://img.shields.io/npm/l/qs.svg +## Security + +Please email [@ljharb](https://github.com/ljharb) or see https://tidelift.com/security if you have a potential security vulnerability to report. + +## qs for enterprise + +Available as part of the Tidelift Subscription + +The maintainers of qs and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-qs?utm_source=npm-qs&utm_medium=referral&utm_campaign=enterprise&utm_term=repo) + +[package-url]: https://npmjs.org/package/qs +[npm-version-svg]: https://versionbadg.es/ljharb/qs.svg +[deps-svg]: https://david-dm.org/ljharb/qs.svg +[deps-url]: https://david-dm.org/ljharb/qs +[dev-deps-svg]: https://david-dm.org/ljharb/qs/dev-status.svg +[dev-deps-url]: https://david-dm.org/ljharb/qs#info=devDependencies +[npm-badge-png]: https://nodei.co/npm/qs.png?downloads=true&stars=true +[license-image]: https://img.shields.io/npm/l/qs.svg [license-url]: LICENSE -[downloads-image]: http://img.shields.io/npm/dm/qs.svg -[downloads-url]: http://npm-stat.com/charts.html?package=qs +[downloads-image]: https://img.shields.io/npm/dm/qs.svg +[downloads-url]: https://npm-stat.com/charts.html?package=qs +[codecov-image]: https://codecov.io/gh/ljharb/qs/branch/main/graphs/badge.svg +[codecov-url]: https://app.codecov.io/gh/ljharb/qs/ +[actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/ljharb/qs +[actions-url]: https://github.com/ljharb/qs/actions diff --git a/node_modules/qs/lib/formats.js b/node_modules/qs/lib/formats.js index df45997..f36cf20 100644 --- a/node_modules/qs/lib/formats.js +++ b/node_modules/qs/lib/formats.js @@ -3,16 +3,21 @@ var replace = String.prototype.replace; var percentTwenties = /%20/g; +var Format = { + RFC1738: 'RFC1738', + RFC3986: 'RFC3986' +}; + module.exports = { - 'default': 'RFC3986', + 'default': Format.RFC3986, formatters: { RFC1738: function (value) { return replace.call(value, percentTwenties, '+'); }, RFC3986: function (value) { - return value; + return String(value); } }, - RFC1738: 'RFC1738', - RFC3986: 'RFC3986' + RFC1738: Format.RFC1738, + RFC3986: Format.RFC3986 }; diff --git a/node_modules/qs/lib/parse.js b/node_modules/qs/lib/parse.js index d81628b..698a310 100644 --- a/node_modules/qs/lib/parse.js +++ b/node_modules/qs/lib/parse.js @@ -3,6 +3,7 @@ var utils = require('./utils'); var has = Object.prototype.hasOwnProperty; +var isArray = Array.isArray; var defaults = { allowDots: false, @@ -28,6 +29,14 @@ var interpretNumericEntities = function (str) { }); }; +var parseArrayValue = function (val, options) { + if (val && typeof val === 'string' && options.comma && val.indexOf(',') > -1) { + return val.split(','); + } + + return val; +}; + // This is what browsers will submit when the ✓ character occurs in an // application/x-www-form-urlencoded body and the encoding of the page containing // the form is iso-8859-1, or when the submitted form has an accept-charset @@ -72,19 +81,24 @@ var parseValues = function parseQueryStringValues(str, options) { var key, val; if (pos === -1) { - key = options.decoder(part, defaults.decoder, charset); + key = options.decoder(part, defaults.decoder, charset, 'key'); val = options.strictNullHandling ? null : ''; } else { - key = options.decoder(part.slice(0, pos), defaults.decoder, charset); - val = options.decoder(part.slice(pos + 1), defaults.decoder, charset); + key = options.decoder(part.slice(0, pos), defaults.decoder, charset, 'key'); + val = utils.maybeMap( + parseArrayValue(part.slice(pos + 1), options), + function (encodedVal) { + return options.decoder(encodedVal, defaults.decoder, charset, 'value'); + } + ); } if (val && options.interpretNumericEntities && charset === 'iso-8859-1') { val = interpretNumericEntities(val); } - if (val && options.comma && val.indexOf(',') > -1) { - val = val.split(','); + if (part.indexOf('[]=') > -1) { + val = isArray(val) ? [val] : val; } if (has.call(obj, key)) { @@ -97,8 +111,8 @@ var parseValues = function parseQueryStringValues(str, options) { return obj; }; -var parseObject = function (chain, val, options) { - var leaf = val; +var parseObject = function (chain, val, options, valuesParsed) { + var leaf = valuesParsed ? val : parseArrayValue(val, options); for (var i = chain.length - 1; i >= 0; --i) { var obj; @@ -121,7 +135,7 @@ var parseObject = function (chain, val, options) { ) { obj = []; obj[index] = leaf; - } else { + } else if (cleanRoot !== '__proto__') { obj[cleanRoot] = leaf; } } @@ -132,7 +146,7 @@ var parseObject = function (chain, val, options) { return leaf; }; -var parseKeys = function parseQueryStringKeys(givenKey, val, options) { +var parseKeys = function parseQueryStringKeys(givenKey, val, options, valuesParsed) { if (!givenKey) { return; } @@ -147,7 +161,7 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options) { // Get the parent - var segment = brackets.exec(key); + var segment = options.depth > 0 && brackets.exec(key); var parent = segment ? key.slice(0, segment.index) : key; // Stash the parent if it exists @@ -167,7 +181,7 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options) { // Loop through children appending to the array until we hit depth var i = 0; - while ((segment = child.exec(key)) !== null && i < options.depth) { + while (options.depth > 0 && (segment = child.exec(key)) !== null && i < options.depth) { i += 1; if (!options.plainObjects && has.call(Object.prototype, segment[1].slice(1, -1))) { if (!options.allowPrototypes) { @@ -183,7 +197,7 @@ var parseKeys = function parseQueryStringKeys(givenKey, val, options) { keys.push('[' + key.slice(segment.index) + ']'); } - return parseObject(keys, val, options); + return parseObject(keys, val, options, valuesParsed); }; var normalizeParseOptions = function normalizeParseOptions(opts) { @@ -196,7 +210,7 @@ var normalizeParseOptions = function normalizeParseOptions(opts) { } if (typeof opts.charset !== 'undefined' && opts.charset !== 'utf-8' && opts.charset !== 'iso-8859-1') { - throw new Error('The charset option must be either utf-8, iso-8859-1, or undefined'); + throw new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined'); } var charset = typeof opts.charset === 'undefined' ? defaults.charset : opts.charset; @@ -209,7 +223,8 @@ var normalizeParseOptions = function normalizeParseOptions(opts) { comma: typeof opts.comma === 'boolean' ? opts.comma : defaults.comma, decoder: typeof opts.decoder === 'function' ? opts.decoder : defaults.decoder, delimiter: typeof opts.delimiter === 'string' || utils.isRegExp(opts.delimiter) ? opts.delimiter : defaults.delimiter, - depth: typeof opts.depth === 'number' ? opts.depth : defaults.depth, + // eslint-disable-next-line no-implicit-coercion, no-extra-parens + depth: (typeof opts.depth === 'number' || opts.depth === false) ? +opts.depth : defaults.depth, ignoreQueryPrefix: opts.ignoreQueryPrefix === true, interpretNumericEntities: typeof opts.interpretNumericEntities === 'boolean' ? opts.interpretNumericEntities : defaults.interpretNumericEntities, parameterLimit: typeof opts.parameterLimit === 'number' ? opts.parameterLimit : defaults.parameterLimit, @@ -234,7 +249,7 @@ module.exports = function (str, opts) { var keys = Object.keys(tempObj); for (var i = 0; i < keys.length; ++i) { var key = keys[i]; - var newObj = parseKeys(key, tempObj[key], options); + var newObj = parseKeys(key, tempObj[key], options, typeof str === 'string'); obj = utils.merge(obj, newObj, options); } diff --git a/node_modules/qs/lib/stringify.js b/node_modules/qs/lib/stringify.js index 7455049..bdc19c6 100644 --- a/node_modules/qs/lib/stringify.js +++ b/node_modules/qs/lib/stringify.js @@ -5,19 +5,20 @@ var formats = require('./formats'); var has = Object.prototype.hasOwnProperty; var arrayPrefixGenerators = { - brackets: function brackets(prefix) { // eslint-disable-line func-name-matching + brackets: function brackets(prefix) { return prefix + '[]'; }, comma: 'comma', - indices: function indices(prefix, key) { // eslint-disable-line func-name-matching + indices: function indices(prefix, key) { return prefix + '[' + key + ']'; }, - repeat: function repeat(prefix) { // eslint-disable-line func-name-matching + repeat: function repeat(prefix) { return prefix; } }; var isArray = Array.isArray; +var split = String.prototype.split; var push = Array.prototype.push; var pushToArray = function (arr, valueOrArray) { push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]); @@ -25,6 +26,7 @@ var pushToArray = function (arr, valueOrArray) { var toISO = Date.prototype.toISOString; +var defaultFormat = formats['default']; var defaults = { addQueryPrefix: false, allowDots: false, @@ -34,17 +36,26 @@ var defaults = { encode: true, encoder: utils.encode, encodeValuesOnly: false, - formatter: formats.formatters[formats['default']], + format: defaultFormat, + formatter: formats.formatters[defaultFormat], // deprecated indices: false, - serializeDate: function serializeDate(date) { // eslint-disable-line func-name-matching + serializeDate: function serializeDate(date) { return toISO.call(date); }, skipNulls: false, strictNullHandling: false }; -var stringify = function stringify( // eslint-disable-line func-name-matching +var isNonNullishPrimitive = function isNonNullishPrimitive(v) { + return typeof v === 'string' + || typeof v === 'number' + || typeof v === 'boolean' + || typeof v === 'symbol' + || typeof v === 'bigint'; +}; + +var stringify = function stringify( object, prefix, generateArrayPrefix, @@ -55,6 +66,7 @@ var stringify = function stringify( // eslint-disable-line func-name-matching sort, allowDots, serializeDate, + format, formatter, encodeValuesOnly, charset @@ -65,21 +77,34 @@ var stringify = function stringify( // eslint-disable-line func-name-matching } else if (obj instanceof Date) { obj = serializeDate(obj); } else if (generateArrayPrefix === 'comma' && isArray(obj)) { - obj = obj.join(','); + obj = utils.maybeMap(obj, function (value) { + if (value instanceof Date) { + return serializeDate(value); + } + return value; + }); } if (obj === null) { if (strictNullHandling) { - return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder, charset) : prefix; + return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder, charset, 'key', format) : prefix; } obj = ''; } - if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean' || utils.isBuffer(obj)) { + if (isNonNullishPrimitive(obj) || utils.isBuffer(obj)) { if (encoder) { - var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset); - return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset))]; + var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset, 'key', format); + if (generateArrayPrefix === 'comma' && encodeValuesOnly) { + var valuesArray = split.call(String(obj), ','); + var valuesJoined = ''; + for (var i = 0; i < valuesArray.length; ++i) { + valuesJoined += (i === 0 ? '' : ',') + formatter(encoder(valuesArray[i], defaults.encoder, charset, 'value', format)); + } + return [formatter(keyValue) + '=' + valuesJoined]; + } + return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset, 'value', format))]; } return [formatter(prefix) + '=' + formatter(String(obj))]; } @@ -91,53 +116,44 @@ var stringify = function stringify( // eslint-disable-line func-name-matching } var objKeys; - if (isArray(filter)) { + if (generateArrayPrefix === 'comma' && isArray(obj)) { + // we need to join elements in + objKeys = [{ value: obj.length > 0 ? obj.join(',') || null : void undefined }]; + } else if (isArray(filter)) { objKeys = filter; } else { var keys = Object.keys(obj); objKeys = sort ? keys.sort(sort) : keys; } - for (var i = 0; i < objKeys.length; ++i) { - var key = objKeys[i]; + for (var j = 0; j < objKeys.length; ++j) { + var key = objKeys[j]; + var value = typeof key === 'object' && typeof key.value !== 'undefined' ? key.value : obj[key]; - if (skipNulls && obj[key] === null) { + if (skipNulls && value === null) { continue; } - if (isArray(obj)) { - pushToArray(values, stringify( - obj[key], - typeof generateArrayPrefix === 'function' ? generateArrayPrefix(prefix, key) : prefix, - generateArrayPrefix, - strictNullHandling, - skipNulls, - encoder, - filter, - sort, - allowDots, - serializeDate, - formatter, - encodeValuesOnly, - charset - )); - } else { - pushToArray(values, stringify( - obj[key], - prefix + (allowDots ? '.' + key : '[' + key + ']'), - generateArrayPrefix, - strictNullHandling, - skipNulls, - encoder, - filter, - sort, - allowDots, - serializeDate, - formatter, - encodeValuesOnly, - charset - )); - } + var keyPrefix = isArray(obj) + ? typeof generateArrayPrefix === 'function' ? generateArrayPrefix(prefix, key) : prefix + : prefix + (allowDots ? '.' + key : '[' + key + ']'); + + pushToArray(values, stringify( + value, + keyPrefix, + generateArrayPrefix, + strictNullHandling, + skipNulls, + encoder, + filter, + sort, + allowDots, + serializeDate, + format, + formatter, + encodeValuesOnly, + charset + )); } return values; @@ -148,7 +164,7 @@ var normalizeStringifyOptions = function normalizeStringifyOptions(opts) { return defaults; } - if (opts.encoder !== null && opts.encoder !== undefined && typeof opts.encoder !== 'function') { + if (opts.encoder !== null && typeof opts.encoder !== 'undefined' && typeof opts.encoder !== 'function') { throw new TypeError('Encoder has to be a function.'); } @@ -181,6 +197,7 @@ var normalizeStringifyOptions = function normalizeStringifyOptions(opts) { encoder: typeof opts.encoder === 'function' ? opts.encoder : defaults.encoder, encodeValuesOnly: typeof opts.encodeValuesOnly === 'boolean' ? opts.encodeValuesOnly : defaults.encodeValuesOnly, filter: filter, + format: format, formatter: formatter, serializeDate: typeof opts.serializeDate === 'function' ? opts.serializeDate : defaults.serializeDate, skipNulls: typeof opts.skipNulls === 'boolean' ? opts.skipNulls : defaults.skipNulls, @@ -246,6 +263,7 @@ module.exports = function (object, opts) { options.sort, options.allowDots, options.serializeDate, + options.format, options.formatter, options.encodeValuesOnly, options.charset diff --git a/node_modules/qs/lib/utils.js b/node_modules/qs/lib/utils.js index 1b219cd..1e54538 100644 --- a/node_modules/qs/lib/utils.js +++ b/node_modules/qs/lib/utils.js @@ -1,5 +1,7 @@ 'use strict'; +var formats = require('./formats'); + var has = Object.prototype.hasOwnProperty; var isArray = Array.isArray; @@ -43,6 +45,7 @@ var arrayToObject = function arrayToObject(source, options) { }; var merge = function merge(target, source, options) { + /* eslint no-param-reassign: 0 */ if (!source) { return target; } @@ -119,14 +122,19 @@ var decode = function (str, decoder, charset) { } }; -var encode = function encode(str, defaultEncoder, charset) { +var encode = function encode(str, defaultEncoder, charset, kind, format) { // This code was originally written by Brian White (mscdex) for the io.js core querystring library. // It has been adapted here for stricter adherence to RFC 3986 if (str.length === 0) { return str; } - var string = typeof str === 'string' ? str : String(str); + var string = str; + if (typeof str === 'symbol') { + string = Symbol.prototype.toString.call(str); + } else if (typeof str !== 'string') { + string = String(str); + } if (charset === 'iso-8859-1') { return escape(string).replace(/%u[0-9a-f]{4}/gi, function ($0) { @@ -146,6 +154,7 @@ var encode = function encode(str, defaultEncoder, charset) { || (c >= 0x30 && c <= 0x39) // 0-9 || (c >= 0x41 && c <= 0x5A) // a-z || (c >= 0x61 && c <= 0x7A) // A-Z + || (format === formats.RFC1738 && (c === 0x28 || c === 0x29)) // ( ) ) { out += string.charAt(i); continue; @@ -168,6 +177,7 @@ var encode = function encode(str, defaultEncoder, charset) { i += 1; c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF)); + /* eslint operator-linebreak: [2, "before"] */ out += hexTable[0xF0 | (c >> 18)] + hexTable[0x80 | ((c >> 12) & 0x3F)] + hexTable[0x80 | ((c >> 6) & 0x3F)] @@ -217,6 +227,17 @@ var combine = function combine(a, b) { return [].concat(a, b); }; +var maybeMap = function maybeMap(val, fn) { + if (isArray(val)) { + var mapped = []; + for (var i = 0; i < val.length; i += 1) { + mapped.push(fn(val[i])); + } + return mapped; + } + return fn(val); +}; + module.exports = { arrayToObject: arrayToObject, assign: assign, @@ -226,5 +247,6 @@ module.exports = { encode: encode, isBuffer: isBuffer, isRegExp: isRegExp, + maybeMap: maybeMap, merge: merge }; diff --git a/node_modules/qs/package.json b/node_modules/qs/package.json index 28d98a1..3ec7c11 100644 --- a/node_modules/qs/package.json +++ b/node_modules/qs/package.json @@ -2,11 +2,14 @@ "name": "qs", "description": "A querystring parser that supports nesting and arrays, with a depth limit", "homepage": "https://github.com/ljharb/qs", - "version": "6.7.0", + "version": "6.9.7", "repository": { "type": "git", "url": "https://github.com/ljharb/qs.git" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + }, "main": "lib/index.js", "contributors": [ { @@ -26,33 +29,42 @@ "engines": { "node": ">=0.6" }, - "dependencies": {}, "devDependencies": { - "@ljharb/eslint-config": "^13.1.1", - "browserify": "^16.2.3", - "covert": "^1.1.1", - "editorconfig-tools": "^0.1.1", - "eslint": "^5.15.3", - "evalmd": "^0.0.17", + "@ljharb/eslint-config": "^20.1.0", + "aud": "^1.1.5", + "browserify": "^16.5.2", + "eclint": "^2.8.1", + "eslint": "^8.6.0", + "evalmd": "^0.0.19", "for-each": "^0.3.3", - "iconv-lite": "^0.4.24", - "mkdirp": "^0.5.1", - "object-inspect": "^1.6.0", + "has-symbols": "^1.0.2", + "iconv-lite": "^0.5.1", + "in-publish": "^2.0.1", + "mkdirp": "^0.5.5", + "nyc": "^10.3.2", + "object-inspect": "^1.12.0", "qs-iconv": "^1.0.4", - "safe-publish-latest": "^1.1.2", + "safe-publish-latest": "^2.0.0", "safer-buffer": "^2.1.2", - "tape": "^4.10.1" + "tape": "^5.4.0" }, "scripts": { - "prepublish": "safe-publish-latest && npm run dist", + "prepublishOnly": "safe-publish-latest && npm run dist", + "prepublish": "not-in-publish || npm run prepublishOnly", "pretest": "npm run --silent readme && npm run --silent lint", - "test": "npm run --silent coverage", - "tests-only": "node test", + "test": "npm run tests-only", + "tests-only": "nyc tape 'test/**/*.js'", + "posttest": "aud --production", "readme": "evalmd README.md", - "postlint": "editorconfig-tools check * lib/* test/*", - "lint": "eslint lib/*.js test/*.js", - "coverage": "covert test", + "postlint": "eclint check * lib/* test/* !dist/*", + "lint": "eslint .", "dist": "mkdirp dist && browserify --standalone Qs lib/index.js > dist/qs.js" }, - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "greenkeeper": { + "ignore": [ + "iconv-lite", + "mkdirp" + ] + } } diff --git a/node_modules/qs/test/.eslintrc b/node_modules/qs/test/.eslintrc deleted file mode 100644 index 9ebbb92..0000000 --- a/node_modules/qs/test/.eslintrc +++ /dev/null @@ -1,17 +0,0 @@ -{ - "rules": { - "array-bracket-newline": 0, - "array-element-newline": 0, - "consistent-return": 2, - "function-paren-newline": 0, - "max-lines": 0, - "max-lines-per-function": 0, - "max-nested-callbacks": [2, 3], - "max-statements": 0, - "no-buffer-constructor": 0, - "no-extend-native": 0, - "no-magic-numbers": 0, - "object-curly-newline": 0, - "sort-keys": 0 - } -} diff --git a/node_modules/qs/test/index.js b/node_modules/qs/test/index.js deleted file mode 100644 index 5e6bc8f..0000000 --- a/node_modules/qs/test/index.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -require('./parse'); - -require('./stringify'); - -require('./utils'); diff --git a/node_modules/qs/test/parse.js b/node_modules/qs/test/parse.js index 8967789..7721aaa 100644 --- a/node_modules/qs/test/parse.js +++ b/node_modules/qs/test/parse.js @@ -32,6 +32,38 @@ test('parse()', function (t) { st.end(); }); + t.test('arrayFormat: brackets allows only explicit arrays', function (st) { + st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'brackets' }), { a: ['b', 'c'] }); + st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'brackets' }), { a: ['b', 'c'] }); + st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'brackets' }), { a: 'b,c' }); + st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'brackets' }), { a: ['b', 'c'] }); + st.end(); + }); + + t.test('arrayFormat: indices allows only indexed arrays', function (st) { + st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'indices' }), { a: ['b', 'c'] }); + st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'indices' }), { a: ['b', 'c'] }); + st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'indices' }), { a: 'b,c' }); + st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'indices' }), { a: ['b', 'c'] }); + st.end(); + }); + + t.test('arrayFormat: comma allows only comma-separated arrays', function (st) { + st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'comma' }), { a: ['b', 'c'] }); + st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'comma' }), { a: ['b', 'c'] }); + st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'comma' }), { a: 'b,c' }); + st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'comma' }), { a: ['b', 'c'] }); + st.end(); + }); + + t.test('arrayFormat: repeat allows only repeated values', function (st) { + st.deepEqual(qs.parse('a[]=b&a[]=c', { arrayFormat: 'repeat' }), { a: ['b', 'c'] }); + st.deepEqual(qs.parse('a[0]=b&a[1]=c', { arrayFormat: 'repeat' }), { a: ['b', 'c'] }); + st.deepEqual(qs.parse('a=b,c', { arrayFormat: 'repeat' }), { a: 'b,c' }); + st.deepEqual(qs.parse('a=b&a=c', { arrayFormat: 'repeat' }), { a: ['b', 'c'] }); + st.end(); + }); + t.test('allows enabling dot notation', function (st) { st.deepEqual(qs.parse('a.b=c'), { 'a.b': 'c' }); st.deepEqual(qs.parse('a.b=c', { allowDots: true }), { a: { b: 'c' } }); @@ -52,6 +84,18 @@ test('parse()', function (t) { st.end(); }); + t.test('uses original key when depth = 0', function (st) { + st.deepEqual(qs.parse('a[0]=b&a[1]=c', { depth: 0 }), { 'a[0]': 'b', 'a[1]': 'c' }); + st.deepEqual(qs.parse('a[0][0]=b&a[0][1]=c&a[1]=d&e=2', { depth: 0 }), { 'a[0][0]': 'b', 'a[0][1]': 'c', 'a[1]': 'd', e: '2' }); + st.end(); + }); + + t.test('uses original key when depth = false', function (st) { + st.deepEqual(qs.parse('a[0]=b&a[1]=c', { depth: false }), { 'a[0]': 'b', 'a[1]': 'c' }); + st.deepEqual(qs.parse('a[0][0]=b&a[0][1]=c&a[1]=d&e=2', { depth: false }), { 'a[0][0]': 'b', 'a[0][1]': 'c', 'a[1]': 'd', e: '2' }); + st.end(); + }); + t.deepEqual(qs.parse('a=b&a=c'), { a: ['b', 'c'] }, 'parses a simple array'); t.test('parses an explicit array', function (st) { @@ -356,6 +400,43 @@ test('parse()', function (t) { st.end(); }); + t.test('parses values with comma as array divider', function (st) { + st.deepEqual(qs.parse({ foo: 'bar,tee' }, { comma: false }), { foo: 'bar,tee' }); + st.deepEqual(qs.parse({ foo: 'bar,tee' }, { comma: true }), { foo: ['bar', 'tee'] }); + st.end(); + }); + + t.test('use number decoder, parses string that has one number with comma option enabled', function (st) { + var decoder = function (str, defaultDecoder, charset, type) { + if (!isNaN(Number(str))) { + return parseFloat(str); + } + return defaultDecoder(str, defaultDecoder, charset, type); + }; + + st.deepEqual(qs.parse('foo=1', { comma: true, decoder: decoder }), { foo: 1 }); + st.deepEqual(qs.parse('foo=0', { comma: true, decoder: decoder }), { foo: 0 }); + + st.end(); + }); + + t.test('parses brackets holds array of arrays when having two parts of strings with comma as array divider', function (st) { + st.deepEqual(qs.parse('foo[]=1,2,3&foo[]=4,5,6', { comma: true }), { foo: [['1', '2', '3'], ['4', '5', '6']] }); + st.deepEqual(qs.parse('foo[]=1,2,3&foo[]=', { comma: true }), { foo: [['1', '2', '3'], ''] }); + st.deepEqual(qs.parse('foo[]=1,2,3&foo[]=,', { comma: true }), { foo: [['1', '2', '3'], ['', '']] }); + st.deepEqual(qs.parse('foo[]=1,2,3&foo[]=a', { comma: true }), { foo: [['1', '2', '3'], 'a'] }); + + st.end(); + }); + + t.test('parses comma delimited array while having percent-encoded comma treated as normal text', function (st) { + st.deepEqual(qs.parse('foo=a%2Cb', { comma: true }), { foo: 'a,b' }); + st.deepEqual(qs.parse('foo=a%2C%20b,d', { comma: true }), { foo: ['a, b', 'd'] }); + st.deepEqual(qs.parse('foo=a%2C%20b,c%2C%20d', { comma: true }), { foo: ['a, b', 'c, d'] }); + + st.end(); + }); + t.test('parses an object in dot notation', function (st) { var input = { 'user.name': { 'pop[bob]': 3 }, @@ -532,13 +613,73 @@ test('parse()', function (t) { st.deepEqual( qs.parse('a[b]=c&a=toString', { plainObjects: true }), - { a: { b: 'c', toString: true } }, + { __proto__: null, a: { __proto__: null, b: 'c', toString: true } }, 'can overwrite prototype with plainObjects true' ); st.end(); }); + t.test('dunder proto is ignored', function (st) { + var payload = 'categories[__proto__]=login&categories[__proto__]&categories[length]=42'; + var result = qs.parse(payload, { allowPrototypes: true }); + + st.deepEqual( + result, + { + categories: { + length: '42' + } + }, + 'silent [[Prototype]] payload' + ); + + var plainResult = qs.parse(payload, { allowPrototypes: true, plainObjects: true }); + + st.deepEqual( + plainResult, + { + __proto__: null, + categories: { + __proto__: null, + length: '42' + } + }, + 'silent [[Prototype]] payload: plain objects' + ); + + var query = qs.parse('categories[__proto__]=cats&categories[__proto__]=dogs&categories[some][json]=toInject', { allowPrototypes: true }); + + st.notOk(Array.isArray(query.categories), 'is not an array'); + st.notOk(query.categories instanceof Array, 'is not instanceof an array'); + st.deepEqual(query.categories, { some: { json: 'toInject' } }); + st.equal(JSON.stringify(query.categories), '{"some":{"json":"toInject"}}', 'stringifies as a non-array'); + + st.deepEqual( + qs.parse('foo[__proto__][hidden]=value&foo[bar]=stuffs', { allowPrototypes: true }), + { + foo: { + bar: 'stuffs' + } + }, + 'hidden values' + ); + + st.deepEqual( + qs.parse('foo[__proto__][hidden]=value&foo[bar]=stuffs', { allowPrototypes: true, plainObjects: true }), + { + __proto__: null, + foo: { + __proto__: null, + bar: 'stuffs' + } + }, + 'hidden values: plain objects' + ); + + st.end(); + }); + t.test('can return null objects', { skip: !Object.create }, function (st) { var expected = Object.create(null); expected.a = Object.create(null); @@ -672,5 +813,20 @@ test('parse()', function (t) { st.end(); }); + t.test('allows for decoding keys and values differently', function (st) { + var decoder = function (str, defaultDecoder, charset, type) { + if (type === 'key') { + return defaultDecoder(str, defaultDecoder, charset, type).toLowerCase(); + } + if (type === 'value') { + return defaultDecoder(str, defaultDecoder, charset, type).toUpperCase(); + } + throw 'this should never happen! type: ' + type; + }; + + st.deepEqual(qs.parse('KeY=vAlUe', { decoder: decoder }), { key: 'VALUE' }); + st.end(); + }); + t.end(); }); diff --git a/node_modules/qs/test/stringify.js b/node_modules/qs/test/stringify.js index 53041c2..f761fb3 100644 --- a/node_modules/qs/test/stringify.js +++ b/node_modules/qs/test/stringify.js @@ -5,6 +5,8 @@ var qs = require('../'); var utils = require('../lib/utils'); var iconv = require('iconv-lite'); var SaferBuffer = require('safer-buffer').Buffer; +var hasSymbols = require('has-symbols'); +var hasBigInt = typeof BigInt === 'function'; test('stringify()', function (t) { t.test('stringifies a querystring object', function (st) { @@ -28,6 +30,39 @@ test('stringify()', function (t) { st.end(); }); + t.test('stringifies symbols', { skip: !hasSymbols() }, function (st) { + st.equal(qs.stringify(Symbol.iterator), ''); + st.equal(qs.stringify([Symbol.iterator]), '0=Symbol%28Symbol.iterator%29'); + st.equal(qs.stringify({ a: Symbol.iterator }), 'a=Symbol%28Symbol.iterator%29'); + st.equal( + qs.stringify({ a: [Symbol.iterator] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), + 'a[]=Symbol%28Symbol.iterator%29' + ); + st.end(); + }); + + t.test('stringifies bigints', { skip: !hasBigInt }, function (st) { + var three = BigInt(3); + var encodeWithN = function (value, defaultEncoder, charset) { + var result = defaultEncoder(value, defaultEncoder, charset); + return typeof value === 'bigint' ? result + 'n' : result; + }; + st.equal(qs.stringify(three), ''); + st.equal(qs.stringify([three]), '0=3'); + st.equal(qs.stringify([three], { encoder: encodeWithN }), '0=3n'); + st.equal(qs.stringify({ a: three }), 'a=3'); + st.equal(qs.stringify({ a: three }, { encoder: encodeWithN }), 'a=3n'); + st.equal( + qs.stringify({ a: [three] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), + 'a[]=3' + ); + st.equal( + qs.stringify({ a: [three] }, { encodeValuesOnly: true, encoder: encodeWithN, arrayFormat: 'brackets' }), + 'a[]=3n' + ); + st.end(); + }); + t.test('adds query prefix', function (st) { st.equal(qs.stringify({ a: 'b' }, { addQueryPrefix: true }), '?a=b'); st.end(); @@ -97,10 +132,10 @@ test('stringify()', function (t) { }); t.test('stringifies a nested array value', function (st) { - st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { arrayFormat: 'indices' }), 'a%5Bb%5D%5B0%5D=c&a%5Bb%5D%5B1%5D=d'); - st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { arrayFormat: 'brackets' }), 'a%5Bb%5D%5B%5D=c&a%5Bb%5D%5B%5D=d'); - st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { arrayFormat: 'comma' }), 'a%5Bb%5D=c%2Cd'); // a[b]=c,d - st.equal(qs.stringify({ a: { b: ['c', 'd'] } }), 'a%5Bb%5D%5B0%5D=c&a%5Bb%5D%5B1%5D=d'); + st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[b][0]=c&a[b][1]=d'); + st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[b][]=c&a[b][]=d'); + st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true, arrayFormat: 'comma' }), 'a[b]=c,d'); + st.equal(qs.stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true }), 'a[b][0]=c&a[b][1]=d'); st.end(); }); @@ -108,7 +143,7 @@ test('stringify()', function (t) { st.equal( qs.stringify( { a: { b: ['c', 'd'] } }, - { allowDots: true, encode: false, arrayFormat: 'indices' } + { allowDots: true, encodeValuesOnly: true, arrayFormat: 'indices' } ), 'a.b[0]=c&a.b[1]=d', 'indices: stringifies with dots + indices' @@ -116,7 +151,7 @@ test('stringify()', function (t) { st.equal( qs.stringify( { a: { b: ['c', 'd'] } }, - { allowDots: true, encode: false, arrayFormat: 'brackets' } + { allowDots: true, encodeValuesOnly: true, arrayFormat: 'brackets' } ), 'a.b[]=c&a.b[]=d', 'brackets: stringifies with dots + brackets' @@ -124,7 +159,7 @@ test('stringify()', function (t) { st.equal( qs.stringify( { a: { b: ['c', 'd'] } }, - { allowDots: true, encode: false, arrayFormat: 'comma' } + { allowDots: true, encodeValuesOnly: true, arrayFormat: 'comma' } ), 'a.b=c,d', 'comma: stringifies with dots + comma' @@ -132,7 +167,7 @@ test('stringify()', function (t) { st.equal( qs.stringify( { a: { b: ['c', 'd'] } }, - { allowDots: true, encode: false } + { allowDots: true, encodeValuesOnly: true } ), 'a.b[0]=c&a.b[1]=d', 'default: stringifies with dots + indices' @@ -180,17 +215,23 @@ test('stringify()', function (t) { t.test('stringifies an array with mixed objects and primitives', function (st) { st.equal( - qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encode: false, arrayFormat: 'indices' }), + qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[0][b]=1&a[1]=2&a[2]=3', 'indices => indices' ); st.equal( - qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encode: false, arrayFormat: 'brackets' }), + qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[][b]=1&a[]=2&a[]=3', 'brackets => brackets' ); st.equal( - qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encode: false }), + qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'comma' }), + '???', + 'brackets => brackets', + { skip: 'TODO: figure out what this should do' } + ); + st.equal( + qs.stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true }), 'a[0][b]=1&a[1]=2&a[2]=3', 'default => indices' ); @@ -301,6 +342,27 @@ test('stringify()', function (t) { st.end(); }); + t.test('stringifies an empty array in different arrayFormat', function (st) { + st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false }), 'b[0]=&c=c'); + // arrayFormat default + st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'indices' }), 'b[0]=&c=c'); + st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'brackets' }), 'b[]=&c=c'); + st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'repeat' }), 'b=&c=c'); + st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma' }), 'b=&c=c'); + // with strictNullHandling + st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'indices', strictNullHandling: true }), 'b[0]&c=c'); + st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'brackets', strictNullHandling: true }), 'b[]&c=c'); + st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'repeat', strictNullHandling: true }), 'b&c=c'); + st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma', strictNullHandling: true }), 'b&c=c'); + // with skipNulls + st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'indices', skipNulls: true }), 'c=c'); + st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'brackets', skipNulls: true }), 'c=c'); + st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'repeat', skipNulls: true }), 'c=c'); + st.equal(qs.stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma', skipNulls: true }), 'c=c'); + + st.end(); + }); + t.test('stringifies a null object', { skip: !Object.create }, function (st) { var obj = Object.create(null); obj.a = 'b'; @@ -520,6 +582,12 @@ test('stringify()', function (t) { return String.fromCharCode(buffer.readUInt8(0) + 97); } }), 'a=b'); + + st.equal(qs.stringify({ a: SaferBuffer.from('a b') }, { + encoder: function (buffer) { + return buffer; + } + }), 'a=a b'); st.end(); }); @@ -554,23 +622,43 @@ test('stringify()', function (t) { 'custom serializeDate function called' ); + st.equal( + qs.stringify( + { a: [date] }, + { + serializeDate: function (d) { return d.getTime(); }, + arrayFormat: 'comma' + } + ), + 'a=' + date.getTime(), + 'works with arrayFormat comma' + ); + st.end(); }); - t.test('RFC 1738 spaces serialization', function (st) { + t.test('RFC 1738 serialization', function (st) { st.equal(qs.stringify({ a: 'b c' }, { format: qs.formats.RFC1738 }), 'a=b+c'); st.equal(qs.stringify({ 'a b': 'c d' }, { format: qs.formats.RFC1738 }), 'a+b=c+d'); + st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }, { format: qs.formats.RFC1738 }), 'a+b=a+b'); + + st.equal(qs.stringify({ 'foo(ref)': 'bar' }, { format: qs.formats.RFC1738 }), 'foo(ref)=bar'); + st.end(); }); t.test('RFC 3986 spaces serialization', function (st) { st.equal(qs.stringify({ a: 'b c' }, { format: qs.formats.RFC3986 }), 'a=b%20c'); st.equal(qs.stringify({ 'a b': 'c d' }, { format: qs.formats.RFC3986 }), 'a%20b=c%20d'); + st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }, { format: qs.formats.RFC3986 }), 'a%20b=a%20b'); + st.end(); }); t.test('Backward compatibility to RFC 3986', function (st) { st.equal(qs.stringify({ a: 'b c' }), 'a=b%20c'); + st.equal(qs.stringify({ 'a b': SaferBuffer.from('a b') }), 'a%20b=a%20b'); + st.end(); }); @@ -675,5 +763,42 @@ test('stringify()', function (t) { st.end(); }); + t.test('allows for encoding keys and values differently', function (st) { + var encoder = function (str, defaultEncoder, charset, type) { + if (type === 'key') { + return defaultEncoder(str, defaultEncoder, charset, type).toLowerCase(); + } + if (type === 'value') { + return defaultEncoder(str, defaultEncoder, charset, type).toUpperCase(); + } + throw 'this should never happen! type: ' + type; + }; + + st.deepEqual(qs.stringify({ KeY: 'vAlUe' }, { encoder: encoder }), 'key=VALUE'); + st.end(); + }); + + t.test('objects inside arrays', function (st) { + var obj = { a: { b: { c: 'd', e: 'f' } } }; + var withArray = { a: { b: [{ c: 'd', e: 'f' }] } }; + + st.equal(qs.stringify(obj, { encode: false }), 'a[b][c]=d&a[b][e]=f', 'no array, no arrayFormat'); + st.equal(qs.stringify(obj, { encode: false, arrayFormat: 'bracket' }), 'a[b][c]=d&a[b][e]=f', 'no array, bracket'); + st.equal(qs.stringify(obj, { encode: false, arrayFormat: 'indices' }), 'a[b][c]=d&a[b][e]=f', 'no array, indices'); + st.equal(qs.stringify(obj, { encode: false, arrayFormat: 'comma' }), 'a[b][c]=d&a[b][e]=f', 'no array, comma'); + + st.equal(qs.stringify(withArray, { encode: false }), 'a[b][0][c]=d&a[b][0][e]=f', 'array, no arrayFormat'); + st.equal(qs.stringify(withArray, { encode: false, arrayFormat: 'bracket' }), 'a[b][0][c]=d&a[b][0][e]=f', 'array, bracket'); + st.equal(qs.stringify(withArray, { encode: false, arrayFormat: 'indices' }), 'a[b][0][c]=d&a[b][0][e]=f', 'array, indices'); + st.equal( + qs.stringify(withArray, { encode: false, arrayFormat: 'comma' }), + '???', + 'array, comma', + { skip: 'TODO: figure out what this should do' } + ); + + st.end(); + }); + t.end(); }); diff --git a/node_modules/qs/test/utils.js b/node_modules/qs/test/utils.js index da31ce5..aa84dfd 100644 --- a/node_modules/qs/test/utils.js +++ b/node_modules/qs/test/utils.js @@ -130,7 +130,7 @@ test('isBuffer()', function (t) { var saferBuffer = SaferBuffer.from('abc'); t.equal(utils.isBuffer(saferBuffer), true, 'SaferBuffer instance is a buffer'); - var buffer = Buffer.from ? Buffer.from('abc') : new Buffer('abc'); + var buffer = Buffer.from && Buffer.alloc ? Buffer.from('abc') : new Buffer('abc'); t.equal(utils.isBuffer(buffer), true, 'real Buffer instance is a buffer'); t.end(); }); diff --git a/node_modules/raw-body/HISTORY.md b/node_modules/raw-body/HISTORY.md index 88c79fc..2659c4d 100644 --- a/node_modules/raw-body/HISTORY.md +++ b/node_modules/raw-body/HISTORY.md @@ -1,3 +1,22 @@ +2.4.3 / 2022-02-14 +================== + + * deps: bytes@3.1.2 + +2.4.2 / 2021-11-16 +================== + + * deps: bytes@3.1.1 + * deps: http-errors@1.8.1 + - deps: setprototypeof@1.2.0 + - deps: toidentifier@1.0.1 + +2.4.1 / 2019-06-25 +================== + + * deps: http-errors@1.7.3 + - deps: inherits@2.0.4 + 2.4.0 / 2019-04-17 ================== diff --git a/node_modules/raw-body/README.md b/node_modules/raw-body/README.md index 2ce79d2..c0d0e6f 100644 --- a/node_modules/raw-body/README.md +++ b/node_modules/raw-body/README.md @@ -3,7 +3,7 @@ [![NPM Version][npm-image]][npm-url] [![NPM Downloads][downloads-image]][downloads-url] [![Node.js Version][node-version-image]][node-version-url] -[![Build status][travis-image]][travis-url] +[![Build status][github-actions-ci-image]][github-actions-ci-url] [![Test coverage][coveralls-image]][coveralls-url] Gets the entire buffer of a stream either as a `Buffer` or a string. @@ -33,8 +33,6 @@ $ npm install @types/node ## API - - ```js var getRawBody = require('raw-body') ``` @@ -63,8 +61,10 @@ You can also pass a string in place of options to just specify the encoding. If an error occurs, the stream will be paused, everything unpiped, and you are responsible for correctly disposing the stream. -For HTTP requests, no handling is required if you send a response. -For streams that use file descriptors, you should `stream.destroy()` or `stream.close()` to prevent leaks. +For HTTP requests, you may need to finish consuming the stream if +you want to keep the socket open for future requests. For streams +that use file descriptors, you should `stream.destroy()` or +`stream.close()` to prevent leaks. ## Errors @@ -81,7 +81,7 @@ otherwise an error created by this module, which has the following attributes: ### Types -The errors from this module have a `type` property which allows for the progamatic +The errors from this module have a `type` property which allows for the programmatic determination of the type of error returned. #### encoding.unsupported @@ -211,9 +211,9 @@ server.listen(3000); [npm-url]: https://npmjs.org/package/raw-body [node-version-image]: https://img.shields.io/node/v/raw-body.svg [node-version-url]: https://nodejs.org/en/download/ -[travis-image]: https://img.shields.io/travis/stream-utils/raw-body/master.svg -[travis-url]: https://travis-ci.org/stream-utils/raw-body [coveralls-image]: https://img.shields.io/coveralls/stream-utils/raw-body/master.svg [coveralls-url]: https://coveralls.io/r/stream-utils/raw-body?branch=master [downloads-image]: https://img.shields.io/npm/dm/raw-body.svg [downloads-url]: https://npmjs.org/package/raw-body +[github-actions-ci-image]: https://img.shields.io/github/workflow/status/stream-utils/raw-body/ci/master?label=ci +[github-actions-ci-url]: https://github.com/jshttp/stream-utils/raw-body?query=workflow%3Aci diff --git a/node_modules/raw-body/package.json b/node_modules/raw-body/package.json index 7f1e5af..88ebcc9 100644 --- a/node_modules/raw-body/package.json +++ b/node_modules/raw-body/package.json @@ -1,7 +1,7 @@ { "name": "raw-body", "description": "Get and validate the raw body of a readable stream.", - "version": "2.4.0", + "version": "2.4.3", "author": "Jonathan Ong (http://jongleberry.com)", "contributors": [ "Douglas Christopher Wilson ", @@ -10,24 +10,24 @@ "license": "MIT", "repository": "stream-utils/raw-body", "dependencies": { - "bytes": "3.1.0", - "http-errors": "1.7.2", + "bytes": "3.1.2", + "http-errors": "1.8.1", "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, "devDependencies": { - "bluebird": "3.5.4", - "eslint": "5.16.0", - "eslint-config-standard": "12.0.0", - "eslint-plugin-import": "2.16.0", - "eslint-plugin-markdown": "1.0.0", - "eslint-plugin-node": "8.0.1", - "eslint-plugin-promise": "4.1.1", - "eslint-plugin-standard": "4.0.0", - "istanbul": "0.4.5", - "mocha": "6.1.3", - "readable-stream": "2.3.6", - "safe-buffer": "5.1.2" + "bluebird": "3.7.2", + "eslint": "7.32.0", + "eslint-config-standard": "14.1.1", + "eslint-plugin-import": "2.25.4", + "eslint-plugin-markdown": "2.2.1", + "eslint-plugin-node": "11.1.0", + "eslint-plugin-promise": "5.2.0", + "eslint-plugin-standard": "4.1.0", + "mocha": "9.2.0", + "nyc": "15.1.0", + "readable-stream": "2.3.7", + "safe-buffer": "5.2.1" }, "engines": { "node": ">= 0.8" @@ -40,9 +40,9 @@ "index.js" ], "scripts": { - "lint": "eslint --plugin markdown --ext js,md .", + "lint": "eslint .", "test": "mocha --trace-deprecation --reporter spec --bail --check-leaks test/", - "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --trace-deprecation --reporter dot --check-leaks test/", - "test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --trace-deprecation --reporter spec --check-leaks test/" + "test-ci": "nyc --reporter=lcov --reporter=text npm test", + "test-cov": "nyc --reporter=html --reporter=text npm test" } } diff --git a/node_modules/safe-buffer/index.js b/node_modules/safe-buffer/index.js index 22438da..f8d3ec9 100644 --- a/node_modules/safe-buffer/index.js +++ b/node_modules/safe-buffer/index.js @@ -1,3 +1,4 @@ +/*! safe-buffer. MIT License. Feross Aboukhadijeh */ /* eslint-disable node/no-deprecated-api */ var buffer = require('buffer') var Buffer = buffer.Buffer @@ -20,6 +21,8 @@ function SafeBuffer (arg, encodingOrOffset, length) { return Buffer(arg, encodingOrOffset, length) } +SafeBuffer.prototype = Object.create(Buffer.prototype) + // Copy static methods from Buffer copyProps(Buffer, SafeBuffer) diff --git a/node_modules/safe-buffer/package.json b/node_modules/safe-buffer/package.json index 623fbc3..f2869e2 100644 --- a/node_modules/safe-buffer/package.json +++ b/node_modules/safe-buffer/package.json @@ -1,18 +1,18 @@ { "name": "safe-buffer", "description": "Safer Node.js Buffer API", - "version": "5.1.2", + "version": "5.2.1", "author": { "name": "Feross Aboukhadijeh", "email": "feross@feross.org", - "url": "http://feross.org" + "url": "https://feross.org" }, "bugs": { "url": "https://github.com/feross/safe-buffer/issues" }, "devDependencies": { "standard": "*", - "tape": "^4.0.0" + "tape": "^5.0.0" }, "homepage": "https://github.com/feross/safe-buffer", "keywords": [ @@ -33,5 +33,19 @@ }, "scripts": { "test": "standard && tape test/*.js" - } + }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] } diff --git a/node_modules/send/HISTORY.md b/node_modules/send/HISTORY.md index d14ac06..8aa3ab3 100644 --- a/node_modules/send/HISTORY.md +++ b/node_modules/send/HISTORY.md @@ -1,3 +1,13 @@ +0.17.2 / 2021-12-11 +=================== + + * pref: ignore empty http tokens + * deps: http-errors@1.8.1 + - deps: inherits@2.0.4 + - deps: toidentifier@1.0.1 + - deps: setprototypeof@1.2.0 + * deps: ms@2.1.3 + 0.17.1 / 2019-05-10 =================== diff --git a/node_modules/send/README.md b/node_modules/send/README.md index 179e8c3..fc1d3a1 100644 --- a/node_modules/send/README.md +++ b/node_modules/send/README.md @@ -2,7 +2,7 @@ [![NPM Version][npm-version-image]][npm-url] [![NPM Downloads][npm-downloads-image]][npm-url] -[![Linux Build][travis-image]][travis-url] +[![Linux Build][github-actions-ci-image]][github-actions-ci-url] [![Windows Build][appveyor-image]][appveyor-url] [![Test Coverage][coveralls-image]][coveralls-url] @@ -26,8 +26,6 @@ $ npm install send ## API - - ```js var send = require('send') ``` @@ -87,7 +85,7 @@ This is skipped if the requested file already has an extension. ##### immutable -Enable or diable the `immutable` directive in the `Cache-Control` response +Enable or disable the `immutable` directive in the `Cache-Control` response header, defaults to `false`. If set to `true`, the `maxAge` option should also be specified to enable caching. The `immutable` directive will prevent supported clients from making conditional requests during the life of the @@ -320,10 +318,10 @@ server.listen(3000) [appveyor-url]: https://ci.appveyor.com/project/dougwilson/send [coveralls-image]: https://badgen.net/coveralls/c/github/pillarjs/send/master [coveralls-url]: https://coveralls.io/r/pillarjs/send?branch=master +[github-actions-ci-image]: https://badgen.net/github/checks/pillarjs/send/master?label=ci +[github-actions-ci-url]: https://github.com/pillarjs/send/actions?query=workflow%3Aci [node-image]: https://badgen.net/npm/node/send [node-url]: https://nodejs.org/en/download/ [npm-downloads-image]: https://badgen.net/npm/dm/send [npm-url]: https://npmjs.org/package/send [npm-version-image]: https://badgen.net/npm/v/send -[travis-image]: https://badgen.net/travis/pillarjs/send/master?label=linux -[travis-url]: https://travis-ci.org/pillarjs/send diff --git a/node_modules/send/index.js b/node_modules/send/index.js index fca2112..06d7507 100644 --- a/node_modules/send/index.js +++ b/node_modules/send/index.js @@ -435,7 +435,7 @@ SendStream.prototype.onStatError = function onStatError (error) { SendStream.prototype.isFresh = function isFresh () { return fresh(this.req.headers, { - 'etag': this.res.getHeader('ETag'), + etag: this.res.getHeader('ETag'), 'last-modified': this.res.getHeader('Last-Modified') }) } @@ -1096,7 +1096,9 @@ function parseTokenList (str) { } break case 0x2c: /* , */ - list.push(str.substring(start, end)) + if (start !== end) { + list.push(str.substring(start, end)) + } start = end = i + 1 break default: @@ -1106,7 +1108,9 @@ function parseTokenList (str) { } // final token - list.push(str.substring(start, end)) + if (start !== end) { + list.push(str.substring(start, end)) + } return list } diff --git a/node_modules/send/node_modules/ms/index.js b/node_modules/send/node_modules/ms/index.js index 7229750..ea734fb 100644 --- a/node_modules/send/node_modules/ms/index.js +++ b/node_modules/send/node_modules/ms/index.js @@ -23,12 +23,12 @@ var y = d * 365.25; * @api public */ -module.exports = function(val, options) { +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) { + } else if (type === 'number' && isFinite(val)) { return options.long ? fmtLong(val) : fmtShort(val); } throw new Error( @@ -50,7 +50,7 @@ function parse(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( + 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) { diff --git a/node_modules/send/node_modules/ms/license.md b/node_modules/send/node_modules/ms/license.md index 69b6125..fa5d39b 100644 --- a/node_modules/send/node_modules/ms/license.md +++ b/node_modules/send/node_modules/ms/license.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2016 Zeit, Inc. +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 diff --git a/node_modules/send/node_modules/ms/package.json b/node_modules/send/node_modules/ms/package.json index fc28cb3..4997189 100644 --- a/node_modules/send/node_modules/ms/package.json +++ b/node_modules/send/node_modules/ms/package.json @@ -1,8 +1,8 @@ { "name": "ms", - "version": "2.1.1", + "version": "2.1.3", "description": "Tiny millisecond conversion utility", - "repository": "zeit/ms", + "repository": "vercel/ms", "main": "./index", "files": [ "index.js" @@ -28,10 +28,11 @@ }, "license": "MIT", "devDependencies": { - "eslint": "4.12.1", + "eslint": "4.18.2", "expect.js": "0.3.1", "husky": "0.14.3", "lint-staged": "5.0.0", - "mocha": "4.0.1" + "mocha": "4.0.1", + "prettier": "2.0.5" } } diff --git a/node_modules/send/node_modules/ms/readme.md b/node_modules/send/node_modules/ms/readme.md index bb76729..0fc1abb 100644 --- a/node_modules/send/node_modules/ms/readme.md +++ b/node_modules/send/node_modules/ms/readme.md @@ -1,7 +1,6 @@ # 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/) +![CI](https://github.com/vercel/ms/workflows/CI/badge.svg) Use this package to easily convert various time formats to milliseconds. diff --git a/node_modules/send/package.json b/node_modules/send/package.json index 2ba9c06..f58140c 100644 --- a/node_modules/send/package.json +++ b/node_modules/send/package.json @@ -1,7 +1,7 @@ { "name": "send", "description": "Better streaming static file server with Range and conditional-GET support", - "version": "0.17.1", + "version": "0.17.2", "author": "TJ Holowaychuk ", "contributors": [ "Douglas Christopher Wilson ", @@ -23,25 +23,25 @@ "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "1.8.1", "mime": "1.6.0", - "ms": "2.1.1", + "ms": "2.1.3", "on-finished": "~2.3.0", "range-parser": "~1.2.1", "statuses": "~1.5.0" }, "devDependencies": { "after": "0.8.2", - "eslint": "5.16.0", - "eslint-config-standard": "12.0.0", - "eslint-plugin-import": "2.17.2", - "eslint-plugin-markdown": "1.0.0", - "eslint-plugin-node": "8.0.1", - "eslint-plugin-promise": "4.1.1", - "eslint-plugin-standard": "4.0.0", - "istanbul": "0.4.5", - "mocha": "6.1.4", - "supertest": "4.0.2" + "eslint": "7.32.0", + "eslint-config-standard": "14.1.1", + "eslint-plugin-import": "2.25.3", + "eslint-plugin-markdown": "2.2.1", + "eslint-plugin-node": "11.1.0", + "eslint-plugin-promise": "5.2.0", + "eslint-plugin-standard": "4.1.0", + "mocha": "9.1.3", + "nyc": "15.1.0", + "supertest": "6.1.6" }, "files": [ "HISTORY.md", @@ -53,9 +53,9 @@ "node": ">= 0.8.0" }, "scripts": { - "lint": "eslint --plugin markdown --ext js,md .", + "lint": "eslint .", "test": "mocha --check-leaks --reporter spec --bail", - "test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --check-leaks --reporter spec", - "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --check-leaks --reporter dot" + "test-ci": "nyc --reporter=lcov --reporter=text npm test", + "test-cov": "nyc --reporter=html --reporter=text npm test" } } diff --git a/node_modules/serve-static/HISTORY.md b/node_modules/serve-static/HISTORY.md index 7203e4f..eafa750 100644 --- a/node_modules/serve-static/HISTORY.md +++ b/node_modules/serve-static/HISTORY.md @@ -1,3 +1,11 @@ +1.14.2 / 2021-12-15 +=================== + + * deps: send@0.17.2 + - deps: http-errors@1.8.1 + - deps: ms@2.1.3 + - pref: ignore empty http tokens + 1.14.1 / 2019-05-10 =================== diff --git a/node_modules/serve-static/README.md b/node_modules/serve-static/README.md index 7cce428..aa94341 100644 --- a/node_modules/serve-static/README.md +++ b/node_modules/serve-static/README.md @@ -2,7 +2,7 @@ [![NPM Version][npm-version-image]][npm-url] [![NPM Downloads][npm-downloads-image]][npm-url] -[![Linux Build][travis-image]][travis-url] +[![Linux Build][github-actions-ci-image]][github-actions-ci-url] [![Windows Build][appveyor-image]][appveyor-url] [![Test Coverage][coveralls-image]][coveralls-url] @@ -18,8 +18,6 @@ $ npm install serve-static ## API - - ```js var serveStatic = require('serve-static') ``` @@ -141,7 +139,7 @@ var http = require('http') var serveStatic = require('serve-static') // Serve up public/ftp folder -var serve = serveStatic('public/ftp', { 'index': ['index.html', 'index.htm'] }) +var serve = serveStatic('public/ftp', { index: ['index.html', 'index.htm'] }) // Create server var server = http.createServer(function onRequest (req, res) { @@ -162,8 +160,8 @@ var serveStatic = require('serve-static') // Serve up public/ftp folder var serve = serveStatic('public/ftp', { - 'index': false, - 'setHeaders': setHeaders + index: false, + setHeaders: setHeaders }) // Set header to force download @@ -192,15 +190,15 @@ var serveStatic = require('serve-static') var app = express() -app.use(serveStatic('public/ftp', { 'index': ['default.html', 'default.htm'] })) +app.use(serveStatic('public/ftp', { index: ['default.html', 'default.htm'] })) app.listen(3000) ``` #### Multiple roots This example shows a simple way to search through multiple directories. -Files are look for in `public-optimized/` first, then `public/` second as -a fallback. +Files are searched for in `public-optimized/` first, then `public/` second +as a fallback. ```js var express = require('express') @@ -250,10 +248,10 @@ function setCustomCacheControl (res, path) { [appveyor-url]: https://ci.appveyor.com/project/dougwilson/serve-static [coveralls-image]: https://badgen.net/coveralls/c/github/expressjs/serve-static/master [coveralls-url]: https://coveralls.io/r/expressjs/serve-static?branch=master +[github-actions-ci-image]: https://badgen.net/github/checks/expressjs/serve-static/master?label=linux +[github-actions-ci-url]: https://github.com/expressjs/serve-static/actions?query=workflow%3Aci [node-image]: https://badgen.net/npm/node/serve-static [node-url]: https://nodejs.org/en/download/ [npm-downloads-image]: https://badgen.net/npm/dm/serve-static [npm-url]: https://npmjs.org/package/serve-static [npm-version-image]: https://badgen.net/npm/v/serve-static -[travis-image]: https://badgen.net/travis/expressjs/serve-static/master?label=linux -[travis-url]: https://travis-ci.org/expressjs/serve-static diff --git a/node_modules/serve-static/package.json b/node_modules/serve-static/package.json index a60c83f..e223bef 100644 --- a/node_modules/serve-static/package.json +++ b/node_modules/serve-static/package.json @@ -1,7 +1,7 @@ { "name": "serve-static", "description": "Serve static files", - "version": "1.14.1", + "version": "1.14.2", "author": "Douglas Christopher Wilson ", "license": "MIT", "repository": "expressjs/serve-static", @@ -9,20 +9,20 @@ "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.1" + "send": "0.17.2" }, "devDependencies": { - "eslint": "5.16.0", - "eslint-config-standard": "12.0.0", - "eslint-plugin-import": "2.17.2", - "eslint-plugin-markdown": "1.0.0", - "eslint-plugin-node": "8.0.1", - "eslint-plugin-promise": "4.1.1", - "eslint-plugin-standard": "4.0.0", - "istanbul": "0.4.5", - "mocha": "6.1.4", - "safe-buffer": "5.1.2", - "supertest": "4.0.2" + "eslint": "7.32.0", + "eslint-config-standard": "14.1.1", + "eslint-plugin-import": "2.25.3", + "eslint-plugin-markdown": "2.2.1", + "eslint-plugin-node": "11.1.0", + "eslint-plugin-promise": "5.2.0", + "eslint-plugin-standard": "4.1.0", + "mocha": "9.1.3", + "nyc": "15.1.0", + "safe-buffer": "5.2.1", + "supertest": "6.1.6" }, "files": [ "LICENSE", @@ -33,10 +33,10 @@ "node": ">= 0.8.0" }, "scripts": { - "lint": "eslint --plugin markdown --ext js,md .", + "lint": "eslint .", "test": "mocha --reporter spec --bail --check-leaks test/", - "test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --reporter spec --check-leaks test/", - "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --reporter dot --check-leaks test/", + "test-ci": "nyc --reporter=lcov --reporter=text npm test", + "test-cov": "nyc --reporter=html --reporter=text npm test", "version": "node scripts/version-history.js && git add HISTORY.md" } } diff --git a/node_modules/setprototypeof/README.md b/node_modules/setprototypeof/README.md index f120044..791eeff 100644 --- a/node_modules/setprototypeof/README.md +++ b/node_modules/setprototypeof/README.md @@ -27,5 +27,5 @@ obj.foo() // bar TypeScript is also supported: ```typescript -import setPrototypeOf = require('setprototypeof') +import setPrototypeOf from 'setprototypeof' ``` diff --git a/node_modules/setprototypeof/index.js b/node_modules/setprototypeof/index.js index 81fd5d7..c527055 100644 --- a/node_modules/setprototypeof/index.js +++ b/node_modules/setprototypeof/index.js @@ -9,7 +9,7 @@ function setProtoOf (obj, proto) { function mixinProperties (obj, proto) { for (var prop in proto) { - if (!obj.hasOwnProperty(prop)) { + if (!Object.prototype.hasOwnProperty.call(obj, prop)) { obj[prop] = proto[prop] } } diff --git a/node_modules/setprototypeof/package.json b/node_modules/setprototypeof/package.json index 41368e1..f20915b 100644 --- a/node_modules/setprototypeof/package.json +++ b/node_modules/setprototypeof/package.json @@ -1,6 +1,6 @@ { "name": "setprototypeof", - "version": "1.1.1", + "version": "1.2.0", "description": "A small polyfill for Object.setprototypeof", "main": "index.js", "typings": "index.d.ts", @@ -12,7 +12,9 @@ "node4": "NODE_VER=4 npm run testversion", "node6": "NODE_VER=6 npm run testversion", "node9": "NODE_VER=9 npm run testversion", - "node11": "NODE_VER=11 npm run testversion" + "node11": "NODE_VER=11 npm run testversion", + "prepublishOnly": "npm t", + "postpublish": "git push origin && git push origin --tags" }, "repository": { "type": "git", @@ -30,7 +32,7 @@ }, "homepage": "https://github.com/wesleytodd/setprototypeof", "devDependencies": { - "mocha": "^5.2.0", - "standard": "^12.0.1" + "mocha": "^6.1.4", + "standard": "^13.0.2" } } diff --git a/node_modules/toidentifier/HISTORY.md b/node_modules/toidentifier/HISTORY.md new file mode 100644 index 0000000..cb7cc89 --- /dev/null +++ b/node_modules/toidentifier/HISTORY.md @@ -0,0 +1,9 @@ +1.0.1 / 2021-11-14 +================== + + * pref: enable strict mode + +1.0.0 / 2018-07-09 +================== + + * Initial release diff --git a/node_modules/toidentifier/README.md b/node_modules/toidentifier/README.md index 7c8794e..57e8a78 100644 --- a/node_modules/toidentifier/README.md +++ b/node_modules/toidentifier/README.md @@ -2,7 +2,7 @@ [![NPM Version][npm-image]][npm-url] [![NPM Downloads][downloads-image]][downloads-url] -[![Build Status][travis-image]][travis-url] +[![Build Status][github-actions-ci-image]][github-actions-ci-url] [![Test Coverage][codecov-image]][codecov-url] > Convert a string of words to a JavaScript identifier @@ -48,10 +48,10 @@ the following rules and the new string will be returned: [codecov-url]: https://codecov.io/gh/component/toidentifier [downloads-image]: https://img.shields.io/npm/dm/toidentifier.svg [downloads-url]: https://npmjs.org/package/toidentifier +[github-actions-ci-image]: https://img.shields.io/github/workflow/status/component/toidentifier/ci/master?label=ci +[github-actions-ci-url]: https://github.com/component/toidentifier?query=workflow%3Aci [npm-image]: https://img.shields.io/npm/v/toidentifier.svg [npm-url]: https://npmjs.org/package/toidentifier -[travis-image]: https://img.shields.io/travis/component/toidentifier/master.svg -[travis-url]: https://travis-ci.org/component/toidentifier ## diff --git a/node_modules/toidentifier/index.js b/node_modules/toidentifier/index.js index bba5411..9295d02 100644 --- a/node_modules/toidentifier/index.js +++ b/node_modules/toidentifier/index.js @@ -4,6 +4,8 @@ * MIT Licensed */ +'use strict' + /** * Module exports. * @public diff --git a/node_modules/toidentifier/package.json b/node_modules/toidentifier/package.json index 3f78165..42db1a6 100644 --- a/node_modules/toidentifier/package.json +++ b/node_modules/toidentifier/package.json @@ -1,7 +1,7 @@ { "name": "toidentifier", "description": "Convert a string of words to a JavaScript identifier", - "version": "1.0.0", + "version": "1.0.1", "author": "Douglas Christopher Wilson ", "contributors": [ "Douglas Christopher Wilson ", @@ -9,26 +9,30 @@ ], "repository": "component/toidentifier", "devDependencies": { - "eslint": "4.19.1", - "eslint-config-standard": "11.0.0", - "eslint-plugin-import": "2.11.0", - "eslint-plugin-markdown": "1.0.0-beta.6", - "eslint-plugin-node": "6.0.1", - "eslint-plugin-promise": "3.7.0", - "eslint-plugin-standard": "3.1.0", - "mocha": "1.21.5", - "nyc": "11.8.0" + "eslint": "7.32.0", + "eslint-config-standard": "14.1.1", + "eslint-plugin-import": "2.25.3", + "eslint-plugin-markdown": "2.2.1", + "eslint-plugin-node": "11.1.0", + "eslint-plugin-promise": "4.3.1", + "eslint-plugin-standard": "4.1.0", + "mocha": "9.1.3", + "nyc": "15.1.0" }, "engines": { "node": ">=0.6" }, "license": "MIT", "files": [ + "HISTORY.md", + "LICENSE", "index.js" ], "scripts": { - "lint": "eslint --plugin markdown --ext js,md .", + "lint": "eslint .", "test": "mocha --reporter spec --bail --check-leaks test/", - "test-cov": "nyc --reporter=html --reporter=text npm test" + "test-ci": "nyc --reporter=lcov --reporter=text npm test", + "test-cov": "nyc --reporter=html --reporter=text npm test", + "version": "node scripts/version-history.js && git add HISTORY.md" } } diff --git a/node_modules/uglify-js/README.md b/node_modules/uglify-js/README.md index ea11a02..60cb6ab 100644 --- a/node_modules/uglify-js/README.md +++ b/node_modules/uglify-js/README.md @@ -115,6 +115,7 @@ a double dash to prevent input files being used as option arguments: Equivalent to setting `ie: true` in `minify()` for `compress`, `mangle` and `output` options. By default UglifyJS will not try to be IE-proof. + --keep-fargs Do not mangle/drop function arguments. --keep-fnames Do not mangle/drop function names. Useful for code relying on Function.prototype.name. --name-cache File to hold mangled name mappings. @@ -504,6 +505,9 @@ if (result.error) throw result.error; - `ie` (default: `false`) — enable workarounds for Internet Explorer bugs. +- `keep_fargs` (default: `false`) — pass `true` to prevent discarding or mangling + of function arguments. + - `keep_fnames` (default: `false`) — pass `true` to prevent discarding or mangling of function names. Useful for code relying on `Function.prototype.name`. @@ -707,7 +711,8 @@ to be `false` and all symbol names will be omitted. - `1` — inline simple functions - `2` — inline functions with arguments - `3` — inline functions with arguments and variables - - `true` — same as `3` + - `4` — inline functions with arguments, variables and statements + - `true` — same as `4` - `join_vars` (default: `true`) — join consecutive `var` statements @@ -867,6 +872,9 @@ UglifyJS.minify(code, { mangle: { toplevel: true } }).code; - `debug` (default: `false`) — Mangle names with the original name still present. Pass an empty string `""` to enable, or a non-empty string to set the debug suffix. +- `keep_fargs` (default: `false`) — Use `true` to prevent mangling of function + arguments. + - `keep_quoted` (default: `false`) — Only mangle unquoted property names. - `regex` (default: `null`) — Pass a RegExp literal to only mangle property @@ -909,9 +917,11 @@ can pass additional arguments that control the code output: - `galio` (default: `false`) — enable workarounds for ANT Galio bugs -- `indent_level` (default: `4`) +- `indent_level` (default: `4`) — indent by specified number of spaces or the + exact whitespace sequence supplied, e.g. `"\t"`. -- `indent_start` (default: `0`) — prefix all lines by that many spaces +- `indent_start` (default: `0`) — prefix all lines by whitespace sequence + specified in the same format as `indent_level`. - `inline_script` (default: `true`) — escape HTML comments and the slash in occurrences of `` in strings @@ -1199,6 +1209,17 @@ To allow for better optimizations, the compiler makes various assumptions: - Object properties can be added, removed and modified (not prevented with `Object.defineProperty()`, `Object.defineProperties()`, `Object.freeze()`, `Object.preventExtensions()` or `Object.seal()`). +- If array destructuring is present, index-like properties in `Array.prototype` + have not been overridden: + ```javascript + Object.prototype[0] = 42; + var [ a ] = []; + var { 0: b } = {}; + // 42 undefined + console.log([][0], a); + // 42 42 + console.log({}[0], b); + ``` - Earlier versions of JavaScript will throw `SyntaxError` with the following: ```javascript ({ diff --git a/node_modules/uglify-js/bin/uglifyjs b/node_modules/uglify-js/bin/uglifyjs index 08e3d49..d7a6498 100755 --- a/node_modules/uglify-js/bin/uglifyjs +++ b/node_modules/uglify-js/bin/uglifyjs @@ -10,7 +10,9 @@ var info = require("../package.json"); var path = require("path"); var UglifyJS = require("../tools/node"); -var skip_keys = [ "cname", "fixed", "inlined", "parent_scope", "scope", "uses_eval", "uses_with" ]; +var skip_keys = [ "cname", "fixed", "in_arg", "inlined", "length_read", "parent_scope", "redef", "scope", "unused" ]; +var truthy_keys = [ "optional", "pure", "terminal", "uses_arguments", "uses_eval", "uses_with" ]; + var files = {}; var options = {}; var short_forms = { @@ -70,6 +72,7 @@ function process_option(name, no_value) { } else { if (padding.length < name.length) padding = Array(name.length + 1).join(" "); toplevels.push([ { + keep_fargs: "keep-fargs", keep_fnames: "keep-fnames", nameCache: "name-cache", }[name] || name, option ]); @@ -102,6 +105,7 @@ function process_option(name, no_value) { " -d, --define [=value] Global definitions.", " -e, --enclose [arg[,...][:value[,...]]] Embed everything in a big function, with configurable argument(s) & value(s).", " --ie Support non-standard Internet Explorer.", + " --keep-fargs Do not mangle/drop function arguments.", " --keep-fnames Do not mangle/drop function names. Useful for code relying on Function.prototype.name.", " --name-cache File to hold mangled name mappings.", " --rename Force symbol expansion.", @@ -158,6 +162,9 @@ function process_option(name, no_value) { case "no-annotations": options.annotations = false; break; + case "keep-fargs": + options.keep_fargs = true; + break; case "keep-fnames": options.keep_fnames = true; break; @@ -430,7 +437,7 @@ function run() { case "thedef": return symdef(value); } - if (skip_key(key)) return; + if (skip_property(key, value)) return; if (value instanceof UglifyJS.AST_Token) return; if (value instanceof UglifyJS.Dictionary) return; if (value instanceof UglifyJS.AST_Node) { @@ -519,7 +526,7 @@ function read_file(path, default_value) { } function parse_js(value, options, flag) { - if (!options || typeof options != "object") options = {}; + if (!options || typeof options != "object") options = Object.create(null); if (typeof value == "string") try { UglifyJS.parse(value, { expression: true @@ -559,8 +566,10 @@ function parse_js(value, options, flag) { return options; } -function skip_key(key) { - return skip_keys.indexOf(key) >= 0; +function skip_property(key, value) { + return skip_keys.indexOf(key) >= 0 + // only skip truthy_keys if their value is falsy + || truthy_keys.indexOf(key) >= 0 && !value; } function symdef(def) { diff --git a/node_modules/uglify-js/lib/ast.js b/node_modules/uglify-js/lib/ast.js index c4866f8..8ba095d 100644 --- a/node_modules/uglify-js/lib/ast.js +++ b/node_modules/uglify-js/lib/ast.js @@ -50,6 +50,8 @@ function DEFNODE(type, props, methods, base) { if (base && base.PROPS) props = props.concat(base.PROPS); var code = [ "return function AST_", type, "(props){", + // not essential, but speeds up compress by a few percent + "this._bits=0;", "if(props){", ]; props.forEach(function(prop) { @@ -135,6 +137,53 @@ var AST_Node = DEFNODE("Node", "start end", { }, }, null); +DEF_BITPROPS(AST_Node, [ + "_optimized", + "_squeezed", + // AST_Call + "call_only", + // AST_Lambda + "collapse_scanning", + // AST_SymbolRef + "defined", + "evaluating", + "falsy", + // AST_SymbolRef + "in_arg", + // AST_Return + "in_bool", + // AST_SymbolRef + "is_undefined", + // AST_LambdaExpression + // AST_LambdaDefinition + "inlined", + // AST_Lambda + "length_read", + // AST_Yield + "nested", + // AST_Lambda + "new", + // AST_Call + // AST_PropAccess + "optional", + // AST_ClassProperty + "private", + // AST_Call + "pure", + // AST_Assign + "redundant", + // AST_ClassProperty + "static", + // AST_Call + // AST_PropAccess + "terminal", + "truthy", + // AST_Scope + "uses_eval", + // AST_Scope + "uses_with", +]); + (AST_Node.log_function = function(fn, verbose) { if (typeof fn != "function") { AST_Node.info = AST_Node.warn = noop; @@ -253,7 +302,7 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", { }, }, AST_Statement); -var AST_BlockScope = DEFNODE("BlockScope", "enclosed functions make_def parent_scope variables", { +var AST_BlockScope = DEFNODE("BlockScope", "_var_names enclosed functions make_def parent_scope variables", { $documentation: "Base class for all statements introducing a lexical scope", $propdoc: { enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes", @@ -484,7 +533,7 @@ var AST_With = DEFNODE("With", "expression", { /* -----[ scope and functions ]----- */ -var AST_Scope = DEFNODE("Scope", "uses_eval uses_with", { +var AST_Scope = DEFNODE("Scope", "fn_defs may_call_this uses_eval uses_with", { $documentation: "Base class for all statements introducing a lexical scope", $propdoc: { uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`", @@ -543,13 +592,13 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", { } }, AST_Scope); -var AST_Lambda = DEFNODE("Lambda", "argnames length_read rest uses_arguments", { +var AST_Lambda = DEFNODE("Lambda", "argnames length_read rest safe_ids uses_arguments", { $documentation: "Base class for functions", $propdoc: { argnames: "[(AST_DefaultValue|AST_Destructured|AST_SymbolFunarg)*] array of function arguments and/or destructured literals", length_read: "[boolean/S] whether length property of this function is accessed", rest: "[(AST_Destructured|AST_SymbolFunarg)?] rest parameter, or null if absent", - uses_arguments: "[boolean/S] whether this function accesses the arguments array", + uses_arguments: "[boolean|number/S] whether this function accesses the arguments array", }, each_argname: function(visit) { var tw = new TreeWalker(function(node) { @@ -1295,7 +1344,7 @@ var AST_Call = DEFNODE("Call", "args expression optional pure terminal", { args: "[AST_Node*] array of arguments", expression: "[AST_Node] expression to invoke as function", optional: "[boolean] whether the expression is optional chaining", - pure: "[string/S] marker for side-effect-free call expression", + pure: "[boolean/S] marker for side-effect-free call expression", terminal: "[boolean] whether the chain has ended", }, walk: function(visitor) { @@ -1489,6 +1538,12 @@ var AST_Assign = DEFNODE("Assign", null, { throw new Error("left must be assignable: " + node.TYPE); } }); + } else if (!(this.left instanceof AST_Infinity + || this.left instanceof AST_NaN + || this.left instanceof AST_PropAccess && !this.left.optional + || this.left instanceof AST_SymbolRef + || this.left instanceof AST_Undefined)) { + throw new Error("left must be assignable"); } }, }, AST_Binary); @@ -1747,7 +1802,7 @@ var AST_SymbolVar = DEFNODE("SymbolVar", null, { $documentation: "Symbol defining a variable", }, AST_SymbolDeclaration); -var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, { +var AST_SymbolFunarg = DEFNODE("SymbolFunarg", "unused", { $documentation: "Symbol naming a function argument", }, AST_SymbolVar); @@ -1923,27 +1978,27 @@ var AST_Atom = DEFNODE("Atom", null, { var AST_Null = DEFNODE("Null", null, { $documentation: "The `null` atom", - value: null + value: null, }, AST_Atom); var AST_NaN = DEFNODE("NaN", null, { $documentation: "The impossible value", - value: 0/0 + value: 0/0, }, AST_Atom); var AST_Undefined = DEFNODE("Undefined", null, { $documentation: "The `undefined` value", - value: function(){}() + value: function(){}(), }, AST_Atom); var AST_Hole = DEFNODE("Hole", null, { $documentation: "A hole in an array", - value: function(){}() + value: function(){}(), }, AST_Atom); var AST_Infinity = DEFNODE("Infinity", null, { $documentation: "The `Infinity` value", - value: 1/0 + value: 1/0, }, AST_Atom); var AST_Boolean = DEFNODE("Boolean", null, { @@ -1955,12 +2010,12 @@ var AST_Boolean = DEFNODE("Boolean", null, { var AST_False = DEFNODE("False", null, { $documentation: "The `false` atom", - value: false + value: false, }, AST_Boolean); var AST_True = DEFNODE("True", null, { $documentation: "The `true` atom", - value: true + value: true, }, AST_Boolean); /* -----[ TreeWalker ]----- */ @@ -1999,7 +2054,7 @@ TreeWalker.prototype = { }, find_parent: function(type) { var stack = this.stack; - for (var i = stack.length; --i >= 0;) { + for (var i = stack.length - 1; --i >= 0;) { var x = stack[i]; if (x instanceof type) return x; } @@ -2030,33 +2085,40 @@ TreeWalker.prototype = { } }, in_boolean_context: function() { - var self = this.self(); - for (var i = 0, p; p = this.parent(i); i++) { - if (p instanceof AST_Conditional && p.condition === self - || p instanceof AST_DWLoop && p.condition === self - || p instanceof AST_For && p.condition === self - || p instanceof AST_If && p.condition === self - || p instanceof AST_Return && p.in_bool - || p instanceof AST_Sequence && p.tail_node() !== self - || p instanceof AST_SimpleStatement - || p instanceof AST_UnaryPrefix && p.operator == "!" && p.expression === self) { - return true; - } - if (p instanceof AST_Binary && (p.operator == "&&" || p.operator == "||") - || p instanceof AST_Conditional - || p.tail_node() === self) { - self = p; - } else if (p instanceof AST_Return) { - for (var call, fn = p; call = this.parent(++i); fn = call) { - if (call.TYPE == "Call") { - if (!(fn instanceof AST_Lambda) || fn.name) return false; - } else if (fn instanceof AST_Lambda) { - return false; - } - } - } else { + for (var drop = true, level = 0, parent, self = this.self(); parent = this.parent(level++); self = parent) { + if (parent instanceof AST_Binary) switch (parent.operator) { + case "&&": + case "||": + if (parent.left === self) drop = false; + continue; + default: return false; } + if (parent instanceof AST_Conditional) { + if (parent.condition === self) return true; + continue; + } + if (parent instanceof AST_DWLoop) return parent.condition === self; + if (parent instanceof AST_For) return parent.condition === self; + if (parent instanceof AST_If) return parent.condition === self; + if (parent instanceof AST_Return) { + if (parent.in_bool) return true; + while (parent = this.parent(level++)) { + if (parent instanceof AST_Lambda) { + if (parent.name) return false; + parent = this.parent(level++); + if (parent.TYPE != "Call") return false; + break; + } + } + } + if (parent instanceof AST_Sequence) { + if (parent.tail_node() === self) continue; + return drop ? "d" : true; + } + if (parent instanceof AST_SimpleStatement) return drop ? "d" : true; + if (parent instanceof AST_UnaryPrefix) return parent.operator == "!"; + return false; } } }; diff --git a/node_modules/uglify-js/lib/compress.js b/node_modules/uglify-js/lib/compress.js index 1c4df6c..80ace96 100644 --- a/node_modules/uglify-js/lib/compress.js +++ b/node_modules/uglify-js/lib/compress.js @@ -116,12 +116,10 @@ function Compressor(options, false_by_default) { var global_defs = this.options["global_defs"]; if (typeof global_defs == "object") for (var key in global_defs) { if (/^@/.test(key) && HOP(global_defs, key)) { - global_defs[key.slice(1)] = parse(global_defs[key], { - expression: true - }); + global_defs[key.slice(1)] = parse(global_defs[key], { expression: true }); } } - if (this.options["inline"] === true) this.options["inline"] = 3; + if (this.options["inline"] === true) this.options["inline"] = 4; this.drop_fargs = this.options["keep_fargs"] ? return_false : function(lambda, parent) { if (lambda.length_read) return false; var name = lambda.name; @@ -185,88 +183,85 @@ function Compressor(options, false_by_default) { }; } -Compressor.prototype = new TreeTransformer; -merge(Compressor.prototype, { - option: function(key) { return this.options[key] }, - exposed: function(def) { - if (def.exported) return true; - if (def.undeclared) return true; - if (!(def.global || def.scope.resolve() instanceof AST_Toplevel)) return false; - var toplevel = this.toplevel; - return !all(def.orig, function(sym) { - return toplevel[sym instanceof AST_SymbolDefun ? "funcs" : "vars"]; - }); - }, - compress: function(node) { - node = node.resolve_defines(this); - node.hoist_exports(this); - if (this.option("expression")) { - node.process_expression(true); - } - var passes = +this.options.passes || 1; - var min_count = 1 / 0; - var stopping = false; - var mangle = { ie: this.option("ie") }; - for (var pass = 0; pass < passes; pass++) { - node.figure_out_scope(mangle); - if (pass > 0 || this.option("reduce_vars")) - node.reset_opt_flags(this); - node = node.transform(this); - if (passes > 1) { - var count = 0; - node.walk(new TreeWalker(function() { - count++; - })); - AST_Node.info("pass {pass}: last_count: {min_count}, count: {count}", { - pass: pass, - min_count: min_count, - count: count, - }); - if (count < min_count) { - min_count = count; - stopping = false; - } else if (stopping) { - break; - } else { - stopping = true; - } +Compressor.prototype = new TreeTransformer(function(node, descend, in_list) { + if (node._squeezed) return node; + var is_scope = node instanceof AST_Scope; + if (is_scope) { + node.hoist_properties(this); + node.hoist_declarations(this); + node.process_returns(this); + } + // Before https://github.com/mishoo/UglifyJS/pull/1602 AST_Node.optimize() + // would call AST_Node.transform() if a different instance of AST_Node is + // produced after OPT(). + // This corrupts TreeWalker.stack, which cause AST look-ups to malfunction. + // Migrate and defer all children's AST_Node.transform() to below, which + // will now happen after this parent AST_Node has been properly substituted + // thus gives a consistent AST snapshot. + descend(node, this); + // Existing code relies on how AST_Node.optimize() worked, and omitting the + // following replacement call would result in degraded efficiency of both + // output and performance. + descend(node, this); + var opt = node.optimize(this); + if (is_scope && opt === node && !this.has_directive("use asm") && !opt.pinned()) { + opt.drop_unused(this); + if (opt.merge_variables(this)) opt.drop_unused(this); + descend(opt, this); + } + if (opt === node) opt._squeezed = true; + return opt; +}); +Compressor.prototype.option = function(key) { + return this.options[key]; +}; +Compressor.prototype.exposed = function(def) { + if (def.exported) return true; + if (def.undeclared) return true; + if (!(def.global || def.scope.resolve() instanceof AST_Toplevel)) return false; + var toplevel = this.toplevel; + return !all(def.orig, function(sym) { + return toplevel[sym instanceof AST_SymbolDefun ? "funcs" : "vars"]; + }); +}; +Compressor.prototype.compress = function(node) { + node = node.resolve_defines(this); + node.hoist_exports(this); + if (this.option("expression")) node.process_expression(true); + var merge_vars = this.options.merge_vars; + var passes = +this.options.passes || 1; + var min_count = 1 / 0; + var stopping = false; + var mangle = { ie: this.option("ie") }; + for (var pass = 0; pass < passes; pass++) { + node.figure_out_scope(mangle); + if (pass > 0 || this.option("reduce_vars")) + node.reset_opt_flags(this); + this.options.merge_vars = merge_vars && (stopping || pass == passes - 1); + node = node.transform(this); + if (passes > 1) { + var count = 0; + node.walk(new TreeWalker(function() { + count++; + })); + AST_Node.info("pass {pass}: last_count: {min_count}, count: {count}", { + pass: pass, + min_count: min_count, + count: count, + }); + if (count < min_count) { + min_count = count; + stopping = false; + } else if (stopping) { + break; + } else { + stopping = true; } } - if (this.option("expression")) { - node.process_expression(false); - } - return node; - }, - before: function(node, descend, in_list) { - if (node._squeezed) return node; - var is_scope = node instanceof AST_Scope; - if (is_scope) { - node.hoist_properties(this); - node.hoist_declarations(this); - node.process_boolean_returns(this); - } - // Before https://github.com/mishoo/UglifyJS/pull/1602 AST_Node.optimize() - // would call AST_Node.transform() if a different instance of AST_Node is - // produced after OPT(). - // This corrupts TreeWalker.stack, which cause AST look-ups to malfunction. - // Migrate and defer all children's AST_Node.transform() to below, which - // will now happen after this parent AST_Node has been properly substituted - // thus gives a consistent AST snapshot. - descend(node, this); - // Existing code relies on how AST_Node.optimize() worked, and omitting the - // following replacement call would result in degraded efficiency of both - // output and performance. - descend(node, this); - var opt = node.optimize(this); - if (is_scope && opt === node && !this.has_directive("use asm") && !opt.pinned()) { - opt.merge_variables(this); - opt.drop_unused(this); - descend(opt, this); - } - if (opt === node) opt._squeezed = true; - return opt; } -}); + if (this.option("expression")) node.process_expression(false); + return node; +}; (function(OPT) { OPT(AST_Node, function(self, compressor) { @@ -309,12 +304,19 @@ merge(Compressor.prototype, { AST_Scope.DEFMETHOD("process_expression", function(insert, transform) { var self = this; var tt = new TreeTransformer(function(node) { - if (insert && node instanceof AST_SimpleStatement) { - return transform ? transform(node) : make_node(AST_Return, node, { value: node.body }); - } - if (!insert && node instanceof AST_Return) { - return transform ? transform(node) : make_node(AST_SimpleStatement, node, { - body: node.value || make_node(AST_UnaryPrefix, node, { + if (insert) { + if (node instanceof AST_Directive) node = make_node(AST_SimpleStatement, node, { + body: make_node(AST_String, node, node), + }); + if (node instanceof AST_SimpleStatement) { + return transform ? transform(node) : make_node(AST_Return, node, { value: node.body }); + } + } else if (node instanceof AST_Return) { + if (transform) return transform(node); + var value = node.value; + if (value instanceof AST_String) return make_node(AST_Directive, node, value); + return make_node(AST_SimpleStatement, node, { + body: value || make_node(AST_UnaryPrefix, node, { operator: "void", expression: make_node(AST_Number, node, { value: 0 }), }), @@ -335,9 +337,7 @@ merge(Compressor.prototype, { } } else if (node instanceof AST_If) { node.body = node.body.transform(tt); - if (node.alternative) { - node.alternative = node.alternative.transform(tt); - } + if (node.alternative) node.alternative = node.alternative.transform(tt); } else if (node instanceof AST_With) { node.body = node.body.transform(tt); } @@ -389,7 +389,18 @@ merge(Compressor.prototype, { } var lhs = is_lhs(node, parent); if (lhs) return lhs; + if (level == 0 && value && value.is_constant()) return; if (parent instanceof AST_Array) return is_modified(compressor, tw, parent, parent, level + 1); + if (parent instanceof AST_Assign) switch (parent.operator) { + case "=": + return is_modified(compressor, tw, parent, value, level + 1, immutable, recursive); + case "&&=": + case "||=": + case "??=": + return is_modified(compressor, tw, parent, parent, level + 1); + default: + return; + } if (parent instanceof AST_Binary) { if (!lazy_op[parent.operator]) return; return is_modified(compressor, tw, parent, parent, level + 1); @@ -433,10 +444,6 @@ merge(Compressor.prototype, { return def.name == "arguments" && def.scope.uses_arguments; } - function is_funarg(def) { - return def.orig[0] instanceof AST_SymbolFunarg || def.orig[1] instanceof AST_SymbolFunarg; - } - function cross_scope(def, sym) { do { if (def === sym) return false; @@ -445,10 +452,11 @@ merge(Compressor.prototype, { } function can_drop_symbol(ref, compressor, keep_lambda) { - var def = ref.definition(); + var def = ref.redef || ref.definition(); if (ref.in_arg && is_funarg(def)) return false; return all(def.orig, function(sym) { if (sym instanceof AST_SymbolConst || sym instanceof AST_SymbolLet) { + if (sym instanceof AST_SymbolImport) return true; return compressor && can_varify(compressor, sym); } return !(keep_lambda && sym instanceof AST_SymbolLambda); @@ -468,7 +476,8 @@ merge(Compressor.prototype, { function reset_def(tw, compressor, def) { def.assignments = 0; - def.bool_fn = 0; + def.bool_return = 0; + def.drop_return = 0; def.cross_loop = false; def.direct_access = false; def.escaped = []; @@ -480,7 +489,6 @@ merge(Compressor.prototype, { def.reassigned = 0; def.recursive_refs = 0; def.references = []; - def.should_replace = undefined; def.single_use = undefined; } @@ -519,6 +527,11 @@ merge(Compressor.prototype, { }); } + function safe_to_visit(tw, fn) { + var marker = fn.safe_ids; + return marker === undefined || marker === tw.safe_ids; + } + function walk_fn_def(tw, fn) { var was_scanning = tw.fn_scanning; tw.fn_scanning = fn; @@ -533,14 +546,14 @@ merge(Compressor.prototype, { d.single_use = false; var fixed = d.fixed; if (typeof fixed == "function") fixed = fixed(); - if (fixed instanceof AST_Lambda && HOP(fixed, "safe_ids")) return; + if (fixed instanceof AST_Lambda && fixed.safe_ids !== undefined) return; d.fixed = false; }); } function mark_fn_def(tw, def, fn) { - if (!HOP(fn, "safe_ids")) return; var marker = fn.safe_ids; + if (marker === undefined) return; if (marker === false) return; if (fn.parent_scope.resolve().may_call_this === return_true) { if (member(fn, tw.fn_visited)) revisit_fn_def(tw, fn); @@ -575,10 +588,10 @@ merge(Compressor.prototype, { walk_fn_def(tw, fn); }); fn_defs.forEach(function(fn) { - delete fn.safe_ids; + fn.safe_ids = undefined; }); - delete scope.fn_defs; - delete scope.may_call_this; + scope.fn_defs = undefined; + scope.may_call_this = undefined; } function push(tw) { @@ -602,12 +615,14 @@ merge(Compressor.prototype, { if (def.single_use == "m") return false; var safe = tw.safe_ids[def.id]; if (safe) { - if (!HOP(tw.safe_ids, def.id)) safe.read = safe.read && safe.read !== tw.safe_ids ? true : tw.safe_ids; + var in_order = HOP(tw.safe_ids, def.id); + if (!in_order) safe.read = safe.read && safe.read !== tw.safe_ids ? true : tw.safe_ids; if (def.fixed == null) { if (is_arguments(def)) return false; if (def.global && def.name == "arguments") return false; tw.loop_ids[def.id] = null; def.fixed = make_node(AST_Undefined, def.orig[0]); + if (in_order) def.safe_ids = undefined; return true; } return !safe.assign || safe.assign === tw.safe_ids; @@ -625,11 +640,11 @@ merge(Compressor.prototype, { if (def.fixed === undefined) return declare || all(def.orig, function(sym) { return !(sym instanceof AST_SymbolLet); }); - if (def.fixed === false) return false; + if (def.fixed === false || def.fixed === 0) return false; var safe = tw.safe_ids[def.id]; if (def.safe_ids) { def.safe_ids[def.id] = false; - delete def.safe_ids; + def.safe_ids = undefined; return def.fixed === null || HOP(tw.safe_ids, def.id) && !safe.read; } if (!HOP(tw.safe_ids, def.id)) { @@ -656,6 +671,16 @@ merge(Compressor.prototype, { return node; } + function replace_ref(ref, fixed) { + return function() { + var node = make_ref(ref, fixed); + var def = ref.definition(); + def.references.push(node); + def.replaced++; + return node; + }; + } + function ref_once(compressor, def) { return compressor.option("unused") && !def.scope.pinned() @@ -690,6 +715,7 @@ merge(Compressor.prototype, { if (depth > 1 && !(value && value.is_constant_expression(scope))) depth = 1; if (!d.escaped.depth || d.escaped.depth > depth) d.escaped.depth = depth; if (d.scope.resolve() !== scope.resolve()) d.escaped.cross_scope = true; + if (d.fixed) d.fixed.escaped = d.escaped; return; } else if (value_in_use(node, parent)) { mark_escaped(tw, d, scope, parent, parent, level + 1, depth); @@ -707,6 +733,7 @@ merge(Compressor.prototype, { if (parent instanceof AST_SimpleStatement) return; if (parent instanceof AST_Unary && !unary_side_effects[parent.operator]) return; d.direct_access = true; + if (d.fixed) d.fixed.direct_access = true; } function mark_assignment_to_arguments(node) { @@ -759,11 +786,16 @@ merge(Compressor.prototype, { node.walk(scanner); }); if (node.rest) { + var fixed_node; if (save) fixed = compressor.option("rests") && function() { var value = save(); - return value instanceof AST_Array ? make_node(AST_Array, node, { - elements: value.elements.slice(node.elements.length), - }) : node; + if (!(value instanceof AST_Array)) return node; + for (var i = 0, len = node.elements.length; i < len; i++) { + if (value.elements[i] instanceof AST_Spread) return node; + } + if (!fixed_node) fixed_node = make_node(AST_Array, node); + fixed_node.elements = value.elements.slice(len); + return fixed_node; }; node.rest.walk(scanner); } @@ -843,11 +875,12 @@ merge(Compressor.prototype, { return arg || make_node(AST_Undefined, iife); }, visit); }); - var rest = fn.rest; + var rest = fn.rest, fixed_node; if (rest) scan_declaration(tw, compressor, rest, compressor.option("rests") && function() { - return fn.rest === rest ? make_node(AST_Array, fn, { - elements: iife.args.slice(fn.argnames.length), - }) : rest; + if (fn.rest !== rest) return rest; + if (!fixed_node) fixed_node = make_node(AST_Array, fn); + fixed_node.elements = iife.args.slice(fn.argnames.length); + return fixed_node; }, visit); walk_lambda(fn, tw); var safe_ids = tw.safe_ids; @@ -879,7 +912,7 @@ merge(Compressor.prototype, { if (left.equivalent_to(right) && !left.has_side_effects(compressor)) { right.walk(tw); walk_prop(left); - node.__drop = true; + node.redundant = true; return true; } if (ld && right instanceof AST_LambdaExpression) { @@ -899,30 +932,22 @@ merge(Compressor.prototype, { case "&&=": case "||=": case "??=": - left.walk(tw); - push(tw); - if (scan) { - right.walk(tw); - walk_assign(); - } else { - mark_assignment_to_arguments(left); - right.walk(tw); - } - pop(tw); - return true; + var lazy = true; default: if (!scan) { mark_assignment_to_arguments(left); - return; + return walk_lazy(); } ld.assignments++; var fixed = ld.fixed; if (is_modified(compressor, tw, node, node, 0)) { ld.fixed = false; - return; + return walk_lazy(); } var safe = safe_to_read(tw, ld); + if (lazy) push(tw); right.walk(tw); + if (lazy) pop(tw); if (safe && !left.in_arg && safe_to_assign(tw, ld)) { push_ref(ld, left); mark(tw, ld); @@ -934,8 +959,9 @@ merge(Compressor.prototype, { right: node.right, }); }; - left.fixed.assigns = !fixed || !fixed.assigns ? [] : fixed.assigns.slice(); + left.fixed.assigns = !fixed || !fixed.assigns ? [ ld.orig[0] ] : fixed.assigns.slice(); left.fixed.assigns.push(node); + left.fixed.to_binary = replace_ref(left, fixed); } else { left.walk(tw); ld.fixed = false; @@ -978,7 +1004,13 @@ merge(Compressor.prototype, { } var d = sym.definition(); d.assignments++; - if (fixed && !modified && !sym.in_arg && safe_to_assign(tw, d)) { + if (!fixed || sym.in_arg || !safe_to_assign(tw, d)) { + walk(); + d.fixed = false; + } else if (modified) { + walk(); + d.fixed = 0; + } else { push_ref(d, sym); mark(tw, d); if (left instanceof AST_Destructured @@ -986,15 +1018,21 @@ merge(Compressor.prototype, { d.single_use = false; } tw.loop_ids[d.id] = tw.in_loop; - mark_escaped(tw, d, sym.scope, node, right, 0, 1); sym.fixed = d.fixed = fixed; sym.fixed.assigns = [ node ]; - } else { - walk(); - d.fixed = false; + mark_escaped(tw, d, sym.scope, node, right, 0, 1); } }); } + + function walk_lazy() { + if (!lazy) return; + left.walk(tw); + push(tw); + right.walk(tw); + pop(tw); + return true; + } }); def(AST_Binary, function(tw) { if (!lazy_op[this.operator]) return; @@ -1021,12 +1059,11 @@ merge(Compressor.prototype, { if (iife) delete exp.reduce_vars; return true; } - if (node.TYPE == "Call" && tw.in_boolean_context()) { - if (exp instanceof AST_SymbolRef) { - exp.definition().bool_fn++; - } else if (exp instanceof AST_Assign && exp.operator == "=" && exp.left instanceof AST_SymbolRef) { - exp.left.definition().bool_fn++; - } + if (node.TYPE == "Call") switch (tw.in_boolean_context()) { + case "d": + var drop = true; + case true: + mark_refs(exp, drop); } exp.walk(tw); var optional = node.optional; @@ -1042,6 +1079,25 @@ merge(Compressor.prototype, { tw.find_parent(AST_Scope).may_call_this(); } return true; + + function mark_refs(node, drop) { + if (node instanceof AST_Assign) { + if (node.operator != "=") return; + mark_refs(node.left, drop); + mark_refs(node.right, drop); + } else if (node instanceof AST_Binary) { + if (!lazy_op[node.operator]) return; + mark_refs(node.left, drop); + mark_refs(node.right, drop); + } else if (node instanceof AST_Conditional) { + mark_refs(node.consequent, drop); + mark_refs(node.alternative, drop); + } else if (node instanceof AST_SymbolRef) { + var def = node.definition(); + def.bool_return++; + if (drop) def.drop_return++; + } + } }); def(AST_Class, function(tw, descend, compressor) { var node = this; @@ -1183,7 +1239,7 @@ merge(Compressor.prototype, { }); def(AST_Lambda, function(tw, descend, compressor) { var fn = this; - if (HOP(fn, "safe_ids") && fn.safe_ids !== tw.safe_ids) return true; + if (!safe_to_visit(tw, fn)) return true; if (!push_uniq(tw.fn_visited, fn)) return true; fn.inlined = false; push(tw); @@ -1198,7 +1254,7 @@ merge(Compressor.prototype, { var def = fn.name.definition(); var parent = tw.parent(); if (parent instanceof AST_ExportDeclaration || parent instanceof AST_ExportDefault) def.single_use = false; - if (HOP(fn, "safe_ids") && fn.safe_ids !== tw.safe_ids) return true; + if (!safe_to_visit(tw, fn)) return true; if (!push_uniq(tw.fn_visited, fn)) return true; fn.inlined = false; push(tw); @@ -1261,7 +1317,7 @@ merge(Compressor.prototype, { if (!safe) return; safe.assign = true; }); - if (d.fixed === false) { + if (d.fixed === false || d.fixed === 0) { var redef = d.redefined(); if (redef && cross_scope(d.scope, this.scope)) redef.single_use = false; } else if (d.fixed === undefined || !safe_to_read(tw, d)) { @@ -1286,7 +1342,7 @@ merge(Compressor.prototype, { if (d.single_use) { d.single_use = "m"; } else { - d.fixed = false; + d.fixed = 0; } } if (d.fixed && tw.loop_ids[d.id] !== tw.in_loop) d.cross_loop = true; @@ -1367,11 +1423,9 @@ merge(Compressor.prototype, { operator: node.operator.slice(0, -1), left: make_node(AST_UnaryPrefix, node, { operator: "+", - expression: make_ref(exp, fixed) + expression: make_ref(exp, fixed), }), - right: make_node(AST_Number, node, { - value: 1 - }) + right: make_node(AST_Number, node, { value: 1 }), }); }; d.fixed.assigns = fixed && fixed.assigns ? fixed.assigns.slice() : []; @@ -1382,10 +1436,11 @@ merge(Compressor.prototype, { exp.fixed = function() { return make_node(AST_UnaryPrefix, node, { operator: "+", - expression: make_ref(exp, fixed) + expression: make_ref(exp, fixed), }); }; exp.fixed.assigns = fixed && fixed.assigns; + exp.fixed.to_prefix = replace_ref(exp, d.fixed); } } else { exp.walk(tw); @@ -1446,8 +1501,8 @@ merge(Compressor.prototype, { function reset_flags(node) { node._squeezed = false; node._optimized = false; - delete node.fixed; - if (node instanceof AST_Scope) delete node._var_names; + if (node instanceof AST_BlockScope) node._var_names = undefined; + if (node instanceof AST_SymbolRef) node.fixed = undefined; } AST_Toplevel.DEFMETHOD("reset_opt_flags", function(compressor) { @@ -1471,14 +1526,19 @@ merge(Compressor.prototype, { AST_Symbol.DEFMETHOD("fixed_value", function() { var fixed = this.definition().fixed; + if (fixed) { + if (this.fixed) fixed = this.fixed; + return (fixed instanceof AST_Node ? fixed : fixed()).tail_node(); + } + fixed = fixed === 0 && this.fixed; if (!fixed) return fixed; - if (this.fixed) fixed = this.fixed; - return fixed instanceof AST_Node ? fixed : fixed(); + var value = (fixed instanceof AST_Node ? fixed : fixed()).tail_node(); + return value.is_constant() && value; }); AST_SymbolRef.DEFMETHOD("is_immutable", function() { var def = this.redef || this.definition(); - return def.orig.length == 1 && def.orig[0] instanceof AST_SymbolLambda; + return (this.in_arg || def.orig.length == 1) && def.orig[0] instanceof AST_SymbolLambda; }); AST_Node.DEFMETHOD("convert_symbol", noop); @@ -1512,6 +1572,12 @@ merge(Compressor.prototype, { AST_SymbolDeclaration.DEFMETHOD("convert_symbol", convert_symbol); AST_SymbolRef.DEFMETHOD("convert_symbol", convert_symbol); + function process_to_assign(ref) { + var def = ref.definition(); + def.assignments++; + def.references.push(ref); + } + function mark_destructured(process, tw) { var marker = new TreeWalker(function(node) { if (node instanceof AST_DefaultValue) { @@ -1613,9 +1679,7 @@ merge(Compressor.prototype, { function make_node_from_constant(val, orig) { switch (typeof val) { case "string": - return make_node(AST_String, orig, { - value: val - }); + return make_node(AST_String, orig, { value: val }); case "number": if (isNaN(val)) return make_node(AST_NaN, orig); if (isFinite(val)) { @@ -1626,7 +1690,7 @@ merge(Compressor.prototype, { } return val < 0 ? make_node(AST_UnaryPrefix, orig, { operator: "-", - expression: make_node(AST_Infinity, orig) + expression: make_node(AST_Infinity, orig), }) : make_node(AST_Infinity, orig); case "boolean": return make_node(val ? AST_True : AST_False, orig); @@ -1634,7 +1698,7 @@ merge(Compressor.prototype, { return make_node(AST_Undefined, orig); default: if (val === null) { - return make_node(AST_Null, orig, { value: null }); + return make_node(AST_Null, orig); } if (val instanceof RegExp) { return make_node(AST_RegExp, orig, { value: val }); @@ -1668,7 +1732,7 @@ merge(Compressor.prototype, { function merge_sequence(array, node) { if (node instanceof AST_Sequence) { - array.push.apply(array, node.expressions); + [].push.apply(array, node.expressions); } else { array.push(node); } @@ -1782,35 +1846,90 @@ merge(Compressor.prototype, { return true; } + // Certain combination of unused name + side effect leads to invalid AST: + // https://github.com/mishoo/UglifyJS/issues/44 + // https://github.com/mishoo/UglifyJS/issues/1838 + // https://github.com/mishoo/UglifyJS/issues/3371 + // We fix it at this stage by moving the `var` outside the `for`. + function patch_for_init(node, in_list) { + var block; + if (node.init instanceof AST_BlockStatement) { + block = node.init; + node.init = block.body.pop(); + block.body.push(node); + } + if (node.init instanceof AST_Defun) { + if (!block) block = make_node(AST_BlockStatement, node, { body: [ node ] }); + block.body.splice(-1, 0, node.init); + node.init = null; + } else if (node.init instanceof AST_SimpleStatement) { + node.init = node.init.body; + } else if (is_empty(node.init)) { + node.init = null; + } + if (!block) return; + return in_list ? List.splice(block.body) : block; + } + function tighten_body(statements, compressor) { - var in_loop, in_try, scope; + var in_lambda = last_of(compressor, function(node) { + return node instanceof AST_Lambda; + }); + var block_scope, in_loop, in_try, scope; find_loop_scope_try(); - var CHANGED, max_iter = 10; + var changed, last_changed, max_iter = 10; do { - CHANGED = false; - eliminate_spurious_blocks(statements); + last_changed = changed; + changed = 0; + if (eliminate_spurious_blocks(statements)) changed = 1; + if (!changed && last_changed == 1) break; if (compressor.option("dead_code")) { - eliminate_dead_code(statements, compressor); + if (eliminate_dead_code(statements, compressor)) changed = 2; + if (!changed && last_changed == 2) break; } if (compressor.option("if_return")) { - handle_if_return(statements, compressor); + if (handle_if_return(statements, compressor)) changed = 3; + if (!changed && last_changed == 3) break; + } + if (compressor.option("awaits") && compressor.option("side_effects")) { + if (trim_awaits(statements, compressor)) changed = 4; + if (!changed && last_changed == 4) break; + } + if (compressor.option("inline") >= 4) { + if (inline_iife(statements, compressor)) changed = 5; + if (!changed && last_changed == 5) break; } if (compressor.sequences_limit > 0) { - sequencesize(statements, compressor); - sequencesize_2(statements, compressor); + if (sequencesize(statements, compressor)) changed = 6; + if (!changed && last_changed == 6) break; + if (sequencesize_2(statements, compressor)) changed = 7; + if (!changed && last_changed == 7) break; } if (compressor.option("join_vars")) { - join_consecutive_vars(statements); + if (join_consecutive_vars(statements)) changed = 8; + if (!changed && last_changed == 8) break; } if (compressor.option("collapse_vars")) { - collapse(statements, compressor); + if (collapse(statements, compressor)) changed = 9; } - } while (CHANGED && max_iter-- > 0); + } while (changed && max_iter-- > 0); return statements; + function last_of(compressor, predicate) { + var block = compressor.self(), stat, level = 0; + do { + do { + if (predicate(block)) return true; + block = compressor.parent(level++); + } while (block instanceof AST_If && (stat = block)); + } while ((block instanceof AST_BlockStatement || block instanceof AST_Scope) + && is_last_statement(block.body, stat)); + } + function find_loop_scope_try() { var node = compressor.self(), level = 0; do { + if (!block_scope && node.variables) block_scope = node; if (node instanceof AST_Catch) { if (compressor.parent(level).bfinally) { if (!in_try) in_try = {}; @@ -1841,11 +1960,12 @@ merge(Compressor.prototype, { // Will not attempt to collapse assignments into or past code blocks // which are not sequentially executed, e.g. loops and conditionals. function collapse(statements, compressor) { - if (scope.pinned()) return statements; + if (scope.pinned()) return; var args; - var assignments = Object.create(null); + var assignments = new Dictionary(); var candidates = []; - var declare_only = Object.create(null); + var changed = false; + var declare_only = new Dictionary(); var force_single; var stat_index = statements.length; var scanner = new TreeTransformer(function(node, descend) { @@ -1860,16 +1980,52 @@ merge(Compressor.prototype, { if (stop_after === node) abort = true; return node; } - // Stop immediately if these node types are encountered var parent = scanner.parent(); - if (should_stop(node, parent)) { - abort = true; - return node; - } // Stop only if candidate is found within conditional branches if (!stop_if_hit && in_conditional(node, parent)) { stop_if_hit = parent; } + // Cascade compound assignments + if (compound && scan_lhs && can_replace && !stop_if_hit + && node instanceof AST_Assign && node.operator != "=" && node.left.equivalent_to(lhs)) { + replaced++; + changed = true; + AST_Node.info("Cascading {node} [{file}:{line},{col}]", { + node: node, + file: node.start.file, + line: node.start.line, + col: node.start.col, + }); + can_replace = false; + lvalues = get_lvalues(lhs); + node.right.transform(scanner); + clear_write_only(candidate); + var folded; + if (abort) { + folded = candidate; + } else { + abort = true; + folded = make_node(AST_Binary, candidate, { + operator: compound, + left: lhs.fixed && lhs.definition().fixed ? lhs.fixed.to_binary() : lhs, + right: rvalue, + }); + } + return make_node(AST_Assign, node, { + operator: "=", + left: node.left, + right: make_node(AST_Binary, node, { + operator: node.operator.slice(0, -1), + left: folded, + right: node.right, + }), + }); + } + // Stop immediately if these node types are encountered + if (should_stop(node, parent)) { + abort = true; + return node; + } // Skip transient nodes caused by single-use variable replacement if (node.single_use && parent instanceof AST_VarDef && parent.value === node) return node; // Replace variable with assignment when found @@ -1891,45 +2047,59 @@ merge(Compressor.prototype, { } else { replaced++; } - CHANGED = abort = true; + changed = abort = true; AST_Node.info("Collapsing {node} [{file}:{line},{col}]", { node: node, file: node.start.file, line: node.start.line, col: node.start.col, }); - if (candidate.TYPE == "Binary") return make_node(AST_Assign, candidate, { - operator: "=", - left: candidate.right.left, - right: make_node(AST_Conditional, candidate, { - condition: candidate.operator == "&&" ? candidate.left : candidate.left.negate(compressor), - consequent: candidate.right.right, - alternative: node, - }), - }); - if (candidate instanceof AST_UnaryPostfix) { - if (lhs instanceof AST_SymbolRef) lhs.definition().fixed = false; - return make_node(AST_UnaryPrefix, candidate, candidate); + if (candidate.TYPE == "Binary") { + update_symbols(candidate, node); + return make_node(AST_Assign, candidate, { + operator: "=", + left: candidate.right.left, + right: candidate.operator == "&&" ? make_node(AST_Conditional, candidate, { + condition: candidate.left, + consequent: candidate.right.right, + alternative: node, + }) : make_node(AST_Conditional, candidate, { + condition: candidate.left, + consequent: node, + alternative: candidate.right.right, + }), + }); } + if (candidate instanceof AST_UnaryPostfix) return make_node(AST_UnaryPrefix, candidate, { + operator: candidate.operator, + expression: lhs.fixed && lhs.definition().fixed ? lhs.fixed.to_prefix() : lhs, + }); + if (candidate instanceof AST_UnaryPrefix) { + clear_write_only(candidate); + return candidate; + } + update_symbols(rvalue, node); if (candidate instanceof AST_VarDef) { var def = candidate.name.definition(); if (def.references.length - def.replaced == 1 && !compressor.exposed(def)) { def.replaced++; - return maintain_this_binding(compressor, parent, node, candidate.value); + return maintain_this_binding(compressor, parent, node, rvalue); } return make_node(AST_Assign, candidate, { operator: "=", - left: make_node(AST_SymbolRef, candidate.name, candidate.name), - right: candidate.value, + left: node, + right: rvalue, }); } - var assign = candidate; - while (assign.write_only) { - assign.write_only = false; - if (!(assign instanceof AST_Assign)) break; - assign = assign.right; - } - return candidate; + clear_write_only(rvalue); + var assign = candidate.clone(); + assign.right = rvalue; + return assign; + } + // Stop signals related to AST_SymbolRef + if (should_stop_ref(node, parent)) { + abort = true; + return node; } // These node types have child nodes that execute sequentially, // but are otherwise not safe to scan into or beyond them. @@ -1966,7 +2136,7 @@ merge(Compressor.prototype, { if (node instanceof AST_BlockScope && !(node instanceof AST_Scope) && !(node.variables && node.variables.all(function(def) { - return !lvalues.has(def.name); + return !enclosed.has(def.name) && !lvalues.has(def.name); }))) { var replace = can_replace; can_replace = false; @@ -1992,7 +2162,8 @@ merge(Compressor.prototype, { var parent = multi_replacer.parent(); if (parent instanceof AST_Sequence && parent.tail_node() !== node) { value_def.replaced++; - return List.skip; + if (rvalue === rhs_value) return List.skip; + return make_sequence(rhs_value, rhs_value.expressions.slice(0, -1)); } return rvalue; case 1: @@ -2010,6 +2181,12 @@ merge(Compressor.prototype, { if (node instanceof AST_SymbolRef && node.definition() === def) { if (is_lhs(node, multi_replacer.parent())) return node; if (!--replaced) abort = true; + AST_Node.info("Replacing {node} [{file}:{line},{col}]", { + node: node, + file: node.start.file, + line: node.start.line, + col: node.start.col, + }); var ref = rvalue.clone(); ref.scope = node.scope; ref.reference(); @@ -2026,7 +2203,9 @@ merge(Compressor.prototype, { } // Skip (non-executed) functions and (leading) default case in switch statements if (node instanceof AST_Default || node instanceof AST_Scope) return node; - }, patch_sequence); + }, function(node) { + return patch_sequence(node, multi_replacer); + }); while (--stat_index >= 0) { // Treat parameters as collapsible in IIFE, i.e. // function(a, b){ ... }(x()); @@ -2048,9 +2227,11 @@ merge(Compressor.prototype, { var stop_if_hit = null; var lhs = get_lhs(candidate); var side_effects = lhs && lhs.has_side_effects(compressor); - var scan_lhs = lhs && !side_effects && !is_lhs_read_only(lhs, compressor); + var scan_lhs = lhs && (!side_effects || lhs instanceof AST_SymbolRef) + && !is_lhs_read_only(lhs, compressor); var scan_rhs = foldable(candidate); if (!scan_lhs && !scan_rhs) continue; + var compound = candidate instanceof AST_Assign && candidate.operator.slice(0, -1); var funarg = candidate.name instanceof AST_SymbolFunarg; var may_throw = return_false; if (candidate.may_throw(compressor)) { @@ -2062,10 +2243,12 @@ merge(Compressor.prototype, { var read_toplevel = false; var modify_toplevel = false; // Locate symbols which may execute code outside of scanning range + var enclosed = new Dictionary(); var well_defined = true; var lvalues = get_lvalues(candidate); var lhs_local = is_lhs_local(lhs); - var rvalue = get_rvalue(candidate); + var rhs_value = get_rvalue(candidate); + var rvalue = !compound && rhs_value instanceof AST_Sequence ? rhs_value.tail_node() : rhs_value; if (!side_effects) side_effects = value_has_side_effects(); var check_destructured = in_try || !lhs_local ? function(node) { return node instanceof AST_Destructured; @@ -2104,11 +2287,12 @@ merge(Compressor.prototype, { && !compressor.exposed(def); value_def.last_ref = false; value_def.single_use = false; - CHANGED = true; + changed = true; } - if (replaced && !remove_candidate(candidate)) statements.splice(stat_index, 1); + if (replaced) remove_candidate(candidate); } } + return changed; function signal_abort(node) { if (abort) return node; @@ -2178,25 +2362,27 @@ merge(Compressor.prototype, { if (node instanceof AST_DestructuredKeyVal) return node.key instanceof AST_Node; if (node instanceof AST_DWLoop) return true; if (node instanceof AST_LoopControl) return true; - if (node instanceof AST_SymbolRef) { - if (node.is_declared(compressor)) { - if (node.fixed_value()) return false; - if (can_drop_symbol(node)) { - return !(parent instanceof AST_PropAccess && parent.expression === node) - && is_arguments(node.definition()); - } - } else if (is_direct_assignment(node, parent)) { - return false; - } - if (!replace_all) return true; - scan_rhs = false; - return false; - } if (node instanceof AST_Try) return true; if (node instanceof AST_With) return true; return false; } + function should_stop_ref(node, parent) { + if (!(node instanceof AST_SymbolRef)) return false; + if (node.is_declared(compressor)) { + if (node.fixed_value()) return false; + if (can_drop_symbol(node)) { + return !(parent instanceof AST_PropAccess && parent.expression === node) + && is_arguments(node.definition()); + } + } else if (is_direct_assignment(node, parent)) { + return false; + } + if (!replace_all) return true; + scan_rhs = false; + return false; + } + function in_conditional(node, parent) { if (parent instanceof AST_Assign) return parent.left !== node && lazy_op[parent.operator.slice(0, -1)]; if (parent instanceof AST_Binary) return parent.left !== node && lazy_op[parent.operator]; @@ -2246,7 +2432,7 @@ merge(Compressor.prototype, { stop_if_hit = if_hit; stop_after = after; can_replace = replace; - delete fn.collapse_scanning; + fn.collapse_scanning = false; if (!abort) return false; abort = false; return true; @@ -2374,7 +2560,7 @@ merge(Compressor.prototype, { }); args = iife.args.slice(); var len = args.length; - var names = Object.create(null); + var names = new Dictionary(); for (var i = fn.argnames.length; --i >= 0;) { var sym = fn.argnames[i]; var arg = args[i]; @@ -2389,9 +2575,9 @@ merge(Compressor.prototype, { candidates.length = 0; break; } - if (sym.name in names) continue; - names[sym.name] = true; - if (value) arg = !arg || is_undefined(arg) ? value : null; + if (names.has(sym.name)) continue; + names.set(sym.name, true); + if (value) arg = is_undefined(arg) ? value : null; if (!arg && !value) { arg = make_node(AST_Undefined, sym).transform(compressor); } else if (arg instanceof AST_Lambda && arg.pinned()) { @@ -2423,7 +2609,7 @@ merge(Compressor.prototype, { extract_candidates(lhs); extract_candidates(expr.right); if (lhs instanceof AST_SymbolRef && expr.operator == "=") { - assignments[lhs.name] = (assignments[lhs.name] || 0) + 1; + assignments.set(lhs.name, (assignments.get(lhs.name) || 0) + 1); } } else if (expr instanceof AST_Await) { extract_candidates(expr.expression, unused); @@ -2515,7 +2701,7 @@ merge(Compressor.prototype, { candidates.push(hit_stack.slice()); } } else { - declare_only[expr.name.name] = (declare_only[expr.name.name] || 0) + 1; + declare_only.set(expr.name.name, (declare_only.get(expr.name.name) || 0) + 1); } } if (expr.value) extract_candidates(expr.value); @@ -2710,6 +2896,7 @@ merge(Compressor.prototype, { return; } if (remaining < 1) return; + rhs = rhs.tail_node(); var value = rhs instanceof AST_Assign && rhs.operator == "=" ? rhs.left : rhs; if (!(value instanceof AST_SymbolRef)) return; var def = value.definition(); @@ -2731,13 +2918,12 @@ merge(Compressor.prototype, { } function remaining_refs(def) { - return def.references.length - def.replaced - (assignments[def.name] || 0); + return def.references.length - def.replaced - (assignments.get(def.name) || 0); } function get_lhs(expr) { if (expr instanceof AST_Assign) { var lhs = expr.left; - if (expr.operator != "=") return lhs; if (!(lhs instanceof AST_SymbolRef)) return lhs; var def = lhs.definition(); if (scope.uses_arguments && is_funarg(def)) return lhs; @@ -2752,7 +2938,7 @@ merge(Compressor.prototype, { assign_pos = 0; } } - mangleable_var(expr.right); + if (expr.operator == "=") mangleable_var(expr.right); return lhs; } if (expr instanceof AST_Binary) return expr.right.left; @@ -2763,7 +2949,7 @@ merge(Compressor.prototype, { if (def.const_redefs) return; if (!member(lhs, def.orig)) return; if (scope.uses_arguments && is_funarg(def)) return; - var declared = def.orig.length - def.eliminated - (declare_only[def.name] || 0); + var declared = def.orig.length - def.eliminated - (declare_only.get(def.name) || 0); remaining = remaining_refs(def); if (def.fixed) remaining = Math.min(remaining, def.references.filter(function(ref) { if (!ref.fixed) return true; @@ -2855,6 +3041,22 @@ merge(Compressor.prototype, { }; } + function clear_write_only(assign) { + while (assign.write_only) { + assign.write_only = false; + if (!(assign instanceof AST_Assign)) break; + assign = assign.right; + } + } + + function update_symbols(value, node) { + var scope = node.scope || find_scope(scanner) || block_scope; + value.walk(new TreeWalker(function(node) { + if (node instanceof AST_BlockScope) return true; + if (node instanceof AST_Symbol) node.scope = scope; + })); + } + function may_be_global(node) { if (node instanceof AST_SymbolRef) { node = node.fixed_value(); @@ -2879,8 +3081,9 @@ merge(Compressor.prototype, { if (!value) { value = node; var def = node.definition(); + var escaped = node.fixed && node.fixed.escaped || def.escaped; if (!def.undeclared - && (def.assignments || !def.escaped || def.escaped.cross_scope) + && (def.assignments || !escaped || escaped.cross_scope) && (has_escaped(def, node.scope, node, tw.parent()) || !same_scope(def))) { well_defined = false; } @@ -2888,8 +3091,36 @@ merge(Compressor.prototype, { } else if (node instanceof AST_ObjectIdentity) { value = node; } - if (value) lvalues.add(node.name, is_modified(compressor, tw, node, value, 0)); - if (find_arguments && node instanceof AST_Sub) { + if (value) { + lvalues.add(node.name, is_modified(compressor, tw, node, value, 0)); + } else if (node instanceof AST_Lambda) { + for (var level = 0, parent, child = node; parent = tw.parent(level++); child = parent) { + if (parent instanceof AST_Assign) { + if (parent.left === child) break; + if (parent.operator == "=") continue; + if (lazy_op[parent.operator.slice(0, -1)]) continue; + break; + } + if (parent instanceof AST_Binary) { + if (lazy_op[parent.operator]) continue; + break; + } + if (parent instanceof AST_Call) return; + if (parent instanceof AST_Scope) return; + if (parent instanceof AST_Sequence) { + if (parent.tail_node() === child) continue; + break; + } + if (parent instanceof AST_Template) { + if (parent.tag) return; + break; + } + } + node.enclosed.forEach(function(def) { + if (def.scope !== node) enclosed.set(def.name, true); + }); + return true; + } else if (find_arguments && node instanceof AST_Sub) { scope.each_argname(function(argname) { if (!compressor.option("reduce_vars") || argname.definition().assignments) { if (!argname.definition().fixed) well_defined = false; @@ -2918,24 +3149,18 @@ merge(Compressor.prototype, { } function remove_candidate(expr) { + var value = rvalue === rhs_value ? null : make_sequence(rhs_value, rhs_value.expressions.slice(0, -1)); var index = expr.name_index; if (index >= 0) { - var argname = scope.argnames[index]; + var args, argname = scope.argnames[index]; if (argname instanceof AST_DefaultValue) { - argname.value = make_node(AST_Number, argname, { - value: 0 - }); - argname.name.definition().fixed = false; - } else { - var args = compressor.parent().args; - if (args[index]) { - args[index] = make_node(AST_Number, args[index], { - value: 0 - }); - argname.definition().fixed = false; - } + scope.argnames[index] = argname = argname.clone(); + argname.value = value || make_node(AST_Number, argname, { value: 0 }); + } else if ((args = compressor.parent().args)[index]) { + scope.argnames[index] = argname.clone(); + args[index] = value || make_node(AST_Number, args[index], { value: 0 }); } - return true; + return; } var end = hit_stack.length - 1; if (hit_stack[end - 1].body === hit_stack[end]) end--; @@ -2946,35 +3171,62 @@ merge(Compressor.prototype, { if (hit_index <= end) return handle_custom_scan_order(node, tt); hit = true; if (node instanceof AST_VarDef) { - declare_only[node.name.name] = (declare_only[node.name.name] || 0) + 1; + declare_only.set(node.name.name, (declare_only.get(node.name.name) || 0) + 1); if (value_def) value_def.replaced++; node = node.clone(); node.value = null; - return node; + return value ? List.splice([ value, node ]) : node; } - return in_list ? List.skip : null; - }, patch_sequence); + if (!value) return in_list ? List.skip : null; + return is_statement(node) ? make_node(AST_SimpleStatement, value, { body: value }) : value; + }, function(node, in_list) { + if (node instanceof AST_Definitions) { + var body = [], defns = node.definitions; + for (var index = 0, pos = 0; index < defns.length; index++) { + var defn = defns[index]; + if (defn instanceof AST_VarDef) continue; + flush(); + pos = index + 1; + body.push(make_node(AST_SimpleStatement, defn, { body: defn })); + } + if (pos == 0) return; + flush(); + if (body.length == 1) return body[0]; + return in_list ? List.splice(body) : make_node(AST_BlockStatement, node, { body: body }); + } + if (node instanceof AST_For) return patch_for_init(node, in_list); + return patch_sequence(node, this); + + function flush() { + if (pos < index) { + var cropped = node.clone(); + cropped.definitions = defns.slice(pos, index); + body.push(cropped); + } + } + }); abort = false; hit = false; hit_index = 0; - return statements[stat_index].transform(tt); + if (!(statements[stat_index] = statements[stat_index].transform(tt))) statements.splice(stat_index, 1); } - function patch_sequence(node) { + function patch_sequence(node, tt) { if (node instanceof AST_Sequence) switch (node.expressions.length) { case 0: return null; - case 1: return maintain_this_binding(compressor, this.parent(), node, node.expressions[0]); + case 1: return maintain_this_binding(compressor, tt.parent(), node, node.expressions[0]); } } function is_lhs_local(lhs) { var sym = root_expr(lhs); - return sym instanceof AST_SymbolRef - && sym.definition().scope.resolve() === scope - && !(in_loop - && (lvalues.has(sym.name) && lvalues.get(sym.name)[0] !== lhs - || candidate instanceof AST_Unary - || candidate instanceof AST_Assign && candidate.operator != "=")); + if (!(sym instanceof AST_SymbolRef)) return false; + if (sym.definition().scope.resolve() !== scope) return false; + if (!in_loop) return true; + if (compound) return false; + if (candidate instanceof AST_Unary) return false; + var lvalue = lvalues.get(sym.name); + return !lvalue || lvalue[0] === lhs; } function value_has_side_effects() { @@ -2996,7 +3248,10 @@ merge(Compressor.prototype, { return false; } var def = lhs.definition(); - return def.references.length - def.replaced == referenced; + if (def.references.length - def.replaced == referenced) return true; + return def.fixed && lhs.fixed && def.references.filter(function(ref) { + return ref.fixed === lhs.fixed; + }).length == referenced; } function symbol_in_lvalues(sym, parent) { @@ -3032,12 +3287,12 @@ merge(Compressor.prototype, { } function eliminate_spurious_blocks(statements) { - var seen_dirs = []; + var changed = false, seen_dirs = []; for (var i = 0; i < statements.length;) { var stat = statements[i]; if (stat instanceof AST_BlockStatement) { if (all(stat.body, safe_to_trim)) { - CHANGED = true; + changed = true; eliminate_spurious_blocks(stat.body); [].splice.apply(statements, [i, 1].concat(stat.body)); i += stat.body.length; @@ -3046,28 +3301,28 @@ merge(Compressor.prototype, { } if (stat instanceof AST_Directive) { if (member(stat.value, seen_dirs)) { - CHANGED = true; + changed = true; statements.splice(i, 1); continue; } seen_dirs.push(stat.value); } if (stat instanceof AST_EmptyStatement) { - CHANGED = true; + changed = true; statements.splice(i, 1); continue; } i++; } + return changed; } function handle_if_return(statements, compressor) { - var self = compressor.self(); + var changed = false; var parent = compressor.parent(); - var in_lambda = last_of(function(node) { - return node instanceof AST_Lambda; - }); - var in_iife = in_lambda && parent && parent.TYPE == "Call"; + var self = compressor.self(); + var in_iife = in_lambda && parent && parent.TYPE == "Call" && parent.expression === self; + var chain_if_returns = in_lambda && compressor.option("conditionals") && compressor.option("sequences"); var multiple_if_returns = has_multiple_if_returns(statements); for (var i = statements.length; --i >= 0;) { var stat = statements[i]; @@ -3076,13 +3331,13 @@ merge(Compressor.prototype, { if (in_lambda && !next && stat instanceof AST_Return) { if (!stat.value) { - CHANGED = true; + changed = true; statements.splice(i, 1); continue; } var tail = stat.value.tail_node(); if (tail instanceof AST_UnaryPrefix && tail.operator == "void") { - CHANGED = true; + changed = true; var body; if (tail === stat.value) { body = tail.expression; @@ -3090,9 +3345,7 @@ merge(Compressor.prototype, { body = stat.value.clone(); body.expressions[body.length - 1] = tail.expression; } - statements[i] = make_node(AST_SimpleStatement, stat, { - body: body, - }); + statements[i] = make_node(AST_SimpleStatement, stat, { body: body }); continue; } } @@ -3101,27 +3354,26 @@ merge(Compressor.prototype, { var ab = aborts(stat.body); if (can_merge_flow(ab)) { if (ab.label) remove(ab.label.thedef.references, ab); - CHANGED = true; + changed = true; stat = stat.clone(); - stat.condition = stat.condition.negate(compressor); - var body = as_statement_array_with_return(stat.body, ab); stat.body = make_node(AST_BlockStatement, stat, { - body: as_statement_array(stat.alternative).concat(extract_functions()) + body: as_statement_array_with_return(stat.body, ab), }); stat.alternative = make_node(AST_BlockStatement, stat, { - body: body + body: as_statement_array(stat.alternative).concat(extract_functions()), }); statements[i] = stat; statements[i] = stat.transform(compressor); continue; } - if (ab && !stat.alternative && stat.body instanceof AST_BlockStatement && next instanceof AST_Jump) { - var negated = stat.condition.negate(compressor); - if (negated.print_to_string().length <= stat.condition.print_to_string().length) { - CHANGED = true; + if (ab && !stat.alternative && next instanceof AST_Jump) { + var cond = stat.condition; + cond = best_of_expression(cond, cond.negate(compressor), stat.body instanceof AST_BlockStatement); + if (cond !== stat.condition) { + changed = true; stat = stat.clone(); - stat.condition = negated; + stat.condition = cond; statements[j] = stat.body; stat.body = next; statements[i] = stat; @@ -3133,14 +3385,13 @@ merge(Compressor.prototype, { var alt = aborts(stat.alternative); if (can_merge_flow(alt)) { if (alt.label) remove(alt.label.thedef.references, alt); - CHANGED = true; + changed = true; stat = stat.clone(); stat.body = make_node(AST_BlockStatement, stat.body, { - body: as_statement_array(stat.body).concat(extract_functions()) + body: as_statement_array(stat.body).concat(extract_functions()), }); - var body = as_statement_array_with_return(stat.alternative, alt); stat.alternative = make_node(AST_BlockStatement, stat.alternative, { - body: body + body: as_statement_array_with_return(stat.alternative, alt), }); statements[i] = stat; statements[i] = stat.transform(compressor); @@ -3149,14 +3400,12 @@ merge(Compressor.prototype, { if (compressor.option("typeofs")) { if (ab && !alt) { - mark_locally_defined(stat.condition, null, make_node(AST_BlockStatement, self, { - body: statements.slice(i + 1) - })); + var stats = make_node(AST_BlockStatement, self, { body: statements.slice(i + 1) }); + mark_locally_defined(stat.condition, null, stats); } if (!ab && alt) { - mark_locally_defined(stat.condition, make_node(AST_BlockStatement, self, { - body: statements.slice(i + 1) - })); + var stats = make_node(AST_BlockStatement, self, { body: statements.slice(i + 1) }); + mark_locally_defined(stat.condition, stats); } } } @@ -3165,20 +3414,9 @@ merge(Compressor.prototype, { var value = stat.body.value; var in_bool = stat.body.in_bool || next instanceof AST_Return && next.in_bool; //--- - // pretty silly case, but: - // if (foo()) return; return; ---> foo(); return; - if (!value && !stat.alternative - && (in_lambda && !next || next instanceof AST_Return && !next.value)) { - CHANGED = true; - statements[i] = make_node(AST_SimpleStatement, stat.condition, { - body: stat.condition - }); - continue; - } - //--- // if (foo()) return x; return y; ---> return foo() ? x : y; if (!stat.alternative && next instanceof AST_Return) { - CHANGED = true; + changed = true; stat = stat.clone(); stat.alternative = next; statements.splice(i, 1, stat.transform(compressor)); @@ -3188,11 +3426,9 @@ merge(Compressor.prototype, { //--- // if (foo()) return x; [ return ; ] ---> return foo() ? x : undefined; if (!stat.alternative && !next && in_lambda && (in_bool || value && multiple_if_returns)) { - CHANGED = true; + changed = true; stat = stat.clone(); - stat.alternative = make_node(AST_Return, stat, { - value: null - }); + stat.alternative = make_node(AST_Return, stat, { value: null }); statements.splice(i, 1, stat.transform(compressor)); continue; } @@ -3202,26 +3438,32 @@ merge(Compressor.prototype, { // if sequences is not enabled, this can lead to an endless loop (issue #866). // however, with sequences on this helps producing slightly better output for // the example code. - var prev = statements[prev_index(i)]; - if (compressor.option("sequences") && in_lambda && !stat.alternative - && (!prev && in_iife || prev instanceof AST_If && prev.body instanceof AST_Return) + var prev, prev_stat; + if (chain_if_returns && !stat.alternative + && (!(prev_stat = statements[prev = prev_index(i)]) && in_iife + || prev_stat instanceof AST_If && prev_stat.body instanceof AST_Return) && next_index(j) == statements.length && next instanceof AST_SimpleStatement) { - CHANGED = true; + changed = true; + var exprs = []; + var args = prev_stat ? trim_defns(prev, exprs) : [ i, 1 ]; stat = stat.clone(); + exprs.push(stat.condition); + stat.condition = make_sequence(stat, exprs); stat.alternative = make_node(AST_BlockStatement, next, { body: [ next, - make_node(AST_Return, next, { - value: null - }) - ] + make_node(AST_Return, next, { value: null }), + ], }); - statements.splice(i, 1, stat.transform(compressor)); + args.push(stat.transform(compressor)); statements.splice(j, 1); + [].splice.apply(statements, args); + i = prev + 1; continue; } } } + return changed; function has_multiple_if_returns(statements) { var n = 0; @@ -3234,29 +3476,14 @@ merge(Compressor.prototype, { return false; } - function is_return_void(value) { - return !value || value instanceof AST_UnaryPrefix && value.operator == "void"; - } - - function last_of(predicate) { - var block = self, stat, level = 0; - do { - do { - if (predicate(block)) return true; - block = compressor.parent(level++); - } while (block instanceof AST_If && (stat = block)); - } while ((block instanceof AST_BlockStatement || block instanceof AST_Scope) - && is_last_statement(block.body, stat)); - } - function match_target(target) { - return last_of(function(node) { + return last_of(compressor, function(node) { return node === target; }); } function can_drop_abort(ab) { - if (ab instanceof AST_Return) return in_lambda && is_return_void(ab.value); + if (ab instanceof AST_Return) return in_lambda && is_undefined(ab.value); if (!(ab instanceof AST_LoopControl)) return false; var lct = compressor.loopcontrol_target(ab); if (ab instanceof AST_Continue) return match_target(loop_body(lct)); @@ -3303,9 +3530,7 @@ merge(Compressor.prototype, { block = last.body; } block.pop(); - if (ab.value) block.push(make_node(AST_SimpleStatement, ab.value, { - body: ab.value.expression - })); + if (ab.value) block.push(make_node(AST_SimpleStatement, ab.value, { body: ab.value })); return body; } @@ -3318,10 +3543,29 @@ merge(Compressor.prototype, { function prev_index(i) { for (var j = i; --j >= 0;) { - if (!is_declaration(statements[j])) break; + if (!(statements[j] instanceof AST_Var)) break; } return j; } + + function trim_defns(j, exprs) { + var args = [ j + 1, i - j ]; + var var_defs = []; + while (++j < i) { + var stat = statements[j]; + stat.remove_initializers(compressor, var_defs); + stat.definitions.forEach(function(var_def) { + if (!var_def.value) return; + exprs.push(make_node(AST_Assign, var_def, { + operator: "=", + left: var_def.name.convert_symbol(AST_SymbolRef, process_to_assign), + right: var_def.value, + })); + }); + } + if (var_defs.length > 0) args.push(make_node(AST_Var, stat, { definitions: var_defs })); + return args; + } } function eliminate_dead_code(statements, compressor) { @@ -3331,14 +3575,11 @@ merge(Compressor.prototype, { var stat = statements[i]; if (stat instanceof AST_LoopControl) { var lct = compressor.loopcontrol_target(stat); - if (stat instanceof AST_Break - && !(lct instanceof AST_IterationStatement) - && loop_body(lct) === self - || stat instanceof AST_Continue - && loop_body(lct) === self) { - if (stat.label) remove(stat.label.thedef.references, stat); - } else { + if (loop_body(lct) !== self + || stat instanceof AST_Break && lct instanceof AST_IterationStatement) { statements[n++] = stat; + } else if (stat.label) { + remove(stat.label.thedef.references, stat); } } else { statements[n++] = stat; @@ -3349,10 +3590,51 @@ merge(Compressor.prototype, { } } statements.length = n; - CHANGED = n != len; if (has_quit) has_quit.forEach(function(stat) { extract_declarations_from_unreachable_code(compressor, stat, statements); }); + return statements.length != len; + } + + function trim_awaits(statements, compressor) { + if (!in_lambda || in_try && in_try.bfinally) return; + var changed = false; + for (var index = statements.length; --index >= 0;) { + var stat = statements[index]; + if (!(stat instanceof AST_SimpleStatement)) break; + var node = stat.body; + if (!(node instanceof AST_Await)) break; + var exp = node.expression; + if (!is_primitive(compressor, exp)) break; + changed = true; + exp = exp.drop_side_effect_free(compressor, true); + if (exp) { + stat.body = exp; + break; + } + } + statements.length = index + 1; + return changed; + } + + function inline_iife(statements, compressor) { + var changed = false; + var index = statements.length - 1; + if (in_lambda && index >= 0) { + var inlined = statements[index].try_inline(compressor, block_scope); + if (inlined) { + statements[index--] = inlined; + changed = true; + } + } + var loop = in_loop && in_try && in_try.bfinally ? "try" : in_loop; + for (; index >= 0; index--) { + var inlined = statements[index].try_inline(compressor, block_scope, true, loop); + if (!inlined) continue; + statements[index] = inlined; + changed = true; + } + return changed; } function sequencesize(statements, compressor) { @@ -3368,9 +3650,7 @@ merge(Compressor.prototype, { var stat = statements[i]; if (stat instanceof AST_SimpleStatement) { if (seq.length >= compressor.sequences_limit) push_seq(); - var body = stat.body; - if (seq.length > 0) body = body.drop_side_effect_free(compressor); - if (body) merge_sequence(seq, body); + merge_sequence(seq, stat.body); } else if (is_declaration(stat)) { statements[n++] = stat; } else { @@ -3380,7 +3660,7 @@ merge(Compressor.prototype, { } push_seq(); statements.length = n; - if (n != len) CHANGED = true; + return n != len; } function to_simple_statement(block, decls) { @@ -3400,13 +3680,7 @@ merge(Compressor.prototype, { } function sequencesize_2(statements, compressor) { - function cons_seq(right) { - n--; - CHANGED = true; - var left = prev.body; - return make_sequence(left, [ left, right ]); - } - var n = 0, prev; + var changed = false, n = 0, prev; for (var i = 0; i < statements.length; i++) { var stat = statements[i]; if (prev) { @@ -3429,7 +3703,7 @@ merge(Compressor.prototype, { else { stat.init = prev.body; n--; - CHANGED = true; + changed = true; } } } @@ -3459,7 +3733,7 @@ merge(Compressor.prototype, { i += len; n += len + 1; prev = null; - CHANGED = true; + changed = true; continue; } } @@ -3467,6 +3741,14 @@ merge(Compressor.prototype, { prev = stat instanceof AST_SimpleStatement ? stat : null; } statements.length = n; + return changed; + + function cons_seq(right) { + n--; + changed = true; + var left = prev.body; + return make_sequence(left, [ left, right ]); + } } function extract_exprs(body) { @@ -3477,19 +3759,30 @@ merge(Compressor.prototype, { function join_assigns(defn, body, keep) { var exprs = extract_exprs(body); if (!exprs) return; + keep = keep || 0; var trimmed = false; - for (var i = exprs.length - 1; --i >= 0;) { + for (var i = exprs.length - keep; --i >= 0;) { var expr = exprs[i]; - if (!(expr instanceof AST_Assign)) continue; - if (expr.operator != "=") continue; - if (!(expr.left instanceof AST_SymbolRef)) continue; - var tail = exprs.slice(i + 1); + if (!can_trim(expr)) continue; + var tail; + if (expr.left instanceof AST_SymbolRef) { + tail = exprs.slice(i + 1); + } else if (expr.left instanceof AST_PropAccess && can_trim(expr.left.expression)) { + tail = exprs.slice(i + 1); + var flattened = expr.clone(); + expr = expr.left.expression; + flattened.left = flattened.left.clone(); + flattened.left.expression = expr.left.clone(); + tail.unshift(flattened); + } else { + continue; + } + if (tail.length == 0) continue; if (!trim_assigns(expr.left, expr.right, tail)) continue; trimmed = true; - exprs = exprs.slice(0, i + 1).concat(tail); + exprs = exprs.slice(0, i).concat(expr, tail); } if (defn instanceof AST_Definitions) { - keep = keep || 0; for (var i = defn.definitions.length; --i >= 0;) { var def = defn.definitions[i]; if (!def.value) continue; @@ -3500,6 +3793,10 @@ merge(Compressor.prototype, { if (defn instanceof AST_Var && join_var_assign(defn.definitions, exprs, keep)) trimmed = true; } return trimmed && exprs; + + function can_trim(node) { + return node instanceof AST_Assign && node.operator == "="; + } } function merge_assigns(prev, defn) { @@ -3556,22 +3853,35 @@ merge(Compressor.prototype, { } function trim_assigns(name, value, exprs) { + var names = new Dictionary(); + names.set(name.name, true); + while (value instanceof AST_Assign && value.operator == "=") { + if (value.left instanceof AST_SymbolRef) names.set(value.left.name, true); + value = value.right; + } if (!(value instanceof AST_Object)) return; var trimmed = false; do { - var node = exprs[0]; - if (!(node instanceof AST_Assign)) break; - if (node.operator != "=") break; - if (!(node.left instanceof AST_PropAccess)) break; + if (!try_join(exprs[0])) break; + exprs.shift(); + trimmed = true; + } while (exprs.length); + return trimmed; + + function try_join(node) { + if (!(node instanceof AST_Assign)) return; + if (node.operator != "=") return; + if (!(node.left instanceof AST_PropAccess)) return; var sym = node.left.expression; - if (!(sym instanceof AST_SymbolRef)) break; - if (name.name != sym.name) break; - if (!node.right.is_constant_expression(scope)) break; + if (!(sym instanceof AST_SymbolRef)) return; + if (!names.has(sym.name)) return; + if (!node.right.is_constant_expression(scope)) return; var prop = node.left.property; if (prop instanceof AST_Node) { + if (try_join(prop)) prop = node.left.property = prop.right.clone(); prop = prop.evaluate(compressor); } - if (prop instanceof AST_Node) break; + if (prop instanceof AST_Node) return; prop = "" + prop; var diff = prop == "__proto__" || compressor.has_directive("use strict") ? function(node) { var key = node.key; @@ -3583,29 +3893,27 @@ merge(Compressor.prototype, { } return key !== "__proto__"; }; - if (!all(value.properties, diff)) break; + if (!all(value.properties, diff)) return; value.properties.push(make_node(AST_ObjectKeyVal, node, { key: prop, - value: node.right + value: node.right, })); - exprs.shift(); - trimmed = true; - } while (exprs.length); - return trimmed; + return true; + } } function join_consecutive_vars(statements) { - var defs; + var changed = false, defs; for (var i = 0, j = -1; i < statements.length; i++) { var stat = statements[i]; var prev = statements[j]; if (stat instanceof AST_Definitions) { if (prev && prev.TYPE == stat.TYPE) { prev.definitions = prev.definitions.concat(stat.definitions); - CHANGED = true; + changed = true; } else if (defs && defs.TYPE == stat.TYPE && declarations_only(stat)) { defs.definitions = defs.definitions.concat(stat.definitions); - CHANGED = true; + changed = true; } else if (stat instanceof AST_Var) { var exprs = merge_assigns(prev, stat); if (exprs) { @@ -3613,7 +3921,7 @@ merge(Compressor.prototype, { prev.body = make_sequence(prev, exprs); j++; } - CHANGED = true; + changed = true; } else { j++; } @@ -3627,25 +3935,26 @@ merge(Compressor.prototype, { } else if (stat instanceof AST_For) { var exprs = join_assigns(prev, stat.init); if (exprs) { - CHANGED = true; + changed = true; stat.init = exprs.length ? make_sequence(stat.init, exprs) : null; } else if (prev instanceof AST_Var && (!stat.init || stat.init.TYPE == prev.TYPE)) { if (stat.init) { prev.definitions = prev.definitions.concat(stat.init.definitions); } + stat = stat.clone(); defs = stat.init = prev; statements[j] = merge_defns(stat); - CHANGED = true; + changed = true; continue; } else if (defs && stat.init && defs.TYPE == stat.init.TYPE && declarations_only(stat.init)) { defs.definitions = defs.definitions.concat(stat.init.definitions); stat.init = null; - CHANGED = true; + changed = true; } else if (stat.init instanceof AST_Var) { defs = stat.init; exprs = merge_assigns(prev, stat.init); if (exprs) { - CHANGED = true; + changed = true; if (exprs.length == 0) { statements[j] = merge_defns(stat); continue; @@ -3664,17 +3973,24 @@ merge(Compressor.prototype, { name.definition().references.push(ref); }); defs.definitions = defns; - CHANGED = true; + changed = true; } stat.object = join_assigns_expr(stat.object); } else if (stat instanceof AST_If) { stat.condition = join_assigns_expr(stat.condition); } else if (stat instanceof AST_SimpleStatement) { - var exprs = join_assigns(prev, stat.body); + var exprs = join_assigns(prev, stat.body), next; if (exprs) { - CHANGED = true; + changed = true; if (!exprs.length) continue; stat.body = make_sequence(stat.body, exprs); + } else if (prev instanceof AST_Definitions + && (next = statements[i + 1]) + && prev.TYPE == next.TYPE + && (next = next.definitions[0]).value) { + changed = true; + next.value = make_sequence(stat, [ stat.body, next.value ]); + continue; } } else if (stat instanceof AST_Switch) { stat.expression = join_assigns_expr(stat.expression); @@ -3684,11 +4000,12 @@ merge(Compressor.prototype, { statements[++j] = defs ? merge_defns(stat) : stat; } statements.length = j + 1; + return changed; function join_assigns_expr(value) { var exprs = join_assigns(prev, value, 1); if (!exprs) return value; - CHANGED = true; + changed = true; var tail = value.tail_node(); if (exprs[exprs.length - 1] !== tail) exprs.push(tail.left); return make_sequence(value, exprs); @@ -3703,7 +4020,7 @@ merge(Compressor.prototype, { if (parent instanceof AST_ForEnumeration && parent.init === node) return node; if (!declarations_only(node)) return node; defs.definitions = defs.definitions.concat(node.definitions); - CHANGED = true; + changed = true; if (parent instanceof AST_For && parent.init === node) return null; return in_list ? List.skip : make_node(AST_EmptyStatement, node); } @@ -3768,7 +4085,8 @@ merge(Compressor.prototype, { } function is_undefined(node, compressor) { - return node.is_undefined + return node == null + || node.is_undefined || node instanceof AST_Undefined || node instanceof AST_UnaryPrefix && node.operator == "void" @@ -4091,9 +4409,6 @@ merge(Compressor.prototype, { "setUTCMonth", "setUTCSeconds", "setYear", - "toExponential", - "toFixed", - "toPrecision", ]); def(AST_Call, function(compressor) { if (!compressor.option("unsafe")) return false; @@ -4109,9 +4424,15 @@ merge(Compressor.prototype, { def(AST_Sequence, function(compressor) { return this.tail_node().is_number(compressor); }); - def(AST_SymbolRef, function(compressor) { + def(AST_SymbolRef, function(compressor, keep_unary) { var fixed = this.fixed_value(); if (!fixed) return false; + if (keep_unary + && fixed instanceof AST_UnaryPrefix + && fixed.operator == "+" + && fixed.expression.equivalent_to(this)) { + return false; + } this.is_number = return_false; var result = fixed.is_number(compressor); delete this.is_number; @@ -4144,7 +4465,10 @@ merge(Compressor.prototype, { "charAt", "substr", "substring", + "toExponential", + "toFixed", "toLowerCase", + "toPrecision", "toString", "toUpperCase", "trim", @@ -4537,7 +4861,6 @@ merge(Compressor.prototype, { } return this; }); - var nonsafe_props = makePredicate("__proto__ toString valueOf"); def(AST_Object, function(compressor, ignore_side_effects, cached, depth) { if (compressor.option("unsafe")) { var val = {}; @@ -4549,7 +4872,12 @@ merge(Compressor.prototype, { key = key._eval(compressor, ignore_side_effects, cached, depth); if (key === prop.key) return this; } - if (nonsafe_props[key]) return this; + switch (key) { + case "__proto__": + case "toString": + case "valueOf": + return this; + } val[key] = prop.value._eval(compressor, ignore_side_effects, cached, depth); if (val[key] === prop.value) return this; } @@ -4681,7 +5009,7 @@ merge(Compressor.prototype, { return result; function decimals(operand) { - var match = /(\.[0-9]*)?(e.+)?$/.exec(+operand); + var match = /(\.[0-9]*)?(e[^e]+)?$/.exec(+operand); return (match[1] || ".").length - 1 - (match[2] || "").slice(1); } }); @@ -4808,10 +5136,11 @@ merge(Compressor.prototype, { if (!all(fn.argnames, function(sym, index) { if (sym instanceof AST_DefaultValue) { if (!args) return false; - if (args[index] !== undefined) return false; - var value = sym.value._eval(compressor, ignore_side_effects, cached, depth); - if (value === sym.value) return false; - args[index] = value; + if (args[index] === undefined) { + var value = sym.value._eval(compressor, ignore_side_effects, cached, depth); + if (value === sym.value) return false; + args[index] = value; + } sym = sym.name; } return !(sym instanceof AST_Destructured); @@ -4834,7 +5163,7 @@ merge(Compressor.prototype, { } if (node instanceof AST_Scope && node !== fn) return true; })); - delete fn.evaluating; + fn.evaluating = false; if (!found) return; } return this; @@ -4845,9 +5174,12 @@ merge(Compressor.prototype, { if (!args || all(fn.argnames, function(sym, i) { return assign(sym, args[i]); }) && !(fn.rest && !assign(fn.rest, args.slice(fn.argnames.length))) || ignore_side_effects) { + if (ignore_side_effects) fn.argnames.forEach(function(sym) { + if (sym instanceof AST_DefaultValue) sym.value.walk(scan_modified); + }); fn.evaluating = true; val = val._eval(compressor, ignore_side_effects, cached, depth); - delete fn.evaluating; + fn.evaluating = false; } cached_args.forEach(function(node) { delete node._eval; @@ -4925,11 +5257,9 @@ merge(Compressor.prototype, { return this; function decode(str) { - return str.replace(/\\(u\{[^}]*\}?|u[\s\S]{0,4}|x[\s\S]{0,2}|[0-9]+|[\s\S])/g, function(match, seq) { - var s = decode_escape_sequence(seq); - if (typeof s != "string") malformed = true; - return s; - }); + str = decode_template(str); + if (typeof str != "string") malformed = true; + return str; } }); })(function(node, func) { @@ -5070,21 +5400,43 @@ merge(Compressor.prototype, { return map && map[prop]; }); - function spread_side_effects(exp) { - while ((exp = exp.tail_node()) instanceof AST_SymbolRef) { - exp = exp.fixed_value(); - if (!exp) return true; - } - return !(exp instanceof AST_Array - || exp.TYPE == "Binary" && !lazy_op[exp.operator] - || exp instanceof AST_Constant - || exp instanceof AST_Lambda - || exp instanceof AST_Object && all(exp.properties, function(prop) { + // determine if object spread syntax may cause runtime exception + (function(def) { + def(AST_Node, return_false); + def(AST_Array, return_true); + def(AST_Assign, function() { + switch (this.operator) { + case "=": + return this.right.safe_to_spread(); + case "&&=": + case "||=": + case "??=": + return this.left.safe_to_spread() && this.right.safe_to_spread(); + } + return true; + }); + def(AST_Binary, function() { + return !lazy_op[this.operator] || this.left.safe_to_spread() && this.right.safe_to_spread(); + }); + def(AST_Constant, return_true); + def(AST_Lambda, return_true); + def(AST_Object, function() { + return all(this.properties, function(prop) { return !(prop instanceof AST_ObjectGetter || prop instanceof AST_Spread); - }) - || exp instanceof AST_ObjectIdentity - || exp instanceof AST_Unary); - } + }); + }); + def(AST_ObjectIdentity, return_true); + def(AST_Sequence, function() { + return this.tail_node().safe_to_spread(); + }); + def(AST_SymbolRef, function() { + var fixed = this.fixed_value(); + return fixed && fixed.safe_to_spread(); + }); + def(AST_Unary, return_true); + })(function(node, func) { + node.DEFMETHOD("safe_to_spread", func); + }); // determine if expression has side effects (function(def) { @@ -5096,7 +5448,8 @@ merge(Compressor.prototype, { }); } function array_spread(node, compressor) { - return !node.expression.is_string(compressor) || node.expression.has_side_effects(compressor); + var exp = node.expression; + return !exp.is_string(compressor) || exp.has_side_effects(compressor); } def(AST_Node, return_true); def(AST_Array, function(compressor) { @@ -5162,7 +5515,7 @@ merge(Compressor.prototype, { return any(this.properties, compressor); }); def(AST_Dot, function(compressor) { - return !this.optional && this.expression.may_throw_on_access(compressor) + return this.expression.may_throw_on_access(compressor) || this.expression.has_side_effects(compressor); }); def(AST_EmptyStatement, return_false); @@ -5178,7 +5531,7 @@ merge(Compressor.prototype, { def(AST_Object, function(compressor) { return any(this.properties, compressor, function(node, compressor) { var exp = node.expression; - return spread_side_effects(exp) || exp.has_side_effects(compressor); + return !exp.safe_to_spread() || exp.has_side_effects(compressor); }); }); def(AST_ObjectIdentity, return_false); @@ -5193,7 +5546,7 @@ merge(Compressor.prototype, { return this.body.has_side_effects(compressor); }); def(AST_Sub, function(compressor) { - return !this.optional && this.expression.may_throw_on_access(compressor) + return this.expression.may_throw_on_access(compressor) || this.expression.has_side_effects(compressor) || this.property.has_side_effects(compressor); }); @@ -5229,7 +5582,6 @@ merge(Compressor.prototype, { def(AST_Node, return_true); def(AST_Constant, return_false); - def(AST_Destructured, return_true); def(AST_EmptyStatement, return_false); def(AST_Lambda, return_false); def(AST_ObjectIdentity, return_false); @@ -5263,6 +5615,9 @@ merge(Compressor.prototype, { } return this.left.may_throw(compressor); }); + def(AST_Await, function(compressor) { + return this.expression.may_throw(compressor); + }); def(AST_Binary, function(compressor) { return this.left.may_throw(compressor) || this.right.may_throw(compressor) @@ -5299,6 +5654,14 @@ merge(Compressor.prototype, { return !this.optional && this.expression.may_throw_on_access(compressor) || this.expression.may_throw(compressor); }); + def(AST_ForEnumeration, function(compressor) { + if (this.init.may_throw(compressor)) return true; + var obj = this.object; + if (obj.may_throw(compressor)) return true; + obj = obj.tail_node(); + if (!(obj instanceof AST_Array || obj.is_string(compressor))) return true; + return this.body.may_throw(compressor); + }); def(AST_If, function(compressor) { return this.condition.may_throw(compressor) || this.body && this.body.may_throw(compressor) @@ -5485,6 +5848,21 @@ merge(Compressor.prototype, { return compressor.option("unused") && self.label.references.length == 0 ? self.body : self; }); + OPT(AST_LoopControl, function(self, compressor) { + if (!compressor.option("dead_code")) return self; + var label = self.label; + if (label) { + var lct = compressor.loopcontrol_target(self); + self.label = null; + if (compressor.loopcontrol_target(self) === lct) { + remove(label.thedef.references, self); + } else { + self.label = label; + } + } + return self; + }); + OPT(AST_Block, function(self, compressor) { self.body = tighten_body(self.body, compressor); return self; @@ -5563,6 +5941,7 @@ merge(Compressor.prototype, { fn = fn.fixed_value(); } if (!(fn instanceof AST_Defun || fn instanceof AST_Function)) break; + if (fn.rest) break; if (fn.uses_arguments) break; if (fn === call.expression) { if (fn.parent_scope !== self) break; @@ -5665,10 +6044,7 @@ merge(Compressor.prototype, { } if (node instanceof AST_Binary) { if (!lazy_op[node.operator]) return; - node.left.walk(tw); - push(); - node.right.walk(tw); - pop(); + walk_cond(node); return true; } if (node instanceof AST_Break) { @@ -5692,14 +6068,25 @@ merge(Compressor.prototype, { tail.walk(tw); return true; } + if (node instanceof AST_Class) { + if (node.name) node.name.walk(tw); + if (node.extends) node.extends.walk(tw); + node.properties.filter(function(prop) { + if (prop.key instanceof AST_Node) prop.key.walk(tw); + return prop.value; + }).forEach(function(prop) { + if (prop.static) { + prop.value.walk(tw); + } else { + push(tw); + prop.value.walk(tw); + pop(tw); + } + }); + return true; + } if (node instanceof AST_Conditional) { - node.condition.walk(tw); - push(); - node.consequent.walk(tw); - pop(); - push(); - node.alternative.walk(tw); - pop(); + walk_cond(node.condition, node.consequent, node.alternative); return true; } if (node instanceof AST_Continue) { @@ -5740,15 +6127,7 @@ merge(Compressor.prototype, { return true; } if (node instanceof AST_If) { - node.condition.walk(tw); - push(); - node.body.walk(tw); - pop(); - if (node.alternative) { - push(); - node.alternative.walk(tw); - pop(); - } + walk_cond(node.condition, node.body, node.alternative); return true; } if (node instanceof AST_LabeledStatement) { @@ -5916,56 +6295,91 @@ merge(Compressor.prototype, { } return true; } + + function walk_cond(condition, consequent, alternative) { + var save = segment; + var segments = [ save, save ]; + if (condition instanceof AST_Binary) switch (condition.operator) { + case "&&": + segments[0] = walk_cond(condition.left, condition.right)[0]; + break; + case "||": + case "??": + segments[1] = walk_cond(condition.left, null, condition.right)[1]; + break; + default: + condition.walk(tw); + break; + } else if (condition instanceof AST_Conditional) { + walk_cond(condition.condition, condition.consequent, condition.alternative); + } else { + condition.walk(tw); + } + segment = segments[0]; + if (consequent) { + push(); + consequent.walk(tw); + } + segments[0] = segment; + segment = segments[1]; + if (alternative) { + push(); + alternative.walk(tw); + } + segments[1] = segment; + segment = save; + return segments; + } }); tw.directives = Object.create(compressor.directives); self.walk(tw); + var changed = false; var merged = Object.create(null); while (first.length && last.length) { - var head = first.pop(); - var def = head.definition; - if (!(def.id in prev)) continue; - if (!references[def.id]) continue; - var head_refs = { - start: references[def.id].start, - }; + var tail = last.shift(); + if (!tail) continue; + var def = tail.definition; + var tail_refs = references[def.id]; + if (!tail_refs) continue; + tail_refs = { end: tail_refs.end }; while (def.id in merged) def = merged[def.id]; - head_refs.end = references[def.id].end; + tail_refs.start = references[def.id].start; var skipped = []; do { - var tail = last.pop(); - if (!tail) continue; + var head = first.shift(); if (tail.index > head.index) continue; - var id = tail.definition.id; - var tail_refs = references[id]; - if (!tail_refs) continue; + var id = head.definition.id; + if (!(id in prev)) continue; + var head_refs = references[id]; + if (!head_refs) continue; if (head_refs.start.block !== tail_refs.start.block || !mergeable(head_refs, tail_refs) || (head_refs.start.loop || !same_scope(def)) && !mergeable(tail_refs, head_refs) - || compressor.option("webkit") && is_funarg(def) !== is_funarg(tail.definition) - || !all(tail_refs, function(sym) { + || compressor.option("webkit") && is_funarg(def) !== is_funarg(head.definition) + || head.definition.const_redefs + || !all(head_refs, function(sym) { return sym.scope.find_variable(def.name) === def; })) { - skipped.unshift(tail); + skipped.push(head); continue; } - var orig = [], refs = []; - tail_refs.forEach(function(sym) { + head_refs.forEach(function(sym) { sym.thedef = def; sym.name = def.name; if (sym instanceof AST_SymbolRef) { - refs.push(sym); + def.references.push(sym); } else { - orig.push(sym); + def.orig.push(sym); } }); - def.orig = orig.concat(def.orig); - def.references = refs.concat(def.references); - def.fixed = tail.definition.fixed && def.fixed; + if (!head.definition.fixed) def.fixed = false; merged[id] = def; + changed = true; break; - } while (last.length); - if (skipped.length) last = last.concat(skipped); + } while (first.length); + if (skipped.length) first = skipped.concat(first); } + return changed; function push() { segment = Object.create(segment); @@ -6057,7 +6471,7 @@ merge(Compressor.prototype, { function to_class_expr(defcl, drop_name) { var cl = make_node(AST_ClassExpression, defcl, defcl); - cl.name = drop_name ? null : make_node(AST_SymbolClass, defcl.name, defcl.name); + if (cl.name) cl.name = drop_name ? null : make_node(AST_SymbolClass, cl.name, cl.name); return cl; } @@ -6175,28 +6589,29 @@ merge(Compressor.prototype, { if (scope === self) { if (node instanceof AST_DefClass) { var def = node.name.definition(); - if ((!drop_funcs || def.exported) && !(def.id in in_use_ids)) { + var drop = drop_funcs && !def.exported; + if (!drop && !(def.id in in_use_ids)) { in_use_ids[def.id] = true; in_use.push(def); } if (node.extends) node.extends.walk(tw); - var is_export = false; - if (tw.parent() instanceof AST_ExportDefault) { - is_export = true; - export_defaults[def.id] = true; - } + var used = tw.parent() instanceof AST_ExportDefault; + if (used) export_defaults[def.id] = true; + var values = []; node.properties.forEach(function(prop) { if (prop.key instanceof AST_Node) prop.key.walk(tw); - if (!prop.value) return; - if (is_export || prop instanceof AST_ClassField && prop.static) { - var save_scope = scope; - scope = node; - prop.value.walk(tw); - scope = save_scope; + var value = prop.value; + if (!value) return; + if (prop instanceof AST_ClassField && prop.static) { + if (!used && value.contains_this()) used = true; + walk_class_prop(value); } else { - initializations.add(def.id, prop.value); + values.push(value); } }); + values.forEach(drop && used ? walk_class_prop : function(value) { + initializations.add(def.id, value); + }); return true; } if (node instanceof AST_LambdaDefinition) { @@ -6262,6 +6677,13 @@ merge(Compressor.prototype, { } } return scan_ref_scoped(node, descend, true); + + function walk_class_prop(value) { + var save_scope = scope; + scope = node; + value.walk(tw); + scope = save_scope; + } }); tw.directives = Object.create(compressor.directives); self.walk(tw); @@ -6327,7 +6749,6 @@ merge(Compressor.prototype, { } }); // pass 3: we should drop declarations not in_use - var trim_defns = []; var unused_fn_names = []; var calls_to_drop_args = []; var fns_with_marked_args = []; @@ -6422,7 +6843,7 @@ merge(Compressor.prototype, { && indexOf_assign(node.expression.definition(), node) < 0) { return make_node(AST_UnaryPrefix, node, { operator: "+", - expression: node.expression + expression: node.expression, }); } } @@ -6434,9 +6855,9 @@ merge(Compressor.prototype, { log(node.name, "Dropping unused class {name}"); def.eliminated++; descend(node, tt); - if (parent instanceof AST_ExportDefault) return to_class_expr(node, true); - var trimmed = node.drop_side_effect_free(compressor, true); - if (trimmed === node) trimmed = to_class_expr(node, true); + var trimmed = to_class_expr(node, true); + if (parent instanceof AST_ExportDefault) return trimmed; + trimmed = trimmed.drop_side_effect_free(compressor, true); if (trimmed) return make_node(AST_SimpleStatement, node, { body: trimmed }); return in_list ? List.skip : make_node(AST_EmptyStatement, node); } @@ -6461,8 +6882,28 @@ merge(Compressor.prototype, { unused_fn_names.push(node); } if (!(node instanceof AST_Accessor)) { - if (node.rest) { - var rest = node.rest.transform(trimmer); + var args, spread, trim = compressor.drop_fargs(node, parent); + if (trim && parent instanceof AST_Call && parent.expression === node) { + args = parent.args; + for (spread = 0; spread < args.length; spread++) { + if (args[spread] instanceof AST_Spread) break; + } + } + var argnames = node.argnames; + var rest = node.rest; + if (rest) { + if (!args || spread < argnames.length || rest instanceof AST_SymbolFunarg) { + rest = rest.transform(trimmer); + } else { + var trimmed = trim_destructured(rest, make_node(AST_Array, parent, { + elements: args.slice(argnames.length), + }), function(node) { + return node.definition().id in in_use_ids ? node : null; + }, !node.uses_arguments, rest); + rest = trimmed.name; + args.length = argnames.length; + if (trimmed.value.elements.length) [].push.apply(args, trimmed.value.elements); + } if (rest instanceof AST_Destructured && !rest.rest && (!node.uses_arguments || tt.has_directive("use strict"))) { if (rest instanceof AST_DestructuredArray) { @@ -6472,38 +6913,44 @@ merge(Compressor.prototype, { } } node.rest = rest; + if (rest) trim = false; } - var argnames = node.argnames; - var trim = compressor.drop_fargs(node, parent) && !node.rest; var default_length = trim ? -1 : node.length(); for (var i = argnames.length; --i >= 0;) { var sym = argnames[i]; - if (!(sym instanceof AST_SymbolFunarg)) { - var arg = sym.transform(trimmer); - if (arg) { + if (sym instanceof AST_SymbolFunarg) { + var def = sym.definition(); + if (def.id in in_use_ids) { + trim = false; + if (indexOf_assign(def, sym) < 0) sym.unused = null; + } else if (trim) { + log(sym, "Dropping unused function argument {name}"); + argnames.pop(); + } else { + sym.unused = true; + } + } else { + var funarg; + if (!args || spread < i) { + funarg = sym.transform(trimmer); + } else { + funarg = trim_destructured(sym, args[i], function(node) { + return node.definition().id in in_use_ids ? node : null; + }, !node.uses_arguments, sym).name; + } + if (funarg) { trim = false; } else if (trim) { - log(sym.name, "Dropping unused default argument {name}"); + log_default(sym, "Dropping unused default argument {name}"); argnames.pop(); } else if (i > default_length) { - log(sym.name, "Dropping unused default argument assignment {name}"); - sym.name.__unused = true; + log_default(sym, "Dropping unused default argument assignment {name}"); + if (sym.name instanceof AST_SymbolFunarg) sym.name.unused = true; argnames[i] = sym.name; } else { - log(sym.name, "Dropping unused default argument value {name}"); + log_default(sym, "Dropping unused default argument value {name}"); sym.value = make_node(AST_Number, sym, { value: 0 }); } - continue; - } - var def = sym.definition(); - if (def.id in in_use_ids) { - trim = false; - if (indexOf_assign(def, sym) < 0) sym.__unused = null; - } else if (trim) { - log(sym, "Dropping unused function argument {name}"); - argnames.pop(); - } else { - sym.__unused = true; } } fns_with_marked_args.push(node); @@ -6546,16 +6993,21 @@ merge(Compressor.prototype, { var sym = def.name.definition(); var drop_sym = is_var ? can_drop_symbol(def.name) : is_safe_lexical(sym); if (!drop_sym || !drop_vars || sym.id in in_use_ids) { - if (value && indexOf_assign(sym, def) < 0) { + var index; + if (value && ((index = indexOf_assign(sym, def)) < 0 || self_assign(value.tail_node()))) { + def = def.clone(); value = value.drop_side_effect_free(compressor); - if (value) { - AST_Node.warn("Side effects in last use of variable {name} [{file}:{line},{col}]", template(def.name)); - side_effects.push(value); + if (value) AST_Node.warn("Side effects in definition of variable {name} [{file}:{line},{col}]", template(def.name)); + if (node instanceof AST_Const) { + def.value = value || make_node(AST_Number, def, { value: 0 }); + } else { + def.value = null; + if (value) side_effects.push(value); } value = null; - trim_defns.push(def); + if (index >= 0) assign_in_use[sym.id][index] = def; } - var old_def; + var old_def, fn; if (!value && !(node instanceof AST_Let)) { if (parent instanceof AST_ExportDeclaration) { flush(); @@ -6569,17 +7021,18 @@ merge(Compressor.prototype, { } else if (compressor.option("functions") && !compressor.option("ie") && drop_sym + && value && var_defs[sym.id] == 1 && sym.assignments == 0 - && value instanceof AST_LambdaExpression + && (fn = value.tail_node()) instanceof AST_LambdaExpression && !is_arguments(sym) - && !is_arrow(value) - && assigned_once(value, sym.references) - && can_declare_defun(value) - && (old_def = rename_def(value, def.name.name)) !== false) { + && !is_arrow(fn) + && assigned_once(fn, sym.references) + && can_declare_defun(fn) + && (old_def = rename_def(fn, def.name.name)) !== false) { AST_Node.warn("Declaring {name} as function [{file}:{line},{col}]", template(def.name)); var ctor; - switch (value.CTOR) { + switch (fn.CTOR) { case AST_AsyncFunction: ctor = AST_AsyncDefun; break; @@ -6593,7 +7046,7 @@ merge(Compressor.prototype, { ctor = AST_GeneratorDefun; break; } - var defun = make_node(ctor, def, value); + var defun = make_node(ctor, def, fn); defun.name = make_node(AST_SymbolDefun, def.name, def.name); var name_def = def.name.scope.resolve().def_function(defun.name); if (old_def) old_def.forEach(function(node) { @@ -6602,6 +7055,7 @@ merge(Compressor.prototype, { node.reference(); }); body.push(defun); + if (value !== fn) [].push.apply(side_effects, value.expressions.slice(0, -1)); } else { if (drop_sym && var_defs[sym.id] > 1 @@ -6624,7 +7078,7 @@ merge(Compressor.prototype, { head.push(def); } } else { - value = value && !value.single_use && value.drop_side_effect_free(compressor); + value = value && value.drop_side_effect_free(compressor); if (value) { AST_Node.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", template(def.name)); side_effects.push(value); @@ -6634,6 +7088,10 @@ merge(Compressor.prototype, { sym.eliminated++; } + function self_assign(ref) { + return ref instanceof AST_SymbolRef && ref.definition() === sym; + } + function assigned_once(fn, refs) { if (refs.length == 0) return fn === def.name.fixed_value(); return all(refs, function(ref) { @@ -6713,7 +7171,7 @@ merge(Compressor.prototype, { var assign = make_node(AST_Assign, def, { operator: "=", left: ref, - right: def.value + right: def.value, }); var index = indexOf_assign(sym, def); if (index >= 0) assign_in_use[sym.id][index] = assign; @@ -6732,13 +7190,18 @@ merge(Compressor.prototype, { } } default: + var seq; + if (tail.length > 0 && (seq = tail[0].value) instanceof AST_Sequence) { + tail[0].value = seq.tail_node(); + body.push(make_node(AST_SimpleStatement, node, { + body: make_sequence(seq, seq.expressions.slice(0, -1)), + })); + } node.definitions = head.concat(tail); body.push(node); } if (side_effects.length > 0) { - body.push(make_node(AST_SimpleStatement, node, { - body: make_sequence(node, side_effects) - })); + body.push(make_node(AST_SimpleStatement, node, { body: make_sequence(node, side_effects) })); } return insert_statements(body, node, in_list); } @@ -6787,33 +7250,7 @@ merge(Compressor.prototype, { } }, function(node, in_list) { if (node instanceof AST_BlockStatement) return trim_block(node, tt.parent(), in_list); - // Certain combination of unused name + side effect leads to invalid AST: - // https://github.com/mishoo/UglifyJS/issues/44 - // https://github.com/mishoo/UglifyJS/issues/1838 - // https://github.com/mishoo/UglifyJS/issues/3371 - // We fix it at this stage by moving the `var` outside the `for`. - if (node instanceof AST_For) { - var block; - if (node.init instanceof AST_BlockStatement) { - block = node.init; - node.init = block.body.pop(); - block.body.push(node); - } - if (node.init instanceof AST_Defun) { - if (!block) { - block = make_node(AST_BlockStatement, node, { - body: [ node ] - }); - } - block.body.splice(-1, 0, node.init); - node.init = null; - } else if (node.init instanceof AST_SimpleStatement) { - node.init = node.init.body; - } else if (is_empty(node.init)) { - node.init = null; - } - return !block ? node : in_list ? List.splice(block.body) : block; - } + if (node instanceof AST_For) return patch_for_init(node, in_list); if (node instanceof AST_ForIn) { if (!drop_vars || !compressor.option("loops")) return; if (!is_empty(node.body)) return; @@ -6853,9 +7290,6 @@ merge(Compressor.prototype, { && self.body[0].value == "use strict") { self.body.length = 0; } - trim_defns.forEach(function(def) { - def.value = null; - }); unused_fn_names.forEach(function(fn) { fn.name = null; }); @@ -6867,6 +7301,19 @@ merge(Compressor.prototype, { AST_Node[sym.definition().references.length > 0 ? "info" : "warn"](text + " [{file}:{line},{col}]", template(sym)); } + function log_default(node, text) { + if (node.name instanceof AST_SymbolFunarg) { + log(node.name, text); + } else { + AST_Node.info(text + " [{file}:{line},{col}]", { + name: node, + file: node.start.file, + line: node.start.line, + col : node.start.col, + }); + } + } + function template(sym) { return { name: sym.name, @@ -7057,24 +7504,26 @@ merge(Compressor.prototype, { var value = node.value.drop_side_effect_free(compressor); if (!value) return null; log(node.name, "Side effects in default value of unused variable {name}"); - node.name.__unused = null; + node.name.unused = null; node.value = value; } return node; } - function trim_destructured(node, value, process, drop) { + function trim_destructured(node, value, process, drop, root) { var trimmer = new TreeTransformer(function(node) { if (node instanceof AST_DefaultValue) { - if (compressor.option("default_values") && value && value.is_defined(compressor)) { - node = node.name; - } else { + if (!(compressor.option("default_values") && value && value.is_defined(compressor))) { var save_drop = drop; drop = false; var trimmed = trim_default(trimmer, node); drop = save_drop; if (!trimmed && drop && value) value = value.drop_side_effect_free(compressor); return trimmed; + } else if (node === root) { + root = node = node.name; + } else { + node = node.name; } } if (node instanceof AST_DestructuredArray) { @@ -7137,12 +7586,17 @@ merge(Compressor.prototype, { if (!node.rest && (value instanceof AST_Array || value && value.is_string(compressor))) switch (elements.length) { case 0: + if (node === root) break; if (drop) value = value.drop_side_effect_free(compressor); return null; case 1: if (!drop) break; + if (node === root) break; var sym = elements[0]; - if (!(sym instanceof AST_Symbol)) break; + if (sym.has_side_effects(compressor)) break; + if (value.has_side_effects(compressor) && sym.match_symbol(function(node) { + return node instanceof AST_PropAccess; + })) break; value = make_node(AST_Sub, node, { expression: value, property: make_node(AST_Number, node, { value: 0 }), @@ -7163,7 +7617,7 @@ merge(Compressor.prototype, { var prop_keys, prop_map; if (value instanceof AST_Object) { prop_keys = []; - prop_map = Object.create(null); + prop_map = new Dictionary(); value.properties.forEach(function(prop, index) { if (prop instanceof AST_Spread) return prop_map = false; var key = prop.key; @@ -7171,7 +7625,7 @@ merge(Compressor.prototype, { if (key instanceof AST_Node) { prop_map = false; } else if (prop_map && !(prop instanceof AST_ObjectSetter)) { - prop_map[key] = prop; + prop_map.set(key, prop); } prop_keys[index] = key; }); @@ -7180,8 +7634,8 @@ merge(Compressor.prototype, { value = false; node.rest = node.rest.transform(compressor.option("rests") ? trimmer : tt); } - var can_drop = Object.create(null); - var drop_keys = drop && Object.create(null); + var can_drop = new Dictionary(); + var drop_keys = drop && new Dictionary(); var properties = []; node.properties.map(function(prop) { var key = prop.key; @@ -7192,7 +7646,7 @@ merge(Compressor.prototype, { if (key instanceof AST_Node) { drop_keys = false; } else { - can_drop[key] = !(key in can_drop); + can_drop.set(key, !can_drop.has(key)); } return key; }).forEach(function(key, index) { @@ -7202,8 +7656,8 @@ merge(Compressor.prototype, { value = false; trimmed = prop.value.transform(trimmer) || retain_lhs(prop.value); } else { - drop = drop_keys && can_drop[key]; - var mapped = prop_map && prop_map[key]; + drop = drop_keys && can_drop.get(key); + var mapped = prop_map && prop_map.get(key); if (mapped) { value = mapped.value; if (value instanceof AST_Accessor) value = false; @@ -7213,21 +7667,21 @@ merge(Compressor.prototype, { trimmed = prop.value.transform(trimmer); if (!trimmed) { if (node.rest || retain_key(prop)) trimmed = retain_lhs(prop.value); - if (drop_keys && !(key in drop_keys)) { + if (drop_keys && !drop_keys.has(key)) { if (mapped) { - drop_keys[key] = mapped; + drop_keys.set(key, mapped); if (value === null) { - prop_map[key] = retain_key(mapped) && make_node(AST_ObjectKeyVal, mapped, { + prop_map.set(key, retain_key(mapped) && make_node(AST_ObjectKeyVal, mapped, { key: mapped.key, value: make_node(AST_Number, mapped, { value: 0 }), - }); + })); } } else { - drop_keys[key] = true; + drop_keys.set(key, true); } } } else if (drop_keys) { - drop_keys[key] = false; + drop_keys.set(key, false); } if (value) mapped.value = value; } @@ -7242,10 +7696,10 @@ merge(Compressor.prototype, { if (prop instanceof AST_Spread) return prop; var key = prop_keys[index]; if (key instanceof AST_Node) return prop; - if (key in drop_keys) { - var mapped = drop_keys[key]; + if (drop_keys.has(key)) { + var mapped = drop_keys.get(key); if (!mapped) return prop; - if (mapped === prop) return prop_map[key] || List.skip; + if (mapped === prop) return prop_map.get(key) || List.skip; } else if (node.rest) { return prop; } @@ -7261,14 +7715,19 @@ merge(Compressor.prototype, { }); if (value && !node.rest) switch (properties.length) { case 0: + if (node === root) break; if (value.may_throw_on_access(compressor, true)) break; if (drop) value = value.drop_side_effect_free(compressor); return null; case 1: if (!drop) break; + if (node === root) break; var prop = properties[0]; if (prop.key instanceof AST_Node) break; - if (!(prop.value instanceof AST_Symbol)) break; + if (prop.value.has_side_effects(compressor)) break; + if (value.has_side_effects(compressor) && prop.value.match_symbol(function(node) { + return node instanceof AST_PropAccess; + })) break; value = make_node(AST_Sub, node, { expression: value, property: make_node_from_constant(prop.key, prop), @@ -7295,20 +7754,41 @@ merge(Compressor.prototype, { return prop.key instanceof AST_Node && prop.key.has_side_effects(compressor); } + function clear_write_only(node) { + if (node instanceof AST_Assign) { + node.write_only = false; + clear_write_only(node.right); + } else if (node instanceof AST_Binary) { + if (!lazy_op[node.operator]) return; + clear_write_only(node.left); + clear_write_only(node.right); + } else if (node instanceof AST_Conditional) { + clear_write_only(node.consequent); + clear_write_only(node.alternative); + } else if (node instanceof AST_Sequence) { + clear_write_only(node.tail_node()); + } else if (node instanceof AST_Unary) { + node.write_only = false; + } + } + function retain_lhs(node) { if (node instanceof AST_DefaultValue) return retain_lhs(node.name); if (node instanceof AST_Destructured) { if (value === null) { value = make_node(AST_Number, node, { value: 0 }); - } else if (value && (value.tail_node().write_only === true - || value.may_throw_on_access(compressor, true))) { - value = make_node(AST_Array, node, { - elements: value instanceof AST_Sequence ? value.expressions : [ value ], - }); + } else if (value) { + if (value.may_throw_on_access(compressor, true)) { + value = make_node(AST_Array, node, { + elements: value instanceof AST_Sequence ? value.expressions : [ value ], + }); + } else { + clear_write_only(value); + } } return make_node(AST_DestructuredObject, node, { properties: [] }); } - node.__unused = null; + node.unused = null; return node; } } @@ -7335,7 +7815,7 @@ merge(Compressor.prototype, { if (var_decl <= 1) hoist_vars = false; } if (!hoist_funs && !hoist_vars) return; - var consts = Object.create(null); + var consts = new Dictionary(); var dirs = []; var hoisted = []; var vars = new Dictionary(), vars_found = 0; @@ -7361,18 +7841,18 @@ merge(Compressor.prototype, { if (!all(node.definitions, function(defn) { var sym = defn.name; return sym instanceof AST_SymbolVar - && !consts[sym.name] + && !consts.has(sym.name) && self.find_variable(sym.name) === sym.definition(); })) return node; - node.definitions.forEach(function(def) { - vars.set(def.name.name, def); + node.definitions.forEach(function(defn) { + vars.set(defn.name.name, defn); ++vars_found; }); var seq = node.to_assignments(); if (p instanceof AST_ForEnumeration && p.init === node) { if (seq) return seq; - var def = node.definitions[0].name; - return make_node(AST_SymbolRef, def, def); + var sym = node.definitions[0].name; + return make_node(AST_SymbolRef, sym, sym); } if (p instanceof AST_For && p.init === node) return seq; if (!seq) return in_list ? List.skip : make_node(AST_EmptyStatement, node); @@ -7380,28 +7860,29 @@ merge(Compressor.prototype, { } if (node instanceof AST_Scope) return node; if (node instanceof AST_SymbolConst) { - consts[node.name] = true; + consts.set(node.name, true); return node; } }); self.transform(tt); if (vars_found > 0) { // collect only vars which don't show up in self's arguments list - var defs = []; + var defns = []; if (self instanceof AST_Lambda) self.each_argname(function(argname) { vars.del(argname.name); }); - vars.each(function(def, name) { - def = def.clone(); - def.value = null; - defs.push(def); - vars.set(name, def); + vars.each(function(defn, name) { + defn = defn.clone(); + defn.name = defn.name.clone(); + defn.value = null; + defns.push(defn); + vars.set(name, defn); + defn.name.definition().orig.unshift(defn.name); }); - if (defs.length > 0) { + if (defns.length > 0) { // try to merge in assignments insert_vars(self.body); - defs = make_node(AST_Var, self, { definitions: defs }); - hoisted.push(defs); + hoisted.push(make_node(AST_Var, self, { definitions: defns })); } } self.body = dirs.concat(hoisted, self.body); @@ -7415,13 +7896,13 @@ merge(Compressor.prototype, { && expr.operator == "=" && (sym = expr.left) instanceof AST_Symbol && vars.has(sym.name)) { - var def = vars.get(sym.name); - if (def.value) break; + var defn = vars.get(sym.name); + if (defn.value) break; var value = expr.right; if (value instanceof AST_Sequence) value = value.clone(); - def.value = value; - remove(defs, def); - defs.push(def); + defn.value = value; + remove(defns, defn); + defns.push(defn); body.shift(); continue; } @@ -7430,11 +7911,11 @@ merge(Compressor.prototype, { && assign.operator == "=" && (sym = assign.left) instanceof AST_Symbol && vars.has(sym.name)) { - var def = vars.get(sym.name); - if (def.value) break; - def.value = assign.right; - remove(defs, def); - defs.push(def); + var defn = vars.get(sym.name); + if (defn.value) break; + defn.value = assign.right; + remove(defns, defn); + defns.push(defn); stat.body = make_sequence(expr, expr.expressions.slice(1)); continue; } @@ -7463,7 +7944,7 @@ merge(Compressor.prototype, { })); } - function map_bool_returns(fn) { + function map_self_returns(fn) { var map = Object.create(null); scan_local_returns(fn, function(node) { var value = node.value; @@ -7476,9 +7957,14 @@ merge(Compressor.prototype, { return map; } - function all_bool(def, bool_returns, compressor) { - return def.bool_fn + (bool_returns[def.id] || 0) === def.references.length - def.replaced - && !compressor.exposed(def); + function can_trim_returns(def, self_returns, compressor) { + if (compressor.exposed(def)) return false; + switch (def.references.length - def.replaced - (self_returns[def.id] || 0)) { + case def.drop_return: + return "d"; + case def.bool_return: + return true; + } } function process_boolean_returns(fn, compressor) { @@ -7504,50 +7990,85 @@ merge(Compressor.prototype, { }); } - AST_Scope.DEFMETHOD("process_boolean_returns", noop); - AST_Defun.DEFMETHOD("process_boolean_returns", function(compressor) { + AST_Scope.DEFMETHOD("process_returns", noop); + AST_Defun.DEFMETHOD("process_returns", function(compressor) { if (!compressor.option("booleans")) return; - var bool_returns = map_bool_returns(this); - if (!all_bool(this.name.definition(), bool_returns, compressor)) return; if (compressor.parent() instanceof AST_ExportDefault) return; - process_boolean_returns(this, compressor); + switch (can_trim_returns(this.name.definition(), map_self_returns(this), compressor)) { + case "d": + drop_returns(compressor, this, true); + break; + case true: + process_boolean_returns(this, compressor); + break; + } }); - AST_Function.DEFMETHOD("process_boolean_returns", function(compressor) { + AST_Function.DEFMETHOD("process_returns", function(compressor) { if (!compressor.option("booleans")) return; - var bool_returns = map_bool_returns(this); - if (this.name && !all_bool(this.name.definition(), bool_returns, compressor)) return; + var drop = true; + var self_returns = map_self_returns(this); + if (this.name && !can_trim(this.name.definition())) return; var parent = compressor.parent(); if (parent instanceof AST_Assign) { if (parent.operator != "=") return; var sym = parent.left; if (!(sym instanceof AST_SymbolRef)) return; - if (!all_bool(sym.definition(), bool_returns, compressor)) return; + if (!can_trim(sym.definition())) return; } else if (parent instanceof AST_Call && parent.expression !== this) { var exp = parent.expression; if (exp instanceof AST_SymbolRef) exp = exp.fixed_value(); if (!(exp instanceof AST_Lambda)) return; if (exp.uses_arguments || exp.pinned()) return; - var sym = exp.argnames[parent.args.indexOf(this)]; + var args = parent.args, sym; + for (var i = 0; i < args.length; i++) { + var arg = args[i]; + if (arg === this) { + sym = exp.argnames[i]; + if (!sym && exp.rest) return; + break; + } + if (arg instanceof AST_Spread) return; + } if (sym instanceof AST_DefaultValue) sym = sym.name; - if (sym instanceof AST_SymbolFunarg && !all_bool(sym.definition(), bool_returns, compressor)) return; + if (sym instanceof AST_SymbolFunarg && !can_trim(sym.definition())) return; } else if (parent.TYPE == "Call") { compressor.pop(); var in_bool = compressor.in_boolean_context(); compressor.push(this); - if (!in_bool) return; + switch (in_bool) { + case true: + drop = false; + case "d": + break; + default: + return; + } } else return; - process_boolean_returns(this, compressor); + if (drop) { + drop_returns(compressor, this, true); + } else { + process_boolean_returns(this, compressor); + } + + function can_trim(def) { + switch (can_trim_returns(def, self_returns, compressor)) { + case true: + drop = false; + case "d": + return true; + } + } }); AST_BlockScope.DEFMETHOD("var_names", function() { var var_names = this._var_names; if (!var_names) { - this._var_names = var_names = Object.create(null); + this._var_names = var_names = new Dictionary(); this.enclosed.forEach(function(def) { - var_names[def.name] = true; + var_names.set(def.name, true); }); this.variables.each(function(def, name) { - var_names[name] = true; + var_names.set(name, true); }); } return var_names; @@ -7563,10 +8084,10 @@ merge(Compressor.prototype, { s = s.parent_scope; } while (s && s !== this); }); - prefix = prefix.replace(/(?:^[^a-z_$]|[^a-z0-9_$])/ig, "_"); + prefix = prefix.replace(/^[^a-z_$]|[^a-z0-9_$]/gi, "_"); var name = prefix; for (var i = 0; !all(scopes, function(scope) { - return !scope.var_names()[name]; + return !scope.var_names().has(name); }); i++) name = prefix + "$" + i; var sym = make_node(type, orig, { name: name, @@ -7575,7 +8096,7 @@ merge(Compressor.prototype, { var def = this.def_variable(sym); scopes.forEach(function(scope) { scope.enclosed.push(def); - scope.var_names()[name] = true; + scope.var_names().set(name, true); }); return sym; }); @@ -7612,6 +8133,7 @@ merge(Compressor.prototype, { right: prop.value, })); }); + defs.value = node.right; defs_by_id[node.left.definition().id] = defs; self.body.splice(self.body.indexOf(this.stack[1]) + 1, 0, make_node(AST_Var, node, { definitions: decls, @@ -7624,12 +8146,16 @@ merge(Compressor.prototype, { descend(node, this); var defs = new Dictionary(); var var_defs = []; + var decl = node.clone(); + decl.value = node.name instanceof AST_SymbolConst ? make_node(AST_Number, node, { value: 0 }) : null; + var_defs.push(decl); node.value.properties.forEach(function(prop) { var_defs.push(make_node(AST_VarDef, node, { name: make_sym(node.name.CTOR, node.name, prop.key), value: prop.value, })); }); + defs.value = node.value; defs_by_id[node.name.definition().id] = defs; return List.splice(var_defs); } @@ -7645,6 +8171,7 @@ merge(Compressor.prototype, { if (!(node.expression instanceof AST_SymbolRef)) return; var defs = defs_by_id[node.expression.definition().id]; if (!defs) return; + if (node.expression.fixed_value() !== defs.value) return; var def = defs.get(node.get_property()); var sym = make_node(AST_SymbolRef, node, { name: def.name, @@ -7655,7 +8182,9 @@ merge(Compressor.prototype, { return sym; } if (node instanceof AST_SymbolRef) { - if (!(node.definition().id in defs_by_id)) return; + var defs = defs_by_id[node.definition().id]; + if (!defs) return; + if (node.fixed_value() !== defs.value) return; return make_node(AST_Object, node, { properties: [] }); } })); @@ -7664,18 +8193,16 @@ merge(Compressor.prototype, { if (!(sym instanceof AST_Symbol)) return; var def = sym.definition(); if (def.assignments != count) return; - if (def.direct_access) return; - if (def.escaped.depth == 1) return; if (def.references.length - def.replaced == count) return; if (def.single_use) return; if (top_retain(def)) return; if (sym.fixed_value() !== right) return; + var fixed = sym.fixed || def.fixed; + if (fixed.direct_access) return; + if (fixed.escaped && fixed.escaped.depth == 1) return; return right instanceof AST_Object && right.properties.length > 0 && all(right.properties, can_hoist_property) - && all(def.references, function(ref) { - return ref.fixed_value() === right; - }) && can_drop_symbol(sym, compressor); } }); @@ -7689,6 +8216,118 @@ merge(Compressor.prototype, { }); } + function drop_returns(compressor, exp, ignore_name) { + if (!(exp instanceof AST_Lambda)) return; + var arrow = is_arrow(exp); + var async = is_async(exp); + var changed = false; + var drop_body = false; + if (arrow && compressor.option("arrows")) { + if (!exp.value) { + drop_body = true; + } else if (!async || is_primitive(compressor, exp.value)) { + var dropped = exp.value.drop_side_effect_free(compressor); + if (dropped !== exp.value) { + changed = true; + exp.value = dropped; + } + } + } else if (!is_generator(exp)) { + if (!ignore_name && exp.name) { + var def = exp.name.definition(); + drop_body = def.references.length == def.replaced; + } else { + drop_body = true; + } + } + if (drop_body) { + exp.process_expression(false, function(node) { + var value = node.value; + if (value) { + if (async && !is_primitive(compressor, value)) return node; + value = value.drop_side_effect_free(compressor, true); + } + changed = true; + if (!value) return make_node(AST_EmptyStatement, node); + return make_node(AST_SimpleStatement, node, { body: value }); + }); + scan_local_returns(exp, function(node) { + var value = node.value; + if (value) { + if (async && !is_primitive(compressor, value)) return; + var dropped = value.drop_side_effect_free(compressor); + if (dropped !== value) { + changed = true; + node.value = dropped; + } + } + }); + } + if (async && compressor.option("awaits")) { + if (drop_body) exp.process_expression("awaits", function(node) { + var body = node.body; + if (body instanceof AST_Await) { + if (is_primitive(compressor, body.expression)) { + changed = true; + body = body.expression.drop_side_effect_free(compressor, true); + if (!body) return make_node(AST_EmptyStatement, node); + node.body = body; + } + } else if (body instanceof AST_Sequence) { + var exprs = body.expressions; + for (var i = exprs.length; --i >= 0;) { + var tail = exprs[i]; + if (!(tail instanceof AST_Await)) break; + var value = tail.expression; + if (!is_primitive(compressor, value)) break; + changed = true; + if (exprs[i] = value.drop_side_effect_free(compressor)) break; + } + switch (i) { + case -1: + return make_node(AST_EmptyStatement, node); + case 0: + node.body = exprs[0]; + break; + default: + exprs.length = i + 1; + break; + } + } + return node; + }); + var abort = !drop_body && exp.name || arrow && exp.value && !is_primitive(compressor, exp.value); + var tw = new TreeWalker(function(node) { + if (abort) return true; + if (tw.parent() === exp && node.may_throw(compressor)) return abort = true; + if (node instanceof AST_Await) return abort = true; + if (node instanceof AST_ForAwaitOf) return abort = true; + if (node instanceof AST_Return) { + if (node.value && !is_primitive(compressor, node.value)) return abort = true; + return; + } + if (node instanceof AST_Scope && node !== exp) return true; + }); + exp.walk(tw); + if (!abort) { + var ctor; + switch (exp.CTOR) { + case AST_AsyncArrow: + ctor = AST_Arrow; + break; + case AST_AsyncFunction: + ctor = AST_Function; + break; + case AST_AsyncGeneratorFunction: + ctor = AST_GeneratorFunction; + break; + } + return make_node(ctor, exp, exp); + } + } + return changed && exp.clone(); + } + // drop_side_effect_free() // remove side-effect-free parts which only affects return value (function(def) { @@ -7721,9 +8360,7 @@ merge(Compressor.prototype, { return exp.drop_side_effect_free(compressor, first_in_statement); } function convert_spread(node) { - return node instanceof AST_Spread ? make_node(AST_Array, node, { - elements: [ node ] - }) : node; + return node instanceof AST_Spread ? make_node(AST_Array, node, { elements: [ node ] }) : node; } def(AST_Node, return_this); def(AST_Accessor, return_null); @@ -7743,21 +8380,25 @@ merge(Compressor.prototype, { if (compressor.has_directive("use strict") && expr.is_constant()) return this; } if (left.has_side_effects(compressor)) return this; - var right = this.right; - if (!lazy_op[this.operator.slice(0, -1)]) { - this.write_only = true; - if (root_expr(left).is_constant_expression(compressor.find_parent(AST_Scope))) { - return right.drop_side_effect_free(compressor); - } - } - return this; + if (lazy_op[this.operator.slice(0, -1)]) return this; + this.write_only = true; + if (!root_expr(left).is_constant_expression(compressor.find_parent(AST_Scope))) return this; + return this.right.drop_side_effect_free(compressor); }); def(AST_Await, function(compressor) { if (!compressor.option("awaits")) return this; var exp = this.expression; if (!is_primitive(compressor, exp)) return this; + if (exp instanceof AST_UnaryPrefix && exp.operator == "!") exp = exp.expression; + var dropped = exp.drop_side_effect_free(compressor); + if (dropped === exp) return this; + if (!dropped) { + dropped = make_node(AST_Number, exp, { value: 0 }); + } else if (!is_primitive(compressor, dropped)) { + dropped = dropped.negate(compressor); + } var node = this.clone(); - node.expression = exp.drop_side_effect_free(compressor) || make_node(AST_Number, this, { value: 0 }); + node.expression = dropped; return node; }); def(AST_Binary, function(compressor, first_in_statement) { @@ -7780,12 +8421,12 @@ merge(Compressor.prototype, { node.right = rhs.drop_side_effect_free(compressor); } if (op == "??") return node; - var negated = make_node(AST_Binary, this, { - operator: op == "&&" ? "||" : "&&", - left: left.negate(compressor, first_in_statement), - right: node.right, - }); - return first_in_statement ? best_of_statement(node, negated) : best_of_expression(node, negated); + var negated = node.clone(); + negated.operator = op == "&&" ? "||" : "&&"; + negated.left = left.negate(compressor, first_in_statement); + if (negated.operator == negated.right.operator) swap_chain(negated); + var best = first_in_statement ? best_of_statement : best_of_expression; + return op == "&&" ? best(node, negated) : best(negated, node); } var lhs = left.drop_side_effect_free(compressor, first_in_statement); if (!lhs) return rhs; @@ -7793,102 +8434,15 @@ merge(Compressor.prototype, { if (!rhs) return lhs; return make_sequence(this, [ lhs, rhs ]); }); - function drop_returns(compressor, exp) { - var arrow = is_arrow(exp); - var async = is_async(exp); - var drop_body = false; - if (arrow && compressor.option("arrows")) { - if (!exp.value) { - drop_body = true; - } else if (!async || is_primitive(compressor, exp.value)) { - exp.value = exp.value.drop_side_effect_free(compressor); - } - } else if (exp instanceof AST_AsyncFunction || exp instanceof AST_Function) { - if (exp.name) { - var def = exp.name.definition(); - drop_body = def.references.length == def.replaced; - } else { - drop_body = true; - } - } - if (drop_body) { - exp.process_expression(false, function(node) { - var value = node.value; - if (value) { - if (async && !is_primitive(compressor, value)) return node; - value = value.drop_side_effect_free(compressor, true); - } - if (!value) return make_node(AST_EmptyStatement, node); - return make_node(AST_SimpleStatement, node, { body: value }); - }); - scan_local_returns(exp, function(node) { - var value = node.value; - if (value) { - if (async && !is_primitive(compressor, value)) return; - node.value = value.drop_side_effect_free(compressor); - } - }); - } - if (async && compressor.option("awaits")) { - if (drop_body) exp.process_expression("awaits", function(node) { - var body = node.body; - if (body instanceof AST_Await) { - if (is_primitive(compressor, body.expression)) { - body = body.expression.drop_side_effect_free(compressor, true); - if (!body) return make_node(AST_EmptyStatement, node); - node.body = body; - } - } else if (body instanceof AST_Sequence) { - var exprs = body.expressions; - for (var i = exprs.length; --i >= 0;) { - var tail = exprs[i]; - if (!(tail instanceof AST_Await)) break; - if (!is_primitive(compressor, tail.expression)) break; - if (exprs[i] = tail.expression.drop_side_effect_free(compressor)) break; - } - switch (i) { - case -1: - return make_node(AST_EmptyStatement, node); - case 0: - node.body = exprs[0]; - break; - default: - exprs.length = i + 1; - break; - } - } - return node; - }); - var abort = !drop_body && exp.name || arrow && exp.value && !is_primitive(compressor, exp.value); - var tw = new TreeWalker(function(node) { - if (abort) return true; - if (tw.parent() === exp && node.may_throw(compressor)) return abort = true; - if (node instanceof AST_Await) return abort = true; - if (node instanceof AST_ForAwaitOf) return abort = true; - if (node instanceof AST_Return) { - if (node.value && !is_primitive(compressor, node.value)) return abort = true; - return; - } - if (node instanceof AST_Scope && node !== exp) return true; - }); - exp.walk(tw); - if (!abort) { - var ctor; - switch (exp.CTOR) { - case AST_AsyncArrow: - ctor = AST_Arrow; - break; - case AST_AsyncFunction: - ctor = AST_Function; - break; - case AST_AsyncGeneratorFunction: - ctor = AST_GeneratorFunction; - break; - } - return make_node(ctor, exp, exp); - } - } - return drop_body && exp.clone(); + function assign_this_only(fn, compressor) { + fn.new = true; + var result = all(fn.body, function(stat) { + return !stat.has_side_effects(compressor); + }) && all(fn.argnames, function(argname) { + return !argname.match_symbol(return_false); + }) && !(fn.rest && fn.rest.match_symbol(return_false)); + fn.new = false; + return result; } def(AST_Call, function(compressor, first_in_statement) { var self = this; @@ -7929,23 +8483,18 @@ merge(Compressor.prototype, { exprs = trim(exprs, compressor, first_in_statement, array_spread); return exprs && make_sequence(self, exprs.map(convert_spread)); } - if (!fn.contains_this()) self = make_node(AST_Call, self, self); + if (!fn.contains_this()) { + self = make_node(AST_Call, self, self); + self.expression = self.expression.clone(); + self.args = self.args.slice(); + } } } self.call_only = true; return self; }); - function assign_this_only(fn, compressor) { - fn.new = true; - var result = all(fn.body, function(stat) { - return !stat.has_side_effects(compressor); - }) && all(fn.argnames, function(argname) { - return !argname.match_symbol(return_false); - }) && !(fn.rest && fn.rest.match_symbol(return_false)); - delete fn.new; - return result; - } - function drop_class(self, compressor, first_in_statement) { + def(AST_ClassExpression, function(compressor, first_in_statement) { + var self = this; var exprs = [], values = []; var props = self.properties; for (var i = 0; i < props.length; i++) { @@ -7968,20 +8517,29 @@ merge(Compressor.prototype, { if (exprs) first_in_statement = false; values = trim(values, compressor, first_in_statement); if (!exprs) { - if (!base && !values) return null; + if (!base && !values && !self.name) return null; exprs = []; } - if (base) { - var node = to_class_expr(self, true); + if (base || self.name || !compressor.has_directive("use strict")) { + var node = to_class_expr(self); + if (!base) node.extends = null; node.properties = []; - if (exprs.length) node.properties.push(make_node(AST_ClassMethod, self, { - key: make_sequence(self, exprs), - value: make_node(AST_Function, self, { - argnames: [], - body: [], - }).init_vars(node), - })); - exprs = [ node ]; + if (values) { + node.properties.push(make_node(AST_ClassField, self, { + static: true, + key: exprs.length ? make_sequence(self, exprs) : "c", + value: make_sequence(self, values), + })); + } else if (exprs.length) { + node.properties.push(make_node(AST_ClassMethod, self, { + key: make_sequence(self, exprs), + value: make_node(AST_Function, self, { + argnames: [], + body: [], + }).init_vars(node), + })); + } + return node; } if (values) exprs.push(make_node(AST_Call, self, { expression: make_node(AST_Arrow, self, { @@ -7992,12 +8550,6 @@ merge(Compressor.prototype, { args: [], })); return make_sequence(self, exprs); - } - def(AST_ClassExpression, function(compressor, first_in_statement) { - var self = this; - var name = self.name; - if (name && name.fixed_value() !== self && name.definition().references.length > 0) return self; - return drop_class(self, compressor, first_in_statement); }); def(AST_Conditional, function(compressor) { var consequent = this.consequent.drop_side_effect_free(compressor); @@ -8020,30 +8572,27 @@ merge(Compressor.prototype, { node = alternative ? make_node(AST_Binary, this, { operator: "||", left: this.condition, - right: alternative + right: alternative, }) : this.condition.drop_side_effect_free(compressor); } else if (!alternative) { node = make_node(AST_Binary, this, { operator: "&&", left: this.condition, - right: consequent + right: consequent, }); } else { node = this.clone(); node.consequent = consequent; node.alternative = alternative; } - if (!compressor.option("ie")) return node; + if (!exprs) return node; if (node) exprs.push(node); return exprs.length == 0 ? null : make_sequence(this, exprs); }); def(AST_Constant, return_null); - def(AST_DefClass, function(compressor, first_in_statement) { - return drop_class(this, compressor, first_in_statement); - }); def(AST_Dot, function(compressor, first_in_statement) { var expr = this.expression; - if (!this.optional && expr.may_throw_on_access(compressor)) return this; + if (expr.may_throw_on_access(compressor)) return this; return expr.drop_side_effect_free(compressor, first_in_statement); }); def(AST_Function, function(compressor) { @@ -8062,16 +8611,14 @@ merge(Compressor.prototype, { }); var values = trim(exprs, compressor, first_in_statement, function(node, compressor, first_in_statement) { var exp = node.expression; - return spread_side_effects(exp) ? node : exp.drop_side_effect_free(compressor, first_in_statement); + return exp.safe_to_spread() ? exp.drop_side_effect_free(compressor, first_in_statement) : node; }); if (!values) return null; if (values === exprs && !all(values, function(node) { return !(node instanceof AST_Spread); })) return this; return make_sequence(this, values.map(function(node) { - return node instanceof AST_Spread ? make_node(AST_Object, node, { - properties: [ node ], - }) : node; + return node instanceof AST_Spread ? make_node(AST_Object, node, { properties: [ node ] }) : node; })); }); def(AST_ObjectIdentity, return_null); @@ -8083,7 +8630,8 @@ merge(Compressor.prototype, { if (compressor.option("awaits") && end > 0 && last instanceof AST_Await && last.expression.is_constant()) { expressions = expressions.slice(0, -1); end--; - last.expression = expressions[end]; + var expr = expressions[end]; + last.expression = is_primitive(compressor, expr) ? expr : expr.negate(compressor); expressions[end] = last; } var assign, cond, lhs; @@ -8102,17 +8650,8 @@ merge(Compressor.prototype, { }); def(AST_Sub, function(compressor, first_in_statement) { var expr = this.expression; + if (expr.may_throw_on_access(compressor)) return this; var prop = this.property; - if (expr.may_throw_on_access(compressor)) { - if (!this.optional) return this; - if (prop.has_side_effects(compressor)) { - prop = prop.drop_side_effect_free(compressor); - if (!prop) return expr.drop_side_effect_free(compressor, first_in_statement); - var node = this.clone(); - node.property = prop; - return node; - } - } expr = expr.drop_side_effect_free(compressor, first_in_statement); if (!expr) return prop.drop_side_effect_free(compressor, first_in_statement); prop = prop.drop_side_effect_free(compressor); @@ -8407,6 +8946,7 @@ merge(Compressor.prototype, { }); function mark_locally_defined(condition, consequent, alternative) { + if (condition instanceof AST_Sequence) condition = condition.tail_node(); if (!(condition instanceof AST_Binary)) return; if (!(condition.left instanceof AST_String)) { switch (condition.operator) { @@ -8438,16 +8978,76 @@ merge(Compressor.prototype, { return; } if (!body) return; + var abort = false; var def = sym.definition(); - var tw = new TreeWalker(function(node) { - if (node instanceof AST_Scope) { - var parent = tw.parent(); - if (parent instanceof AST_Call && parent.expression === node) return; + var fn; + var refs = []; + var scanned = []; + var tw = new TreeWalker(function(node, descend) { + if (abort) return true; + if (node instanceof AST_Assign) { + var ref = node.left; + if (!(ref instanceof AST_SymbolRef && ref.definition() === def)) return; + node.right.walk(tw); + switch (node.operator) { + case "=": + case "&&=": + abort = true; + } + return true; + } + if (node instanceof AST_Call) { + descend(); + fn = node.expression.tail_node(); + var save; + if (fn instanceof AST_SymbolRef) { + fn = fn.fixed_value(); + save = refs.length; + } + if (!(fn instanceof AST_Lambda)) { + abort = true; + } else if (push_uniq(scanned, fn)) { + fn.walk(tw); + } + if (save >= 0) refs.length = save; + return true; + } + if (node instanceof AST_DWLoop) { + var save = refs.length; + descend(); + if (abort) refs.length = save; + return true; + } + if (node instanceof AST_For) { + if (node.init) node.init.walk(tw); + var save = refs.length; + if (node.condition) node.condition.walk(tw); + node.body.walk(tw); + if (node.step) node.step.walk(tw); + if (abort) refs.length = save; + return true; + } + if (node instanceof AST_ForEnumeration) { + node.object.walk(tw); + var save = refs.length; + node.init.walk(tw); + node.body.walk(tw); + if (abort) refs.length = save; + return true; + } + if (node instanceof AST_Scope) { + if (node === fn) return; + return true; + } + if (node instanceof AST_SymbolRef) { + if (node.definition() === def) refs.push(node); return true; } - if (node instanceof AST_SymbolRef && node.definition() === def) node.defined = true; }); body.walk(tw); + refs.forEach(function(ref) { + ref.defined = true; + }); function negate(node) { if (!(node instanceof AST_Binary)) return; @@ -8558,14 +9158,16 @@ merge(Compressor.prototype, { var cond = fuzzy_eval(compressor, self.condition); if (!cond) { AST_Node.warn("Condition always false [{file}:{line},{col}]", self.condition.start); - var body = [ make_node(AST_SimpleStatement, self.condition, { body: self.condition }) ]; + var body = [ + make_node(AST_SimpleStatement, self.condition, { body: self.condition }).transform(compressor), + ]; extract_declarations_from_unreachable_code(compressor, self.body, body); if (self.alternative) body.push(self.alternative); return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor); } else if (!(cond instanceof AST_Node)) { AST_Node.warn("Condition always true [{file}:{line},{col}]", self.condition.start); var body = [ - make_node(AST_SimpleStatement, self.condition, { body: self.condition }), + make_node(AST_SimpleStatement, self.condition, { body: self.condition }).transform(compressor), self.body, ]; if (self.alternative) extract_declarations_from_unreachable_code(compressor, self.alternative, body); @@ -8582,21 +9184,64 @@ merge(Compressor.prototype, { // here because they are only used in an equality comparison later on. self.condition = negated; var tmp = self.body; - self.body = self.alternative || make_node(AST_EmptyStatement, self); - self.alternative = tmp; + self.body = self.alternative; + self.alternative = is_empty(tmp) ? null : tmp; } - var body = [], var_defs = [], refs = []; - var body_exprs = sequencesize(self.body, body, var_defs, refs); - var alt_exprs = sequencesize(self.alternative, body, var_defs, refs); - if (body_exprs && alt_exprs) { + var body_defuns = []; + var body_var_defs = []; + var body_refs = []; + var body_exprs = sequencesize(self.body, body_defuns, body_var_defs, body_refs); + var alt_defuns = []; + var alt_var_defs = []; + var alt_refs = []; + var alt_exprs = sequencesize(self.alternative, alt_defuns, alt_var_defs, alt_refs); + if (body_exprs instanceof AST_BlockStatement || alt_exprs instanceof AST_BlockStatement) { + var body = [], var_defs = []; + if (body_exprs) { + [].push.apply(body, body_defuns); + [].push.apply(var_defs, body_var_defs); + if (body_exprs instanceof AST_BlockStatement) { + self.body = body_exprs; + } else if (body_exprs.length == 0) { + self.body = make_node(AST_EmptyStatement, self.body); + } else { + self.body = make_node(AST_SimpleStatement, self.body, { + body: make_sequence(self.body, body_exprs), + }); + } + body_refs.forEach(process_to_assign); + } + if (alt_exprs) { + [].push.apply(body, alt_defuns); + [].push.apply(var_defs, alt_var_defs); + if (alt_exprs instanceof AST_BlockStatement) { + self.alternative = alt_exprs; + } else if (alt_exprs.length == 0) { + self.alternative = null; + } else { + self.alternative = make_node(AST_SimpleStatement, self.alternative, { + body: make_sequence(self.alternative, alt_exprs), + }); + } + alt_refs.forEach(process_to_assign); + } if (var_defs.length > 0) body.push(make_node(AST_Var, self, { definitions: var_defs })); + if (body.length > 0) { + body.push(self); + return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor); + } + } else if (body_exprs && alt_exprs) { + var body = body_defuns.concat(alt_defuns); + if (body_var_defs.length > 0 || alt_var_defs.length > 0) body.push(make_node(AST_Var, self, { + definitions: body_var_defs.concat(alt_var_defs), + })); if (body_exprs.length == 0) { body.push(make_node(AST_SimpleStatement, self.condition, { body: alt_exprs.length > 0 ? make_node(AST_Binary, self, { - operator : "||", - left : self.condition, - right : make_sequence(self.alternative, alt_exprs) - }).transform(compressor) : self.condition.clone() + operator: "||", + left: self.condition, + right: make_sequence(self.alternative, alt_exprs), + }).transform(compressor) : self.condition.clone(), }).optimize(compressor)); } else if (alt_exprs.length == 0) { if (self_condition_length === negated_length && !negated_is_best @@ -8608,79 +9253,63 @@ merge(Compressor.prototype, { } body.push(make_node(AST_SimpleStatement, self, { body: make_node(AST_Binary, self, { - operator : negated_is_best ? "||" : "&&", - left : negated_is_best ? negated : self.condition, - right : make_sequence(self.body, body_exprs) - }).transform(compressor) + operator: negated_is_best ? "||" : "&&", + left: negated_is_best ? negated : self.condition, + right: make_sequence(self.body, body_exprs), + }).transform(compressor), }).optimize(compressor)); } else { body.push(make_node(AST_SimpleStatement, self, { body: make_node(AST_Conditional, self, { - condition : self.condition, - consequent : make_sequence(self.body, body_exprs), - alternative : make_sequence(self.alternative, alt_exprs) - }) + condition: self.condition, + consequent: make_sequence(self.body, body_exprs), + alternative: make_sequence(self.alternative, alt_exprs), + }), }).optimize(compressor)); } - refs.forEach(function(ref) { - ref.definition().references.push(ref); - }); - return make_node(AST_BlockStatement, self, { - body: body - }).optimize(compressor); + body_refs.forEach(process_to_assign); + alt_refs.forEach(process_to_assign); + return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor); } - if (is_empty(self.body)) { - self = make_node(AST_If, self, { - condition: negated, - body: self.alternative, - alternative: null - }); - } - if (self.body instanceof AST_Exit - && self.alternative instanceof AST_Exit - && self.body.TYPE == self.alternative.TYPE) { + if (is_empty(self.body)) self = make_node(AST_If, self, { + condition: negated, + body: self.alternative, + alternative: null, + }); + if (self.alternative instanceof AST_Exit && self.body.TYPE == self.alternative.TYPE) { var exit = make_node(self.body.CTOR, self, { value: make_node(AST_Conditional, self, { - condition : self.condition, - consequent : self.body.value || make_node(AST_Undefined, self.body).transform(compressor), - alternative : self.alternative.value || make_node(AST_Undefined, self.alternative).transform(compressor) - }) + condition: self.condition, + consequent: self.body.value || make_node(AST_Undefined, self.body).transform(compressor), + alternative: self.alternative.value + || make_node(AST_Undefined, self.alternative).transform(compressor), + }), }); - if (exit instanceof AST_Return) { - exit.in_bool = self.body.in_bool || self.alternative.in_bool; - } + if (exit instanceof AST_Return) exit.in_bool = self.body.in_bool || self.alternative.in_bool; return exit; } - if (self.body instanceof AST_If - && !self.body.alternative - && !self.alternative) { + if (self.body instanceof AST_If && !self.body.alternative && !self.alternative) { self = make_node(AST_If, self, { condition: make_node(AST_Binary, self.condition, { operator: "&&", left: self.condition, - right: self.body.condition + right: self.body.condition, }), body: self.body.body, - alternative: null + alternative: null, }); } - if (aborts(self.body)) { - if (self.alternative) { - var alt = self.alternative; - self.alternative = null; - return make_node(AST_BlockStatement, self, { - body: [ self, alt ] - }).optimize(compressor); - } + if (aborts(self.body) && self.alternative) { + var alt = self.alternative; + self.alternative = null; + return make_node(AST_BlockStatement, self, { body: [ self, alt ] }).optimize(compressor); } if (aborts(self.alternative)) { var body = self.body; self.body = self.alternative; self.condition = negated_is_best ? negated : self.condition.negate(compressor); self.alternative = null; - return make_node(AST_BlockStatement, self, { - body: [ self, body ] - }).optimize(compressor); + return make_node(AST_BlockStatement, self, { body: [ self, body ] }).optimize(compressor); } if (compressor.option("typeofs")) mark_locally_defined(self.condition, self.body, self.alternative); return self; @@ -8691,10 +9320,21 @@ merge(Compressor.prototype, { var exprs = []; for (var i = 0; i < stat.body.length; i++) { var line = stat.body[i]; + if (line instanceof AST_EmptyStatement) continue; + if (line instanceof AST_Exit) { + if (i == 0) return; + if (exprs.length > 0) { + line = line.clone(); + exprs.push(line.value || make_node(AST_Undefined, line).transform(compressor)); + line.value = make_sequence(stat, exprs); + } + var block = stat.clone(); + block.body = block.body.slice(i + 1); + block.body.unshift(line); + return block; + } if (line instanceof AST_LambdaDefinition) { defuns.push(line); - } else if (line instanceof AST_EmptyStatement) { - continue; } else if (line instanceof AST_SimpleStatement) { if (!compressor.option("sequences") && exprs.length > 0) return; exprs.push(line.body); @@ -8728,7 +9368,7 @@ merge(Compressor.prototype, { left: var_def.name.convert_symbol(AST_SymbolRef, function(ref) { refs.push(ref); }), - right: var_def.value + right: var_def.value, })); } } @@ -8856,20 +9496,12 @@ merge(Compressor.prototype, { left: self.expression, right: exp, }), - body: make_node(AST_BlockStatement, self, { - body: statements, - }), + body: make_node(AST_BlockStatement, self, { body: statements }), alternative: null, }).optimize(compressor); - if (exp) statements.unshift(make_node(AST_SimpleStatement, exp, { - body: exp, - })); - statements.unshift(make_node(AST_SimpleStatement, self.expression, { - body:self.expression, - })); - return make_node(AST_BlockStatement, self, { - body: statements, - }).optimize(compressor); + if (exp) statements.unshift(make_node(AST_SimpleStatement, exp, { body: exp })); + statements.unshift(make_node(AST_SimpleStatement, self.expression, { body: self.expression })); + return make_node(AST_BlockStatement, self, { body: statements }).optimize(compressor); case 2: if (!member(default_branch, body) || !no_break(body[1])) break; var statements = body[0].body.slice(); @@ -8887,14 +9519,10 @@ merge(Compressor.prototype, { left: self.expression, right: body[0].expression, }), - body: make_node(AST_BlockStatement, body[0], { - body: statements, - }), + body: make_node(AST_BlockStatement, body[0], { body: statements }), alternative: exclusive && alternative || null, }); - if (!exclusive && alternative) node = make_node(AST_BlockStatement, self, { - body: [ node, alternative ], - }); + if (!exclusive && alternative) node = make_node(AST_BlockStatement, self, { body: [ node, alternative ] }); return node.optimize(compressor); } return self; @@ -8949,16 +9577,12 @@ merge(Compressor.prototype, { if (self.bfinally) { body.push(make_node(AST_BlockStatement, self.bfinally, self.bfinally).optimize(compressor)); } - return make_node(AST_BlockStatement, self, { - body: body - }).optimize(compressor); + return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor); } if (self.bfinally && has_declarations_only(self.bfinally)) { var body = make_node(AST_BlockStatement, self.bfinally, self.bfinally).optimize(compressor); body = self.body.concat(body); - if (!self.bcatch) return make_node(AST_BlockStatement, self, { - body: body - }).optimize(compressor); + if (!self.bcatch) return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor); self.body = body; self.bfinally = null; } @@ -9001,16 +9625,20 @@ merge(Compressor.prototype, { right: value, }); a.push(assign); - name.fixed = function() { + var fixed = function() { return assign.right; }; - name.fixed.assigns = [ assign ]; + fixed.assigns = [ assign ]; + fixed.direct_access = def.direct_access; + fixed.escaped = def.escaped; + name.fixed = fixed; def.references.forEach(function(ref) { var assigns = ref.fixed && ref.fixed.assigns; if (assigns && assigns[0] === defn) assigns[0] = assign; }); def.references.push(name); } + def.assignments++; def.eliminated++; def.single_use = false; return a; @@ -9028,7 +9656,7 @@ merge(Compressor.prototype, { var scope = def.scope.resolve(); for (var s = def.scope; s !== scope;) { s = s.parent_scope; - if (s.var_names()[def.name]) return true; + if (s.var_names().has(def.name)) return true; } } @@ -9044,7 +9672,7 @@ merge(Compressor.prototype, { def.scope = scope; scope.variables.set(def.name, def); scope.enclosed.push(def); - scope.var_names()[def.name] = true; + scope.var_names().set(def.name, true); }), value: defn.value, }); @@ -9130,7 +9758,7 @@ merge(Compressor.prototype, { if (argname instanceof AST_DestructuredObject) { return argname.properties.length == 0 && !argname.rest && arg && !arg.may_throw_on_access(compressor); } - return argname.__unused; + return argname.unused; } : return_false; var side_effects = []; for (var i = 0; i < args.length; i++) { @@ -9138,7 +9766,7 @@ merge(Compressor.prototype, { if (drop_defaults && argname instanceof AST_DefaultValue && args[i].is_defined(compressor)) { argnames[i] = argname = argname.name; } - if (!argname || "__unused" in argname) { + if (!argname || argname.unused !== undefined) { var node = args[i].drop_side_effect_free(compressor); if (drop_fargs(argname)) { if (argname) argnames.splice(i, 1); @@ -9155,9 +9783,7 @@ merge(Compressor.prototype, { args[pos++] = make_sequence(call, side_effects); side_effects = []; } else { - args[pos++] = make_node(AST_Number, args[i], { - value: 0 - }); + args[pos++] = make_node(AST_Number, args[i], { value: 0 }); continue; } } @@ -9189,6 +9815,33 @@ merge(Compressor.prototype, { }) : arg); } + function avoid_await_yield(parent_scope) { + var avoid = []; + if (is_async(parent_scope)) avoid.push("await"); + if (is_generator(parent_scope)) avoid.push("yield"); + return avoid.length && makePredicate(avoid); + } + + function safe_from_await_yield(fn, avoid) { + if (!avoid) return true; + var safe = true; + var tw = new TreeWalker(function(node) { + if (!safe) return true; + if (node instanceof AST_Scope) { + if (node === fn) return; + if (is_arrow(node)) { + for (var i = 0; safe && i < node.argnames.length; i++) node.argnames[i].walk(tw); + } else if (node instanceof AST_LambdaDefinition && avoid[node.name.name]) { + safe = false; + } + return true; + } + if (node instanceof AST_Symbol && avoid[node.name] && node !== fn.name) safe = false; + }); + fn.walk(tw); + return safe; + } + OPT(AST_Call, function(self, compressor) { var exp = self.expression; var terminated = trim_optional_chain(self, compressor); @@ -9407,7 +10060,7 @@ merge(Compressor.prototype, { expression: exp.expression, property: "call", }), - args: args + args: args, }).optimize(compressor); } break; @@ -9421,11 +10074,11 @@ merge(Compressor.prototype, { self.args[0], make_node(AST_Call, self, { expression: exp.expression, - args: self.args.slice(1) - }) + args: self.args.slice(1), + }), ]) : make_node(AST_Call, self, { expression: exp.expression, - args: [] + args: [], })).optimize(compressor); } break; @@ -9503,24 +10156,27 @@ merge(Compressor.prototype, { if (argname instanceof AST_DefaultValue) { if (!has_default) has_default = 1; var arg = has_default == 1 && self.args[index]; - if (arg && !is_undefined(arg)) has_default = 2; - if (has_arg_refs(argname.value)) return false; + if (!is_undefined(arg)) has_default = 2; + if (has_arg_refs(fn, argname.value)) return false; argname = argname.name; } if (argname instanceof AST_Destructured) { has_destructured = true; - if (has_arg_refs(argname)) return false; + if (has_arg_refs(fn, argname)) return false; } return true; - }) && !(fn.rest instanceof AST_Destructured && has_arg_refs(fn.rest)); + }) && !(fn.rest instanceof AST_Destructured && has_arg_refs(fn, fn.rest)); var can_inline = can_drop && compressor.option("inline") && !self.is_expr_pure(compressor); if (can_inline && stat instanceof AST_Return) { var value = stat.value; - if (exp === fn && !fn.name && (!value || value.is_constant_expression()) && safe_from_await_yield(fn)) { + if (exp === fn + && !fn.name + && (!value || value.is_constant_expression()) + && safe_from_await_yield(fn, avoid_await_yield(compressor.find_parent(AST_Scope)))) { return make_sequence(self, convert_args(value)).optimize(compressor); } } - if (is_func) { + if (is_func && !fn.contains_this()) { var def, value, var_assigned = false; if (can_inline && !fn.uses_arguments @@ -9528,14 +10184,12 @@ merge(Compressor.prototype, { && !(fn.name && fn instanceof AST_LambdaExpression) && (exp === fn || !recursive_ref(compressor, def = exp.definition(), fn) && fn.is_constant_expression(find_scope(compressor))) - && !has_spread - && (value = can_flatten_body(stat)) - && !fn.contains_this()) { + && (value = can_flatten_body(stat))) { var replacing = exp === fn || def.single_use && def.references.length - def.replaced == 1; if (can_substitute_directly()) { var args = self.args.slice(); var refs = []; - args.push(value.clone(true).transform(new TreeTransformer(function(node) { + var retValue = value.clone(true).transform(new TreeTransformer(function(node) { if (node instanceof AST_SymbolRef) { var def = node.definition(); if (fn.variables.get(node.name) !== def) { @@ -9549,12 +10203,20 @@ merge(Compressor.prototype, { var parent = this.parent(); return parent ? maintain_this_binding(compressor, parent, node, arg) : arg; } - }))); + })); var save_inlined = fn.inlined; if (exp !== fn) fn.inlined = true; - var node = make_sequence(self, args.filter(function(arg) { - return arg; - })).optimize(compressor); + var exprs = []; + args.forEach(function(arg) { + if (!arg) return; + arg = arg.clone(true); + arg.walk(new TreeWalker(function(node) { + if (node instanceof AST_SymbolRef) refs.push(node); + })); + exprs.push(arg); + }, []); + exprs.push(retValue); + var node = make_sequence(self, exprs).optimize(compressor); fn.inlined = save_inlined; node = maintain_this_binding(compressor, parent, current, node); if (replacing || best_of_expression(node, self) === node) { @@ -9567,7 +10229,12 @@ merge(Compressor.prototype, { }); return node; } else if (!node.has_side_effects(compressor)) { - self.drop_side_effect_free = return_null; + self.drop_side_effect_free = function(compressor, first_in_statement) { + var self = this; + var exprs = self.args.slice(); + exprs.unshift(self.expression); + return make_sequence(self, exprs).drop_side_effect_free(compressor, first_in_statement); + }; } } var arg_used, insert, in_loop, scope; @@ -9583,7 +10250,7 @@ merge(Compressor.prototype, { && all(fn.body, is_empty) && (fn === exp ? fn_name_unused(fn, compressor) : !has_default && !has_destructured && !fn.rest) && !(is_arrow(fn) && fn.value) - && safe_from_await_yield(fn)) { + && safe_from_await_yield(fn, avoid_await_yield(compressor.find_parent(AST_Scope)))) { return make_sequence(self, convert_args()).optimize(compressor); } } @@ -9603,17 +10270,6 @@ merge(Compressor.prototype, { } return try_evaluate(compressor, self); - function has_arg_refs(node) { - var found = false; - node.walk(new TreeWalker(function(node) { - if (found) return true; - if (node instanceof AST_SymbolRef && fn.variables.get(node.name) === node.definition()) { - return found = true; - } - })); - return found; - } - function make_void_lhs(orig) { return make_node(AST_Dot, orig, { expression: make_node(AST_Array, orig, { elements: [] }), @@ -9691,35 +10347,6 @@ merge(Compressor.prototype, { return args; } - function avoid_await_yield() { - var avoid = []; - var parent_scope = scope || compressor.find_parent(AST_Scope); - if (is_async(parent_scope)) avoid.push("await"); - if (is_generator(parent_scope)) avoid.push("yield"); - return avoid.length && makePredicate(avoid); - } - - function safe_from_await_yield(node) { - var avoid = avoid_await_yield(); - if (!avoid) return true; - var safe = true; - var tw = new TreeWalker(function(node) { - if (!safe) return true; - if (node instanceof AST_Scope) { - if (node === fn) return; - if (is_arrow(node)) { - for (var i = 0; safe && i < node.argnames.length; i++) node.argnames[i].walk(tw); - } else if (node instanceof AST_LambdaDefinition && avoid[node.name.name]) { - safe = false; - } - return true; - } - if (node instanceof AST_Symbol && avoid[node.name] && node !== fn.name) safe = false; - }); - node.walk(tw); - return safe; - } - function noop_value() { return self.call_only ? make_node(AST_Number, self, { value: 0 }) : make_node(AST_Undefined, self); } @@ -9746,10 +10373,14 @@ merge(Compressor.prototype, { for (var i = 0; i < len; i++) { var line = fn.body[i]; if (line instanceof AST_Var) { - var assigned = var_assigned || !declarations_only(line); - if (assigned) { + if (var_assigned) { + if (!stat) continue; + if (!(stat instanceof AST_SimpleStatement)) return false; + if (!declarations_only(line)) stat = null; + } else if (!declarations_only(line)) { + if (stat && !(stat instanceof AST_SimpleStatement)) return false; + stat = null; var_assigned = true; - if (stat) return false; } } else if (line instanceof AST_AsyncDefun || line instanceof AST_Defun @@ -9771,13 +10402,14 @@ merge(Compressor.prototype, { } function can_substitute_directly() { - if (has_default || has_destructured || var_assigned || fn.rest) return; + if (has_default || has_destructured || has_spread || var_assigned || fn.rest) return; if (compressor.option("inline") < 2 && fn.argnames.length) return; if (!fn.variables.all(function(def) { return def.references.length - def.replaced < 2 && def.orig[0] instanceof AST_SymbolFunarg; })) return; + var scope = compressor.find_parent(AST_Scope); var abort = false; - var avoid = avoid_await_yield(); + var avoid = avoid_await_yield(scope); var begin; var in_order = []; var side_effects = false; @@ -9821,8 +10453,7 @@ merge(Compressor.prototype, { while (end-- > begin && fn.argnames[end] === in_order.pop()); end++; } - var scope = side_effects && !in_order && compressor.find_parent(AST_Scope); - return end <= begin || all(self.args.slice(begin, end), scope ? function(funarg) { + return end <= begin || all(self.args.slice(begin, end), side_effects && !in_order ? function(funarg) { return funarg.is_constant_expression(scope); } : function(funarg) { return !funarg.has_side_effects(compressor); @@ -9830,30 +10461,33 @@ merge(Compressor.prototype, { } function var_exists(defined, name) { - return defined[name] || identifier_atom[name] || scope.var_names()[name]; + return defined.has(name) || identifier_atom[name] || scope.var_names().has(name); } - function can_inject_args(defined, used, safe_to_inject) { + function can_inject_args(defined, safe_to_inject) { var abort = false; fn.each_argname(function(arg) { if (abort) return; - if (arg.__unused) return; + if (arg.unused) return; if (!safe_to_inject || var_exists(defined, arg.name)) return abort = true; - used[arg.name] = true; + arg_used.set(arg.name, true); if (in_loop) in_loop.push(arg.definition()); }); return !abort; } - function can_inject_vars(defined, used, safe_to_inject) { + function can_inject_vars(defined, safe_to_inject) { for (var i = 0; i < fn.body.length; i++) { var stat = fn.body[i]; if (stat instanceof AST_LambdaDefinition) { - if (!safe_to_inject || var_exists(used, stat.name.name)) return false; + var name = stat.name; + if (!safe_to_inject) return false; + if (arg_used.has(name.name)) return false; + if (var_exists(defined, name.name)) return false; if (!all(stat.enclosed, function(def) { - return def.scope === stat || !defined[def.name]; + return def.scope === scope || def.scope === stat || !defined.has(def.name); })) return false; - if (in_loop) in_loop.push(stat.name.definition()); + if (in_loop) in_loop.push(name.definition()); continue; } if (!(stat instanceof AST_Var)) continue; @@ -9868,12 +10502,12 @@ merge(Compressor.prototype, { } function can_inject_symbols() { - var defined = Object.create(null); + var defined = new Dictionary(); var level = 0, child; scope = current; do { if (scope.variables) scope.variables.each(function(def) { - defined[def.name] = true; + defined.set(def.name, true); }); child = scope; scope = compressor.parent(level++); @@ -9886,33 +10520,30 @@ merge(Compressor.prototype, { if (scope.init === child) continue; if (scope.object === child) continue; in_loop = []; - } else if (scope instanceof AST_SymbolRef) { - if (scope.fixed_value() instanceof AST_Scope) return false; } } while (!(scope instanceof AST_Scope)); insert = scope.body.indexOf(child) + 1; if (!insert) return false; - if (!safe_from_await_yield(fn)) return false; - var safe_to_inject = exp !== fn || fn.parent_scope.resolve() === scope; + if (!safe_from_await_yield(fn, avoid_await_yield(scope))) return false; + var safe_to_inject = (exp !== fn || fn.parent_scope.resolve() === scope) && !scope.pinned(); if (scope instanceof AST_Toplevel) { if (compressor.toplevel.vars) { - defined["arguments"] = true; + defined.set("arguments", true); } else { safe_to_inject = false; } } + arg_used = new Dictionary(); var inline = compressor.option("inline"); - arg_used = Object.create(defined); - if (!can_inject_args(defined, arg_used, inline >= 2 && safe_to_inject)) return false; - var used = Object.create(arg_used); - if (!can_inject_vars(defined, used, inline >= 3 && safe_to_inject)) return false; + if (!can_inject_args(defined, inline >= 2 && safe_to_inject)) return false; + if (!can_inject_vars(defined, inline >= 3 && safe_to_inject)) return false; return !in_loop || in_loop.length == 0 || !is_reachable(fn, in_loop); } function append_var(decls, expressions, name, value) { var def = name.definition(); - if (!scope.var_names()[name.name]) { - scope.var_names()[name.name] = true; + if (!scope.var_names().has(name.name)) { + scope.var_names().set(name.name, true); decls.push(make_node(AST_VarDef, name, { name: name, value: null, @@ -9922,6 +10553,7 @@ merge(Compressor.prototype, { scope.enclosed.push(def); if (!value) return; var sym = make_node(AST_SymbolRef, name, name); + def.assignments++; def.references.push(sym); expressions.push(make_node(AST_Assign, self, { operator: "=", @@ -9946,12 +10578,14 @@ merge(Compressor.prototype, { name = argname; } var value = self.args[i]; - if (name.__unused || scope.var_names()[name.name]) { + if (name.unused || scope.var_names().has(name.name)) { if (value) expressions.push(value); } else { var symbol = make_node(AST_SymbolVar, name, name); - name.definition().orig.push(symbol); - if ("__unused" in name) { + var def = name.definition(); + def.orig.push(symbol); + def.eliminated++; + if (name.unused !== undefined) { append_var(decls, expressions, symbol); if (value) expressions.push(value); } else { @@ -9964,7 +10598,7 @@ merge(Compressor.prototype, { expressions.reverse(); for (i = default_args.length; --i >= 0;) { var node = default_args[i]; - if ("__unused" in node.name) { + if (node.name.unused !== undefined) { expressions.push(node.value); } else { var sym = make_node(AST_SymbolRef, node.name, node.name); @@ -9983,7 +10617,7 @@ merge(Compressor.prototype, { operator: "=", left: make_node(AST_DestructuredArray, self, { elements: fn.argnames.map(function(argname) { - if (argname.__unused) return make_node(AST_Hole, argname); + if (argname.unused) return make_node(AST_Hole, argname); return argname.convert_symbol(AST_SymbolRef, process); }), rest: fn.rest && fn.rest.convert_symbol(AST_SymbolRef, process), @@ -9993,61 +10627,60 @@ merge(Compressor.prototype, { function process(ref, name) { var def = name.definition(); + def.assignments++; def.references.push(ref); var symbol = make_node(AST_SymbolVar, name, name); def.orig.push(symbol); + def.eliminated++; append_var(decls, expressions, symbol); } } - function flatten_var(name) { - var redef = name.definition().redefined(); - if (redef) { - name = name.clone(); - name.thedef = redef; - } - return name; - } - function flatten_vars(decls, expressions) { var args = [ insert, 0 ]; - var decl_var = [], expr_var = [], expr_loop = []; - for (var i = 0; i < fn.body.length; i++) { - var stat = fn.body[i]; - if (stat instanceof AST_LambdaDefinition) { - if (in_loop) { - var name = make_node(AST_SymbolVar, stat.name, flatten_var(stat.name)); - name.definition().orig.push(name); - append_var(decls, expressions, name, to_func_expr(stat, true)); - } else { - var def = stat.name.definition(); - scope.functions.set(def.name, def); - scope.variables.set(def.name, def); - scope.enclosed.push(def); - scope.var_names()[def.name] = true; - args.push(stat); - } - continue; + var decl_var = [], expr_fn = [], expr_var = [], expr_loop = [], exprs = []; + fn.body.filter(in_loop ? function(stat) { + if (!(stat instanceof AST_LambdaDefinition)) return true; + var name = make_node(AST_SymbolVar, stat.name, flatten_var(stat.name)); + var def = name.definition(); + def.fixed = false; + def.orig.push(name); + def.eliminated++; + append_var(decls, expr_fn, name, to_func_expr(stat, true)); + return false; + } : function(stat) { + if (!(stat instanceof AST_LambdaDefinition)) return true; + var def = stat.name.definition(); + scope.functions.set(def.name, def); + scope.variables.set(def.name, def); + scope.enclosed.push(def); + scope.var_names().set(def.name, true); + args.push(stat); + return false; + }).forEach(function(stat) { + if (!(stat instanceof AST_Var)) { + if (stat instanceof AST_SimpleStatement) exprs.push(stat.body); + return; } - if (!(stat instanceof AST_Var)) continue; for (var j = 0; j < stat.definitions.length; j++) { var var_def = stat.definitions[j]; var name = flatten_var(var_def.name); - append_var(decl_var, expr_var, name, var_def.value); - if (in_loop && !HOP(arg_used, name.name)) { - var def = fn.variables.get(name.name); - var sym = make_node(AST_SymbolRef, name, name); - def.references.push(sym); - expr_loop.push(make_node(AST_Assign, var_def, { - operator: "=", - left: sym, - right: make_node(AST_Undefined, name), - })); + var value = var_def.value; + if (value && exprs.length > 0) { + exprs.push(value); + value = make_sequence(var_def, exprs); + exprs = []; } + append_var(decl_var, expr_var, name, value); + if (!in_loop) continue; + if (arg_used.has(name.name)) continue; + if (name.definition().orig.length == 1 && fn.functions.has(name.name)) continue; + expr_loop.push(init_ref(compressor, name)); } - } + }); [].push.apply(decls, decl_var); [].push.apply(expressions, expr_loop); + [].push.apply(expressions, expr_fn); [].push.apply(expressions, expr_var); return args; } @@ -10055,21 +10688,19 @@ merge(Compressor.prototype, { function flatten_fn() { var decls = []; var expressions = []; - if (has_default > 1 || has_destructured || fn.rest) { + if (has_default > 1 || has_destructured || has_spread || fn.rest) { flatten_destructured(decls, expressions); } else { flatten_args(decls, expressions); } var args = flatten_vars(decls, expressions); expressions.push(value); - if (decls.length) args.push(make_node(AST_Var, fn, { - definitions: decls - })); + if (decls.length) args.push(make_node(AST_Var, fn, { definitions: decls })); [].splice.apply(scope.body, args); fn.enclosed.forEach(function(def) { - if (scope.var_names()[def.name]) return; + if (scope.var_names().has(def.name)) return; scope.enclosed.push(def); - scope.var_names()[def.name] = true; + scope.var_names().set(def.name, true); }); return expressions; } @@ -10215,42 +10846,52 @@ merge(Compressor.prototype, { OPT(AST_UnaryPrefix, function(self, compressor) { var op = self.operator; var exp = self.expression; - if (compressor.option("evaluate") && op == "delete" && !may_not_delete(exp)) { - return make_sequence(self, [ exp, make_node(AST_True, self) ]).optimize(compressor); - } if (compressor.option("sequences") && can_lift()) { var seq = lift_sequence_in_expression(self, compressor); if (seq !== self) return seq.optimize(compressor); } - if (compressor.option("side_effects") && op == "void") { + switch (op) { + case "+": + if (!compressor.option("evaluate")) break; + if (!exp.is_number(compressor, true)) break; + var parent = compressor.parent(); + if (parent instanceof AST_UnaryPrefix && parent.operator == "delete") break; + return exp; + case "-": + if (exp instanceof AST_Infinity) exp = exp.transform(compressor); + // avoids infinite recursion of numerals + if (exp instanceof AST_Number || exp instanceof AST_Infinity) return self; + break; + case "!": + if (!compressor.option("booleans")) break; + if (exp.is_truthy()) return make_sequence(self, [ exp, make_node(AST_False, self) ]).optimize(compressor); + if (compressor.in_boolean_context()) { + // !!foo ---> foo, if we're in boolean context + if (exp instanceof AST_UnaryPrefix && exp.operator == "!") return exp.expression; + if (exp instanceof AST_Binary) { + self = best_of(compressor, self, exp.negate(compressor, first_in_statement(compressor))); + } + } + break; + case "delete": + if (!compressor.option("evaluate")) break; + if (may_not_delete(exp)) break; + return make_sequence(self, [ exp, make_node(AST_True, self) ]).optimize(compressor); + case "typeof": + if (!compressor.option("booleans")) break; + if (!compressor.in_boolean_context()) break; + // typeof always returns a non-empty string, thus always truthy + AST_Node.warn("Boolean expression always true [{file}:{line},{col}]", self.start); + var exprs = [ make_node(AST_True, self) ]; + if (!(exp instanceof AST_SymbolRef && can_drop_symbol(exp, compressor))) exprs.unshift(exp); + return make_sequence(self, exprs).optimize(compressor); + case "void": + if (!compressor.option("side_effects")) break; exp = exp.drop_side_effect_free(compressor); if (!exp) return make_node(AST_Undefined, self).optimize(compressor); self.expression = exp; return self; } - if (compressor.option("booleans")) { - if (op == "!" && exp.is_truthy()) { - return make_sequence(self, [ exp, make_node(AST_False, self) ]).optimize(compressor); - } else if (compressor.in_boolean_context()) switch (op) { - case "!": - if (exp instanceof AST_UnaryPrefix && exp.operator == "!") { - // !!foo ---> foo, if we're in boolean context - return exp.expression; - } - if (exp instanceof AST_Binary) { - self = best_of(compressor, self, exp.negate(compressor, first_in_statement(compressor))); - } - break; - case "typeof": - // typeof always returns a non-empty string, thus it's - // always true in booleans - AST_Node.warn("Boolean expression always true [{file}:{line},{col}]", self.start); - var exprs = [ make_node(AST_True, self) ]; - if (!(exp instanceof AST_SymbolRef && can_drop_symbol(exp, compressor))) exprs.unshift(exp); - return make_sequence(self, exprs).optimize(compressor); - } - } - if (op == "-" && exp instanceof AST_Infinity) exp = exp.transform(compressor); if (compressor.option("evaluate") && exp instanceof AST_Binary && SIGN_OPS[op] @@ -10260,14 +10901,12 @@ merge(Compressor.prototype, { operator: exp.operator, left: make_node(AST_UnaryPrefix, exp.left, { operator: op, - expression: exp.left + expression: exp.left, }), - right: exp.right + right: exp.right, }); } - // avoids infinite recursion of numerals - return op == "-" && (exp instanceof AST_Number || exp instanceof AST_Infinity) - ? self : try_evaluate(compressor, self); + return try_evaluate(compressor, self); function may_not_delete(node) { return node instanceof AST_Infinity @@ -10299,13 +10938,7 @@ merge(Compressor.prototype, { if (compressor.option("side_effects")) { var exp = self.expression; if (exp instanceof AST_Await) return exp.optimize(compressor); - if (exp instanceof AST_UnaryPrefix) { - if (exp.expression instanceof AST_Await) return exp.optimize(compressor); - if (exp.operator == "void") return make_node(AST_UnaryPrefix, self, { - operator: "void", - expression: make_node(AST_Await, self, { expression: exp.expression }), - }).optimize(compressor); - } + if (exp instanceof AST_UnaryPrefix && exp.expression instanceof AST_Await) return exp.optimize(compressor); for (var level = 0, node = self, parent; parent = compressor.parent(level++); node = parent) { if (is_arrow(parent)) { if (parent.value === node) return exp.optimize(compressor); @@ -10314,7 +10947,7 @@ merge(Compressor.prototype, { do { node = parent; parent = compressor.parent(level++); - if (parent instanceof AST_Try && parent.bfinally && parent.bfinally !== node) { + if (parent instanceof AST_Try && (parent.bfinally || parent.bcatch) !== node) { drop = false; break; } @@ -10427,33 +11060,24 @@ merge(Compressor.prototype, { return !node.has_side_effects(compressor); } - OPT(AST_Binary, function(self, compressor) { - function reversible() { - return self.left.is_constant() - || self.right.is_constant() - || !self.left.has_side_effects(compressor) - && !self.right.has_side_effects(compressor); - } - function reverse(op) { - if (reversible()) { - if (op) self.operator = op; - var tmp = self.left; - self.left = self.right; - self.right = tmp; - } - } - function swap_chain() { - var rhs = self.right; - self.left = make_node(AST_Binary, self, { - operator: self.operator, - left: self.left, - right: rhs.left, - start: self.left.start, - end: rhs.left.end - }); - self.right = rhs.right; + function swap_chain(self, compressor) { + var rhs = self.right; + self.left = make_node(AST_Binary, self, { + operator: self.operator, + left: self.left, + right: rhs.left, + start: self.left.start, + end: rhs.left.end + }); + self.right = rhs.right; + if (compressor) { self.left = self.left.transform(compressor); + } else if (self.operator == rhs.left.operator) { + swap_chain(self.left); } + } + + OPT(AST_Binary, function(self, compressor) { if (commutativeOperators[self.operator] && self.right.is_constant() && !self.left.is_constant() @@ -10532,30 +11156,20 @@ merge(Compressor.prototype, { // void 0 !== x && null !== x ---> null != x // void 0 === x || null === x ---> null == x var lhs = self.left; - if (lhs.operator == self.operator) { - lhs = lhs.right; - } + if (lhs.operator == self.operator) lhs = lhs.right; + var expr = lhs.right; + if (expr instanceof AST_Assign && expr.operator == "=") expr = expr.left; if (lhs instanceof AST_Binary && lhs.operator == (self.operator == "&&" ? "!==" : "===") && self.right instanceof AST_Binary && lhs.operator == self.right.operator && (is_undefined(lhs.left, compressor) && self.right.left instanceof AST_Null || lhs.left instanceof AST_Null && is_undefined(self.right.left, compressor)) - && !lhs.right.has_side_effects(compressor) - && lhs.right.equivalent_to(self.right.right)) { - var combined = make_node(AST_Binary, self, { - operator: lhs.operator.slice(0, -1), - left: make_node(AST_Null, self), - right: lhs.right - }); - if (lhs !== self.left) { - combined = make_node(AST_Binary, self, { - operator: self.operator, - left: self.left.left, - right: combined - }); - } - return combined; + && !expr.has_side_effects(compressor) + && expr.equivalent_to(self.right.right)) { + lhs.operator = lhs.operator.slice(0, -1); + lhs.left = make_node(AST_Null, self); + return self.left; } break; } @@ -10573,21 +11187,17 @@ merge(Compressor.prototype, { } if (in_bool) switch (self.operator) { case "+": - var ll = self.left.evaluate(compressor); - var rr = self.right.evaluate(compressor); - if (ll && typeof ll == "string") { + var ev = self.left.evaluate(compressor, true); + if (ev && typeof ev == "string" || (ev = self.right.evaluate(compressor, true)) && typeof ev == "string") { AST_Node.warn("+ in boolean context always true [{file}:{line},{col}]", self.start); - return make_sequence(self, [ - self.right, - make_node(AST_True, self) - ]).optimize(compressor); - } - if (rr && typeof rr == "string") { - AST_Node.warn("+ in boolean context always true [{file}:{line},{col}]", self.start); - return make_sequence(self, [ - self.left, - make_node(AST_True, self) - ]).optimize(compressor); + var exprs = []; + if (self.left.evaluate(compressor) instanceof AST_Node) exprs.push(self.left); + if (self.right.evaluate(compressor) instanceof AST_Node) exprs.push(self.right); + if (exprs.length < 2) { + exprs.push(make_node(AST_True, self)); + return make_sequence(self, exprs).optimize(compressor); + } + self.truthy = true; } break; case "==": @@ -10623,7 +11233,7 @@ merge(Compressor.prototype, { && lazy_op[self.operator] && self.right instanceof AST_Binary && self.operator == self.right.operator) { - swap_chain(); + swap_chain(self, compressor); } if (compressor.option("strings") && self.operator == "+") { // "foo" + 42 + "" ---> "foo" + 42 @@ -10643,7 +11253,8 @@ merge(Compressor.prototype, { && self.left.operator == "+" && self.left.left instanceof AST_String && self.left.left.value == "" - && self.right.is_string(compressor)) { + && self.right.is_string(compressor) + && (self.left.right.is_constant() || !self.right.has_side_effects(compressor))) { self.left = self.left.right; return self.optimize(compressor); } @@ -10654,7 +11265,7 @@ merge(Compressor.prototype, { && (self.left.is_string(compressor) && self.right.is_string(compressor) || self.right.left.is_string(compressor) && (self.left.is_constant() || !self.right.right.has_side_effects(compressor)))) { - swap_chain(); + swap_chain(self, compressor); } } if (compressor.option("evaluate")) { @@ -10669,20 +11280,15 @@ merge(Compressor.prototype, { AST_Node.warn("Condition left of && always true [{file}:{line},{col}]", self.start); return make_sequence(self, [ self.left, self.right ]).optimize(compressor); } - var rr = self.right.evaluate(compressor); - if (!rr) { - if (in_bool) { + if (!self.right.evaluate(compressor, true)) { + if (in_bool && !(self.right.evaluate(compressor) instanceof AST_Node)) { AST_Node.warn("Boolean && always false [{file}:{line},{col}]", self.start); - return make_sequence(self, [ - self.left, - make_node(AST_False, self) - ]).optimize(compressor); + return make_sequence(self, [ self.left, make_node(AST_False, self) ]).optimize(compressor); } else self.falsy = true; - } else if (!(rr instanceof AST_Node)) { - if (in_bool || parent.operator == "&&" && parent.left === compressor.self()) { - AST_Node.warn("Dropping side-effect-free && [{file}:{line},{col}]", self.start); - return self.left.optimize(compressor); - } + } else if ((in_bool || parent.operator == "&&" && parent.left === compressor.self()) + && !(self.right.evaluate(compressor) instanceof AST_Node)) { + AST_Node.warn("Dropping side-effect-free && [{file}:{line},{col}]", self.start); + return self.left.optimize(compressor); } // (x || false) && y ---> x ? y : false if (self.left.operator == "||") { @@ -10717,25 +11323,21 @@ merge(Compressor.prototype, { }); return maintain_this_binding(compressor, parent, compressor.self(), self.left).optimize(compressor); } - var rr = self.right.evaluate(compressor); - if (!rr) { - if (in_bool || parent.operator == "||" && parent.left === compressor.self()) { - AST_Node.warn("Dropping side-effect-free {operator} [{file}:{line},{col}]", { - operator: self.operator, - file: self.start.file, - line: self.start.line, - col: self.start.col, - }); - return self.left.optimize(compressor); - } - } else if (!nullish && !(rr instanceof AST_Node)) { - if (in_bool) { + var rr; + if (!nullish && (rr = self.right.evaluate(compressor, true)) && !(rr instanceof AST_Node)) { + if (in_bool && !(self.right.evaluate(compressor) instanceof AST_Node)) { AST_Node.warn("Boolean || always true [{file}:{line},{col}]", self.start); - return make_sequence(self, [ - self.left, - make_node(AST_True, self) - ]).optimize(compressor); + return make_sequence(self, [ self.left, make_node(AST_True, self) ]).optimize(compressor); } else self.truthy = true; + } else if ((in_bool || parent.operator == "||" && parent.left === compressor.self()) + && !self.right.evaluate(compressor)) { + AST_Node.warn("Dropping side-effect-free {operator} [{file}:{line},{col}]", { + operator: self.operator, + file: self.start.file, + line: self.start.line, + col: self.start.col, + }); + return self.left.optimize(compressor); } // x && true || y ---> x ? true : y if (!nullish && self.left.operator == "&&") { @@ -10938,19 +11540,17 @@ merge(Compressor.prototype, { if (self.left.value == 0) { if (self.right.is_boolean(compressor)) return make_node(AST_UnaryPrefix, self, { operator: "+", - expression: self.right + expression: self.right, }).optimize(compressor); if (self.right.is_number(compressor) && !self.right.is_negative_zero()) return self.right; } break; // 1 * n ---> n case "*": - if (self.left.value == 1) { - return self.right.is_number(compressor) ? self.right : make_node(AST_UnaryPrefix, self, { - operator: "+", - expression: self.right - }).optimize(compressor); - } + if (self.left.value == 1) return make_node(AST_UnaryPrefix, self, { + operator: "+", + expression: self.right, + }).optimize(compressor); break; } if (self.right instanceof AST_Number && !self.left.is_constant()) switch (self.operator) { @@ -10959,28 +11559,24 @@ merge(Compressor.prototype, { if (self.right.value == 0) { if (self.left.is_boolean(compressor)) return make_node(AST_UnaryPrefix, self, { operator: "+", - expression: self.left + expression: self.left, }).optimize(compressor); if (self.left.is_number(compressor) && !self.left.is_negative_zero()) return self.left; } break; // n - 0 ---> n case "-": - if (self.right.value == 0) { - return self.left.is_number(compressor) ? self.left : make_node(AST_UnaryPrefix, self, { - operator: "+", - expression: self.left - }).optimize(compressor); - } + if (self.right.value == 0) return make_node(AST_UnaryPrefix, self, { + operator: "+", + expression: self.left, + }).optimize(compressor); break; // n / 1 ---> n case "/": - if (self.right.value == 1) { - return self.left.is_number(compressor) ? self.left : make_node(AST_UnaryPrefix, self, { - operator: "+", - expression: self.left - }).optimize(compressor); - } + if (self.right.value == 1) return make_node(AST_UnaryPrefix, self, { + operator: "+", + expression: self.left, + }).optimize(compressor); break; } } @@ -11105,6 +11701,22 @@ merge(Compressor.prototype, { && self.left.expression instanceof AST_Number && self.left.expression.value == 1; } } + + function reversible() { + return self.left.is_constant() + || self.right.is_constant() + || !self.left.has_side_effects(compressor) + && !self.right.has_side_effects(compressor); + } + + function reverse(op) { + if (reversible()) { + if (op) self.operator = op; + var tmp = self.left; + self.left = self.right; + self.right = tmp; + } + } }); OPT(AST_SymbolExport, function(self) { @@ -11190,9 +11802,9 @@ merge(Compressor.prototype, { var scope = self.scope.resolve(); fixed.enclosed.forEach(function(def) { if (fixed.variables.has(def.name)) return; - if (scope.var_names()[def.name]) return; + if (scope.var_names().has(def.name)) return; scope.enclosed.push(def); - scope.var_names()[def.name] = true; + scope.var_names().set(def.name, true); }); } var value; @@ -11261,11 +11873,11 @@ merge(Compressor.prototype, { def.replaced++; return value; } - var local = self.fixed !== def.fixed; - if (fixed && (local || def.should_replace !== false)) { + var state; + if (fixed && (state = self.fixed || def.fixed).should_replace !== false) { var ev, init; if (fixed instanceof AST_This) { - if (!is_funarg(def) && same_scope(def)) init = fixed; + if (!is_funarg(def) && same_scope(def) && !cross_class(def)) init = fixed; } else if ((ev = fixed.evaluate(compressor, true)) !== fixed && typeof ev != "function" && (ev === null @@ -11275,20 +11887,22 @@ merge(Compressor.prototype, { init = make_node_from_constant(ev, fixed); } if (init) { - if (!local && def.should_replace === undefined) { + if (state.should_replace === undefined) { var value_length = init.optimize(compressor).print_to_string().length; if (!has_symbol_ref(fixed)) { value_length = Math.min(value_length, fixed.print_to_string().length); } var name_length = def.name.length; if (compressor.option("unused") && !compressor.exposed(def)) { - var referenced = def.references.length - def.replaced; - name_length += (name_length + 2 + value_length) / (referenced - def.assignments); + var refs = def.references.length - def.replaced - def.assignments; + refs = Math.min(refs, def.references.filter(function(ref) { + return ref.fixed === state; + }).length); + name_length += (name_length + 2 + value_length) / Math.max(1, refs); } - var delta = value_length - Math.floor(name_length); - def.should_replace = delta < compressor.eval_threshold; + state.should_replace = value_length - Math.floor(name_length) < compressor.eval_threshold; } - if (local || def.should_replace) { + if (state.should_replace) { var value; if (has_symbol_ref(fixed)) { value = init.optimize(compressor); @@ -11305,6 +11919,14 @@ merge(Compressor.prototype, { } return self; + function cross_class(def) { + var scope = self.scope; + while (scope !== def.scope) { + if (scope instanceof AST_Class) return true; + scope = scope.parent_scope; + } + } + function has_symbol_ref(value) { var found; value.walk(new TreeWalker(function(node) { @@ -11323,42 +11945,98 @@ merge(Compressor.prototype, { && tag.expression.name == "String"; } + function decode_template(str) { + var malformed = false; + str = str.replace(/\\(u\{[^{}]*\}?|u[\s\S]{0,4}|x[\s\S]{0,2}|[0-9]+|[\s\S])/g, function(match, seq) { + var ch = decode_escape_sequence(seq); + if (typeof ch == "string") return ch; + malformed = true; + }); + if (!malformed) return str; + } + OPT(AST_Template, function(self, compressor) { if (!compressor.option("templates")) return self; var tag = self.tag; if (!tag || is_raw_tag(compressor, tag)) { - var exprs = self.expressions.slice(); - var strs = self.strings.slice(); - var CHANGED = false; - for (var i = exprs.length; --i >= 0;) { - var node = exprs[i]; - var ev = node.evaluate(compressor); - if (ev === node) continue; - if (tag && /\r|\\|`/.test(ev)) continue; - ev = ("" + ev).replace(/\r|\\|`/g, function(s) { - return "\\" + (s == "\r" ? "r" : s); - }); - if (ev.length > node.print_to_string().length + 3) continue; - var combined = strs[i] + ev + strs[i + 1]; - if (typeof make_node(AST_Template, self, { - expressions: [], - strings: [ combined ], - tag: tag, - }).evaluate(compressor) != typeof make_node(AST_Template, self, { - expressions: [ node ], - strings: strs.slice(i, i + 2), - tag: tag, - }).evaluate(compressor)) continue; - exprs.splice(i, 1); - strs.splice(i, 2, combined); - CHANGED = true; + var exprs = []; + var strs = []; + for (var i = 0, status; i < self.strings.length; i++) { + var str = self.strings[i]; + if (!tag) { + var trimmed = decode_template(str); + if (trimmed) str = escape_literal(trimmed); + } + if (i > 0) { + var node = self.expressions[i - 1]; + var value = should_join(node); + if (value) { + var prev = strs[strs.length - 1]; + var joined = prev + value + str; + var decoded; + if (tag || typeof (decoded = decode_template(joined)) == status) { + strs[strs.length - 1] = decoded ? escape_literal(decoded) : joined; + continue; + } + } + exprs.push(node); + } + strs.push(str); + if (!tag) status = typeof trimmed; } - if (CHANGED) { - self.expressions = exprs; - self.strings = strs; + if (!tag && strs.length > 1) { + if (strs[strs.length - 1] == "") return make_node(AST_Binary, self, { + operator: "+", + left: make_node(AST_Template, self, { + expressions: exprs.slice(0, -1), + strings: strs.slice(0, -1), + tag: tag, + }).transform(compressor), + right: exprs[exprs.length - 1], + }).optimize(compressor); + if (strs[0] == "") { + var left = make_node(AST_Binary, self, { + operator: "+", + left: make_node(AST_String, self, { value: "" }), + right: exprs[0], + }); + for (var i = 1; strs[i] == "" && i < exprs.length; i++) { + left = make_node(AST_Binary, self, { + operator: "+", + left: left, + right: exprs[i], + }); + } + return best_of(compressor, self, make_node(AST_Binary, self, { + operator: "+", + left: left.transform(compressor), + right: make_node(AST_Template, self, { + expressions: exprs.slice(i), + strings: strs.slice(i), + tag: tag, + }).transform(compressor), + }).optimize(compressor)); + } } + self.expressions = exprs; + self.strings = strs; } return try_evaluate(compressor, self); + + function escape_literal(str) { + return str.replace(/\r|\\|`|\${/g, function(s) { + return "\\" + (s == "\r" ? "r" : s); + }); + } + + function should_join(node) { + var ev = node.evaluate(compressor); + if (ev === node) return; + if (tag && /\r|\\|`/.test(ev)) return; + ev = escape_literal("" + ev); + if (ev.length > node.print_to_string().length + "${}".length) return; + return ev; + } }); function is_atomic(lhs, self) { @@ -11382,9 +12060,7 @@ merge(Compressor.prototype, { if (lhs && is_atomic(lhs, self)) return self; return make_node(AST_UnaryPrefix, self, { operator: "void", - expression: make_node(AST_Number, self, { - value: 0 - }) + expression: make_node(AST_Number, self, { value: 0 }), }); }); @@ -11396,12 +12072,8 @@ merge(Compressor.prototype, { } return make_node(AST_Binary, self, { operator: "/", - left: make_node(AST_Number, self, { - value: 1 - }), - right: make_node(AST_Number, self, { - value: 0 - }) + left: make_node(AST_Number, self, { value: 1 }), + right: make_node(AST_Number, self, { value: 0 }), }); }); @@ -11411,12 +12083,8 @@ merge(Compressor.prototype, { if (!lhs && !find_scope(compressor).find_variable("NaN")) return self; return make_node(AST_Binary, self, { operator: "/", - left: make_node(AST_Number, self, { - value: 0 - }), - right: make_node(AST_Number, self, { - value: 0 - }) + left: make_node(AST_Number, self, { value: 0 }), + right: make_node(AST_Number, self, { value: 0 }), }); }); @@ -11424,9 +12092,7 @@ merge(Compressor.prototype, { var reachable = false; var find_ref = new TreeWalker(function(node) { if (reachable) return true; - if (node instanceof AST_SymbolRef && member(node.definition(), defs)) { - return reachable = true; - } + if (node instanceof AST_SymbolRef && member(node.definition(), defs)) return reachable = true; }); var scan_scope = new TreeWalker(function(node) { if (reachable) return true; @@ -11449,7 +12115,7 @@ merge(Compressor.prototype, { if (compressor.option("dead_code")) { if (self.left instanceof AST_PropAccess) { if (self.operator == "=") { - if (self.__drop) { + if (self.redundant) { var exprs = [ self.left.expression ]; if (self.left instanceof AST_Sub) exprs.push(self.left.property); exprs.push(self.right); @@ -11485,16 +12151,14 @@ merge(Compressor.prototype, { node = parent; parent = compressor.parent(level++); if (parent instanceof AST_Assign) { - var found = false; + if (parent.left instanceof AST_SymbolRef && parent.left.definition() === def) { + if (in_try(level, parent)) break; + return strip_assignment(def); + } if (parent.left.match_symbol(function(node) { if (node instanceof AST_PropAccess) return true; - if (!found && node instanceof AST_SymbolRef && node.definition() === def) { - if (in_try(level, parent)) return true; - found = true; - } })) break; - if (!found) continue; - return strip_assignment(def); + continue; } if (parent instanceof AST_Exit) { if (!local) break; @@ -11528,22 +12192,29 @@ merge(Compressor.prototype, { } if (compressor.option("assignments")) { if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) { + var ref; // x = expr1 OP expr2 - if (self.right.left instanceof AST_SymbolRef - && self.right.left.name == self.left.name + if ((ref = self.right.left) instanceof AST_SymbolRef + && ref.name == self.left.name && ASSIGN_OPS[self.right.operator]) { // x = x - 2 ---> x -= 2 + if (self.left.fixed) self.left.fixed.to_binary = function() { + return ref; + }; return make_node(AST_Assign, self, { operator: self.right.operator + "=", left: self.left, right: self.right.right, }); } - if (self.right.right instanceof AST_SymbolRef - && self.right.right.name == self.left.name + if ((ref = self.right.right) instanceof AST_SymbolRef + && ref.name == self.left.name && ASSIGN_OPS_COMMUTATIVE[self.right.operator] && !self.right.left.has_side_effects(compressor)) { // x = 2 & x ---> x &= 2 + if (self.left.fixed) self.left.fixed.to_binary = function() { + return ref; + }; return make_node(AST_Assign, self, { operator: self.right.operator + "=", left: self.left, @@ -11981,18 +12652,14 @@ merge(Compressor.prototype, { } function pop_seq(node) { - if (!(node instanceof AST_Sequence)) return make_node(AST_Number, node, { - value: 0 - }); + if (!(node instanceof AST_Sequence)) return make_node(AST_Number, node, { value: 0 }); return make_sequence(node, node.expressions.slice(0, -1)); } }); OPT(AST_Boolean, function(self, compressor) { if (!compressor.option("booleans")) return self; - if (compressor.in_boolean_context()) return make_node(AST_Number, self, { - value: +self.value - }); + if (compressor.in_boolean_context()) return make_node(AST_Number, self, { value: +self.value }); var p = compressor.parent(); if (p instanceof AST_Binary && (p.operator == "==" || p.operator == "!=")) { AST_Node.warn("Non-strict equality against boolean: {operator} {value} [{file}:{line},{col}]", { @@ -12002,15 +12669,11 @@ merge(Compressor.prototype, { line : p.start.line, col : p.start.col, }); - return make_node(AST_Number, self, { - value: +self.value - }); + return make_node(AST_Number, self, { value: +self.value }); } return make_node(AST_UnaryPrefix, self, { operator: "!", - expression: make_node(AST_Number, self, { - value: 1 - self.value - }) + expression: make_node(AST_Number, self, { value: 1 - self.value }), }); }); @@ -12118,7 +12781,7 @@ merge(Compressor.prototype, { if (assigned) def.reassigned--; var sym = make_node(AST_SymbolRef, self, argname); sym.reference(); - delete argname.__unused; + argname.unused = undefined; return sym; } } @@ -12171,7 +12834,8 @@ merge(Compressor.prototype, { if (flatten) { values.push(retValue); return make_sequence(self, values).optimize(compressor); - } else return make_node(AST_Sub, self, { + } + return make_node(AST_Sub, self, { expression: make_node(AST_Array, expr, { elements: values }), property: make_node(AST_Number, prop, { value: index }), }); @@ -12196,10 +12860,8 @@ merge(Compressor.prototype, { } }); - AST_Arrow.DEFMETHOD("contains_super", return_false); - AST_AsyncArrow.DEFMETHOD("contains_super", return_false); - AST_Lambda.DEFMETHOD("contains_super", function() { - var result; + AST_LambdaExpression.DEFMETHOD("contains_super", function() { + var result = false; var self = this; self.walk(new TreeWalker(function(node) { if (result) return true; @@ -12208,20 +12870,26 @@ merge(Compressor.prototype, { })); return result; }); - AST_LambdaDefinition.DEFMETHOD("contains_super", return_false); - AST_Scope.DEFMETHOD("contains_super", return_false); - AST_Arrow.DEFMETHOD("contains_this", return_false); - AST_AsyncArrow.DEFMETHOD("contains_this", return_false); - AST_Node.DEFMETHOD("contains_this", function() { - var result; - var self = this; - self.walk(new TreeWalker(function(node) { - if (result) return true; - if (node instanceof AST_This) return result = true; - if (node !== self && node instanceof AST_Scope && !is_arrow(node)) return true; - })); - return result; + // contains_this() + // returns false only if context bound by the specified scope (or scope + // containing the specified expression) is not referenced by `this` + (function(def) { + // scope of arrow function cannot bind to any context + def(AST_Arrow, return_false); + def(AST_AsyncArrow, return_false); + def(AST_Node, function() { + var result = false; + var self = this; + self.walk(new TreeWalker(function(node) { + if (result) return true; + if (node instanceof AST_This) return result = true; + if (node !== self && node instanceof AST_Scope && !is_arrow(node)) return true; + })); + return result; + }); + })(function(node, func) { + node.DEFMETHOD("contains_this", func); }); function can_hoist_property(prop) { @@ -12239,19 +12907,34 @@ merge(Compressor.prototype, { for (var i = props.length; --i >= 0;) { var prop = props[i]; if (prop.key !== key) continue; - if (!all(props, can_hoist_property)) break; - if (!safe_to_flatten(prop.value, compressor)) break; - props = props.map(function(prop) { - return prop.value; - }); - if (prop instanceof AST_ObjectMethod - && prop.value instanceof AST_Function - && !(compressor.parent() instanceof AST_Call)) { - if (prop.value.uses_arguments) break; - props[i] = make_node(AST_Arrow, prop.value, prop.value); + if (!all(props, can_hoist_property)) return; + if (!safe_to_flatten(prop.value, compressor)) return; + var scope, values = []; + for (var j = 0; j < props.length; j++) { + var value = props[j].value; + if (props[j] instanceof AST_ObjectMethod) { + var arrow = !(value.uses_arguments || is_generator(value) || value.contains_this()); + if (arrow) { + if (!scope) scope = compressor.find_parent(AST_Scope); + var avoid = avoid_await_yield(scope); + value.each_argname(function(argname) { + if (avoid[argname.name]) arrow = false; + }); + } + var ctor; + if (arrow) { + ctor = is_async(value) ? AST_AsyncArrow : AST_Arrow; + } else if (i === j && !(compressor.parent() instanceof AST_Call)) { + return; + } else { + ctor = value.CTOR; + } + value = make_node(ctor, value, value); + } + values.push(value); } return make_node(AST_Sub, this, { - expression: make_node(AST_Array, expr, { elements: props }), + expression: make_node(AST_Array, expr, { elements: values }), property: make_node(AST_Number, this, { value: i }), }); } @@ -12283,35 +12966,25 @@ merge(Compressor.prototype, { var exp = self.expression.expression; if (is_undeclared_ref(exp)) switch (exp.name) { case "Array": - self.expression = make_node(AST_Array, self.expression, { - elements: [] - }); + self.expression = make_node(AST_Array, self.expression, { elements: [] }); break; case "Function": self.expression = make_node(AST_Function, self.expression, { argnames: [], - body: [] + body: [], }).init_vars(exp.scope); break; case "Number": - self.expression = make_node(AST_Number, self.expression, { - value: 0 - }); + self.expression = make_node(AST_Number, self.expression, { value: 0 }); break; case "Object": - self.expression = make_node(AST_Object, self.expression, { - properties: [] - }); + self.expression = make_node(AST_Object, self.expression, { properties: [] }); break; case "RegExp": - self.expression = make_node(AST_RegExp, self.expression, { - value: /t/ - }); + self.expression = make_node(AST_RegExp, self.expression, { value: /t/ }); break; case "String": - self.expression = make_node(AST_String, self.expression, { - value: "" - }); + self.expression = make_node(AST_String, self.expression, { value: "" }); break; } } @@ -12347,7 +13020,8 @@ merge(Compressor.prototype, { var found = false; var generated = false; var keep_duplicate = compressor.has_directive("use strict"); - var keys = new Dictionary(); + var keys = []; + var map = new Dictionary(); var values = []; self.properties.forEach(function(prop) { if (!(prop instanceof AST_Spread)) return process(prop); @@ -12390,19 +13064,27 @@ merge(Compressor.prototype, { return make_node(AST_Object, self, { properties: values }); function flush() { - keys.each(function(props) { - if (props.length == 1) return values.push(props[0]); + keys.forEach(function(key) { + var props = map.get(key); + switch (props.length) { + case 0: + return; + case 1: + return values.push(props[0]); + } changed = true; var tail = keep_duplicate && !generated && props.pop(); values.push(props.length == 1 ? props[0] : make_node(AST_ObjectKeyVal, self, { key: props[0].key, value: make_sequence(self, props.map(function(prop) { return prop.value; - })) + })), })); if (tail) values.push(tail); + props.length = 0; }); - keys = new Dictionary(); + keys = []; + map = new Dictionary(); } function process(prop) { @@ -12418,23 +13100,513 @@ merge(Compressor.prototype, { } if (can_hoist_property(prop)) { if (prop.value.has_side_effects(compressor)) flush(); - keys.add(key, prop); + keys.push(key); + map.add(key, prop); } else { flush(); values.push(prop); } if (found && !generated && typeof key == "string" && RE_POSITIVE_INTEGER.test(key)) { generated = true; - if (keys.has(key)) prop = keys.get(key)[0]; + if (map.has(key)) prop = map.get(key)[0]; prop.key = make_node(AST_Number, prop, { value: +key }); } } }); + function flatten_var(name) { + var redef = name.definition().redefined(); + if (redef) { + name = name.clone(); + name.thedef = redef; + } + return name; + } + + function has_arg_refs(fn, node) { + var found = false; + node.walk(new TreeWalker(function(node) { + if (found) return true; + if (node instanceof AST_SymbolRef && fn.variables.get(node.name) === node.definition()) { + return found = true; + } + })); + return found; + } + + function init_ref(compressor, name) { + var sym = make_node(AST_SymbolRef, name, name); + var assign = make_node(AST_Assign, name, { + operator: "=", + left: sym, + right: make_node(AST_Undefined, name).transform(compressor), + }); + var def = name.definition(); + if (def.fixed) { + sym.fixed = function() { + return assign.right; + }; + sym.fixed.assigns = [ assign ]; + var visited = []; + def.references.forEach(function(ref) { + var fixed = ref.fixed; + if (!fixed || !push_uniq(visited, fixed)) return; + if (fixed.assigns) { + fixed.assigns.unshift(assign); + } else { + fixed.assigns = [ assign ]; + } + }); + } + def.assignments++; + def.references.push(sym); + return assign; + } + + (function(def) { + def(AST_Node, noop); + def(AST_Assign, noop); + def(AST_Await, function(compressor, scope, no_return, in_loop) { + var self = this; + var inlined = sync(self.expression).try_inline(compressor, scope, no_return, in_loop); + if (!inlined) return; + if (!no_return) scan_local_returns(inlined, function(node) { + node.in_bool = false; + var value = node.value; + if (value instanceof AST_Await) return; + node.value = make_node(AST_Await, self, { + expression: value || make_node(AST_Undefined, node).transform(compressor), + }); + }); + return aborts(inlined) ? inlined : make_node(AST_BlockStatement, self, { + body: [ inlined, make_node(AST_SimpleStatement, self, { + body: make_node(AST_Await, self, { expression: make_node(AST_Number, self, { value: 0 })}), + }) ], + }); + + function sync(node) { + if (!no_return) return node; + if (node.TYPE != "Call") return node; + var fn = node.expression; + switch (fn.CTOR) { + case AST_AsyncArrow: + fn = make_node(AST_Arrow, fn, fn); + break; + case AST_AsyncFunction: + fn = make_node(AST_Function, fn, fn); + break; + case AST_AsyncGeneratorFunction: + fn = make_node(AST_GeneratorFunction, fn, fn); + break; + default: + return node; + } + node = node.clone(); + node.expression = fn; + return node; + } + }); + def(AST_Binary, function(compressor, scope, no_return, in_loop) { + if (no_return === undefined) return; + var self = this; + var op = self.operator; + if (!lazy_op[op]) return; + var inlined = self.right.try_inline(compressor, scope, no_return, in_loop); + if (!inlined) return; + return make_node(AST_If, self, { + condition: make_condition(self.left), + body: inlined, + alternative: no_return ? null : make_node(AST_Return, self, { value: null }), + }); + + function make_condition(cond) { + switch (op) { + case "&&": + return cond; + case "||": + return cond.negate(compressor); + case "??": + return make_node(AST_Binary, self, { + operator: "==", + left: make_node(AST_Null, self), + right: cond, + }); + } + } + }); + def(AST_BlockStatement, function(compressor, scope, no_return, in_loop) { + if (no_return) return; + if (!this.variables) return; + var body = this.body; + var last = body.length - 1; + if (last < 0) return; + var inlined = body[last].try_inline(compressor, this, no_return, in_loop); + if (!inlined) return; + body[last] = inlined; + return this; + }); + def(AST_Call, function(compressor, scope, no_return, in_loop) { + if (compressor.option("inline") < 4) return; + var call = this; + if (call.is_expr_pure(compressor)) return; + var fn = call.expression; + if (!(fn instanceof AST_LambdaExpression)) return; + if (fn.name) return; + if (fn.uses_arguments) return; + if (fn.pinned()) return; + if (is_generator(fn)) return; + var arrow = is_arrow(fn); + if (arrow && fn.value) return; + if (fn.body[0] instanceof AST_Directive) return; + if (fn.contains_this()) return; + if (!scope) scope = find_scope(compressor); + var defined = new Dictionary(); + defined.set("NaN", true); + while (!(scope instanceof AST_Scope)) { + scope.variables.each(function(def) { + defined.set(def.name, true); + }); + scope = scope.parent_scope; + } + if (!member(scope, compressor.stack)) return; + if (scope.pinned() && fn.variables.size() > (arrow ? 0 : 1)) return; + if (scope instanceof AST_Toplevel) { + if (fn.variables.size() > (arrow ? 0 : 1)) { + if (!compressor.toplevel.vars) return; + if (fn.functions.size() > 0 && !compressor.toplevel.funcs) return; + } + defined.set("arguments", true); + } + var async = is_async(fn); + if (async) { + if (!compressor.option("awaits")) return; + if (!is_async(scope)) return; + if (call.may_throw(compressor)) return; + } + var names = scope.var_names(); + if (in_loop) in_loop = []; + if (!fn.variables.all(function(def, name) { + if (in_loop) in_loop.push(def); + if (!defined.has(name) && !names.has(name)) return true; + return !arrow && name == "arguments" && def.orig.length == 1; + })) return; + if (in_loop && in_loop.length > 0 && is_reachable(fn, in_loop)) return; + var simple_argnames = true; + if (!all(fn.argnames, function(argname) { + var abort = false; + var tw = new TreeWalker(function(node) { + if (abort) return true; + if (node instanceof AST_DefaultValue) { + if (has_arg_refs(fn, node.value)) return abort = true; + node.name.walk(tw); + return true; + } + if (node instanceof AST_DestructuredKeyVal) { + if (node.key instanceof AST_Node && has_arg_refs(fn, node.key)) return abort = true; + node.value.walk(tw); + return true; + } + if (node instanceof AST_SymbolFunarg && !all(node.definition().orig, function(sym) { + return !(sym instanceof AST_SymbolDefun); + })) return abort = true; + }); + argname.walk(tw); + if (abort) return false; + if (!(argname instanceof AST_SymbolFunarg)) simple_argnames = false; + return true; + })) return; + if (fn.rest) { + if (has_arg_refs(fn, fn.rest)) return; + simple_argnames = false; + } + if (no_return && !all(fn.body, function(stat) { + var abort = false; + stat.walk(new TreeWalker(function(node) { + if (abort) return true; + if (async && node instanceof AST_Await || node instanceof AST_Return) return abort = true; + if (node instanceof AST_Scope && node !== fn) return true; + })); + return !abort; + })) return; + if (!safe_from_await_yield(fn, avoid_await_yield(scope))) return; + fn.functions.each(function(def, name) { + scope.functions.set(name, def); + }); + var body = []; + fn.variables.each(function(def, name) { + if (name == "arguments") return; + names.set(name, true); + scope.enclosed.push(def); + scope.variables.set(name, def); + def.single_use = false; + if (!in_loop) return; + if (def.references.length == def.replaced) return; + if (def.orig.length == def.eliminated) return; + if (def.orig.length == 1 && fn.functions.has(name)) return; + if (!all(def.orig, function(sym) { + if (sym instanceof AST_SymbolConst) return false; + if (sym instanceof AST_SymbolFunarg) return def.scope.resolve() !== fn; + if (sym instanceof AST_SymbolLet) return false; + return true; + })) return; + var sym = def.orig[0]; + if (sym instanceof AST_SymbolCatch) return; + body.push(make_node(AST_SimpleStatement, sym, { body: init_ref(compressor, flatten_var(sym)) })); + }); + var defs = Object.create(null), syms = new Dictionary(); + if (simple_argnames && all(call.args, function(arg) { + return !(arg instanceof AST_Spread); + })) { + var values = call.args.slice(); + fn.argnames.forEach(function(argname) { + var value = values.shift(); + if (argname.unused) { + if (value) body.push(make_node(AST_SimpleStatement, call, { body: value })); + return; + } + body.push(make_node(AST_Var, call, { + definitions: [ make_node(AST_VarDef, call, { + name: argname.convert_symbol(AST_SymbolVar, process), + value: value || make_node(AST_Undefined, call).transform(compressor), + }) ], + })); + }); + if (values.length) body.push(make_node(AST_SimpleStatement, call, { + body: make_sequence(call, values), + })); + } else { + body.push(make_node(AST_Var, call, { + definitions: [ make_node(AST_VarDef, call, { + name: make_node(AST_DestructuredArray, call, { + elements: fn.argnames.map(function(argname) { + if (argname.unused) return make_node(AST_Hole, argname); + return argname.convert_symbol(AST_SymbolVar, process); + }), + rest: fn.rest && fn.rest.convert_symbol(AST_SymbolVar, process), + }), + value: make_node(AST_Array, call, { elements: call.args.slice() }), + }) ], + })); + } + syms.each(function(orig, id) { + var def = defs[id]; + [].unshift.apply(def.orig, orig); + def.eliminated += orig.length; + }); + [].push.apply(body, in_loop ? fn.body.filter(function(stat) { + if (!(stat instanceof AST_LambdaDefinition)) return true; + var name = make_node(AST_SymbolVar, stat.name, flatten_var(stat.name)); + var def = name.definition(); + def.fixed = false; + def.orig.push(name); + def.eliminated++; + body.push(make_node(AST_Var, stat, { + definitions: [ make_node(AST_VarDef, stat, { + name: name, + value: to_func_expr(stat, true), + }) ], + })); + return false; + }) : fn.body); + var inlined = make_node(AST_BlockStatement, call, { body: body }); + if (!no_return) { + if (async) scan_local_returns(inlined, function(node) { + var value = node.value; + if (is_undefined(value)) return; + node.value = make_node(AST_Await, call, { expression: value }); + }); + body.push(make_node(AST_Return, call, { value: null })); + } + return inlined; + + function process(sym, argname) { + var def = argname.definition(); + defs[def.id] = def; + syms.add(def.id, sym); + } + }); + def(AST_Conditional, function(compressor, scope, no_return, in_loop) { + var self = this; + var body = self.consequent.try_inline(compressor, scope, no_return, in_loop); + var alt = self.alternative.try_inline(compressor, scope, no_return, in_loop); + if (!body && !alt) return; + return make_node(AST_If, self, { + condition: self.condition, + body: body || make_body(self.consequent), + alternative: alt || make_body(self.alternative), + }); + + function make_body(value) { + if (no_return) return make_node(AST_SimpleStatement, value, { body: value }); + return make_node(AST_Return, value, { value: value }); + } + }); + def(AST_For, function(compressor, scope, no_return, in_loop) { + var body = this.body.try_inline(compressor, scope, true, true); + if (body) this.body = body; + var inlined = this.init; + if (inlined) { + inlined = inlined.try_inline(compressor, scope, true, in_loop); + if (inlined) { + this.init = null; + if (inlined instanceof AST_BlockStatement) { + inlined.body.push(this); + return inlined; + } + return make_node(AST_BlockStatement, inlined, { body: [ inlined, this ] }); + } + } + return body && this; + }); + def(AST_ForEnumeration, function(compressor, scope, no_return, in_loop) { + var body = this.body.try_inline(compressor, scope, true, true); + if (body) this.body = body; + var obj = this.object; + if (obj instanceof AST_Sequence) { + var inlined = inline_sequence(compressor, scope, true, in_loop, obj, 1); + if (inlined) { + this.object = obj.tail_node(); + inlined.body.push(this); + return inlined; + } + } + return body && this; + }); + def(AST_If, function(compressor, scope, no_return, in_loop) { + var body = this.body.try_inline(compressor, scope, no_return, in_loop); + if (body) this.body = body; + var alt = this.alternative; + if (alt) { + alt = alt.try_inline(compressor, scope, no_return, in_loop); + if (alt) this.alternative = alt; + } + var cond = this.condition; + if (cond instanceof AST_Sequence) { + var inlined = inline_sequence(compressor, scope, true, in_loop, cond, 1); + if (inlined) { + this.condition = cond.tail_node(); + inlined.body.push(this); + return inlined; + } + } + return (body || alt) && this; + }); + def(AST_IterationStatement, function(compressor, scope, no_return, in_loop) { + var body = this.body.try_inline(compressor, scope, true, true); + if (!body) return; + this.body = body; + return this; + }); + def(AST_LabeledStatement, function(compressor, scope, no_return, in_loop) { + var body = this.body.try_inline(compressor, scope, no_return, in_loop); + if (!body) return; + this.body = body; + return this; + }); + def(AST_New, noop); + def(AST_Return, function(compressor, scope, no_return, in_loop) { + var value = this.value; + return value && value.try_inline(compressor, scope, undefined, in_loop === "try"); + }); + function inline_sequence(compressor, scope, no_return, in_loop, node, skip) { + var body = [], exprs = node.expressions, no_ret = no_return; + for (var i = exprs.length - (skip || 0), j = i; --i >= 0; no_ret = true) { + var inlined = exprs[i].try_inline(compressor, scope, no_ret, in_loop); + if (!inlined) continue; + flush(); + body.push(inlined); + } + if (body.length == 0) return; + flush(); + if (!no_return && body[0] instanceof AST_SimpleStatement) { + body[0] = make_node(AST_Return, node, { value: body[0].body }); + } + return make_node(AST_BlockStatement, node, { body: body.reverse() }); + + function flush() { + if (j > i + 1) body.push(make_node(AST_SimpleStatement, node, { + body: make_sequence(node, exprs.slice(i + 1, j)), + })); + j = i; + } + } + def(AST_Sequence, function(compressor, scope, no_return, in_loop) { + return inline_sequence(compressor, scope, no_return, in_loop, this); + }); + def(AST_SimpleStatement, function(compressor, scope, no_return, in_loop) { + var body = this.body; + while (body instanceof AST_UnaryPrefix) { + var op = body.operator; + if (unary_side_effects[op]) break; + if (op == "void") break; + body = body.expression; + } + if (!no_return && !is_undefined(body)) body = make_node(AST_UnaryPrefix, this, { + operator: "void", + expression: body, + }); + return body.try_inline(compressor, scope, no_return || false, in_loop); + }); + def(AST_UnaryPrefix, function(compressor, scope, no_return, in_loop) { + var self = this; + var op = self.operator; + if (unary_side_effects[op]) return; + if (!no_return && op == "void") no_return = false; + var inlined = self.expression.try_inline(compressor, scope, no_return, in_loop); + if (!inlined) return; + if (!no_return) scan_local_returns(inlined, function(node) { + node.in_bool = false; + var value = node.value; + if (op == "void" && is_undefined(value)) return; + node.value = make_node(AST_UnaryPrefix, self, { + operator: op, + expression: value || make_node(AST_Undefined, node).transform(compressor), + }); + }); + return inlined; + }); + def(AST_With, function(compressor, scope, no_return, in_loop) { + var body = this.body.try_inline(compressor, scope, no_return, in_loop); + if (body) this.body = body; + var exp = this.expression; + if (exp instanceof AST_Sequence) { + var inlined = inline_sequence(compressor, scope, true, in_loop, exp, 1); + if (inlined) { + this.expression = exp.tail_node(); + inlined.body.push(this); + return inlined; + } + } + return body && this; + }); + def(AST_Yield, function(compressor, scope, no_return, in_loop) { + if (!compressor.option("yields")) return; + if (!this.nested) return; + var call = this.expression; + if (call.TYPE != "Call") return; + var fn = call.expression; + switch (fn.CTOR) { + case AST_AsyncGeneratorFunction: + fn = make_node(AST_AsyncFunction, fn, fn); + break; + case AST_GeneratorFunction: + fn = make_node(AST_Function, fn, fn); + break; + default: + return; + } + call = call.clone(); + call.expression = fn; + return call.try_inline(compressor, scope, no_return, in_loop); + }); + })(function(node, func) { + node.DEFMETHOD("try_inline", func); + }); + OPT(AST_Return, function(self, compressor) { - if (compressor.option("side_effects") - && self.value - && is_undefined(self.value, compressor) + var value = self.value; + if (value && compressor.option("side_effects") + && is_undefined(value, compressor) && !in_async_generator(compressor.find_parent(AST_Scope))) { self.value = null; } diff --git a/node_modules/uglify-js/lib/minify.js b/node_modules/uglify-js/lib/minify.js index 8d4e5d9..aca7f5f 100644 --- a/node_modules/uglify-js/lib/minify.js +++ b/node_modules/uglify-js/lib/minify.js @@ -28,7 +28,7 @@ function read_source_map(name, toplevel) { var match = /^# ([^\s=]+)=(\S+)\s*$/.exec(comment.value); if (!match) break; if (match[1] == "sourceMappingURL") { - match = /^data:application\/json(;.*?)?;base64,(\S+)$/.exec(match[2]); + match = /^data:application\/json(;.*?)?;base64,([^,]+)$/.exec(match[2]); if (!match) break; return to_ascii(match[2]); } @@ -78,6 +78,7 @@ function minify(files, options) { enclose: false, ie: false, ie8: false, + keep_fargs: false, keep_fnames: false, mangle: {}, nameCache: null, @@ -99,6 +100,7 @@ function minify(files, options) { if (options.annotations !== undefined) set_shorthand("annotations", options, [ "compress", "output" ]); if (options.ie8) options.ie = options.ie || options.ie8; if (options.ie) set_shorthand("ie", options, [ "compress", "mangle", "output" ]); + if (options.keep_fargs) set_shorthand("keep_fargs", options, [ "compress", "mangle" ]); if (options.keep_fnames) set_shorthand("keep_fnames", options, [ "compress", "mangle" ]); if (options.toplevel) set_shorthand("toplevel", options, [ "compress", "mangle" ]); if (options.v8) set_shorthand("v8", options, [ "mangle", "output" ]); @@ -109,6 +111,7 @@ function minify(files, options) { cache: options.nameCache && (options.nameCache.vars || {}), eval: false, ie: false, + keep_fargs: false, keep_fnames: false, properties: false, reserved: [], diff --git a/node_modules/uglify-js/lib/mozilla-ast.js b/node_modules/uglify-js/lib/mozilla-ast.js index 8bf6a97..8cb3231 100644 --- a/node_modules/uglify-js/lib/mozilla-ast.js +++ b/node_modules/uglify-js/lib/mozilla-ast.js @@ -1005,7 +1005,7 @@ }); def_to_moz(AST_RegExp, function To_Moz_RegExpLiteral(M) { - var flags = M.value.toString().match(/[gimuy]*$/)[0]; + var flags = M.value.toString().match(/\/([gimuy]*)$/)[1]; var value = "/" + M.value.raw_source + "/" + flags; return { type: "Literal", @@ -1013,8 +1013,8 @@ raw: value, regex: { pattern: M.value.raw_source, - flags: flags - } + flags: flags, + }, }; }); diff --git a/node_modules/uglify-js/lib/output.js b/node_modules/uglify-js/lib/output.js index c35c8ff..ea233d3 100644 --- a/node_modules/uglify-js/lib/output.js +++ b/node_modules/uglify-js/lib/output.js @@ -101,10 +101,18 @@ function OutputStream(options) { } } + function make_indent(value) { + if (typeof value == "number") return new Array(value + 1).join(" "); + if (!value) return ""; + if (!/^\s*$/.test(value)) throw new Error("unsupported indentation: " + JSON.stringify("" + value)); + return value; + } + var current_col = 0; var current_line = 1; - var current_pos = 0; - var indentation = options.indent_start; + var current_indent = make_indent(options.indent_start); + var full_indent = make_indent(options.indent_level); + var half_indent = full_indent.length + 1 >> 1; var last; var line_end = 0; var line_fixed = true; @@ -115,17 +123,17 @@ function OutputStream(options) { var might_need_semicolon; var need_newline_indented = false; var need_space = false; - var newline_insert = -1; + var output; var stack; - var OUTPUT; + var stored = ""; function reset() { last = ""; might_need_space = false; might_need_semicolon = false; stack = []; - var str = OUTPUT; - OUTPUT = ""; + var str = output; + output = ""; return str; } @@ -227,32 +235,30 @@ function OutputStream(options) { } : noop; function insert_newlines(count) { - var index = OUTPUT.lastIndexOf("\n"); - if (line_end < index) line_end = index; - var left = OUTPUT.slice(0, line_end); - var right = OUTPUT.slice(line_end); - adjust_mappings(count, right.length - current_col); + stored += output.slice(0, line_end); + output = output.slice(line_end); + var new_col = output.length; + adjust_mappings(count, new_col - current_col); current_line += count; - current_pos += count; - current_col = right.length; - OUTPUT = left; - while (count--) OUTPUT += "\n"; - OUTPUT += right; + current_col = new_col; + while (count--) stored += "\n"; } - var fix_line = options.max_line_len ? function() { + var fix_line = options.max_line_len ? function(flush) { if (line_fixed) { if (current_col > options.max_line_len) { AST_Node.warn("Output exceeds {max_line_len} characters", options); } return; } - if (current_col > options.max_line_len) insert_newlines(1); - line_fixed = true; - flush_mappings(); + if (current_col > options.max_line_len) { + insert_newlines(1); + line_fixed = true; + } + if (line_fixed || flush) flush_mappings(); } : noop; - var requireSemicolonChars = makePredicate("( [ + * / - , ."); + var require_semicolon = makePredicate("( [ + * / - , ."); var print = options.beautify || options.comments @@ -276,32 +282,32 @@ function OutputStream(options) { space(); } } - newline_insert = -1; var prev = last.slice(-1); if (might_need_semicolon) { might_need_semicolon = false; - - if (prev == ":" && ch == "}" || (!ch || ";}".indexOf(ch) < 0) && prev != ";") { - if (options.semicolons || requireSemicolonChars[ch]) { - OUTPUT += ";"; + if (prev == ":" && ch == "}" || prev != ";" && (!ch || ";}".indexOf(ch) < 0)) { + var need_semicolon = require_semicolon[ch]; + if (need_semicolon || options.semicolons) { + output += ";"; current_col++; - current_pos++; + if (!line_fixed) { + fix_line(); + if (line_fixed && !need_semicolon && output == ";") { + output = ""; + current_col = 0; + } + } + if (line_end == output.length - 1) line_end++; } else { fix_line(); - OUTPUT += "\n"; - current_pos++; + output += "\n"; current_line++; current_col = 0; - - if (/^\s+$/.test(str)) { - // reset the semicolon flag, since we didn't print one - // now and might still have to later - might_need_semicolon = true; - } + // reset the semicolon flag, since we didn't print one + // now and might still have to later + if (/^\s+$/.test(str)) might_need_semicolon = true; } - - if (!options.beautify) - might_need_space = false; + if (!options.beautify) might_need_space = false; } } @@ -312,9 +318,8 @@ function OutputStream(options) { || str == "--" && last == "!" || str == "in" && prev == "/" || last == "--" && ch == ">") { - OUTPUT += " "; + output += " "; current_col++; - current_pos++; } if (prev != "<" || str != "!") might_need_space = false; } @@ -324,14 +329,13 @@ function OutputStream(options) { token: mapping_token, name: mapping_name, line: current_line, - col: current_col + col: current_col, }); mapping_token = false; if (line_fixed) flush_mappings(); } - OUTPUT += str; - current_pos += str.length; + output += str; var a = str.split(/\r?\n/), n = a.length - 1; current_line += n; current_col += a[0].length; @@ -346,7 +350,7 @@ function OutputStream(options) { if (might_need_semicolon) { might_need_semicolon = false; if (prev == ":" && ch == "}" || (!ch || ";}".indexOf(ch) < 0) && prev != ";") { - OUTPUT += ";"; + output += ";"; might_need_space = false; } } @@ -357,11 +361,11 @@ function OutputStream(options) { || str == "--" && last == "!" || str == "in" && prev == "/" || last == "--" && ch == ">") { - OUTPUT += " "; + output += " "; } if (prev != "<" || str != "!") might_need_space = false; } - OUTPUT += str; + output += str; last = str; }; @@ -373,30 +377,25 @@ function OutputStream(options) { var indent = options.beautify ? function(half) { if (need_newline_indented) print("\n"); - print(repeat_string(" ", half ? indentation - (options.indent_level >> 1) : indentation)); + print(half ? current_indent.slice(0, -half_indent) : current_indent); } : noop; var with_indent = options.beautify ? function(cont) { - var save_indentation = indentation; - indentation += options.indent_level; + var save_indentation = current_indent; + current_indent += full_indent; cont(); - indentation = save_indentation; + current_indent = save_indentation; } : function(cont) { cont() }; var may_add_newline = options.max_line_len || options.preserve_line ? function() { fix_line(); - line_end = OUTPUT.length; + line_end = output.length; line_fixed = false; } : noop; var newline = options.beautify ? function() { - if (newline_insert < 0) return print("\n"); - if (OUTPUT[newline_insert] != "\n") { - OUTPUT = OUTPUT.slice(0, newline_insert) + "\n" + OUTPUT.slice(newline_insert); - current_pos++; - current_line++; - } - newline_insert++; + print("\n"); + line_end = output.length; } : may_add_newline; var semicolon = options.beautify ? function() { @@ -452,13 +451,12 @@ function OutputStream(options) { } : noop; function get() { - if (!line_fixed) fix_line(); - return OUTPUT; + if (!line_fixed) fix_line(true); + return stored + output; } function has_nlb() { - var index = OUTPUT.lastIndexOf("\n"); - return /^ *$/.test(OUTPUT.slice(index + 1)); + return /(^|\n) *$/.test(output); } function pad_comment(token, force) { @@ -515,15 +513,13 @@ function OutputStream(options) { scan.walk(tw); } - if (current_pos == 0) { + if (current_line == 1 && current_col == 0) { if (comments.length > 0 && options.shebang && comments[0].type == "comment5") { print("#!" + comments.shift().value + "\n"); indent(); } var preamble = options.preamble; - if (preamble) { - print(preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n")); - } + if (preamble) print(preamble.replace(/\r\n?|\u2028|\u2029|(^|\S)\s*$/g, "$1\n")); } comments = comments.filter(comment_filter, node); @@ -561,20 +557,18 @@ function OutputStream(options) { return !/comment[134]/.test(c.type); }))) return; comments._dumped = self; - var insert = OUTPUT.length; comments.filter(comment_filter, node).forEach(function(comment, index) { pad_comment(comment, index || !tail); print_comment(comment); }); - if (OUTPUT.length > insert) newline_insert = insert; } return { get : get, reset : reset, indent : indent, - should_break : options.width ? function() { - return current_col - indentation >= options.width; + should_break : options.beautify && options.width ? function() { + return current_col >= options.width; } : return_false, has_parens : function() { return last.slice(-1) == "(" }, newline : newline, @@ -1152,8 +1146,9 @@ function OutputStream(options) { }); } function print_arrow(self, output) { - if (self.argnames.length == 1 && self.argnames[0] instanceof AST_SymbolFunarg && !self.rest) { - self.argnames[0].print(output); + var argname = self.argnames.length == 1 && !self.rest && self.argnames[0]; + if (argname instanceof AST_SymbolFunarg && argname.name != "yield") { + argname.print(output); } else { print_funargs(self, output); } @@ -1464,7 +1459,7 @@ function OutputStream(options) { parent = output.parent(level++); if (parent instanceof AST_Call && parent.expression === node) return; } while (parent instanceof AST_PropAccess && parent.expression === node); - output.print(typeof self.pure == "string" ? "/*" + self.pure + "*/" : "/*@__PURE__*/"); + output.print("/*@__PURE__*/"); } function print_call_args(self, output) { if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) { @@ -1869,8 +1864,8 @@ function OutputStream(options) { len = match[0].length; digits = str.slice(len); candidates.push(digits + "e-" + (digits.length + len - 1)); - } else if (match = /0+$/.exec(str)) { - len = match[0].length; + } else if (match = /[^0]0+$/.exec(str)) { + len = match[0].length - 1; candidates.push(str.slice(0, -len) + "e" + len); } else if (match = /^(\d)\.(\d+)e(-?\d+)$/.exec(str)) { candidates.push(match[1] + match[2] + "e" + (match[3] - match[2].length)); diff --git a/node_modules/uglify-js/lib/parse.js b/node_modules/uglify-js/lib/parse.js index a80fcaf..982d9d4 100644 --- a/node_modules/uglify-js/lib/parse.js +++ b/node_modules/uglify-js/lib/parse.js @@ -44,10 +44,10 @@ "use strict"; -var KEYWORDS = "break case catch class const continue debugger default delete do else extends finally for function if in instanceof let new return switch throw try typeof var void while with"; +var KEYWORDS = "break case catch class const continue debugger default delete do else extends finally for function if in instanceof new return switch throw try typeof var void while with"; var KEYWORDS_ATOM = "false null true"; var RESERVED_WORDS = [ - "abstract async await boolean byte char double enum export final float goto implements import int interface long native package private protected public short static super synchronized this throws transient volatile yield", + "abstract async await boolean byte char double enum export final float goto implements import int interface let long native package private protected public short static super synchronized this throws transient volatile yield", KEYWORDS_ATOM, KEYWORDS, ].join(" "); @@ -242,10 +242,10 @@ function tokenizer($TEXT, filename, html5_comments, shebang) { read_template : with_eof_error("Unterminated template literal", function(strings) { var s = ""; for (;;) { - var ch = next(true, true); + var ch = read(); switch (ch) { case "\\": - ch += next(true, true); + ch += read(); break; case "`": strings.push(s); @@ -260,6 +260,11 @@ function tokenizer($TEXT, filename, html5_comments, shebang) { } s += ch; } + + function read() { + var ch = next(true, true); + return ch == "\r" ? "\n" : ch; + } }), }; var prev_was_dot = false; @@ -862,6 +867,15 @@ function parse($TEXT, options) { next(); return import_(); } + break; + case "let": + if (is_vardefs()) { + next(); + var node = let_(); + semicolon(); + return node; + } + break; case "yield": if (S.in_generator) return simple_statement(); break; @@ -947,12 +961,6 @@ function parse($TEXT, options) { next(); return if_(); - case "let": - next(); - var node = let_(); - semicolon(); - return node; - case "return": if (S.in_function == 0 && !options.bare_returns) croak("'return' outside of function"); @@ -1192,7 +1200,7 @@ function parse($TEXT, options) { if (await || !is("punc", ";")) { init = is("keyword", "const") ? (next(), const_(true)) - : is("keyword", "let") + : is("name", "let") && is_vardefs() ? (next(), let_(true)) : is("keyword", "var") ? (next(), var_(true)) @@ -1308,6 +1316,11 @@ function parse($TEXT, options) { } if (node instanceof AST_SymbolFunarg) return node; if (node instanceof AST_SymbolRef) return new AST_SymbolFunarg(node); + if (node instanceof AST_Yield) return new AST_SymbolFunarg({ + start: node.start, + name: "yield", + end: node.end, + }); token_error(node.start, "Invalid arrow parameter"); } @@ -1535,12 +1548,18 @@ function parse($TEXT, options) { } var export_decl = embed_tokens(function() { - if (is("name", "async")) { + if (is("name")) switch (S.token.value) { + case "async": next(); expect_token("keyword", "function"); if (!is("operator", "*")) return function_(AST_AsyncDefun); next(); return function_(AST_AsyncGeneratorDefun); + case "let": + next(); + var node = let_(); + semicolon(); + return node; } else if (is("keyword")) switch (S.token.value) { case "class": next(); @@ -1555,11 +1574,6 @@ function parse($TEXT, options) { if (!is("operator", "*")) return function_(AST_Defun); next(); return function_(AST_GeneratorDefun); - case "let": - next(); - var node = let_(); - semicolon(); - return node; case "var": next(); var node = var_(); @@ -1720,6 +1734,11 @@ function parse($TEXT, options) { return a; } + function is_vardefs() { + var token = peek(); + return is_token(token, "name") || is_token(token, "punc", "[") || is_token(token, "punc", "{"); + } + var const_ = function(no_in) { return new AST_Const({ start : prev(), @@ -2130,7 +2149,7 @@ function parse($TEXT, options) { } function strict_verify_symbol(sym) { - if (sym.name == "arguments" || sym.name == "eval") + if (sym.name == "arguments" || sym.name == "eval" || sym.name == "let") token_error(sym.start, "Unexpected " + sym.name + " in strict mode"); } @@ -2297,9 +2316,8 @@ function parse($TEXT, options) { var comments = start.comments_before; var i = HOP(start, "comments_before_length") ? start.comments_before_length : comments.length; while (--i >= 0) { - var match = /[@#]__PURE__/.exec(comments[i].value); - if (match) { - expr.pure = match[0]; + if (/[@#]__PURE__/.test(comments[i].value)) { + expr.pure = true; break; } } diff --git a/node_modules/uglify-js/lib/propmangle.js b/node_modules/uglify-js/lib/propmangle.js index e7dc509..d5e13da 100644 --- a/node_modules/uglify-js/lib/propmangle.js +++ b/node_modules/uglify-js/lib/propmangle.js @@ -44,7 +44,7 @@ "use strict"; var builtins = function() { - var names = []; + var names = new Dictionary(); // NaN will be included due to Number.NaN [ "null", @@ -72,10 +72,10 @@ var builtins = function() { Object.getOwnPropertyNames(ctor.prototype).map(add); } }); - return makePredicate(names); + return names; function add(name) { - names.push(name); + names.set(name, true); } }(); @@ -116,9 +116,9 @@ function mangle_properties(ast, options) { reserved: null, }, true); - var reserved = Object.create(options.builtins ? null : builtins); + var reserved = options.builtins ? new Dictionary() : builtins.clone(); if (Array.isArray(options.reserved)) options.reserved.forEach(function(name) { - reserved[name] = true; + reserved.set(name, true); }); var cname = -1; @@ -126,7 +126,7 @@ function mangle_properties(ast, options) { if (options.cache) { cache = options.cache.props; cache.each(function(name) { - reserved[name] = true; + reserved.set(name, true); }); } else { cache = new Dictionary(); @@ -141,8 +141,8 @@ function mangle_properties(ast, options) { var debug_suffix; if (debug) debug_suffix = options.debug === true ? "" : options.debug; - var names_to_mangle = Object.create(null); - var unmangleable = Object.create(reserved); + var names_to_mangle = new Dictionary(); + var unmangleable = reserved.clone(); // step 1: find candidates to mangle ast.walk(new TreeWalker(function(node) { @@ -211,20 +211,20 @@ function mangle_properties(ast, options) { // only function declarations after this line function can_mangle(name) { - if (unmangleable[name]) return false; + if (unmangleable.has(name)) return false; if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false; return true; } function should_mangle(name) { - if (reserved[name]) return false; + if (reserved.has(name)) return false; if (regex && !regex.test(name)) return false; - return cache.has(name) || names_to_mangle[name]; + return cache.has(name) || names_to_mangle.has(name); } function add(name) { - if (can_mangle(name)) names_to_mangle[name] = true; - if (!should_mangle(name)) unmangleable[name] = true; + if (can_mangle(name)) names_to_mangle.set(name, true); + if (!should_mangle(name)) unmangleable.set(name, true); } function mangle(name) { diff --git a/node_modules/uglify-js/lib/scope.js b/node_modules/uglify-js/lib/scope.js index 2219b89..ad31f30 100644 --- a/node_modules/uglify-js/lib/scope.js +++ b/node_modules/uglify-js/lib/scope.js @@ -44,9 +44,9 @@ "use strict"; function SymbolDef(id, scope, orig, init) { + this._bits = 0; + this.defun = undefined; this.eliminated = 0; - this.exported = false; - this.global = false; this.id = id; this.init = init; this.mangled_name = null; @@ -54,8 +54,8 @@ function SymbolDef(id, scope, orig, init) { this.orig = [ orig ]; this.references = []; this.replaced = 0; + this.safe_ids = undefined; this.scope = scope; - this.undeclared = false; } SymbolDef.prototype = { @@ -92,18 +92,35 @@ SymbolDef.prototype = { if (def && def !== self) return def.redefined() || def; }, unmangleable: function(options) { - return this.global && !options.toplevel - || this.exported - || this.undeclared - || !options.eval && this.scope.pinned() - || options.keep_fnames - && (this.orig[0] instanceof AST_SymbolClass - || this.orig[0] instanceof AST_SymbolDefClass - || this.orig[0] instanceof AST_SymbolDefun - || this.orig[0] instanceof AST_SymbolLambda); + if (this.exported) return true; + if (this.undeclared) return true; + if (!options.eval && this.scope.pinned()) return true; + if (options.keep_fargs && is_funarg(this)) return true; + if (options.keep_fnames) { + var sym = this.orig[0]; + if (sym instanceof AST_SymbolClass) return true; + if (sym instanceof AST_SymbolDefClass) return true; + if (sym instanceof AST_SymbolDefun) return true; + if (sym instanceof AST_SymbolLambda) return true; + } + if (!options.toplevel && this.global) return true; + return false; }, }; +DEF_BITPROPS(SymbolDef, [ + "const_redefs", + "cross_loop", + "direct_access", + "exported", + "global", + "undeclared", +]); + +function is_funarg(def) { + return def.orig[0] instanceof AST_SymbolFunarg || def.orig[1] instanceof AST_SymbolFunarg; +} + var unary_side_effects = makePredicate("delete ++ --"); function is_lhs(node, parent) { @@ -205,20 +222,17 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) { } else if (node instanceof AST_SymbolDefun) { var def = defun.def_function(node, tw.parent()); if (exported) def.exported = true; - entangle(defun, scope); } else if (node instanceof AST_SymbolFunarg) { defun.def_variable(node); - entangle(defun, scope); } else if (node instanceof AST_SymbolLambda) { var def = defun.def_function(node, node.name == "arguments" ? undefined : defun); - if (options.ie) def.defun = defun.parent_scope.resolve(); + if (options.ie && node.name != "arguments") def.defun = defun.parent_scope.resolve(); } else if (node instanceof AST_SymbolLet) { var def = scope.def_variable(node); if (exported) def.exported = true; } else if (node instanceof AST_SymbolVar) { var def = defun.def_variable(node, node instanceof AST_SymbolImport ? undefined : null); if (exported) def.exported = true; - entangle(defun, scope); } function walk_scope(descend) { @@ -231,16 +245,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) { scope = save_scope; defun = save_defun; } - - function entangle(defun, scope) { - if (defun === scope) return; - node.mark_enclosed(options); - var def = scope.find_variable(node.name); - if (node.thedef === def) return; - node.thedef = def; - def.orig.push(node); - node.mark_enclosed(options); - } }); self.make_def = function(orig, init) { return new SymbolDef(++next_def_id, this, orig, init); @@ -261,6 +265,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) { } if (node instanceof AST_Lambda) { in_arg.push(node); + if (node.name) node.name.walk(tw); node.argnames.forEach(function(argname) { argname.walk(tw); }); @@ -287,6 +292,16 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) { // ensure compression works if `const` reuses a scope variable var redef = def.redefined(); if (redef) redef.const_redefs = true; + } else if (def.scope !== node.scope && (node instanceof AST_SymbolDefun + || node instanceof AST_SymbolFunarg + || node instanceof AST_SymbolVar)) { + node.mark_enclosed(options); + var redef = node.scope.find_variable(node.name); + if (node.thedef !== redef) { + node.thedef = redef; + redef.orig.push(node); + node.mark_enclosed(options); + } } if (node.name != "arguments") return true; var parent = node instanceof AST_SymbolVar && tw.parent(); @@ -363,7 +378,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) { if (node instanceof AST_SymbolLambda) { var def = node.thedef; if (!redefine(node, node.scope.parent_scope.resolve())) { - delete def.defun; + def.defun = undefined; } else if (typeof node.thedef.init !== "undefined") { node.thedef.init = false; } else if (def.init) { @@ -465,9 +480,12 @@ AST_Symbol.DEFMETHOD("mark_enclosed", function(options) { for (var s = this.scope; s; s = s.parent_scope) { push_uniq(s.enclosed, def); if (!options) { - delete s._var_names; - } else if (options.keep_fnames) { - s.functions.each(function(d) { + s._var_names = undefined; + } else { + if (options.keep_fargs && s instanceof AST_Lambda) s.each_argname(function(arg) { + push_uniq(def.scope.enclosed, arg.definition()); + }); + if (options.keep_fnames) s.functions.each(function(d) { push_uniq(def.scope.enclosed, d); }); } @@ -510,12 +528,12 @@ function names_in_use(scope, options) { if (!names) { scope.cname = -1; scope.cname_holes = []; - scope.names_in_use = names = Object.create(null); + scope.names_in_use = names = new Dictionary(); var cache = options.cache && options.cache.props; scope.enclosed.forEach(function(def) { - if (def.unmangleable(options)) names[def.name] = true; + if (def.unmangleable(options)) names.set(def.name, true); if (def.global && cache && cache.has(def.name)) { - names[cache.get(def.name)] = true; + names.set(cache.get(def.name), true); } }); } @@ -526,34 +544,33 @@ function next_mangled_name(def, options) { var scope = def.scope; var in_use = names_in_use(scope, options); var holes = scope.cname_holes; - var names = Object.create(null); + var names = new Dictionary(); var scopes = [ scope ]; def.forEach(function(sym) { var scope = sym.scope; do { - if (scopes.indexOf(scope) < 0) { - for (var name in names_in_use(scope, options)) { - names[name] = true; - } - scopes.push(scope); - } else break; + if (member(scope, scopes)) break; + names_in_use(scope, options).each(function(marker, name) { + names.set(name, marker); + }); + scopes.push(scope); } while (scope = scope.parent_scope); }); var name; for (var i = 0; i < holes.length; i++) { name = base54(holes[i]); - if (names[name]) continue; + if (names.has(name)) continue; holes.splice(i, 1); - in_use[name] = true; + in_use.set(name, true); return name; } while (true) { name = base54(++scope.cname); - if (in_use[name] || RESERVED_WORDS[name] || options.reserved.has[name]) continue; - if (!names[name]) break; + if (in_use.has(name) || RESERVED_WORDS[name] || options.reserved.has[name]) continue; + if (!names.has(name)) break; holes.push(scope.cname); } - in_use[name] = true; + in_use.set(name, true); return name; } @@ -573,6 +590,7 @@ function _default_mangler_options(options) { options = defaults(options, { eval : false, ie : false, + keep_fargs : false, keep_fnames : false, reserved : [], toplevel : false, @@ -580,32 +598,30 @@ function _default_mangler_options(options) { webkit : false, }); if (!Array.isArray(options.reserved)) options.reserved = []; - // Never mangle arguments + // Never mangle `arguments` push_uniq(options.reserved, "arguments"); options.reserved.has = makePredicate(options.reserved); return options; } +// We only need to mangle declaration nodes. Special logic wired into the code +// generator will display the mangled name if it is present (and for +// `AST_SymbolRef`s it will use the mangled name of the `AST_SymbolDeclaration` +// that it points to). AST_Toplevel.DEFMETHOD("mangle_names", function(options) { options = _default_mangler_options(options); - - // We only need to mangle declaration nodes. Special logic wired - // into the code generator will display the mangled name if it's - // present (and for AST_SymbolRef-s it'll use the mangled name of - // the AST_SymbolDeclaration that it points to). - var lname = -1; - if (options.cache && options.cache.props) { var mangled_names = names_in_use(this, options); options.cache.props.each(function(mangled_name) { - mangled_names[mangled_name] = true; + mangled_names.set(mangled_name, true); }); } - + var cutoff = 36; + var lname = -1; var redefined = []; var tw = new TreeWalker(function(node, descend) { if (node instanceof AST_LabeledStatement) { - // lname is incremented when we get to the AST_Label + // `lname` is incremented when we get to the `AST_Label` var save_nesting = lname; descend(); if (!options.v8 || !in_label(tw)) lname = save_nesting; @@ -627,9 +643,9 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) { }); }, true); } - node.to_mangle = []; + var to_mangle = node.to_mangle = []; node.variables.each(function(def) { - if (!defer_redef(def)) node.to_mangle.push(def); + if (!defer_redef(def)) to_mangle.push(def); }); descend(); if (options.cache && node instanceof AST_Toplevel) { @@ -640,7 +656,23 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) { sym.scope = node; sym.reference(options); } - node.to_mangle.forEach(mangle); + if (to_mangle.length > cutoff) { + var indices = to_mangle.map(function(def, index) { + return index; + }).sort(function(i, j) { + return to_mangle[j].references.length - to_mangle[i].references.length || i - j; + }); + to_mangle = indices.slice(0, cutoff).sort(function(i, j) { + return i - j; + }).map(function(index) { + return to_mangle[index]; + }).concat(indices.slice(cutoff).sort(function(i, j) { + return i - j; + }).map(function(index) { + return to_mangle[index]; + })); + } + to_mangle.forEach(mangle); return true; } if (node instanceof AST_Label) { diff --git a/node_modules/uglify-js/lib/sourcemap.js b/node_modules/uglify-js/lib/sourcemap.js index 94966a6..a230a44 100644 --- a/node_modules/uglify-js/lib/sourcemap.js +++ b/node_modules/uglify-js/lib/sourcemap.js @@ -77,21 +77,23 @@ function vlq_encode(num) { } function create_array_map() { - var map = Object.create(null); + var map = new Dictionary(); var array = []; array.index = function(name) { - if (!HOP(map, name)) { - map[name] = array.length; + var index = map.get(name); + if (!(index >= 0)) { + index = array.length; array.push(name); + map.set(name, index); } - return map[name]; + return index; }; return array; } function SourceMap(options) { var sources = create_array_map(); - var sources_content = options.includeSources && Object.create(null); + var sources_content = options.includeSources && new Dictionary(); var names = create_array_map(); var mappings = ""; if (options.orig) Object.keys(options.orig).forEach(function(name) { @@ -110,7 +112,7 @@ function SourceMap(options) { if (!sources_content || !map.sourcesContent) return; for (var i = 0; i < map.sources.length; i++) { var content = map.sourcesContent[i]; - if (content) sources_content[map.sources[i]] = content; + if (content) sources_content.set(map.sources[i], content); } }); var prev_source; @@ -144,8 +146,8 @@ function SourceMap(options) { add(source, gen_line, gen_col, orig_line, orig_col, name); } : add, setSourceContent: sources_content ? function(source, content) { - if (!(source in sources_content)) { - sources_content[source] = content; + if (!sources_content.has(source)) { + sources_content.set(source, content); } } : noop, toString: function() { @@ -155,7 +157,7 @@ function SourceMap(options) { sourceRoot: options.root || undefined, sources: sources, sourcesContent: sources_content ? sources.map(function(source) { - return sources_content[source] || null; + return sources_content.get(source) || null; }) : undefined, names: names, mappings: mappings, diff --git a/node_modules/uglify-js/lib/utils.js b/node_modules/uglify-js/lib/utils.js index 28c8b43..5b64af5 100644 --- a/node_modules/uglify-js/lib/utils.js +++ b/node_modules/uglify-js/lib/utils.js @@ -55,14 +55,6 @@ function find_if(func, array) { for (var i = array.length; --i >= 0;) if (func(array[i])) return array[i]; } -function repeat_string(str, i) { - if (i <= 0) return ""; - if (i == 1) return str; - var d = repeat_string(str, i >> 1); - d += d; - return i & 1 ? d + str : d; -} - function configure_error_stack(fn) { Object.defineProperty(fn.prototype, "stack", { get: function() { @@ -96,15 +88,6 @@ function defaults(args, defs, croak) { return defs; } -function merge(obj, ext) { - var count = 0; - for (var i in ext) if (HOP(ext, i)) { - obj[i] = ext[i]; - count++; - } - return count; -} - function noop() {} function return_false() { return false; } function return_true() { return true; } @@ -143,7 +126,7 @@ function push_uniq(array, el) { } function string_template(text, props) { - return text.replace(/\{([^}]+)\}/g, function(str, p) { + return text.replace(/\{([^{}]+)\}/g, function(str, p) { var value = props[p]; return value instanceof AST_Node ? value.print_to_string() : value; }); @@ -171,63 +154,80 @@ function all(array, predicate) { } function Dictionary() { - this._values = Object.create(null); - this._size = 0; + this.values = Object.create(null); } Dictionary.prototype = { set: function(key, val) { - if (!this.has(key)) ++this._size; - this._values["$" + key] = val; + if (key == "__proto__") { + this.proto_value = val; + } else { + this.values[key] = val; + } return this; }, add: function(key, val) { - if (this.has(key)) { - this.get(key).push(val); + var list = this.get(key); + if (list) { + list.push(val); } else { this.set(key, [ val ]); } return this; }, - get: function(key) { return this._values["$" + key] }, + get: function(key) { + return key == "__proto__" ? this.proto_value : this.values[key]; + }, del: function(key) { - if (this.has(key)) { - --this._size; - delete this._values["$" + key]; + if (key == "__proto__") { + delete this.proto_value; + } else { + delete this.values[key]; } return this; }, - has: function(key) { return ("$" + key) in this._values }, + has: function(key) { + return key == "__proto__" ? "proto_value" in this : key in this.values; + }, all: function(predicate) { - for (var i in this._values) - if (!predicate(this._values[i], i.substr(1))) - return false; + for (var i in this.values) + if (!predicate(this.values[i], i)) return false; + if ("proto_value" in this && !predicate(this.proto_value, "__proto__")) return false; return true; }, each: function(f) { - for (var i in this._values) - f(this._values[i], i.substr(1)); + for (var i in this.values) + f(this.values[i], i); + if ("proto_value" in this) f(this.proto_value, "__proto__"); }, size: function() { - return this._size; + return Object.keys(this.values).length + ("proto_value" in this); }, map: function(f) { var ret = []; - for (var i in this._values) - ret.push(f(this._values[i], i.substr(1))); + for (var i in this.values) + ret.push(f(this.values[i], i)); + if ("proto_value" in this) ret.push(f(this.proto_value, "__proto__")); return ret; }, clone: function() { var ret = new Dictionary(); - for (var i in this._values) - ret._values[i] = this._values[i]; - ret._size = this._size; + this.each(function(value, i) { + ret.set(i, value); + }); return ret; }, - toObject: function() { return this._values } + toObject: function() { + var obj = {}; + this.each(function(value, i) { + obj["$" + i] = value; + }); + return obj; + }, }; Dictionary.fromObject = function(obj) { var dict = new Dictionary(); - dict._size = merge(dict._values, obj); + for (var i in obj) + if (HOP(obj, i)) dict.set(i.slice(1), obj[i]); return dict; }; @@ -265,3 +265,21 @@ function first_in_statement(stack, arrow, export_default) { return false; } } + +function DEF_BITPROPS(ctor, props) { + if (props.length > 31) throw new Error("Too many properties: " + props.length + "\n" + props.join(", ")); + props.forEach(function(name, pos) { + var mask = 1 << pos; + Object.defineProperty(ctor.prototype, name, { + get: function() { + return !!(this._bits & mask); + }, + set: function(val) { + if (val) + this._bits |= mask; + else + this._bits &= ~mask; + }, + }); + }); +} diff --git a/node_modules/uglify-js/package.json b/node_modules/uglify-js/package.json index 2d0e3d6..47cf44e 100644 --- a/node_modules/uglify-js/package.json +++ b/node_modules/uglify-js/package.json @@ -3,7 +3,7 @@ "description": "JavaScript parser, mangler/compressor and beautifier toolkit", "author": "Mihai Bazon (http://lisperator.net/)", "license": "BSD-2-Clause", - "version": "3.14.2", + "version": "3.15.3", "engines": { "node": ">=0.8.0" },