From ee158b0fe5dfdc8201057b5edb40847727958b03 Mon Sep 17 00:00:00 2001 From: John McLear Date: Sat, 23 Jan 2021 13:54:50 +0000 Subject: [PATCH 001/153] bugfix: bump ueberdb to 1.2.5 to resolve #4645 which caused a users color not to be persistent --- src/package-lock.json | 1303 +++++++++++++++++++---------------------- src/package.json | 2 +- 2 files changed, 618 insertions(+), 687 deletions(-) diff --git a/src/package-lock.json b/src/package-lock.json index db0516bf9..f4f145474 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -286,6 +286,37 @@ "@babel/helper-validator-identifier": "^7.10.4", "chalk": "^2.0.0", "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "@babel/parser": { @@ -357,9 +388,9 @@ } }, "@eslint/eslintrc": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz", - "integrity": "sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz", + "integrity": "sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg==", "dev": true, "requires": { "ajv": "^6.12.4", @@ -369,23 +400,11 @@ "ignore": "^4.0.6", "import-fresh": "^3.2.1", "js-yaml": "^3.13.1", - "lodash": "^4.17.19", + "lodash": "^4.17.20", "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" }, "dependencies": { - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, "debug": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", @@ -509,9 +528,9 @@ "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" }, "@sinonjs/commons": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", - "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.2.tgz", + "integrity": "sha512-sruwd86RJHdsVf/AtBoijDmUqJp3B6hF/DGC23C+JaegnDHaZyewCjoVGTdg3J0uz3Zs7NnIT05OBOmML72lQw==", "dev": true, "requires": { "type-detect": "4.0.8" @@ -526,20 +545,10 @@ "@sinonjs/commons": "^1.7.0" } }, - "@sinonjs/formatio": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz", - "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1", - "@sinonjs/samsam": "^5.0.2" - } - }, "@sinonjs/samsam": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.3.0.tgz", - "integrity": "sha512-hXpcfx3aq+ETVBwPlRFICld5EnrkexXuXDwqUNhDdr5L8VjvMeSRwyOa0qL7XFmR+jVWR4rUZtnxlG7RX72sBg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.3.1.tgz", + "integrity": "sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg==", "dev": true, "requires": { "@sinonjs/commons": "^1.6.0", @@ -564,9 +573,9 @@ "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" }, "@types/node": { - "version": "14.14.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.21.tgz", - "integrity": "sha512-cHYfKsnwllYhjOzuC5q1VpguABBeecUp24yFluHpn/BQaVxB1CuQ1FSRZCzrPxrkIfWISXV2LbeoBthLWg0+0A==" + "version": "14.14.22", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.22.tgz", + "integrity": "sha512-g+f/qj/cNcqKkc3tFqlXOYjrmZA+jNBiDzbP3kH+B+otKFqAdPgVTGP1IeKRdMml/aE69as5S4FqtxAbl+LaMw==" }, "@types/node-fetch": { "version": "2.5.8", @@ -717,9 +726,9 @@ } }, "ajv": { - "version": "6.12.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", - "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -728,27 +737,26 @@ } }, "ansi-colors": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", - "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==" + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true }, "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" }, "anymatch": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, "requires": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -792,20 +800,6 @@ "requires": { "lodash": "^4.17.14" } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } } } }, @@ -827,20 +821,6 @@ "readable-stream": "^2.0.0" }, "dependencies": { - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -964,11 +944,6 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" - }, "astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -980,11 +955,6 @@ "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" - }, "async-stacktrace": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/async-stacktrace/-/async-stacktrace-0.0.2.tgz", @@ -1001,9 +971,9 @@ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, "aws4": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", - "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==" + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" }, "backo2": { "version": "1.0.2", @@ -1049,23 +1019,16 @@ "tweetnacl": "^0.14.3" } }, - "better-assert": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", - "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", - "requires": { - "callsite": "1.0.0" - } - }, "bignumber.js": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" }, "binary-extensions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", - "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==" + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true }, "binary-search": { "version": "1.3.6", @@ -1073,14 +1036,55 @@ "integrity": "sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA==" }, "bl": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz", - "integrity": "sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==", - "dev": true, + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", + "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "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==" + } + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "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==" + } + } + } } }, "blob": { @@ -1156,6 +1160,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, "requires": { "fill-range": "^7.0.1" } @@ -1168,7 +1173,8 @@ "browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true }, "bson": { "version": "1.1.5", @@ -1224,12 +1230,13 @@ } }, "call-bind": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz", - "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, "requires": { "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.0" + "get-intrinsic": "^1.0.2" } }, "call-me-maybe": { @@ -1237,11 +1244,6 @@ "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=" }, - "callsite": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", - "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" - }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1250,7 +1252,8 @@ "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true }, "caseless": { "version": "0.12.0", @@ -1273,27 +1276,16 @@ "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz", "integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==" }, - "chai": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", - "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", - "requires": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "pathval": "^1.1.0", - "type-detect": "^4.0.5" - } - }, "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "channels": { @@ -1311,11 +1303,6 @@ "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==" }, - "check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" - }, "cheerio": { "version": "0.22.0", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", @@ -1343,6 +1330,7 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, "requires": { "anymatch": "~3.1.1", "braces": "~3.0.2", @@ -1374,19 +1362,11 @@ "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "dev": true }, - "cli-table": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.4.tgz", - "integrity": "sha512-1vinpnX/ZERcmE443i3SZTmU5DF0rPO9DrL4I2iVAllhxzCM9SzPlHnz19fsZB78htkKZvYBvj6SZ6vXnaxmTA==", - "requires": { - "chalk": "^2.4.1", - "string-width": "^4.2.0" - } - }, "cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, "requires": { "string-width": "^3.1.0", "strip-ansi": "^5.2.0", @@ -1396,22 +1376,26 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true }, "emoji-regex": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -1422,6 +1406,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, "requires": { "ansi-regex": "^4.1.0" } @@ -1456,13 +1441,13 @@ "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "optional": true + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, "requires": { "color-name": "1.1.3" } @@ -1470,7 +1455,8 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true }, "combined-stream": { "version": "1.0.8", @@ -1502,9 +1488,9 @@ "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" }, "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, "component-inherit": { "version": "0.0.3", @@ -1720,15 +1706,8 @@ "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", - "requires": { - "type-detect": "^4.0.0" - } + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true }, "deep-extend": { "version": "0.6.0", @@ -1755,6 +1734,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, "requires": { "object-keys": "^1.0.12" } @@ -1794,7 +1774,8 @@ "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true }, "dirty": { "version": "1.1.0", @@ -1841,11 +1822,6 @@ "domelementtype": "1" } }, - "drange": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/drange/-/drange-1.1.1.tgz", - "integrity": "sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==" - }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -1881,49 +1857,13 @@ "agentkeepalive": "^3.4.1", "chalk": "^1.0.0", "lodash": "^4.17.10" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } } }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true }, "encodeurl": { "version": "1.0.2", @@ -1940,22 +1880,22 @@ } }, "engine.io": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.4.2.tgz", - "integrity": "sha512-b4Q85dFkGw+TqgytGPrGgACRUhsdKc9S9ErRAXpPGy/CXKs4tYoHDkvIRdsseAF7NjfVwjRFIn6KTnbw7LwJZg==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.5.0.tgz", + "integrity": "sha512-21HlvPUKaitDGE4GXNtQ7PLP0Sz4aWLddMPw2VTyFz1FVZqu/kZsJUO8WNpKuE/OCL7nkfRaOui2ZCJloGznGA==", "requires": { "accepts": "~1.3.4", "base64id": "2.0.0", - "cookie": "0.3.1", + "cookie": "~0.4.1", "debug": "~4.1.0", "engine.io-parser": "~2.2.0", - "ws": "^7.1.2" + "ws": "~7.4.2" }, "dependencies": { "cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" }, "debug": { "version": "4.1.1", @@ -1973,9 +1913,9 @@ } }, "engine.io-client": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.4.tgz", - "integrity": "sha512-iU4CRr38Fecj8HoZEnFtm2EiKGbYZcPn3cHxqNGl/tmdWRf60KhK+9vE0JeSjgnlS/0oynEfLgKbT9ALpim0sQ==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.0.tgz", + "integrity": "sha512-12wPRfMrugVw/DNyJk34GQ5vIVArEcVMXWugQGGuw2XxUSztFNmJggZmv8IZlLyEdnpO1QB9LkcjeWewO2vxtA==", "requires": { "component-emitter": "~1.3.0", "component-inherit": "0.0.3", @@ -1985,16 +1925,11 @@ "indexof": "0.0.1", "parseqs": "0.0.6", "parseuri": "0.0.6", - "ws": "~6.1.0", + "ws": "~7.4.2", "xmlhttprequest-ssl": "~1.5.4", "yeast": "0.1.2" }, "dependencies": { - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" - }, "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", @@ -2002,24 +1937,6 @@ "requires": { "ms": "2.0.0" } - }, - "parseqs": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", - "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==" - }, - "parseuri": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz", - "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==" - }, - "ws": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz", - "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==", - "requires": { - "async-limiter": "~1.0.0" - } } } }, @@ -2042,14 +1959,6 @@ "dev": true, "requires": { "ansi-colors": "^4.1.1" - }, - "dependencies": { - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - } } }, "entities": { @@ -2063,28 +1972,32 @@ "integrity": "sha1-eYCZstvTfKK8dJ5TinwTB9C1BJk=" }, "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "version": "1.18.0-next.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.2.tgz", + "integrity": "sha512-Ih4ZMFHEtZupnUh6497zEL4y2+w8+1ljnCyaTa+adcoafI1GOvMwFlDjBLfWR7y9VLfrjRJe9ocuHY1PSR9jjw==", + "dev": true, "requires": { + "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2", "has": "^1.0.3", "has-symbols": "^1.0.1", "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", + "is-negative-zero": "^2.0.1", "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", + "object-inspect": "^1.9.0", "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.3", + "string.prototype.trimstart": "^1.0.3" }, "dependencies": { "object.assign": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, "requires": { "call-bind": "^1.0.0", "define-properties": "^1.1.3", @@ -2098,6 +2011,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -2121,13 +2035,13 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "eslint": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.17.0.tgz", - "integrity": "sha512-zJk08MiBgwuGoxes5sSQhOtibZ75pz0J35XTRlZOk9xMffhpA9BTbQZxoXZzOl5zMbleShbGwtw+1kGferfFwQ==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.18.0.tgz", + "integrity": "sha512-fbgTiE8BfUJZuBeq2Yi7J3RB3WGUQ9PNuNbmgi6jt9Iv8qrkxfy19Ds3OpL1Pm7zg3BtTVhvcUZbIRQ0wmSjAQ==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@eslint/eslintrc": "^0.2.2", + "@eslint/eslintrc": "^0.3.0", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -2151,7 +2065,7 @@ "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", - "lodash": "^4.17.19", + "lodash": "^4.17.20", "minimatch": "^3.0.4", "natural-compare": "^1.4.0", "optionator": "^0.9.1", @@ -2165,6 +2079,12 @@ "v8-compile-cache": "^2.0.3" }, "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -2229,6 +2149,15 @@ "lru-cache": "^6.0.0" } }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -2247,9 +2176,9 @@ } }, "eslint-config-etherpad": { - "version": "1.0.21", - "resolved": "https://registry.npmjs.org/eslint-config-etherpad/-/eslint-config-etherpad-1.0.21.tgz", - "integrity": "sha512-kJjTElXtgWqAtJNyyhl8k5g/phSg3PUpNSb1PHZBC72q7ibP3uB22hbIxZrg9PkB3dwl2w8GCBp8uLI+3OX7SA==", + "version": "1.0.23", + "resolved": "https://registry.npmjs.org/eslint-config-etherpad/-/eslint-config-etherpad-1.0.23.tgz", + "integrity": "sha512-/yMp7aK5zg309DgNIDotl+CtxrDq5ovwVz5ScmjOZgRgaG1rHhtUX5BFewOaoRlYGg+F2xYkqZ5Zhh9fgjs/jg==", "dev": true }, "eslint-plugin-es": { @@ -2555,6 +2484,11 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" } } }, @@ -2569,9 +2503,9 @@ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, "fast-deep-equal": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", - "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fast-json-stable-stringify": { "version": "2.1.0", @@ -2597,6 +2531,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, "requires": { "to-regex-range": "^5.0.1" } @@ -2635,6 +2570,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, "requires": { "locate-path": "^3.0.0" } @@ -2643,6 +2579,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz", "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==", + "dev": true, "requires": { "is-buffer": "~2.0.3" } @@ -2655,12 +2592,23 @@ "requires": { "flatted": "^3.1.0", "rimraf": "^3.0.2" + }, + "dependencies": { + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, "flatted": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.0.tgz", - "integrity": "sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", + "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", "dev": true }, "foreground-child": { @@ -2733,6 +2681,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, "optional": true }, "fstream": { @@ -2745,23 +2694,13 @@ "inherits": "~2.0.0", "mkdirp": ">=0.5 0", "rimraf": "2" - }, - "dependencies": { - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "optional": true, - "requires": { - "glob": "^7.1.3" - } - } } }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true }, "functional-red-black-tree": { "version": "1.0.1", @@ -2783,43 +2722,6 @@ "string-width": "^1.0.1", "strip-ansi": "^3.0.1", "wide-align": "^1.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } } }, "gensync": { @@ -2831,17 +2733,14 @@ "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" - }, - "get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=" + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true }, "get-intrinsic": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.2.tgz", "integrity": "sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg==", + "dev": true, "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -2863,9 +2762,9 @@ } }, "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -2879,6 +2778,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, "requires": { "is-glob": "^4.0.1" } @@ -2900,7 +2800,8 @@ "growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==" + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true }, "har-schema": { "version": "2.0.0", @@ -2908,11 +2809,11 @@ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", "requires": { - "ajv": "^6.5.5", + "ajv": "^6.12.3", "har-schema": "^2.0.0" } }, @@ -2920,6 +2821,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, "requires": { "function-bind": "^1.1.1" } @@ -2930,13 +2832,6 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "requires": { "ansi-regex": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - } } }, "has-binary2": { @@ -2962,12 +2857,14 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true }, "has-symbols": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true }, "has-unicode": { "version": "2.0.1", @@ -3051,7 +2948,8 @@ "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true }, "html-escaper": { "version": "2.0.2", @@ -3151,6 +3049,14 @@ "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } } }, "imurmurhash": { @@ -3218,19 +3124,21 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, "requires": { "binary-extensions": "^2.0.0" } }, "is-buffer": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", - "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==" + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" }, "is-callable": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", - "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==" + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", + "dev": true }, "is-core-module": { "version": "2.2.0", @@ -3244,7 +3152,8 @@ "is-date-object": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true }, "is-decimal": { "version": "1.0.4", @@ -3254,17 +3163,22 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true }, "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } }, "is-glob": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, "requires": { "is-extglob": "^2.1.1" } @@ -3277,12 +3191,14 @@ "is-negative-zero": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "dev": true }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true }, "is-observable": { "version": "1.1.0", @@ -3306,6 +3222,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, "requires": { "has-symbols": "^1.0.1" } @@ -3320,6 +3237,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, "requires": { "has-symbols": "^1.0.1" } @@ -3398,6 +3316,17 @@ "p-map": "^3.0.0", "rimraf": "^3.0.0", "uuid": "^3.3.3" + }, + "dependencies": { + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, "istanbul-lib-report": { @@ -3478,9 +3407,9 @@ "dev": true }, "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -3655,6 +3584,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" @@ -3768,8 +3698,40 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, "requires": { "chalk": "^2.4.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "log4js": { @@ -3879,16 +3841,16 @@ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" }, "mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" + "version": "1.45.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz", + "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==" }, "mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "version": "2.1.28", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz", + "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==", "requires": { - "mime-db": "1.44.0" + "mime-db": "1.45.0" } }, "minimatch": { @@ -3935,6 +3897,7 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.2.tgz", "integrity": "sha512-o96kdRKMKI3E8U0bjnfqW4QMk12MwZ4mhdBTf+B5a1q9+aq2HRnj+3ZdJu0B/ZhJeK78MgYuv6L8d/rA5AeBJA==", + "dev": true, "requires": { "ansi-colors": "3.2.3", "browser-stdout": "1.3.1", @@ -3962,23 +3925,56 @@ "yargs-unparser": "1.6.0" }, "dependencies": { + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true + }, "debug": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, "requires": { "ms": "^2.1.1" } }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, "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==" + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true }, "supports-color": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -4011,58 +4007,6 @@ "require_optional": "^1.0.1", "safe-buffer": "^5.1.2", "saslprep": "^1.0.0" - }, - "dependencies": { - "bl": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", - "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", - "requires": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - }, - "dependencies": { - "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==" - } - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - }, - "dependencies": { - "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==" - } - } - } } }, "ms": { @@ -4071,9 +4015,9 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "mssql": { - "version": "7.0.0-beta.1", - "resolved": "https://registry.npmjs.org/mssql/-/mssql-7.0.0-beta.1.tgz", - "integrity": "sha512-iyFnNVWhjTnIy5nKCq+v/de8mr41TbNKRrulDXASuDqbjOlfLe6YefnXp+ZRPHJUU1rrjmtAnrUoN2y7dc2LUg==", + "version": "7.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mssql/-/mssql-7.0.0-beta.2.tgz", + "integrity": "sha512-7fOp+QzFf24ir/gGeSvyyGlQKfxZj6tx88vsk4UiQw/t/zpJ9PLjOBOoi6Ff+Tw/CZ1aJTa83MPm+CRYJ/UCQA==", "requires": { "debug": "^4", "tarn": "^3.0.1", @@ -4245,6 +4189,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "dev": true, "requires": { "object.getownpropertydescriptors": "^2.0.3", "semver": "^5.7.0" @@ -4253,7 +4198,8 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true } } }, @@ -4282,15 +4228,6 @@ "which": "1" }, "dependencies": { - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, "semver": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", @@ -4327,15 +4264,6 @@ "osenv": "^0.1.4" } }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, "tar": { "version": "4.4.13", "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", @@ -4383,7 +4311,8 @@ "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true }, "npm": { "version": "6.14.8", @@ -7517,8 +7446,7 @@ "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "optional": true + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "nyc": { "version": "15.0.1", @@ -7554,6 +7482,12 @@ "yargs": "^15.0.2" }, "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -7599,19 +7533,11 @@ "path-exists": "^4.0.0" } }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true }, "locate-path": { "version": "5.0.0", @@ -7643,6 +7569,35 @@ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, "wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", @@ -7696,25 +7651,23 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "optional": true }, - "object-component": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", - "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" - }, "object-inspect": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", - "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==" + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "dev": true }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true }, "object.assign": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, "requires": { "define-properties": "^1.1.2", "function-bind": "^1.1.1", @@ -7726,6 +7679,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.1.tgz", "integrity": "sha512-6DtXgZ/lIZ9hqx4GtZETobXLR/ZLaa0aqV0kzbn80Rf8Z2e/XFnhA0I7p07N2wH8bBBltr2xQPi6sbKWAY2Eng==", + "dev": true, "requires": { "call-bind": "^1.0.0", "define-properties": "^1.1.3", @@ -7834,6 +7788,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, "requires": { "p-try": "^2.0.0" } @@ -7842,6 +7797,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, "requires": { "p-limit": "^2.0.0" } @@ -7858,7 +7814,8 @@ "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true }, "package-hash": { "version": "4.0.0", @@ -7892,20 +7849,14 @@ "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" }, "parseqs": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", - "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", - "requires": { - "better-assert": "~1.0.0" - } + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", + "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==" }, "parseuri": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", - "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", - "requires": { - "better-assert": "~1.0.0" - } + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz", + "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==" }, "parseurl": { "version": "1.3.3", @@ -7915,7 +7866,8 @@ "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true }, "path-is-absolute": { "version": "1.0.1", @@ -7939,11 +7891,6 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, - "pathval": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", - "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=" - }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -8006,7 +7953,8 @@ "picomatch": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true }, "pkg-dir": { "version": "4.2.0", @@ -8154,15 +8102,6 @@ "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==", "dev": true }, - "randexp": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.5.3.tgz", - "integrity": "sha512-U+5l2KrcMNOUPYvazA3h5ekF80FHTUG+87SEAmHZmolh1M+i/WyTCxVzmi+tidIa1tM4BSe8g2Y/D3loWDjj+w==", - "requires": { - "drange": "^1.0.2", - "ret": "^0.2.0" - } - }, "random-bytes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", @@ -8174,9 +8113,9 @@ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "rate-limiter-flexible": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-2.1.4.tgz", - "integrity": "sha512-wtbWcqZbCqyAO1k63moagJlCZuPCEqbJJ6il1y2JVoiUyxlE36+cM7ETta9K6tTom9O5pNK+CxwHMgyyyJ31Gg==" + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-2.2.1.tgz", + "integrity": "sha512-rxCP6kDDdn0cZmVqVlF06yLU+mG3TuwaHV/fUIw3OQyYhza7pzVBtdMhUmfXbBzMS+O464XP+x33pfTDGRGYVA==" }, "raw-body": { "version": "2.4.0", @@ -8234,6 +8173,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, "requires": { "picomatch": "^2.0.4" } @@ -8366,7 +8306,8 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true }, "require-from-string": { "version": "2.0.2", @@ -8377,7 +8318,8 @@ "require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true }, "require_optional": { "version": "1.0.1", @@ -8386,13 +8328,6 @@ "requires": { "resolve-from": "^2.0.0", "semver": "^5.1.0" - }, - "dependencies": { - "resolve-from": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", - "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" - } } }, "resolve": { @@ -8401,15 +8336,9 @@ "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" }, "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "ret": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz", - "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" }, "rethinkdb": { "version": "2.4.2", @@ -8420,17 +8349,18 @@ } }, "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "optional": true, "requires": { "glob": "^7.1.3" } }, "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, "safer-buffer": { "version": "2.1.2", @@ -8517,9 +8447,9 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "set-cookie-parser": { - "version": "2.4.6", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.4.6.tgz", - "integrity": "sha512-mNCnTUF0OYPwYzSHbdRdCfNNHqrne+HS5tS5xNb6yJbdP9wInV0q5xPLE0EyfV/Q3tImo3y/OXpD8Jn0Jtnjrg==", + "version": "2.4.7", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.4.7.tgz", + "integrity": "sha512-VaSdYN1DlYuKOzBKqhYJnwaPeirZdNNUNmYdnp9/6Umr9s8amidctYitrX2Gk8wCqiBuiG5mpOYCiVhG5o4iMQ==", "dev": true }, "setprototypeof": { @@ -8573,15 +8503,14 @@ } }, "sinon": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.0.tgz", - "integrity": "sha512-eSNXz1XMcGEMHw08NJXSyTHIu6qTCOiN8x9ODACmZpNQpr0aXTBXBnI4xTzQzR+TEpOmLiKowGf9flCuKIzsbw==", + "version": "9.2.4", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.4.tgz", + "integrity": "sha512-zljcULZQsJxVra28qIAL6ow1Z9tpattkCTEJR4RBP3TGc00FcttsP5pK284Nas5WjMZU5Yzy3kAIp3B3KRf5Yg==", "dev": true, "requires": { "@sinonjs/commons": "^1.8.1", "@sinonjs/fake-timers": "^6.0.1", - "@sinonjs/formatio": "^5.0.1", - "@sinonjs/samsam": "^5.2.0", + "@sinonjs/samsam": "^5.3.1", "diff": "^4.0.2", "nise": "^4.0.4", "supports-color": "^7.1.0" @@ -8644,6 +8573,12 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true } } }, @@ -8653,15 +8588,15 @@ "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=" }, "socket.io": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.3.0.tgz", - "integrity": "sha512-2A892lrj0GcgR/9Qk81EaY2gYhCBxurV0PfmmESO6p27QPrUK1J3zdns+5QPqvUYK2q657nSj0guoIil9+7eFg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.4.1.tgz", + "integrity": "sha512-Si18v0mMXGAqLqCVpTxBa8MGqriHGQh8ccEOhmsmNS3thNCGBwO8WGrwMibANsWtQQ5NStdZwHqZR3naJVFc3w==", "requires": { "debug": "~4.1.0", - "engine.io": "~3.4.0", + "engine.io": "~3.5.0", "has-binary2": "~1.0.2", "socket.io-adapter": "~1.1.0", - "socket.io-client": "2.3.0", + "socket.io-client": "2.4.0", "socket.io-parser": "~3.4.0" }, "dependencies": { @@ -8686,37 +8621,29 @@ "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==" }, "socket.io-client": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.3.0.tgz", - "integrity": "sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.4.0.tgz", + "integrity": "sha512-M6xhnKQHuuZd4Ba9vltCLT9oa+YvTsP8j9NcEiLElfIg8KeYPyhWOes6x4t+LTAC8enQbE/995AdTem2uNyKKQ==", "requires": { "backo2": "1.0.2", - "base64-arraybuffer": "0.1.5", "component-bind": "1.0.0", - "component-emitter": "1.2.1", - "debug": "~4.1.0", - "engine.io-client": "~3.4.0", + "component-emitter": "~1.3.0", + "debug": "~3.1.0", + "engine.io-client": "~3.5.0", "has-binary2": "~1.0.2", - "has-cors": "1.1.0", "indexof": "0.0.1", - "object-component": "0.0.3", - "parseqs": "0.0.5", - "parseuri": "0.0.5", + "parseqs": "0.0.6", + "parseuri": "0.0.6", "socket.io-parser": "~3.3.0", "to-array": "0.1.4" }, "dependencies": { - "base64-arraybuffer": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", - "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" - }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "requires": { - "ms": "^2.1.1" + "ms": "2.0.0" } }, "isarray": { @@ -8724,39 +8651,14 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, "socket.io-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.1.tgz", - "integrity": "sha512-1QLvVAe8dTz+mKmZ07Swxt+LAo4Y1ff50rlyoEx00TQmDFVQYPfcqGvIDJLGaBdhdNCecXtyKpD+EgKGcmmbuQ==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.2.tgz", + "integrity": "sha512-FJvDBuOALxdCI9qwRrO/Rfp9yfndRtc1jSgVgV8FDraihmSP/MLGD5PEuJrNfjALvcQ+vMDM/33AWOYP/JSjDg==", "requires": { "component-emitter": "~1.3.0", "debug": "~3.1.0", "isarray": "2.0.1" - }, - "dependencies": { - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } } } } @@ -8771,6 +8673,11 @@ "isarray": "2.0.1" }, "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", @@ -8833,6 +8740,15 @@ "which": "^2.0.1" }, "dependencies": { + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -8895,19 +8811,20 @@ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "string.prototype.trimend": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==", + "dev": true, "requires": { "call-bind": "^1.0.0", "define-properties": "^1.1.3" @@ -8917,6 +8834,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz", "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==", + "dev": true, "requires": { "call-bind": "^1.0.0", "define-properties": "^1.1.3" @@ -8943,11 +8861,11 @@ } }, "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^2.0.0" } }, "strip-bom": { @@ -9043,12 +8961,9 @@ } }, "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" }, "swagger-parser": { "version": "9.0.1", @@ -9092,11 +9007,43 @@ "uri-js": "^4.2.2" } }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, "json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } } } }, @@ -9122,6 +9069,19 @@ "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" + }, + "dependencies": { + "bl": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz", + "integrity": "sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + } } }, "tarn": { @@ -9176,9 +9136,9 @@ } }, "terser": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.7.0.tgz", - "integrity": "sha512-Lfb0RiZcjRDXCC3OSHJpEkxJ9Qeqs6mp2v4jf2MHfy8vGERmVDuvjXdd/EnP5Deme5F2yBRBymKmKHCBg2echw==", + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", + "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", "requires": { "commander": "^2.20.0", "source-map": "~0.6.1", @@ -9194,22 +9154,6 @@ "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" - }, - "dependencies": { - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } } }, "text-table": { @@ -9219,9 +9163,9 @@ "dev": true }, "threads": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/threads/-/threads-1.4.1.tgz", - "integrity": "sha512-LSgGCu2lwdrfqjYWmeqO+7fgxAbUtjlsa7UA5J6r4x8fCoMd015h19rMwXqz4/q8l3svdloE36Of41rpZWiYFg==", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/threads/-/threads-1.6.3.tgz", + "integrity": "sha512-tKwFIWRgfAT85KGkrpDt2jWPO8IVH0sLNfB/pXad/VW9eUIY2Zlz+QyeizypXhPHv9IHfqRzvk2t3mPw+imhWw==", "requires": { "callsites": "^3.1.0", "debug": "^4.1.1", @@ -9273,6 +9217,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "requires": { "is-number": "^7.0.0" } @@ -9331,7 +9276,8 @@ "type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true }, "type-fest": { "version": "0.8.1", @@ -9358,30 +9304,24 @@ } }, "ueberdb2": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/ueberdb2/-/ueberdb2-1.2.3.tgz", - "integrity": "sha512-D7lbzudPcOzCSWOHFRvPb6JGFa/zyNB2VcqrTXydwJ6+QlbTF4q6UzriEIWi0xIvp9KkCNJdwzKsDb6EBvXhwQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/ueberdb2/-/ueberdb2-1.2.5.tgz", + "integrity": "sha512-Bts6kmVvhVDWiZjD1JAT1qYknHHK6t9L7kGIFIedGAZRNQ3lRw2XJdf9hKbFpN2HM0J3S/aJoLrZO5BLk3UiaA==", "requires": { "async": "^3.2.0", "cassandra-driver": "^4.5.1", - "chai": "^4.2.0", "channels": "0.0.4", - "cli-table": "^0.3.1", "dirty": "^1.1.0", "elasticsearch": "^16.7.1", - "mocha": "^7.1.2", "mongodb": "^3.6.3", - "mssql": "^7.0.0-beta.1", + "mssql": "^7.0.0-beta.2", "mysql": "2.18.1", "nano": "^8.2.2", "pg": "^8.0.3", - "randexp": "^0.5.3", "redis": "^3.0.2", "rethinkdb": "^2.4.2", - "rimraf": "^3.0.2", "simple-git": "^2.4.0", - "sqlite3": "^5.0.0", - "wtfnode": "^0.8.4" + "sqlite3": "^5.0.1" } }, "uid-safe": { @@ -9434,9 +9374,9 @@ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "requires": { "punycode": "^2.1.0" } @@ -9600,7 +9540,8 @@ "which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true }, "wide-align": { "version": "1.1.3", @@ -9608,35 +9549,6 @@ "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "requires": { "string-width": "^1.0.2 || 2" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "^3.0.0" - } - } } }, "word-wrap": { @@ -9649,6 +9561,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, "requires": { "ansi-styles": "^3.2.0", "string-width": "^3.0.0", @@ -9658,22 +9571,35 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } }, "emoji-regex": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -9684,6 +9610,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, "requires": { "ansi-regex": "^4.1.0" } @@ -9712,11 +9639,6 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.2.tgz", "integrity": "sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA==" }, - "wtfnode": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/wtfnode/-/wtfnode-0.8.4.tgz", - "integrity": "sha512-64GEKtMt/MUBuAm+8kHqP74ojjafzu00aT0JKsmkIwYmjRQ/odO0yhbzKLm+Z9v1gMla+8dwITRKzTAlHsB+Og==" - }, "xml2js": { "version": "0.4.23", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", @@ -9752,9 +9674,10 @@ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" }, "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "dev": true }, "yallist": { "version": "3.1.1", @@ -9766,6 +9689,7 @@ "version": "13.3.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, "requires": { "cliui": "^5.0.0", "find-up": "^3.0.0", @@ -9782,22 +9706,26 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true }, "emoji-regex": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -9808,6 +9736,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, "requires": { "ansi-regex": "^4.1.0" } @@ -9818,6 +9747,7 @@ "version": "13.1.2", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" @@ -9827,6 +9757,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, "requires": { "flat": "^4.1.0", "lodash": "^4.17.15", diff --git a/src/package.json b/src/package.json index 268caa59c..f8949d801 100644 --- a/src/package.json +++ b/src/package.json @@ -70,7 +70,7 @@ "threads": "^1.4.0", "tiny-worker": "^2.3.0", "tinycon": "0.0.1", - "ueberdb2": "^1.2.3", + "ueberdb2": "^1.2.5", "underscore": "1.8.3", "unorm": "1.4.1" }, From 41a501778d1a4e29b63c5af4fd59cbff5429ed6e Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sat, 23 Jan 2021 17:11:52 -0500 Subject: [PATCH 002/153] Update top-level `package-lock.json` Whenever `src/package-lock.json` is updated, the top-level `package-lock.json` must also be updated. --- package-lock.json | 3468 ++++++++++++++++++++++----------------------- 1 file changed, 1679 insertions(+), 1789 deletions(-) diff --git a/package-lock.json b/package-lock.json index cf5941f4c..d8f783a04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2,6 +2,38 @@ "requires": true, "lockfileVersion": 1, "dependencies": { + "@azure/ms-rest-azure-env": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@azure/ms-rest-azure-env/-/ms-rest-azure-env-2.0.0.tgz", + "integrity": "sha512-dG76W7ElfLi+fbTjnZVGj+M9e0BIEJmRxU6fHaUQ12bZBe8EJKYb2GV50YWNaP2uJiVQ5+7nXEVj1VN1UQtaEw==" + }, + "@azure/ms-rest-js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-2.1.0.tgz", + "integrity": "sha512-4BXLVImYRt+jcUmEJ5LUWglI8RBNVQndY6IcyvQ4U8O4kIXdmlRz3cJdA/RpXf5rKT38KOoTO2T6Z1f6Z1HDBg==", + "requires": { + "@types/node-fetch": "^2.3.7", + "@types/tunnel": "0.0.1", + "abort-controller": "^3.0.0", + "form-data": "^2.5.0", + "node-fetch": "^2.6.0", + "tough-cookie": "^3.0.1", + "tslib": "^1.10.0", + "tunnel": "0.0.6", + "uuid": "^3.3.2", + "xml2js": "^0.4.19" + } + }, + "@azure/ms-rest-nodeauth": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@azure/ms-rest-nodeauth/-/ms-rest-nodeauth-3.0.6.tgz", + "integrity": "sha512-2twuzsXHdKMzEFI2+Sr82o6yS4ppNGZceYwil8PFo+rJxOZIoBm9e0//YC+dKilV/3F+6K/HuW8LdskDrJEQWA==", + "requires": { + "@azure/ms-rest-azure-env": "^2.0.0", + "@azure/ms-rest-js": "^2.0.4", + "adal-node": "^0.1.28" + } + }, "@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", @@ -59,6 +91,98 @@ "strip-json-comments": "^3.1.1" } }, + "@js-joda/core": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@js-joda/core/-/core-3.2.0.tgz", + "integrity": "sha512-PMqgJ0sw5B7FKb2d5bWYIoxjri+QlW/Pys7+Rw82jSH0QN3rB05jZ/VrrsUdh1w4+i2kw9JOejXGq/KhDOX7Kg==" + }, + "@kwsites/file-exists": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "requires": { + "debug": "^4.1.1" + } + }, + "@kwsites/promise-deferred": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" + }, + "@types/caseless": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==" + }, + "@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, + "@types/node": { + "version": "14.14.22", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.22.tgz", + "integrity": "sha512-g+f/qj/cNcqKkc3tFqlXOYjrmZA+jNBiDzbP3kH+B+otKFqAdPgVTGP1IeKRdMml/aE69as5S4FqtxAbl+LaMw==" + }, + "@types/node-fetch": { + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.8.tgz", + "integrity": "sha512-fbjI6ja0N5ZA8TV53RUqzsKNkl9fv8Oj3T7zxW7FGv1GSH7gwJaNF8dzCjrqKaxKeUpTz4yT1DaJFq/omNpGfw==", + "requires": { + "@types/node": "*", + "form-data": "^3.0.0" + }, + "dependencies": { + "form-data": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", + "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + } + } + }, + "@types/request": { + "version": "2.48.5", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz", + "integrity": "sha512-/LO7xRVnL3DxJ1WkPGDQrp4VTV1reX9RkC85mJ+Qzykj2Bdw+mG15aAfDahc76HtknjzE16SX/Yddn6MxVbmGQ==", + "requires": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" + } + }, + "@types/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==" + }, + "@types/tunnel": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@types/tunnel/-/tunnel-0.0.1.tgz", + "integrity": "sha512-AOqu6bQu5MSWwYvehMXLukFHnupHrpZ8nvgae5Ggie9UwzDR1CCwoXgSSWNZJuyOlCdfdsWMA5F2LlmvyoTv8A==", + "requires": { + "@types/node": "*" + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "optional": true + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, "acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", @@ -71,11 +195,46 @@ "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", "dev": true }, + "adal-node": { + "version": "0.1.28", + "resolved": "https://registry.npmjs.org/adal-node/-/adal-node-0.1.28.tgz", + "integrity": "sha1-RoxLs+u9lrEnBmn0ucuk4AZepIU=", + "requires": { + "@types/node": "^8.0.47", + "async": ">=0.6.0", + "date-utils": "*", + "jws": "3.x.x", + "request": ">= 2.52.0", + "underscore": ">= 1.3.1", + "uuid": "^3.1.0", + "xmldom": ">= 0.1.x", + "xpath.js": "~1.1.0" + }, + "dependencies": { + "@types/node": { + "version": "8.10.66", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", + "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==" + } + } + }, + "adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==" + }, + "agentkeepalive": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", + "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", + "requires": { + "humanize-ms": "^1.2.1" + } + }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -104,6 +263,22 @@ "color-convert": "^1.9.0" } }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -113,34 +288,137 @@ "sprintf-js": "~1.0.2" } }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "dev": true }, + "async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" + }, + "bl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", + "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", + "requires": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "optional": true, + "requires": { + "inherits": "~2.0.0" + } + }, + "bluebird": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", + "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, + "browser-request": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/browser-request/-/browser-request-0.3.3.tgz", + "integrity": "sha1-ns5bWsqJopkyJC4Yv5M975h2zBc=" + }, + "bson": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.5.tgz", + "integrity": "sha512-kDuEzldR21lHciPQAIulLs1LZlCXdLziXI6Mb/TDkwXhb//UORJNPXgcRs2CuO4H0DcMkpfT3/ySsP3unoZjBg==" + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "cassandra-driver": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/cassandra-driver/-/cassandra-driver-4.6.1.tgz", + "integrity": "sha512-Vk0kUHlMV4vFXRPwRpKnCZEEMZkp9/RucBDB7gpaUmn9sCusKzzUzVkXeusTxKSoGuIgLJJ7YBiFJdXOctUS7A==", + "requires": { + "@types/long": "^4.0.0", + "@types/node": ">=8", + "adm-zip": "^0.4.13", + "long": "^2.2.0" + } + }, "chalk": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", @@ -192,11 +470,37 @@ } } }, + "channels": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/channels/-/channels-0.0.4.tgz", + "integrity": "sha1-G+4yPt6hUrue8E9BvG5rD1lIqUE=" + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "optional": true + }, + "cloudant-follow": { + "version": "0.18.2", + "resolved": "https://registry.npmjs.org/cloudant-follow/-/cloudant-follow-0.18.2.tgz", + "integrity": "sha512-qu/AmKxDqJds+UmT77+0NbM7Yab2K3w0qSeJRzsq5dRWJTEJdWeb+XpG4OpKuTE9RKOa/Awn2gR3TTnvNr3TeA==", + "requires": { + "browser-request": "~0.3.0", + "debug": "^4.0.1", + "request": "^2.88.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "optional": true + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -204,14 +508,31 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "cross-spawn": { "version": "7.0.3", @@ -224,21 +545,71 @@ "which": "^2.0.1" } }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "date-utils": { + "version": "1.2.21", + "resolved": "https://registry.npmjs.org/date-utils/-/date-utils-1.2.21.tgz", + "integrity": "sha1-YfsWzcEnSzyayq/+n8ad+HIKK2Q=" + }, "debug": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, "requires": { "ms": "2.1.2" } }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "optional": true + }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "optional": true + }, + "denque": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz", + "integrity": "sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ==" + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "optional": true + }, + "dirty": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/dirty/-/dirty-1.1.0.tgz", + "integrity": "sha1-cO3SuZlUHcmXT9Ooy9DGcP4jYHg=" + }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -248,6 +619,70 @@ "esutils": "^2.0.2" } }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "elasticsearch": { + "version": "16.7.2", + "resolved": "https://registry.npmjs.org/elasticsearch/-/elasticsearch-16.7.2.tgz", + "integrity": "sha512-1ZLKZlG2ABfYVBX2d7/JgxOsKJrM5Yu62GvshWu7ZSvhxPomCN4Gas90DS51yYI56JolY0XGhyiRlUhLhIL05Q==", + "requires": { + "agentkeepalive": "^3.4.1", + "chalk": "^1.0.0", + "lodash": "^4.17.10" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, "emoji-regex": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", @@ -306,7 +741,7 @@ "threads": "^1.4.0", "tiny-worker": "^2.3.0", "tinycon": "0.0.1", - "ueberdb2": "^1.2.3", + "ueberdb2": "^1.2.5", "underscore": "1.8.3", "unorm": "1.4.1" }, @@ -345,36 +780,6 @@ "z-schema": "^4.2.2" } }, - "@azure/ms-rest-azure-env": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@azure/ms-rest-azure-env/-/ms-rest-azure-env-1.1.2.tgz", - "integrity": "sha512-l7z0DPCi2Hp88w12JhDTtx5d0Y3+vhfE7JKJb9O7sEz71Cwp053N8piTtTnnk/tUor9oZHgEKi/p3tQQmLPjvA==" - }, - "@azure/ms-rest-js": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-1.9.0.tgz", - "integrity": "sha512-cB4Z2Mg7eBmet1rfbf0QSO1XbhfknRW7B+mX3IHJq0KGHaGJvCPoVTgdsJdCkazEMK1jtANFNEDDzSQacxyzbA==", - "requires": { - "@types/tunnel": "0.0.0", - "axios": "^0.19.0", - "form-data": "^2.3.2", - "tough-cookie": "^2.4.3", - "tslib": "^1.9.2", - "tunnel": "0.0.6", - "uuid": "^3.2.1", - "xml2js": "^0.4.19" - } - }, - "@azure/ms-rest-nodeauth": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@azure/ms-rest-nodeauth/-/ms-rest-nodeauth-2.0.2.tgz", - "integrity": "sha512-KmNNICOxt3EwViAJI3iu2VH8t8BQg5J2rSAyO4IUYLF9ZwlyYsP419pdvl4NBUhluAP2cgN7dfD2V6E6NOMZlQ==", - "requires": { - "@azure/ms-rest-azure-env": "^1.1.2", - "@azure/ms-rest-js": "^1.8.7", - "adal-node": "^0.1.28" - } - }, "@babel/code-frame": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", @@ -706,7 +1111,6 @@ "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz", "integrity": "sha512-ZR0rq/f/E4f4XcgnDvtMWXCUJpi8eO0rssVhmztsZqLIEFA9UUP9zmpE0VxlM+kv/E1ul2I876Fwil2ayptDVg==", "requires": { - "camelcase": "^5.3.1", "find-up": "^4.1.0", "js-yaml": "^3.13.1", "resolve-from": "^5.0.0" @@ -732,10 +1136,7 @@ "p-locate": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "requires": { - "p-limit": "^2.2.0" - } + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==" }, "path-exists": { "version": "4.0.0", @@ -754,41 +1155,10 @@ "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.2.tgz", "integrity": "sha512-qS/a24RA5FEoiJS9wiv6Pwg2c/kiUo3IVUQcfeM9JvsR6pM8Yx+yl/6xWYLckZCT5jpLNhslgjiA8p/XcGyMRQ==" }, - "@kwsites/file-exists": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", - "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", - "requires": { - "debug": "^4.1.1" - }, - "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "@kwsites/promise-deferred": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", - "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" - }, "@sinonjs/commons": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", - "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==", - "requires": { - "type-detect": "4.0.8" - } + "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==" }, "@sinonjs/fake-timers": { "version": "6.0.1", @@ -813,8 +1183,7 @@ "integrity": "sha512-CaIcyX5cDsjcW/ab7HposFWzV1kC++4HNsfnEdFJa7cP1QIuILAKV+BgfeqRXhcnSAc76r/Rh/O5C+300BwUIw==", "requires": { "@sinonjs/commons": "^1.6.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" + "lodash.get": "^4.4.2" } }, "@sinonjs/text-encoding": { @@ -822,71 +1191,11 @@ "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==" }, - "@types/caseless": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", - "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==" - }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" }, - "@types/long": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", - "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" - }, - "@types/node": { - "version": "14.14.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.13.tgz", - "integrity": "sha512-vbxr0VZ8exFMMAjCW8rJwaya0dMCDyYW2ZRdTyjtrCvJoENMpdUHOT/eTzvgyA5ZnqRZ/sI0NwqAxNHKYokLJQ==" - }, - "@types/readable-stream": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.9.tgz", - "integrity": "sha512-sqsgQqFT7HmQz/V5jH1O0fvQQnXAJO46Gg9LRO/JPfjmVmGUlcx831TZZO3Y3HtWhIkzf3kTsNT0Z0kzIhIvZw==", - "requires": { - "@types/node": "*", - "safe-buffer": "*" - } - }, - "@types/request": { - "version": "2.48.5", - "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz", - "integrity": "sha512-/LO7xRVnL3DxJ1WkPGDQrp4VTV1reX9RkC85mJ+Qzykj2Bdw+mG15aAfDahc76HtknjzE16SX/Yddn6MxVbmGQ==", - "requires": { - "@types/caseless": "*", - "@types/node": "*", - "@types/tough-cookie": "*", - "form-data": "^2.5.0" - }, - "dependencies": { - "form-data": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", - "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - } - } - }, - "@types/tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==" - }, - "@types/tunnel": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/@types/tunnel/-/tunnel-0.0.0.tgz", - "integrity": "sha512-FGDp0iBRiBdPjOgjJmn1NH0KDLN+Z8fRmo+9J7XGBhubq1DPrGrbmG4UTlGzrpbCpesMqD0sWkzi27EYkOMHyg==", - "requires": { - "@types/node": "*" - } - }, "@types/unist": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz", @@ -911,47 +1220,11 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==" }, - "adal-node": { - "version": "0.1.28", - "resolved": "https://registry.npmjs.org/adal-node/-/adal-node-0.1.28.tgz", - "integrity": "sha1-RoxLs+u9lrEnBmn0ucuk4AZepIU=", - "requires": { - "@types/node": "^8.0.47", - "async": ">=0.6.0", - "date-utils": "*", - "jws": "3.x.x", - "request": ">= 2.52.0", - "underscore": ">= 1.3.1", - "uuid": "^3.1.0", - "xmldom": ">= 0.1.x", - "xpath.js": "~1.1.0" - }, - "dependencies": { - "@types/node": { - "version": "8.10.66", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", - "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==" - } - } - }, - "adm-zip": { - "version": "0.4.16", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", - "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==" - }, "after": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" }, - "agentkeepalive": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", - "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", - "requires": { - "humanize-ms": "^1.2.1" - } - }, "aggregate-error": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", @@ -972,33 +1245,6 @@ "uri-js": "^4.2.2" } }, - "ansi-colors": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", - "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==" - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, "append-transform": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", @@ -1057,7 +1303,6 @@ "lodash.flatten": "^4.4.0", "lodash.isplainobject": "^4.0.6", "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", "readable-stream": "^2.0.0" }, "dependencies": { @@ -1144,11 +1389,6 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" - }, "astral-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", @@ -1184,14 +1424,6 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==" }, - "axios": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", - "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", - "requires": { - "follow-redirects": "1.5.10" - } - }, "backo2": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", @@ -1202,11 +1434,6 @@ "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==" }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, "base64-arraybuffer": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", @@ -1243,16 +1470,6 @@ "callsite": "1.0.0" } }, - "bignumber.js": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", - "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" - }, - "binary-extensions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", - "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==" - }, "binary-search": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/binary-search/-/binary-search-1.3.6.tgz", @@ -1273,11 +1490,6 @@ "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" }, - "bluebird": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", - "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" - }, "body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", @@ -1319,33 +1531,6 @@ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "requires": { - "fill-range": "^7.0.1" - } - }, - "browser-request": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/browser-request/-/browser-request-0.3.3.tgz", - "integrity": "sha1-ns5bWsqJopkyJC4Yv5M975h2zBc=" - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" - }, "buffer": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", @@ -1360,21 +1545,11 @@ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" - }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" }, - "buffer-writer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", - "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" - }, "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -1391,15 +1566,6 @@ "write-file-atomic": "^3.0.0" } }, - "call-bind": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz", - "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.0" - } - }, "call-me-maybe": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", @@ -1415,55 +1581,16 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" - }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, - "cassandra-driver": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/cassandra-driver/-/cassandra-driver-4.6.1.tgz", - "integrity": "sha512-Vk0kUHlMV4vFXRPwRpKnCZEEMZkp9/RucBDB7gpaUmn9sCusKzzUzVkXeusTxKSoGuIgLJJ7YBiFJdXOctUS7A==", - "requires": { - "@types/long": "^4.0.0", - "@types/node": ">=8", - "adm-zip": "^0.4.13", - "long": "^2.2.0" - } - }, "ccount": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.0.5.tgz", "integrity": "sha512-MOli1W+nfbPLlKEhInaxhRdp7KVLFxLN5ykwzHgLsLI3H3gs5jjFAK4Eoj3OzzcxCtumDaI8onoVDeQyWaNTkw==" }, - "chai": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", - "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", - "requires": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "pathval": "^1.1.0", - "type-detect": "^4.0.5" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, "channels": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/channels/-/channels-0.0.4.tgz", @@ -1479,11 +1606,6 @@ "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==" }, - "check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" - }, "cheerio": { "version": "0.22.0", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", @@ -1507,21 +1629,6 @@ "lodash.some": "^4.4.0" } }, - "chokidar": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", - "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", - "requires": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.1.1", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.2.0" - } - }, "clean-css": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", @@ -1535,98 +1642,6 @@ "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" }, - "cli-table": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.4.tgz", - "integrity": "sha512-1vinpnX/ZERcmE443i3SZTmU5DF0rPO9DrL4I2iVAllhxzCM9SzPlHnz19fsZB78htkKZvYBvj6SZ6vXnaxmTA==", - "requires": { - "chalk": "^2.4.1", - "string-width": "^4.2.0" - } - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "cloudant-follow": { - "version": "0.18.2", - "resolved": "https://registry.npmjs.org/cloudant-follow/-/cloudant-follow-0.18.2.tgz", - "integrity": "sha512-qu/AmKxDqJds+UmT77+0NbM7Yab2K3w0qSeJRzsq5dRWJTEJdWeb+XpG4OpKuTE9RKOa/Awn2gR3TTnvNr3TeA==", - "requires": { - "browser-request": "~0.3.0", - "debug": "^4.0.1", - "request": "^2.88.0" - }, - "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -1672,7 +1687,6 @@ "requires": { "buffer-crc32": "^0.2.13", "crc32-stream": "^3.0.1", - "normalize-path": "^3.0.0", "readable-stream": "^2.3.6" }, "dependencies": { @@ -1710,11 +1724,6 @@ } } }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, "content-disposition": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", @@ -1847,11 +1856,6 @@ "assert-plus": "^1.0.0" } }, - "date-utils": { - "version": "1.2.21", - "resolved": "https://registry.npmjs.org/date-utils/-/date-utils-1.2.21.tgz", - "integrity": "sha1-YfsWzcEnSzyayq/+n8ad+HIKK2Q=" - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -1860,19 +1864,6 @@ "ms": "2.0.0" } }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", - "requires": { - "type-detect": "^4.0.0" - } - }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", @@ -1886,24 +1877,11 @@ "strip-bom": "^4.0.0" } }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "requires": { - "object-keys": "^1.0.12" - } - }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, - "denque": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz", - "integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==" - }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -1914,16 +1892,6 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" - }, - "dirty": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/dirty/-/dirty-1.1.0.tgz", - "integrity": "sha1-cO3SuZlUHcmXT9Ooy9DGcP4jYHg=" - }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -1963,11 +1931,6 @@ "domelementtype": "1" } }, - "drange": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/drange/-/drange-1.1.1.tgz", - "integrity": "sha512-pYxfDYpued//QpnLIm4Avk7rsNtAtQkUES2cwAYSvD/wd2pKD71gN2Ebj3e7klzXwjocvE8c5vx/1fxwpqmSxA==" - }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -1977,14 +1940,6 @@ "safer-buffer": "^2.1.0" } }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -1995,58 +1950,6 @@ "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.6.1.tgz", "integrity": "sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ==" }, - "elasticsearch": { - "version": "16.7.2", - "resolved": "https://registry.npmjs.org/elasticsearch/-/elasticsearch-16.7.2.tgz", - "integrity": "sha512-1ZLKZlG2ABfYVBX2d7/JgxOsKJrM5Yu62GvshWu7ZSvhxPomCN4Gas90DS51yYI56JolY0XGhyiRlUhLhIL05Q==", - "requires": { - "agentkeepalive": "^3.4.1", - "chalk": "^1.0.0", - "lodash": "^4.17.10" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -2166,53 +2069,6 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" }, - "errs": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/errs/-/errs-0.3.2.tgz", - "integrity": "sha1-eYCZstvTfKK8dJ5TinwTB9C1BJk=" - }, - "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - }, - "dependencies": { - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } - } - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, "es6-error": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", @@ -2223,11 +2079,6 @@ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, "eslint": { "version": "7.14.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.14.0.tgz", @@ -2662,14 +2513,6 @@ "flat-cache": "^2.0.1" } }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "requires": { - "to-regex-range": "^5.0.1" - } - }, "finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", @@ -2699,22 +2542,6 @@ "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, - "flat": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz", - "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==", - "requires": { - "is-buffer": "~2.0.3" - } - }, "flat-cache": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", @@ -2740,24 +2567,6 @@ "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==" }, - "follow-redirects": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", - "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", - "requires": { - "debug": "=3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - } - } - }, "foreground-child": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", @@ -2807,16 +2616,6 @@ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", @@ -2827,26 +2626,6 @@ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==" }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" - }, - "get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=" - }, - "get-intrinsic": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz", - "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -2855,27 +2634,6 @@ "assert-plus": "^1.0.0" } }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "requires": { - "is-glob": "^4.0.1" - } - }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -2886,11 +2644,6 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==" - }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -2905,29 +2658,6 @@ "har-schema": "^2.0.0" } }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - } - } - }, "has-binary2": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", @@ -2948,16 +2678,6 @@ "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" - }, "hasha": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.0.tgz", @@ -3037,11 +2757,6 @@ "space-separated-tokens": "^1.0.0" } }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" - }, "html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -3094,14 +2809,6 @@ "sshpk": "^1.7.0" } }, - "humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", - "requires": { - "ms": "^2.0.0" - } - }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -3151,15 +2858,6 @@ "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -3184,24 +2882,11 @@ "is-decimal": "^1.0.0" } }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "requires": { - "binary-extensions": "^2.0.0" - } - }, "is-buffer": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==" }, - "is-callable": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", - "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==" - }, "is-core-module": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz", @@ -3210,49 +2895,16 @@ "has": "^1.0.3" } }, - "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" - }, "is-decimal": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==" }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "requires": { - "is-extglob": "^2.1.1" - } - }, "is-hexadecimal": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==" }, - "is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" - }, "is-observable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz", @@ -3271,27 +2923,11 @@ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-1.0.1.tgz", "integrity": "sha1-MVc3YcBX4zwukaq56W2gjO++duU=" }, - "is-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", - "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", - "requires": { - "has-symbols": "^1.0.1" - } - }, "is-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "requires": { - "has-symbols": "^1.0.1" - } - }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -3307,11 +2943,6 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -3440,11 +3071,6 @@ "esprima": "^4.0.0" } }, - "jsbi": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-3.1.4.tgz", - "integrity": "sha512-52QRRFSsi9impURE8ZUbzAMCLjPm4THO7H2fcuIvaaeFTbSysvkodbQQXIVsNgq/ypDbq6dJiuGKL0vZ/i9hUg==" - }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", @@ -3514,25 +3140,6 @@ "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.1.tgz", "integrity": "sha512-aWgeGFW67BP3e5181Ep1Fv2v8z//iBJfrvyTnq8wG86vEESwmonn1zPBJ0VfmT9CJq2FIT0VsETtrNFm2a+SHA==" }, - "jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "requires": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, "languages4translatewiki": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/languages4translatewiki/-/languages4translatewiki-0.1.3.tgz", @@ -3589,15 +3196,6 @@ "type-check": "~0.4.0" } }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, "lodash": { "version": "4.17.20", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", @@ -3698,14 +3296,6 @@ "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=" }, - "log-symbols": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", - "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", - "requires": { - "chalk": "^2.4.2" - } - }, "log4js": { "version": "0.6.35", "resolved": "https://registry.npmjs.org/log4js/-/log4js-0.6.35.tgz", @@ -3738,11 +3328,6 @@ } } }, - "long": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/long/-/long-2.4.0.tgz", - "integrity": "sha1-n6GAux2VAM3CnEFWdmoZleH0Uk8=" - }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -3800,56 +3385,19 @@ "mime-db": "1.44.0" } }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" - } - }, "mocha": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.2.tgz", "integrity": "sha512-o96kdRKMKI3E8U0bjnfqW4QMk12MwZ4mhdBTf+B5a1q9+aq2HRnj+3ZdJu0B/ZhJeK78MgYuv6L8d/rA5AeBJA==", "requires": { - "ansi-colors": "3.2.3", - "browser-stdout": "1.3.1", - "chokidar": "3.3.0", "debug": "3.2.6", - "diff": "3.5.0", "escape-string-regexp": "1.0.5", - "find-up": "3.0.0", - "glob": "7.1.3", - "growl": "1.10.5", - "he": "1.2.0", "js-yaml": "3.13.1", - "log-symbols": "3.0.0", "minimatch": "3.0.4", "mkdirp": "0.5.5", "ms": "2.1.1", - "node-environment-flags": "1.0.6", - "object.assign": "4.1.0", - "strip-json-comments": "2.0.1", "supports-color": "6.0.0", - "which": "1.3.1", - "wide-align": "1.1.3", - "yargs": "13.3.2", - "yargs-parser": "13.1.2", - "yargs-unparser": "1.6.0" + "wide-align": "1.1.3" }, "dependencies": { "debug": { @@ -3894,108 +3442,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, - "mssql": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/mssql/-/mssql-6.3.0.tgz", - "integrity": "sha512-6/BK/3J8Oe4t6BYnmdCCORHhyBtBI/Fh0Sh6l1hPzb/hKtxDrsaSDGIpck1u8bzkLzev39TH5W2nz+ffeRz7gg==", - "requires": { - "debug": "^4.3.1", - "tarn": "^1.1.5", - "tedious": "^6.7.0" - }, - "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "mysql": { - "version": "2.18.1", - "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", - "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", - "requires": { - "bignumber.js": "9.0.0", - "readable-stream": "2.3.7", - "safe-buffer": "5.1.2", - "sqlstring": "2.3.1" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "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==" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "nano": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/nano/-/nano-8.2.3.tgz", - "integrity": "sha512-nubyTQeZ/p+xf3ZFFMd7WrZwpcy9tUDrbaXw9HFBsM6zBY5gXspvOjvG2Zz3emT6nfJtP/h7F2/ESfsVVXnuMw==", - "requires": { - "@types/request": "^2.48.4", - "cloudant-follow": "^0.18.2", - "debug": "^4.1.1", - "errs": "^0.3.2", - "request": "^2.88.0" - }, - "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "native-duplexpair": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/native-duplexpair/-/native-duplexpair-1.0.0.tgz", - "integrity": "sha1-eJkHjmS/PIo9cyYBs9QP8F21j6A=" - }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -4028,22 +3474,6 @@ } } }, - "node-environment-flags": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", - "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", - "requires": { - "object.getownpropertydescriptors": "^2.0.3", - "semver": "^5.7.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, "node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -4061,11 +3491,6 @@ "promise": "~1.3.0" } }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" - }, "npm": { "version": "6.14.8", "resolved": "https://registry.npmjs.org/npm/-/npm-6.14.8.tgz", @@ -7599,7 +7024,6 @@ "@istanbuljs/schema": "^0.1.2", "caching-transform": "^4.0.0", "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", "find-cache-dir": "^3.2.0", "find-up": "^4.1.0", "foreground-child": "^2.0.0", @@ -7703,10 +7127,7 @@ "p-locate": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "requires": { - "p-limit": "^2.2.0" - } + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==" }, "path-exists": { "version": "4.0.0", @@ -7747,26 +7168,16 @@ "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==", "requires": { "cliui": "^6.0.0", - "decamelize": "^1.2.0", "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", "yargs-parser": "^18.1.1" } }, "yargs-parser": { "version": "18.1.3", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==" } } }, @@ -7780,37 +7191,6 @@ "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" }, - "object-inspect": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", - "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==" - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "object.getownpropertydescriptors": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.1.tgz", - "integrity": "sha512-6DtXgZ/lIZ9hqx4GtZETobXLR/ZLaa0aqV0kzbn80Rf8Z2e/XFnhA0I7p07N2wH8bBBltr2xQPi6sbKWAY2Eng==", - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1" - } - }, "observable-fns": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/observable-fns/-/observable-fns-0.5.1.tgz", @@ -7829,14 +7209,6 @@ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, "openapi-backend": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/openapi-backend/-/openapi-backend-2.4.1.tgz", @@ -7893,22 +7265,6 @@ "word-wrap": "^1.2.3" } }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, "p-map": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", @@ -7917,11 +7273,6 @@ "aggregate-error": "^3.0.0" } }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, "package-hash": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", @@ -7933,11 +7284,6 @@ "release-zalgo": "^1.0.0" } }, - "packet-reader": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", - "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" - }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -7972,16 +7318,6 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -7997,75 +7333,11 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, - "pathval": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", - "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=" - }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, - "pg": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.5.1.tgz", - "integrity": "sha512-9wm3yX9lCfjvA98ybCyw2pADUivyNWT/yIP4ZcDVpMN0og70BUWYEGXPCTAQdGTAqnytfRADb7NERrY1qxhIqw==", - "requires": { - "buffer-writer": "2.0.0", - "packet-reader": "1.0.0", - "pg-connection-string": "^2.4.0", - "pg-pool": "^3.2.2", - "pg-protocol": "^1.4.0", - "pg-types": "^2.1.0", - "pgpass": "1.x" - } - }, - "pg-connection-string": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.4.0.tgz", - "integrity": "sha512-3iBXuv7XKvxeMrIgym7njT+HlZkwZqqGX4Bu9cci8xHZNT+Um1gWKqCsAzcC0d95rcKMU5WBg6YRUcHyV0HZKQ==" - }, - "pg-int8": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", - "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" - }, - "pg-pool": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.2.2.tgz", - "integrity": "sha512-ORJoFxAlmmros8igi608iVEbQNNZlp89diFVx6yV5v+ehmpMY9sK6QgpmgoXbmkNaBAx8cOOZh9g80kJv1ooyA==" - }, - "pg-protocol": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.4.0.tgz", - "integrity": "sha512-El+aXWcwG/8wuFICMQjM5ZSAm6OWiJicFdNYo+VY3QP+8vI4SvLIWVe51PppTzMhikUJR+PsyIFKqfdXPz/yxA==" - }, - "pg-types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", - "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", - "requires": { - "pg-int8": "1.0.1", - "postgres-array": "~2.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.4", - "postgres-interval": "^1.1.0" - } - }, - "pgpass": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.4.tgz", - "integrity": "sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w==", - "requires": { - "split2": "^3.1.1" - } - }, - "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" - }, "pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -8094,10 +7366,7 @@ "p-locate": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "requires": { - "p-limit": "^2.2.0" - } + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==" }, "path-exists": { "version": "4.0.0", @@ -8106,39 +7375,11 @@ } } }, - "postgres-array": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", - "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" - }, - "postgres-bytea": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", - "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=" - }, - "postgres-date": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", - "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" - }, - "postgres-interval": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", - "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", - "requires": { - "xtend": "^4.0.0" - } - }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" - }, "process-on-spawn": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", @@ -8202,15 +7443,6 @@ "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz", "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==" }, - "randexp": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.5.3.tgz", - "integrity": "sha512-U+5l2KrcMNOUPYvazA3h5ekF80FHTUG+87SEAmHZmolh1M+i/WyTCxVzmi+tidIa1tM4BSe8g2Y/D3loWDjj+w==", - "requires": { - "drange": "^1.0.2", - "ret": "^0.2.0" - } - }, "random-bytes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", @@ -8266,43 +7498,6 @@ "util-deprecate": "^1.0.1" } }, - "readdirp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", - "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", - "requires": { - "picomatch": "^2.0.4" - } - }, - "redis": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/redis/-/redis-3.0.2.tgz", - "integrity": "sha512-PNhLCrjU6vKVuMOyFu7oSP296mwBkcE6lrAjruBYG5LgdSqtRBoVQIylrMyVZD/lkF24RSNNatzvYag6HRBHjQ==", - "requires": { - "denque": "^1.4.1", - "redis-commands": "^1.5.0", - "redis-errors": "^1.2.0", - "redis-parser": "^3.0.0" - } - }, - "redis-commands": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.6.0.tgz", - "integrity": "sha512-2jnZ0IkjZxvguITjFTrGiLyzQZcTvaw8DAaCXxZq/dsHXz7KfMQ3OUJy7Tz9vnRtZRVz6VRCPDvruvU8Ts44wQ==" - }, - "redis-errors": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", - "integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=" - }, - "redis-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", - "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=", - "requires": { - "redis-errors": "^1.0.0" - } - }, "regexpp": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", @@ -8402,16 +7597,6 @@ } } }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" - }, "resolve": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", @@ -8422,27 +7607,6 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" }, - "ret": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz", - "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==" - }, - "rethinkdb": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/rethinkdb/-/rethinkdb-2.4.2.tgz", - "integrity": "sha512-6DzwqEpFc8cqesAdo07a845oBRxLiHvWzopTKBo/uY2ypGWIsJQFJk3wjRDtSEhczxJqLS0jnf37rwgzYAw8NQ==", - "requires": { - "bluebird": ">= 2.3.2 < 3" - } - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "requires": { - "glob": "^7.1.3" - } - }, "safe-buffer": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", @@ -8453,11 +7617,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, "security": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/security/-/security-1.0.0.tgz", @@ -8518,11 +7677,6 @@ "send": "0.17.1" } }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, "set-cookie-parser": { "version": "2.4.6", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.4.6.tgz", @@ -8551,31 +7705,6 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" }, - "simple-git": { - "version": "2.27.0", - "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-2.27.0.tgz", - "integrity": "sha512-/Q4aolzErYrIx6SgyH421jmtv5l1DaAw+KYWMWy229+isW6yld/nHGxJ2xUR/aeX3SuYJnbucyUigERwaw4Xow==", - "requires": { - "@kwsites/file-exists": "^1.1.1", - "@kwsites/promise-deferred": "^1.1.1", - "debug": "^4.3.1" - }, - "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, "sinon": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.0.tgz", @@ -8811,24 +7940,11 @@ } } }, - "split2": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", - "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", - "requires": { - "readable-stream": "^3.0.0" - } - }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, - "sqlstring": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", - "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=" - }, "sshpk": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", @@ -8850,34 +7966,6 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "string.prototype.trimend": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", - "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==", - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3" - } - }, - "string.prototype.trimstart": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz", - "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==", - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3" - } - }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -8898,24 +7986,11 @@ "is-hexadecimal": "^1.0.0" } }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "requires": { - "ansi-regex": "^5.0.0" - } - }, "strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==" }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" - }, "superagent": { "version": "3.8.3", "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", @@ -9053,14 +8128,6 @@ } } }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - }, "swagger-parser": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-9.0.1.tgz", @@ -9137,62 +8204,6 @@ "readable-stream": "^3.1.1" } }, - "tarn": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/tarn/-/tarn-1.1.5.tgz", - "integrity": "sha512-PMtJ3HCLAZeedWjJPgGnCvcphbCOMbtZpjKgLq3qM5Qq9aQud+XHrL0WlrlgnTyS8U+jrjGbEXprFcQrxPy52g==" - }, - "tedious": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/tedious/-/tedious-6.7.0.tgz", - "integrity": "sha512-8qr7+sB0h4SZVQBRWUgHmYuOEflAOl2eihvxk0fVNvpvGJV4V5UC/YmSvebyfgyfwWcPO22/AnSbYVZZqf9wuQ==", - "requires": { - "@azure/ms-rest-nodeauth": "2.0.2", - "@types/node": "^12.12.17", - "@types/readable-stream": "^2.3.5", - "bl": "^3.0.0", - "depd": "^2.0.0", - "iconv-lite": "^0.5.0", - "jsbi": "^3.1.1", - "native-duplexpair": "^1.0.0", - "punycode": "^2.1.0", - "readable-stream": "^3.4.0", - "sprintf-js": "^1.1.2" - }, - "dependencies": { - "@types/node": { - "version": "12.19.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.9.tgz", - "integrity": "sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q==" - }, - "bl": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/bl/-/bl-3.0.1.tgz", - "integrity": "sha512-jrCW5ZhfQ/Vt07WX1Ngs+yn9BDqPL/gw28S7s9H6QK/gupnizNzJAss5akW20ISgOrbLTlXOOCTJeNUQqruAWQ==", - "requires": { - "readable-stream": "^3.0.1" - } - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, - "iconv-lite": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.2.tgz", - "integrity": "sha512-kERHXvpSaB4aU3eANwidg79K8FlrN77m8G9V+0vOR3HYaRifrlwMEpT7ZBJqLSEIHnEgJTHcWK82wwLwwKwtag==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "sprintf-js": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", - "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==" - } - } - }, "terser": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/terser/-/terser-4.7.0.tgz", @@ -9283,14 +8294,6 @@ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "requires": { - "is-number": "^7.0.0" - } - }, "toidentifier": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", @@ -9310,16 +8313,6 @@ "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==" }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" - }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -9341,11 +8334,6 @@ "prelude-ls": "^1.2.1" } }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" - }, "type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", @@ -9368,84 +8356,6 @@ "is-typedarray": "^1.0.0" } }, - "ueberdb2": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/ueberdb2/-/ueberdb2-0.5.6.tgz", - "integrity": "sha512-stLhNkWlxUMAO33JjEh8JCRuZvHYeDQjbo6K1C3I7R37AlMKNu9GWXSZm1wQDnAqpXAXeMVh3owBsAdj0YvOrg==", - "requires": { - "async": "^3.2.0", - "cassandra-driver": "^4.5.1", - "chai": "^4.2.0", - "channels": "0.0.4", - "cli-table": "^0.3.1", - "dirty": "^1.1.0", - "elasticsearch": "^16.7.1", - "mocha": "^7.1.2", - "mssql": "^6.2.3", - "mysql": "2.18.1", - "nano": "^8.2.2", - "pg": "^8.0.3", - "randexp": "^0.5.3", - "redis": "^3.0.2", - "rethinkdb": "^2.4.2", - "rimraf": "^3.0.2", - "simple-git": "^2.4.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "requires": { - "ms": "^2.1.1" - } - }, - "mocha": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.2.0.tgz", - "integrity": "sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==", - "requires": { - "ansi-colors": "3.2.3", - "browser-stdout": "1.3.1", - "chokidar": "3.3.0", - "debug": "3.2.6", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "find-up": "3.0.0", - "glob": "7.1.3", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "3.13.1", - "log-symbols": "3.0.0", - "minimatch": "3.0.4", - "mkdirp": "0.5.5", - "ms": "2.1.1", - "node-environment-flags": "1.0.6", - "object.assign": "4.1.0", - "strip-json-comments": "2.0.1", - "supports-color": "6.0.0", - "which": "1.3.1", - "wide-align": "1.1.3", - "yargs": "13.3.2", - "yargs-parser": "13.1.2", - "yargs-unparser": "1.6.0" - } - }, - "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==" - }, - "supports-color": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", - "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, "uid-safe": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", @@ -9644,111 +8554,11 @@ "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.4.tgz", "integrity": "sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==" }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "requires": { - "string-width": "^1.0.2 || 2" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, "write": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", @@ -9773,116 +8583,16 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.0.tgz", "integrity": "sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w==" }, - "xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - } - }, - "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" - }, - "xmldom": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.4.0.tgz", - "integrity": "sha512-2E93k08T30Ugs+34HBSTQLVtpi6mCddaY8uO+pMNk1pqSjV5vElzn4mmh6KLxN3hki8rNcHSYzILoh3TEWORvA==" - }, "xmlhttprequest-ssl": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" }, - "xpath.js": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/xpath.js/-/xpath.js-1.1.0.tgz", - "integrity": "sha512-jg+qkfS4K8E7965sqaUl8mRngXiKb3WZGfONgE18pr03FUQiuSV6G+Ej4tS55B+rIQSFEIw3phdVAQ4pPqNWfQ==" - }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" }, - "y18n": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==" - }, - "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "yargs-unparser": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", - "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", - "requires": { - "flat": "^4.1.0", - "lodash": "^4.17.15", - "yargs": "^13.3.0" - } - }, "yeast": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", @@ -9911,11 +8621,15 @@ } } }, + "errs": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/errs/-/errs-0.3.2.tgz", + "integrity": "sha1-eYCZstvTfKK8dJ5TinwTB9C1BJk=" + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "eslint": { "version": "7.15.0", @@ -10159,17 +8873,30 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "fast-levenshtein": { "version": "2.0.6", @@ -10202,23 +8929,62 @@ "integrity": "sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA==", "dev": true }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "optional": true, + "requires": { + "minipass": "^2.6.0" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, - "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "optional": true + "fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "optional": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "optional": true, + "requires": { + "glob": "^7.1.3" + } + } + } }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "functional-red-black-tree": { "version": "1.0.1", @@ -10226,11 +8992,71 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -10244,7 +9070,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "dev": true, "requires": { "is-glob": "^4.0.1" } @@ -10258,20 +9083,85 @@ "type-fest": "^0.8.1" } }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "optional": true + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "requires": { "function-bind": "^1.1.1" } }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + } + } + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "optional": true + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "requires": { + "ms": "^2.0.0" + } + }, + "iconv-lite": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", + "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } }, "ignore": { "version": "4.0.6", @@ -10279,6 +9169,15 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, + "ignore-walk": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", + "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, "import-fresh": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.2.tgz", @@ -10299,7 +9198,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -10308,8 +9206,18 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "optional": true + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=" }, "is-core-module": { "version": "2.1.0", @@ -10323,29 +9231,40 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, "is-glob": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, "requires": { "is-extglob": "^2.1.1" } }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "js-tokens": { "version": "4.0.0", @@ -10363,11 +9282,25 @@ "esprima": "^4.0.0" } }, + "jsbi": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-3.1.4.tgz", + "integrity": "sha512-52QRRFSsi9impURE8ZUbzAMCLjPm4THO7H2fcuIvaaeFTbSysvkodbQQXIVsNgq/ypDbq6dJiuGKL0vZ/i9hUg==" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -10375,6 +9308,41 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "kebab-case": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/kebab-case/-/kebab-case-1.0.0.tgz", @@ -10394,8 +9362,12 @@ "lodash": { "version": "4.17.20", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", - "dev": true + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + }, + "long": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/long/-/long-2.4.0.tgz", + "integrity": "sha1-n6GAux2VAM3CnEFWdmoZleH0Uk8=" }, "lru-cache": { "version": "6.0.0", @@ -10406,20 +9378,135 @@ "yallist": "^4.0.0" } }, + "memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, + "mime-db": { + "version": "1.45.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz", + "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==" + }, + "mime-types": { + "version": "2.1.28", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz", + "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==", + "requires": { + "mime-db": "1.45.0" + } + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + }, + "dependencies": { + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "optional": true + } + } + }, + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "optional": true, + "requires": { + "minipass": "^2.9.0" + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "mongodb": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.3.tgz", + "integrity": "sha512-rOZuR0QkodZiM+UbQE5kDsJykBqWi0CL4Ec2i1nrGrUI3KO11r6Fbxskqmq3JK2NH7aW4dcccBuUujAP0ERl5w==", + "requires": { + "bl": "^2.2.1", + "bson": "^1.1.4", + "denque": "^1.4.1", + "require_optional": "^1.0.1", + "safe-buffer": "^5.1.2", + "saslprep": "^1.0.0" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "mssql": { + "version": "7.0.0-beta.2", + "resolved": "https://registry.npmjs.org/mssql/-/mssql-7.0.0-beta.2.tgz", + "integrity": "sha512-7fOp+QzFf24ir/gGeSvyyGlQKfxZj6tx88vsk4UiQw/t/zpJ9PLjOBOoi6Ff+Tw/CZ1aJTa83MPm+CRYJ/UCQA==", + "requires": { + "debug": "^4", + "tarn": "^3.0.1", + "tedious": "^9.2.3" + } + }, + "mysql": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", + "requires": { + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", + "safe-buffer": "5.1.2", + "sqlstring": "2.3.1" + }, + "dependencies": { + "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==" + } + } + }, + "nano": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/nano/-/nano-8.2.3.tgz", + "integrity": "sha512-nubyTQeZ/p+xf3ZFFMd7WrZwpcy9tUDrbaXw9HFBsM6zBY5gXspvOjvG2Zz3emT6nfJtP/h7F2/ESfsVVXnuMw==", + "requires": { + "@types/request": "^2.48.4", + "cloudant-follow": "^0.18.2", + "debug": "^4.1.1", + "errs": "^0.3.2", + "request": "^2.88.0" + } + }, + "native-duplexpair": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/native-duplexpair/-/native-duplexpair-1.0.0.tgz", + "integrity": "sha1-eJkHjmS/PIo9cyYBs9QP8F21j6A=" }, "natural-compare": { "version": "1.4.0", @@ -10427,11 +9514,228 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "needle": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.6.0.tgz", + "integrity": "sha512-KKYdza4heMsEfSWD7VPUIz3zX2XDwOyX2d+geb4vrERZMT5RMU6ujjaD+I5Yr54uZxQ2w6XRTAhHBbSCyovZBg==", + "optional": true, + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, + "node-addon-api": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.1.0.tgz", + "integrity": "sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw==", + "optional": true + }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + }, + "node-gyp": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", + "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", + "optional": true, + "requires": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "^2.87.0", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "optional": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "optional": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "node-pre-gyp": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz", + "integrity": "sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==", + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + }, + "dependencies": { + "nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "optional": true + }, + "tar": { + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "optional": true + } + } + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "optional": true, + "requires": { + "abbrev": "1" + } + }, + "npm-bundled": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", + "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", + "optional": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "optional": true + }, + "npm-packlist": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", + "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "optional": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "optional": true + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1" } @@ -10450,6 +9754,33 @@ "word-wrap": "^1.2.3" } }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "optional": true + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -10462,8 +9793,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-key": { "version": "3.1.1", @@ -10477,23 +9807,119 @@ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "pg": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.5.1.tgz", + "integrity": "sha512-9wm3yX9lCfjvA98ybCyw2pADUivyNWT/yIP4ZcDVpMN0og70BUWYEGXPCTAQdGTAqnytfRADb7NERrY1qxhIqw==", + "requires": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.4.0", + "pg-pool": "^3.2.2", + "pg-protocol": "^1.4.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + } + }, + "pg-connection-string": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.4.0.tgz", + "integrity": "sha512-3iBXuv7XKvxeMrIgym7njT+HlZkwZqqGX4Bu9cci8xHZNT+Um1gWKqCsAzcC0d95rcKMU5WBg6YRUcHyV0HZKQ==" + }, + "pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" + }, + "pg-pool": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.2.2.tgz", + "integrity": "sha512-ORJoFxAlmmros8igi608iVEbQNNZlp89diFVx6yV5v+ehmpMY9sK6QgpmgoXbmkNaBAx8cOOZh9g80kJv1ooyA==" + }, + "pg-protocol": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.4.0.tgz", + "integrity": "sha512-El+aXWcwG/8wuFICMQjM5ZSAm6OWiJicFdNYo+VY3QP+8vI4SvLIWVe51PppTzMhikUJR+PsyIFKqfdXPz/yxA==" + }, + "pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "requires": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + } + }, + "pgpass": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.4.tgz", + "integrity": "sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w==", + "requires": { + "split2": "^3.1.1" + } + }, + "postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" + }, + "postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=" + }, + "postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" + }, + "postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "requires": { + "xtend": "^4.0.0" + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, "ramda": { "version": "0.27.1", @@ -10501,12 +9927,151 @@ "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==", "dev": true }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "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==" + } + } + }, + "redis": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/redis/-/redis-3.0.2.tgz", + "integrity": "sha512-PNhLCrjU6vKVuMOyFu7oSP296mwBkcE6lrAjruBYG5LgdSqtRBoVQIylrMyVZD/lkF24RSNNatzvYag6HRBHjQ==", + "requires": { + "denque": "^1.4.1", + "redis-commands": "^1.5.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0" + } + }, + "redis-commands": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.6.0.tgz", + "integrity": "sha512-2jnZ0IkjZxvguITjFTrGiLyzQZcTvaw8DAaCXxZq/dsHXz7KfMQ3OUJy7Tz9vnRtZRVz6VRCPDvruvU8Ts44wQ==" + }, + "redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=" + }, + "redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=", + "requires": { + "redis-errors": "^1.0.0" + } + }, "regexpp": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", "dev": true }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + } + } + }, + "require_optional": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", + "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", + "requires": { + "resolve-from": "^2.0.0", + "semver": "^5.1.0" + }, + "dependencies": { + "resolve-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, "resolve": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", @@ -10523,15 +10088,46 @@ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, + "rethinkdb": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/rethinkdb/-/rethinkdb-2.4.2.tgz", + "integrity": "sha512-6DzwqEpFc8cqesAdo07a845oBRxLiHvWzopTKBo/uY2ypGWIsJQFJk3wjRDtSEhczxJqLS0jnf37rwgzYAw8NQ==", + "requires": { + "bluebird": ">= 2.3.2 < 3" + } + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "requires": { "glob": "^7.1.3" } }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "requires": { + "sparse-bitfield": "^3.0.3" + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, "semver": { "version": "7.3.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", @@ -10541,6 +10137,11 @@ "lru-cache": "^6.0.0" } }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -10556,6 +10157,22 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "optional": true + }, + "simple-git": { + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-2.31.0.tgz", + "integrity": "sha512-/+rmE7dYZMbRAfEmn8EUIOwlM2G7UdzpkC60KF86YAfXGnmGtsPrKsym0hKvLBdFLLW019C+aZld1+6iIVy5xA==", + "requires": { + "@kwsites/file-exists": "^1.1.1", + "@kwsites/promise-deferred": "^1.1.1", + "debug": "^4.3.1" + } + }, "slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", @@ -10567,12 +10184,73 @@ "is-fullwidth-code-point": "^2.0.0" } }, + "sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", + "optional": true, + "requires": { + "memory-pager": "^1.0.2" + } + }, + "split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "requires": { + "readable-stream": "^3.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "sqlite3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.0.1.tgz", + "integrity": "sha512-kh2lTIcYNfmVcvhVJihsYuPj9U0xzBbh6bmqILO2hkryWSC9RRhzYmkIDtJkJ+d8Kg4wZRJ0T1reyHUEspICfg==", + "optional": true, + "requires": { + "node-addon-api": "^3.0.0", + "node-gyp": "3.x", + "node-pre-gyp": "^0.11.0" + } + }, + "sqlstring": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=" + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -10601,6 +10279,21 @@ } } }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "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==" + } + } + }, "strip-ansi": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", @@ -10637,12 +10330,104 @@ "string-width": "^3.0.0" } }, + "tar": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", + "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", + "optional": true, + "requires": { + "block-stream": "*", + "fstream": "^1.0.12", + "inherits": "2" + } + }, + "tarn": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.1.tgz", + "integrity": "sha512-6usSlV9KyHsspvwu2duKH+FMUhqJnAh6J5J/4MITl8s94iSUQTLkJggdiewKv4RyARQccnigV48Z+khiuVZDJw==" + }, + "tedious": { + "version": "9.2.3", + "resolved": "https://registry.npmjs.org/tedious/-/tedious-9.2.3.tgz", + "integrity": "sha512-+mI2r/5mqxpTHKBZ/SW+NNH2MK5i3Pwwkw0gF5ZrS2wf2uT/03bLSss8nm7xh604abJXyjx0sirhwH63H328qA==", + "requires": { + "@azure/ms-rest-nodeauth": "^3.0.6", + "@js-joda/core": "^3.1.0", + "adal-node": "^0.1.28", + "bl": "^3.0.0", + "depd": "^2.0.0", + "iconv-lite": "^0.6.2", + "jsbi": "^3.1.3", + "native-duplexpair": "^1.0.0", + "punycode": "^2.1.0", + "readable-stream": "^3.6.0", + "sprintf-js": "^1.1.2" + }, + "dependencies": { + "bl": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-3.0.1.tgz", + "integrity": "sha512-jrCW5ZhfQ/Vt07WX1Ngs+yn9BDqPL/gw28S7s9H6QK/gupnizNzJAss5akW20ISgOrbLTlXOOCTJeNUQqruAWQ==", + "requires": { + "readable-stream": "^3.0.1" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==" + } + } + }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "tough-cookie": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", + "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", + "requires": { + "ip-regex": "^2.1.0", + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -10658,21 +10443,66 @@ "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true }, + "ueberdb2": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/ueberdb2/-/ueberdb2-1.2.5.tgz", + "integrity": "sha512-Bts6kmVvhVDWiZjD1JAT1qYknHHK6t9L7kGIFIedGAZRNQ3lRw2XJdf9hKbFpN2HM0J3S/aJoLrZO5BLk3UiaA==", + "requires": { + "async": "^3.2.0", + "cassandra-driver": "^4.5.1", + "channels": "0.0.4", + "dirty": "^1.1.0", + "elasticsearch": "^16.7.1", + "mongodb": "^3.6.3", + "mssql": "^7.0.0-beta.2", + "mysql": "2.18.1", + "nano": "^8.2.2", + "pg": "^8.0.3", + "redis": "^3.0.2", + "rethinkdb": "^2.4.2", + "simple-git": "^2.4.0", + "sqlite3": "^5.0.1" + } + }, + "underscore": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.0.tgz", + "integrity": "sha512-21rQzss/XPMjolTiIezSu3JAjgagXKROtNrYFEOWK109qY1Uv2tVjPTZ1ci2HgvQDA16gHYSthQIJfB+XId/rQ==" + }, "uri-js": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", - "dev": true, "requires": { "punycode": "^2.1.0" } }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, "v8-compile-cache": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", "dev": true }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -10682,6 +10512,38 @@ "isexe": "^2.0.0" } }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "requires": { + "string-width": "^1.0.2 || 2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -10691,8 +10553,36 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + }, + "xmldom": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.4.0.tgz", + "integrity": "sha512-2E93k08T30Ugs+34HBSTQLVtpi6mCddaY8uO+pMNk1pqSjV5vElzn4mmh6KLxN3hki8rNcHSYzILoh3TEWORvA==" + }, + "xpath.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xpath.js/-/xpath.js-1.1.0.tgz", + "integrity": "sha512-jg+qkfS4K8E7965sqaUl8mRngXiKb3WZGfONgE18pr03FUQiuSV6G+Ej4tS55B+rIQSFEIw3phdVAQ4pPqNWfQ==" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" }, "yallist": { "version": "4.0.0", From 57be60d1d46c2037844e37479c7defea78f184ef Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sat, 23 Jan 2021 18:04:20 -0500 Subject: [PATCH 003/153] GitHub workflows: Break list of plugins across multiple lines This makes it easier to review changes to the list. --- .github/workflows/backend-tests.yml | 16 ++++++++++++++-- .github/workflows/frontend-tests.yml | 17 +++++++++++++++-- .github/workflows/load-test.yml | 14 +++++++++++++- 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/.github/workflows/backend-tests.yml b/.github/workflows/backend-tests.yml index e50491d23..245dffb97 100644 --- a/.github/workflows/backend-tests.yml +++ b/.github/workflows/backend-tests.yml @@ -52,8 +52,20 @@ jobs: - name: Install all dependencies and symlink for ep_etherpad-lite run: bin/installDeps.sh - - name: Install etherpad plugins - run: npm install ep_align ep_author_hover ep_cursortrace ep_font_size ep_hash_auth ep_headings2 ep_markdown ep_readonly_guest ep_spellcheck ep_subscript_and_superscript ep_table_of_contents + - name: Install Etherpad plugins + run: > + npm install + ep_align + ep_author_hover + ep_cursortrace + ep_font_size + ep_hash_auth + ep_headings2 + ep_markdown + ep_readonly_guest + ep_spellcheck + ep_subscript_and_superscript + ep_table_of_contents # configures some settings and runs npm run test - name: Run the backend tests diff --git a/.github/workflows/frontend-tests.yml b/.github/workflows/frontend-tests.yml index 3b178622e..52fa0af1b 100644 --- a/.github/workflows/frontend-tests.yml +++ b/.github/workflows/frontend-tests.yml @@ -58,8 +58,21 @@ jobs: - name: Install all dependencies and symlink for ep_etherpad-lite run: bin/installDeps.sh - - name: Install etherpad plugins - run: npm install ep_align ep_author_hover ep_cursortrace ep_font_size ep_hash_auth ep_headings2 ep_markdown ep_readonly_guest ep_spellcheck ep_subscript_and_superscript ep_table_of_contents ep_set_title_on_pad + - name: Install Etherpad plugins + run: > + npm install + ep_align + ep_author_hover + ep_cursortrace + ep_font_size + ep_hash_auth + ep_headings2 + ep_markdown + ep_readonly_guest + ep_set_title_on_pad + ep_spellcheck + ep_subscript_and_superscript + ep_table_of_contents - name: export GIT_HASH to env id: environment diff --git a/.github/workflows/load-test.yml b/.github/workflows/load-test.yml index 095adc785..c590da06c 100644 --- a/.github/workflows/load-test.yml +++ b/.github/workflows/load-test.yml @@ -46,7 +46,19 @@ jobs: run: sudo npm install -g etherpad-load-test - name: Install etherpad plugins - run: npm install ep_align ep_author_hover ep_cursortrace ep_font_size ep_hash_auth ep_headings2 ep_markdown ep_readonly_guest ep_spellcheck ep_subscript_and_superscript ep_table_of_contents + run: > + npm install + ep_align + ep_author_hover + ep_cursortrace + ep_font_size + ep_hash_auth + ep_headings2 + ep_markdown + ep_readonly_guest + ep_spellcheck + ep_subscript_and_superscript + ep_table_of_contents # configures some settings and runs npm run test - name: Run load test From e32a62346832140107de53428532597f0b9bc6c2 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sat, 23 Jan 2021 18:12:18 -0500 Subject: [PATCH 004/153] GitHub workflows: Synchronize plugin lists --- .github/workflows/backend-tests.yml | 1 + .github/workflows/load-test.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/backend-tests.yml b/.github/workflows/backend-tests.yml index 245dffb97..962b9e80b 100644 --- a/.github/workflows/backend-tests.yml +++ b/.github/workflows/backend-tests.yml @@ -63,6 +63,7 @@ jobs: ep_headings2 ep_markdown ep_readonly_guest + ep_set_title_on_pad ep_spellcheck ep_subscript_and_superscript ep_table_of_contents diff --git a/.github/workflows/load-test.yml b/.github/workflows/load-test.yml index c590da06c..89f766253 100644 --- a/.github/workflows/load-test.yml +++ b/.github/workflows/load-test.yml @@ -56,6 +56,7 @@ jobs: ep_headings2 ep_markdown ep_readonly_guest + ep_set_title_on_pad ep_spellcheck ep_subscript_and_superscript ep_table_of_contents From f7b11336003b43fb2fb88bef28dfd40adf578c8e Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sat, 23 Jan 2021 18:06:50 -0500 Subject: [PATCH 005/153] GitHub workflows: Install Etherpad deps after installing plugins --- .github/workflows/backend-tests.yml | 13 ++++++++++--- .github/workflows/frontend-tests.yml | 13 ++++++++++--- .github/workflows/load-test.yml | 13 ++++++++++--- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/.github/workflows/backend-tests.yml b/.github/workflows/backend-tests.yml index 962b9e80b..8c9c45f28 100644 --- a/.github/workflows/backend-tests.yml +++ b/.github/workflows/backend-tests.yml @@ -49,9 +49,6 @@ jobs: sudo apt update sudo apt install -y --no-install-recommends libreoffice libreoffice-pdfimport - - name: Install all dependencies and symlink for ep_etherpad-lite - run: bin/installDeps.sh - - name: Install Etherpad plugins run: > npm install @@ -68,6 +65,16 @@ jobs: ep_subscript_and_superscript ep_table_of_contents + # This must be run after installing the plugins, otherwise npm will try to + # hoist common dependencies by removing them from src/node_modules and + # installing them in the top-level node_modules. As of v6.14.10, npm's hoist + # logic appears to be buggy, because it sometimes removes dependencies from + # src/node_modules but fails to add them to the top-level node_modules. Even + # if npm correctly hoists the dependencies, the hoisting seems to confuse + # tools such as `npm outdated`, `npm update`, and some ESLint rules. + - name: Install all dependencies and symlink for ep_etherpad-lite + run: bin/installDeps.sh + # configures some settings and runs npm run test - name: Run the backend tests run: tests/frontend/travis/runnerBackend.sh diff --git a/.github/workflows/frontend-tests.yml b/.github/workflows/frontend-tests.yml index 52fa0af1b..0052cafe0 100644 --- a/.github/workflows/frontend-tests.yml +++ b/.github/workflows/frontend-tests.yml @@ -55,9 +55,6 @@ jobs: TRAVIS_JOB_NUMBER: ${{ github.run_id }}-${{ github.run_number }}-${{ github.job }} run: tests/frontend/travis/sauce_tunnel.sh - - name: Install all dependencies and symlink for ep_etherpad-lite - run: bin/installDeps.sh - - name: Install Etherpad plugins run: > npm install @@ -74,6 +71,16 @@ jobs: ep_subscript_and_superscript ep_table_of_contents + # This must be run after installing the plugins, otherwise npm will try to + # hoist common dependencies by removing them from src/node_modules and + # installing them in the top-level node_modules. As of v6.14.10, npm's hoist + # logic appears to be buggy, because it sometimes removes dependencies from + # src/node_modules but fails to add them to the top-level node_modules. Even + # if npm correctly hoists the dependencies, the hoisting seems to confuse + # tools such as `npm outdated`, `npm update`, and some ESLint rules. + - name: Install all dependencies and symlink for ep_etherpad-lite + run: bin/installDeps.sh + - name: export GIT_HASH to env id: environment run: echo "::set-output name=sha_short::$(git rev-parse --short ${{ github.sha }})" diff --git a/.github/workflows/load-test.yml b/.github/workflows/load-test.yml index 89f766253..ab0fb3bd0 100644 --- a/.github/workflows/load-test.yml +++ b/.github/workflows/load-test.yml @@ -39,9 +39,6 @@ jobs: - name: Checkout repository uses: actions/checkout@v2 - - name: Install all dependencies and symlink for ep_etherpad-lite - run: bin/installDeps.sh - - name: Install etherpad-load-test run: sudo npm install -g etherpad-load-test @@ -61,6 +58,16 @@ jobs: ep_subscript_and_superscript ep_table_of_contents + # This must be run after installing the plugins, otherwise npm will try to + # hoist common dependencies by removing them from src/node_modules and + # installing them in the top-level node_modules. As of v6.14.10, npm's hoist + # logic appears to be buggy, because it sometimes removes dependencies from + # src/node_modules but fails to add them to the top-level node_modules. Even + # if npm correctly hoists the dependencies, the hoisting seems to confuse + # tools such as `npm outdated`, `npm update`, and some ESLint rules. + - name: Install all dependencies and symlink for ep_etherpad-lite + run: bin/installDeps.sh + # configures some settings and runs npm run test - name: Run load test run: tests/frontend/travis/runnerLoadTest.sh From f0cafe88f2f86c4ead2f7cac2d0cc1a5cd0a286e Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 25 Jan 2021 18:04:09 +0100 Subject: [PATCH 006/153] Localisation updates from https://translatewiki.net. --- src/locales/ru.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/locales/ru.json b/src/locales/ru.json index 007fb4c51..792162e57 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -18,21 +18,39 @@ "Арсен Асхат" ] }, + "admin.page-title": "Панель администратора — Etherpad", "admin_plugins": "Менеджер плагинов", "admin_plugins.available": "Доступные плагины", "admin_plugins.available_not-found": "Плагины не найдены.", + "admin_plugins.available_fetching": "Получение…", "admin_plugins.available_install.value": "Установить", + "admin_plugins.available_search.placeholder": "Искать плагины для установки", "admin_plugins.description": "Описание", "admin_plugins.installed": "Установленные плагины", + "admin_plugins.installed_fetching": "Получение установленных плагинов…", "admin_plugins.installed_nothing": "Вы еще не установили ни одного плагина.", "admin_plugins.installed_uninstall.value": "Удалить", "admin_plugins.last-update": "Последнее обновление", + "admin_plugins.name": "Название", + "admin_plugins.page-title": "Менеджер плагинов — Etherpad", "admin_plugins.version": "Версия", + "admin_plugins_info": "Информация об устранении неполадок", "admin_plugins_info.hooks": "Установленные крючки", + "admin_plugins_info.hooks_client": "Клиентские хуки", + "admin_plugins_info.hooks_server": "Серверные хуки", + "admin_plugins_info.parts": "Установленные части", + "admin_plugins_info.plugins": "Установленные плагины", + "admin_plugins_info.page-title": "Информация о плагине — Etherpad", + "admin_plugins_info.version": "Версия Etherpad", + "admin_plugins_info.version_latest": "Последняя доступная версия", "admin_plugins_info.version_number": "Номер версии", "admin_settings": "Настройки", "admin_settings.current": "Текущая конфигурация", + "admin_settings.current_example-devel": "Пример шаблона настроек для среда разработки", + "admin_settings.current_example-prod": "Пример шаблона настроек для боевой среды", + "admin_settings.current_restart.value": "Перезагрузить Etherpad", "admin_settings.current_save.value": "Сохранить настройки", + "admin_settings.page-title": "Настройки — Etherpad", "index.newPad": "Создать", "index.createOpenPad": "или создать/открыть документ с именем:", "index.openPad": "откройте существующий документ с именем:", From d9225f326fce37ab33979b811e6b5bcc1ef32ef8 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 007/153] lint: src/node/db/API.js --- src/node/db/API.js | 170 ++++++++++++++++++++++++--------------------- 1 file changed, 92 insertions(+), 78 deletions(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index 2c58a69a3..ea77ac7df 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -1,3 +1,4 @@ +'use strict'; /** * This module provides all API functions */ @@ -18,8 +19,8 @@ * limitations under the License. */ -const Changeset = require('ep_etherpad-lite/static/js/Changeset'); -const customError = require('../utils/customError'); +const Changeset = require('../../static/js/Changeset'); +const CustomError = require('../utils/customError'); const padManager = require('./PadManager'); const padMessageHandler = require('../handler/PadMessageHandler'); const readOnlyManager = require('./ReadOnlyManager'); @@ -101,7 +102,7 @@ Example returns: } */ -exports.getAttributePool = async function (padID) { +exports.getAttributePool = async (padID) => { const pad = await getPadSafe(padID, true); return {pool: pad.pool}; }; @@ -119,7 +120,7 @@ Example returns: } */ -exports.getRevisionChangeset = async function (padID, rev) { +exports.getRevisionChangeset = async (padID, rev) => { // try to parse the revision number if (rev !== undefined) { rev = checkValidRev(rev); @@ -133,7 +134,7 @@ exports.getRevisionChangeset = async function (padID, rev) { if (rev !== undefined) { // check if this is a valid revision if (rev > head) { - throw new customError('rev is higher than the head revision of the pad', 'apierror'); + throw new CustomError('rev is higher than the head revision of the pad', 'apierror'); } // get the changeset for this revision @@ -152,7 +153,7 @@ Example returns: {code: 0, message:"ok", data: {text:"Welcome Text"}} {code: 1, message:"padID does not exist", data: null} */ -exports.getText = async function (padID, rev) { +exports.getText = async (padID, rev) => { // try to parse the revision number if (rev !== undefined) { rev = checkValidRev(rev); @@ -166,7 +167,7 @@ exports.getText = async function (padID, rev) { if (rev !== undefined) { // check if this is a valid revision if (rev > head) { - throw new customError('rev is higher than the head revision of the pad', 'apierror'); + throw new CustomError('rev is higher than the head revision of the pad', 'apierror'); } // get the text of this revision @@ -188,10 +189,10 @@ Example returns: {code: 1, message:"padID does not exist", data: null} {code: 1, message:"text too long", data: null} */ -exports.setText = async function (padID, text) { +exports.setText = async (padID, text) => { // text is required if (typeof text !== 'string') { - throw new customError('text is not a string', 'apierror'); + throw new CustomError('text is not a string', 'apierror'); } // get the pad @@ -212,10 +213,10 @@ Example returns: {code: 1, message:"padID does not exist", data: null} {code: 1, message:"text too long", data: null} */ -exports.appendText = async function (padID, text) { +exports.appendText = async (padID, text) => { // text is required if (typeof text !== 'string') { - throw new customError('text is not a string', 'apierror'); + throw new CustomError('text is not a string', 'apierror'); } const pad = await getPadSafe(padID, true); @@ -233,7 +234,7 @@ Example returns: {code: 0, message:"ok", data: {text:"Welcome Text"}} {code: 1, message:"padID does not exist", data: null} */ -exports.getHTML = async function (padID, rev) { +exports.getHTML = async (padID, rev) => { if (rev !== undefined) { rev = checkValidRev(rev); } @@ -245,7 +246,7 @@ exports.getHTML = async function (padID, rev) { // check if this is a valid revision const head = pad.getHeadRevisionNumber(); if (rev > head) { - throw new customError('rev is higher than the head revision of the pad', 'apierror'); + throw new CustomError('rev is higher than the head revision of the pad', 'apierror'); } } @@ -265,10 +266,10 @@ Example returns: {code: 0, message:"ok", data: null} {code: 1, message:"padID does not exist", data: null} */ -exports.setHTML = async function (padID, html) { +exports.setHTML = async (padID, html) => { // html string is required if (typeof html !== 'string') { - throw new customError('html is not a string', 'apierror'); + throw new CustomError('html is not a string', 'apierror'); } // get the pad @@ -278,7 +279,7 @@ exports.setHTML = async function (padID, html) { try { await importHtml.setPadHTML(pad, cleanText(html)); } catch (e) { - throw new customError('HTML is malformed', 'apierror'); + throw new CustomError('HTML is malformed', 'apierror'); } // update the clients on the pad @@ -294,23 +295,25 @@ getChatHistory(padId, start, end), returns a part of or the whole chat-history o Example returns: -{"code":0,"message":"ok","data":{"messages":[{"text":"foo","authorID":"a.foo","time":1359199533759,"userName":"test"}, - {"text":"bar","authorID":"a.foo","time":1359199534622,"userName":"test"}]}} +{"code":0,"message":"ok","data":{"messages":[ + {"text":"foo","authorID":"a.foo","time":1359199533759,"userName":"test"}, + {"text":"bar","authorID":"a.foo","time":1359199534622,"userName":"test"} +]}} {code: 1, message:"start is higher or equal to the current chatHead", data: null} {code: 1, message:"padID does not exist", data: null} */ -exports.getChatHistory = async function (padID, start, end) { +exports.getChatHistory = async (padID, start, end) => { if (start && end) { if (start < 0) { - throw new customError('start is below zero', 'apierror'); + throw new CustomError('start is below zero', 'apierror'); } if (end < 0) { - throw new customError('end is below zero', 'apierror'); + throw new CustomError('end is below zero', 'apierror'); } if (start > end) { - throw new customError('start is higher than end', 'apierror'); + throw new CustomError('start is higher than end', 'apierror'); } } @@ -320,16 +323,16 @@ exports.getChatHistory = async function (padID, start, end) { const chatHead = pad.chatHead; // fall back to getting the whole chat-history if a parameter is missing - if (!start || !end) { + if (!start || !end) { start = 0; end = pad.chatHead; } if (start > chatHead) { - throw new customError('start is higher than the current chatHead', 'apierror'); + throw new CustomError('start is higher than the current chatHead', 'apierror'); } if (end > chatHead) { - throw new customError('end is higher than the current chatHead', 'apierror'); + throw new CustomError('end is higher than the current chatHead', 'apierror'); } // the the whole message-log and return it to the client @@ -339,21 +342,22 @@ exports.getChatHistory = async function (padID, start, end) { }; /** -appendChatMessage(padID, text, authorID, time), creates a chat message for the pad id, time is a timestamp +appendChatMessage(padID, text, authorID, time), creates a chat message for the pad id, +time is a timestamp Example returns: {code: 0, message:"ok", data: null} {code: 1, message:"padID does not exist", data: null} */ -exports.appendChatMessage = async function (padID, text, authorID, time) { +exports.appendChatMessage = async (padID, text, authorID, time) => { // text is required if (typeof text !== 'string') { - throw new customError('text is not a string', 'apierror'); + throw new CustomError('text is not a string', 'apierror'); } // if time is not an integer value set time to current timestamp - if (time === undefined || !is_int(time)) { + if (time === undefined || !isInt(time)) { time = Date.now(); } @@ -375,7 +379,7 @@ Example returns: {code: 0, message:"ok", data: {revisions: 56}} {code: 1, message:"padID does not exist", data: null} */ -exports.getRevisionsCount = async function (padID) { +exports.getRevisionsCount = async (padID) => { // get the pad const pad = await getPadSafe(padID, true); return {revisions: pad.getHeadRevisionNumber()}; @@ -389,7 +393,7 @@ Example returns: {code: 0, message:"ok", data: {savedRevisions: 42}} {code: 1, message:"padID does not exist", data: null} */ -exports.getSavedRevisionsCount = async function (padID) { +exports.getSavedRevisionsCount = async (padID) => { // get the pad const pad = await getPadSafe(padID, true); return {savedRevisions: pad.getSavedRevisionsNumber()}; @@ -403,7 +407,7 @@ Example returns: {code: 0, message:"ok", data: {savedRevisions: [2, 42, 1337]}} {code: 1, message:"padID does not exist", data: null} */ -exports.listSavedRevisions = async function (padID) { +exports.listSavedRevisions = async (padID) => { // get the pad const pad = await getPadSafe(padID, true); return {savedRevisions: pad.getSavedRevisionsList()}; @@ -417,7 +421,7 @@ Example returns: {code: 0, message:"ok", data: null} {code: 1, message:"padID does not exist", data: null} */ -exports.saveRevision = async function (padID, rev) { +exports.saveRevision = async (padID, rev) => { // check if rev is a number if (rev !== undefined) { rev = checkValidRev(rev); @@ -430,7 +434,7 @@ exports.saveRevision = async function (padID, rev) { // the client asked for a special revision if (rev !== undefined) { if (rev > head) { - throw new customError('rev is higher than the head revision of the pad', 'apierror'); + throw new CustomError('rev is higher than the head revision of the pad', 'apierror'); } } else { rev = pad.getHeadRevisionNumber(); @@ -448,7 +452,7 @@ Example returns: {code: 0, message:"ok", data: {lastEdited: 1340815946602}} {code: 1, message:"padID does not exist", data: null} */ -exports.getLastEdited = async function (padID) { +exports.getLastEdited = async (padID) => { // get the pad const pad = await getPadSafe(padID, true); const lastEdited = await pad.getLastEdit(); @@ -463,16 +467,16 @@ Example returns: {code: 0, message:"ok", data: null} {code: 1, message:"pad does already exist", data: null} */ -exports.createPad = async function (padID, text) { +exports.createPad = async (padID, text) => { if (padID) { // ensure there is no $ in the padID if (padID.indexOf('$') !== -1) { - throw new customError("createPad can't create group pads", 'apierror'); + throw new CustomError("createPad can't create group pads", 'apierror'); } // check for url special characters if (padID.match(/(\/|\?|&|#)/)) { - throw new customError('malformed padID: Remove special characters', 'apierror'); + throw new CustomError('malformed padID: Remove special characters', 'apierror'); } } @@ -488,7 +492,7 @@ Example returns: {code: 0, message:"ok", data: null} {code: 1, message:"padID does not exist", data: null} */ -exports.deletePad = async function (padID) { +exports.deletePad = async (padID) => { const pad = await getPadSafe(padID, true); await pad.remove(); }; @@ -501,10 +505,10 @@ exports.deletePad = async function (padID) { {code:0, message:"ok", data:null} {code: 1, message:"padID does not exist", data: null} */ -exports.restoreRevision = async function (padID, rev) { +exports.restoreRevision = async (padID, rev) => { // check if rev is a number if (rev === undefined) { - throw new customError('rev is not defined', 'apierror'); + throw new CustomError('rev is not defined', 'apierror'); } rev = checkValidRev(rev); @@ -513,7 +517,7 @@ exports.restoreRevision = async function (padID, rev) { // check if this is a valid revision if (rev > pad.getHeadRevisionNumber()) { - throw new customError('rev is higher than the head revision of the pad', 'apierror'); + throw new CustomError('rev is higher than the head revision of the pad', 'apierror'); } const atext = await pad.getInternalRevisionAText(rev); @@ -521,7 +525,7 @@ exports.restoreRevision = async function (padID, rev) { const oldText = pad.text(); atext.text += '\n'; - function eachAttribRun(attribs, func) { + const eachAttribRun = (attribs, func) => { const attribsIter = Changeset.opIterator(attribs); let textIndex = 0; const newTextStart = 0; @@ -534,7 +538,7 @@ exports.restoreRevision = async function (padID, rev) { } textIndex = nextIndex; } - } + }; // create a new changeset with a helper builder object const builder = Changeset.builder(oldText.length); @@ -569,7 +573,7 @@ Example returns: {code: 0, message:"ok", data: {padID: destinationID}} {code: 1, message:"padID does not exist", data: null} */ -exports.copyPad = async function (sourceID, destinationID, force) { +exports.copyPad = async (sourceID, destinationID, force) => { const pad = await getPadSafe(sourceID, true); await pad.copy(destinationID, force); }; @@ -583,7 +587,7 @@ Example returns: {code: 0, message:"ok", data: {padID: destinationID}} {code: 1, message:"padID does not exist", data: null} */ -exports.copyPadWithoutHistory = async function (sourceID, destinationID, force) { +exports.copyPadWithoutHistory = async (sourceID, destinationID, force) => { const pad = await getPadSafe(sourceID, true); await pad.copyPadWithoutHistory(destinationID, force); }; @@ -597,7 +601,7 @@ Example returns: {code: 0, message:"ok", data: {padID: destinationID}} {code: 1, message:"padID does not exist", data: null} */ -exports.movePad = async function (sourceID, destinationID, force) { +exports.movePad = async (sourceID, destinationID, force) => { const pad = await getPadSafe(sourceID, true); await pad.copy(destinationID, force); await pad.remove(); @@ -611,7 +615,7 @@ Example returns: {code: 0, message:"ok", data: null} {code: 1, message:"padID does not exist", data: null} */ -exports.getReadOnlyID = async function (padID) { +exports.getReadOnlyID = async (padID) => { // we don't need the pad object, but this function does all the security stuff for us await getPadSafe(padID, true); @@ -629,11 +633,11 @@ Example returns: {code: 0, message:"ok", data: {padID: padID}} {code: 1, message:"padID does not exist", data: null} */ -exports.getPadID = async function (roID) { +exports.getPadID = async (roID) => { // get the PadId const padID = await readOnlyManager.getPadId(roID); - if (padID === null) { - throw new customError('padID does not exist', 'apierror'); + if (padID == null) { + throw new CustomError('padID does not exist', 'apierror'); } return {padID}; @@ -647,7 +651,7 @@ Example returns: {code: 0, message:"ok", data: null} {code: 1, message:"padID does not exist", data: null} */ -exports.setPublicStatus = async function (padID, publicStatus) { +exports.setPublicStatus = async (padID, publicStatus) => { // ensure this is a group pad checkGroupPad(padID, 'publicStatus'); @@ -670,7 +674,7 @@ Example returns: {code: 0, message:"ok", data: {publicStatus: true}} {code: 1, message:"padID does not exist", data: null} */ -exports.getPublicStatus = async function (padID) { +exports.getPublicStatus = async (padID) => { // ensure this is a group pad checkGroupPad(padID, 'publicStatus'); @@ -687,7 +691,7 @@ Example returns: {code: 0, message:"ok", data: {authorIDs : ["a.s8oes9dhwrvt0zif", "a.akf8finncvomlqva"]} {code: 1, message:"padID does not exist", data: null} */ -exports.listAuthorsOfPad = async function (padID) { +exports.listAuthorsOfPad = async (padID) => { // get the pad const pad = await getPadSafe(padID, true); const authorIDs = pad.getAllAuthors(); @@ -717,7 +721,7 @@ Example returns: {code: 1, message:"padID does not exist"} */ -exports.sendClientsMessage = async function (padID, msg) { +exports.sendClientsMessage = async (padID, msg) => { const pad = await getPadSafe(padID, true); padMessageHandler.handleCustomMessage(padID, msg); }; @@ -730,7 +734,7 @@ Example returns: {"code":0,"message":"ok","data":null} {"code":4,"message":"no or wrong API Key","data":null} */ -exports.checkToken = async function () { +exports.checkToken = async () => { }; /** @@ -741,7 +745,7 @@ Example returns: {code: 0, message:"ok", data: {chatHead: 42}} {code: 1, message:"padID does not exist", data: null} */ -exports.getChatHead = async function (padID) { +exports.getChatHead = async (padID) => { // get the pad const pad = await getPadSafe(padID, true); return {chatHead: pad.chatHead}; @@ -751,11 +755,21 @@ exports.getChatHead = async function (padID) { createDiffHTML(padID, startRev, endRev) returns an object of diffs from 2 points in a pad Example returns: - -{"code":0,"message":"ok","data":{"html":"Welcome to Etherpad!

This pad text is synchronized as you type, so that everyone viewing this page sees the same text. This allows you to collaborate seamlessly on documents!

Get involved with Etherpad at http://etherpad.org
aw

","authors":["a.HKIv23mEbachFYfH",""]}} +{ + "code": 0, + "message": "ok", + "data": { + "html": "...", + "authors": [ + "a.HKIv23mEbachFYfH", + "" + ] + } +} {"code":4,"message":"no or wrong API Key","data":null} + */ -exports.createDiffHTML = async function (padID, startRev, endRev) { +exports.createDiffHTML = async (padID, startRev, endRev) => { // check if startRev is a number if (startRev !== undefined) { startRev = checkValidRev(startRev); @@ -768,8 +782,9 @@ exports.createDiffHTML = async function (padID, startRev, endRev) { // get the pad const pad = await getPadSafe(padID, true); + let padDiff; try { - var padDiff = new PadDiff(pad, startRev, endRev); + padDiff = new PadDiff(pad, startRev, endRev); } catch (e) { throw {stop: e.message}; } @@ -793,7 +808,7 @@ exports.createDiffHTML = async function (padID, startRev, endRev) { {"code":4,"message":"no or wrong API Key","data":null} */ -exports.getStats = async function () { +exports.getStats = async () => { const sessionInfos = padMessageHandler.sessioninfos; const sessionKeys = Object.keys(sessionInfos); @@ -813,20 +828,18 @@ exports.getStats = async function () { **************************** */ // checks if a number is an int -function is_int(value) { - return (parseFloat(value) == parseInt(value, 10)) && !isNaN(value); -} +const isInt = (value) => (parseFloat(value) === parseInt(value, 10)) && !isNaN(value); // gets a pad safe async function getPadSafe(padID, shouldExist, text) { // check if padID is a string if (typeof padID !== 'string') { - throw new customError('padID is not a string', 'apierror'); + throw new CustomError('padID is not a string', 'apierror'); } // check if the padID maches the requirements if (!padManager.isValidPadId(padID)) { - throw new customError('padID did not match requirements', 'apierror'); + throw new CustomError('padID did not match requirements', 'apierror'); } // check if the pad exists @@ -834,12 +847,12 @@ async function getPadSafe(padID, shouldExist, text) { if (!exists && shouldExist) { // does not exist, but should - throw new customError('padID does not exist', 'apierror'); + throw new CustomError('padID does not exist', 'apierror'); } if (exists && !shouldExist) { // does exist, but shouldn't - throw new customError('padID does already exist', 'apierror'); + throw new CustomError('padID does already exist', 'apierror'); } // pad exists, let's get it @@ -848,33 +861,34 @@ async function getPadSafe(padID, shouldExist, text) { // checks if a rev is a legal number // pre-condition is that `rev` is not undefined -function checkValidRev(rev) { +const checkValidRev = (rev) => { if (typeof rev !== 'number') { rev = parseInt(rev, 10); } // check if rev is a number if (isNaN(rev)) { - throw new customError('rev is not a number', 'apierror'); + throw new CustomError('rev is not a number', 'apierror'); } // ensure this is not a negative number if (rev < 0) { - throw new customError('rev is not a negative number', 'apierror'); + throw new CustomError('rev is not a negative number', 'apierror'); } // ensure this is not a float value - if (!is_int(rev)) { - throw new customError('rev is a float value', 'apierror'); + if (!isInt(rev)) { + throw new CustomError('rev is a float value', 'apierror'); } return rev; -} +}; // checks if a padID is part of a group -function checkGroupPad(padID, field) { +const checkGroupPad = (padID, field) => { // ensure this is a group pad if (padID && padID.indexOf('$') === -1) { - throw new customError(`You can only get/set the ${field} of pads that belong to a group`, 'apierror'); + throw new CustomError( + `You can only get/set the ${field} of pads that belong to a group`, 'apierror'); } -} +}; From 8aa729a36ffdae54bf9e7ff01895e2906760b630 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 008/153] lint: src/node/db/AuthorManager.js --- src/node/db/AuthorManager.js | 189 +++++++++++++++++------------------ 1 file changed, 89 insertions(+), 100 deletions(-) diff --git a/src/node/db/AuthorManager.js b/src/node/db/AuthorManager.js index f4ef903cf..3fde1e4b1 100644 --- a/src/node/db/AuthorManager.js +++ b/src/node/db/AuthorManager.js @@ -1,3 +1,4 @@ +'use strict'; /** * The AuthorManager controlls all information about the Pad authors */ @@ -19,85 +20,83 @@ */ const db = require('./DB'); -const customError = require('../utils/customError'); -const randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString; +const CustomError = require('../utils/customError'); +const randomString = require('../../static/js/pad_utils').randomString; -exports.getColorPalette = function () { - return [ - '#ffc7c7', - '#fff1c7', - '#e3ffc7', - '#c7ffd5', - '#c7ffff', - '#c7d5ff', - '#e3c7ff', - '#ffc7f1', - '#ffa8a8', - '#ffe699', - '#cfff9e', - '#99ffb3', - '#a3ffff', - '#99b3ff', - '#cc99ff', - '#ff99e5', - '#e7b1b1', - '#e9dcAf', - '#cde9af', - '#bfedcc', - '#b1e7e7', - '#c3cdee', - '#d2b8ea', - '#eec3e6', - '#e9cece', - '#e7e0ca', - '#d3e5c7', - '#bce1c5', - '#c1e2e2', - '#c1c9e2', - '#cfc1e2', - '#e0bdd9', - '#baded3', - '#a0f8eb', - '#b1e7e0', - '#c3c8e4', - '#cec5e2', - '#b1d5e7', - '#cda8f0', - '#f0f0a8', - '#f2f2a6', - '#f5a8eb', - '#c5f9a9', - '#ececbb', - '#e7c4bc', - '#daf0b2', - '#b0a0fd', - '#bce2e7', - '#cce2bb', - '#ec9afe', - '#edabbd', - '#aeaeea', - '#c4e7b1', - '#d722bb', - '#f3a5e7', - '#ffa8a8', - '#d8c0c5', - '#eaaedd', - '#adc6eb', - '#bedad1', - '#dee9af', - '#e9afc2', - '#f8d2a0', - '#b3b3e6', - ]; -}; +exports.getColorPalette = () => [ + '#ffc7c7', + '#fff1c7', + '#e3ffc7', + '#c7ffd5', + '#c7ffff', + '#c7d5ff', + '#e3c7ff', + '#ffc7f1', + '#ffa8a8', + '#ffe699', + '#cfff9e', + '#99ffb3', + '#a3ffff', + '#99b3ff', + '#cc99ff', + '#ff99e5', + '#e7b1b1', + '#e9dcAf', + '#cde9af', + '#bfedcc', + '#b1e7e7', + '#c3cdee', + '#d2b8ea', + '#eec3e6', + '#e9cece', + '#e7e0ca', + '#d3e5c7', + '#bce1c5', + '#c1e2e2', + '#c1c9e2', + '#cfc1e2', + '#e0bdd9', + '#baded3', + '#a0f8eb', + '#b1e7e0', + '#c3c8e4', + '#cec5e2', + '#b1d5e7', + '#cda8f0', + '#f0f0a8', + '#f2f2a6', + '#f5a8eb', + '#c5f9a9', + '#ececbb', + '#e7c4bc', + '#daf0b2', + '#b0a0fd', + '#bce2e7', + '#cce2bb', + '#ec9afe', + '#edabbd', + '#aeaeea', + '#c4e7b1', + '#d722bb', + '#f3a5e7', + '#ffa8a8', + '#d8c0c5', + '#eaaedd', + '#adc6eb', + '#bedad1', + '#dee9af', + '#e9afc2', + '#f8d2a0', + '#b3b3e6', +]; /** * Checks if the author exists */ -exports.doesAuthorExist = async function (authorID) { +exports.doesAuthorExist = async (authorID) => { const author = await db.get(`globalAuthor:${authorID}`); - return author !== null; + return author != null; }; /* exported for backwards compatibility */ @@ -107,7 +106,7 @@ exports.doesAuthorExists = exports.doesAuthorExist; * Returns the AuthorID for a token. * @param {String} token The token */ -exports.getAuthor4Token = async function (token) { +exports.getAuthor4Token = async (token) => { const author = await mapAuthorWithDBKey('token2author', token); // return only the sub value authorID @@ -119,7 +118,7 @@ exports.getAuthor4Token = async function (token) { * @param {String} token The mapper * @param {String} name The name of the author (optional) */ -exports.createAuthorIfNotExistsFor = async function (authorMapper, name) { +exports.createAuthorIfNotExistsFor = async (authorMapper, name) => { const author = await mapAuthorWithDBKey('mapper2author', authorMapper); if (name) { @@ -140,7 +139,7 @@ async function mapAuthorWithDBKey(mapperkey, mapper) { // try to map to an author const author = await db.get(`${mapperkey}:${mapper}`); - if (author === null) { + if (author == null) { // there is no author with this mapper, so create one const author = await exports.createAuthor(null); @@ -163,7 +162,7 @@ async function mapAuthorWithDBKey(mapperkey, mapper) { * Internal function that creates the database entry for an author * @param {String} name The name of the author */ -exports.createAuthor = function (name) { +exports.createAuthor = (name) => { // create the new author name const author = `a.${randomString(16)}`; @@ -185,50 +184,40 @@ exports.createAuthor = function (name) { * Returns the Author Obj of the author * @param {String} author The id of the author */ -exports.getAuthor = function (author) { - // NB: result is already a Promise - return db.get(`globalAuthor:${author}`); -}; +exports.getAuthor = (author) => db.get(`globalAuthor:${author}`); /** * Returns the color Id of the author * @param {String} author The id of the author */ -exports.getAuthorColorId = function (author) { - return db.getSub(`globalAuthor:${author}`, ['colorId']); -}; +exports.getAuthorColorId = (author) => db.getSub(`globalAuthor:${author}`, ['colorId']); /** * Sets the color Id of the author * @param {String} author The id of the author * @param {String} colorId The color id of the author */ -exports.setAuthorColorId = function (author, colorId) { - return db.setSub(`globalAuthor:${author}`, ['colorId'], colorId); -}; +exports.setAuthorColorId = (author, colorId) => db.setSub( + `globalAuthor:${author}`, ['colorId'], colorId); /** * Returns the name of the author * @param {String} author The id of the author */ -exports.getAuthorName = function (author) { - return db.getSub(`globalAuthor:${author}`, ['name']); -}; +exports.getAuthorName = (author) => db.getSub(`globalAuthor:${author}`, ['name']); /** * Sets the name of the author * @param {String} author The id of the author * @param {String} name The name of the author */ -exports.setAuthorName = function (author, name) { - return db.setSub(`globalAuthor:${author}`, ['name'], name); -}; +exports.setAuthorName = (author, name) => db.setSub(`globalAuthor:${author}`, ['name'], name); /** * Returns an array of all pads this author contributed to * @param {String} author The id of the author */ -exports.listPadsOfAuthor = async function (authorID) { +exports.listPadsOfAuthor = async (authorID) => { /* There are two other places where this array is manipulated: * (1) When the author is added to a pad, the author object is also updated * (2) When a pad is deleted, each author of that pad is also updated @@ -237,9 +226,9 @@ exports.listPadsOfAuthor = async function (authorID) { // get the globalAuthor const author = await db.get(`globalAuthor:${authorID}`); - if (author === null) { + if (author == null) { // author does not exist - throw new customError('authorID does not exist', 'apierror'); + throw new CustomError('authorID does not exist', 'apierror'); } // everything is fine, return the pad IDs @@ -253,11 +242,11 @@ exports.listPadsOfAuthor = async function (authorID) { * @param {String} author The id of the author * @param {String} padID The id of the pad the author contributes to */ -exports.addPad = async function (authorID, padID) { +exports.addPad = async (authorID, padID) => { // get the entry const author = await db.get(`globalAuthor:${authorID}`); - if (author === null) return; + if (author == null) return; /* * ACHTUNG: padIDs can also be undefined, not just null, so it is not possible @@ -280,12 +269,12 @@ exports.addPad = async function (authorID, padID) { * @param {String} author The id of the author * @param {String} padID The id of the pad the author contributes to */ -exports.removePad = async function (authorID, padID) { +exports.removePad = async (authorID, padID) => { const author = await db.get(`globalAuthor:${authorID}`); - if (author === null) return; + if (author == null) return; - if (author.padIDs !== null) { + if (author.padIDs != null) { // remove pad from author delete author.padIDs[padID]; await db.set(`globalAuthor:${authorID}`, author); From 5ecb3f9f3742800afdc45be3b3c90818a488ac80 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 009/153] lint: src/node/db/GroupManager.js --- src/node/db/GroupManager.js | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/node/db/GroupManager.js b/src/node/db/GroupManager.js index 1330acc43..203e21a35 100644 --- a/src/node/db/GroupManager.js +++ b/src/node/db/GroupManager.js @@ -1,3 +1,4 @@ +'use strict'; /** * The Group Manager provides functions to manage groups in the database */ @@ -18,13 +19,13 @@ * limitations under the License. */ -const customError = require('../utils/customError'); -const randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString; +const CustomError = require('../utils/customError'); +const randomString = require('../../static/js/pad_utils').randomString; const db = require('./DB'); const padManager = require('./PadManager'); const sessionManager = require('./SessionManager'); -exports.listAllGroups = async function () { +exports.listAllGroups = async () => { let groups = await db.get('groups'); groups = groups || {}; @@ -32,17 +33,20 @@ exports.listAllGroups = async function () { return {groupIDs}; }; -exports.deleteGroup = async function (groupID) { +exports.deleteGroup = async (groupID) => { const group = await db.get(`group:${groupID}`); // ensure group exists if (group == null) { // group does not exist - throw new customError('groupID does not exist', 'apierror'); + throw new CustomError('groupID does not exist', 'apierror'); } // iterate through all pads of this group and delete them (in parallel) - await Promise.all(Object.keys(group.pads).map((padID) => padManager.getPad(padID).then((pad) => pad.remove()))); + await Promise.all(Object.keys(group.pads) + .map((padID) => padManager.getPad(padID) + .then((pad) => pad.remove()) + )); // iterate through group2sessions and delete all sessions const group2sessions = await db.get(`group2sessions:${groupID}`); @@ -76,14 +80,14 @@ exports.deleteGroup = async function (groupID) { await db.set('groups', newGroups); }; -exports.doesGroupExist = async function (groupID) { +exports.doesGroupExist = async (groupID) => { // try to get the group entry const group = await db.get(`group:${groupID}`); return (group != null); }; -exports.createGroup = async function () { +exports.createGroup = async () => { // search for non existing groupID const groupID = `g.${randomString(16)}`; @@ -103,10 +107,10 @@ exports.createGroup = async function () { return {groupID}; }; -exports.createGroupIfNotExistsFor = async function (groupMapper) { +exports.createGroupIfNotExistsFor = async (groupMapper) => { // ensure mapper is optional if (typeof groupMapper !== 'string') { - throw new customError('groupMapper is not a string', 'apierror'); + throw new CustomError('groupMapper is not a string', 'apierror'); } // try to get a group for this mapper @@ -128,7 +132,7 @@ exports.createGroupIfNotExistsFor = async function (groupMapper) { return result; }; -exports.createGroupPad = async function (groupID, padName, text) { +exports.createGroupPad = async (groupID, padName, text) => { // create the padID const padID = `${groupID}$${padName}`; @@ -136,7 +140,7 @@ exports.createGroupPad = async function (groupID, padName, text) { const groupExists = await exports.doesGroupExist(groupID); if (!groupExists) { - throw new customError('groupID does not exist', 'apierror'); + throw new CustomError('groupID does not exist', 'apierror'); } // ensure pad doesn't exist already @@ -144,7 +148,7 @@ exports.createGroupPad = async function (groupID, padName, text) { if (padExists) { // pad exists already - throw new customError('padName does already exist', 'apierror'); + throw new CustomError('padName does already exist', 'apierror'); } // create the pad @@ -156,12 +160,12 @@ exports.createGroupPad = async function (groupID, padName, text) { return {padID}; }; -exports.listPads = async function (groupID) { +exports.listPads = async (groupID) => { const exists = await exports.doesGroupExist(groupID); // ensure the group exists if (!exists) { - throw new customError('groupID does not exist', 'apierror'); + throw new CustomError('groupID does not exist', 'apierror'); } // group exists, let's get the pads From f0c26c9ba2fccc987d267ae81096d2d50abbb0e3 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 010/153] lint: src/node/db/Pad.js --- src/node/db/Pad.js | 68 +++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/src/node/db/Pad.js b/src/node/db/Pad.js index c39b3c69e..67842c14d 100644 --- a/src/node/db/Pad.js +++ b/src/node/db/Pad.js @@ -1,21 +1,21 @@ +'use strict'; /** * The pad object, defined with joose */ -const Changeset = require('ep_etherpad-lite/static/js/Changeset'); -const AttributePool = require('ep_etherpad-lite/static/js/AttributePool'); +const Changeset = require('../../static/js/Changeset'); +const AttributePool = require('../../static/js/AttributePool'); const db = require('./DB'); const settings = require('../utils/Settings'); const authorManager = require('./AuthorManager'); const padManager = require('./PadManager'); const padMessageHandler = require('../handler/PadMessageHandler'); const groupManager = require('./GroupManager'); -const customError = require('../utils/customError'); +const CustomError = require('../utils/customError'); const readOnlyManager = require('./ReadOnlyManager'); -const crypto = require('crypto'); const randomString = require('../utils/randomstring'); -const hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks'); +const hooks = require('../../static/js/pluginfw/hooks'); const promises = require('../utils/promises'); // serialization/deserialization attributes @@ -23,13 +23,14 @@ const attributeBlackList = ['id']; const jsonableList = ['pool']; /** - * Copied from the Etherpad source code. It converts Windows line breaks to Unix line breaks and convert Tabs to spaces + * Copied from the Etherpad source code. It converts Windows line breaks to Unix + * line breaks and convert Tabs to spaces * @param txt */ -exports.cleanText = function (txt) { - return txt.replace(/\r\n/g, '\n').replace(/\r/g, '\n').replace(/\t/g, ' ').replace(/\xa0/g, ' '); -}; - +exports.cleanText = (txt) => txt.replace(/\r\n/g, '\n') + .replace(/\r/g, '\n') + .replace(/\t/g, ' ') + .replace(/\xa0/g, ' '); const Pad = function Pad(id) { this.atext = Changeset.makeAText('\n'); @@ -56,7 +57,7 @@ Pad.prototype.getSavedRevisionsNumber = function getSavedRevisionsNumber() { }; Pad.prototype.getSavedRevisionsList = function getSavedRevisionsList() { - const savedRev = new Array(); + const savedRev = []; for (const rev in this.savedRevisions) { savedRev.push(this.savedRevisions[rev].revNum); } @@ -85,11 +86,11 @@ Pad.prototype.appendRevision = async function appendRevision(aChangeset, author) newRevData.meta.timestamp = Date.now(); // ex. getNumForAuthor - if (author != '') { + if (author !== '') { this.pool.putAttrib(['author', author || '']); } - if (newRev % 100 == 0) { + if (newRev % 100 === 0) { newRevData.meta.pool = this.pool; newRevData.meta.atext = this.atext; } @@ -104,7 +105,7 @@ Pad.prototype.appendRevision = async function appendRevision(aChangeset, author) p.push(authorManager.addPad(author, this.id)); } - if (this.head == 0) { + if (this.head === 0) { hooks.callAll('padCreate', {pad: this, author}); } else { hooks.callAll('padUpdate', {pad: this, author, revs: newRev, changeset: aChangeset}); @@ -153,7 +154,7 @@ Pad.prototype.getAllAuthors = function getAllAuthors() { const authors = []; for (const key in this.pool.numToAttrib) { - if (this.pool.numToAttrib[key][0] == 'author' && this.pool.numToAttrib[key][1] != '') { + if (this.pool.numToAttrib[key][0] === 'author' && this.pool.numToAttrib[key][1] !== '') { authors.push(this.pool.numToAttrib[key][1]); } } @@ -177,9 +178,10 @@ Pad.prototype.getInternalRevisionAText = async function getInternalRevisionAText // get all needed changesets const changesets = []; - await Promise.all(neededChangesets.map((item) => this.getRevisionChangeset(item).then((changeset) => { - changesets[item] = changeset; - }))); + await Promise.all( + neededChangesets.map((item) => this.getRevisionChangeset(item).then((changeset) => { + changesets[item] = changeset; + }))); // we should have the atext by now let atext = await p_atext; @@ -204,10 +206,11 @@ Pad.prototype.getAllAuthorColors = async function getAllAuthorColors() { const returnTable = {}; const colorPalette = authorManager.getColorPalette(); - await Promise.all(authors.map((author) => authorManager.getAuthorColorId(author).then((colorId) => { - // colorId might be a hex color or an number out of the palette - returnTable[author] = colorPalette[colorId] || colorId; - }))); + await Promise.all( + authors.map((author) => authorManager.getAuthorColorId(author).then((colorId) => { + // colorId might be a hex color or an number out of the palette + returnTable[author] = colorPalette[colorId] || colorId; + }))); return returnTable; }; @@ -227,7 +230,7 @@ Pad.prototype.getValidRevisionRange = function getValidRevisionRange(startRev, e endRev = head; } - if (startRev !== null && endRev !== null) { + if (startRev != null && endRev != null) { return {startRev, endRev}; } return null; @@ -251,7 +254,7 @@ Pad.prototype.setText = async function setText(newText) { // We want to ensure the pad still ends with a \n, but otherwise keep // getText() and setText() consistent. let changeset; - if (newText[newText.length - 1] == '\n') { + if (newText[newText.length - 1] === '\n') { changeset = Changeset.makeSplice(oldText, 0, oldText.length, newText); } else { changeset = Changeset.makeSplice(oldText, 0, oldText.length - 1, newText); @@ -304,9 +307,10 @@ Pad.prototype.getChatMessages = async function getChatMessages(start, end) { // get all entries out of the database const entries = []; - await Promise.all(neededEntries.map((entryObject) => this.getChatMessage(entryObject.entryNum).then((entry) => { - entries[entryObject.order] = entry; - }))); + await Promise.all( + neededEntries.map((entryObject) => this.getChatMessage(entryObject.entryNum).then((entry) => { + entries[entryObject.order] = entry; + }))); // sort out broken chat entries // it looks like in happened in the past that the chat head was @@ -384,14 +388,16 @@ Pad.prototype.copy = async function copy(destinationID, force) { // copy all chat messages const chatHead = this.chatHead; for (let i = 0; i <= chatHead; ++i) { - const p = db.get(`pad:${sourceID}:chat:${i}`).then((chat) => db.set(`pad:${destinationID}:chat:${i}`, chat)); + const p = db.get(`pad:${sourceID}:chat:${i}`) + .then((chat) => db.set(`pad:${destinationID}:chat:${i}`, chat)); promises.push(p); } // copy all revisions const revHead = this.head; for (let i = 0; i <= revHead; ++i) { - const p = db.get(`pad:${sourceID}:revs:${i}`).then((rev) => db.set(`pad:${destinationID}:revs:${i}`, rev)); + const p = db.get(`pad:${sourceID}:revs:${i}`) + .then((rev) => db.set(`pad:${destinationID}:revs:${i}`, rev)); promises.push(p); } @@ -426,7 +432,7 @@ Pad.prototype.checkIfGroupExistAndReturnIt = async function checkIfGroupExistAnd // group does not exist if (!groupExists) { - throw new customError('groupID does not exist for destinationID', 'apierror'); + throw new CustomError('groupID does not exist for destinationID', 'apierror'); } } return destGroupID; @@ -446,7 +452,7 @@ Pad.prototype.removePadIfForceIsTrueAndAlreadyExist = async function removePadIf if (exists) { if (!force) { console.error('erroring out without force'); - throw new customError('destinationID already exists', 'apierror'); + throw new CustomError('destinationID already exists', 'apierror'); } // exists and forcing From e06b9442e01ea2413dfe7e901206ceb3638337ea Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 011/153] lint: src/node/db/PadManager.js --- src/node/db/PadManager.js | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/node/db/PadManager.js b/src/node/db/PadManager.js index 9334b92a4..11e8cb1a5 100644 --- a/src/node/db/PadManager.js +++ b/src/node/db/PadManager.js @@ -1,3 +1,4 @@ +'use strict'; /** * The Pad Manager is a Factory for pad Objects */ @@ -18,7 +19,7 @@ * limitations under the License. */ -const customError = require('../utils/customError'); +const CustomError = require('../utils/customError'); const Pad = require('../db/Pad').Pad; const db = require('./DB'); @@ -109,22 +110,22 @@ const padList = { * @param id A String with the id of the pad * @param {Function} callback */ -exports.getPad = async function (id, text) { +exports.getPad = async (id, text) => { // check if this is a valid padId if (!exports.isValidPadId(id)) { - throw new customError(`${id} is not a valid padId`, 'apierror'); + throw new CustomError(`${id} is not a valid padId`, 'apierror'); } // check if this is a valid text if (text != null) { // check if text is a string if (typeof text !== 'string') { - throw new customError('text is not a string', 'apierror'); + throw new CustomError('text is not a string', 'apierror'); } // check if text is less than 100k chars if (text.length > 100000) { - throw new customError('text must be less than 100k chars', 'apierror'); + throw new CustomError('text must be less than 100k chars', 'apierror'); } } @@ -146,14 +147,14 @@ exports.getPad = async function (id, text) { return pad; }; -exports.listAllPads = async function () { +exports.listAllPads = async () => { const padIDs = await padList.getPads(); return {padIDs}; }; // checks if a pad exists -exports.doesPadExist = async function (padId) { +exports.doesPadExist = async (padId) => { const value = await db.get(`pad:${padId}`); return (value != null && value.atext); @@ -189,9 +190,7 @@ exports.sanitizePadId = async function sanitizePadId(padId) { return padId; }; -exports.isValidPadId = function (padId) { - return /^(g.[a-zA-Z0-9]{16}\$)?[^$]{1,50}$/.test(padId); -}; +exports.isValidPadId = (padId) => /^(g.[a-zA-Z0-9]{16}\$)?[^$]{1,50}$/.test(padId); /** * Removes the pad from database and unloads it. @@ -204,6 +203,6 @@ exports.removePad = async (padId) => { }; // removes a pad from the cache -exports.unloadPad = function (padId) { +exports.unloadPad = (padId) => { globalPads.remove(padId); }; From 5ce255c789c80ff373afc076fc868482258beed2 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 012/153] lint: src/node/db/ReadOnlyManager.js --- src/node/db/ReadOnlyManager.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/node/db/ReadOnlyManager.js b/src/node/db/ReadOnlyManager.js index 54f8c592e..5dabe2e06 100644 --- a/src/node/db/ReadOnlyManager.js +++ b/src/node/db/ReadOnlyManager.js @@ -1,3 +1,4 @@ +'use strict'; /** * The ReadOnlyManager manages the database and rendering releated to read only pads */ @@ -27,15 +28,13 @@ const randomString = require('../utils/randomstring'); * checks if the id pattern matches a read-only pad id * @param {String} the pad's id */ -exports.isReadOnlyId = function (id) { - return id.indexOf('r.') === 0; -}; +exports.isReadOnlyId = (id) => id.indexOf('r.') === 0; /** * returns a read only id for a pad * @param {String} padId the id of the pad */ -exports.getReadOnlyId = async function (padId) { +exports.getReadOnlyId = async (padId) => { // check if there is a pad2readonly entry let readOnlyId = await db.get(`pad2readonly:${padId}`); @@ -53,15 +52,13 @@ exports.getReadOnlyId = async function (padId) { * returns the padId for a read only id * @param {String} readOnlyId read only id */ -exports.getPadId = function (readOnlyId) { - return db.get(`readonly2pad:${readOnlyId}`); -}; +exports.getPadId = (readOnlyId) => db.get(`readonly2pad:${readOnlyId}`); /** * returns the padId and readonlyPadId in an object for any id * @param {String} padIdOrReadonlyPadId read only id or real pad id */ -exports.getIds = async function (id) { +exports.getIds = async (id) => { const readonly = (id.indexOf('r.') === 0); // Might be null, if this is an unknown read-only id From 93bc21b5f30ecd98e959001ba92837b7a61193d6 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 013/153] lint: src/node/db/SecurityManager.js --- src/node/db/SecurityManager.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/node/db/SecurityManager.js b/src/node/db/SecurityManager.js index 64091dbdc..24d966d18 100644 --- a/src/node/db/SecurityManager.js +++ b/src/node/db/SecurityManager.js @@ -1,3 +1,4 @@ +'use strict'; /** * Controls the security of pad access */ @@ -19,7 +20,7 @@ */ const authorManager = require('./AuthorManager'); -const hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks.js'); +const hooks = require('../../static/js/pluginfw/hooks.js'); const padManager = require('./PadManager'); const sessionManager = require('./SessionManager'); const settings = require('../utils/Settings'); @@ -47,7 +48,7 @@ const DENY = Object.freeze({accessStatus: 'deny'}); * WARNING: Tokens and session IDs MUST be kept secret, otherwise users will be able to impersonate * each other (which might allow them to gain privileges). */ -exports.checkAccess = async function (padID, sessionCookie, token, userSettings) { +exports.checkAccess = async (padID, sessionCookie, token, userSettings) => { if (!padID) { authLogger.debug('access denied: missing padID'); return DENY; From 3681f72afd10a20715147a8c76b0bc9bcde49491 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 014/153] lint: src/node/db/SessionManager.js --- src/node/db/SessionManager.js | 55 ++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/src/node/db/SessionManager.js b/src/node/db/SessionManager.js index 8f1daab52..d46ed9fae 100644 --- a/src/node/db/SessionManager.js +++ b/src/node/db/SessionManager.js @@ -1,5 +1,7 @@ +'use strict'; /** - * The Session Manager provides functions to manage session in the database, it only provides session management for sessions created by the API + * The Session Manager provides functions to manage session in the database, + * it only provides session management for sessions created by the API */ /* @@ -18,7 +20,7 @@ * limitations under the License. */ -const customError = require('../utils/customError'); +const CustomError = require('../utils/customError'); const promises = require('../utils/promises'); const randomString = require('../utils/randomstring'); const db = require('./DB'); @@ -40,7 +42,8 @@ exports.findAuthorID = async (groupID, sessionCookie) => { * Sometimes, RFC 6265-compliant web servers may send back a cookie whose * value is enclosed in double quotes, such as: * - * Set-Cookie: sessionCookie="s.37cf5299fbf981e14121fba3a588c02b,s.2b21517bf50729d8130ab85736a11346"; Version=1; Path=/; Domain=localhost; Discard + * Set-Cookie: sessionCookie="s.37cf5299fbf981e14121fba3a588c02b, + * s.2b21517bf50729d8130ab85736a11346"; Version=1; Path=/; Domain=localhost; Discard * * Where the double quotes at the start and the end of the header value are * just delimiters. This is perfectly legal: Etherpad parsing logic should @@ -78,26 +81,26 @@ exports.findAuthorID = async (groupID, sessionCookie) => { return sessionInfo.authorID; }; -exports.doesSessionExist = async function (sessionID) { +exports.doesSessionExist = async (sessionID) => { // check if the database entry of this session exists const session = await db.get(`session:${sessionID}`); - return (session !== null); + return (session != null); }; /** * Creates a new session between an author and a group */ -exports.createSession = async function (groupID, authorID, validUntil) { +exports.createSession = async (groupID, authorID, validUntil) => { // check if the group exists const groupExists = await groupManager.doesGroupExist(groupID); if (!groupExists) { - throw new customError('groupID does not exist', 'apierror'); + throw new CustomError('groupID does not exist', 'apierror'); } // check if the author exists const authorExists = await authorManager.doesAuthorExist(authorID); if (!authorExists) { - throw new customError('authorID does not exist', 'apierror'); + throw new CustomError('authorID does not exist', 'apierror'); } // try to parse validUntil if it's not a number @@ -107,22 +110,22 @@ exports.createSession = async function (groupID, authorID, validUntil) { // check it's a valid number if (isNaN(validUntil)) { - throw new customError('validUntil is not a number', 'apierror'); + throw new CustomError('validUntil is not a number', 'apierror'); } // ensure this is not a negative number if (validUntil < 0) { - throw new customError('validUntil is a negative number', 'apierror'); + throw new CustomError('validUntil is a negative number', 'apierror'); } // ensure this is not a float value - if (!is_int(validUntil)) { - throw new customError('validUntil is a float value', 'apierror'); + if (!isInt(validUntil)) { + throw new CustomError('validUntil is a float value', 'apierror'); } // check if validUntil is in the future if (validUntil < Math.floor(Date.now() / 1000)) { - throw new customError('validUntil is in the past', 'apierror'); + throw new CustomError('validUntil is in the past', 'apierror'); } // generate sessionID @@ -170,13 +173,13 @@ exports.createSession = async function (groupID, authorID, validUntil) { return {sessionID}; }; -exports.getSessionInfo = async function (sessionID) { +exports.getSessionInfo = async (sessionID) => { // check if the database entry of this session exists const session = await db.get(`session:${sessionID}`); if (session == null) { // session does not exist - throw new customError('sessionID does not exist', 'apierror'); + throw new CustomError('sessionID does not exist', 'apierror'); } // everything is fine, return the sessioninfos @@ -186,11 +189,11 @@ exports.getSessionInfo = async function (sessionID) { /** * Deletes a session */ -exports.deleteSession = async function (sessionID) { +exports.deleteSession = async (sessionID) => { // ensure that the session exists const session = await db.get(`session:${sessionID}`); if (session == null) { - throw new customError('sessionID does not exist', 'apierror'); + throw new CustomError('sessionID does not exist', 'apierror'); } // everything is fine, use the sessioninfos @@ -217,22 +220,22 @@ exports.deleteSession = async function (sessionID) { } }; -exports.listSessionsOfGroup = async function (groupID) { +exports.listSessionsOfGroup = async (groupID) => { // check that the group exists const exists = await groupManager.doesGroupExist(groupID); if (!exists) { - throw new customError('groupID does not exist', 'apierror'); + throw new CustomError('groupID does not exist', 'apierror'); } const sessions = await listSessionsWithDBKey(`group2sessions:${groupID}`); return sessions; }; -exports.listSessionsOfAuthor = async function (authorID) { +exports.listSessionsOfAuthor = async (authorID) => { // check that the author exists const exists = await authorManager.doesAuthorExist(authorID); if (!exists) { - throw new customError('authorID does not exist', 'apierror'); + throw new CustomError('authorID does not exist', 'apierror'); } const sessions = await listSessionsWithDBKey(`author2sessions:${authorID}`); @@ -241,7 +244,7 @@ exports.listSessionsOfAuthor = async function (authorID) { // this function is basically the code listSessionsOfAuthor and listSessionsOfGroup has in common // required to return null rather than an empty object if there are none -async function listSessionsWithDBKey(dbkey) { +const listSessionsWithDBKey = async (dbkey) => { // get the group2sessions entry const sessionObject = await db.get(dbkey); const sessions = sessionObject ? sessionObject.sessionIDs : null; @@ -252,7 +255,7 @@ async function listSessionsWithDBKey(dbkey) { const sessionInfo = await exports.getSessionInfo(sessionID); sessions[sessionID] = sessionInfo; } catch (err) { - if (err == 'apierror: sessionID does not exist') { + if (err === 'apierror: sessionID does not exist') { console.warn(`Found bad session ${sessionID} in ${dbkey}`); sessions[sessionID] = null; } else { @@ -262,9 +265,7 @@ async function listSessionsWithDBKey(dbkey) { } return sessions; -} +}; // checks if a number is an int -function is_int(value) { - return (parseFloat(value) == parseInt(value)) && !isNaN(value); -} +const isInt = (value) => (parseFloat(value) === parseInt(value)) && !isNaN(value); From 8fb6912fc986c815c6515d38037d7f66d13e67c5 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 015/153] lint: src/node/db/SessionStore.js --- src/node/db/SessionStore.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/node/db/SessionStore.js b/src/node/db/SessionStore.js index 91bd75561..2c5d1ca25 100644 --- a/src/node/db/SessionStore.js +++ b/src/node/db/SessionStore.js @@ -1,3 +1,4 @@ +'use strict'; /* * Stores session data in the database * Source; https://github.com/edy-b/SciFlowWriter/blob/develop/available_plugins/ep_sciflowwriter/db/DirtyStore.js @@ -7,9 +8,9 @@ * express-session, which can't actually use promises anyway. */ -const DB = require('ep_etherpad-lite/node/db/DB'); -const Store = require('ep_etherpad-lite/node_modules/express-session').Store; -const log4js = require('ep_etherpad-lite/node_modules/log4js'); +const DB = require('./DB'); +const Store = require('express-session').Store; +const log4js = require('log4js'); const logger = log4js.getLogger('SessionStore'); From ee9bb019b2e62658b2912fe43cc475c401dfdc91 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 016/153] lint: src/node/easysync_tests.js --- src/node/easysync_tests.js | 315 +++++++++++++++++++++---------------- 1 file changed, 180 insertions(+), 135 deletions(-) diff --git a/src/node/easysync_tests.js b/src/node/easysync_tests.js index c8a5c9853..78d9f61e8 100644 --- a/src/node/easysync_tests.js +++ b/src/node/easysync_tests.js @@ -1,6 +1,8 @@ +'use strict'; /** - * I found this tests in the old Etherpad and used it to test if the Changeset library can be run on node.js. - * It has no use for ep-lite, but I thought I keep it cause it may help someone to understand the Changeset library + * I found this tests in the old Etherpad and used it to test if the Changeset library can be run on + * node.js. It has no use for ep-lite, but I thought I keep it cause it may help someone to + * understand the Changeset library * https://github.com/ether/pad/blob/master/infrastructure/ace/www/easysync2_tests.js */ @@ -21,52 +23,47 @@ */ -const Changeset = require('ep_etherpad-lite/static/js/Changeset'); -const AttributePool = require('ep_etherpad-lite/static/js/AttributePool'); +const Changeset = require('../static/js/Changeset'); +const AttributePool = require('../static/js/AttributePool'); function random() { - this.nextInt = function (maxValue) { - return Math.floor(Math.random() * maxValue); - }; - - this.nextDouble = function (maxValue) { - return Math.random(); - }; + this.nextInt = (maxValue) => Math.floor(Math.random() * maxValue); + this.nextDouble = (maxValue) => Math.random(); } -function runTests() { - function print(str) { +const runTests = () => { + const print = (str) => { console.log(str); - } + }; - function assert(code, optMsg) { - if (!eval(code)) throw new Error(`FALSE: ${optMsg || code}`); - } + const assert = (code, optMsg) => { + if (!eval(code)) throw new Error(`FALSE: ${optMsg || code}`); /* eslint-disable-line no-eval */ + }; - function literal(v) { + const literal = (v) => { if ((typeof v) === 'string') { return `"${v.replace(/[\\\"]/g, '\\$1').replace(/\n/g, '\\n')}"`; } else { return JSON.stringify(v); } - } + }; - function assertEqualArrays(a, b) { + const assertEqualArrays = (a, b) => { assert(`JSON.stringify(${literal(a)}) == JSON.stringify(${literal(b)})`); - } + }; - function assertEqualStrings(a, b) { + const assertEqualStrings = (a, b) => { assert(`${literal(a)} == ${literal(b)}`); - } + }; - function throughIterator(opsStr) { + const throughIterator = (opsStr) => { const iter = Changeset.opIterator(opsStr); const assem = Changeset.opAssembler(); while (iter.hasNext()) { assem.append(iter.next()); } return assem.toString(); - } + }; - function throughSmartAssembler(opsStr) { + const throughSmartAssembler = (opsStr) => { const iter = Changeset.opIterator(opsStr); const assem = Changeset.smartOpAssembler(); while (iter.hasNext()) { @@ -74,50 +71,50 @@ function runTests() { } assem.endDocument(); return assem.toString(); - } + }; - (function () { + (() => { print('> throughIterator'); const x = '-c*3*4+6|3=az*asdf0*1*2*3+1=1-1+1*0+1=1-1+1|c=c-1'; assert(`throughIterator(${literal(x)}) == ${literal(x)}`); })(); - (function () { + (() => { print('> throughSmartAssembler'); const x = '-c*3*4+6|3=az*asdf0*1*2*3+1=1-1+1*0+1=1-1+1|c=c-1'; assert(`throughSmartAssembler(${literal(x)}) == ${literal(x)}`); })(); - function applyMutations(mu, arrayOfArrays) { + const applyMutations = (mu, arrayOfArrays) => { arrayOfArrays.forEach((a) => { const result = mu[a[0]].apply(mu, a.slice(1)); - if (a[0] == 'remove' && a[3]) { + if (a[0] === 'remove' && a[3]) { assertEqualStrings(a[3], result); } }); - } + }; - function mutationsToChangeset(oldLen, arrayOfArrays) { + const mutationsToChangeset = (oldLen, arrayOfArrays) => { const assem = Changeset.smartOpAssembler(); const op = Changeset.newOp(); const bank = Changeset.stringAssembler(); let oldPos = 0; let newLen = 0; arrayOfArrays.forEach((a) => { - if (a[0] == 'skip') { + if (a[0] === 'skip') { op.opcode = '='; op.chars = a[1]; op.lines = (a[2] || 0); assem.append(op); oldPos += op.chars; newLen += op.chars; - } else if (a[0] == 'remove') { + } else if (a[0] === 'remove') { op.opcode = '-'; op.chars = a[1]; op.lines = (a[2] || 0); assem.append(op); oldPos += op.chars; - } else if (a[0] == 'insert') { + } else if (a[0] === 'insert') { op.opcode = '+'; bank.append(a[1]); op.chars = a[1].length; @@ -129,9 +126,9 @@ function runTests() { newLen += oldLen - oldPos; assem.endDocument(); return Changeset.pack(oldLen, newLen, assem.toString(), bank.toString()); - } + }; - function runMutationTest(testId, origLines, muts, correct) { + const runMutationTest = (testId, origLines, muts, correct) => { print(`> runMutationTest#${testId}`); let lines = origLines.slice(); const mu = Changeset.textLinesMutator(lines); @@ -149,7 +146,7 @@ function runTests() { // print(literal(cs)); const outText = Changeset.applyToText(cs, inText); assertEqualStrings(correctText, outText); - } + }; runMutationTest(1, ['apple\n', 'banana\n', 'cabbage\n', 'duffle\n', 'eggplant\n'], [ ['remove', 1, 0, 'a'], @@ -220,7 +217,7 @@ function runTests() { ['skip', 1, 1, true], ], ['banana\n', 'cabbage\n', 'duffle\n']); - function poolOrArray(attribs) { + const poolOrArray = (attribs) => { if (attribs.getAttrib) { return attribs; // it's already an attrib pool } else { @@ -231,23 +228,25 @@ function runTests() { }); return p; } - } + }; - function runApplyToAttributionTest(testId, attribs, cs, inAttr, outCorrect) { + const runApplyToAttributionTest = (testId, attribs, cs, inAttr, outCorrect) => { print(`> applyToAttribution#${testId}`); const p = poolOrArray(attribs); const result = Changeset.applyToAttribution( Changeset.checkRep(cs), inAttr, p); assertEqualStrings(outCorrect, result); - } + }; // turn cactus\n into actusabcd\n - runApplyToAttributionTest(1, ['bold,', 'bold,true'], 'Z:7>3-1*0=1*1=1=3+4$abcd', '+1*1+1|1+5', '+1*1+1|1+8'); + runApplyToAttributionTest(1, + ['bold,', 'bold,true'], 'Z:7>3-1*0=1*1=1=3+4$abcd', '+1*1+1|1+5', '+1*1+1|1+8'); // turn "david\ngreenspan\n" into "david\ngreen\n" - runApplyToAttributionTest(2, ['bold,', 'bold,true'], 'Z:g<4*1|1=6*1=5-4$', '|2+g', '*1|1+6*1+5|1+1'); + runApplyToAttributionTest(2, + ['bold,', 'bold,true'], 'Z:g<4*1|1=6*1=5-4$', '|2+g', '*1|1+6*1+5|1+1'); - (function () { + (() => { print('> mutatorHasMore'); const lines = ['1\n', '2\n', '3\n', '4\n']; let mu; @@ -288,7 +287,7 @@ function runTests() { assert(`${mu.hasMore()} == false`); })(); - function runMutateAttributionTest(testId, attribs, cs, alines, outCorrect) { + const runMutateAttributionTest = (testId, attribs, cs, alines, outCorrect) => { print(`> runMutateAttributionTest#${testId}`); const p = poolOrArray(attribs); const alines2 = Array.prototype.slice.call(alines); @@ -298,30 +297,35 @@ function runTests() { print(`> runMutateAttributionTest#${testId}.applyToAttribution`); - function removeQuestionMarks(a) { - return a.replace(/\?/g, ''); - } + const removeQuestionMarks = (a) => a.replace(/\?/g, ''); const inMerged = Changeset.joinAttributionLines(alines.map(removeQuestionMarks)); const correctMerged = Changeset.joinAttributionLines(outCorrect.map(removeQuestionMarks)); const mergedResult = Changeset.applyToAttribution(cs, inMerged, p); assertEqualStrings(correctMerged, mergedResult); - } + }; // turn 123\n 456\n 789\n into 123\n 456\n 789\n - runMutateAttributionTest(1, ['bold,true'], 'Z:c>0|1=4=1*0=1$', ['|1+4', '|1+4', '|1+4'], ['|1+4', '+1*0+1|1+2', '|1+4']); + runMutateAttributionTest(1, + ['bold,true'], 'Z:c>0|1=4=1*0=1$', ['|1+4', '|1+4', '|1+4'], ['|1+4', '+1*0+1|1+2', '|1+4']); // make a document bold - runMutateAttributionTest(2, ['bold,true'], 'Z:c>0*0|3=c$', ['|1+4', '|1+4', '|1+4'], ['*0|1+4', '*0|1+4', '*0|1+4']); + runMutateAttributionTest(2, + ['bold,true'], 'Z:c>0*0|3=c$', ['|1+4', '|1+4', '|1+4'], ['*0|1+4', '*0|1+4', '*0|1+4']); // clear bold on document - runMutateAttributionTest(3, ['bold,', 'bold,true'], 'Z:c>0*0|3=c$', ['*1+1+1*1+1|1+1', '+1*1+1|1+2', '*1+1+1*1+1|1+1'], ['|1+4', '|1+4', '|1+4']); + runMutateAttributionTest(3, + ['bold,', 'bold,true'], 'Z:c>0*0|3=c$', + ['*1+1+1*1+1|1+1', '+1*1+1|1+2', '*1+1+1*1+1|1+1'], ['|1+4', '|1+4', '|1+4']); // add a character on line 3 of a document with 5 blank lines, and make sure // the optimization that skips purely-kept lines is working; if any attribution string // with a '?' is parsed it will cause an error. - runMutateAttributionTest(4, ['foo,bar', 'line,1', 'line,2', 'line,3', 'line,4', 'line,5'], 'Z:5>1|2=2+1$x', ['?*1|1+1', '?*2|1+1', '*3|1+1', '?*4|1+1', '?*5|1+1'], ['?*1|1+1', '?*2|1+1', '+1*3|1+1', '?*4|1+1', '?*5|1+1']); + runMutateAttributionTest(4, + ['foo,bar', 'line,1', 'line,2', 'line,3', 'line,4', 'line,5'], + 'Z:5>1|2=2+1$x', ['?*1|1+1', '?*2|1+1', '*3|1+1', '?*4|1+1', '?*5|1+1'], + ['?*1|1+1', '?*2|1+1', '+1*3|1+1', '?*4|1+1', '?*5|1+1']); - const testPoolWithChars = (function () { + const testPoolWithChars = (() => { const p = new AttributePool(); p.putAttrib(['char', 'newline']); for (let i = 1; i < 36; i++) { @@ -332,39 +336,66 @@ function runTests() { })(); // based on runMutationTest#1 - runMutateAttributionTest(5, testPoolWithChars, 'Z:11>7-2*t+1*u+1|2=b|2+a=2*b+1*o+1*t+1*0|1+1*b+1*u+1=3|1-3-6$' + 'tucream\npie\nbot\nbu', ['*a+1*p+2*l+1*e+1*0|1+1', '*b+1*a+1*n+1*a+1*n+1*a+1*0|1+1', '*c+1*a+1*b+2*a+1*g+1*e+1*0|1+1', '*d+1*u+1*f+2*l+1*e+1*0|1+1', '*e+1*g+2*p+1*l+1*a+1*n+1*t+1*0|1+1'], ['*t+1*u+1*p+1*l+1*e+1*0|1+1', '*b+1*a+1*n+1*a+1*n+1*a+1*0|1+1', '|1+6', '|1+4', '*c+1*a+1*b+1*o+1*t+1*0|1+1', '*b+1*u+1*b+2*a+1*0|1+1', '*e+1*g+2*p+1*l+1*a+1*n+1*t+1*0|1+1']); + runMutateAttributionTest(5, testPoolWithChars, + 'Z:11>7-2*t+1*u+1|2=b|2+a=2*b+1*o+1*t+1*0|1+1*b+1*u+1=3|1-3-6$' + 'tucream\npie\nbot\nbu', ['*a+1*p+2*l+1*e+1*0|1+1', '*b+1*a+1*n+1*a+1*n+1*a+1*0|1+1', '*c+1*a+1*b+2*a+1*g+1*e+1*0|1+1', '*d+1*u+1*f+2*l+1*e+1*0|1+1', '*e+1*g+2*p+1*l+1*a+1*n+1*t+1*0|1+1'], ['*t+1*u+1*p+1*l+1*e+1*0|1+1', '*b+1*a+1*n+1*a+1*n+1*a+1*0|1+1', '|1+6', '|1+4', '*c+1*a+1*b+1*o+1*t+1*0|1+1', '*b+1*u+1*b+2*a+1*0|1+1', '*e+1*g+2*p+1*l+1*a+1*n+1*t+1*0|1+1']); // based on runMutationTest#3 - runMutateAttributionTest(6, testPoolWithChars, 'Z:117=1|4+7$\n2\n3\n4\n', ['*1+1*5|1+2'], ['*1+1|1+1', '|1+2', '|1+2', '|1+2', '*5|1+2']); + runMutateAttributionTest(7, testPoolWithChars, 'Z:3>7=1|4+7$\n2\n3\n4\n', + ['*1+1*5|1+2'], ['*1+1|1+1', '|1+2', '|1+2', '|1+2', '*5|1+2']); // based on runMutationTest#5 - runMutateAttributionTest(8, testPoolWithChars, 'Z:a<7=1|4-7$', ['*1|1+2', '*2|1+2', '*3|1+2', '*4|1+2', '*5|1+2'], ['*1+1*5|1+2']); + runMutateAttributionTest(8, testPoolWithChars, 'Z:a<7=1|4-7$', + ['*1|1+2', '*2|1+2', '*3|1+2', '*4|1+2', '*5|1+2'], ['*1+1*5|1+2']); // based on runMutationTest#6 - runMutateAttributionTest(9, testPoolWithChars, 'Z:k<7*0+1*10|2=8|2-8$0', ['*1+1*2+1*3+1|1+1', '*a+1*b+1*c+1|1+1', '*d+1*e+1*f+1|1+1', '*g+1*h+1*i+1|1+1', '?*x+1*y+1*z+1|1+1'], ['*0+1|1+4', '|1+4', '?*x+1*y+1*z+1|1+1']); + runMutateAttributionTest(9, testPoolWithChars, 'Z:k<7*0+1*10|2=8|2-8$0', + [ + '*1+1*2+1*3+1|1+1', + '*a+1*b+1*c+1|1+1', + '*d+1*e+1*f+1|1+1', + '*g+1*h+1*i+1|1+1', + '?*x+1*y+1*z+1|1+1', + ], + ['*0+1|1+4', '|1+4', '?*x+1*y+1*z+1|1+1']); - runMutateAttributionTest(10, testPoolWithChars, 'Z:6>4=1+1=1+1|1=1+1=1*0+1$abcd', ['|1+3', '|1+3'], ['|1+5', '+2*0+1|1+2']); + runMutateAttributionTest(10, testPoolWithChars, 'Z:6>4=1+1=1+1|1=1+1=1*0+1$abcd', + ['|1+3', '|1+3'], ['|1+5', '+2*0+1|1+2']); - runMutateAttributionTest(11, testPoolWithChars, 'Z:s>1|1=4=6|1+1$\n', ['*0|1+4', '*0|1+8', '*0+5|1+1', '*0|1+1', '*0|1+5', '*0|1+1', '*0|1+1', '*0|1+1', '|1+1'], ['*0|1+4', '*0+6|1+1', '*0|1+2', '*0+5|1+1', '*0|1+1', '*0|1+5', '*0|1+1', '*0|1+1', '*0|1+1', '|1+1']); + runMutateAttributionTest(11, testPoolWithChars, 'Z:s>1|1=4=6|1+1$\n', + ['*0|1+4', '*0|1+8', '*0+5|1+1', '*0|1+1', '*0|1+5', '*0|1+1', '*0|1+1', '*0|1+1', '|1+1'], + [ + '*0|1+4', + '*0+6|1+1', + '*0|1+2', + '*0+5|1+1', + '*0|1+1', + '*0|1+5', + '*0|1+1', + '*0|1+1', + '*0|1+1', + '|1+1', + ]); - function randomInlineString(len, rand) { + const randomInlineString = (len, rand) => { const assem = Changeset.stringAssembler(); for (let i = 0; i < len; i++) { assem.append(String.fromCharCode(rand.nextInt(26) + 97)); } return assem.toString(); - } + }; - function randomMultiline(approxMaxLines, approxMaxCols, rand) { + const randomMultiline = (approxMaxLines, approxMaxCols, rand) => { const numParts = rand.nextInt(approxMaxLines * 2) + 1; const txt = Changeset.stringAssembler(); txt.append(rand.nextInt(2) ? '\n' : ''); for (let i = 0; i < numParts; i++) { - if ((i % 2) == 0) { + if ((i % 2) === 0) { if (rand.nextInt(10)) { txt.append(randomInlineString(rand.nextInt(approxMaxCols) + 1, rand)); } else { @@ -375,9 +406,9 @@ function runTests() { } } return txt.toString(); - } + }; - function randomStringOperation(numCharsLeft, rand) { + const randomStringOperation = (numCharsLeft, rand) => { let result; switch (rand.nextInt(9)) { case 0: @@ -476,26 +507,26 @@ function runTests() { result.skip = Math.min(result.skip, maxOrig); } return result; - } + }; - function randomTwoPropAttribs(opcode, rand) { + const randomTwoPropAttribs = (opcode, rand) => { // assumes attrib pool like ['apple,','apple,true','banana,','banana,true'] - if (opcode == '-' || rand.nextInt(3)) { + if (opcode === '-' || rand.nextInt(3)) { return ''; } else if (rand.nextInt(3)) { - if (opcode == '+' || rand.nextInt(2)) { + if (opcode === '+' || rand.nextInt(2)) { return `*${Changeset.numToString(rand.nextInt(2) * 2 + 1)}`; } else { return `*${Changeset.numToString(rand.nextInt(2) * 2)}`; } - } else if (opcode == '+' || rand.nextInt(4) == 0) { + } else if (opcode === '+' || rand.nextInt(4) === 0) { return '*1*3'; } else { return ['*0*2', '*0*3', '*1*2'][rand.nextInt(3)]; } - } + }; - function randomTestChangeset(origText, rand, withAttribs) { + const randomTestChangeset = (origText, rand, withAttribs) => { const charBank = Changeset.stringAssembler(); let textLeft = origText; // always keep final newline const outTextAssem = Changeset.stringAssembler(); @@ -504,13 +535,13 @@ function runTests() { const nextOp = Changeset.newOp(); - function appendMultilineOp(opcode, txt) { + const appendMultilineOp = (opcode, txt) => { nextOp.opcode = opcode; if (withAttribs) { nextOp.attribs = randomTwoPropAttribs(opcode, rand); } txt.replace(/\n|[^\n]+/g, (t) => { - if (t == '\n') { + if (t === '\n') { nextOp.chars = 1; nextOp.lines = 1; opAssem.append(nextOp); @@ -521,26 +552,26 @@ function runTests() { } return ''; }); - } + }; - function doOp() { + const doOp = () => { const o = randomStringOperation(textLeft.length, rand); if (o.insert) { - var txt = o.insert; + const txt = o.insert; charBank.append(txt); outTextAssem.append(txt); appendMultilineOp('+', txt); } else if (o.skip) { - var txt = textLeft.substring(0, o.skip); + const txt = textLeft.substring(0, o.skip); textLeft = textLeft.substring(o.skip); outTextAssem.append(txt); appendMultilineOp('=', txt); } else if (o.remove) { - var txt = textLeft.substring(0, o.remove); + const txt = textLeft.substring(0, o.remove); textLeft = textLeft.substring(o.remove); appendMultilineOp('-', txt); } - } + }; while (textLeft.length > 1) doOp(); for (let i = 0; i < 5; i++) doOp(); // do some more (only insertions will happen) @@ -549,9 +580,9 @@ function runTests() { const cs = Changeset.pack(oldLen, outText.length, opAssem.toString(), charBank.toString()); Changeset.checkRep(cs); return [cs, outText]; - } + }; - function testCompose(randomSeed) { + const testCompose = (randomSeed) => { const rand = new random(); print(`> testCompose#${randomSeed}`); @@ -583,9 +614,9 @@ function runTests() { assertEqualStrings(text2, Changeset.applyToText(change12, startText)); assertEqualStrings(text3, Changeset.applyToText(change23, text1)); assertEqualStrings(text3, Changeset.applyToText(change123, startText)); - } + }; - for (var i = 0; i < 30; i++) testCompose(i); + for (let i = 0; i < 30; i++) testCompose(i); (function simpleComposeAttributesTest() { print('> simpleComposeAttributesTest'); @@ -607,12 +638,12 @@ function runTests() { p.putAttrib(['y', 'abc']); p.putAttrib(['y', 'def']); - function testFollow(a, b, afb, bfa, merge) { + const testFollow = (a, b, afb, bfa, merge) => { assertEqualStrings(afb, Changeset.followAttributes(a, b, p)); assertEqualStrings(bfa, Changeset.followAttributes(b, a, p)); assertEqualStrings(merge, Changeset.composeAttributes(a, afb, true, p)); assertEqualStrings(merge, Changeset.composeAttributes(b, bfa, true, p)); - } + }; testFollow('', '', '', '', ''); testFollow('*0', '', '', '*0', '*0'); @@ -624,7 +655,7 @@ function runTests() { testFollow('*0*4', '*2', '', '*0*4', '*0*4'); })(); - function testFollow(randomSeed) { + const testFollow = (randomSeed) => { const rand = new random(); print(`> testFollow#${randomSeed}`); @@ -642,37 +673,37 @@ function runTests() { const merge2 = Changeset.checkRep(Changeset.compose(cs2, bfa)); assertEqualStrings(merge1, merge2); - } + }; - for (var i = 0; i < 30; i++) testFollow(i); + for (let i = 0; i < 30; i++) testFollow(i); - function testSplitJoinAttributionLines(randomSeed) { + const testSplitJoinAttributionLines = (randomSeed) => { const rand = new random(); print(`> testSplitJoinAttributionLines#${randomSeed}`); const doc = `${randomMultiline(10, 20, rand)}\n`; - function stringToOps(str) { + const stringToOps = (str) => { const assem = Changeset.mergingOpAssembler(); const o = Changeset.newOp('+'); o.chars = 1; for (let i = 0; i < str.length; i++) { const c = str.charAt(i); - o.lines = (c == '\n' ? 1 : 0); - o.attribs = (c == 'a' || c == 'b' ? `*${c}` : ''); + o.lines = (c === '\n' ? 1 : 0); + o.attribs = (c === 'a' || c === 'b' ? `*${c}` : ''); assem.append(o); } return assem.toString(); - } + }; const theJoined = stringToOps(doc); const theSplit = doc.match(/[^\n]*\n/g).map(stringToOps); assertEqualArrays(theSplit, Changeset.splitAttributionLines(theJoined, doc)); assertEqualStrings(theJoined, Changeset.joinAttributionLines(theSplit)); - } + }; - for (var i = 0; i < 10; i++) testSplitJoinAttributionLines(i); + for (let i = 0; i < 10; i++) testSplitJoinAttributionLines(i); (function testMoveOpsToNewPool() { print('> testMoveOpsToNewPool'); @@ -685,8 +716,10 @@ function runTests() { pool2.putAttrib(['foo', 'bar']); - assertEqualStrings(Changeset.moveOpsToNewPool('Z:1>2*1+1*0+1$ab', pool1, pool2), 'Z:1>2*0+1*1+1$ab'); - assertEqualStrings(Changeset.moveOpsToNewPool('*1+1*0+1', pool1, pool2), '*0+1*1+1'); + assertEqualStrings( + Changeset.moveOpsToNewPool('Z:1>2*1+1*0+1$ab', pool1, pool2), 'Z:1>2*0+1*1+1$ab'); + assertEqualStrings( + Changeset.moveOpsToNewPool('*1+1*0+1', pool1, pool2), '*0+1*1+1'); })(); @@ -709,14 +742,15 @@ function runTests() { assertEqualArrays(correctSplices, Changeset.toSplices(cs)); })(); - function testCharacterRangeFollow(testId, cs, oldRange, insertionsAfter, correctNewRange) { + const testCharacterRangeFollow = (testId, cs, oldRange, insertionsAfter, correctNewRange) => { print(`> testCharacterRangeFollow#${testId}`); + cs = Changeset.checkRep(cs); + assertEqualArrays(correctNewRange, Changeset.characterRangeFollow( + cs, oldRange[0], oldRange[1], insertionsAfter)); + }; - var cs = Changeset.checkRep(cs); - assertEqualArrays(correctNewRange, Changeset.characterRangeFollow(cs, oldRange[0], oldRange[1], insertionsAfter)); - } - - testCharacterRangeFollow(1, 'Z:z>9*0=1=4-3+9=1|1-4-4+1*0+a$123456789abcdefghijk', [7, 10], false, [14, 15]); + testCharacterRangeFollow(1, 'Z:z>9*0=1=4-3+9=1|1-4-4+1*0+a$123456789abcdefghijk', + [7, 10], false, [14, 15]); testCharacterRangeFollow(2, 'Z:bc<6|x=b4|2-6$', [400, 407], false, [400, 401]); testCharacterRangeFollow(3, 'Z:4>0-3+3$abc', [0, 3], false, [3, 3]); testCharacterRangeFollow(4, 'Z:4>0-3+3$abc', [0, 3], true, [0, 0]); @@ -735,23 +769,31 @@ function runTests() { p.putAttrib(['name', 'david']); p.putAttrib(['color', 'green']); - assertEqualStrings('david', Changeset.opAttributeValue(Changeset.stringOp('*0*1+1'), 'name', p)); - assertEqualStrings('david', Changeset.opAttributeValue(Changeset.stringOp('*0+1'), 'name', p)); - assertEqualStrings('', Changeset.opAttributeValue(Changeset.stringOp('*1+1'), 'name', p)); - assertEqualStrings('', Changeset.opAttributeValue(Changeset.stringOp('+1'), 'name', p)); - assertEqualStrings('green', Changeset.opAttributeValue(Changeset.stringOp('*0*1+1'), 'color', p)); - assertEqualStrings('green', Changeset.opAttributeValue(Changeset.stringOp('*1+1'), 'color', p)); - assertEqualStrings('', Changeset.opAttributeValue(Changeset.stringOp('*0+1'), 'color', p)); - assertEqualStrings('', Changeset.opAttributeValue(Changeset.stringOp('+1'), 'color', p)); + assertEqualStrings('david', + Changeset.opAttributeValue(Changeset.stringOp('*0*1+1'), 'name', p)); + assertEqualStrings('david', + Changeset.opAttributeValue(Changeset.stringOp('*0+1'), 'name', p)); + assertEqualStrings('', + Changeset.opAttributeValue(Changeset.stringOp('*1+1'), 'name', p)); + assertEqualStrings('', + Changeset.opAttributeValue(Changeset.stringOp('+1'), 'name', p)); + assertEqualStrings('green', + Changeset.opAttributeValue(Changeset.stringOp('*0*1+1'), 'color', p)); + assertEqualStrings('green', + Changeset.opAttributeValue(Changeset.stringOp('*1+1'), 'color', p)); + assertEqualStrings('', + Changeset.opAttributeValue(Changeset.stringOp('*0+1'), 'color', p)); + assertEqualStrings('', + Changeset.opAttributeValue(Changeset.stringOp('+1'), 'color', p)); })(); - function testAppendATextToAssembler(testId, atext, correctOps) { + const testAppendATextToAssembler = (testId, atext, correctOps) => { print(`> testAppendATextToAssembler#${testId}`); const assem = Changeset.smartOpAssembler(); Changeset.appendATextToAssembler(atext, assem); assertEqualStrings(correctOps, assem.toString()); - } + }; testAppendATextToAssembler(1, { text: '\n', @@ -786,13 +828,13 @@ function runTests() { attribs: '|2+2*x|2+5', }, '|2+2*x|1+1*x+3'); - function testMakeAttribsString(testId, pool, opcode, attribs, correctString) { + const testMakeAttribsString = (testId, pool, opcode, attribs, correctString) => { print(`> testMakeAttribsString#${testId}`); const p = poolOrArray(pool); const str = Changeset.makeAttribsString(opcode, attribs, p); assertEqualStrings(correctString, str); - } + }; testMakeAttribsString(1, ['bold,'], '+', [ ['bold', ''], @@ -809,12 +851,12 @@ function runTests() { ['abc', 'def'], ], '*0*1'); - function testSubattribution(testId, astr, start, end, correctOutput) { + const testSubattribution = (testId, astr, start, end, correctOutput) => { print(`> testSubattribution#${testId}`); const str = Changeset.subattribution(astr, start, end); assertEqualStrings(correctOutput, str); - } + }; testSubattribution(1, '+1', 0, 0, ''); testSubattribution(2, '+1', 0, 1, '+1'); @@ -859,39 +901,42 @@ function runTests() { testSubattribution(41, '*0+2+1*1|1+3', 2, 6, '+1*1|1+3'); testSubattribution(42, '*0+2+1*1+3', 2, 6, '+1*1+3'); - function testFilterAttribNumbers(testId, cs, filter, correctOutput) { + const testFilterAttribNumbers = (testId, cs, filter, correctOutput) => { print(`> testFilterAttribNumbers#${testId}`); const str = Changeset.filterAttribNumbers(cs, filter); assertEqualStrings(correctOutput, str); - } + }; - testFilterAttribNumbers(1, '*0*1+1+2+3*1+4*2+5*0*2*1*b*c+6', (n) => (n % 2) == 0, '*0+1+2+3+4*2+5*0*2*c+6'); - testFilterAttribNumbers(2, '*0*1+1+2+3*1+4*2+5*0*2*1*b*c+6', (n) => (n % 2) == 1, '*1+1+2+3*1+4+5*1*b+6'); + testFilterAttribNumbers(1, '*0*1+1+2+3*1+4*2+5*0*2*1*b*c+6', + (n) => (n % 2) === 0, '*0+1+2+3+4*2+5*0*2*c+6'); + testFilterAttribNumbers(2, '*0*1+1+2+3*1+4*2+5*0*2*1*b*c+6', + (n) => (n % 2) === 1, '*1+1+2+3*1+4+5*1*b+6'); - function testInverse(testId, cs, lines, alines, pool, correctOutput) { + const testInverse = (testId, cs, lines, alines, pool, correctOutput) => { print(`> testInverse#${testId}`); pool = poolOrArray(pool); const str = Changeset.inverse(Changeset.checkRep(cs), lines, alines, pool); assertEqualStrings(correctOutput, str); - } + }; // take "FFFFTTTTT" and apply "-FT--FFTT", the inverse of which is "--F--TT--" - testInverse(1, 'Z:9>0=1*0=1*1=1=2*0=2*1|1=2$', null, ['+4*1+5'], ['bold,', 'bold,true'], 'Z:9>0=2*0=1=2*1=2$'); + testInverse(1, 'Z:9>0=1*0=1*1=1=2*0=2*1|1=2$', null, + ['+4*1+5'], ['bold,', 'bold,true'], 'Z:9>0=2*0=1=2*1=2$'); - function testMutateTextLines(testId, cs, lines, correctLines) { + const testMutateTextLines = (testId, cs, lines, correctLines) => { print(`> testMutateTextLines#${testId}`); const a = lines.slice(); Changeset.mutateTextLines(cs, a); assertEqualArrays(correctLines, a); - } + }; testMutateTextLines(1, 'Z:4<1|1-2-1|1+1+1$\nc', ['a\n', 'b\n'], ['\n', 'c\n']); testMutateTextLines(2, 'Z:4>0|1-2-1|2+3$\nc\n', ['a\n', 'b\n'], ['\n', 'c\n', '\n']); - function testInverseRandom(randomSeed) { + const testInverseRandom = (randomSeed) => { const rand = new random(); print(`> testInverseRandom#${randomSeed}`); @@ -928,9 +973,9 @@ function runTests() { // print(lines.map(function(s) { return '3: '+s.slice(0,-1); }).join('\n')); assertEqualArrays(origLines, lines); assertEqualArrays(origALines, alines); - } + }; - for (var i = 0; i < 30; i++) testInverseRandom(i); -} + for (let i = 0; i < 30; i++) testInverseRandom(i); +}; runTests(); From a7d9a703cdce8488c3ddf446a3bbf44b6a053469 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 017/153] lint: src/node/handler/APIHandler.js --- src/node/handler/APIHandler.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/node/handler/APIHandler.js b/src/node/handler/APIHandler.js index 0708cc009..6bc6e5378 100644 --- a/src/node/handler/APIHandler.js +++ b/src/node/handler/APIHandler.js @@ -1,3 +1,4 @@ +'use strict'; /** * The API Handler handles all API http requests */ @@ -37,7 +38,8 @@ try { apikey = fs.readFileSync(apikeyFilename, 'utf8'); apiHandlerLogger.info(`Api key file read from: "${apikeyFilename}"`); } catch (e) { - apiHandlerLogger.info(`Api key file "${apikeyFilename}" not found. Creating with random contents.`); + apiHandlerLogger.info( + `Api key file "${apikeyFilename}" not found. Creating with random contents.`); apikey = randomString(32); fs.writeFileSync(apikeyFilename, apikey, 'utf8'); } From 2fe5d1f8739a4847bb9a0740881d229d1f7e0bde Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 018/153] lint: src/node/handler/ExportHandler.js --- src/node/handler/ExportHandler.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/node/handler/ExportHandler.js b/src/node/handler/ExportHandler.js index 0a92633f7..fbb9e57da 100644 --- a/src/node/handler/ExportHandler.js +++ b/src/node/handler/ExportHandler.js @@ -1,3 +1,4 @@ +'use strict'; /** * Handles the export requests */ @@ -25,7 +26,7 @@ const exportEtherpad = require('../utils/ExportEtherpad'); const fs = require('fs'); const settings = require('../utils/Settings'); const os = require('os'); -const hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks'); +const hooks = require('../../static/js/pluginfw/hooks'); const TidyHtml = require('../utils/TidyHtml'); const util = require('util'); @@ -49,7 +50,7 @@ const tempDirectory = os.tmpdir(); /** * do a requested export */ -async function doExport(req, res, padId, readOnlyId, type) { +const doExport = async (req, res, padId, readOnlyId, type) => { // avoid naming the read-only file as the original pad's id let fileName = readOnlyId ? readOnlyId : padId; @@ -104,7 +105,6 @@ async function doExport(req, res, padId, readOnlyId, type) { const result = await hooks.aCallAll('exportConvert', {srcFile, destFile, req, res}); if (result.length > 0) { // console.log("export handled by plugin", destFile); - handledByPlugin = true; } else { // @TODO no Promise interface for convertors (yet) await new Promise((resolve, reject) => { @@ -115,7 +115,6 @@ async function doExport(req, res, padId, readOnlyId, type) { } // send the file - const sendFile = util.promisify(res.sendFile); await res.sendFile(destFile, null); // clean up temporary files @@ -128,9 +127,9 @@ async function doExport(req, res, padId, readOnlyId, type) { await fsp_unlink(destFile); } -} +}; -exports.doExport = function (req, res, padId, readOnlyId, type) { +exports.doExport = (req, res, padId, readOnlyId, type) => { doExport(req, res, padId, readOnlyId, type).catch((err) => { if (err !== 'stop') { throw err; From 841d45cbe1157e3c5a4fceb9903a5f98c29c7dbd Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 019/153] lint: src/node/handler/ImportHandler.js --- src/node/handler/ImportHandler.js | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/node/handler/ImportHandler.js b/src/node/handler/ImportHandler.js index c25623d76..d2f98f47d 100644 --- a/src/node/handler/ImportHandler.js +++ b/src/node/handler/ImportHandler.js @@ -1,3 +1,4 @@ +'use strict'; /** * Handles the import requests */ @@ -30,7 +31,7 @@ const os = require('os'); const importHtml = require('../utils/ImportHtml'); const importEtherpad = require('../utils/ImportEtherpad'); const log4js = require('log4js'); -const hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks.js'); +const hooks = require('../../static/js/pluginfw/hooks.js'); const util = require('util'); const fsp_exists = util.promisify(fs.exists); @@ -42,7 +43,7 @@ let convertor = null; let exportExtension = 'htm'; // load abiword only if it is enabled and if soffice is disabled -if (settings.abiword != null && settings.soffice === null) { +if (settings.abiword != null && settings.soffice == null) { convertor = require('../utils/Abiword'); } @@ -57,7 +58,7 @@ const tmpDirectory = os.tmpdir(); /** * do a requested import */ -async function doImport(req, res, padId) { +const doImport = async (req, res, padId) => { const apiLogger = log4js.getLogger('ImportHandler'); // pipe to a file @@ -112,7 +113,8 @@ async function doImport(req, res, padId) { // ensure this is a file ending we know, else we change the file ending to .txt // this allows us to accept source code files like .c or .java const fileEnding = path.extname(srcFile).toLowerCase(); - const knownFileEndings = ['.txt', '.doc', '.docx', '.pdf', '.odt', '.html', '.htm', '.etherpad', '.rtf']; + const knownFileEndings = + ['.txt', '.doc', '.docx', '.pdf', '.odt', '.html', '.htm', '.etherpad', '.rtf']; const fileEndingUnknown = (knownFileEndings.indexOf(fileEnding) < 0); if (fileEndingUnknown) { @@ -146,7 +148,7 @@ async function doImport(req, res, padId) { const headCount = _pad.head; if (headCount >= 10) { - apiLogger.warn("Direct database Import attempt of a pad that already has content, we won't be doing this"); + apiLogger.warn('Aborting direct database import attempt of a pad that already has content'); throw 'padHasData'; } @@ -251,9 +253,9 @@ async function doImport(req, res, padId) { if (await fsp_exists(destFile)) { fsp_unlink(destFile); } -} +}; -exports.doImport = function (req, res, padId) { +exports.doImport = (req, res, padId) => { /** * NB: abuse the 'req' object by storing an additional * 'directDatabaseAccess' property on it so that it can @@ -266,7 +268,10 @@ exports.doImport = function (req, res, padId) { let status = 'ok'; doImport(req, res, padId).catch((err) => { // check for known errors and replace the status - if (err == 'uploadFailed' || err == 'convertFailed' || err == 'padHasData' || err == 'maxFileSize') { + if (err === 'uploadFailed' || + err === 'convertFailed' || + err === 'padHasData' || + err === 'maxFileSize') { status = err; } else { throw err; From 532bde71f77bb04f11b7ddd26d9db4b9e3e555ca Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 020/153] lint: src/node/handler/PadMessageHandler.js --- src/node/handler/PadMessageHandler.js | 190 +++++++++++++++----------- 1 file changed, 110 insertions(+), 80 deletions(-) diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js index 279b08dfa..99cac5ca4 100644 --- a/src/node/handler/PadMessageHandler.js +++ b/src/node/handler/PadMessageHandler.js @@ -1,3 +1,4 @@ +'use strict'; /** * The MessageHandler handles all Messages that comes from Socket.IO and controls the sessions */ @@ -18,22 +19,20 @@ * limitations under the License. */ -/* global exports, process, require */ - const padManager = require('../db/PadManager'); -const Changeset = require('ep_etherpad-lite/static/js/Changeset'); -const AttributePool = require('ep_etherpad-lite/static/js/AttributePool'); -const AttributeManager = require('ep_etherpad-lite/static/js/AttributeManager'); +const Changeset = require('../../static/js/Changeset'); +const AttributePool = require('../../static/js/AttributePool'); +const AttributeManager = require('../../static/js/AttributeManager'); const authorManager = require('../db/AuthorManager'); const readOnlyManager = require('../db/ReadOnlyManager'); const settings = require('../utils/Settings'); const securityManager = require('../db/SecurityManager'); -const plugins = require('ep_etherpad-lite/static/js/pluginfw/plugin_defs.js'); +const plugins = require('../../static/js/pluginfw/plugin_defs.js'); const log4js = require('log4js'); const messageLogger = log4js.getLogger('message'); const accessLogger = log4js.getLogger('access'); const _ = require('underscore'); -const hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks.js'); +const hooks = require('../../static/js/pluginfw/hooks.js'); const channels = require('channels'); const stats = require('../stats'); const assert = require('assert').strict; @@ -65,7 +64,9 @@ stats.gauge('totalUsers', () => Object.keys(socketio.sockets.sockets).length); /** * A changeset queue per pad that is processed by handleUserChanges() */ -const padChannels = new channels.channels(({socket, message}, callback) => nodeify(handleUserChanges(socket, message), callback)); +const padChannels = new channels.channels( + ({socket, message}, callback) => nodeify(handleUserChanges(socket, message), callback) +); /** * Saves the Socket class we need to send and receive data from the client @@ -76,7 +77,7 @@ let socketio; * This Method is called by server.js to tell the message handler on which socket it should send * @param socket_io The Socket */ -exports.setSocketIO = function (socket_io) { +exports.setSocketIO = (socket_io) => { socketio = socket_io; }; @@ -94,7 +95,7 @@ exports.handleConnect = (socket) => { /** * Kicks all sessions from a pad */ -exports.kickSessionsFromPad = function (padID) { +exports.kickSessionsFromPad = (padID) => { if (typeof socketio.sockets.clients !== 'function') return; // skip if there is nobody on this pad @@ -114,7 +115,8 @@ exports.handleDisconnect = async (socket) => { // save the padname of this session const session = sessioninfos[socket.id]; - // if this connection was already etablished with a handshake, send a disconnect message to the others + // if this connection was already etablished with a handshake, + // send a disconnect message to the others if (session && session.author) { const {session: {user} = {}} = socket.client.request; accessLogger.info(`${'[LEAVE]' + @@ -192,7 +194,8 @@ exports.handleMessage = async (socket, message) => { const auth = thisSession.auth; if (!auth) { - console.error('Auth was never applied to a session. If you are using the stress-test tool then restart Etherpad and the Stress test tool.'); + console.error('Auth was never applied to a session. If you are using the ' + + 'stress-test tool then restart Etherpad and the Stress test tool.'); return; } @@ -234,7 +237,7 @@ exports.handleMessage = async (socket, message) => { } // Call handleMessage hook. If a plugin returns null, the message will be dropped. - if ((await hooks.aCallAll('handleMessage', context)).some((m) => m === null)) { + if ((await hooks.aCallAll('handleMessage', context)).some((m) => m == null)) { return; } @@ -283,11 +286,11 @@ exports.handleMessage = async (socket, message) => { * @param socket the socket.io Socket object for the client * @param message the message from the client */ -async function handleSaveRevisionMessage(socket, message) { +const handleSaveRevisionMessage = async (socket, message) => { const {padId, author: authorId} = sessioninfos[socket.id]; const pad = await padManager.getPad(padId); await pad.addSavedRevision(pad.head, authorId); -} +}; /** * Handles a custom message, different to the function below as it handles @@ -296,7 +299,7 @@ async function handleSaveRevisionMessage(socket, message) { * @param msg {Object} the message we're sending * @param sessionID {string} the socketIO session to which we're sending this message */ -exports.handleCustomObjectMessage = function (msg, sessionID) { +exports.handleCustomObjectMessage = (msg, sessionID) => { if (msg.data.type === 'CUSTOM') { if (sessionID) { // a sessionID is targeted: directly to this sessionID @@ -314,7 +317,7 @@ exports.handleCustomObjectMessage = function (msg, sessionID) { * @param padID {Pad} the pad to which we're sending this message * @param msgString {String} the message we're sending */ -exports.handleCustomMessage = function (padID, msgString) { +exports.handleCustomMessage = (padID, msgString) => { const time = Date.now(); const msg = { type: 'COLLABROOM', @@ -331,12 +334,12 @@ exports.handleCustomMessage = function (padID, msgString) { * @param socket the socket.io Socket object for the client * @param message the message from the client */ -async function handleChatMessage(socket, message) { +const handleChatMessage = async (socket, message) => { const time = Date.now(); const text = message.data.text; const {padId, author: authorId} = sessioninfos[socket.id]; await exports.sendChatMessageToPadClients(time, authorId, text, padId); -} +}; /** * Sends a chat message to all clients of this pad @@ -345,7 +348,7 @@ async function handleChatMessage(socket, message) { * @param text the text of the chat message * @param padId the padId to send the chat message to */ -exports.sendChatMessageToPadClients = async function (time, userId, text, padId) { +exports.sendChatMessageToPadClients = async (time, userId, text, padId) => { // get the pad const pad = await padManager.getPad(padId); @@ -371,7 +374,7 @@ exports.sendChatMessageToPadClients = async function (time, userId, text, padId) * @param socket the socket.io Socket object for the client * @param message the message from the client */ -async function handleGetChatMessages(socket, message) { +const handleGetChatMessages = async (socket, message) => { if (message.data.start == null) { messageLogger.warn('Dropped message, GetChatMessages Message has no start!'); return; @@ -387,7 +390,8 @@ async function handleGetChatMessages(socket, message) { const count = end - start; if (count < 0 || count > 100) { - messageLogger.warn('Dropped message, GetChatMessages Message, client requested invalid amount of messages!'); + messageLogger.warn( + 'Dropped message, GetChatMessages Message, client requested invalid amount of messages!'); return; } @@ -405,14 +409,14 @@ async function handleGetChatMessages(socket, message) { // send the messages back to the client socket.json.send(infoMsg); -} +}; /** * Handles a handleSuggestUserName, that means a user have suggest a userName for a other user * @param socket the socket.io Socket object for the client * @param message the message from the client */ -function handleSuggestUserName(socket, message) { +const handleSuggestUserName = (socket, message) => { // check if all ok if (message.data.payload.newName == null) { messageLogger.warn('Dropped message, suggestUserName Message has no newName!'); @@ -433,14 +437,15 @@ function handleSuggestUserName(socket, message) { socket.json.send(message); } }); -} +}; /** - * Handles a USERINFO_UPDATE, that means that a user have changed his color or name. Anyway, we get both informations + * Handles a USERINFO_UPDATE, that means that a user have changed his color or name. + * Anyway, we get both informations * @param socket the socket.io Socket object for the client * @param message the message from the client */ -async function handleUserInfoUpdate(socket, message) { +const handleUserInfoUpdate = async (socket, message) => { // check if all ok if (message.data.userInfo == null) { messageLogger.warn('Dropped message, USERINFO_UPDATE Message has no userInfo!'); @@ -463,7 +468,8 @@ async function handleUserInfoUpdate(socket, message) { const author = session.author; // Check colorId is a Hex color - const isColor = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(message.data.userInfo.colorId); // for #f00 (Thanks Smamatti) + // for #f00 (Thanks Smamatti) + const isColor = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(message.data.userInfo.colorId); if (!isColor) { messageLogger.warn(`Dropped message, USERINFO_UPDATE Color is malformed.${message.data}`); return; @@ -496,7 +502,7 @@ async function handleUserInfoUpdate(socket, message) { // Block until the authorManager has stored the new attributes. await p; -} +}; /** * Handles a USER_CHANGES message, where the client submits its local @@ -512,7 +518,7 @@ async function handleUserInfoUpdate(socket, message) { * @param socket the socket.io Socket object for the client * @param message the message from the client */ -async function handleUserChanges(socket, message) { +const handleUserChanges = async (socket, message) => { // This one's no longer pending, as we're gonna process it now stats.counter('pendingEdits').dec(); @@ -578,7 +584,8 @@ async function handleUserChanges(socket, message) { // + can add text with attribs // = can change or add attribs - // - can have attribs, but they are discarded and don't show up in the attribs - but do show up in the pool + // - can have attribs, but they are discarded and don't show up in the attribs - + // but do show up in the pool op.attribs.split('*').forEach((attr) => { if (!attr) return; @@ -586,9 +593,11 @@ async function handleUserChanges(socket, message) { attr = wireApool.getAttrib(attr); if (!attr) return; - // the empty author is used in the clearAuthorship functionality so this should be the only exception + // the empty author is used in the clearAuthorship functionality so this + // should be the only exception if ('author' === attr[0] && (attr[1] !== thisSession.author && attr[1] !== '')) { - throw new Error(`Author ${thisSession.author} tried to submit changes as author ${attr[1]} in changeset ${changeset}`); + throw new Error(`Author ${thisSession.author} tried to submit changes as author ` + + `${attr[1]} in changeset ${changeset}`); } }); } @@ -628,7 +637,7 @@ async function handleUserChanges(socket, message) { if (baseRev + 1 === r && c === changeset) { socket.json.send({disconnect: 'badChangeset'}); stats.meter('failedChangesets').mark(); - throw new Error("Won't apply USER_CHANGES, because it contains an already accepted changeset"); + throw new Error("Won't apply USER_CHANGES, as it contains an already accepted changeset"); } changeset = Changeset.follow(c, changeset, false, apool); @@ -672,9 +681,9 @@ async function handleUserChanges(socket, message) { } stopWatch.end(); -} +}; -exports.updatePadClients = async function (pad) { +exports.updatePadClients = async (pad) => { // skip this if no-one is on this pad const roomSockets = _getRoomSockets(pad.id); if (roomSockets.length === 0) return; @@ -682,9 +691,12 @@ exports.updatePadClients = async function (pad) { // since all clients usually get the same set of changesets, store them in local cache // to remove unnecessary roundtrip to the datalayer // NB: note below possibly now accommodated via the change to promises/async - // TODO: in REAL world, if we're working without datalayer cache, all requests to revisions will be fired - // BEFORE first result will be landed to our cache object. The solution is to replace parallel processing - // via async.forEach with sequential for() loop. There is no real benefits of running this in parallel, + // TODO: in REAL world, if we're working without datalayer cache, + // all requests to revisions will be fired + // BEFORE first result will be landed to our cache object. + // The solution is to replace parallel processing + // via async.forEach with sequential for() loop. There is no real + // benefits of running this in parallel, // but benefit of reusing cached revision object is HUGE const revCache = {}; @@ -737,7 +749,7 @@ exports.updatePadClients = async function (pad) { /** * Copied from the Etherpad Source Code. Don't know what this method does excatly... */ -function _correctMarkersInPad(atext, apool) { +const _correctMarkersInPad = (atext, apool) => { const text = atext.text; // collect char positions of line markers (e.g. bullets) in new atext @@ -746,9 +758,11 @@ function _correctMarkersInPad(atext, apool) { const iter = Changeset.opIterator(atext.attribs); let offset = 0; while (iter.hasNext()) { - var op = iter.next(); + const op = iter.next(); - const hasMarker = _.find(AttributeManager.lineAttributes, (attribute) => Changeset.opAttributeValue(op, attribute, apool)) !== undefined; + const hasMarker = _.find( + AttributeManager.lineAttributes, + (attribute) => Changeset.opAttributeValue(op, attribute, apool)) !== undefined; if (hasMarker) { for (let i = 0; i < op.chars; i++) { @@ -778,9 +792,9 @@ function _correctMarkersInPad(atext, apool) { }); return builder.toString(); -} +}; -async function handleSwitchToPad(socket, message, _authorID) { +const handleSwitchToPad = async (socket, message, _authorID) => { const currentSessionInfo = sessioninfos[socket.id]; const padId = currentSessionInfo.padId; @@ -816,10 +830,10 @@ async function handleSwitchToPad(socket, message, _authorID) { const newSessionInfo = sessioninfos[socket.id]; createSessionInfoAuth(newSessionInfo, message); await handleClientReady(socket, message, authorID); -} +}; // Creates/replaces the auth object in the given session info. -function createSessionInfoAuth(sessionInfo, message) { +const createSessionInfoAuth = (sessionInfo, message) => { // Remember this information since we won't // have the cookie in further socket.io messages. // This information will be used to check if @@ -830,15 +844,16 @@ function createSessionInfoAuth(sessionInfo, message) { padID: message.padId, token: message.token, }; -} +}; /** - * Handles a CLIENT_READY. A CLIENT_READY is the first message from the client to the server. The Client sends his token + * Handles a CLIENT_READY. A CLIENT_READY is the first message from the client + * to the server. The Client sends his token * and the pad it wants to enter. The Server answers with the inital values (clientVars) of the pad * @param socket the socket.io Socket object for the client * @param message the message from the client */ -async function handleClientReady(socket, message, authorID) { +const handleClientReady = async (socket, message, authorID) => { // check if all ok if (!message.token) { messageLogger.warn('Dropped message, CLIENT_READY Message has no token!'); @@ -884,9 +899,11 @@ async function handleClientReady(socket, message, authorID) { const historicalAuthorData = {}; await Promise.all(authors.map((authorId) => authorManager.getAuthor(authorId).then((author) => { if (!author) { - messageLogger.error('There is no author for authorId: ', authorId, '. This is possibly related to https://github.com/ether/etherpad-lite/issues/2802'); + messageLogger.error(`There is no author for authorId: ${authorId}. ` + + 'This is possibly related to https://github.com/ether/etherpad-lite/issues/2802'); } else { - historicalAuthorData[authorId] = {name: author.name, colorId: author.colorId}; // Filter author attribs (e.g. don't send author's pads to all clients) + // Filter author attribs (e.g. don't send author's pads to all clients) + historicalAuthorData[authorId] = {name: author.name, colorId: author.colorId}; } }))); @@ -931,7 +948,8 @@ async function handleClientReady(socket, message, authorID) { // Save the revision in sessioninfos, we take the revision from the info the client send to us sessionInfo.rev = message.client_rev; - // During the client reconnect, client might miss some revisions from other clients. By using client revision, + // During the client reconnect, client might miss some revisions from other clients. + // By using client revision, // this below code sends all the revisions missed during the client reconnect const revisionsNeeded = []; const changesets = {}; @@ -987,12 +1005,13 @@ async function handleClientReady(socket, message, authorID) { } } else { // This is a normal first connect - + let atext; + let apool; // prepare all values for the wire, there's a chance that this throws, if the pad is corrupted try { - var atext = Changeset.cloneAText(pad.atext); + atext = Changeset.cloneAText(pad.atext); const attribsForWire = Changeset.prepareForWire(atext.attribs, pad.pool); - var apool = attribsForWire.pool.toJsonable(); + apool = attribsForWire.pool.toJsonable(); atext.attribs = attribsForWire.translated; } catch (e) { console.error(e.stack || e); @@ -1147,12 +1166,12 @@ async function handleClientReady(socket, message, authorID) { socket.json.send(msg); })); } -} +}; /** * Handles a request for a rough changeset, the timeslider client needs it */ -async function handleChangesetRequest(socket, message) { +const handleChangesetRequest = async (socket, message) => { // check if all ok if (message.data == null) { messageLogger.warn('Dropped message, changeset request has no data!'); @@ -1197,15 +1216,16 @@ async function handleChangesetRequest(socket, message) { data.requestID = message.data.requestID; socket.json.send({type: 'CHANGESET_REQ', data}); } catch (err) { - console.error(`Error while handling a changeset request for ${padIds.padId}`, err.toString(), message.data); + console.error(`Error while handling a changeset request for ${padIds.padId}`, + err.toString(), message.data); } -} +}; /** * Tries to rebuild the getChangestInfo function of the original Etherpad * https://github.com/ether/pad/blob/master/etherpad/src/etherpad/control/pad/pad_changeset_control.js#L144 */ -async function getChangesetInfo(padId, startNum, endNum, granularity) { +const getChangesetInfo = async (padId, startNum, endNum, granularity) => { const pad = await padManager.getPad(padId); const head_revision = pad.getHeadRevisionNumber(); @@ -1237,15 +1257,25 @@ async function getChangesetInfo(padId, startNum, endNum, granularity) { // get all needed composite Changesets const composedChangesets = {}; - const p1 = Promise.all(compositesChangesetNeeded.map((item) => composePadChangesets(padId, item.start, item.end).then((changeset) => { - composedChangesets[`${item.start}/${item.end}`] = changeset; - }))); + const p1 = Promise.all( + compositesChangesetNeeded.map( + (item) => composePadChangesets( + padId, item.start, item.end + ).then( + (changeset) => { + composedChangesets[`${item.start}/${item.end}`] = changeset; + } + ) + ) + ); // get all needed revision Dates const revisionDate = []; - const p2 = Promise.all(revTimesNeeded.map((revNum) => pad.getRevisionDate(revNum).then((revDate) => { - revisionDate[revNum] = Math.floor(revDate / 1000); - }))); + const p2 = Promise.all(revTimesNeeded.map((revNum) => pad.getRevisionDate(revNum) + .then((revDate) => { + revisionDate[revNum] = Math.floor(revDate / 1000); + }) + )); // get the lines let lines; @@ -1288,13 +1318,13 @@ async function getChangesetInfo(padId, startNum, endNum, granularity) { return {forwardsChangesets, backwardsChangesets, apool: apool.toJsonable(), actualEndNum: endNum, timeDeltas, start: startNum, granularity}; -} +}; /** * Tries to rebuild the getPadLines function of the original Etherpad * https://github.com/ether/pad/blob/master/etherpad/src/etherpad/control/pad/pad_changeset_control.js#L263 */ -async function getPadLines(padId, revNum) { +const getPadLines = async (padId, revNum) => { const pad = await padManager.getPad(padId); // get the atext @@ -1310,13 +1340,13 @@ async function getPadLines(padId, revNum) { textlines: Changeset.splitTextLines(atext.text), alines: Changeset.splitAttributionLines(atext.attribs, atext.text), }; -} +}; /** * Tries to rebuild the composePadChangeset function of the original Etherpad * https://github.com/ether/pad/blob/master/etherpad/src/etherpad/control/pad/pad_changeset_control.js#L241 */ -async function composePadChangesets(padId, startNum, endNum) { +const composePadChangesets = async (padId, startNum, endNum) => { const pad = await padManager.getPad(padId); // fetch all changesets we need @@ -1333,7 +1363,9 @@ async function composePadChangesets(padId, startNum, endNum) { // get all changesets const changesets = {}; - await Promise.all(changesetsNeeded.map((revNum) => pad.getRevisionChangeset(revNum).then((changeset) => changesets[revNum] = changeset))); + await Promise.all(changesetsNeeded.map( + (revNum) => pad.getRevisionChangeset(revNum).then((changeset) => changesets[revNum] = changeset) + )); // compose Changesets let r; @@ -1351,9 +1383,9 @@ async function composePadChangesets(padId, startNum, endNum) { console.warn('failed to compose cs in pad:', padId, ' startrev:', startNum, ' current rev:', r); throw e; } -} +}; -function _getRoomSockets(padID) { +const _getRoomSockets = (padID) => { const roomSockets = []; const room = socketio.sockets.adapter.rooms[padID]; @@ -1364,21 +1396,19 @@ function _getRoomSockets(padID) { } return roomSockets; -} +}; /** * Get the number of users in a pad */ -exports.padUsersCount = function (padID) { - return { - padUsersCount: _getRoomSockets(padID).length, - }; -}; +exports.padUsersCount = (padID) => ({ + padUsersCount: _getRoomSockets(padID).length, +}); /** * Get the list of users in a pad */ -exports.padUsers = async function (padID) { +exports.padUsers = async (padID) => { const padUsers = []; // iterate over all clients (in parallel) From acf889b7de88dca6d679e57e4bac04386c35c33b Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 021/153] lint: src/node/handler/SocketIORouter.js --- src/node/handler/SocketIORouter.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/node/handler/SocketIORouter.js b/src/node/handler/SocketIORouter.js index 56e5c5be4..42d710a39 100644 --- a/src/node/handler/SocketIORouter.js +++ b/src/node/handler/SocketIORouter.js @@ -1,3 +1,4 @@ +'use strict'; /** * This is the Socket.IO Router. It routes the Messages between the * components of the Server. The components are at the moment: pad and timeslider @@ -21,9 +22,6 @@ const log4js = require('log4js'); const messageLogger = log4js.getLogger('message'); -const securityManager = require('../db/SecurityManager'); -const readOnlyManager = require('../db/ReadOnlyManager'); -const settings = require('../utils/Settings'); /** * Saves all components @@ -37,7 +35,7 @@ let socket; /** * adds a component */ -exports.addComponent = function (moduleName, module) { +exports.addComponent = (moduleName, module) => { // save the component components[moduleName] = module; @@ -48,14 +46,14 @@ exports.addComponent = function (moduleName, module) { /** * sets the socket.io and adds event functions for routing */ -exports.setSocketIO = function (_socket) { +exports.setSocketIO = (_socket) => { // save this socket internaly socket = _socket; socket.sockets.on('connection', (client) => { // wrap the original send function to log the messages client._send = client.send; - client.send = function (message) { + client.send = (message) => { messageLogger.debug(`to ${client.id}: ${JSON.stringify(message)}`); client._send(message); }; @@ -66,7 +64,7 @@ exports.setSocketIO = function (_socket) { } client.on('message', async (message) => { - if (message.protocolVersion && message.protocolVersion != 2) { + if (message.protocolVersion && message.protocolVersion !== 2) { messageLogger.warn(`Protocolversion header is not correct: ${JSON.stringify(message)}`); return; } From 3a586a7aadd76e1a8ff55361e5bf3083ef13f0a7 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 022/153] lint: src/node/hooks/express/admin.js --- src/node/hooks/express/admin.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/node/hooks/express/admin.js b/src/node/hooks/express/admin.js index 417939600..763698332 100644 --- a/src/node/hooks/express/admin.js +++ b/src/node/hooks/express/admin.js @@ -1,8 +1,9 @@ -const eejs = require('ep_etherpad-lite/node/eejs'); +'use strict'; +const eejs = require('../../eejs'); -exports.expressCreateServer = function (hook_name, args, cb) { +exports.expressCreateServer = (hookName, args, cb) => { args.app.get('/admin', (req, res) => { - if ('/' != req.path[req.path.length - 1]) return res.redirect('./admin/'); + if ('/' !== req.path[req.path.length - 1]) return res.redirect('./admin/'); res.send(eejs.require('ep_etherpad-lite/templates/admin/index.html', {req})); }); return cb(); From fbc70c12768791c6a70a2589db4eccc1722d0a15 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 023/153] lint: src/node/hooks/express/adminplugins.js --- src/node/hooks/express/adminplugins.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/node/hooks/express/adminplugins.js b/src/node/hooks/express/adminplugins.js index 0a6d97808..e2129c116 100644 --- a/src/node/hooks/express/adminplugins.js +++ b/src/node/hooks/express/adminplugins.js @@ -4,7 +4,6 @@ const eejs = require('../../eejs'); const settings = require('../../utils/Settings'); const installer = require('../../../static/js/pluginfw/installer'); const plugins = require('../../../static/js/pluginfw/plugin_defs'); -const _ = require('underscore'); const semver = require('semver'); const UpdateCheck = require('../../utils/UpdateCheck'); @@ -51,7 +50,7 @@ exports.socketio = (hookName, args, cb) => { try { const results = await installer.getAvailablePlugins(/* maxCacheAge:*/ 60 * 10); - const updatable = _(plugins.plugins).keys().filter((plugin) => { + const updatable = Object.keys(plugins.plugins).filter((plugin) => { if (!results[plugin]) return false; const latestVersion = results[plugin].version; From 4de2844af2d38dcb30e2203806e92faf9c8dc007 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 024/153] lint: src/node/hooks/express/apicalls.js --- src/node/hooks/express/apicalls.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/node/hooks/express/apicalls.js b/src/node/hooks/express/apicalls.js index c87998e94..b72ed11e5 100644 --- a/src/node/hooks/express/apicalls.js +++ b/src/node/hooks/express/apicalls.js @@ -1,9 +1,11 @@ +'use strict'; + const log4js = require('log4js'); const clientLogger = log4js.getLogger('client'); const formidable = require('formidable'); const apiHandler = require('../../handler/APIHandler'); -exports.expressCreateServer = function (hook_name, args, cb) { +exports.expressCreateServer = (hookName, args, cb) => { // The Etherpad client side sends information about how a disconnect happened args.app.post('/ep/pad/connection-diagnostic-info', (req, res) => { new formidable.IncomingForm().parse(req, (err, fields, files) => { @@ -15,8 +17,9 @@ exports.expressCreateServer = function (hook_name, args, cb) { // The Etherpad client side sends information about client side javscript errors args.app.post('/jserror', (req, res) => { new formidable.IncomingForm().parse(req, (err, fields, files) => { + let data; try { - var data = JSON.parse(fields.errorInfo); + data = JSON.parse(fields.errorInfo); } catch (e) { return res.end(); } From 3cf6e1f015aad2e9104e8dc74d1d32fc9ca605b4 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 025/153] lint: src/node/hooks/express/errorhandling.js --- src/node/hooks/express/errorhandling.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/node/hooks/express/errorhandling.js b/src/node/hooks/express/errorhandling.js index 4a20b70d2..884ca9be0 100644 --- a/src/node/hooks/express/errorhandling.js +++ b/src/node/hooks/express/errorhandling.js @@ -1,6 +1,8 @@ -const stats = require('ep_etherpad-lite/node/stats'); +'use strict'; -exports.expressCreateServer = function (hook_name, args, cb) { +const stats = require('../../stats'); + +exports.expressCreateServer = (hook_name, args, cb) => { exports.app = args.app; // Handle errors From 3571eb7c3213b69ae4f0aa303eb68af191e82a21 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 026/153] lint: src/node/hooks/express/importexport.js --- src/node/hooks/express/importexport.js | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/node/hooks/express/importexport.js b/src/node/hooks/express/importexport.js index 7a6c38655..4dbe816f6 100644 --- a/src/node/hooks/express/importexport.js +++ b/src/node/hooks/express/importexport.js @@ -1,39 +1,43 @@ -const assert = require('assert').strict; +'use strict'; + const hasPadAccess = require('../../padaccess'); const settings = require('../../utils/Settings'); const exportHandler = require('../../handler/ExportHandler'); const importHandler = require('../../handler/ImportHandler'); const padManager = require('../../db/PadManager'); const readOnlyManager = require('../../db/ReadOnlyManager'); -const authorManager = require('../../db/AuthorManager'); const rateLimit = require('express-rate-limit'); const securityManager = require('../../db/SecurityManager'); const webaccess = require('./webaccess'); -settings.importExportRateLimiting.onLimitReached = function (req, res, options) { +settings.importExportRateLimiting.onLimitReached = (req, res, options) => { // when the rate limiter triggers, write a warning in the logs - console.warn(`Import/Export rate limiter triggered on "${req.originalUrl}" for IP address ${req.ip}`); + console.warn('Import/Export rate limiter triggered on ' + + `"${req.originalUrl}" for IP address ${req.ip}`); }; const limiter = rateLimit(settings.importExportRateLimiting); -exports.expressCreateServer = function (hook_name, args, cb) { +exports.expressCreateServer = (hookName, args, cb) => { // handle export requests args.app.use('/p/:pad/:rev?/export/:type', limiter); args.app.get('/p/:pad/:rev?/export/:type', async (req, res, next) => { const types = ['pdf', 'doc', 'txt', 'html', 'odt', 'etherpad']; // send a 404 if we don't support this filetype - if (types.indexOf(req.params.type) == -1) { + if (types.indexOf(req.params.type) === -1) { return next(); } // if abiword is disabled, and this is a format we only support with abiword, output a message - if (settings.exportAvailable() == 'no' && + if (settings.exportAvailable() === 'no' && ['odt', 'pdf', 'doc'].indexOf(req.params.type) !== -1) { - console.error(`Impossible to export pad "${req.params.pad}" in ${req.params.type} format. There is no converter configured`); + console.error(`Impossible to export pad "${req.params.pad}" in ${req.params.type} format.` + + ' There is no converter configured'); - // ACHTUNG: do not include req.params.type in res.send() because there is no HTML escaping and it would lead to an XSS - res.send('This export is not enabled at this Etherpad instance. Set the path to Abiword or soffice (LibreOffice) in settings.json to enable this feature'); + // ACHTUNG: do not include req.params.type in res.send() because there is + // no HTML escaping and it would lead to an XSS + res.send('This export is not enabled at this Etherpad instance. Set the path to Abiword' + + ' or soffice (LibreOffice) in settings.json to enable this feature'); return; } From 18ebf7b69afd8b56745efcc2571687c5cf782cc8 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 027/153] lint: src/node/hooks/express/isValidJSONPName.js --- src/node/hooks/express/isValidJSONPName.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/node/hooks/express/isValidJSONPName.js b/src/node/hooks/express/isValidJSONPName.js index 442c963e9..c8ca5bea1 100644 --- a/src/node/hooks/express/isValidJSONPName.js +++ b/src/node/hooks/express/isValidJSONPName.js @@ -1,3 +1,5 @@ +'use strict'; + const RESERVED_WORDS = [ 'abstract', 'arguments', @@ -65,9 +67,9 @@ const RESERVED_WORDS = [ 'yield', ]; -const regex = /^[a-zA-Z_$][0-9a-zA-Z_$]*(?:\[(?:".+"|\'.+\'|\d+)\])*?$/; +const regex = /^[a-zA-Z_$][0-9a-zA-Z_$]*(?:\[(?:".+"|'.+'|\d+)\])*?$/; -module.exports.check = function (inputStr) { +module.exports.check = (inputStr) => { let isValid = true; inputStr.split('.').forEach((part) => { if (!regex.test(part)) { From 2f9a3ec655c46f4aee0798d5f410f117398d43e8 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 028/153] lint: src/node/hooks/express/openapi.js --- src/node/hooks/express/openapi.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/node/hooks/express/openapi.js b/src/node/hooks/express/openapi.js index 8ea9529c7..344913389 100644 --- a/src/node/hooks/express/openapi.js +++ b/src/node/hooks/express/openapi.js @@ -1,3 +1,5 @@ +'use strict'; + /** * node/hooks/express/openapi.js * @@ -31,7 +33,9 @@ const OPENAPI_VERSION = '3.0.2'; // Swagger/OAS version const info = { title: 'Etherpad API', description: - 'Etherpad is a real-time collaborative editor scalable to thousands of simultaneous real time users. It provides full data export capabilities, and runs on your server, under your control.', + 'Etherpad is a real-time collaborative editor scalable to thousands of simultaneous ' + + 'real time users. It provides full data export capabilities, and runs on your server, ' + + 'under your control.', termsOfService: 'https://etherpad.org/', contact: { name: 'The Etherpad Foundation', @@ -80,7 +84,9 @@ const resources = { listSessions: { operationId: 'listSessionsOfGroup', summary: '', - responseSchema: {sessions: {type: 'array', items: {$ref: '#/components/schemas/SessionInfo'}}}, + responseSchema: { + sessions: {type: 'array', items: {$ref: '#/components/schemas/SessionInfo'}}, + }, }, list: { operationId: 'listAllGroups', @@ -109,7 +115,9 @@ const resources = { listSessions: { operationId: 'listSessionsOfAuthor', summary: 'returns all sessions of an author', - responseSchema: {sessions: {type: 'array', items: {$ref: '#/components/schemas/SessionInfo'}}}, + responseSchema: { + sessions: {type: 'array', items: {$ref: '#/components/schemas/SessionInfo'}}, + }, }, // We need an operation that return a UserInfo so it can be picked up by the codegen :( getName: { @@ -153,7 +161,8 @@ const resources = { create: { operationId: 'createPad', description: - 'creates a new (non-group) pad. Note that if you need to create a group Pad, you should call createGroupPad', + 'creates a new (non-group) pad. Note that if you need to create a group Pad, ' + + 'you should call createGroupPad', }, getText: { operationId: 'getText', @@ -607,7 +616,7 @@ exports.expressCreateServer = (hookName, args, cb) => { if (createHTTPError.isHttpError(err)) { // pass http errors thrown by handler forward throw err; - } else if (err.name == 'apierror') { + } else if (err.name === 'apierror') { // parameters were wrong and the api stopped execution, pass the error // convert to http error throw new createHTTPError.BadRequest(err.message); From 43ce0f839bdacb61b2ca096d46a3c0f0be039c51 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 029/153] lint: src/node/hooks/express/padreadonly.js --- src/node/hooks/express/padreadonly.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/node/hooks/express/padreadonly.js b/src/node/hooks/express/padreadonly.js index f17f7f0d6..4dda67b1f 100644 --- a/src/node/hooks/express/padreadonly.js +++ b/src/node/hooks/express/padreadonly.js @@ -1,8 +1,10 @@ +'use strict'; + const readOnlyManager = require('../../db/ReadOnlyManager'); const hasPadAccess = require('../../padaccess'); const exporthtml = require('../../utils/ExportHtml'); -exports.expressCreateServer = function (hook_name, args, cb) { +exports.expressCreateServer = (hookName, args, cb) => { // serve read only pad args.app.get('/ro/:id', async (req, res) => { // translate the read only pad to a padId From 72ddf35426b1bb855cdec97e2c4ed221fabd693b Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 030/153] lint: src/node/hooks/express/padurlsanitize.js --- src/node/hooks/express/padurlsanitize.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/node/hooks/express/padurlsanitize.js b/src/node/hooks/express/padurlsanitize.js index 8a287a961..c4c1b6751 100644 --- a/src/node/hooks/express/padurlsanitize.js +++ b/src/node/hooks/express/padurlsanitize.js @@ -1,7 +1,9 @@ +'use strict'; + const padManager = require('../../db/PadManager'); const url = require('url'); -exports.expressCreateServer = function (hook_name, args, cb) { +exports.expressCreateServer = (hookName, args, cb) => { // redirects browser to the pad's sanitized url if needed. otherwise, renders the html args.app.param('pad', async (req, res, next, padId) => { // ensure the padname is valid and the url doesn't end with a / @@ -17,12 +19,12 @@ exports.expressCreateServer = function (hook_name, args, cb) { next(); } else { // the pad id was sanitized, so we redirect to the sanitized version - let real_url = sanitizedPadId; - real_url = encodeURIComponent(real_url); + let realURL = sanitizedPadId; + realURL = encodeURIComponent(realURL); const query = url.parse(req.url).query; - if (query) real_url += `?${query}`; - res.header('Location', real_url); - res.status(302).send(`You should be redirected to ${real_url}`); + if (query) realURL += `?${query}`; + res.header('Location', realURL); + res.status(302).send(`You should be redirected to ${realURL}`); } }); return cb(); From 09fc7438ea626463dcddd0d154fde9a555e9a13e Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 031/153] lint: src/node/hooks/express/specialpages.js --- src/node/hooks/express/specialpages.js | 30 ++++++++++++++++++++------ 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/node/hooks/express/specialpages.js b/src/node/hooks/express/specialpages.js index f53ce1ac7..c11e374e9 100644 --- a/src/node/hooks/express/specialpages.js +++ b/src/node/hooks/express/specialpages.js @@ -1,14 +1,16 @@ +'use strict'; + const path = require('path'); -const eejs = require('ep_etherpad-lite/node/eejs'); -const toolbar = require('ep_etherpad-lite/node/utils/toolbar'); -const hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks'); +const eejs = require('../../eejs'); +const toolbar = require('../../utils/toolbar'); +const hooks = require('../../../static/js/pluginfw/hooks'); const settings = require('../../utils/Settings'); const webaccess = require('./webaccess'); -exports.expressCreateServer = function (hook_name, args, cb) { +exports.expressCreateServer = (hookName, args, cb) => { // expose current stats args.app.get('/stats', (req, res) => { - res.json(require('ep_etherpad-lite/node/stats').toJSON()); + res.json(require('../../stats').toJSON()); }); // serve index.html under / @@ -24,7 +26,14 @@ exports.expressCreateServer = function (hook_name, args, cb) { // serve robots.txt args.app.get('/robots.txt', (req, res) => { - let filePath = path.join(settings.root, 'src', 'static', 'skins', settings.skinName, 'robots.txt'); + let filePath = path.join( + settings.root, + 'src', + 'static', + 'skins', + settings.skinName, + 'robots.txt' + ); res.sendFile(filePath, (err) => { // there is no custom robots.txt, send the default robots.txt which dissallows all if (err) { @@ -66,7 +75,14 @@ exports.expressCreateServer = function (hook_name, args, cb) { // serve favicon.ico from all path levels except as a pad name args.app.get(/\/favicon.ico$/, (req, res) => { - let filePath = path.join(settings.root, 'src', 'static', 'skins', settings.skinName, 'favicon.ico'); + let filePath = path.join( + settings.root, + 'src', + 'static', + 'skins', + settings.skinName, + 'favicon.ico' + ); res.sendFile(filePath, (err) => { // there is no custom favicon, send the default favicon From 6df3eadecd12e81bceb799eb7fd17c705bc0ed4c Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 032/153] lint: src/node/hooks/express/static.js --- src/node/hooks/express/static.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/node/hooks/express/static.js b/src/node/hooks/express/static.js index 2df757e64..950fe3f78 100644 --- a/src/node/hooks/express/static.js +++ b/src/node/hooks/express/static.js @@ -1,11 +1,12 @@ +'use strict'; + const minify = require('../../utils/Minify'); -const plugins = require('ep_etherpad-lite/static/js/pluginfw/plugin_defs'); +const plugins = require('../../../static/js/pluginfw/plugin_defs'); const CachingMiddleware = require('../../utils/caching_middleware'); -const settings = require('../../utils/Settings'); const Yajsml = require('etherpad-yajsml'); const _ = require('underscore'); -exports.expressCreateServer = function (hook_name, args, cb) { +exports.expressCreateServer = (hookName, args, cb) => { // Cache both minified and static. const assetCache = new CachingMiddleware(); args.app.all(/\/javascripts\/(.*)/, assetCache.handle); @@ -34,7 +35,8 @@ exports.expressCreateServer = function (hook_name, args, cb) { args.app.use(jsServer.handle.bind(jsServer)); // serve plugin definitions - // not very static, but served here so that client can do require("pluginfw/static/js/plugin-definitions.js"); + // not very static, but served here so that client can do + // require("pluginfw/static/js/plugin-definitions.js"); args.app.get('/pluginfw/plugin-definitions.json', (req, res, next) => { const clientParts = _(plugins.parts) .filter((part) => _(part).has('client_hooks')); From 2dec36bfd7254d86a3a4f7f343d417f1fcd07021 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 033/153] lint: src/node/hooks/express/tests.js --- src/node/hooks/express/tests.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/node/hooks/express/tests.js b/src/node/hooks/express/tests.js index 87edc2a09..641ca819a 100644 --- a/src/node/hooks/express/tests.js +++ b/src/node/hooks/express/tests.js @@ -1,9 +1,11 @@ +'use strict'; + const path = require('path'); const npm = require('npm'); const fs = require('fs'); const util = require('util'); -exports.expressCreateServer = function (hook_name, args, cb) { +exports.expressCreateServer = (hookName, args, cb) => { args.app.get('/tests/frontend/specs_list.js', async (req, res) => { const [coreTests, pluginTests] = await Promise.all([ exports.getCoreTests(), @@ -24,9 +26,9 @@ exports.expressCreateServer = function (hook_name, args, cb) { // path.join seems to normalize by default, but we'll just be explicit const rootTestFolder = path.normalize(path.join(npm.root, '../tests/frontend/')); - const url2FilePath = function (url) { + const url2FilePath = (url) => { let subPath = url.substr('/tests/frontend'.length); - if (subPath == '') { + if (subPath === '') { subPath = 'index.html'; } subPath = subPath.split('?')[0]; @@ -49,8 +51,9 @@ exports.expressCreateServer = function (hook_name, args, cb) { content = `describe(${JSON.stringify(specFileName)}, function(){ ${content} });`; - if(!specFilePath.endsWith('index.html')) res.setHeader('content-type', 'application/javascript'); - + if (!specFilePath.endsWith('index.html')) { + res.setHeader('content-type', 'application/javascript'); + } res.send(content); }); }); @@ -69,7 +72,7 @@ exports.expressCreateServer = function (hook_name, args, cb) { const readdir = util.promisify(fs.readdir); -exports.getPluginTests = async function (callback) { +exports.getPluginTests = async (callback) => { const moduleDir = 'node_modules/'; const specPath = '/static/tests/frontend/specs/'; const staticDir = '/static/plugins/'; @@ -88,7 +91,4 @@ exports.getPluginTests = async function (callback) { return Promise.all(promises).then(() => pluginSpecs); }; -exports.getCoreTests = function () { - // get the core test specs - return readdir('tests/frontend/specs'); -}; +exports.getCoreTests = () => readdir('tests/frontend/specs'); From 6054f6d93f7a902ba7027d7c913ecc25d3a9e05d Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 034/153] lint: src/node/hooks/i18n.js --- src/node/hooks/i18n.js | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/node/hooks/i18n.js b/src/node/hooks/i18n.js index 610c3f68f..5b4b0ec12 100644 --- a/src/node/hooks/i18n.js +++ b/src/node/hooks/i18n.js @@ -1,24 +1,23 @@ +'use strict'; + const languages = require('languages4translatewiki'); const fs = require('fs'); const path = require('path'); const _ = require('underscore'); const npm = require('npm'); -const plugins = require('ep_etherpad-lite/static/js/pluginfw/plugin_defs.js').plugins; -const semver = require('semver'); +const plugins = require('../../static/js/pluginfw/plugin_defs.js').plugins; const existsSync = require('../utils/path_exists'); -const settings = require('../utils/Settings') -; - +const settings = require('../utils/Settings'); // returns all existing messages merged together and grouped by langcode // {es: {"foo": "string"}, en:...} -function getAllLocales() { +const getAllLocales = () => { const locales2paths = {}; // Puts the paths of all locale files contained in a given directory // into `locales2paths` (files from various dirs are grouped by lang code) // (only json files with valid language code as name) - function extractLangs(dir) { + const extractLangs = (dir) => { if (!existsSync(dir)) return; let stat = fs.lstatSync(dir); if (!stat.isDirectory() || stat.isSymbolicLink()) return; @@ -31,12 +30,12 @@ function getAllLocales() { const ext = path.extname(file); const locale = path.basename(file, ext).toLowerCase(); - if ((ext == '.json') && languages.isValid(locale)) { + if ((ext === '.json') && languages.isValid(locale)) { if (!locales2paths[locale]) locales2paths[locale] = []; locales2paths[locale].push(file); } }); - } + }; // add core supported languages first extractLangs(`${npm.root}/ep_etherpad-lite/locales`); @@ -78,29 +77,29 @@ function getAllLocales() { } return locales; -} +}; // returns a hash of all available languages availables with nativeName and direction // e.g. { es: {nativeName: "español", direction: "ltr"}, ... } -function getAvailableLangs(locales) { +const getAvailableLangs = (locales) => { const result = {}; _.each(_.keys(locales), (langcode) => { result[langcode] = languages.getLanguageInfo(langcode); }); return result; -} +}; // returns locale index that will be served in /locales.json -const generateLocaleIndex = function (locales) { +const generateLocaleIndex = (locales) => { const result = _.clone(locales); // keep English strings _.each(_.keys(locales), (langcode) => { - if (langcode != 'en') result[langcode] = `locales/${langcode}.json`; + if (langcode !== 'en') result[langcode] = `locales/${langcode}.json`; }); return JSON.stringify(result); }; -exports.expressCreateServer = function (n, args, cb) { +exports.expressCreateServer = (n, args, cb) => { // regenerate locales on server restart const locales = getAllLocales(); const localeIndex = generateLocaleIndex(locales); From 666dd7abd182f5586f89bdbe4e6d62058b5ccd63 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 035/153] lint: src/node/padaccess.js --- src/node/padaccess.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/node/padaccess.js b/src/node/padaccess.js index 617056a97..241302852 100644 --- a/src/node/padaccess.js +++ b/src/node/padaccess.js @@ -1,3 +1,4 @@ +'use strict'; const securityManager = require('./db/SecurityManager'); // checks for padAccess From 7afc809073df00d74fd108e14a445b2a751358d2 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 036/153] lint: src/node/utils/Abiword.js --- src/node/utils/Abiword.js | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/node/utils/Abiword.js b/src/node/utils/Abiword.js index b75487d75..b93646cd5 100644 --- a/src/node/utils/Abiword.js +++ b/src/node/utils/Abiword.js @@ -1,3 +1,4 @@ +'use strict'; /** * Controls the communication with the Abiword application */ @@ -25,11 +26,12 @@ const os = require('os'); let doConvertTask; -// on windows we have to spawn a process for each convertion, cause the plugin abicommand doesn't exist on this platform +// on windows we have to spawn a process for each convertion, +// cause the plugin abicommand doesn't exist on this platform if (os.type().indexOf('Windows') > -1) { let stdoutBuffer = ''; - doConvertTask = function (task, callback) { + doConvertTask = (task, callback) => { // span an abiword process to perform the conversion const abiword = spawn(settings.abiword, [`--to=${task.destFile}`, task.srcFile]); @@ -46,11 +48,11 @@ if (os.type().indexOf('Windows') > -1) { // throw exceptions if abiword is dieing abiword.on('exit', (code) => { - if (code != 0) { + if (code !== 0) { return callback(`Abiword died with exit code ${code}`); } - if (stdoutBuffer != '') { + if (stdoutBuffer !== '') { console.log(stdoutBuffer); } @@ -58,17 +60,17 @@ if (os.type().indexOf('Windows') > -1) { }); }; - exports.convertFile = function (srcFile, destFile, type, callback) { + exports.convertFile = (srcFile, destFile, type, callback) => { doConvertTask({srcFile, destFile, type}, callback); }; -} -// on unix operating systems, we can start abiword with abicommand and communicate with it via stdin/stdout -// thats much faster, about factor 10 -else { + // on unix operating systems, we can start abiword with abicommand and + // communicate with it via stdin/stdout + // thats much faster, about factor 10 +} else { // spawn the abiword process let abiword; let stdoutCallback = null; - var spawnAbiword = function () { + const spawnAbiword = () => { abiword = spawn(settings.abiword, ['--plugin', 'AbiCommand']); let stdoutBuffer = ''; let firstPrompt = true; @@ -90,9 +92,9 @@ else { stdoutBuffer += data.toString(); // we're searching for the prompt, cause this means everything we need is in the buffer - if (stdoutBuffer.search('AbiWord:>') != -1) { + if (stdoutBuffer.search('AbiWord:>') !== -1) { // filter the feedback message - const err = stdoutBuffer.search('OK') != -1 ? null : stdoutBuffer; + const err = stdoutBuffer.search('OK') !== -1 ? null : stdoutBuffer; // reset the buffer stdoutBuffer = ''; @@ -110,10 +112,10 @@ else { }; spawnAbiword(); - doConvertTask = function (task, callback) { + doConvertTask = (task, callback) => { abiword.stdin.write(`convert ${task.srcFile} ${task.destFile} ${task.type}\n`); // create a callback that calls the task callback and the caller callback - stdoutCallback = function (err) { + stdoutCallback = (err) => { callback(); console.log('queue continue'); try { @@ -126,7 +128,7 @@ else { // Queue with the converts we have to do const queue = async.queue(doConvertTask, 1); - exports.convertFile = function (srcFile, destFile, type, callback) { + exports.convertFile = (srcFile, destFile, type, callback) => { queue.push({srcFile, destFile, type, callback}); }; } From 60bc849be2788230757c6c5cb9dcfdb5e1106d15 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 037/153] lint: src/node/utils/AbsolutePaths.js --- src/node/utils/AbsolutePaths.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/node/utils/AbsolutePaths.js b/src/node/utils/AbsolutePaths.js index 22294cfe2..5b364ed80 100644 --- a/src/node/utils/AbsolutePaths.js +++ b/src/node/utils/AbsolutePaths.js @@ -1,3 +1,4 @@ +'use strict'; /** * Library for deterministic relative filename expansion for Etherpad. */ @@ -40,7 +41,7 @@ let etherpadRoot = null; * @return {string[]|boolean} The shortened array, or false if there was no * overlap. */ -const popIfEndsWith = function (stringArray, lastDesiredElements) { +const popIfEndsWith = (stringArray, lastDesiredElements) => { if (stringArray.length <= lastDesiredElements.length) { absPathLogger.debug(`In order to pop "${lastDesiredElements.join(path.sep)}" from "${stringArray.join(path.sep)}", it should contain at least ${lastDesiredElements.length + 1} elements`); @@ -72,8 +73,8 @@ const popIfEndsWith = function (stringArray, lastDesiredElements) { * @return {string} The identified absolute base path. If such path cannot be * identified, prints a log and exits the application. */ -exports.findEtherpadRoot = function () { - if (etherpadRoot !== null) { +exports.findEtherpadRoot = () => { + if (etherpadRoot != null) { return etherpadRoot; } @@ -126,7 +127,7 @@ exports.findEtherpadRoot = function () { * it is returned unchanged. Otherwise it is interpreted * relative to exports.root. */ -exports.makeAbsolute = function (somePath) { +exports.makeAbsolute = (somePath) => { if (path.isAbsolute(somePath)) { return somePath; } @@ -145,7 +146,7 @@ exports.makeAbsolute = function (somePath) { * a subdirectory of the base one * @return {boolean} */ -exports.isSubdir = function (parent, arbitraryDir) { +exports.isSubdir = (parent, arbitraryDir) => { // modified from: https://stackoverflow.com/questions/37521893/determine-if-a-path-is-subdirectory-of-another-in-node-js#45242825 const relative = path.relative(parent, arbitraryDir); const isSubdir = !!relative && !relative.startsWith('..') && !path.isAbsolute(relative); From 52f60ceeaabd58b463715d8887e5a050a495b51f Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 038/153] lint: src/node/utils/Cli.js --- src/node/utils/Cli.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/node/utils/Cli.js b/src/node/utils/Cli.js index 6297a4f8c..a5cdee83a 100644 --- a/src/node/utils/Cli.js +++ b/src/node/utils/Cli.js @@ -1,3 +1,4 @@ +'use strict'; /** * The CLI module handles command line parameters */ @@ -30,22 +31,22 @@ for (let i = 0; i < argv.length; i++) { arg = argv[i]; // Override location of settings.json file - if (prevArg == '--settings' || prevArg == '-s') { + if (prevArg === '--settings' || prevArg === '-s') { exports.argv.settings = arg; } // Override location of credentials.json file - if (prevArg == '--credentials') { + if (prevArg === '--credentials') { exports.argv.credentials = arg; } // Override location of settings.json file - if (prevArg == '--sessionkey') { + if (prevArg === '--sessionkey') { exports.argv.sessionkey = arg; } // Override location of settings.json file - if (prevArg == '--apikey') { + if (prevArg === '--apikey') { exports.argv.apikey = arg; } From a4764fadeda1344572740aec74d621a9046751b8 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 039/153] lint: src/node/utils/ExportEtherpad.js --- src/node/utils/ExportEtherpad.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/node/utils/ExportEtherpad.js b/src/node/utils/ExportEtherpad.js index ace298ab7..48c850af9 100644 --- a/src/node/utils/ExportEtherpad.js +++ b/src/node/utils/ExportEtherpad.js @@ -1,3 +1,4 @@ +'use strict'; /** * 2014 John McLear (Etherpad Foundation / McLear Ltd) * @@ -16,9 +17,9 @@ const db = require('../db/DB'); -const hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks'); +const hooks = require('../../static/js/pluginfw/hooks'); -exports.getPadRaw = async function (padId) { +exports.getPadRaw = async (padId) => { const padKey = `pad:${padId}`; const padcontent = await db.get(padKey); From c44c4edc1081e583999309ac5ddb112d0d67c883 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 040/153] lint: src/node/utils/ExportHelper.js --- src/node/utils/ExportHelper.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/node/utils/ExportHelper.js b/src/node/utils/ExportHelper.js index e498d4c42..0c593eca1 100644 --- a/src/node/utils/ExportHelper.js +++ b/src/node/utils/ExportHelper.js @@ -1,3 +1,4 @@ +'use strict'; /** * Helpers for export requests */ @@ -18,9 +19,9 @@ * limitations under the License. */ -const Changeset = require('ep_etherpad-lite/static/js/Changeset'); +const Changeset = require('../../static/js/Changeset'); -exports.getPadPlainText = function (pad, revNum) { +exports.getPadPlainText = (pad, revNum) => { const _analyzeLine = exports._analyzeLine; const atext = ((revNum !== undefined) ? pad.getInternalRevisionAText(revNum) : pad.atext); const textLines = atext.text.slice(0, -1).split('\n'); @@ -43,7 +44,7 @@ exports.getPadPlainText = function (pad, revNum) { }; -exports._analyzeLine = function (text, aline, apool) { +exports._analyzeLine = (text, aline, apool) => { const line = {}; // identify list @@ -81,6 +82,5 @@ exports._analyzeLine = function (text, aline, apool) { }; -exports._encodeWhitespace = function (s) { - return s.replace(/[^\x21-\x7E\s\t\n\r]/gu, (c) => `&#${c.codePointAt(0)};`); -}; +exports._encodeWhitespace = + (s) => s.replace(/[^\x21-\x7E\s\t\n\r]/gu, (c) => `&#${c.codePointAt(0)};`); From bfabe7c297997107e2ed36c4f050a60d059e2491 Mon Sep 17 00:00:00 2001 From: John McLear Date: Thu, 21 Jan 2021 21:06:52 +0000 Subject: [PATCH 041/153] lint: src/node/utils/ExportHtml.js --- src/node/utils/ExportHtml.js | 169 ++++++++++++++++++++--------------- 1 file changed, 96 insertions(+), 73 deletions(-) diff --git a/src/node/utils/ExportHtml.js b/src/node/utils/ExportHtml.js index 2f5a77c9a..999b22639 100644 --- a/src/node/utils/ExportHtml.js +++ b/src/node/utils/ExportHtml.js @@ -1,3 +1,4 @@ +'use strict'; /** * Copyright 2009 Google Inc. * @@ -14,32 +15,29 @@ * limitations under the License. */ -const Changeset = require('ep_etherpad-lite/static/js/Changeset'); +const Changeset = require('../../static/js/Changeset'); const padManager = require('../db/PadManager'); const _ = require('underscore'); -const Security = require('ep_etherpad-lite/static/js/security'); -const hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks'); -const eejs = require('ep_etherpad-lite/node/eejs'); +const Security = require('../../static/js/security'); +const hooks = require('../../static/js/pluginfw/hooks'); +const eejs = require('../eejs'); const _analyzeLine = require('./ExportHelper')._analyzeLine; const _encodeWhitespace = require('./ExportHelper')._encodeWhitespace; const padutils = require('../../static/js/pad_utils').padutils; -async function getPadHTML(pad, revNum) { +const getPadHTML = async (pad, revNum) => { let atext = pad.atext; // fetch revision atext - if (revNum != undefined) { + if (revNum !== undefined) { atext = await pad.getInternalRevisionAText(revNum); } // convert atext to html return await getHTMLFromAtext(pad, atext); -} +}; -exports.getPadHTML = getPadHTML; -exports.getHTMLFromAtext = getHTMLFromAtext; - -async function getHTMLFromAtext(pad, atext, authorColors) { +const getHTMLFromAtext = async (pad, atext, authorColors) => { const apool = pad.apool(); const textLines = atext.text.slice(0, -1).split('\n'); const attribLines = Changeset.splitAttributionLines(atext.attribs, atext.text); @@ -72,9 +70,7 @@ async function getHTMLFromAtext(pad, atext, authorColors) { const anumMap = {}; let css = ''; - const stripDotFromAuthorID = function (id) { - return id.replace(/\./g, '_'); - }; + const stripDotFromAuthorID = (id) => id.replace(/\./g, '_'); if (authorColors) { css += 'empty
', - expectedHTML: 'empty

', - expectedText: 'empty\n\n', + wantHTML: 'empty

', + wantText: 'empty\n\n', }, 'indentedListsAreNotBullets': { description: 'Indented lists are represented with tabs and without bullets', input: '
  • indent
  • indent
', - expectedHTML: '
  • indent
  • indent

', - expectedText: '\tindent\n\tindent\n\n', + wantHTML: '
  • indent
  • indent

', + wantText: '\tindent\n\tindent\n\n', }, 'lineWithMultipleSpaces': { description: 'Multiple spaces should be collapsed', input: 'Text with more than one space.
', - expectedHTML: 'Text with more than one space.

', - expectedText: 'Text with more than one space.\n\n', + wantHTML: 'Text with more than one space.

', + wantText: 'Text with more than one space.\n\n', }, 'lineWithMultipleNonBreakingAndNormalSpaces': { // XXX the HTML between "than" and "one" looks strange description: 'non-breaking space should be preserved, but can be replaced when it', input: 'Text with  more   than  one space.
', - expectedHTML: 'Text with  more   than  one space.

', - expectedText: 'Text with more than one space.\n\n', + wantHTML: 'Text with  more   than  one space.

', + wantText: 'Text with more than one space.\n\n', }, 'multiplenbsp': { description: 'Multiple non-breaking space should be preserved', input: '  
', - expectedHTML: '  

', - expectedText: ' \n\n', + wantHTML: '  

', + wantText: ' \n\n', }, 'multipleNonBreakingSpaceBetweenWords': { description: 'A normal space is always inserted before a word', input: '  word1  word2   word3
', - expectedHTML: '  word1  word2   word3

', - expectedText: ' word1 word2 word3\n\n', + wantHTML: '  word1  word2   word3

', + wantText: ' word1 word2 word3\n\n', }, 'nonBreakingSpacePreceededBySpaceBetweenWords': { description: 'A non-breaking space preceeded by a normal space', input: '  word1  word2  word3
', - expectedHTML: ' word1  word2  word3

', - expectedText: ' word1 word2 word3\n\n', + wantHTML: ' word1  word2  word3

', + wantText: ' word1 word2 word3\n\n', }, 'nonBreakingSpaceFollowededBySpaceBetweenWords': { description: 'A non-breaking space followed by a normal space', input: '  word1  word2  word3
', - expectedHTML: '  word1  word2  word3

', - expectedText: ' word1 word2 word3\n\n', + wantHTML: '  word1  word2  word3

', + wantText: ' word1 word2 word3\n\n', }, 'spacesAfterNewline': { description: 'Collapse spaces that follow a newline', input: 'something
something
', - expectedHTML: 'something
something

', - expectedText: 'something\nsomething\n\n', + wantHTML: 'something
something

', + wantText: 'something\nsomething\n\n', }, 'spacesAfterNewlineP': { description: 'Collapse spaces that follow a paragraph', input: 'something

something
', - expectedHTML: 'something

something

', - expectedText: 'something\n\nsomething\n\n', + wantHTML: 'something

something

', + wantText: 'something\n\nsomething\n\n', }, 'spacesAtEndOfLine': { description: 'Collapse spaces that preceed/follow a newline', input: 'something
something
', - expectedHTML: 'something
something

', - expectedText: 'something\nsomething\n\n', + wantHTML: 'something
something

', + wantText: 'something\nsomething\n\n', }, 'spacesAtEndOfLineP': { description: 'Collapse spaces that preceed/follow a paragraph', input: 'something

something
', - expectedHTML: 'something

something

', - expectedText: 'something\n\nsomething\n\n', + wantHTML: 'something

something

', + wantText: 'something\n\nsomething\n\n', }, 'nonBreakingSpacesAfterNewlines': { description: 'Don\'t collapse non-breaking spaces that follow a newline', input: 'something
   something
', - expectedHTML: 'something
   something

', - expectedText: 'something\n something\n\n', + wantHTML: 'something
   something

', + wantText: 'something\n something\n\n', }, 'nonBreakingSpacesAfterNewlinesP': { description: 'Don\'t collapse non-breaking spaces that follow a paragraph', input: 'something

   something
', - expectedHTML: 'something

   something

', - expectedText: 'something\n\n something\n\n', + wantHTML: 'something

   something

', + wantText: 'something\n\n something\n\n', }, 'collapseSpacesInsideElements': { description: 'Preserve only one space when multiple are present', input: 'Need more space s !
', - expectedHTML: 'Need more space s !

', - expectedText: 'Need more space s !\n\n', + wantHTML: 'Need more space s !

', + wantText: 'Need more space s !\n\n', }, 'collapseSpacesAcrossNewlines': { description: 'Newlines and multiple spaces across newlines should be collapsed', @@ -155,14 +155,14 @@ const testImports = { space s !
`, - expectedHTML: 'Need more space s !

', - expectedText: 'Need more space s !\n\n', + wantHTML: 'Need more space s !

', + wantText: 'Need more space s !\n\n', }, 'multipleNewLinesAtBeginning': { description: 'Multiple new lines and paragraphs at the beginning should be preserved', input: '

first line

second line
', - expectedHTML: '



first line

second line

', - expectedText: '\n\n\n\nfirst line\n\nsecond line\n\n', + wantHTML: '



first line

second line

', + wantText: '\n\n\n\nfirst line\n\nsecond line\n\n', }, 'multiLineParagraph': { description: 'A paragraph with multiple lines should not loose spaces when lines are combined', @@ -172,8 +172,8 @@ const testImports = { п р с т у ф х ц ч ш щ ю я ь

`, - expectedHTML: 'а б в г ґ д е є ж з и і ї й к л м н о п р с т у ф х ц ч ш щ ю я ь

', - expectedText: 'а б в г ґ д е є ж з и і ї й к л м н о п р с т у ф х ц ч ш щ ю я ь\n\n', + wantHTML: 'а б в г ґ д е є ж з и і ї й к л м н о п р с т у ф х ц ч ш щ ю я ь

', + wantText: 'а б в г ґ д е є ж з и і ї й к л м н о п р с т у ф х ц ч ш щ ю я ь\n\n', }, 'multiLineParagraphWithPre': { // XXX why is there   before "in"? @@ -187,8 +187,8 @@ const testImports = {

п р с т у ф х ц ч ш щ ю я ь

`, - expectedHTML: 'а б в г ґ д е є ж з и і ї й к л м н о
multiple
   lines
 in
      pre

п р с т у ф х ц ч ш щ ю я ь

', - expectedText: 'а б в г ґ д е є ж з и і ї й к л м н о\nmultiple\n lines\n in\n pre\n\nп р с т у ф х ц ч ш щ ю я ь\n\n', + wantHTML: 'а б в г ґ д е є ж з и і ї й к л м н о
multiple
   lines
 in
      pre

п р с т у ф х ц ч ш щ ю я ь

', + wantText: 'а б в г ґ д е є ж з и і ї й к л м н о\nmultiple\n lines\n in\n pre\n\nп р с т у ф х ц ч ш щ ю я ь\n\n', }, 'preIntroducesASpace': { description: 'pre should be on a new line not preceeded by a space', @@ -196,32 +196,32 @@ const testImports = { 1
preline
 

`, - expectedHTML: '1
preline


', - expectedText: '1\npreline\n\n\n', + wantHTML: '1
preline


', + wantText: '1\npreline\n\n\n', }, 'dontDeleteSpaceInsideElements': { description: 'Preserve spaces inside elements', input: 'Need more space s !
', - expectedHTML: 'Need more space s !

', - expectedText: 'Need more space s !\n\n', + wantHTML: 'Need more space s !

', + wantText: 'Need more space s !\n\n', }, 'dontDeleteSpaceOutsideElements': { description: 'Preserve spaces outside elements', input: 'Need more space s !
', - expectedHTML: 'Need more space s !

', - expectedText: 'Need more space s !\n\n', + wantHTML: 'Need more space s !

', + wantText: 'Need more space s !\n\n', }, 'dontDeleteSpaceAtEndOfElement': { description: 'Preserve spaces at the end of an element', input: 'Need more space s !
', - expectedHTML: 'Need more space s !

', - expectedText: 'Need more space s !\n\n', + wantHTML: 'Need more space s !

', + wantText: 'Need more space s !\n\n', }, 'dontDeleteSpaceAtBeginOfElements': { description: 'Preserve spaces at the start of an element', input: 'Need more space s !
', - expectedHTML: 'Need more space s !

', - expectedText: 'Need more space s !\n\n', + wantHTML: 'Need more space s !

', + wantText: 'Need more space s !\n\n', }, }; @@ -256,17 +256,17 @@ describe(__filename, function () { it('getHTML', function (done) { api.get(`${endPoint('getHTML')}&padID=${testPadId}`) .expect((res) => { - const receivedHtml = res.body.data.html; - if (receivedHtml !== test.expectedHTML) { + const gotHtml = res.body.data.html; + if (gotHtml !== test.wantHTML) { throw new Error(`HTML received from export is not the one we were expecting. Test Name: ${testName} - Received: - ${JSON.stringify(receivedHtml)} + Got: + ${JSON.stringify(gotHtml)} - Expected: - ${JSON.stringify(test.expectedHTML)} + Want: + ${JSON.stringify(test.wantHTML)} Which is a different version of the originally imported one: ${test.input}`); @@ -279,17 +279,17 @@ describe(__filename, function () { it('getText', function (done) { api.get(`${endPoint('getText')}&padID=${testPadId}`) .expect((res) => { - const receivedText = res.body.data.text; - if (receivedText !== test.expectedText) { + const gotText = res.body.data.text; + if (gotText !== test.wantText) { throw new Error(`Text received from export is not the one we were expecting. Test Name: ${testName} - Received: - ${JSON.stringify(receivedText)} + Got: + ${JSON.stringify(gotText)} - Expected: - ${JSON.stringify(test.expectedText)} + Want: + ${JSON.stringify(test.wantText)} Which is a different version of the originally imported one: ${test.input}`); diff --git a/tests/backend/specs/contentcollector.js b/tests/backend/specs/contentcollector.js index 7014cac2a..c9ebb7482 100644 --- a/tests/backend/specs/contentcollector.js +++ b/tests/backend/specs/contentcollector.js @@ -18,17 +18,17 @@ const tests = { nestedLi: { description: 'Complex nested Li', html: '
  1. one
    1. 1.1
  2. two
', - expectedLineAttribs: [ + wantLineAttribs: [ '*0*1*2*3+1+3', '*0*4*2*5+1+3', '*0*1*2*5+1+3', ], - expectedText: [ + wantText: [ '*one', '*1.1', '*two', ], }, complexNest: { description: 'Complex list of different types', html: '
  • one
  • two
  • 0
  • 1
  • 2
    • 3
    • 4
  1. item
    1. item1
    2. item2
', - expectedLineAttribs: [ + wantLineAttribs: [ '*0*1*2+1+3', '*0*1*2+1+3', '*0*1*2+1+1', @@ -40,7 +40,7 @@ const tests = { '*0*6*2*7+1+5', '*0*6*2*7+1+5', ], - expectedText: [ + wantText: [ '*one', '*two', '*0', @@ -56,142 +56,142 @@ const tests = { ul: { description: 'Tests if uls properly get attributes', html: '
  • a
  • b
div

foo

', - expectedLineAttribs: ['*0*1*2+1+1', '*0*1*2+1+1', '+3', '+3'], - expectedText: ['*a', '*b', 'div', 'foo'], + wantLineAttribs: ['*0*1*2+1+1', '*0*1*2+1+1', '+3', '+3'], + wantText: ['*a', '*b', 'div', 'foo'], }, ulIndented: { description: 'Tests if indented uls properly get attributes', html: '
  • a
    • b
  • a

foo

', - expectedLineAttribs: ['*0*1*2+1+1', '*0*3*2+1+1', '*0*1*2+1+1', '+3'], - expectedText: ['*a', '*b', '*a', 'foo'], + wantLineAttribs: ['*0*1*2+1+1', '*0*3*2+1+1', '*0*1*2+1+1', '+3'], + wantText: ['*a', '*b', '*a', 'foo'], }, ol: { description: 'Tests if ols properly get line numbers when in a normal OL', html: '
  1. a
  2. b
  3. c

test

', - expectedLineAttribs: ['*0*1*2*3+1+1', '*0*1*2*3+1+1', '*0*1*2*3+1+1', '+4'], - expectedText: ['*a', '*b', '*c', 'test'], + wantLineAttribs: ['*0*1*2*3+1+1', '*0*1*2*3+1+1', '*0*1*2*3+1+1', '+4'], + wantText: ['*a', '*b', '*c', 'test'], noteToSelf: 'Ensure empty P does not induce line attribute marker, wont this break the editor?', }, lineDoBreakInOl: { description: 'A single completely empty line break within an ol should reset count if OL is closed off..', html: '
  1. should be 1

hello

  1. should be 1
  2. should be 2

', - expectedLineAttribs: ['*0*1*2*3+1+b', '+5', '*0*1*2*4+1+b', '*0*1*2*4+1+b', ''], - expectedText: ['*should be 1', 'hello', '*should be 1', '*should be 2', ''], + wantLineAttribs: ['*0*1*2*3+1+b', '+5', '*0*1*2*4+1+b', '*0*1*2*4+1+b', ''], + wantText: ['*should be 1', 'hello', '*should be 1', '*should be 2', ''], noteToSelf: "Shouldn't include attribute marker in the

line", }, testP: { description: 'A single

should create a new line', html: '

', - expectedLineAttribs: ['', ''], - expectedText: ['', ''], + wantLineAttribs: ['', ''], + wantText: ['', ''], noteToSelf: '

should create a line break but not break numbering', }, nestedOl: { description: 'Tests if ols properly get line numbers when in a normal OL', html: 'a
  1. b
    1. c
notlist

foo

', - expectedLineAttribs: ['+1', '*0*1*2*3+1+1', '*0*4*2*5+1+1', '+7', '+3'], - expectedText: ['a', '*b', '*c', 'notlist', 'foo'], + wantLineAttribs: ['+1', '*0*1*2*3+1+1', '*0*4*2*5+1+1', '+7', '+3'], + wantText: ['a', '*b', '*c', 'notlist', 'foo'], noteToSelf: 'Ensure empty P does not induce line attribute marker, wont this break the editor?', }, nestedOl2: { description: 'First item being an UL then subsequent being OL will fail', html: '
  • a
    1. b
    2. c
', - expectedLineAttribs: ['+1', '*0*1*2*3+1+1', '*0*4*2*5+1+1'], - expectedText: ['a', '*b', '*c'], + wantLineAttribs: ['+1', '*0*1*2*3+1+1', '*0*4*2*5+1+1'], + wantText: ['a', '*b', '*c'], noteToSelf: 'Ensure empty P does not induce line attribute marker, wont this break the editor?', disabled: true, }, lineDontBreakOL: { description: 'A single completely empty line break within an ol should NOT reset count', html: '
  1. should be 1
  2. should be 2
  3. should be 3

', - expectedLineAttribs: [], - expectedText: ['*should be 1', '*should be 2', '*should be 3'], + wantLineAttribs: [], + wantText: ['*should be 1', '*should be 2', '*should be 3'], noteToSelf: "

should create a line break but not break numbering -- This is what I can't get working!", disabled: true, }, ignoreAnyTagsOutsideBody: { description: 'Content outside body should be ignored', html: 'titleempty
', - expectedLineAttribs: ['+5'], - expectedText: ['empty'], + wantLineAttribs: ['+5'], + wantText: ['empty'], }, lineWithMultipleSpaces: { description: 'Multiple spaces should be preserved', html: 'Text with more than one space.
', - expectedLineAttribs: ['+10'], - expectedText: ['Text with more than one space.'], + wantLineAttribs: ['+10'], + wantText: ['Text with more than one space.'], }, lineWithMultipleNonBreakingAndNormalSpaces: { description: 'non-breaking and normal space should be preserved', html: 'Text with  more   than  one space.
', - expectedLineAttribs: ['+10'], - expectedText: ['Text with more than one space.'], + wantLineAttribs: ['+10'], + wantText: ['Text with more than one space.'], }, multiplenbsp: { description: 'Multiple nbsp should be preserved', html: '  
', - expectedLineAttribs: ['+2'], - expectedText: [' '], + wantLineAttribs: ['+2'], + wantText: [' '], }, multipleNonBreakingSpaceBetweenWords: { description: 'Multiple nbsp between words ', html: '  word1  word2   word3
', - expectedLineAttribs: ['+m'], - expectedText: [' word1 word2 word3'], + wantLineAttribs: ['+m'], + wantText: [' word1 word2 word3'], }, nonBreakingSpacePreceededBySpaceBetweenWords: { description: 'A non-breaking space preceeded by a normal space', html: '  word1  word2  word3
', - expectedLineAttribs: ['+l'], - expectedText: [' word1 word2 word3'], + wantLineAttribs: ['+l'], + wantText: [' word1 word2 word3'], }, nonBreakingSpaceFollowededBySpaceBetweenWords: { description: 'A non-breaking space followed by a normal space', html: '  word1  word2  word3
', - expectedLineAttribs: ['+l'], - expectedText: [' word1 word2 word3'], + wantLineAttribs: ['+l'], + wantText: [' word1 word2 word3'], }, spacesAfterNewline: { description: 'Don\'t collapse spaces that follow a newline', html: 'something
something
', - expectedLineAttribs: ['+9', '+m'], - expectedText: ['something', ' something'], + wantLineAttribs: ['+9', '+m'], + wantText: ['something', ' something'], }, spacesAfterNewlineP: { description: 'Don\'t collapse spaces that follow a empty paragraph', html: 'something

something
', - expectedLineAttribs: ['+9', '', '+m'], - expectedText: ['something', '', ' something'], + wantLineAttribs: ['+9', '', '+m'], + wantText: ['something', '', ' something'], }, spacesAtEndOfLine: { description: 'Don\'t collapse spaces that preceed/follow a newline', html: 'something
something
', - expectedLineAttribs: ['+l', '+m'], - expectedText: ['something ', ' something'], + wantLineAttribs: ['+l', '+m'], + wantText: ['something ', ' something'], }, spacesAtEndOfLineP: { description: 'Don\'t collapse spaces that preceed/follow a empty paragraph', html: 'something

something
', - expectedLineAttribs: ['+l', '', '+m'], - expectedText: ['something ', '', ' something'], + wantLineAttribs: ['+l', '', '+m'], + wantText: ['something ', '', ' something'], }, nonBreakingSpacesAfterNewlines: { description: 'Don\'t collapse non-breaking spaces that follow a newline', html: 'something
   something
', - expectedLineAttribs: ['+9', '+c'], - expectedText: ['something', ' something'], + wantLineAttribs: ['+9', '+c'], + wantText: ['something', ' something'], }, nonBreakingSpacesAfterNewlinesP: { description: 'Don\'t collapse non-breaking spaces that follow a paragraph', html: 'something

   something
', - expectedLineAttribs: ['+9', '', '+c'], - expectedText: ['something', '', ' something'], + wantLineAttribs: ['+9', '', '+c'], + wantText: ['something', '', ' something'], }, preserveSpacesInsideElements: { description: 'Preserve all spaces when multiple are present', html: 'Need more space s !
', - expectedLineAttribs: ['+h*0+4+2'], - expectedText: ['Need more space s !'], + wantLineAttribs: ['+h*0+4+2'], + wantText: ['Need more space s !'], }, preserveSpacesAcrossNewlines: { description: 'Newlines and multiple spaces across newlines should be preserved', @@ -201,14 +201,14 @@ const tests = { space s !
`, - expectedLineAttribs: ['+19*0+4+b'], - expectedText: ['Need more space s !'], + wantLineAttribs: ['+19*0+4+b'], + wantText: ['Need more space s !'], }, multipleNewLinesAtBeginning: { description: 'Multiple new lines at the beginning should be preserved', html: '

first line

second line
', - expectedLineAttribs: ['', '', '', '', '+a', '', '+b'], - expectedText: ['', '', '', '', 'first line', '', 'second line'], + wantLineAttribs: ['', '', '', '', '+a', '', '+b'], + wantText: ['', '', '', '', 'first line', '', 'second line'], }, multiLineParagraph: { description: 'A paragraph with multiple lines should not loose spaces when lines are combined', @@ -216,8 +216,8 @@ const tests = { а б в г ґ д е є ж з и і ї й к л м н о п р с т у ф х ц ч ш щ ю я ь

`, - expectedLineAttribs: ['+1t'], - expectedText: ['а б в г ґ д е є ж з и і ї й к л м н о п р с т у ф х ц ч ш щ ю я ь'], + wantLineAttribs: ['+1t'], + wantText: ['а б в г ґ д е є ж з и і ї й к л м н о п р с т у ф х ц ч ш щ ю я ь'], }, multiLineParagraphWithPre: { description: 'lines in preformatted text should be kept intact', @@ -229,8 +229,8 @@ pre

п р с т у ф х ц ч ш щ ю я ь

`, - expectedLineAttribs: ['+11', '+8', '+5', '+2', '+3', '+r'], - expectedText: [ + wantLineAttribs: ['+11', '+8', '+5', '+2', '+3', '+r'], + wantText: [ 'а б в г ґ д е є ж з и і ї й к л м н о', 'multiple', 'lines', @@ -245,32 +245,32 @@ pre 1

preline
 
`, - expectedLineAttribs: ['+6', '+7'], - expectedText: [' 1 ', 'preline'], + wantLineAttribs: ['+6', '+7'], + wantText: [' 1 ', 'preline'], }, dontDeleteSpaceInsideElements: { description: 'Preserve spaces on the beginning and end of a element', html: 'Need more space s !
', - expectedLineAttribs: ['+f*0+3+1'], - expectedText: ['Need more space s !'], + wantLineAttribs: ['+f*0+3+1'], + wantText: ['Need more space s !'], }, dontDeleteSpaceOutsideElements: { description: 'Preserve spaces outside elements', html: 'Need more space s !
', - expectedLineAttribs: ['+g*0+1+2'], - expectedText: ['Need more space s !'], + wantLineAttribs: ['+g*0+1+2'], + wantText: ['Need more space s !'], }, dontDeleteSpaceAtEndOfElement: { description: 'Preserve spaces at the end of an element', html: 'Need more space s !
', - expectedLineAttribs: ['+g*0+2+1'], - expectedText: ['Need more space s !'], + wantLineAttribs: ['+g*0+2+1'], + wantText: ['Need more space s !'], }, dontDeleteSpaceAtBeginOfElements: { description: 'Preserve spaces at the start of an element', html: 'Need more space s !
', - expectedLineAttribs: ['+f*0+2+2'], - expectedText: ['Need more space s !'], + wantLineAttribs: ['+f*0+2+2'], + wantText: ['Need more space s !'], }, }; @@ -294,13 +294,13 @@ describe(__filename, function () { const cc = contentcollector.makeContentCollector(true, null, apool); cc.collectContent(doc); const result = cc.finish(); - const recievedAttributes = result.lineAttribs; - const expectedAttributes = testObj.expectedLineAttribs; - const recievedText = new Array(result.lines); - const expectedText = testObj.expectedText; + const gotAttributes = result.lineAttribs; + const wantAttributes = testObj.wantLineAttribs; + const gotText = new Array(result.lines); + const wantText = testObj.wantText; - assert.deepEqual(recievedText[0], expectedText); - assert.deepEqual(recievedAttributes, expectedAttributes); + assert.deepEqual(gotText[0], wantText); + assert.deepEqual(gotAttributes, wantAttributes); }); }); } From 56f617060a18d5830e29e582879030e87c2274ce Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 24 Jan 2021 01:57:11 -0500 Subject: [PATCH 073/153] tests: Fix missing call to `done` callback --- tests/backend/specs/contentcollector.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/backend/specs/contentcollector.js b/tests/backend/specs/contentcollector.js index c9ebb7482..e6aff389a 100644 --- a/tests/backend/specs/contentcollector.js +++ b/tests/backend/specs/contentcollector.js @@ -284,7 +284,7 @@ describe(__filename, function () { }); } - it(testObj.description, function (done) { + it(testObj.description, async function () { const $ = cheerio.load(testObj.html); // Load HTML into Cheerio const doc = $('body')[0]; // Creates a dom-like representation of HTML // Create an empty attribute pool From 42c25b25363a97ec3ab7a1e5d1eafe345a87a14d Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 24 Jan 2021 00:52:24 -0500 Subject: [PATCH 074/153] openapi: Fix error logging --- src/node/hooks/express/openapi.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/hooks/express/openapi.js b/src/node/hooks/express/openapi.js index d7059896a..444077fda 100644 --- a/src/node/hooks/express/openapi.js +++ b/src/node/hooks/express/openapi.js @@ -623,7 +623,7 @@ exports.expressCreateServer = (hookName, args, cb) => { } else { // an unknown error happened // log it and throw internal error - apiLogger.error(err); + apiLogger.error(err.stack || err.toString()); throw new createHTTPError.InternalError('internal error'); } }); From 74bb2f76ccd1474543390bd159bb52cb6119d3af Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 21 Jan 2021 02:30:29 -0500 Subject: [PATCH 075/153] contentcollector: Delete unused `domInterface` parameter --- src/static/js/ace2_inner.js | 2 +- src/static/js/contentcollector.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js index 95db2c14f..60b029f3b 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -1139,7 +1139,7 @@ function Ace2Inner() { lastDirtyNode = (lastDirtyNode && isNodeDirty(lastDirtyNode) && lastDirtyNode); if (firstDirtyNode && lastDirtyNode) { - const cc = makeContentCollector(isStyled, browser, rep.apool, null, className2Author); + const cc = makeContentCollector(isStyled, browser, rep.apool, className2Author); cc.notifySelection(selection); const dirtyNodes = []; for (let n = firstDirtyNode; n && diff --git a/src/static/js/contentcollector.js b/src/static/js/contentcollector.js index ab5781725..a77c4e5f0 100644 --- a/src/static/js/contentcollector.js +++ b/src/static/js/contentcollector.js @@ -32,8 +32,8 @@ const hooks = require('./pluginfw/hooks'); const sanitizeUnicode = (s) => UNorm.nfc(s); -const makeContentCollector = (collectStyles, abrowser, apool, domInterface, className2Author) => { - const dom = domInterface || { +const makeContentCollector = (collectStyles, abrowser, apool, className2Author) => { + const dom = { isNodeText: (n) => n.nodeType === 3, nodeTagName: (n) => n.tagName, nodeValue: (n) => n.nodeValue, From dd7fb1babee440e8395aa0862e96e57446199001 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 24 Jan 2021 18:03:13 -0500 Subject: [PATCH 076/153] contentcollector: Document the `dom` object --- src/static/js/contentcollector.js | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/static/js/contentcollector.js b/src/static/js/contentcollector.js index a77c4e5f0..a717df3a3 100644 --- a/src/static/js/contentcollector.js +++ b/src/static/js/contentcollector.js @@ -33,26 +33,47 @@ const hooks = require('./pluginfw/hooks'); const sanitizeUnicode = (s) => UNorm.nfc(s); const makeContentCollector = (collectStyles, abrowser, apool, className2Author) => { + // This file is used both in browsers and with cheerio in Node.js (for importing HTML). Cheerio's + // Node-like objects are not 100% API compatible with the DOM Node specification; this `dom` + // object abstracts away the differences. const dom = { - isNodeText: (n) => n.nodeType === 3, + // .nodeType works with DOM and cheerio 0.22.0. Note: Cheerio 0.22.0 does not provide the + // Node.*_NODE constants, so they cannot be used here. + isNodeText: (n) => n.nodeType === 3, // Node.TEXT_NODE + // .tagName works with DOM and cheerio 0.22.0, but: + // * With DOM, .tagName is an uppercase string. + // * With cheerio 0.22.0, .tagName is a lowercase string. nodeTagName: (n) => n.tagName, + // .nodeValue works with DOM and cheerio 0.22.0. nodeValue: (n) => n.nodeValue, + // Returns the number of Node children (n.childNodes.length), not the number of Element children + // (n.children.length in DOM). nodeNumChildren: (n) => { + // .childNodes.length works with DOM and cheerio 0.22.0, except in cheerio the .childNodes + // property does not exist on text nodes (and maybe other non-element nodes). if (n.childNodes == null) return 0; return n.childNodes.length; }, + // Returns the i'th Node child (n.childNodes[i]), not the i'th Element child (n.children[i] in + // DOM). nodeChild: (n, i) => { if (n.childNodes.item == null) { + // .childNodes[] works with DOM and cheerio 0.22.0. return n.childNodes[i]; } + // .childNodes.item() works with DOM but not with cheerio 0.22.0. return n.childNodes.item(i); }, nodeProp: (n, p) => n[p], nodeAttr: (n, a) => { + // .getAttribute() works with DOM but not with cheerio 0.22.0. if (n.getAttribute != null) return n.getAttribute(a); + // .attribs[] works with cheerio 0.22.0 but not with DOM. if (n.attribs != null) return n.attribs[a]; return null; }, + // .innerHTML works with DOM but not with cheerio 0.22.0. Cheerio's Element-like objects have no + // equivalent. (Cheerio objects have an .html() method, but that isn't accessible here.) optNodeInnerHTML: (n) => n.innerHTML, }; From 99625950c8ceb78e652d2ac52e5dc4e521ae6a39 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 21 Jan 2021 02:27:15 -0500 Subject: [PATCH 077/153] contentcollector: Factor out call to `.toLowerCase()` --- src/static/js/contentcollector.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/static/js/contentcollector.js b/src/static/js/contentcollector.js index a717df3a3..9f60b9033 100644 --- a/src/static/js/contentcollector.js +++ b/src/static/js/contentcollector.js @@ -43,7 +43,8 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) // .tagName works with DOM and cheerio 0.22.0, but: // * With DOM, .tagName is an uppercase string. // * With cheerio 0.22.0, .tagName is a lowercase string. - nodeTagName: (n) => n.tagName, + // For consistency, this function always returns a lowercase string. + nodeTagName: (n) => n.tagName && n.tagName.toLowerCase(), // .nodeValue works with DOM and cheerio 0.22.0. nodeValue: (n) => n.nodeValue, // Returns the number of Node children (n.childNodes.length), not the number of Element children @@ -88,7 +89,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) _blockElems[element] = 1; }); - const isBlockElement = (n) => !!_blockElems[(dom.nodeTagName(n) || '').toLowerCase()]; + const isBlockElement = (n) => !!_blockElems[dom.nodeTagName(n) || '']; const textify = (str) => sanitizeUnicode( str.replace(/(\n | \n)/g, ' ') @@ -406,7 +407,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) } } } else { - const tname = (dom.nodeTagName(node) || '').toLowerCase(); + const tname = dom.nodeTagName(node) || ''; if (tname === 'img') { hooks.callAll('collectContentImage', { From 8763c3bb2965874d2497f22d6bb347bc92aad22b Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 21 Jan 2021 00:30:55 -0500 Subject: [PATCH 078/153] contentcollector: Fix Element attribute accesses The `attribs` property is only available on cheerio's Element-like objects; DOM Element objects do not have an `attribs` property. Switch to `dom.nodeAttr()` to fix the logic for browsers. --- src/static/js/contentcollector.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/static/js/contentcollector.js b/src/static/js/contentcollector.js index 9f60b9033..ecd84c6bb 100644 --- a/src/static/js/contentcollector.js +++ b/src/static/js/contentcollector.js @@ -491,14 +491,14 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) cc.doAttrib(state, 'strikethrough'); } if (tname === 'ul' || tname === 'ol') { - let type = node.attribs ? node.attribs.class : null; + let type = dom.nodeAttr(node, 'class'); const rr = cls && /(?:^| )list-([a-z]+[0-9]+)\b/.exec(cls); // lists do not need to have a type, so before we make a wrong guess // check if we find a better hint within the node's children if (!rr && !type) { for (const i in node.children) { if (node.children[i] && node.children[i].name === 'ul') { - type = node.children[i].attribs.class; + type = dom.nodeAttr(node.children[i], 'class'); if (type) { break; } @@ -509,8 +509,8 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) type = rr[1]; } else { if (tname === 'ul') { - if ((type && type.match('indent')) || - (node.attribs && node.attribs.class && node.attribs.class.match('indent'))) { + const cls = dom.nodeAttr(node, 'class'); + if ((type && type.match('indent')) || (cls && cls.match('indent'))) { type = 'indent'; } else { type = 'bullet'; From 3cfec58948f652f3306ec0cb68d3fbe57ae1805b Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 24 Jan 2021 18:20:19 -0500 Subject: [PATCH 079/153] contentcollector: Rename `dom` functions for consistency with DOM spec --- src/static/js/contentcollector.js | 46 +++++++++++++++---------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/static/js/contentcollector.js b/src/static/js/contentcollector.js index ecd84c6bb..884f4b693 100644 --- a/src/static/js/contentcollector.js +++ b/src/static/js/contentcollector.js @@ -39,17 +39,17 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) const dom = { // .nodeType works with DOM and cheerio 0.22.0. Note: Cheerio 0.22.0 does not provide the // Node.*_NODE constants, so they cannot be used here. - isNodeText: (n) => n.nodeType === 3, // Node.TEXT_NODE + isTextNode: (n) => n.nodeType === 3, // Node.TEXT_NODE // .tagName works with DOM and cheerio 0.22.0, but: // * With DOM, .tagName is an uppercase string. // * With cheerio 0.22.0, .tagName is a lowercase string. // For consistency, this function always returns a lowercase string. - nodeTagName: (n) => n.tagName && n.tagName.toLowerCase(), + tagName: (n) => n.tagName && n.tagName.toLowerCase(), // .nodeValue works with DOM and cheerio 0.22.0. nodeValue: (n) => n.nodeValue, // Returns the number of Node children (n.childNodes.length), not the number of Element children // (n.children.length in DOM). - nodeNumChildren: (n) => { + numChildNodes: (n) => { // .childNodes.length works with DOM and cheerio 0.22.0, except in cheerio the .childNodes // property does not exist on text nodes (and maybe other non-element nodes). if (n.childNodes == null) return 0; @@ -57,7 +57,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) }, // Returns the i'th Node child (n.childNodes[i]), not the i'th Element child (n.children[i] in // DOM). - nodeChild: (n, i) => { + childNode: (n, i) => { if (n.childNodes.item == null) { // .childNodes[] works with DOM and cheerio 0.22.0. return n.childNodes[i]; @@ -66,7 +66,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) return n.childNodes.item(i); }, nodeProp: (n, p) => n[p], - nodeAttr: (n, a) => { + getAttribute: (n, a) => { // .getAttribute() works with DOM but not with cheerio 0.22.0. if (n.getAttribute != null) return n.getAttribute(a); // .attribs[] works with cheerio 0.22.0 but not with DOM. @@ -75,7 +75,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) }, // .innerHTML works with DOM but not with cheerio 0.22.0. Cheerio's Element-like objects have no // equivalent. (Cheerio objects have an .html() method, but that isn't accessible here.) - optNodeInnerHTML: (n) => n.innerHTML, + innerHTML: (n) => n.innerHTML, }; const _blockElems = { @@ -89,7 +89,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) _blockElems[element] = 1; }); - const isBlockElement = (n) => !!_blockElems[dom.nodeTagName(n) || '']; + const isBlockElement = (n) => !!_blockElems[dom.tagName(n) || '']; const textify = (str) => sanitizeUnicode( str.replace(/(\n | \n)/g, ' ') @@ -145,13 +145,13 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) let selEnd = [-1, -1]; const _isEmpty = (node, state) => { // consider clean blank lines pasted in IE to be empty - if (dom.nodeNumChildren(node) === 0) return true; - if (dom.nodeNumChildren(node) === 1 && + if (dom.numChildNodes(node) === 0) return true; + if (dom.numChildNodes(node) === 1 && getAssoc(node, 'shouldBeEmpty') && - dom.optNodeInnerHTML(node) === ' ' && + dom.innerHTML(node) === ' ' && !getAssoc(node, 'unpasted')) { if (state) { - const child = dom.nodeChild(node, 0); + const child = dom.childNode(node, 0); _reachPoint(child, 0, state); _reachPoint(child, 1, state); } @@ -171,7 +171,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) }; const _reachBlockPoint = (nd, idx, state) => { - if (!dom.isNodeText(nd)) _reachPoint(nd, idx, state); + if (!dom.isTextNode(nd)) _reachPoint(nd, idx, state); }; const _reachPoint = (nd, idx, state) => { @@ -338,9 +338,9 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) const startLine = lines.length() - 1; _reachBlockPoint(node, 0, state); - if (dom.isNodeText(node)) { + if (dom.isTextNode(node)) { let txt = dom.nodeValue(node); - const tname = dom.nodeAttr(node.parentNode, 'name'); + const tname = dom.getAttribute(node.parentNode, 'name'); const txtFromHook = hooks.callAll('collectContentLineText', { cc: this, @@ -407,7 +407,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) } } } else { - const tname = dom.nodeTagName(node) || ''; + const tname = dom.tagName(node) || ''; if (tname === 'img') { hooks.callAll('collectContentImage', { @@ -425,7 +425,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) if (tname === 'br') { this.breakLine = true; - const tvalue = dom.nodeAttr(node, 'value'); + const tvalue = dom.getAttribute(node, 'value'); const induceLineBreak = hooks.callAll('collectContentLineBreak', { cc: this, state, @@ -443,8 +443,8 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) } else if (tname === 'script' || tname === 'style') { // ignore } else if (!isEmpty) { - let styl = dom.nodeAttr(node, 'style'); - let cls = dom.nodeAttr(node, 'class'); + let styl = dom.getAttribute(node, 'style'); + let cls = dom.getAttribute(node, 'class'); let isPre = (tname === 'pre'); if ((!isPre) && abrowser && abrowser.safari) { isPre = (styl && /\bwhite-space:\s*pre\b/i.exec(styl)); @@ -491,14 +491,14 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) cc.doAttrib(state, 'strikethrough'); } if (tname === 'ul' || tname === 'ol') { - let type = dom.nodeAttr(node, 'class'); + let type = dom.getAttribute(node, 'class'); const rr = cls && /(?:^| )list-([a-z]+[0-9]+)\b/.exec(cls); // lists do not need to have a type, so before we make a wrong guess // check if we find a better hint within the node's children if (!rr && !type) { for (const i in node.children) { if (node.children[i] && node.children[i].name === 'ul') { - type = dom.nodeAttr(node.children[i], 'class'); + type = dom.getAttribute(node.children[i], 'class'); if (type) { break; } @@ -509,7 +509,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) type = rr[1]; } else { if (tname === 'ul') { - const cls = dom.nodeAttr(node, 'class'); + const cls = dom.getAttribute(node, 'class'); if ((type && type.match('indent')) || (cls && cls.match('indent'))) { type = 'indent'; } else { @@ -581,9 +581,9 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) } } - const nc = dom.nodeNumChildren(node); + const nc = dom.numChildNodes(node); for (let i = 0; i < nc; i++) { - const c = dom.nodeChild(node, i); + const c = dom.childNode(node, i); cc.collectContent(c, state); } From d0bfb54c0ad695854e09e6a8f0bce3814f72dc99 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 20 Jan 2021 23:50:33 -0500 Subject: [PATCH 080/153] contentcollector: Avoid `for..in` iteration of object properties `for..in` iterates over inherited properties, which is almost never desired. In most cases there aren't any inherited enumerable properties so it's not that big of a deal, but in the case of HTMLCollection it's very bad because it iterates over every entry twice (once by numerical index and once by name) plus it includes the `length` property in the iteration. --- src/static/js/contentcollector.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/static/js/contentcollector.js b/src/static/js/contentcollector.js index 884f4b693..86043baf8 100644 --- a/src/static/js/contentcollector.js +++ b/src/static/js/contentcollector.js @@ -250,8 +250,8 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) const _recalcAttribString = (state) => { const lst = []; - for (const a in state.attribs) { - if (state.attribs[a]) { + for (const [a, count] of Object.entries(state.attribs)) { + if (count) { // The following splitting of the attribute name is a workaround // to enable the content collector to store key-value attributes // see https://github.com/ether/etherpad-lite/issues/2567 for more information @@ -496,9 +496,18 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) // lists do not need to have a type, so before we make a wrong guess // check if we find a better hint within the node's children if (!rr && !type) { - for (const i in node.children) { - if (node.children[i] && node.children[i].name === 'ul') { - type = dom.getAttribute(node.children[i], 'class'); + // If `node` is from the DOM (not cheerio) then it implements the ParentNode interface + // and `node.children` is a HTMLCollection. The DOM + Web IDL specs guarantee that + // HTMLCollection implements the iterable protocol, so for..of iteration should always + // work. See: https://stackoverflow.com/a/41759532. Cheerio behaves the same with + // regard to iteration. + // + // TODO: The set of Nodes included in node.children differs between the DOM and + // cheerio 0.22.0: cheerio includes all child Nodes (including non-Element Nodes) + // whereas the DOM only includes Nodes that are Elements. + for (const child of node.children) { + if (child && child.name === 'ul') { + type = dom.getAttribute(child, 'class'); if (type) { break; } From fc2420c244b682ad514363fbdb7cac3d3ae574bf Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 24 Jan 2021 18:50:50 -0500 Subject: [PATCH 081/153] contentcollector: Fix iteration over child Nodes In the DOM, `.children` only includes children that are Element objects. In cheerio 0.22.0, `.children` includes all child Nodes, not just Elements. Use `dom.numChildNodes()` and `dom.childNode()` so that browsers behave the same as cheerio. --- src/static/js/contentcollector.js | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/static/js/contentcollector.js b/src/static/js/contentcollector.js index 86043baf8..f940f257b 100644 --- a/src/static/js/contentcollector.js +++ b/src/static/js/contentcollector.js @@ -496,16 +496,8 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) // lists do not need to have a type, so before we make a wrong guess // check if we find a better hint within the node's children if (!rr && !type) { - // If `node` is from the DOM (not cheerio) then it implements the ParentNode interface - // and `node.children` is a HTMLCollection. The DOM + Web IDL specs guarantee that - // HTMLCollection implements the iterable protocol, so for..of iteration should always - // work. See: https://stackoverflow.com/a/41759532. Cheerio behaves the same with - // regard to iteration. - // - // TODO: The set of Nodes included in node.children differs between the DOM and - // cheerio 0.22.0: cheerio includes all child Nodes (including non-Element Nodes) - // whereas the DOM only includes Nodes that are Elements. - for (const child of node.children) { + for (let i = 0; i < dom.numChildNodes(node); i++) { + const child = dom.childNode(node, i); if (child && child.name === 'ul') { type = dom.getAttribute(child, 'class'); if (type) { From b811030846b72d5449f58510e32c75e12995c987 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 21 Jan 2021 02:34:50 -0500 Subject: [PATCH 082/153] contentcollector: Delete unnecessary truthiness check --- src/static/js/contentcollector.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/static/js/contentcollector.js b/src/static/js/contentcollector.js index f940f257b..f4fc015cf 100644 --- a/src/static/js/contentcollector.js +++ b/src/static/js/contentcollector.js @@ -498,7 +498,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) if (!rr && !type) { for (let i = 0; i < dom.numChildNodes(node); i++) { const child = dom.childNode(node, i); - if (child && child.name === 'ul') { + if (child.name === 'ul') { type = dom.getAttribute(child, 'class'); if (type) { break; From b547ce9a47eece44a1c23e22aa90e39a996d0710 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 21 Jan 2021 02:35:44 -0500 Subject: [PATCH 083/153] contentcollector: Invert logic to improve readability --- src/static/js/contentcollector.js | 42 ++++++++++++++----------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/src/static/js/contentcollector.js b/src/static/js/contentcollector.js index f4fc015cf..c03ab6d64 100644 --- a/src/static/js/contentcollector.js +++ b/src/static/js/contentcollector.js @@ -251,24 +251,23 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) const _recalcAttribString = (state) => { const lst = []; for (const [a, count] of Object.entries(state.attribs)) { - if (count) { - // The following splitting of the attribute name is a workaround - // to enable the content collector to store key-value attributes - // see https://github.com/ether/etherpad-lite/issues/2567 for more information - // in long term the contentcollector should be refactored to get rid of this workaround - const ATTRIBUTE_SPLIT_STRING = '::'; + if (!count) continue; + // The following splitting of the attribute name is a workaround + // to enable the content collector to store key-value attributes + // see https://github.com/ether/etherpad-lite/issues/2567 for more information + // in long term the contentcollector should be refactored to get rid of this workaround + const ATTRIBUTE_SPLIT_STRING = '::'; - // see if attributeString is splittable - const attributeSplits = a.split(ATTRIBUTE_SPLIT_STRING); - if (attributeSplits.length > 1) { - // the attribute name follows the convention key::value - // so save it as a key value attribute - lst.push([attributeSplits[0], attributeSplits[1]]); - } else { - // the "normal" case, the attribute is just a switch - // so set it true - lst.push([a, 'true']); - } + // see if attributeString is splittable + const attributeSplits = a.split(ATTRIBUTE_SPLIT_STRING); + if (attributeSplits.length > 1) { + // the attribute name follows the convention key::value + // so save it as a key value attribute + lst.push([attributeSplits[0], attributeSplits[1]]); + } else { + // the "normal" case, the attribute is just a switch + // so set it true + lst.push([a, 'true']); } } if (state.authorLevel > 0) { @@ -498,12 +497,9 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) if (!rr && !type) { for (let i = 0; i < dom.numChildNodes(node); i++) { const child = dom.childNode(node, i); - if (child.name === 'ul') { - type = dom.getAttribute(child, 'class'); - if (type) { - break; - } - } + if (child.name !== 'ul') continue; + type = dom.getAttribute(child, 'class'); + if (type) break; } } if (rr && rr[1]) { From 4e220538a15b0b6108251b18141dc43a0beccc11 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 21 Jan 2021 00:06:43 -0500 Subject: [PATCH 084/153] contentcollector: Use destructuring to improve readability --- src/static/js/contentcollector.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/static/js/contentcollector.js b/src/static/js/contentcollector.js index c03ab6d64..b20c2583a 100644 --- a/src/static/js/contentcollector.js +++ b/src/static/js/contentcollector.js @@ -425,7 +425,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) if (tname === 'br') { this.breakLine = true; const tvalue = dom.getAttribute(node, 'value'); - const induceLineBreak = hooks.callAll('collectContentLineBreak', { + const [startNewLine = true] = hooks.callAll('collectContentLineBreak', { cc: this, state, tname, @@ -433,9 +433,6 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) styl: null, cls: null, }); - const startNewLine = ( - typeof (induceLineBreak) === 'object' && - induceLineBreak.length === 0) ? true : induceLineBreak[0]; if (startNewLine) { cc.startNewLine(state); } From e3a47e48f9ee2391fb4e60c97eb7137855e580af Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 22 Jan 2021 02:06:06 -0500 Subject: [PATCH 085/153] contentcollector: Fix collectContentLineText hook Before, the hook always ignored the return values provided by the hook functions. Now the hook functions can change the text by either returning a string or setting `context.text` to the desired value. Also drop the `styl` and `cls` context properties. They were never documented and they were always null. --- doc/api/hooks_client-side.md | 15 ++++++++++++++- src/static/js/contentcollector.js | 24 +++++++----------------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/doc/api/hooks_client-side.md b/doc/api/hooks_client-side.md index 478f5d0a5..e87536cfe 100755 --- a/doc/api/hooks_client-side.md +++ b/doc/api/hooks_client-side.md @@ -421,7 +421,20 @@ Things in context: 4. text - the text for that line This hook allows you to validate/manipulate the text before it's sent to the -server side. The return value should be the validated/manipulated text. +server side. To change the text, either: + +* Set the `text` context property to the desired value and return `undefined`. +* (Deprecated) Return a string. If a hook function changes the `text` context + property, the return value is ignored. If no hook function changes `text` but + multiple hook functions return a string, the first one wins. + +Example: + +``` +exports.collectContentLineText = (hookName, context) => { + context.text = tweakText(context.text); +}; +``` ## collectContentLineBreak diff --git a/src/static/js/contentcollector.js b/src/static/js/contentcollector.js index b20c2583a..357b50195 100644 --- a/src/static/js/contentcollector.js +++ b/src/static/js/contentcollector.js @@ -338,24 +338,14 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) _reachBlockPoint(node, 0, state); if (dom.isTextNode(node)) { - let txt = dom.nodeValue(node); const tname = dom.getAttribute(node.parentNode, 'name'); - - const txtFromHook = hooks.callAll('collectContentLineText', { - cc: this, - state, - tname, - node, - text: txt, - styl: null, - cls: null, - }); - - if (typeof (txtFromHook) === 'object') { - txt = dom.nodeValue(node); - } else if (txtFromHook) { - txt = txtFromHook; - } + const context = {cc: this, state, tname, node, text: dom.nodeValue(node)}; + // Hook functions may either return a string (deprecated) or modify context.text. If any hook + // function modifies context.text then all returned strings are ignored. If no hook functions + // modify context.text, the first hook function to return a string wins. + const [hookTxt] = + hooks.callAll('collectContentLineText', context).filter((s) => typeof s === 'string'); + let txt = context.text === dom.nodeValue(node) && hookTxt != null ? hookTxt : context.text; let rest = ''; let x = 0; // offset into original text From 1d36549152c383264877b0f9a395ab93a7408b13 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 24 Jan 2021 19:27:00 -0500 Subject: [PATCH 086/153] contentcollector: Delete unnecessary parentheses --- src/static/js/contentcollector.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/static/js/contentcollector.js b/src/static/js/contentcollector.js index 357b50195..c7db55fa0 100644 --- a/src/static/js/contentcollector.js +++ b/src/static/js/contentcollector.js @@ -509,7 +509,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) // This has undesirable behavior in Chrome but is right in other browsers. // See https://github.com/ether/etherpad-lite/issues/2412 for reasoning if (!abrowser.chrome) oldListTypeOrNull = (_enterList(state, undefined) || 'none'); - } else if ((tname === 'li')) { + } else if (tname === 'li') { state.lineAttributes.start = state.start || 0; _recalcAttribString(state); if (state.lineAttributes.list.indexOf('number') !== -1) { From e3ec9d9a4c9afba34a3edb14f73c7a1fa1f4988f Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 24 Jan 2021 19:29:56 -0500 Subject: [PATCH 087/153] contentcollector: Fix parent node access The `parent` property is only available on cheerio's Node-like objects; DOM Node objects do not have a `parent` property. Switch to the `parentNode` property so that the code works in browsers as well as cheerio. --- src/static/js/contentcollector.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/static/js/contentcollector.js b/src/static/js/contentcollector.js index c7db55fa0..0b85b434b 100644 --- a/src/static/js/contentcollector.js +++ b/src/static/js/contentcollector.js @@ -519,7 +519,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) Note how the
    item has to be inside a
  1. Because of this we don't increment the start number */ - if (node.parent && node.parent.name !== 'ol') { + if (node.parentNode && node.parentNode.name !== 'ol') { /* TODO: start number has to increment based on indentLevel(numberX) This means we have to build an object IE @@ -536,7 +536,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) } } // UL list items never modify the start value. - if (node.parent && node.parent.name === 'ul') { + if (node.parentNode && node.parentNode.name === 'ul') { state.start++; // TODO, this is hacky. // Because if the first item is an UL it will increment a list no? From 075969aea08e5cf767db489f8feeadbc0ef0ae50 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 21 Jan 2021 02:46:22 -0500 Subject: [PATCH 088/153] contentcollector: Fix Element tag name fetch The `name` property is only available on cheerio's Element-like objects; DOM Element objects do not have a `name` property. Switch to `dom.tagName()` to fix the logic for browsers. --- src/static/js/contentcollector.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/static/js/contentcollector.js b/src/static/js/contentcollector.js index 0b85b434b..89dfd8ff8 100644 --- a/src/static/js/contentcollector.js +++ b/src/static/js/contentcollector.js @@ -484,7 +484,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) if (!rr && !type) { for (let i = 0; i < dom.numChildNodes(node); i++) { const child = dom.childNode(node, i); - if (child.name !== 'ul') continue; + if (dom.tagName(child) !== 'ul') continue; type = dom.getAttribute(child, 'class'); if (type) break; } @@ -519,7 +519,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) Note how the
      item has to be inside a
    1. Because of this we don't increment the start number */ - if (node.parentNode && node.parentNode.name !== 'ol') { + if (node.parentNode && dom.tagName(node.parentNode) !== 'ol') { /* TODO: start number has to increment based on indentLevel(numberX) This means we have to build an object IE @@ -536,7 +536,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) } } // UL list items never modify the start value. - if (node.parentNode && node.parentNode.name === 'ul') { + if (node.parentNode && dom.tagName(node.parentNode) === 'ul') { state.start++; // TODO, this is hacky. // Because if the first item is an UL it will increment a list no? From 1cb5453aeb98bfd5521500bfbead23ad92f137c4 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 24 Jan 2021 02:07:33 -0500 Subject: [PATCH 089/153] contentcollector: Skip over non-Text, non-Element Nodes --- src/static/js/contentcollector.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/static/js/contentcollector.js b/src/static/js/contentcollector.js index 89dfd8ff8..28ac8cb6e 100644 --- a/src/static/js/contentcollector.js +++ b/src/static/js/contentcollector.js @@ -39,6 +39,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) const dom = { // .nodeType works with DOM and cheerio 0.22.0. Note: Cheerio 0.22.0 does not provide the // Node.*_NODE constants, so they cannot be used here. + isElementNode: (n) => n.nodeType === 1, // Node.ELEMENT_NODE isTextNode: (n) => n.nodeType === 3, // Node.TEXT_NODE // .tagName works with DOM and cheerio 0.22.0, but: // * With DOM, .tagName is an uppercase string. @@ -395,7 +396,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) cc.startNewLine(state); } } - } else { + } else if (dom.isElementNode(node)) { const tname = dom.tagName(node) || ''; if (tname === 'img') { From 275f041fbb39c0c6518f7f26d73fd760045412d0 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 25 Jan 2021 01:29:08 -0500 Subject: [PATCH 090/153] contentcollector: Simplify child node access --- src/static/js/contentcollector.js | 34 ++++++++----------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/src/static/js/contentcollector.js b/src/static/js/contentcollector.js index 28ac8cb6e..ff9b5d9e4 100644 --- a/src/static/js/contentcollector.js +++ b/src/static/js/contentcollector.js @@ -48,24 +48,9 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) tagName: (n) => n.tagName && n.tagName.toLowerCase(), // .nodeValue works with DOM and cheerio 0.22.0. nodeValue: (n) => n.nodeValue, - // Returns the number of Node children (n.childNodes.length), not the number of Element children - // (n.children.length in DOM). - numChildNodes: (n) => { - // .childNodes.length works with DOM and cheerio 0.22.0, except in cheerio the .childNodes - // property does not exist on text nodes (and maybe other non-element nodes). - if (n.childNodes == null) return 0; - return n.childNodes.length; - }, - // Returns the i'th Node child (n.childNodes[i]), not the i'th Element child (n.children[i] in - // DOM). - childNode: (n, i) => { - if (n.childNodes.item == null) { - // .childNodes[] works with DOM and cheerio 0.22.0. - return n.childNodes[i]; - } - // .childNodes.item() works with DOM but not with cheerio 0.22.0. - return n.childNodes.item(i); - }, + // .childNodes works with DOM and cheerio 0.22.0, except in cheerio the .childNodes property + // does not exist on text nodes (and maybe other non-element nodes). + childNodes: (n) => n.childNodes || [], nodeProp: (n, p) => n[p], getAttribute: (n, a) => { // .getAttribute() works with DOM but not with cheerio 0.22.0. @@ -146,13 +131,13 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) let selEnd = [-1, -1]; const _isEmpty = (node, state) => { // consider clean blank lines pasted in IE to be empty - if (dom.numChildNodes(node) === 0) return true; - if (dom.numChildNodes(node) === 1 && + if (dom.childNodes(node).length === 0) return true; + if (dom.childNodes(node).length === 1 && getAssoc(node, 'shouldBeEmpty') && dom.innerHTML(node) === ' ' && !getAssoc(node, 'unpasted')) { if (state) { - const child = dom.childNode(node, 0); + const child = dom.childNodes(node)[0]; _reachPoint(child, 0, state); _reachPoint(child, 1, state); } @@ -483,8 +468,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) // lists do not need to have a type, so before we make a wrong guess // check if we find a better hint within the node's children if (!rr && !type) { - for (let i = 0; i < dom.numChildNodes(node); i++) { - const child = dom.childNode(node, i); + for (const child of dom.childNodes(node)) { if (dom.tagName(child) !== 'ul') continue; type = dom.getAttribute(child, 'class'); if (type) break; @@ -566,9 +550,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) } } - const nc = dom.numChildNodes(node); - for (let i = 0; i < nc; i++) { - const c = dom.childNode(node, i); + for (const c of dom.childNodes(node)) { cc.collectContent(c, state); } From e5b45cc98479470463cb66882f61121807d586c7 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 25 Jan 2021 00:33:18 -0500 Subject: [PATCH 091/153] contentcollector: Delete unnecessary `dom` functions And move the remaining functions out of the `makeContentCollector()` function. --- src/static/js/contentcollector.js | 107 +++++++++++++++--------------- 1 file changed, 52 insertions(+), 55 deletions(-) diff --git a/src/static/js/contentcollector.js b/src/static/js/contentcollector.js index ff9b5d9e4..7ac27168f 100644 --- a/src/static/js/contentcollector.js +++ b/src/static/js/contentcollector.js @@ -32,38 +32,31 @@ const hooks = require('./pluginfw/hooks'); const sanitizeUnicode = (s) => UNorm.nfc(s); -const makeContentCollector = (collectStyles, abrowser, apool, className2Author) => { - // This file is used both in browsers and with cheerio in Node.js (for importing HTML). Cheerio's - // Node-like objects are not 100% API compatible with the DOM Node specification; this `dom` - // object abstracts away the differences. - const dom = { - // .nodeType works with DOM and cheerio 0.22.0. Note: Cheerio 0.22.0 does not provide the - // Node.*_NODE constants, so they cannot be used here. - isElementNode: (n) => n.nodeType === 1, // Node.ELEMENT_NODE - isTextNode: (n) => n.nodeType === 3, // Node.TEXT_NODE - // .tagName works with DOM and cheerio 0.22.0, but: - // * With DOM, .tagName is an uppercase string. - // * With cheerio 0.22.0, .tagName is a lowercase string. - // For consistency, this function always returns a lowercase string. - tagName: (n) => n.tagName && n.tagName.toLowerCase(), - // .nodeValue works with DOM and cheerio 0.22.0. - nodeValue: (n) => n.nodeValue, - // .childNodes works with DOM and cheerio 0.22.0, except in cheerio the .childNodes property - // does not exist on text nodes (and maybe other non-element nodes). - childNodes: (n) => n.childNodes || [], - nodeProp: (n, p) => n[p], - getAttribute: (n, a) => { - // .getAttribute() works with DOM but not with cheerio 0.22.0. - if (n.getAttribute != null) return n.getAttribute(a); - // .attribs[] works with cheerio 0.22.0 but not with DOM. - if (n.attribs != null) return n.attribs[a]; - return null; - }, - // .innerHTML works with DOM but not with cheerio 0.22.0. Cheerio's Element-like objects have no - // equivalent. (Cheerio objects have an .html() method, but that isn't accessible here.) - innerHTML: (n) => n.innerHTML, - }; +// This file is used both in browsers and with cheerio in Node.js (for importing HTML). Cheerio's +// Node-like objects are not 100% API compatible with the DOM specification; the following functions +// abstract away the differences. +// .nodeType works with DOM and cheerio 0.22.0, but cheerio 0.22.0 does not provide the Node.*_NODE +// constants so they cannot be used here. +const isElementNode = (n) => n.nodeType === 1; // Node.ELEMENT_NODE +const isTextNode = (n) => n.nodeType === 3; // Node.TEXT_NODE +// .tagName works with DOM and cheerio 0.22.0, but: +// * With DOM, .tagName is an uppercase string. +// * With cheerio 0.22.0, .tagName is a lowercase string. +// For consistency, this function always returns a lowercase string. +const tagName = (n) => n.tagName && n.tagName.toLowerCase(); +// .childNodes works with DOM and cheerio 0.22.0, except in cheerio the .childNodes property does +// not exist on text nodes (and maybe other non-element nodes). +const childNodes = (n) => n.childNodes || []; +const getAttribute = (n, a) => { + // .getAttribute() works with DOM but not with cheerio 0.22.0. + if (n.getAttribute != null) return n.getAttribute(a); + // .attribs[] works with cheerio 0.22.0 but not with DOM. + if (n.attribs != null) return n.attribs[a]; + return null; +}; + +const makeContentCollector = (collectStyles, abrowser, apool, className2Author) => { const _blockElems = { div: 1, p: 1, @@ -75,7 +68,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) _blockElems[element] = 1; }); - const isBlockElement = (n) => !!_blockElems[dom.tagName(n) || '']; + const isBlockElement = (n) => !!_blockElems[tagName(n) || '']; const textify = (str) => sanitizeUnicode( str.replace(/(\n | \n)/g, ' ') @@ -83,7 +76,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) .replace(/\xa0/g, ' ') .replace(/\t/g, ' ')); - const getAssoc = (node, name) => dom.nodeProp(node, `_magicdom_${name}`); + const getAssoc = (node, name) => node[`_magicdom_${name}`]; const lines = (() => { const textArray = []; @@ -131,13 +124,17 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) let selEnd = [-1, -1]; const _isEmpty = (node, state) => { // consider clean blank lines pasted in IE to be empty - if (dom.childNodes(node).length === 0) return true; - if (dom.childNodes(node).length === 1 && + if (childNodes(node).length === 0) return true; + if (childNodes(node).length === 1 && getAssoc(node, 'shouldBeEmpty') && - dom.innerHTML(node) === ' ' && + // Note: The .innerHTML property exists on DOM Element objects but not on cheerio's + // Element-like objects (cheerio v0.22.0) so this equality check will always be false. + // Cheerio's Element-like objects have no equivalent to .innerHTML. (Cheerio objects have an + // .html() method, but that isn't accessible here.) + node.innerHTML === ' ' && !getAssoc(node, 'unpasted')) { if (state) { - const child = dom.childNodes(node)[0]; + const child = childNodes(node)[0]; _reachPoint(child, 0, state); _reachPoint(child, 1, state); } @@ -157,7 +154,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) }; const _reachBlockPoint = (nd, idx, state) => { - if (!dom.isTextNode(nd)) _reachPoint(nd, idx, state); + if (!isTextNode(nd)) _reachPoint(nd, idx, state); }; const _reachPoint = (nd, idx, state) => { @@ -323,15 +320,15 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) const startLine = lines.length() - 1; _reachBlockPoint(node, 0, state); - if (dom.isTextNode(node)) { - const tname = dom.getAttribute(node.parentNode, 'name'); - const context = {cc: this, state, tname, node, text: dom.nodeValue(node)}; + if (isTextNode(node)) { + const tname = getAttribute(node.parentNode, 'name'); + const context = {cc: this, state, tname, node, text: node.nodeValue}; // Hook functions may either return a string (deprecated) or modify context.text. If any hook // function modifies context.text then all returned strings are ignored. If no hook functions // modify context.text, the first hook function to return a string wins. const [hookTxt] = hooks.callAll('collectContentLineText', context).filter((s) => typeof s === 'string'); - let txt = context.text === dom.nodeValue(node) && hookTxt != null ? hookTxt : context.text; + let txt = context.text === node.nodeValue && hookTxt != null ? hookTxt : context.text; let rest = ''; let x = 0; // offset into original text @@ -381,8 +378,8 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) cc.startNewLine(state); } } - } else if (dom.isElementNode(node)) { - const tname = dom.tagName(node) || ''; + } else if (isElementNode(node)) { + const tname = tagName(node) || ''; if (tname === 'img') { hooks.callAll('collectContentImage', { @@ -400,7 +397,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) if (tname === 'br') { this.breakLine = true; - const tvalue = dom.getAttribute(node, 'value'); + const tvalue = getAttribute(node, 'value'); const [startNewLine = true] = hooks.callAll('collectContentLineBreak', { cc: this, state, @@ -415,8 +412,8 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) } else if (tname === 'script' || tname === 'style') { // ignore } else if (!isEmpty) { - let styl = dom.getAttribute(node, 'style'); - let cls = dom.getAttribute(node, 'class'); + let styl = getAttribute(node, 'style'); + let cls = getAttribute(node, 'class'); let isPre = (tname === 'pre'); if ((!isPre) && abrowser && abrowser.safari) { isPre = (styl && /\bwhite-space:\s*pre\b/i.exec(styl)); @@ -463,14 +460,14 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) cc.doAttrib(state, 'strikethrough'); } if (tname === 'ul' || tname === 'ol') { - let type = dom.getAttribute(node, 'class'); + let type = getAttribute(node, 'class'); const rr = cls && /(?:^| )list-([a-z]+[0-9]+)\b/.exec(cls); // lists do not need to have a type, so before we make a wrong guess // check if we find a better hint within the node's children if (!rr && !type) { - for (const child of dom.childNodes(node)) { - if (dom.tagName(child) !== 'ul') continue; - type = dom.getAttribute(child, 'class'); + for (const child of childNodes(node)) { + if (tagName(child) !== 'ul') continue; + type = getAttribute(child, 'class'); if (type) break; } } @@ -478,7 +475,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) type = rr[1]; } else { if (tname === 'ul') { - const cls = dom.getAttribute(node, 'class'); + const cls = getAttribute(node, 'class'); if ((type && type.match('indent')) || (cls && cls.match('indent'))) { type = 'indent'; } else { @@ -504,7 +501,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) Note how the
        item has to be inside a
      1. Because of this we don't increment the start number */ - if (node.parentNode && dom.tagName(node.parentNode) !== 'ol') { + if (node.parentNode && tagName(node.parentNode) !== 'ol') { /* TODO: start number has to increment based on indentLevel(numberX) This means we have to build an object IE @@ -521,7 +518,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) } } // UL list items never modify the start value. - if (node.parentNode && dom.tagName(node.parentNode) === 'ul') { + if (node.parentNode && tagName(node.parentNode) === 'ul') { state.start++; // TODO, this is hacky. // Because if the first item is an UL it will increment a list no? @@ -550,7 +547,7 @@ const makeContentCollector = (collectStyles, abrowser, apool, className2Author) } } - for (const c of dom.childNodes(node)) { + for (const c of childNodes(node)) { cc.collectContent(c, state); } From 53092fa7af7f6c54596a4ce33bcd580eaedaf2f0 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 28 Jan 2021 00:35:46 -0500 Subject: [PATCH 092/153] db/Pad: Call padCopy and padRemove hooks asynchronously --- src/node/db/Pad.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/node/db/Pad.js b/src/node/db/Pad.js index 67842c14d..965f2793f 100644 --- a/src/node/db/Pad.js +++ b/src/node/db/Pad.js @@ -418,7 +418,7 @@ Pad.prototype.copy = async function copy(destinationID, force) { await padManager.getPad(destinationID, null); // this runs too early. // let the plugins know the pad was copied - hooks.callAll('padCopy', {originalPad: this, destinationID}); + await hooks.aCallAll('padCopy', {originalPad: this, destinationID}); return {padID: destinationID}; }; @@ -520,7 +520,7 @@ Pad.prototype.copyPadWithoutHistory = async function copyPadWithoutHistory(desti const changeset = Changeset.pack(oldLength, newLength, assem.toString(), newText); newPad.appendRevision(changeset); - hooks.callAll('padCopy', {originalPad: this, destinationID}); + await hooks.aCallAll('padCopy', {originalPad: this, destinationID}); return {padID: destinationID}; }; @@ -574,7 +574,7 @@ Pad.prototype.remove = async function remove() { // delete the pad entry and delete pad from padManager p.push(padManager.removePad(padID)); - hooks.callAll('padRemove', {padID}); + p.push(hooks.aCallAll('padRemove', {padID})); await Promise.all(p); }; From 7f392e12e971df679038dbc84a2d18b90bf999b8 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Thu, 28 Jan 2021 00:41:23 -0500 Subject: [PATCH 093/153] tests: Create a `src/tests/` symlink that points to `tests/` This makes it possible for plugin backend tests to do `require('ep_etherpad-lite/tests/backend/common')` to access the API key (among other things). Eventually we probably should reverse these (move `tests/` to `src/tests/` and make `tests/` a symlink to `src/tests/`) and move `bin/` to `src/bin/` so that we can avoid the top-level `package.json` mess. --- src/tests | 1 + 1 file changed, 1 insertion(+) create mode 120000 src/tests diff --git a/src/tests b/src/tests new file mode 120000 index 000000000..6dd24e02b --- /dev/null +++ b/src/tests @@ -0,0 +1 @@ +../tests \ No newline at end of file From 989f42204f3169c4f7992ebd356f608a156084f2 Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Thu, 28 Jan 2021 18:48:11 +0100 Subject: [PATCH 094/153] Localisation updates from https://translatewiki.net. --- src/locales/de.json | 23 +++++++++++++++++++++-- src/locales/fi.json | 3 ++- src/locales/sl.json | 8 ++++++-- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/locales/de.json b/src/locales/de.json index 781abe099..439e9c9e3 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -11,24 +11,42 @@ "Sebastian Wallroth", "Thargon", "Tim.krieger", - "Wikinaut" + "Wikinaut", + "Zunkelty" ] }, + "admin.page-title": "Admin Dashboard - Etherpad", "admin_plugins": "Plugins verwalten", "admin_plugins.available": "Verfügbare Plugins", "admin_plugins.available_not-found": "Keine Plugins gefunden.", + "admin_plugins.available_fetching": "Wird abgerufen...", "admin_plugins.available_install.value": "Installieren", + "admin_plugins.available_search.placeholder": "Suche nach Plugins zum Installieren", "admin_plugins.description": "Beschreibung", + "admin_plugins.installed": "Installierte Plugins", + "admin_plugins.installed_fetching": "Rufe installierte Plugins ab...", "admin_plugins.installed_nothing": "Du hast bisher noch keine Plugins installiert.", + "admin_plugins.installed_uninstall.value": "Deinstallieren", "admin_plugins.last-update": "Letze Aktualisierung", "admin_plugins.name": "Name", + "admin_plugins.page-title": "Plugin Manager - Etherpad", "admin_plugins.version": "Version", + "admin_plugins_info": "Hilfestellung", "admin_plugins_info.hooks": "Installierte Hooks", + "admin_plugins_info.hooks_client": "Client-seitige Hooks", + "admin_plugins_info.hooks_server": "Server-seitige Hooks", + "admin_plugins_info.parts": "Installierte Teile", "admin_plugins_info.plugins": "Installierte Plugins", + "admin_plugins_info.page-title": "Plugin Informationen - Etherpad", + "admin_plugins_info.version": "Etherpad Version", + "admin_plugins_info.version_latest": "Neueste Version", "admin_plugins_info.version_number": "Versionsnummer", "admin_settings": "Einstellungen", "admin_settings.current": "Derzeitige Konfiguration", + "admin_settings.current_example-devel": "Beispielhafte Entwicklungseinstellungs-Templates", + "admin_settings.current_restart.value": "Etherpad neustarten", "admin_settings.current_save.value": "Einstellungen speichern", + "admin_settings.page-title": "Einstellungen - Etherpad", "index.newPad": "Neues Pad", "index.createOpenPad": "oder ein Pad mit folgendem Namen erstellen/öffnen:", "index.openPad": "Öffne ein vorhandenes Pad mit folgendem Namen:", @@ -78,7 +96,7 @@ "pad.importExport.exportopen": "ODF (Open Document Format)", "pad.importExport.abiword.innerHTML": "Du kannst nur aus reinen Text- oder HTML-Formaten importieren. Für umfangreichere Importfunktionen muss AbiWord oder LibreOffice auf dem Server installiert werden.", "pad.modals.connected": "Verbunden.", - "pad.modals.reconnecting": "Wiederherstellen der Verbindung …", + "pad.modals.reconnecting": "Dein Pad wird neu verbunden...", "pad.modals.forcereconnect": "Erneutes Verbinden erzwingen", "pad.modals.reconnecttimer": "Versuche Neuverbindung in", "pad.modals.cancel": "Abbrechen", @@ -102,6 +120,7 @@ "pad.modals.deleted.explanation": "Dieses Pad wurde entfernt.", "pad.modals.rateLimited": "Begrenzte Rate.", "pad.modals.rateLimited.explanation": "Sie haben zu viele Nachrichten an dieses Pad gesendet, so dass die Verbindung unterbrochen wurde.", + "pad.modals.rejected.explanation": "Der Server hat eine Nachricht abgelehnt, die von deinem Browser gesendet wurde.", "pad.modals.disconnected": "Ihre Verbindung wurde getrennt.", "pad.modals.disconnected.explanation": "Die Verbindung zum Server wurde unterbrochen.", "pad.modals.disconnected.cause": "Möglicherweise ist der Server nicht erreichbar. Bitte benachrichtige den Dienstadministrator, falls dies weiterhin passiert.", diff --git a/src/locales/fi.json b/src/locales/fi.json index 2af040a3d..9f569d44b 100644 --- a/src/locales/fi.json +++ b/src/locales/fi.json @@ -18,6 +18,7 @@ "VezonThunder" ] }, + "admin_plugins.available": "Saatavilla olevat liitännäiset", "admin_plugins.available_install.value": "Lataa", "admin_plugins.available_search.placeholder": "Etsi asennettavia laajennuksia", "admin_plugins.description": "Kuvaus", @@ -92,7 +93,7 @@ "pad.importExport.exportopen": "ODF (Open Document Format)", "pad.importExport.abiword.innerHTML": "Tuonti on tuettu vain HTML- ja raakatekstitiedostoista. Monipuoliset tuontiominaisuudet ovat käytettävissä asentamalla AbiWordin tai LibreOfficen.", "pad.modals.connected": "Yhdistetty.", - "pad.modals.reconnecting": "Muodostetaan yhteyttä muistioon uudelleen...", + "pad.modals.reconnecting": "Muodostetaan yhteyttä muistioon uudelleen…", "pad.modals.forcereconnect": "Pakota yhdistämään uudelleen", "pad.modals.reconnecttimer": "Yritetään yhdistää uudelleen", "pad.modals.cancel": "Peruuta", diff --git a/src/locales/sl.json b/src/locales/sl.json index 0314f07ce..5ceb49d34 100644 --- a/src/locales/sl.json +++ b/src/locales/sl.json @@ -9,6 +9,10 @@ "Upwinxp" ] }, + "admin_plugins.last-update": "Zadnja posodobitev", + "admin_plugins.name": "Ime", + "admin_plugins.version": "Različica", + "admin_settings": "Nastavitve", "index.newPad": "Nov dokument", "index.createOpenPad": "ali pa ustvari/odpri dokument z imenom:", "pad.toolbar.bold.title": "Krepko (Ctrl-B)", @@ -54,7 +58,7 @@ "pad.importExport.exportword": "DOC (zapis Microsoft Word)", "pad.importExport.exportpdf": "PDF (zapis Acrobat PDF)", "pad.importExport.exportopen": "ODF (zapis Open Document)", - "pad.importExport.abiword.innerHTML": "Uvoziti je mogoče le običajno neoblikovano besedilo in zapise HTML. Za naprednejše zmožnosti namestite program AbiWord.", + "pad.importExport.abiword.innerHTML": "Uvoziti je mogoče le neoblikovano besedilo in zapise HTML. Za naprednejše možnosti uvoza namestite program AbiWord.", "pad.modals.connected": "Povezano.", "pad.modals.reconnecting": "Poteka povezovanje z dokumentom ...", "pad.modals.forcereconnect": "Vsili ponovno povezavo", @@ -64,7 +68,7 @@ "pad.modals.userdup.explanation": "Videti je, da je ta dokument odprt v več kot enem oknu brskalnika na tem računalniku.", "pad.modals.userdup.advice": "Ponovno vzpostavite povezavo in uporabljajte to okno.", "pad.modals.unauth": "Nepooblaščen dostop", - "pad.modals.unauth.explanation": "Med pregledovanjem te strani so se dovoljenja za ogled spremenila. Poskusite se ponovno povezati.", + "pad.modals.unauth.explanation": "Med ogledovanjem strani so se dovoljenja za ogled spremenila. Poskusite se znova povezati.", "pad.modals.looping.explanation": "Zaznane so težave pri komunikaciji s strežnikom za usklajevanje.", "pad.modals.looping.cause": "Morda ste se povezali preko neustrezno nastavljenega požarnega zidu ali posredniškega strežnika.", "pad.modals.initsocketfail": "Strežnik je nedosegljiv.", From f6eb6bd266ff90094159540decd5bb721ab2d21b Mon Sep 17 00:00:00 2001 From: John McLear Date: Mon, 21 Dec 2020 20:25:17 +0000 Subject: [PATCH 095/153] remove dead object code --- src/static/js/ace2_common.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/static/js/ace2_common.js b/src/static/js/ace2_common.js index 9055b34e3..9322a1d41 100644 --- a/src/static/js/ace2_common.js +++ b/src/static/js/ace2_common.js @@ -26,12 +26,6 @@ function isNodeText(node) { return (node.nodeType == 3); } -function object(o) { - const f = function () {}; - f.prototype = o; - return new f(); -} - function getAssoc(obj, name) { return obj[`_magicdom_${name}`]; } @@ -75,7 +69,6 @@ function htmlPrettyEscape(str) { const noop = function () {}; exports.isNodeText = isNodeText; -exports.object = object; exports.getAssoc = getAssoc; exports.setAssoc = setAssoc; exports.binarySearch = binarySearch; From 5d7645e36add1862fbd5b07c4ee4efac4d454956 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 15 Dec 2020 15:37:28 +0000 Subject: [PATCH 096/153] lint: ace2_common.js linting --- src/static/js/ace2_common.js | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/static/js/ace2_common.js b/src/static/js/ace2_common.js index 9322a1d41..d3f86f699 100644 --- a/src/static/js/ace2_common.js +++ b/src/static/js/ace2_common.js @@ -1,3 +1,5 @@ +'use strict'; + /** * This code is mostly from the old Etherpad. Please help us to comment this code. * This helps other people to understand this code better and helps them to improve it. @@ -22,27 +24,23 @@ const Security = require('./security'); -function isNodeText(node) { - return (node.nodeType == 3); -} +const isNodeText = (node) => (node.nodeType === 3); -function getAssoc(obj, name) { - return obj[`_magicdom_${name}`]; -} +const getAssoc = (obj, name) => obj[`_magicdom_${name}`]; -function setAssoc(obj, name, value) { +const setAssoc = (obj, name, value) => { // note that in IE designMode, properties of a node can get // copied to new nodes that are spawned during editing; also, // properties representable in HTML text can survive copy-and-paste obj[`_magicdom_${name}`] = value; -} +}; // "func" is a function over 0..(numItems-1) that is monotonically // "increasing" with index (false, then true). Finds the boundary // between false and true, a number between 0 and numItems inclusive. -function binarySearch(numItems, func) { +const binarySearch = (numItems, func) => { if (numItems < 1) return 0; if (func(0)) return 0; if (!func(numItems - 1)) return numItems; @@ -54,19 +52,17 @@ function binarySearch(numItems, func) { else low = x; } return high; -} +}; -function binarySearchInfinite(expectedLength, func) { +const binarySearchInfinite = (expectedLength, func) => { let i = 0; while (!func(i)) i += expectedLength; return binarySearch(i, func); -} +}; -function htmlPrettyEscape(str) { - return Security.escapeHTML(str).replace(/\r?\n/g, '\\n'); -} +const htmlPrettyEscape = (str) => Security.escapeHTML(str).replace(/\r?\n/g, '\\n'); -const noop = function () {}; +const noop = () => {}; exports.isNodeText = isNodeText; exports.getAssoc = getAssoc; From b02ab430fe0337abf588c9a57cb446262d244954 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 29 Jan 2021 01:00:33 -0500 Subject: [PATCH 097/153] Bump eslint-config-etherpad to 1.0.24 --- bin/plugins/checkPlugin.js | 6 +- package-lock.json | 174 ++++++++++++++++++++++++------------- package.json | 6 +- src/package-lock.json | 12 +-- src/package.json | 6 +- 5 files changed, 129 insertions(+), 75 deletions(-) diff --git a/bin/plugins/checkPlugin.js b/bin/plugins/checkPlugin.js index 3b8c0b31a..cbe146aa1 100755 --- a/bin/plugins/checkPlugin.js +++ b/bin/plugins/checkPlugin.js @@ -220,12 +220,12 @@ fs.readdir(pluginPath, (err, rootFiles) => { } updateDeps(parsedPackageJSON, 'devDependencies', { - 'eslint': '^7.17.0', - 'eslint-config-etherpad': '^1.0.22', + 'eslint': '^7.18.0', + 'eslint-config-etherpad': '^1.0.24', 'eslint-plugin-eslint-comments': '^3.2.0', 'eslint-plugin-mocha': '^8.0.0', 'eslint-plugin-node': '^11.1.0', - 'eslint-plugin-prefer-arrow': '^1.2.2', + 'eslint-plugin-prefer-arrow': '^1.2.3', 'eslint-plugin-promise': '^4.2.1', 'eslint-plugin-you-dont-need-lodash-underscore': '^6.10.0', }); diff --git a/package-lock.json b/package-lock.json index 4ac678d3f..4dcc411d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -74,9 +74,9 @@ } }, "@eslint/eslintrc": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz", - "integrity": "sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz", + "integrity": "sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg==", "dev": true, "requires": { "ajv": "^6.12.4", @@ -86,7 +86,7 @@ "ignore": "^4.0.6", "import-fresh": "^3.2.1", "js-yaml": "^3.13.1", - "lodash": "^4.17.19", + "lodash": "^4.17.20", "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" } @@ -321,9 +321,9 @@ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true }, "async": { @@ -743,9 +743,9 @@ } }, "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, "engine.io": { @@ -2450,6 +2450,11 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" } } }, @@ -8410,13 +8415,13 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "eslint": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.15.0.tgz", - "integrity": "sha512-Vr64xFDT8w30wFll643e7cGrIkPEU50yIiI36OdSIDoSGguIeaLzBo0vpGvzo9RECUqq7htURfwEtKqwytkqzA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.18.0.tgz", + "integrity": "sha512-fbgTiE8BfUJZuBeq2Yi7J3RB3WGUQ9PNuNbmgi6jt9Iv8qrkxfy19Ds3OpL1Pm7zg3BtTVhvcUZbIRQ0wmSjAQ==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@eslint/eslintrc": "^0.2.2", + "@eslint/eslintrc": "^0.3.0", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -8440,7 +8445,7 @@ "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", - "lodash": "^4.17.19", + "lodash": "^4.17.20", "minimatch": "^3.0.4", "natural-compare": "^1.4.0", "optionator": "^0.9.1", @@ -8449,15 +8454,15 @@ "semver": "^7.2.1", "strip-ansi": "^6.0.0", "strip-json-comments": "^3.1.0", - "table": "^5.2.3", + "table": "^6.0.4", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" } }, "eslint-config-etherpad": { - "version": "1.0.20", - "resolved": "https://registry.npmjs.org/eslint-config-etherpad/-/eslint-config-etherpad-1.0.20.tgz", - "integrity": "sha512-dDEmWphxOmYe7XC0Uevzb0lK7o1jDBGwYMMCdNeZlgo2EfJljnijPgodlimM4R+4OsnfegEMY6rdWoXjzdd5Rw==", + "version": "1.0.24", + "resolved": "https://registry.npmjs.org/eslint-config-etherpad/-/eslint-config-etherpad-1.0.24.tgz", + "integrity": "sha512-zM92/lricP0ALURQWhSFKk8gwDUVkgNiup/Gv5lly6bHj9OIMpK86SlLv/NPkQZYM609pyQjKIeiObsiCSdQsw==", "dev": true }, "eslint-plugin-es": { @@ -8527,9 +8532,9 @@ } }, "eslint-plugin-prefer-arrow": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-prefer-arrow/-/eslint-plugin-prefer-arrow-1.2.2.tgz", - "integrity": "sha512-C8YMhL+r8RMeMdYAw/rQtE6xNdMulj+zGWud/qIGnlmomiPRaLDGLMeskZ3alN6uMBojmooRimtdrXebLN4svQ==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prefer-arrow/-/eslint-plugin-prefer-arrow-1.2.3.tgz", + "integrity": "sha512-J9I5PKCOJretVuiZRGvPQxCbllxGAV/viI20JO3LYblAodofBxyMnZAJ+WGeClHgANnSJberTNoFWWjrWKBuXQ==", "dev": true }, "eslint-plugin-promise": { @@ -8702,9 +8707,9 @@ } }, "flatted": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.0.tgz", - "integrity": "sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", + "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", "dev": true }, "forever-agent": { @@ -8977,9 +8982,9 @@ } }, "import-fresh": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.2.tgz", - "integrity": "sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "requires": { "parent-module": "^1.0.0", @@ -9869,6 +9874,12 @@ } } }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, "require_optional": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", @@ -9992,14 +10003,46 @@ } }, "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + } } }, "socket.io": { @@ -10176,30 +10219,21 @@ } }, "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", "dev": true, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } } } }, @@ -10243,15 +10277,35 @@ } }, "table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/table/-/table-6.0.7.tgz", + "integrity": "sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g==", "dev": true, "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" + "ajv": "^7.0.2", + "lodash": "^4.17.20", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0" + }, + "dependencies": { + "ajv": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.0.3.tgz", + "integrity": "sha512-R50QRlXSxqXcQP5SvKUrw8VZeypvo12i2IX0EeR5PiZ7bEKeHWgzgo264LDadUsCU42lTJVhFikTqJwNeH34gQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } } }, "tar": { diff --git a/package.json b/package.json index 1704f8816..41e472831 100644 --- a/package.json +++ b/package.json @@ -3,12 +3,12 @@ "ep_etherpad-lite": "file:src" }, "devDependencies": { - "eslint": "^7.15.0", - "eslint-config-etherpad": "^1.0.20", + "eslint": "^7.18.0", + "eslint-config-etherpad": "^1.0.24", "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-mocha": "^8.0.0", "eslint-plugin-node": "^11.1.0", - "eslint-plugin-prefer-arrow": "^1.2.2", + "eslint-plugin-prefer-arrow": "^1.2.3", "eslint-plugin-promise": "^4.2.1", "eslint-plugin-you-dont-need-lodash-underscore": "^6.10.0" }, diff --git a/src/package-lock.json b/src/package-lock.json index f4f145474..3a5a35ad0 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -2176,9 +2176,9 @@ } }, "eslint-config-etherpad": { - "version": "1.0.23", - "resolved": "https://registry.npmjs.org/eslint-config-etherpad/-/eslint-config-etherpad-1.0.23.tgz", - "integrity": "sha512-/yMp7aK5zg309DgNIDotl+CtxrDq5ovwVz5ScmjOZgRgaG1rHhtUX5BFewOaoRlYGg+F2xYkqZ5Zhh9fgjs/jg==", + "version": "1.0.24", + "resolved": "https://registry.npmjs.org/eslint-config-etherpad/-/eslint-config-etherpad-1.0.24.tgz", + "integrity": "sha512-zM92/lricP0ALURQWhSFKk8gwDUVkgNiup/Gv5lly6bHj9OIMpK86SlLv/NPkQZYM609pyQjKIeiObsiCSdQsw==", "dev": true }, "eslint-plugin-es": { @@ -2258,9 +2258,9 @@ } }, "eslint-plugin-prefer-arrow": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-prefer-arrow/-/eslint-plugin-prefer-arrow-1.2.2.tgz", - "integrity": "sha512-C8YMhL+r8RMeMdYAw/rQtE6xNdMulj+zGWud/qIGnlmomiPRaLDGLMeskZ3alN6uMBojmooRimtdrXebLN4svQ==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prefer-arrow/-/eslint-plugin-prefer-arrow-1.2.3.tgz", + "integrity": "sha512-J9I5PKCOJretVuiZRGvPQxCbllxGAV/viI20JO3LYblAodofBxyMnZAJ+WGeClHgANnSJberTNoFWWjrWKBuXQ==", "dev": true }, "eslint-plugin-promise": { diff --git a/src/package.json b/src/package.json index dffcd3fed..dd6525d36 100644 --- a/src/package.json +++ b/src/package.json @@ -78,12 +78,12 @@ "etherpad-lite": "node/server.js" }, "devDependencies": { - "eslint": "^7.15.0", - "eslint-config-etherpad": "^1.0.20", + "eslint": "^7.18.0", + "eslint-config-etherpad": "^1.0.24", "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-mocha": "^8.0.0", "eslint-plugin-node": "^11.1.0", - "eslint-plugin-prefer-arrow": "^1.2.2", + "eslint-plugin-prefer-arrow": "^1.2.3", "eslint-plugin-promise": "^4.2.1", "eslint-plugin-you-dont-need-lodash-underscore": "^6.10.0", "etherpad-cli-client": "0.0.9", From c1ef12b8da5fe2bd4be130fd9f777cf088bf05d4 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 29 Jan 2021 01:14:03 -0500 Subject: [PATCH 098/153] lint: Re-run eslint --fix --- src/node/handler/PadMessageHandler.js | 2 +- src/static/js/pad_automatic_reconnect.js | 2 +- src/static/js/pluginfw/tsort.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js index 99cac5ca4..01981d1f0 100644 --- a/src/node/handler/PadMessageHandler.js +++ b/src/node/handler/PadMessageHandler.js @@ -1217,7 +1217,7 @@ const handleChangesetRequest = async (socket, message) => { socket.json.send({type: 'CHANGESET_REQ', data}); } catch (err) { console.error(`Error while handling a changeset request for ${padIds.padId}`, - err.toString(), message.data); + err.toString(), message.data); } }; diff --git a/src/static/js/pad_automatic_reconnect.js b/src/static/js/pad_automatic_reconnect.js index db803e896..9d9ee953a 100644 --- a/src/static/js/pad_automatic_reconnect.js +++ b/src/static/js/pad_automatic_reconnect.js @@ -113,7 +113,7 @@ const reconnectionTries = { nextTry() { // double the time to try to reconnect on every time reconnection fails - const nextCounterFactor = Math.pow(2, this.counter); + const nextCounterFactor = 2 ** this.counter; this.counter++; return nextCounterFactor; diff --git a/src/static/js/pluginfw/tsort.js b/src/static/js/pluginfw/tsort.js index f988de3ad..e584ada29 100644 --- a/src/static/js/pluginfw/tsort.js +++ b/src/static/js/pluginfw/tsort.js @@ -55,7 +55,7 @@ const tsort = (edges) => { Object.keys(nodes).forEach(visit); return sorted; -} +}; /** * TEST From 8efc87f33a88cb1dec4b8e88ca2193e3eb63a225 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 29 Jan 2021 02:55:02 -0500 Subject: [PATCH 099/153] AttributeManager: Fix bogus `this` during attribute removal Before this commit, the callback passed to `.map()` during attribute removal was a normal function, not an arrow function. This meant that the value of `this` in the function body depended on how the callback was invoked. In this case, the callback was invoked without any explicit context (it was not called as a method, nor was it called via `.call()`, `.apply()`, or `.bind()`). Without any explicit context, the value of `this` depends on strict mode. Currently the function is in sloppy mode, so `this` refers to the "global this" object (a.k.a., `window`). It doesn't make sense for the callback to reference `window.author`, so I'm assuming the previous behavior was a bug. Now the function is an arrow function, so the value of `this` comes from the enclosing lexical context, which in this case is the AttributeManager object. I believe that was the original intention. --- src/static/js/AttributeManager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/static/js/AttributeManager.js b/src/static/js/AttributeManager.js index c1257a9bc..32df255da 100644 --- a/src/static/js/AttributeManager.js +++ b/src/static/js/AttributeManager.js @@ -349,7 +349,7 @@ AttributeManager.prototype = _(AttributeManager.prototype).extend({ const hasMarker = this.lineHasMarker(lineNum); let found = false; - const attribs = _(this.getAttributesOnLine(lineNum)).map(function (attrib) { + const attribs = _(this.getAttributesOnLine(lineNum)).map((attrib) => { if (attrib[0] === attributeName && (!attributeValue || attrib[0] === attributeValue)) { found = true; return [attributeName, '']; From 462530eafb6116b490177ff3b7f6a7f2ce7cbe74 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 29 Jan 2021 03:01:05 -0500 Subject: [PATCH 100/153] AttributeManager: Fix attribute name during attribute removal Before this change, the `author` attribute was silently discarded during `.map()` iteration and the name of the attribute to remove was included twice with two different values. --- src/static/js/AttributeManager.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/static/js/AttributeManager.js b/src/static/js/AttributeManager.js index 32df255da..336364196 100644 --- a/src/static/js/AttributeManager.js +++ b/src/static/js/AttributeManager.js @@ -352,10 +352,10 @@ AttributeManager.prototype = _(AttributeManager.prototype).extend({ const attribs = _(this.getAttributesOnLine(lineNum)).map((attrib) => { if (attrib[0] === attributeName && (!attributeValue || attrib[0] === attributeValue)) { found = true; - return [attributeName, '']; + return [attrib[0], '']; } else if (attrib[0] === 'author') { // update last author to make changes to line attributes on this line - return [attributeName, this.author]; + return [attrib[0], this.author]; } return attrib; }); From 873987f98988ec7708f091482a4828e89f59ccfd Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 29 Jan 2021 03:05:08 -0500 Subject: [PATCH 101/153] tests: Asyncify indentation test This makes it much easier to see why a test is failing. Before, a `helper.waitFor()` failure would simply cause the test to time out. Now an exception is displayed. --- tests/frontend/specs/indentation.js | 50 ++++++++++++++--------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/tests/frontend/specs/indentation.js b/tests/frontend/specs/indentation.js index f35b7ca00..c52f5f406 100644 --- a/tests/frontend/specs/indentation.js +++ b/tests/frontend/specs/indentation.js @@ -130,41 +130,39 @@ describe('indentation button', function () { }); }); - it("issue #2772 shows '*' when multiple indented lines receive a style and are outdented", function (done) { + it("issue #2772 shows '*' when multiple indented lines receive a style and are outdented", async function () { const inner$ = helper.padInner$; const chrome$ = helper.padChrome$; // make sure pad has more than one line inner$('div').first().sendkeys('First{enter}Second{enter}'); - helper.waitFor(() => inner$('div').first().text().trim() === 'First').done(() => { - // indent first 2 lines - const $lines = inner$('div'); - const $firstLine = $lines.first(); - const $secondLine = $lines.slice(1, 2); - helper.selectLines($firstLine, $secondLine); + await helper.waitForPromise(() => inner$('div').first().text().trim() === 'First'); - const $indentButton = chrome$('.buttonicon-indent'); - $indentButton.click(); + // indent first 2 lines + const $lines = inner$('div'); + const $firstLine = $lines.first(); + let $secondLine = $lines.slice(1, 2); + helper.selectLines($firstLine, $secondLine); - helper.waitFor(() => inner$('div').first().find('ul li').length === 1).done(() => { - // apply bold - const $boldButton = chrome$('.buttonicon-bold'); - $boldButton.click(); + const $indentButton = chrome$('.buttonicon-indent'); + $indentButton.click(); - helper.waitFor(() => inner$('div').first().find('b').length === 1).done(() => { - // outdent first 2 lines - const $outdentButton = chrome$('.buttonicon-outdent'); - $outdentButton.click(); - helper.waitFor(() => inner$('div').first().find('ul li').length === 0).done(() => { - // check if '*' is displayed - const $secondLine = inner$('div').slice(1, 2); - expect($secondLine.text().trim()).to.be('Second'); + await helper.waitForPromise(() => inner$('div').first().find('ul li').length === 1); - done(); - }); - }); - }); - }); + // apply bold + const $boldButton = chrome$('.buttonicon-bold'); + $boldButton.click(); + + await helper.waitForPromise(() => inner$('div').first().find('b').length === 1); + + // outdent first 2 lines + const $outdentButton = chrome$('.buttonicon-outdent'); + $outdentButton.click(); + await helper.waitForPromise(() => inner$('div').first().find('ul li').length === 0); + + // check if '*' is displayed + $secondLine = inner$('div').slice(1, 2); + expect($secondLine.text().trim()).to.be('Second'); }); /* From 0897a28e70a29f084ca6a7a3b6b9bc8a242fa06c Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 15 Dec 2020 15:42:10 +0000 Subject: [PATCH 102/153] lint: AttributeManager --- src/static/js/AttributeManager.js | 52 +++++++++++++++++-------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/src/static/js/AttributeManager.js b/src/static/js/AttributeManager.js index 336364196..19424b0a7 100644 --- a/src/static/js/AttributeManager.js +++ b/src/static/js/AttributeManager.js @@ -1,3 +1,5 @@ +'use strict'; + const Changeset = require('./Changeset'); const ChangesetUtils = require('./ChangesetUtils'); const _ = require('./underscore'); @@ -72,10 +74,12 @@ AttributeManager.prototype = _(AttributeManager.prototype).extend({ const rowChangeset = this._setAttributesOnRangeByLine(row, startCol, endCol, attribs); - // compose changesets of all rows into a single changeset, as the range might not be continuous + // compose changesets of all rows into a single changeset + // as the range might not be continuous // due to the presence of line markers on the rows if (allChangesets) { - allChangesets = Changeset.compose(allChangesets.toString(), rowChangeset.toString(), this.rep.apool); + allChangesets = Changeset.compose( + allChangesets.toString(), rowChangeset.toString(), this.rep.apool); } else { allChangesets = rowChangeset; } @@ -118,7 +122,8 @@ AttributeManager.prototype = _(AttributeManager.prototype).extend({ _setAttributesOnRangeByLine(row, startCol, endCol, attribs) { const builder = Changeset.builder(this.rep.lines.totalWidth()); ChangesetUtils.buildKeepToStartOfRange(this.rep, builder, [row, startCol]); - ChangesetUtils.buildKeepRange(this.rep, builder, [row, startCol], [row, endCol], attribs, this.rep.apool); + ChangesetUtils.buildKeepRange( + this.rep, builder, [row, startCol], [row, endCol], attribs, this.rep.apool); return builder; }, @@ -127,9 +132,8 @@ AttributeManager.prototype = _(AttributeManager.prototype).extend({ @param lineNum: the number of the line */ lineHasMarker(lineNum) { - const that = this; - - return _.find(lineAttributes, (attribute) => that.getAttributeOnLine(lineNum, attribute) != '') !== undefined; + return lineAttributes.find( + (attribute) => this.getAttributeOnLine(lineNum, attribute) !== '') !== undefined; }, /* @@ -184,7 +188,7 @@ AttributeManager.prototype = _(AttributeManager.prototype).extend({ if (!(rep.selStart && rep.selEnd)) return; // If we're looking for the caret attribute not the selection // has the user already got a selection or is this purely a caret location? - const isNotSelection = (rep.selStart[0] == rep.selEnd[0] && rep.selEnd[1] === rep.selStart[1]); + const isNotSelection = (rep.selStart[0] === rep.selEnd[0] && rep.selEnd[1] === rep.selStart[1]); if (isNotSelection) { if (prevChar) { // If it's not the start of the line @@ -198,21 +202,18 @@ AttributeManager.prototype = _(AttributeManager.prototype).extend({ [attributeName, 'true'], ], rep.apool); const withItRegex = new RegExp(`${withIt.replace(/\*/g, '\\*')}(\\*|$)`); - function hasIt(attribs) { - return withItRegex.test(attribs); - } + const hasIt = (attribs) => withItRegex.test(attribs); - return rangeHasAttrib(rep.selStart, rep.selEnd); - - function rangeHasAttrib(selStart, selEnd) { + const rangeHasAttrib = (selStart, selEnd) => { // if range is collapsed -> no attribs in range - if (selStart[1] == selEnd[1] && selStart[0] == selEnd[0]) return false; + if (selStart[1] === selEnd[1] && selStart[0] === selEnd[0]) return false; - if (selStart[0] != selEnd[0]) { // -> More than one line selected - var hasAttrib = true; + if (selStart[0] !== selEnd[0]) { // -> More than one line selected + let hasAttrib = true; // from selStart to the end of the first line - hasAttrib = hasAttrib && rangeHasAttrib(selStart, [selStart[0], rep.lines.atIndex(selStart[0]).text.length]); + hasAttrib = hasAttrib && rangeHasAttrib( + selStart, [selStart[0], rep.lines.atIndex(selStart[0]).text.length]); // for all lines in between for (let n = selStart[0] + 1; n < selEnd[0]; n++) { @@ -230,7 +231,7 @@ AttributeManager.prototype = _(AttributeManager.prototype).extend({ const lineNum = selStart[0]; const start = selStart[1]; const end = selEnd[1]; - var hasAttrib = true; + let hasAttrib = true; // Iterate over attribs on this line @@ -244,7 +245,8 @@ AttributeManager.prototype = _(AttributeManager.prototype).extend({ if (!hasIt(op.attribs)) { // does op overlap selection? if (!(opEndInLine <= start || opStartInLine >= end)) { - hasAttrib = false; // since it's overlapping but hasn't got the attrib -> range hasn't got it + // since it's overlapping but hasn't got the attrib -> range hasn't got it + hasAttrib = false; break; } } @@ -252,7 +254,8 @@ AttributeManager.prototype = _(AttributeManager.prototype).extend({ } return hasAttrib; - } + }; + return rangeHasAttrib(rep.selStart, rep.selEnd); }, /* @@ -349,7 +352,7 @@ AttributeManager.prototype = _(AttributeManager.prototype).extend({ const hasMarker = this.lineHasMarker(lineNum); let found = false; - const attribs = _(this.getAttributesOnLine(lineNum)).map((attrib) => { + const attribs = this.getAttributesOnLine(lineNum).map((attrib) => { if (attrib[0] === attributeName && (!attributeValue || attrib[0] === attributeValue)) { found = true; return [attrib[0], '']; @@ -373,7 +376,8 @@ AttributeManager.prototype = _(AttributeManager.prototype).extend({ if (hasMarker && !countAttribsWithMarker) { ChangesetUtils.buildRemoveRange(this.rep, builder, [lineNum, 0], [lineNum, 1]); } else { - ChangesetUtils.buildKeepRange(this.rep, builder, [lineNum, 0], [lineNum, 1], attribs, this.rep.apool); + ChangesetUtils.buildKeepRange( + this.rep, builder, [lineNum, 0], [lineNum, 1], attribs, this.rep.apool); } return this.applyChangeset(builder); @@ -394,7 +398,9 @@ AttributeManager.prototype = _(AttributeManager.prototype).extend({ }, hasAttributeOnSelectionOrCaretPosition(attributeName) { - const hasSelection = ((this.rep.selStart[0] !== this.rep.selEnd[0]) || (this.rep.selEnd[1] !== this.rep.selStart[1])); + const hasSelection = ( + (this.rep.selStart[0] !== this.rep.selEnd[0]) || (this.rep.selEnd[1] !== this.rep.selStart[1]) + ); let hasAttrib; if (hasSelection) { hasAttrib = this.getAttributeOnSelection(attributeName); From 89bcfa2b4af8b2c034cae74c384f0b9890d13c76 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 29 Jan 2021 03:20:41 -0500 Subject: [PATCH 103/153] tests: Stop using nyc There are some problems with nyc: * The coverage numbers aren't useful in our case because most of the code is executed outside the test process (the test code is mostly API client logic). * nyc messes with line numbers, which makes it much harder to debug problems. * We're seeing frequent SIGABRT crashes while nyc is printing the results table. I'm not sure if nyc is the cause of the crashes, or if it's making a race condition worse, or if the crashes have nothing to do with nyc, but we don't lose much by removing it so we might as well see if the crash frequency improves. --- src/package-lock.json | 984 +----------------------------------------- src/package.json | 5 +- 2 files changed, 4 insertions(+), 985 deletions(-) diff --git a/src/package-lock.json b/src/package-lock.json index 3a5a35ad0..3e04ec287 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -101,182 +101,12 @@ "@babel/highlight": "^7.10.4" } }, - "@babel/core": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.10.tgz", - "integrity": "sha512-eTAlQKq65zHfkHZV0sIVODCPGVgoo1HdBlbSLi9CqOzuZanMv2ihzY+4paiKr1mH+XmYESMAmJ/dpZ68eN6d8w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.10", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.5", - "@babel/parser": "^7.12.10", - "@babel/template": "^7.12.7", - "@babel/traverse": "^7.12.10", - "@babel/types": "^7.12.10", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.19", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.11.tgz", - "integrity": "sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA==", - "dev": true, - "requires": { - "@babel/types": "^7.12.11", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/helper-function-name": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz", - "integrity": "sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.12.10", - "@babel/template": "^7.12.7", - "@babel/types": "^7.12.11" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz", - "integrity": "sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag==", - "dev": true, - "requires": { - "@babel/types": "^7.12.10" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz", - "integrity": "sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw==", - "dev": true, - "requires": { - "@babel/types": "^7.12.7" - } - }, - "@babel/helper-module-imports": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz", - "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", - "dev": true, - "requires": { - "@babel/types": "^7.12.5" - } - }, - "@babel/helper-module-transforms": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz", - "integrity": "sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.12.1", - "@babel/helper-replace-supers": "^7.12.1", - "@babel/helper-simple-access": "^7.12.1", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/helper-validator-identifier": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.1", - "@babel/types": "^7.12.1", - "lodash": "^4.17.19" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.10.tgz", - "integrity": "sha512-4tpbU0SrSTjjt65UMWSrUOPZTsgvPgGG4S8QSTNHacKzpS51IVWGDj0yCwyeZND/i+LSN2g/O63jEXEWm49sYQ==", - "dev": true, - "requires": { - "@babel/types": "^7.12.10" - } - }, - "@babel/helper-replace-supers": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.11.tgz", - "integrity": "sha512-q+w1cqmhL7R0FNzth/PLLp2N+scXEK/L2AHbXUyydxp828F4FEa5WcVoqui9vFRiHDQErj9Zof8azP32uGVTRA==", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.12.7", - "@babel/helper-optimise-call-expression": "^7.12.10", - "@babel/traverse": "^7.12.10", - "@babel/types": "^7.12.11" - } - }, - "@babel/helper-simple-access": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz", - "integrity": "sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==", - "dev": true, - "requires": { - "@babel/types": "^7.12.1" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz", - "integrity": "sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g==", - "dev": true, - "requires": { - "@babel/types": "^7.12.11" - } - }, "@babel/helper-validator-identifier": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", "dev": true }, - "@babel/helpers": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.5.tgz", - "integrity": "sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==", - "dev": true, - "requires": { - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.5", - "@babel/types": "^7.12.5" - } - }, "@babel/highlight": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", @@ -319,74 +149,6 @@ } } }, - "@babel/parser": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.11.tgz", - "integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==", - "dev": true - }, - "@babel/template": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz", - "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.12.7", - "@babel/types": "^7.12.7" - } - }, - "@babel/traverse": { - "version": "7.12.12", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.12.tgz", - "integrity": "sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.11", - "@babel/generator": "^7.12.11", - "@babel/helper-function-name": "^7.12.11", - "@babel/helper-split-export-declaration": "^7.12.11", - "@babel/parser": "^7.12.11", - "@babel/types": "^7.12.12", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" - }, - "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.12.12", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz", - "integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - }, "@eslint/eslintrc": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz", @@ -428,67 +190,6 @@ } } }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "@istanbuljs/schema": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", - "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", - "dev": true - }, "@js-joda/core": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/@js-joda/core/-/core-3.2.0.tgz", @@ -715,16 +416,6 @@ "humanize-ms": "^1.2.1" } }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -762,15 +453,6 @@ "picomatch": "^2.0.4" } }, - "append-transform": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", - "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", - "dev": true, - "requires": { - "default-require-extensions": "^3.0.0" - } - }, "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", @@ -859,12 +541,6 @@ } } }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true - }, "are-we-there-yet": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", @@ -1217,18 +893,6 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" }, - "caching-transform": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", - "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", - "dev": true, - "requires": { - "hasha": "^5.0.0", - "make-dir": "^3.0.0", - "package-hash": "^4.0.0", - "write-file-atomic": "^3.0.0" - } - }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -1356,12 +1020,6 @@ "source-map": "~0.6.0" } }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true - }, "cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", @@ -1476,12 +1134,6 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, "component-bind": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", @@ -1578,23 +1230,6 @@ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, - "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - }, - "dependencies": { - "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==", - "dev": true - } - } - }, "cookie": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", @@ -1721,15 +1356,6 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, - "default-require-extensions": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", - "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", - "dev": true, - "requires": { - "strip-bom": "^4.0.0" - } - }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -2018,12 +1644,6 @@ "is-symbol": "^1.0.2" } }, - "es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true - }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -2550,17 +2170,6 @@ "unpipe": "~1.0.0" } }, - "find-cache-dir": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", - "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - } - }, "find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", @@ -2611,16 +2220,6 @@ "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", "dev": true }, - "foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - } - }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -2651,12 +2250,6 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, - "fromentries": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", - "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", - "dev": true - }, "fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -2724,12 +2317,6 @@ "wide-align": "^1.1.0" } }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -2747,12 +2334,6 @@ "has-symbols": "^1.0.1" } }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -2872,16 +2453,6 @@ "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "optional": true }, - "hasha": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", - "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", - "dev": true, - "requires": { - "is-stream": "^2.0.0", - "type-fest": "^0.8.0" - } - }, "hast-util-embedded": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/hast-util-embedded/-/hast-util-embedded-1.0.6.tgz", @@ -2951,12 +2522,6 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, "html-void-elements": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz", @@ -3065,12 +2630,6 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true - }, "indexof": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", @@ -3227,12 +2786,6 @@ "has-symbols": "^1.0.1" } }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true - }, "is-symbol": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", @@ -3247,12 +2800,6 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", @@ -3268,133 +2815,6 @@ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, - "istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", - "dev": true - }, - "istanbul-lib-hook": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", - "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", - "dev": true, - "requires": { - "append-transform": "^2.0.0" - } - }, - "istanbul-lib-instrument": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", - "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", - "dev": true, - "requires": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "istanbul-lib-processinfo": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", - "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", - "dev": true, - "requires": { - "archy": "^1.0.0", - "cross-spawn": "^7.0.0", - "istanbul-lib-coverage": "^3.0.0-alpha.1", - "make-dir": "^3.0.0", - "p-map": "^3.0.0", - "rimraf": "^3.0.0", - "uuid": "^3.3.3" - }, - "dependencies": { - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", - "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, "js-cookie": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz", @@ -3425,12 +2845,6 @@ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -3452,15 +2866,6 @@ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, - "json5": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, "jsonminify": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/jsonminify/-/jsonminify-0.4.1.tgz", @@ -3631,12 +3036,6 @@ "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" }, - "lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", - "dev": true - }, "lodash.foreach": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", @@ -3788,23 +3187,6 @@ } } }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, "measured-core": { "version": "1.11.2", "resolved": "https://registry.npmjs.org/measured-core/-/measured-core-1.11.2.tgz", @@ -4281,15 +3663,6 @@ } } }, - "node-preload": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", - "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", - "dev": true, - "requires": { - "process-on-spawn": "^1.0.0" - } - }, "nodeify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/nodeify/-/nodeify-1.0.1.tgz", @@ -7448,198 +6821,6 @@ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, - "nyc": { - "version": "15.0.1", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.0.1.tgz", - "integrity": "sha512-n0MBXYBYRqa67IVt62qW1r/d9UH/Qtr7SF1w/nQLJ9KxvWF6b2xCHImRAixHN9tnMMYHC2P14uo6KddNGwMgGg==", - "dev": true, - "requires": { - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "caching-transform": "^4.0.0", - "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", - "find-cache-dir": "^3.2.0", - "find-up": "^4.1.0", - "foreground-child": "^2.0.0", - "glob": "^7.1.6", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-hook": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "make-dir": "^3.0.0", - "node-preload": "^0.2.1", - "p-map": "^3.0.0", - "process-on-spawn": "^1.0.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", - "yargs": "^15.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - } - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", @@ -7802,33 +6983,12 @@ "p-limit": "^2.0.0" } }, - "p-map": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, - "package-hash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", - "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.15", - "hasha": "^5.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" - } - }, "packet-reader": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", @@ -7956,51 +7116,6 @@ "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", "dev": true }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - } - } - }, "postgres-array": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", @@ -8035,15 +7150,6 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, - "process-on-spawn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", - "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", - "dev": true, - "requires": { - "fromentries": "^1.2.0" - } - }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -8260,15 +7366,6 @@ "xtend": "^4.0.0" } }, - "release-zalgo": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", - "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", - "dev": true, - "requires": { - "es6-error": "^4.0.1" - } - }, "request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -8475,7 +7572,8 @@ "signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "optional": true }, "simple-git": { "version": "2.31.0", @@ -8726,40 +7824,6 @@ "memory-pager": "^1.0.2" } }, - "spawn-wrap": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", - "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", - "dev": true, - "requires": { - "foreground-child": "^2.0.0", - "is-windows": "^1.0.2", - "make-dir": "^3.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "which": "^2.0.1" - }, - "dependencies": { - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, "split2": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", @@ -8868,12 +7932,6 @@ "ansi-regex": "^2.0.0" } }, - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -9145,17 +8203,6 @@ "source-map-support": "~0.5.12" } }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -9207,12 +8254,6 @@ "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -9294,15 +8335,6 @@ "mime-types": "~2.1.24" } }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, "ueberdb2": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/ueberdb2/-/ueberdb2-1.2.5.tgz", @@ -9622,18 +8654,6 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, "ws": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.2.tgz", diff --git a/src/package.json b/src/package.json index dd6525d36..bc3e4d22f 100644 --- a/src/package.json +++ b/src/package.json @@ -89,7 +89,6 @@ "etherpad-cli-client": "0.0.9", "mocha": "7.1.2", "mocha-froth": "^0.2.10", - "nyc": "15.0.1", "set-cookie-parser": "^2.4.6", "sinon": "^9.2.0", "superagent": "^3.8.3", @@ -148,8 +147,8 @@ }, "scripts": { "lint": "eslint .", - "test": "nyc mocha --timeout 120000 --recursive ../tests/backend/specs ../node_modules/ep_*/static/tests/backend/specs", - "test-container": "nyc mocha --timeout 5000 ../tests/container/specs/api" + "test": "mocha --timeout 120000 --recursive ../tests/backend/specs ../node_modules/ep_*/static/tests/backend/specs", + "test-container": "mocha --timeout 5000 ../tests/container/specs/api" }, "version": "1.8.7", "license": "Apache-2.0" From f72ce463ef4aafecc82d6ddbbc609a0961f3ca00 Mon Sep 17 00:00:00 2001 From: John McLear Date: Mon, 21 Dec 2020 23:11:17 +0000 Subject: [PATCH 104/153] lint: undomodule --- src/static/js/undomodule.js | 116 ++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 59 deletions(-) diff --git a/src/static/js/undomodule.js b/src/static/js/undomodule.js index 44efa0449..b8270b805 100644 --- a/src/static/js/undomodule.js +++ b/src/static/js/undomodule.js @@ -1,3 +1,5 @@ +'use strict'; + /** * This code is mostly from the old Etherpad. Please help us to comment this code. * This helps other people to understand this code better and helps them to improve it. @@ -23,8 +25,8 @@ const Changeset = require('./Changeset'); const _ = require('./underscore'); -var undoModule = (function () { - const stack = (function () { +const undoModule = (() => { + const stack = (() => { const stackElements = []; // two types of stackElements: // 1) { elementType: UNDOABLE_EVENT, eventType: "anything", [backset: ,] @@ -36,7 +38,7 @@ var undoModule = (function () { const UNDOABLE_EVENT = 'undoableEvent'; const EXTERNAL_CHANGE = 'externalChange'; - function clearStack() { + const clearStack = () => { stackElements.length = 0; stackElements.push( { @@ -44,22 +46,23 @@ var undoModule = (function () { eventType: 'bottom', }); numUndoableEvents = 1; - } + }; clearStack(); - function pushEvent(event) { + const pushEvent = (event) => { const e = _.extend( {}, event); e.elementType = UNDOABLE_EVENT; stackElements.push(e); numUndoableEvents++; // dmesg("pushEvent backset: "+event.backset); - } + }; - function pushExternalChange(cs) { + const pushExternalChange = (cs) => { const idx = stackElements.length - 1; - if (stackElements[idx].elementType == EXTERNAL_CHANGE) { - stackElements[idx].changeset = Changeset.compose(stackElements[idx].changeset, cs, getAPool()); + if (stackElements[idx].elementType === EXTERNAL_CHANGE) { + stackElements[idx].changeset = + Changeset.compose(stackElements[idx].changeset, cs, getAPool()); } else { stackElements.push( { @@ -67,14 +70,14 @@ var undoModule = (function () { changeset: cs, }); } - } + }; - function _exposeEvent(nthFromTop) { + const _exposeEvent = (nthFromTop) => { // precond: 0 <= nthFromTop < numUndoableEvents const targetIndex = stackElements.length - 1 - nthFromTop; let idx = stackElements.length - 1; - while (idx > targetIndex || stackElements[idx].elementType == EXTERNAL_CHANGE) { - if (stackElements[idx].elementType == EXTERNAL_CHANGE) { + while (idx > targetIndex || stackElements[idx].elementType === EXTERNAL_CHANGE) { + if (stackElements[idx].elementType === EXTERNAL_CHANGE) { const ex = stackElements[idx]; const un = stackElements[idx - 1]; if (un.backset) { @@ -86,15 +89,16 @@ var undoModule = (function () { const newSel = Changeset.characterRangeFollow(excs, un.selStart, un.selEnd); un.selStart = newSel[0]; un.selEnd = newSel[1]; - if (un.selStart == un.selEnd) { + if (un.selStart === un.selEnd) { un.selFocusAtStart = false; } } } stackElements[idx - 1] = ex; stackElements[idx] = un; - if (idx >= 2 && stackElements[idx - 2].elementType == EXTERNAL_CHANGE) { - ex.changeset = Changeset.compose(stackElements[idx - 2].changeset, ex.changeset, getAPool()); + if (idx >= 2 && stackElements[idx - 2].elementType === EXTERNAL_CHANGE) { + ex.changeset = + Changeset.compose(stackElements[idx - 2].changeset, ex.changeset, getAPool()); stackElements.splice(idx - 2, 1); idx--; } @@ -102,24 +106,22 @@ var undoModule = (function () { idx--; } } - } + }; - function getNthFromTop(n) { + const getNthFromTop = (n) => { // precond: 0 <= n < numEvents() _exposeEvent(n); return stackElements[stackElements.length - 1 - n]; - } + }; - function numEvents() { - return numUndoableEvents; - } + const numEvents = () => numUndoableEvents; - function popEvent() { + const popEvent = () => { // precond: numEvents() > 0 _exposeEvent(0); numUndoableEvents--; return stackElements.pop(); - } + }; return { numEvents, @@ -134,12 +136,12 @@ var undoModule = (function () { // invariant: stack always has at least one undoable event let undoPtr = 0; // zero-index from top of stack, 0 == top - function clearHistory() { + const clearHistory = () => { stack.clearStack(); undoPtr = 0; - } + }; - function _charOccurrences(str, c) { + const _charOccurrences = (str, c) => { let i = 0; let count = 0; while (i >= 0 && i < str.length) { @@ -150,13 +152,11 @@ var undoModule = (function () { } } return count; - } + }; - function _opcodeOccurrences(cs, opcode) { - return _charOccurrences(Changeset.unpack(cs).ops, opcode); - } + const _opcodeOccurrences = (cs, opcode) => _charOccurrences(Changeset.unpack(cs).ops, opcode); - function _mergeChangesets(cs1, cs2) { + const _mergeChangesets = (cs1, cs2) => { if (!cs1) return cs2; if (!cs2) return cs1; @@ -170,40 +170,40 @@ var undoModule = (function () { const plusCount2 = _opcodeOccurrences(cs2, '+'); const minusCount1 = _opcodeOccurrences(cs1, '-'); const minusCount2 = _opcodeOccurrences(cs2, '-'); - if (plusCount1 == 1 && plusCount2 == 1 && minusCount1 == 0 && minusCount2 == 0) { - var merge = Changeset.compose(cs1, cs2, getAPool()); - var plusCount3 = _opcodeOccurrences(merge, '+'); - var minusCount3 = _opcodeOccurrences(merge, '-'); - if (plusCount3 == 1 && minusCount3 == 0) { + if (plusCount1 === 1 && plusCount2 === 1 && minusCount1 === 0 && minusCount2 === 0) { + const merge = Changeset.compose(cs1, cs2, getAPool()); + const plusCount3 = _opcodeOccurrences(merge, '+'); + const minusCount3 = _opcodeOccurrences(merge, '-'); + if (plusCount3 === 1 && minusCount3 === 0) { return merge; } - } else if (plusCount1 == 0 && plusCount2 == 0 && minusCount1 == 1 && minusCount2 == 1) { - var merge = Changeset.compose(cs1, cs2, getAPool()); - var plusCount3 = _opcodeOccurrences(merge, '+'); - var minusCount3 = _opcodeOccurrences(merge, '-'); - if (plusCount3 == 0 && minusCount3 == 1) { + } else if (plusCount1 === 0 && plusCount2 === 0 && minusCount1 === 1 && minusCount2 === 1) { + const merge = Changeset.compose(cs1, cs2, getAPool()); + const plusCount3 = _opcodeOccurrences(merge, '+'); + const minusCount3 = _opcodeOccurrences(merge, '-'); + if (plusCount3 === 0 && minusCount3 === 1) { return merge; } } return null; - } + }; - function reportEvent(event) { + const reportEvent = (event) => { const topEvent = stack.getNthFromTop(0); - function applySelectionToTop() { + const applySelectionToTop = () => { if ((typeof event.selStart) === 'number') { topEvent.selStart = event.selStart; topEvent.selEnd = event.selEnd; topEvent.selFocusAtStart = event.selFocusAtStart; } - } + }; if ((!event.backset) || Changeset.isIdentity(event.backset)) { applySelectionToTop(); } else { let merged = false; - if (topEvent.eventType == event.eventType) { + if (topEvent.eventType === event.eventType) { const merge = _mergeChangesets(event.backset, topEvent.backset); if (merge) { topEvent.backset = merge; @@ -225,15 +225,15 @@ var undoModule = (function () { } undoPtr = 0; } - } + }; - function reportExternalChange(changeset) { + const reportExternalChange = (changeset) => { if (changeset && !Changeset.isIdentity(changeset)) { stack.pushExternalChange(changeset); } - } + }; - function _getSelectionInfo(event) { + const _getSelectionInfo = (event) => { if ((typeof event.selStart) !== 'number') { return null; } else { @@ -243,7 +243,7 @@ var undoModule = (function () { selFocusAtStart: event.selFocusAtStart, }; } - } + }; // For "undo" and "redo", the change event must be returned // by eventFunc and NOT reported through the normal mechanism. @@ -251,7 +251,7 @@ var undoModule = (function () { // or can be called with no arguments to mean that no undo is possible. // "eventFunc" will be called exactly once. - function performUndo(eventFunc) { + const performUndo = (eventFunc) => { if (undoPtr < stack.numEvents() - 1) { const backsetEvent = stack.getNthFromTop(undoPtr); const selectionEvent = stack.getNthFromTop(undoPtr + 1); @@ -259,9 +259,9 @@ var undoModule = (function () { stack.pushEvent(undoEvent); undoPtr += 2; } else { eventFunc(); } - } + }; - function performRedo(eventFunc) { + const performRedo = (eventFunc) => { if (undoPtr >= 2) { const backsetEvent = stack.getNthFromTop(0); const selectionEvent = stack.getNthFromTop(1); @@ -269,11 +269,9 @@ var undoModule = (function () { stack.popEvent(); undoPtr -= 2; } else { eventFunc(); } - } + }; - function getAPool() { - return undoModule.apool; - } + const getAPool = () => undoModule.apool; return { clearHistory, From 29179e512f7fa41b64a4de555b427c7b507997d4 Mon Sep 17 00:00:00 2001 From: John McLear Date: Mon, 21 Dec 2020 23:23:16 +0000 Subject: [PATCH 105/153] lint: skiplist --- src/static/js/skiplist.js | 177 ++++++++++++++------------------------ 1 file changed, 65 insertions(+), 112 deletions(-) diff --git a/src/static/js/skiplist.js b/src/static/js/skiplist.js index bf7a74f97..4ea740104 100644 --- a/src/static/js/skiplist.js +++ b/src/static/js/skiplist.js @@ -1,3 +1,5 @@ +'use strict'; + /** * This code is mostly from the old Etherpad. Please help us to comment this code. * This helps other people to understand this code better and helps them to improve it. @@ -28,15 +30,13 @@ const noop = Ace2Common.noop; function SkipList() { let PROFILER = window.PROFILER; if (!PROFILER) { - PROFILER = function () { - return { - start: noop, - mark: noop, - literal: noop, - end: noop, - cancel: noop, - }; - }; + PROFILER = () => ({ + start: noop, + mark: noop, + literal: noop, + end: noop, + cancel: noop, + }); } // if there are N elements in the skiplist, "start" is element -1 and "end" is element N @@ -68,7 +68,7 @@ function SkipList() { // this point. - function _getPoint(targetLoc) { + const _getPoint = (targetLoc) => { const numLevels = start.levels; let lvl = numLevels - 1; let i = -1; @@ -99,13 +99,11 @@ function SkipList() { idxs, loc: targetLoc, widthSkips, - toString() { - return `getPoint(${targetLoc})`; - }, + toString: () => `getPoint(${targetLoc})`, }; - } + }; - function _getNodeAtOffset(targetOffset) { + const _getNodeAtOffset = (targetOffset) => { let i = 0; let n = start; let lvl = start.levels - 1; @@ -117,16 +115,14 @@ function SkipList() { lvl--; } if (n === start) return (start.downPtrs[0] || null); - else if (n === end) return (targetOffset == totalWidth ? (end.upPtrs[0] || null) : null); + else if (n === end) return (targetOffset === totalWidth ? (end.upPtrs[0] || null) : null); return n; - } + }; - function _entryWidth(e) { - return (e && e.width) || 0; - } + const _entryWidth = (e) => (e && e.width) || 0; - function _insertKeyAtPoint(point, newKey, entry) { - const p = PROFILER('insertKey', false); + const _insertKeyAtPoint = (point, newKey, entry) => { + const p = PROFILER('insertKey', false); // eslint-disable-line new-cap const newNode = { key: newKey, levels: 0, @@ -145,10 +141,10 @@ function SkipList() { // The new node will have at least level 1 // With a proability of 0.01^(n-1) the nodes level will be >= n - while (newNode.levels == 0 || Math.random() < 0.01) { - var lvl = newNode.levels; + while (newNode.levels === 0 || Math.random() < 0.01) { + const lvl = newNode.levels; newNode.levels++; - if (lvl == pNodes.length) { + if (lvl === pNodes.length) { // assume we have just passed the end of point.nodes, and reached one level greater // than the skiplist currently supports pNodes[lvl] = start; @@ -162,7 +158,7 @@ function SkipList() { point.widthSkips[lvl] = 0; } const me = newNode; - var up = pNodes[lvl]; + const up = pNodes[lvl]; const down = up.downPtrs[lvl]; const skip1 = pLoc - pIdxs[lvl]; const skip2 = up.downSkips[lvl] + 1 - skip1; @@ -179,8 +175,8 @@ function SkipList() { } p.mark('loop2'); p.literal(pNodes.length, 'PNL'); - for (var lvl = newNode.levels; lvl < pNodes.length; lvl++) { - var up = pNodes[lvl]; + for (let lvl = newNode.levels; lvl < pNodes.length; lvl++) { + const up = pNodes[lvl]; up.downSkips[lvl]++; up.downSkipWidths[lvl] += newWidth; } @@ -189,30 +185,17 @@ function SkipList() { numNodes++; totalWidth += newWidth; p.end(); - } + }; - function _getNodeAtPoint(point) { - return point.nodes[0].downPtrs[0]; - } + const _getNodeAtPoint = (point) => point.nodes[0].downPtrs[0]; - function _incrementPoint(point) { - point.loc++; - for (let i = 0; i < point.nodes.length; i++) { - if (point.idxs[i] + point.nodes[i].downSkips[i] < point.loc) { - point.idxs[i] += point.nodes[i].downSkips[i]; - point.widthSkips[i] += point.nodes[i].downSkipWidths[i]; - point.nodes[i] = point.nodes[i].downPtrs[i]; - } - } - } - - function _deleteKeyAtPoint(point) { + const _deleteKeyAtPoint = (point) => { const elem = point.nodes[0].downPtrs[0]; const elemWidth = _entryWidth(elem.entry); for (let i = 0; i < point.nodes.length; i++) { if (i < elem.levels) { - var up = elem.upPtrs[i]; - var down = elem.downPtrs[i]; + const up = elem.upPtrs[i]; + const down = elem.downPtrs[i]; const totalSkip = up.downSkips[i] + elem.downSkips[i] - 1; up.downPtrs[i] = down; down.upPtrs[i] = up; @@ -220,8 +203,7 @@ function SkipList() { const totalWidthSkip = up.downSkipWidths[i] + elem.downSkipWidths[i] - elemWidth; up.downSkipWidths[i] = totalWidthSkip; } else { - var up = point.nodes[i]; - var down = up.downPtrs[i]; + const up = point.nodes[i]; up.downSkips[i]--; up.downSkipWidths[i] -= elemWidth; } @@ -229,9 +211,9 @@ function SkipList() { delete keyToNodeMap[`$KEY$${elem.key}`]; numNodes--; totalWidth -= elemWidth; - } + }; - function _propagateWidthChange(node) { + const _propagateWidthChange = (node) => { const oldWidth = node.downSkipWidths[0]; const newWidth = _entryWidth(node.entry); const widthChange = newWidth - oldWidth; @@ -245,9 +227,9 @@ function SkipList() { } } totalWidth += widthChange; - } + }; - function _getNodeIndex(node, byWidth) { + const _getNodeIndex = (node, byWidth) => { let dist = (byWidth ? 0 : -1); let n = node; while (n !== start) { @@ -257,27 +239,26 @@ function SkipList() { else dist += n.downSkips[lvl]; } return dist; - } + }; - function _getNodeByKey(key) { - return keyToNodeMap[`$KEY$${key}`]; - } + const _getNodeByKey = (key) => keyToNodeMap[`$KEY$${key}`]; // Returns index of first entry such that entryFunc(entry) is truthy, // or length() if no such entry. Assumes all falsy entries come before // all truthy entries. - function _search(entryFunc) { + const _search = (entryFunc) => { let low = start; let lvl = start.levels - 1; let lowIndex = -1; - function f(node) { + const f = (node) => { if (node === start) return false; else if (node === end) return true; else return entryFunc(node.entry); - } + }; + while (lvl >= 0) { let nextLow = low.downPtrs[lvl]; while (!f(nextLow)) { @@ -288,7 +269,7 @@ function SkipList() { lvl--; } return lowIndex + 1; - } + }; /* The skip-list contains "entries", JavaScript objects that each must have a unique "key" property @@ -296,16 +277,14 @@ that is a string. */ const self = this; _.extend(this, { - length() { - return numNodes; - }, - atIndex(i) { + length: () => numNodes, + atIndex: (i) => { if (i < 0) console.warn(`atIndex(${i})`); if (i >= numNodes) console.warn(`atIndex(${i}>=${numNodes})`); return _getNodeAtPoint(_getPoint(i)).entry; }, // differs from Array.splice() in that new elements are in an array, not varargs - splice(start, deleteCount, newEntryArray) { + splice: (start, deleteCount, newEntryArray) => { if (start < 0) console.warn(`splice(${start}, ...)`); if (start + deleteCount > numNodes) { console.warn(`splice(${start}, ${deleteCount}, ...), N=${numNodes}`); @@ -315,26 +294,22 @@ that is a string. if (!newEntryArray) newEntryArray = []; const pt = _getPoint(start); - for (var i = 0; i < deleteCount; i++) { + for (let i = 0; i < deleteCount; i++) { _deleteKeyAtPoint(pt); } - for (var i = (newEntryArray.length - 1); i >= 0; i--) { + for (let i = (newEntryArray.length - 1); i >= 0; i--) { const entry = newEntryArray[i]; _insertKeyAtPoint(pt, entry.key, entry); const node = _getNodeByKey(entry.key); node.entry = entry; } }, - next(entry) { - return _getNodeByKey(entry.key).downPtrs[0].entry || null; - }, - prev(entry) { - return _getNodeByKey(entry.key).upPtrs[0].entry || null; - }, - push(entry) { + next: (entry) => _getNodeByKey(entry.key).downPtrs[0].entry || null, + prev: (entry) => _getNodeByKey(entry.key).upPtrs[0].entry || null, + push: (entry) => { self.splice(numNodes, 0, [entry]); }, - slice(start, end) { + slice: (start, end) => { // act like Array.slice() if (start === undefined) start = 0; else if (start < 0) start += numNodes; @@ -346,7 +321,7 @@ that is a string. if (end < 0) end = 0; if (end > numNodes) end = numNodes; - dmesg(String([start, end, numNodes])); + window.dmesg(String([start, end, numNodes])); if (end <= start) return []; let n = self.atIndex(start); const array = [n]; @@ -356,56 +331,34 @@ that is a string. } return array; }, - atKey(key) { - return _getNodeByKey(key).entry; - }, - indexOfKey(key) { - return _getNodeIndex(_getNodeByKey(key)); - }, - indexOfEntry(entry) { - return self.indexOfKey(entry.key); - }, - containsKey(key) { - return !!(_getNodeByKey(key)); - }, + atKey: (key) => _getNodeByKey(key).entry, + indexOfKey: (key) => _getNodeIndex(_getNodeByKey(key)), + indexOfEntry: (entry) => self.indexOfKey(entry.key), + containsKey: (key) => !!(_getNodeByKey(key)), // gets the last entry starting at or before the offset - atOffset(offset) { - return _getNodeAtOffset(offset).entry; - }, - keyAtOffset(offset) { - return self.atOffset(offset).key; - }, - offsetOfKey(key) { - return _getNodeIndex(_getNodeByKey(key), true); - }, - offsetOfEntry(entry) { - return self.offsetOfKey(entry.key); - }, - setEntryWidth(entry, width) { + atOffset: (offset) => _getNodeAtOffset(offset).entry, + keyAtOffset: (offset) => self.atOffset(offset).key, + offsetOfKey: (key) => _getNodeIndex(_getNodeByKey(key), true), + offsetOfEntry: (entry) => self.offsetOfKey(entry.key), + setEntryWidth: (entry, width) => { entry.width = width; _propagateWidthChange(_getNodeByKey(entry.key)); }, - totalWidth() { - return totalWidth; - }, - offsetOfIndex(i) { + totalWidth: () => totalWidth, + offsetOfIndex: (i) => { if (i < 0) return 0; if (i >= numNodes) return totalWidth; return self.offsetOfEntry(self.atIndex(i)); }, - indexOfOffset(offset) { + indexOfOffset: (offset) => { if (offset <= 0) return 0; if (offset >= totalWidth) return numNodes; return self.indexOfEntry(self.atOffset(offset)); }, - search(entryFunc) { - return _search(entryFunc); - }, + search: (entryFunc) => _search(entryFunc), // debugToString: _debugToString, debugGetPoint: _getPoint, - debugDepth() { - return start.levels; - }, + debugDepth: () => start.levels, }); } From 5bcd6f44a5a8d2aca76fbb863ce0c165f0990f16 Mon Sep 17 00:00:00 2001 From: John McLear Date: Sat, 30 Jan 2021 07:32:12 +0000 Subject: [PATCH 106/153] lint: skin-variants (#4603) * lint: skin-variants * for squash: Fix attachment of event listener Before this PR the statement was outside the function. I'm assuming the move into the function body was accidental, so move it back out. * for squash: Preserve order of function calls Co-authored-by: Richard Hansen --- src/static/js/skin_variants.js | 42 +++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/static/js/skin_variants.js b/src/static/js/skin_variants.js index d5d663c08..a7902545e 100644 --- a/src/static/js/skin_variants.js +++ b/src/static/js/skin_variants.js @@ -1,19 +1,14 @@ -// Specific hash to display the skin variants builder popup -if (window.location.hash.toLowerCase() == '#skinvariantsbuilder') { - $('#skin-variants').addClass('popup-show'); +'use strict'; - $('.skin-variant').change(() => { - updateSkinVariantsClasses(); - }); +// Specific hash to display the skin variants builder popup +if (window.location.hash.toLowerCase() === '#skinvariantsbuilder') { + $('#skin-variants').addClass('popup-show'); const containers = ['editor', 'background', 'toolbar']; const colors = ['super-light', 'light', 'dark', 'super-dark']; - updateCheckboxFromSkinClasses(); - updateSkinVariantsClasses(); - // add corresponding classes when config change - function updateSkinVariantsClasses() { + const updateSkinVariantsClasses = () => { const domsToUpdate = [ $('html'), $('iframe[name=ace_outer]').contents().find('html'), @@ -27,23 +22,21 @@ if (window.location.hash.toLowerCase() == '#skinvariantsbuilder') { domsToUpdate.forEach((el) => { el.removeClass('full-width-editor'); }); - const new_classes = []; + const newClasses = []; $('select.skin-variant-color').each(function () { - new_classes.push(`${$(this).val()}-${$(this).data('container')}`); + newClasses.push(`${$(this).val()}-${$(this).data('container')}`); }); - if ($('#skin-variant-full-width').is(':checked')) new_classes.push('full-width-editor'); + if ($('#skin-variant-full-width').is(':checked')) newClasses.push('full-width-editor'); - domsToUpdate.forEach((el) => { el.addClass(new_classes.join(' ')); }); + domsToUpdate.forEach((el) => { el.addClass(newClasses.join(' ')); }); - $('#skin-variants-result').val(`"skinVariants": "${new_classes.join(' ')}",`); - } + $('#skin-variants-result').val(`"skinVariants": "${newClasses.join(' ')}",`); + }; // run on init - function updateCheckboxFromSkinClasses() { + const updateCheckboxFromSkinClasses = () => { $('html').attr('class').split(' ').forEach((classItem) => { - var container = classItem.split('-').slice(-1); - - var container = classItem.substring(classItem.lastIndexOf('-') + 1, classItem.length); + const container = classItem.substring(classItem.lastIndexOf('-') + 1, classItem.length); if (containers.indexOf(container) > -1) { const color = classItem.substring(0, classItem.lastIndexOf('-')); $(`.skin-variant-color[data-container="${container}"`).val(color); @@ -51,5 +44,12 @@ if (window.location.hash.toLowerCase() == '#skinvariantsbuilder') { }); $('#skin-variant-full-width').prop('checked', $('html').hasClass('full-width-editor')); - } + }; + + $('.skin-variant').change(() => { + updateSkinVariantsClasses(); + }); + + updateCheckboxFromSkinClasses(); + updateSkinVariantsClasses(); } From f03c4bd7f7c5108284167943f26a209d87daa2e4 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 8 Jan 2021 17:47:38 -0500 Subject: [PATCH 107/153] bin scripts: compare against null, not undefined --- bin/checkAllPads.js | 4 ++-- bin/checkPad.js | 8 ++++---- bin/checkPadDeltas.js | 4 +--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/bin/checkAllPads.js b/bin/checkAllPads.js index 6e1f14842..8426d4429 100644 --- a/bin/checkAllPads.js +++ b/bin/checkAllPads.js @@ -30,7 +30,7 @@ npm.load({}, async () => { const pad = await padManager.getPad(padId); // check if the pad has a pool - if (pad.pool === undefined) { + if (pad.pool == null) { console.error(`[${pad.id}] Missing attribute pool`); continue; } @@ -66,7 +66,7 @@ npm.load({}, async () => { } // check if there is a atext in the keyRevisions - if (revisions[keyRev].meta === undefined || revisions[keyRev].meta.atext === undefined) { + if (revisions[keyRev].meta == null || revisions[keyRev].meta.atext == null) { console.error(`[${pad.id}] Missing atext in revision ${keyRev}`); continue; } diff --git a/bin/checkPad.js b/bin/checkPad.js index de1c51402..374a3c856 100644 --- a/bin/checkPad.js +++ b/bin/checkPad.js @@ -59,12 +59,12 @@ npm.load({}, async () => { } // check if the pad has a pool - if (pad.pool === undefined) throw new Error('Attribute pool is missing'); + if (pad.pool == null) throw new Error('Attribute pool is missing'); // check if there is an atext in the keyRevisions - if (revisions[keyRev] === undefined || - revisions[keyRev].meta === undefined || - revisions[keyRev].meta.atext === undefined) { + if (revisions[keyRev] == null || + revisions[keyRev].meta == null || + revisions[keyRev].meta.atext == null) { console.error(`No atext in key revision ${keyRev}`); continue; } diff --git a/bin/checkPadDeltas.js b/bin/checkPadDeltas.js index ecbb20846..c53275a28 100644 --- a/bin/checkPadDeltas.js +++ b/bin/checkPadDeltas.js @@ -55,9 +55,7 @@ npm.load({}, async () => { const revision = await db.get(`pad:${padId}:revs:${revNum}`); // check if there is a atext in the keyRevisions if (~keyRevisions.indexOf(revNum) && - (revision === undefined || - revision.meta === undefined || - revision.meta.atext === undefined)) { + (revision == null || revision.meta == null || revision.meta.atext == null)) { console.error(`No atext in key revision ${revNum}`); continue; } From 92cd2cc760f369b14f48f0f3c3cf4feccf9568b1 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sat, 9 Jan 2021 02:28:45 -0500 Subject: [PATCH 108/153] bin scripts: Use destructuring instead of long condition checks --- bin/checkAllPads.js | 4 ++-- bin/checkPad.js | 6 ++---- bin/checkPadDeltas.js | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/bin/checkAllPads.js b/bin/checkAllPads.js index 8426d4429..063da96a5 100644 --- a/bin/checkAllPads.js +++ b/bin/checkAllPads.js @@ -66,13 +66,13 @@ npm.load({}, async () => { } // check if there is a atext in the keyRevisions - if (revisions[keyRev].meta == null || revisions[keyRev].meta.atext == null) { + let {meta: {atext} = {}} = revisions[keyRev]; + if (atext == null) { console.error(`[${pad.id}] Missing atext in revision ${keyRev}`); continue; } const apool = pad.pool; - let atext = revisions[keyRev].meta.atext; for (let rev = keyRev + 1; rev <= keyRev + 100 && rev <= head; rev++) { try { const cs = revisions[rev].changeset; diff --git a/bin/checkPad.js b/bin/checkPad.js index 374a3c856..42e5946c1 100644 --- a/bin/checkPad.js +++ b/bin/checkPad.js @@ -62,15 +62,13 @@ npm.load({}, async () => { if (pad.pool == null) throw new Error('Attribute pool is missing'); // check if there is an atext in the keyRevisions - if (revisions[keyRev] == null || - revisions[keyRev].meta == null || - revisions[keyRev].meta.atext == null) { + let {meta: {atext} = {}} = revisions[keyRev] || {}; + if (atext == null) { console.error(`No atext in key revision ${keyRev}`); continue; } const apool = pad.pool; - let atext = revisions[keyRev].meta.atext; for (let rev = keyRev + 1; rev <= keyRev + 100 && rev <= head; rev++) { checkRevisionCount++; diff --git a/bin/checkPadDeltas.js b/bin/checkPadDeltas.js index c53275a28..19d4ba4db 100644 --- a/bin/checkPadDeltas.js +++ b/bin/checkPadDeltas.js @@ -54,8 +54,8 @@ npm.load({}, async () => { // console.log('Fetching', revNum) const revision = await db.get(`pad:${padId}:revs:${revNum}`); // check if there is a atext in the keyRevisions - if (~keyRevisions.indexOf(revNum) && - (revision == null || revision.meta == null || revision.meta.atext == null)) { + const {meta: {atext: revAtext} = {}} = revision || {}; + if (~keyRevisions.indexOf(revNum) && revAtext == null) { console.error(`No atext in key revision ${revNum}`); continue; } From efdcaae5269450ef49fdd6efb6fce9cc5fee2a6f Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sat, 9 Jan 2021 02:44:59 -0500 Subject: [PATCH 109/153] bin scripts: Promisify npm.load --- bin/checkAllPads.js | 11 +++++++---- bin/checkPad.js | 11 +++++++---- bin/checkPadDeltas.js | 8 +++++--- bin/extractPadData.js | 8 ++++---- bin/importSqlFile.js | 9 ++++++--- bin/migrateDirtyDBtoRealDB.js | 7 +++++-- bin/repairPad.js | 8 +++++--- 7 files changed, 39 insertions(+), 23 deletions(-) diff --git a/bin/checkAllPads.js b/bin/checkAllPads.js index 063da96a5..3e2ea8407 100644 --- a/bin/checkAllPads.js +++ b/bin/checkAllPads.js @@ -7,11 +7,14 @@ // unhandled rejection into an uncaught exception, which does cause Node.js to exit. process.on('unhandledRejection', (err) => { throw err; }); +const npm = require('ep_etherpad-lite/node_modules/npm'); +const util = require('util'); + if (process.argv.length !== 2) throw new Error('Use: node bin/checkAllPads.js'); -// load and initialize NPM -const npm = require('ep_etherpad-lite/node_modules/npm'); -npm.load({}, async () => { +(async () => { + await util.promisify(npm.load)({}); + try { // initialize the database require('ep_etherpad-lite/node/utils/Settings'); @@ -92,4 +95,4 @@ npm.load({}, async () => { console.trace(err); throw err; } -}); +})(); diff --git a/bin/checkPad.js b/bin/checkPad.js index 42e5946c1..56464648b 100644 --- a/bin/checkPad.js +++ b/bin/checkPad.js @@ -7,15 +7,18 @@ // unhandled rejection into an uncaught exception, which does cause Node.js to exit. process.on('unhandledRejection', (err) => { throw err; }); +const npm = require('ep_etherpad-lite/node_modules/npm'); +const util = require('util'); + if (process.argv.length !== 3) throw new Error('Use: node bin/checkPad.js $PADID'); // get the padID const padId = process.argv[2]; let checkRevisionCount = 0; -// load and initialize NPM; -const npm = require('ep_etherpad-lite/node_modules/npm'); -npm.load({}, async () => { +(async () => { + await util.promisify(npm.load)({}); + try { // initialize database require('ep_etherpad-lite/node/utils/Settings'); @@ -86,4 +89,4 @@ npm.load({}, async () => { console.trace(err); throw err; } -}); +})(); diff --git a/bin/checkPadDeltas.js b/bin/checkPadDeltas.js index 19d4ba4db..45ee27d72 100644 --- a/bin/checkPadDeltas.js +++ b/bin/checkPadDeltas.js @@ -12,12 +12,14 @@ if (process.argv.length !== 3) throw new Error('Use: node bin/checkPadDeltas.js // get the padID const padId = process.argv[2]; -// load and initialize NPM; const expect = require('../tests/frontend/lib/expect'); const diff = require('ep_etherpad-lite/node_modules/diff'); const npm = require('ep_etherpad-lite/node_modules/npm'); +const util = require('util'); + +(async () => { + await util.promisify(npm.load)({}); -npm.load({}, async () => { // initialize database require('ep_etherpad-lite/node/utils/Settings'); const db = require('ep_etherpad-lite/node/db/DB'); @@ -102,4 +104,4 @@ npm.load({}, async () => { } })); } -}); +})(); diff --git a/bin/extractPadData.js b/bin/extractPadData.js index 3b182a571..58fe50a42 100644 --- a/bin/extractPadData.js +++ b/bin/extractPadData.js @@ -16,9 +16,10 @@ if (process.argv.length !== 3) throw new Error('Use: node extractPadData.js $PAD const padId = process.argv[2]; const npm = require('ep_etherpad-lite/node_modules/npm'); +const util = require('util'); -npm.load({}, async (err) => { - if (err) throw err; +(async () => { + await util.promisify(npm.load)({}); try { // initialize database @@ -29,7 +30,6 @@ npm.load({}, async (err) => { // load extra modules const dirtyDB = require('ep_etherpad-lite/node_modules/dirty'); const padManager = require('ep_etherpad-lite/node/db/PadManager'); - const util = require('util'); // initialize output database const dirty = dirtyDB(`${padId}.db`); @@ -71,4 +71,4 @@ npm.load({}, async (err) => { console.error(err); throw err; } -}); +})(); diff --git a/bin/importSqlFile.js b/bin/importSqlFile.js index 35fe4f323..b02e9e10c 100644 --- a/bin/importSqlFile.js +++ b/bin/importSqlFile.js @@ -4,6 +4,9 @@ // unhandled rejection into an uncaught exception, which does cause Node.js to exit. process.on('unhandledRejection', (err) => { throw err; }); +const npm = require('ep_etherpad-lite/node_modules/npm'); +const util = require('util'); + const startTime = Date.now(); const log = (str) => { @@ -43,10 +46,10 @@ const unescape = (val) => { return val; }; +(async () => { + await util.promisify(npm.load)({}); -require('ep_etherpad-lite/node_modules/npm').load({}, (er, npm) => { const fs = require('fs'); - const ueberDB = require('ep_etherpad-lite/node_modules/ueberdb2'); const settings = require('ep_etherpad-lite/node/utils/Settings'); const log4js = require('ep_etherpad-lite/node_modules/log4js'); @@ -106,4 +109,4 @@ require('ep_etherpad-lite/node_modules/npm').load({}, (er, npm) => { }); } }); -}); +})(); diff --git a/bin/migrateDirtyDBtoRealDB.js b/bin/migrateDirtyDBtoRealDB.js index 48760b8ba..c79d9b747 100644 --- a/bin/migrateDirtyDBtoRealDB.js +++ b/bin/migrateDirtyDBtoRealDB.js @@ -4,9 +4,12 @@ // unhandled rejection into an uncaught exception, which does cause Node.js to exit. process.on('unhandledRejection', (err) => { throw err; }); +const npm = require('ep_etherpad-lite/node_modules/npm'); const util = require('util'); -require('ep_etherpad-lite/node_modules/npm').load({}, async (er, npm) => { +(async () => { + await util.promisify(npm.load)({}); + process.chdir(`${npm.root}/..`); // This script requires that you have modified your settings.json file @@ -56,4 +59,4 @@ require('ep_etherpad-lite/node_modules/npm').load({}, async (er, npm) => { await util.promisify(db.close.bind(db))(); console.log('Finished.'); -}); +})(); diff --git a/bin/repairPad.js b/bin/repairPad.js index e083f30b9..ff2da9776 100644 --- a/bin/repairPad.js +++ b/bin/repairPad.js @@ -18,8 +18,10 @@ const padId = process.argv[2]; let valueCount = 0; const npm = require('ep_etherpad-lite/node_modules/npm'); -npm.load({}, async (err) => { - if (err) throw err; +const util = require('util'); + +(async () => { + await util.promisify(npm.load)({}); // intialize database require('ep_etherpad-lite/node/utils/Settings'); @@ -56,4 +58,4 @@ npm.load({}, async (err) => { } console.info(`Finished: Replaced ${valueCount} values in the database`); -}); +})(); From 0a617679012728d7e48d28658cd08341d77808f6 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 17 Jan 2021 03:16:01 -0500 Subject: [PATCH 110/153] bin scripts: Delete redundant exception log messages The exception will cause Node.js to print the error message and stack trace so there's no point in logging it ourselves. --- bin/checkAllPads.js | 131 ++++++++++++++++++++---------------------- bin/checkPad.js | 107 ++++++++++++++++------------------ bin/extractPadData.js | 79 ++++++++++++------------- 3 files changed, 151 insertions(+), 166 deletions(-) diff --git a/bin/checkAllPads.js b/bin/checkAllPads.js index 3e2ea8407..356112e59 100644 --- a/bin/checkAllPads.js +++ b/bin/checkAllPads.js @@ -15,84 +15,79 @@ if (process.argv.length !== 2) throw new Error('Use: node bin/checkAllPads.js'); (async () => { await util.promisify(npm.load)({}); - try { - // initialize the database - require('ep_etherpad-lite/node/utils/Settings'); - const db = require('ep_etherpad-lite/node/db/DB'); - await db.init(); + // initialize the database + require('ep_etherpad-lite/node/utils/Settings'); + const db = require('ep_etherpad-lite/node/db/DB'); + await db.init(); - // load modules - const Changeset = require('ep_etherpad-lite/static/js/Changeset'); - const padManager = require('ep_etherpad-lite/node/db/PadManager'); + // load modules + const Changeset = require('ep_etherpad-lite/static/js/Changeset'); + const padManager = require('ep_etherpad-lite/node/db/PadManager'); - let revTestedCount = 0; + let revTestedCount = 0; - // get all pads - const res = await padManager.listAllPads(); - for (const padId of res.padIDs) { - const pad = await padManager.getPad(padId); + // get all pads + const res = await padManager.listAllPads(); + for (const padId of res.padIDs) { + const pad = await padManager.getPad(padId); - // check if the pad has a pool - if (pad.pool == null) { - console.error(`[${pad.id}] Missing attribute pool`); + // check if the pad has a pool + if (pad.pool == null) { + console.error(`[${pad.id}] Missing attribute pool`); + continue; + } + // create an array with key kevisions + // key revisions always save the full pad atext + const head = pad.getHeadRevisionNumber(); + const keyRevisions = []; + for (let rev = 0; rev < head; rev += 100) { + keyRevisions.push(rev); + } + + // run through all key revisions + for (const keyRev of keyRevisions) { + // create an array of revisions we need till the next keyRevision or the End + const revisionsNeeded = []; + for (let rev = keyRev; rev <= keyRev + 100 && rev <= head; rev++) { + revisionsNeeded.push(rev); + } + + // this array will hold all revision changesets + const revisions = []; + + // run through all needed revisions and get them from the database + for (const revNum of revisionsNeeded) { + const revision = await db.get(`pad:${pad.id}:revs:${revNum}`); + revisions[revNum] = revision; + } + + // check if the revision exists + if (revisions[keyRev] == null) { + console.error(`[${pad.id}] Missing revision ${keyRev}`); continue; } - // create an array with key kevisions - // key revisions always save the full pad atext - const head = pad.getHeadRevisionNumber(); - const keyRevisions = []; - for (let rev = 0; rev < head; rev += 100) { - keyRevisions.push(rev); + + // check if there is a atext in the keyRevisions + let {meta: {atext} = {}} = revisions[keyRev]; + if (atext == null) { + console.error(`[${pad.id}] Missing atext in revision ${keyRev}`); + continue; } - // run through all key revisions - for (const keyRev of keyRevisions) { - // create an array of revisions we need till the next keyRevision or the End - const revisionsNeeded = []; - for (let rev = keyRev; rev <= keyRev + 100 && rev <= head; rev++) { - revisionsNeeded.push(rev); - } - - // this array will hold all revision changesets - const revisions = []; - - // run through all needed revisions and get them from the database - for (const revNum of revisionsNeeded) { - const revision = await db.get(`pad:${pad.id}:revs:${revNum}`); - revisions[revNum] = revision; - } - - // check if the revision exists - if (revisions[keyRev] == null) { - console.error(`[${pad.id}] Missing revision ${keyRev}`); - continue; - } - - // check if there is a atext in the keyRevisions - let {meta: {atext} = {}} = revisions[keyRev]; - if (atext == null) { - console.error(`[${pad.id}] Missing atext in revision ${keyRev}`); - continue; - } - - const apool = pad.pool; - for (let rev = keyRev + 1; rev <= keyRev + 100 && rev <= head; rev++) { - try { - const cs = revisions[rev].changeset; - atext = Changeset.applyToAText(cs, atext, apool); - revTestedCount++; - } catch (e) { - console.error(`[${pad.id}] Bad changeset at revision ${rev} - ${e.message}`); - } + const apool = pad.pool; + for (let rev = keyRev + 1; rev <= keyRev + 100 && rev <= head; rev++) { + try { + const cs = revisions[rev].changeset; + atext = Changeset.applyToAText(cs, atext, apool); + revTestedCount++; + } catch (e) { + console.error(`[${pad.id}] Bad changeset at revision ${rev} - ${e.message}`); } } } - if (revTestedCount === 0) { - throw new Error('No revisions tested'); - } - console.log(`Finished: Tested ${revTestedCount} revisions`); - } catch (err) { - console.trace(err); - throw err; } + if (revTestedCount === 0) { + throw new Error('No revisions tested'); + } + console.log(`Finished: Tested ${revTestedCount} revisions`); })(); diff --git a/bin/checkPad.js b/bin/checkPad.js index 56464648b..20b3fa226 100644 --- a/bin/checkPad.js +++ b/bin/checkPad.js @@ -19,74 +19,69 @@ let checkRevisionCount = 0; (async () => { await util.promisify(npm.load)({}); - try { - // initialize database - require('ep_etherpad-lite/node/utils/Settings'); - const db = require('ep_etherpad-lite/node/db/DB'); - await db.init(); + // initialize database + require('ep_etherpad-lite/node/utils/Settings'); + const db = require('ep_etherpad-lite/node/db/DB'); + await db.init(); - // load modules - const Changeset = require('ep_etherpad-lite/static/js/Changeset'); - const padManager = require('ep_etherpad-lite/node/db/PadManager'); + // load modules + const Changeset = require('ep_etherpad-lite/static/js/Changeset'); + const padManager = require('ep_etherpad-lite/node/db/PadManager'); - const exists = await padManager.doesPadExists(padId); - if (!exists) throw new Error('Pad does not exist'); + const exists = await padManager.doesPadExists(padId); + if (!exists) throw new Error('Pad does not exist'); - // get the pad - const pad = await padManager.getPad(padId); + // get the pad + const pad = await padManager.getPad(padId); - // create an array with key revisions - // key revisions always save the full pad atext - const head = pad.getHeadRevisionNumber(); - const keyRevisions = []; - for (let rev = 0; rev < head; rev += 100) { - keyRevisions.push(rev); + // create an array with key revisions + // key revisions always save the full pad atext + const head = pad.getHeadRevisionNumber(); + const keyRevisions = []; + for (let rev = 0; rev < head; rev += 100) { + keyRevisions.push(rev); + } + + // run through all key revisions + for (let keyRev of keyRevisions) { + keyRev = parseInt(keyRev); + // create an array of revisions we need till the next keyRevision or the End + const revisionsNeeded = []; + for (let rev = keyRev; rev <= keyRev + 100 && rev <= head; rev++) { + revisionsNeeded.push(rev); } - // run through all key revisions - for (let keyRev of keyRevisions) { - keyRev = parseInt(keyRev); - // create an array of revisions we need till the next keyRevision or the End - const revisionsNeeded = []; - for (let rev = keyRev; rev <= keyRev + 100 && rev <= head; rev++) { - revisionsNeeded.push(rev); - } + // this array will hold all revision changesets + const revisions = []; - // this array will hold all revision changesets - const revisions = []; + // run through all needed revisions and get them from the database + for (const revNum of revisionsNeeded) { + const revision = await db.get(`pad:${padId}:revs:${revNum}`); + revisions[revNum] = revision; + } - // run through all needed revisions and get them from the database - for (const revNum of revisionsNeeded) { - const revision = await db.get(`pad:${padId}:revs:${revNum}`); - revisions[revNum] = revision; - } + // check if the pad has a pool + if (pad.pool == null) throw new Error('Attribute pool is missing'); - // check if the pad has a pool - if (pad.pool == null) throw new Error('Attribute pool is missing'); + // check if there is an atext in the keyRevisions + let {meta: {atext} = {}} = revisions[keyRev] || {}; + if (atext == null) { + console.error(`No atext in key revision ${keyRev}`); + continue; + } - // check if there is an atext in the keyRevisions - let {meta: {atext} = {}} = revisions[keyRev] || {}; - if (atext == null) { - console.error(`No atext in key revision ${keyRev}`); + const apool = pad.pool; + + for (let rev = keyRev + 1; rev <= keyRev + 100 && rev <= head; rev++) { + checkRevisionCount++; + try { + const cs = revisions[rev].changeset; + atext = Changeset.applyToAText(cs, atext, apool); + } catch (e) { + console.error(`Bad changeset at revision ${rev} - ${e.message}`); continue; } - - const apool = pad.pool; - - for (let rev = keyRev + 1; rev <= keyRev + 100 && rev <= head; rev++) { - checkRevisionCount++; - try { - const cs = revisions[rev].changeset; - atext = Changeset.applyToAText(cs, atext, apool); - } catch (e) { - console.error(`Bad changeset at revision ${rev} - ${e.message}`); - continue; - } - } - console.log(`Finished: Checked ${checkRevisionCount} revisions`); } - } catch (err) { - console.trace(err); - throw err; + console.log(`Finished: Checked ${checkRevisionCount} revisions`); } })(); diff --git a/bin/extractPadData.js b/bin/extractPadData.js index 58fe50a42..181a8c6bf 100644 --- a/bin/extractPadData.js +++ b/bin/extractPadData.js @@ -21,54 +21,49 @@ const util = require('util'); (async () => { await util.promisify(npm.load)({}); - try { - // initialize database - require('ep_etherpad-lite/node/utils/Settings'); - const db = require('ep_etherpad-lite/node/db/DB'); - await db.init(); + // initialize database + require('ep_etherpad-lite/node/utils/Settings'); + const db = require('ep_etherpad-lite/node/db/DB'); + await db.init(); - // load extra modules - const dirtyDB = require('ep_etherpad-lite/node_modules/dirty'); - const padManager = require('ep_etherpad-lite/node/db/PadManager'); + // load extra modules + const dirtyDB = require('ep_etherpad-lite/node_modules/dirty'); + const padManager = require('ep_etherpad-lite/node/db/PadManager'); - // initialize output database - const dirty = dirtyDB(`${padId}.db`); + // initialize output database + const dirty = dirtyDB(`${padId}.db`); - // Promise wrapped get and set function - const wrapped = db.db.db.wrappedDB; - const get = util.promisify(wrapped.get.bind(wrapped)); - const set = util.promisify(dirty.set.bind(dirty)); + // Promise wrapped get and set function + const wrapped = db.db.db.wrappedDB; + const get = util.promisify(wrapped.get.bind(wrapped)); + const set = util.promisify(dirty.set.bind(dirty)); - // array in which required key values will be accumulated - const neededDBValues = [`pad:${padId}`]; + // array in which required key values will be accumulated + const neededDBValues = [`pad:${padId}`]; - // get the actual pad object - const pad = await padManager.getPad(padId); + // get the actual pad object + const pad = await padManager.getPad(padId); - // add all authors - neededDBValues.push(...pad.getAllAuthors().map((author) => `globalAuthor:${author}`)); + // add all authors + neededDBValues.push(...pad.getAllAuthors().map((author) => `globalAuthor:${author}`)); - // add all revisions - for (let rev = 0; rev <= pad.head; ++rev) { - neededDBValues.push(`pad:${padId}:revs:${rev}`); - } - - // add all chat values - for (let chat = 0; chat <= pad.chatHead; ++chat) { - neededDBValues.push(`pad:${padId}:chat:${chat}`); - } - - for (const dbkey of neededDBValues) { - let dbvalue = await get(dbkey); - if (dbvalue && typeof dbvalue !== 'object') { - dbvalue = JSON.parse(dbvalue); - } - await set(dbkey, dbvalue); - } - - console.log('finished'); - } catch (err) { - console.error(err); - throw err; + // add all revisions + for (let rev = 0; rev <= pad.head; ++rev) { + neededDBValues.push(`pad:${padId}:revs:${rev}`); } + + // add all chat values + for (let chat = 0; chat <= pad.chatHead; ++chat) { + neededDBValues.push(`pad:${padId}:chat:${chat}`); + } + + for (const dbkey of neededDBValues) { + let dbvalue = await get(dbkey); + if (dbvalue && typeof dbvalue !== 'object') { + dbvalue = JSON.parse(dbvalue); + } + await set(dbkey, dbvalue); + } + + console.log('finished'); })(); From c622894fe0b6b7d17f5e286b9c2b2d85a3408b04 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sat, 9 Jan 2021 03:08:50 -0500 Subject: [PATCH 111/153] bin scripts: Promisify db.init and db.close --- bin/importSqlFile.js | 59 +++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 33 deletions(-) diff --git a/bin/importSqlFile.js b/bin/importSqlFile.js index b02e9e10c..5927d82ce 100644 --- a/bin/importSqlFile.js +++ b/bin/importSqlFile.js @@ -71,42 +71,35 @@ const unescape = (val) => { if (!sqlFile) throw new Error('Use: node importSqlFile.js $SQLFILE'); log('initializing db'); - db.init((err) => { - // there was an error while initializing the database, output it and stop - if (err) { - throw err; - } else { - log('done'); + await util.promisify(db.init.bind(db))(); + log('done'); - log('open output file...'); - const lines = fs.readFileSync(sqlFile, 'utf8').split('\n'); + log('open output file...'); + const lines = fs.readFileSync(sqlFile, 'utf8').split('\n'); - const count = lines.length; - let keyNo = 0; + const count = lines.length; + let keyNo = 0; - process.stdout.write(`Start importing ${count} keys...\n`); - lines.forEach((l) => { - if (l.substr(0, 27) === 'REPLACE INTO store VALUES (') { - const pos = l.indexOf("', '"); - const key = l.substr(28, pos - 28); - let value = l.substr(pos + 3); - value = value.substr(0, value.length - 2); - console.log(`key: ${key} val: ${value}`); - console.log(`unval: ${unescape(value)}`); - db.set(key, unescape(value), null); - keyNo++; - if (keyNo % 1000 === 0) { - process.stdout.write(` ${keyNo}/${count}\n`); - } - } - }); - process.stdout.write('\n'); - process.stdout.write('done. waiting for db to finish transaction. ' + - 'depended on dbms this may take some time..\n'); - - db.close(() => { - log(`finished, imported ${keyNo} keys.`); - }); + process.stdout.write(`Start importing ${count} keys...\n`); + lines.forEach((l) => { + if (l.substr(0, 27) === 'REPLACE INTO store VALUES (') { + const pos = l.indexOf("', '"); + const key = l.substr(28, pos - 28); + let value = l.substr(pos + 3); + value = value.substr(0, value.length - 2); + console.log(`key: ${key} val: ${value}`); + console.log(`unval: ${unescape(value)}`); + db.set(key, unescape(value), null); + keyNo++; + if (keyNo % 1000 === 0) { + process.stdout.write(` ${keyNo}/${count}\n`); + } } }); + process.stdout.write('\n'); + process.stdout.write('done. waiting for db to finish transaction. ' + + 'depended on dbms this may take some time..\n'); + + await util.promisify(db.close.bind(db))(); + log(`finished, imported ${keyNo} keys.`); })(); From 69efd16a6db1794ae3a719740d296a035e79c7f0 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 17 Jan 2021 03:58:28 -0500 Subject: [PATCH 112/153] bin/rebuildPad.js: Add missing calls to `util.callbackify` --- bin/rebuildPad.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/rebuildPad.js b/bin/rebuildPad.js index 0034fe336..83c9bf342 100644 --- a/bin/rebuildPad.js +++ b/bin/rebuildPad.js @@ -29,7 +29,7 @@ async.series([ (callback) => { // Get a handle into the database db = require('ep_etherpad-lite/node/db/DB'); - db.init(callback); + util.callbackify(db.init)(callback); }, (callback) => { Pad = require('ep_etherpad-lite/node/db/Pad').Pad; @@ -44,10 +44,10 @@ async.series([ if (!PadManager.isValidPadId(newPadId)) { throw new Error('Cannot create a pad with that id as it is invalid'); } - PadManager.doesPadExists(newPadId, (err, exists) => { + util.callbackify(PadManager.doesPadExist)(newPadId, (err, exists) => { if (exists) throw new Error('Cannot create a pad with that id as it already exists'); }); - PadManager.getPad(padId, (err, pad) => { + util.callbackify(PadManager.getPad)(padId, (err, pad) => { oldPad = pad; newPad = new Pad(newPadId); callback(); From 72c2abab8d1d5477075c7c09117c55136cd461aa Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 17 Jan 2021 04:19:02 -0500 Subject: [PATCH 113/153] bin/rebuildPad.js: Fix sequencing of asynchronous functions --- bin/rebuildPad.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/bin/rebuildPad.js b/bin/rebuildPad.js index 83c9bf342..0f929ef75 100644 --- a/bin/rebuildPad.js +++ b/bin/rebuildPad.js @@ -45,9 +45,14 @@ async.series([ throw new Error('Cannot create a pad with that id as it is invalid'); } util.callbackify(PadManager.doesPadExist)(newPadId, (err, exists) => { + if (err != null) return callback(err); if (exists) throw new Error('Cannot create a pad with that id as it already exists'); + callback(); }); + }, + (callback) => { util.callbackify(PadManager.getPad)(padId, (err, pad) => { + if (err) return callback(err); oldPad = pad; newPad = new Pad(newPadId); callback(); @@ -102,12 +107,11 @@ async.series([ newPad.savedRevisions = newSavedRevisions; callback(); }, + // Save the source pad + (callback) => db.db.set(`pad:${newPadId}`, newPad, callback), (callback) => { - // Save the source pad - db.db.set(`pad:${newPadId}`, newPad, (err) => { - console.log(`Created: Source Pad: pad:${newPadId}`); - util.callbackify(newPad.saveToDatabase.bind(newPad))(callback); - }); + console.log(`Created: Source Pad: pad:${newPadId}`); + util.callbackify(newPad.saveToDatabase.bind(newPad))(callback); }, ], (err) => { if (err) throw err; From 5b519b9a9cf2d5fe8412bbba56ac649f8c0fc618 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 29 Jan 2021 17:01:04 -0500 Subject: [PATCH 114/153] bin/rebuildPad.js: Asyncify --- bin/rebuildPad.js | 160 ++++++++++++++++++++-------------------------- 1 file changed, 68 insertions(+), 92 deletions(-) diff --git a/bin/rebuildPad.js b/bin/rebuildPad.js index 0f929ef75..3e6e6e5fa 100644 --- a/bin/rebuildPad.js +++ b/bin/rebuildPad.js @@ -13,7 +13,6 @@ if (process.argv.length !== 4 && process.argv.length !== 5) { throw new Error('Use: node bin/repairPad.js $PADID $REV [$NEWPADID]'); } -const async = require('ep_etherpad-lite/node_modules/async'); const npm = require('ep_etherpad-lite/node_modules/npm'); const util = require('util'); @@ -21,99 +20,76 @@ const padId = process.argv[2]; const newRevHead = process.argv[3]; const newPadId = process.argv[4] || `${padId}-rebuilt`; -let db, oldPad, newPad; -let Pad, PadManager; +(async () => { + await util.promisify(npm.load)({}); -async.series([ - (callback) => npm.load({}, callback), - (callback) => { - // Get a handle into the database - db = require('ep_etherpad-lite/node/db/DB'); - util.callbackify(db.init)(callback); - }, - (callback) => { - Pad = require('ep_etherpad-lite/node/db/Pad').Pad; - PadManager = require('ep_etherpad-lite/node/db/PadManager'); - // Get references to the original pad and to a newly created pad - // HACK: This is a standalone script, so we want to write everything - // out to the database immediately. The only problem with this is - // that a driver (like the mysql driver) can hardcode these values. - db.db.db.settings = {cache: 0, writeInterval: 0, json: true}; - // Validate the newPadId if specified and that a pad with that ID does - // not already exist to avoid overwriting it. - if (!PadManager.isValidPadId(newPadId)) { - throw new Error('Cannot create a pad with that id as it is invalid'); + const db = require('ep_etherpad-lite/node/db/DB'); + await db.init(); + + const Pad = require('ep_etherpad-lite/node/db/Pad').Pad; + const PadManager = require('ep_etherpad-lite/node/db/PadManager'); + // Get references to the original pad and to a newly created pad + // HACK: This is a standalone script, so we want to write everything + // out to the database immediately. The only problem with this is + // that a driver (like the mysql driver) can hardcode these values. + db.db.db.settings = {cache: 0, writeInterval: 0, json: true}; + // Validate the newPadId if specified and that a pad with that ID does + // not already exist to avoid overwriting it. + if (!PadManager.isValidPadId(newPadId)) { + throw new Error('Cannot create a pad with that id as it is invalid'); + } + const exists = await PadManager.doesPadExist(newPadId); + if (exists) throw new Error('Cannot create a pad with that id as it already exists'); + + const oldPad = await PadManager.getPad(padId); + const newPad = new Pad(newPadId); + + // Clone all Chat revisions + const chatHead = oldPad.chatHead; + await Promise.all([...Array(chatHead + 1).keys()].map(async (i) => { + const chat = await db.get(`pad:${padId}:chat:${i}`); + await db.set(`pad:${newPadId}:chat:${i}`, chat); + console.log(`Created: Chat Revision: pad:${newPadId}:chat:${i}`); + })); + + // Rebuild Pad from revisions up to and including the new revision head + const AuthorManager = require('ep_etherpad-lite/node/db/AuthorManager'); + const Changeset = require('ep_etherpad-lite/static/js/Changeset'); + // Author attributes are derived from changesets, but there can also be + // non-author attributes with specific mappings that changesets depend on + // and, AFAICT, cannot be recreated any other way + newPad.pool.numToAttrib = oldPad.pool.numToAttrib; + for (let curRevNum = 0; curRevNum <= newRevHead; curRevNum++) { + const rev = await db.get(`pad:${padId}:revs:${curRevNum}`); + if (rev.meta) { + throw new Error('The specified revision number could not be found.'); } - util.callbackify(PadManager.doesPadExist)(newPadId, (err, exists) => { - if (err != null) return callback(err); - if (exists) throw new Error('Cannot create a pad with that id as it already exists'); - callback(); - }); - }, - (callback) => { - util.callbackify(PadManager.getPad)(padId, (err, pad) => { - if (err) return callback(err); - oldPad = pad; - newPad = new Pad(newPadId); - callback(); - }); - }, - (callback) => { - // Clone all Chat revisions - const chatHead = oldPad.chatHead; - for (let i = 0, curHeadNum = 0; i <= chatHead; i++) { - db.db.get(`pad:${padId}:chat:${i}`, (err, chat) => { - db.db.set(`pad:${newPadId}:chat:${curHeadNum++}`, chat); - console.log(`Created: Chat Revision: pad:${newPadId}:chat:${curHeadNum}`); - }); + const newRevNum = ++newPad.head; + const newRevId = `pad:${newPad.id}:revs:${newRevNum}`; + await Promise.all([ + db.set(newRevId, rev), + AuthorManager.addPad(rev.meta.author, newPad.id), + ]); + newPad.atext = Changeset.applyToAText(rev.changeset, newPad.atext, newPad.pool); + console.log(`Created: Revision: pad:${newPad.id}:revs:${newRevNum}`); + } + + // Add saved revisions up to the new revision head + console.log(newPad.head); + const newSavedRevisions = []; + for (const savedRev of oldPad.savedRevisions) { + if (savedRev.revNum <= newRevHead) { + newSavedRevisions.push(savedRev); + console.log(`Added: Saved Revision: ${savedRev.revNum}`); } - callback(); - }, - (callback) => { - // Rebuild Pad from revisions up to and including the new revision head - const AuthorManager = require('ep_etherpad-lite/node/db/AuthorManager'); - const Changeset = require('ep_etherpad-lite/static/js/Changeset'); - // Author attributes are derived from changesets, but there can also be - // non-author attributes with specific mappings that changesets depend on - // and, AFAICT, cannot be recreated any other way - newPad.pool.numToAttrib = oldPad.pool.numToAttrib; - for (let curRevNum = 0; curRevNum <= newRevHead; curRevNum++) { - db.db.get(`pad:${padId}:revs:${curRevNum}`, (err, rev) => { - if (rev.meta) { - throw new Error('The specified revision number could not be found.'); - } - const newRevNum = ++newPad.head; - const newRevId = `pad:${newPad.id}:revs:${newRevNum}`; - db.db.set(newRevId, rev); - AuthorManager.addPad(rev.meta.author, newPad.id); - newPad.atext = Changeset.applyToAText(rev.changeset, newPad.atext, newPad.pool); - console.log(`Created: Revision: pad:${newPad.id}:revs:${newRevNum}`); - if (newRevNum === newRevHead) { - callback(); - } - }); - } - }, - (callback) => { - // Add saved revisions up to the new revision head - console.log(newPad.head); - const newSavedRevisions = []; - for (const savedRev of oldPad.savedRevisions) { - if (savedRev.revNum <= newRevHead) { - newSavedRevisions.push(savedRev); - console.log(`Added: Saved Revision: ${savedRev.revNum}`); - } - } - newPad.savedRevisions = newSavedRevisions; - callback(); - }, + } + newPad.savedRevisions = newSavedRevisions; + // Save the source pad - (callback) => db.db.set(`pad:${newPadId}`, newPad, callback), - (callback) => { - console.log(`Created: Source Pad: pad:${newPadId}`); - util.callbackify(newPad.saveToDatabase.bind(newPad))(callback); - }, -], (err) => { - if (err) throw err; + await db.set(`pad:${newPadId}`, newPad); + + console.log(`Created: Source Pad: pad:${newPadId}`); + await newPad.saveToDatabase(); + console.info('finished'); -}); +})(); From 809dc6e367f1db7f25e08dcc04fda5eb7e9b1b0f Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 29 Jan 2021 17:15:00 -0500 Subject: [PATCH 115/153] bin/rebuildPad.js: PadManager must be loaded before Pad There is a circular dependency between the two; loading PadManager first ensures that PadManager's Pad variable is not undefined. --- bin/rebuildPad.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/rebuildPad.js b/bin/rebuildPad.js index 3e6e6e5fa..f5043b85b 100644 --- a/bin/rebuildPad.js +++ b/bin/rebuildPad.js @@ -26,8 +26,8 @@ const newPadId = process.argv[4] || `${padId}-rebuilt`; const db = require('ep_etherpad-lite/node/db/DB'); await db.init(); - const Pad = require('ep_etherpad-lite/node/db/Pad').Pad; const PadManager = require('ep_etherpad-lite/node/db/PadManager'); + const Pad = require('ep_etherpad-lite/node/db/Pad').Pad; // Get references to the original pad and to a newly created pad // HACK: This is a standalone script, so we want to write everything // out to the database immediately. The only problem with this is From bf209ddad38ce12f446093092c7f5899a6d7144b Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 29 Jan 2021 17:19:40 -0500 Subject: [PATCH 116/153] bin/rebuildPad.js: Close the database when done This prevents loss of data due to unflushed writes. --- bin/rebuildPad.js | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/rebuildPad.js b/bin/rebuildPad.js index f5043b85b..f541a4ce4 100644 --- a/bin/rebuildPad.js +++ b/bin/rebuildPad.js @@ -91,5 +91,6 @@ const newPadId = process.argv[4] || `${padId}-rebuilt`; console.log(`Created: Source Pad: pad:${newPadId}`); await newPad.saveToDatabase(); + await db.shutdown(); console.info('finished'); })(); From 846e3e9fbdce80c3ff84e7ae94d5d7d698e4978a Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 29 Jan 2021 17:20:25 -0500 Subject: [PATCH 117/153] bin/rebuildPad.js: Don't overwrite DB settings There's no need, and setting `json` to true breaks databases that do their own serialization of ECMAScript objects. --- bin/rebuildPad.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/bin/rebuildPad.js b/bin/rebuildPad.js index f541a4ce4..870bbcc4a 100644 --- a/bin/rebuildPad.js +++ b/bin/rebuildPad.js @@ -28,11 +28,6 @@ const newPadId = process.argv[4] || `${padId}-rebuilt`; const PadManager = require('ep_etherpad-lite/node/db/PadManager'); const Pad = require('ep_etherpad-lite/node/db/Pad').Pad; - // Get references to the original pad and to a newly created pad - // HACK: This is a standalone script, so we want to write everything - // out to the database immediately. The only problem with this is - // that a driver (like the mysql driver) can hardcode these values. - db.db.db.settings = {cache: 0, writeInterval: 0, json: true}; // Validate the newPadId if specified and that a pad with that ID does // not already exist to avoid overwriting it. if (!PadManager.isValidPadId(newPadId)) { From 0ad0160b7ce8e17053c6c255cd34ccd845d291fc Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Fri, 29 Jan 2021 17:23:11 -0500 Subject: [PATCH 118/153] bin/rebuildPad.js: Fix check for existing rev --- bin/rebuildPad.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bin/rebuildPad.js b/bin/rebuildPad.js index 870bbcc4a..1bc942fe2 100644 --- a/bin/rebuildPad.js +++ b/bin/rebuildPad.js @@ -56,9 +56,7 @@ const newPadId = process.argv[4] || `${padId}-rebuilt`; newPad.pool.numToAttrib = oldPad.pool.numToAttrib; for (let curRevNum = 0; curRevNum <= newRevHead; curRevNum++) { const rev = await db.get(`pad:${padId}:revs:${curRevNum}`); - if (rev.meta) { - throw new Error('The specified revision number could not be found.'); - } + if (!rev || !rev.meta) throw new Error('The specified revision number could not be found.'); const newRevNum = ++newPad.head; const newRevId = `pad:${newPad.id}:revs:${newRevNum}`; await Promise.all([ From 86ceb2b610a2a9a15fedc70b5690017e41fee5fe Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 14 Dec 2020 20:45:12 -0500 Subject: [PATCH 119/153] server: Exit on unhandled Promise rejection --- src/node/server.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/node/server.js b/src/node/server.js index 3e3b25d21..d14fca92d 100755 --- a/src/node/server.js +++ b/src/node/server.js @@ -77,6 +77,9 @@ exports.start = async () => { } process.on('uncaughtException', exports.exit); + // As of v14, Node.js does not exit when there is an unhandled Promise rejection. Convert an + // unhandled rejection into an uncaught exception, which does cause Node.js to exit. + process.on('unhandledRejection', (err) => { throw err; }); /* * Connect graceful shutdown with sigint and uncaught exception From d339f2a6715f154bae7d68e52393377f0030f18f Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 22 Dec 2020 00:45:33 -0500 Subject: [PATCH 120/153] server: Perform init after adding uncaught exception handler This avoids an unnecessary `try` block. --- src/node/server.js | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/node/server.js b/src/node/server.js index d14fca92d..ece5ed25b 100755 --- a/src/node/server.js +++ b/src/node/server.js @@ -60,22 +60,6 @@ exports.start = async () => { stats.gauge('memoryUsage', () => process.memoryUsage().rss); stats.gauge('memoryUsageHeap', () => process.memoryUsage().heapUsed); - await util.promisify(npm.load)(); - - try { - await db.init(); - await plugins.update(); - console.info(`Installed plugins: ${plugins.formatPluginsWithVersion()}`); - console.debug(`Installed parts:\n${plugins.formatParts()}`); - console.debug(`Installed hooks:\n${plugins.formatHooks()}`); - await hooks.aCallAll('loadSettings', {settings}); - await hooks.aCallAll('createServer'); - } catch (e) { - console.error(`exception thrown: ${e.message}`); - if (e.stack) console.log(e.stack); - process.exit(1); - } - process.on('uncaughtException', exports.exit); // As of v14, Node.js does not exit when there is an unhandled Promise rejection. Convert an // unhandled rejection into an uncaught exception, which does cause Node.js to exit. @@ -105,6 +89,15 @@ exports.start = async () => { // Pass undefined to exports.exit because this is not an abnormal termination. process.on('SIGTERM', () => exports.exit()); + await util.promisify(npm.load)(); + await db.init(); + await plugins.update(); + console.info(`Installed plugins: ${plugins.formatPluginsWithVersion()}`); + console.debug(`Installed parts:\n${plugins.formatParts()}`); + console.debug(`Installed hooks:\n${plugins.formatHooks()}`); + await hooks.aCallAll('loadSettings', {settings}); + await hooks.aCallAll('createServer'); + // Return the HTTP server to make it easier to write tests. return express.server; }; From 725023fe5883ebc67723948a98e7c06042216fc0 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 22 Dec 2020 01:01:37 -0500 Subject: [PATCH 121/153] server: Refactor `stop()` to avoid no-async-promise-executor lint error Also log when Etherpad has stopped. --- src/node/server.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/node/server.js b/src/node/server.js index ece5ed25b..38ffce22c 100755 --- a/src/node/server.js +++ b/src/node/server.js @@ -106,12 +106,15 @@ exports.stop = async () => { if (stopped) return; stopped = true; console.log('Stopping Etherpad...'); - await new Promise(async (resolve, reject) => { - const id = setTimeout(() => reject(new Error('Timed out waiting for shutdown tasks')), 3000); - await hooks.aCallAll('shutdown'); - clearTimeout(id); - resolve(); - }); + let timeout = null; + await Promise.race([ + hooks.aCallAll('shutdown'), + new Promise((resolve, reject) => { + timeout = setTimeout(() => reject(new Error('Timed out waiting for shutdown tasks')), 3000); + }), + ]); + clearTimeout(timeout); + console.log('Etherpad stopped'); }; exports.exit = async (err) => { From ecdb105bfed80f22ab67ec3640cc09e0019233c6 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 22 Dec 2020 01:08:50 -0500 Subject: [PATCH 122/153] server: Refine process lifetime management Define states and use them to properly handle multiple calls to `start()`, `stop()`, and `exit()`. (Multiple calls to `exit()` can happen if there is an uncaught exception or signal during shutdown.) This should also make it easier to add support for cleanly restarting the server after a shutdown (for tests or via an `/admin` page). --- src/node/server.js | 127 +++++++++++++++++++++++++++++++++------- tests/backend/common.js | 2 +- 2 files changed, 108 insertions(+), 21 deletions(-) diff --git a/src/node/server.js b/src/node/server.js index 38ffce22c..4cfca5fd1 100755 --- a/src/node/server.js +++ b/src/node/server.js @@ -44,13 +44,38 @@ const plugins = require('../static/js/pluginfw/plugins'); const settings = require('./utils/Settings'); const util = require('util'); -let started = false; -let stopped = false; +const State = { + INITIAL: 1, + STARTING: 2, + RUNNING: 3, + STOPPING: 4, + STOPPED: 5, + EXITING: 6, + WAITING_FOR_EXIT: 7, +}; +let state = State.INITIAL; + +const runningCallbacks = []; exports.start = async () => { - if (started) return express.server; - started = true; - if (stopped) throw new Error('restart not supported'); + switch (state) { + case State.INITIAL: + break; + case State.STARTING: + await new Promise((resolve) => runningCallbacks.push(resolve)); + // fall through + case State.RUNNING: + return express.server; + case State.STOPPING: + case State.STOPPED: + case State.EXITING: + case State.WAITING_FOR_EXIT: + throw new Error('restart not supported'); + default: + throw new Error(`unknown State: ${state.toString()}`); + } + console.log('Starting Etherpad...'); + state = State.STARTING; // Check if Etherpad version is up-to-date UpdateCheck.check(); @@ -86,8 +111,7 @@ exports.start = async () => { process.on('SIGINT', exports.exit); // When running as PID1 (e.g. in docker container) allow graceful shutdown on SIGTERM c.f. #3265. - // Pass undefined to exports.exit because this is not an abnormal termination. - process.on('SIGTERM', () => exports.exit()); + process.on('SIGTERM', exports.exit); await util.promisify(npm.load)(); await db.init(); @@ -98,14 +122,36 @@ exports.start = async () => { await hooks.aCallAll('loadSettings', {settings}); await hooks.aCallAll('createServer'); + console.log('Etherpad is running'); + state = State.RUNNING; + while (runningCallbacks.length > 0) setImmediate(runningCallbacks.pop()); + // Return the HTTP server to make it easier to write tests. return express.server; }; +const stoppedCallbacks = []; exports.stop = async () => { - if (stopped) return; - stopped = true; + switch (state) { + case State.STARTING: + await exports.start(); + // Don't fall through to State.RUNNING in case another caller is also waiting for startup. + return await exports.stop(); + case State.RUNNING: + break; + case State.STOPPING: + await new Promise((resolve) => stoppedCallbacks.push(resolve)); + // fall through + case State.INITIAL: + case State.STOPPED: + case State.EXITING: + case State.WAITING_FOR_EXIT: + return; + default: + throw new Error(`unknown State: ${state.toString()}`); + } console.log('Stopping Etherpad...'); + state = State.STOPPING; let timeout = null; await Promise.race([ hooks.aCallAll('shutdown'), @@ -115,21 +161,62 @@ exports.stop = async () => { ]); clearTimeout(timeout); console.log('Etherpad stopped'); + state = State.STOPPED; + while (stoppedCallbacks.length > 0) setImmediate(stoppedCallbacks.pop()); }; -exports.exit = async (err) => { - let exitCode = 0; - if (err) { - exitCode = 1; - console.error(err.stack ? err.stack : err); +const exitCallbacks = []; +let exitCalled = false; +exports.exit = async (err = null) => { + /* eslint-disable no-process-exit */ + if (err === 'SIGTERM') { + // Termination from SIGTERM is not treated as an abnormal termination. + console.log('Received SIGTERM signal'); + err = null; + } else if (err != null) { + console.error(err.stack || err.toString()); + process.exitCode = 1; + if (exitCalled) { + console.error('Error occurred while waiting to exit. Forcing an immediate unclean exit...'); + process.exit(1); + } } - try { - await exports.stop(); - } catch (err) { - exitCode = 1; - console.error(err.stack ? err.stack : err); + exitCalled = true; + switch (state) { + case State.STARTING: + case State.RUNNING: + case State.STOPPING: + await exports.stop(); + // Don't fall through to State.STOPPED in case another caller is also waiting for stop(). + // Don't pass err to exports.exit() because this err has already been processed. (If err is + // passed again to exit() then exit() will think that a second error occurred while exiting.) + return await exports.exit(); + case State.INITIAL: + case State.STOPPED: + break; + case State.EXITING: + await new Promise((resolve) => exitCallbacks.push(resolve)); + // fall through + case State.WAITING_FOR_EXIT: + return; + default: + throw new Error(`unknown State: ${state.toString()}`); } - process.exit(exitCode); + console.log('Exiting...'); + state = State.EXITING; + while (exitCallbacks.length > 0) setImmediate(exitCallbacks.pop()); + // Node.js should exit on its own without further action. Add a timeout to force Node.js to exit + // just in case something failed to get cleaned up during the shutdown hook. unref() is called on + // the timeout so that the timeout itself does not prevent Node.js from exiting. + setTimeout(() => { + console.error('Something that should have been cleaned up during the shutdown hook (such as ' + + 'a timer, worker thread, or open connection) is preventing Node.js from exiting'); + console.error('Forcing an unclean exit...'); + process.exit(1); + }, 5000).unref(); + console.log('Waiting for Node.js to exit...'); + state = State.WAITING_FOR_EXIT; + /* eslint-enable no-process-exit */ }; if (require.main === module) exports.start(); diff --git a/tests/backend/common.js b/tests/backend/common.js index 22a84c097..642f83afe 100644 --- a/tests/backend/common.js +++ b/tests/backend/common.js @@ -50,10 +50,10 @@ exports.init = async function () { after(async function () { webaccess.authnFailureDelayMs = backups.authnFailureDelayMs; - await server.stop(); // Note: This does not unset settings that were added. Object.assign(settings, backups.settings); log4js.setGlobalLogLevel(logLevel); + await server.exit(); }); return exports.agent; From ba81ead1018e2c78ae724226bb7a0b845544b62f Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 22 Dec 2020 01:21:43 -0500 Subject: [PATCH 123/153] server: Remove all other signal listeners --- src/node/server.js | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/node/server.js b/src/node/server.js index 4cfca5fd1..1a6f9cbe5 100755 --- a/src/node/server.js +++ b/src/node/server.js @@ -56,6 +56,13 @@ const State = { let state = State.INITIAL; +const removeSignalListener = (signal, listener) => { + console.debug(`Removing ${signal} listener because it might interfere with shutdown tasks. ` + + `Function code:\n${listener.toString()}\n` + + `Current stack:\n${(new Error()).stack.split('\n').slice(1).join('\n')}`); + process.off(signal, listener); +}; + const runningCallbacks = []; exports.start = async () => { switch (state) { @@ -90,28 +97,21 @@ exports.start = async () => { // unhandled rejection into an uncaught exception, which does cause Node.js to exit. process.on('unhandledRejection', (err) => { throw err; }); - /* - * Connect graceful shutdown with sigint and uncaught exception - * - * Until Etherpad 1.7.5, process.on('SIGTERM') and process.on('SIGINT') were - * not hooked up under Windows, because old nodejs versions did not support - * them. - * - * According to nodejs 6.x documentation, it is now safe to do so. This - * allows to gracefully close the DB connection when hitting CTRL+C under - * Windows, for example. - * - * Source: https://nodejs.org/docs/latest-v6.x/api/process.html#process_signal_events - * - * - SIGTERM is not supported on Windows, it can be listened on. - * - SIGINT from the terminal is supported on all platforms, and can usually - * be generated with +C (though this may be configurable). It is not - * generated when terminal raw mode is enabled. - */ - process.on('SIGINT', exports.exit); - - // When running as PID1 (e.g. in docker container) allow graceful shutdown on SIGTERM c.f. #3265. - process.on('SIGTERM', exports.exit); + for (const signal of ['SIGINT', 'SIGTERM']) { + // Forcibly remove other signal listeners to prevent them from terminating node before we are + // done cleaning up. See https://github.com/andywer/threads.js/pull/329 for an example of a + // problematic listener. This means that exports.exit is solely responsible for performing all + // necessary cleanup tasks. + for (const listener of process.listeners(signal)) { + removeSignalListener(signal, listener); + } + process.on(signal, exports.exit); + // Prevent signal listeners from being added in the future. + process.on('newListener', (event, listener) => { + if (event !== signal) return; + removeSignalListener(signal, listener); + }); + } await util.promisify(npm.load)(); await db.init(); From 877f0c5883a33c9e513e81fc56d2fa6c3ed66c9e Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Tue, 15 Dec 2020 03:23:12 -0500 Subject: [PATCH 124/153] server: Use wtfnode to log reasons why node isn't exiting --- package-lock.json | 8 +++++++- src/node/server.js | 5 +++++ src/package-lock.json | 5 +++++ src/package.json | 3 ++- 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4dcc411d9..67ca85767 100644 --- a/package-lock.json +++ b/package-lock.json @@ -870,7 +870,8 @@ "tinycon": "0.0.1", "ueberdb2": "^1.2.5", "underscore": "1.8.3", - "unorm": "1.4.1" + "unorm": "1.4.1", + "wtfnode": "^0.8.4" }, "dependencies": { "@apidevtools/json-schema-ref-parser": { @@ -10577,6 +10578,11 @@ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" }, + "wtfnode": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/wtfnode/-/wtfnode-0.8.4.tgz", + "integrity": "sha512-64GEKtMt/MUBuAm+8kHqP74ojjafzu00aT0JKsmkIwYmjRQ/odO0yhbzKLm+Z9v1gMla+8dwITRKzTAlHsB+Og==" + }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/src/node/server.js b/src/node/server.js index 1a6f9cbe5..bbe4c7aeb 100755 --- a/src/node/server.js +++ b/src/node/server.js @@ -27,6 +27,10 @@ const log4js = require('log4js'); log4js.replaceConsole(); +// wtfnode should be loaded after log4js.replaceConsole() so that it uses log4js for logging, and it +// should be above everything else so that it can hook in before resources are used. +const wtfnode = require('wtfnode'); + /* * early check for version compatibility before calling * any modules that require newer versions of NodeJS @@ -211,6 +215,7 @@ exports.exit = async (err = null) => { setTimeout(() => { console.error('Something that should have been cleaned up during the shutdown hook (such as ' + 'a timer, worker thread, or open connection) is preventing Node.js from exiting'); + wtfnode.dump(); console.error('Forcing an unclean exit...'); process.exit(1); }, 5000).unref(); diff --git a/src/package-lock.json b/src/package-lock.json index 3e04ec287..07441bde4 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -8659,6 +8659,11 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.2.tgz", "integrity": "sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA==" }, + "wtfnode": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/wtfnode/-/wtfnode-0.8.4.tgz", + "integrity": "sha512-64GEKtMt/MUBuAm+8kHqP74ojjafzu00aT0JKsmkIwYmjRQ/odO0yhbzKLm+Z9v1gMla+8dwITRKzTAlHsB+Og==" + }, "xml2js": { "version": "0.4.23", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", diff --git a/src/package.json b/src/package.json index bc3e4d22f..816f5b587 100644 --- a/src/package.json +++ b/src/package.json @@ -72,7 +72,8 @@ "tinycon": "0.0.1", "ueberdb2": "^1.2.5", "underscore": "1.8.3", - "unorm": "1.4.1" + "unorm": "1.4.1", + "wtfnode": "^0.8.4" }, "bin": { "etherpad-lite": "node/server.js" From 0cc8405e9c8e2c7acfe5607c46907287c0a52006 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 19 Jan 2021 16:37:12 +0000 Subject: [PATCH 125/153] Bump minimum required Node.js version to 10.17.0 This makes it possible to use fs.promises. --- CHANGELOG.md | 4 ++++ README.md | 4 ++-- bin/plugins/checkPlugin.js | 2 +- doc/plugins.md | 2 +- package.json | 2 +- src/node/server.js | 4 ++-- src/package.json | 2 +- 7 files changed, 12 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b39ce09ec..42c2692b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ # Changes for the next release + +### Compatibility changes +* Node.js 10.17.0 or newer is now required. + ### Notable new features * Database performance is significantly improved. diff --git a/README.md b/README.md index 10dbd36cd..5a66ddd78 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Etherpad is a real-time collaborative editor [scalable to thousands of simultane # Installation ## Requirements -- `nodejs` >= **10.13.0**. +- `nodejs` >= **10.17.0**. ## GNU/Linux and other UNIX-like systems @@ -25,7 +25,7 @@ git clone --branch master https://github.com/ether/etherpad-lite.git && cd ether ``` ### Manual install -You'll need git and [node.js](https://nodejs.org) installed (minimum required Node version: **10.13.0**). +You'll need git and [node.js](https://nodejs.org) installed (minimum required Node version: **10.17.0**). **As any user (we recommend creating a separate user called etherpad):** diff --git a/bin/plugins/checkPlugin.js b/bin/plugins/checkPlugin.js index cbe146aa1..0b736af80 100755 --- a/bin/plugins/checkPlugin.js +++ b/bin/plugins/checkPlugin.js @@ -263,7 +263,7 @@ fs.readdir(pluginPath, (err, rootFiles) => { console.warn('No engines or node engine in package.json'); if (autoFix) { const engines = { - node: '>=10.13.0', + node: '^10.17.0 || >=11.14.0', }; parsedPackageJSON.engines = engines; writePackageJson(parsedPackageJSON); diff --git a/doc/plugins.md b/doc/plugins.md index 2062378bb..d8239c68a 100644 --- a/doc/plugins.md +++ b/doc/plugins.md @@ -225,7 +225,7 @@ publish your plugin. "author": "USERNAME (REAL NAME) ", "contributors": [], "dependencies": {"MODULE": "0.3.20"}, - "engines": { "node": ">= 10.13.0"} + "engines": { "node": "^10.17.0 || >=11.14.0"} } ``` diff --git a/package.json b/package.json index 41e472831..03cb677ba 100644 --- a/package.json +++ b/package.json @@ -100,6 +100,6 @@ "lint": "eslint ." }, "engines": { - "node": ">=10.13.0" + "node": "^10.17.0 || >=11.14.0" } } diff --git a/src/node/server.js b/src/node/server.js index bbe4c7aeb..a0d9e2adc 100755 --- a/src/node/server.js +++ b/src/node/server.js @@ -36,8 +36,8 @@ const wtfnode = require('wtfnode'); * any modules that require newer versions of NodeJS */ const NodeVersion = require('./utils/NodeVersion'); -NodeVersion.enforceMinNodeVersion('10.13.0'); -NodeVersion.checkDeprecationStatus('10.13.0', '1.8.3'); +NodeVersion.enforceMinNodeVersion('10.17.0'); +NodeVersion.checkDeprecationStatus('10.17.0', '1.8.8'); const UpdateCheck = require('./utils/UpdateCheck'); const db = require('./db/DB'); diff --git a/src/package.json b/src/package.json index 816f5b587..8399c19bd 100644 --- a/src/package.json +++ b/src/package.json @@ -139,7 +139,7 @@ "root": true }, "engines": { - "node": ">=10.13.0", + "node": "^10.17.0 || >=11.14.0", "npm": ">=5.5.1" }, "repository": { From b3dda3b11c23f36942d283c0974a3664268f6242 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 19 Jan 2021 16:37:12 +0000 Subject: [PATCH 126/153] lint: src/static/js/pluginfw/*.js --- src/static/js/pluginfw/hooks.js | 56 ++++++++++----------- src/static/js/pluginfw/installer.js | 72 ++++++++++++++------------- src/static/js/pluginfw/plugin_defs.js | 2 + src/static/js/pluginfw/plugins.js | 51 ++++++++----------- src/static/js/pluginfw/shared.js | 34 +++++++------ 5 files changed, 109 insertions(+), 106 deletions(-) diff --git a/src/static/js/pluginfw/hooks.js b/src/static/js/pluginfw/hooks.js index 6243a9305..e61079eb6 100644 --- a/src/static/js/pluginfw/hooks.js +++ b/src/static/js/pluginfw/hooks.js @@ -1,4 +1,4 @@ -/* global exports, require */ +'use strict'; const _ = require('underscore'); const pluginDefs = require('./plugin_defs'); @@ -15,30 +15,28 @@ exports.deprecationNotices = {}; const deprecationWarned = {}; -function checkDeprecation(hook) { +const checkDeprecation = (hook) => { const notice = exports.deprecationNotices[hook.hook_name]; if (notice == null) return; if (deprecationWarned[hook.hook_fn_name]) return; console.warn(`${hook.hook_name} hook used by the ${hook.part.plugin} plugin ` + `(${hook.hook_fn_name}) is deprecated: ${notice}`); deprecationWarned[hook.hook_fn_name] = true; -} +}; exports.bubbleExceptions = true; -const hookCallWrapper = function (hook, hook_name, args, cb) { - if (cb === undefined) cb = function (x) { return x; }; +const hookCallWrapper = (hook, hook_name, args, cb) => { + if (cb === undefined) cb = (x) => x; checkDeprecation(hook); // Normalize output to list for both sync and async cases - const normalize = function (x) { + const normalize = (x) => { if (x === undefined) return []; return x; }; - const normalizedhook = function () { - return normalize(hook.hook_fn(hook_name, args, (x) => cb(normalize(x)))); - }; + const normalizedhook = () => normalize(hook.hook_fn(hook_name, args, (x) => cb(normalize(x)))); if (exports.bubbleExceptions) { return normalizedhook(); @@ -51,7 +49,7 @@ const hookCallWrapper = function (hook, hook_name, args, cb) { } }; -exports.syncMapFirst = function (lst, fn) { +exports.syncMapFirst = (lst, fn) => { let i; let result; for (i = 0; i < lst.length; i++) { @@ -61,11 +59,11 @@ exports.syncMapFirst = function (lst, fn) { return []; }; -exports.mapFirst = function (lst, fn, cb, predicate) { +exports.mapFirst = (lst, fn, cb, predicate) => { if (predicate == null) predicate = (x) => (x != null && x.length > 0); let i = 0; - var next = function () { + const next = () => { if (i >= lst.length) return cb(null, []); fn(lst[i++], (err, result) => { if (err) return cb(err); @@ -104,7 +102,7 @@ exports.mapFirst = function (lst, fn, cb, predicate) { // // See the tests in tests/backend/specs/hooks.js for examples of supported and prohibited behaviors. // -function callHookFnSync(hook, context) { +const callHookFnSync = (hook, context) => { checkDeprecation(hook); // This var is used to keep track of whether the hook function already settled. @@ -190,7 +188,7 @@ function callHookFnSync(hook, context) { settle(null, val, 'returned value'); return outcome.val; -} +}; // Invokes all registered hook functions synchronously. // @@ -203,7 +201,7 @@ function callHookFnSync(hook, context) { // 1. Collect all values returned by the hook functions into an array. // 2. Convert each `undefined` entry into `[]`. // 3. Flatten one level. -exports.callAll = function (hookName, context) { +exports.callAll = (hookName, context) => { if (context == null) context = {}; const hooks = pluginDefs.hooks[hookName] || []; return _.flatten(hooks.map((hook) => { @@ -248,7 +246,7 @@ exports.callAll = function (hookName, context) { // // See the tests in tests/backend/specs/hooks.js for examples of supported and prohibited behaviors. // -async function callHookFnAsync(hook, context) { +const callHookFnAsync = async (hook, context) => { checkDeprecation(hook); return await new Promise((resolve, reject) => { // This var is used to keep track of whether the hook function already settled. @@ -326,7 +324,7 @@ async function callHookFnAsync(hook, context) { (val) => settle(null, val, 'returned value'), (err) => settle(err, null, 'Promise rejection')); }); -} +}; // Invokes all registered hook functions asynchronously. // @@ -350,20 +348,22 @@ exports.aCallAll = async (hookName, context, cb) => { const hooks = pluginDefs.hooks[hookName] || []; let resultsPromise = Promise.all(hooks.map((hook) => callHookFnAsync(hook, context) // `undefined` (but not `null`!) is treated the same as []. - .then((result) => (result === undefined) ? [] : result))).then((results) => _.flatten(results, 1)); + .then((result) => (result === undefined) ? [] : result))) + .then((results) => _.flatten(results, 1)); if (cb != null) resultsPromise = resultsPromise.then((val) => cb(null, val), cb); return await resultsPromise; }; -exports.callFirst = function (hook_name, args) { +exports.callFirst = (hook_name, args) => { if (!args) args = {}; if (pluginDefs.hooks[hook_name] === undefined) return []; - return exports.syncMapFirst(pluginDefs.hooks[hook_name], (hook) => hookCallWrapper(hook, hook_name, args)); + return exports.syncMapFirst(pluginDefs.hooks[hook_name], + (hook) => hookCallWrapper(hook, hook_name, args)); }; -function aCallFirst(hook_name, args, cb, predicate) { +const aCallFirst = (hook_name, args, cb, predicate) => { if (!args) args = {}; - if (!cb) cb = function () {}; + if (!cb) cb = () => {}; if (pluginDefs.hooks[hook_name] === undefined) return cb(null, []); exports.mapFirst( pluginDefs.hooks[hook_name], @@ -373,10 +373,10 @@ function aCallFirst(hook_name, args, cb, predicate) { cb, predicate ); -} +}; /* return a Promise if cb is not supplied */ -exports.aCallFirst = function (hook_name, args, cb, predicate) { +exports.aCallFirst = (hook_name, args, cb, predicate) => { if (cb === undefined) { return new Promise((resolve, reject) => { aCallFirst(hook_name, args, (err, res) => err ? reject(err) : resolve(res), predicate); @@ -386,10 +386,10 @@ exports.aCallFirst = function (hook_name, args, cb, predicate) { } }; -exports.callAllStr = function (hook_name, args, sep, pre, post) { - if (sep == undefined) sep = ''; - if (pre == undefined) pre = ''; - if (post == undefined) post = ''; +exports.callAllStr = (hook_name, args, sep, pre, post) => { + if (sep === undefined) sep = ''; + if (pre === undefined) pre = ''; + if (post === undefined) post = ''; const newCallhooks = []; const callhooks = exports.callAll(hook_name, args); for (let i = 0, ii = callhooks.length; i < ii; i++) { diff --git a/src/static/js/pluginfw/installer.js b/src/static/js/pluginfw/installer.js index 7d29b91b1..ae5c06e10 100644 --- a/src/static/js/pluginfw/installer.js +++ b/src/static/js/pluginfw/installer.js @@ -1,6 +1,8 @@ +'use strict'; + const log4js = require('log4js'); -const plugins = require('ep_etherpad-lite/static/js/pluginfw/plugins'); -const hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks'); +const plugins = require('./plugins'); +const hooks = require('./hooks'); const npm = require('npm'); const request = require('request'); const util = require('util'); @@ -13,22 +15,22 @@ const loadNpm = async () => { npm.on('log', log4js.getLogger('npm').log); }; +const onAllTasksFinished = () => { + hooks.aCallAll('restartServer', {}, () => {}); +}; + let tasks = 0; function wrapTaskCb(cb) { tasks++; - return function () { - cb && cb.apply(this, arguments); + return function (...args) { + cb && cb.apply(this, args); tasks--; - if (tasks == 0) onAllTasksFinished(); + if (tasks === 0) onAllTasksFinished(); }; } -function onAllTasksFinished() { - hooks.aCallAll('restartServer', {}, () => {}); -} - exports.uninstall = async (pluginName, cb = null) => { cb = wrapTaskCb(cb); try { @@ -60,7 +62,7 @@ exports.install = async (pluginName, cb = null) => { exports.availablePlugins = null; let cacheTimestamp = 0; -exports.getAvailablePlugins = function (maxCacheAge) { +exports.getAvailablePlugins = (maxCacheAge) => { const nowTimestamp = Math.round(Date.now() / 1000); return new Promise((resolve, reject) => { @@ -87,31 +89,33 @@ exports.getAvailablePlugins = function (maxCacheAge) { }; -exports.search = function (searchTerm, maxCacheAge) { - return exports.getAvailablePlugins(maxCacheAge).then((results) => { - const res = {}; +exports.search = (searchTerm, maxCacheAge) => exports.getAvailablePlugins(maxCacheAge).then( + (results) => { + const res = {}; - if (searchTerm) { - searchTerm = searchTerm.toLowerCase(); - } - - for (const pluginName in results) { - // for every available plugin - if (pluginName.indexOf(plugins.prefix) != 0) continue; // TODO: Also search in keywords here! - - if (searchTerm && !~results[pluginName].name.toLowerCase().indexOf(searchTerm) && - (typeof results[pluginName].description !== 'undefined' && !~results[pluginName].description.toLowerCase().indexOf(searchTerm)) - ) { - if (typeof results[pluginName].description === 'undefined') { - console.debug('plugin without Description: %s', results[pluginName].name); - } - - continue; + if (searchTerm) { + searchTerm = searchTerm.toLowerCase(); } - res[pluginName] = results[pluginName]; - } + for (const pluginName in results) { + // for every available plugin + // TODO: Also search in keywords here! + if (pluginName.indexOf(plugins.prefix) !== 0) continue; - return res; - }); -}; + if (searchTerm && !~results[pluginName].name.toLowerCase().indexOf(searchTerm) && + (typeof results[pluginName].description !== 'undefined' && + !~results[pluginName].description.toLowerCase().indexOf(searchTerm)) + ) { + if (typeof results[pluginName].description === 'undefined') { + console.debug('plugin without Description: %s', results[pluginName].name); + } + + continue; + } + + res[pluginName] = results[pluginName]; + } + + return res; + } +); diff --git a/src/static/js/pluginfw/plugin_defs.js b/src/static/js/pluginfw/plugin_defs.js index 95bbcb95c..768d99c3e 100644 --- a/src/static/js/pluginfw/plugin_defs.js +++ b/src/static/js/pluginfw/plugin_defs.js @@ -1,3 +1,5 @@ +'use strict'; + // This module contains processed plugin definitions. The data structures in this file are set by // plugins.js (server) or client_plugins.js (client). diff --git a/src/static/js/pluginfw/plugins.js b/src/static/js/pluginfw/plugins.js index 52fbdd271..4acdee7bd 100644 --- a/src/static/js/pluginfw/plugins.js +++ b/src/static/js/pluginfw/plugins.js @@ -1,6 +1,7 @@ +'use strict'; + const fs = require('fs').promises; const hooks = require('./hooks'); -const npm = require('npm/lib/npm.js'); const readInstalled = require('./read-installed.js'); const path = require('path'); const tsort = require('./tsort'); @@ -13,11 +14,9 @@ const defs = require('./plugin_defs'); exports.prefix = 'ep_'; -exports.formatPlugins = function () { - return _.keys(defs.plugins).join(', '); -}; +exports.formatPlugins = () => Object.keys(defs.plugins).join(', '); -exports.formatPluginsWithVersion = function () { +exports.formatPluginsWithVersion = () => { const plugins = []; _.forEach(defs.plugins, (plugin) => { if (plugin.package.name !== 'ep_etherpad-lite') { @@ -28,17 +27,16 @@ exports.formatPluginsWithVersion = function () { return plugins.join(', '); }; -exports.formatParts = function () { - return _.map(defs.parts, (part) => part.full_name).join('\n'); -}; +exports.formatParts = () => _.map(defs.parts, (part) => part.full_name).join('\n'); -exports.formatHooks = function (hook_set_name) { +exports.formatHooks = (hook_set_name) => { const res = []; const hooks = pluginUtils.extractHooks(defs.parts, hook_set_name || 'hooks'); _.chain(hooks).keys().forEach((hook_name) => { _.forEach(hooks[hook_name], (hook) => { - res.push(`
        ${hook.hook_name}
        ${hook.hook_fn_name} from ${hook.part.full_name}
        `); + res.push(`
        ${hook.hook_name}
        ${hook.hook_fn_name} ` + + `from ${hook.part.full_name}
        `); }); }); return `
        ${res.join('\n')}
        `; @@ -57,7 +55,7 @@ const callInit = async () => { })); }; -exports.pathNormalization = function (part, hook_fn_name, hook_name) { +exports.pathNormalization = (part, hook_fn_name, hook_name) => { const tmp = hook_fn_name.split(':'); // hook_fn_name might be something like 'C:\\foo.js:myFunc'. // If there is a single colon assume it's 'filename:funcname' not 'C:\\filename'. const functionName = (tmp.length > 1 ? tmp.pop() : null) || hook_name; @@ -67,7 +65,7 @@ exports.pathNormalization = function (part, hook_fn_name, hook_name) { return `${fileName}:${functionName}`; }; -exports.update = async function () { +exports.update = async () => { const packages = await exports.getPackages(); const parts = {}; // Key is full name. sortParts converts this into a topologically sorted array. const plugins = {}; @@ -83,13 +81,14 @@ exports.update = async function () { await callInit(); }; -exports.getPackages = async function () { - // Load list of installed NPM packages, flatten it to a list, and filter out only packages with names that +exports.getPackages = async () => { + // Load list of installed NPM packages, flatten it to a list, + // and filter out only packages with names that const dir = settings.root; const data = await util.promisify(readInstalled)(dir); const packages = {}; - function flatten(deps) { + const flatten = (deps) => { _.chain(deps).keys().each((name) => { if (name.indexOf(exports.prefix) === 0) { packages[name] = _.clone(deps[name]); @@ -102,7 +101,7 @@ exports.getPackages = async function () { // I don't think we need recursion // if (deps[name].dependencies !== undefined) flatten(deps[name].dependencies); }); - } + }; const tmp = {}; tmp[data.name] = data; @@ -110,7 +109,7 @@ exports.getPackages = async function () { return packages; }; -async function loadPlugin(packages, plugin_name, plugins, parts) { +const loadPlugin = async (packages, plugin_name, plugins, parts) => { const plugin_path = path.resolve(packages[plugin_name].path, 'ep.json'); try { const data = await fs.readFile(plugin_path); @@ -129,9 +128,9 @@ async function loadPlugin(packages, plugin_name, plugins, parts) { } catch (er) { console.error(`Unable to load plugin definition file ${plugin_path}`); } -} +}; -function partsToParentChildList(parts) { +const partsToParentChildList = (parts) => { const res = []; _.chain(parts).keys().forEach((name) => { _.each(parts[name].post || [], (child_name) => { @@ -145,15 +144,9 @@ function partsToParentChildList(parts) { } }); return res; -} +}; // Used only in Node, so no need for _ -function sortParts(parts) { - return tsort( - partsToParentChildList(parts) - ).filter( - (name) => parts[name] !== undefined - ).map( - (name) => parts[name] - ); -} +const sortParts = (parts) => tsort(partsToParentChildList(parts)) + .filter((name) => parts[name] !== undefined) + .map((name) => parts[name]); diff --git a/src/static/js/pluginfw/shared.js b/src/static/js/pluginfw/shared.js index 749706812..981cd2558 100644 --- a/src/static/js/pluginfw/shared.js +++ b/src/static/js/pluginfw/shared.js @@ -1,3 +1,4 @@ +'use strict'; const _ = require('underscore'); const defs = require('./plugin_defs'); @@ -8,13 +9,13 @@ const disabledHookReasons = { }, }; -function loadFn(path, hookName) { +const loadFn = (path, hookName) => { let functionName; const parts = path.split(':'); // on windows: C:\foo\bar:xyz - if (parts[0].length == 1) { - if (parts.length == 3) { + if (parts[0].length === 1) { + if (parts.length === 3) { functionName = parts.pop(); } path = parts.join(':'); @@ -30,9 +31,9 @@ function loadFn(path, hookName) { fn = fn[name]; }); return fn; -} +}; -function extractHooks(parts, hook_set_name, normalizer) { +const extractHooks = (parts, hook_set_name, normalizer) => { const hooks = {}; _.each(parts, (part) => { _.chain(part[hook_set_name] || {}) @@ -50,20 +51,23 @@ function extractHooks(parts, hook_set_name, normalizer) { const disabledReason = (disabledHookReasons[hook_set_name] || {})[hook_name]; if (disabledReason) { - console.error(`Hook ${hook_set_name}/${hook_name} is disabled. Reason: ${disabledReason}`); + console.error( + `Hook ${hook_set_name}/${hook_name} is disabled. Reason: ${disabledReason}`); console.error(`The hook function ${hook_fn_name} from plugin ${part.plugin} ` + - 'will never be called, which may cause the plugin to fail'); - console.error(`Please update the ${part.plugin} plugin to not use the ${hook_name} hook`); + 'will never be called, which may cause the plugin to fail'); + console.error( + `Please update the ${part.plugin} plugin to not use the ${hook_name} hook`); return; } - + let hook_fn; try { - var hook_fn = loadFn(hook_fn_name, hook_name); + hook_fn = loadFn(hook_fn_name, hook_name); if (!hook_fn) { - throw 'Not a function'; + throw new Error('Not a function'); } } catch (exc) { - console.error(`Failed to load '${hook_fn_name}' for '${part.full_name}/${hook_set_name}/${hook_name}': ${exc.toString()}`); + console.error(`Failed to load '${hook_fn_name}' for ` + + `'${part.full_name}/${hook_set_name}/${hook_name}': ${exc.toString()}`); } if (hook_fn) { if (hooks[hook_name] == null) hooks[hook_name] = []; @@ -72,7 +76,7 @@ function extractHooks(parts, hook_set_name, normalizer) { }); }); return hooks; -} +}; exports.extractHooks = extractHooks; @@ -88,10 +92,10 @@ exports.extractHooks = extractHooks; * No plugins: [] * Some plugins: [ 'ep_adminpads', 'ep_add_buttons', 'ep_activepads' ] */ -exports.clientPluginNames = function () { +exports.clientPluginNames = () => { const client_plugin_names = _.uniq( defs.parts - .filter((part) => part.hasOwnProperty('client_hooks')) + .filter((part) => Object.prototype.hasOwnProperty.call(part, 'client_hooks')) .map((part) => `plugin-${part.plugin}`) ); From 5b701b97c3969486affef8b4a4e6ab9bc096c79b Mon Sep 17 00:00:00 2001 From: "translatewiki.net" Date: Mon, 1 Feb 2021 15:21:50 +0100 Subject: [PATCH 127/153] Localisation updates from https://translatewiki.net. --- src/locales/gl.json | 69 +++++++++++++++++++++++++++++++++++++-------- src/locales/pt.json | 44 ++++++++++++++++++++++++++--- 2 files changed, 97 insertions(+), 16 deletions(-) diff --git a/src/locales/gl.json b/src/locales/gl.json index 406c99521..02a04f563 100644 --- a/src/locales/gl.json +++ b/src/locales/gl.json @@ -2,12 +2,47 @@ "@metadata": { "authors": [ "Elisardojm", + "Ghose", "Toliño" ] }, + "admin.page-title": "Panel de administración - Etherpad", + "admin_plugins": "Xestor de complementos", + "admin_plugins.available": "Complementos dispoñibles", + "admin_plugins.available_not-found": "Non se atopan complementos.", + "admin_plugins.available_fetching": "Obtendo...", + "admin_plugins.available_install.value": "Instalar", + "admin_plugins.available_search.placeholder": "Buscar complementos para instalar", + "admin_plugins.description": "Descrición", + "admin_plugins.installed": "Complementos instalados", + "admin_plugins.installed_fetching": "Obtendo os complementos instalados...", + "admin_plugins.installed_nothing": "Aínda non instalaches ningún complemento.", + "admin_plugins.installed_uninstall.value": "Desinstalar", + "admin_plugins.last-update": "Última actualización", + "admin_plugins.name": "Nome", + "admin_plugins.page-title": "Xestos de complementos - Etherpad", + "admin_plugins.version": "Versión", + "admin_plugins_info": "Información para resolver problemas", + "admin_plugins_info.hooks": "Ganchos instalados", + "admin_plugins_info.hooks_client": "Ganchos do lado do cliente", + "admin_plugins_info.hooks_server": "Ganchos do lado do servidor", + "admin_plugins_info.parts": "Partes instaladas", + "admin_plugins_info.plugins": "Complementos instalados", + "admin_plugins_info.page-title": "Información do complemento - Etherpad", + "admin_plugins_info.version": "Versión de Etherpad", + "admin_plugins_info.version_latest": "Última versión dispoñible", + "admin_plugins_info.version_number": "Número da versión", + "admin_settings": "Axustes", + "admin_settings.current": "Configuración actual", + "admin_settings.current_example-devel": "Modelo de exemplo dos axustes de desenvolvemento", + "admin_settings.current_example-prod": "Modelo de exemplo dos axustes en produción", + "admin_settings.current_restart.value": "Reiniciar Etherpad", + "admin_settings.current_save.value": "Gardar axustes", + "admin_settings.page-title": "Axustes - Etherpad", "index.newPad": "Novo documento", - "index.createOpenPad": "ou cree/abra un documento co nome:", - "pad.toolbar.bold.title": "Negra (Ctrl-B)", + "index.createOpenPad": "ou crea/abre un documento co nome:", + "index.openPad": "abrir un Pad existente co nome:", + "pad.toolbar.bold.title": "Resaltado (Ctrl-B)", "pad.toolbar.italic.title": "Cursiva (Ctrl-I)", "pad.toolbar.underline.title": "Subliñar (Ctrl-U)", "pad.toolbar.strikethrough.title": "Riscar (Ctrl+5)", @@ -17,28 +52,30 @@ "pad.toolbar.unindent.title": "Sen sangría (Maiús.+TAB)", "pad.toolbar.undo.title": "Desfacer (Ctrl-Z)", "pad.toolbar.redo.title": "Refacer (Ctrl-Y)", - "pad.toolbar.clearAuthorship.title": "Limpar as cores de identificación dos autores (Ctrl+Shift+C)", + "pad.toolbar.clearAuthorship.title": "Eliminar as cores que identifican ás autoras (Ctrl+Shift+C)", "pad.toolbar.import_export.title": "Importar/Exportar desde/a diferentes formatos de ficheiro", "pad.toolbar.timeslider.title": "Liña do tempo", "pad.toolbar.savedRevision.title": "Gardar a revisión", - "pad.toolbar.settings.title": "Configuracións", + "pad.toolbar.settings.title": "Axustes", "pad.toolbar.embed.title": "Compartir e incorporar este documento", - "pad.toolbar.showusers.title": "Mostrar os usuarios deste documento", + "pad.toolbar.showusers.title": "Mostrar as usuarias deste documento", "pad.colorpicker.save": "Gardar", "pad.colorpicker.cancel": "Cancelar", "pad.loading": "Cargando...", - "pad.noCookie": "Non se puido atopar a cookie. Por favor, habilite as cookies no seu navegador!", - "pad.permissionDenied": "Non ten permiso para acceder a este documento", + "pad.noCookie": "Non se puido atopar a cookie. Por favor, habilita as cookies no teu navegador! A túa sesión e axustes non se gardarán entre visitas. Esto podería deberse a que Etherpad está incluído nalgún iFrame nalgúns navegadores. Asegúrate de que Etherpad está no mesmo subdominio/dominio que o iFrame pai", + "pad.permissionDenied": "Non tes permiso para acceder a este documento", "pad.settings.padSettings": "Configuracións do documento", "pad.settings.myView": "A miña vista", "pad.settings.stickychat": "Chat sempre visible", "pad.settings.chatandusers": "Mostrar o chat e os usuarios", "pad.settings.colorcheck": "Cores de identificación", "pad.settings.linenocheck": "Números de liña", - "pad.settings.rtlcheck": "Quere ler o contido da dereita á esquerda?", + "pad.settings.rtlcheck": "Queres ler o contido da dereita á esquerda?", "pad.settings.fontType": "Tipo de letra:", "pad.settings.fontType.normal": "Normal", "pad.settings.language": "Lingua:", + "pad.settings.about": "Acerca de", + "pad.settings.poweredBy": "Grazas a", "pad.importExport.import_export": "Importar/Exportar", "pad.importExport.import": "Cargar un ficheiro de texto ou documento", "pad.importExport.importSuccessful": "Correcto!", @@ -49,9 +86,9 @@ "pad.importExport.exportword": "Microsoft Word", "pad.importExport.exportpdf": "PDF", "pad.importExport.exportopen": "ODF (Open Document Format)", - "pad.importExport.abiword.innerHTML": "Só pode importar texto simple ou formatos HTML. Para obter máis información sobre as características de importación avanzadas instale AbiWord.", + "pad.importExport.abiword.innerHTML": "Só podes importar texto simple ou formatos HTML. Para obter máis información sobre as características de importación avanzadas instala AbiWord.", "pad.modals.connected": "Conectado.", - "pad.modals.reconnecting": "Reconectando co seu documento...", + "pad.modals.reconnecting": "Reconectando co teu documento...", "pad.modals.forcereconnect": "Forzar a reconexión", "pad.modals.reconnecttimer": "Intentarase reconectar en", "pad.modals.cancel": "Cancelar", @@ -73,6 +110,10 @@ "pad.modals.corruptPad.cause": "Isto pode deberse a unha cofiguración errónea do servidor ou algún outro comportamento inesperado. Póñase en contacto co administrador do servizo.", "pad.modals.deleted": "Borrado.", "pad.modals.deleted.explanation": "Este documento foi eliminado.", + "pad.modals.rateLimited": "Taxa limitada.", + "pad.modals.rateLimited.explanation": "Enviaches demasiadas mensaxes a este documento polo que te desconectamos.", + "pad.modals.rejected.explanation": "O servidor rexeitou unha mensaxe que o teu navegador enviou.", + "pad.modals.rejected.cause": "O servidor podería ter sido actualizado mentras ollabas o documento, ou pode que sexa un fallo de Etherpad. Intenta recargar a páxina.", "pad.modals.disconnected": "Foi desconectado.", "pad.modals.disconnected.explanation": "Perdeuse a conexión co servidor", "pad.modals.disconnected.cause": "O servidor non está dispoñible. Póñase en contacto co administrador do servizo se o problema continúa.", @@ -83,6 +124,9 @@ "pad.chat": "Chat", "pad.chat.title": "Abrir o chat deste documento.", "pad.chat.loadmessages": "Cargar máis mensaxes", + "pad.chat.stick.title": "Pegar a conversa á pantalla", + "pad.chat.writeMessage.placeholder": "Escribe aquí a túa mensaxe", + "timeslider.followContents": "Segue as actualizacións do contido", "timeslider.pageTitle": "Liña do tempo de {{appTitle}}", "timeslider.toolbar.returnbutton": "Volver ao documento", "timeslider.toolbar.authors": "Autores:", @@ -112,7 +156,7 @@ "pad.savedrevs.timeslider": "Pode consultar as revisións gardadas visitando a liña do tempo", "pad.userlist.entername": "Insira o seu nome", "pad.userlist.unnamed": "anónimo", - "pad.editbar.clearcolors": "Quere limpar as cores de identificación dos autores en todo o documento?", + "pad.editbar.clearcolors": "Eliminar as cores relativas aos autores en todo o documento? Non se poderán recuperar", "pad.impexp.importbutton": "Importar agora", "pad.impexp.importing": "Importando...", "pad.impexp.confirmimport": "A importación dun ficheiro ha sobrescribir o texto actual do documento. Está seguro de querer continuar?", @@ -121,5 +165,6 @@ "pad.impexp.uploadFailed": "Houbo un erro ao cargar o ficheiro; inténteo de novo", "pad.impexp.importfailed": "Fallou a importación", "pad.impexp.copypaste": "Copie e pegue", - "pad.impexp.exportdisabled": "A exportación en formato {{type}} está desactivada. Póñase en contacto co administrador do sistema se quere máis detalles." + "pad.impexp.exportdisabled": "A exportación en formato {{type}} está desactivada. Póñase en contacto co administrador do sistema se quere máis detalles.", + "pad.impexp.maxFileSize": "Ficheiro demasiado granda. Contacta coa administración para aumentar o tamaño permitido para importacións" } diff --git a/src/locales/pt.json b/src/locales/pt.json index d9faa3ba0..82972333e 100644 --- a/src/locales/pt.json +++ b/src/locales/pt.json @@ -4,6 +4,7 @@ "Athena in Wonderland", "Cainamarques", "GoEThe", + "Guilha", "Hamilton Abreu", "Imperadeiro98", "Luckas", @@ -16,9 +17,42 @@ "Waldyrious" ] }, + "admin.page-title": "Painel do administrador - Etherpad", + "admin_plugins": "Gestor de plugins", + "admin_plugins.available": "Plugins disponíveis", + "admin_plugins.available_not-found": "Não foram encontrados plugins.", + "admin_plugins.available_fetching": "A obter...", + "admin_plugins.available_install.value": "Instalar", + "admin_plugins.available_search.placeholder": "Procura plugins para instalar", + "admin_plugins.description": "Descrição", + "admin_plugins.installed": "Plugins instalados", + "admin_plugins.installed_fetching": "A obter plugins instalados...", + "admin_plugins.installed_nothing": "Não instalas-te nenhum plugin ainda.", + "admin_plugins.installed_uninstall.value": "Desinstalar", + "admin_plugins.last-update": "Ultima atualização", + "admin_plugins.name": "Nome", + "admin_plugins.page-title": "Gestor de plugins - Etherpad", + "admin_plugins.version": "Versão", + "admin_plugins_info": "Informação de resolução de problemas", + "admin_plugins_info.hooks": "Hooks instalados", + "admin_plugins_info.hooks_client": "Hooks do lado-do-cliente", + "admin_plugins_info.hooks_server": "Hooks do lado-do-servidor", + "admin_plugins_info.parts": "Partes instaladas", + "admin_plugins_info.plugins": "Plugins instalados", + "admin_plugins_info.page-title": "Informação do plugin - Etherpad", + "admin_plugins_info.version": "Versão do Etherpad", + "admin_plugins_info.version_latest": "Última versão disponível", + "admin_plugins_info.version_number": "Número de versão", + "admin_settings": "Definições", + "admin_settings.current": "Configuração atual", + "admin_settings.current_example-devel": "Exemplo do modo de Desenvolvedor", + "admin_settings.current_example-prod": "Exemplo do modo de Produção", + "admin_settings.current_restart.value": "Reiniciar Etherpad", + "admin_settings.current_save.value": "Guardar Definições", + "admin_settings.page-title": "Definições - Etherpad", "index.newPad": "Nova Nota", - "index.createOpenPad": "ou crie/abra uma nota com o nome:", - "index.openPad": "abrir uma «Nota» existente com o nome:", + "index.createOpenPad": "ou cria/abre uma nota com o nome:", + "index.openPad": "abrir uma Nota existente com o nome:", "pad.toolbar.bold.title": "Negrito (Ctrl+B)", "pad.toolbar.italic.title": "Itálico (Ctrl+I)", "pad.toolbar.underline.title": "Sublinhado (Ctrl+U)", @@ -26,7 +60,7 @@ "pad.toolbar.ol.title": "Lista ordenada (Ctrl+Shift+N)", "pad.toolbar.ul.title": "Lista desordenada (Ctrl+Shift+L)", "pad.toolbar.indent.title": "Indentar (TAB)", - "pad.toolbar.unindent.title": "Remover indentação (Shift+TAB)", + "pad.toolbar.unindent.title": "Indentação (Shift+TAB)", "pad.toolbar.undo.title": "Desfazer (Ctrl+Z)", "pad.toolbar.redo.title": "Refazer (Ctrl+Y)", "pad.toolbar.clearAuthorship.title": "Limpar cores de autoria (Ctrl+Shift+C)", @@ -65,7 +99,7 @@ "pad.importExport.exportopen": "ODF (Open Document Format)", "pad.importExport.abiword.innerHTML": "Só pode fazer importações de texto não formatado ou com formato HTML. Para funcionalidades de importação de texto mais avançadas, instale AbiWord ou LibreOffice, por favor.", "pad.modals.connected": "Ligado.", - "pad.modals.reconnecting": "A restabelecer ligação ao seu bloco…", + "pad.modals.reconnecting": "A restabelecer ligação à nota…", "pad.modals.forcereconnect": "Forçar restabelecimento de ligação", "pad.modals.reconnecttimer": "A tentar restabelecer ligação", "pad.modals.cancel": "Cancelar", @@ -89,6 +123,8 @@ "pad.modals.deleted.explanation": "Esta nota foi removida.", "pad.modals.rateLimited": "Limitado.", "pad.modals.rateLimited.explanation": "Enviou demasiadas mensagens para este pad, por isso foi desligado.", + "pad.modals.rejected.explanation": "O servidor rejeitou a mensagem que foi enviada pelo teu navegador.", + "pad.modals.rejected.cause": "O server foi atualizado enquanto estávas a ver esta nota, ou talvez seja apenas um bug do Etherpad. Tenta recarregar a página.", "pad.modals.disconnected": "Você foi desligado.", "pad.modals.disconnected.explanation": "A ligação ao servidor foi perdida", "pad.modals.disconnected.cause": "O servidor pode estar indisponível. Por favor, notifique o administrador de serviço se isto continuar a acontecer.", From 9987fab574d0e5b1291e5a3e88351b2ec35a4325 Mon Sep 17 00:00:00 2001 From: John McLear Date: Mon, 1 Feb 2021 09:47:42 +0000 Subject: [PATCH 128/153] lint: low hanging bin/doc/*.js --- bin/doc/generate.js | 28 +++++++++++---------- bin/doc/html.js | 42 +++++++++++++++---------------- bin/doc/json.js | 59 ++++++++++++++++++++++---------------------- bin/doc/package.json | 2 +- 4 files changed, 67 insertions(+), 64 deletions(-) diff --git a/bin/doc/generate.js b/bin/doc/generate.js index 803f5017e..d04468a8b 100644 --- a/bin/doc/generate.js +++ b/bin/doc/generate.js @@ -1,4 +1,7 @@ #!/usr/bin/env node + +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -20,7 +23,6 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. -const marked = require('marked'); const fs = require('fs'); const path = require('path'); @@ -33,12 +35,12 @@ let template = null; let inputFile = null; args.forEach((arg) => { - if (!arg.match(/^\-\-/)) { + if (!arg.match(/^--/)) { inputFile = arg; - } else if (arg.match(/^\-\-format=/)) { - format = arg.replace(/^\-\-format=/, ''); - } else if (arg.match(/^\-\-template=/)) { - template = arg.replace(/^\-\-template=/, ''); + } else if (arg.match(/^--format=/)) { + format = arg.replace(/^--format=/, ''); + } else if (arg.match(/^--template=/)) { + template = arg.replace(/^--template=/, ''); } }); @@ -56,11 +58,11 @@ fs.readFile(inputFile, 'utf8', (er, input) => { }); -const includeExpr = /^@include\s+([A-Za-z0-9-_\/]+)(?:\.)?([a-zA-Z]*)$/gmi; +const includeExpr = /^@include\s+([A-Za-z0-9-_/]+)(?:\.)?([a-zA-Z]*)$/gmi; const includeData = {}; -function processIncludes(inputFile, input, cb) { +const processIncludes = (inputFile, input, cb) => { const includes = input.match(includeExpr); - if (includes === null) return cb(null, input); + if (includes == null) return cb(null, input); let errState = null; console.error(includes); let incCount = includes.length; @@ -70,7 +72,7 @@ function processIncludes(inputFile, input, cb) { let fname = include.replace(/^@include\s+/, ''); if (!fname.match(/\.md$/)) fname += '.md'; - if (includeData.hasOwnProperty(fname)) { + if (Object.prototype.hasOwnProperty.call(includeData, fname)) { input = input.split(include).join(includeData[fname]); incCount--; if (incCount === 0) { @@ -94,10 +96,10 @@ function processIncludes(inputFile, input, cb) { }); }); }); -} +}; -function next(er, input) { +const next = (er, input) => { if (er) throw er; switch (format) { case 'json': @@ -117,4 +119,4 @@ function next(er, input) { default: throw new Error(`Invalid format: ${format}`); } -} +}; diff --git a/bin/doc/html.js b/bin/doc/html.js index 26cf3f185..2c38aec23 100644 --- a/bin/doc/html.js +++ b/bin/doc/html.js @@ -1,3 +1,5 @@ +'use strict'; + // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -23,17 +25,17 @@ const fs = require('fs'); const marked = require('marked'); const path = require('path'); -module.exports = toHTML; -function toHTML(input, filename, template, cb) { +const toHTML = (input, filename, template, cb) => { const lexed = marked.lexer(input); fs.readFile(template, 'utf8', (er, template) => { if (er) return cb(er); render(lexed, filename, template, cb); }); -} +}; +module.exports = toHTML; -function render(lexed, filename, template, cb) { +const render = (lexed, filename, template, cb) => { // get the section const section = getSection(lexed); @@ -52,23 +54,23 @@ function render(lexed, filename, template, cb) { // content has to be the last thing we do with // the lexed tokens, because it's destructive. - content = marked.parser(lexed); + const content = marked.parser(lexed); template = template.replace(/__CONTENT__/g, content); cb(null, template); }); -} +}; // just update the list item text in-place. // lists that come right after a heading are what we're after. -function parseLists(input) { +const parseLists = (input) => { let state = null; let depth = 0; const output = []; output.links = input.links; input.forEach((tok) => { - if (state === null) { + if (state == null) { if (tok.type === 'heading') { state = 'AFTERHEADING'; } @@ -112,29 +114,27 @@ function parseLists(input) { }); return output; -} +}; -function parseListItem(text) { - text = text.replace(/\{([^\}]+)\}/, '$1'); +const parseListItem = (text) => { + text = text.replace(/\{([^}]+)\}/, '$1'); // XXX maybe put more stuff here? return text; -} +}; // section is just the first heading -function getSection(lexed) { - const section = ''; +const getSection = (lexed) => { for (let i = 0, l = lexed.length; i < l; i++) { const tok = lexed[i]; if (tok.type === 'heading') return tok.text; } return ''; -} +}; -function buildToc(lexed, filename, cb) { - const indent = 0; +const buildToc = (lexed, filename, cb) => { let toc = []; let depth = 0; lexed.forEach((tok) => { @@ -155,18 +155,18 @@ function buildToc(lexed, filename, cb) { toc = marked.parse(toc.join('\n')); cb(null, toc); -} +}; const idCounters = {}; -function getId(text) { +const getId = (text) => { text = text.toLowerCase(); text = text.replace(/[^a-z0-9]+/g, '_'); text = text.replace(/^_+|_+$/, ''); text = text.replace(/^([^a-z])/, '_$1'); - if (idCounters.hasOwnProperty(text)) { + if (Object.prototype.hasOwnProperty.call(idCounters, text)) { text += `_${++idCounters[text]}`; } else { idCounters[text] = 0; } return text; -} +}; diff --git a/bin/doc/json.js b/bin/doc/json.js index 3ce62a301..c71611e5f 100644 --- a/bin/doc/json.js +++ b/bin/doc/json.js @@ -1,3 +1,4 @@ +'use strict'; // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -26,7 +27,7 @@ module.exports = doJSON; const marked = require('marked'); -function doJSON(input, filename, cb) { +const doJSON = (input, filename, cb) => { const root = {source: filename}; const stack = [root]; let depth = 0; @@ -40,7 +41,7 @@ function doJSON(input, filename, cb) { // // This is for cases where the markdown semantic structure is lacking. if (type === 'paragraph' || type === 'html') { - const metaExpr = /\n*/g; + const metaExpr = /\n*/g; text = text.replace(metaExpr, (_0, k, v) => { current[k.trim()] = v.trim(); return ''; @@ -146,7 +147,7 @@ function doJSON(input, filename, cb) { } return cb(null, root); -} +}; // go from something like this: @@ -191,7 +192,7 @@ function doJSON(input, filename, cb) { // desc: 'whether or not to send output to parent\'s stdio.', // default: 'false' } ] } ] -function processList(section) { +const processList = (section) => { const list = section.list; const values = []; let current; @@ -203,13 +204,13 @@ function processList(section) { if (type === 'space') return; if (type === 'list_item_start') { if (!current) { - var n = {}; + const n = {}; values.push(n); current = n; } else { current.options = current.options || []; stack.push(current); - var n = {}; + const n = {}; current.options.push(n); current = n; } @@ -283,11 +284,11 @@ function processList(section) { // section.listParsed = values; delete section.list; -} +}; // textRaw = "someobject.someMethod(a, [b=100], [c])" -function parseSignature(text, sig) { +const parseSignature = (text, sig) => { let params = text.match(paramExpr); if (!params) return; params = params[1]; @@ -322,10 +323,10 @@ function parseSignature(text, sig) { if (optional) param.optional = true; if (def !== undefined) param.default = def; }); -} +}; -function parseListItem(item) { +const parseListItem = (item) => { if (item.options) item.options.forEach(parseListItem); if (!item.textRaw) return; @@ -341,7 +342,7 @@ function parseListItem(item) { item.name = 'return'; text = text.replace(retExpr, ''); } else { - const nameExpr = /^['`"]?([^'`": \{]+)['`"]?\s*:?\s*/; + const nameExpr = /^['`"]?([^'`": {]+)['`"]?\s*:?\s*/; const name = text.match(nameExpr); if (name) { item.name = name[1]; @@ -358,7 +359,7 @@ function parseListItem(item) { } text = text.trim(); - const typeExpr = /^\{([^\}]+)\}/; + const typeExpr = /^\{([^}]+)\}/; const type = text.match(typeExpr); if (type) { item.type = type[1]; @@ -376,10 +377,10 @@ function parseListItem(item) { text = text.replace(/^\s*-\s*/, ''); text = text.trim(); if (text) item.desc = text; -} +}; -function finishSection(section, parent) { +const finishSection = (section, parent) => { if (!section || !parent) { throw new Error(`Invalid finishSection call\n${ JSON.stringify(section)}\n${ @@ -479,50 +480,50 @@ function finishSection(section, parent) { parent[plur] = parent[plur] || []; parent[plur].push(section); -} +}; // Not a general purpose deep copy. // But sufficient for these basic things. -function deepCopy(src, dest) { +const deepCopy = (src, dest) => { Object.keys(src).filter((k) => !dest.hasOwnProperty(k)).forEach((k) => { dest[k] = deepCopy_(src[k]); }); -} +}; -function deepCopy_(src) { +const deepCopy_ = (src) => { if (!src) return src; if (Array.isArray(src)) { - var c = new Array(src.length); + const c = new Array(src.length); src.forEach((v, i) => { c[i] = deepCopy_(v); }); return c; } if (typeof src === 'object') { - var c = {}; + const c = {}; Object.keys(src).forEach((k) => { c[k] = deepCopy_(src[k]); }); return c; } return src; -} +}; // these parse out the contents of an H# tag const eventExpr = /^Event(?::|\s)+['"]?([^"']+).*$/i; const classExpr = /^Class:\s*([^ ]+).*?$/i; -const propExpr = /^(?:property:?\s*)?[^\.]+\.([^ \.\(\)]+)\s*?$/i; -const braceExpr = /^(?:property:?\s*)?[^\.\[]+(\[[^\]]+\])\s*?$/i; +const propExpr = /^(?:property:?\s*)?[^.]+\.([^ .()]+)\s*?$/i; +const braceExpr = /^(?:property:?\s*)?[^.[]+(\[[^\]]+\])\s*?$/i; const classMethExpr = - /^class\s*method\s*:?[^\.]+\.([^ \.\(\)]+)\([^\)]*\)\s*?$/i; + /^class\s*method\s*:?[^.]+\.([^ .()]+)\([^)]*\)\s*?$/i; const methExpr = - /^(?:method:?\s*)?(?:[^\.]+\.)?([^ \.\(\)]+)\([^\)]*\)\s*?$/i; -const newExpr = /^new ([A-Z][a-z]+)\([^\)]*\)\s*?$/; -var paramExpr = /\((.*)\);?$/; + /^(?:method:?\s*)?(?:[^.]+\.)?([^ .()]+)\([^)]*\)\s*?$/i; +const newExpr = /^new ([A-Z][a-z]+)\([^)]*\)\s*?$/; +const paramExpr = /\((.*)\);?$/; -function newSection(tok) { +const newSection = (tok) => { const section = {}; // infer the type from the text. const text = section.textRaw = tok.text; @@ -551,4 +552,4 @@ function newSection(tok) { section.name = text; } return section; -} +}; diff --git a/bin/doc/package.json b/bin/doc/package.json index 1a29f1b1c..2f027616c 100644 --- a/bin/doc/package.json +++ b/bin/doc/package.json @@ -4,7 +4,7 @@ "description": "Internal tool for generating Node.js API docs", "version": "0.0.0", "engines": { - "node": ">=0.6.10" + "node": ">=10.17.0" }, "dependencies": { "marked": "0.8.2" From 759e2aaec39a8b6f6e15409e6a9750c49f55627c Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 1 Feb 2021 14:43:09 -0500 Subject: [PATCH 129/153] lint: Use node config for tests/frontend/travis, tests/ratelimit The files in these directories contain test drivers, not tests. --- package.json | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 03cb677ba..de9298807 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,9 @@ "tests/**/*" ], "excludedFiles": [ - "**/.eslintrc.js" + "**/.eslintrc.js", + "tests/frontend/travis/**/*", + "tests/ratelimit/**/*" ], "extends": "etherpad/tests", "rules": { @@ -75,7 +77,8 @@ "tests/frontend/**/*" ], "excludedFiles": [ - "**/.eslintrc.js" + "**/.eslintrc.js", + "tests/frontend/travis/**/*" ], "extends": "etherpad/tests/frontend", "overrides": [ @@ -92,6 +95,12 @@ } } ] + }, + { + "files": [ + "tests/frontend/travis/**/*" + ], + "extends": "etherpad/node" } ], "root": true From 915849b3197158427c1a755e2d60e38822dc16a9 Mon Sep 17 00:00:00 2001 From: John McLear Date: Mon, 1 Feb 2021 20:23:14 +0000 Subject: [PATCH 130/153] Low hanging lint frontend tests (#4695) * lint: low hanging specs/alphabet.js * lint: low hanging specs/authorship_of_editions.js * lint: low hanging specs/bold.js * lint: low hanging specs/caret.js * lint: low hanging specs/change_user_color.js * lint: low hanging specs/change_user_name.js * lint: low hanging specs/chat.js * lint: low hanging specs/chat_load_messages.js * lint: low hanging specs/clear_authorship_colors.js * lint: low hanging specs/delete.js * lint: low hanging specs/drag_and_drop.js * lint: low hanging specs/embed_value.js * lint: low hanging specs/enter.js * lint: low hanging specs/font_type.js * lint: low hanging specs/helper.js * lint: low hanging specs/importexport.js * lint: low hanging specs/importindents.js * lint: low hanging specs/indentation.js * lint: low hanging specs/italic.js * lint: low hanging specs/language.js * lint: low hanging specs/multiple_authors_clear_authorship_colors.js * lint: low hanging specs/ordered_list.js * lint: low hanging specs/pad_modal.js * lint: low hanging specs/redo.js * lint: low hanging specs/responsiveness.js * lint: low hanging specs/select_formatting_buttons.js * lint: low hanging specs/strikethrough.js * lint: low hanging specs/timeslider.js * lint: low hanging specs/timeslider_labels.js * lint: low hanging specs/timeslider_numeric_padID.js * lint: low hanging specs/timeslider_revisions.js * lint: low hanging specs/undo.js * lint: low hanging specs/unordered_list.js * lint: low hanging specs/xxauto_reconnect.js * lint: attempt to do remote_runner.js * lint: helper linting * lint: rate limit linting * use constructor for Event to make eslint happier * for squash: lint fix refinements * for squash: lint fix refinements Co-authored-by: Richard Hansen --- tests/frontend/helper.js | 4 +- tests/frontend/helper/methods.js | 8 +- tests/frontend/helper/ui.js | 2 + tests/frontend/specs/alphabet.js | 3 +- .../frontend/specs/authorship_of_editions.js | 26 +- tests/frontend/specs/bold.js | 7 +- tests/frontend/specs/caret.js | 67 +++-- tests/frontend/specs/change_user_color.js | 16 +- tests/frontend/specs/change_user_name.js | 2 + tests/frontend/specs/chat.js | 19 +- tests/frontend/specs/chat_load_messages.js | 18 +- .../frontend/specs/clear_authorship_colors.js | 35 +-- tests/frontend/specs/delete.js | 8 +- tests/frontend/specs/drag_and_drop.js | 29 +- tests/frontend/specs/embed_value.js | 2 + tests/frontend/specs/enter.js | 9 +- tests/frontend/specs/font_type.js | 3 +- tests/frontend/specs/helper.js | 28 +- tests/frontend/specs/importexport.js | 271 ++++++++++++------ tests/frontend/specs/importindents.js | 82 ++++-- tests/frontend/specs/indentation.js | 39 +-- tests/frontend/specs/italic.js | 9 +- tests/frontend/specs/language.js | 18 +- ...ultiple_authors_clear_authorship_colors.js | 9 +- tests/frontend/specs/ordered_list.js | 27 +- tests/frontend/specs/pad_modal.js | 12 +- tests/frontend/specs/redo.js | 7 +- tests/frontend/specs/responsiveness.js | 37 ++- .../specs/select_formatting_buttons.js | 9 +- tests/frontend/specs/strikethrough.js | 4 +- tests/frontend/specs/timeslider.js | 3 +- tests/frontend/specs/timeslider_labels.js | 4 +- .../specs/timeslider_numeric_padID.js | 2 + tests/frontend/specs/timeslider_revisions.js | 48 ++-- tests/frontend/specs/undo.js | 5 +- tests/frontend/specs/unordered_list.js | 5 +- tests/frontend/specs/xxauto_reconnect.js | 2 + tests/frontend/travis/remote_runner.js | 63 ++-- tests/ratelimit/send_changesets.js | 10 +- 39 files changed, 595 insertions(+), 357 deletions(-) diff --git a/tests/frontend/helper.js b/tests/frontend/helper.js index 37c5af3b1..c38175fe1 100644 --- a/tests/frontend/helper.js +++ b/tests/frontend/helper.js @@ -1,5 +1,5 @@ 'use strict'; -const helper = {}; // eslint-disable-line +const helper = {}; // eslint-disable-line no-redeclare (function () { let $iframe; const @@ -181,7 +181,7 @@ const helper = {}; // eslint-disable-line }; helper.waitFor = function (conditionFunc, timeoutTime = 1900, intervalTime = 10) { - const deferred = $.Deferred(); // eslint-disable-line + const deferred = new $.Deferred(); const _fail = deferred.fail.bind(deferred); let listenForFail = false; diff --git a/tests/frontend/helper/methods.js b/tests/frontend/helper/methods.js index 4c7fe1204..157ba6aba 100644 --- a/tests/frontend/helper/methods.js +++ b/tests/frontend/helper/methods.js @@ -6,12 +6,12 @@ */ helper.spyOnSocketIO = function () { helper.contentWindow().pad.socket.on('message', (msg) => { - if (msg.type == 'COLLABROOM') { - if (msg.data.type == 'ACCEPT_COMMIT') { + if (msg.type === 'COLLABROOM') { + if (msg.data.type === 'ACCEPT_COMMIT') { helper.commits.push(msg); - } else if (msg.data.type == 'USER_NEWINFO') { + } else if (msg.data.type === 'USER_NEWINFO') { helper.userInfos.push(msg); - } else if (msg.data.type == 'CHAT_MESSAGE') { + } else if (msg.data.type === 'CHAT_MESSAGE') { helper.chatMessages.push(msg); } } diff --git a/tests/frontend/helper/ui.js b/tests/frontend/helper/ui.js index 0f3e64169..7ab8b990d 100644 --- a/tests/frontend/helper/ui.js +++ b/tests/frontend/helper/ui.js @@ -1,3 +1,5 @@ +'use strict'; + /** * the contentWindow is either the normal pad or timeslider * diff --git a/tests/frontend/specs/alphabet.js b/tests/frontend/specs/alphabet.js index a0ad61bdf..cc50e7d87 100644 --- a/tests/frontend/specs/alphabet.js +++ b/tests/frontend/specs/alphabet.js @@ -1,3 +1,5 @@ +'use strict'; + describe('All the alphabet works n stuff', function () { const expectedString = 'abcdefghijklmnopqrstuvwxyz'; @@ -9,7 +11,6 @@ describe('All the alphabet works n stuff', function () { it('when you enter any char it appears right', function (done) { const inner$ = helper.padInner$; - const chrome$ = helper.padChrome$; // get the first text element out of the inner iframe const firstTextElement = inner$('div').first(); diff --git a/tests/frontend/specs/authorship_of_editions.js b/tests/frontend/specs/authorship_of_editions.js index 6cf14b869..f6f29d491 100644 --- a/tests/frontend/specs/authorship_of_editions.js +++ b/tests/frontend/specs/authorship_of_editions.js @@ -1,3 +1,5 @@ +'use strict'; + describe('author of pad edition', function () { const REGULAR_LINE = 0; const LINE_WITH_ORDERED_LIST = 1; @@ -5,10 +7,11 @@ describe('author of pad edition', function () { // author 1 creates a new pad with some content (regular lines and lists) before(function (done) { - var padId = helper.newPad(() => { + const padId = helper.newPad(() => { // make sure pad has at least 3 lines const $firstLine = helper.padInner$('div').first(); - const threeLines = ['regular line', 'line with ordered list', 'line with unordered list'].join('
        '); + const threeLines = ['regular line', 'line with ordered list', 'line with unordered list'] + .join('
        '); $firstLine.html(threeLines); // wait for lines to be processed by Etherpad @@ -43,7 +46,8 @@ describe('author of pad edition', function () { setTimeout(() => { // Expire cookie, so author is changed after reloading the pad. // See https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie#Example_4_Reset_the_previous_cookie - helper.padChrome$.document.cookie = 'token=foo;expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/'; + helper.padChrome$.document.cookie = + 'token=foo;expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/'; helper.newPad(done, padId); }, 1000); @@ -59,24 +63,22 @@ describe('author of pad edition', function () { changeLineAndCheckOnlyThatChangeIsFromThisAuthor(REGULAR_LINE, 'x', done); }); - it('marks only the new content as changes of the second user on a line with ordered list', function (done) { + it('marks only the new content as changes of the second user on a ' + + 'line with ordered list', function (done) { changeLineAndCheckOnlyThatChangeIsFromThisAuthor(LINE_WITH_ORDERED_LIST, 'y', done); }); - it('marks only the new content as changes of the second user on a line with unordered list', function (done) { + it('marks only the new content as changes of the second user on ' + + 'a line with unordered list', function (done) { changeLineAndCheckOnlyThatChangeIsFromThisAuthor(LINE_WITH_UNORDERED_LIST, 'z', done); }); /* ********************** Helper functions ************************ */ - var getLine = function (lineNumber) { - return helper.padInner$('div').eq(lineNumber); - }; + const getLine = (lineNumber) => helper.padInner$('div').eq(lineNumber); - const getAuthorFromClassList = function (classes) { - return classes.find((cls) => cls.startsWith('author')); - }; + const getAuthorFromClassList = (classes) => classes.find((cls) => cls.startsWith('author')); - var changeLineAndCheckOnlyThatChangeIsFromThisAuthor = function (lineNumber, textChange, done) { + const changeLineAndCheckOnlyThatChangeIsFromThisAuthor = (lineNumber, textChange, done) => { // get original author class const classes = getLine(lineNumber).find('span').first().attr('class').split(' '); const originalAuthor = getAuthorFromClassList(classes); diff --git a/tests/frontend/specs/bold.js b/tests/frontend/specs/bold.js index a7c46e1bc..613de4699 100644 --- a/tests/frontend/specs/bold.js +++ b/tests/frontend/specs/bold.js @@ -1,3 +1,5 @@ +'use strict'; + describe('bold button', function () { // create a new pad before each test run beforeEach(function (cb) { @@ -19,7 +21,6 @@ describe('bold button', function () { const $boldButton = chrome$('.buttonicon-bold'); $boldButton.click(); - // ace creates a new dom element when you press a button, so just get the first text element again const $newFirstTextElement = inner$('div').first(); // is there a element now? @@ -36,7 +37,6 @@ describe('bold button', function () { it('makes text bold on keypress', function (done) { const inner$ = helper.padInner$; - const chrome$ = helper.padChrome$; // get the first text element out of the inner iframe const $firstTextElement = inner$('div').first(); @@ -44,12 +44,11 @@ describe('bold button', function () { // select this text element $firstTextElement.sendkeys('{selectall}'); - const e = inner$.Event(helper.evtType); + const e = new inner$.Event(helper.evtType); e.ctrlKey = true; // Control key e.which = 66; // b inner$('#innerdocbody').trigger(e); - // ace creates a new dom element when you press a button, so just get the first text element again const $newFirstTextElement = inner$('div').first(); // is there a element now? diff --git a/tests/frontend/specs/caret.js b/tests/frontend/specs/caret.js index 1fb8d8aa7..e5ce255b8 100644 --- a/tests/frontend/specs/caret.js +++ b/tests/frontend/specs/caret.js @@ -1,7 +1,9 @@ +'use strict'; + describe('As the caret is moved is the UI properly updated?', function () { + /* let padName; const numberOfRows = 50; - /* //create a new pad before each test run beforeEach(function(cb){ @@ -16,7 +18,8 @@ describe('As the caret is moved is the UI properly updated?', function () { */ /* Tests to do - * Keystroke up (38), down (40), left (37), right (39) with and without special keys IE control / shift + * Keystroke up (38), down (40), left (37), right (39) + * with and without special keys IE control / shift * Page up (33) / down (34) with and without special keys * Page up on the first line shouldn't move the viewport * Down down on the last line shouldn't move the viewport @@ -25,7 +28,9 @@ describe('As the caret is moved is the UI properly updated?', function () { */ /* Challenges - * How do we keep the authors focus on a line if the lines above the author are modified? We should only redraw the user to a location if they are typing and make sure shift and arrow keys aren't redrawing the UI else highlight - copy/paste would get broken + * How do we keep the authors focus on a line if the lines above the author are modified? + * We should only redraw the user to a location if they are typing and make sure shift + * and arrow keys aren't redrawing the UI else highlight - copy/paste would get broken * How can we simulate an edit event in the test framework? */ /* @@ -200,7 +205,8 @@ console.log(inner$); var chrome$ = helper.padChrome$; var numberOfRows = 50; - //ace creates a new dom element when you press a keystroke, so just get the first text element again + // ace creates a new dom element when you press a keystroke, + // so just get the first text element again var $newFirstTextElement = inner$("div").first(); var originalDivHeight = inner$("div").first().css("height"); prepareDocument(numberOfRows, $newFirstTextElement); // N lines into the first div as a target @@ -208,28 +214,33 @@ console.log(inner$); helper.waitFor(function(){ // Wait for the DOM to register the new items return inner$("div").first().text().length == 6; }).done(function(){ // Once the DOM has registered the items - inner$("div").each(function(index){ // Randomize the item heights (replicates images / headings etc) + // Randomize the item heights (replicates images / headings etc) + inner$("div").each(function(index){ var random = Math.floor(Math.random() * (50)) + 20; $(this).css("height", random+"px"); }); console.log(caretPosition(inner$)); var newDivHeight = inner$("div").first().css("height"); - var heightHasChanged = originalDivHeight != newDivHeight; // has the new div height changed from the original div height + // has the new div height changed from the original div height + var heightHasChanged = originalDivHeight != newDivHeight; expect(heightHasChanged).to.be(true); // expect the first line to be blank }); // Is this Element now visible to the pad user? helper.waitFor(function(){ // Wait for the DOM to register the new items - return isScrolledIntoView(inner$("div:nth-child("+numberOfRows+")"), inner$); // Wait for the DOM to scroll into place + // Wait for the DOM to scroll into place + return isScrolledIntoView(inner$("div:nth-child("+numberOfRows+")"), inner$); }).done(function(){ // Once the DOM has registered the items - inner$("div").each(function(index){ // Randomize the item heights (replicates images / headings etc) + // Randomize the item heights (replicates images / headings etc) + inner$("div").each(function(index){ var random = Math.floor(Math.random() * (80 - 20 + 1)) + 20; $(this).css("height", random+"px"); }); var newDivHeight = inner$("div").first().css("height"); - var heightHasChanged = originalDivHeight != newDivHeight; // has the new div height changed from the original div height + // has the new div height changed from the original div height + var heightHasChanged = originalDivHeight != newDivHeight; expect(heightHasChanged).to.be(true); // expect the first line to be blank }); var i = 0; @@ -241,7 +252,8 @@ console.log(inner$); // Does scrolling back up the pad with the up arrow show the correct contents? helper.waitFor(function(){ // Wait for the new position to be in place try{ - return isScrolledIntoView(inner$("div:nth-child("+numberOfRows+")"), inner$); // Wait for the DOM to scroll into place + // Wait for the DOM to scroll into place + return isScrolledIntoView(inner$("div:nth-child("+numberOfRows+")"), inner$); }catch(e){ return false; } @@ -256,7 +268,8 @@ console.log(inner$); // Does scrolling back up the pad with the up arrow show the correct contents? helper.waitFor(function(){ // Wait for the new position to be in place try{ - return isScrolledIntoView(inner$("div:nth-child(0)"), inner$); // Wait for the DOM to scroll into place + // Wait for the DOM to scroll into place + return isScrolledIntoView(inner$("div:nth-child(0)"), inner$); }catch(e){ return false; } @@ -276,7 +289,8 @@ console.log(inner$); // Does scrolling back up the pad with the up arrow show the correct contents? helper.waitFor(function(){ // Wait for the new position to be in place - return isScrolledIntoView(inner$("div:nth-child(1)"), inner$); // Wait for the DOM to scroll into place + // Wait for the DOM to scroll into place + return isScrolledIntoView(inner$("div:nth-child(1)"), inner$); }).done(function(){ // Once the DOM has registered the items expect(true).to.be(true); done(); @@ -284,17 +298,19 @@ console.log(inner$); */ }); -function prepareDocument(n, target) { // generates a random document with random content on n lines +// generates a random document with random content on n lines +const prepareDocument = (n, target) => { let i = 0; while (i < n) { // for each line target.sendkeys(makeStr()); // generate a random string and send that to the editor target.sendkeys('{enter}'); // generator an enter keypress i++; // rinse n times } -} +}; -function keyEvent(target, charCode, ctrl, shift) { // sends a charCode to the window - const e = target.Event(helper.evtType); +// sends a charCode to the window +const keyEvent = (target, charCode, ctrl, shift) => { + const e = new target.Event(helper.evtType); if (ctrl) { e.ctrlKey = true; // Control key } @@ -304,30 +320,33 @@ function keyEvent(target, charCode, ctrl, shift) { // sends a charCode to the wi e.which = charCode; e.keyCode = charCode; target('#innerdocbody').trigger(e); -} +}; -function makeStr() { // from http://stackoverflow.com/questions/1349404/generate-a-string-of-5-random-characters-in-javascript +// from http://stackoverflow.com/questions/1349404/generate-a-string-of-5-random-characters-in-javascript +const makeStr = () => { let text = ''; const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; for (let i = 0; i < 5; i++) text += possible.charAt(Math.floor(Math.random() * possible.length)); return text; -} +}; -function isScrolledIntoView(elem, $) { // from http://stackoverflow.com/questions/487073/check-if-element-is-visible-after-scrolling +// from http://stackoverflow.com/questions/487073/check-if-element-is-visible-after-scrolling +const isScrolledIntoView = (elem, $) => { const docViewTop = $(window).scrollTop(); const docViewBottom = docViewTop + $(window).height(); const elemTop = $(elem).offset().top; // how far the element is from the top of it's container - let elemBottom = elemTop + $(elem).height(); // how far plus the height of the elem.. IE is it all in? + // how far plus the height of the elem.. IE is it all in? + let elemBottom = elemTop + $(elem).height(); elemBottom -= 16; // don't ask, sorry but this is needed.. return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop)); -} +}; -function caretPosition($) { +const caretPosition = ($) => { const doc = $.window.document; const pos = doc.getSelection(); pos.y = pos.anchorNode.parentElement.offsetTop; pos.x = pos.anchorNode.parentElement.offsetLeft; return pos; -} +}; diff --git a/tests/frontend/specs/change_user_color.js b/tests/frontend/specs/change_user_color.js index e8c16db37..c8a3bf5b9 100644 --- a/tests/frontend/specs/change_user_color.js +++ b/tests/frontend/specs/change_user_color.js @@ -1,3 +1,5 @@ +'use strict'; + describe('change user color', function () { // create a new pad before each test run beforeEach(function (cb) { @@ -5,7 +7,8 @@ describe('change user color', function () { this.timeout(60000); }); - it('Color picker matches original color and remembers the user color after a refresh', function (done) { + it('Color picker matches original color and remembers the user color' + + ' after a refresh', function (done) { this.timeout(60000); const chrome$ = helper.padChrome$; @@ -60,7 +63,6 @@ describe('change user color', function () { }); it('Own user color is shown when you enter a chat', function (done) { - const inner$ = helper.padInner$; const chrome$ = helper.padChrome$; const $colorOption = helper.padChrome$('#options-colorscheck'); @@ -90,13 +92,15 @@ describe('change user color', function () { $chatButton.click(); const $chatInput = chrome$('#chatinput'); $chatInput.sendkeys('O hi'); // simulate a keypress of typing user - $chatInput.sendkeys('{enter}'); // simulate a keypress of enter actually does evt.which = 10 not 13 + // simulate a keypress of enter actually does evt.which = 10 not 13 + $chatInput.sendkeys('{enter}'); - // check if chat shows up - helper.waitFor(() => chrome$('#chattext').children('p').length !== 0 // wait until the chat message shows up + // wait until the chat message shows up + helper.waitFor(() => chrome$('#chattext').children('p').length !== 0 ).done(() => { const $firstChatMessage = chrome$('#chattext').children('p'); - expect($firstChatMessage.css('background-color')).to.be(testColorRGB); // expect the first chat message to be of the user's color + // expect the first chat message to be of the user's color + expect($firstChatMessage.css('background-color')).to.be(testColorRGB); done(); }); }); diff --git a/tests/frontend/specs/change_user_name.js b/tests/frontend/specs/change_user_name.js index 0b9132f80..3c4b8b5bc 100644 --- a/tests/frontend/specs/change_user_name.js +++ b/tests/frontend/specs/change_user_name.js @@ -1,3 +1,5 @@ +'use strict'; + describe('change username value', function () { // create a new pad before each test run beforeEach(function (cb) { diff --git a/tests/frontend/specs/chat.js b/tests/frontend/specs/chat.js index d45988d60..fbc6ce788 100644 --- a/tests/frontend/specs/chat.js +++ b/tests/frontend/specs/chat.js @@ -1,10 +1,13 @@ +'use strict'; + describe('Chat messages and UI', function () { // create a new pad before each test run beforeEach(function (cb) { helper.newPad(cb); }); - it('opens chat, sends a message, makes sure it exists on the page and hides chat', async function () { + it('opens chat, sends a message, makes sure it exists ' + + 'on the page and hides chat', async function () { const chatValue = 'JohnMcLear'; await helper.showChat(); @@ -31,7 +34,8 @@ describe('Chat messages and UI', function () { await helper.showChat(); - await helper.sendChatMessage(`{enter}${chatValue}{enter}`); // simulate a keypress of typing enter, mluto and enter (to send 'mluto') + // simulate a keypress of typing enter, mluto and enter (to send 'mluto') + await helper.sendChatMessage(`{enter}${chatValue}{enter}`); const chat = helper.chatTextParagraphs(); @@ -44,7 +48,8 @@ describe('Chat messages and UI', function () { expect(chat.text()).to.be(`${username}${time} ${chatValue}`); }); - it('makes chat stick to right side of the screen via settings, remove sticky via settings, close it', async function () { + it('makes chat stick to right side of the screen via settings, ' + + 'remove sticky via settings, close it', async function () { await helper.showSettings(); await helper.enableStickyChatviaSettings(); @@ -60,7 +65,8 @@ describe('Chat messages and UI', function () { expect(helper.isChatboxShown()).to.be(false); }); - it('makes chat stick to right side of the screen via icon on the top right, remove sticky via icon, close it', async function () { + it('makes chat stick to right side of the screen via icon on the top' + + ' right, remove sticky via icon, close it', async function () { await helper.showChat(); await helper.enableStickyChatviaIcon(); @@ -76,10 +82,9 @@ describe('Chat messages and UI', function () { expect(helper.isChatboxShown()).to.be(false); }); - xit('Checks showChat=false URL Parameter hides chat then when removed it shows chat', function (done) { + xit('Checks showChat=false URL Parameter hides chat then' + + ' when removed it shows chat', function (done) { this.timeout(60000); - const inner$ = helper.padInner$; - const chrome$ = helper.padChrome$; setTimeout(() => { // give it a second to save the username on the server side helper.newPad({ // get a new pad, but don't clear the cookies diff --git a/tests/frontend/specs/chat_load_messages.js b/tests/frontend/specs/chat_load_messages.js index 29c1734ca..63d90fd63 100644 --- a/tests/frontend/specs/chat_load_messages.js +++ b/tests/frontend/specs/chat_load_messages.js @@ -1,3 +1,5 @@ +'use strict'; + describe('chat-load-messages', function () { let padName; @@ -7,7 +9,6 @@ describe('chat-load-messages', function () { }); it('adds a lot of messages', function (done) { - const inner$ = helper.padInner$; const chrome$ = helper.padChrome$; const chatButton = chrome$('#chaticon'); chatButton.click(); @@ -19,12 +20,12 @@ describe('chat-load-messages', function () { const messages = 140; for (let i = 1; i <= messages; i++) { let num = `${i}`; - if (num.length == 1) num = `00${num}`; - if (num.length == 2) num = `0${num}`; + if (num.length === 1) num = `00${num}`; + if (num.length === 2) num = `0${num}`; chatInput.sendkeys(`msg${num}`); chatInput.sendkeys('{enter}'); } - helper.waitFor(() => chatText.children('p').length == messages, 60000).always(() => { + helper.waitFor(() => chatText.children('p').length === messages, 60000).always(() => { expect(chatText.children('p').length).to.be(messages); helper.newPad(done, padName); }); @@ -38,7 +39,7 @@ describe('chat-load-messages', function () { const chatButton = chrome$('#chaticon'); chatButton.click(); chatText = chrome$('#chattext'); - return chatText.children('p').length == expectedCount; + return chatText.children('p').length === expectedCount; }).always(() => { expect(chatText.children('p').length).to.be(expectedCount); done(); @@ -54,7 +55,7 @@ describe('chat-load-messages', function () { const loadMsgBtn = chrome$('#chatloadmessagesbutton'); loadMsgBtn.click(); - helper.waitFor(() => chatText.children('p').length == expectedCount).always(() => { + helper.waitFor(() => chatText.children('p').length === expectedCount).always(() => { expect(chatText.children('p').length).to.be(expectedCount); done(); }); @@ -65,13 +66,12 @@ describe('chat-load-messages', function () { const chrome$ = helper.padChrome$; const chatButton = chrome$('#chaticon'); chatButton.click(); - const chatText = chrome$('#chattext'); const loadMsgBtn = chrome$('#chatloadmessagesbutton'); const loadMsgBall = chrome$('#chatloadmessagesball'); loadMsgBtn.click(); - helper.waitFor(() => loadMsgBtn.css('display') == expectedDisplay && - loadMsgBall.css('display') == expectedDisplay).always(() => { + helper.waitFor(() => loadMsgBtn.css('display') === expectedDisplay && + loadMsgBall.css('display') === expectedDisplay).always(() => { expect(loadMsgBtn.css('display')).to.be(expectedDisplay); expect(loadMsgBall.css('display')).to.be(expectedDisplay); done(); diff --git a/tests/frontend/specs/clear_authorship_colors.js b/tests/frontend/specs/clear_authorship_colors.js index f622e912a..63d4c2f54 100644 --- a/tests/frontend/specs/clear_authorship_colors.js +++ b/tests/frontend/specs/clear_authorship_colors.js @@ -1,3 +1,5 @@ +'use strict'; + describe('clear authorship colors button', function () { // create a new pad before each test run beforeEach(function (cb) { @@ -17,9 +19,6 @@ describe('clear authorship colors button', function () { // get the first text element out of the inner iframe const $firstTextElement = inner$('div').first(); - // Get the original text - const originalText = inner$('div').first().text(); - // Set some new text const sentText = 'Hello'; @@ -28,7 +27,8 @@ describe('clear authorship colors button', function () { $firstTextElement.sendkeys(sentText); $firstTextElement.sendkeys('{rightarrow}'); - helper.waitFor(() => inner$('div span').first().attr('class').indexOf('author') !== -1 // wait until we have the full value available + // wait until we have the full value available + helper.waitFor(() => inner$('div span').first().attr('class').indexOf('author') !== -1 ).done(() => { // IE hates you if you don't give focus to the inner frame bevore you do a clearAuthorship inner$('div').first().focus(); @@ -37,16 +37,13 @@ describe('clear authorship colors button', function () { const $clearauthorshipcolorsButton = chrome$('.buttonicon-clearauthorship'); $clearauthorshipcolorsButton.click(); - // does the first divs span include an author class? - var hasAuthorClass = inner$('div span').first().attr('class').indexOf('author') !== -1; - // expect(hasAuthorClass).to.be(false); - // does the first div include an author class? - var hasAuthorClass = inner$('div').first().attr('class').indexOf('author') !== -1; + const hasAuthorClass = inner$('div').first().attr('class').indexOf('author') !== -1; expect(hasAuthorClass).to.be(false); helper.waitFor(() => { - const disconnectVisible = chrome$('div.disconnected').attr('class').indexOf('visible') === -1; + const disconnectVisible = + chrome$('div.disconnected').attr('class').indexOf('visible') === -1; return (disconnectVisible === true); }); @@ -69,9 +66,6 @@ describe('clear authorship colors button', function () { // get the first text element out of the inner iframe const $firstTextElement = inner$('div').first(); - // Get the original text - const originalText = inner$('div').first().text(); - // Set some new text const sentText = 'Hello'; @@ -80,7 +74,9 @@ describe('clear authorship colors button', function () { $firstTextElement.sendkeys(sentText); $firstTextElement.sendkeys('{rightarrow}'); - helper.waitFor(() => inner$('div span').first().attr('class').indexOf('author') !== -1 // wait until we have the full value available + // wait until we have the full value available + helper.waitFor( + () => inner$('div span').first().attr('class').indexOf('author') !== -1 ).done(() => { // IE hates you if you don't give focus to the inner frame bevore you do a clearAuthorship inner$('div').first().focus(); @@ -89,15 +85,11 @@ describe('clear authorship colors button', function () { const $clearauthorshipcolorsButton = chrome$('.buttonicon-clearauthorship'); $clearauthorshipcolorsButton.click(); - // does the first divs span include an author class? - var hasAuthorClass = inner$('div span').first().attr('class').indexOf('author') !== -1; - // expect(hasAuthorClass).to.be(false); - // does the first div include an author class? - var hasAuthorClass = inner$('div').first().attr('class').indexOf('author') !== -1; + let hasAuthorClass = inner$('div').first().attr('class').indexOf('author') !== -1; expect(hasAuthorClass).to.be(false); - const e = inner$.Event(helper.evtType); + const e = new inner$.Event(helper.evtType); e.ctrlKey = true; // Control key e.which = 90; // z inner$('#innerdocbody').trigger(e); // shouldn't od anything @@ -115,7 +107,8 @@ describe('clear authorship colors button', function () { expect(hasAuthorClass).to.be(false); helper.waitFor(() => { - const disconnectVisible = chrome$('div.disconnected').attr('class').indexOf('visible') === -1; + const disconnectVisible = + chrome$('div.disconnected').attr('class').indexOf('visible') === -1; return (disconnectVisible === true); }); diff --git a/tests/frontend/specs/delete.js b/tests/frontend/specs/delete.js index 4267aeec7..6cde43f47 100644 --- a/tests/frontend/specs/delete.js +++ b/tests/frontend/specs/delete.js @@ -1,3 +1,5 @@ +'use strict'; + describe('delete keystroke', function () { // create a new pad before each test run beforeEach(function (cb) { @@ -7,7 +9,6 @@ describe('delete keystroke', function () { it('makes text delete', function (done) { const inner$ = helper.padInner$; - const chrome$ = helper.padChrome$; // get the first text element out of the inner iframe const $firstTextElement = inner$('div').first(); @@ -15,15 +16,10 @@ describe('delete keystroke', function () { // get the original length of this element const elementLength = $firstTextElement.text().length; - // get the original string value minus the last char - const originalTextValue = $firstTextElement.text(); - const originalTextValueMinusFirstChar = originalTextValue.substring(1, originalTextValue.length); - // simulate key presses to delete content $firstTextElement.sendkeys('{leftarrow}'); // simulate a keypress of the left arrow key $firstTextElement.sendkeys('{del}'); // simulate a keypress of delete - // ace creates a new dom element when you press a keystroke, so just get the first text element again const $newFirstTextElement = inner$('div').first(); // get the new length of this element diff --git a/tests/frontend/specs/drag_and_drop.js b/tests/frontend/specs/drag_and_drop.js index a9726111c..2d1339beb 100644 --- a/tests/frontend/specs/drag_and_drop.js +++ b/tests/frontend/specs/drag_and_drop.js @@ -1,4 +1,6 @@ -// WARNING: drag and drop is only simulated on these tests, so manual testing might also be necessary +'use strict'; + +// WARNING: drag and drop is only simulated on these tests, manual testing might also be necessary describe('drag and drop', function () { before(function (done) { helper.newPad(() => { @@ -78,18 +80,19 @@ describe('drag and drop', function () { }); /* ********************* Helper functions/constants ********************* */ - var TARGET_LINE = 2; - var FIRST_SOURCE_LINE = 5; + const TARGET_LINE = 2; + const FIRST_SOURCE_LINE = 5; - var getLine = function (lineNumber) { + const getLine = (lineNumber) => { const $lines = helper.padInner$('div'); return $lines.slice(lineNumber, lineNumber + 1); }; - var createScriptWithSeveralLines = function (done) { + const createScriptWithSeveralLines = (done) => { // create some lines to be used on the tests const $firstLine = helper.padInner$('div').first(); - $firstLine.html('...
        ...
        Target line []
        ...
        ...
        Source line 1.
        Source line 2.
        '); + $firstLine.html('...
        ...
        Target line []
        ...
        ...
        ' + + 'Source line 1.
        Source line 2.
        '); // wait for lines to be split helper.waitFor(() => { @@ -98,7 +101,7 @@ describe('drag and drop', function () { }).done(done); }; - var selectPartOfSourceLine = function () { + const selectPartOfSourceLine = () => { const $sourceLine = getLine(FIRST_SOURCE_LINE); // select 'line 1' from 'Source line 1.' @@ -106,14 +109,14 @@ describe('drag and drop', function () { const end = start + 'line 1'.length; helper.selectLines($sourceLine, $sourceLine, start, end); }; - var selectMultipleSourceLines = function () { + const selectMultipleSourceLines = () => { const $firstSourceLine = getLine(FIRST_SOURCE_LINE); const $lastSourceLine = getLine(FIRST_SOURCE_LINE + 1); helper.selectLines($firstSourceLine, $lastSourceLine); }; - var dragSelectedTextAndDropItIntoMiddleOfLine = function (targetLineNumber) { + const dragSelectedTextAndDropItIntoMiddleOfLine = (targetLineNumber) => { // dragstart: start dragging content triggerEvent('dragstart'); @@ -126,7 +129,7 @@ describe('drag and drop', function () { triggerEvent('dragend'); }; - var getHtmlFromSelectedText = function () { + const getHtmlFromSelectedText = () => { const innerDocument = helper.padInner$.document; const range = innerDocument.getSelection().getRangeAt(0); @@ -139,12 +142,12 @@ describe('drag and drop', function () { return draggedHtml; }; - var triggerEvent = function (eventName) { - const event = helper.padInner$.Event(eventName); + const triggerEvent = (eventName) => { + const event = new helper.padInner$.Event(eventName); helper.padInner$('#innerdocbody').trigger(event); }; - var moveSelectionIntoTarget = function (draggedHtml, targetLineNumber) { + const moveSelectionIntoTarget = (draggedHtml, targetLineNumber) => { const innerDocument = helper.padInner$.document; // delete original content diff --git a/tests/frontend/specs/embed_value.js b/tests/frontend/specs/embed_value.js index d6fb8c977..dac4c869d 100644 --- a/tests/frontend/specs/embed_value.js +++ b/tests/frontend/specs/embed_value.js @@ -1,3 +1,5 @@ +'use strict'; + describe('embed links', function () { const objectify = function (str) { const hash = {}; diff --git a/tests/frontend/specs/enter.js b/tests/frontend/specs/enter.js index 6108d7f82..2f5a90a69 100644 --- a/tests/frontend/specs/enter.js +++ b/tests/frontend/specs/enter.js @@ -1,3 +1,5 @@ +'use strict'; + describe('enter keystroke', function () { // create a new pad before each test run beforeEach(function (cb) { @@ -7,7 +9,6 @@ describe('enter keystroke', function () { it('creates a new line & puts cursor onto a new line', function (done) { const inner$ = helper.padInner$; - const chrome$ = helper.padChrome$; // get the first text element out of the inner iframe const $firstTextElement = inner$('div').first(); @@ -18,14 +19,12 @@ describe('enter keystroke', function () { // simulate key presses to enter content $firstTextElement.sendkeys('{enter}'); - // ace creates a new dom element when you press a keystroke, so just get the first text element again - const $newFirstTextElement = inner$('div').first(); - helper.waitFor(() => inner$('div').first().text() === '').done(() => { const $newSecondLine = inner$('div').first().next(); const newFirstTextElementValue = inner$('div').first().text(); expect(newFirstTextElementValue).to.be(''); // expect the first line to be blank - expect($newSecondLine.text()).to.be(originalTextValue); // expect the second line to be the same as the original first line. + // expect the second line to be the same as the original first line. + expect($newSecondLine.text()).to.be(originalTextValue); done(); }); }); diff --git a/tests/frontend/specs/font_type.js b/tests/frontend/specs/font_type.js index 51971da39..68df2f5e7 100644 --- a/tests/frontend/specs/font_type.js +++ b/tests/frontend/specs/font_type.js @@ -1,3 +1,5 @@ +'use strict'; + describe('font select', function () { // create a new pad before each test run beforeEach(function (cb) { @@ -15,7 +17,6 @@ describe('font select', function () { // get the font menu and RobotoMono option const $viewfontmenu = chrome$('#viewfontmenu'); - const $RobotoMonooption = $viewfontmenu.find('[value=RobotoMono]'); // select RobotoMono and fire change event // $RobotoMonooption.attr('selected','selected'); diff --git a/tests/frontend/specs/helper.js b/tests/frontend/specs/helper.js index 6bc6a3643..cb72fcf7a 100644 --- a/tests/frontend/specs/helper.js +++ b/tests/frontend/specs/helper.js @@ -1,3 +1,5 @@ +'use strict'; + describe('the test helper', function () { describe('the newPad method', function () { xit("doesn't leak memory if you creates iframes over and over again", function (done) { @@ -5,7 +7,7 @@ describe('the test helper', function () { let times = 10; - var loadPad = function () { + const loadPad = () => { helper.newPad(() => { times--; if (times > 0) { @@ -75,13 +77,14 @@ describe('the test helper', function () { // Before refreshing, make sure the name is there expect($usernameInput.val()).to.be('John McLear'); - // Now that we have a chrome, we can set a pad cookie, so we can confirm it gets wiped as well + // Now that we have a chrome, we can set a pad cookie + // so we can confirm it gets wiped as well chrome$.document.cookie = 'prefsHtml=baz;expires=Thu, 01 Jan 3030 00:00:00 GMT'; expect(chrome$.document.cookie).to.contain('prefsHtml=baz'); - // Cookies are weird. Because it's attached to chrome$ (as helper.setPadCookies does), AND we - // didn't put path=/, we shouldn't expect it to be visible on window.document.cookie. Let's just - // be sure. + // Cookies are weird. Because it's attached to chrome$ (as helper.setPadCookies does) + // AND we didn't put path=/, we shouldn't expect it to be visible on + // window.document.cookie. Let's just be sure. expect(window.document.cookie).to.not.contain('prefsHtml=baz'); setTimeout(() => { // give it a second to save the username on the server side @@ -266,7 +269,8 @@ describe('the test helper', function () { this.timeout(60000); }); - it('changes editor selection to be between startOffset of $startLine and endOffset of $endLine', function (done) { + it('changes editor selection to be between startOffset of $startLine ' + + 'and endOffset of $endLine', function (done) { const inner$ = helper.padInner$; const startOffset = 2; @@ -313,7 +317,8 @@ describe('the test helper', function () { * is not consistent between browsers but that's the situation so that's * how I'm covering it in this test. */ - expect(cleanText(selection.toString().replace(/(\r\n|\n|\r)/gm, ''))).to.be('ort lines to test'); + expect(cleanText( + selection.toString().replace(/(\r\n|\n|\r)/gm, ''))).to.be('ort lines to test'); done(); }); @@ -365,12 +370,14 @@ describe('the test helper', function () { * is not consistent between browsers but that's the situation so that's * how I'm covering it in this test. */ - expect(cleanText(selection.toString().replace(/(\r\n|\n|\r)/gm, ''))).to.be('ort lines to test'); + expect(cleanText( + selection.toString().replace(/(\r\n|\n|\r)/gm, ''))).to.be('ort lines to test'); done(); }); - it('selects all text between beginning of $startLine and end of $endLine when no offset is provided', function (done) { + it('selects all text between beginning of $startLine and end of $endLine ' + + 'when no offset is provided', function (done) { const inner$ = helper.padInner$; const $lines = inner$('div'); @@ -388,7 +395,8 @@ describe('the test helper', function () { * is not consistent between browsers but that's the situation so that's * how I'm covering it in this test. */ - expect(cleanText(selection.toString().replace(/(\r\n|\n|\r)/gm, ''))).to.be('short lines to test'); + expect(cleanText( + selection.toString().replace(/(\r\n|\n|\r)/gm, ''))).to.be('short lines to test'); done(); }); diff --git a/tests/frontend/specs/importexport.js b/tests/frontend/specs/importexport.js index 0be2a0744..4eb95eeb0 100644 --- a/tests/frontend/specs/importexport.js +++ b/tests/frontend/specs/importexport.js @@ -1,3 +1,5 @@ +'use strict'; + describe('import functionality', function () { beforeEach(function (cb) { helper.newPad(cb); // creates a new pad @@ -16,7 +18,6 @@ describe('import functionality', function () { return newtext; } function importrequest(data, importurl, type) { - let success; let error; const result = $.ajax({ url: importurl, @@ -27,7 +28,17 @@ describe('import functionality', function () { accepts: { text: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', }, - data: `Content-Type: multipart/form-data; boundary=--boundary\r\n\r\n--boundary\r\nContent-Disposition: form-data; name="file"; filename="import.${type}"\r\nContent-Type: text/plain\r\n\r\n${data}\r\n\r\n--boundary`, + data: [ + 'Content-Type: multipart/form-data; boundary=--boundary', + '', + '--boundary', + `Content-Disposition: form-data; name="file"; filename="import.${type}"`, + 'Content-Type: text/plain', + '', + data, + '', + '--boundary', + ].join('\r\n'), error(res) { error = res; }, @@ -56,7 +67,8 @@ describe('import functionality', function () { const importurl = `${helper.padChrome$.window.location.href}/import`; const textWithNewLines = 'imported text\nnewline'; importrequest(textWithNewLines, importurl, 'txt'); - helper.waitFor(() => expect(getinnertext()).to.be('imported text\nnewline\n
        \n')); + helper.waitFor(() => expect(getinnertext()) + .to.be('imported text\nnewline\n
        \n')); const results = exportfunc(helper.padChrome$.window.location.href); expect(results[0][1]).to.be('imported text
        newline

        '); expect(results[1][1]).to.be('imported text\nnewline\n\n'); @@ -66,7 +78,8 @@ describe('import functionality', function () { const importurl = `${helper.padChrome$.window.location.href}/import`; const htmlWithNewLines = 'htmltext
        newline'; importrequest(htmlWithNewLines, importurl, 'html'); - helper.waitFor(() => expect(getinnertext()).to.be('htmltext\nnewline\n
        \n')); + helper.waitFor(() => expect(getinnertext()) + .to.be('htmltext\nnewline\n
        \n')); const results = exportfunc(helper.padChrome$.window.location.href); expect(results[0][1]).to.be('htmltext
        newline

        '); expect(results[1][1]).to.be('htmltext\nnewline\n\n'); @@ -74,69 +87,109 @@ describe('import functionality', function () { }); xit('import a pad with attributes from html', function (done) { const importurl = `${helper.padChrome$.window.location.href}/import`; - const htmlWithNewLines = 'htmltext
        newline'; + const htmlWithNewLines = 'htmltext
        ' + + 'newline'; importrequest(htmlWithNewLines, importurl, 'html'); - helper.waitFor(() => expect(getinnertext()).to.be('htmltext\nnewline\n
        \n')); + helper.waitFor(() => expect(getinnertext()) + .to.be('htmltext\n' + + 'newline\n
        \n')); const results = exportfunc(helper.padChrome$.window.location.href); - expect(results[0][1]).to.be('htmltext
        newline

        '); + expect(results[0][1]) + .to.be('htmltext
        newline

        '); expect(results[1][1]).to.be('htmltext\nnewline\n\n'); done(); }); xit('import a pad with bullets from html', function (done) { const importurl = `${helper.padChrome$.window.location.href}/import`; - const htmlWithBullets = '
        • bullet line 1
        • bullet line 2
          • bullet2 line 1
          • bullet2 line 2
        '; + const htmlWithBullets = '
        • bullet line 1
        • ' + + '
        • bullet line 2
          • bullet2 line 1
          • ' + + '
          • bullet2 line 2
        '; importrequest(htmlWithBullets, importurl, 'html'); - helper.waitFor(() => expect(getinnertext()).to.be('\ -
        • bullet line 1
        \n\ -
        • bullet line 2
        \n\ -
        • bullet2 line 1
        \n\ -
        • bullet2 line 2
        \n\ -
        \n')); + helper.waitFor(() => expect(getinnertext()).to.be( + '
        • bullet line 1
        \n' + + '
        • bullet line 2
        \n' + + '
        • bullet2 line 1
        \n' + + '
        • bullet2 line 2
        \n' + + '
        \n')); const results = exportfunc(helper.padChrome$.window.location.href); - expect(results[0][1]).to.be('
        • bullet line 1
        • bullet line 2
          • bullet2 line 1
          • bullet2 line 2

        '); - expect(results[1][1]).to.be('\t* bullet line 1\n\t* bullet line 2\n\t\t* bullet2 line 1\n\t\t* bullet2 line 2\n\n'); + expect(results[0][1]).to.be( + '
        • bullet line 1
        • bullet line 2
        • ' + + '
          • bullet2 line 1
          • bullet2 line 2

        '); + expect(results[1][1]) + .to.be('\t* bullet line 1\n\t* bullet line 2\n' + + '\t\t* bullet2 line 1\n\t\t* bullet2 line 2\n\n'); done(); }); xit('import a pad with bullets and newlines from html', function (done) { const importurl = `${helper.padChrome$.window.location.href}/import`; - const htmlWithBullets = '
        • bullet line 1

        • bullet line 2
          • bullet2 line 1

          • bullet2 line 2
        '; + const htmlWithBullets = '
        • bullet line 1
        • ' + + '

        • bullet line 2
          • ' + + '
          • bullet2 line 1

          ' + + '
          • bullet2 line 2
        '; importrequest(htmlWithBullets, importurl, 'html'); - helper.waitFor(() => expect(getinnertext()).to.be('\ -
        • bullet line 1
        \n\ -
        \n\ -
        • bullet line 2
        \n\ -
        • bullet2 line 1
        \n\ -
        \n\ -
        • bullet2 line 2
        \n\ -
        \n')); + helper.waitFor(() => expect(getinnertext()).to.be( + '
        • bullet line 1
        \n' + + '
        \n' + + '
        • bullet line 2
        \n' + + '
        • bullet2 line 1
        \n' + + '
        \n' + + '
        • bullet2 line 2
        \n' + + '
        \n')); const results = exportfunc(helper.padChrome$.window.location.href); - expect(results[0][1]).to.be('
        • bullet line 1

        • bullet line 2
          • bullet2 line 1

          • bullet2 line 2

        '); - expect(results[1][1]).to.be('\t* bullet line 1\n\n\t* bullet line 2\n\t\t* bullet2 line 1\n\n\t\t* bullet2 line 2\n\n'); + expect(results[0][1]).to.be( + '
        • bullet line 1

          ' + + '
        • bullet line 2
          • bullet2 line 1
          ' + + '

          • bullet2 line 2

        '); + expect(results[1][1]).to.be( + '\t* bullet line 1\n\n\t* bullet line 2\n\t\t* bullet2 line 1\n\n\t\t* bullet2 line 2\n\n'); done(); }); xit('import a pad with bullets and newlines and attributes from html', function (done) { const importurl = `${helper.padChrome$.window.location.href}/import`; - const htmlWithBullets = '
        • bullet line 1

        • bullet line 2
          • bullet2 line 1

              • bullet4 line 2 bisu
              • bullet4 line 2 bs
              • bullet4 line 2 uuis
        '; + const htmlWithBullets = '
        • bullet line 1
        • ' + + '

        • bullet line 2
        • ' + + '
          • bullet2 line 1
        ' + + '
              ' + + '
              • ' + + 'bullet4 line 2 bisu
              • ' + + 'bullet4 line 2 bs
              • ' + + '
              • bullet4 line 2 u' + + 'uis
        '; importrequest(htmlWithBullets, importurl, 'html'); - helper.waitFor(() => expect(getinnertext()).to.be('\ -
        • bullet line 1
        \n\
        \n\ -
        • bullet line 2
        \n\ -
        • bullet2 line 1
        \n
        \n\ -
        • bullet4 line 2 bisu
        \n\ -
        • bullet4 line 2 bs
        \n\ -
        • bullet4 line 2 uuis
        \n\ -
        \n')); + helper.waitFor(() => expect(getinnertext()).to.be( + '
        • bullet line 1
        \n
        \n' + + '
        • bullet line 2
        \n' + + '
        • bullet2 line 1
        \n
        \n' + + '
        • ' + + 'bullet4 line 2 bisu
        \n' + + '
        • ' + + 'bullet4 line 2 bs
        \n' + + '
        • bullet4 line 2 u' + + 'uis
        \n' + + '
        \n')); const results = exportfunc(helper.padChrome$.window.location.href); - expect(results[0][1]).to.be('
        • bullet line 1

        • bullet line 2
          • bullet2 line 1

              • bullet4 line 2 bisu
              • bullet4 line 2 bs
              • bullet4 line 2 uuis

        '); - expect(results[1][1]).to.be('\t* bullet line 1\n\n\t* bullet line 2\n\t\t* bullet2 line 1\n\n\t\t\t\t* bullet4 line 2 bisu\n\t\t\t\t* bullet4 line 2 bs\n\t\t\t\t* bullet4 line 2 uuis\n\n'); + expect(results[0][1]).to.be( + '
        • bullet line 1
        ' + + '
        • bullet line 2
          • bullet2 line 1
          • ' + + '

              • bullet4 line 2 bisu' + + '
              • bullet4 line 2 bs' + + '
              • bullet4 line 2 uuis

        '); + expect(results[1][1]).to.be( + '\t* bullet line 1\n\n\t* bullet line 2\n\t\t* bullet2 line 1\n\n\t\t\t\t* bullet4 line 2' + + ' bisu\n\t\t\t\t* bullet4 line 2 bs\n\t\t\t\t* bullet4 line 2 uuis\n\n'); done(); }); xit('import a pad with nested bullets from html', function (done) { const importurl = `${helper.padChrome$.window.location.href}/import`; - const htmlWithBullets = '
        • bullet line 1
        • bullet line 2
          • bullet2 line 1
              • bullet4 line 2
              • bullet4 line 2
              • bullet4 line 2
            • bullet3 line 1
        • bullet2 line 1
        '; + const htmlWithBullets = '
        • bullet line 1
        • ' + + '
        • bullet line 2
          • ' + + '
          • bullet2 line 1
            ' + + '
              • bullet4 line 2
              • ' + + '
              • bullet4 line 2
              • bullet4 line 2
            • bullet3 line 1
            ' + + '
        • bullet2 line 1
        '; importrequest(htmlWithBullets, importurl, 'html'); const oldtext = getinnertext(); - helper.waitFor(() => oldtext != getinnertext() + helper.waitFor(() => oldtext !== getinnertext() // return expect(getinnertext()).to.be('\ //
        • bullet line 1
        \n\ //
        • bullet line 2
        \n\ @@ -148,73 +201,127 @@ describe('import functionality', function () { ); const results = exportfunc(helper.padChrome$.window.location.href); - expect(results[0][1]).to.be('
        • bullet line 1
        • bullet line 2
          • bullet2 line 1
              • bullet4 line 2
              • bullet4 line 2
              • bullet4 line 2
            • bullet3 line 1
        • bullet2 line 1

        '); - expect(results[1][1]).to.be('\t* bullet line 1\n\t* bullet line 2\n\t\t* bullet2 line 1\n\t\t\t\t* bullet4 line 2\n\t\t\t\t* bullet4 line 2\n\t\t\t\t* bullet4 line 2\n\t\t\t* bullet3 line 1\n\t* bullet2 line 1\n\n'); + expect(results[0][1]).to.be( + '
        • bullet line 1
        • bullet line 2
        • ' + + '
          • bullet2 line 1
              • bullet4 line 2
              • ' + + '
              • bullet4 line 2
              • bullet4 line 2
            • bullet3 line 1
          ' + + '
        • bullet2 line 1

        '); + expect(results[1][1]).to.be( + '\t* bullet line 1\n\t* bullet line 2\n\t\t* bullet2 line 1\n\t\t\t\t* bullet4 line 2' + + '\n\t\t\t\t* bullet4 line 2\n\t\t\t\t* bullet4 line 2\n\t\t\t* bullet3 line 1' + + '\n\t* bullet2 line 1\n\n'); done(); }); - xit('import a pad with 8 levels of bullets and newlines and attributes from html', function (done) { + xit('import with 8 levels of bullets and newlines and attributes from html', function (done) { const importurl = `${helper.padChrome$.window.location.href}/import`; - const htmlWithBullets = '
        • bullet line 1

        • bullet line 2
          • bullet2 line 1

              • bullet4 line 2 bisu
              • bullet4 line 2 bs
              • bullet4 line 2 uuis
                      • foo
                      • foobar bs
                • foobar
          '; + const htmlWithBullets = + '
          • bullet line 1
          • ' + + '

          • bullet line 2
            • ' + + 'bullet2 line 1

              ' + + '
                • ' + + 'bullet4 line 2 bisu
                • ' + + 'bullet4 line 2 bs
                • bullet4 line 2 u' + + 'uis
                • ' + + '
                        ' + + '
                        • foo
                        • ' + + 'foobar bs
                    ' + + '
                  • foobar
            '; importrequest(htmlWithBullets, importurl, 'html'); - helper.waitFor(() => expect(getinnertext()).to.be('\ -
            • bullet line 1
            \n\
            \n\ -
            • bullet line 2
            \n\ -
            • bullet2 line 1
            \n
            \n\ -
            • bullet4 line 2 bisu
            \n\ -
            • bullet4 line 2 bs
            \n\ -
            • bullet4 line 2 uuis
            \n\ -
            • foo
            \n\ -
            • foobar bs
            \n\ -
            • foobar
            \n\ -
            \n')); + helper.waitFor(() => expect(getinnertext()).to.be( + '
            • bullet line 1
            \n
            \n' + + '
            • bullet line 2
            \n' + + '
            • bullet2 line 1
            \n
            \n' + + '
            • bullet4 line 2 bisu' + + '
            \n' + + '
            • bullet4 line 2 bs' + + '
            \n' + + '
            • bullet4 line 2 u' + + 'uis' + + '
            \n' + + '
            • foo
            \n' + + '
            • foobar bs' + + '
            \n' + + '
            • foobar
            \n' + + '
            \n')); const results = exportfunc(helper.padChrome$.window.location.href); - expect(results[0][1]).to.be('
            • bullet line 1

            • bullet line 2
              • bullet2 line 1

                  • bullet4 line 2 bisu
                  • bullet4 line 2 bs
                  • bullet4 line 2 uuis
                          • foo
                          • foobar bs
                    • foobar

            '); - expect(results[1][1]).to.be('\t* bullet line 1\n\n\t* bullet line 2\n\t\t* bullet2 line 1\n\n\t\t\t\t* bullet4 line 2 bisu\n\t\t\t\t* bullet4 line 2 bs\n\t\t\t\t* bullet4 line 2 uuis\n\t\t\t\t\t\t\t\t* foo\n\t\t\t\t\t\t\t\t* foobar bs\n\t\t\t\t\t* foobar\n\n'); + expect(results[0][1]).to.be( + '
            • bullet line 1

              ' + + '
            • bullet line 2
              • bullet2 line 1
            ' + + '
                  • ' + + 'bullet4 line 2 bisu
                  • ' + + 'bullet4 line 2 bs
                  • bullet4 line 2 u' + + 'uis
                          • foo
                          • ' + + '
                          • foobar bs
                    • foobar
                    • ' + + '

            '); + expect(results[1][1]).to.be( + '\t* bullet line 1\n\n\t* bullet line 2\n\t\t* ' + + 'bullet2 line 1\n\n\t\t\t\t* bullet4 line 2 bisu\n\t\t\t\t* bullet4 line 2 ' + + 'bs\n\t\t\t\t* bullet4 line 2 uuis\n\t\t\t\t\t\t\t\t* foo\n\t\t\t\t\t\t\t\t* ' + + 'foobar bs\n\t\t\t\t\t* foobar\n\n'); done(); }); xit('import a pad with ordered lists from html', function (done) { const importurl = `${helper.padChrome$.window.location.href}/import`; - const htmlWithBullets = '
            1. number 1 line 1
            1. number 2 line 2
            '; + const htmlWithBullets = '
              ' + + '
            1. number 1 line 1
              ' + + '
            1. number 2 line 2
            '; importrequest(htmlWithBullets, importurl, 'html'); console.error(getinnertext()); - expect(getinnertext()).to.be('\ -
            1. number 1 line 1
            \n\ -
            1. number 2 line 2
            \n\ -
            \n'); + expect(getinnertext()).to.be( + '
            1. number 1 line 1
            \n' + + '
            1. number 2 line 2
            \n' + + '
            \n'); const results = exportfunc(helper.padChrome$.window.location.href); - expect(results[0][1]).to.be('
            1. number 1 line 1
            1. number 2 line 2
            '); + expect(results[0][1]).to.be( + '
            1. number 1 line 1
            2. ' + + '
            1. number 2 line 2
            '); expect(results[1][1]).to.be(''); done(); }); xit('import a pad with ordered lists and newlines from html', function (done) { const importurl = `${helper.padChrome$.window.location.href}/import`; - const htmlWithBullets = '
            1. number 9 line 1

            1. number 10 line 2
              1. number 2 times line 1

              1. number 2 times line 2
            '; + const htmlWithBullets = '
              ' + + '
            1. number 9 line 1

              ' + + '
            1. number 10 line 2
              1. ' + + '
              2. number 2 times line 1

              ' + + '
              1. number 2 times line 2
            '; importrequest(htmlWithBullets, importurl, 'html'); - expect(getinnertext()).to.be('\ -
            1. number 9 line 1
            \n\ -
            \n\ -
            1. number 10 line 2
            \n\ -
            1. number 2 times line 1
            \n\ -
            \n\ -
            1. number 2 times line 2
            \n\ -
            \n'); + expect(getinnertext()).to.be( + '
            1. number 9 line 1
            \n' + + '
            \n' + + '
            1. number 10 line 2
            2. ' + + '
            \n' + + '
            1. number 2 times line 1
            \n' + + '
            \n' + + '
            1. number 2 times line 2
            \n' + + '
            \n'); const results = exportfunc(helper.padChrome$.window.location.href); console.error(results); done(); }); - xit('import a pad with nested ordered lists and attributes and newlines from html', function (done) { + xit('import with nested ordered lists and attributes and newlines from html', function (done) { const importurl = `${helper.padChrome$.window.location.href}/import`; - const htmlWithBullets = '
            1. bold strikethrough italics underline line 1bold

            1. number 10 line 2
              1. number 2 times line 1

              1. number 2 times line 2
            '; + const htmlWithBullets = '
            1. ' + + 'bold strikethrough italics underline' + + ' line 1bold
            2. ' + + '

              ' + + '
            1. number 10 line 2
              1. ' + + '
              2. number 2 times line 1

            ' + + '
                ' + + '
              1. number 2 times line 2
            '; importrequest(htmlWithBullets, importurl, 'html'); - expect(getinnertext()).to.be('\ -
            1. bold strikethrough italics underline line 1bold
            \n\ -
            \n\ -
            1. number 10 line 2
            \n\ -
            1. number 2 times line 1
            \n\ -
            \n\ -
            1. number 2 times line 2
            \n\ -
            \n'); + expect(getinnertext()).to.be( + '
            1. ' + + 'bold strikethrough italics underline' + + ' line 1bold
            \n' + + '
            \n' + + '
            1. number 10 line 2
            \n' + + '
            1. ' + + 'number 2 times line 1
            \n' + + '
            \n' + + '
            1. number 2 times line 2
            \n' + + '
            \n'); const results = exportfunc(helper.padChrome$.window.location.href); console.error(results); done(); diff --git a/tests/frontend/specs/importindents.js b/tests/frontend/specs/importindents.js index 6209236df..eecbbce59 100644 --- a/tests/frontend/specs/importindents.js +++ b/tests/frontend/specs/importindents.js @@ -1,3 +1,5 @@ +'use strict'; + describe('import indents functionality', function () { beforeEach(function (cb) { helper.newPad(cb); // creates a new pad @@ -13,7 +15,6 @@ describe('import indents functionality', function () { return newtext; } function importrequest(data, importurl, type) { - let success; let error; const result = $.ajax({ url: importurl, @@ -24,7 +25,17 @@ describe('import indents functionality', function () { accepts: { text: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', }, - data: `Content-Type: multipart/form-data; boundary=--boundary\r\n\r\n--boundary\r\nContent-Disposition: form-data; name="file"; filename="import.${type}"\r\nContent-Type: text/plain\r\n\r\n${data}\r\n\r\n--boundary`, + data: [ + 'Content-Type: multipart/form-data; boundary=--boundary', + '', + '--boundary', + `Content-Disposition: form-data; name="file"; filename="import.${type}"`, + 'Content-Type: text/plain', + '', + data, + '', + '--boundary', + ].join('\r\n'), error(res) { error = res; }, @@ -51,54 +62,67 @@ describe('import indents functionality', function () { xit('import a pad with indents from html', function (done) { const importurl = `${helper.padChrome$.window.location.href}/import`; + /* eslint-disable-next-line max-len */ const htmlWithIndents = '
            • indent line 1
            • indent line 2
              • indent2 line 1
              • indent2 line 2
            '; importrequest(htmlWithIndents, importurl, 'html'); - helper.waitFor(() => expect(getinnertext()).to.be('\ -
            • indent line 1
            \n\ -
            • indent line 2
            \n\ -
            • indent2 line 1
            \n\ -
            • indent2 line 2
            \n\ -
            \n')); + helper.waitFor(() => expect(getinnertext()).to.be( + '
            • indent line 1
            \n' + + '
            • indent line 2
            \n' + + '
            • indent2 line 1
            \n' + + '
            • indent2 line 2
            \n' + + '
            \n')); const results = exportfunc(helper.padChrome$.window.location.href); + /* eslint-disable-next-line max-len */ expect(results[0][1]).to.be('
            • indent line 1
            • indent line 2
              • indent2 line 1
              • indent2 line 2

            '); - expect(results[1][1]).to.be('\tindent line 1\n\tindent line 2\n\t\tindent2 line 1\n\t\tindent2 line 2\n\n'); + expect(results[1][1]) + .to.be('\tindent line 1\n\tindent line 2\n\t\tindent2 line 1\n\t\tindent2 line 2\n\n'); done(); }); xit('import a pad with indented lists and newlines from html', function (done) { const importurl = `${helper.padChrome$.window.location.href}/import`; + /* eslint-disable-next-line max-len */ const htmlWithIndents = '
            • indent line 1

            • indent 1 line 2
              • indent 2 times line 1

              • indent 2 times line 2
            '; importrequest(htmlWithIndents, importurl, 'html'); - helper.waitFor(() => expect(getinnertext()).to.be('\ -
            • indent line 1
            \n\ -
            \n\ -
            • indent 1 line 2
            \n\ -
            • indent 2 times line 1
            \n\ -
            \n\ -
            • indent 2 times line 2
            \n\ -
            \n')); + helper.waitFor(() => expect(getinnertext()).to.be( + '
            • indent line 1
            \n' + + '
            \n' + + '
            • indent 1 line 2
            \n' + + '
            • indent 2 times line 1
            \n' + + '
            \n' + + '
            • indent 2 times line 2
            \n' + + '
            \n')); const results = exportfunc(helper.padChrome$.window.location.href); + /* eslint-disable-next-line max-len */ expect(results[0][1]).to.be('
            • indent line 1

            • indent 1 line 2
              • indent 2 times line 1

              • indent 2 times line 2

            '); + /* eslint-disable-next-line max-len */ expect(results[1][1]).to.be('\tindent line 1\n\n\tindent 1 line 2\n\t\tindent 2 times line 1\n\n\t\tindent 2 times line 2\n\n'); done(); }); - xit('import a pad with 8 levels of indents and newlines and attributes from html', function (done) { + xit('import with 8 levels of indents and newlines and attributes from html', function (done) { const importurl = `${helper.padChrome$.window.location.href}/import`; + /* eslint-disable-next-line max-len */ const htmlWithIndents = '
            • indent line 1

            • indent line 2
              • indent2 line 1

                  • indent4 line 2 bisu
                  • indent4 line 2 bs
                  • indent4 line 2 uuis
                          • foo
                          • foobar bs
                    • foobar
              '; importrequest(htmlWithIndents, importurl, 'html'); - helper.waitFor(() => expect(getinnertext()).to.be('\ -
              • indent line 1
              \n\
              \n\ -
              • indent line 2
              \n\ -
              • indent2 line 1
              \n
              \n\ -
              • indent4 line 2 bisu
              \n\ -
              • indent4 line 2 bs
              \n\ -
              • indent4 line 2 uuis
              \n\ -
              • foo
              \n\ -
              • foobar bs
              \n\ -
              • foobar
              \n\ -
              \n')); + helper.waitFor(() => expect(getinnertext()).to.be( + '
              • indent line 1
              \n
              \n' + + '
              • indent line 2
              \n' + + '
              • indent2 line 1
              \n
              \n' + + '
              • indent4 ' + + 'line 2 bisu
              \n' + + '
              • ' + + 'indent4 line 2 bs
              \n' + + '
              • indent4 line 2 u' + + 'uis
              \n' + + '
              • foo
              \n' + + '
              • foobar bs' + + '
              \n' + + '
              • foobar
              \n' + + '
              \n')); const results = exportfunc(helper.padChrome$.window.location.href); + /* eslint-disable-next-line max-len */ expect(results[0][1]).to.be('
              • indent line 1

              • indent line 2
                • indent2 line 1

                    • indent4 line 2 bisu
                    • indent4 line 2 bs
                    • indent4 line 2 uuis
                            • foo
                            • foobar bs
                      • foobar

              '); + /* eslint-disable-next-line max-len */ expect(results[1][1]).to.be('\tindent line 1\n\n\tindent line 2\n\t\tindent2 line 1\n\n\t\t\t\tindent4 line 2 bisu\n\t\t\t\tindent4 line 2 bs\n\t\t\t\tindent4 line 2 uuis\n\t\t\t\t\t\t\t\tfoo\n\t\t\t\t\t\t\t\tfoobar bs\n\t\t\t\t\tfoobar\n\n'); done(); }); diff --git a/tests/frontend/specs/indentation.js b/tests/frontend/specs/indentation.js index c52f5f406..006c52bb4 100644 --- a/tests/frontend/specs/indentation.js +++ b/tests/frontend/specs/indentation.js @@ -1,3 +1,5 @@ +'use strict'; + describe('indentation button', function () { // create a new pad before each test run beforeEach(function (cb) { @@ -7,7 +9,6 @@ describe('indentation button', function () { it('indent text with keypress', function (done) { const inner$ = helper.padInner$; - const chrome$ = helper.padChrome$; // get the first text element out of the inner iframe const $firstTextElement = inner$('div').first(); @@ -15,7 +16,7 @@ describe('indentation button', function () { // select this text element $firstTextElement.sendkeys('{selectall}'); - const e = inner$.Event(helper.evtType); + const e = new inner$.Event(helper.evtType); e.keyCode = 9; // tab :| inner$('#innerdocbody').trigger(e); @@ -56,9 +57,9 @@ describe('indentation button', function () { }); }); - it("indents text with spaces on enter if previous line ends with ':', '[', '(', or '{'", function (done) { + it('indents text with spaces on enter if previous line ends ' + + "with ':', '[', '(', or '{'", function (done) { const inner$ = helper.padInner$; - const chrome$ = helper.padChrome$; // type a bit, make a line break and type again const $firstTextElement = inner$('div').first(); @@ -77,7 +78,8 @@ describe('indentation button', function () { // curly braces const $lineWithCurlyBraces = inner$('div').first().next().next().next(); $lineWithCurlyBraces.sendkeys('{{}'); - pressEnter(); // cannot use sendkeys('{enter}') here, browser does not read the command properly + // cannot use sendkeys('{enter}') here, browser does not read the command properly + pressEnter(); const $lineAfterCurlyBraces = inner$('div').first().next().next().next().next(); expect($lineAfterCurlyBraces.text()).to.match(/\s{4}/); // tab === 4 spaces @@ -106,9 +108,9 @@ describe('indentation button', function () { }); }); - it("appends indentation to the indent of previous line if previous line ends with ':', '[', '(', or '{'", function (done) { + it('appends indentation to the indent of previous line if previous line ends ' + + "with ':', '[', '(', or '{'", function (done) { const inner$ = helper.padInner$; - const chrome$ = helper.padChrome$; // type a bit, make a line break and type again const $firstTextElement = inner$('div').first(); @@ -124,13 +126,15 @@ describe('indentation button', function () { $lineWithColon.sendkeys(':'); pressEnter(); const $lineAfterColon = inner$('div').first().next(); - expect($lineAfterColon.text()).to.match(/\s{6}/); // previous line indentation + regular tab (4 spaces) + // previous line indentation + regular tab (4 spaces) + expect($lineAfterColon.text()).to.match(/\s{6}/); done(); }); }); - it("issue #2772 shows '*' when multiple indented lines receive a style and are outdented", async function () { + it("issue #2772 shows '*' when multiple indented lines " + + ' receive a style and are outdented', async function () { const inner$ = helper.padInner$; const chrome$ = helper.padChrome$; @@ -182,7 +186,6 @@ describe('indentation button', function () { var $indentButton = testHelper.$getPadChrome().find(".buttonicon-indent"); $indentButton.click(); - //ace creates a new dom element when you press a button, so just get the first text element again var newFirstTextElement = $inner.find("div").first(); // is there a list-indent class element now? @@ -220,7 +223,6 @@ describe('indentation button', function () { $outdentButton.click(); $outdentButton.click(); - //ace creates a new dom element when you press a button, so just get the first text element again var newFirstTextElement = $inner.find("div").first(); // is there a list-indent class element now? @@ -267,7 +269,9 @@ describe('indentation button', function () { //get the second text element out of the inner iframe setTimeout(function(){ // THIS IS REALLY BAD - var secondTextElement = $('iframe').contents().find('iframe').contents().find('iframe').contents().find('body > div').get(1); // THIS IS UGLY + var secondTextElement = $('iframe').contents() + .find('iframe').contents() + .find('iframe').contents().find('body > div').get(1); // THIS IS UGLY // is there a list-indent class element now? var firstChild = secondTextElement.children(":first"); @@ -282,7 +286,10 @@ describe('indentation button', function () { expect(isLI).to.be(true); //get the first text element out of the inner iframe - var thirdTextElement = $('iframe').contents().find('iframe').contents().find('iframe').contents().find('body > div').get(2); // THIS IS UGLY TOO + var thirdTextElement = $('iframe').contents() + .find('iframe').contents() + .find('iframe').contents() + .find('body > div').get(2); // THIS IS UGLY TOO // is there a list-indent class element now? var firstChild = thirdTextElement.children(":first"); @@ -300,9 +307,9 @@ describe('indentation button', function () { });*/ }); -function pressEnter() { +const pressEnter = () => { const inner$ = helper.padInner$; - const e = inner$.Event(helper.evtType); + const e = new inner$.Event(helper.evtType); e.keyCode = 13; // enter :| inner$('#innerdocbody').trigger(e); -} +}; diff --git a/tests/frontend/specs/italic.js b/tests/frontend/specs/italic.js index 3660f71f3..cbaf9e3da 100644 --- a/tests/frontend/specs/italic.js +++ b/tests/frontend/specs/italic.js @@ -1,3 +1,5 @@ +'use strict'; + describe('italic some text', function () { // create a new pad before each test run beforeEach(function (cb) { @@ -19,7 +21,7 @@ describe('italic some text', function () { const $boldButton = chrome$('.buttonicon-italic'); $boldButton.click(); - // ace creates a new dom element when you press a button, so just get the first text element again + // ace creates a new dom element when you press a button, just get the first text element again const $newFirstTextElement = inner$('div').first(); // is there a element now? @@ -36,7 +38,6 @@ describe('italic some text', function () { it('makes text italic using keypress', function (done) { const inner$ = helper.padInner$; - const chrome$ = helper.padChrome$; // get the first text element out of the inner iframe const $firstTextElement = inner$('div').first(); @@ -44,12 +45,12 @@ describe('italic some text', function () { // select this text element $firstTextElement.sendkeys('{selectall}'); - const e = inner$.Event(helper.evtType); + const e = new inner$.Event(helper.evtType); e.ctrlKey = true; // Control key e.which = 105; // i inner$('#innerdocbody').trigger(e); - // ace creates a new dom element when you press a button, so just get the first text element again + // ace creates a new dom element when you press a button, just get the first text element again const $newFirstTextElement = inner$('div').first(); // is there a element now? diff --git a/tests/frontend/specs/language.js b/tests/frontend/specs/language.js index d29b2407e..072c64e92 100644 --- a/tests/frontend/specs/language.js +++ b/tests/frontend/specs/language.js @@ -1,6 +1,8 @@ -function deletecookie(name) { +'use strict'; + +const deletecookie = (name) => { document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:01 GMT;`; -} +}; describe('Language select and change', function () { // Destroy language cookies @@ -14,7 +16,6 @@ describe('Language select and change', function () { // Destroy language cookies it('makes text german', function (done) { - const inner$ = helper.padInner$; const chrome$ = helper.padChrome$; // click on the settings button to make settings visible @@ -29,7 +30,7 @@ describe('Language select and change', function () { $languageoption.attr('selected', 'selected'); $language.change(); - helper.waitFor(() => chrome$('.buttonicon-bold').parent()[0].title == 'Fett (Strg-B)') + helper.waitFor(() => chrome$('.buttonicon-bold').parent()[0].title === 'Fett (Strg-B)') .done(() => { // get the value of the bold button const $boldButton = chrome$('.buttonicon-bold').parent(); @@ -44,7 +45,6 @@ describe('Language select and change', function () { }); it('makes text English', function (done) { - const inner$ = helper.padInner$; const chrome$ = helper.padChrome$; // click on the settings button to make settings visible @@ -60,7 +60,7 @@ describe('Language select and change', function () { // get the value of the bold button const $boldButton = chrome$('.buttonicon-bold').parent(); - helper.waitFor(() => $boldButton[0].title != 'Fett (Strg+B)') + helper.waitFor(() => $boldButton[0].title !== 'Fett (Strg+B)') .done(() => { // get the value of the bold button const $boldButton = chrome$('.buttonicon-bold').parent(); @@ -75,7 +75,6 @@ describe('Language select and change', function () { }); it('changes direction when picking an rtl lang', function (done) { - const inner$ = helper.padInner$; const chrome$ = helper.padChrome$; // click on the settings button to make settings visible @@ -91,7 +90,7 @@ describe('Language select and change', function () { $language.val('ar'); $languageoption.change(); - helper.waitFor(() => chrome$('html')[0].dir != 'ltr') + helper.waitFor(() => chrome$('html')[0].dir !== 'ltr') .done(() => { // check if the document's direction was changed expect(chrome$('html')[0].dir).to.be('rtl'); @@ -100,7 +99,6 @@ describe('Language select and change', function () { }); it('changes direction when picking an ltr lang', function (done) { - const inner$ = helper.padInner$; const chrome$ = helper.padChrome$; // click on the settings button to make settings visible @@ -117,7 +115,7 @@ describe('Language select and change', function () { $language.val('en'); $languageoption.change(); - helper.waitFor(() => chrome$('html')[0].dir != 'rtl') + helper.waitFor(() => chrome$('html')[0].dir !== 'rtl') .done(() => { // check if the document's direction was changed expect(chrome$('html')[0].dir).to.be('ltr'); diff --git a/tests/frontend/specs/multiple_authors_clear_authorship_colors.js b/tests/frontend/specs/multiple_authors_clear_authorship_colors.js index f532ea4be..19dfb44f9 100755 --- a/tests/frontend/specs/multiple_authors_clear_authorship_colors.js +++ b/tests/frontend/specs/multiple_authors_clear_authorship_colors.js @@ -1,7 +1,9 @@ +'use strict'; + describe('author of pad edition', function () { // author 1 creates a new pad with some content (regular lines and lists) before(function (done) { - var padId = helper.newPad(() => { + const padId = helper.newPad(() => { // make sure pad has at least 3 lines const $firstLine = helper.padInner$('div').first(); $firstLine.html('Hello World'); @@ -13,7 +15,8 @@ describe('author of pad edition', function () { setTimeout(() => { // Expire cookie, so author is changed after reloading the pad. // See https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie#Example_4_Reset_the_previous_cookie - helper.padChrome$.document.cookie = 'token=foo;expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/'; + helper.padChrome$.document.cookie = + 'token=foo;expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/'; helper.newPad(done, padId); }, 1000); @@ -27,7 +30,7 @@ describe('author of pad edition', function () { clearAuthorship(done); }); - var clearAuthorship = function (done) { + const clearAuthorship = (done) => { const inner$ = helper.padInner$; const chrome$ = helper.padChrome$; diff --git a/tests/frontend/specs/ordered_list.js b/tests/frontend/specs/ordered_list.js index a932335e8..d069a6487 100644 --- a/tests/frontend/specs/ordered_list.js +++ b/tests/frontend/specs/ordered_list.js @@ -1,3 +1,5 @@ +'use strict'; + describe('assign ordered list', function () { // create a new pad before each test run beforeEach(function (cb) { @@ -34,7 +36,8 @@ describe('assign ordered list', function () { }); it('does not insert unordered list', function (done) { - helper.waitFor(() => helper.padInner$('div').first().find('ol li').length === 1).done(() => { + helper.waitFor( + () => helper.padInner$('div').first().find('ol li').length === 1).done(() => { expect().fail(() => 'Unordered list inserted, should ignore shortcut'); }).fail(() => { done(); @@ -62,7 +65,8 @@ describe('assign ordered list', function () { }); it('does not insert unordered list', function (done) { - helper.waitFor(() => helper.padInner$('div').first().find('ol li').length === 1).done(() => { + helper.waitFor( + () => helper.padInner$('div').first().find('ol li').length === 1).done(() => { expect().fail(() => 'Unordered list inserted, should ignore shortcut'); }).fail(() => { done(); @@ -71,7 +75,8 @@ describe('assign ordered list', function () { }); }); - xit('issue #1125 keeps the numbered list on enter for the new line - EMULATES PASTING INTO A PAD', function (done) { + xit('issue #1125 keeps the numbered list on enter for the new line', function (done) { + // EMULATES PASTING INTO A PAD const inner$ = helper.padInner$; const chrome$ = helper.padChrome$; @@ -91,24 +96,25 @@ describe('assign ordered list', function () { expect(hasOLElement).to.be(true); expect($newSecondLine.text()).to.be('line 2'); const hasLineNumber = $newSecondLine.find('ol').attr('start') === 2; - expect(hasLineNumber).to.be(true); // This doesn't work because pasting in content doesn't work + // This doesn't work because pasting in content doesn't work + expect(hasLineNumber).to.be(true); done(); }); }); - var triggerCtrlShiftShortcut = function (shortcutChar) { + const triggerCtrlShiftShortcut = (shortcutChar) => { const inner$ = helper.padInner$; - const e = inner$.Event(helper.evtType); + const e = new inner$.Event(helper.evtType); e.ctrlKey = true; e.shiftKey = true; e.which = shortcutChar.toString().charCodeAt(0); inner$('#innerdocbody').trigger(e); }; - var makeSureShortcutIsDisabled = function (shortcut) { + const makeSureShortcutIsDisabled = (shortcut) => { helper.padChrome$.window.clientVars.padShortcutEnabled[shortcut] = false; }; - var makeSureShortcutIsEnabled = function (shortcut) { + const makeSureShortcutIsEnabled = (shortcut) => { helper.padChrome$.window.clientVars.padShortcutEnabled[shortcut] = true; }; }); @@ -133,7 +139,7 @@ describe('Pressing Tab in an OL increases and decreases indentation', function ( const $insertorderedlistButton = chrome$('.buttonicon-insertorderedlist'); $insertorderedlistButton.click(); - const e = inner$.Event(helper.evtType); + const e = new inner$.Event(helper.evtType); e.keyCode = 9; // tab inner$('#innerdocbody').trigger(e); @@ -147,7 +153,8 @@ describe('Pressing Tab in an OL increases and decreases indentation', function ( }); -describe('Pressing indent/outdent button in an OL increases and decreases indentation and bullet / ol formatting', function () { +describe('Pressing indent/outdent button in an OL increases and ' + + 'decreases indentation and bullet / ol formatting', function () { // create a new pad before each test run beforeEach(function (cb) { helper.newPad(cb); diff --git a/tests/frontend/specs/pad_modal.js b/tests/frontend/specs/pad_modal.js index 1711e38b8..30277d5de 100644 --- a/tests/frontend/specs/pad_modal.js +++ b/tests/frontend/specs/pad_modal.js @@ -1,3 +1,5 @@ +'use strict'; + describe('Pad modal', function () { context('when modal is a "force reconnect" message', function () { const MODAL_SELECTOR = '#connectivity'; @@ -93,17 +95,17 @@ describe('Pad modal', function () { }); }); - var clickOnPadInner = function () { + const clickOnPadInner = () => { const $editor = helper.padInner$('#innerdocbody'); $editor.click(); }; - var clickOnPadOuter = function () { + const clickOnPadOuter = () => { const $lineNumbersColumn = helper.padOuter$('#sidedivinner'); $lineNumbersColumn.click(); }; - var openSettingsAndWaitForModalToBeVisible = function (done) { + const openSettingsAndWaitForModalToBeVisible = (done) => { helper.padChrome$('.buttonicon-settings').click(); // wait for modal to be displayed @@ -111,7 +113,7 @@ describe('Pad modal', function () { helper.waitFor(() => isModalOpened(modalSelector), 10000).done(done); }; - var isEditorDisabled = function () { + const isEditorDisabled = () => { const editorDocument = helper.padOuter$("iframe[name='ace_inner']").get(0).contentDocument; const editorBody = editorDocument.getElementById('innerdocbody'); @@ -121,7 +123,7 @@ describe('Pad modal', function () { return editorIsDisabled; }; - var isModalOpened = function (modalSelector) { + const isModalOpened = (modalSelector) => { const $modal = helper.padChrome$(modalSelector); return $modal.hasClass('popup-show'); diff --git a/tests/frontend/specs/redo.js b/tests/frontend/specs/redo.js index 58d5b6c12..3e8d3a168 100644 --- a/tests/frontend/specs/redo.js +++ b/tests/frontend/specs/redo.js @@ -1,3 +1,5 @@ +'use strict'; + describe('undo button then redo button', function () { beforeEach(function (cb) { helper.newPad(cb); // creates a new pad @@ -33,7 +35,6 @@ describe('undo button then redo button', function () { it('redo some typing with keypress', function (done) { const inner$ = helper.padInner$; - const chrome$ = helper.padChrome$; // get the first text element inside the editable space const $firstTextElement = inner$('div span').first(); @@ -44,12 +45,12 @@ describe('undo button then redo button', function () { const modifiedValue = $firstTextElement.text(); // get the modified value expect(modifiedValue).not.to.be(originalValue); // expect the value to change - var e = inner$.Event(helper.evtType); + let e = inner$.Event(helper.evtType); e.ctrlKey = true; // Control key e.which = 90; // z inner$('#innerdocbody').trigger(e); - var e = inner$.Event(helper.evtType); + e = inner$.Event(helper.evtType); e.ctrlKey = true; // Control key e.which = 121; // y inner$('#innerdocbody').trigger(e); diff --git a/tests/frontend/specs/responsiveness.js b/tests/frontend/specs/responsiveness.js index 63803f641..ec63faa10 100644 --- a/tests/frontend/specs/responsiveness.js +++ b/tests/frontend/specs/responsiveness.js @@ -1,14 +1,19 @@ +'use strict'; + // Test for https://github.com/ether/etherpad-lite/issues/1763 // This test fails in Opera, IE and Safari -// Opera fails due to a weird way of handling the order of execution, yet actual performance seems fine +// Opera fails due to a weird way of handling the order of execution, +// yet actual performance seems fine // Safari fails due the delay being too great yet the actual performance seems fine // Firefox might panic that the script is taking too long so will fail // IE will fail due to running out of memory as it can't fit 2M chars in memory. -// Just FYI Google Docs crashes on large docs whilst trying to Save, it's likely the limitations we are +// Just FYI Google Docs crashes on large docs whilst trying to Save, +// it's likely the limitations we are // experiencing are more to do with browser limitations than improper implementation. -// A ueber fix for this would be to have a separate lower cpu priority thread that handles operations that aren't +// A ueber fix for this would be to have a separate lower cpu priority +// thread that handles operations that aren't // visible to the user. // Adapted from John McLear's original test case. @@ -20,16 +25,18 @@ xdescribe('Responsiveness of Editor', function () { this.timeout(6000); }); // JM commented out on 8th Sep 2020 for a release, after release this needs uncommenting - // And the test needs to be fixed to work in Firefox 52 on Windows 7. I am not sure why it fails on this specific platform - // The errors show this.timeout... then crash the browser but I am sure something is actually causing the stack trace and + // And the test needs to be fixed to work in Firefox 52 on Windows 7. + // I am not sure why it fails on this specific platform + // The errors show this.timeout... then crash the browser but + // I am sure something is actually causing the stack trace and // I just need to narrow down what, offers to help accepted. it('Fast response to keypress in pad with large amount of contents', function (done) { // skip on Windows Firefox 52.0 - if (window.bowser && window.bowser.windows && window.bowser.firefox && window.bowser.version == '52.0') { + if (window.bowser && + window.bowser.windows && window.bowser.firefox && window.bowser.version === '52.0') { this.skip(); } const inner$ = helper.padInner$; - const chrome$ = helper.padChrome$; const chars = '0000000000'; // row of placeholder chars const amount = 200000; // number of blocks of chars we will insert const length = (amount * (chars.length) + 1); // include a counter for each space @@ -39,7 +46,7 @@ xdescribe('Responsiveness of Editor', function () { // get keys to send const keyMultiplier = 10; // multiplier * 10 == total number of key events let keysToSend = ''; - for (var i = 0; i <= keyMultiplier; i++) { + for (let i = 0; i <= keyMultiplier; i++) { keysToSend += chars; } @@ -47,23 +54,23 @@ xdescribe('Responsiveness of Editor', function () { textElement.sendkeys('{selectall}'); // select all textElement.sendkeys('{del}'); // clear the pad text - for (var i = 0; i <= amount; i++) { + for (let i = 0; i <= amount; i++) { text = `${text + chars} `; // add the chars and space to the text contents } inner$('div').first().text(text); // Put the text contents into the pad - helper.waitFor(() => // Wait for the new contents to be on the pad - inner$('div').text().length > length - ).done(() => { - expect(inner$('div').text().length).to.be.greaterThan(length); // has the text changed? + // Wait for the new contents to be on the pad + helper.waitFor(() => inner$('div').text().length > length).done(() => { + // has the text changed? + expect(inner$('div').text().length).to.be.greaterThan(length); const start = Date.now(); // get the start time // send some new text to the screen (ensure all 3 key events are sent) const el = inner$('div').first(); for (let i = 0; i < keysToSend.length; ++i) { - var x = keysToSend.charCodeAt(i); + const x = keysToSend.charCodeAt(i); ['keyup', 'keypress', 'keydown'].forEach((type) => { - const e = $.Event(type); + const e = new $.Event(type); e.keyCode = x; el.trigger(e); }); diff --git a/tests/frontend/specs/select_formatting_buttons.js b/tests/frontend/specs/select_formatting_buttons.js index 52595a044..358d9e5b7 100644 --- a/tests/frontend/specs/select_formatting_buttons.js +++ b/tests/frontend/specs/select_formatting_buttons.js @@ -1,3 +1,5 @@ +'use strict'; + describe('select formatting buttons when selection has style applied', function () { const STYLES = ['italic', 'bold', 'underline', 'strikethrough']; const SHORTCUT_KEYS = ['I', 'B', 'U', '5']; // italic, bold, underline, strikethrough @@ -21,7 +23,7 @@ describe('select formatting buttons when selection has style applied', function return $formattingButton.parent().hasClass('selected'); }; - var selectLine = function (lineNumber, offsetStart, offsetEnd) { + const selectLine = function (lineNumber, offsetStart, offsetEnd) { const inner$ = helper.padInner$; const $line = inner$('div').eq(lineNumber); helper.selectLines($line, $line, offsetStart, offsetEnd); @@ -58,7 +60,7 @@ describe('select formatting buttons when selection has style applied', function applyStyleOnLineOnFullLineAndRemoveSelection(line, style, placeCaretOnLine, cb); }; - var applyStyleOnLineOnFullLineAndRemoveSelection = function (line, style, selectTarget, cb) { + const applyStyleOnLineOnFullLineAndRemoveSelection = function (line, style, selectTarget, cb) { // see if line html has changed const inner$ = helper.padInner$; const oldLineHTML = inner$.find('div')[line]; @@ -80,7 +82,6 @@ describe('select formatting buttons when selection has style applied', function const pressFormattingShortcutOnSelection = function (key) { const inner$ = helper.padInner$; - const chrome$ = helper.padChrome$; // get the first text element out of the inner iframe const $firstTextElement = inner$('div').first(); @@ -88,7 +89,7 @@ describe('select formatting buttons when selection has style applied', function // select this text element $firstTextElement.sendkeys('{selectall}'); - const e = inner$.Event(helper.evtType); + const e = new inner$.Event(helper.evtType); e.ctrlKey = true; // Control key e.which = key.charCodeAt(0); // I, U, B, 5 inner$('#innerdocbody').trigger(e); diff --git a/tests/frontend/specs/strikethrough.js b/tests/frontend/specs/strikethrough.js index d8feae3be..9731ec75c 100644 --- a/tests/frontend/specs/strikethrough.js +++ b/tests/frontend/specs/strikethrough.js @@ -1,3 +1,5 @@ +'use strict'; + describe('strikethrough button', function () { // create a new pad before each test run beforeEach(function (cb) { @@ -19,7 +21,7 @@ describe('strikethrough button', function () { const $strikethroughButton = chrome$('.buttonicon-strikethrough'); $strikethroughButton.click(); - // ace creates a new dom element when you press a button, so just get the first text element again + // ace creates a new dom element when you press a button, just get the first text element again const $newFirstTextElement = inner$('div').first(); // is there a element now? diff --git a/tests/frontend/specs/timeslider.js b/tests/frontend/specs/timeslider.js index bea7932df..10f94b3cb 100644 --- a/tests/frontend/specs/timeslider.js +++ b/tests/frontend/specs/timeslider.js @@ -1,3 +1,5 @@ +'use strict'; + // deactivated, we need a nice way to get the timeslider, this is ugly xdescribe('timeslider button takes you to the timeslider of a pad', function () { beforeEach(function (cb) { @@ -12,7 +14,6 @@ xdescribe('timeslider button takes you to the timeslider of a pad', function () // get the first text element inside the editable space const $firstTextElement = inner$('div span').first(); const originalValue = $firstTextElement.text(); // get the original value - const newValue = `Testing${originalValue}`; $firstTextElement.sendkeys('Testing'); // send line 1 to the pad const modifiedValue = $firstTextElement.text(); // get the modified value diff --git a/tests/frontend/specs/timeslider_labels.js b/tests/frontend/specs/timeslider_labels.js index c7a4aca5a..dd418d976 100644 --- a/tests/frontend/specs/timeslider_labels.js +++ b/tests/frontend/specs/timeslider_labels.js @@ -1,3 +1,5 @@ +'use strict'; + describe('timeslider', function () { // create a new pad before each test run beforeEach(function (cb) { @@ -7,7 +9,7 @@ describe('timeslider', function () { /** * @todo test authorsList */ - it("Shows a date and time in the timeslider and make sure it doesn't include NaN", async function () { + it("Shows a date/time in the timeslider and make sure it doesn't include NaN", async function () { // make some changes to produce 3 revisions const revs = 3; diff --git a/tests/frontend/specs/timeslider_numeric_padID.js b/tests/frontend/specs/timeslider_numeric_padID.js index 53eb4a29c..4d05f95b3 100644 --- a/tests/frontend/specs/timeslider_numeric_padID.js +++ b/tests/frontend/specs/timeslider_numeric_padID.js @@ -1,3 +1,5 @@ +'use strict'; + describe('timeslider', function () { const padId = 735773577357 + (Math.round(Math.random() * 1000)); diff --git a/tests/frontend/specs/timeslider_revisions.js b/tests/frontend/specs/timeslider_revisions.js index fbfbb3615..2f5cc170a 100644 --- a/tests/frontend/specs/timeslider_revisions.js +++ b/tests/frontend/specs/timeslider_revisions.js @@ -1,3 +1,5 @@ +'use strict'; + describe('timeslider', function () { // create a new pad before each test run beforeEach(function (cb) { @@ -23,7 +25,8 @@ describe('timeslider', function () { setTimeout(() => { // go to timeslider - $('#iframe-container iframe').attr('src', `${$('#iframe-container iframe').attr('src')}/timeslider`); + $('#iframe-container iframe').attr('src', + `${$('#iframe-container iframe').attr('src')}/timeslider`); setTimeout(() => { const timeslider$ = $('#iframe-container iframe')[0].contentWindow.$; @@ -66,7 +69,6 @@ describe('timeslider', function () { // Disabled as jquery trigger no longer works properly xit('changes the url when clicking on the timeslider', function (done) { const inner$ = helper.padInner$; - const chrome$ = helper.padChrome$; // make some changes to produce 7 revisions const timePerRev = 1000; @@ -81,13 +83,13 @@ describe('timeslider', function () { setTimeout(() => { // go to timeslider - $('#iframe-container iframe').attr('src', `${$('#iframe-container iframe').attr('src')}/timeslider`); + $('#iframe-container iframe').attr('src', + `${$('#iframe-container iframe').attr('src')}/timeslider`); setTimeout(() => { const timeslider$ = $('#iframe-container iframe')[0].contentWindow.$; const $sliderBar = timeslider$('#ui-slider-bar'); - const latestContents = timeslider$('#innerdocbody').text(); const oldUrl = $('#iframe-container iframe')[0].contentWindow.location.hash; // Click somewhere on the timeslider @@ -96,20 +98,23 @@ describe('timeslider', function () { e.clientY = e.pageY = 60; $sliderBar.trigger(e); - helper.waitFor(() => $('#iframe-container iframe')[0].contentWindow.location.hash != oldUrl, 6000).always(() => { - expect($('#iframe-container iframe')[0].contentWindow.location.hash).not.to.eql(oldUrl); - done(); - }); + helper.waitFor( + () => $('#iframe-container iframe')[0].contentWindow.location.hash !== oldUrl, 6000) + .always(() => { + expect( + $('#iframe-container iframe')[0].contentWindow.location.hash + ).not.to.eql(oldUrl); + done(); + }); }, 6000); }, revs * timePerRev); }); it('jumps to a revision given in the url', function (done) { const inner$ = helper.padInner$; - const chrome$ = helper.padChrome$; this.timeout(40000); // wait for the text to be loaded - helper.waitFor(() => inner$('body').text().length != 0, 10000).always(() => { + helper.waitFor(() => inner$('body').text().length !== 0, 10000).always(() => { const newLines = inner$('body div').length; const oldLength = inner$('body').text().length + newLines / 2; expect(oldLength).to.not.eql(0); @@ -120,22 +125,25 @@ describe('timeslider', function () { helper.waitFor(() => { // newLines takes the new lines into account which are strippen when using // inner$('body').text(), one
              is used for one line in ACE. - const lenOkay = inner$('body').text().length + newLines / 2 != oldLength; + const lenOkay = inner$('body').text().length + newLines / 2 !== oldLength; // this waits for the color to be added to our , which means that the revision // was accepted by the server. - const colorOkay = inner$('span').first().attr('class').indexOf('author-') == 0; + const colorOkay = inner$('span').first().attr('class').indexOf('author-') === 0; return lenOkay && colorOkay; }, 10000).always(() => { // go to timeslider with a specific revision set - $('#iframe-container iframe').attr('src', `${$('#iframe-container iframe').attr('src')}/timeslider#0`); + $('#iframe-container iframe').attr('src', + `${$('#iframe-container iframe').attr('src')}/timeslider#0`); // wait for the timeslider to be loaded helper.waitFor(() => { try { timeslider$ = $('#iframe-container iframe')[0].contentWindow.$; - } catch (e) {} + } catch (e) { + // Empty catch block <3 + } if (timeslider$) { - return timeslider$('#innerdocbody').text().length == oldLength; + return timeslider$('#innerdocbody').text().length === oldLength; } }, 10000).always(() => { expect(timeslider$('#innerdocbody').text().length).to.eql(oldLength); @@ -147,24 +155,26 @@ describe('timeslider', function () { it('checks the export url', function (done) { const inner$ = helper.padInner$; - const chrome$ = helper.padChrome$; this.timeout(11000); inner$('div').first().sendkeys('a'); setTimeout(() => { // go to timeslider - $('#iframe-container iframe').attr('src', `${$('#iframe-container iframe').attr('src')}/timeslider#0`); + $('#iframe-container iframe').attr('src', + `${$('#iframe-container iframe').attr('src')}/timeslider#0`); let timeslider$; let exportLink; helper.waitFor(() => { try { timeslider$ = $('#iframe-container iframe')[0].contentWindow.$; - } catch (e) {} + } catch (e) { + // Empty catch block <3 + } if (!timeslider$) return false; exportLink = timeslider$('#exportplaina').attr('href'); if (!exportLink) return false; - return exportLink.substr(exportLink.length - 12) == '0/export/txt'; + return exportLink.substr(exportLink.length - 12) === '0/export/txt'; }, 6000).always(() => { expect(exportLink.substr(exportLink.length - 12)).to.eql('0/export/txt'); done(); diff --git a/tests/frontend/specs/undo.js b/tests/frontend/specs/undo.js index 0c94f2230..0daa282fc 100644 --- a/tests/frontend/specs/undo.js +++ b/tests/frontend/specs/undo.js @@ -1,3 +1,5 @@ +'use strict'; + describe('undo button', function () { beforeEach(function (cb) { helper.newPad(cb); // creates a new pad @@ -30,7 +32,6 @@ describe('undo button', function () { it('undo some typing using a keypress', function (done) { const inner$ = helper.padInner$; - const chrome$ = helper.padChrome$; // get the first text element inside the editable space const $firstTextElement = inner$('div span').first(); @@ -40,7 +41,7 @@ describe('undo button', function () { const modifiedValue = $firstTextElement.text(); // get the modified value expect(modifiedValue).not.to.be(originalValue); // expect the value to change - const e = inner$.Event(helper.evtType); + const e = new inner$.Event(helper.evtType); e.ctrlKey = true; // Control key e.which = 90; // z inner$('#innerdocbody').trigger(e); diff --git a/tests/frontend/specs/unordered_list.js b/tests/frontend/specs/unordered_list.js index 4cbdabfac..22d1a6fe2 100644 --- a/tests/frontend/specs/unordered_list.js +++ b/tests/frontend/specs/unordered_list.js @@ -1,3 +1,5 @@ +'use strict'; + describe('assign unordered list', function () { // create a new pad before each test run beforeEach(function (cb) { @@ -130,7 +132,8 @@ describe('Pressing Tab in an UL increases and decreases indentation', function ( }); }); -describe('Pressing indent/outdent button in an UL increases and decreases indentation and bullet / ol formatting', function () { +describe('Pressing indent/outdent button in an UL increases and decreases indentation ' + + 'and bullet / ol formatting', function () { // create a new pad before each test run beforeEach(function (cb) { helper.newPad(cb); diff --git a/tests/frontend/specs/xxauto_reconnect.js b/tests/frontend/specs/xxauto_reconnect.js index 574616ce5..d92936563 100644 --- a/tests/frontend/specs/xxauto_reconnect.js +++ b/tests/frontend/specs/xxauto_reconnect.js @@ -1,3 +1,5 @@ +'use strict'; + describe('Automatic pad reload on Force Reconnect message', function () { let padId, $originalPadFrame; diff --git a/tests/frontend/travis/remote_runner.js b/tests/frontend/travis/remote_runner.js index 70c850ca8..ba0e7be0c 100644 --- a/tests/frontend/travis/remote_runner.js +++ b/tests/frontend/travis/remote_runner.js @@ -1,17 +1,19 @@ -var srcFolder = '../../../src/node_modules/'; -var wd = require(`${srcFolder}wd`); -var async = require(`${srcFolder}async`); +'use strict'; -var config = { +const wd = require('ep_etherpad-lite/node_modules/wd'); +const async = require('ep_etherpad-lite/node_modules/async'); + +const config = { host: 'ondemand.saucelabs.com', port: 80, username: process.env.SAUCE_USER, accessKey: process.env.SAUCE_ACCESS_KEY, }; -var allTestsPassed = true; +let allTestsPassed = true; // overwrite the default exit code -// in case not all worker can be run (due to saucelabs limits), `queue.drain` below will not be called +// in case not all worker can be run (due to saucelabs limits), +// `queue.drain` below will not be called // and the script would silently exit with error code 0 process.exitCode = 2; process.on('exit', (code) => { @@ -20,13 +22,18 @@ process.on('exit', (code) => { } }); -var sauceTestWorker = async.queue((testSettings, callback) => { - const browser = wd.promiseChainRemote(config.host, config.port, config.username, config.accessKey); - const name = `${process.env.GIT_HASH} - ${testSettings.browserName} ${testSettings.version}, ${testSettings.platform}`; +const sauceTestWorker = async.queue((testSettings, callback) => { + const browser = wd.promiseChainRemote( + config.host, config.port, config.username, config.accessKey); + const name = + `${process.env.GIT_HASH} - ${testSettings.browserName} ` + + `${testSettings.version}, ${testSettings.platform}`; testSettings.name = name; testSettings.public = true; testSettings.build = process.env.GIT_HASH; - testSettings.extendedDebugging = true; // console.json can be downloaded via saucelabs, don't know how to print them into output of the tests + // console.json can be downloaded via saucelabs, + // don't know how to print them into output of the tests + testSettings.extendedDebugging = true; testSettings.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER; browser.init(testSettings).get('http://localhost:9001/tests/frontend/', () => { @@ -34,7 +41,7 @@ var sauceTestWorker = async.queue((testSettings, callback) => { console.log(`Remote sauce test '${name}' started! ${url}`); // tear down the test excecution - const stopSauce = function (success, timesup) { + const stopSauce = (success, timesup) => { clearInterval(getStatusInterval); clearTimeout(timeout); @@ -43,12 +50,15 @@ var sauceTestWorker = async.queue((testSettings, callback) => { allTestsPassed = false; } - // if stopSauce is called via timeout (in contrast to via getStatusInterval) than the log of up to the last + // if stopSauce is called via timeout + // (in contrast to via getStatusInterval) than the log of up to the last // five seconds may not be available here. It's an error anyway, so don't care about it. printLog(logIndex); if (timesup) { - console.log(`[${testSettings.browserName} ${testSettings.platform}${testSettings.version === '' ? '' : (` ${testSettings.version}`)}] \x1B[31mFAILED\x1B[39m allowed test duration exceeded`); + console.log(`[${testSettings.browserName} ${testSettings.platform}` + + `${testSettings.version === '' ? '' : (` ${testSettings.version}`)}]` + + ' \x1B[31mFAILED\x1B[39m allowed test duration exceeded'); } console.log(`Remote sauce test '${name}' finished! ${url}`); @@ -58,17 +68,19 @@ var sauceTestWorker = async.queue((testSettings, callback) => { /** * timeout if a test hangs or the job exceeds 14.5 minutes - * It's necessary because if travis kills the saucelabs session due to inactivity, we don't get any output - * @todo this should be configured in testSettings, see https://wiki.saucelabs.com/display/DOCS/Test+Configuration+Options#TestConfigurationOptions-Timeouts + * It's necessary because if travis kills the saucelabs session due to inactivity, + * we don't get any output + * @todo this should be configured in testSettings, see + * https://wiki.saucelabs.com/display/DOCS/Test+Configuration+Options#TestConfigurationOptions-Timeouts */ - var timeout = setTimeout(() => { + const timeout = setTimeout(() => { stopSauce(false, true); }, 870000); // travis timeout is 15 minutes, set this to a slightly lower value let knownConsoleText = ''; // how many characters of the log have been sent to travis let logIndex = 0; - var getStatusInterval = setInterval(() => { + const getStatusInterval = setInterval(() => { browser.eval("$('#console').text()", (err, consoleText) => { if (!consoleText || err) { return; @@ -76,9 +88,10 @@ var sauceTestWorker = async.queue((testSettings, callback) => { knownConsoleText = consoleText; if (knownConsoleText.indexOf('FINISHED') > 0) { - const match = knownConsoleText.match(/FINISHED.*([0-9]+) tests passed, ([0-9]+) tests failed/); + const match = knownConsoleText.match( + /FINISHED.*([0-9]+) tests passed, ([0-9]+) tests failed/); // finished without failures - if (match[2] && match[2] == '0') { + if (match[2] && match[2] === '0') { stopSauce(true); // finished but some tests did not return or some tests failed @@ -99,13 +112,17 @@ var sauceTestWorker = async.queue((testSettings, callback) => { * * @param {number} index offset from where to start */ - function printLog(index) { - let testResult = knownConsoleText.substring(index).replace(/\[red\]/g, '\x1B[31m').replace(/\[yellow\]/g, '\x1B[33m') + const printLog = (index) => { + let testResult = knownConsoleText.substring(index) + .replace(/\[red\]/g, '\x1B[31m').replace(/\[yellow\]/g, '\x1B[33m') .replace(/\[green\]/g, '\x1B[32m').replace(/\[clear\]/g, '\x1B[39m'); - testResult = testResult.split('\\n').map((line) => `[${testSettings.browserName} ${testSettings.platform}${testSettings.version === '' ? '' : (` ${testSettings.version}`)}] ${line}`).join('\n'); + testResult = testResult.split('\\n').map((line) => `[${testSettings.browserName} ` + + `${testSettings.platform}` + + `${testSettings.version === '' ? '' : (` ${testSettings.version}`)}]` + + `${line}`).join('\n'); console.log(testResult); - } + }; }); }, 6); // run 6 tests in parrallel diff --git a/tests/ratelimit/send_changesets.js b/tests/ratelimit/send_changesets.js index b0d994c8c..92af23e18 100644 --- a/tests/ratelimit/send_changesets.js +++ b/tests/ratelimit/send_changesets.js @@ -1,8 +1,12 @@ +'use strict'; + +let etherpad; try { - var etherpad = require('../../src/node_modules/etherpad-cli-client'); + etherpad = require('ep_etherpad-lite/node_modules/etherpad-cli-client'); // ugly } catch { - var etherpad = require('etherpad-cli-client'); + /* eslint-disable-next-line node/no-missing-require */ + etherpad = require('etherpad-cli-client'); // uses global } const pad = etherpad.connect(process.argv[2]); pad.on('connected', () => { @@ -18,7 +22,7 @@ pad.on('connected', () => { }); // in case of disconnect exit code 1 pad.on('message', (message) => { - if (message.disconnect == 'rateLimited') { + if (message.disconnect === 'rateLimited') { process.exit(1); } }); From 3e910b990568eb7afe33e75511b0771c5a161340 Mon Sep 17 00:00:00 2001 From: John McLear Date: Mon, 1 Feb 2021 22:45:51 +0000 Subject: [PATCH 131/153] stale: remove convert.js as no one runs old Etherpad --- bin/convert.js | 391 ------------------------------------------------- 1 file changed, 391 deletions(-) delete mode 100644 bin/convert.js diff --git a/bin/convert.js b/bin/convert.js deleted file mode 100644 index 47f8b2d27..000000000 --- a/bin/convert.js +++ /dev/null @@ -1,391 +0,0 @@ -const startTime = Date.now(); -const fs = require('fs'); -const ueberDB = require('../src/node_modules/ueberdb2'); -const mysql = require('../src/node_modules/ueberdb2/node_modules/mysql'); -const async = require('../src/node_modules/async'); -const Changeset = require('ep_etherpad-lite/static/js/Changeset'); -const randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString; -const AttributePool = require('ep_etherpad-lite/static/js/AttributePool'); - -const settingsFile = process.argv[2]; -const sqlOutputFile = process.argv[3]; - -// stop if the settings file is not set -if (!settingsFile || !sqlOutputFile) { - console.error('Use: node convert.js $SETTINGSFILE $SQLOUTPUT'); - process.exit(1); -} - -log('read settings file...'); -// read the settings file and parse the json -const settings = JSON.parse(fs.readFileSync(settingsFile, 'utf8')); -log('done'); - -log('open output file...'); -const sqlOutput = fs.openSync(sqlOutputFile, 'w'); -const sql = 'SET CHARACTER SET UTF8;\n' + - 'CREATE TABLE IF NOT EXISTS `store` ( \n' + - '`key` VARCHAR( 100 ) NOT NULL , \n' + - '`value` LONGTEXT NOT NULL , \n' + - 'PRIMARY KEY ( `key` ) \n' + - ') ENGINE = INNODB;\n' + - 'START TRANSACTION;\n\n'; -fs.writeSync(sqlOutput, sql); -log('done'); - -const etherpadDB = mysql.createConnection({ - host: settings.etherpadDB.host, - user: settings.etherpadDB.user, - password: settings.etherpadDB.password, - database: settings.etherpadDB.database, - port: settings.etherpadDB.port, -}); - -// get the timestamp once -const timestamp = Date.now(); - -let padIDs; - -async.series([ - // get all padids out of the database... - function (callback) { - log('get all padIds out of the database...'); - - etherpadDB.query('SELECT ID FROM PAD_META', [], (err, _padIDs) => { - padIDs = _padIDs; - callback(err); - }); - }, - function (callback) { - log('done'); - - // create a queue with a concurrency 100 - const queue = async.queue((padId, callback) => { - convertPad(padId, (err) => { - incrementPadStats(); - callback(err); - }); - }, 100); - - // set the step callback as the queue callback - queue.drain = callback; - - // add the padids to the worker queue - for (let i = 0, length = padIDs.length; i < length; i++) { - queue.push(padIDs[i].ID); - } - }, -], (err) => { - if (err) throw err; - - // write the groups - let sql = ''; - for (const proID in proID2groupID) { - const groupID = proID2groupID[proID]; - const subdomain = proID2subdomain[proID]; - - sql += `REPLACE INTO store VALUES (${etherpadDB.escape(`group:${groupID}`)}, ${etherpadDB.escape(JSON.stringify(groups[groupID]))});\n`; - sql += `REPLACE INTO store VALUES (${etherpadDB.escape(`mapper2group:subdomain:${subdomain}`)}, ${etherpadDB.escape(groupID)});\n`; - } - - // close transaction - sql += 'COMMIT;'; - - // end the sql file - fs.writeSync(sqlOutput, sql, undefined, 'utf-8'); - fs.closeSync(sqlOutput); - - log('finished.'); - process.exit(0); -}); - -function log(str) { - console.log(`${(Date.now() - startTime) / 1000}\t${str}`); -} - -let padsDone = 0; - -function incrementPadStats() { - padsDone++; - - if (padsDone % 100 == 0) { - const averageTime = Math.round(padsDone / ((Date.now() - startTime) / 1000)); - log(`${padsDone}/${padIDs.length}\t${averageTime} pad/s`); - } -} - -var proID2groupID = {}; -var proID2subdomain = {}; -var groups = {}; - -function convertPad(padId, callback) { - const changesets = []; - const changesetsMeta = []; - const chatMessages = []; - const authors = []; - let apool; - let subdomain; - let padmeta; - - async.series([ - // get all needed db values - function (callback) { - async.parallel([ - // get the pad revisions - function (callback) { - const sql = 'SELECT * FROM `PAD_CHAT_TEXT` WHERE NUMID = (SELECT `NUMID` FROM `PAD_CHAT_META` WHERE ID=?)'; - - etherpadDB.query(sql, [padId], (err, results) => { - if (!err) { - try { - // parse the pages - for (let i = 0, length = results.length; i < length; i++) { - parsePage(chatMessages, results[i].PAGESTART, results[i].OFFSETS, results[i].DATA, true); - } - } catch (e) { err = e; } - } - - callback(err); - }); - }, - // get the chat entries - function (callback) { - const sql = 'SELECT * FROM `PAD_REVS_TEXT` WHERE NUMID = (SELECT `NUMID` FROM `PAD_REVS_META` WHERE ID=?)'; - - etherpadDB.query(sql, [padId], (err, results) => { - if (!err) { - try { - // parse the pages - for (let i = 0, length = results.length; i < length; i++) { - parsePage(changesets, results[i].PAGESTART, results[i].OFFSETS, results[i].DATA, false); - } - } catch (e) { err = e; } - } - - callback(err); - }); - }, - // get the pad revisions meta data - function (callback) { - const sql = 'SELECT * FROM `PAD_REVMETA_TEXT` WHERE NUMID = (SELECT `NUMID` FROM `PAD_REVMETA_META` WHERE ID=?)'; - - etherpadDB.query(sql, [padId], (err, results) => { - if (!err) { - try { - // parse the pages - for (let i = 0, length = results.length; i < length; i++) { - parsePage(changesetsMeta, results[i].PAGESTART, results[i].OFFSETS, results[i].DATA, true); - } - } catch (e) { err = e; } - } - - callback(err); - }); - }, - // get the attribute pool of this pad - function (callback) { - const sql = 'SELECT `JSON` FROM `PAD_APOOL` WHERE `ID` = ?'; - - etherpadDB.query(sql, [padId], (err, results) => { - if (!err) { - try { - apool = JSON.parse(results[0].JSON).x; - } catch (e) { err = e; } - } - - callback(err); - }); - }, - // get the authors informations - function (callback) { - const sql = 'SELECT * FROM `PAD_AUTHORS_TEXT` WHERE NUMID = (SELECT `NUMID` FROM `PAD_AUTHORS_META` WHERE ID=?)'; - - etherpadDB.query(sql, [padId], (err, results) => { - if (!err) { - try { - // parse the pages - for (let i = 0, length = results.length; i < length; i++) { - parsePage(authors, results[i].PAGESTART, results[i].OFFSETS, results[i].DATA, true); - } - } catch (e) { err = e; } - } - - callback(err); - }); - }, - // get the pad information - function (callback) { - const sql = 'SELECT JSON FROM `PAD_META` WHERE ID=?'; - - etherpadDB.query(sql, [padId], (err, results) => { - if (!err) { - try { - padmeta = JSON.parse(results[0].JSON).x; - } catch (e) { err = e; } - } - - callback(err); - }); - }, - // get the subdomain - function (callback) { - // skip if this is no proPad - if (padId.indexOf('$') == -1) { - callback(); - return; - } - - // get the proID out of this padID - const proID = padId.split('$')[0]; - - const sql = 'SELECT subDomain FROM pro_domains WHERE ID = ?'; - - etherpadDB.query(sql, [proID], (err, results) => { - if (!err) { - subdomain = results[0].subDomain; - } - - callback(err); - }); - }, - ], callback); - }, - function (callback) { - // saves all values that should be written to the database - const values = {}; - - // this is a pro pad, let's convert it to a group pad - if (padId.indexOf('$') != -1) { - const padIdParts = padId.split('$'); - const proID = padIdParts[0]; - const padName = padIdParts[1]; - - let groupID; - - // this proID is not converted so far, do it - if (proID2groupID[proID] == null) { - groupID = `g.${randomString(16)}`; - - // create the mappers for this new group - proID2groupID[proID] = groupID; - proID2subdomain[proID] = subdomain; - groups[groupID] = {pads: {}}; - } - - // use the generated groupID; - groupID = proID2groupID[proID]; - - // rename the pad - padId = `${groupID}$${padName}`; - - // set the value for this pad in the group - groups[groupID].pads[padId] = 1; - } - - try { - const newAuthorIDs = {}; - const oldName2newName = {}; - - // replace the authors with generated authors - // we need to do that cause where the original etherpad saves pad local authors, the new (lite) etherpad uses them global - for (var i in apool.numToAttrib) { - var key = apool.numToAttrib[i][0]; - const value = apool.numToAttrib[i][1]; - - // skip non authors and anonymous authors - if (key != 'author' || value == '') continue; - - // generate new author values - const authorID = `a.${randomString(16)}`; - const authorColorID = authors[i].colorId || Math.floor(Math.random() * (exports.getColorPalette().length)); - const authorName = authors[i].name || null; - - // overwrite the authorID of the attribute pool - apool.numToAttrib[i][1] = authorID; - - // write the author to the database - values[`globalAuthor:${authorID}`] = {colorId: authorColorID, name: authorName, timestamp}; - - // save in mappers - newAuthorIDs[i] = authorID; - oldName2newName[value] = authorID; - } - - // save all revisions - for (var i = 0; i < changesets.length; i++) { - values[`pad:${padId}:revs:${i}`] = {changeset: changesets[i], - meta: { - author: newAuthorIDs[changesetsMeta[i].a], - timestamp: changesetsMeta[i].t, - atext: changesetsMeta[i].atext || undefined, - }}; - } - - // save all chat messages - for (var i = 0; i < chatMessages.length; i++) { - values[`pad:${padId}:chat:${i}`] = {text: chatMessages[i].lineText, - userId: oldName2newName[chatMessages[i].userId], - time: chatMessages[i].time}; - } - - // generate the latest atext - const fullAPool = (new AttributePool()).fromJsonable(apool); - const keyRev = Math.floor(padmeta.head / padmeta.keyRevInterval) * padmeta.keyRevInterval; - let atext = changesetsMeta[keyRev].atext; - let curRev = keyRev; - while (curRev < padmeta.head) { - curRev++; - const changeset = changesets[curRev]; - atext = Changeset.applyToAText(changeset, atext, fullAPool); - } - - values[`pad:${padId}`] = {atext, - pool: apool, - head: padmeta.head, - chatHead: padmeta.numChatMessages}; - } catch (e) { - console.error(`Error while converting pad ${padId}, pad skipped`); - console.error(e.stack ? e.stack : JSON.stringify(e)); - callback(); - return; - } - - let sql = ''; - for (var key in values) { - sql += `REPLACE INTO store VALUES (${etherpadDB.escape(key)}, ${etherpadDB.escape(JSON.stringify(values[key]))});\n`; - } - - fs.writeSync(sqlOutput, sql, undefined, 'utf-8'); - callback(); - }, - ], callback); -} - -/** - * This parses a Page like Etherpad uses them in the databases - * The offsets describes the length of a unit in the page, the data are - * all values behind each other - */ -function parsePage(array, pageStart, offsets, data, json) { - let start = 0; - const lengths = offsets.split(','); - - for (let i = 0; i < lengths.length; i++) { - let unitLength = lengths[i]; - - // skip empty units - if (unitLength == '') continue; - - // parse the number - unitLength = Number(unitLength); - - // cut the unit out of data - const unit = data.substr(start, unitLength); - - // put it into the array - array[pageStart + i] = json ? JSON.parse(unit) : unit; - - // update start - start += unitLength; - } -} From 1bc52f49134ffffadde61264a6f2d3cbb001af37 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sat, 30 Jan 2021 20:29:49 -0500 Subject: [PATCH 132/153] hooks: Remove unnecessary `callAllStr()` function --- src/static/js/linestylefilter.js | 7 ++----- src/static/js/pluginfw/hooks.js | 12 ------------ 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/src/static/js/linestylefilter.js b/src/static/js/linestylefilter.js index f70eefc23..254168990 100644 --- a/src/static/js/linestylefilter.js +++ b/src/static/js/linestylefilter.js @@ -93,11 +93,8 @@ linestylefilter.getLineStyleFilter = (lineLength, aline, textAndClassFunc, apool } else if (linestylefilter.ATTRIB_CLASSES[key]) { classes += ` ${linestylefilter.ATTRIB_CLASSES[key]}`; } else { - classes += hooks.callAllStr('aceAttribsToClasses', { - linestylefilter, - key, - value, - }, ' ', ' ', ''); + const results = hooks.callAll('aceAttribsToClasses', {linestylefilter, key, value}); + classes += ` ${results.join(' ')}`; } } } diff --git a/src/static/js/pluginfw/hooks.js b/src/static/js/pluginfw/hooks.js index e61079eb6..e0b733e5d 100644 --- a/src/static/js/pluginfw/hooks.js +++ b/src/static/js/pluginfw/hooks.js @@ -386,18 +386,6 @@ exports.aCallFirst = (hook_name, args, cb, predicate) => { } }; -exports.callAllStr = (hook_name, args, sep, pre, post) => { - if (sep === undefined) sep = ''; - if (pre === undefined) pre = ''; - if (post === undefined) post = ''; - const newCallhooks = []; - const callhooks = exports.callAll(hook_name, args); - for (let i = 0, ii = callhooks.length; i < ii; i++) { - newCallhooks[i] = pre + callhooks[i] + post; - } - return newCallhooks.join(sep || ''); -}; - exports.exportedForTestingOnly = { callHookFnAsync, callHookFnSync, From 47f0a7dacfa811c4c69605c207f4e353c96b1a0a Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 31 Jan 2021 15:23:44 -0500 Subject: [PATCH 133/153] lint: Fix more ESLint errors --- src/static/js/pluginfw/hooks.js | 38 +++++++++++++++++--------------- tests/backend/specs/hooks.js | 17 +++++--------- tests/backend/specs/webaccess.js | 10 ++++----- 3 files changed, 30 insertions(+), 35 deletions(-) diff --git a/src/static/js/pluginfw/hooks.js b/src/static/js/pluginfw/hooks.js index e0b733e5d..7ce71ae7b 100644 --- a/src/static/js/pluginfw/hooks.js +++ b/src/static/js/pluginfw/hooks.js @@ -1,6 +1,5 @@ 'use strict'; -const _ = require('underscore'); const pluginDefs = require('./plugin_defs'); // Maps the name of a server-side hook to a string explaining the deprecation @@ -24,9 +23,12 @@ const checkDeprecation = (hook) => { deprecationWarned[hook.hook_fn_name] = true; }; +// Flattens the array one level. +const flatten1 = (array) => array.reduce((a, b) => a.concat(b), []); + exports.bubbleExceptions = true; -const hookCallWrapper = (hook, hook_name, args, cb) => { +const hookCallWrapper = (hook, hookName, args, cb) => { if (cb === undefined) cb = (x) => x; checkDeprecation(hook); @@ -36,7 +38,7 @@ const hookCallWrapper = (hook, hook_name, args, cb) => { if (x === undefined) return []; return x; }; - const normalizedhook = () => normalize(hook.hook_fn(hook_name, args, (x) => cb(normalize(x)))); + const normalizedhook = () => normalize(hook.hook_fn(hookName, args, (x) => cb(normalize(x)))); if (exports.bubbleExceptions) { return normalizedhook(); @@ -44,7 +46,7 @@ const hookCallWrapper = (hook, hook_name, args, cb) => { try { return normalizedhook(); } catch (ex) { - console.error([hook_name, hook.part.full_name, ex.stack || ex]); + console.error([hookName, hook.part.full_name, ex.stack || ex]); } } }; @@ -204,12 +206,12 @@ const callHookFnSync = (hook, context) => { exports.callAll = (hookName, context) => { if (context == null) context = {}; const hooks = pluginDefs.hooks[hookName] || []; - return _.flatten(hooks.map((hook) => { + return flatten1(hooks.map((hook) => { const ret = callHookFnSync(hook, context); // `undefined` (but not `null`!) is treated the same as []. if (ret === undefined) return []; return ret; - }), 1); + })); }; // Calls the hook function asynchronously and returns a Promise that either resolves to the hook @@ -349,26 +351,26 @@ exports.aCallAll = async (hookName, context, cb) => { let resultsPromise = Promise.all(hooks.map((hook) => callHookFnAsync(hook, context) // `undefined` (but not `null`!) is treated the same as []. .then((result) => (result === undefined) ? [] : result))) - .then((results) => _.flatten(results, 1)); + .then(flatten1); if (cb != null) resultsPromise = resultsPromise.then((val) => cb(null, val), cb); return await resultsPromise; }; -exports.callFirst = (hook_name, args) => { +exports.callFirst = (hookName, args) => { if (!args) args = {}; - if (pluginDefs.hooks[hook_name] === undefined) return []; - return exports.syncMapFirst(pluginDefs.hooks[hook_name], - (hook) => hookCallWrapper(hook, hook_name, args)); + if (pluginDefs.hooks[hookName] === undefined) return []; + return exports.syncMapFirst(pluginDefs.hooks[hookName], + (hook) => hookCallWrapper(hook, hookName, args)); }; -const aCallFirst = (hook_name, args, cb, predicate) => { +const aCallFirst = (hookName, args, cb, predicate) => { if (!args) args = {}; if (!cb) cb = () => {}; - if (pluginDefs.hooks[hook_name] === undefined) return cb(null, []); + if (pluginDefs.hooks[hookName] === undefined) return cb(null, []); exports.mapFirst( - pluginDefs.hooks[hook_name], + pluginDefs.hooks[hookName], (hook, cb) => { - hookCallWrapper(hook, hook_name, args, (res) => { cb(null, res); }); + hookCallWrapper(hook, hookName, args, (res) => { cb(null, res); }); }, cb, predicate @@ -376,13 +378,13 @@ const aCallFirst = (hook_name, args, cb, predicate) => { }; /* return a Promise if cb is not supplied */ -exports.aCallFirst = (hook_name, args, cb, predicate) => { +exports.aCallFirst = (hookName, args, cb, predicate) => { if (cb === undefined) { return new Promise((resolve, reject) => { - aCallFirst(hook_name, args, (err, res) => err ? reject(err) : resolve(res), predicate); + aCallFirst(hookName, args, (err, res) => err ? reject(err) : resolve(res), predicate); }); } else { - return aCallFirst(hook_name, args, cb, predicate); + return aCallFirst(hookName, args, cb, predicate); } }; diff --git a/tests/backend/specs/hooks.js b/tests/backend/specs/hooks.js index 0e0f8075f..327b9bd1c 100644 --- a/tests/backend/specs/hooks.js +++ b/tests/backend/specs/hooks.js @@ -1,14 +1,9 @@ -/* global __dirname, __filename, afterEach, beforeEach, describe, it, process, require */ - -function m(mod) { return `${__dirname}/../../../src/${mod}`; } +'use strict'; const assert = require('assert').strict; -const common = require('../common'); -const hooks = require(m('static/js/pluginfw/hooks')); -const plugins = require(m('static/js/pluginfw/plugin_defs')); -const sinon = require(m('node_modules/sinon')); - -const logger = common.logger; +const hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks'); +const plugins = require('ep_etherpad-lite/static/js/pluginfw/plugin_defs'); +const sinon = require('ep_etherpad-lite/node_modules/sinon'); describe(__filename, function () { const hookName = 'testHook'; @@ -203,7 +198,7 @@ describe(__filename, function () { // Test various ways a hook might attempt to settle twice. (Examples: call the callback a second // time, or call the callback and then return a value.) describe('bad hook function behavior (double settle)', function () { - beforeEach(function () { + beforeEach(async function () { sinon.stub(console, 'error'); }); @@ -558,7 +553,7 @@ describe(__filename, function () { // Test various ways a hook might attempt to settle twice. (Examples: call the callback a second // time, or call the callback and then return a value.) describe('bad hook function behavior (double settle)', function () { - beforeEach(function () { + beforeEach(async function () { sinon.stub(console, 'error'); }); diff --git a/tests/backend/specs/webaccess.js b/tests/backend/specs/webaccess.js index a21cc73a8..3b140c46c 100644 --- a/tests/backend/specs/webaccess.js +++ b/tests/backend/specs/webaccess.js @@ -1,11 +1,9 @@ -/* global __dirname, __filename, Buffer, afterEach, before, beforeEach, describe, it, require */ - -function m(mod) { return `${__dirname}/../../../src/${mod}`; } +'use strict'; const assert = require('assert').strict; const common = require('../common'); -const plugins = require(m('static/js/pluginfw/plugin_defs')); -const settings = require(m('node/utils/Settings')); +const plugins = require('ep_etherpad-lite/static/js/pluginfw/plugin_defs'); +const settings = require('ep_etherpad-lite/node/utils/Settings'); describe(__filename, function () { let agent; @@ -402,7 +400,7 @@ describe(__filename, function () { }; const handlers = {}; - beforeEach(function () { + beforeEach(async function () { failHookNames.forEach((hookName) => { const handler = new Handler(hookName); handlers[hookName] = handler; From ba02e700201f4d94c233c1b2211414ee978cdfa5 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 1 Feb 2021 23:55:16 -0500 Subject: [PATCH 134/153] tests: Make the fake webaccess hook registrations look more real The additional properties will be needed once `aCallAll()` is upgraded to use `callHookFnAsync()`. --- tests/backend/specs/webaccess.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/tests/backend/specs/webaccess.js b/tests/backend/specs/webaccess.js index 3b140c46c..b82a5f017 100644 --- a/tests/backend/specs/webaccess.js +++ b/tests/backend/specs/webaccess.js @@ -10,6 +10,13 @@ describe(__filename, function () { const backups = {}; const authHookNames = ['preAuthorize', 'authenticate', 'authorize']; const failHookNames = ['preAuthzFailure', 'authnFailure', 'authzFailure', 'authFailure']; + const makeHook = (hookName, hookFn) => ({ + hook_fn: hookFn, + hook_fn_name: `fake_plugin/${hookName}`, + hook_name: hookName, + part: {plugin: 'fake_plugin'}, + }); + before(async function () { agent = await common.init(); }); beforeEach(async function () { backups.hooks = {}; @@ -139,7 +146,10 @@ describe(__filename, function () { const h0 = new Handler(hookName, '_0'); const h1 = new Handler(hookName, '_1'); handlers[hookName] = [h0, h1]; - plugins.hooks[hookName] = [{hook_fn: h0.handle.bind(h0)}, {hook_fn: h1.handle.bind(h1)}]; + plugins.hooks[hookName] = [ + makeHook(hookName, h0.handle.bind(h0)), + makeHook(hookName, h1.handle.bind(h1)), + ]; } }); @@ -195,7 +205,7 @@ describe(__filename, function () { it('runs preAuthzFailure hook when access is denied', async function () { handlers.preAuthorize[0].innerHandle = () => [false]; let called = false; - plugins.hooks.preAuthzFailure = [{hook_fn: (hookName, {req, res}, cb) => { + plugins.hooks.preAuthzFailure = [makeHook('preAuthzFailure', (hookName, {req, res}, cb) => { assert.equal(hookName, 'preAuthzFailure'); assert(req != null); assert(res != null); @@ -203,7 +213,7 @@ describe(__filename, function () { called = true; res.status(200).send('injected'); return cb([true]); - }}]; + })]; await agent.get('/admin/').auth('admin', 'admin-password').expect(200, 'injected'); assert(called); }); @@ -404,7 +414,7 @@ describe(__filename, function () { failHookNames.forEach((hookName) => { const handler = new Handler(hookName); handlers[hookName] = handler; - plugins.hooks[hookName] = [{hook_fn: handler.handle.bind(handler)}]; + plugins.hooks[hookName] = [makeHook(hookName, handler.handle.bind(handler))]; }); settings.requireAuthentication = true; settings.requireAuthorization = true; From 6b42dabf6c3e3e72dd4c5571c20cd2b418fba2c8 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 31 Jan 2021 15:28:06 -0500 Subject: [PATCH 135/153] hooks: Delete unused `bubbleExceptions` setting --- src/static/js/pluginfw/hooks.js | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/static/js/pluginfw/hooks.js b/src/static/js/pluginfw/hooks.js index 7ce71ae7b..489e6d6dc 100644 --- a/src/static/js/pluginfw/hooks.js +++ b/src/static/js/pluginfw/hooks.js @@ -26,8 +26,6 @@ const checkDeprecation = (hook) => { // Flattens the array one level. const flatten1 = (array) => array.reduce((a, b) => a.concat(b), []); -exports.bubbleExceptions = true; - const hookCallWrapper = (hook, hookName, args, cb) => { if (cb === undefined) cb = (x) => x; @@ -38,17 +36,7 @@ const hookCallWrapper = (hook, hookName, args, cb) => { if (x === undefined) return []; return x; }; - const normalizedhook = () => normalize(hook.hook_fn(hookName, args, (x) => cb(normalize(x)))); - - if (exports.bubbleExceptions) { - return normalizedhook(); - } else { - try { - return normalizedhook(); - } catch (ex) { - console.error([hookName, hook.part.full_name, ex.stack || ex]); - } - } + return () => normalize(hook.hook_fn(hookName, args, (x) => cb(normalize(x)))); }; exports.syncMapFirst = (lst, fn) => { From 7dba847f21f8969e52f39d336cba6254426054f5 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 31 Jan 2021 16:49:17 -0500 Subject: [PATCH 136/153] hooks: Don't export `syncMapFirst` or `mapFirst` Nobody uses these functions outside of this file. --- src/static/js/pluginfw/hooks.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/static/js/pluginfw/hooks.js b/src/static/js/pluginfw/hooks.js index 489e6d6dc..7d7e1dd43 100644 --- a/src/static/js/pluginfw/hooks.js +++ b/src/static/js/pluginfw/hooks.js @@ -39,7 +39,7 @@ const hookCallWrapper = (hook, hookName, args, cb) => { return () => normalize(hook.hook_fn(hookName, args, (x) => cb(normalize(x)))); }; -exports.syncMapFirst = (lst, fn) => { +const syncMapFirst = (lst, fn) => { let i; let result; for (i = 0; i < lst.length; i++) { @@ -49,7 +49,7 @@ exports.syncMapFirst = (lst, fn) => { return []; }; -exports.mapFirst = (lst, fn, cb, predicate) => { +const mapFirst = (lst, fn, cb, predicate) => { if (predicate == null) predicate = (x) => (x != null && x.length > 0); let i = 0; @@ -347,7 +347,7 @@ exports.aCallAll = async (hookName, context, cb) => { exports.callFirst = (hookName, args) => { if (!args) args = {}; if (pluginDefs.hooks[hookName] === undefined) return []; - return exports.syncMapFirst(pluginDefs.hooks[hookName], + return syncMapFirst(pluginDefs.hooks[hookName], (hook) => hookCallWrapper(hook, hookName, args)); }; @@ -355,7 +355,7 @@ const aCallFirst = (hookName, args, cb, predicate) => { if (!args) args = {}; if (!cb) cb = () => {}; if (pluginDefs.hooks[hookName] === undefined) return cb(null, []); - exports.mapFirst( + mapFirst( pluginDefs.hooks[hookName], (hook, cb) => { hookCallWrapper(hook, hookName, args, (res) => { cb(null, res); }); From f02f288e8012538061a3973b42f2d4b8d1113c32 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 31 Jan 2021 18:07:36 -0500 Subject: [PATCH 137/153] hooks: Rename `args` to `context` for consistency --- src/static/js/pluginfw/hooks.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/static/js/pluginfw/hooks.js b/src/static/js/pluginfw/hooks.js index 7d7e1dd43..8434906b5 100644 --- a/src/static/js/pluginfw/hooks.js +++ b/src/static/js/pluginfw/hooks.js @@ -26,7 +26,7 @@ const checkDeprecation = (hook) => { // Flattens the array one level. const flatten1 = (array) => array.reduce((a, b) => a.concat(b), []); -const hookCallWrapper = (hook, hookName, args, cb) => { +const hookCallWrapper = (hook, hookName, context, cb) => { if (cb === undefined) cb = (x) => x; checkDeprecation(hook); @@ -36,7 +36,7 @@ const hookCallWrapper = (hook, hookName, args, cb) => { if (x === undefined) return []; return x; }; - return () => normalize(hook.hook_fn(hookName, args, (x) => cb(normalize(x)))); + return () => normalize(hook.hook_fn(hookName, context, (x) => cb(normalize(x)))); }; const syncMapFirst = (lst, fn) => { @@ -344,21 +344,21 @@ exports.aCallAll = async (hookName, context, cb) => { return await resultsPromise; }; -exports.callFirst = (hookName, args) => { - if (!args) args = {}; +exports.callFirst = (hookName, context) => { + if (!context) context = {}; if (pluginDefs.hooks[hookName] === undefined) return []; return syncMapFirst(pluginDefs.hooks[hookName], - (hook) => hookCallWrapper(hook, hookName, args)); + (hook) => hookCallWrapper(hook, hookName, context)); }; -const aCallFirst = (hookName, args, cb, predicate) => { - if (!args) args = {}; +const aCallFirst = (hookName, context, cb, predicate) => { + if (!context) context = {}; if (!cb) cb = () => {}; if (pluginDefs.hooks[hookName] === undefined) return cb(null, []); mapFirst( pluginDefs.hooks[hookName], (hook, cb) => { - hookCallWrapper(hook, hookName, args, (res) => { cb(null, res); }); + hookCallWrapper(hook, hookName, context, (res) => { cb(null, res); }); }, cb, predicate @@ -366,13 +366,13 @@ const aCallFirst = (hookName, args, cb, predicate) => { }; /* return a Promise if cb is not supplied */ -exports.aCallFirst = (hookName, args, cb, predicate) => { +exports.aCallFirst = (hookName, context, cb, predicate) => { if (cb === undefined) { return new Promise((resolve, reject) => { - aCallFirst(hookName, args, (err, res) => err ? reject(err) : resolve(res), predicate); + aCallFirst(hookName, context, (err, res) => err ? reject(err) : resolve(res), predicate); }); } else { - return aCallFirst(hookName, args, cb, predicate); + return aCallFirst(hookName, context, cb, predicate); } }; From c89db33ff038d3744bc907b8ce4e944b1556be59 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 31 Jan 2021 16:15:52 -0500 Subject: [PATCH 138/153] hooks: Refine caveat comments about function parameter count --- src/static/js/pluginfw/hooks.js | 40 ++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/static/js/pluginfw/hooks.js b/src/static/js/pluginfw/hooks.js index 8434906b5..5e8d9e73b 100644 --- a/src/static/js/pluginfw/hooks.js +++ b/src/static/js/pluginfw/hooks.js @@ -165,14 +165,27 @@ const callHookFnSync = (hook, context) => { // The hook function is assumed to not have a callback parameter, so fall through and accept // `undefined` as the resolved value. // - // IMPORTANT: "Rest" parameters and default parameters are not counted in`Function.length`, so - // the assumption does not hold for wrappers like `(...args) => { real(...args); }`. Such - // functions will still work properly without any logged warnings or errors for now, but: + // IMPORTANT: "Rest" parameters and default parameters are not included in `Function.length`, + // so the assumption does not hold for wrappers such as: + // + // const wrapper = (...args) => real(...args); + // + // ECMAScript does not provide a way to determine whether a function has default or rest + // parameters, so there is no way to be certain that a hook function with `length` < 3 will + // not call the callback. Synchronous hook functions that call the callback even though + // `length` < 3 will still work properly without any logged warnings or errors, but: + // // * Once the hook is upgraded to support asynchronous hook functions, calling the callback - // will (eventually) cause a double settle error, and the function might prematurely + // asynchronously will cause a double settle error, and the hook function will prematurely // resolve to `undefined` instead of the desired value. + // // * The above "unsettled function" warning is not logged if the function fails to call the // callback like it is supposed to. + // + // Wrapper functions can avoid problems by setting the wrapper's `length` property to match + // the real function's `length` property: + // + // Object.defineProperty(wrapper, 'length', {value: real.length}); } } @@ -300,10 +313,21 @@ const callHookFnAsync = async (hook, context) => { // The hook function is assumed to not have a callback parameter, so fall through and accept // `undefined` as the resolved value. // - // IMPORTANT: "Rest" parameters and default parameters are not counted in `Function.length`, - // so the assumption does not hold for wrappers like `(...args) => { real(...args); }`. For - // such functions, calling the callback will (eventually) cause a double settle error, and - // the function might prematurely resolve to `undefined` instead of the desired value. + // IMPORTANT: "Rest" parameters and default parameters are not included in + // `Function.length`, so the assumption does not hold for wrappers such as: + // + // const wrapper = (...args) => real(...args); + // + // ECMAScript does not provide a way to determine whether a function has default or rest + // parameters, so there is no way to be certain that a hook function with `length` < 3 will + // not call the callback. Hook functions with `length` < 3 that call the callback + // asynchronously will cause a double settle error, and the hook function will prematurely + // resolve to `undefined` instead of the desired value. + // + // Wrapper functions can avoid problems by setting the wrapper's `length` property to match + // the real function's `length` property: + // + // Object.defineProperty(wrapper, 'length', {value: real.length}); } } From 0b83ff8ec286087aa9ee9f826d31d289be89e03a Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 31 Jan 2021 16:30:55 -0500 Subject: [PATCH 139/153] hooks: Simplify `syncMapFirst` iteration --- src/static/js/pluginfw/hooks.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/static/js/pluginfw/hooks.js b/src/static/js/pluginfw/hooks.js index 5e8d9e73b..98b2af4c8 100644 --- a/src/static/js/pluginfw/hooks.js +++ b/src/static/js/pluginfw/hooks.js @@ -39,12 +39,11 @@ const hookCallWrapper = (hook, hookName, context, cb) => { return () => normalize(hook.hook_fn(hookName, context, (x) => cb(normalize(x)))); }; -const syncMapFirst = (lst, fn) => { - let i; - let result; - for (i = 0; i < lst.length; i++) { - result = fn(lst[i]); - if (result.length) return result; +const syncMapFirst = (hooks, fn) => { + const predicate = (val) => val.length; + for (const hook of hooks) { + const val = fn(hook); + if (predicate(val)) return val; } return []; }; From 53ccfa87030f795366df53050a483921900ffe5c Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 31 Jan 2021 16:51:37 -0500 Subject: [PATCH 140/153] hooks: Asyncify `mapFirst` --- src/static/js/pluginfw/hooks.js | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/src/static/js/pluginfw/hooks.js b/src/static/js/pluginfw/hooks.js index 98b2af4c8..de7ddc32c 100644 --- a/src/static/js/pluginfw/hooks.js +++ b/src/static/js/pluginfw/hooks.js @@ -1,6 +1,7 @@ 'use strict'; const pluginDefs = require('./plugin_defs'); +const util = require('util'); // Maps the name of a server-side hook to a string explaining the deprecation // (e.g., 'use the foo hook instead'). @@ -48,19 +49,13 @@ const syncMapFirst = (hooks, fn) => { return []; }; -const mapFirst = (lst, fn, cb, predicate) => { - if (predicate == null) predicate = (x) => (x != null && x.length > 0); - let i = 0; - - const next = () => { - if (i >= lst.length) return cb(null, []); - fn(lst[i++], (err, result) => { - if (err) return cb(err); - if (predicate(result)) return cb(null, result); - next(); - }); - }; - next(); +const mapFirst = async (hooks, fn, predicate = null) => { + if (predicate == null) predicate = (val) => val.length; + for (const hook of hooks) { + const val = await fn(hook); + if (predicate(val)) return val; + } + return []; }; // Calls the hook function synchronously and returns the value provided by the hook function (via @@ -377,15 +372,9 @@ exports.callFirst = (hookName, context) => { const aCallFirst = (hookName, context, cb, predicate) => { if (!context) context = {}; if (!cb) cb = () => {}; - if (pluginDefs.hooks[hookName] === undefined) return cb(null, []); - mapFirst( - pluginDefs.hooks[hookName], - (hook, cb) => { - hookCallWrapper(hook, hookName, context, (res) => { cb(null, res); }); - }, - cb, - predicate - ); + const hooks = pluginDefs.hooks[hookName] || []; + const fn = async (hook) => await util.promisify(hookCallWrapper)(hook, hookName, context); + util.callbackify(mapFirst)(hooks, fn, predicate, cb); }; /* return a Promise if cb is not supplied */ From 4ab7a99512a69b5438b45a7f37a2b824433f4eec Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 31 Jan 2021 18:35:17 -0500 Subject: [PATCH 141/153] hooks: Inline `syncMapFirst()` into `callFirst()` for readability There's only one caller of the function, and the function is simple, so there's no need for a separate function. --- src/static/js/pluginfw/hooks.js | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/static/js/pluginfw/hooks.js b/src/static/js/pluginfw/hooks.js index de7ddc32c..4370b87f8 100644 --- a/src/static/js/pluginfw/hooks.js +++ b/src/static/js/pluginfw/hooks.js @@ -40,15 +40,6 @@ const hookCallWrapper = (hook, hookName, context, cb) => { return () => normalize(hook.hook_fn(hookName, context, (x) => cb(normalize(x)))); }; -const syncMapFirst = (hooks, fn) => { - const predicate = (val) => val.length; - for (const hook of hooks) { - const val = fn(hook); - if (predicate(val)) return val; - } - return []; -}; - const mapFirst = async (hooks, fn, predicate = null) => { if (predicate == null) predicate = (val) => val.length; for (const hook of hooks) { @@ -364,9 +355,13 @@ exports.aCallAll = async (hookName, context, cb) => { exports.callFirst = (hookName, context) => { if (!context) context = {}; - if (pluginDefs.hooks[hookName] === undefined) return []; - return syncMapFirst(pluginDefs.hooks[hookName], - (hook) => hookCallWrapper(hook, hookName, context)); + const predicate = (val) => val.length; + const hooks = pluginDefs.hooks[hookName] || []; + for (const hook of hooks) { + const val = hookCallWrapper(hook, hookName, context); + if (predicate(val)) return val; + } + return []; }; const aCallFirst = (hookName, context, cb, predicate) => { From 13e806ad7a21e18352880b16b43b1caa2784887f Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 31 Jan 2021 18:35:17 -0500 Subject: [PATCH 142/153] hooks: Inline `mapFirst()` into `aCallFirst()` for readability There's only one caller of the function, and the function is simple, so there's no need for a separate function. --- src/static/js/pluginfw/hooks.js | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/static/js/pluginfw/hooks.js b/src/static/js/pluginfw/hooks.js index 4370b87f8..2851e92a0 100644 --- a/src/static/js/pluginfw/hooks.js +++ b/src/static/js/pluginfw/hooks.js @@ -40,15 +40,6 @@ const hookCallWrapper = (hook, hookName, context, cb) => { return () => normalize(hook.hook_fn(hookName, context, (x) => cb(normalize(x)))); }; -const mapFirst = async (hooks, fn, predicate = null) => { - if (predicate == null) predicate = (val) => val.length; - for (const hook of hooks) { - const val = await fn(hook); - if (predicate(val)) return val; - } - return []; -}; - // Calls the hook function synchronously and returns the value provided by the hook function (via // callback or return value). // @@ -364,12 +355,18 @@ exports.callFirst = (hookName, context) => { return []; }; -const aCallFirst = (hookName, context, cb, predicate) => { +const aCallFirst = (hookName, context, cb, predicate = null) => { if (!context) context = {}; if (!cb) cb = () => {}; + if (predicate == null) predicate = (val) => val.length; const hooks = pluginDefs.hooks[hookName] || []; - const fn = async (hook) => await util.promisify(hookCallWrapper)(hook, hookName, context); - util.callbackify(mapFirst)(hooks, fn, predicate, cb); + util.callbackify(async () => { + for (const hook of hooks) { + const val = await util.promisify(hookCallWrapper)(hook, hookName, context); + if (predicate(val)) return val; + } + return []; + })(cb); }; /* return a Promise if cb is not supplied */ From 708206449a888ed46a0acdf52de68d996778696d Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 31 Jan 2021 19:11:48 -0500 Subject: [PATCH 143/153] hooks: Factor out callback attachment The separate function will be reused in a future commit. --- src/static/js/pluginfw/hooks.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/static/js/pluginfw/hooks.js b/src/static/js/pluginfw/hooks.js index 2851e92a0..2c0dd13b7 100644 --- a/src/static/js/pluginfw/hooks.js +++ b/src/static/js/pluginfw/hooks.js @@ -24,6 +24,11 @@ const checkDeprecation = (hook) => { deprecationWarned[hook.hook_fn_name] = true; }; +// Calls the node-style callback when the Promise settles. Unlike util.callbackify, this takes a +// Promise (rather than a function that returns a Promise), and it returns a Promise (rather than a +// function that returns undefined). +const attachCallback = (p, cb) => p.then((val) => cb(null, val), cb); + // Flattens the array one level. const flatten1 = (array) => array.reduce((a, b) => a.concat(b), []); @@ -333,15 +338,14 @@ const callHookFnAsync = async (hook, context) => { // 2. Convert each `undefined` entry into `[]`. // 3. Flatten one level. // If cb is non-null, this function resolves to the value returned by cb. -exports.aCallAll = async (hookName, context, cb) => { +exports.aCallAll = async (hookName, context, cb = null) => { + if (cb != null) return await attachCallback(exports.aCallAll(hookName, context), cb); if (context == null) context = {}; const hooks = pluginDefs.hooks[hookName] || []; - let resultsPromise = Promise.all(hooks.map((hook) => callHookFnAsync(hook, context) + const results = await Promise.all(hooks.map((hook) => callHookFnAsync(hook, context) // `undefined` (but not `null`!) is treated the same as []. - .then((result) => (result === undefined) ? [] : result))) - .then(flatten1); - if (cb != null) resultsPromise = resultsPromise.then((val) => cb(null, val), cb); - return await resultsPromise; + .then((result) => (result === undefined) ? [] : result))); + return flatten1(results); }; exports.callFirst = (hookName, context) => { From f316a3bacdc282de9cd60121013ea6421bfab9ca Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 31 Jan 2021 23:41:11 -0500 Subject: [PATCH 144/153] hooks: Never pass a falsy error to a callback --- src/static/js/pluginfw/hooks.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/static/js/pluginfw/hooks.js b/src/static/js/pluginfw/hooks.js index 2c0dd13b7..1b04a61c7 100644 --- a/src/static/js/pluginfw/hooks.js +++ b/src/static/js/pluginfw/hooks.js @@ -27,7 +27,11 @@ const checkDeprecation = (hook) => { // Calls the node-style callback when the Promise settles. Unlike util.callbackify, this takes a // Promise (rather than a function that returns a Promise), and it returns a Promise (rather than a // function that returns undefined). -const attachCallback = (p, cb) => p.then((val) => cb(null, val), cb); +const attachCallback = (p, cb) => p.then( + (val) => cb(null, val), + // Callbacks often only check the truthiness, not the nullness, of the first parameter. To avoid + // problems, always pass a truthy value as the first argument if the Promise is rejected. + (err) => cb(err || new Error(err))); // Flattens the array one level. const flatten1 = (array) => array.reduce((a, b) => a.concat(b), []); @@ -326,10 +330,11 @@ const callHookFnAsync = async (hook, context) => { // Arguments: // * hookName: Name of the hook to invoke. // * context: Passed unmodified to the hook functions, except nullish becomes {}. -// * cb: Deprecated callback. The following: +// * cb: Deprecated. Optional node-style callback. The following: // const p1 = hooks.aCallAll('myHook', context, cb); // is equivalent to: -// const p2 = hooks.aCallAll('myHook', context).then((val) => cb(null, val), cb); +// const p2 = hooks.aCallAll('myHook', context).then( +// (val) => cb(null, val), (err) => cb(err || new Error(err))); // // Return value: // If cb is nullish, this function resolves to a flattened array of hook results. Specifically, it From 22d02dbcbf3da3e8373f52cb99572144e1bd2e98 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 31 Jan 2021 18:56:06 -0500 Subject: [PATCH 145/153] hooks: Factor out value normalization --- src/static/js/pluginfw/hooks.js | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/static/js/pluginfw/hooks.js b/src/static/js/pluginfw/hooks.js index 1b04a61c7..5b3add2d1 100644 --- a/src/static/js/pluginfw/hooks.js +++ b/src/static/js/pluginfw/hooks.js @@ -33,20 +33,24 @@ const attachCallback = (p, cb) => p.then( // problems, always pass a truthy value as the first argument if the Promise is rejected. (err) => cb(err || new Error(err))); +// Normalizes the value provided by hook functions so that it is always an array. `undefined` (but +// not `null`!) becomes an empty array, array values are returned unmodified, and non-array values +// are wrapped in an array (so `null` becomes `[null]`). +const normalizeValue = (val) => { + // `undefined` is treated the same as `[]`. IMPORTANT: `null` is *not* treated the same as `[]` + // because some hooks use `null` as a special value. + if (val === undefined) return []; + if (Array.isArray(val)) return val; + return [val]; +}; + // Flattens the array one level. const flatten1 = (array) => array.reduce((a, b) => a.concat(b), []); const hookCallWrapper = (hook, hookName, context, cb) => { if (cb === undefined) cb = (x) => x; - checkDeprecation(hook); - - // Normalize output to list for both sync and async cases - const normalize = (x) => { - if (x === undefined) return []; - return x; - }; - return () => normalize(hook.hook_fn(hookName, context, (x) => cb(normalize(x)))); + return () => normalizeValue(hook.hook_fn(hookName, context, (x) => cb(normalizeValue(x)))); }; // Calls the hook function synchronously and returns the value provided by the hook function (via @@ -192,12 +196,7 @@ const callHookFnSync = (hook, context) => { exports.callAll = (hookName, context) => { if (context == null) context = {}; const hooks = pluginDefs.hooks[hookName] || []; - return flatten1(hooks.map((hook) => { - const ret = callHookFnSync(hook, context); - // `undefined` (but not `null`!) is treated the same as []. - if (ret === undefined) return []; - return ret; - })); + return flatten1(hooks.map((hook) => normalizeValue(callHookFnSync(hook, context)))); }; // Calls the hook function asynchronously and returns a Promise that either resolves to the hook @@ -347,9 +346,8 @@ exports.aCallAll = async (hookName, context, cb = null) => { if (cb != null) return await attachCallback(exports.aCallAll(hookName, context), cb); if (context == null) context = {}; const hooks = pluginDefs.hooks[hookName] || []; - const results = await Promise.all(hooks.map((hook) => callHookFnAsync(hook, context) - // `undefined` (but not `null`!) is treated the same as []. - .then((result) => (result === undefined) ? [] : result))); + const results = await Promise.all( + hooks.map(async (hook) => normalizeValue(await callHookFnAsync(hook, context)))); return flatten1(results); }; From 77f480d954bcefd99c176e87604d47aa9b8848ee Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 1 Feb 2021 00:03:06 -0500 Subject: [PATCH 146/153] hooks: Asyncify `aCallFirst` --- src/static/js/pluginfw/hooks.js | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/static/js/pluginfw/hooks.js b/src/static/js/pluginfw/hooks.js index 5b3add2d1..c570068cf 100644 --- a/src/static/js/pluginfw/hooks.js +++ b/src/static/js/pluginfw/hooks.js @@ -362,29 +362,21 @@ exports.callFirst = (hookName, context) => { return []; }; -const aCallFirst = (hookName, context, cb, predicate = null) => { +const aCallFirst = async (hookName, context, predicate = null) => { if (!context) context = {}; - if (!cb) cb = () => {}; if (predicate == null) predicate = (val) => val.length; const hooks = pluginDefs.hooks[hookName] || []; - util.callbackify(async () => { - for (const hook of hooks) { - const val = await util.promisify(hookCallWrapper)(hook, hookName, context); - if (predicate(val)) return val; - } - return []; - })(cb); + for (const hook of hooks) { + const val = await util.promisify(hookCallWrapper)(hook, hookName, context); + if (predicate(val)) return val; + } + return []; }; /* return a Promise if cb is not supplied */ exports.aCallFirst = (hookName, context, cb, predicate) => { - if (cb === undefined) { - return new Promise((resolve, reject) => { - aCallFirst(hookName, context, (err, res) => err ? reject(err) : resolve(res), predicate); - }); - } else { - return aCallFirst(hookName, context, cb, predicate); - } + if (cb == null) return aCallFirst(hookName, context, predicate); + util.callbackify(aCallFirst)(hookName, context, predicate, cb); }; exports.exportedForTestingOnly = { From fd5d3ce777c5cb93e3c49cccc77289099afa2b71 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 1 Feb 2021 00:34:49 -0500 Subject: [PATCH 147/153] hooks: Inline `aCallFirst()` into `exports.aCallFirst()` --- src/static/js/pluginfw/hooks.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/static/js/pluginfw/hooks.js b/src/static/js/pluginfw/hooks.js index c570068cf..75e37315f 100644 --- a/src/static/js/pluginfw/hooks.js +++ b/src/static/js/pluginfw/hooks.js @@ -362,7 +362,10 @@ exports.callFirst = (hookName, context) => { return []; }; -const aCallFirst = async (hookName, context, predicate = null) => { +exports.aCallFirst = async (hookName, context, cb = null, predicate = null) => { + if (cb != null) { + return await attachCallback(exports.aCallFirst(hookName, context, null, predicate), cb); + } if (!context) context = {}; if (predicate == null) predicate = (val) => val.length; const hooks = pluginDefs.hooks[hookName] || []; @@ -373,12 +376,6 @@ const aCallFirst = async (hookName, context, predicate = null) => { return []; }; -/* return a Promise if cb is not supplied */ -exports.aCallFirst = (hookName, context, cb, predicate) => { - if (cb == null) return aCallFirst(hookName, context, predicate); - util.callbackify(aCallFirst)(hookName, context, predicate, cb); -}; - exports.exportedForTestingOnly = { callHookFnAsync, callHookFnSync, From c11d60c5f6f2e36f1643f57ed789a74ea4224175 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 1 Feb 2021 00:37:45 -0500 Subject: [PATCH 148/153] hooks: Check context nullness, not truthiness --- src/static/js/pluginfw/hooks.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/static/js/pluginfw/hooks.js b/src/static/js/pluginfw/hooks.js index 75e37315f..14bd9d57e 100644 --- a/src/static/js/pluginfw/hooks.js +++ b/src/static/js/pluginfw/hooks.js @@ -352,7 +352,7 @@ exports.aCallAll = async (hookName, context, cb = null) => { }; exports.callFirst = (hookName, context) => { - if (!context) context = {}; + if (context == null) context = {}; const predicate = (val) => val.length; const hooks = pluginDefs.hooks[hookName] || []; for (const hook of hooks) { @@ -366,7 +366,7 @@ exports.aCallFirst = async (hookName, context, cb = null, predicate = null) => { if (cb != null) { return await attachCallback(exports.aCallFirst(hookName, context, null, predicate), cb); } - if (!context) context = {}; + if (context == null) context = {}; if (predicate == null) predicate = (val) => val.length; const hooks = pluginDefs.hooks[hookName] || []; for (const hook of hooks) { From 6f30ea7c38c81b0b334426fea87462d1e23c3369 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 1 Feb 2021 00:41:53 -0500 Subject: [PATCH 149/153] hooks: Use `callHookFn{Sync,Async}()` for `{call,aCall}First()` Benefits of `callHookFnSync()` and `callHookFnAsync()`: * They are a lot more forgiving than `hookCallWrapper()` was. * They perform useful sanity checks. * They have extensive unit test coverage. * They make the behavior of `callFirst()` and `aCallFirst()` match the behavior of `callAll()` and `aCallAll()`. --- src/static/js/pluginfw/hooks.js | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/static/js/pluginfw/hooks.js b/src/static/js/pluginfw/hooks.js index 14bd9d57e..65854730c 100644 --- a/src/static/js/pluginfw/hooks.js +++ b/src/static/js/pluginfw/hooks.js @@ -1,7 +1,6 @@ 'use strict'; const pluginDefs = require('./plugin_defs'); -const util = require('util'); // Maps the name of a server-side hook to a string explaining the deprecation // (e.g., 'use the foo hook instead'). @@ -47,12 +46,6 @@ const normalizeValue = (val) => { // Flattens the array one level. const flatten1 = (array) => array.reduce((a, b) => a.concat(b), []); -const hookCallWrapper = (hook, hookName, context, cb) => { - if (cb === undefined) cb = (x) => x; - checkDeprecation(hook); - return () => normalizeValue(hook.hook_fn(hookName, context, (x) => cb(normalizeValue(x)))); -}; - // Calls the hook function synchronously and returns the value provided by the hook function (via // callback or return value). // @@ -356,7 +349,7 @@ exports.callFirst = (hookName, context) => { const predicate = (val) => val.length; const hooks = pluginDefs.hooks[hookName] || []; for (const hook of hooks) { - const val = hookCallWrapper(hook, hookName, context); + const val = normalizeValue(callHookFnSync(hook, context)); if (predicate(val)) return val; } return []; @@ -370,7 +363,7 @@ exports.aCallFirst = async (hookName, context, cb = null, predicate = null) => { if (predicate == null) predicate = (val) => val.length; const hooks = pluginDefs.hooks[hookName] || []; for (const hook of hooks) { - const val = await util.promisify(hookCallWrapper)(hook, hookName, context); + const val = normalizeValue(await callHookFnAsync(hook, context)); if (predicate(val)) return val; } return []; From ba0544ea9e8b443326830adc69a14103a4eda980 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 1 Feb 2021 18:31:50 -0500 Subject: [PATCH 150/153] hooks: Add unit tests for `callFirst()`, `aCallFirst()` --- tests/backend/specs/hooks.js | 240 +++++++++++++++++++++++++++++++++++ 1 file changed, 240 insertions(+) diff --git a/tests/backend/specs/hooks.js b/tests/backend/specs/hooks.js index 327b9bd1c..2ea7fac00 100644 --- a/tests/backend/specs/hooks.js +++ b/tests/backend/specs/hooks.js @@ -389,6 +389,90 @@ describe(__filename, function () { }); }); + describe('hooks.callFirst', function () { + it('no registered hooks (undefined) -> []', async function () { + delete plugins.hooks.testHook; + assert.deepEqual(hooks.callFirst(hookName), []); + }); + + it('no registered hooks (empty list) -> []', async function () { + testHooks.length = 0; + assert.deepEqual(hooks.callFirst(hookName), []); + }); + + it('passes hook name => {}', async function () { + hook.hook_fn = (hn) => { assert.equal(hn, hookName); }; + hooks.callFirst(hookName); + }); + + it('undefined context => {}', async function () { + hook.hook_fn = (hn, ctx) => { assert.deepEqual(ctx, {}); }; + hooks.callFirst(hookName); + }); + + it('null context => {}', async function () { + hook.hook_fn = (hn, ctx) => { assert.deepEqual(ctx, {}); }; + hooks.callFirst(hookName, null); + }); + + it('context unmodified', async function () { + const wantContext = {}; + hook.hook_fn = (hn, ctx) => { assert.equal(ctx, wantContext); }; + hooks.callFirst(hookName, wantContext); + }); + + it('predicate never satisfied -> calls all in order', async function () { + const gotCalls = []; + testHooks.length = 0; + for (let i = 0; i < 3; i++) { + const hook = makeHook(); + hook.hook_fn = () => { gotCalls.push(i); }; + testHooks.push(hook); + } + assert.deepEqual(hooks.callFirst(hookName), []); + assert.deepEqual(gotCalls, [0, 1, 2]); + }); + + it('stops when predicate is satisfied', async function () { + testHooks.length = 0; + testHooks.push(makeHook(), makeHook('val1'), makeHook('val2')); + assert.deepEqual(hooks.callFirst(hookName), ['val1']); + }); + + it('skips values that do not satisfy predicate (undefined)', async function () { + testHooks.length = 0; + testHooks.push(makeHook(), makeHook('val1')); + assert.deepEqual(hooks.callFirst(hookName), ['val1']); + }); + + it('skips values that do not satisfy predicate (empty list)', async function () { + testHooks.length = 0; + testHooks.push(makeHook([]), makeHook('val1')); + assert.deepEqual(hooks.callFirst(hookName), ['val1']); + }); + + it('null satisifes the predicate', async function () { + testHooks.length = 0; + testHooks.push(makeHook(null), makeHook('val1')); + assert.deepEqual(hooks.callFirst(hookName), [null]); + }); + + it('non-empty arrays are returned unmodified', async function () { + const want = ['val1']; + testHooks.length = 0; + testHooks.push(makeHook(want), makeHook(['val2'])); + assert.equal(hooks.callFirst(hookName), want); // Note: *NOT* deepEqual! + }); + + it('value can be passed via callback', async function () { + const want = {}; + hook.hook_fn = (hn, ctx, cb) => { cb(want); }; + const got = hooks.callFirst(hookName); + assert.deepEqual(got, [want]); + assert.equal(got[0], want); // Note: *NOT* deepEqual! + }); + }); + describe('callHookFnAsync', function () { const callHookFnAsync = hooks.exportedForTestingOnly.callHookFnAsync; // Convenience shorthand. @@ -883,4 +967,160 @@ describe(__filename, function () { }); }); }); + + describe('hooks.aCallFirst', function () { + it('no registered hooks (undefined) -> []', async function () { + delete plugins.hooks.testHook; + assert.deepEqual(await hooks.aCallFirst(hookName), []); + }); + + it('no registered hooks (empty list) -> []', async function () { + testHooks.length = 0; + assert.deepEqual(await hooks.aCallFirst(hookName), []); + }); + + it('passes hook name => {}', async function () { + hook.hook_fn = (hn) => { assert.equal(hn, hookName); }; + await hooks.aCallFirst(hookName); + }); + + it('undefined context => {}', async function () { + hook.hook_fn = (hn, ctx) => { assert.deepEqual(ctx, {}); }; + await hooks.aCallFirst(hookName); + }); + + it('null context => {}', async function () { + hook.hook_fn = (hn, ctx) => { assert.deepEqual(ctx, {}); }; + await hooks.aCallFirst(hookName, null); + }); + + it('context unmodified', async function () { + const wantContext = {}; + hook.hook_fn = (hn, ctx) => { assert.equal(ctx, wantContext); }; + await hooks.aCallFirst(hookName, wantContext); + }); + + it('default predicate: predicate never satisfied -> calls all in order', async function () { + const gotCalls = []; + testHooks.length = 0; + for (let i = 0; i < 3; i++) { + const hook = makeHook(); + hook.hook_fn = () => { gotCalls.push(i); }; + testHooks.push(hook); + } + assert.deepEqual(await hooks.aCallFirst(hookName), []); + assert.deepEqual(gotCalls, [0, 1, 2]); + }); + + it('calls hook functions serially', async function () { + const gotCalls = []; + testHooks.length = 0; + for (let i = 0; i < 3; i++) { + const hook = makeHook(); + hook.hook_fn = async () => { + gotCalls.push(i); + // Check gotCalls asynchronously to ensure that the next hook function does not start + // executing before this hook function has resolved. + return await new Promise((resolve) => { + setImmediate(() => { + assert.deepEqual(gotCalls, [...Array(i + 1).keys()]); + resolve(); + }); + }); + }; + testHooks.push(hook); + } + assert.deepEqual(await hooks.aCallFirst(hookName), []); + assert.deepEqual(gotCalls, [0, 1, 2]); + }); + + it('default predicate: stops when satisfied', async function () { + testHooks.length = 0; + testHooks.push(makeHook(), makeHook('val1'), makeHook('val2')); + assert.deepEqual(await hooks.aCallFirst(hookName), ['val1']); + }); + + it('default predicate: skips values that do not satisfy (undefined)', async function () { + testHooks.length = 0; + testHooks.push(makeHook(), makeHook('val1')); + assert.deepEqual(await hooks.aCallFirst(hookName), ['val1']); + }); + + it('default predicate: skips values that do not satisfy (empty list)', async function () { + testHooks.length = 0; + testHooks.push(makeHook([]), makeHook('val1')); + assert.deepEqual(await hooks.aCallFirst(hookName), ['val1']); + }); + + it('default predicate: null satisifes', async function () { + testHooks.length = 0; + testHooks.push(makeHook(null), makeHook('val1')); + assert.deepEqual(await hooks.aCallFirst(hookName), [null]); + }); + + it('custom predicate: called for each hook function', async function () { + testHooks.length = 0; + testHooks.push(makeHook(0), makeHook(1), makeHook(2)); + let got = 0; + await hooks.aCallFirst(hookName, null, null, (val) => { ++got; return false; }); + assert.equal(got, 3); + }); + + it('custom predicate: boolean false/true continues/stops iteration', async function () { + testHooks.length = 0; + testHooks.push(makeHook(1), makeHook(2), makeHook(3)); + let nCall = 0; + const predicate = (val) => { + assert.deepEqual(val, [++nCall]); + return nCall === 2; + }; + assert.deepEqual(await hooks.aCallFirst(hookName, null, null, predicate), [2]); + assert.equal(nCall, 2); + }); + + it('custom predicate: non-boolean falsy/truthy continues/stops iteration', async function () { + testHooks.length = 0; + testHooks.push(makeHook(1), makeHook(2), makeHook(3)); + let nCall = 0; + const predicate = (val) => { + assert.deepEqual(val, [++nCall]); + return nCall === 2 ? {} : null; + }; + assert.deepEqual(await hooks.aCallFirst(hookName, null, null, predicate), [2]); + assert.equal(nCall, 2); + }); + + it('custom predicate: array value passed unmodified to predicate', async function () { + const want = [0]; + hook.hook_fn = () => want; + const predicate = (got) => { assert.equal(got, want); }; // Note: *NOT* deepEqual! + await hooks.aCallFirst(hookName, null, null, predicate); + }); + + it('custom predicate: normalized value passed to predicate (undefined)', async function () { + const predicate = (got) => { assert.deepEqual(got, []); }; + await hooks.aCallFirst(hookName, null, null, predicate); + }); + + it('custom predicate: normalized value passed to predicate (null)', async function () { + hook.hook_fn = () => null; + const predicate = (got) => { assert.deepEqual(got, [null]); }; + await hooks.aCallFirst(hookName, null, null, predicate); + }); + + it('non-empty arrays are returned unmodified', async function () { + const want = ['val1']; + testHooks.length = 0; + testHooks.push(makeHook(want), makeHook(['val2'])); + assert.equal(await hooks.aCallFirst(hookName), want); // Note: *NOT* deepEqual! + }); + + it('value can be passed via callback', async function () { + const want = {}; + hook.hook_fn = (hn, ctx, cb) => { cb(want); }; + const got = await hooks.aCallFirst(hookName); + assert.deepEqual(got, [want]); + assert.equal(got[0], want); // Note: *NOT* deepEqual! + }); + }); }); From 763fe6fc2615962d54ccbf80d05df49b751a90c5 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 1 Feb 2021 01:43:04 -0500 Subject: [PATCH 151/153] hooks: Document `callFirst()` and `aCallFirst()` --- src/static/js/pluginfw/hooks.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/static/js/pluginfw/hooks.js b/src/static/js/pluginfw/hooks.js index 65854730c..459f84489 100644 --- a/src/static/js/pluginfw/hooks.js +++ b/src/static/js/pluginfw/hooks.js @@ -344,6 +344,9 @@ exports.aCallAll = async (hookName, context, cb = null) => { return flatten1(results); }; +// DEPRECATED: Use `aCallFirst()` instead. +// +// Like `aCallFirst()`, but synchronous. Hook functions must provide their values synchronously. exports.callFirst = (hookName, context) => { if (context == null) context = {}; const predicate = (val) => val.length; @@ -355,6 +358,27 @@ exports.callFirst = (hookName, context) => { return []; }; +// Invokes the registered hook functions one at a time until one provides a value that meets a +// customizable condition. +// +// Arguments: +// * hookName: Name of the hook to invoke. +// * context: Passed unmodified to the hook functions, except nullish becomes {}. +// * cb: Deprecated callback. The following: +// const p1 = hooks.aCallFirst('myHook', context, cb); +// is equivalent to: +// const p2 = hooks.aCallFirst('myHook', context).then( +// (val) => cb(null, val), (err) => cb(err || new Error(err))); +// * predicate: Optional predicate function that returns true if the hook function provided a +// value that satisfies a desired condition. If nullish, the predicate defaults to a non-empty +// array check. The predicate is invoked each time a hook function returns. It takes one +// argument: the normalized value provided by the hook function. If the predicate returns +// truthy, iteration over the hook functions stops (no more hook functions will be called). +// +// Return value: +// If cb is nullish, resolves to an array that is either the normalized value that satisfied the +// predicate or empty if the predicate was never satisfied. If cb is non-nullish, resolves to the +// value returned from cb(). exports.aCallFirst = async (hookName, context, cb = null, predicate = null) => { if (cb != null) { return await attachCallback(exports.aCallFirst(hookName, context, null, predicate), cb); From 05e0e8dbf7941cb2ff4b235a088034b2404fce46 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Mon, 1 Feb 2021 01:18:44 -0500 Subject: [PATCH 152/153] hooks: New `callAllSerial()` function This is necessary to migrate away from `callAll()` (which only supports synchronous hook functions). --- src/static/js/pluginfw/hooks.js | 20 +++++++- tests/backend/specs/hooks.js | 83 +++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/src/static/js/pluginfw/hooks.js b/src/static/js/pluginfw/hooks.js index 459f84489..72da63021 100644 --- a/src/static/js/pluginfw/hooks.js +++ b/src/static/js/pluginfw/hooks.js @@ -175,6 +175,8 @@ const callHookFnSync = (hook, context) => { return outcome.val; }; +// DEPRECATED: Use `callAllSerial()` or `aCallAll()` instead. +// // Invokes all registered hook functions synchronously. // // Arguments: @@ -317,7 +319,10 @@ const callHookFnAsync = async (hook, context) => { }); }; -// Invokes all registered hook functions asynchronously. +// Invokes all registered hook functions asynchronously and concurrently. This is NOT the async +// equivalent of `callAll()`: `callAll()` calls the hook functions serially (one at a time) but this +// function calls them concurrently. Use `callAllSerial()` if the hook functions must be called one +// at a time. // // Arguments: // * hookName: Name of the hook to invoke. @@ -344,6 +349,19 @@ exports.aCallAll = async (hookName, context, cb = null) => { return flatten1(results); }; +// Like `aCallAll()` except the hook functions are called one at a time instead of concurrently. +// Only use this function if the hook functions must be called one at a time, otherwise use +// `aCallAll()`. +exports.callAllSerial = async (hookName, context) => { + if (context == null) context = {}; + const hooks = pluginDefs.hooks[hookName] || []; + const results = []; + for (const hook of hooks) { + results.push(normalizeValue(await callHookFnAsync(hook, context))); + } + return flatten1(results); +}; + // DEPRECATED: Use `aCallFirst()` instead. // // Like `aCallFirst()`, but synchronous. Hook functions must provide their values synchronously. diff --git a/tests/backend/specs/hooks.js b/tests/backend/specs/hooks.js index 2ea7fac00..865cb132b 100644 --- a/tests/backend/specs/hooks.js +++ b/tests/backend/specs/hooks.js @@ -968,6 +968,89 @@ describe(__filename, function () { }); }); + describe('hooks.callAllSerial', function () { + describe('basic behavior', function () { + it('calls all asynchronously, serially, in order', async function () { + const gotCalls = []; + testHooks.length = 0; + for (let i = 0; i < 3; i++) { + const hook = makeHook(); + hook.hook_fn = async () => { + gotCalls.push(i); + // Check gotCalls asynchronously to ensure that the next hook function does not start + // executing before this hook function has resolved. + return await new Promise((resolve) => { + setImmediate(() => { + assert.deepEqual(gotCalls, [...Array(i + 1).keys()]); + resolve(i); + }); + }); + }; + testHooks.push(hook); + } + assert.deepEqual(await hooks.callAllSerial(hookName), [0, 1, 2]); + assert.deepEqual(gotCalls, [0, 1, 2]); + }); + + it('passes hook name', async function () { + hook.hook_fn = async (hn) => { assert.equal(hn, hookName); }; + await hooks.callAllSerial(hookName); + }); + + it('undefined context -> {}', async function () { + hook.hook_fn = async (hn, ctx) => { assert.deepEqual(ctx, {}); }; + await hooks.callAllSerial(hookName); + }); + + it('null context -> {}', async function () { + hook.hook_fn = async (hn, ctx) => { assert.deepEqual(ctx, {}); }; + await hooks.callAllSerial(hookName, null); + }); + + it('context unmodified', async function () { + const wantContext = {}; + hook.hook_fn = async (hn, ctx) => { assert.equal(ctx, wantContext); }; + await hooks.callAllSerial(hookName, wantContext); + }); + }); + + describe('result processing', function () { + it('no registered hooks (undefined) -> []', async function () { + delete plugins.hooks[hookName]; + assert.deepEqual(await hooks.callAllSerial(hookName), []); + }); + + it('no registered hooks (empty list) -> []', async function () { + testHooks.length = 0; + assert.deepEqual(await hooks.callAllSerial(hookName), []); + }); + + it('flattens one level', async function () { + testHooks.length = 0; + testHooks.push(makeHook(1), makeHook([2]), makeHook([[3]])); + assert.deepEqual(await hooks.callAllSerial(hookName), [1, 2, [3]]); + }); + + it('filters out undefined', async function () { + testHooks.length = 0; + testHooks.push(makeHook(), makeHook([2]), makeHook([[3]]), makeHook(Promise.resolve())); + assert.deepEqual(await hooks.callAllSerial(hookName), [2, [3]]); + }); + + it('preserves null', async function () { + testHooks.length = 0; + testHooks.push(makeHook(null), makeHook([2]), makeHook(Promise.resolve(null))); + assert.deepEqual(await hooks.callAllSerial(hookName), [null, 2, null]); + }); + + it('all undefined -> []', async function () { + testHooks.length = 0; + testHooks.push(makeHook(), makeHook(Promise.resolve())); + assert.deepEqual(await hooks.callAllSerial(hookName), []); + }); + }); + }); + describe('hooks.aCallFirst', function () { it('no registered hooks (undefined) -> []', async function () { delete plugins.hooks.testHook; From 65dec5bd2cfd3576fbfe6de5e5d652888a999e3f Mon Sep 17 00:00:00 2001 From: John McLear Date: Mon, 1 Feb 2021 23:11:11 +0000 Subject: [PATCH 153/153] lint: json.js --- bin/doc/json.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/bin/doc/json.js b/bin/doc/json.js index c71611e5f..1a5ecb1d8 100644 --- a/bin/doc/json.js +++ b/bin/doc/json.js @@ -248,11 +248,11 @@ const processList = (section) => { switch (section.type) { case 'ctor': case 'classMethod': - case 'method': + case 'method': { // each item is an argument, unless the name is 'return', // in which case it's the return value. section.signatures = section.signatures || []; - var sig = {}; + const sig = {}; section.signatures.push(sig); sig.params = values.filter((v) => { if (v.name === 'return') { @@ -263,11 +263,11 @@ const processList = (section) => { }); parseSignature(section.textRaw, sig); break; - - case 'property': + } + case 'property': { // there should be only one item, which is the value. // copy the data up to the section. - var value = values[0] || {}; + const value = values[0] || {}; delete value.name; section.typeof = value.type; delete value.type; @@ -275,14 +275,15 @@ const processList = (section) => { section[k] = value[k]; }); break; + } - case 'event': + case 'event': { // event: each item is an argument. section.params = values; break; + } } - // section.listParsed = values; delete section.list; }; @@ -417,7 +418,7 @@ const finishSection = (section, parent) => { ctor.signatures.forEach((sig) => { sig.desc = ctor.desc; }); - sigs.push.apply(sigs, ctor.signatures); + sigs.push(...ctor.signatures); }); delete section.ctors; } @@ -486,7 +487,7 @@ const finishSection = (section, parent) => { // Not a general purpose deep copy. // But sufficient for these basic things. const deepCopy = (src, dest) => { - Object.keys(src).filter((k) => !dest.hasOwnProperty(k)).forEach((k) => { + Object.keys(src).filter((k) => !Object.prototype.hasOwnProperty.call(dest, k)).forEach((k) => { dest[k] = deepCopy_(src[k]); }); };