From af50ad08e495286e5db0196c3d8ca0ee52c02e75 Mon Sep 17 00:00:00 2001 From: eyelidlessness Date: Sun, 25 Dec 2022 10:17:34 -0800 Subject: [PATCH 01/11] Convert bad-external.js to TypeScript, fix type errors --- package-lock.json | 494 +++++++++++++++++- package.json | 9 +- src/transformer.js | 10 +- ...-external.spec.js => bad-external.spec.ts} | 66 +-- test/shared.ts | 10 + test/tsconfig.json | 4 + tsconfig.json | 7 +- typings/libxmljs.d.ts | 39 ++ typings/test.d.ts | 1 + vite.config.ts | 20 + 10 files changed, 615 insertions(+), 45 deletions(-) rename test/{bad-external.spec.js => bad-external.spec.ts} (81%) create mode 100644 test/shared.ts create mode 100644 test/tsconfig.json create mode 100644 typings/libxmljs.d.ts create mode 100644 typings/test.d.ts create mode 100644 vite.config.ts diff --git a/package-lock.json b/package-lock.json index ff2556d..553b090 100644 --- a/package-lock.json +++ b/package-lock.json @@ -365,6 +365,160 @@ } } }, + "@esbuild/android-arm": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.10.tgz", + "integrity": "sha512-RmJjQTRrO6VwUWDrzTBLmV4OJZTarYsiepLGlF2rYTVB701hSorPywPGvP6d8HCuuRibyXa5JX4s3jN2kHEtjQ==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.10.tgz", + "integrity": "sha512-47Y+NwVKTldTlDhSgJHZ/RpvBQMUDG7eKihqaF/u6g7s0ZPz4J1vy8A3rwnnUOF2CuDn7w7Gj/QcMoWz3U3SJw==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.10.tgz", + "integrity": "sha512-C4PfnrBMcuAcOurQzpF1tTtZz94IXO5JmICJJ3NFJRHbXXsQUg9RFG45KvydKqtFfBaFLCHpduUkUfXwIvGnRg==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.10.tgz", + "integrity": "sha512-bH/bpFwldyOKdi9HSLCLhhKeVgRYr9KblchwXgY2NeUHBB/BzTUHtUSBgGBmpydB1/4E37m+ggXXfSrnD7/E7g==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.10.tgz", + "integrity": "sha512-OXt7ijoLuy+AjDSKQWu+KdDFMBbdeaL6wtgMKtDUXKWHiAMKHan5+R1QAG6HD4+K0nnOvEJXKHeA9QhXNAjOTQ==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.10.tgz", + "integrity": "sha512-shSQX/3GHuspE3Uxtq5kcFG/zqC+VuMnJkqV7LczO41cIe6CQaXHD3QdMLA4ziRq/m0vZo7JdterlgbmgNIAlQ==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.10.tgz", + "integrity": "sha512-5YVc1zdeaJGASijZmTzSO4h6uKzsQGG3pkjI6fuXvolhm3hVRhZwnHJkforaZLmzvNv5Tb7a3QL2FAVmrgySIA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.10.tgz", + "integrity": "sha512-c360287ZWI2miBnvIj23bPyVctgzeMT2kQKR+x94pVqIN44h3GF8VMEs1SFPH1UgyDr3yBbx3vowDS1SVhyVhA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.10.tgz", + "integrity": "sha512-2aqeNVxIaRfPcIaMZIFoblLh588sWyCbmj1HHCCs9WmeNWm+EIN0SmvsmPvTa/TsNZFKnxTcvkX2eszTcCqIrA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.10.tgz", + "integrity": "sha512-sqMIEWeyrLGU7J5RB5fTkLRIFwsgsQ7ieWXlDLEmC2HblPYGb3AucD7inw2OrKFpRPKsec1l+lssiM3+NV5aOw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.10.tgz", + "integrity": "sha512-O7Pd5hLEtTg37NC73pfhUOGTjx/+aXu5YoSq3ahCxcN7Bcr2F47mv+kG5t840thnsEzrv0oB70+LJu3gUgchvg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.10.tgz", + "integrity": "sha512-FN8mZOH7531iPHM0kaFhAOqqNHoAb6r/YHW2ZIxNi0a85UBi2DO4Vuyn7t1p4UN8a4LoAnLOT1PqNgHkgBJgbA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.10.tgz", + "integrity": "sha512-Dg9RiqdvHOAWnOKIOTsIx8dFX9EDlY2IbPEY7YFzchrCiTZmMkD7jWA9UdZbNUygPjdmQBVPRCrLydReFlX9yg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.10.tgz", + "integrity": "sha512-XMqtpjwzbmlar0BJIxmzu/RZ7EWlfVfH68Vadrva0Wj5UKOdKvqskuev2jY2oPV3aoQUyXwnMbMrFmloO2GfAw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.10.tgz", + "integrity": "sha512-fu7XtnoeRNFMx8DjK3gPWpFBDM2u5ba+FYwg27SjMJwKvJr4bDyKz5c+FLXLUSSAkMAt/UL+cUbEbra+rYtUgw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.10.tgz", + "integrity": "sha512-61lcjVC/RldNNMUzQQdyCWjCxp9YLEQgIxErxU9XluX7juBdGKb0pvddS0vPNuCvotRbzijZ1pzII+26haWzbA==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.10.tgz", + "integrity": "sha512-JeZXCX3viSA9j4HqSoygjssdqYdfHd6yCFWyfSekLbz4Ef+D2EjvsN02ZQPwYl5a5gg/ehdHgegHhlfOFP0HCA==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.10.tgz", + "integrity": "sha512-3qpxQKuEVIIg8SebpXsp82OBrqjPV/OwNWmG+TnZDr3VGyChNnGMHccC1xkbxCHDQNnnXjxhMQNyHmdFJbmbRA==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.10.tgz", + "integrity": "sha512-z+q0xZ+et/7etz7WoMyXTHZ1rB8PMSNp/FOqURLJLOPb3GWJ2aj4oCqFCjPwEbW1rsT7JPpxeH/DwGAWk/I1Bg==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.10.tgz", + "integrity": "sha512-+YYu5sbQ9npkNT9Dec+tn1F/kjg6SMgr6bfi/6FpXYZvCRfu2YFPZGb+3x8K30s8eRxFpoG4sGhiSUkr1xbHEw==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.10.tgz", + "integrity": "sha512-Aw7Fupk7XNehR1ftHGYwUteyJ2q+em/aE+fVU3YMTBN2V5A7Z4aVCSV+SvCp9HIIHZavPFBpbdP3VfjQpdf6Xg==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.10.tgz", + "integrity": "sha512-qddWullt3sC1EIpfHvCRBq3H4g3L86DZpD6n8k2XFjFVyp01D++uNbN1hT/JRsHxTbyyemZcpwL5aRlJwc/zFw==", + "dev": true, + "optional": true + }, "@eslint/eslintrc": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", @@ -519,6 +673,21 @@ "@types/node": "*" } }, + "@types/chai": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz", + "integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==", + "dev": true + }, + "@types/chai-subset": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.3.tgz", + "integrity": "sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==", + "dev": true, + "requires": { + "@types/chai": "*" + } + }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", @@ -592,9 +761,9 @@ "dev": true }, "@types/node": { - "version": "18.11.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.11.tgz", - "integrity": "sha512-KJ021B1nlQUBLopzZmPBVuGU9un7WJd/W4ya7Ih02B4Uwky5Nja0yGYav2EfYIk0RR2Q9oVhf60S2XR1BCWJ2g==", + "version": "18.11.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz", + "integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng==", "dev": true }, "@types/normalize-package-data": { @@ -663,6 +832,12 @@ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, "aggregate-error": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", @@ -1310,6 +1485,12 @@ "node-releases": "^1.1.75" } }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, "builtin-modules": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", @@ -1852,6 +2033,36 @@ "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "dev": true }, + "esbuild": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.10.tgz", + "integrity": "sha512-z5dIViHoVnw2l+NCJ3zj5behdXjYvXne9gL18OOivCadXDUhyDkeSvEtLcGVAJW2fNmh33TDUpsi704XYlDodw==", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.16.10", + "@esbuild/android-arm64": "0.16.10", + "@esbuild/android-x64": "0.16.10", + "@esbuild/darwin-arm64": "0.16.10", + "@esbuild/darwin-x64": "0.16.10", + "@esbuild/freebsd-arm64": "0.16.10", + "@esbuild/freebsd-x64": "0.16.10", + "@esbuild/linux-arm": "0.16.10", + "@esbuild/linux-arm64": "0.16.10", + "@esbuild/linux-ia32": "0.16.10", + "@esbuild/linux-loong64": "0.16.10", + "@esbuild/linux-mips64el": "0.16.10", + "@esbuild/linux-ppc64": "0.16.10", + "@esbuild/linux-riscv64": "0.16.10", + "@esbuild/linux-s390x": "0.16.10", + "@esbuild/linux-x64": "0.16.10", + "@esbuild/netbsd-x64": "0.16.10", + "@esbuild/openbsd-x64": "0.16.10", + "@esbuild/sunos-x64": "0.16.10", + "@esbuild/win32-arm64": "0.16.10", + "@esbuild/win32-ia32": "0.16.10", + "@esbuild/win32-x64": "0.16.10" + } + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -4507,6 +4718,12 @@ "minimist": "^1.2.5" } }, + "jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, "jsx-ast-utils": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", @@ -4769,6 +4986,12 @@ "uc.micro": "^1.0.1" } }, + "local-pkg": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.2.tgz", + "integrity": "sha512-mlERgSPrbxU3BP4qBqAvvwlgW4MTg78iwJdGGnv7kibKjWcJksrG3t6LB5lXI93wXRDvG4NpUgJFmTG4T6rdrg==", + "dev": true + }, "locate-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", @@ -5317,6 +5540,32 @@ } } }, + "mlly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.0.0.tgz", + "integrity": "sha512-QL108Hwt+u9bXdWgOI0dhzZfACovn5Aen4Xvc8Jasd9ouRH4NjnrXEiyP3nVvJo91zPlYjVRckta0Nt2zfoR6g==", + "dev": true, + "requires": { + "acorn": "^8.8.1", + "pathe": "^1.0.0", + "pkg-types": "^1.0.0", + "ufo": "^1.0.0" + }, + "dependencies": { + "acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true + }, + "pathe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.0.0.tgz", + "integrity": "sha512-nPdMG0Pd09HuSsr7QOKUXO2Jr9eqaDiZvDwdyIhNG5SHYujkQHYKDfGQkulBxvbDHz8oHLsTgKN86LSwYzSHAg==", + "dev": true + } + } + }, "mocha": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", @@ -6531,12 +6780,24 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, + "pathe": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-0.2.0.tgz", + "integrity": "sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==", + "dev": true + }, "pathval": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", "dev": true }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -6582,6 +6843,25 @@ } } }, + "pkg-types": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.1.tgz", + "integrity": "sha512-jHv9HB+Ho7dj6ItwppRDDl0iZRYBD0jsakHXtFgoLr+cHSF6xC+QL54sJmWxyGxOLYSHm0afhXhXcQDQqH9z8g==", + "dev": true, + "requires": { + "jsonc-parser": "^3.2.0", + "mlly": "^1.0.0", + "pathe": "^1.0.0" + }, + "dependencies": { + "pathe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.0.0.tgz", + "integrity": "sha512-nPdMG0Pd09HuSsr7QOKUXO2Jr9eqaDiZvDwdyIhNG5SHYujkQHYKDfGQkulBxvbDHz8oHLsTgKN86LSwYzSHAg==", + "dev": true + } + } + }, "pluralize": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", @@ -6625,6 +6905,25 @@ } } }, + "postcss": { + "version": "8.4.20", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", + "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", + "dev": true, + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "dependencies": { + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true + } + } + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -6982,6 +7281,15 @@ "glob": "^7.1.3" } }, + "rollup": { + "version": "3.7.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.7.5.tgz", + "integrity": "sha512-z0ZbqHBtS/et2EEUKMrAl2CoSdwN7ZPzL17UMiKN9RjjqHShTlv7F9J6ZJZJNREYjBh3TvBrdfjkFDIXFNeuiQ==", + "dev": true, + "requires": { + "fsevents": "~2.3.2" + } + }, "run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -7216,6 +7524,30 @@ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "spawn-wrap": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", @@ -7521,6 +7853,23 @@ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, + "strip-literal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.0.0.tgz", + "integrity": "sha512-5o4LsH1lzBzO9UFH63AJ2ad2/S2AVx6NtjOcaz+VTT2h1RiRvbipW72z8M/lxEhcPHDBQwpDrnTF7sXy/7OwCQ==", + "dev": true, + "requires": { + "acorn": "^8.8.1" + }, + "dependencies": { + "acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true + } + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -7637,6 +7986,24 @@ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, + "tinybench": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.3.1.tgz", + "integrity": "sha512-hGYWYBMPr7p4g5IarQE7XhlyWveh1EKhy4wUBS1LrHXCKYgvz+4/jCqgmJqZxxldesn05vccrtME2RLLZNW7iA==", + "dev": true + }, + "tinypool": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.3.0.tgz", + "integrity": "sha512-NX5KeqHOBZU6Bc0xj9Vr5Szbb1j8tUHIeD18s41aDJaPeC5QTdEhK0SpdpUrZlj2nv5cctNcSjaKNanXlfcVEQ==", + "dev": true + }, + "tinyspy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-1.0.2.tgz", + "integrity": "sha512-bSGlgwLBYf7PnUsQ6WOc6SJ3pGOcd+d8AA6EUnLDDM0kWEstC1JIlSZA3UNliDXhd9ABoS7hiRBDCu+XP/sf1Q==", + "dev": true + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -7772,6 +8139,12 @@ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", "dev": true }, + "ufo": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.0.1.tgz", + "integrity": "sha512-boAm74ubXHY7KJQZLlXrtMz52qFvpsbOxDcZOnw/Wf+LS4Mmyu7JxmzD4tDLtUQtmZECypJ0FrCz4QIe6dvKRA==", + "dev": true + }, "uglify-js": { "version": "3.14.0", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.0.tgz", @@ -7896,6 +8269,121 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" }, + "vite": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.0.3.tgz", + "integrity": "sha512-HvuNv1RdE7deIfQb8mPk51UKjqptO/4RXZ5yXSAvurd5xOckwS/gg8h9Tky3uSbnjYTgUm0hVCet1cyhKd73ZA==", + "dev": true, + "requires": { + "esbuild": "^0.16.3", + "fsevents": "~2.3.2", + "postcss": "^8.4.20", + "resolve": "^1.22.1", + "rollup": "^3.7.0" + }, + "dependencies": { + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + } + } + }, + "vite-node": { + "version": "0.26.2", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.26.2.tgz", + "integrity": "sha512-4M/zlatItZAyvrQG+82zQBhgDjRZRhVJYFW4T9wcAKh7eMmSiPOVSeI5zsV9UzHXgCcIDKX0o0r3s4OxExTHqg==", + "dev": true, + "requires": { + "debug": "^4.3.4", + "mlly": "^1.0.0", + "pathe": "^0.2.0", + "source-map": "^0.6.1", + "source-map-support": "^0.5.21", + "vite": "^3.0.0 || ^4.0.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "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.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "vitest": { + "version": "0.26.2", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.26.2.tgz", + "integrity": "sha512-Jvqxh6SDy9SsuslkDjts0iDewDIdq4rveEt69YgDuAb1tVDGV0lDepVaeAFraoySWqneJmOt4TngFFNhlw7GfA==", + "dev": true, + "requires": { + "@types/chai": "^4.3.4", + "@types/chai-subset": "^1.3.3", + "@types/node": "*", + "acorn": "^8.8.1", + "acorn-walk": "^8.2.0", + "chai": "^4.3.7", + "debug": "^4.3.4", + "local-pkg": "^0.4.2", + "source-map": "^0.6.1", + "strip-literal": "^1.0.0", + "tinybench": "^2.3.1", + "tinypool": "^0.3.0", + "tinyspy": "^1.0.2", + "vite": "^3.0.0 || ^4.0.0", + "vite-node": "0.26.2" + }, + "dependencies": { + "acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "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.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", diff --git a/package.json b/package.json index d5f60ad..81b0139 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,9 @@ "eslint-fix": "eslint app.js src/**/*.js test/**/*.js --fix", "prettier-fix": "prettier --write .", "test": "nyc mocha test/*.spec.js --timeout 6000 && npm run prettier-fix && npm run eslint-fix && node update-readme-with-shield-badge.js", - "test:watch": "nodemon --exec 'mocha test/*.spec.js --timeout 6000000' --watch src --watch test --ext js,xml,xsl", + "vitest": "vitest run", + "test:watch": "nodemon --exec 'mocha test/*.spec.js --timeout 6000000' --watch src --watch test --ext js,xml,xsl,ts", + "vitest:watch": "vitest", "build-docs": "rimraf docs && ./node_modules/.bin/jsdoc -c jsdoc.config.js", "develop": "DEBUG=api,transformer,markdown,language node app.js & http-server test/forms -p 8081" }, @@ -50,6 +52,7 @@ }, "devDependencies": { "@types/express": "^4.17.14", + "@types/node": "^18.11.17", "@xmldom/xmldom": "^0.7.9", "chai": "^4.3.7", "chai-as-promised": "^7.1.1", @@ -75,7 +78,9 @@ "nodemon": "^2.0.20", "nyc": "^15.1.0", "prettier": "^2.8.1", - "rimraf": "^3.0.2" + "rimraf": "^3.0.2", + "vite": "^4.0.3", + "vitest": "^0.26.2" }, "volta": { "node": "16.5.0", diff --git a/src/transformer.js b/src/transformer.js index f1c2b36..6fc599b 100644 --- a/src/transformer.js +++ b/src/transformer.js @@ -23,9 +23,6 @@ const xslModel = fs.readFileSync( ); /** * @constant - * @static - * @type {object} - * @default */ const NAMESPACES = { xmlns: 'http://www.w3.org/2002/xforms', @@ -44,18 +41,19 @@ const version = _getVersion(); */ /** - * @typedef {Function} TransformPreprocess - * @this {typeof libxmljs} + * @callback TransformPreprocess + * @param {typeof libxmljs} this * @param {XMLJSDocument} doc */ /** * @typedef Survey * @property {string} xform - * @property {string} theme + * @property {string} [theme] * @property {boolean} [markdown] * @property {Record} [media] * @property {boolean} [openclinica] + * @property {TransformPreprocess} [preprocess] */ /** diff --git a/test/bad-external.spec.js b/test/bad-external.spec.ts similarity index 81% rename from test/bad-external.spec.js rename to test/bad-external.spec.ts index cc8170f..76e21bb 100644 --- a/test/bad-external.spec.js +++ b/test/bad-external.spec.ts @@ -1,17 +1,17 @@ -const chai = require('chai'); -const chaiAsPromised = require('chai-as-promised'); +import chai from 'chai'; +import transformer from '../src/transformer'; +import { getXForm, parser } from './shared'; -const { expect } = chai; -const fs = require('fs'); -const { DOMParser } = require('@xmldom/xmldom'); -const transformer = require('../src/transformer'); - -chai.use(chaiAsPromised); +import type { TransformPreprocess } from '../src/transformer'; describe('for incompatible forms that require preprocessing', () => { - const xform = fs.readFileSync('./test/forms/bad-external.xml'); - const parser = new DOMParser(); - const preprocess = function (doc) { + let xform: string; + + beforeAll(async () => { + xform = await getXForm('bad-external.xml'); + }); + + const preprocess: TransformPreprocess = function (doc) { const libxmljs = this; const { NAMESPACES } = transformer; const model = doc.get('/h:html/h:head/xmlns:model', NAMESPACES); @@ -36,8 +36,8 @@ describe('for incompatible forms that require preprocessing', () => { * Preprocess Model * - add instances */ - const match = query.match(/^instance\('([^)]+)'\)/); - const id = match && match.length ? match[1] : null; + const match = query?.match(/^instance\('([^)]+)'\)/); + const id = match?.length ? match[1] : null; if ( id && @@ -78,10 +78,12 @@ describe('for incompatible forms that require preprocessing', () => { // add all attributes including unknowns, except the query attribute attrs.forEach((attr) => { - const obj = {}; - obj[attr.name()] = attr.value(); - if (attr.name() !== 'query') { - select1.attr(obj); + const name = attr.name(); + + if (name !== 'query') { + const value = attr.value(); + + select1.attr(name, value); } }); @@ -108,7 +110,6 @@ describe('for incompatible forms that require preprocessing', () => { } ); - // console.log( doc.toString( true ) ); return doc; }; @@ -125,7 +126,7 @@ describe('for incompatible forms that require preprocessing', () => { expect(doc.getElementsByTagName('instance')).to.have.length(2), expect(doc.getElementById('existing')).to.not.be.null, expect( - doc.getElementById('existing').getAttribute('src') + doc.getElementById('existing')!.getAttribute('src') ).to.equal('jr://file/existing.xml'), expect(doc.getElementById('counties')).to.be.null, expect(doc.getElementById('cities')).to.be.null, @@ -147,15 +148,15 @@ describe('for incompatible forms that require preprocessing', () => { expect(doc.getElementsByTagName('instance')).to.have.length(4), expect(doc.getElementById('existing')).to.not.be.null, expect( - doc.getElementById('existing').getAttribute('src') + doc.getElementById('existing')!.getAttribute('src') ).to.equal('jr://file/existing.xml'), expect(doc.getElementById('counties')).to.not.be.null, expect( - doc.getElementById('counties').getAttribute('src') + doc.getElementById('counties')!.getAttribute('src') ).to.equal('esri://file-csv/list_name/counties/itemsets.csv'), expect(doc.getElementById('cities')).to.not.be.null, expect( - doc.getElementById('cities').getAttribute('src') + doc.getElementById('cities')!.getAttribute('src') ).to.equal('esri://file-csv/list_name/cities/itemsets.csv'), ]); }); @@ -192,25 +193,28 @@ describe('for incompatible forms that require preprocessing', () => { "instance('cities')/root/item[state= /select_one_external/state and county= /select_one_external/county ]" ), expect( - selects[1].nextSibling.nextSibling.getAttribute('class') + ( + selects[1].nextSibling!.nextSibling! as Element + ).getAttribute('class') ).to.equal('itemset-labels'), expect( - selects[1].nextSibling.nextSibling.getAttribute( - 'data-label-ref' - ) + ( + selects[1].nextSibling!.nextSibling! as Element + ).getAttribute('data-label-ref') ).to.equal('translate(label)'), expect( - selects[1].nextSibling.nextSibling.getAttribute( - 'data-value-ref' - ) + ( + selects[1].nextSibling!.nextSibling! as Element + ).getAttribute('data-value-ref') ).to.equal('name'), ]); }); }); - it('fn does not correct instances if not necessary', () => { + it('fn does not correct instances if not necessary', async () => { + const xform = await getXForm('widgets.xml'); const result = transformer.transform({ - xform: fs.readFileSync('./test/forms/widgets.xml'), + xform, preprocess, }); diff --git a/test/shared.ts b/test/shared.ts new file mode 100644 index 0000000..6f05e1e --- /dev/null +++ b/test/shared.ts @@ -0,0 +1,10 @@ +import { DOMParser } from '@xmldom/xmldom'; +import fs from 'fs/promises'; + +export const getXForm = async (fileName: string) => { + const fileContents = await fs.readFile(`./test/forms/${fileName}`); + + return String(fileContents); +}; + +export const parser = new DOMParser(); diff --git a/test/tsconfig.json b/test/tsconfig.json new file mode 100644 index 0000000..d0791da --- /dev/null +++ b/test/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../tsconfig.json", + "files": ["../typings/test.d.ts"] +} diff --git a/tsconfig.json b/tsconfig.json index d04dbb8..a78b4ab 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,7 @@ "experimentalDecorators": true, "forceConsistentCasingInFileNames": true, "inlineSourceMap": true, - "lib": ["dom", "ES2018"], + "lib": ["ES2018"], "module": "amd", "moduleResolution": "node", "noEmit": true, @@ -21,8 +21,9 @@ "resolveJsonModule": true, "skipLibCheck": true, "strict": true, - "target": "es2018" + "target": "es2018", + "types": ["node"] }, - "exclude": ["node_modules"], + "exclude": ["node_modules", "typings/test.d.ts"], "include": ["src", "test", "typings"] } diff --git a/typings/libxmljs.d.ts b/typings/libxmljs.d.ts new file mode 100644 index 0000000..679e5de --- /dev/null +++ b/typings/libxmljs.d.ts @@ -0,0 +1,39 @@ +declare module 'libxmljs' { + export interface Node { + replace(node: Node): unknown; + } + + export interface Attr extends Node { + name(): string; + value(): string | null; + } + + interface ParentNode extends Node { + attrs(): Attr[]; + childNodes(): Element[]; + + get( + expression: string, + namespaces?: Record + ): Element | null; + + find( + expression: string, + namespaces?: Record + ): Element[]; + + node(localName: string): Element; + } + + interface NamespacedNode extends ParentNode { + namespace(uri: string): this; + } + + export interface Element extends NamespacedNode { + attr(name: string): Attr | null; + attr(name: string, value: string): this; + attr(attributes: Record): this; + } + + export interface Document extends NamespacedNode {} +} diff --git a/typings/test.d.ts b/typings/test.d.ts new file mode 100644 index 0000000..9896c47 --- /dev/null +++ b/typings/test.d.ts @@ -0,0 +1 @@ +/// diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..59b5bbe --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,20 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + assetsInclude: ['**/*.xml', '**/*.xsl'], + build: { + outDir: 'build', + minify: 'esbuild', + sourcemap: true, + }, + esbuild: { + sourcemap: 'inline', + }, + test: { + globals: true, + include: [ + // 'test/**/*.spec.js', + 'test/**/*.spec.ts', + ], + }, +}); From 006a77d1a55cfd31bcdde136cd2f8cc3e10e68f6 Mon Sep 17 00:00:00 2001 From: eyelidlessness Date: Wed, 21 Dec 2022 16:12:36 -0800 Subject: [PATCH 02/11] Convert language.spec.js to TypeScript, fix type errors --- test/{language.spec.js => language.spec.ts} | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) rename test/{language.spec.js => language.spec.ts} (94%) diff --git a/test/language.spec.js b/test/language.spec.ts similarity index 94% rename from test/language.spec.js rename to test/language.spec.ts index a5a6dda..b09981d 100644 --- a/test/language.spec.js +++ b/test/language.spec.ts @@ -1,11 +1,16 @@ -const chai = require('chai'); +import language from '../src/language'; -const { expect } = chai; -const language = require('../src/language'); +import type { LanguageObj } from '../src/language'; describe('language', () => { describe('parser', () => { - const test = (t) => { + type ParserTestParameters = [ + name: string, + sample: string, + language: LanguageObj + ]; + + const test = (t: ParserTestParameters) => { const name = t[0]; const sample = t[1]; const expected = t[2]; @@ -14,7 +19,7 @@ describe('language', () => { }); }; - [ + const tests: ParserTestParameters[] = [ // no lanuage (only inline XForm text) [ '', @@ -238,6 +243,8 @@ describe('language', () => { src: 'nonexisting (0a)', }, ], - ].forEach(test); + ]; + + tests.forEach(test); }); }); From 3a5a276b3d873b98298196b7e8c15ac572b77764 Mon Sep 17 00:00:00 2001 From: eyelidlessness Date: Wed, 21 Dec 2022 16:13:54 -0800 Subject: [PATCH 03/11] Convert markdown.spec.js to TypeScript, fix type errors --- test/{markdown.spec.js => markdown.spec.ts} | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) rename test/{markdown.spec.js => markdown.spec.ts} (98%) diff --git a/test/markdown.spec.js b/test/markdown.spec.ts similarity index 98% rename from test/markdown.spec.js rename to test/markdown.spec.ts index 307793f..fabb9c4 100644 --- a/test/markdown.spec.js +++ b/test/markdown.spec.ts @@ -1,7 +1,4 @@ -const chai = require('chai'); - -const { expect } = chai; -const markdown = require('../src/markdown'); +import markdown from '../src/markdown'; describe('markdown', () => { describe('rendering', () => { From 3dc854e728b62bab41f4d7200a7abfef8d0d35d3 Mon Sep 17 00:00:00 2001 From: eyelidlessness Date: Sun, 25 Dec 2022 10:41:06 -0800 Subject: [PATCH 04/11] Rename transformer.spec.js to transformer.spec.ts... ... as a separate commit so the diff makes more sense --- test/{transformer.spec.js => transformer.spec.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/{transformer.spec.js => transformer.spec.ts} (100%) diff --git a/test/transformer.spec.js b/test/transformer.spec.ts similarity index 100% rename from test/transformer.spec.js rename to test/transformer.spec.ts From c183c1026c869e3d05ff9146570abf240cf3f7ef Mon Sep 17 00:00:00 2001 From: eyelidlessness Date: Sun, 25 Dec 2022 10:41:40 -0800 Subject: [PATCH 05/11] Convert transformer.spec.js to TypeScript, ... + fix type errors + a variety of cleanup and consistency across test modules + trivial conversion of sheets.spec.js to TypeScript as well # Conflicts: # test/transformer.spec.ts --- src/transformer.js | 2 +- test/bad-external.spec.ts | 218 ++- test/shared.ts | 87 +- test/{sheets.spec.js => sheets.spec.ts} | 6 +- test/transformer.spec.ts | 2150 ++++++++++------------- vite.config.ts | 15 +- 6 files changed, 1167 insertions(+), 1311 deletions(-) rename test/{sheets.spec.js => sheets.spec.ts} (74%) diff --git a/src/transformer.js b/src/transformer.js index 6fc599b..db94c41 100644 --- a/src/transformer.js +++ b/src/transformer.js @@ -52,7 +52,7 @@ const version = _getVersion(); * @property {string} [theme] * @property {boolean} [markdown] * @property {Record} [media] - * @property {boolean} [openclinica] + * @property {boolean | number} [openclinica] * @property {TransformPreprocess} [preprocess] */ diff --git a/test/bad-external.spec.ts b/test/bad-external.spec.ts index 76e21bb..0b3fc20 100644 --- a/test/bad-external.spec.ts +++ b/test/bad-external.spec.ts @@ -1,19 +1,23 @@ -import chai from 'chai'; -import transformer from '../src/transformer'; -import { getXForm, parser } from './shared'; - -import type { TransformPreprocess } from '../src/transformer'; +import { NAMESPACES } from '../src/transformer'; +import { + Document, + getTransformedForm, + getTransformedModelDocument, + parser, + XMLDocument, +} from './shared'; + +import type { + TransformedSurvey, + TransformPreprocess, +} from '../src/transformer'; describe('for incompatible forms that require preprocessing', () => { - let xform: string; - - beforeAll(async () => { - xform = await getXForm('bad-external.xml'); - }); + let preprocessed: TransformedSurvey; + let preprocessedForm: Document; const preprocess: TransformPreprocess = function (doc) { const libxmljs = this; - const { NAMESPACES } = transformer; const model = doc.get('/h:html/h:head/xmlns:model', NAMESPACES); if (!model) { @@ -113,118 +117,106 @@ describe('for incompatible forms that require preprocessing', () => { return doc; }; - it('preprocess fn does nothing if not provided...', () => { - const result = transformer.transform({ - xform, + beforeAll(async () => { + preprocessed = await getTransformedForm('bad-external.xml', { + preprocess, }); + preprocessedForm = parser.parseFromString( + preprocessed.form, + 'text/html' + ); + }); - return result.then((res) => { - const doc = parser.parseFromString(res.model, 'text/xml'); - - return Promise.all([ - expect(doc).to.be.an('object'), - expect(doc.getElementsByTagName('instance')).to.have.length(2), - expect(doc.getElementById('existing')).to.not.be.null, - expect( - doc.getElementById('existing')!.getAttribute('src') - ).to.equal('jr://file/existing.xml'), - expect(doc.getElementById('counties')).to.be.null, - expect(doc.getElementById('cities')).to.be.null, - ]); - }); + it('preprocess fn does nothing if not provided...', async () => { + const doc = await getTransformedModelDocument('bad-external.xml'); + + return Promise.all([ + expect(doc).to.be.an.instanceOf(XMLDocument), + expect(doc.getElementsByTagName('instance')).to.have.length(2), + expect(doc.getElementById('existing')).to.not.be.null, + expect( + doc.getElementById('existing')!.getAttribute('src') + ).to.equal('jr://file/existing.xml'), + expect(doc.getElementById('counties')).to.be.null, + expect(doc.getElementById('cities')).to.be.null, + ]); }); - it('preprocess fn corrects instances if necessary', () => { - const result = transformer.transform({ - xform, - preprocess, - }); + it('preprocess fn corrects instances if necessary', async () => { + const preprocessedModel = parser.parseFromString( + preprocessed.model, + 'text/xml' + ); - return result.then((res) => { - const doc = parser.parseFromString(res.model, 'text/xml'); - - return Promise.all([ - expect(doc).to.be.an('object'), - expect(doc.getElementsByTagName('instance')).to.have.length(4), - expect(doc.getElementById('existing')).to.not.be.null, - expect( - doc.getElementById('existing')!.getAttribute('src') - ).to.equal('jr://file/existing.xml'), - expect(doc.getElementById('counties')).to.not.be.null, - expect( - doc.getElementById('counties')!.getAttribute('src') - ).to.equal('esri://file-csv/list_name/counties/itemsets.csv'), - expect(doc.getElementById('cities')).to.not.be.null, - expect( - doc.getElementById('cities')!.getAttribute('src') - ).to.equal('esri://file-csv/list_name/cities/itemsets.csv'), - ]); - }); + return Promise.all([ + expect(preprocessedModel).to.be.an.instanceOf(XMLDocument), + expect( + preprocessedModel.getElementsByTagName('instance') + ).to.have.length(4), + expect(preprocessedModel.getElementById('existing')).to.not.be.null, + expect( + preprocessedModel + .getElementById('existing')! + .getAttribute('src') + ).to.equal('jr://file/existing.xml'), + expect(preprocessedModel.getElementById('counties')).to.not.be.null, + expect( + preprocessedModel + .getElementById('counties')! + .getAttribute('src') + ).to.equal('esri://file-csv/list_name/counties/itemsets.csv'), + expect(preprocessedModel.getElementById('cities')).to.not.be.null, + expect( + preprocessedModel.getElementById('cities')!.getAttribute('src') + ).to.equal('esri://file-csv/list_name/cities/itemsets.csv'), + ]); }); it('fn corrects body elements if necessary', () => { - const result = transformer.transform({ - xform, - preprocess, - }); - - return result.then((res) => { - const doc = parser.parseFromString(res.form, 'text/xml'); - const selects = doc.getElementsByTagName('select'); - - return Promise.all([ - expect(selects).to.have.length(2), // language selector and the one with appearance=minimal - expect(selects[1].getAttribute('name')).to.equal( - '/select_one_external/city2' - ), - expect(selects[1].getAttribute('data-type-xml')).to.equal( - 'select1' - ), - expect( - selects[1] - .getElementsByTagName('option')[0] - .getAttribute('class') - ).to.equal('itemset-template'), - expect( - selects[1] - .getElementsByTagName('option')[0] - .getAttribute('data-items-path') - ).to.equal( - "instance('cities')/root/item[state= /select_one_external/state and county= /select_one_external/county ]" - ), - expect( - ( - selects[1].nextSibling!.nextSibling! as Element - ).getAttribute('class') - ).to.equal('itemset-labels'), - expect( - ( - selects[1].nextSibling!.nextSibling! as Element - ).getAttribute('data-label-ref') - ).to.equal('translate(label)'), - expect( - ( - selects[1].nextSibling!.nextSibling! as Element - ).getAttribute('data-value-ref') - ).to.equal('name'), - ]); - }); + const selects = preprocessedForm.getElementsByTagName('select'); + + return Promise.all([ + expect(selects).to.have.length(2), // language selector and the one with appearance=minimal + expect(selects[1].getAttribute('name')).to.equal( + '/select_one_external/city2' + ), + expect(selects[1].getAttribute('data-type-xml')).to.equal( + 'select1' + ), + expect( + selects[1] + .getElementsByTagName('option')[0] + .getAttribute('class') + ).to.equal('itemset-template'), + expect( + selects[1] + .getElementsByTagName('option')[0] + .getAttribute('data-items-path') + ).to.equal( + "instance('cities')/root/item[state= /select_one_external/state and county= /select_one_external/county ]" + ), + expect( + (selects[1].nextSibling!.nextSibling! as Element).getAttribute( + 'class' + ) + ).to.equal('itemset-labels'), + expect( + (selects[1].nextSibling!.nextSibling! as Element).getAttribute( + 'data-label-ref' + ) + ).to.equal('translate(label)'), + expect( + (selects[1].nextSibling!.nextSibling! as Element).getAttribute( + 'data-value-ref' + ) + ).to.equal('name'), + ]); }); it('fn does not correct instances if not necessary', async () => { - const xform = await getXForm('widgets.xml'); - const result = transformer.transform({ - xform, - preprocess, - }); - - return result.then((res) => { - const doc = parser.parseFromString(res.model, 'text/xml'); - - return Promise.all([ - expect(doc).to.be.an('object'), - expect(doc.getElementById('counties')).to.be.null, - ]); - }); + return Promise.all([ + expect(preprocessedForm).to.be.an.instanceOf(Document), + expect(preprocessedForm.getElementById('counties')).to.be.null, + ]); }); }); diff --git a/test/shared.ts b/test/shared.ts index 6f05e1e..41668b2 100644 --- a/test/shared.ts +++ b/test/shared.ts @@ -1,5 +1,8 @@ import { DOMParser } from '@xmldom/xmldom'; import fs from 'fs/promises'; +import { transform } from '../src/transformer'; + +import type { Survey } from '../src/transformer'; export const getXForm = async (fileName: string) => { const fileContents = await fs.readFile(`./test/forms/${fileName}`); @@ -7,4 +10,86 @@ export const getXForm = async (fileName: string) => { return String(fileContents); }; -export const parser = new DOMParser(); +type GetTransformedFormOptions = Omit; + +export const getTransformedForm = async ( + fileName: string, + options?: GetTransformedFormOptions +) => { + const xform = await getXForm(fileName); + + return transform({ + ...options, + xform, + }); +}; + +const attributeMissedValuePattern = + /^\[xmldom warning\]\s+attribute "[^"]+" missed value!!/; + +class SuppressAttributeShorthandWarningDOMParser extends DOMParser { + private isParsingHTML = false; + + constructor() { + super({ + errorHandler: { + warning: (msg: string) => { + if ( + this.isParsingHTML && + attributeMissedValuePattern.test(msg) + ) { + return; + } + + console.warn(msg); + }, + }, + }); + } + + parseFromString(xmlsource: string, mimeType?: string) { + if (mimeType === 'text/html') { + this.isParsingHTML = true; + } + + try { + return super.parseFromString(xmlsource, mimeType); + } finally { + this.isParsingHTML = false; + } + } +} + +export const parser = new SuppressAttributeShorthandWarningDOMParser(); + +export const getTransformedFormDocument = async ( + fileName: string, + options?: GetTransformedFormOptions +) => { + const { form } = await getTransformedForm(fileName, options); + + return parser.parseFromString(form, 'text/html'); +}; + +export const getTransformedModelDocument = async ( + fileName: string, + options?: GetTransformedFormOptions +) => { + const { model } = await getTransformedForm(fileName, options); + + return parser.parseFromString(model, 'text/xml'); +}; + +/** + * TODO: `@xmldom/xmldom` does not export `Document`. It's pretty linkely that @see {@link https://github.com/WebReflection/linkedom | `linkedom`}: + * + * 1. Does export it. + * 2. Is a drop-in replacement for `@xmldom/xmldom`. + * 3. Could very possibly go away soon anyway ;) + */ +export const Document = parser.parseFromString('', 'text/html').constructor; + +/** + * TODO: this is at least temporarily a necessary fib. + */ +export const XMLDocument = Document; diff --git a/test/sheets.spec.js b/test/sheets.spec.ts similarity index 74% rename from test/sheets.spec.js rename to test/sheets.spec.ts index 7bb3549..7a931c6 100644 --- a/test/sheets.spec.js +++ b/test/sheets.spec.ts @@ -1,8 +1,4 @@ -/* eslint-env mocha */ -const chai = require('chai'); - -const { expect } = chai; -const { sheets } = require('../src/transformer'); +import { sheets } from '../src/transformer'; describe('sheets', () => { it('should return an xslForm sheet', () => { diff --git a/test/transformer.spec.ts b/test/transformer.spec.ts index caa7e1b..dbd867f 100644 --- a/test/transformer.spec.ts +++ b/test/transformer.spec.ts @@ -1,20 +1,18 @@ -const chai = require('chai'); -const chaiAsPromised = require('chai-as-promised'); - -const { expect } = chai; -const fs = require('fs'); -const { DOMParser } = require('@xmldom/xmldom'); - -const parser = new DOMParser(); -const transformer = require('../src/transformer'); - -chai.use(chaiAsPromised); - -function parseHtmlForm(transformationResult) { - return parser.parseFromString(transformationResult.form, 'text/html'); -} - -function findElementByName(htmlDoc, tagName, nameAttributeValue) { +import { transform } from '../src/transformer'; +import { + getTransformedForm, + getTransformedFormDocument, + getXForm, + parser, +} from './shared'; + +import type { TransformedSurvey } from '../src/transformer'; + +function findElementByName( + htmlDoc: Document, + tagName: string, + nameAttributeValue: string +) { const elements = Array.prototype.slice.call( htmlDoc.getElementsByTagName(tagName) ); @@ -25,7 +23,11 @@ function findElementByName(htmlDoc, tagName, nameAttributeValue) { return target || null; } -function findElementsByName(htmlDoc, tagName, nameAttributeValue) { +function findElementsByName( + htmlDoc: Document, + tagName: string, + nameAttributeValue: string +) { const elements = Array.prototype.slice.call( htmlDoc.getElementsByTagName(tagName) ); @@ -36,158 +38,159 @@ function findElementsByName(htmlDoc, tagName, nameAttributeValue) { } describe('transformer', () => { - describe('transforms valid XForms', () => { - const xform = fs.readFileSync('./test/forms/widgets.xml', 'utf8'); - const result = transformer.transform({ - xform, - }); + let advancedRequired: TransformedSurvey; + let autocomplete: TransformedSurvey; + let autocompleteDoc: Document; + let externalXForm: string; + let external: TransformedSurvey; + let formattedOutput: TransformedSurvey; + let itemsetDoc: Document; + let modelNamespace: TransformedSurvey; + let widgetsXForm: string; + let widgets: TransformedSurvey; + + beforeAll(async () => { + advancedRequired = await getTransformedForm('advanced-required.xml'); + autocomplete = await getTransformedForm('autocomplete.xml'); + autocompleteDoc = parser.parseFromString( + autocomplete.form, + 'text/html' + ); + externalXForm = await getXForm('external.xml'); + external = await getTransformedForm('external.xml'); + formattedOutput = await getTransformedForm('formatted-output.xml'); + itemsetDoc = await getTransformedFormDocument('itemset.xml'); + modelNamespace = await getTransformedForm('model-namespace.xml'); + widgetsXForm = await getXForm('widgets.xml'); + widgets = await getTransformedForm('widgets.xml'); + }); + describe('transforms valid XForms', () => { it('without an error', () => Promise.all([ - expect(result).to.eventually.to.be.an('object'), - expect(result).to.eventually.have.property('form').and.to.not.be - .empty, - expect(result).to.eventually.have.property('model').and.to.not - .be.empty, - expect(result).to.eventually.have.property('transformerVersion') - .and.to.not.be.empty, + expect(widgets).to.be.an('object'), + expect(widgets).to.have.property('form').and.to.not.be.empty, + expect(widgets).to.have.property('model').and.to.not.be.empty, + expect(widgets).to.have.property('transformerVersion').and.to + .not.be.empty, ])); it('does not include the xform in the response', () => - expect(result).to.eventually.not.have.property('xform')); + expect(widgets).to.not.have.property('xform')); }); describe('transforms invalid XForms', () => { const invalidXForms = [undefined, null, '', '']; invalidXForms.forEach((xform) => { - it('with a parse error', () => { - const result = transformer.transform({ + it.fails('with a parse error', async () => { + await transform({ + // @ts-expect-error xform, }); - - return expect(result).to.eventually.be.rejectedWith(Error); }); }); }); describe('puts attributes on root', () => { - it('copies the formId', () => { - const xform = fs.readFileSync('./test/forms/widgets.xml', 'utf8'); - const result = transformer.transform({ xform }); - - return expect(result) - .to.eventually.have.property('form') + it('copies the formId', async () => { + expect(widgets) + .to.have.property('form') .and.to.contain('data-form-id="widgets"'); }); - it('copies the formId with accents', () => { - const xform = fs.readFileSync( - './test/forms/form-id-with-accent.xml', - 'utf8' - ); - const result = transformer.transform({ xform }); + it('copies the formId with accents', async () => { + const result = await getTransformedForm('form-id-with-accent.xml'); return expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.contain('data-form-id="Éphémère"'); }); // https://github.com/enketo/enketo-transformer/issues/100 - it('copies the formId with spaces', () => { - const xform = fs.readFileSync( - './test/forms/form-id-with-space.xml', - 'utf8' - ); - const result = transformer.transform({ xform }); + it('copies the formId with spaces', async () => { + const result = await getTransformedForm('form-id-with-space.xml'); return expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.contain('data-form-id="FormId with spaces"'); }); }); describe('copies attributes on the ``', () => { it('copies the odk:xforms-version attribute', () => { - const xform = fs.readFileSync( - './test/forms/autocomplete.xml', - 'utf8' - ); - const result = transformer.transform({ xform }); - - return expect(result) - .to.eventually.have.property('model') + expect(autocomplete) + .to.have.property('model') .and.to.contain('odk:xforms-version="1.0.0"'); }); }); describe('manipulates themes and', () => { - const xform = fs.readFileSync('./test/forms/widgets.xml', 'utf8'); - - it('adds a provided theme if none is defined in the XForm', () => { - const result = transformer.transform({ - xform, + it('adds a provided theme if none is defined in the XForm', async () => { + const result = await getTransformedForm('widgets.xml', { theme: 'mytheme', }); - return expect(result) - .to.eventually.have.property('form') + expect(result) + .to.have.property('form') .and.to.contain('theme-mytheme'); }); - it('leaves the XForm-defined theme unchanged if the theme value provided is falsy', () => { - const newXform = xform.replace( + it('leaves the XForm-defined theme unchanged if the theme value provided is falsy', async () => { + const newXform = widgetsXForm.replace( '', '' ); - const result1 = transformer.transform({ + const result1 = await transform({ xform: newXform, }); - const result2 = transformer.transform({ + const result2 = await transform({ xform: newXform, theme: '', }); - const result3 = transformer.transform({ + const result3 = await transform({ xform: newXform, + // @ts-expect-error theme: null, }); - const result4 = transformer.transform({ + const result4 = await transform({ xform: newXform, + // @ts-expect-error theme: false, }); return Promise.all([ expect(result1) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.contain('theme-one'), expect(result2) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.contain('theme-one'), expect(result3) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.contain('theme-one'), expect(result4) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.contain('theme-one'), ]); }); - it('replaces a theme defined in the XForm with a provided one', () => { - const newXform = xform.replace( + it('replaces a theme defined in the XForm with a provided one', async () => { + const newXform = widgetsXForm.replace( '', '' ); - const result = transformer.transform({ + const result = await transform({ xform: newXform, theme: 'mytheme', }); return Promise.all([ expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.not.contain('theme-one'), expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.contain('theme-mytheme'), ]); }); @@ -195,16 +198,8 @@ describe('transformer', () => { describe('manipulates languages and', () => { it('provides a languageMap as output property', () => { - const xform = fs.readFileSync( - './test/forms/advanced-required.xml', - 'utf8' - ); - const result = transformer.transform({ - xform, - }); - - return expect(result) - .to.eventually.have.property('languageMap') + expect(advancedRequired) + .to.have.property('languageMap') .and.to.deep.equal({ dutch: 'nl', english: 'en', @@ -212,60 +207,36 @@ describe('transformer', () => { }); it('provides an empty languageMap as output property if nothing was changed', () => { - const xform = fs.readFileSync('./test/forms/widgets.xml', 'utf8'); - const result = transformer.transform({ - xform, - }); - - return expect(result) - .to.eventually.have.property('languageMap') + expect(widgets) + .to.have.property('languageMap') .and.to.deep.equal({}); }); }); describe('renders markdown', () => { - it('takes into account that libxmljs Element.text() converts html entities', () => { - const xform = fs.readFileSync('./test/forms/external.xml', 'utf8'); - const result = transformer.transform({ - xform, - }); - + it('takes into account that libxmljs Element.text() converts html entities', async () => { return Promise.all([ - expect(result) - .to.eventually.have.property('form') + expect(external) + .to.have.property('form') .and.to.not.contain( '<span style="color:pink;">Intro</span>' ), - expect(result) - .to.eventually.have.property('form') + expect(external) + .to.have.property('form') .and.to.contain('Intro'), ]); }); it('and picks up formatting of s', () => { - const xform = fs.readFileSync( - './test/forms/formatted-output.xml', - 'utf8' - ); - const result = transformer.transform({ - xform, - }); - - return expect(result) - .to.eventually.have.property('form') + expect(formattedOutput) + .to.have.property('form') .and.to.contain( 'formatted: and' ); }); it('preserves text containing special string replacement sequences', async () => { - const xform = fs.readFileSync( - './test/forms/md-str-replace-chars.xml', - 'utf8' - ); - const result = await transformer.transform({ - xform, - }); + const result = await getTransformedForm('md-str-replace-chars.xml'); expect(result.form).to.contain( "$' is $` this $& the $$ real $0 $<life>?" @@ -274,18 +245,13 @@ describe('transformer', () => { }); describe('does not render markdown', () => { - it('when `markdown: false` is provided as option', () => { - const xform = fs.readFileSync( - './test/forms/formatted-output.xml', - 'utf8' - ); - const result = transformer.transform({ - xform, + it('when `markdown: false` is provided as option', async () => { + const result = await getTransformedForm('formatted-output.xml', { markdown: false, }); - return expect(result) - .to.eventually.have.property('form') + expect(result) + .to.have.property('form') .and.to.contain( 'formatted: * * and _normal_ text' ); @@ -293,226 +259,204 @@ describe('transformer', () => { }); describe('arbitrary HTML', () => { - it('strips arbitrary HTML in labels but preserves text', () => { - const xform = fs.readFileSync( - './test/forms/arbitrary-html.xml', - 'utf8' - ); - const result = transformer.transform({ - xform, - }); + it('strips arbitrary HTML in labels but preserves text', async () => { + const result = await getTransformedForm('arbitrary-html.xml'); return Promise.all([ expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.not.contain('
'), expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.contain('Label text'), ]); }); }); describe('manipulates media sources', () => { - it('in the View by replacing media elements according to a provided map', () => { - const xform = fs.readFileSync('./test/forms/widgets.xml', 'utf8'); + it('in the View by replacing media elements according to a provided map', async () => { const media = { 'happy.jpg': '/i/am/happy.jpg', 'pigeon.png': '/a/b/pigeon.png', }; - const result1 = transformer.transform({ - xform, - }); - const result2 = transformer.transform({ - xform, + const result1 = widgets; + const result2 = await transform({ + xform: widgetsXForm, media, }); return Promise.all([ expect(result1) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.contain('jr://images/happy.jpg'), expect(result1) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.contain('jr://images/pigeon.png'), expect(result1) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.not.contain('/i/am/happy.jpg'), expect(result1) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.not.contain('/a/b/pigeon.png'), expect(result2) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.not.contain('jr://images/happy.jpg'), expect(result2) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.not.contain('jr://images/pigeon.png'), expect(result2) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.contain('/i/am/happy.jpg'), expect(result2) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.contain('/a/b/pigeon.png'), ]); }); - it('in the View by replacing big-image link hrefs according to a provided map', () => { + it('in the View by replacing big-image link hrefs according to a provided map', async () => { const img = 'jr://images/happy.jpg'; - const xform = fs - .readFileSync('./test/forms/widgets.xml', 'utf8') - .replace( - img, - `${img}\njr://images/very-happy.jpg` - ); + const xform = widgetsXForm.replace( + img, + `${img}\njr://images/very-happy.jpg` + ); const media = { 'happy.jpg': '/i/am/happy.jpg', 'very-happy.jpg': '/i/am/very-happy.jpg', }; - const result = transformer.transform({ + const result = await transform({ xform, media, }); return Promise.all([ expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.not.to.contain('jr://images/happy.jpg'), expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.not.to.contain('jr://images/very-happy.jpg'), expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.contain('/i/am/happy.jpg'), expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.contain('/i/am/very-happy.jpg'), ]); }); - it('in the Model by replacing them according to a provided map', () => { - const xform = fs.readFileSync('./test/forms/external.xml', 'utf8'); + it('in the Model by replacing them according to a provided map', async () => { const media = { 'neighborhoods.csv': '/path/to/neighborhoods.csv', 'cities.xml': '/path/to/cities.xml', }; - const result1 = transformer.transform({ - xform, - }); - const result2 = transformer.transform({ - xform, + const result1 = external; + const result2 = await transform({ + xform: externalXForm, media, }); return Promise.all([ expect(result1) - .to.eventually.have.property('model') + .to.have.property('model') .and.to.contain('jr://file-csv/neighborhoods.csv'), expect(result1) - .to.eventually.have.property('model') + .to.have.property('model') .and.to.contain('jr://file/cities.xml'), expect(result1) - .to.eventually.have.property('model') + .to.have.property('model') .and.to.not.contain('/path/to/neighborhoods.csv'), expect(result1) - .to.eventually.have.property('model') + .to.have.property('model') .and.to.not.contain('/path/to/cities.xml'), expect(result2) - .to.eventually.have.property('model') + .to.have.property('model') .and.to.not.contain('jr://file-csv/neighborhoods.csv'), expect(result2) - .to.eventually.have.property('model') + .to.have.property('model') .and.to.not.contain('jr://file/cities.xml'), expect(result2) - .to.eventually.have.property('model') + .to.have.property('model') .and.to.contain('/path/to/neighborhoods.csv'), expect(result2) - .to.eventually.have.property('model') + .to.have.property('model') .and.to.contain('/path/to/cities.xml'), ]); }); it(`in the model for binary questions that contain a default value by copying to a - src attribute and resolving the URL according to a provided map`, () => { - const xform = fs.readFileSync( - './test/forms/image-default.xml', - 'utf8' - ); + src attribute and resolving the URL according to a provided map`, async () => { const media = { 'happy.jpg': 'https://feelings/happy.jpg', 'unhappy.jpg': 'https://feelings/unhappy.jpg', 'indifferent.png': 'https://feelings/indifferent.png', }; - const result = transformer.transform({ - xform, + const result = await getTransformedForm('image-default.xml', { media, }); return Promise.all([ expect(result) - .to.eventually.have.property('model') + .to.have.property('model') .and.to.contain( 'jr://images/unhappy.jpg' ), expect(result) - .to.eventually.have.property('model') + .to.have.property('model') .and.to.contain( 'jr://images/indifferent.png' ), ]); }); - it('by adding a form logo if needed', () => { - const xform = fs.readFileSync('./test/forms/widgets.xml', 'utf8'); + it('by adding a form logo if needed', async () => { const media = { 'form_logo.png': '/i/am/logo.png', }; - const result1 = transformer.transform({ - xform, - }); - const result2 = transformer.transform({ - xform, + const result1 = widgets; + const result2 = await transform({ + xform: widgetsXForm, media, }); return Promise.all([ expect(result1) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.not.contain(' { - const xform = fs.readFileSync( - './test/forms/bold-media.xml', - 'utf8' - ); + it('without mangling markdown-created HTML elements', async () => { const media = { 'users.xml': '/path/to/users.xml', }; - const result = transformer.transform({ xform, media }); + const result = await getTransformedForm('bold-media.xml', { + media, + }); + return expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.contain('Note with bold nnnn'); }); describe('spaces in jr: media URLs', () => { - const xform = fs.readFileSync( - './test/forms/jr-url-space.xml', - 'utf8' - ); + let xform: string; - /** @type {import('../src/transformer).TransformedSurvey[]} */ - let results; + let results: TransformedSurvey[]; - const mediaMaps = [ + interface MediaMapTestParams { + description: string; + media: Record; + } + + const mediaMaps: MediaMapTestParams[] = [ { description: 'unescaped', media: { @@ -582,18 +526,16 @@ describe('transformer', () => { }, ]; - before((done) => { - Promise.all( + beforeAll(async () => { + xform = await getXForm('jr-url-space.xml'); + results = await Promise.all( mediaMaps.map(({ media }) => - transformer.transform({ + transform({ xform, media, }) ) - ).then((transformed) => { - results = transformed; - done(); - }, done); + ); }); mediaMaps.forEach(({ description }, index) => { @@ -718,7 +660,7 @@ describe('transformer', () => { '/hallo spaceboy/wishful beginnings.xml?p=q&r', }; - const result = await transformer.transform({ + const result = await transform({ xform, media, }); @@ -750,7 +692,7 @@ describe('transformer', () => { // Before that change, omitting a media mapping would fall back to an empty object // as a default. it('returns an empty media map when none was provided at the call site', async () => { - const result = await transformer.transform({ xform }); + const result = await transform({ xform }); expect(result.form).to.contain('jr://images/first%20image.jpg'); expect(result.form).to.contain('jr://audio/a%20song.mp3'); @@ -768,210 +710,133 @@ describe('transformer', () => { }); describe('processes questions with constraints', () => { - it('and adds the correct number of constraint-msg elements', () => { - const count = (result) => { + it('and adds the correct number of constraint-msg elements', async () => { + const count = (result: TransformedSurvey) => { const matches = result.form.match(/class="or-constraint-msg/g); return matches ? matches.length : 0; }; - const xform1 = fs.readFileSync('./test/forms/widgets.xml', 'utf8'); - const count1 = transformer - .transform({ - xform: xform1, - }) - .then(count); - const xform2 = fs.readFileSync( - './test/forms/advanced-required.xml', - 'utf8' - ); - const count2 = transformer - .transform({ - xform: xform2, - }) - .then(count); + + const count1 = count(widgets); + const count2 = count(advancedRequired); return Promise.all([ - expect(count1).to.eventually.equal(4), - expect(count2).to.eventually.equal(0), + expect(count1).to.equal(4), + expect(count2).to.equal(0), ]); }); }); describe('processes required questions', () => { it('and adds the data-required HTML attribute for required XForm attributes keeping the value unchanged', () => { - const xform = fs.readFileSync('./test/forms/widgets.xml', 'utf8'); - const result = transformer.transform({ - xform, - }); - - return Promise.all([ - expect(result) - .to.eventually.have.property('form') + Promise.all([ + expect(widgets) + .to.have.property('form') .and.to.contain('data-required="true()"'), - expect(result) - .to.eventually.have.property('form') + expect(widgets) + .to.have.property('form') .and.to.not.contain(' required="required"'), ]); }); - it('and does not add the data-required attribute if the value is false()', () => { - const xform = fs - .readFileSync('./test/forms/widgets.xml', 'utf8') - .replace('required="true()"', 'required="false()"'); - const result = transformer.transform({ + it('and does not add the data-required attribute if the value is false()', async () => { + const xform = widgetsXForm.replace( + 'required="true()"', + 'required="false()"' + ); + const result = await transform({ xform, }); - return expect(result) - .to.eventually.have.property('form') + expect(result) + .to.have.property('form') .and.to.not.contain('data-required'); }); - it('and adds the correct number of required-msg elements', () => { - const count = (result) => - result.form.match(/class="or-required-msg/g).length; - const xform1 = fs.readFileSync('./test/forms/widgets.xml', 'utf8'); - const count1 = transformer - .transform({ - xform: xform1, - }) - .then(count); - const xform2 = fs.readFileSync( - './test/forms/advanced-required.xml', - 'utf8' - ); - const count2 = transformer - .transform({ - xform: xform2, - }) - .then(count); + it('and adds the correct number of required-msg elements', async () => { + const count = (result: TransformedSurvey) => + result.form.match(/class="or-required-msg/g)!.length; + + const count1 = count(widgets); + const count2 = count(advancedRequired); return Promise.all([ - expect(count1).to.eventually.equal(1), - expect(count2).to.eventually.equal(2), + expect(count1).to.equal(1), + expect(count2).to.equal(2), ]); }); it('and adds a default requiredMsg if no custom is provided', () => { - const xform = fs.readFileSync('./test/forms/widgets.xml', 'utf8'); - const result = transformer.transform({ - xform, - }); - - return expect(result) - .to.eventually.have.property('form') + expect(widgets) + .to.have.property('form') .and.to.contain('data-i18n="constraint.required"'); }); it('and adds a custom requiredMsg if provided', () => { - const xform = fs - .readFileSync('./test/forms/advanced-required.xml', 'utf8') - .replace('required="true()"', 'required="false()"'); - const result = transformer.transform({ - xform, - }); - return Promise.all([ - expect(result) - .to.eventually.have.property('form') + expect(advancedRequired) + .to.have.property('form') .and.to.not.contain('data-i18n'), - expect(result) - .to.eventually.have.property('form') + expect(advancedRequired) + .to.have.property('form') .and.to.contain('custom verplicht bericht'), - expect(result) - .to.eventually.have.property('form') + expect(advancedRequired) + .to.have.property('form') .and.to.contain('custom required message'), ]); }); }); describe('processes readonly questions', () => { - it('and outputs a disabled attribute for readonly select-minimal questions with itemsets', () => { - const xform = fs.readFileSync( - './test/forms/select-dynamic-readonly.xml', - 'utf8' + it('and outputs a disabled attribute for readonly select-minimal questions with itemsets', async () => { + const doc = await getTransformedFormDocument( + 'select-dynamic-readonly.xml' ); - const transform = transformer - .transform({ xform }) - .then(parseHtmlForm); - return transform.then((doc) => - Promise.all([ - expect( - doc - .getElementsByTagName('option')[0] - .getAttribute('disabled') - ).to.equal('disabled'), - ]) - ); + expect( + doc.getElementsByTagName('option')[0].getAttribute('disabled') + ).to.equal('disabled'); }); }); describe('processes multiline questions', () => { it('and outputs a textarea for appearance="multiline" on text input', () => { - const xform = fs.readFileSync('./test/forms/widgets.xml', 'utf8'); - const result = transformer.transform({ - xform, - }); - - return expect(result) - .to.eventually.have.property('form') + expect(widgets) + .to.have.property('form') .and.to.contain(' { - const xform = fs - .readFileSync('./test/forms/widgets.xml', 'utf8') - .replace('appearance="multiline"', 'appearance="multi-line"'); - const result = transformer.transform({ - xform, - }); - - return expect(result) - .to.eventually.have.property('form') + expect(widgets) + .to.have.property('form') .and.to.contain(' { - const xform = fs - .readFileSync('./test/forms/widgets.xml', 'utf8') - .replace('appearance="multiline"', 'appearance="textarea"'); - const result = transformer.transform({ - xform, - }); - - return expect(result) - .to.eventually.have.property('form') + expect(widgets) + .to.have.property('form') .and.to.contain(' { - const xform = fs - .readFileSync('./test/forms/widgets.xml', 'utf8') - .replace('appearance="multiline"', 'appearance="text-area"'); - const result = transformer.transform({ - xform, - }); - - return expect(result) - .to.eventually.have.property('form') + expect(widgets) + .to.have.property('form') .and.to.contain(' { - const xform = fs - .readFileSync('./test/forms/widgets.xml', 'utf8') - .replace('appearance="multiline"', 'rows="5"'); - const result = transformer.transform({ - xform, - }); + it('and outputs a textarea for rows="x" attribute on text input, with a rows appearance', async () => { + const xform = widgetsXForm.replace( + 'appearance="multiline"', + 'rows="5"' + ); + const result = await transform({ xform }); return Promise.all([ expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.contain(' { describe('processes autocomplete questions by producing elements', () => { it('and outputs elements', () => { - const xform = fs.readFileSync('./test/forms/autocomplete.xml'); - const transform = transformer - .transform({ xform }) - .then(parseHtmlForm); - - return transform.then((doc) => - Promise.all([ - expect(doc).to.be.an('object'), - expect(doc.getElementsByTagName('select')).to.have.length( - 4 - ), - expect(doc.getElementsByTagName('datalist')).to.have.length( - 2 - ), - expect( - doc - .getElementById('selectoneautocompletethree') - .nodeName.toLowerCase() - ).to.equal('datalist'), - expect( - doc - .getElementsByTagName('input')[0] - .getAttribute('list') - ).to.equal('selectoneautocompletethree'), - expect( - doc - .getElementsByTagName('input')[0] - .getAttribute('type') - ).to.equal('text'), - expect( - doc - .getElementById('selectoneautocompletefour') - .nodeName.toLowerCase() - ).to.equal('datalist'), - expect( - doc - .getElementsByTagName('input')[1] - .getAttribute('list') - ).to.equal('selectoneautocompletefour'), - ]) - ); + return Promise.all([ + expect(autocompleteDoc).to.be.an('object'), + expect( + autocompleteDoc.getElementsByTagName('select') + ).to.have.length(4), + expect( + autocompleteDoc.getElementsByTagName('datalist') + ).to.have.length(2), + expect( + autocompleteDoc + .getElementById('selectoneautocompletethree')! + .nodeName.toLowerCase() + ).to.equal('datalist'), + expect( + autocompleteDoc + .getElementsByTagName('input')[0] + .getAttribute('list') + ).to.equal('selectoneautocompletethree'), + expect( + autocompleteDoc + .getElementsByTagName('input')[0] + .getAttribute('type') + ).to.equal('text'), + expect( + autocompleteDoc + .getElementById('selectoneautocompletefour')! + .nodeName.toLowerCase() + ).to.equal('datalist'), + expect( + autocompleteDoc + .getElementsByTagName('input')[1] + .getAttribute('list') + ).to.equal('selectoneautocompletefour'), + ]); }); }); describe('processes a model with namespaces', () => { - const xform = fs.readFileSync('./test/forms/model-namespace.xml'); - const result = transformer.transform({ - xform, - }); - it('leaves namespace prefixes and declarations intact on nodes', () => Promise.all([ - expect(result) - .to.eventually.have.property('model') + expect(modelNamespace) + .to.have.property('model') .and.to.contain(''), ])); }); describe('for backwards compatibility of forms without a /meta/instanceID node', () => { - const xform1 = fs.readFileSync('./test/forms/no-instance-id.xml'); - const result1 = transformer.transform({ - xform: xform1, - }); + let result1: TransformedSurvey; + beforeAll(async () => { + result1 = await getTransformedForm('no-instance-id.xml'); + }); it('adds a /meta/instanceID node', () => expect(result1) - .to.eventually.have.property('model') + .to.have.property('model') .and.to.contain('')); - const xform2 = fs.readFileSync('./test/forms/model-namespace.xml'); - const result2 = transformer.transform({ - xform: xform2, - }); - it('does not add it if it contains /meta/instanceID in the OpenRosa namespace', () => - expect(result2) - .to.eventually.have.property('model') + expect(modelNamespace) + .to.have.property('model') .and.to.not.contain('')); }); describe('converts deprecated', () => { - const xform = fs.readFileSync('./test/forms/deprecated.xml'); - const result = transformer.transform({ xform }); + it('method="form-data-post" to "post" in submission element', async () => { + const result = await getTransformedForm('deprecated.xml'); - it('method="form-data-post" to "post" in submission element', () => expect(result) - .to.eventually.have.property('form') - .and.to.contain('method="post"')); + .to.have.property('form') + .and.to.contain('method="post"'); + }); }); describe('itext ids for itemsets are extracted', () => { - const xform = fs.readFileSync('./test/forms/rank.xml', 'utf8'); const MATCH = /itemset-labels.+Mexico.+USA.+The Netherlands/; const REPLACE = /randomize\(.+\)/; - it('works for itemset nodesets using a simple randomize()', () => { - const result = transformer.transform({ xform }); + let xform: string; - return expect(result) - .to.eventually.have.property('form') - .and.to.match(MATCH); + beforeAll(async () => { + xform = await getXForm('rank.xml'); + }); + + it('works for itemset nodesets using a simple randomize()', async () => { + const result = await transform({ xform }); + + return expect(result).to.have.property('form').and.to.match(MATCH); }); - it('works for itemset nodesets using a randomize() with static seed', () => { - const result = transformer.transform({ + it('works for itemset nodesets using a randomize() with static seed', async () => { + const result = await transform({ xform: xform.replace( REPLACE, "randomize(instance('holiday')/root/item, 34)" ), }); - return expect(result) - .to.eventually.have.property('form') - .and.to.match(MATCH); + return expect(result).to.have.property('form').and.to.match(MATCH); }); - xit('works for itemset nodesets using a simple randomize() with complex multi-parameter predicate function', () => { - const result = transformer.transform({ + it.skip('works for itemset nodesets using a simple randomize() with complex multi-parameter predicate function', async () => { + const result = await transform({ xform: xform.replace( REPLACE, 'randomize(instance(\'holiday\')/root/item[value=concat("a", "b")]/name)' ), }); - return expect(result) - .to.eventually.have.property('form') - .and.to.match(MATCH); + return expect(result).to.have.property('form').and.to.match(MATCH); }); - xit('works for itemset nodesets using a randomize() with a static seed and with a complex multi-parameter predicate function', () => { - const result = transformer.transform({ + it.skip('works for itemset nodesets using a randomize() with a static seed and with a complex multi-parameter predicate function', async () => { + const result = await transform({ xform: xform.replace( REPLACE, 'randomize(instance(\'holiday\')/root/item[value=concat("a", "b")]/name, 34)' ), }); - return expect(result) - .to.eventually.have.property('form') - .and.to.match(MATCH); + return expect(result).to.have.property('form').and.to.match(MATCH); }); }); describe('range questions', () => { - it('with "picker" appearance, have the same HTML form output as the equivalent select-one-minimal question', () => { - const selectMinimalXform = fs.readFileSync( - './test/forms/select-one-numbers.xml', - 'utf8' - ); - const rangePickerXform = fs.readFileSync( - './test/forms/range-picker.xml', - 'utf8' - ); + it('with "picker" appearance, have the same HTML form output as the equivalent select-one-minimal question', async () => { + const results = await Promise.all([ + getTransformedForm('select-one-numbers.xml'), + getTransformedForm('range-picker.xml'), + ]); - return Promise.all([ - transformer.transform({ xform: selectMinimalXform }), - transformer.transform({ xform: rangePickerXform }), - ]).then((results) => { - // eliminate some acceptable differences: - const modifiedSelectMinimalResult = results[0].form - .replace('or-appearance-minimal', '') - .replace(/data-type-xml=".+" /, '') - .replace(/data-name=".+" /, ''); - const modifiedRangePickerResult = results[1].form - .replace('or-appearance-picker', '') - .replace(/data-type-xml=".+" /, '') - .replace(/min=".+" /, '') - .replace(/max=".+" /, '') - .replace(/step=".+" /, ''); - - expect(modifiedSelectMinimalResult).to.equal( - modifiedRangePickerResult - ); - }); + // eliminate some acceptable differences: + const modifiedSelectMinimalResult = results[0].form + .replace('or-appearance-minimal', '') + .replace(/data-type-xml=".+" /, '') + .replace(/data-name=".+" /, ''); + const modifiedRangePickerResult = results[1].form + .replace('or-appearance-picker', '') + .replace(/data-type-xml=".+" /, '') + .replace(/min=".+" /, '') + .replace(/max=".+" /, '') + .replace(/step=".+" /, ''); + + expect(modifiedSelectMinimalResult).to.equal( + modifiedRangePickerResult + ); }); }); describe('setvalue actions', () => { - const xform = fs.readFileSync('./test/forms/setvalue.xml', 'utf8'); - const transform = transformer.transform({ xform }).then(parseHtmlForm); - - it('included in XForm body', () => - transform.then((form) => { - const target = findElementByName(form, 'input', '/data/b'); - expect(target).to.not.equal(null); - expect(target.getAttribute('data-event')).to.equal( - 'odk-instance-first-load' - ); - expect(target.getAttribute('data-setvalue')).to.equal( - 'string-length(/data/c)' - ); - expect(target.getAttribute('data-type-xml')).to.equal('string'); - })); - - it('included as XForm sibling ', () => - transform.then((form) => { - const target = findElementByName(form, 'input', '/data/a'); - expect(target).to.not.equal(null); - expect(target.getAttribute('data-event')).to.equal( - 'odk-instance-first-load' - ); - expect(target.getAttribute('data-setvalue')).to.equal('"ab"'); - expect(target.getAttribute('data-type-xml')).to.equal('int'); - })); - - it('with odk-new-repeat included inside a repeat ', () => - transform.then((form) => { - const targets = findElementsByName( - form, - 'input', - '/data/person/age' - ); - // Duplicates added by xsl sheet are merged. - expect(targets.length).to.equal(1); - // The empty .setvalue label is removed. - expect(form.getElementsByTagName('label').length).to.equal(5); - const target = targets[0]; - expect(target).to.not.equal(null); - expect(target.getAttribute('data-event')).to.equal( - 'odk-new-repeat odk-instance-first-load' - ); - expect(target.getAttribute('data-setvalue')).to.equal( - '../../my_age + 2' - ); - expect(target.getAttribute('data-type-xml')).to.equal( - 'decimal' - ); - })); - - it('with xforms-value-changed included inside an input form control', () => - transform.then((form) => { - const target = findElementByName( - form, - 'input', - '/data/person/age_changed' - ); - expect(target).to.not.equal(null); - // The nested labels are removed - expect(form.getElementsByTagName('label').length).to.equal(5); - expect(target.getAttribute('data-event')).to.equal( - 'xforms-value-changed' - ); - expect(target.getAttribute('data-setvalue')).to.equal( - '"Age changed!"' - ); - expect(target.getAttribute('data-type-xml')).to.equal('string'); - // Check location as sibling of /data/person/age - const sibling = - target.parentNode.getElementsByTagName('input')[0]; - expect(sibling.getAttribute('name')).to.equal( - '/data/person/age' - ); - })); - - it('with xforms-value-changed included inside a select1 form control with minimal appearance', () => - transform.then((form) => { - const target = findElementByName( - form, - 'input', - '/data/my_age_changed' - ); - expect(target).to.not.equal(null); - // The nested labels are removed - expect(form.getElementsByTagName('label').length).to.equal(5); - expect(target.getAttribute('data-event')).to.equal( - 'xforms-value-changed' - ); - expect(target.getAttribute('data-setvalue')).to.equal('3+3'); - expect(target.getAttribute('data-type-xml')).to.equal('int'); - // check location of target as sibling + const sibling = target.parentNode.getElementsByTagName('select')[0]; + expect(sibling.getAttribute('name')).to.equal('/data/my_age'); + }); + + it('with xforms-value-changed included inside a select form control', async () => { const xform2 = xform.replace('appearance="minimal"', ''); - const transform = transformer - .transform({ xform: xform2 }) - .then(parseHtmlForm); - - return transform.then((form) => { - const target = findElementByName( - form, - 'input', - '/data/my_age_changed' - ); - expect(target).to.not.equal(null); - // The nested labels are removed - expect(form.getElementsByTagName('label').length).to.equal(6); - expect(target.getAttribute('data-event')).to.equal( - 'xforms-value-changed' - ); - expect(target.getAttribute('data-setvalue')).to.equal('3+3'); - expect(target.getAttribute('data-type-xml')).to.equal('int'); - // check location of target inside same label as input[name="/data/my_age"] - const radio = - target.parentNode.getElementsByTagName('input')[0]; - expect(radio.getAttribute('name')).to.equal('/data/my_age'); + const { form } = await transform({ + xform: xform2, }); + const doc = parser.parseFromString(form, 'text/html'); + const target = findElementByName( + doc, + 'input', + '/data/my_age_changed' + ); + + expect(target).to.not.equal(null); + // The nested labels are removed + expect(doc.getElementsByTagName('label').length).to.equal(6); + expect(target.getAttribute('data-event')).to.equal( + 'xforms-value-changed' + ); + expect(target.getAttribute('data-setvalue')).to.equal('3+3'); + expect(target.getAttribute('data-type-xml')).to.equal('int'); + + // check location of target inside same label as input[name="/data/my_age"] + const radio = target.parentNode.getElementsByTagName('input')[0]; + + expect(radio.getAttribute('name')).to.equal('/data/my_age'); }); - it('with xforms-value-changed included inside a rank form control', () => { + it('with xforms-value-changed included inside a rank form control', async () => { const xform2 = xform .replace('appearance="minimal"', '') .replace(/select1/g, 'odk:rank'); - const transform = transformer - .transform({ xform: xform2 }) - .then(parseHtmlForm); - - return transform.then((form) => { - const target = findElementByName( - form, - 'input', - '/data/my_age_changed' - ); - expect(target).to.not.equal(null); - // The nested labels are removed - expect(form.getElementsByTagName('label').length).to.equal(6); - expect(target.getAttribute('data-event')).to.equal( - 'xforms-value-changed' - ); - expect(target.getAttribute('data-setvalue')).to.equal('3+3'); - expect(target.getAttribute('data-type-xml')).to.equal('int'); - // check location of target inside same label as input[name="/data/my_age"] - const radio = - target.parentNode.getElementsByTagName('input')[0]; - expect(radio.getAttribute('name')).to.equal('/data/my_age'); + const { form } = await transform({ + xform: xform2, }); + const doc = parser.parseFromString(form, 'text/html'); + const target = findElementByName( + doc, + 'input', + '/data/my_age_changed' + ); + expect(target).to.not.equal(null); + // The nested labels are removed + expect(doc.getElementsByTagName('label').length).to.equal(6); + expect(target.getAttribute('data-event')).to.equal( + 'xforms-value-changed' + ); + expect(target.getAttribute('data-setvalue')).to.equal('3+3'); + expect(target.getAttribute('data-type-xml')).to.equal('int'); + // check location of target inside same label as input[name="/data/my_age"] + const radio = target.parentNode.getElementsByTagName('input')[0]; + expect(radio.getAttribute('name')).to.equal('/data/my_age'); }); - it('with xforms-value-changed included inside a range form control', () => { + it('with xforms-value-changed included inside a range form control', async () => { const xform2 = xform.replace( /(.*)<\/input>/gm, '$1' ); - const transform = transformer - .transform({ xform: xform2 }) - .then(parseHtmlForm); - - return transform.then((form) => { - const target = findElementByName( - form, - 'input', - '/data/person/age_changed' - ); - expect(target).to.not.equal(null); - // The nested labels are removed - expect(form.getElementsByTagName('label').length).to.equal(5); - expect(target.getAttribute('data-event')).to.equal( - 'xforms-value-changed' - ); - expect(target.getAttribute('data-setvalue')).to.equal( - '"Age changed!"' - ); - expect(target.getAttribute('data-type-xml')).to.equal('string'); - // Check location as sibling of /data/person/age - const sibling = - target.parentNode.getElementsByTagName('input')[0]; - expect(sibling.getAttribute('name')).to.equal( - '/data/person/age' - ); + const { form } = await transform({ + xform: xform2, }); + // console.log('form', form); + const doc = parser.parseFromString(form, 'text/html'); + const target = findElementByName( + doc, + 'input', + '/data/person/age_changed' + ); + + expect(target).to.not.equal(null); + // The nested labels are removed + expect(doc.getElementsByTagName('label').length).to.equal(5); + expect(target.getAttribute('data-event')).to.equal( + 'xforms-value-changed' + ); + expect(target.getAttribute('data-setvalue')).to.equal( + '"Age changed!"' + ); + expect(target.getAttribute('data-type-xml')).to.equal('string'); + + // Check location as sibling of /data/person/age + const sibling = target.parentNode.getElementsByTagName('input')[0]; + + expect(sibling.getAttribute('name')).to.equal('/data/person/age'); }); - it('with xforms-value-changed included inside a select form control with an itemset', () => { - const xform2 = fs.readFileSync('./test/forms/itemset.xml', 'utf8'); - const transform = transformer - .transform({ xform: xform2 }) - .then(parseHtmlForm); + it('with xforms-value-changed included inside a select form control with an itemset', async () => { + const target = findElementByName( + itemsetDoc, + 'input', + '/data/state_changed' + ); - return transform.then((form) => { - const target = findElementByName( - form, - 'input', - '/data/state_changed' - ); - expect(target).to.not.equal(null); - // The nested labels are removed - expect(target.getAttribute('data-event')).to.equal( - 'xforms-value-changed' - ); - expect(target.getAttribute('data-setvalue')).to.equal('3+3'); - expect(target.getAttribute('data-type-xml')).to.equal('string'); - // check location of target inside same label as input[name="/data/state"] - const parent = target.parentNode; - expect(parent.nodeName).to.equal('fieldset'); - expect( - parent.getElementsByTagName('input')[0].getAttribute('name') - ).to.equal('/data/state'); - }); + expect(target).to.not.equal(null); + // The nested labels are removed + expect(target.getAttribute('data-event')).to.equal( + 'xforms-value-changed' + ); + expect(target.getAttribute('data-setvalue')).to.equal('3+3'); + expect(target.getAttribute('data-type-xml')).to.equal('string'); + + // check location of target inside same label as input[name="/data/state"] + const parent = target.parentNode; + + expect(parent.nodeName).to.equal('fieldset'); + expect( + parent.getElementsByTagName('input')[0].getAttribute('name') + ).to.equal('/data/state'); }); - it('with multiple xforms-value-changed inside a single text input', () => { - const xform2 = fs.readFileSync( - './test/forms/setvalue-value-changed-multiple.xml', - 'utf8' - ); - const transform = transformer - .transform({ xform: xform2 }) - .then(parseHtmlForm); - - return transform.then((form) => { - const target = findElementByName(form, 'input', '/data/a'); - expect(target).to.not.equal(null); - expect(target.hasAttribute('data-event')).to.equal(false); - expect(target.hasAttribute('data-setvalue')).to.equal(false); - expect(target.getAttribute('data-type-xml')).to.equal('string'); - // check for 4 setvalue siblings - const parent = target.parentNode; - const sibs = Array.prototype.slice - .call(parent.getElementsByTagName('input')) - .slice(1); - // data/b - expect(sibs[0].getAttribute('name')).to.equal('/data/b'); - expect(sibs[0].getAttribute('data-setvalue')).to.equal('1 + 1'); - expect(sibs[0].getAttribute('data-event')).to.equal( - 'xforms-value-changed' - ); - expect(sibs[0].getAttribute('type')).to.equal('hidden'); - // data/c - expect(sibs[1].getAttribute('name')).to.equal('/data/c'); - expect(sibs[1].getAttribute('data-setvalue')).to.equal('now()'); - expect(sibs[1].getAttribute('data-event')).to.equal( - 'xforms-value-changed' - ); - expect(sibs[1].getAttribute('type')).to.equal('hidden'); - // data/d - expect(sibs[2].getAttribute('name')).to.equal('/data/d'); - expect(sibs[2].hasAttribute('data-setvalue')).to.equal(true); - expect(sibs[2].getAttribute('data-setvalue')).to.equal(''); - expect(sibs[2].getAttribute('data-event')).to.equal( - 'xforms-value-changed' - ); - expect(sibs[2].getAttribute('type')).to.equal('hidden'); - // data/e - expect(sibs[3].getAttribute('name')).to.equal('/data/e'); - expect(sibs[3].hasAttribute('data-setvalue')).to.equal(true); - expect(sibs[3].getAttribute('data-setvalue')).to.equal(''); - expect(sibs[3].getAttribute('data-event')).to.equal( - 'xforms-value-changed' + it('with multiple xforms-value-changed inside a single text input', async () => { + const doc = await getTransformedFormDocument( + 'setvalue-value-changed-multiple.xml' + ); + const target = findElementByName(doc, 'input', '/data/a'); + + expect(target).to.not.equal(null); + expect(target.hasAttribute('data-event')).to.equal(false); + expect(target.hasAttribute('data-setvalue')).to.equal(false); + expect(target.getAttribute('data-type-xml')).to.equal('string'); + + // check for 4 setvalue siblings + const parent = target.parentNode; + const sibs = Array.prototype.slice + .call(parent.getElementsByTagName('input')) + .slice(1); + + // data/b + expect(sibs[0].getAttribute('name')).to.equal('/data/b'); + expect(sibs[0].getAttribute('data-setvalue')).to.equal('1 + 1'); + expect(sibs[0].getAttribute('data-event')).to.equal( + 'xforms-value-changed' + ); + expect(sibs[0].getAttribute('type')).to.equal('hidden'); + + // data/c + expect(sibs[1].getAttribute('name')).to.equal('/data/c'); + expect(sibs[1].getAttribute('data-setvalue')).to.equal('now()'); + expect(sibs[1].getAttribute('data-event')).to.equal( + 'xforms-value-changed' + ); + expect(sibs[1].getAttribute('type')).to.equal('hidden'); + + // data/d + expect(sibs[2].getAttribute('name')).to.equal('/data/d'); + expect(sibs[2].hasAttribute('data-setvalue')).to.equal(true); + expect(sibs[2].getAttribute('data-setvalue')).to.equal(''); + expect(sibs[2].getAttribute('data-event')).to.equal( + 'xforms-value-changed' + ); + expect(sibs[2].getAttribute('type')).to.equal('hidden'); + + // data/e + expect(sibs[3].getAttribute('name')).to.equal('/data/e'); + expect(sibs[3].hasAttribute('data-setvalue')).to.equal(true); + expect(sibs[3].getAttribute('data-setvalue')).to.equal(''); + expect(sibs[3].getAttribute('data-event')).to.equal( + 'xforms-value-changed' + ); + expect(sibs[3].getAttribute('type')).to.equal('hidden'); + + // other form controls + const questions = Array.prototype.slice + .call(doc.getElementsByTagName('label')) + .filter((question) => + question.getAttribute('class').includes('question') ); - expect(sibs[3].getAttribute('type')).to.equal('hidden'); - - // other form controls - const questions = Array.prototype.slice - .call(form.getElementsByTagName('label')) - .filter((question) => - question.getAttribute('class').includes('question') - ); - expect(questions.length).to.equal(3); - - const c = questions[1].getElementsByTagName('input'); - expect(c.length).to.equal(1); - expect(c[0].getAttribute('name')).to.equal('/data/c'); - expect(c[0].hasAttribute('data-event')).to.equal(false); - expect(c[0].hasAttribute('data-setvalue')).to.equal(false); - - const d = questions[2].getElementsByTagName('input'); - expect(d.length).to.equal(1); - expect(d[0].getAttribute('name')).to.equal('/data/d'); - expect(d[0].hasAttribute('data-event')).to.equal(false); - expect(d[0].hasAttribute('data-setvalue')).to.equal(false); - }); + expect(questions.length).to.equal(3); + + const c = questions[1].getElementsByTagName('input'); + expect(c.length).to.equal(1); + expect(c[0].getAttribute('name')).to.equal('/data/c'); + expect(c[0].hasAttribute('data-event')).to.equal(false); + expect(c[0].hasAttribute('data-setvalue')).to.equal(false); + + const d = questions[2].getElementsByTagName('input'); + expect(d.length).to.equal(1); + expect(d[0].getAttribute('name')).to.equal('/data/d'); + expect(d[0].hasAttribute('data-event')).to.equal(false); + expect(d[0].hasAttribute('data-setvalue')).to.equal(false); }); - it('with a dynamic default set on a radiobutton question', () => { - const xform = fs.readFileSync( - './test/forms/setvalue-radiobuttons-default.xml', - 'utf8' + it('with a dynamic default set on a radiobutton question', async () => { + const doc = await getTransformedFormDocument( + 'setvalue-radiobuttons-default.xml' ); - const transform = transformer - .transform({ xform }) - .then(parseHtmlForm); + const sel1 = findElementsByName(doc, 'input', '/data/sel1'); - return transform.then((form) => { - const sel1 = findElementsByName(form, 'input', '/data/sel1'); - expect(sel1.length).to.equal(2); - expect(sel1[0].getAttribute('data-event')).to.equal( - 'odk-instance-first-load' - ); - // It probably wouldn't be an issue if the events and setvalue attributes were added to all radiobuttons (or checkboxes) - // but this test is to show it is deliberately/lazily only added to the first. - expect(sel1[1].getAttribute('data-event')).to.equal(''); - }); + expect(sel1.length).to.equal(2); + expect(sel1[0].getAttribute('data-event')).to.equal( + 'odk-instance-first-load' + ); + // It probably wouldn't be an issue if the events and setvalue attributes were added to all radiobuttons (or checkboxes) + // but this test is to show it is deliberately/lazily only added to the first. + expect(sel1[1].getAttribute('data-event')).to.equal(''); }); - it('with a dynamic default repeat question, that also gets its value set by a trigger', () => { - const xform = fs.readFileSync( - './test/forms/setvalue-repeat-tricky.xml', - 'utf8' + it('with a dynamic default repeat question, that also gets its value set by a trigger', async () => { + const doc = await getTransformedFormDocument( + 'setvalue-repeat-tricky.xml' + ); + const ages = findElementsByName( + doc, + 'input', + '/data/person/group/age' ); - const transform = transformer - .transform({ xform }) - .then(parseHtmlForm); - return transform.then((form) => { - const ages = findElementsByName( - form, - 'input', - '/data/person/group/age' - ); - expect(ages.length).to.equal(2); + expect(ages.length).to.equal(2); - const agePrimary = ages[1]; // actual form control shown in form - const ageHidden = ages[0]; // hidden setvalue/xforms-value-changed directive - expect(agePrimary.getAttribute('data-event')).to.equal( - 'odk-new-repeat odk-instance-first-load' - ); - expect(agePrimary.getAttribute('data-setvalue')).to.equal( - '100' - ); + const agePrimary = ages[1]; // actual form control shown in form + const ageHidden = ages[0]; // hidden setvalue/xforms-value-changed directive - expect(ageHidden.getAttribute('data-event')).to.equal( - 'xforms-value-changed' - ); - expect(ageHidden.getAttribute('data-setvalue')).to.equal('15'); - }); + expect(agePrimary.getAttribute('data-event')).to.equal( + 'odk-new-repeat odk-instance-first-load' + ); + expect(agePrimary.getAttribute('data-setvalue')).to.equal('100'); + + expect(ageHidden.getAttribute('data-event')).to.equal( + 'xforms-value-changed' + ); + expect(ageHidden.getAttribute('data-setvalue')).to.equal('15'); }); }); describe('setgeopoint actions', () => { - const xform = fs.readFileSync('./test/forms/setgeopoint.xml', 'utf8'); - const transform = transformer.transform({ xform }).then(parseHtmlForm); - - it('included in XForm body', () => - transform.then((form) => { - const target = findElementByName( - form, - 'input', - '/data/visible_first_load' - ); - expect(target).to.not.equal(null); - expect(target.getAttribute('data-event')).to.equal( - 'odk-instance-first-load' - ); - expect(target.hasAttribute('data-setgeopoint')).to.equal(true); - expect(target.getAttribute('data-type-xml')).to.equal( - 'geopoint' - ); - })); - - it('included as XForm sibling ', () => - transform.then((form) => { - const target = findElementByName( - form, - 'input', - '/data/hidden_first_load' - ); - expect(target).to.not.equal(null); - expect(target.getAttribute('data-event')).to.equal( - 'odk-instance-first-load' - ); - expect(target.hasAttribute('data-setgeopoint')).to.equal(true); - expect(target.getAttribute('data-type-xml')).to.equal( - 'geopoint' - ); - })); - - it('with odk-new-repeat included inside a repeat ', () => - transform.then((form) => { - const targets = findElementsByName( - form, - 'input', - '/data/repeats/first_load' - ); - // Duplicates added by xsl sheet are merged. - expect(targets.length).to.equal(1); - // The empty .setgeopoint label is removed. - expect(form.getElementsByTagName('label').length).to.equal(5); - const target = targets[0]; - expect(target).to.not.equal(null); - expect(target.getAttribute('data-event')).to.equal( - 'odk-new-repeat odk-instance-first-load' - ); - expect(target.hasAttribute('data-setgeopoint')).to.equal(true); - expect(target.getAttribute('data-type-xml')).to.equal( - 'geopoint' - ); - })); - - it('with xforms-value-changed included inside an input form control', () => - transform.then((form) => { - const target = findElementByName( - form, - 'input', - '/data/repeats/changed_location' - ); - expect(target).to.not.equal(null); - // The nested labels are removed - expect(form.getElementsByTagName('label').length).to.equal(5); - expect(target.getAttribute('data-event')).to.equal( - 'xforms-value-changed' - ); - expect(target.hasAttribute('data-setgeopoint')).to.equal(true); - expect(target.getAttribute('data-type-xml')).to.equal( - 'geopoint' - ); - // Check location as sibling of /data/repeats/changed_location - const sibling = - target.parentNode.getElementsByTagName('input')[0]; - expect(sibling.getAttribute('name')).to.equal( - '/data/repeats/changes' - ); - })); - - it('with xforms-value-changed included inside a select1 form control with minimal appearance', () => - transform.then((form) => { - const target = findElementByName( - form, - 'input', - '/data/changed_location' - ); - expect(target).to.not.equal(null); - // The nested labels are removed - expect(form.getElementsByTagName('label').length).to.equal(5); - expect(target.getAttribute('data-event')).to.equal( - 'xforms-value-changed' - ); - expect(target.hasAttribute('data-setgeopoint')).to.equal(true); - expect(target.getAttribute('data-type-xml')).to.equal( - 'geopoint' - ); - // check location of target as sibling + const sibling = target.parentNode.getElementsByTagName('select')[0]; + + expect(sibling.getAttribute('name')).to.equal('/data/changes'); + }); - it('with xforms-value-changed included inside a select form control', () => { + it('with xforms-value-changed included inside a select form control', async () => { const xform2 = xform.replace('appearance="minimal"', ''); - const transform = transformer - .transform({ xform: xform2 }) - .then(parseHtmlForm); - - return transform.then((form) => { - const target = findElementByName( - form, - 'input', - '/data/changed_location' - ); - expect(target).to.not.equal(null); - // The nested labels are removed - expect(form.getElementsByTagName('label').length).to.equal(6); - expect(target.getAttribute('data-event')).to.equal( - 'xforms-value-changed' - ); - expect(target.hasAttribute('data-setgeopoint')).to.equal(true); - expect(target.getAttribute('data-type-xml')).to.equal( - 'geopoint' - ); - // check location of target inside same label as input[name="/data/my_age"] - const radio = - target.parentNode.getElementsByTagName('input')[0]; - expect(radio.getAttribute('name')).to.equal('/data/changes'); + const { form } = await transform({ + xform: xform2, }); + const doc = parser.parseFromString(form, 'text/html'); + const target = findElementByName( + doc, + 'input', + '/data/changed_location' + ); + + expect(target).to.not.equal(null); + // The nested labels are removed + expect(doc.getElementsByTagName('label').length).to.equal(6); + expect(target.getAttribute('data-event')).to.equal( + 'xforms-value-changed' + ); + expect(target.hasAttribute('data-setgeopoint')).to.equal(true); + expect(target.getAttribute('data-type-xml')).to.equal('geopoint'); + + // check location of target inside same label as input[name="/data/my_age"] + const radio = target.parentNode.getElementsByTagName('input')[0]; + + expect(radio.getAttribute('name')).to.equal('/data/changes'); }); - it('with xforms-value-changed included inside a rank form control', () => { + it('with xforms-value-changed included inside a rank form control', async () => { const xform2 = xform .replace('appearance="minimal"', '') .replace(/select1/g, 'odk:rank'); - const transform = transformer - .transform({ xform: xform2 }) - .then(parseHtmlForm); - - return transform.then((form) => { - const target = findElementByName( - form, - 'input', - '/data/changed_location' - ); - expect(target).to.not.equal(null); - // The nested labels are removed - expect(form.getElementsByTagName('label').length).to.equal(6); - expect(target.getAttribute('data-event')).to.equal( - 'xforms-value-changed' - ); - expect(target.hasAttribute('data-setgeopoint')).to.equal(true); - expect(target.getAttribute('data-type-xml')).to.equal( - 'geopoint' - ); - // check location of target inside same label as input[name="/data/my_age"] - const radio = - target.parentNode.getElementsByTagName('input')[0]; - expect(radio.getAttribute('name')).to.equal('/data/changes'); + const { form } = await transform({ + xform: xform2, }); + const doc = parser.parseFromString(form, 'text/html'); + const target = findElementByName( + doc, + 'input', + '/data/changed_location' + ); + + expect(target).to.not.equal(null); + // The nested labels are removed + expect(doc.getElementsByTagName('label').length).to.equal(6); + expect(target.getAttribute('data-event')).to.equal( + 'xforms-value-changed' + ); + expect(target.hasAttribute('data-setgeopoint')).to.equal(true); + expect(target.getAttribute('data-type-xml')).to.equal('geopoint'); + + // check location of target inside same label as input[name="/data/my_age"] + const radio = target.parentNode.getElementsByTagName('input')[0]; + expect(radio.getAttribute('name')).to.equal('/data/changes'); }); - it('with xforms-value-changed included inside a range form control', () => { + it('with xforms-value-changed included inside a range form control', async () => { const xform2 = xform.replace( /(.*)<\/input>/gm, '$1' ); - const transform = transformer - .transform({ xform: xform2 }) - .then(parseHtmlForm); - - return transform.then((form) => { - const target = findElementByName( - form, - 'input', - '/data/repeats/changed_location' - ); - expect(target).to.not.equal(null); - // The nested labels are removed - expect(form.getElementsByTagName('label').length).to.equal(5); - expect(target.getAttribute('data-event')).to.equal( - 'xforms-value-changed' - ); - expect(target.hasAttribute('data-setgeopoint')).to.equal(true); - expect(target.getAttribute('data-type-xml')).to.equal( - 'geopoint' - ); - // Check location as sibling of /data/person/age - const sibling = - target.parentNode.getElementsByTagName('input')[0]; - expect(sibling.getAttribute('name')).to.equal( - '/data/repeats/changes' - ); + const { form } = await transform({ + xform: xform2, }); + const doc = parser.parseFromString(form, 'text/html'); + const target = findElementByName( + doc, + 'input', + '/data/repeats/changed_location' + ); + + expect(target).to.not.equal(null); + // The nested labels are removed + expect(doc.getElementsByTagName('label').length).to.equal(5); + expect(target.getAttribute('data-event')).to.equal( + 'xforms-value-changed' + ); + expect(target.hasAttribute('data-setgeopoint')).to.equal(true); + expect(target.getAttribute('data-type-xml')).to.equal('geopoint'); + + // Check location as sibling of /data/person/age + const sibling = target.parentNode.getElementsByTagName('input')[0]; + expect(sibling.getAttribute('name')).to.equal( + '/data/repeats/changes' + ); }); - it('with xforms-value-changed included inside a select form control with an itemset', () => { - const xform2 = fs.readFileSync('./test/forms/itemset.xml', 'utf8'); - const transform = transformer - .transform({ xform: xform2 }) - .then(parseHtmlForm); + it('with xforms-value-changed included inside a select form control with an itemset', async () => { + const target = findElementByName( + itemsetDoc, + 'input', + '/data/location_changed' + ); - return transform.then((form) => { - const target = findElementByName( - form, - 'input', - '/data/location_changed' - ); - expect(target).to.not.equal(null); - // The nested labels are removed - expect(target.getAttribute('data-event')).to.equal( - 'xforms-value-changed' - ); - expect(target.hasAttribute('data-setgeopoint')).to.equal(true); - expect(target.getAttribute('data-type-xml')).to.equal( - 'geopoint' - ); - // check location of target inside same label as input[name="/data/state"] - const parent = target.parentNode; - expect(parent.nodeName).to.equal('fieldset'); - expect( - parent.getElementsByTagName('input')[0].getAttribute('name') - ).to.equal('/data/state'); - }); + expect(target).to.not.equal(null); + // The nested labels are removed + expect(target.getAttribute('data-event')).to.equal( + 'xforms-value-changed' + ); + expect(target.hasAttribute('data-setgeopoint')).to.equal(true); + expect(target.getAttribute('data-type-xml')).to.equal('geopoint'); + + // check location of target inside same label as input[name="/data/state"] + const parent = target.parentNode; + expect(parent.nodeName).to.equal('fieldset'); + expect( + parent.getElementsByTagName('input')[0].getAttribute('name') + ).to.equal('/data/state'); }); - it('with multiple xforms-value-changed inside a single text input', () => { - const xform2 = fs.readFileSync( - './test/forms/setgeopoint-value-changed-multiple.xml', - 'utf8' - ); - const transform = transformer - .transform({ xform: xform2 }) - .then(parseHtmlForm); - - return transform.then((form) => { - const target = findElementByName(form, 'input', '/data/a'); - expect(target).to.not.equal(null); - expect(target.hasAttribute('data-event')).to.equal(false); - expect(target.hasAttribute('data-setgeopoint')).to.equal(false); - expect(target.getAttribute('data-type-xml')).to.equal('string'); - // check for 4 setgeopoint siblings - const parent = target.parentNode; - const sibs = Array.prototype.slice - .call(parent.getElementsByTagName('input')) - .slice(1); - // data/b - expect(sibs[0].getAttribute('name')).to.equal('/data/b'); - expect(sibs[0].hasAttribute('data-setgeopoint')).to.equal(true); - expect(sibs[0].getAttribute('data-event')).to.equal( - 'xforms-value-changed' - ); - expect(sibs[0].getAttribute('type')).to.equal('hidden'); - // data/c - expect(sibs[1].getAttribute('name')).to.equal('/data/c'); - expect(sibs[1].hasAttribute('data-setgeopoint')).to.equal(true); - expect(sibs[1].getAttribute('data-event')).to.equal( - 'xforms-value-changed' - ); - expect(sibs[1].getAttribute('type')).to.equal('hidden'); - // data/d - expect(sibs[2].getAttribute('name')).to.equal('/data/d'); - expect(sibs[2].hasAttribute('data-setgeopoint')).to.equal(true); - expect(sibs[2].getAttribute('data-event')).to.equal( - 'xforms-value-changed' - ); - expect(sibs[2].getAttribute('type')).to.equal('hidden'); - // data/e - expect(sibs[3].getAttribute('name')).to.equal('/data/e'); - expect(sibs[3].hasAttribute('data-setgeopoint')).to.equal(true); - expect(sibs[3].getAttribute('data-event')).to.equal( - 'xforms-value-changed' + it('with multiple xforms-value-changed inside a single text input', async () => { + const doc = await getTransformedFormDocument( + 'setgeopoint-value-changed-multiple.xml' + ); + const target = findElementByName(doc, 'input', '/data/a'); + + expect(target).to.not.equal(null); + expect(target.hasAttribute('data-event')).to.equal(false); + expect(target.hasAttribute('data-setgeopoint')).to.equal(false); + expect(target.getAttribute('data-type-xml')).to.equal('string'); + + // check for 4 setgeopoint siblings + const parent = target.parentNode; + const sibs = Array.prototype.slice + .call(parent.getElementsByTagName('input')) + .slice(1); + + // data/b + expect(sibs[0].getAttribute('name')).to.equal('/data/b'); + expect(sibs[0].hasAttribute('data-setgeopoint')).to.equal(true); + expect(sibs[0].getAttribute('data-event')).to.equal( + 'xforms-value-changed' + ); + expect(sibs[0].getAttribute('type')).to.equal('hidden'); + + // data/c + expect(sibs[1].getAttribute('name')).to.equal('/data/c'); + expect(sibs[1].hasAttribute('data-setgeopoint')).to.equal(true); + expect(sibs[1].getAttribute('data-event')).to.equal( + 'xforms-value-changed' + ); + expect(sibs[1].getAttribute('type')).to.equal('hidden'); + + // data/d + expect(sibs[2].getAttribute('name')).to.equal('/data/d'); + expect(sibs[2].hasAttribute('data-setgeopoint')).to.equal(true); + expect(sibs[2].getAttribute('data-event')).to.equal( + 'xforms-value-changed' + ); + expect(sibs[2].getAttribute('type')).to.equal('hidden'); + + // data/e + expect(sibs[3].getAttribute('name')).to.equal('/data/e'); + expect(sibs[3].hasAttribute('data-setgeopoint')).to.equal(true); + expect(sibs[3].getAttribute('data-event')).to.equal( + 'xforms-value-changed' + ); + expect(sibs[3].getAttribute('type')).to.equal('hidden'); + + // other form controls + const questions = Array.prototype.slice + .call(doc.getElementsByTagName('label')) + .filter((question) => + question.getAttribute('class').includes('question') ); - expect(sibs[3].getAttribute('type')).to.equal('hidden'); - - // other form controls - const questions = Array.prototype.slice - .call(form.getElementsByTagName('label')) - .filter((question) => - question.getAttribute('class').includes('question') - ); - expect(questions.length).to.equal(3); - - const c = questions[1].getElementsByTagName('input'); - expect(c.length).to.equal(1); - expect(c[0].getAttribute('name')).to.equal('/data/c'); - expect(c[0].hasAttribute('data-event')).to.equal(false); - expect(c[0].hasAttribute('data-setgeopoint')).to.equal(false); - - const d = questions[2].getElementsByTagName('input'); - expect(d.length).to.equal(1); - expect(d[0].getAttribute('name')).to.equal('/data/d'); - expect(d[0].hasAttribute('data-event')).to.equal(false); - expect(d[0].hasAttribute('data-setgeopoint')).to.equal(false); - }); + expect(questions.length).to.equal(3); + + const c = questions[1].getElementsByTagName('input'); + + expect(c.length).to.equal(1); + expect(c[0].getAttribute('name')).to.equal('/data/c'); + expect(c[0].hasAttribute('data-event')).to.equal(false); + expect(c[0].hasAttribute('data-setgeopoint')).to.equal(false); + + const d = questions[2].getElementsByTagName('input'); + + expect(d.length).to.equal(1); + expect(d[0].getAttribute('name')).to.equal('/data/d'); + expect(d[0].hasAttribute('data-event')).to.equal(false); + expect(d[0].hasAttribute('data-setgeopoint')).to.equal(false); }); - it('with a dynamic default repeat question, that also gets its value set by a trigger', () => { - const xform = fs.readFileSync( - './test/forms/setgeopoint-repeat-tricky.xml', - 'utf8' + it('with a dynamic default repeat question, that also gets its value set by a trigger', async () => { + const doc = await getTransformedFormDocument( + 'setgeopoint-repeat-tricky.xml' + ); + const ages = findElementsByName( + doc, + 'input', + '/data/person/group/age' ); - const transform = transformer - .transform({ xform }) - .then(parseHtmlForm); - return transform.then((form) => { - const ages = findElementsByName( - form, - 'input', - '/data/person/group/age' - ); - expect(ages.length).to.equal(2); + expect(ages.length).to.equal(2); - const agePrimary = ages[1]; // actual form control shown in form - const ageHidden = ages[0]; // hidden setgeopoint/xforms-value-changed directive - expect(agePrimary.getAttribute('data-event')).to.equal( - 'odk-new-repeat odk-instance-first-load' - ); - expect(agePrimary.hasAttribute('data-setgeopoint')).to.equal( - true - ); + const agePrimary = ages[1]; // actual form control shown in form + const ageHidden = ages[0]; // hidden setgeopoint/xforms-value-changed directive - expect(ageHidden.getAttribute('data-event')).to.equal( - 'xforms-value-changed' - ); - expect(ageHidden.hasAttribute('data-setgeopoint')).to.equal( - true - ); - }); + expect(agePrimary.getAttribute('data-event')).to.equal( + 'odk-new-repeat odk-instance-first-load' + ); + expect(agePrimary.hasAttribute('data-setgeopoint')).to.equal(true); + + expect(ageHidden.getAttribute('data-event')).to.equal( + 'xforms-value-changed' + ); + expect(ageHidden.hasAttribute('data-setgeopoint')).to.equal(true); }); }); }); describe('custom stuff', () => { describe('supports the enk:for attribute', () => { - const xform = fs.readFileSync('./test/forms/for.xml'); - const result = transformer.transform({ - xform, - }); + it('by turning it into the data-for attribute', async () => { + const result = await getTransformedForm('for.xml'); - it('by turning it into the data-for attribute', () => - Promise.all([ - expect(result) - .to.eventually.have.property('form') - .and.to.contain('data-for="../a"'), - ])); + expect(result) + .to.have.property('form') + .and.to.contain('data-for="../a"'); + }); }); describe('supports the oc:external attribute if openclinica=1', () => { - it('by turning it into the data-oc-external attribute', () => { - const xform = fs.readFileSync('./test/forms/oc-external.xml'); - const result = transformer.transform({ - xform, + it('by turning it into the data-oc-external attribute', async () => { + const result = await getTransformedForm('oc-external.xml', { openclinica: 1, }); return expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.contain('data-oc-external="clinicaldata"'); }); - it('for setvalue/odk-instance-first-load actions by turning it into the data-oc-external attribute', () => { - const xform = fs.readFileSync('./test/forms/oc-438-setvalue.xml'); - const result = transformer.transform({ - xform, + it('for setvalue/odk-instance-first-load actions by turning it into the data-oc-external attribute', async () => { + const result = await getTransformedForm('oc-438-setvalue.xml', { openclinica: 1, }); return expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.contain('data-oc-external="clinicaldata"'); }); - it('for setgeopoint/odk-instance-first-load actions by turning it into the data-oc-external attribute', () => { - const xform = fs.readFileSync( - './test/forms/oc-438-setgeopoint.xml' - ); - const result = transformer.transform({ - xform, + it('for setgeopoint/odk-instance-first-load actions by turning it into the data-oc-external attribute', async () => { + const result = await getTransformedForm('oc-438-setgeopoint.xml', { openclinica: 1, }); return expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.contain('data-oc-external="clinicaldata"'); }); }); describe('oc:relevantMsg binding attributes', () => { - const xform = fs.readFileSync( - './test/forms/relevant_constraint_required.xml' - ); - - it('if openclinica=1, are copied to or-relevant-msg elements or a default is added for relevant expressions', () => { - const result = transformer.transform({ - xform, - openclinica: 1, - }); + it('if openclinica=1, are copied to or-relevant-msg elements or a default is added for relevant expressions', async () => { + const result = await getTransformedForm( + 'relevant_constraint_required.xml', + { + openclinica: 1, + } + ); return expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.satisfy( - (form) => form.match(/or-relevant-msg/g).length === 4 + (form: string) => + form.match(/or-relevant-msg/g)!.length === 4 ); }); - it('are ignored by default', () => { - const result = transformer.transform({ - xform, - }); + it('are ignored by default', async () => { + const result = await getTransformedForm( + 'relevant_constraint_required.xml' + ); return expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.not.to.contain('or-relevant-msg'); }); }); describe('multiple OC constraints', () => { - const xform = fs.readFileSync( - './test/forms/oc-custom-multiple-constraints.xml' - ); - describe('if openclinica=1', () => { - const result = transformer.transform({ xform, openclinica: 1 }); + let result: TransformedSurvey; + + beforeAll(async () => { + result = await getTransformedForm( + 'oc-custom-multiple-constraints.xml', + { + openclinica: 1, + } + ); + }); describe('are added via oc:constraint[N] attribute', () => { it('works for N=1', () => expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.contain('data-oc-constraint1=". != \'a\'"')); it('works for N=20', () => expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.contain('data-oc-constraint20=". != \'c\'"')); // it( 'ignores oc:constraint without a number', () => { - // return expect( result ).to.eventually.have.property( 'form' ).and.to.not.contain( 'constraint to be ignored' ); + // return expect( result ).to.have.property( 'form' ).and.to.not.contain( 'constraint to be ignored' ); // } ); it('does not add constraint messages in this manner', () => expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.not.contain('data-oc-constraint20Msg="')); }); describe('can get individual constraint messages with the oc:constraint[N]Msg attribute', () => { it('works for N=1', () => expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.contain('class="or-constraint1-msg')); it('works for N=20', () => expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.to.contain('class="or-constraint20-msg')); it('ignores constraint messages without a number', () => // The text "msg to be ignored is actually part of the result but is not present in a .or-constraint-msg span elmement expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.not.to.match( /or-constraint-msg [^>]+>msg to be ignored/ )); @@ -1988,55 +1762,57 @@ describe('custom stuff', () => { }); describe('are ignored by default', () => { - const result = transformer.transform({ xform }); + let result: TransformedSurvey; + + beforeAll(async () => { + result = await getTransformedForm( + 'oc-custom-multiple-constraints.xml' + ); + }); it('for N=1 (attribute)', () => expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.not.to.contain('data-oc-constraint1=". != \'a\'"')); it('for N=20 (attribute)', () => expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.not.to.contain('data-oc-constraint20=". != \'c\'"')); it('for N=1 (message)', () => expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.not.to.contain('class="or-constraint1-msg')); it('for N=20 (message', () => expect(result) - .to.eventually.have.property('form') + .to.have.property('form') .and.not.to.contain('class="or-constraint20-msg')); }); - it('with different ways of specify a "value" for setvalue', () => { - const xform2 = fs.readFileSync( - './test/forms/setvalue-values.xml', - 'utf8' + it('with different ways of specify a "value" for setvalue', async () => { + const doc = await getTransformedFormDocument('setvalue-values.xml'); + const a = findElementByName(doc, 'input', '/data/a'); + expect(a.getAttribute('data-setvalue')).to.equal('"ab"'); + const b = findElementByName(doc, 'input', '/data/b'); + + expect(b.getAttribute('data-setvalue')).to.equal('"not ignored"'); + + const c = findElementByName(doc, 'input', '/data/c'); + + expect(c.getAttribute('data-setvalue')).to.equal( + "string-length('two')" ); - const transform = transformer - .transform({ xform: xform2 }) - .then(parseHtmlForm); - return transform.then((form) => { - const a = findElementByName(form, 'input', '/data/a'); - expect(a.getAttribute('data-setvalue')).to.equal('"ab"'); - const b = findElementByName(form, 'input', '/data/b'); - expect(b.getAttribute('data-setvalue')).to.equal( - '"not ignored"' - ); - const c = findElementByName(form, 'input', '/data/c'); - expect(c.getAttribute('data-setvalue')).to.equal( - "string-length('two')" - ); - const f = findElementByName(form, 'input', '/data/f'); - expect(f.getAttribute('data-setvalue')).to.equal(''); - const hs = findElementsByName(form, 'input', '/data/h'); - const h = hs.filter((el) => el.getAttribute('data-event'))[0]; - expect(h.getAttribute('data-setvalue')).to.equal(''); - }); + const f = findElementByName(doc, 'input', '/data/f'); + + expect(f.getAttribute('data-setvalue')).to.equal(''); + + const hs = findElementsByName(doc, 'input', '/data/h'); + const h = hs.filter((el) => el.getAttribute('data-event'))[0]; + + expect(h.getAttribute('data-setvalue')).to.equal(''); }); }); }); diff --git a/vite.config.ts b/vite.config.ts index 59b5bbe..a601aec 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -11,10 +11,17 @@ export default defineConfig({ sourcemap: 'inline', }, test: { + // Vitest uses thread-based concurrency by defualt. + // While this would significantly improve the speed + // of test runs, native Node extensions using N-API + // are often not thread safe. In this case, that + // means we cannot use concurrency for testing + // functionality which depends on libxmljs/libxslt. + threads: false, + globals: true, - include: [ - // 'test/**/*.spec.js', - 'test/**/*.spec.ts', - ], + include: ['test/**/*.spec.ts'], + reporters: 'verbose', + sequence: { shuffle: true }, }, }); From 893eabae9eee374df4804d9a9e4f1fc438a5e2e5 Mon Sep 17 00:00:00 2001 From: eyelidlessness Date: Thu, 22 Dec 2022 13:41:06 -0800 Subject: [PATCH 06/11] Clean up no-longer-relevant remnants of chai-as-promised - Promise.all around assertions - .to.have.property('foo').and... (these were previously .to.eventually...) --- src/transformer.js | 1 + test/bad-external.spec.ts | 56 ++-- test/transformer.spec.ts | 676 ++++++++++++++------------------------ 3 files changed, 266 insertions(+), 467 deletions(-) diff --git a/src/transformer.js b/src/transformer.js index db94c41..a723a81 100644 --- a/src/transformer.js +++ b/src/transformer.js @@ -61,6 +61,7 @@ const version = _getVersion(); * @property {string} form * @property {string} model * @property {string} transformerVersion + * @property {Record} languageMap */ /** diff --git a/test/bad-external.spec.ts b/test/bad-external.spec.ts index 0b3fc20..569ee6e 100644 --- a/test/bad-external.spec.ts +++ b/test/bad-external.spec.ts @@ -130,16 +130,14 @@ describe('for incompatible forms that require preprocessing', () => { it('preprocess fn does nothing if not provided...', async () => { const doc = await getTransformedModelDocument('bad-external.xml'); - return Promise.all([ - expect(doc).to.be.an.instanceOf(XMLDocument), - expect(doc.getElementsByTagName('instance')).to.have.length(2), - expect(doc.getElementById('existing')).to.not.be.null, - expect( - doc.getElementById('existing')!.getAttribute('src') - ).to.equal('jr://file/existing.xml'), - expect(doc.getElementById('counties')).to.be.null, - expect(doc.getElementById('cities')).to.be.null, - ]); + expect(doc).to.be.an.instanceOf(XMLDocument); + expect(doc.getElementsByTagName('instance')).to.have.length(2); + expect(doc.getElementById('existing')).to.not.be.null; + expect(doc.getElementById('existing')!.getAttribute('src')).to.equal( + 'jr://file/existing.xml' + ); + expect(doc.getElementById('counties')).to.be.null; + expect(doc.getElementById('cities')).to.be.null; }); it('preprocess fn corrects instances if necessary', async () => { @@ -148,28 +146,22 @@ describe('for incompatible forms that require preprocessing', () => { 'text/xml' ); - return Promise.all([ - expect(preprocessedModel).to.be.an.instanceOf(XMLDocument), - expect( - preprocessedModel.getElementsByTagName('instance') - ).to.have.length(4), - expect(preprocessedModel.getElementById('existing')).to.not.be.null, - expect( - preprocessedModel - .getElementById('existing')! - .getAttribute('src') - ).to.equal('jr://file/existing.xml'), - expect(preprocessedModel.getElementById('counties')).to.not.be.null, - expect( - preprocessedModel - .getElementById('counties')! - .getAttribute('src') - ).to.equal('esri://file-csv/list_name/counties/itemsets.csv'), - expect(preprocessedModel.getElementById('cities')).to.not.be.null, - expect( - preprocessedModel.getElementById('cities')!.getAttribute('src') - ).to.equal('esri://file-csv/list_name/cities/itemsets.csv'), - ]); + expect(preprocessedModel).to.be.an.instanceOf(XMLDocument); + expect( + preprocessedModel.getElementsByTagName('instance') + ).to.have.length(4); + expect(preprocessedModel.getElementById('existing')).to.not.be.null; + expect( + preprocessedModel.getElementById('existing')!.getAttribute('src') + ).to.equal('jr://file/existing.xml'); + expect(preprocessedModel.getElementById('counties')).to.not.be.null; + expect( + preprocessedModel.getElementById('counties')!.getAttribute('src') + ).to.equal('esri://file-csv/list_name/counties/itemsets.csv'); + expect(preprocessedModel.getElementById('cities')).to.not.be.null; + expect( + preprocessedModel.getElementById('cities')!.getAttribute('src') + ).to.equal('esri://file-csv/list_name/cities/itemsets.csv'); }); it('fn corrects body elements if necessary', () => { diff --git a/test/transformer.spec.ts b/test/transformer.spec.ts index dbd867f..1cbe86e 100644 --- a/test/transformer.spec.ts +++ b/test/transformer.spec.ts @@ -66,17 +66,16 @@ describe('transformer', () => { }); describe('transforms valid XForms', () => { - it('without an error', () => - Promise.all([ - expect(widgets).to.be.an('object'), - expect(widgets).to.have.property('form').and.to.not.be.empty, - expect(widgets).to.have.property('model').and.to.not.be.empty, - expect(widgets).to.have.property('transformerVersion').and.to - .not.be.empty, - ])); - - it('does not include the xform in the response', () => - expect(widgets).to.not.have.property('xform')); + it('without an error', () => { + expect(widgets).to.be.an('object'); + expect(widgets.form).to.not.be.empty; + expect(widgets.model).to.not.be.empty; + expect(widgets.transformerVersion).to.not.be.empty; + }); + + it('does not include the xform in the response', () => { + expect(widgets).to.not.have.property('xform'); + }); }); describe('transforms invalid XForms', () => { @@ -94,34 +93,26 @@ describe('transformer', () => { describe('puts attributes on root', () => { it('copies the formId', async () => { - expect(widgets) - .to.have.property('form') - .and.to.contain('data-form-id="widgets"'); + expect(widgets.form).to.contain('data-form-id="widgets"'); }); it('copies the formId with accents', async () => { const result = await getTransformedForm('form-id-with-accent.xml'); - return expect(result) - .to.have.property('form') - .and.to.contain('data-form-id="Éphémère"'); + expect(result.form).to.contain('data-form-id="Éphémère"'); }); // https://github.com/enketo/enketo-transformer/issues/100 it('copies the formId with spaces', async () => { const result = await getTransformedForm('form-id-with-space.xml'); - return expect(result) - .to.have.property('form') - .and.to.contain('data-form-id="FormId with spaces"'); + expect(result.form).to.contain('data-form-id="FormId with spaces"'); }); }); describe('copies attributes on the ``', () => { it('copies the odk:xforms-version attribute', () => { - expect(autocomplete) - .to.have.property('model') - .and.to.contain('odk:xforms-version="1.0.0"'); + expect(autocomplete.model).to.contain('odk:xforms-version="1.0.0"'); }); }); @@ -131,9 +122,7 @@ describe('transformer', () => { theme: 'mytheme', }); - expect(result) - .to.have.property('form') - .and.to.contain('theme-mytheme'); + expect(result.form).to.contain('theme-mytheme'); }); it('leaves the XForm-defined theme unchanged if the theme value provided is falsy', async () => { @@ -159,20 +148,10 @@ describe('transformer', () => { theme: false, }); - return Promise.all([ - expect(result1) - .to.have.property('form') - .and.to.contain('theme-one'), - expect(result2) - .to.have.property('form') - .and.to.contain('theme-one'), - expect(result3) - .to.have.property('form') - .and.to.contain('theme-one'), - expect(result4) - .to.have.property('form') - .and.to.contain('theme-one'), - ]); + expect(result1.form).to.contain('theme-one'); + expect(result2.form).to.contain('theme-one'); + expect(result3.form).to.contain('theme-one'); + expect(result4.form).to.contain('theme-one'); }); it('replaces a theme defined in the XForm with a provided one', async () => { @@ -185,54 +164,38 @@ describe('transformer', () => { theme: 'mytheme', }); - return Promise.all([ - expect(result) - .to.have.property('form') - .and.to.not.contain('theme-one'), - expect(result) - .to.have.property('form') - .and.to.contain('theme-mytheme'), - ]); + expect(result.form).to.not.contain('theme-one'); + expect(result.form).to.contain('theme-mytheme'); }); }); describe('manipulates languages and', () => { it('provides a languageMap as output property', () => { - expect(advancedRequired) - .to.have.property('languageMap') - .and.to.deep.equal({ - dutch: 'nl', - english: 'en', - }); + expect(advancedRequired.languageMap).to.deep.equal({ + dutch: 'nl', + english: 'en', + }); }); it('provides an empty languageMap as output property if nothing was changed', () => { - expect(widgets) - .to.have.property('languageMap') - .and.to.deep.equal({}); + expect(widgets.languageMap).to.deep.equal({}); }); }); describe('renders markdown', () => { it('takes into account that libxmljs Element.text() converts html entities', async () => { - return Promise.all([ - expect(external) - .to.have.property('form') - .and.to.not.contain( - '<span style="color:pink;">Intro</span>' - ), - expect(external) - .to.have.property('form') - .and.to.contain('Intro'), - ]); + expect(external.form).to.not.contain( + '<span style="color:pink;">Intro</span>' + ); + expect(external.form).to.contain( + 'Intro' + ); }); it('and picks up formatting of s', () => { - expect(formattedOutput) - .to.have.property('form') - .and.to.contain( - 'formatted: and' - ); + expect(formattedOutput.form).to.contain( + 'formatted: and' + ); }); it('preserves text containing special string replacement sequences', async () => { @@ -250,11 +213,9 @@ describe('transformer', () => { markdown: false, }); - expect(result) - .to.have.property('form') - .and.to.contain( - 'formatted: * * and _normal_ text' - ); + expect(result.form).to.contain( + 'formatted: * * and _normal_ text' + ); }); }); @@ -262,15 +223,9 @@ describe('transformer', () => { it('strips arbitrary HTML in labels but preserves text', async () => { const result = await getTransformedForm('arbitrary-html.xml'); - return Promise.all([ - expect(result) - .to.have.property('form') - .and.to.not.contain('
'), + expect(result.form).to.not.contain('
'); - expect(result) - .to.have.property('form') - .and.to.contain('Label text'), - ]); + expect(result.form).to.contain('Label text'); }); }); @@ -286,33 +241,15 @@ describe('transformer', () => { media, }); - return Promise.all([ - expect(result1) - .to.have.property('form') - .and.to.contain('jr://images/happy.jpg'), - expect(result1) - .to.have.property('form') - .and.to.contain('jr://images/pigeon.png'), - expect(result1) - .to.have.property('form') - .and.to.not.contain('/i/am/happy.jpg'), - expect(result1) - .to.have.property('form') - .and.to.not.contain('/a/b/pigeon.png'), - - expect(result2) - .to.have.property('form') - .and.to.not.contain('jr://images/happy.jpg'), - expect(result2) - .to.have.property('form') - .and.to.not.contain('jr://images/pigeon.png'), - expect(result2) - .to.have.property('form') - .and.to.contain('/i/am/happy.jpg'), - expect(result2) - .to.have.property('form') - .and.to.contain('/a/b/pigeon.png'), - ]); + expect(result1.form).to.contain('jr://images/happy.jpg'); + expect(result1.form).to.contain('jr://images/pigeon.png'); + expect(result1.form).to.not.contain('/i/am/happy.jpg'); + expect(result1.form).to.not.contain('/a/b/pigeon.png'); + + expect(result2.form).to.not.contain('jr://images/happy.jpg'); + expect(result2.form).to.not.contain('jr://images/pigeon.png'); + expect(result2.form).to.contain('/i/am/happy.jpg'); + expect(result2.form).to.contain('/a/b/pigeon.png'); }); it('in the View by replacing big-image link hrefs according to a provided map', async () => { @@ -330,20 +267,10 @@ describe('transformer', () => { media, }); - return Promise.all([ - expect(result) - .to.have.property('form') - .and.not.to.contain('jr://images/happy.jpg'), - expect(result) - .to.have.property('form') - .and.not.to.contain('jr://images/very-happy.jpg'), - expect(result) - .to.have.property('form') - .and.to.contain('/i/am/happy.jpg'), - expect(result) - .to.have.property('form') - .and.to.contain('/i/am/very-happy.jpg'), - ]); + expect(result.form).not.to.contain('jr://images/happy.jpg'); + expect(result.form).not.to.contain('jr://images/very-happy.jpg'); + expect(result.form).to.contain('/i/am/happy.jpg'); + expect(result.form).to.contain('/i/am/very-happy.jpg'); }); it('in the Model by replacing them according to a provided map', async () => { @@ -357,33 +284,17 @@ describe('transformer', () => { media, }); - return Promise.all([ - expect(result1) - .to.have.property('model') - .and.to.contain('jr://file-csv/neighborhoods.csv'), - expect(result1) - .to.have.property('model') - .and.to.contain('jr://file/cities.xml'), - expect(result1) - .to.have.property('model') - .and.to.not.contain('/path/to/neighborhoods.csv'), - expect(result1) - .to.have.property('model') - .and.to.not.contain('/path/to/cities.xml'), - - expect(result2) - .to.have.property('model') - .and.to.not.contain('jr://file-csv/neighborhoods.csv'), - expect(result2) - .to.have.property('model') - .and.to.not.contain('jr://file/cities.xml'), - expect(result2) - .to.have.property('model') - .and.to.contain('/path/to/neighborhoods.csv'), - expect(result2) - .to.have.property('model') - .and.to.contain('/path/to/cities.xml'), - ]); + expect(result1.model).to.contain('jr://file-csv/neighborhoods.csv'); + expect(result1.model).to.contain('jr://file/cities.xml'); + expect(result1.model).to.not.contain('/path/to/neighborhoods.csv'); + expect(result1.model).to.not.contain('/path/to/cities.xml'); + + expect(result2.model).to.not.contain( + 'jr://file-csv/neighborhoods.csv' + ); + expect(result2.model).to.not.contain('jr://file/cities.xml'); + expect(result2.model).to.contain('/path/to/neighborhoods.csv'); + expect(result2.model).to.contain('/path/to/cities.xml'); }); it(`in the model for binary questions that contain a default value by copying to a @@ -398,18 +309,12 @@ describe('transformer', () => { media, }); - return Promise.all([ - expect(result) - .to.have.property('model') - .and.to.contain( - 'jr://images/unhappy.jpg' - ), - expect(result) - .to.have.property('model') - .and.to.contain( - 'jr://images/indifferent.png' - ), - ]); + expect(result.model).to.contain( + 'jr://images/unhappy.jpg' + ); + expect(result.model).to.contain( + 'jr://images/indifferent.png' + ); }); it('by adding a form logo if needed', async () => { @@ -422,14 +327,8 @@ describe('transformer', () => { media, }); - return Promise.all([ - expect(result1) - .to.have.property('form') - .and.to.not.contain(' { media, }); - return expect(result) - .to.have.property('form') - .and.to.contain('Note with bold nnnn'); + expect(result.form).to.contain( + 'Note with bold nnnn' + ); }); describe('spaces in jr: media URLs', () => { @@ -543,104 +442,70 @@ describe('transformer', () => { it('escapes media in labels', () => { const result = results[index]; - return Promise.all([ - expect(result) - .to.have.property('form') - .and.to.not.contain( - 'jr://images/first image.jpg' - ), - expect(result) - .to.have.property('form') - .and.to.not.contain('jr://audio/a song.mp3'), - expect(result) - .to.have.property('form') - .and.to.not.contain( - 'jr://video/some video.mp4' - ), - - expect(result) - .to.have.property('form') - .and.to.contain( - 'hallo%20spaceboy/spiders%20from%20mars.jpg' - ), - expect(result) - .to.have.property('form') - .and.to.contain( - 'hallo%20spaceboy/space%20oddity.mp3' - ), - expect(result) - .to.have.property('form') - .and.to.contain( - 'hallo%20spaceboy/a%20small%20plot%20of%20land.mp4' - ), - ]); + expect(result.form).to.not.contain( + 'jr://images/first image.jpg' + ); + expect(result.form).to.not.contain( + 'jr://audio/a song.mp3' + ); + expect(result.form).to.not.contain( + 'jr://video/some video.mp4' + ); + + expect(result.form).to.contain( + 'hallo%20spaceboy/spiders%20from%20mars.jpg' + ); + expect(result.form).to.contain( + 'hallo%20spaceboy/space%20oddity.mp3' + ); + expect(result.form).to.contain( + 'hallo%20spaceboy/a%20small%20plot%20of%20land.mp4' + ); }); it('escapes binary defaults', () => { const result = results[index]; - return Promise.all([ - expect(result) - .to.have.property('model') - .and.to.not.contain( - 'jr://images/another image.png' - ), - - expect(result) - .to.have.property('model') - .and.to.contain( - 'hallo%20spaceboy/under%20pressure.png' - ), - ]); + expect(result.model).to.not.contain( + 'jr://images/another image.png' + ); + + expect(result.model).to.contain( + 'hallo%20spaceboy/under%20pressure.png' + ); }); it('escapes external instance URLs', () => { const result = results[index]; - return Promise.all([ - expect(result) - .to.have.property('model') - .and.to.not.contain( - 'jr://file/an instance.xml' - ), - expect(result) - .to.have.property('model') - .and.to.not.contain( - 'jr://file-csv/a spreadsheet.csv' - ), - - expect(result) - .to.have.property('model') - .and.to.contain( - 'hallo%20spaceboy/golden%20years.xml' - ), - expect(result) - .to.have.property('model') - .and.to.contain( - 'hallo%20spaceboy/little%20wonder.csv' - ), - ]); + expect(result.model).to.not.contain( + 'jr://file/an instance.xml' + ); + expect(result.model).to.not.contain( + 'jr://file-csv/a spreadsheet.csv' + ); + + expect(result.model).to.contain( + 'hallo%20spaceboy/golden%20years.xml' + ); + expect(result.model).to.contain( + 'hallo%20spaceboy/little%20wonder.csv' + ); }); it('escapes media URLs in markdown linkes', () => { const result = results[index]; - return Promise.all([ - expect(result) - .to.have.property('form') - .and.to.not.contain('jr://file/a link.xml'), - - expect(result) - .to.have.property('form') - .and.to.contain( - 'hallo%20spaceboy/wishful%20beginnings.xml' - ), - - // issue https://github.com/enketo/enketo-transformer/issues/149 - expect(result) - .to.have.property('form') - .and.to.contain('markdown
'), - ]); + expect(result.form).to.not.contain( + 'jr://file/a link.xml' + ); + + expect(result.form).to.contain( + 'hallo%20spaceboy/wishful%20beginnings.xml' + ); + + // issue https://github.com/enketo/enketo-transformer/issues/149 + expect(result.form).to.contain('markdown
'); }); }); }); @@ -720,23 +585,15 @@ describe('transformer', () => { const count1 = count(widgets); const count2 = count(advancedRequired); - return Promise.all([ - expect(count1).to.equal(4), - expect(count2).to.equal(0), - ]); + expect(count1).to.equal(4); + expect(count2).to.equal(0); }); }); describe('processes required questions', () => { it('and adds the data-required HTML attribute for required XForm attributes keeping the value unchanged', () => { - Promise.all([ - expect(widgets) - .to.have.property('form') - .and.to.contain('data-required="true()"'), - expect(widgets) - .to.have.property('form') - .and.to.not.contain(' required="required"'), - ]); + expect(widgets.form).to.contain('data-required="true()"'); + expect(widgets.form).to.not.contain(' required="required"'); }); it('and does not add the data-required attribute if the value is false()', async () => { @@ -748,9 +605,7 @@ describe('transformer', () => { xform, }); - expect(result) - .to.have.property('form') - .and.to.not.contain('data-required'); + expect(result.form).to.not.contain('data-required'); }); it('and adds the correct number of required-msg elements', async () => { @@ -760,30 +615,20 @@ describe('transformer', () => { const count1 = count(widgets); const count2 = count(advancedRequired); - return Promise.all([ - expect(count1).to.equal(1), - expect(count2).to.equal(2), - ]); + expect(count1).to.equal(1); + expect(count2).to.equal(2); }); it('and adds a default requiredMsg if no custom is provided', () => { - expect(widgets) - .to.have.property('form') - .and.to.contain('data-i18n="constraint.required"'); + expect(widgets.form).to.contain('data-i18n="constraint.required"'); }); it('and adds a custom requiredMsg if provided', () => { - return Promise.all([ - expect(advancedRequired) - .to.have.property('form') - .and.to.not.contain('data-i18n'), - expect(advancedRequired) - .to.have.property('form') - .and.to.contain('custom verplicht bericht'), - expect(advancedRequired) - .to.have.property('form') - .and.to.contain('custom required message'), - ]); + expect(advancedRequired.form).to.not.contain('data-i18n'); + expect(advancedRequired.form).to.contain( + 'custom verplicht bericht' + ); + expect(advancedRequired.form).to.contain('custom required message'); }); }); @@ -801,27 +646,19 @@ describe('transformer', () => { describe('processes multiline questions', () => { it('and outputs a textarea for appearance="multiline" on text input', () => { - expect(widgets) - .to.have.property('form') - .and.to.contain(' { - expect(widgets) - .to.have.property('form') - .and.to.contain(' { - expect(widgets) - .to.have.property('form') - .and.to.contain(' { - expect(widgets) - .to.have.property('form') - .and.to.contain(' { @@ -831,76 +668,64 @@ describe('transformer', () => { ); const result = await transform({ xform }); - return Promise.all([ - expect(result) - .to.have.property('form') - .and.to.contain(' elements', () => { it('and outputs elements', () => { - return Promise.all([ - expect(autocompleteDoc).to.be.an('object'), - expect( - autocompleteDoc.getElementsByTagName('select') - ).to.have.length(4), - expect( - autocompleteDoc.getElementsByTagName('datalist') - ).to.have.length(2), - expect( - autocompleteDoc - .getElementById('selectoneautocompletethree')! - .nodeName.toLowerCase() - ).to.equal('datalist'), - expect( - autocompleteDoc - .getElementsByTagName('input')[0] - .getAttribute('list') - ).to.equal('selectoneautocompletethree'), - expect( - autocompleteDoc - .getElementsByTagName('input')[0] - .getAttribute('type') - ).to.equal('text'), - expect( - autocompleteDoc - .getElementById('selectoneautocompletefour')! - .nodeName.toLowerCase() - ).to.equal('datalist'), - expect( - autocompleteDoc - .getElementsByTagName('input')[1] - .getAttribute('list') - ).to.equal('selectoneautocompletefour'), - ]); + expect(autocompleteDoc).to.be.an('object'); + expect( + autocompleteDoc.getElementsByTagName('select') + ).to.have.length(4); + expect( + autocompleteDoc.getElementsByTagName('datalist') + ).to.have.length(2); + expect( + autocompleteDoc + .getElementById('selectoneautocompletethree')! + .nodeName.toLowerCase() + ).to.equal('datalist'); + expect( + autocompleteDoc + .getElementsByTagName('input')[0] + .getAttribute('list') + ).to.equal('selectoneautocompletethree'); + expect( + autocompleteDoc + .getElementsByTagName('input')[0] + .getAttribute('type') + ).to.equal('text'); + expect( + autocompleteDoc + .getElementById('selectoneautocompletefour')! + .nodeName.toLowerCase() + ).to.equal('datalist'); + expect( + autocompleteDoc + .getElementsByTagName('input')[1] + .getAttribute('list') + ).to.equal('selectoneautocompletefour'); }); }); describe('processes a model with namespaces', () => { - it('leaves namespace prefixes and declarations intact on nodes', () => - Promise.all([ - expect(modelNamespace) - .to.have.property('model') - .and.to.contain(''), - ])); + it('leaves namespace prefixes and declarations intact on nodes', () => { + expect(modelNamespace.model).to.contain('' + ); + }); }); describe('for backwards compatibility of forms without a /meta/instanceID node', () => { @@ -910,23 +735,17 @@ describe('transformer', () => { result1 = await getTransformedForm('no-instance-id.xml'); }); it('adds a /meta/instanceID node', () => - expect(result1) - .to.have.property('model') - .and.to.contain('')); + expect(result1.model).to.contain('')); it('does not add it if it contains /meta/instanceID in the OpenRosa namespace', () => - expect(modelNamespace) - .to.have.property('model') - .and.to.not.contain('')); + expect(modelNamespace.model).to.not.contain('')); }); describe('converts deprecated', () => { it('method="form-data-post" to "post" in submission element', async () => { const result = await getTransformedForm('deprecated.xml'); - expect(result) - .to.have.property('form') - .and.to.contain('method="post"'); + expect(result.form).to.contain('method="post"'); }); }); @@ -943,7 +762,7 @@ describe('transformer', () => { it('works for itemset nodesets using a simple randomize()', async () => { const result = await transform({ xform }); - return expect(result).to.have.property('form').and.to.match(MATCH); + expect(result.form).to.match(MATCH); }); it('works for itemset nodesets using a randomize() with static seed', async () => { @@ -954,7 +773,7 @@ describe('transformer', () => { ), }); - return expect(result).to.have.property('form').and.to.match(MATCH); + expect(result.form).to.match(MATCH); }); it.skip('works for itemset nodesets using a simple randomize() with complex multi-parameter predicate function', async () => { @@ -965,7 +784,7 @@ describe('transformer', () => { ), }); - return expect(result).to.have.property('form').and.to.match(MATCH); + expect(result.form).to.match(MATCH); }); it.skip('works for itemset nodesets using a randomize() with a static seed and with a complex multi-parameter predicate function', async () => { @@ -976,7 +795,7 @@ describe('transformer', () => { ), }); - return expect(result).to.have.property('form').and.to.match(MATCH); + expect(result.form).to.match(MATCH); }); }); @@ -1640,9 +1459,7 @@ describe('custom stuff', () => { it('by turning it into the data-for attribute', async () => { const result = await getTransformedForm('for.xml'); - expect(result) - .to.have.property('form') - .and.to.contain('data-for="../a"'); + expect(result.form).to.contain('data-for="../a"'); }); }); @@ -1652,9 +1469,7 @@ describe('custom stuff', () => { openclinica: 1, }); - return expect(result) - .to.have.property('form') - .and.to.contain('data-oc-external="clinicaldata"'); + expect(result.form).to.contain('data-oc-external="clinicaldata"'); }); it('for setvalue/odk-instance-first-load actions by turning it into the data-oc-external attribute', async () => { @@ -1662,9 +1477,7 @@ describe('custom stuff', () => { openclinica: 1, }); - return expect(result) - .to.have.property('form') - .and.to.contain('data-oc-external="clinicaldata"'); + expect(result.form).to.contain('data-oc-external="clinicaldata"'); }); it('for setgeopoint/odk-instance-first-load actions by turning it into the data-oc-external attribute', async () => { @@ -1672,9 +1485,7 @@ describe('custom stuff', () => { openclinica: 1, }); - return expect(result) - .to.have.property('form') - .and.to.contain('data-oc-external="clinicaldata"'); + expect(result.form).to.contain('data-oc-external="clinicaldata"'); }); }); @@ -1687,12 +1498,9 @@ describe('custom stuff', () => { } ); - return expect(result) - .to.have.property('form') - .and.to.satisfy( - (form: string) => - form.match(/or-relevant-msg/g)!.length === 4 - ); + expect(result.form).to.satisfy( + (form: string) => form.match(/or-relevant-msg/g)!.length === 4 + ); }); it('are ignored by default', async () => { @@ -1700,9 +1508,7 @@ describe('custom stuff', () => { 'relevant_constraint_required.xml' ); - return expect(result) - .to.have.property('form') - .and.not.to.contain('or-relevant-msg'); + expect(result.form).not.to.contain('or-relevant-msg'); }); }); @@ -1721,43 +1527,43 @@ describe('custom stuff', () => { describe('are added via oc:constraint[N] attribute', () => { it('works for N=1', () => - expect(result) - .to.have.property('form') - .and.to.contain('data-oc-constraint1=". != \'a\'"')); + expect(result.form).to.contain( + 'data-oc-constraint1=". != \'a\'"' + )); it('works for N=20', () => - expect(result) - .to.have.property('form') - .and.to.contain('data-oc-constraint20=". != \'c\'"')); - - // it( 'ignores oc:constraint without a number', () => { - // return expect( result ).to.have.property( 'form' ).and.to.not.contain( 'constraint to be ignored' ); - // } ); + expect(result.form).to.contain( + 'data-oc-constraint20=". != \'c\'"' + )); + + it('ignores oc:constraint without a number', () => { + expect(result.form).to.not.contain( + 'constraint to be ignored' + ); + }); it('does not add constraint messages in this manner', () => - expect(result) - .to.have.property('form') - .and.to.not.contain('data-oc-constraint20Msg="')); + expect(result.form).to.not.contain( + 'data-oc-constraint20Msg="' + )); }); describe('can get individual constraint messages with the oc:constraint[N]Msg attribute', () => { it('works for N=1', () => - expect(result) - .to.have.property('form') - .and.to.contain('class="or-constraint1-msg')); + expect(result.form).to.contain( + 'class="or-constraint1-msg' + )); it('works for N=20', () => - expect(result) - .to.have.property('form') - .and.to.contain('class="or-constraint20-msg')); + expect(result.form).to.contain( + 'class="or-constraint20-msg' + )); it('ignores constraint messages without a number', () => // The text "msg to be ignored is actually part of the result but is not present in a .or-constraint-msg span elmement - expect(result) - .to.have.property('form') - .and.not.to.match( - /or-constraint-msg [^>]+>msg to be ignored/ - )); + expect(result.form).not.to.match( + /or-constraint-msg [^>]+>msg to be ignored/ + )); }); }); @@ -1771,24 +1577,24 @@ describe('custom stuff', () => { }); it('for N=1 (attribute)', () => - expect(result) - .to.have.property('form') - .and.not.to.contain('data-oc-constraint1=". != \'a\'"')); + expect(result.form).not.to.contain( + 'data-oc-constraint1=". != \'a\'"' + )); it('for N=20 (attribute)', () => - expect(result) - .to.have.property('form') - .and.not.to.contain('data-oc-constraint20=". != \'c\'"')); + expect(result.form).not.to.contain( + 'data-oc-constraint20=". != \'c\'"' + )); it('for N=1 (message)', () => - expect(result) - .to.have.property('form') - .and.not.to.contain('class="or-constraint1-msg')); + expect(result.form).not.to.contain( + 'class="or-constraint1-msg' + )); it('for N=20 (message', () => - expect(result) - .to.have.property('form') - .and.not.to.contain('class="or-constraint20-msg')); + expect(result.form).not.to.contain( + 'class="or-constraint20-msg' + )); }); it('with different ways of specify a "value" for setvalue', async () => { From afb87f7cb8605ec1b5fe03977c15abc34466e536 Mon Sep 17 00:00:00 2001 From: eyelidlessness Date: Thu, 22 Dec 2022 14:56:31 -0800 Subject: [PATCH 07/11] Fix and enforce lint rules in TypeScript --- .eslintrc.json | 65 ++++++- package-lock.json | 384 ++++++++++++++++++++++++++++++++++++++ package.json | 8 +- test/bad-external.spec.ts | 10 +- test/transformer.spec.ts | 7 +- typings/test.d.ts | 1 + 6 files changed, 462 insertions(+), 13 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 8d1d24c..c800252 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -7,13 +7,29 @@ "globals": { "Promise": true }, - "extends": ["airbnb", "prettier"], - "plugins": ["chai-friendly", "jsdoc", "prettier", "unicorn"], + "extends": ["plugin:@typescript-eslint/recommended", "airbnb", "prettier"], + "plugins": [ + "chai-friendly", + "jsdoc", + "prettier", + "unicorn", + "@typescript-eslint" + ], + "parser": "@typescript-eslint/parser", "parserOptions": { "sourceType": "module", "ecmaVersion": 2020 }, "settings": { + "import/extensions": [".js", ".ts"], + "import/parsers": { + "@typescript-eslint/parser": [".ts"] + }, + "import/resolver": { + "node": { + "extensions": [".js", ".ts"] + } + }, "jsdoc": { "tagNamePreference": { "returns": "return" @@ -21,6 +37,8 @@ } }, "rules": { + "@typescript-eslint/no-non-null-assertion": "error", + "chai-friendly/no-unused-expressions": "error", "prettier/prettier": "error", "guard-for-in": "warn", @@ -35,6 +53,7 @@ ], "no-shadow": "warn", "no-underscore-dangle": "warn", + "no-unused-expressions": "off", "no-use-before-define": [ "warn", { @@ -52,11 +71,53 @@ } }, + { + "files": ["./**/*.js"], + "rules": { + "@typescript-eslint/no-var-requires": "off" + } + }, + { "files": ["./test/**/*.js"], "env": { "mocha": true } + }, + + { + "files": ["./**/*.ts"], + "rules": { + "@typescript-eslint/no-unused-expressions": "off" + } + }, + + { + "files": ["./test/**/*.ts"], + "plugins": ["vitest"], + "globals": { + "describe": true, + "it": true, + "expect": true, + "beforeAll": true, + "beforeEach": true, + "afterAll": true, + "afterEach": true + }, + "rules": { + "@typescript-eslint/no-non-null-assertion": "off", + "import/extensions": [ + "error", + "ignorePackages", + { + "js": "never", + "jsx": "never", + "ts": "never", + "tsx": "never" + } + ], + "no-undef": "off" + } } ] } diff --git a/package-lock.json b/package-lock.json index 553b090..5427fe9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -663,6 +663,32 @@ "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, "@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -726,6 +752,12 @@ "@types/range-parser": "*" } }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -784,6 +816,12 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "dev": true }, + "@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, "@types/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", @@ -794,6 +832,224 @@ "@types/node": "*" } }, + "@typescript-eslint/eslint-plugin": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.47.0.tgz", + "integrity": "sha512-AHZtlXAMGkDmyLuLZsRpH3p4G/1iARIwc/T0vIem2YB+xW6pZaXYXzCBnZSF/5fdM97R9QqZWZ+h3iW10XgevQ==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.47.0", + "@typescript-eslint/type-utils": "5.47.0", + "@typescript-eslint/utils": "5.47.0", + "debug": "^4.3.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "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 + }, + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/parser": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.47.0.tgz", + "integrity": "sha512-udPU4ckK+R1JWCGdQC4Qa27NtBg7w020ffHqGyAK8pAgOVuNw7YaKXGChk+udh+iiGIJf6/E/0xhVXyPAbsczw==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.47.0", + "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/typescript-estree": "5.47.0", + "debug": "^4.3.4" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "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 + } + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.47.0.tgz", + "integrity": "sha512-dvJab4bFf7JVvjPuh3sfBUWsiD73aiftKBpWSfi3sUkysDQ4W8x+ZcFpNp7Kgv0weldhpmMOZBjx1wKN8uWvAw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/visitor-keys": "5.47.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.47.0.tgz", + "integrity": "sha512-1J+DFFrYoDUXQE1b7QjrNGARZE6uVhBqIvdaXTe5IN+NmEyD68qXR1qX1g2u4voA+nCaelQyG8w30SAOihhEYg==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "5.47.0", + "@typescript-eslint/utils": "5.47.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "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 + } + } + }, + "@typescript-eslint/types": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.0.tgz", + "integrity": "sha512-eslFG0Qy8wpGzDdYKu58CEr3WLkjwC5Usa6XbuV89ce/yN5RITLe1O8e+WFEuxnfftHiJImkkOBADj58ahRxSg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.0.tgz", + "integrity": "sha512-LxfKCG4bsRGq60Sqqu+34QT5qT2TEAHvSCCJ321uBWywgE2dS0LKcu5u+3sMGo+Vy9UmLOhdTw5JHzePV/1y4Q==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/visitor-keys": "5.47.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "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 + }, + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/utils": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.47.0.tgz", + "integrity": "sha512-U9xcc0N7xINrCdGVPwABjbAKqx4GK67xuMV87toI+HUqgXj26m6RBp9UshEXcTrgCkdGYFzgKLt8kxu49RilDw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.47.0", + "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/typescript-estree": "5.47.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "dependencies": { + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + } + }, + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.0.tgz", + "integrity": "sha512-ByPi5iMa6QqDXe/GmT/hR6MZtVPi0SqMQPDx15FczCBXJo/7M8T88xReOALAfpBLm+zxpPfmhuEvPb577JRAEg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.47.0", + "eslint-visitor-keys": "^3.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + } + } + }, "@ungap/promise-all-settled": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", @@ -1000,6 +1256,12 @@ "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", "dev": true }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, "array.prototype.flat": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", @@ -1919,6 +2181,15 @@ "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", "dev": true }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, "docdash": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/docdash/-/docdash-1.2.0.tgz", @@ -2941,6 +3212,15 @@ } } }, + "eslint-plugin-vitest": { + "version": "0.0.21", + "resolved": "https://registry.npmjs.org/eslint-plugin-vitest/-/eslint-plugin-vitest-0.0.21.tgz", + "integrity": "sha512-eer/eS0T9MW8X9CKHg6M9URKgSEOJ8I24CKQlz1WhD68Hz2Uuwepb61OHZ+33Fcuzp4YXl/qqd7XSSq+p8BJAw==", + "dev": true, + "requires": { + "@typescript-eslint/utils": "^5.42.1" + } + }, "eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -3167,6 +3447,19 @@ "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", "dev": true }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, "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", @@ -3179,6 +3472,15 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fastq": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", + "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, "figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -3599,6 +3901,28 @@ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "dependencies": { + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true + } + } + }, "gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -5448,6 +5772,12 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -5742,6 +6072,12 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, "needle": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/needle/-/needle-2.8.0.tgz", @@ -6780,6 +7116,12 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, "pathe": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/pathe/-/pathe-0.2.0.tgz", @@ -7006,6 +7348,12 @@ "side-channel": "^1.0.4" } }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -7272,6 +7620,12 @@ "signal-exit": "^3.0.2" } }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -7296,6 +7650,15 @@ "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", "dev": true }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, "rxjs": { "version": "6.6.7", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", @@ -7475,6 +7838,12 @@ } } }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, "slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", @@ -8094,6 +8463,15 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -8133,6 +8511,12 @@ "is-typedarray": "^1.0.0" } }, + "typescript": { + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "dev": true + }, "uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", diff --git a/package.json b/package.json index 81b0139..7454bed 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,8 @@ "contributors": [], "scripts": { "start": "node app.js", - "eslint-check": "eslint app.js src/**/*.js test/**/*.js", - "eslint-fix": "eslint app.js src/**/*.js test/**/*.js --fix", + "eslint-check": "eslint app.js src/**/*.js test/**/*.ts", + "eslint-fix": "eslint app.js src/**/*.js test/**/*.ts --fix", "prettier-fix": "prettier --write .", "test": "nyc mocha test/*.spec.js --timeout 6000 && npm run prettier-fix && npm run eslint-fix && node update-readme-with-shield-badge.js", "vitest": "vitest run", @@ -53,6 +53,8 @@ "devDependencies": { "@types/express": "^4.17.14", "@types/node": "^18.11.17", + "@typescript-eslint/eslint-plugin": "^5.47.0", + "@typescript-eslint/parser": "^5.47.0", "@xmldom/xmldom": "^0.7.9", "chai": "^4.3.7", "chai-as-promised": "^7.1.1", @@ -68,6 +70,7 @@ "eslint-plugin-react": "^7.31.11", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-unicorn": "^36.0.0", + "eslint-plugin-vitest": "0.0.21", "grunt": "^1.5.3", "http-server": "^13.1.0", "istanbul-reporter-shield-badge": "^1.2.1", @@ -79,6 +82,7 @@ "nyc": "^15.1.0", "prettier": "^2.8.1", "rimraf": "^3.0.2", + "typescript": "^4.9.4", "vite": "^4.0.3", "vitest": "^0.26.2" }, diff --git a/test/bad-external.spec.ts b/test/bad-external.spec.ts index 569ee6e..0973e4e 100644 --- a/test/bad-external.spec.ts +++ b/test/bad-external.spec.ts @@ -17,7 +17,6 @@ describe('for incompatible forms that require preprocessing', () => { let preprocessedForm: Document; const preprocess: TransformPreprocess = function (doc) { - const libxmljs = this; const model = doc.get('/h:html/h:head/xmlns:model', NAMESPACES); if (!model) { @@ -76,7 +75,7 @@ describe('for incompatible forms that require preprocessing', () => { */ const children = input.childNodes(); const attrs = input.attrs(); - const select1 = new libxmljs.Element(doc, 'select1').namespace( + const select1 = new this.Element(doc, 'select1').namespace( NAMESPACES.xmlns ); @@ -205,10 +204,9 @@ describe('for incompatible forms that require preprocessing', () => { ]); }); - it('fn does not correct instances if not necessary', async () => { - return Promise.all([ + it('fn does not correct instances if not necessary', async () => + Promise.all([ expect(preprocessedForm).to.be.an.instanceOf(Document), expect(preprocessedForm.getElementById('counties')).to.be.null, - ]); - }); + ])); }); diff --git a/test/transformer.spec.ts b/test/transformer.spec.ts index 1cbe86e..eb23721 100644 --- a/test/transformer.spec.ts +++ b/test/transformer.spec.ts @@ -7,6 +7,7 @@ import { } from './shared'; import type { TransformedSurvey } from '../src/transformer'; +import type { Document } from './shared'; function findElementByName( htmlDoc: Document, @@ -84,7 +85,7 @@ describe('transformer', () => { invalidXForms.forEach((xform) => { it.fails('with a parse error', async () => { await transform({ - // @ts-expect-error + // @ts-expect-error: this is specifically testing invalid values xform, }); }); @@ -139,12 +140,12 @@ describe('transformer', () => { }); const result3 = await transform({ xform: newXform, - // @ts-expect-error + // @ts-expect-error: this is specifically testing non-theme values theme: null, }); const result4 = await transform({ xform: newXform, - // @ts-expect-error + // @ts-expect-error: this is specifically testing non-theme values theme: false, }); diff --git a/typings/test.d.ts b/typings/test.d.ts index 9896c47..6a345df 100644 --- a/typings/test.d.ts +++ b/typings/test.d.ts @@ -1 +1,2 @@ +/// /// From 891f866558467951713a5b2d20f937bed6296c1a Mon Sep 17 00:00:00 2001 From: eyelidlessness Date: Thu, 22 Dec 2022 14:57:10 -0800 Subject: [PATCH 08/11] Swap test scripts --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 7454bed..ed334c2 100644 --- a/package.json +++ b/package.json @@ -23,10 +23,10 @@ "eslint-check": "eslint app.js src/**/*.js test/**/*.ts", "eslint-fix": "eslint app.js src/**/*.js test/**/*.ts --fix", "prettier-fix": "prettier --write .", - "test": "nyc mocha test/*.spec.js --timeout 6000 && npm run prettier-fix && npm run eslint-fix && node update-readme-with-shield-badge.js", - "vitest": "vitest run", - "test:watch": "nodemon --exec 'mocha test/*.spec.js --timeout 6000000' --watch src --watch test --ext js,xml,xsl,ts", - "vitest:watch": "vitest", + "test": "vitest run", + "test:mocha": "nyc mocha test/*.spec.js --timeout 6000 && npm run prettier-fix && npm run eslint-fix && node update-readme-with-shield-badge.js", + "test:watch": "vitest", + "test:mocha-watch": "nodemon --exec 'mocha test/*.spec.ts --timeout 6000000' --watch src --watch test --ext js,xml,xsl,ts", "build-docs": "rimraf docs && ./node_modules/.bin/jsdoc -c jsdoc.config.js", "develop": "DEBUG=api,transformer,markdown,language node app.js & http-server test/forms -p 8081" }, From 38e01cbb826145a1e110dd842677059e5adb86ac Mon Sep 17 00:00:00 2001 From: eyelidlessness Date: Sat, 24 Dec 2022 14:05:46 -0800 Subject: [PATCH 09/11] Fix linting of Vite config --- .eslintrc.json | 50 ++++++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index c800252..f2e2845 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -43,6 +43,20 @@ "guard-for-in": "warn", "import/extensions": "warn", + "import/no-extraneous-dependencies": [ + "error", + { + "devDependencies": ["vite.config.ts", "test/**/*.ts"], + "optionalDependencies": false, + "peerDependencies": false + } + ], + "import/no-unresolved": [ + "error", + { + "ignore": ["vitest/config"] + } + ], "import/order": "warn", "no-param-reassign": "warn", "no-restricted-syntax": [ @@ -78,34 +92,10 @@ } }, - { - "files": ["./test/**/*.js"], - "env": { - "mocha": true - } - }, - { "files": ["./**/*.ts"], "rules": { - "@typescript-eslint/no-unused-expressions": "off" - } - }, - - { - "files": ["./test/**/*.ts"], - "plugins": ["vitest"], - "globals": { - "describe": true, - "it": true, - "expect": true, - "beforeAll": true, - "beforeEach": true, - "afterAll": true, - "afterEach": true - }, - "rules": { - "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/no-unused-expressions": "off", "import/extensions": [ "error", "ignorePackages", @@ -115,7 +105,15 @@ "ts": "never", "tsx": "never" } - ], + ] + } + }, + + { + "files": ["./test/**/*.ts"], + "plugins": ["vitest"], + "rules": { + "@typescript-eslint/no-non-null-assertion": "off", "no-undef": "off" } } From 997c2f02ccfb28ab0c23c7d1db61debaaad93772 Mon Sep 17 00:00:00 2001 From: eyelidlessness Date: Sat, 24 Dec 2022 14:05:53 -0800 Subject: [PATCH 10/11] Restore coverage, remove mocha scripts/dependencies --- nyc.config.js | 6 - package-lock.json | 1453 ++++----------------------------------------- package.json | 12 +- vite.config.ts | 7 + 4 files changed, 112 insertions(+), 1366 deletions(-) delete mode 100644 nyc.config.js diff --git a/nyc.config.js b/nyc.config.js deleted file mode 100644 index 4df55a7..0000000 --- a/nyc.config.js +++ /dev/null @@ -1,6 +0,0 @@ -'use strict'; - -module.exports = { - reporter: ['html', 'text-summary', 'json'], - 'report-dir': './test-coverage', -}; diff --git a/package-lock.json b/package-lock.json index 5427fe9..a3af817 100644 --- a/package-lock.json +++ b/package-lock.json @@ -602,61 +602,6 @@ "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", "dev": true }, - "@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.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", @@ -714,12 +659,6 @@ "@types/chai": "*" } }, - "@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==", - "dev": true - }, "@types/connect": { "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", @@ -1050,11 +989,45 @@ } } }, - "@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true + "@vitest/coverage-istanbul": { + "version": "0.26.2", + "resolved": "https://registry.npmjs.org/@vitest/coverage-istanbul/-/coverage-istanbul-0.26.2.tgz", + "integrity": "sha512-3tU7vrgnPiGdIoX9VpIqR2geBuk5er4+2m0flO563R+1lV4guqO2bKbCNqEGpnIRcmnWJKQI1LeXndPexqIHtA==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-instrument": "^5.2.1", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.1", + "istanbul-reports": "^3.1.5", + "test-exclude": "^6.0.0", + "vitest": "0.26.2" + }, + "dependencies": { + "istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + } + }, + "istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + } + } }, "@xmldom/xmldom": { "version": "0.7.9", @@ -1094,16 +1067,6 @@ "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true }, - "aggregate-error": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", - "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", - "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", @@ -1160,36 +1123,11 @@ "color-convert": "^1.9.0" } }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "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", - "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", "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", - "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", @@ -1661,12 +1599,6 @@ "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", "dev": true }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, "bindings": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", @@ -1728,12 +1660,6 @@ "fill-range": "^7.0.1" } }, - "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==", - "dev": true - }, "browserslist": { "version": "4.16.8", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.8.tgz", @@ -1772,18 +1698,6 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" }, - "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", @@ -1799,12 +1713,6 @@ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, "caniuse-lite": { "version": "1.0.30001252", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001252.tgz", @@ -1884,22 +1792,6 @@ "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", "dev": true }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, "chownr": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", @@ -1914,12 +1806,6 @@ "escape-string-regexp": "^1.0.5" } }, - "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 - }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -1935,17 +1821,6 @@ "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", "dev": true }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", @@ -1984,12 +1859,6 @@ "integrity": "sha512-pm0b+qv+CkWNriSTMsfnjChF9kH0kxz55y44Wo5le9qLxMj5xDQAaEd9ZN1ovSuk9CsrncWaFwgpOMg7ClJwkw==", "dev": true }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2105,12 +1974,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=", - "dev": true - }, "deep-eql": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", @@ -2131,15 +1994,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", @@ -2175,12 +2029,6 @@ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" }, - "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true - }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -2298,12 +2146,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 - }, "esbuild": { "version": "0.16.10", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.10.tgz", @@ -3527,17 +3369,6 @@ "unpipe": "~1.0.0" } }, - "find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - } - }, "find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", @@ -3590,12 +3421,6 @@ "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", "dev": true }, - "flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true - }, "flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -3633,59 +3458,6 @@ "for-in": "^1.0.1" } }, - "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" - }, - "dependencies": { - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "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" - } - } - } - }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -3696,12 +3468,6 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" }, - "fromentries": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", - "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", - "dev": true - }, "fs-minipass": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", @@ -3805,12 +3571,6 @@ "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", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, "get-func-name": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", @@ -3827,12 +3587,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 - }, "get-symbol-description": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", @@ -3957,12 +3711,6 @@ "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", "dev": true }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true - }, "grunt": { "version": "1.5.3", "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.5.3.tgz", @@ -4207,16 +3955,6 @@ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" }, - "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" - } - }, "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -4343,12 +4081,6 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, - "ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", - "dev": true - }, "ignore-walk": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz", @@ -4373,12 +4105,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 - }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -4502,15 +4228,6 @@ "has-bigints": "^1.0.1" } }, - "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==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, "is-boolean-object": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", @@ -4595,12 +4312,6 @@ "has-tostringtag": "^1.0.0" } }, - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true - }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -4635,12 +4346,6 @@ "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", "dev": true }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, "is-string": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", @@ -4659,12 +4364,6 @@ "has-symbols": "^1.0.2" } }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, "is-unc-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", @@ -4674,12 +4373,6 @@ "unc-path-regex": "^0.1.2" } }, - "is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true - }, "is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -4782,132 +4475,47 @@ "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", "dev": true }, - "istanbul-lib-hook": { + "istanbul-lib-report": { "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==", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", "dev": true, "requires": { - "@babel/core": "^7.7.5", - "@istanbuljs/schema": "^0.1.2", "istanbul-lib-coverage": "^3.0.0", - "semver": "^6.3.0" + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" } }, - "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==", + "istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "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" + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" }, "dependencies": { - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "dev": true, "requires": { - "shebang-regex": "^3.0.0" + "ms": "2.1.2" } }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "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 }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true - }, - "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" - } - } - } - }, - "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" - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "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.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } @@ -4922,16 +4530,6 @@ "lodash.includes": "^4.3.0" } }, - "istanbul-reports": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.3.tgz", - "integrity": "sha512-x9LtDVtfm/t1GFiLl3NffC7hz+I1ragvgX1P/Lg1NlIagifZDKUkuuaAxH/qpwj2IuEfD8G2Bs/UKp+sZ/pKkg==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -5346,12 +4944,6 @@ "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", "dev": true }, - "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.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -5370,52 +4962,6 @@ "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.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" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.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 - } - } - }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -5896,148 +5442,6 @@ } } }, - "mocha": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", - "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", - "dev": true, - "requires": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.3", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "4.2.1", - "ms": "2.1.3", - "nanoid": "3.3.1", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "which": "2.0.2", - "workerpool": "6.2.0", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "dependencies": { - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "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 - } - } - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "minimatch": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", - "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "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" - } - } - } - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -6060,12 +5464,6 @@ "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==" }, - "nanoid": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", - "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", - "dev": true - }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -6161,15 +5559,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" - } - }, "node-releases": { "version": "1.1.75", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.75.tgz", @@ -6186,62 +5575,6 @@ "node-pre-gyp": "^0.9.1" } }, - "nodemon": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", - "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", - "dev": true, - "requires": { - "chokidar": "^3.5.2", - "debug": "^3.2.7", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.1.2", - "pstree.remy": "^1.1.8", - "semver": "^5.7.1", - "simple-update-notifier": "^1.0.7", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "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" - } - } - } - }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", @@ -6271,267 +5604,45 @@ } } }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "npm-bundled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", - "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", - "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==" - }, - "npm-packlist": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", - "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", - "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==", - "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=" - }, - "nyc": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", - "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", - "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", - "get-package-type": "^0.1.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.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "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" - } - }, - "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", - "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 - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - } - } - }, - "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" - } - } + "npm-bundled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", + "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "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==" + }, + "npm-packlist": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", + "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", + "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==", + "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=" + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -7003,33 +6114,12 @@ } } }, - "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" - } - }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -7146,45 +6236,6 @@ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "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" - } - } - } - }, "pkg-types": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.1.tgz", @@ -7292,15 +6343,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", @@ -7327,12 +6369,6 @@ "ipaddr.js": "1.9.1" } }, - "pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true - }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -7354,15 +6390,6 @@ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -7490,15 +6517,6 @@ } } }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, "rechoir": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", @@ -7543,33 +6561,12 @@ "integrity": "sha512-k519uI04Z3SaY0fLX843MRXnDeG2+vHOFsyhiPZvNLe7r8rD2YNRjq4BQLZZ0oAr2NrtvZlICsXysGNFPGa3CQ==", "dev": true }, - "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" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, "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-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==", - "dev": true - }, "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -7761,15 +6758,6 @@ } } }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, "serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", @@ -7821,23 +6809,6 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==" }, - "simple-update-notifier": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz", - "integrity": "sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew==", - "dev": true, - "requires": { - "semver": "~7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true - } - } - }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -7917,31 +6888,6 @@ } } }, - "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": { - "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" - } - } - } - }, "spdx-correct": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", @@ -8210,12 +7156,6 @@ "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==", - "dev": true - }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -8402,26 +7342,6 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, - "touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "dev": true, - "requires": { - "nopt": "~1.0.10" - }, - "dependencies": { - "nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", - "dev": true, - "requires": { - "abbrev": "1" - } - } - } - }, "tsconfig-paths": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", @@ -8502,15 +7422,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" - } - }, "typescript": { "version": "4.9.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", @@ -8554,12 +7465,6 @@ "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", "dev": true }, - "undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true - }, "underscore": { "version": "1.13.6", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", @@ -8790,12 +7695,6 @@ "is-symbol": "^1.0.3" } }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, "wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", @@ -8816,77 +7715,6 @@ "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", "dev": true }, - "workerpool": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", - "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.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 - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - } - } - } - } - }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -8901,96 +7729,17 @@ "mkdirp": "^0.5.1" } }, - "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" - } - }, "xmlcreate": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", "dev": true }, - "y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "dependencies": { - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - } - } - }, - "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true - }, - "yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "requires": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "dependencies": { - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true - } - } - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true } } } diff --git a/package.json b/package.json index ed334c2..e820266 100644 --- a/package.json +++ b/package.json @@ -20,13 +20,11 @@ "contributors": [], "scripts": { "start": "node app.js", - "eslint-check": "eslint app.js src/**/*.js test/**/*.ts", - "eslint-fix": "eslint app.js src/**/*.js test/**/*.ts --fix", + "eslint-check": "eslint app.js src/**/*.js vite.config.ts test/**/*.ts", + "eslint-fix": "eslint app.js src/**/*.js vite.config.ts test/**/*.ts --fix", "prettier-fix": "prettier --write .", - "test": "vitest run", - "test:mocha": "nyc mocha test/*.spec.js --timeout 6000 && npm run prettier-fix && npm run eslint-fix && node update-readme-with-shield-badge.js", + "test": "vitest run --coverage && npm run prettier-fix && npm run eslint-fix && node update-readme-with-shield-badge.js", "test:watch": "vitest", - "test:mocha-watch": "nodemon --exec 'mocha test/*.spec.ts --timeout 6000000' --watch src --watch test --ext js,xml,xsl,ts", "build-docs": "rimraf docs && ./node_modules/.bin/jsdoc -c jsdoc.config.js", "develop": "DEBUG=api,transformer,markdown,language node app.js & http-server test/forms -p 8081" }, @@ -55,6 +53,7 @@ "@types/node": "^18.11.17", "@typescript-eslint/eslint-plugin": "^5.47.0", "@typescript-eslint/parser": "^5.47.0", + "@vitest/coverage-istanbul": "^0.26.2", "@xmldom/xmldom": "^0.7.9", "chai": "^4.3.7", "chai-as-promised": "^7.1.1", @@ -77,9 +76,6 @@ "jsdoc": "^3.6.11", "jsdoc-plugin-typescript": "^2.2.0", "markdown-eslint-parser": "^1.2.1", - "mocha": "^9.2.2", - "nodemon": "^2.0.20", - "nyc": "^15.1.0", "prettier": "^2.8.1", "rimraf": "^3.0.2", "typescript": "^4.9.4", diff --git a/vite.config.ts b/vite.config.ts index a601aec..723d56e 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -19,6 +19,13 @@ export default defineConfig({ // functionality which depends on libxmljs/libxslt. threads: false, + coverage: { + provider: 'istanbul', + include: ['src/**/*.js'], + reporter: ['html', 'text-summary', 'json'], + reportsDirectory: './test-coverage', + }, + globals: true, include: ['test/**/*.spec.ts'], reporters: 'verbose', From 0da3c322ee11a79fb5cbd01cf571d8ea6c42389c Mon Sep 17 00:00:00 2001 From: eyelidlessness Date: Sat, 24 Dec 2022 15:01:02 -0800 Subject: [PATCH 11/11] Add type checking, fix TypeScript configs, fix a few errors that show up in `tsc` --- jsconfig.json | 2 +- package.json | 5 +++-- test/bad-external.spec.ts | 7 +++---- test/shared.ts | 11 +++++------ test/tsconfig.json | 4 ---- tsconfig.base.json | 29 +++++++++++++++++++++++++++++ tsconfig.json | 30 +++--------------------------- 7 files changed, 44 insertions(+), 44 deletions(-) delete mode 100644 test/tsconfig.json create mode 100644 tsconfig.base.json diff --git a/jsconfig.json b/jsconfig.json index 192df60..c802454 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -1,4 +1,4 @@ { "exclude": ["node_modules"], - "include": ["src", "test", "typings"] + "include": ["src", "typings"] } diff --git a/package.json b/package.json index e820266..59f6a59 100644 --- a/package.json +++ b/package.json @@ -23,10 +23,11 @@ "eslint-check": "eslint app.js src/**/*.js vite.config.ts test/**/*.ts", "eslint-fix": "eslint app.js src/**/*.js vite.config.ts test/**/*.ts --fix", "prettier-fix": "prettier --write .", - "test": "vitest run --coverage && npm run prettier-fix && npm run eslint-fix && node update-readme-with-shield-badge.js", + "test": "vitest run --coverage && npm run prettier-fix && npm run eslint-fix && tsc && node update-readme-with-shield-badge.js", "test:watch": "vitest", "build-docs": "rimraf docs && ./node_modules/.bin/jsdoc -c jsdoc.config.js", - "develop": "DEBUG=api,transformer,markdown,language node app.js & http-server test/forms -p 8081" + "develop": "DEBUG=api,transformer,markdown,language node app.js & http-server test/forms -p 8081", + "tsc": "tsc" }, "repository": { "type": "git", diff --git a/test/bad-external.spec.ts b/test/bad-external.spec.ts index 0973e4e..e249609 100644 --- a/test/bad-external.spec.ts +++ b/test/bad-external.spec.ts @@ -1,10 +1,9 @@ import { NAMESPACES } from '../src/transformer'; import { - Document, + DocumentConstructor as Document, getTransformedForm, getTransformedModelDocument, parser, - XMLDocument, } from './shared'; import type { @@ -129,7 +128,7 @@ describe('for incompatible forms that require preprocessing', () => { it('preprocess fn does nothing if not provided...', async () => { const doc = await getTransformedModelDocument('bad-external.xml'); - expect(doc).to.be.an.instanceOf(XMLDocument); + expect(doc).to.be.an.instanceOf(Document); expect(doc.getElementsByTagName('instance')).to.have.length(2); expect(doc.getElementById('existing')).to.not.be.null; expect(doc.getElementById('existing')!.getAttribute('src')).to.equal( @@ -145,7 +144,7 @@ describe('for incompatible forms that require preprocessing', () => { 'text/xml' ); - expect(preprocessedModel).to.be.an.instanceOf(XMLDocument); + expect(preprocessedModel).to.be.an.instanceOf(Document); expect( preprocessedModel.getElementsByTagName('instance') ).to.have.length(4); diff --git a/test/shared.ts b/test/shared.ts index 41668b2..f22721d 100644 --- a/test/shared.ts +++ b/test/shared.ts @@ -81,15 +81,14 @@ export const getTransformedModelDocument = async ( }; /** - * TODO: `@xmldom/xmldom` does not export `Document`. It's pretty linkely that @see {@link https://github.com/WebReflection/linkedom | `linkedom`}: + * TODO: `@xmldom/xmldom` does not export `Document`. It's pretty linkely that {@link https://github.com/WebReflection/linkedom linkedom}: * * 1. Does export it. * 2. Is a drop-in replacement for `@xmldom/xmldom`. * 3. Could very possibly go away soon anyway ;) */ -export const Document = parser.parseFromString('', 'text/html').constructor; +const document = parser.parseFromString('', 'text/html'); -/** - * TODO: this is at least temporarily a necessary fib. - */ -export const XMLDocument = Document; +export const DocumentConstructor = document.constructor; + +export type Document = typeof document; diff --git a/test/tsconfig.json b/test/tsconfig.json deleted file mode 100644 index d0791da..0000000 --- a/test/tsconfig.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "../tsconfig.json", - "files": ["../typings/test.d.ts"] -} diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 0000000..0151e33 --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "allowJs": true, + "allowSyntheticDefaultImports": true, + "allowUnreachableCode": false, + "baseUrl": ".", + "checkJs": false, + "declaration": false, + "downlevelIteration": true, + "esModuleInterop": true, + "experimentalDecorators": true, + "forceConsistentCasingInFileNames": true, + "inlineSourceMap": true, + "lib": ["ES2018"], + "module": "amd", + "moduleResolution": "node", + "noEmit": true, + "noFallthroughCasesInSwitch": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "es2018", + "types": ["node"] + }, + "exclude": ["node_modules", "typings/test.d.ts"], + "include": ["src", "typings"] +} diff --git a/tsconfig.json b/tsconfig.json index a78b4ab..95ac83f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,29 +1,5 @@ { - "compilerOptions": { - "allowJs": true, - "allowSyntheticDefaultImports": true, - "allowUnreachableCode": false, - "baseUrl": ".", - "checkJs": false, - "declaration": false, - "downlevelIteration": true, - "esModuleInterop": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true, - "inlineSourceMap": true, - "lib": ["ES2018"], - "module": "amd", - "moduleResolution": "node", - "noEmit": true, - "noFallthroughCasesInSwitch": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "resolveJsonModule": true, - "skipLibCheck": true, - "strict": true, - "target": "es2018", - "types": ["node"] - }, - "exclude": ["node_modules", "typings/test.d.ts"], - "include": ["src", "test", "typings"] + "extends": "./tsconfig.base.json", + "include": ["test", "typings"], + "files": ["./typings/test.d.ts"] }